diff options
49 files changed, 383 insertions, 178 deletions
diff --git a/bin/nova-all b/bin/nova-all index 2bbc27c82..ce0a459b4 100755 --- a/bin/nova-all +++ b/bin/nova-all @@ -40,6 +40,7 @@ if os.path.exists(os.path.join(possible_topdir, "nova", "__init__.py")): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.objectstore import s3server from nova.openstack.common import log as logging @@ -51,7 +52,7 @@ from nova.vnc import xvp_proxy LOG = logging.getLogger('nova.all') if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() launcher = service.ProcessLauncher() diff --git a/bin/nova-api b/bin/nova-api index f55eca719..4bcfa7f79 100755 --- a/bin/nova-api +++ b/bin/nova-api @@ -36,13 +36,14 @@ if os.path.exists(os.path.join(possible_topdir, "nova", "__init__.py")): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() launcher = service.ProcessLauncher() diff --git a/bin/nova-api-ec2 b/bin/nova-api-ec2 index 8e66ab874..f165b5ce9 100755 --- a/bin/nova-api-ec2 +++ b/bin/nova-api-ec2 @@ -32,13 +32,14 @@ if os.path.exists(os.path.join(possible_topdir, "nova", "__init__.py")): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() server = service.WSGIService('ec2') diff --git a/bin/nova-api-metadata b/bin/nova-api-metadata index d445a16a9..f50e5ce84 100755 --- a/bin/nova-api-metadata +++ b/bin/nova-api-metadata @@ -32,13 +32,14 @@ if os.path.exists(os.path.join(possible_topdir, "nova", "__init__.py")): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() server = service.WSGIService('metadata') diff --git a/bin/nova-api-os-compute b/bin/nova-api-os-compute index 529d58821..5cf5f6910 100755 --- a/bin/nova-api-os-compute +++ b/bin/nova-api-os-compute @@ -32,13 +32,14 @@ if os.path.exists(os.path.join(possible_topdir, "nova", "__init__.py")): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() server = service.WSGIService('osapi_compute') diff --git a/bin/nova-cert b/bin/nova-cert index ebdd0e0b9..317739329 100755 --- a/bin/nova-cert +++ b/bin/nova-cert @@ -32,13 +32,14 @@ if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')): sys.path.insert(0, POSSIBLE_TOPDIR) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) FLAGS = flags.FLAGS logging.setup("nova") utils.monkey_patch() diff --git a/bin/nova-clear-rabbit-queues b/bin/nova-clear-rabbit-queues index 0cbf5ab19..05531de9b 100755 --- a/bin/nova-clear-rabbit-queues +++ b/bin/nova-clear-rabbit-queues @@ -42,6 +42,7 @@ gettext.install('nova', unicode=1) from nova import context from nova import exception +from nova import config from nova import flags from nova.openstack.common import cfg from nova.openstack.common import log as logging @@ -69,7 +70,7 @@ def delete_queues(queues): x.queue_delete(q) if __name__ == '__main__': - args = flags.parse_args(sys.argv) + args = config.parse_args(sys.argv) logging.setup("nova") delete_queues(args[1:]) if FLAGS.delete_exchange: diff --git a/bin/nova-compute b/bin/nova-compute index 2a2a0013a..2ff98ccfc 100755 --- a/bin/nova-compute +++ b/bin/nova-compute @@ -34,13 +34,14 @@ if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')): sys.path.insert(0, POSSIBLE_TOPDIR) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) FLAGS = flags.FLAGS logging.setup('nova') utils.monkey_patch() diff --git a/bin/nova-console b/bin/nova-console index f664040b7..92b99edfb 100755 --- a/bin/nova-console +++ b/bin/nova-console @@ -33,12 +33,13 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) FLAGS = flags.FLAGS logging.setup("nova") server = service.Service.create(binary='nova-console', diff --git a/bin/nova-consoleauth b/bin/nova-consoleauth index 58ecd37b3..14ef701a7 100755 --- a/bin/nova-consoleauth +++ b/bin/nova-consoleauth @@ -32,13 +32,14 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): from nova.consoleauth import manager +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service if __name__ == "__main__": - flags.parse_args(sys.argv) + config.parse_args(sys.argv) FLAGS = flags.FLAGS logging.setup("nova") server = service.Service.create(binary='nova-consoleauth', diff --git a/bin/nova-dhcpbridge b/bin/nova-dhcpbridge index 0fc7751fc..48639ce87 100755 --- a/bin/nova-dhcpbridge +++ b/bin/nova-dhcpbridge @@ -37,6 +37,7 @@ gettext.install('nova', unicode=1) from nova import context from nova import db +from nova import config from nova import flags from nova.network import linux_net from nova.network import rpcapi as network_rpcapi @@ -94,7 +95,7 @@ def init_leases(network_id): def main(): """Parse environment and arguments and call the approproate action.""" flagfile = os.environ.get('FLAGFILE', FLAGS.dhcpbridge_flagfile) - argv = flags.parse_args(sys.argv, default_config_files=[flagfile]) + argv = config.parse_args(sys.argv, default_config_files=[flagfile]) logging.setup("nova") if int(os.environ.get('TESTING', '0')): diff --git a/bin/nova-manage b/bin/nova-manage index 93b079488..1cb2dabb7 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -73,6 +73,7 @@ gettext.install('nova', unicode=1) from nova.api.ec2 import ec2utils from nova.compute import instance_types from nova.compute import rpcapi as compute_rpcapi +from nova import config from nova import context from nova import db from nova.db import migration @@ -1220,7 +1221,7 @@ def main(): """Parse options and call the appropriate class/method.""" try: - argv = flags.parse_args(sys.argv) + argv = config.parse_args(sys.argv) logging.setup("nova") except cfg.ConfigFilesNotFoundError: cfgfile = FLAGS.config_file[-1] if FLAGS.config_file else None diff --git a/bin/nova-network b/bin/nova-network index 36343bb73..d23d7882c 100755 --- a/bin/nova-network +++ b/bin/nova-network @@ -34,13 +34,14 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) FLAGS = flags.FLAGS logging.setup("nova") utils.monkey_patch() diff --git a/bin/nova-novncproxy b/bin/nova-novncproxy index 483c72e81..d3d9702af 100755 --- a/bin/nova-novncproxy +++ b/bin/nova-novncproxy @@ -28,6 +28,7 @@ import sys import websockify +from nova import config from nova.consoleauth import rpcapi as consoleauth_rpcapi from nova import context from nova import flags @@ -133,7 +134,7 @@ if __name__ == '__main__': parser.error("SSL only and %s not found" % FLAGS.cert) # Setup flags - flags.parse_args(sys.argv) + config.parse_args(sys.argv) # Check to see if novnc html/js/css files are present if not os.path.exists(FLAGS.web): diff --git a/bin/nova-objectstore b/bin/nova-objectstore index 2149b1610..9b9e2b7a7 100755 --- a/bin/nova-objectstore +++ b/bin/nova-objectstore @@ -34,6 +34,7 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.objectstore import s3server from nova.openstack.common import log as logging @@ -42,7 +43,7 @@ from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() server = s3server.get_wsgi_server() diff --git a/bin/nova-rpc-zmq-receiver b/bin/nova-rpc-zmq-receiver index 5636718a2..d63ea108e 100755 --- a/bin/nova-rpc-zmq-receiver +++ b/bin/nova-rpc-zmq-receiver @@ -32,6 +32,7 @@ POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')): sys.path.insert(0, POSSIBLE_TOPDIR) +from nova import config from nova import exception from nova import flags from nova.openstack.common import log as logging @@ -45,7 +46,7 @@ FLAGS.register_opts(impl_zmq.zmq_opts) def main(): - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() diff --git a/bin/nova-scheduler b/bin/nova-scheduler index 64dadb9e4..fc345808a 100755 --- a/bin/nova-scheduler +++ b/bin/nova-scheduler @@ -36,13 +36,14 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): gettext.install('nova', unicode=1) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova import service from nova import utils if __name__ == '__main__': - flags.parse_args(sys.argv) + config.parse_args(sys.argv) FLAGS = flags.FLAGS logging.setup("nova") utils.monkey_patch() diff --git a/bin/nova-xvpvncproxy b/bin/nova-xvpvncproxy index 5929a33b5..e884b3f52 100755 --- a/bin/nova-xvpvncproxy +++ b/bin/nova-xvpvncproxy @@ -31,6 +31,7 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): sys.path.insert(0, possible_topdir) +from nova import config from nova import flags from nova.openstack.common import log as logging from nova.openstack.common import rpc @@ -40,7 +41,7 @@ from nova.vnc import xvp_proxy FLAGS = flags.FLAGS if __name__ == "__main__": - flags.parse_args(sys.argv) + config.parse_args(sys.argv) logging.setup("nova") wsgi_server = xvp_proxy.get_wsgi_server() diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py index 4d0a926df..580cfdac7 100644 --- a/nova/api/ec2/ec2utils.py +++ b/nova/api/ec2/ec2utils.py @@ -25,7 +25,7 @@ from nova import flags from nova.network import model as network_model from nova.openstack.common import log as logging from nova.openstack.common import timeutils -from nova import utils +from nova.openstack.common import uuidutils FLAGS = flags.FLAGS @@ -130,7 +130,7 @@ def id_to_ec2_id(instance_id, template='i-%08x'): def id_to_ec2_inst_id(instance_id): """Get or create an ec2 instance ID (i-[base 16 number]) from uuid.""" - if utils.is_uuid_like(instance_id): + if uuidutils.is_uuid_like(instance_id): ctxt = context.get_admin_context() int_id = get_int_id_from_instance_uuid(ctxt, instance_id) return id_to_ec2_id(int_id) @@ -150,7 +150,7 @@ def get_instance_uuid_from_int_id(context, int_id): def id_to_ec2_snap_id(snapshot_id): """Get or create an ec2 volume ID (vol-[base 16 number]) from uuid.""" - if utils.is_uuid_like(snapshot_id): + if uuidutils.is_uuid_like(snapshot_id): ctxt = context.get_admin_context() int_id = get_int_id_from_snapshot_uuid(ctxt, snapshot_id) return id_to_ec2_id(int_id, 'snap-%08x') @@ -160,7 +160,7 @@ def id_to_ec2_snap_id(snapshot_id): def id_to_ec2_vol_id(volume_id): """Get or create an ec2 volume ID (vol-[base 16 number]) from uuid.""" - if utils.is_uuid_like(volume_id): + if uuidutils.is_uuid_like(volume_id): ctxt = context.get_admin_context() int_id = get_int_id_from_volume_uuid(ctxt, volume_id) return id_to_ec2_id(int_id, 'vol-%08x') diff --git a/nova/api/openstack/compute/contrib/floating_ips.py b/nova/api/openstack/compute/contrib/floating_ips.py index 56a6a8fad..4f6dbffdb 100644 --- a/nova/api/openstack/compute/contrib/floating_ips.py +++ b/nova/api/openstack/compute/contrib/floating_ips.py @@ -27,7 +27,7 @@ from nova.compute import utils as compute_utils from nova import exception from nova import network from nova.openstack.common import log as logging -from nova import utils +from nova.openstack.common import uuidutils LOG = logging.getLogger(__name__) @@ -307,7 +307,7 @@ class FloatingIPActionController(wsgi.Controller): # disassociate if associated if (instance and floating_ip.get('fixed_ip_id') and - (utils.is_uuid_like(id) and + (uuidutils.is_uuid_like(id) and [instance['uuid'] == id] or [instance['id'] == id])[0]): disassociate_floating_ip(self, context, instance, address) diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index ba88d72e7..c4293255d 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -36,6 +36,7 @@ from nova.openstack.common import importutils from nova.openstack.common import log as logging from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils +from nova.openstack.common import uuidutils from nova import utils @@ -621,7 +622,7 @@ class Controller(wsgi.Controller): # port parameter is only for qunatum v2.0 msg = _("Unknown argment : port") raise exc.HTTPBadRequest(explanation=msg) - if not utils.is_uuid_like(port_id): + if not uuidutils.is_uuid_like(port_id): msg = _("Bad port format: port uuid is " "not in proper format " "(%s)") % port_id @@ -629,9 +630,9 @@ class Controller(wsgi.Controller): else: network_uuid = network['uuid'] - if not port_id and not utils.is_uuid_like(network_uuid): + if not port_id and not uuidutils.is_uuid_like(network_uuid): br_uuid = network_uuid.split('-', 1)[-1] - if not utils.is_uuid_like(br_uuid): + if not uuidutils.is_uuid_like(br_uuid): msg = _("Bad networks format: network uuid is " "not in proper format " "(%s)") % network_uuid @@ -1099,7 +1100,7 @@ class Controller(wsgi.Controller): # down to an id and use the default glance connection params image_uuid = image_href.split('/').pop() - if not utils.is_uuid_like(image_uuid): + if not uuidutils.is_uuid_like(image_uuid): msg = _("Invalid imageRef provided.") raise exc.HTTPBadRequest(explanation=msg) diff --git a/nova/compute/api.py b/nova/compute/api.py index 1bbcdbda9..28c7068ba 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -48,6 +48,7 @@ from nova.openstack.common import importutils from nova.openstack.common import jsonutils from nova.openstack.common import log as logging from nova.openstack.common import timeutils +from nova.openstack.common import uuidutils import nova.policy from nova import quota from nova.scheduler import rpcapi as scheduler_rpcapi @@ -1067,7 +1068,7 @@ class API(base.Base): def get(self, context, instance_id): """Get a single instance with the given instance_id.""" # NOTE(ameade): we still need to support integer ids for ec2 - if utils.is_uuid_like(instance_id): + if uuidutils.is_uuid_like(instance_id): instance = self.db.instance_get_by_uuid(context, instance_id) else: instance = self.db.instance_get(context, instance_id) @@ -1557,7 +1558,7 @@ class API(base.Base): expected_task_state=None) self.compute_rpcapi.revert_resize(context, - instance=instance, migration_id=migration_ref['id'], + instance=instance, migration=migration_ref, host=migration_ref['dest_compute'], reservations=reservations) self.db.migration_update(elevated, migration_ref['id'], @@ -2173,7 +2174,7 @@ class AggregateAPI(base.Base): self.db.aggregate_host_add(context, aggregate_id, host) #NOTE(jogo): Send message to host to support resource pools self.compute_rpcapi.add_aggregate_host(context, - aggregate_id=aggregate_id, host_param=host, host=host) + aggregate=aggregate, host_param=host, host=host) return self.get_aggregate(context, aggregate_id) def remove_host_from_aggregate(self, context, aggregate_id, host): diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 39c3faddf..de848abdd 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -230,7 +230,7 @@ class ComputeVirtAPI(virtapi.VirtAPI): class ComputeManager(manager.SchedulerDependentManager): """Manages the running instances from creation to destruction.""" - RPC_API_VERSION = '2.11' + RPC_API_VERSION = '2.14' def __init__(self, compute_driver=None, *args, **kwargs): """Load configuration options and connect to the hypervisor.""" @@ -1532,16 +1532,17 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @reverts_task_state @wrap_instance_fault - def revert_resize(self, context, instance, migration_id, - reservations=None): + def revert_resize(self, context, instance, migration=None, + migration_id=None, reservations=None): """Destroys the new instance on the destination machine. Reverts the model changes, and powers on the old instance on the source machine. """ - migration_ref = self.db.migration_get(context.elevated(), - migration_id) + if not migration: + migration = self.db.migration_get(context.elevated(), + migration_id) # NOTE(comstud): A revert_resize is essentially a resize back to # the old size, so we need to send a usage event here. @@ -1555,7 +1556,7 @@ class ComputeManager(manager.SchedulerDependentManager): teardown=True) self.network_api.migrate_instance_start(context, instance, - migration_ref) + migration) network_info = self._get_instance_nw_info(context, instance) block_device_info = self._get_instance_volume_block_device_info( @@ -1567,14 +1568,14 @@ class ComputeManager(manager.SchedulerDependentManager): self._terminate_volume_connections(context, instance) self.compute_rpcapi.finish_revert_resize(context, instance, - migration_ref['id'], migration_ref['source_compute'], + migration, migration['source_compute'], reservations) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @reverts_task_state @wrap_instance_fault - def finish_revert_resize(self, context, migration_id, instance, - reservations=None): + def finish_revert_resize(self, context, instance, reservations=None, + migration=None, migration_id=None): """Finishes the second half of reverting a resize. Power back on the source instance and revert the resized attributes @@ -1582,7 +1583,9 @@ class ComputeManager(manager.SchedulerDependentManager): """ elevated = context.elevated() - migration_ref = self.db.migration_get(elevated, migration_id) + + if not migration: + migration = self.db.migration_get(elevated, migration_id) with self._error_out_instance_on_exception(context, instance['uuid'], reservations): @@ -1593,11 +1596,11 @@ class ComputeManager(manager.SchedulerDependentManager): instance = self._instance_update(context, instance['uuid'], - host=migration_ref['source_compute']) + host=migration['source_compute']) self.network_api.setup_networks_on_host(context, instance, - migration_ref['source_compute']) + migration['source_compute']) - old_instance_type = migration_ref['old_instance_type_id'] + old_instance_type = migration['old_instance_type_id'] instance_type = instance_types.get_instance_type(old_instance_type) bdms = self._get_instance_volume_bdms(context, instance['uuid']) @@ -1628,13 +1631,13 @@ class ComputeManager(manager.SchedulerDependentManager): RESIZE_REVERTING) self.network_api.migrate_instance_finish(context, instance, - migration_ref) + migration) self._instance_update(context, instance['uuid'], vm_state=vm_states.ACTIVE, task_state=None) - self.db.migration_update(elevated, migration_id, + self.db.migration_update(elevated, migration['id'], {'status': 'reverted'}) self._notify_about_instance_usage( @@ -2667,7 +2670,10 @@ class ComputeManager(manager.SchedulerDependentManager): @manager.periodic_task def _poll_rebooting_instances(self, context): if FLAGS.reboot_timeout > 0: - self.driver.poll_rebooting_instances(FLAGS.reboot_timeout) + instances = self.db.instance_get_all_hung_in_rebooting( + context, FLAGS.reboot_timeout) + self.driver.poll_rebooting_instances(FLAGS.reboot_timeout, + instances) @manager.periodic_task def _poll_rescued_instances(self, context): @@ -3108,9 +3114,12 @@ class ComputeManager(manager.SchedulerDependentManager): self._set_instance_error_state(context, instance_uuid) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) - def add_aggregate_host(self, context, aggregate_id, host, slave_info=None): + def add_aggregate_host(self, context, host, slave_info=None, + aggregate=None, aggregate_id=None): """Notify hypervisor of change (for hypervisor pools).""" - aggregate = self.db.aggregate_get(context, aggregate_id) + if not aggregate: + aggregate = self.db.aggregate_get(context, aggregate_id) + try: self.driver.add_to_aggregate(context, aggregate, host, slave_info=slave_info) @@ -3118,7 +3127,7 @@ class ComputeManager(manager.SchedulerDependentManager): with excutils.save_and_reraise_exception(): self.driver.undo_aggregate_operation(context, self.db.aggregate_host_delete, - aggregate.id, host) + aggregate['id'], host) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) def remove_aggregate_host(self, context, aggregate_id, diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py index e42e025dc..5bf17adcd 100644 --- a/nova/compute/rpcapi.py +++ b/nova/compute/rpcapi.py @@ -139,6 +139,9 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): 2.9 - Add publish_service_capabilities() 2.10 - Adds filter_properties and request_spec to prep_resize() 2.11 - Adds soft_delete_instance() and restore_instance() + 2.12 - Remove migration_id, add migration to revert_resize + 2.13 - Remove migration_id, add migration to finish_revert_resize + 2.14 - Remove aggregate_id, add aggregate to add_aggregate_host ''' # @@ -156,7 +159,7 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): topic=FLAGS.compute_topic, default_version=self.BASE_RPC_API_VERSION) - def add_aggregate_host(self, ctxt, aggregate_id, host_param, host, + def add_aggregate_host(self, ctxt, aggregate, host_param, host, slave_info=None): '''Add aggregate host. @@ -167,11 +170,12 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): :param host: This is the host to send the message to. ''' + aggregate_p = jsonutils.to_primitive(aggregate) self.cast(ctxt, self.make_msg('add_aggregate_host', - aggregate_id=aggregate_id, host=host_param, + aggregate=aggregate_p, host=host_param, slave_info=slave_info), topic=_compute_topic(self.topic, ctxt, host, None), - version='2.2') + version='2.14') def add_fixed_ip_to_instance(self, ctxt, instance, network_id): instance_p = jsonutils.to_primitive(instance) @@ -237,13 +241,15 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): topic=_compute_topic(self.topic, ctxt, host, None), version='2.8') - def finish_revert_resize(self, ctxt, instance, migration_id, host, + def finish_revert_resize(self, ctxt, instance, migration, host, reservations=None): instance_p = jsonutils.to_primitive(instance) + migration_p = jsonutils.to_primitive(migration) self.cast(ctxt, self.make_msg('finish_revert_resize', - instance=instance_p, migration_id=migration_id, + instance=instance_p, migration=migration_p, reservations=reservations), - topic=_compute_topic(self.topic, ctxt, host, None)) + topic=_compute_topic(self.topic, ctxt, host, None), + version='2.13') def get_console_output(self, ctxt, instance, tail_length): instance_p = jsonutils.to_primitive(instance) @@ -441,13 +447,15 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): instance=instance_p), topic=_compute_topic(self.topic, ctxt, None, instance)) - def revert_resize(self, ctxt, instance, migration_id, host, + def revert_resize(self, ctxt, instance, migration, host, reservations=None): instance_p = jsonutils.to_primitive(instance) + migration_p = jsonutils.to_primitive(migration) self.cast(ctxt, self.make_msg('revert_resize', - instance=instance_p, migration_id=migration_id, + instance=instance_p, migration=migration_p, reservations=reservations), - topic=_compute_topic(self.topic, ctxt, host, instance)) + topic=_compute_topic(self.topic, ctxt, host, instance), + version='2.12') def rollback_live_migration_at_destination(self, ctxt, instance, host): instance_p = jsonutils.to_primitive(instance) diff --git a/nova/config.py b/nova/config.py new file mode 100644 index 000000000..608a3ee53 --- /dev/null +++ b/nova/config.py @@ -0,0 +1,29 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# Copyright 2012 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.openstack.common import cfg + +CONF = cfg.CONF + + +def parse_args(argv, default_config_files=None): + CONF.disable_interspersed_args() + return argv[:1] + CONF(argv[1:], + project='nova', + default_config_files=default_config_files) diff --git a/nova/console/api.py b/nova/console/api.py index 8becf35cf..5a9294ce7 100644 --- a/nova/console/api.py +++ b/nova/console/api.py @@ -22,7 +22,7 @@ from nova.console import rpcapi as console_rpcapi from nova.db import base from nova import flags from nova.openstack.common import rpc -from nova import utils +from nova.openstack.common import uuidutils FLAGS = flags.FLAGS @@ -63,7 +63,7 @@ class API(base.Base): return rpcapi.get_console_topic(context, instance_host) def _get_instance(self, context, instance_uuid): - if utils.is_uuid_like(instance_uuid): + if uuidutils.is_uuid_like(instance_uuid): instance = self.db.instance_get_by_uuid(context, instance_uuid) else: instance = self.db.instance_get(context, instance_uuid) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index a00895c57..ea7e665cf 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -25,6 +25,16 @@ import datetime import functools import warnings +from sqlalchemy import and_ +from sqlalchemy.exc import IntegrityError +from sqlalchemy import or_ +from sqlalchemy.orm import joinedload +from sqlalchemy.orm import joinedload_all +from sqlalchemy.sql.expression import asc +from sqlalchemy.sql.expression import desc +from sqlalchemy.sql.expression import literal_column +from sqlalchemy.sql import func + from nova import block_device from nova.common.sqlalchemyutils import paginate_query from nova.compute import vm_states @@ -35,16 +45,9 @@ from nova import exception from nova import flags from nova.openstack.common import log as logging from nova.openstack.common import timeutils +from nova.openstack.common import uuidutils from nova import utils -from sqlalchemy import and_ -from sqlalchemy.exc import IntegrityError -from sqlalchemy import or_ -from sqlalchemy.orm import joinedload -from sqlalchemy.orm import joinedload_all -from sqlalchemy.sql.expression import asc -from sqlalchemy.sql.expression import desc -from sqlalchemy.sql.expression import literal_column -from sqlalchemy.sql import func + FLAGS = flags.FLAGS @@ -1035,7 +1038,7 @@ def fixed_ip_associate(context, address, instance_uuid, network_id=None, reserved -- should be a boolean value(True or False), exact value will be used to filter on the fixed ip address """ - if not utils.is_uuid_like(instance_uuid): + if not uuidutils.is_uuid_like(instance_uuid): raise exception.InvalidUUID(uuid=instance_uuid) session = get_session() @@ -1067,7 +1070,7 @@ def fixed_ip_associate(context, address, instance_uuid, network_id=None, @require_admin_context def fixed_ip_associate_pool(context, network_id, instance_uuid=None, host=None): - if instance_uuid and not utils.is_uuid_like(instance_uuid): + if instance_uuid and not uuidutils.is_uuid_like(instance_uuid): raise exception.InvalidUUID(uuid=instance_uuid) session = get_session() @@ -1211,7 +1214,7 @@ def fixed_ip_get_by_address(context, address, session=None): @require_context def fixed_ip_get_by_instance(context, instance_uuid): - if not utils.is_uuid_like(instance_uuid): + if not uuidutils.is_uuid_like(instance_uuid): raise exception.InvalidUUID(uuid=instance_uuid) result = model_query(context, models.FixedIp, read_deleted="no").\ @@ -1463,7 +1466,7 @@ def instance_data_get_for_project(context, project_id, session=None): def instance_destroy(context, instance_uuid, constraint=None): session = get_session() with session.begin(): - if utils.is_uuid_like(instance_uuid): + if uuidutils.is_uuid_like(instance_uuid): instance_ref = instance_get_by_uuid(context, instance_uuid, session=session) else: @@ -1783,7 +1786,7 @@ def instance_test_and_set(context, instance_uuid, attr, ok_states, query = model_query(context, models.Instance, session=session, project_only=True) - if utils.is_uuid_like(instance_uuid): + if uuidutils.is_uuid_like(instance_uuid): query = query.filter_by(uuid=instance_uuid) else: raise exception.InvalidUUID(instance_uuid) @@ -1835,7 +1838,7 @@ def instance_update_and_get_original(context, instance_uuid, values): def _instance_update(context, instance_uuid, values, copy_old_instance=False): session = get_session() - if not utils.is_uuid_like(instance_uuid): + if not uuidutils.is_uuid_like(instance_uuid): raise exception.InvalidUUID(instance_uuid) with session.begin(): @@ -2926,7 +2929,7 @@ def volume_allocate_iscsi_target(context, volume_id, host): @require_admin_context def volume_attached(context, volume_id, instance_uuid, mountpoint): - if not utils.is_uuid_like(instance_uuid): + if not uuidutils.is_uuid_like(instance_uuid): raise exception.InvalidUUID(instance_uuid) session = get_session() diff --git a/nova/flags.py b/nova/flags.py index 7d09915a5..a27674472 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -36,13 +36,6 @@ from nova.openstack.common import cfg FLAGS = cfg.CONF -def parse_args(argv, default_config_files=None): - FLAGS.disable_interspersed_args() - return argv[:1] + FLAGS(argv[1:], - project='nova', - default_config_files=default_config_files) - - class UnrecognizedFlag(Exception): pass diff --git a/nova/network/api.py b/nova/network/api.py index bb05a0c2a..d2ce876b8 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -353,6 +353,7 @@ class API(base.Base): if self._is_multi_host(context, instance): args['floating_addresses'] = \ self._get_floating_ip_addresses(context, instance) + args['host'] = migration['dest_compute'] self.network_rpcapi.migrate_instance_start(context, **args) @@ -370,5 +371,6 @@ class API(base.Base): if self._is_multi_host(context, instance): args['floating_addresses'] = \ self._get_floating_ip_addresses(context, instance) + args['host'] = migration['dest_compute'] self.network_rpcapi.migrate_instance_finish(context, **args) diff --git a/nova/network/manager.py b/nova/network/manager.py index afe79a664..cfd1a320f 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -69,6 +69,7 @@ from nova.openstack.common import lockutils from nova.openstack.common import log as logging from nova.openstack.common.notifier import api as notifier from nova.openstack.common import timeutils +from nova.openstack.common import uuidutils import nova.policy from nova import quota from nova import utils @@ -943,7 +944,7 @@ class NetworkManager(manager.SchedulerDependentManager): # NOTE(francois.charlier): the instance may have been deleted already # thus enabling `read_deleted` admin_context = context.get_admin_context(read_deleted='yes') - if utils.is_uuid_like(instance_id): + if uuidutils.is_uuid_like(instance_id): instance_ref = self.db.instance_get_by_uuid(admin_context, instance_id) else: @@ -1277,7 +1278,7 @@ class NetworkManager(manager.SchedulerDependentManager): @wrap_check_policy def add_fixed_ip_to_instance(self, context, instance_id, host, network_id): """Adds a fixed ip to an instance from specified network.""" - if utils.is_uuid_like(network_id): + if uuidutils.is_uuid_like(network_id): network = self.get_network(context, network_id) else: network = self._get_network_by_id(context, network_id) diff --git a/nova/network/quantumv2/api.py b/nova/network/quantumv2/api.py index e8d672835..2cc607684 100644 --- a/nova/network/quantumv2/api.py +++ b/nova/network/quantumv2/api.py @@ -26,7 +26,7 @@ from nova.network import quantumv2 from nova.openstack.common import cfg from nova.openstack.common import excutils from nova.openstack.common import log as logging -from nova import utils +from nova.openstack.common import uuidutils quantum_opts = [ @@ -437,7 +437,7 @@ class API(base.Base): def _get_floating_ip_pool_id_by_name_or_id(self, client, name_or_id): search_opts = {NET_EXTERNAL: True, 'fields': 'id'} - if utils.is_uuid_like(name_or_id): + if uuidutils.is_uuid_like(name_or_id): search_opts.update({'id': name_or_id}) else: search_opts.update({'name': name_or_id}) diff --git a/nova/network/rpcapi.py b/nova/network/rpcapi.py index 6f31e140b..8dd5e3a69 100644 --- a/nova/network/rpcapi.py +++ b/nova/network/rpcapi.py @@ -267,7 +267,11 @@ class NetworkAPI(rpc_proxy.RpcProxy): def migrate_instance_start(self, ctxt, instance_uuid, rxtx_factor, project_id, source_compute, dest_compute, - floating_addresses): + floating_addresses, host=None): + if host is not None: + topic = rpc.queue_get_for(ctxt, self.topic, host) + else: + topic = self.topic return self.call(ctxt, self.make_msg( 'migrate_instance_start', instance_uuid=instance_uuid, @@ -276,13 +280,16 @@ class NetworkAPI(rpc_proxy.RpcProxy): source=source_compute, dest=dest_compute, floating_addresses=floating_addresses), - topic=rpc.queue_get_for(ctxt, self.topic, - dest_compute), - version='1.2') + topic=topic, + version='1.2') def migrate_instance_finish(self, ctxt, instance_uuid, rxtx_factor, project_id, source_compute, dest_compute, - floating_addresses): + floating_addresses, host=None): + if host is not None: + topic = rpc.queue_get_for(ctxt, self.topic, host) + else: + topic = self.topic return self.call(ctxt, self.make_msg( 'migrate_instance_finish', instance_uuid=instance_uuid, @@ -291,6 +298,5 @@ class NetworkAPI(rpc_proxy.RpcProxy): source=source_compute, dest=dest_compute, floating_addresses=floating_addresses), - topic=rpc.queue_get_for(ctxt, self.topic, - dest_compute), - version='1.2') + topic=topic, + version='1.2') diff --git a/nova/test.py b/nova/test.py index 911ad1390..cd82d74e2 100644 --- a/nova/test.py +++ b/nova/test.py @@ -32,6 +32,7 @@ import nose.plugins.skip import stubout import testtools +from nova import config from nova import flags from nova.openstack.common import cfg from nova.openstack.common import log as logging @@ -68,7 +69,7 @@ class TestCase(testtools.TestCase): super(TestCase, self).setUp() fake_flags.set_defaults(FLAGS) - flags.parse_args([], default_config_files=[]) + config.parse_args([], default_config_files=[]) # NOTE(vish): We need a better method for creating fixtures for tests # now that we have some required db setup for the system diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index a7cb2f856..d8bc34883 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -207,6 +207,8 @@ class ComputeTestCase(BaseTestCase): self.stubs.Set(network_api.API, 'allocate_for_instance', fake_get_nw_info) self.compute_api = compute.API() + # Just to make long lines short + self.rt = self.compute.resource_tracker def tearDown(self): super(ComputeTestCase, self).tearDown() @@ -305,20 +307,17 @@ class ComputeTestCase(BaseTestCase): def test_create_instance_unlimited_memory(self): """Default of memory limit=None is unlimited""" self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) params = {"memory_mb": 999999999999} filter_properties = {'limits': {'memory_mb': None}} instance = self._create_fake_instance(params) self.compute.run_instance(self.context, instance=instance, filter_properties=filter_properties) - self.assertEqual(999999999999, - self.compute.resource_tracker.compute_node['memory_mb_used']) + self.assertEqual(999999999999, self.rt.compute_node['memory_mb_used']) def test_create_instance_unlimited_disk(self): self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) params = {"root_gb": 999999999999, "ephemeral_gb": 99999999999} filter_properties = {'limits': {'disk_gb': None}} @@ -328,26 +327,21 @@ class ComputeTestCase(BaseTestCase): def test_create_multiple_instances_then_starve(self): self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) filter_properties = {'limits': {'memory_mb': 4096, 'disk_gb': 1000}} params = {"memory_mb": 1024, "root_gb": 128, "ephemeral_gb": 128} instance = self._create_fake_instance(params) self.compute.run_instance(self.context, instance=instance, filter_properties=filter_properties) - self.assertEquals(1024, - self.compute.resource_tracker.compute_node['memory_mb_used']) - self.assertEquals(256, - self.compute.resource_tracker.compute_node['local_gb_used']) + self.assertEquals(1024, self.rt.compute_node['memory_mb_used']) + self.assertEquals(256, self.rt.compute_node['local_gb_used']) params = {"memory_mb": 2048, "root_gb": 256, "ephemeral_gb": 256} instance = self._create_fake_instance(params) self.compute.run_instance(self.context, instance=instance, filter_properties=filter_properties) - self.assertEquals(3072, - self.compute.resource_tracker.compute_node['memory_mb_used']) - self.assertEquals(768, - self.compute.resource_tracker.compute_node['local_gb_used']) + self.assertEquals(3072, self.rt.compute_node['memory_mb_used']) + self.assertEquals(768, self.rt.compute_node['local_gb_used']) params = {"memory_mb": 8192, "root_gb": 8192, "ephemeral_gb": 8192} instance = self._create_fake_instance(params) @@ -359,8 +353,7 @@ class ComputeTestCase(BaseTestCase): """Test passing of oversubscribed ram policy from the scheduler.""" self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) # get total memory as reported by virt driver: resources = self.compute.driver.get_available_resource() @@ -380,16 +373,14 @@ class ComputeTestCase(BaseTestCase): self.compute.run_instance(self.context, instance=instance, filter_properties=filter_properties) - self.assertEqual(instance_mb, - self.compute.resource_tracker.compute_node['memory_mb_used']) + self.assertEqual(instance_mb, self.rt.compute_node['memory_mb_used']) def test_create_instance_with_oversubscribed_ram_fail(self): """Test passing of oversubscribed ram policy from the scheduler, but with insufficient memory. """ self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) # get total memory as reported by virt driver: resources = self.compute.driver.get_available_resource() @@ -414,8 +405,7 @@ class ComputeTestCase(BaseTestCase): """Test passing of oversubscribed cpu policy from the scheduler.""" self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) limits = {'vcpu': 3} filter_properties = {'limits': limits} @@ -431,8 +421,7 @@ class ComputeTestCase(BaseTestCase): self.compute.run_instance(self.context, instance=instance, filter_properties=filter_properties) - self.assertEqual(2, - self.compute.resource_tracker.compute_node['vcpus_used']) + self.assertEqual(2, self.rt.compute_node['vcpus_used']) # create one more instance: params = {"memory_mb": 10, "root_gb": 1, @@ -441,16 +430,14 @@ class ComputeTestCase(BaseTestCase): self.compute.run_instance(self.context, instance=instance, filter_properties=filter_properties) - self.assertEqual(3, - self.compute.resource_tracker.compute_node['vcpus_used']) + self.assertEqual(3, self.rt.compute_node['vcpus_used']) # delete the instance: instance['vm_state'] = vm_states.DELETED - self.compute.resource_tracker.update_usage(self.context, + self.rt.update_usage(self.context, instance=instance) - self.assertEqual(2, - self.compute.resource_tracker.compute_node['vcpus_used']) + self.assertEqual(2, self.rt.compute_node['vcpus_used']) # now oversubscribe vcpus and fail: params = {"memory_mb": 10, "root_gb": 1, @@ -467,8 +454,7 @@ class ComputeTestCase(BaseTestCase): """Test passing of oversubscribed disk policy from the scheduler.""" self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) # get total memory as reported by virt driver: resources = self.compute.driver.get_available_resource() @@ -487,16 +473,14 @@ class ComputeTestCase(BaseTestCase): self.compute.run_instance(self.context, instance=instance, filter_properties=filter_properties) - self.assertEqual(instance_gb, - self.compute.resource_tracker.compute_node['local_gb_used']) + self.assertEqual(instance_gb, self.rt.compute_node['local_gb_used']) def test_create_instance_with_oversubscribed_disk_fail(self): """Test passing of oversubscribed disk policy from the scheduler, but with insufficient disk. """ self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0) - self.compute.resource_tracker.update_available_resource( - self.context.elevated()) + self.rt.update_available_resource(self.context.elevated()) # get total memory as reported by virt driver: resources = self.compute.driver.get_available_resource() @@ -2002,8 +1986,8 @@ class ComputeTestCase(BaseTestCase): fake_setup_networks_on_host) self.compute.finish_revert_resize(self.context, - migration_id=migration_ref['id'], instance=rpcinst, - reservations=reservations) + migration=jsonutils.to_primitive(migration_ref), + instance=rpcinst, reservations=reservations) instance = db.instance_get_by_uuid(self.context, instance_uuid) self.assertEqual(instance['vm_state'], vm_states.ACTIVE) @@ -5085,7 +5069,8 @@ class ComputeAggrTestCase(BaseTestCase): self.stubs.Set(self.compute.driver, "add_to_aggregate", fake_driver_add_to_aggregate) - self.compute.add_aggregate_host(self.context, self.aggr.id, "host") + self.compute.add_aggregate_host(self.context, "host", + aggregate=jsonutils.to_primitive(self.aggr)) self.assertTrue(fake_driver_add_to_aggregate.called) def test_remove_aggregate_host(self): @@ -5103,15 +5088,16 @@ class ComputeAggrTestCase(BaseTestCase): def test_add_aggregate_host_passes_slave_info_to_driver(self): def driver_add_to_aggregate(context, aggregate, host, **kwargs): self.assertEquals(self.context, context) - self.assertEquals(aggregate.id, self.aggr.id) + self.assertEquals(aggregate['id'], self.aggr.id) self.assertEquals(host, "the_host") self.assertEquals("SLAVE_INFO", kwargs.get("slave_info")) self.stubs.Set(self.compute.driver, "add_to_aggregate", driver_add_to_aggregate) - self.compute.add_aggregate_host(self.context, self.aggr.id, - "the_host", slave_info="SLAVE_INFO") + self.compute.add_aggregate_host(self.context, "the_host", + slave_info="SLAVE_INFO", + aggregate=jsonutils.to_primitive(self.aggr)) def test_remove_from_aggregate_passes_slave_info_to_driver(self): def driver_remove_from_aggregate(context, aggregate, host, **kwargs): diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py index f94cca857..1edfa771f 100644 --- a/nova/tests/compute/test_rpcapi.py +++ b/nova/tests/compute/test_rpcapi.py @@ -95,8 +95,9 @@ class ComputeRpcAPITestCase(test.TestCase): self.assertEqual(arg, expected_arg) def test_add_aggregate_host(self): - self._test_compute_api('add_aggregate_host', 'cast', aggregate_id='id', - host_param='host', host='host', slave_info={}, version='2.2') + self._test_compute_api('add_aggregate_host', 'cast', + aggregate={'id': 'fake_id'}, host_param='host', host='host', + slave_info={}, version='2.14') def test_add_fixed_ip_to_instance(self): self._test_compute_api('add_fixed_ip_to_instance', 'cast', @@ -143,8 +144,8 @@ class ComputeRpcAPITestCase(test.TestCase): def test_finish_revert_resize(self): self._test_compute_api('finish_revert_resize', 'cast', - instance=self.fake_instance, migration_id='id', host='host', - reservations=list('fake_res')) + instance=self.fake_instance, migration={'id': 'fake_id'}, + host='host', reservations=list('fake_res'), version='2.13') def test_get_console_output(self): self._test_compute_api('get_console_output', 'call', @@ -293,8 +294,8 @@ class ComputeRpcAPITestCase(test.TestCase): def test_revert_resize(self): self._test_compute_api('revert_resize', 'cast', - instance=self.fake_instance, migration_id='id', host='host', - reservations=list('fake_res')) + instance=self.fake_instance, migration={'id': 'fake_id'}, + host='host', reservations=list('fake_res'), version='2.12') def test_rollback_live_migration_at_destination(self): self._test_compute_api('rollback_live_migration_at_destination', diff --git a/nova/tests/network/test_api.py b/nova/tests/network/test_api.py index 9bbd7ba92..04f646ef0 100644 --- a/nova/tests/network/test_api.py +++ b/nova/tests/network/test_api.py @@ -19,6 +19,7 @@ from nova import context from nova import network +from nova.network import rpcapi as network_rpcapi from nova.openstack.common import rpc from nova import test @@ -78,3 +79,66 @@ class ApiTestCase(test.TestCase): def test_associate_unassociated_floating_ip(self): self._do_test_associate_floating_ip(None) + + def _stub_migrate_instance_calls(self, method, multi_host, info): + fake_instance_type = {'rxtx_factor': 'fake_factor'} + fake_instance = {'uuid': 'fake_uuid', + 'instance_type': fake_instance_type, + 'project_id': 'fake_project_id'} + fake_migration = {'source_compute': 'fake_compute_source', + 'dest_compute': 'fake_compute_dest'} + + def fake_mig_inst_method(*args, **kwargs): + info['kwargs'] = kwargs + + def fake_is_multi_host(*args, **kwargs): + return multi_host + + def fake_get_floaters(*args, **kwargs): + return ['fake_float1', 'fake_float2'] + + self.stubs.Set(network_rpcapi.NetworkAPI, method, + fake_mig_inst_method) + self.stubs.Set(self.network_api, '_is_multi_host', + fake_is_multi_host) + self.stubs.Set(self.network_api, '_get_floating_ip_addresses', + fake_get_floaters) + + expected = {'instance_uuid': 'fake_uuid', + 'source_compute': 'fake_compute_source', + 'dest_compute': 'fake_compute_dest', + 'rxtx_factor': 'fake_factor', + 'project_id': 'fake_project_id', + 'floating_addresses': None} + if multi_host: + expected['host'] = 'fake_compute_dest' + expected['floating_addresses'] = ['fake_float1', 'fake_float2'] + return fake_instance, fake_migration, expected + + def test_migrate_instance_start_with_multhost(self): + info = {'kwargs': {}} + arg1, arg2, expected = self._stub_migrate_instance_calls( + 'migrate_instance_start', True, info) + self.network_api.migrate_instance_start(self.context, arg1, arg2) + self.assertEqual(info['kwargs'], expected) + + def test_migrate_instance_start_without_multhost(self): + info = {'kwargs': {}} + arg1, arg2, expected = self._stub_migrate_instance_calls( + 'migrate_instance_start', False, info) + self.network_api.migrate_instance_start(self.context, arg1, arg2) + self.assertEqual(info['kwargs'], expected) + + def test_migrate_instance_finish_with_multhost(self): + info = {'kwargs': {}} + arg1, arg2, expected = self._stub_migrate_instance_calls( + 'migrate_instance_finish', True, info) + self.network_api.migrate_instance_finish(self.context, arg1, arg2) + self.assertEqual(info['kwargs'], expected) + + def test_migrate_instance_finish_without_multhost(self): + info = {'kwargs': {}} + arg1, arg2, expected = self._stub_migrate_instance_calls( + 'migrate_instance_finish', False, info) + self.network_api.migrate_instance_finish(self.context, arg1, arg2) + self.assertEqual(info['kwargs'], expected) diff --git a/nova/tests/network/test_rpcapi.py b/nova/tests/network/test_rpcapi.py index a087ba97f..de3f19cea 100644 --- a/nova/tests/network/test_rpcapi.py +++ b/nova/tests/network/test_rpcapi.py @@ -36,11 +36,17 @@ class NetworkRpcAPITestCase(test.TestCase): expected_version = kwargs.pop('version', rpcapi.BASE_RPC_API_VERSION) expected_topic = FLAGS.network_topic expected_msg = rpcapi.make_msg(method, **kwargs) + if 'source_compute' in expected_msg['args']: + # Fix up for migrate_instance_* calls. + args = expected_msg['args'] + args['source'] = args.pop('source_compute') + args['dest'] = args.pop('dest_compute') targeted_methods = [ 'lease_fixed_ip', 'release_fixed_ip', 'rpc_setup_network_on_host', '_rpc_allocate_fixed_ip', 'deallocate_fixed_ip', '_associate_floating_ip', '_disassociate_floating_ip', - 'lease_fixed_ip', 'release_fixed_ip' + 'lease_fixed_ip', 'release_fixed_ip', + 'migrate_instance_start', 'migrate_instance_finish', ] if method in targeted_methods and 'host' in kwargs: if method != 'deallocate_fixed_ip': @@ -258,3 +264,45 @@ class NetworkRpcAPITestCase(test.TestCase): def test_release_fixed_ip(self): self._test_network_api('release_fixed_ip', rpc_method='cast', address='fake_addr', host='fake_host') + + def test_migrate_instance_start(self): + self._test_network_api('migrate_instance_start', rpc_method='call', + instance_uuid='fake_instance_uuid', + rxtx_factor='fake_factor', + project_id='fake_project', + source_compute='fake_src_compute', + dest_compute='fake_dest_compute', + floating_addresses='fake_floating_addresses', + version='1.2') + + def test_migrate_instance_start_multi_host(self): + self._test_network_api('migrate_instance_start', rpc_method='call', + instance_uuid='fake_instance_uuid', + rxtx_factor='fake_factor', + project_id='fake_project', + source_compute='fake_src_compute', + dest_compute='fake_dest_compute', + floating_addresses='fake_floating_addresses', + host='fake_host', + version='1.2') + + def test_migrate_instance_finish(self): + self._test_network_api('migrate_instance_finish', rpc_method='call', + instance_uuid='fake_instance_uuid', + rxtx_factor='fake_factor', + project_id='fake_project', + source_compute='fake_src_compute', + dest_compute='fake_dest_compute', + floating_addresses='fake_floating_addresses', + version='1.2') + + def test_migrate_instance_finish_multi_host(self): + self._test_network_api('migrate_instance_finish', rpc_method='call', + instance_uuid='fake_instance_uuid', + rxtx_factor='fake_factor', + project_id='fake_project', + source_compute='fake_src_compute', + dest_compute='fake_dest_compute', + floating_addresses='fake_floating_addresses', + host='fake_host', + version='1.2') diff --git a/nova/tests/test_flags.py b/nova/tests/test_flags.py index 973d54a1f..15dec56b9 100644 --- a/nova/tests/test_flags.py +++ b/nova/tests/test_flags.py @@ -17,6 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. +from nova import config from nova import flags from nova.openstack.common import cfg from nova import test @@ -44,7 +45,7 @@ class FlagsTestCase(test.TestCase): self.assert_('runtime_answer' not in FLAGS) argv = ['flags_test', 'extra_arg', '--runtime_answer=60'] - args = flags.parse_args(argv, default_config_files=[]) + args = config.parse_args(argv, default_config_files=[]) self.assertEqual(len(args), 3) self.assertEqual(argv, args) @@ -60,7 +61,7 @@ class FlagsTestCase(test.TestCase): default='val', help='desc')) argv = ['flags_test', '--duplicate_answer=60', 'extra_arg'] - args = flags.parse_args(argv, default_config_files=[]) + args = config.parse_args(argv, default_config_files=[]) self.assert_('duplicate_answer' not in FLAGS) self.assert_(FLAGS.duplicate_answer_long, 60) @@ -68,7 +69,7 @@ class FlagsTestCase(test.TestCase): FLAGS.clear() FLAGS.register_cli_opt(cfg.IntOpt('duplicate_answer', default=60, help='desc')) - args = flags.parse_args(argv, default_config_files=[]) + args = config.parse_args(argv, default_config_files=[]) self.assertEqual(FLAGS.duplicate_answer, 60) self.assertEqual(FLAGS.duplicate_answer_long, 'val') diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py index 1b84b858d..8b883f755 100644 --- a/nova/tests/test_utils.py +++ b/nova/tests/test_utils.py @@ -30,6 +30,7 @@ import nova from nova import exception from nova import flags from nova.openstack.common import timeutils +from nova.openstack.common import uuidutils from nova import test from nova import utils @@ -510,7 +511,7 @@ class GenericUtilsTestCase(test.TestCase): class IsUUIDLikeTestCase(test.TestCase): def assertUUIDLike(self, val, expected): - result = utils.is_uuid_like(val) + result = uuidutils.is_uuid_like(val) self.assertEqual(result, expected) def test_good_uuid(self): diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py index 1f30ee695..9d48cdf06 100644 --- a/nova/tests/test_virt_drivers.py +++ b/nova/tests/test_virt_drivers.py @@ -269,7 +269,8 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase): @catch_notimplementederror def test_poll_rebooting_instances(self): - self.connection.poll_rebooting_instances(10) + instances = [self._get_running_instance()] + self.connection.poll_rebooting_instances(10, instances) @catch_notimplementederror def test_poll_rescued_instances(self): diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 404c183a0..54f7948b6 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -27,6 +27,8 @@ import re from nova.compute import api as compute_api from nova.compute import instance_types from nova.compute import power_state +from nova.compute import task_states +from nova.compute import vm_states from nova import context from nova import db from nova import exception @@ -896,6 +898,37 @@ class XenAPIVMTestCase(stubs.XenAPITestBase): self.assertRaises(xenapi_fake.Failure, conn.reboot, instance, None, "SOFT") + def test_maintenance_mode(self): + real_call_xenapi = self.conn._session.call_xenapi + instance = self._create_instance(spawn=True) + api_calls = {} + + # Record all the xenapi calls, and return a fake list of hosts + # for the host.get_all call + def fake_call_xenapi(method, *args): + api_calls[method] = args + if method == 'host.get_all': + return ['foo', 'bar', 'baz'] + return real_call_xenapi(method, *args) + self.stubs.Set(self.conn._session, 'call_xenapi', fake_call_xenapi) + + # Always find the 'bar' destination host + def fake_host_find(context, session, src, dst): + return 'bar' + self.stubs.Set(host, '_host_find', fake_host_find) + + result = self.conn.host_maintenance_mode('bar', 'on_maintenance') + self.assertEqual(result, 'on_maintenance') + + # We expect the VM.pool_migrate call to have been called to + # migrate our instance to the 'bar' host + expected = (instance['uuid'], 'bar', {}) + self.assertTrue(api_calls.get('VM.pool_migrate'), expected) + + instance = db.instance_get_by_uuid(self.context, instance['uuid']) + self.assertTrue(instance['vm_state'], vm_states.ACTIVE) + self.assertTrue(instance['task_state'], task_states.MIGRATING) + def _create_instance(self, instance_id=1, spawn=True): """Creates and spawns a test instance.""" instance_values = { @@ -2241,7 +2274,8 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase): self.assertRaises(exception.AggregateError, self.compute.add_aggregate_host, - self.context, self.aggr.id, "fake_host") + self.context, "fake_host", + aggregate=jsonutils.to_primitive(self.aggr)) excepted = db.aggregate_get(self.context, self.aggr.id) self.assertEqual(excepted.metadetails[pool_states.KEY], pool_states.ERROR) @@ -2258,10 +2292,10 @@ class MockComputeAPI(object): def __init__(self): self._mock_calls = [] - def add_aggregate_host(self, ctxt, aggregate_id, + def add_aggregate_host(self, ctxt, aggregate, host_param, host, slave_info): self._mock_calls.append(( - self.add_aggregate_host, ctxt, aggregate_id, + self.add_aggregate_host, ctxt, aggregate, host_param, host, slave_info)) def remove_aggregate_host(self, ctxt, aggregate_id, host_param, @@ -2304,7 +2338,8 @@ class HypervisorPoolTestCase(test.TestCase): self.assertIn( (slave.compute_rpcapi.add_aggregate_host, - "CONTEXT", 98, "slave", "master", "SLAVE_INFO"), + "CONTEXT", jsonutils.to_primitive(aggregate), + "slave", "master", "SLAVE_INFO"), slave.compute_rpcapi._mock_calls) def test_slave_asks_master_to_remove_slave_from_pool(self): diff --git a/nova/utils.py b/nova/utils.py index 284d72b55..d97c2ce3f 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -772,18 +772,6 @@ def gen_uuid(): return uuid.uuid4() -def is_uuid_like(val): - """For our purposes, a UUID is a string in canonical form: - - aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa - """ - try: - uuid.UUID(val) - return True - except (TypeError, ValueError, AttributeError): - return False - - def bool_from_str(val): """Convert a string representation of a bool into a bool value""" diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 9c8a6448d..a466fa180 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -604,8 +604,14 @@ class ComputeDriver(object): # TODO(Vek): Need to pass context in for access to auth_token pass - def poll_rebooting_instances(self, timeout): - """Poll for rebooting instances""" + def poll_rebooting_instances(self, timeout, instances): + """Poll for rebooting instances + + :param timeout: the currently configured timeout for considering + rebooting instances to be stuck + :param instances: instances that have been in rebooting state + longer than the configured timeout + """ # TODO(Vek): Need to pass context in for access to auth_token raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 03711fe98..877fb7603 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -123,7 +123,7 @@ class FakeDriver(driver.ComputeDriver): def unrescue(self, instance, network_info): pass - def poll_rebooting_instances(self, timeout): + def poll_rebooting_instances(self, timeout, instances): pass def poll_rescued_instances(self, timeout): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 97ce1710c..3104fafd3 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -1052,7 +1052,7 @@ class LibvirtDriver(driver.ComputeDriver): libvirt_utils.file_delete(rescue_file) @exception.wrap_exception() - def poll_rebooting_instances(self, timeout): + def poll_rebooting_instances(self, timeout, instances): pass @exception.wrap_exception() diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py index e4c4150a8..a928bf861 100644 --- a/nova/virt/xenapi/driver.py +++ b/nova/virt/xenapi/driver.py @@ -290,9 +290,9 @@ class XenAPIDriver(driver.ComputeDriver): """Restore the specified instance""" self._vmops.restore(instance) - def poll_rebooting_instances(self, timeout): + def poll_rebooting_instances(self, timeout, instances): """Poll for rebooting instances""" - self._vmops.poll_rebooting_instances(timeout) + self._vmops.poll_rebooting_instances(timeout, instances) def poll_rescued_instances(self, timeout): """Poll for rescued instances""" diff --git a/nova/virt/xenapi/pool.py b/nova/virt/xenapi/pool.py index 71b21ce24..0c2565dbd 100644 --- a/nova/virt/xenapi/pool.py +++ b/nova/virt/xenapi/pool.py @@ -126,7 +126,7 @@ class ResourcePool(object): slave_info = self._create_slave_info() self.compute_rpcapi.add_aggregate_host( - context, aggregate.id, host, master_compute, slave_info) + context, aggregate, host, master_compute, slave_info) def remove_from_aggregate(self, context, aggregate, host, slave_info=None): """Remove a compute host from an aggregate.""" diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 5a295d194..7aa4a20ce 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -1145,10 +1145,12 @@ class VMOps(object): instance=instance) else: vm_utils.shutdown_vm(self._session, instance, vm_ref, hard=True) + self._acquire_bootlock(vm_ref) def restore(self, instance): """Restore the specified instance.""" vm_ref = self._get_vm_opaque_ref(instance) + self._release_bootlock(vm_ref) self._start(instance, vm_ref) def power_off(self, instance): @@ -1172,7 +1174,7 @@ class VMOps(object): if timeutils.is_older_than(task_created, timeout): self._session.call_xenapi("task.cancel", task_ref) - def poll_rebooting_instances(self, timeout): + def poll_rebooting_instances(self, timeout, instances): """Look for expirable rebooting instances. - issue a "hard" reboot to any instance that has been stuck in a @@ -1183,7 +1185,6 @@ class VMOps(object): self._cancel_stale_tasks(timeout, 'VM.clean_reboot') ctxt = nova_context.get_admin_context() - instances = db.instance_get_all_hung_in_rebooting(ctxt, timeout) instances_info = dict(instance_count=len(instances), timeout=timeout) diff --git a/tools/xenserver/destroy_cached_images.py b/tools/xenserver/destroy_cached_images.py index dd6e91adc..a9045cd61 100644 --- a/tools/xenserver/destroy_cached_images.py +++ b/tools/xenserver/destroy_cached_images.py @@ -25,6 +25,7 @@ POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')): sys.path.insert(0, POSSIBLE_TOPDIR) +from nova import config from nova import flags from nova.openstack.common import cfg from nova.openstack.common import log as logging @@ -47,7 +48,7 @@ FLAGS.register_cli_opts(destroy_opts) def main(): - flags.parse_args(sys.argv) + config.parse_args(sys.argv) utils.monkey_patch() xenapi = xenapi_driver.XenAPIDriver() |