Merge "Make the metadata paths use conductor"

This commit is contained in:
Jenkins 2013-02-12 22:17:54 +00:00 committed by Gerrit Code Review
commit 9994a9161d
9 changed files with 144 additions and 40 deletions

View File

@ -115,10 +115,10 @@ def get_ip_info_for_instance(context, instance):
return get_ip_info_for_instance_from_nw_info(nw_info) return get_ip_info_for_instance_from_nw_info(nw_info)
def get_availability_zone_by_host(services, host): def get_availability_zone_by_host(services, host, conductor_api=None):
if len(services) > 0: if len(services) > 0:
return availability_zones.get_host_availability_zone( return availability_zones.get_host_availability_zone(
context.get_admin_context(), host) context.get_admin_context(), host, conductor_api)
return 'unknown zone' return 'unknown zone'

View File

@ -26,8 +26,8 @@ import posixpath
from nova.api.ec2 import ec2utils from nova.api.ec2 import ec2utils
from nova.api.metadata import password from nova.api.metadata import password
from nova import block_device from nova import block_device
from nova import conductor
from nova import context from nova import context
from nova import db
from nova import network from nova import network
from nova.openstack.common import cfg from nova.openstack.common import cfg
from nova.openstack.common import timeutils from nova.openstack.common import timeutils
@ -83,7 +83,8 @@ class InvalidMetadataPath(Exception):
class InstanceMetadata(): class InstanceMetadata():
"""Instance metadata.""" """Instance metadata."""
def __init__(self, instance, address=None, content=[], extra_md=None): def __init__(self, instance, address=None, content=[], extra_md=None,
conductor_api=None):
"""Creation of this object should basically cover all time consuming """Creation of this object should basically cover all time consuming
collection. Methods after that should not cause time delays due to collection. Methods after that should not cause time delays due to
network operations or lengthy cpu operations. network operations or lengthy cpu operations.
@ -95,39 +96,32 @@ class InstanceMetadata():
self.instance = instance self.instance = instance
self.extra_md = extra_md self.extra_md = extra_md
if conductor_api:
self.conductor_api = conductor_api
else:
self.conductor_api = conductor.API()
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
services = db.service_get_all_by_host(ctxt.elevated(), capi = self.conductor_api
services = capi.service_get_all_by_host(ctxt.elevated(),
instance['host']) instance['host'])
self.availability_zone = ec2utils.get_availability_zone_by_host( self.availability_zone = ec2utils.get_availability_zone_by_host(
services, instance['host']) services, instance['host'], capi)
self.ip_info = ec2utils.get_ip_info_for_instance(ctxt, instance) self.ip_info = ec2utils.get_ip_info_for_instance(ctxt, instance)
self.security_groups = db.security_group_get_by_instance(ctxt, self.security_groups = capi.security_group_get_by_instance(ctxt,
instance['id']) instance)
self.mappings = _format_instance_mapping(ctxt, instance) self.mappings = _format_instance_mapping(capi, ctxt, instance)
if instance.get('user_data', None) is not None: if instance.get('user_data', None) is not None:
self.userdata_raw = base64.b64decode(instance['user_data']) self.userdata_raw = base64.b64decode(instance['user_data'])
else: else:
self.userdata_raw = None self.userdata_raw = None
self.ec2_ids = {} self.ec2_ids = capi.get_ec2_ids(ctxt, instance)
self.ec2_ids['instance-id'] = ec2utils.id_to_ec2_inst_id(
instance['uuid'])
self.ec2_ids['ami-id'] = ec2utils.glance_id_to_ec2_id(ctxt,
instance['image_ref'])
for image_type in ['kernel', 'ramdisk']:
if self.instance.get('%s_id' % image_type):
image_id = self.instance['%s_id' % image_type]
ec2_image_type = ec2utils.image_type(image_type)
ec2_id = ec2utils.glance_id_to_ec2_id(ctxt, image_id,
ec2_image_type)
self.ec2_ids['%s-id' % image_type] = ec2_id
self.address = address self.address = address
@ -404,23 +398,26 @@ class InstanceMetadata():
yield ('%s/%s/%s' % ("openstack", CONTENT_DIR, cid), content) yield ('%s/%s/%s' % ("openstack", CONTENT_DIR, cid), content)
def get_metadata_by_address(address): def get_metadata_by_address(conductor_api, address):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
fixed_ip = network.API().get_fixed_ip_by_address(ctxt, address) fixed_ip = network.API().get_fixed_ip_by_address(ctxt, address)
return get_metadata_by_instance_id(fixed_ip['instance_uuid'], return get_metadata_by_instance_id(conductor_api,
fixed_ip['instance_uuid'],
address, address,
ctxt) ctxt)
def get_metadata_by_instance_id(instance_id, address, ctxt=None): def get_metadata_by_instance_id(conductor_api, instance_id, address,
ctxt=None):
ctxt = ctxt or context.get_admin_context() ctxt = ctxt or context.get_admin_context()
instance = db.instance_get_by_uuid(ctxt, instance_id) instance = conductor_api.instance_get_by_uuid(ctxt, instance_id)
return InstanceMetadata(instance, address) return InstanceMetadata(instance, address)
def _format_instance_mapping(ctxt, instance): def _format_instance_mapping(conductor_api, ctxt, instance):
bdms = db.block_device_mapping_get_all_by_instance(ctxt, instance['uuid']) bdms = conductor_api.block_device_mapping_get_all_by_instance(
ctxt, instance)
return block_device.instance_block_mapping(instance, bdms) return block_device.instance_block_mapping(instance, bdms)

View File

@ -26,6 +26,7 @@ import webob.exc
from nova.api.metadata import base from nova.api.metadata import base
from nova.common import memorycache from nova.common import memorycache
from nova import conductor
from nova import exception from nova import exception
from nova.openstack.common import cfg from nova.openstack.common import cfg
from nova.openstack.common import log as logging from nova.openstack.common import log as logging
@ -58,6 +59,7 @@ class MetadataRequestHandler(wsgi.Application):
def __init__(self): def __init__(self):
self._cache = memorycache.get_client() self._cache = memorycache.get_client()
self.conductor_api = conductor.API()
def get_metadata_by_remote_address(self, address): def get_metadata_by_remote_address(self, address):
if not address: if not address:
@ -69,7 +71,7 @@ class MetadataRequestHandler(wsgi.Application):
return data return data
try: try:
data = base.get_metadata_by_address(address) data = base.get_metadata_by_address(self.conductor_api, address)
except exception.NotFound: except exception.NotFound:
return None return None
@ -84,7 +86,8 @@ class MetadataRequestHandler(wsgi.Application):
return data return data
try: try:
data = base.get_metadata_by_instance_id(instance_id, address) data = base.get_metadata_by_instance_id(self.conductor_api,
instance_id, address)
except exception.NotFound: except exception.NotFound:
return None return None

View File

@ -52,7 +52,11 @@ def set_availability_zones(context, services):
return services return services
def get_host_availability_zone(context, host): def get_host_availability_zone(context, host, conductor_api=None):
if conductor_api:
metadata = conductor_api.aggregate_metadata_get_by_host(
context, host, key='availability_zone')
else:
metadata = db.aggregate_metadata_get_by_host( metadata = db.aggregate_metadata_get_by_host(
context, host, key='availability_zone') context, host, key='availability_zone')
if 'availability_zone' in metadata: if 'availability_zone' in metadata:

View File

@ -154,6 +154,12 @@ class LocalAPI(object):
aggregate, aggregate,
key) key)
def aggregate_metadata_get_by_host(self, context, host,
key='availability_zone'):
return self._manager.aggregate_metadata_get_by_host(context,
host,
key)
def bw_usage_get(self, context, uuid, start_period, mac): def bw_usage_get(self, context, uuid, start_period, mac):
return self._manager.bw_usage_update(context, uuid, mac, start_period) return self._manager.bw_usage_update(context, uuid, mac, start_period)
@ -319,6 +325,9 @@ class LocalAPI(object):
def quota_rollback(self, context, reservations): def quota_rollback(self, context, reservations):
return self._manager.quota_rollback(context, reservations) return self._manager.quota_rollback(context, reservations)
def get_ec2_ids(self, context, instance):
return self._manager.get_ec2_ids(context, instance)
class API(object): class API(object):
"""Conductor API that does updates via RPC to the ConductorManager.""" """Conductor API that does updates via RPC to the ConductorManager."""
@ -463,6 +472,12 @@ class API(object):
aggregate, aggregate,
key) key)
def aggregate_metadata_get_by_host(self, context, host,
key='availability_zone'):
return self.conductor_rpcapi.aggregate_metadata_get_by_host(context,
host,
key)
def bw_usage_get(self, context, uuid, start_period, mac): def bw_usage_get(self, context, uuid, start_period, mac):
return self.conductor_rpcapi.bw_usage_update(context, uuid, mac, return self.conductor_rpcapi.bw_usage_update(context, uuid, mac,
start_period) start_period)
@ -636,3 +651,6 @@ class API(object):
def quota_rollback(self, context, reservations): def quota_rollback(self, context, reservations):
return self.conductor_rpcapi.quota_rollback(context, reservations) return self.conductor_rpcapi.quota_rollback(context, reservations)
def get_ec2_ids(self, context, instance):
return self.conductor_rpcapi.get_ec2_ids(context, instance)

View File

@ -14,6 +14,7 @@
"""Handles database requests from other nova services.""" """Handles database requests from other nova services."""
from nova.api.ec2 import ec2utils
from nova.compute import api as compute_api from nova.compute import api as compute_api
from nova.compute import utils as compute_utils from nova.compute import utils as compute_utils
from nova import exception from nova import exception
@ -47,7 +48,7 @@ datetime_fields = ['launched_at', 'terminated_at']
class ConductorManager(manager.SchedulerDependentManager): class ConductorManager(manager.SchedulerDependentManager):
"""Mission: TBD.""" """Mission: TBD."""
RPC_API_VERSION = '1.41' RPC_API_VERSION = '1.42'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ConductorManager, self).__init__(service_name='conductor', super(ConductorManager, self).__init__(service_name='conductor',
@ -175,6 +176,11 @@ class ConductorManager(manager.SchedulerDependentManager):
self.db.aggregate_metadata_delete(context.elevated(), self.db.aggregate_metadata_delete(context.elevated(),
aggregate['id'], key) aggregate['id'], key)
def aggregate_metadata_get_by_host(self, context, host,
key='availability_zone'):
result = self.db.aggregate_metadata_get_by_host(context, host, key)
return jsonutils.to_primitive(result)
def bw_usage_update(self, context, uuid, mac, start_period, def bw_usage_update(self, context, uuid, mac, start_period,
bw_in=None, bw_out=None, bw_in=None, bw_out=None,
last_ctr_in=None, last_ctr_out=None, last_ctr_in=None, last_ctr_out=None,
@ -384,3 +390,19 @@ class ConductorManager(manager.SchedulerDependentManager):
def quota_rollback(self, context, reservations): def quota_rollback(self, context, reservations):
quota.QUOTAS.rollback(context, reservations) quota.QUOTAS.rollback(context, reservations)
def get_ec2_ids(self, context, instance):
ec2_ids = {}
ec2_ids['instance-id'] = ec2utils.id_to_ec2_inst_id(instance['uuid'])
ec2_ids['ami-id'] = ec2utils.glance_id_to_ec2_id(context,
instance['image_ref'])
for image_type in ['kernel', 'ramdisk']:
if '%s_id' % image_type in instance:
image_id = instance['%s_id' % image_type]
ec2_image_type = ec2utils.image_type(image_type)
ec2_id = ec2utils.glance_id_to_ec2_id(context, image_id,
ec2_image_type)
ec2_ids['%s-id' % image_type] = ec2_id
return ec2_ids

View File

@ -78,6 +78,7 @@ class ConductorAPI(nova.openstack.common.rpc.proxy.RpcProxy):
1.41 - Added fixed_ip_get_by_instance, network_get, 1.41 - Added fixed_ip_get_by_instance, network_get,
instance_floating_address_get_all, quota_commit, instance_floating_address_get_all, quota_commit,
quota_rollback quota_rollback
1.42 - Added get_ec2_ids, aggregate_metadata_get_by_host
""" """
BASE_RPC_API_VERSION = '1.0' BASE_RPC_API_VERSION = '1.0'
@ -176,6 +177,11 @@ class ConductorAPI(nova.openstack.common.rpc.proxy.RpcProxy):
key=key) key=key)
return self.call(context, msg, version='1.7') return self.call(context, msg, version='1.7')
def aggregate_metadata_get_by_host(self, context, host, key):
msg = self.make_msg('aggregate_metadata_get_by_host', host=host,
key=key)
return self.call(context, msg, version='1.42')
def bw_usage_update(self, context, uuid, mac, start_period, def bw_usage_update(self, context, uuid, mac, start_period,
bw_in=None, bw_out=None, bw_in=None, bw_out=None,
last_ctr_in=None, last_ctr_out=None, last_ctr_in=None, last_ctr_out=None,
@ -409,3 +415,8 @@ class ConductorAPI(nova.openstack.common.rpc.proxy.RpcProxy):
reservations_p = jsonutils.to_primitive(reservations) reservations_p = jsonutils.to_primitive(reservations)
msg = self.make_msg('quota_rollback', reservations=reservations_p) msg = self.make_msg('quota_rollback', reservations=reservations_p)
return self.call(context, msg, version='1.41') return self.call(context, msg, version='1.41')
def get_ec2_ids(self, context, instance):
instance_p = jsonutils.to_primitive(instance)
msg = self.make_msg('get_ec2_ids', instance=instance_p)
return self.call(context, msg, version='1.42')

View File

@ -16,6 +16,7 @@
import mox import mox
from nova.api.ec2 import ec2utils
from nova.compute import instance_types from nova.compute import instance_types
from nova.compute import utils as compute_utils from nova.compute import utils as compute_utils
from nova.compute import vm_states from nova.compute import vm_states
@ -241,6 +242,15 @@ class _BaseTestCase(object):
aggregate, aggregate,
'fake') 'fake')
def test_aggregate_metadata_get_by_host(self):
self.mox.StubOutWithMock(db, 'aggregate_metadata_get_by_host')
db.aggregate_metadata_get_by_host(self.context, 'host',
'key').AndReturn('result')
self.mox.ReplayAll()
result = self.conductor.aggregate_metadata_get_by_host(self.context,
'host', 'key')
self.assertEqual(result, 'result')
def test_bw_usage_update(self): def test_bw_usage_update(self):
self.mox.StubOutWithMock(db, 'bw_usage_update') self.mox.StubOutWithMock(db, 'bw_usage_update')
self.mox.StubOutWithMock(db, 'bw_usage_get') self.mox.StubOutWithMock(db, 'bw_usage_get')
@ -537,6 +547,39 @@ class _BaseTestCase(object):
self.mox.ReplayAll() self.mox.ReplayAll()
self.conductor.quota_rollback(self.context, 'reservations') self.conductor.quota_rollback(self.context, 'reservations')
def test_get_ec2_ids(self):
expected = {
'instance-id': 'ec2-inst-id',
'ami-id': 'ec2-ami-id',
'kernel-id': 'ami-kernel-ec2-kernelid',
'ramdisk-id': 'ami-ramdisk-ec2-ramdiskid',
}
inst = {
'uuid': 'fake-uuid',
'kernel_id': 'ec2-kernelid',
'ramdisk_id': 'ec2-ramdiskid',
'image_ref': 'fake-image',
}
self.mox.StubOutWithMock(ec2utils, 'id_to_ec2_inst_id')
self.mox.StubOutWithMock(ec2utils, 'glance_id_to_ec2_id')
self.mox.StubOutWithMock(ec2utils, 'image_type')
ec2utils.id_to_ec2_inst_id(inst['uuid']).AndReturn(
expected['instance-id'])
ec2utils.glance_id_to_ec2_id(self.context,
inst['image_ref']).AndReturn(
expected['ami-id'])
for image_type in ['kernel', 'ramdisk']:
image_id = inst['%s_id' % image_type]
ec2utils.image_type(image_type).AndReturn('ami-' + image_type)
ec2utils.glance_id_to_ec2_id(self.context, image_id,
'ami-' + image_type).AndReturn(
'ami-%s-ec2-%sid' % (image_type, image_type))
self.mox.ReplayAll()
result = self.conductor.get_ec2_ids(self.context, inst)
self.assertEqual(result, expected)
class ConductorTestCase(_BaseTestCase, test.TestCase): class ConductorTestCase(_BaseTestCase, test.TestCase):
"""Conductor Manager Tests.""" """Conductor Manager Tests."""

View File

@ -31,6 +31,7 @@ from nova.api.metadata import base
from nova.api.metadata import handler from nova.api.metadata import handler
from nova.api.metadata import password from nova.api.metadata import password
from nova import block_device from nova import block_device
from nova.conductor import api as conductor_api
from nova import db from nova import db
from nova.db.sqlalchemy import api from nova.db.sqlalchemy import api
from nova import exception from nova import exception
@ -118,6 +119,7 @@ class MetadataTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(MetadataTestCase, self).setUp() super(MetadataTestCase, self).setUp()
self.instance = INSTANCES[0] self.instance = INSTANCES[0]
self.flags(use_local=True, group='conductor')
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True) spectacular=True)
@ -191,10 +193,11 @@ class MetadataTestCase(test.TestCase):
'swap': '/dev/sdc', 'swap': '/dev/sdc',
'ebs0': '/dev/sdh'} 'ebs0': '/dev/sdh'}
self.assertEqual(base._format_instance_mapping(ctxt, instance_ref0), capi = conductor_api.LocalAPI()
block_device._DEFAULT_MAPPINGS) self.assertEqual(base._format_instance_mapping(capi, ctxt,
self.assertEqual(base._format_instance_mapping(ctxt, instance_ref1), instance_ref0), block_device._DEFAULT_MAPPINGS)
expected) self.assertEqual(base._format_instance_mapping(capi, ctxt,
instance_ref1), expected)
def test_pubkey(self): def test_pubkey(self):
md = fake_InstanceMetadata(self.stubs, copy.copy(self.instance)) md = fake_InstanceMetadata(self.stubs, copy.copy(self.instance))
@ -247,6 +250,7 @@ class OpenStackMetadataTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(OpenStackMetadataTestCase, self).setUp() super(OpenStackMetadataTestCase, self).setUp()
self.instance = INSTANCES[0] self.instance = INSTANCES[0]
self.flags(use_local=True, group='conductor')
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True) spectacular=True)
@ -382,6 +386,7 @@ class MetadataHandlerTestCase(test.TestCase):
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True) spectacular=True)
self.instance = INSTANCES[0] self.instance = INSTANCES[0]
self.flags(use_local=True, group='conductor')
self.mdinst = fake_InstanceMetadata(self.stubs, self.instance, self.mdinst = fake_InstanceMetadata(self.stubs, self.instance,
address=None, sgroups=None) address=None, sgroups=None)
@ -547,6 +552,7 @@ class MetadataPasswordTestCase(test.TestCase):
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True) spectacular=True)
self.instance = copy.copy(INSTANCES[0]) self.instance = copy.copy(INSTANCES[0])
self.flags(use_local=True, group='conductor')
self.mdinst = fake_InstanceMetadata(self.stubs, self.instance, self.mdinst = fake_InstanceMetadata(self.stubs, self.instance,
address=None, sgroups=None) address=None, sgroups=None)
self.flags(use_local=True, group='conductor') self.flags(use_local=True, group='conductor')