Merge "Add more association support to network API"
This commit is contained in:
commit
38fd49bb30
@ -296,6 +296,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/networks/api/v1.1",
|
||||
"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",
|
||||
|
@ -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>
|
||||
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"associate_host": "testHost"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<associate_host>testHost</associate_host>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_host": null
|
||||
}
|
@ -0,0 +1 @@
|
||||
<disassociate_host/>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_project": null
|
||||
}
|
@ -0,0 +1 @@
|
||||
<disassociate_project/>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate": null
|
||||
}
|
@ -0,0 +1 @@
|
||||
<disassociate/>
|
@ -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": "",
|
||||
|
@ -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)
|
||||
|
69
nova/api/openstack/compute/contrib/networks_associate.py
Normal file
69
nova/api/openstack/compute/contrib/networks_associate.py
Normal file
@ -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]
|
@ -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"):
|
||||
|
@ -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
|
||||
|
@ -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."""
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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": "",
|
||||
|
@ -304,6 +304,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/networks/api/v1.1",
|
||||
"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",
|
||||
|
@ -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>
|
||||
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"associate_host": "%(host)s"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<associate_host>%(host)s</associate_host>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_host": null
|
||||
}
|
@ -0,0 +1 @@
|
||||
<disassociate_host/>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_project": null
|
||||
}
|
@ -0,0 +1 @@
|
||||
<disassociate_project/>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate": null
|
||||
}
|
@ -0,0 +1 @@
|
||||
<disassociate/>
|
@ -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'
|
||||
|
@ -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')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user