summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-08-15 01:27:45 +0000
committerGerrit Code Review <review@openstack.org>2012-08-15 01:27:45 +0000
commit0bc32cfef94dc2e45f86a0e526e3415ec5d4ca39 (patch)
treeef33778221b5d9d9a71774ce903929d58406de2b
parent76267f4d6268b3a39e46dbace140e15d874dadc5 (diff)
parent9af40c167879096a8f0f209bde4e6c5cc9295b86 (diff)
downloadnova-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.py35
-rw-r--r--nova/db/api.py4
-rw-r--r--nova/db/sqlalchemy/api.py11
-rw-r--r--nova/network/api.py5
-rw-r--r--nova/network/manager.py8
-rw-r--r--nova/network/quantumv2/api.py2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_networks.py53
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')