diff options
-rw-r--r-- | ceilometer/api/controllers/v2.py | 3 | ||||
-rw-r--r-- | ceilometer/collector/service.py | 10 | ||||
-rw-r--r-- | ceilometer/compute/instance.py | 11 | ||||
-rw-r--r-- | ceilometer/nova_client.py | 48 | ||||
-rw-r--r-- | ceilometer/pipeline.py | 2 | ||||
-rw-r--r-- | ceilometer/service.py | 6 | ||||
-rw-r--r-- | ceilometer/storage/impl_mongodb.py | 2 | ||||
-rw-r--r-- | doc/source/configuration.rst | 1 | ||||
-rw-r--r-- | doc/source/measurements.rst | 9 | ||||
-rw-r--r-- | etc/ceilometer/ceilometer.conf.sample | 5 | ||||
-rw-r--r-- | tests/compute/test_instance.py | 58 | ||||
-rw-r--r-- | tests/compute/test_pollsters.py | 3 | ||||
-rw-r--r-- | tests/test_novaclient.py | 127 |
13 files changed, 225 insertions, 60 deletions
diff --git a/ceilometer/api/controllers/v2.py b/ceilometer/api/controllers/v2.py index c58241ee..8f98feb3 100644 --- a/ceilometer/api/controllers/v2.py +++ b/ceilometer/api/controllers/v2.py @@ -139,8 +139,7 @@ def _query_to_kwargs(query, db_func): if trans: for k in trans: if k not in valid_keys: - raise wsme.exc.UnknownArgument(i.field, - "unrecognized query field") + raise wsme.exc.UnknownArgument(k, "unrecognized query field") kwargs[k] = trans[k] return kwargs diff --git a/ceilometer/collector/service.py b/ceilometer/collector/service.py index 2f4ddf14..eda82706 100644 --- a/ceilometer/collector/service.py +++ b/ceilometer/collector/service.py @@ -131,11 +131,11 @@ class CollectorService(service.PeriodicService): data = [data] for meter in data: - LOG.info('metering data %s for %s @ %s: %s', - meter['counter_name'], - meter['resource_id'], - meter.get('timestamp', 'NO TIMESTAMP'), - meter['counter_volume']) + LOG.debug('metering data %s for %s @ %s: %s', + meter['counter_name'], + meter['resource_id'], + meter.get('timestamp', 'NO TIMESTAMP'), + meter['counter_volume']) if meter_api.verify_signature(meter, cfg.CONF.metering_secret): try: # Convert the timestamp to a datetime instance. diff --git a/ceilometer/compute/instance.py b/ceilometer/compute/instance.py index dff5ec6e..82026c6a 100644 --- a/ceilometer/compute/instance.py +++ b/ceilometer/compute/instance.py @@ -24,25 +24,26 @@ INSTANCE_PROPERTIES = [ # Type properties 'architecture', # Location properties - 'availability_zone', 'kernel_id', 'os_type', 'ramdisk_id', # Capacity properties - 'disk_gb', 'ephemeral_gb', - 'memory_mb', - 'root_gb', - 'vcpus'] + 'root_gb'] def get_metadata_from_object(instance): """Return a metadata dictionary for the instance. """ metadata = { + 'availability_zone': getattr(instance, + 'OS-EXT-AZ:availability_zone', u''), 'display_name': instance.name, 'name': getattr(instance, 'OS-EXT-SRV-ATTR:instance_name', u''), 'instance_type': (instance.flavor['id'] if instance.flavor else None), + 'disk_gb': (instance.flavor['disk'] if instance.flavor else None), + 'memory_mb': (instance.flavor['ram'] if instance.flavor else None), + 'vcpus': (instance.flavor['vcpus'] if instance.flavor else None), 'host': instance.hostId, # Image properties 'image_ref': (instance.image['id'] if instance.image else None), diff --git a/ceilometer/nova_client.py b/ceilometer/nova_client.py index 9bbff9ff..e8f4714d 100644 --- a/ceilometer/nova_client.py +++ b/ceilometer/nova_client.py @@ -16,6 +16,7 @@ import functools +import novaclient from novaclient.v1_1 import client as nova_client from oslo.config import cfg @@ -44,27 +45,58 @@ class Client(object): """Returns a nova Client object.""" conf = cfg.CONF tenant = conf.os_tenant_id and conf.os_tenant_id or conf.os_tenant_name + endpoint_type = cfg.CONF.os_endpoint_type self.nova_client = nova_client.Client(username=cfg.CONF.os_username, api_key=cfg.CONF.os_password, project_id=tenant, auth_url=cfg.CONF.os_auth_url, + endpoint_type=endpoint_type, no_cache=True) - def _with_flavor(self, instances): - flavors = dict((f.id, f) for f in self.nova_client.flavors.list()) + def _with_flavor_and_image(self, instances): for instance in instances: - fid = instance.flavor['id'] - try: - instance.flavor['name'] = flavors[fid].name - except KeyError: - instance.flavor['name'] = 'unknown-id-%s' % fid + self._with_flavor(instance) + self._with_image(instance) + return instances + def _with_flavor(self, instance): + fid = instance.flavor['id'] + try: + flavor = self.nova_client.flavors.get(fid) + except novaclient.exceptions.NotFound: + flavor = None + + attr_defaults = [('name', 'unknown-id-%s' % fid), + ('vcpus', 0), ('ram', 0), ('disk', 0)] + for attr, default in attr_defaults: + if not flavor: + instance.flavor[attr] = default + continue + instance.flavor[attr] = getattr(flavor, attr, default) + + def _with_image(self, instance): + iid = instance.image['id'] + try: + image = self.nova_client.images.get(iid) + except novaclient.exceptions.NotFound: + instance.image['name'] = 'unknown-id-%s' % iid + instance.kernel_id = None + instance.ramdisk_id = None + return + + instance.image['name'] = getattr(image, 'name') + image_metadata = getattr(image, 'metadata', None) + + for attr in ['kernel_id', 'ramdisk_id']: + ameta = image_metadata.get(attr, None) if image_metadata else None + setattr(instance, attr, ameta) + @logged def instance_get_all_by_host(self, hostname): """Returns list of instances on particular host.""" search_opts = {'host': hostname, 'all_tenants': True} - return self._with_flavor(self.nova_client.servers.list( + return self._with_flavor_and_image(self.nova_client.servers.list( detailed=True, search_opts=search_opts)) diff --git a/ceilometer/pipeline.py b/ceilometer/pipeline.py index 8609a64c..65d4dc1a 100644 --- a/ceilometer/pipeline.py +++ b/ceilometer/pipeline.py @@ -230,7 +230,7 @@ class Pipeline(object): transformed_counters = [] for counter in counters: - LOG.audit("Pipeline %s: Transform counter %s from %s transformer", + LOG.debug("Pipeline %s: Transform counter %s from %s transformer", self, counter, start) counter = self._transform_counter(start, ctxt, counter, source) if counter: diff --git a/ceilometer/service.py b/ceilometer/service.py index 9286abd1..5cabe8f0 100644 --- a/ceilometer/service.py +++ b/ceilometer/service.py @@ -33,7 +33,7 @@ cfg.CONF.register_opts([ default=600, help='seconds between running periodic tasks'), cfg.StrOpt('host', - default=socket.getfqdn(), + default=socket.gethostname(), help='Name of this node. This can be an opaque identifier. ' 'It is not necessarily a hostname, FQDN, or IP address. ' 'However, the node name must be valid within ' @@ -58,6 +58,10 @@ CLI_OPTIONS = [ default=os.environ.get('OS_AUTH_URL', 'http://localhost:5000/v2.0'), help='Auth URL to use for openstack service access'), + cfg.StrOpt('os-endpoint-type', + default=os.environ.get('OS_ENDPOINT_TYPE', 'publicURL'), + help='Type of endpoint in Identity service catalog to use for ' + 'communication with OpenStack services.'), ] cfg.CONF.register_cli_opts(CLI_OPTIONS) diff --git a/ceilometer/storage/impl_mongodb.py b/ceilometer/storage/impl_mongodb.py index 77ca0b5d..e364b805 100644 --- a/ceilometer/storage/impl_mongodb.py +++ b/ceilometer/storage/impl_mongodb.py @@ -264,6 +264,8 @@ class Connection(base.Connection): ('timestamp', pymongo.ASCENDING), ('source', pymongo.ASCENDING), ], name='meter_idx') + self.db.meter.ensure_index([('timestamp', pymongo.DESCENDING)], + name='timestamp_idx') def upgrade(self, version=None): pass diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst index 73104f56..9ecb629a 100644 --- a/doc/source/configuration.rst +++ b/doc/source/configuration.rst @@ -45,6 +45,7 @@ os_password admin Password os_tenant_id Tenant ID to use for openstack service access os_tenant_name admin Tenant name to use for openstack service access os_auth_url http://localhost:5000/v2.0 Auth URL to use for openstack service access +os_endpoint_type publicURL Endpoint type in the catalog to use to access services database_connection mongodb://localhost:27017/ceilometer Database connection string metering_api_port 8777 The port for the ceilometer API server disabled_central_pollsters List of central pollsters to skip loading diff --git a/doc/source/measurements.rst b/doc/source/measurements.rst index f53a7e08..d16b1aaf 100644 --- a/doc/source/measurements.rst +++ b/doc/source/measurements.rst @@ -78,11 +78,10 @@ disk.read.bytes Cumulative B inst ID pollster Volume o disk.write.bytes Cumulative B inst ID pollster Volume of write in B disk.root.size Gauge GB inst ID notification Size of root disk in GB disk.ephemeral.size Gauge GB inst ID notification Size of ephemeral disk in GB -network.incoming.bytes Cumulative B iface ID pollster number of incoming bytes on the network -network.outgoing.bytes Cumulative B iface ID pollster number of outgoing bytes on the network -network.incoming.packets Cumulative packets iface ID pollster number of incoming packets -network.outgoing.packets Cumulative packets iface ID pollster number of outgoing packets - +network.incoming.bytes Cumulative B iface ID pollster number of incoming bytes on the network for a VM interface +network.outgoing.bytes Cumulative B iface ID pollster number of outgoing bytes on the network for a VM interface +network.incoming.packets Cumulative packets iface ID pollster number of incoming packets for a VM interface +network.outgoing.packets Cumulative packets iface ID pollster number of outgoing packets for a VM interface ======================== ========== ======== ======== ============ ======================================================= Network (Quantum) diff --git a/etc/ceilometer/ceilometer.conf.sample b/etc/ceilometer/ceilometer.conf.sample index d028fe4d..db274eda 100644 --- a/etc/ceilometer/ceilometer.conf.sample +++ b/etc/ceilometer/ceilometer.conf.sample @@ -43,6 +43,9 @@ # Auth URL to use for openstack service access (string value) #os_auth_url= +# Type of endpoint in Identity service catalog to use for +# communication with OpenStack services. (string value) +#os_endpoint_type=publicURL ######## defined in ceilometer.api ######## @@ -477,4 +480,4 @@ #password=<None> -# Total option count: 105 +# Total option count: 106 diff --git a/tests/compute/test_instance.py b/tests/compute/test_instance.py index 09cc0afa..9a199f5c 100644 --- a/tests/compute/test_instance.py +++ b/tests/compute/test_instance.py @@ -53,49 +53,53 @@ class TestLocationMetadata(unittest.TestCase): self.INSTANCE_PROPERTIES = {'name': 'display name', 'OS-EXT-SRV-ATTR:instance_name': 'instance-000001', + 'availability_zone': None, + 'OS-EXT-AZ:availability_zone': + 'foo-zone', 'reservation_id': 'reservation id', 'architecture': 'x86_64', - 'availability_zone': 'zone1', 'kernel_id': 'kernel id', 'os_type': 'linux', 'ramdisk_id': 'ramdisk id', - 'disk_gb': 10, 'ephemeral_gb': 7, - 'memory_mb': 2048, 'root_gb': 3, - 'vcpus': 1, 'image': {'id': 1, 'links': [{"rel": "bookmark", 'href': 2}]}, - 'flavor': {'id': 1}, - 'hostId': '1234-5678'} + 'hostId': '1234-5678', + 'flavor': {'id': 1, + 'disk': 0, + 'ram': 512, + 'vcpus': 2}, + 'metadata': {'metering.autoscale.group': + 'X' * 512, + 'metering.ephemeral_gb': 42}} self.instance = FauxInstance(**self.INSTANCE_PROPERTIES) - self.instance.host = 'made-up-hostname' - m = mock.MagicMock() - m.flavorid = 1 - self.instance.instance_type = m def test_metadata(self): md = instance.get_metadata_from_object(self.instance) iprops = self.INSTANCE_PROPERTIES - for name in md.keys(): - actual = md[name] - print 'checking', name, actual - if name == 'name': - assert actual == iprops['OS-EXT-SRV-ATTR:instance_name'] - elif name == 'host': - assert actual == iprops['hostId'] - elif name == 'display_name': - assert actual == iprops['name'] - elif name == 'instance_type': - assert actual == iprops['flavor']['id'] - elif name == 'image_ref': - assert actual == iprops['image']['id'] - elif name == 'image_ref_url': - assert actual == iprops['image']['links'][0]['href'] - else: - assert actual == iprops[name] + self.assertEqual(md['availability_zone'], + iprops['OS-EXT-AZ:availability_zone']) + self.assertEqual(md['name'], iprops['OS-EXT-SRV-ATTR:instance_name']) + self.assertEqual(md['disk_gb'], iprops['flavor']['disk']) + self.assertEqual(md['display_name'], iprops['name']) + self.assertEqual(md['instance_type'], iprops['flavor']['id']) + self.assertEqual(md['image_ref'], iprops['image']['id']) + self.assertEqual(md['image_ref_url'], + iprops['image']['links'][0]['href']) + self.assertEqual(md['memory_mb'], iprops['flavor']['ram']) + self.assertEqual(md['vcpus'], iprops['flavor']['vcpus']) + self.assertEqual(md['host'], iprops['hostId']) + + self.assertEqual(md['reservation_id'], iprops['reservation_id']) + self.assertEqual(md['kernel_id'], iprops['kernel_id']) + self.assertEqual(md['ramdisk_id'], iprops['ramdisk_id']) + self.assertEqual(md['architecture'], iprops['architecture']) + self.assertEqual(md['os_type'], iprops['os_type']) + self.assertEqual(md['ephemeral_gb'], iprops['ephemeral_gb']) + self.assertEqual(md['root_gb'], iprops['root_gb']) def test_metadata_empty_image(self): self.INSTANCE_PROPERTIES['image'] = '' diff --git a/tests/compute/test_pollsters.py b/tests/compute/test_pollsters.py index 1aa5543c..526a7dbb 100644 --- a/tests/compute/test_pollsters.py +++ b/tests/compute/test_pollsters.py @@ -41,7 +41,8 @@ class TestPollsterBase(test_base.TestCase): setattr(self.instance, 'OS-EXT-SRV-ATTR:instance_name', self.instance.name) self.instance.id = 1 - self.instance.flavor = {'name': 'm1.small', 'id': 2} + self.instance.flavor = {'name': 'm1.small', 'id': 2, 'vcpus': 1, + 'ram': 512, 'disk': 0} class TestInstancePollster(TestPollsterBase): diff --git a/tests/test_novaclient.py b/tests/test_novaclient.py index ee3715d7..2b563694 100644 --- a/tests/test_novaclient.py +++ b/tests/test_novaclient.py @@ -19,6 +19,7 @@ import mock +import novaclient from ceilometer.tests import base from ceilometer import nova_client @@ -28,6 +29,42 @@ class TestNovaClient(base.TestCase): def setUp(self): super(TestNovaClient, self).setUp() self.nv = nova_client.Client() + self.stubs.Set(self.nv.nova_client.flavors, 'get', + self.fake_flavors_get) + self.stubs.Set(self.nv.nova_client.images, 'get', self.fake_images_get) + + @staticmethod + def fake_flavors_get(*args, **kwargs): + a = mock.MagicMock() + a.id = args[0] + if a.id == 1: + a.name = 'm1.tiny' + elif a.id == 2: + a.name = 'm1.large' + else: + raise novaclient.exceptions.NotFound('foobar') + return a + + @staticmethod + def fake_images_get(*args, **kwargs): + a = mock.MagicMock() + a.id = args[0] + image_details = { + 1: ('ubuntu-12.04-x86', dict(kernel_id=11, ramdisk_id=21)), + 2: ('centos-5.4-x64', dict(kernel_id=12, ramdisk_id=22)), + 3: ('rhel-6-x64', None), + 4: ('rhel-6-x64', dict()), + 5: ('rhel-6-x64', dict(kernel_id=11)), + 6: ('rhel-6-x64', dict(ramdisk_id=21)) + } + + if a.id in image_details: + a.name = image_details[a.id][0] + a.metadata = image_details[a.id][1] + else: + raise novaclient.exceptions.NotFound('foobar') + + return a @staticmethod def fake_flavors_list(): @@ -44,31 +81,113 @@ class TestNovaClient(base.TestCase): a = mock.MagicMock() a.id = 42 a.flavor = {'id': 1} + a.image = {'id': 1} return [a] def test_instance_get_all_by_host(self): - self.stubs.Set(self.nv.nova_client.flavors, 'list', - self.fake_flavors_list) self.stubs.Set(self.nv.nova_client.servers, 'list', self.fake_servers_list) instances = self.nv.instance_get_all_by_host('foobar') self.assertEqual(len(instances), 1) self.assertEqual(instances[0].flavor['name'], 'm1.tiny') + self.assertEqual(instances[0].image['name'], 'ubuntu-12.04-x86') + self.assertEqual(instances[0].kernel_id, 11) + self.assertEqual(instances[0].ramdisk_id, 21) @staticmethod def fake_servers_list_unknown_flavor(*args, **kwargs): a = mock.MagicMock() a.id = 42 a.flavor = {'id': 666} + a.image = {'id': 1} return [a] def test_instance_get_all_by_host_unknown_flavor(self): - self.stubs.Set(self.nv.nova_client.flavors, 'list', - self.fake_flavors_list) self.stubs.Set(self.nv.nova_client.servers, 'list', self.fake_servers_list_unknown_flavor) instances = self.nv.instance_get_all_by_host('foobar') self.assertEqual(len(instances), 1) self.assertEqual(instances[0].flavor['name'], 'unknown-id-666') + + @staticmethod + def fake_servers_list_unknown_image(*args, **kwargs): + a = mock.MagicMock() + a.id = 42 + a.flavor = {'id': 1} + a.image = {'id': 666} + return [a] + + @staticmethod + def fake_servers_list_image_missing_metadata(*args, **kwargs): + a = mock.MagicMock() + a.id = 42 + a.flavor = {'id': 1} + a.image = {'id': args[0]} + return [a] + + def test_instance_get_all_by_host_unknown_image(self): + self.stubs.Set(self.nv.nova_client.servers, 'list', + self.fake_servers_list_unknown_image) + + instances = self.nv.instance_get_all_by_host('foobar') + self.assertEqual(len(instances), 1) + self.assertEqual(instances[0].image['name'], 'unknown-id-666') + + def test_with_flavor_and_image(self): + results = self.nv._with_flavor_and_image(self.fake_servers_list()) + instance = results[0] + self.assertEqual(instance.image['name'], 'ubuntu-12.04-x86') + self.assertEqual(instance.flavor['name'], 'm1.tiny') + self.assertEqual(instance.kernel_id, 11) + self.assertEqual(instance.ramdisk_id, 21) + + def test_with_flavor_and_image_unknown_image(self): + instances = self.fake_servers_list_unknown_image() + results = self.nv._with_flavor_and_image(instances) + instance = results[0] + self.assertEqual(instance.image['name'], 'unknown-id-666') + self.assertNotEqual(instance.flavor['name'], 'unknown-id-666') + self.assertIsNone(instance.kernel_id) + self.assertIsNone(instance.ramdisk_id) + + def test_with_flavor_and_image_unknown_flavor(self): + instances = self.fake_servers_list_unknown_flavor() + results = self.nv._with_flavor_and_image(instances) + instance = results[0] + self.assertEqual(instance.flavor['name'], 'unknown-id-666') + self.assertEqual(instance.flavor['vcpus'], 0) + self.assertEqual(instance.flavor['ram'], 0) + self.assertEqual(instance.flavor['disk'], 0) + self.assertNotEqual(instance.image['name'], 'unknown-id-666') + self.assertEqual(instance.kernel_id, 11) + self.assertEqual(instance.ramdisk_id, 21) + + def test_with_flavor_and_image_none_metadata(self): + instances = self.fake_servers_list_image_missing_metadata(3) + results = self.nv._with_flavor_and_image(instances) + instance = results[0] + self.assertIsNone(instance.kernel_id) + self.assertIsNone(instance.ramdisk_id) + + def test_with_flavor_and_image_missing_metadata(self): + instances = self.fake_servers_list_image_missing_metadata(4) + results = self.nv._with_flavor_and_image(instances) + instance = results[0] + self.assertIsNone(instance.kernel_id) + self.assertIsNone(instance.ramdisk_id) + + def test_with_flavor_and_image_missing_ramdisk(self): + instances = self.fake_servers_list_image_missing_metadata(5) + results = self.nv._with_flavor_and_image(instances) + instance = results[0] + self.assertEqual(instance.kernel_id, 11) + self.assertIsNone(instance.ramdisk_id) + + def test_with_flavor_and_image_missing_kernel(self): + instances = self.fake_servers_list_image_missing_metadata(6) + results = self.nv._with_flavor_and_image(instances) + instance = results[0] + self.assertIsNone(instance.kernel_id) + self.assertEqual(instance.ramdisk_id, 21) |