Prevent max_count > 1 and specified ip address as input
Previously, if one did: nova boot --num-instances 2 --nic net-id=<net_id>,v4-fixed-ip=10.0.0.17 this would result in all of the instances failing to boot because neither nova-network or neutron allows multiple instances to have the same ip_address. This patch fixes this from occuring by checking for this and raising an error to the caller from nova-api. Change-Id: I7e44d58e66aeb10fb15c3553072f988f65ab823b Closes-bug: 1318754
This commit is contained in:
parent
54d0f898f6
commit
1181d5e65f
|
@ -516,6 +516,7 @@ class ServersController(wsgi.Controller):
|
|||
exception.InvalidMetadata,
|
||||
exception.InvalidRequest,
|
||||
exception.MultiplePortsNotApplicable,
|
||||
exception.InvalidFixedIpAndMaxCountRequest,
|
||||
exception.InstanceUserDataMalformed,
|
||||
exception.PortNotFound,
|
||||
exception.FixedIpAlreadyInUse,
|
||||
|
|
|
@ -986,6 +986,7 @@ class Controller(wsgi.Controller):
|
|||
exception.InvalidMetadata,
|
||||
exception.InvalidRequest,
|
||||
exception.MultiplePortsNotApplicable,
|
||||
exception.InvalidFixedIpAndMaxCountRequest,
|
||||
exception.NetworkNotFound,
|
||||
exception.PortNotFound,
|
||||
exception.FixedIpAlreadyInUse,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.")
|
||||
|
||||
|
|
|
@ -2449,6 +2449,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'
|
||||
|
|
|
@ -3109,6 +3109,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'
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue