Adding slice and XOS service details to ceilometer meters
diff --git a/xos/core/xoslib/methods/ceilometerview.py b/xos/core/xoslib/methods/ceilometerview.py
index a416110..d02e716 100644
--- a/xos/core/xoslib/methods/ceilometerview.py
+++ b/xos/core/xoslib/methods/ceilometerview.py
@@ -1,4 +1,3 @@
-import logging
 import requests
 from six.moves import urllib
 import urllib2
@@ -18,9 +17,9 @@
 from django.utils import timezone
 from syndicate_storage.models import Volume
 from django.core.exceptions import PermissionDenied
+from util.logger import observer_logger as logger
 
 # This REST API endpoint provides information that the ceilometer view needs to display
-LOG = logging.getLogger(__name__)
 
 def getTenantCeilometerProxyURL(user):
     monitoring_channel = None
@@ -36,11 +35,12 @@
             response = urllib2.urlopen(monitoring_channel.ceilometer_url,timeout=1)
             break
         except urllib2.HTTPError, e:
-            LOG.info('SRIKANTH: HTTP error %(reason)s' % {'reason':e.reason})
+            logger.info('SRIKANTH: HTTP error %(reason)s' % {'reason':e.reason})
             break
         except urllib2.URLError, e:
-            LOG.info('SRIKANTH: URL error %(reason)s' % {'reason':e.reason})
+            logger.info('SRIKANTH: URL error %(reason)s' % {'reason':e.reason})
             pass
+    logger.info("SRIKANTH: Ceilometer proxy URL for user %(user)s is %(url)s" % {'user':user.username,'url':monitoring_channel.ceilometer_url})
     return monitoring_channel.ceilometer_url
 
 def getTenantControllerTenantMap(user):
@@ -48,7 +48,12 @@
     for slice in Slice.objects.filter(creator=user):
         for cs in slice.controllerslices.all():
             if cs.tenant_id:
-                tenantmap[cs.tenant_id] = cs.slice.name
+                tenantmap[cs.tenant_id] = {"slice": cs.slice.name}
+                if cs.slice.service:
+                    tenantmap[cs.tenant_id]["service"] = slice.service.name
+                else:
+                    logger.warn("SRIKANTH: Slice %(slice)s is not associated with any service" % {'slice':cs.slice.name})
+                    tenantmap[cs.tenant_id]["service"] = "Other"
     return tenantmap
 
 def build_url(path, q, params=None):
@@ -171,7 +176,6 @@
             try:
                 query=[]
                 self._ceilometer_meter_list = meter_list(request, self.ceilometer_url, query)
-                #LOG.info('SRIKANTH: meters=%(meters)s'%{'meters':[m.project_id for m in self._ceilometer_meter_list]})
             except requests.exceptions.RequestException as e:
                 self._ceilometer_meter_list = []
                 raise e
@@ -354,9 +358,9 @@
 
         meters = []
         for meter_name in meter_names:
-            meter = self._get_meter(meter_name)
-            if meter:
-                meters.append(meter)
+            meter_candidates = self._get_meter(meter_name)
+            if meter_candidates:
+                meters.extend(meter_candidates)
         return meters
 
     def _get_meter(self, meter_name):
@@ -368,8 +372,8 @@
         :Parameters:
           - `meter_name`: A meter name we want to fetch.
         """
-        meter = self._cached_meters.get(meter_name, None)
-        if not meter:
+        meter_candidates = self._cached_meters.get(meter_name, None)
+        if not meter_candidates:
             meter_candidates = [m for m in self._ceilometer_meter_list
                                 if m["name"] == meter_name]
 
@@ -378,20 +382,25 @@
                 if meter_info:
                     label = meter_info["label"]
                     description = meter_info["description"]
+                    meter_type = meter_info["type"]
                 else:
                     label = ""
                     description = ""
-                meter = meter_candidates[0]
-                meter["label"] = label
-                meter["description"] = description
-                if meter["project_id"] in self.tenant_map.keys():
-                    meter["project_name"] = self.tenant_map[meter["project_id"]]
-                else:
-                    meter["project_name"] = meter["project_id"]
+                    meter_type = "Other"
+                for meter in meter_candidates:
+                    meter["label"] = label
+                    meter["description"] = description
+                    meter["type"] = meter_type
+                    if meter["project_id"] in self.tenant_map.keys():
+                        meter["slice"] = self.tenant_map[meter["project_id"]]["slice"]
+                        meter["service"] = self.tenant_map[meter["project_id"]]["service"]
+                    else:
+                        meter["slice"] = meter["project_id"]
+                        meter["service"] = "Other"
 
-                self._cached_meters[meter_name] = meter
+                self._cached_meters[meter_name] = meter_candidates
 
-        return meter
+        return meter_candidates
 
     def _get_nova_meters_info(self):
         """Returns additional info for each meter.
@@ -405,40 +414,49 @@
         # some day it will be supported all.
         meters_info = datastructures.SortedDict([
             ("instance", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Existence of instance"),
             }),
             ("instance:<type>", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Existence of instance <type> "
                                  "(openstack types)"),
             }),
             ("memory", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Volume of RAM"),
             }),
             ("memory.usage", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Volume of RAM used"),
             }),
             ("cpu", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("CPU time used"),
             }),
             ("cpu_util", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Average CPU utilization"),
             }),
             ("vcpus", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Number of VCPUs"),
             }),
             ("network.incoming.bytes.rate", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Average rate per sec of incoming "
                                  "bytes on a VM network interface"),
             }),
             ("network.outgoing.bytes.rate", {
+                'type': _("Nova"),
                 'label': '',
                 'description': _("Average rate per sec of outgoing "
                                  "bytes on a VM network interface"),
@@ -471,18 +489,22 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('network', {
+                'type': _("Neutron"),
                 'label': '',
                 'description': _("Existence of network"),
             }),
             ('subnet', {
+                'type': _("Neutron"),
                 'label': '',
                 'description': _("Existence of subnet"),
             }),
             ('port', {
+                'type': _("Neutron"),
                 'label': '',
                 'description': _("Existence of port"),
             }),
             ('ip.floating', {
+                'type': _("Neutron"),
                 'label': '',
                 'description': _("Existence of floating ip"),
             }),
@@ -500,30 +522,37 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('image', {
+                'type': _("Glance"),
                 'label': '',
                 'description': _("Image existence check"),
             }),
             ('image.size', {
+                'type': _("Glance"),
                 'label': '',
                 'description': _("Uploaded image size"),
             }),
             ('image.update', {
+                'type': _("Glance"),
                 'label': '',
                 'description': _("Number of image updates"),
             }),
             ('image.upload', {
+                'type': _("Glance"),
                 'label': '',
                 'description': _("Number of image uploads"),
             }),
             ('image.delete', {
+                'type': _("Glance"),
                 'label': '',
                 'description': _("Number of image deletions"),
             }),
             ('image.download', {
+                'type': _("Glance"),
                 'label': '',
                 'description': _("Image is downloaded"),
             }),
             ('image.serve', {
+                'type': _("Glance"),
                 'label': '',
                 'description': _("Image is served out"),
             }),
@@ -541,10 +570,12 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('volume', {
+                'type': _("Cinder"),
                 'label': '',
                 'description': _("Existence of volume"),
             }),
             ('volume.size', {
+                'type': _("Cinder"),
                 'label': '',
                 'description': _("Size of volume"),
             }),
@@ -562,26 +593,32 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('storage.objects', {
+                'type': _("Swift"),
                 'label': '',
                 'description': _("Number of objects"),
             }),
             ('storage.objects.size', {
+                'type': _("Swift"),
                 'label': '',
                 'description': _("Total size of stored objects"),
             }),
             ('storage.objects.containers', {
+                'type': _("Swift"),
                 'label': '',
                 'description': _("Number of containers"),
             }),
             ('storage.objects.incoming.bytes', {
+                'type': _("Swift"),
                 'label': '',
                 'description': _("Number of incoming bytes"),
             }),
             ('storage.objects.outgoing.bytes', {
+                'type': _("Swift"),
                 'label': '',
                 'description': _("Number of outgoing bytes"),
             }),
             ('storage.api.request', {
+                'type': _("Swift"),
                 'label': '',
                 'description': _("Number of API requests against swift"),
             }),
@@ -599,10 +636,12 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('energy', {
+                'type': _("Kwapi"),
                 'label': '',
                 'description': _("Amount of energy"),
             }),
             ('power', {
+                'type': _("Kwapi"),
                 'label': '',
                 'description': _("Power consumption"),
             }),
@@ -620,50 +659,62 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('hardware.ipmi.node.power', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System Current Power"),
             }),
             ('hardware.ipmi.fan', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("Fan RPM"),
             }),
             ('hardware.ipmi.temperature', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("Sensor Temperature Reading"),
             }),
             ('hardware.ipmi.current', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("Sensor Current Reading"),
             }),
             ('hardware.ipmi.voltage', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("Sensor Voltage Reading"),
             }),
             ('hardware.ipmi.node.inlet_temperature', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System Inlet Temperature Reading"),
             }),
             ('hardware.ipmi.node.outlet_temperature', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System Outlet Temperature Reading"),
             }),
             ('hardware.ipmi.node.airflow', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System Airflow Reading"),
             }),
             ('hardware.ipmi.node.cups', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System CUPS Reading"),
             }),
             ('hardware.ipmi.node.cpu_util', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System CPU Utility Reading"),
             }),
             ('hardware.ipmi.node.mem_util', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System Memory Utility Reading"),
             }),
             ('hardware.ipmi.node.io_util', {
+                'type': _("IPMI"),
                 'label': '',
                 'description': _("System IO Utility Reading"),
             }),
@@ -681,34 +732,42 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('vcpe', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("Existence of vcpe instance"),
             }),
             ('vcpe.dns.cache.size', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("Number of entries in DNS cache"),
             }),
             ('vcpe.dns.total_instered_entries', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("Total number of inserted entries into the cache"),
             }),
             ('vcpe.dns.replaced_unexpired_entries', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("Unexpired entries that were thrown out of cache"),
             }),
             ('vcpe.dns.queries_answered_locally', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("Number of cache hits"),
             }),
             ('vcpe.dns.queries_forwarded', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("Number of cache misses"),
             }),
             ('vcpe.dns.server.queries_sent', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("For each upstream server, the number of queries sent"),
             }),
             ('vcpe.dns.server.queries_failed', {
+                'type': _("VCPE"),
                 'label': '',
                 'description': _("For each upstream server, the number of queries failed"),
             }),
@@ -726,50 +785,62 @@
         # some day it will be supported all.
         return datastructures.SortedDict([
             ('switch', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Existence of switch"),
             }),
             ('switch.port', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Existence of port"),
             }),
             ('switch.port.receive.packets', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Packets received on port"),
             }),
             ('switch.port.transmit.packets', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Packets transmitted on port"),
             }),
             ('switch.port.receive.drops', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Drops received on port"),
             }),
             ('switch.port.transmit.drops', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Drops transmitted on port"),
             }),
             ('switch.port.receive.errors', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Errors received on port"),
             }),
             ('switch.port.transmit.errors', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Errors transmitted on port"),
             }),
             ('switch.flow', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Duration of flow"),
             }),
             ('switch.flow.packets', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Packets received"),
             }),
             ('switch.table', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Existence of table"),
             }),
             ('switch.table.active.entries', {
+                'type': _("SDN"),
                 'label': '',
                 'description': _("Active entries in table"),
             }),
@@ -865,7 +936,10 @@
             _('VCPE'): meters.list_vcpe(),
             _('SDN'): meters.list_sdn(),
         }
-        return Response(meters._cached_meters.values())
+        meters = []
+        for service,smeters in services.iteritems():
+             meters.extend(smeters)
+        return Response(meters)
 
 class MeterStatisticsList(APIView):
     method_kind = "list"
@@ -890,6 +964,39 @@
         except Exception as e:
            raise e 
 
+        additional_query = []
+        if date_from:
+            additional_query.append({'field': 'timestamp',
+                                     'op': 'ge',
+                                     'value': date_from})
+        if date_to:
+            additional_query.append({'field': 'timestamp',
+                                     'op': 'le',
+                                     'value': date_to})
+
+        meter_name = request.QUERY_PARAMS.get('meter', None)
+        tenant_id = request.QUERY_PARAMS.get('tenant', None)
+        resource_id = request.QUERY_PARAMS.get('resource', None)
+
+        if meter_name:
+            #Statistics query for one meter
+            query = []
+            if tenant_id:
+                query.extend(make_query(tenant_id=tenant_id))
+            if resource_id:
+                query.extend(make_query(resource_id=resource_id))
+            if additional_query:
+                query = query + additional_query
+            statistics = statistic_list(request, meter_name,
+                                        ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+            statistic = statistics[-1]
+            row = {"name": 'none',
+                   "meter": meter_name,
+                   "time": statistic["period_end"],
+                   "value": statistic["avg"]}
+            return Response(row)
+
+        #Statistics query for all meter
         meters = Meters(request, ceilometer_url=tenant_ceilometer_url, tenant_map=tenant_map)
         services = {
             _('Nova'): meters.list_nova(),
@@ -900,17 +1007,21 @@
         report_rows = []
         for service,meters in services.items():
             for meter in meters:
-                query = make_query(tenant_id=meter["project_id"])
+                query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
+                if additional_query:
+                    query = query + additional_query
                 statistics = statistic_list(request, meter["name"],
                                         ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
                 if not statistics:
                     continue
-                statistic = statistics[0]
+                statistic = statistics[-1]
                 row = {"name": 'none',
-                       "project": meter["project_name"],
+                       "slice": meter["slice"],
+                       "service": meter["service"],
+                       "resource_id": meter["resource_id"],
                        "meter": meter["name"],
                        "description": meter["description"],
-                       "service": service,
+                       "type": service,
                        "time": statistic["period_end"],
                        "value": statistic["avg"],
                        "unit": meter["unit"]}
diff --git a/xos/observers/monitoring_channel/templates/ceilometer_proxy_server.py b/xos/observers/monitoring_channel/templates/ceilometer_proxy_server.py
index 249c965..9329cfa 100644
--- a/xos/observers/monitoring_channel/templates/ceilometer_proxy_server.py
+++ b/xos/observers/monitoring_channel/templates/ceilometer_proxy_server.py
@@ -223,11 +223,15 @@
              "q.op": [],
              "q.type": [],
              "q.value": [],
+             "limit": None,
+             "links": None,
         }
         query_params = web.input(**keyword_args)
         new_query, user_specified_tenants = filter_query_params(query_params)
 
         client = ceilometerclient()
+        limit=query_params.limit
+        links=query_params.links
         resources=[]
         for (k,v) in config.items('allowed_tenants'):
               if user_specified_tenants and (k not in user_specified_tenants):
@@ -237,7 +241,7 @@
               query = make_query(tenant_id=k)
               final_query.extend(query)
               logger.debug('final query=%s',final_query)
-              results = client.resources.list(q=final_query, links=1)
+              results = client.resources.list(q=final_query, limit=limit, links=links)
               resources.extend(results)
         return json.dumps([ob._info for ob in resources])