diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-08-15 16:50:45 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-08-15 16:50:45 +0000 |
| commit | 6f924bbeb0dd66f3c5ba2465099f23069d2cacf2 (patch) | |
| tree | 0d103f3066904d97e9f6c307c10bfc2bfbcc38f9 | |
| parent | 35c12feb8c9467b9b4a7eac7a3f3d63bd620a35b (diff) | |
| parent | 51ad3d4ee9f28184510a2802867535284c0f1b8b (diff) | |
Merge "Adding port attribute in network parameter of boot."
| -rw-r--r-- | nova/api/openstack/compute/servers.py | 49 | ||||
| -rw-r--r-- | nova/exception.py | 12 | ||||
| -rw-r--r-- | nova/network/quantumv2/api.py | 67 | ||||
| -rw-r--r-- | nova/tests/network/test_quantumv2.py | 71 |
4 files changed, 161 insertions, 38 deletions
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 99d48d8a6..0c5a2e530 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -197,6 +197,8 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer): item["uuid"] = network_node.getAttribute("uuid") if network_node.hasAttribute("fixed_ip"): item["fixed_ip"] = network_node.getAttribute("fixed_ip") + if network_node.hasAttribute("port"): + item["port"] = network_node.getAttribute("port") networks.append(item) return networks else: @@ -498,14 +500,31 @@ class Controller(wsgi.Controller): injected_files.append((path, contents)) return injected_files + def _is_quantum_v2(self): + return FLAGS.network_api_class ==\ + "nova.network.quantumv2.api.API" + def _get_requested_networks(self, requested_networks): """Create a list of requested networks from the networks attribute.""" networks = [] for network in requested_networks: try: - network_uuid = network['uuid'] + port_id = network.get('port', None) + if port_id: + network_uuid = None + if not self._is_quantum_v2(): + # port parameter is only for qunatum v2.0 + msg = _("Unknown argment : port") + raise exc.HTTPBadRequest(explanation=msg) + if not utils.is_uuid_like(port_id): + msg = _("Bad port format: port uuid is " + "not in proper format " + "(%s)") % port_id + raise exc.HTTPBadRequest(explanation=msg) + else: + network_uuid = network['uuid'] - if not utils.is_uuid_like(network_uuid): + if not port_id and not utils.is_uuid_like(network_uuid): br_uuid = network_uuid.split('-', 1)[-1] if not utils.is_uuid_like(br_uuid): msg = _("Bad networks format: network uuid is " @@ -520,16 +539,22 @@ class Controller(wsgi.Controller): if address is not None and not utils.is_valid_ipv4(address): msg = _("Invalid fixed IP address (%s)") % address raise exc.HTTPBadRequest(explanation=msg) - # check if the network id is already present in the list, - # we don't want duplicate networks to be passed - # at the boot time - for id, ip in networks: - if id == network_uuid: - expl = (_("Duplicate networks (%s) are not allowed") % - network_uuid) - raise exc.HTTPBadRequest(explanation=expl) - - networks.append((network_uuid, address)) + + # For quantumv2, requestd_networks + # should be tuple of (network_uuid, fixed_ip, port_id) + if self._is_quantum_v2(): + networks.append((network_uuid, address, port_id)) + else: + # check if the network id is already present in the list, + # we don't want duplicate networks to be passed + # at the boot time + for id, ip in networks: + if id == network_uuid: + expl = (_("Duplicate networks" + " (%s) are not allowed") % + network_uuid) + raise exc.HTTPBadRequest(explanation=expl) + networks.append((network_uuid, address)) except KeyError as key: expl = _('Bad network format: missing %s') % key raise exc.HTTPBadRequest(explanation=expl) diff --git a/nova/exception.py b/nova/exception.py index 9beadd2df..86d3a59b2 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -588,10 +588,22 @@ class NetworkBusy(NovaException): message = _("Network %(network)s has active ports, cannot delete.") +class NetworkIsDuplicated(NovaException): + message = _("Network %(network)s is duplicated.") + + class DatastoreNotFound(NotFound): message = _("Could not find the datastore reference(s) which the VM uses.") +class PortInUse(NovaException): + message = _("Port %(port_id)s is still in use.") + + +class PortNotFound(NotFound): + message = _("Port %(port_id)s could not be found.") + + 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 ca5b44e25..be288f46e 100644 --- a/nova/network/quantumv2/api.py +++ b/nova/network/quantumv2/api.py @@ -62,6 +62,7 @@ class API(base.Base): def allocate_for_instance(self, context, instance, **kwargs): """Allocate all network resources for the instance.""" + quantum = quantumv2.get_client(context) LOG.debug(_('allocate_for_instance() for %s'), instance['display_name']) search_opts = {} @@ -76,28 +77,55 @@ class API(base.Base): # networks, add them to **search_opts # Tenant-only network only allowed so far requested_networks = kwargs.get('requested_networks') + ports = {} + fixed_ips = {} if requested_networks: - net_ids = [net_id for (net_id, _i) in requested_networks] + net_ids = [] + for network_id, fixed_ip, port_id in requested_networks: + if port_id: + port = quantum.show_port(port_id).get('port') + network_id = port['network_id'] + ports[network_id] = port + elif fixed_ip: + fixed_ips[network_id] = fixed_ip + net_ids.append(network_id) search_opts['id'] = net_ids - data = quantumv2.get_client(context).list_networks(**search_opts) + data = quantum.list_networks(**search_opts) nets = data.get('networks', []) + + touched_port_ids = [] created_port_ids = [] for network in nets: - port_req_body = {'port': {'network_id': network['id'], - 'admin_state_up': True, - 'device_id': instance['uuid'], - 'tenant_id': instance['project_id']}, - } + network_id = network['id'] + zone = 'compute:%s' % FLAGS.node_availability_zone + port_req_body = {'port': {'device_id': instance['uuid'], + 'device_owner': zone}} try: - created_port_ids.append( - quantumv2.get_client(context).create_port( - port_req_body)['port']['id']) + port = ports.get(network_id) + if port: + quantum.update_port(port['id'], port_req_body) + touched_port_ids.append(port['id']) + else: + if fixed_ips.get(network_id): + port_req_body['port']['fixed_ip'] = fixed_ip + port_req_body['port']['network_id'] = network_id + port_req_body['port']['admin_state_up'] = True + port_req_body['port']['tenant_id'] = instance['project_id'] + created_port_ids.append( + quantum.create_port(port_req_body)['port']['id']) except Exception: with excutils.save_and_reraise_exception(): + for port_id in touched_port_ids: + port_in_server = quantum.show_port(port_id).get('port') + if not port_in_server: + raise Exception('Port have already lost') + port_req_body = {'port': {'device_id': None}} + quantum.update_port(port_id, port_req_body) + for port_id in created_port_ids: try: - quantumv2.get_client(context).delete_port(port_id) + quantum.delete_port(port_id) except Exception as ex: msg = _("Fail to delete port %(portid)s with" " failure: %(exception)s") @@ -147,7 +175,22 @@ class API(base.Base): if not requested_networks: return search_opts = {"tenant_id": context.project_id} - net_ids = [net_id for (net_id, _i) in requested_networks] + net_ids = [] + + for (net_id, _i, port_id) in requested_networks: + if not port_id: + net_ids.append(net_id) + continue + port = quantumv2.get_client(context).show_port(port_id).get('port') + if not port: + raise exception.PortNotFound(port_id=port_id) + if port.get('device_id', None): + raise exception.PortInUse(port_id=port_id) + net_id = port['network_id'] + if net_id in net_ids: + raise exception.NetworkDuplicated(network_id=net_id) + net_ids.append(net_id) + search_opts['id'] = net_ids data = quantumv2.get_client(context).list_networks(**search_opts) nets = data.get('networks', []) diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py index 1f4d72462..7ee814b6b 100644 --- a/nova/tests/network/test_quantumv2.py +++ b/nova/tests/network/test_quantumv2.py @@ -159,6 +159,7 @@ class TestQuantumv2(test.TestCase): self.port_data1 = [{'network_id': 'my_netid1', 'device_id': 'device_id1', + 'device_owner': 'compute:nova', 'id': 'my_portid1', 'fixed_ips': [{'ip_address': '10.0.1.2', 'subnet_id': 'my_subid1'}], @@ -167,6 +168,7 @@ class TestQuantumv2(test.TestCase): self.port_data2.append(self.port_data1[0]) self.port_data2.append({'network_id': 'my_netid2', 'device_id': 'device_id2', + 'device_owner': 'compute:nova', 'id': 'my_portid2', 'fixed_ips': [{'ip_address': '10.0.2.2', 'subnet_id': 'my_subid2'}], @@ -262,8 +264,22 @@ class TestQuantumv2(test.TestCase): networks=nets).AndReturn(None) mox_list_network_params = dict(tenant_id=self.instance['project_id']) + ports = {} + fixed_ips = {} if 'requested_networks' in kwargs: - req_net_ids = [id for (id, _i) in kwargs['requested_networks']] + req_net_ids = [] + for 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'}}) + req_net_ids.append('my_netid1') + ports['my_netid1'] = self.port_data1[0] + id = 'my_netid1' + else: + fixed_ips[id] = fixed_ip + req_net_ids.append(id) + mox_list_network_params['id'] = [net['id'] for net in nets if net['id'] in req_net_ids] self.moxed_client.list_networks( @@ -272,15 +288,28 @@ class TestQuantumv2(test.TestCase): for network in nets: port_req_body = { 'port': { - 'network_id': network['id'], - 'admin_state_up': True, 'device_id': self.instance['uuid'], - 'tenant_id': self.instance['project_id'], + 'device_owner': 'compute:nova', }, } - port = {'id': 'portid_' + network['id']} - self.moxed_client.create_port( - MyComparator(port_req_body)).AndReturn({'port': port}) + port = ports.get(network['id'], None) + if port: + port_id = port['id'] + self.moxed_client.update_port(port_id, + MyComparator(port_req_body) + ).AndReturn( + {'port': port}) + else: + fixed_ip = fixed_ips.get(network['id']) + if fixed_ip: + port_req_body['port']['fixed_ip'] = fixed_ip + port_req_body['port']['network_id'] = network['id'] + port_req_body['port']['admin_state_up'] = True + port_req_body['port']['tenant_id'] = \ + self.instance['project_id'] + res_port = {'port': {'id': 'fake'}} + self.moxed_client.create_port( + MyComparator(port_req_body)).AndReturn(res_port) self.mox.ReplayAll() api.allocate_for_instance(self.context, self.instance, **kwargs) @@ -294,12 +323,23 @@ class TestQuantumv2(test.TestCase): def test_allocate_for_instance_with_requested_networks(self): # specify only first and last network - requested_networks = [(net['id'], object()) + requested_networks = [(net['id'], None, None) for net in (self.nets3[0], self.nets3[-1])] - self._allocate_for_instance(net_idx=3, requested_networks=requested_networks) + def test_allocate_for_instance_with_requested_networks_with_fixedip(self): + # specify only first and last network + requested_networks = [(self.nets1[0]['id'], '10.0.1.0/24', None)] + self._allocate_for_instance(net_idx=1, + 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) + def test_allocate_for_instance_ex1(self): """verify we will delete created ports if we fail to allocate all net resources. @@ -318,6 +358,7 @@ class TestQuantumv2(test.TestCase): 'network_id': network['id'], 'admin_state_up': True, 'device_id': self.instance['uuid'], + 'device_owner': 'compute:nova', 'tenant_id': self.instance['project_id'], }, } @@ -381,7 +422,8 @@ class TestQuantumv2(test.TestCase): self._deallocate_for_instance(2) def test_validate_networks(self): - requested_networks = [('my_netid1', 'test'), ('my_netid2', 'test2')] + requested_networks = [('my_netid1', 'test', None), + ('my_netid2', 'test2', None)] self.moxed_client.list_networks( id=mox.SameElementsAs(['my_netid1', 'my_netid2']), tenant_id=self.context.project_id).AndReturn( @@ -391,7 +433,8 @@ class TestQuantumv2(test.TestCase): api.validate_networks(self.context, requested_networks) def test_validate_networks_ex_1(self): - requested_networks = [('my_netid1', 'test'), ('my_netid2', 'test2')] + requested_networks = [('my_netid1', 'test', None), + ('my_netid2', 'test2', None)] self.moxed_client.list_networks( id=mox.SameElementsAs(['my_netid1', 'my_netid2']), tenant_id=self.context.project_id).AndReturn( @@ -404,9 +447,9 @@ class TestQuantumv2(test.TestCase): self.assertTrue("my_netid2" in str(ex)) def test_validate_networks_ex_2(self): - requested_networks = [('my_netid1', 'test'), - ('my_netid2', 'test2'), - ('my_netid3', 'test3')] + requested_networks = [('my_netid1', 'test', None), + ('my_netid2', 'test2', None), + ('my_netid3', 'test3', None)] self.moxed_client.list_networks( id=mox.SameElementsAs(['my_netid1', 'my_netid2', 'my_netid3']), tenant_id=self.context.project_id).AndReturn( |
