diff options
Diffstat (limited to 'nova')
-rw-r--r-- | nova/api/openstack/compute/plugins/v3/servers.py | 1 | ||||
-rw-r--r-- | nova/api/openstack/compute/servers.py | 1 | ||||
-rw-r--r-- | nova/compute/api.py | 27 | ||||
-rw-r--r-- | nova/exception.py | 4 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/plugins/v3/test_servers.py | 15 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/test_servers.py | 15 | ||||
-rw-r--r-- | nova/tests/compute/test_compute_api.py | 26 |
7 files changed, 87 insertions, 2 deletions
diff --git a/nova/api/openstack/compute/plugins/v3/servers.py b/nova/api/openstack/compute/plugins/v3/servers.py index a2023fd42c..294de977bd 100644 --- a/nova/api/openstack/compute/plugins/v3/servers.py +++ b/nova/api/openstack/compute/plugins/v3/servers.py @@ -516,6 +516,7 @@ class ServersController(wsgi.Controller): exception.InvalidMetadata, exception.InvalidRequest, exception.MultiplePortsNotApplicable, + exception.InvalidFixedIpAndMaxCountRequest, exception.InstanceUserDataMalformed, exception.InstanceUserDataTooLarge, exception.PortNotFound, diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 5be4da9cf8..12c1b907cd 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -986,6 +986,7 @@ class Controller(wsgi.Controller): exception.InvalidMetadata, exception.InvalidRequest, exception.MultiplePortsNotApplicable, + exception.InvalidFixedIpAndMaxCountRequest, exception.NetworkNotFound, exception.PortNotFound, exception.FixedIpAlreadyInUse, diff --git a/nova/compute/api.py b/nova/compute/api.py index f7cbfd5e52..2610bfcc77 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1290,6 +1290,26 @@ class API(base.Base): " instance one by one with different ports.") raise exception.MultiplePortsNotApplicable(reason=msg) + def _check_multiple_instances_and_specified_ip(self, requested_networks): + """Check whether multiple instances are created with specified ip.""" + + error = False + if utils.is_neutron(): + for net, ip, port in requested_networks: + if net and ip: + error = True + break + else: + # nova-network case + for id, ip in requested_networks: + if id and ip: + error = True + break + if error: + msg = _("max_count cannot be greater than 1 if an fixed_ip " + "is specified.") + raise exception.InvalidFixedIpAndMaxCountRequest(reason=msg) + @hooks.add_hook("create_instance") def create(self, context, instance_type, image_href, kernel_id=None, ramdisk_id=None, @@ -1311,8 +1331,11 @@ class API(base.Base): self._check_create_policies(context, availability_zone, requested_networks, block_device_mapping) - if requested_networks and max_count > 1 and utils.is_neutron(): - self._check_multiple_instances_neutron_ports(requested_networks) + if requested_networks and max_count > 1: + self._check_multiple_instances_and_specified_ip(requested_networks) + if utils.is_neutron(): + self._check_multiple_instances_neutron_ports( + requested_networks) return self._create_instance( context, instance_type, diff --git a/nova/exception.py b/nova/exception.py index c383ef128e..7f28db1727 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -402,6 +402,10 @@ class MultiplePortsNotApplicable(Invalid): msg_fmt = _("Failed to launch instances: %(reason)s") +class InvalidFixedIpAndMaxCountRequest(Invalid): + msg_fmt = _("Failed to launch instances: %(reason)s") + + class ServiceUnavailable(Invalid): msg_fmt = _("Service is unavailable at this time.") diff --git a/nova/tests/api/openstack/compute/plugins/v3/test_servers.py b/nova/tests/api/openstack/compute/plugins/v3/test_servers.py index f83926a84f..8f6a6e5889 100644 --- a/nova/tests/api/openstack/compute/plugins/v3/test_servers.py +++ b/nova/tests/api/openstack/compute/plugins/v3/test_servers.py @@ -2458,6 +2458,21 @@ class ServersControllerCreateTest(test.TestCase): self.assertRaises(webob.exc.HTTPConflict, self._test_create_extra, params) + @mock.patch.object(compute_api.API, 'create') + def test_create_multiple_instance_with_specified_ip_neutronv2(self, + _api_mock): + _api_mock.side_effect = exception.InvalidFixedIpAndMaxCountRequest( + reason="") + network = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' + port = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee' + address = '10.0.0.1' + requested_networks = [{'uuid': network, 'fixed_ip': address, + 'port': port}] + params = {'networks': requested_networks} + self.body['server']['max_count'] = 2 + self.assertRaises(webob.exc.HTTPBadRequest, + self._test_create_extra, params) + def test_create_multiple_instance_with_neutronv2_port(self): network = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' port = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee' diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index f25e44bfcd..944c90cb65 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -3118,6 +3118,21 @@ class ServersControllerCreateTest(test.TestCase): self.assertRaises(webob.exc.HTTPBadRequest, self._test_create_extra, params) + @mock.patch.object(compute_api.API, 'create') + def test_create_multiple_instance_with_specified_ip_neutronv2(self, + _api_mock): + _api_mock.side_effect = exception.InvalidFixedIpAndMaxCountRequest( + reason="") + network = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' + port = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee' + address = '10.0.0.1' + self.body['server']['max_count'] = 2 + requested_networks = [{'uuid': network, 'fixed_ip': address, + 'port': port}] + params = {'networks': requested_networks} + self.assertRaises(webob.exc.HTTPBadRequest, + self._test_create_extra, params) + def test_create_multiple_instance_with_neutronv2_port(self): self.flags(network_api_class='nova.network.neutronv2.api.API') network = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' diff --git a/nova/tests/compute/test_compute_api.py b/nova/tests/compute/test_compute_api.py index b53b806a3e..a1edeab2e4 100644 --- a/nova/tests/compute/test_compute_api.py +++ b/nova/tests/compute/test_compute_api.py @@ -174,6 +174,32 @@ class _ComputeAPIUnitTestMixIn(object): else: self.fail("Exception not raised") + def _test_specified_ip_and_multiple_instances_helper(self, + requested_networks): + # Tests that if ip is specified there is only one instance booting + # (i.e max_count == 1) + min_count = 1 + max_count = 2 + self.assertRaises(exception.InvalidFixedIpAndMaxCountRequest, + self.compute_api.create, self.context, "fake_flavor", 'image_id', + min_count=min_count, max_count=max_count, + requested_networks=requested_networks) + + def test_specified_ip_and_multiple_instances(self): + network = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' + address = '10.0.0.1' + requested_networks = [(network, address)] + self._test_specified_ip_and_multiple_instances_helper( + requested_networks) + + def test_specified_ip_and_multiple_instances_neutronv2(self): + self.flags(network_api_class='nova.network.neutronv2.api.API') + network = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' + address = '10.0.0.1' + requested_networks = [(network, address, None)] + self._test_specified_ip_and_multiple_instances_helper( + requested_networks) + def test_suspend(self): # Ensure instance can be suspended. instance = self._create_instance_obj() |