add metadata to nova_client results

Fixes bug 1190547

Change-Id: I90861038f0623e6183dfd43899669aba88b47796
This commit is contained in:
John Tran 2013-06-25 18:07:58 +00:00
parent 69cb42933d
commit 298e2f7e7b
5 changed files with 131 additions and 46 deletions

View File

@ -37,16 +37,12 @@ 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 add_reserved_user_metadata(instance, metadata):
@ -71,9 +67,14 @@ 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),

View File

@ -16,6 +16,7 @@
import functools
import novaclient
from novaclient.v1_1 import client as nova_client
from oslo.config import cfg
@ -52,21 +53,44 @@ class Client(object):
auth_url=cfg.CONF.service_credentials.os_auth_url,
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):
flavor_attrs = ['name', 'vcpus', 'ram', 'disk']
for instance in instances:
fid = instance.flavor['id']
try:
instance.flavor['name'] = flavors[fid].name
except KeyError:
instance.flavor['name'] = 'unknown-id-%s' % fid
flavor = self.nova_client.flavors.get(fid)
except novaclient.exceptions.NotFound:
flavor = None
for attr in flavor_attrs:
try:
instance.flavor[attr] = getattr(flavor, attr)
except (KeyError, AttributeError):
if attr == 'name':
instance.flavor['name'] = 'unknown-id-%s' % fid
iid = instance.image['id']
try:
image = self.nova_client.images.get(iid)
except novaclient.exceptions.NotFound:
image = None
try:
image_meta = getattr(image, 'metadata')
except (KeyError, AttributeError):
instance.image['name'] = 'unknown-id-%s' % iid
else:
instance.image['name'] = getattr(image, 'name')
instance.kernel_id = image_meta['kernel_id']
instance.ramdisk_id = image_meta['ramdisk_id']
return instances
@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))

View File

@ -52,56 +52,57 @@ class TestLocationMetadata(base.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',
'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']
elif name == 'user_metadata':
expected = iprops['metadata']['metering.autoscale.group'][:256]
self.assertEqual(actual['autoscale_group'], expected)
self.assertEqual(len(actual), 1)
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'])
user_metadata = md['user_metadata']
expected = iprops['metadata']['metering.autoscale.group'][:256]
self.assertEqual(user_metadata['autoscale_group'], expected)
self.assertEqual(len(user_metadata), 1)
def test_metadata_empty_image(self):
self.INSTANCE_PROPERTIES['image'] = ''

View File

@ -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):

View File

@ -29,6 +29,35 @@ class TestNovaClient(base.TestCase):
super(TestNovaClient, self).setUp()
self.nv = nova_client.Client()
@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:
return None
return a
@staticmethod
def fake_images_get(*args, **kwargs):
a = mock.MagicMock()
a.id = args[0]
if a.id == 1:
a.name = 'ubuntu-12.04-x86'
a.metadata = {'kernel_id': 11,
'ramdisk_id': 21}
elif a.id == 2:
a.name = 'centos-5.4-x64'
a.metadata = {'kernel_id': 12,
'ramdisk_id': 22}
else:
return None
return a
@staticmethod
def fake_flavors_list():
a = mock.MagicMock()
@ -44,31 +73,60 @@ 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.flavors, 'get',
self.fake_flavors_get)
self.stubs.Set(self.nv.nova_client.servers, 'list',
self.fake_servers_list)
self.stubs.Set(self.nv.nova_client.images, 'get',
self.fake_images_get)
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.flavors, 'get',
self.fake_flavors_get)
self.stubs.Set(self.nv.nova_client.servers, 'list',
self.fake_servers_list_unknown_flavor)
self.stubs.Set(self.nv.nova_client.images, 'get',
self.fake_images_get)
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]
def test_instance_get_all_by_host_unknown_image(self):
self.stubs.Set(self.nv.nova_client.flavors, 'get',
self.fake_flavors_get)
self.stubs.Set(self.nv.nova_client.servers, 'list',
self.fake_servers_list_unknown_image)
self.stubs.Set(self.nv.nova_client.images, 'get',
self.fake_images_get)
instances = self.nv.instance_get_all_by_host('foobar')
self.assertEqual(len(instances), 1)
self.assertEqual(instances[0].image['name'], 'unknown-id-666')