Boot an instance with multiple vnics on same network
If the same L2 network is requested multiple times for the same instance then creating ports on same network and attaching them to the same instance raises a DuplicateNetworks exception. Similarly, attaching multiple existent ports on same L2 network to the same instance raises a DuplicateNetworks exception. This is the default behavior that is defaulted by a newly introduced nova flag "allow_duplicate_networks" which is set to False by default. Not raising a DuplicateNetwork exception and allowing an instance to have multiple vnics on same network is useful for NfV service instances and in that case this newly introduced nova flag should be set to True. DocImpact: New neutron.allow_duplicate_networks configuration option Implements blueprint multiple-if-1-net Change-Id: Id4d633162c785c9b56b9c8426c0445770bc1352e Closes-Bug: #1187244
This commit is contained in:
parent
374418085d
commit
322cc9336f
|
@ -104,6 +104,10 @@ neutron_opts = [
|
|||
'neutron client requests.',
|
||||
deprecated_group='DEFAULT',
|
||||
deprecated_name='neutron_ca_certificates_file'),
|
||||
cfg.BoolOpt('allow_duplicate_networks',
|
||||
default=False,
|
||||
help='Allow an instance to have multiple vNICs attached to '
|
||||
'the same Neutron network.'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -258,8 +262,8 @@ class API(base_api.NetworkAPI):
|
|||
requested_networks = kwargs.get('requested_networks')
|
||||
dhcp_opts = kwargs.get('dhcp_options', None)
|
||||
ports = {}
|
||||
fixed_ips = {}
|
||||
net_ids = []
|
||||
ordered_networks = []
|
||||
if requested_networks:
|
||||
for network_id, fixed_ip, port_id in requested_networks:
|
||||
if port_id:
|
||||
|
@ -277,19 +281,30 @@ class API(base_api.NetworkAPI):
|
|||
# discard rather than popping.
|
||||
available_macs.discard(port['mac_address'])
|
||||
network_id = port['network_id']
|
||||
ports[network_id] = port
|
||||
elif fixed_ip and network_id:
|
||||
fixed_ips[network_id] = fixed_ip
|
||||
ports[port_id] = port
|
||||
if network_id:
|
||||
net_ids.append(network_id)
|
||||
ordered_networks.append((network_id, fixed_ip, port_id))
|
||||
|
||||
nets = self._get_available_networks(context, instance['project_id'],
|
||||
net_ids)
|
||||
|
||||
if not nets:
|
||||
LOG.warn(_("No network configured!"), instance=instance)
|
||||
return network_model.NetworkInfo([])
|
||||
|
||||
# if this function is directly called without a requested_network param
|
||||
# or if it is indirectly called through allocate_port_for_instance()
|
||||
# with None params=(network_id=None, requested_ip=None, port_id=None):
|
||||
if (not requested_networks
|
||||
or requested_networks == [(None, None, None)]):
|
||||
# bug/1267723 - if no network is requested and more
|
||||
# than one is available then raise NetworkAmbiguous Exception
|
||||
if len(nets) > 1:
|
||||
msg = _("Multiple possible networks found, use a Network "
|
||||
"ID to be more specific.")
|
||||
raise exception.NetworkAmbiguous(msg)
|
||||
ordered_networks.append((nets[0]['id'], None, None))
|
||||
|
||||
security_groups = kwargs.get('security_groups', [])
|
||||
security_group_ids = []
|
||||
|
||||
|
@ -328,7 +343,20 @@ class API(base_api.NetworkAPI):
|
|||
touched_port_ids = []
|
||||
created_port_ids = []
|
||||
ports_in_requested_order = []
|
||||
for network in nets:
|
||||
nets_in_requested_order = []
|
||||
for network_id, fixed_ip, port_id in ordered_networks:
|
||||
# Network lookup for available network_id
|
||||
network = None
|
||||
for net in nets:
|
||||
if net['id'] == network_id:
|
||||
network = net
|
||||
break
|
||||
# if network_id did not pass validate_networks() and not available
|
||||
# here then skip it safely not continuing with a None Network
|
||||
else:
|
||||
continue
|
||||
|
||||
nets_in_requested_order.append(network)
|
||||
# If security groups are requested on an instance then the
|
||||
# network must has a subnet associated with it. Some plugins
|
||||
# implement the port-security extension which requires
|
||||
|
@ -345,21 +373,21 @@ class API(base_api.NetworkAPI):
|
|||
port_req_body = {'port': {'device_id': instance['uuid'],
|
||||
'device_owner': zone}}
|
||||
try:
|
||||
port = ports.get(network_id)
|
||||
self._populate_neutron_extension_values(context, instance,
|
||||
port_req_body)
|
||||
# Requires admin creds to set port bindings
|
||||
port_client = (neutron if not
|
||||
self._has_port_binding_extension(context) else
|
||||
neutronv2.get_client(context, admin=True))
|
||||
if port:
|
||||
if port_id:
|
||||
port = ports[port_id]
|
||||
port_client.update_port(port['id'], port_req_body)
|
||||
touched_port_ids.append(port['id'])
|
||||
ports_in_requested_order.append(port['id'])
|
||||
else:
|
||||
created_port = self._create_port(
|
||||
port_client, instance, network_id,
|
||||
port_req_body, fixed_ips.get(network_id),
|
||||
port_req_body, fixed_ip,
|
||||
security_group_ids, available_macs, dhcp_opts)
|
||||
created_port_ids.append(created_port)
|
||||
ports_in_requested_order.append(created_port)
|
||||
|
@ -387,7 +415,8 @@ class API(base_api.NetworkAPI):
|
|||
msg = _("Failed to delete port %s")
|
||||
LOG.exception(msg, port_id)
|
||||
|
||||
nw_info = self.get_instance_nw_info(context, instance, networks=nets,
|
||||
nw_info = self.get_instance_nw_info(context, instance,
|
||||
networks=nets_in_requested_order,
|
||||
port_ids=ports_in_requested_order)
|
||||
# NOTE(danms): Only return info about ports we created in this run.
|
||||
# In the initial allocation case, this will be everything we created,
|
||||
|
@ -690,8 +719,9 @@ class API(base_api.NetworkAPI):
|
|||
address=fixed_ip,
|
||||
instance_uuid=i_uuid)
|
||||
|
||||
if net_id in instance_on_net_ids:
|
||||
raise exception.NetworkDuplicated(network_id=net_id)
|
||||
if (not CONF.neutron.allow_duplicate_networks and
|
||||
net_id in instance_on_net_ids):
|
||||
raise exception.NetworkDuplicated(network_id=net_id)
|
||||
instance_on_net_ids.append(net_id)
|
||||
|
||||
# Now check to see if all requested networks exist
|
||||
|
@ -709,10 +739,11 @@ class API(base_api.NetworkAPI):
|
|||
requested_netid_set = set(net_ids_requested)
|
||||
returned_netid_set = set([net['id'] for net in nets])
|
||||
lostid_set = requested_netid_set - returned_netid_set
|
||||
id_str = ''
|
||||
for _id in lostid_set:
|
||||
id_str = id_str and id_str + ', ' + _id or _id
|
||||
raise exception.NetworkNotFound(network_id=id_str)
|
||||
if lostid_set:
|
||||
id_str = ''
|
||||
for _id in lostid_set:
|
||||
id_str = id_str and id_str + ', ' + _id or _id
|
||||
raise exception.NetworkNotFound(network_id=id_str)
|
||||
|
||||
# Note(PhilD): Ideally Nova would create all required ports as part of
|
||||
# network validation, but port creation requires some details
|
||||
|
|
|
@ -814,8 +814,14 @@ class MockClient(object):
|
|||
return {'security_groups': ret}
|
||||
|
||||
def list_networks(self, **_params):
|
||||
return {'networks':
|
||||
[network for network in self._fake_networks.values()]}
|
||||
# neutronv2/api.py _get_available_networks calls this assuming
|
||||
# search_opts filter "shared" is implemented and not ignored
|
||||
shared = _params.get("shared", None)
|
||||
if shared:
|
||||
return {'networks': []}
|
||||
else:
|
||||
return {'networks':
|
||||
[network for network in self._fake_networks.values()]}
|
||||
|
||||
def list_ports(self, **_params):
|
||||
ret = []
|
||||
|
|
|
@ -228,8 +228,19 @@ class TestNeutronv2Base(test.TestCase):
|
|||
'name': 'out-of-this-world',
|
||||
'router:external': True,
|
||||
'tenant_id': 'should-be-an-admin'}]
|
||||
# A network request with a duplicate
|
||||
self.nets6 = []
|
||||
self.nets6.append(self.nets1[0])
|
||||
self.nets6.append(self.nets1[0])
|
||||
# A network request with a combo
|
||||
self.nets7 = []
|
||||
self.nets7.append(self.nets2[1])
|
||||
self.nets7.append(self.nets1[0])
|
||||
self.nets7.append(self.nets2[1])
|
||||
self.nets7.append(self.nets1[0])
|
||||
|
||||
self.nets = [self.nets1, self.nets2, self.nets3,
|
||||
self.nets4, self.nets5]
|
||||
self.nets4, self.nets5, self.nets6, self.nets7]
|
||||
|
||||
self.port_address = '10.0.1.2'
|
||||
self.port_data1 = [{'network_id': 'my_netid1',
|
||||
|
@ -357,30 +368,49 @@ class TestNeutronv2Base(test.TestCase):
|
|||
if macs:
|
||||
macs = set(macs)
|
||||
req_net_ids = []
|
||||
ordered_networks = []
|
||||
port = {}
|
||||
if 'requested_networks' in kwargs:
|
||||
for id, fixed_ip, port_id in kwargs['requested_networks']:
|
||||
for n_id, fixed_ip, port_id in kwargs['requested_networks']:
|
||||
if port_id:
|
||||
self.moxed_client.show_port(port_id).AndReturn(
|
||||
{'port': {'id': 'my_portid1',
|
||||
'network_id': 'my_netid1',
|
||||
'mac_address': 'my_mac1',
|
||||
'device_id': kwargs.get('_device') and
|
||||
self.instance2['uuid'] or ''}})
|
||||
|
||||
ports['my_netid1'] = self.port_data1[0]
|
||||
id = 'my_netid1'
|
||||
if macs is not None:
|
||||
macs.discard('my_mac1')
|
||||
if port_id == 'my_portid3':
|
||||
self.moxed_client.show_port(port_id).AndReturn(
|
||||
{'port': {'id': 'my_portid3',
|
||||
'network_id': 'my_netid1',
|
||||
'mac_address': 'my_mac1',
|
||||
'device_id': kwargs.get('_device') and
|
||||
self.instance2['uuid'] or
|
||||
''}})
|
||||
ports['my_netid1'] = [self.port_data1[0],
|
||||
self.port_data3[0]]
|
||||
ports[port_id] = self.port_data3[0]
|
||||
n_id = 'my_netid1'
|
||||
if macs is not None:
|
||||
macs.discard('my_mac1')
|
||||
else:
|
||||
self.moxed_client.show_port(port_id).AndReturn(
|
||||
{'port': {'id': 'my_portid1',
|
||||
'network_id': 'my_netid1',
|
||||
'mac_address': 'my_mac1',
|
||||
'device_id': kwargs.get('_device') and
|
||||
self.instance2['uuid'] or
|
||||
''}})
|
||||
ports[port_id] = self.port_data1[0]
|
||||
n_id = 'my_netid1'
|
||||
if macs is not None:
|
||||
macs.discard('my_mac1')
|
||||
else:
|
||||
fixed_ips[id] = fixed_ip
|
||||
req_net_ids.append(id)
|
||||
expected_network_order = req_net_ids
|
||||
fixed_ips[n_id] = fixed_ip
|
||||
req_net_ids.append(n_id)
|
||||
ordered_networks.append((n_id, fixed_ip, port_id))
|
||||
else:
|
||||
expected_network_order = [n['id'] for n in nets]
|
||||
for n in nets:
|
||||
ordered_networks.append((n['id'], None, None))
|
||||
if kwargs.get('_break') == 'pre_list_networks':
|
||||
self.mox.ReplayAll()
|
||||
return api
|
||||
search_ids = [net['id'] for net in nets if net['id'] in req_net_ids]
|
||||
# search all req_net_ids as in api.py
|
||||
search_ids = req_net_ids
|
||||
|
||||
if search_ids:
|
||||
mox_list_params = {'id': mox.SameElementsAs(search_ids)}
|
||||
|
@ -395,18 +425,34 @@ class TestNeutronv2Base(test.TestCase):
|
|||
self.moxed_client.list_networks(
|
||||
**mox_list_params).AndReturn({'networks': []})
|
||||
|
||||
if (('requested_networks' not in kwargs
|
||||
or kwargs['requested_networks'] == [(None, None, None)])
|
||||
and len(nets) > 1):
|
||||
self.mox.ReplayAll()
|
||||
return api
|
||||
|
||||
ports_in_requested_net_order = []
|
||||
for net_id in expected_network_order:
|
||||
nets_in_requested_net_order = []
|
||||
for net_id, fixed_ip, port_id in ordered_networks:
|
||||
port_req_body = {
|
||||
'port': {
|
||||
'device_id': self.instance['uuid'],
|
||||
'device_owner': 'compute:nova',
|
||||
},
|
||||
}
|
||||
# Network lookup for available network_id
|
||||
network = None
|
||||
for net in nets:
|
||||
if net['id'] == net_id:
|
||||
network = net
|
||||
break
|
||||
# if net_id did not pass validate_networks() and not available
|
||||
# here then skip it safely not continuing with a None Network
|
||||
else:
|
||||
continue
|
||||
if has_portbinding:
|
||||
port_req_body['port']['binding:host_id'] = (
|
||||
self.instance.get('host'))
|
||||
port = ports.get(net_id, None)
|
||||
if not has_portbinding:
|
||||
api._populate_neutron_extension_values(mox.IgnoreArg(),
|
||||
self.instance, mox.IgnoreArg()).AndReturn(None)
|
||||
|
@ -417,8 +463,8 @@ class TestNeutronv2Base(test.TestCase):
|
|||
AndReturn(has_portbinding)
|
||||
api._has_port_binding_extension(mox.IgnoreArg()).\
|
||||
AndReturn(has_portbinding)
|
||||
if port:
|
||||
port_id = port['id']
|
||||
if port_id:
|
||||
port = ports[port_id]
|
||||
self.moxed_client.update_port(port_id,
|
||||
MyComparator(port_req_body)
|
||||
).AndReturn(
|
||||
|
@ -448,9 +494,11 @@ class TestNeutronv2Base(test.TestCase):
|
|||
MyComparator(port_req_body)).AndReturn(res_port)
|
||||
ports_in_requested_net_order.append(res_port['port']['id'])
|
||||
|
||||
nets_in_requested_net_order.append(network)
|
||||
|
||||
api.get_instance_nw_info(mox.IgnoreArg(),
|
||||
self.instance,
|
||||
networks=nets,
|
||||
networks=nets_in_requested_net_order,
|
||||
port_ids=ports_in_requested_net_order
|
||||
).AndReturn(self._returned_nw_info)
|
||||
self.mox.ReplayAll()
|
||||
|
@ -783,7 +831,10 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
|
||||
def test_allocate_for_instance_2(self):
|
||||
# Allocate one port in two networks env.
|
||||
self._allocate_for_instance(2)
|
||||
api = self._stub_allocate_for_instance(net_idx=2)
|
||||
self.assertRaises(exception.NetworkAmbiguous,
|
||||
api.allocate_for_instance,
|
||||
self.context, self.instance)
|
||||
|
||||
def test_allocate_for_instance_accepts_macs_kwargs_None(self):
|
||||
# The macs kwarg should be accepted as None.
|
||||
|
@ -859,6 +910,23 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
self.instance, requested_networks=requested_networks,
|
||||
macs=set(['unknown:mac']))
|
||||
|
||||
def test_allocate_for_instance_without_requested_networks(self):
|
||||
api = self._stub_allocate_for_instance(net_idx=3)
|
||||
self.assertRaises(exception.NetworkAmbiguous,
|
||||
api.allocate_for_instance,
|
||||
self.context, self.instance)
|
||||
|
||||
def test_allocate_for_instance_with_requested_non_available_network(self):
|
||||
"""verify that a non available network is ignored.
|
||||
self.nets2 (net_idx=2) is composed of self.nets3[0] and self.nets3[1]
|
||||
Do not create a port on a non available network self.nets3[2].
|
||||
"""
|
||||
requested_networks = [
|
||||
(net['id'], None, None)
|
||||
for net in (self.nets3[0], self.nets3[2], self.nets3[1])]
|
||||
self._allocate_for_instance(net_idx=2,
|
||||
requested_networks=requested_networks)
|
||||
|
||||
def test_allocate_for_instance_with_requested_networks(self):
|
||||
# specify only first and last network
|
||||
requested_networks = [
|
||||
|
@ -874,7 +942,7 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
requested_networks=requested_networks)
|
||||
|
||||
def test_allocate_for_instance_with_requested_networks_with_port(self):
|
||||
requested_networks = [(None, None, 'myportid1')]
|
||||
requested_networks = [(None, None, 'my_portid1')]
|
||||
self._allocate_for_instance(net_idx=1,
|
||||
requested_networks=requested_networks)
|
||||
|
||||
|
@ -903,12 +971,11 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
self.mox.StubOutWithMock(api, '_has_port_binding_extension')
|
||||
api._has_port_binding_extension(mox.IgnoreArg()).MultipleTimes().\
|
||||
AndReturn(False)
|
||||
requested_networks = [
|
||||
(net['id'], None, None)
|
||||
for net in (self.nets2[0], self.nets2[1])]
|
||||
self.moxed_client.list_networks(
|
||||
tenant_id=self.instance['project_id'],
|
||||
shared=False).AndReturn(
|
||||
{'networks': self.nets2})
|
||||
self.moxed_client.list_networks(shared=True).AndReturn(
|
||||
{'networks': []})
|
||||
id=['my_netid1', 'my_netid2']).AndReturn({'networks': self.nets2})
|
||||
index = 0
|
||||
for network in self.nets2:
|
||||
binding_port_req_body = {
|
||||
|
@ -941,7 +1008,8 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
self.mox.ReplayAll()
|
||||
self.assertRaises(exception.PortLimitExceeded,
|
||||
api.allocate_for_instance,
|
||||
self.context, self.instance)
|
||||
self.context, self.instance,
|
||||
requested_networks=requested_networks)
|
||||
|
||||
def test_allocate_for_instance_ex2(self):
|
||||
"""verify we have no port to delete
|
||||
|
@ -955,12 +1023,11 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
self.mox.StubOutWithMock(api, '_has_port_binding_extension')
|
||||
api._has_port_binding_extension(mox.IgnoreArg()).MultipleTimes().\
|
||||
AndReturn(False)
|
||||
requested_networks = [
|
||||
(net['id'], None, None)
|
||||
for net in (self.nets2[0], self.nets2[1])]
|
||||
self.moxed_client.list_networks(
|
||||
tenant_id=self.instance['project_id'],
|
||||
shared=False).AndReturn(
|
||||
{'networks': self.nets2})
|
||||
self.moxed_client.list_networks(shared=True).AndReturn(
|
||||
{'networks': []})
|
||||
id=['my_netid1', 'my_netid2']).AndReturn({'networks': self.nets2})
|
||||
binding_port_req_body = {
|
||||
'port': {
|
||||
'device_id': self.instance['uuid'],
|
||||
|
@ -982,7 +1049,8 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
Exception("fail to create port"))
|
||||
self.mox.ReplayAll()
|
||||
self.assertRaises(NEUTRON_CLIENT_EXCEPTION, api.allocate_for_instance,
|
||||
self.context, self.instance)
|
||||
self.context, self.instance,
|
||||
requested_networks=requested_networks)
|
||||
|
||||
def test_allocate_for_instance_no_port_or_network(self):
|
||||
class BailOutEarly(Exception):
|
||||
|
@ -1211,9 +1279,10 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
except exception.NetworkNotFound as ex:
|
||||
self.assertIn("my_netid2, my_netid3", str(ex))
|
||||
|
||||
def test_validate_networks_duplicate(self):
|
||||
def test_validate_networks_duplicate_disable(self):
|
||||
"""Verify that the correct exception is thrown when duplicate
|
||||
network ids are passed to validate_networks.
|
||||
network ids are passed to validate_networks, when nova config flag
|
||||
allow_duplicate_networks is set to its default value: False
|
||||
"""
|
||||
requested_networks = [('my_netid1', None, None),
|
||||
('my_netid1', None, None)]
|
||||
|
@ -1222,8 +1291,59 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
neutronv2.get_client(None)
|
||||
api = neutronapi.API()
|
||||
self.assertRaises(exception.NetworkDuplicated,
|
||||
api.validate_networks,
|
||||
self.context, requested_networks, 1)
|
||||
api.validate_networks,
|
||||
self.context, requested_networks, 1)
|
||||
|
||||
def test_validate_networks_duplicate_enable(self):
|
||||
"""Verify that no duplicateNetworks exception is thrown when duplicate
|
||||
network ids are passed to validate_networks, when nova config flag
|
||||
allow_duplicate_networks is set to its non default value: True
|
||||
"""
|
||||
self.flags(allow_duplicate_networks=True, group='neutron')
|
||||
requested_networks = [('my_netid1', None, None),
|
||||
('my_netid1', None, None)]
|
||||
ids = ['my_netid1', 'my_netid1']
|
||||
|
||||
self.moxed_client.list_networks(
|
||||
id=mox.SameElementsAs(ids)).AndReturn(
|
||||
{'networks': self.nets1})
|
||||
self.moxed_client.list_ports(tenant_id='my_tenantid').AndReturn(
|
||||
{'ports': []})
|
||||
self.moxed_client.show_quota(
|
||||
tenant_id='my_tenantid').AndReturn(
|
||||
{'quota': {'port': 50}})
|
||||
self.mox.ReplayAll()
|
||||
api = neutronapi.API()
|
||||
api.validate_networks(self.context, requested_networks, 1)
|
||||
|
||||
def test_allocate_for_instance_with_requested_networks_duplicates(self):
|
||||
# specify a duplicate network to allocate to instance
|
||||
self.flags(allow_duplicate_networks=True, group='neutron')
|
||||
requested_networks = [
|
||||
(net['id'], None, None)
|
||||
for net in (self.nets6[0], self.nets6[1])]
|
||||
self._allocate_for_instance(net_idx=6,
|
||||
requested_networks=requested_networks)
|
||||
|
||||
def test_allocate_for_instance_requested_networks_duplicates_port(self):
|
||||
# specify first port and last port that are in same network
|
||||
self.flags(allow_duplicate_networks=True, group='neutron')
|
||||
requested_networks = [
|
||||
(None, None, port['id'])
|
||||
for port in (self.port_data1[0], self.port_data3[0])]
|
||||
self._allocate_for_instance(net_idx=6,
|
||||
requested_networks=requested_networks)
|
||||
|
||||
def test_allocate_for_instance_requested_networks_duplicates_combo(self):
|
||||
# specify a combo net_idx=7 : net2, port in net1, net2, port in net1
|
||||
self.flags(allow_duplicate_networks=True, group='neutron')
|
||||
requested_networks = [
|
||||
('my_netid2', None, None),
|
||||
(None, None, self.port_data1[0]['id']),
|
||||
('my_netid2', None, None),
|
||||
(None, None, self.port_data3[0]['id'])]
|
||||
self._allocate_for_instance(net_idx=7,
|
||||
requested_networks=requested_networks)
|
||||
|
||||
def test_validate_networks_not_specified(self):
|
||||
requested_networks = []
|
||||
|
@ -1315,7 +1435,41 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
api.validate_networks,
|
||||
self.context, requested_networks, 1)
|
||||
|
||||
def test_validate_networks_ports_in_same_network(self):
|
||||
def test_validate_networks_ports_in_same_network_disable(self):
|
||||
"""Verify that duplicateNetworks exception is thrown when ports on same
|
||||
duplicate network are passed to validate_networks, when nova config
|
||||
flag allow_duplicate_networks is set to its default False
|
||||
"""
|
||||
self.flags(allow_duplicate_networks=False, group='neutron')
|
||||
port_a = self.port_data3[0]
|
||||
port_a['fixed_ips'] = {'ip_address': '10.0.0.2',
|
||||
'subnet_id': 'subnet_id'}
|
||||
port_b = self.port_data1[0]
|
||||
self.assertEqual(port_a['network_id'], port_b['network_id'])
|
||||
for port in [port_a, port_b]:
|
||||
port['device_id'] = None
|
||||
port['device_owner'] = None
|
||||
|
||||
requested_networks = [(None, None, port_a['id']),
|
||||
(None, None, port_b['id'])]
|
||||
self.moxed_client.show_port(port_a['id']).AndReturn(
|
||||
{'port': port_a})
|
||||
self.moxed_client.show_port(port_b['id']).AndReturn(
|
||||
{'port': port_b})
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
api = neutronapi.API()
|
||||
self.assertRaises(exception.NetworkDuplicated,
|
||||
api.validate_networks,
|
||||
self.context, requested_networks, 1)
|
||||
|
||||
def test_validate_networks_ports_in_same_network_enable(self):
|
||||
"""Verify that duplicateNetworks exception is not thrown when ports
|
||||
on same duplicate network are passed to validate_networks, when nova
|
||||
config flag allow_duplicate_networks is set to its True
|
||||
"""
|
||||
self.flags(allow_duplicate_networks=True, group='neutron')
|
||||
port_a = self.port_data3[0]
|
||||
port_a['fixed_ips'] = {'ip_address': '10.0.0.2',
|
||||
'subnet_id': 'subnet_id'}
|
||||
|
@ -1327,15 +1481,15 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||
|
||||
requested_networks = [(None, None, port_a['id']),
|
||||
(None, None, port_b['id'])]
|
||||
self.moxed_client.show_port(port_a['id']).AndReturn({'port': port_a})
|
||||
self.moxed_client.show_port(port_b['id']).AndReturn({'port': port_b})
|
||||
self.moxed_client.show_port(port_a['id']).AndReturn(
|
||||
{'port': port_a})
|
||||
self.moxed_client.show_port(port_b['id']).AndReturn(
|
||||
{'port': port_b})
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
api = neutronapi.API()
|
||||
self.assertRaises(exception.NetworkDuplicated,
|
||||
api.validate_networks,
|
||||
self.context, requested_networks, 1)
|
||||
api.validate_networks(self.context, requested_networks, 1)
|
||||
|
||||
def test_validate_networks_ports_not_in_same_network(self):
|
||||
port_a = self.port_data3[0]
|
||||
|
|
Loading…
Reference in New Issue