diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-08-15 01:27:45 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-08-15 01:27:45 +0000 |
| commit | 0bc32cfef94dc2e45f86a0e526e3415ec5d4ca39 (patch) | |
| tree | ef33778221b5d9d9a71774ce903929d58406de2b | |
| parent | 76267f4d6268b3a39e46dbace140e15d874dadc5 (diff) | |
| parent | 9af40c167879096a8f0f209bde4e6c5cc9295b86 (diff) | |
| download | nova-0bc32cfef94dc2e45f86a0e526e3415ec5d4ca39.tar.gz nova-0bc32cfef94dc2e45f86a0e526e3415ec5d4ca39.tar.xz nova-0bc32cfef94dc2e45f86a0e526e3415ec5d4ca39.zip | |
Merge "Implement network association in OS API"
| -rw-r--r-- | nova/api/openstack/compute/contrib/networks.py | 35 | ||||
| -rw-r--r-- | nova/db/api.py | 4 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/api.py | 11 | ||||
| -rw-r--r-- | nova/network/api.py | 5 | ||||
| -rw-r--r-- | nova/network/manager.py | 8 | ||||
| -rw-r--r-- | nova/network/quantumv2/api.py | 2 | ||||
| -rw-r--r-- | nova/tests/api/openstack/compute/contrib/test_networks.py | 53 |
7 files changed, 91 insertions, 27 deletions
diff --git a/nova/api/openstack/compute/contrib/networks.py b/nova/api/openstack/compute/contrib/networks.py index ece331fbb..fb1d3d77e 100644 --- a/nova/api/openstack/compute/contrib/networks.py +++ b/nova/api/openstack/compute/contrib/networks.py @@ -17,6 +17,7 @@ # under the License. +import webob from webob import exc from nova.api.openstack import extensions @@ -113,6 +114,31 @@ class NetworkController(object): def create(self, req, id, body=None): raise exc.HTTPNotImplemented() + def add(self, req, body): + context = req.environ['nova.context'] + authorize(context) + if not body: + raise exc.HTTPUnprocessableEntity() + + network_id = body.get('id', None) + project_id = context.project_id + LOG.debug(_("Associating network %(network)s" + " with project %(project)s") % + {"network": network_id or "", + "project": project_id}) + try: + self.network_api.add_network_to_project( + context, project_id, network_id) + except Exception as ex: + msg = (_("Cannot associate network %(network)s" + " with project %(project)s: %(message)s") % + {"network": network_id or "", + "project": project_id, + "message": getattr(ex, "value", str(ex))}) + raise exc.HTTPBadRequest(explanation=msg) + + return webob.Response(status_int=202) + class Networks(extensions.ExtensionDescriptor): """Admin-only Network Management Extension""" @@ -124,7 +150,10 @@ class Networks(extensions.ExtensionDescriptor): def get_resources(self): member_actions = {'action': 'POST'} - res = extensions.ResourceExtension('os-networks', - NetworkController(), - member_actions=member_actions) + collection_actions = {'add': 'POST'} + res = extensions.ResourceExtension( + 'os-networks', + NetworkController(), + member_actions=member_actions, + collection_actions=collection_actions) return [res] diff --git a/nova/db/api.py b/nova/db/api.py index cbbc105c7..1df1e970c 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -779,9 +779,9 @@ def key_pair_count_by_user(context, user_id): #################### -def network_associate(context, project_id, force=False): +def network_associate(context, project_id, network_id=None, force=False): """Associate a free network to a project.""" - return IMPL.network_associate(context, project_id, force) + return IMPL.network_associate(context, project_id, network_id, force) def network_count(context): diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 63947cdb3..5adb633e6 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1993,7 +1993,7 @@ def key_pair_count_by_user(context, user_id): @require_admin_context -def network_associate(context, project_id, force=False): +def network_associate(context, project_id, network_id=None, force=False): """Associate a project with a network. called by project_get_networks under certain conditions @@ -2011,10 +2011,13 @@ def network_associate(context, project_id, force=False): session = get_session() with session.begin(): - def network_query(project_filter): + def network_query(project_filter, id=None): + filter_kwargs = {'project_id': project_filter} + if id is not None: + filter_kwargs['id'] = id return model_query(context, models.Network, session=session, read_deleted="no").\ - filter_by(project_id=project_filter).\ + filter_by(**filter_kwargs).\ with_lockmode('update').\ first() @@ -2027,7 +2030,7 @@ def network_associate(context, project_id, force=False): # with a new network # get new network - network_ref = network_query(None) + network_ref = network_query(None, network_id) if not network_ref: raise db.NoMoreNetworks() diff --git a/nova/network/api.py b/nova/network/api.py index ae230455f..daa41a2e7 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -278,11 +278,12 @@ class API(base.Base): {'method': 'remove_fixed_ip_from_instance', 'args': args}) - def add_network_to_project(self, context, project_id): + def add_network_to_project(self, context, project_id, network_uuid=None): """Force adds another network to a project.""" rpc.call(context, FLAGS.network_topic, {'method': 'add_network_to_project', - 'args': {'project_id': project_id}}) + 'args': {'project_id': project_id, + 'network_uuid': network_uuid}}) @refresh_cache def get_instance_nw_info(self, context, instance): diff --git a/nova/network/manager.py b/nova/network/manager.py index a79700dcd..470a186ee 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -1907,9 +1907,13 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): return address @wrap_check_policy - def add_network_to_project(self, context, project_id): + def add_network_to_project(self, context, project_id, network_uuid=None): """Force adds another network to a project.""" - self.db.network_associate(context, project_id, force=True) + if network_uuid is not None: + network_id = self.get_network(context, network_uuid)['id'] + else: + network_id = None + self.db.network_associate(context, project_id, network_id, force=True) def _get_networks_for_instance(self, context, instance_id, project_id, requested_networks=None): diff --git a/nova/network/quantumv2/api.py b/nova/network/quantumv2/api.py index 50042278b..ca5b44e25 100644 --- a/nova/network/quantumv2/api.py +++ b/nova/network/quantumv2/api.py @@ -244,7 +244,7 @@ class API(base.Base): it is associated with.""" raise NotImplementedError() - def add_network_to_project(self, context, project_id): + def add_network_to_project(self, context, project_id, network_uuid=None): """Force add a network to the project.""" raise NotImplementedError() diff --git a/nova/tests/api/openstack/compute/contrib/test_networks.py b/nova/tests/api/openstack/compute/contrib/test_networks.py index 91858f156..efbb7ceba 100644 --- a/nova/tests/api/openstack/compute/contrib/test_networks.py +++ b/nova/tests/api/openstack/compute/contrib/test_networks.py @@ -46,6 +46,7 @@ FAKE_NETWORKS = [ 'bridge': 'br101', 'vpn_public_port': 1001, 'dhcp_start': '10.0.0.11', 'bridge_interface': 'eth0', 'updated_at': None, 'id': 2, 'cidr_v6': None, + 'uuid': '20c8acc0-f747-4d71-a389-46d078ebf000', 'deleted_at': None, 'gateway': '10.0.0.9', 'label': 'mynet_1', 'project_id': None, 'vpn_private_address': '10.0.0.10', 'deleted': False, @@ -70,7 +71,7 @@ FAKE_USER_NETWORKS = [ 'id': 2, 'cidr': '10.0.0.10/29', 'netmask': '255.255.255.248', 'gateway': '10.0.0.9', 'broadcast': '10.0.0.15', 'dns1': None, 'dns2': None, 'cidr_v6': None, 'gateway_v6': None, 'label': 'mynet_1', - 'netmask_v6': None, + 'netmask_v6': None, 'uuid': '20c8acc0-f747-4d71-a389-46d078ebf000', }, ] @@ -87,13 +88,26 @@ class FakeNetworkAPI(object): return True raise exception.NetworkNotFoundForUUID() - #NOTE(bcwaldon): this does nothing other than check for existance - def disassociate(self, context, network_id): - for i, network in enumerate(self.networks): - if network.get('uuid') == network_id: + def disassociate(self, context, network_uuid): + for network in self.networks: + if network.get('uuid') == network_uuid: + network['project_id'] = None return True raise exception.NetworkNotFound() + def add_network_to_project(self, context, + project_id, network_uuid=None): + if network_uuid: + for network in self.networks: + if network.get('project_id', None) is None: + network['project_id'] = project_id + return + return + for network in self.networks: + if network.get('uuid') == network_uuid: + network['project_id'] = project_id + return + def get_all(self, context): return self.networks @@ -113,13 +127,18 @@ class NetworksTest(test.TestCase): fakes.stub_out_networking(self.stubs) fakes.stub_out_rate_limiting(self.stubs) + @staticmethod + def network_uuid_to_id(network): + network['id'] = network['uuid'] + del network['uuid'] + def test_network_list_all_as_user(self): self.maxDiff = None req = fakes.HTTPRequest.blank('/v2/1234/os-networks') res_dict = self.controller.index(req) expected = copy.deepcopy(FAKE_USER_NETWORKS) - expected[0]['id'] = expected[0]['uuid'] - del expected[0]['uuid'] + for network in expected: + self.network_uuid_to_id(network) self.assertEquals(res_dict, {'networks': expected}) def test_network_list_all_as_admin(self): @@ -127,8 +146,8 @@ class NetworksTest(test.TestCase): req.environ["nova.context"].is_admin = True res_dict = self.controller.index(req) expected = copy.deepcopy(FAKE_NETWORKS) - expected[0]['id'] = expected[0]['uuid'] - del expected[0]['uuid'] + for network in expected: + self.network_uuid_to_id(network) self.assertEquals(res_dict, {'networks': expected}) def test_network_disassociate(self): @@ -148,8 +167,7 @@ class NetworksTest(test.TestCase): req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s' % uuid) res_dict = self.controller.show(req, uuid) expected = {'network': copy.deepcopy(FAKE_USER_NETWORKS[0])} - expected['network']['id'] = expected['network']['uuid'] - del expected['network']['uuid'] + self.network_uuid_to_id(expected['network']) self.assertEqual(res_dict, expected) def test_network_get_as_admin(self): @@ -158,8 +176,7 @@ class NetworksTest(test.TestCase): req.environ["nova.context"].is_admin = True res_dict = self.controller.show(req, uuid) expected = {'network': copy.deepcopy(FAKE_NETWORKS[0])} - expected['network']['id'] = expected['network']['uuid'] - del expected['network']['uuid'] + self.network_uuid_to_id(expected['network']) self.assertEqual(res_dict, expected) def test_network_get_not_found(self): @@ -177,3 +194,13 @@ class NetworksTest(test.TestCase): req = fakes.HTTPRequest.blank('/v2/1234/os-networks/100') self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req, 100) + + def test_network_add(self): + uuid = FAKE_NETWORKS[1]['uuid'] + req = fakes.HTTPRequest.blank('/v2/1234/os-networks/add') + res = self.controller.add(req, {'id': uuid}) + self.assertEqual(res.status_int, 202) + req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s' % uuid) + req.environ["nova.context"].is_admin = True + res_dict = self.controller.show(req, uuid) + self.assertEqual(res_dict['network']['project_id'], 'fake') |
