From c01c66c10fe8e78883664def0604158b7b77b7c9 Mon Sep 17 00:00:00 2001 From: Eoghan Glynn Date: Mon, 8 Oct 2012 18:26:32 +0000 Subject: [PATCH] Use glance public API as opposed to registry API. Fixes bug 1064008 The motivation for switching over to the public API: - the registry API is more of an artifact of the internal glance architecture than a true public API - the registry API exposes internal attributes such as the backend store image location, which is stripped from the API-provided image representation for security reasons (hence should not bleed into metering) - the internalURL should be available from the keystone service catalog, so we can get rid of the registry host/port config Change-Id: I0d75392066a020c608a67f1ecf0e8dba15aa48f0 --- ceilometer/image/glance.py | 49 +++++++-------- doc/source/configuration.rst | 2 - tests/image/test_glance.py | 113 ++++++++++++++++++----------------- 3 files changed, 80 insertions(+), 84 deletions(-) diff --git a/ceilometer/image/glance.py b/ceilometer/image/glance.py index 3125c4c6..b943b666 100644 --- a/ceilometer/image/glance.py +++ b/ceilometer/image/glance.py @@ -22,49 +22,45 @@ from __future__ import absolute_import import itertools +import glanceclient from keystoneclient.v2_0 import client as ksclient -from glance.registry import client from ceilometer import plugin from ceilometer import counter from ceilometer.openstack.common import cfg from ceilometer.openstack.common import timeutils -cfg.CONF.register_opts( - [ - cfg.StrOpt('glance_registry_host', - default='localhost', - help="URL of Glance API server"), - cfg.IntOpt('glance_registry_port', - default=9191, - help="URL of Glance API server"), - ]) - class _Base(plugin.PollsterBase): @staticmethod - def get_registry_client(): + def get_glance_client(): k = ksclient.Client(username=cfg.CONF.os_username, password=cfg.CONF.os_password, tenant_id=cfg.CONF.os_tenant_id, tenant_name=cfg.CONF.os_tenant_name, auth_url=cfg.CONF.os_auth_url) - return client.RegistryClient(cfg.CONF.glance_registry_host, - cfg.CONF.glance_registry_port, - auth_tok=k.auth_token) + + endpoint = k.service_catalog.url_for(service_type='image', + endpoint_type='internalURL') + + # hard-code v1 glance API version selection while v2 API matures + return glanceclient.Client('1', endpoint, token=k.auth_token) def iter_images(self): """Iterate over all images.""" - # We need to ask for both public and non public to get all images. - client = self.get_registry_client() + client = self.get_glance_client() + #TODO(eglynn): use pagination to protect against unbounded + # memory usage return itertools.chain( - client.get_images_detailed(filters={"is_public": True}), - client.get_images_detailed(filters={"is_public": False})) + client.images.list(filters={"is_public": True}), + #TODO(eglynn): extend glance API with all_tenants logic to + # avoid second call to retrieve private images + client.images.list(filters={"is_public": False})) @staticmethod def extract_image_metadata(image): - return dict([(k, image[k]) + return dict((k, getattr(image, k)) for k in [ "status", "is_public", @@ -77,13 +73,12 @@ class _Base(plugin.PollsterBase): "properties", "min_disk", "protected", - "location", "checksum", "deleted_at", "min_ram", "size", ] - ]) + ) class ImagePollster(_Base): @@ -96,8 +91,8 @@ class ImagePollster(_Base): type=counter.TYPE_GAUGE, volume=1, user_id=None, - project_id=image['owner'], - resource_id=image['id'], + project_id=image.owner, + resource_id=image.id, timestamp=timeutils.isotime(), resource_metadata=self.extract_image_metadata(image), ) @@ -111,10 +106,10 @@ class ImageSizePollster(_Base): source='?', name='image.size', type=counter.TYPE_GAUGE, - volume=image['size'], + volume=image.size, user_id=None, - project_id=image['owner'], - resource_id=image['id'], + project_id=image.owner, + resource_id=image.id, timestamp=timeutils.isotime(), resource_metadata=self.extract_image_metadata(image), ) diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst index 75bcb91d..7485d625 100644 --- a/doc/source/configuration.rst +++ b/doc/source/configuration.rst @@ -32,8 +32,6 @@ Parameter Default Note ========================== ==================================== ============================================================== nova_control_exchange nova Exchange name for Nova notifications glance_control_exchange glance_notifications Exchange name for Glance notifications -glance_registry_host localhost URL of Glance API server -glance_registry_port 9191 port of Glance API server cinder_control_exchange cinder Exchange name for Cinder notifications quantum_control_exchange quantum Exchange name for Quantum notifications metering_secret change this or be hacked Secret value for signing metering messages diff --git a/tests/image/test_glance.py b/tests/image/test_glance.py index 005c3bf3..9f23217d 100644 --- a/tests/image/test_glance.py +++ b/tests/image/test_glance.py @@ -23,60 +23,63 @@ from ceilometer.openstack.common import context IMAGE_LIST = [ - {u'status': u'queued', - u'name': "some name", - u'deleted': False, - u'container_format': None, - u'created_at': u'2012-09-18T16:29:46', - u'disk_format': None, - u'updated_at': u'2012-09-18T16:29:46', - u'properties': {}, - u'min_disk': 0, - u'protected': False, - u'id': u'1d21a8d0-25f4-4e0a-b4ec-85f40237676b', - u'location': None, - u'checksum': None, - u'owner': u'4c8364fc20184ed7971b76602aa96184', - u'is_public': True, - u'deleted_at': None, - u'min_ram': 0, - u'size': 2048}, - {u'status': u'active', - u'name': "hello world", - u'deleted': False, - u'container_format': None, - u'created_at': u'2012-09-18T16:27:41', - u'disk_format': None, - u'updated_at': u'2012-09-18T16:27:41', - u'properties': {}, - u'min_disk': 0, - u'protected': False, - u'id': u'22be9f90-864d-494c-aa74-8035fd535989', - u'location': None, - u'checksum': None, - u'owner': u'9e4f98287a0246daa42eaf4025db99d4', - u'is_public': True, - u'deleted_at': None, - u'min_ram': 0, - u'size': 0}, - {u'status': u'queued', - u'name': None, - u'deleted': False, - u'container_format': None, - u'created_at': u'2012-09-18T16:23:27', - u'disk_format': "raw", - u'updated_at': u'2012-09-18T16:23:27', - u'properties': {}, - u'min_disk': 0, - u'protected': False, - u'id': u'8d133f6c-38a8-403c-b02c-7071b69b432d', - u'location': None, - u'checksum': None, - u'owner': u'5f8806a76aa34ee8b8fc8397bd154319', - u'is_public': True, - u'deleted_at': None, - u'min_ram': 0, - u'size': 1024}, + type('Image', (object,), + {u'status': u'queued', + u'name': "some name", + u'deleted': False, + u'container_format': None, + u'created_at': u'2012-09-18T16:29:46', + u'disk_format': None, + u'updated_at': u'2012-09-18T16:29:46', + u'properties': {}, + u'min_disk': 0, + u'protected': False, + u'id': u'1d21a8d0-25f4-4e0a-b4ec-85f40237676b', + u'location': None, + u'checksum': None, + u'owner': u'4c8364fc20184ed7971b76602aa96184', + u'is_public': True, + u'deleted_at': None, + u'min_ram': 0, + u'size': 2048}), + type('Image', (object,), + {u'status': u'active', + u'name': "hello world", + u'deleted': False, + u'container_format': None, + u'created_at': u'2012-09-18T16:27:41', + u'disk_format': None, + u'updated_at': u'2012-09-18T16:27:41', + u'properties': {}, + u'min_disk': 0, + u'protected': False, + u'id': u'22be9f90-864d-494c-aa74-8035fd535989', + u'location': None, + u'checksum': None, + u'owner': u'9e4f98287a0246daa42eaf4025db99d4', + u'is_public': True, + u'deleted_at': None, + u'min_ram': 0, + u'size': 0}), + type('Image', (object,), + {u'status': u'queued', + u'name': None, + u'deleted': False, + u'container_format': None, + u'created_at': u'2012-09-18T16:23:27', + u'disk_format': "raw", + u'updated_at': u'2012-09-18T16:23:27', + u'properties': {}, + u'min_disk': 0, + u'protected': False, + u'id': u'8d133f6c-38a8-403c-b02c-7071b69b432d', + u'location': None, + u'checksum': None, + u'owner': u'5f8806a76aa34ee8b8fc8397bd154319', + u'is_public': True, + u'deleted_at': None, + u'min_ram': 0, + u'size': 1024}), ] @@ -106,5 +109,5 @@ class TestImagePollster(base.TestCase): self.assertEqual(len(counters), 3) for image in IMAGE_LIST: self.assert_( - any(map(lambda counter: counter.volume == image['size'], + any(map(lambda counter: counter.volume == image.size, counters)))