diff options
| author | Robert Collins <robertc@robertcollins.net> | 2013-01-16 09:37:39 +1300 |
|---|---|---|
| committer | Robert Collins <robertc@robertcollins.net> | 2013-01-16 09:37:39 +1300 |
| commit | a3eaf784ad2f9103a010646aa2a13db6f09f3679 (patch) | |
| tree | bb6e363839037b491ade8377459b6c4c5c20d021 | |
| parent | 9670c932c913fccbca263713bd9cee1b5e149d1c (diff) | |
| download | nova-a3eaf784ad2f9103a010646aa2a13db6f09f3679.tar.gz nova-a3eaf784ad2f9103a010646aa2a13db6f09f3679.tar.xz nova-a3eaf784ad2f9103a010646aa2a13db6f09f3679.zip | |
Reject user ports that have MACs the hypervisor cannot use.
If a hypervisor has requested specific MAC addresses, ports requested
by the user have to be in that set of MAC addresses, or they cannot be
used. Raising an error at network allocation time is cleaner than
waiting for the hypervisor to attempt to plug its vifs and error.
Change-Id: If556cc518a01df658044e3ba6b9d7584bfabe588
| -rw-r--r-- | nova/exception.py | 4 | ||||
| -rw-r--r-- | nova/network/quantumv2/api.py | 7 | ||||
| -rw-r--r-- | nova/tests/network/test_quantumv2.py | 33 |
3 files changed, 36 insertions, 8 deletions
diff --git a/nova/exception.py b/nova/exception.py index f96b1eaf3..b16bc7669 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -522,6 +522,10 @@ class PortNotFound(NotFound): message = _("Port %(port_id)s could not be found.") +class PortNotUsable(NovaException): + message = _("Port %(port_id)s not usable for instance %(instance)s.") + + class FixedIpNotFound(NotFound): message = _("No fixed IP associated with id %(id)s.") diff --git a/nova/network/quantumv2/api.py b/nova/network/quantumv2/api.py index 8347ee94d..0deb3a4bb 100644 --- a/nova/network/quantumv2/api.py +++ b/nova/network/quantumv2/api.py @@ -113,6 +113,7 @@ class API(base.Base): with requested_networks which is user supplied). NB: QuantumV2 does not yet honour mac address limits. """ + hypervisor_macs = kwargs.get('macs', None) quantum = quantumv2.get_client(context) LOG.debug(_('allocate_for_instance() for %s'), instance['display_name']) @@ -127,7 +128,11 @@ class API(base.Base): if requested_networks: for network_id, fixed_ip, port_id in requested_networks: if port_id: - port = quantum.show_port(port_id).get('port') + port = quantum.show_port(port_id)['port'] + if hypervisor_macs is not None: + if port['mac_address'] not in hypervisor_macs: + raise exception.PortNotUsable(port_id=port_id, + instance=instance['display_name']) network_id = port['network_id'] ports[network_id] = port elif fixed_ip: diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py index f92dba443..876bce90d 100644 --- a/nova/tests/network/test_quantumv2.py +++ b/nova/tests/network/test_quantumv2.py @@ -342,15 +342,11 @@ class TestQuantumv2(test.TestCase): self.assertEquals('my_mac%s' % id_suffix, nw_inf[0]['address']) self.assertEquals(0, len(nw_inf[0]['network']['subnets'])) - def _allocate_for_instance(self, net_idx=1, **kwargs): + def _stub_allocate_for_instance(self, net_idx=1, **kwargs): api = quantumapi.API() self.mox.StubOutWithMock(api, 'get_instance_nw_info') # Net idx is 1-based for compatibility with existing unit tests nets = self.nets[net_idx - 1] - api.get_instance_nw_info(mox.IgnoreArg(), - self.instance, - networks=nets).AndReturn(None) - ports = {} fixed_ips = {} req_net_ids = [] @@ -359,7 +355,8 @@ class TestQuantumv2(test.TestCase): if port_id: self.moxed_client.show_port(port_id).AndReturn( {'port': {'id': 'my_portid1', - 'network_id': 'my_netid1'}}) + 'network_id': 'my_netid1', + 'mac_address': 'my_mac1'}}) ports['my_netid1'] = self.port_data1[0] id = 'my_netid1' else: @@ -368,6 +365,9 @@ class TestQuantumv2(test.TestCase): expected_network_order = req_net_ids else: expected_network_order = [n['id'] for n in nets] + if kwargs.get('_break_list_networks'): + self.mox.ReplayAll() + return api search_ids = [net['id'] for net in nets if net['id'] in req_net_ids] mox_list_network_params = dict(tenant_id=self.instance['project_id'], @@ -409,7 +409,15 @@ class TestQuantumv2(test.TestCase): res_port = {'port': {'id': 'fake'}} self.moxed_client.create_port( MyComparator(port_req_body)).AndReturn(res_port) + + api.get_instance_nw_info(mox.IgnoreArg(), + self.instance, + networks=nets).AndReturn(None) self.mox.ReplayAll() + return api + + def _allocate_for_instance(self, net_idx=1, **kwargs): + api = self._stub_allocate_for_instance(net_idx, **kwargs) api.allocate_for_instance(self.context, self.instance, **kwargs) def test_allocate_for_instance_1(self): @@ -428,6 +436,18 @@ class TestQuantumv2(test.TestCase): # The macs kwarg should be accepted, as a set. self._allocate_for_instance(1, macs=set(['ab:cd:ef:01:23:45'])) + def test_allocate_for_instance_mac_conflicting_requested_port(self): + # specify only first and last network + requested_networks = [(None, None, 'my_portid1')] + api = self._stub_allocate_for_instance( + net_idx=1, requested_networks=requested_networks, + macs=set(['unknown:mac']), + _break_list_networks=True) + self.assertRaises(exception.PortNotUsable, + api.allocate_for_instance, self.context, + self.instance, requested_networks=requested_networks, + macs=set(['unknown:mac'])) + def test_allocate_for_instance_with_requested_networks(self): # specify only first and last network requested_networks = [ @@ -443,7 +463,6 @@ class TestQuantumv2(test.TestCase): requested_networks=requested_networks) def test_allocate_for_instance_with_requested_networks_with_port(self): - # specify only first and last network requested_networks = [(None, None, 'myportid1')] self._allocate_for_instance(net_idx=1, requested_networks=requested_networks) |
