diff options
author | Jenkins <jenkins@review.openstack.org> | 2012-12-18 00:23:46 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2012-12-18 00:23:46 +0000 |
commit | 38fd49bb30a52415e670523052434ef1bae0fa94 (patch) | |
tree | 81d3e97544d2a0f52b078c1958d10d26cc66352a | |
parent | aaae75dc3568ba95d4db5478b1c92eec454356f4 (diff) | |
parent | 37d42caeab3a9e040291afecb5238b28028f566e (diff) | |
download | nova-38fd49bb30a52415e670523052434ef1bae0fa94.tar.gz nova-38fd49bb30a52415e670523052434ef1bae0fa94.tar.xz nova-38fd49bb30a52415e670523052434ef1bae0fa94.zip |
Merge "Add more association support to network API"
32 files changed, 310 insertions, 34 deletions
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json index 79211b946..b85fae2de 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.json +++ b/doc/api_samples/all_extensions/extensions-get-resp.json @@ -297,6 +297,14 @@ "updated": "2011-12-23T00:00:00+00:00" }, { + "alias": "os-networks-associate", + "description": "Network association support", + "links": [], + "name": "NetworkAssociationSupport", + "namespace": "http://docs.openstack.org/compute/ext/networks_associate/api/v2", + "updated": "2012-11-19T00:00:00+00:00" + }, + { "alias": "os-quota-class-sets", "description": "Quota classes management support", "links": [], diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml index 6c53c875b..049498fc4 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.xml +++ b/doc/api_samples/all_extensions/extensions-get-resp.xml @@ -125,6 +125,9 @@ <extension alias="os-networks" updated="2011-12-23T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/networks/api/v1.1" name="Networks"> <description>Admin-only Network Management Extension</description> </extension> + <extension alias="os-networks-associate" updated="2012-11-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/networks_associate/api/v2" name="NetworkAssociationSupport"> + <description>Network association support</description> + </extension> <extension alias="os-quota-class-sets" updated="2012-03-12T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1" name="QuotaClasses"> <description>Quota classes management support</description> </extension> diff --git a/doc/api_samples/os-networks-associate/network-associate-host-req.json b/doc/api_samples/os-networks-associate/network-associate-host-req.json new file mode 100644 index 000000000..a6487211e --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-associate-host-req.json @@ -0,0 +1,3 @@ +{ + "associate_host": "testHost" +}
\ No newline at end of file diff --git a/doc/api_samples/os-networks-associate/network-associate-host-req.xml b/doc/api_samples/os-networks-associate/network-associate-host-req.xml new file mode 100644 index 000000000..3221be61d --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-associate-host-req.xml @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='UTF-8'?> +<associate_host>testHost</associate_host>
\ No newline at end of file diff --git a/doc/api_samples/os-networks-associate/network-disassociate-host-req.json b/doc/api_samples/os-networks-associate/network-disassociate-host-req.json new file mode 100644 index 000000000..d6c5419fd --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-disassociate-host-req.json @@ -0,0 +1,3 @@ +{ + "disassociate_host": null +}
\ No newline at end of file diff --git a/doc/api_samples/os-networks-associate/network-disassociate-host-req.xml b/doc/api_samples/os-networks-associate/network-disassociate-host-req.xml new file mode 100644 index 000000000..3c2cc0d84 --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-disassociate-host-req.xml @@ -0,0 +1 @@ +<disassociate_host/>
\ No newline at end of file diff --git a/doc/api_samples/os-networks-associate/network-disassociate-project-req.json b/doc/api_samples/os-networks-associate/network-disassociate-project-req.json new file mode 100644 index 000000000..6c0e46730 --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-disassociate-project-req.json @@ -0,0 +1,3 @@ +{ + "disassociate_project": null +}
\ No newline at end of file diff --git a/doc/api_samples/os-networks-associate/network-disassociate-project-req.xml b/doc/api_samples/os-networks-associate/network-disassociate-project-req.xml new file mode 100644 index 000000000..be94feb9f --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-disassociate-project-req.xml @@ -0,0 +1 @@ +<disassociate_project/>
\ No newline at end of file diff --git a/doc/api_samples/os-networks-associate/network-disassociate-req.json b/doc/api_samples/os-networks-associate/network-disassociate-req.json new file mode 100644 index 000000000..66ab7cef0 --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-disassociate-req.json @@ -0,0 +1,3 @@ +{ + "disassociate": null +}
\ No newline at end of file diff --git a/doc/api_samples/os-networks-associate/network-disassociate-req.xml b/doc/api_samples/os-networks-associate/network-disassociate-req.xml new file mode 100644 index 000000000..bcad8e0a8 --- /dev/null +++ b/doc/api_samples/os-networks-associate/network-disassociate-req.xml @@ -0,0 +1 @@ +<disassociate/>
\ No newline at end of file diff --git a/etc/nova/policy.json b/etc/nova/policy.json index e5eb92c7c..d06430129 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -61,6 +61,7 @@ "compute_extension:multinic": "", "compute_extension:networks": "rule:admin_api", "compute_extension:networks:view": "", + "compute_extension:networks_associate": "rule:admin_api", "compute_extension:quotas:show": "", "compute_extension:quotas:update": "rule:admin_api", "compute_extension:quota_classes": "", diff --git a/nova/api/openstack/compute/contrib/networks.py b/nova/api/openstack/compute/contrib/networks.py index 0a494ea88..a45de72fe 100644 --- a/nova/api/openstack/compute/contrib/networks.py +++ b/nova/api/openstack/compute/contrib/networks.py @@ -21,6 +21,8 @@ import webob from webob import exc from nova.api.openstack import extensions +from nova.api.openstack import wsgi +from nova import db from nova import exception from nova import network from nova.openstack.common import log as logging @@ -52,35 +54,11 @@ def network_dict(context, network): return {} -class NetworkController(object): +class NetworkController(wsgi.Controller): def __init__(self, network_api=None): self.network_api = network_api or network.API() - def action(self, req, id, body): - _actions = { - 'disassociate': self._disassociate, - } - - for action, data in body.iteritems(): - try: - return _actions[action](req, id, body) - except KeyError: - msg = _("Network does not have %s action") % action - raise exc.HTTPBadRequest(explanation=msg) - - raise exc.HTTPBadRequest(explanation=_("Invalid request body")) - - def _disassociate(self, request, network_id, body): - context = request.environ['nova.context'] - authorize(context) - LOG.debug(_("Disassociating network with id %s"), network_id) - try: - self.network_api.disassociate(context, network_id) - except exception.NetworkNotFound: - raise exc.HTTPNotFound(_("Network not found")) - return exc.HTTPAccepted() - def index(self, req): context = req.environ['nova.context'] authorize_view(context) @@ -88,6 +66,18 @@ class NetworkController(object): result = [network_dict(context, net_ref) for net_ref in networks] return {'networks': result} + @wsgi.action("disassociate") + def _disassociate_host_and_project(self, req, id, body): + context = req.environ['nova.context'] + authorize(context) + LOG.debug(_("Disassociating network with id %s"), id) + + try: + self.network_api.associate(context, id, host=None, project=None) + except exception.NetworkNotFound: + raise exc.HTTPNotFound(_("Network not found")) + return exc.HTTPAccepted() + def show(self, req, id): context = req.environ['nova.context'] authorize_view(context) diff --git a/nova/api/openstack/compute/contrib/networks_associate.py b/nova/api/openstack/compute/contrib/networks_associate.py new file mode 100644 index 000000000..a923c769d --- /dev/null +++ b/nova/api/openstack/compute/contrib/networks_associate.py @@ -0,0 +1,69 @@ +import netaddr +import webob +from webob import exc + +from nova.api.openstack import extensions +from nova.api.openstack import wsgi +from nova import exception +from nova import network +from nova.openstack.common import log as logging + +LOG = logging.getLogger(__name__) +authorize = extensions.extension_authorizer('compute', 'networks_associate') + + +class NetworkAssociateActionController(wsgi.Controller): + """Network Association API Controller.""" + + def __init__(self, network_api=None): + self.network_api = network_api or network.API() + + @wsgi.action("disassociate_host") + def _disassociate_host_only(self, req, id, body): + context = req.environ['nova.context'] + authorize(context) + LOG.debug(_("Disassociating host with network with id %s"), id) + try: + self.network_api.associate(context, id, host=None) + except exception.NetworkNotFound: + raise exc.HTTPNotFound(_("Network not found")) + return exc.HTTPAccepted() + + @wsgi.action("disassociate_project") + def _disassociate_project_only(self, req, id, body): + context = req.environ['nova.context'] + authorize(context) + LOG.debug(_("Disassociating project with network with id %s"), id) + try: + self.network_api.associate(context, id, project=None) + except exception.NetworkNotFound: + raise exc.HTTPNotFound(_("Network not found")) + return exc.HTTPAccepted() + + @wsgi.action("associate_host") + def _associate_host(self, req, id, body): + context = req.environ['nova.context'] + authorize(context) + + try: + self.network_api.associate(context, id, + host=body['associate_host']) + except exception.NetworkNotFound: + raise exc.HTTPNotFound(_("Network not found")) + return exc.HTTPAccepted() + + +class Networks_associate(extensions.ExtensionDescriptor): + """Network association support""" + + name = "NetworkAssociationSupport" + alias = "os-networks-associate" + namespace = ("http://docs.openstack.org/compute/ext/" + "networks_associate/api/v2") + updated = "2012-11-19T00:00:00+00:00" + + def get_controller_extensions(self): + extension = extensions.ControllerExtension( + self, 'os-networks', NetworkAssociateActionController()) + + return [extension] diff --git a/nova/db/api.py b/nova/db/api.py index 67d8e7618..4acff8a99 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -785,9 +785,12 @@ def network_delete_safe(context, network_id): return IMPL.network_delete_safe(context, network_id) -def network_disassociate(context, network_id): - """Disassociate the network from project or raise if it does not exist.""" - return IMPL.network_disassociate(context, network_id) +def network_disassociate(context, network_id, disassociate_host=True, + disassociate_project=True): + """Disassociate the network from project or host and raise if it does + not exist.""" + return IMPL.network_disassociate(context, network_id, disassociate_host, + disassociate_project) def network_get(context, network_id, project_only="allow_none"): diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 29c40bb69..ec85ddcef 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2135,9 +2135,14 @@ def network_delete_safe(context, network_id): @require_admin_context -def network_disassociate(context, network_id): - network_update(context, network_id, {'project_id': None, - 'host': None}) +def network_disassociate(context, network_id, disassociate_host, + disassociate_project): + net_update = {} + if disassociate_project: + net_update['project_id'] = None + if disassociate_host: + net_update['host'] = None + network_update(context, network_id, net_update) @require_context diff --git a/nova/network/api.py b/nova/network/api.py index db8b87268..beee802c1 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -82,6 +82,8 @@ def update_instance_cache_with_nw_info(api, context, instance, class API(base.Base): """API for interacting with the network manager.""" + _sentinel = object() + def __init__(self, **kwargs): self.network_rpcapi = network_rpcapi.NetworkAPI() super(API, self).__init__(**kwargs) @@ -232,6 +234,16 @@ class API(base.Base): self.network_rpcapi.add_network_to_project(context, project_id, network_uuid) + def associate(self, context, network_uuid, host=_sentinel, + project=_sentinel): + """Associate or disassociate host or project to network""" + associations = {} + if host is not API._sentinel: + associations['host'] = host + if project is not API._sentinel: + associations['project'] = project + self.network_rpcapi.associate(context, network_uuid, associations) + @refresh_cache def get_instance_nw_info(self, context, instance): """Returns all network info related to an instance.""" diff --git a/nova/network/manager.py b/nova/network/manager.py index d916d3fb7..cea7f6dc3 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -887,7 +887,7 @@ class NetworkManager(manager.SchedulerDependentManager): The one at a time part is to flatten the layout to help scale """ - RPC_API_VERSION = '1.4' + RPC_API_VERSION = '1.5' # If True, this manager requires VIF to create a bridge. SHOULD_CREATE_BRIDGE = False @@ -2210,6 +2210,27 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): network_id = None self.db.network_associate(context, project_id, network_id, force=True) + @wrap_check_policy + def associate(self, context, network_uuid, associations): + """Associate or disassociate host or project to network.""" + network_id = self.get_network(context, network_uuid)['id'] + if 'host' in associations: + host = associations['host'] + if host is None: + self.db.network_disassociate(context, network_id, + disassociate_host=True, + disassociate_project=False) + else: + self.db.network_set_host(context, network_id, host) + if 'project' in associations: + project = associations['project'] + if project is None: + self.db.network_disassociate(context, network_id, + disassociate_host=False, + disassociate_project=True) + else: + self.db.network_associate(context, project, network_id, True) + def _get_network_by_id(self, context, network_id): # NOTE(vish): Don't allow access to networks with project_id=None as # these are networksa that haven't been allocated to a diff --git a/nova/network/rpcapi.py b/nova/network/rpcapi.py index f7bc02d84..8ee1ce443 100644 --- a/nova/network/rpcapi.py +++ b/nova/network/rpcapi.py @@ -37,6 +37,7 @@ class NetworkAPI(rpc_proxy.RpcProxy): 1.2 - Make migrate_instance_[start|finish] a little more flexible 1.3 - Adds fanout cast update_dns for multi_host networks 1.4 - Add get_backdoor_port() + 1.5 - Adds associate ''' # @@ -163,6 +164,11 @@ class NetworkAPI(rpc_proxy.RpcProxy): return self.call(ctxt, self.make_msg('add_network_to_project', project_id=project_id, network_uuid=network_uuid)) + def associate(self, ctxt, network_uuid, associations): + return self.call(ctxt, self.make_msg('associate', + network_uuid=network_uuid, associations=associations), + self.topic, version="1.5") + def get_instance_nw_info(self, ctxt, instance_id, instance_uuid, rxtx_factor, host, project_id): return self.call(ctxt, self.make_msg('get_instance_nw_info', diff --git a/nova/tests/api/openstack/compute/contrib/test_networks.py b/nova/tests/api/openstack/compute/contrib/test_networks.py index a50e8d89e..367e61910 100644 --- a/nova/tests/api/openstack/compute/contrib/test_networks.py +++ b/nova/tests/api/openstack/compute/contrib/test_networks.py @@ -23,6 +23,9 @@ import uuid import webob from nova.api.openstack.compute.contrib import networks +from nova.api.openstack.compute.contrib import networks_associate +from nova import config +from nova import db from nova import exception from nova.openstack.common import cfg from nova import test @@ -93,6 +96,8 @@ NEW_NETWORK = { class FakeNetworkAPI(object): + _sentinel = object() + def __init__(self): self.networks = copy.deepcopy(FAKE_NETWORKS) @@ -110,6 +115,17 @@ class FakeNetworkAPI(object): return True raise exception.NetworkNotFound() + def associate(self, context, network_uuid, host=_sentinel, + project=_sentinel): + for network in self.networks: + if network.get('uuid') == network_uuid: + if host is not FakeNetworkAPI._sentinel: + network['host'] = host + if project is not FakeNetworkAPI._sentinel: + network['project_id'] = project + return True + raise exception.NetworkNotFound() + def add_network_to_project(self, context, project_id, network_uuid=None): if network_uuid: @@ -165,6 +181,8 @@ class NetworksTest(test.TestCase): super(NetworksTest, self).setUp() self.fake_network_api = FakeNetworkAPI() self.controller = networks.NetworkController(self.fake_network_api) + self.associate_controller = networks_associate\ + .NetworkAssociateActionController(self.fake_network_api) fakes.stub_out_networking(self.stubs) fakes.stub_out_rate_limiting(self.stubs) @@ -194,13 +212,35 @@ class NetworksTest(test.TestCase): def test_network_disassociate(self): uuid = FAKE_NETWORKS[0]['uuid'] req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s/action' % uuid) - res = self.controller.action(req, uuid, {'disassociate': None}) + res = self.controller._disassociate_host_and_project( + req, uuid, {'disassociate': None}) self.assertEqual(res.status_int, 202) + self.assertEqual(self.fake_network_api.networks[0]['project_id'], None) + self.assertEqual(self.fake_network_api.networks[0]['host'], None) + + def test_network_disassociate_host_only(self): + uuid = FAKE_NETWORKS[0]['uuid'] + req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s/action' % uuid) + res = self.associate_controller._disassociate_host_only( + req, uuid, {'disassociate_host': None}) + self.assertEqual(res.status_int, 202) + self.assertNotEqual(self.fake_network_api.networks[0]['project_id'], + None) + self.assertEqual(self.fake_network_api.networks[0]['host'], None) + + def test_network_disassociate_project_only(self): + uuid = FAKE_NETWORKS[0]['uuid'] + req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s/action' % uuid) + res = self.associate_controller._disassociate_project_only( + req, uuid, {'disassociate_project': None}) + self.assertEqual(res.status_int, 202) + self.assertEqual(self.fake_network_api.networks[0]['project_id'], None) + self.assertNotEqual(self.fake_network_api.networks[0]['host'], None) def test_network_disassociate_not_found(self): req = fakes.HTTPRequest.blank('/v2/1234/os-networks/100/action') self.assertRaises(webob.exc.HTTPNotFound, - self.controller.action, + self.controller._disassociate_host_and_project, req, 100, {'disassociate': None}) def test_network_get_as_user(self): @@ -246,6 +286,17 @@ class NetworksTest(test.TestCase): res_dict = self.controller.show(req, uuid) self.assertEqual(res_dict['network']['project_id'], 'fake') + def test_network_associate_with_host(self): + uuid = FAKE_NETWORKS[1]['uuid'] + req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s/action' % uuid) + res = self.associate_controller._associate_host( + req, uuid, {'associate_host': "TestHost"}) + 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']['host'], 'TestHost') + def test_network_create(self): req = fakes.HTTPRequest.blank('/v2/1234/os-networks') res_dict = self.controller.create(req, NEW_NETWORK) diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py index 3823a77b0..9c1140922 100644 --- a/nova/tests/fake_policy.py +++ b/nova/tests/fake_policy.py @@ -137,6 +137,7 @@ policy_data = """ "compute_extension:multinic": "", "compute_extension:networks": "", "compute_extension:networks:view": "", + "compute_extension:networks_associate": "", "compute_extension:quotas:show": "", "compute_extension:quotas:update": "", "compute_extension:quota_classes": "", diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index efd6893bb..4a8d96844 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -305,6 +305,14 @@ "updated": "%(timestamp)s" }, { + "alias": "os-networks-associate", + "description": "%(text)s", + "links": [], + "name": "NetworkAssociationSupport", + "namespace": "http://docs.openstack.org/compute/ext/networks_associate/api/v2", + "updated": "%(timestamp)s" + }, + { "alias": "os-quota-class-sets", "description": "%(text)s", "links": [], diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index ee957be90..7d4683986 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -114,6 +114,9 @@ <extension alias="os-networks" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/networks/api/v1.1" name="Networks"> <description>%(text)s</description> </extension> + <extension alias="os-networks-associate" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/networks_associate/api/v2" name="NetworkAssociationSupport"> + <description>%(text)s</description> + </extension> <extension alias="os-quota-class-sets" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1" name="QuotaClasses"> <description>%(text)s</description> </extension> diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-associate-host-req.json.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-associate-host-req.json.tpl new file mode 100644 index 000000000..762e88175 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-associate-host-req.json.tpl @@ -0,0 +1,3 @@ +{ + "associate_host": "%(host)s" +} diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-associate-host-req.xml.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-associate-host-req.xml.tpl new file mode 100644 index 000000000..7c96c96a1 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-associate-host-req.xml.tpl @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='UTF-8'?> +<associate_host>%(host)s</associate_host> diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-host-req.json.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-host-req.json.tpl new file mode 100644 index 000000000..46f69b3e8 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-host-req.json.tpl @@ -0,0 +1,3 @@ +{ + "disassociate_host": null +} diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-host-req.xml.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-host-req.xml.tpl new file mode 100644 index 000000000..910504a44 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-host-req.xml.tpl @@ -0,0 +1 @@ +<disassociate_host/> diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-project-req.json.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-project-req.json.tpl new file mode 100644 index 000000000..63b6eb683 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-project-req.json.tpl @@ -0,0 +1,3 @@ +{ + "disassociate_project": null +} diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-project-req.xml.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-project-req.xml.tpl new file mode 100644 index 000000000..d4162c19e --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-project-req.xml.tpl @@ -0,0 +1 @@ +<disassociate_project/> diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-req.json.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-req.json.tpl new file mode 100644 index 000000000..2e09d15a6 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-req.json.tpl @@ -0,0 +1,3 @@ +{ + "disassociate": null +} diff --git a/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-req.xml.tpl b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-req.xml.tpl new file mode 100644 index 000000000..c26f7b61a --- /dev/null +++ b/nova/tests/integrated/api_samples/os-networks-associate/network-disassociate-req.xml.tpl @@ -0,0 +1 @@ +<disassociate/> diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 8b78d3b51..49ff77306 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -30,6 +30,7 @@ from nova.compute import api from nova import context from nova import db from nova.db.sqlalchemy import models +from nova.network import api from nova.network.manager import NetworkManager from nova.openstack.common import cfg from nova.openstack.common import importutils @@ -2048,3 +2049,56 @@ class DiskConfigJsonTest(ServersSampleBase): class DiskConfigXmlTest(DiskConfigJsonTest): ctype = 'xml' + + +class NetworksAssociateJsonTests(ApiSampleTestBase): + extension_name = ("nova.api.openstack.compute.contrib" + ".networks_associate.Networks_associate") + + _sentinel = object() + + def _get_flags(self): + f = super(NetworksAssociateJsonTests, self)._get_flags() + f['osapi_compute_extension'] = CONF.osapi_compute_extension[:] + # Networks_associate requires Networks to be update + f['osapi_compute_extension'].append( + 'nova.api.openstack.compute.contrib.networks.Networks') + return f + + def setUp(self): + super(NetworksAssociateJsonTests, self).setUp() + + def fake_associate(self, context, network_id, + host=NetworksAssociateJsonTests._sentinel, + project=NetworksAssociateJsonTests._sentinel): + return True + + self.stubs.Set(api.API, "associate", fake_associate) + + def test_disassociate(self): + response = self._do_post('os-networks/1/action', + 'network-disassociate-req', + {}) + self.assertEqual(response.status, 202) + + def test_disassociate_host(self): + response = self._do_post('os-networks/1/action', + 'network-disassociate-host-req', + {}) + self.assertEqual(response.status, 202) + + def test_disassociate_project(self): + response = self._do_post('os-networks/1/action', + 'network-disassociate-project-req', + {}) + self.assertEqual(response.status, 202) + + def test_associate_host(self): + response = self._do_post('os-networks/1/action', + 'network-associate-host-req', + {"host": "testHost"}) + self.assertEqual(response.status, 202) + + +class NetworksAssociateXmlTests(NetworksAssociateJsonTests): + ctype = 'xml' diff --git a/nova/tests/network/test_rpcapi.py b/nova/tests/network/test_rpcapi.py index dd6cccf0f..2ded5230d 100644 --- a/nova/tests/network/test_rpcapi.py +++ b/nova/tests/network/test_rpcapi.py @@ -92,6 +92,13 @@ class NetworkRpcAPITestCase(test.TestCase): self._test_network_api('disassociate_network', rpc_method='call', network_uuid='fake_uuid') + def test_associate_host_and_project(self): + self._test_network_api('associate', rpc_method='call', + network_uuid='fake_uuid', + associations={'host': "testHost", + 'project': 'testProject'}, + version="1.5") + def test_get_fixed_ip(self): self._test_network_api('get_fixed_ip', rpc_method='call', id='id') |