diff options
-rw-r--r-- | nova/api/ec2/cloud.py | 5 | ||||
-rw-r--r-- | nova/api/openstack/servers.py | 3 | ||||
-rw-r--r-- | nova/compute/api.py | 35 | ||||
-rw-r--r-- | nova/scheduler/driver.py | 3 | ||||
-rw-r--r-- | nova/tests/api/ec2/test_cloud.py | 5 | ||||
-rw-r--r-- | nova/tests/api/openstack/test_servers.py | 8 | ||||
-rw-r--r-- | nova/tests/test_compute.py | 19 |
7 files changed, 38 insertions, 40 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 16ea74025..b2aa120e6 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -1437,10 +1437,7 @@ class CloudController(object): security_group=kwargs.get('security_group'), availability_zone=kwargs.get('placement', {}).get( 'AvailabilityZone'), - block_device_mapping=kwargs.get('block_device_mapping', {}), - # NOTE(comstud): Unfortunately, EC2 requires that the - # instance DB entries have been created.. - wait_for_instances=True) + block_device_mapping=kwargs.get('block_device_mapping', {})) return self._format_run_instances(context, resv_id) def _do_instance(self, action, context, ec2_id): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 8c1eaae9d..b71e5df31 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -462,8 +462,7 @@ class Controller(object): user_data=user_data, availability_zone=availability_zone, config_drive=config_drive, - block_device_mapping=block_device_mapping, - wait_for_instances=not ret_resv_id) + block_device_mapping=block_device_mapping) except quota.QuotaError as error: self._handle_quota_error(error) except exception.InstanceTypeMemoryTooSmall as error: diff --git a/nova/compute/api.py b/nova/compute/api.py index 436dc79b5..b6ba86eb3 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -45,6 +45,7 @@ LOG = logging.getLogger('nova.compute.api') FLAGS = flags.FLAGS +flags.DECLARE('enable_zone_routing', 'nova.scheduler.api') flags.DECLARE('vncproxy_topic', 'nova.vnc') flags.DEFINE_integer('find_host_timeout', 30, 'Timeout after NN seconds when looking for a host.') @@ -189,8 +190,7 @@ class API(base.Base): injected_files, admin_password, zone_blob, reservation_id, access_ip_v4, access_ip_v6, requested_networks, config_drive, - block_device_mapping, - wait_for_instances): + block_device_mapping, create_instance_here=False): """Verify all the input parameters regardless of the provisioning strategy being performed and schedule the instance(s) for creation.""" @@ -325,10 +325,18 @@ class API(base.Base): LOG.debug(_("Going to run %s instances...") % num_instances) - if wait_for_instances: - rpc_method = rpc.call - else: + if create_instance_here: + instance = self.create_db_entry_for_new_instance( + context, instance_type, image, base_options, + security_group, block_device_mapping) + # Tells scheduler we created the instance already. + base_options['id'] = instance['id'] rpc_method = rpc.cast + else: + # We need to wait for the scheduler to create the instance + # DB entries, because the instance *could* be # created in + # a child zone. + rpc_method = rpc.call # TODO(comstud): We should use rpc.multicall when we can # retrieve the full instance dictionary from the scheduler. @@ -344,6 +352,8 @@ class API(base.Base): num_instances, requested_networks, block_device_mapping, security_group) + if create_instance_here: + return ([instance], reservation_id) return (instances, reservation_id) @staticmethod @@ -534,8 +544,7 @@ class API(base.Base): injected_files=None, admin_password=None, zone_blob=None, reservation_id=None, block_device_mapping=None, access_ip_v4=None, access_ip_v6=None, - requested_networks=None, config_drive=None, - wait_for_instances=True): + requested_networks=None, config_drive=None): """ Provision instances, sending instance information to the scheduler. The scheduler will determine where the instance(s) @@ -546,6 +555,13 @@ class API(base.Base): we waited for information from the scheduler or not. """ + # We can create the DB entry for the instance here if we're + # only going to create 1 instance and we're in a single + # zone deployment. This speeds up API responses for builds + # as we don't need to wait for the scheduler. + create_instance_here = (max_count == 1 and + not FLAGS.enable_zone_routing) + (instances, reservation_id) = self._create_instance( context, instance_type, image_href, kernel_id, ramdisk_id, @@ -557,10 +573,9 @@ class API(base.Base): reservation_id, access_ip_v4, access_ip_v6, requested_networks, config_drive, block_device_mapping, - wait_for_instances) + create_instance_here=create_instance_here) - if instances is None: - # wait_for_instances must have been False + if create_instance_here or instances is None: return (instances, reservation_id) inst_ret_list = [] diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index 7c79d28c9..af39b2edb 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -155,6 +155,9 @@ class Scheduler(object): def create_instance_db_entry(self, context, request_spec): """Create instance DB entry based on request_spec""" base_options = request_spec['instance_properties'] + if base_options.get('id'): + # Instance was already created before calling scheduler + return db.instance_get(context, base_options['id']) image = request_spec['image'] instance_type = request_spec.get('instance_type') security_group = request_spec.get('security_group', 'default') diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py index c0f3d44d7..f76690831 100644 --- a/nova/tests/api/ec2/test_cloud.py +++ b/nova/tests/api/ec2/test_cloud.py @@ -1013,8 +1013,6 @@ class CloudTestCase(test.TestCase): self.assertDictListUnorderedMatch(result['blockDeviceMapping'], self._expected_bdms2, 'deviceName') - self.stubs.UnsetAll() - def test_describe_image_attribute(self): describe_image_attribute = self.cloud.describe_image_attribute @@ -1216,6 +1214,9 @@ class CloudTestCase(test.TestCase): self.stubs.UnsetAll() self.stubs.Set(fake._FakeImageService, 'show', fake_show) + # NOTE(comstud): Make 'cast' behave like a 'call' which will + # ensure that operations complete + self.stubs.Set(rpc, 'cast', rpc.call) result = run_instances(self.context, **kwargs) instance = result['instancesSet'][0] diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 4518ef8e2..31c87e630 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1354,7 +1354,7 @@ class ServersControllerCreateTest(test.TestCase): self.instance_cache_num += 1 instance = { 'id': self.instance_cache_num, - 'display_name': 'server_test', + 'display_name': inst['display_name'] or 'test', 'uuid': FAKE_UUID, 'instance_type': dict(inst_type), 'access_ip_v4': '1.2.3.4', @@ -1390,8 +1390,10 @@ class ServersControllerCreateTest(test.TestCase): request_spec['instance_properties'])) return instances - def server_update(context, id, params): - return instance_create(context, id) + def server_update(context, instance_id, params): + inst = self.instance_cache[instance_id] + inst.update(params) + return inst def fake_method(*args, **kwargs): pass diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index addb6084d..7295c9f1f 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -1409,25 +1409,6 @@ class ComputeTestCase(test.TestCase): self.assertEqual(instance['reservation_id'], resv_id) db.instance_destroy(self.context, instance['id']) - def test_reservation_ids_two_instances_no_wait(self): - """Verify building 2 instances at once without waiting for - instance IDs results in a reservation_id being returned equal - to reservation id set in both instances - """ - (refs, resv_id) = self.compute_api.create(self.context, - instance_types.get_default_instance_type(), None, - min_count=2, max_count=2, wait_for_instances=False) - try: - self.assertEqual(refs, None) - self.assertNotEqual(resv_id, None) - finally: - instances = self.compute_api.get_all(self.context, - search_opts={'reservation_id': resv_id}) - self.assertEqual(len(instances), 2) - for instance in instances: - self.assertEqual(instance['reservation_id'], resv_id) - db.instance_destroy(self.context, instance['id']) - def test_create_with_specified_reservation_id(self): """Verify building instances with a specified reservation_id results in the correct reservation_id |