summaryrefslogtreecommitdiff
path: root/nova
diff options
context:
space:
mode:
Diffstat (limited to 'nova')
-rw-r--r--nova/api/openstack/compute/plugins/v3/servers.py1
-rw-r--r--nova/api/openstack/compute/servers.py1
-rw-r--r--nova/compute/api.py27
-rw-r--r--nova/exception.py4
-rw-r--r--nova/tests/api/openstack/compute/plugins/v3/test_servers.py15
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py15
-rw-r--r--nova/tests/compute/test_compute_api.py26
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()