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])