Adds tenant network support to the client
Modifies novaclient, changing the existing networks implementation to a more appropriate os-admin-networks namespace, and supplements with a tenant-base network extenion that lives under the os-networks namespace as a Nova API extension. Also removes from the duplicately named network test methods. Implements: blueprint tenant-networks Change-Id: I54c9f017b86fc413f1646c7bded8cebd94f6a287
This commit is contained in:
parent
7b124b8872
commit
dffd415fba
77
novaclient/v1_1/contrib/tenant_networks.py
Normal file
77
novaclient/v1_1/contrib/tenant_networks.py
Normal file
@ -0,0 +1,77 @@
|
||||
# Copyright 2013 OpenStack, LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from novaclient import base
|
||||
from novaclient import utils
|
||||
|
||||
|
||||
class TenantNetwork(base.Resource):
|
||||
def delete(self):
|
||||
self.manager.delete(network=self)
|
||||
|
||||
|
||||
class TenantNetworkManager(base.ManagerWithFind):
|
||||
resource_class = base.Resource
|
||||
|
||||
def list(self):
|
||||
return self._list('/os-tenant-networks', 'networks')
|
||||
|
||||
def get(self, network):
|
||||
return self._get('/os-tenant-networks/%s' % base.getid(network),
|
||||
'network')
|
||||
|
||||
def delete(self, network):
|
||||
self._delete('/os-tenant-networks/%s' % base.getid(network))
|
||||
|
||||
def create(self, label, cidr):
|
||||
body = {'network': {'label': label, 'cidr': cidr}}
|
||||
return self._create('/os-tenant-networks', body, 'network')
|
||||
|
||||
|
||||
@utils.arg('network_id', metavar='<network_id>', help='ID of network')
|
||||
def do_net(cs, args):
|
||||
"""
|
||||
Show a network
|
||||
"""
|
||||
network = cs.tenant_networks.get(args.network_id)
|
||||
utils.print_dict(network._info)
|
||||
|
||||
|
||||
def do_net_list(cs, args):
|
||||
"""
|
||||
List networks
|
||||
"""
|
||||
networks = cs.tenant_networks.list()
|
||||
utils.print_list(networks, ['ID', 'Label', 'CIDR'])
|
||||
|
||||
|
||||
@utils.arg('label', metavar='<network_label>',
|
||||
help='Network label (ex. my_new_network)')
|
||||
@utils.arg('cidr', metavar='<cidr>',
|
||||
help='IP block to allocate from (ex. 172.16.0.0/24 or '
|
||||
'2001:DB8::/64)')
|
||||
def do_net_create(cs, args):
|
||||
"""
|
||||
Create a network
|
||||
"""
|
||||
network = cs.tenant_networks.create(args.label, args.cidr)
|
||||
utils.print_dict(network._info)
|
||||
|
||||
|
||||
@utils.arg('network_id', metavar='<network_id>', help='ID of network')
|
||||
def do_net_delete(cs, args):
|
||||
"""
|
||||
Delete a network
|
||||
"""
|
||||
cs.tenant_networks.delete(args.network_id)
|
@ -18,6 +18,7 @@ Network interface.
|
||||
"""
|
||||
|
||||
from novaclient import base
|
||||
from novaclient import exceptions
|
||||
|
||||
|
||||
class Network(base.Resource):
|
||||
@ -55,7 +56,8 @@ class NetworkManager(base.ManagerWithFind):
|
||||
:param network: The ID of the :class:`Network` to get.
|
||||
:rtype: :class:`Network`
|
||||
"""
|
||||
return self._get("/os-networks/%s" % base.getid(network), "network")
|
||||
return self._get("/os-networks/%s" % base.getid(network),
|
||||
"network")
|
||||
|
||||
def delete(self, network):
|
||||
"""
|
||||
@ -107,11 +109,11 @@ class NetworkManager(base.ManagerWithFind):
|
||||
elif disassociate_host:
|
||||
body = {"disassociate_host": None}
|
||||
else:
|
||||
raise CommandError(
|
||||
raise exceptions.CommandError(
|
||||
"Must disassociate either host or project or both")
|
||||
|
||||
self.api.client.post("/os-networks/%s/action" % base.getid(network),
|
||||
body=body)
|
||||
self.api.client.post("/os-networks/%s/action" %
|
||||
base.getid(network), body=body)
|
||||
|
||||
def associate_host(self, network, host):
|
||||
"""
|
||||
@ -120,7 +122,8 @@ class NetworkManager(base.ManagerWithFind):
|
||||
:param network: The ID of the :class:`Network`.
|
||||
:param host: The name of the host to associate the network with
|
||||
"""
|
||||
self.api.client.post("/os-networks/%s/action" % base.getid(network),
|
||||
self.api.client.post("/os-networks/%s/action" %
|
||||
base.getid(network),
|
||||
body={"associate_host": host})
|
||||
|
||||
def associate_project(self, network):
|
||||
|
44
tests/v1_1/contrib/fakes.py
Normal file
44
tests/v1_1/contrib/fakes.py
Normal file
@ -0,0 +1,44 @@
|
||||
# Copyright 2012 OpenStack, LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from novaclient.v1_1 import client
|
||||
from tests.v1_1 import fakes
|
||||
|
||||
|
||||
class FakeClient(fakes.FakeClient):
|
||||
def __init__(self, *args, **kwargs):
|
||||
client.Client.__init__(self, 'username', 'password',
|
||||
'project_id', 'auth_url',
|
||||
extensions=kwargs.get('extensions'))
|
||||
self.client = FakeHTTPClient(**kwargs)
|
||||
|
||||
|
||||
class FakeHTTPClient(fakes.FakeHTTPClient):
|
||||
def get_os_tenant_networks(self):
|
||||
return (200, {}, {'networks': [{"label": "1", "cidr": "10.0.0.0/24",
|
||||
'project_id': '4ffc664c198e435e9853f2538fbcd7a7',
|
||||
'id': '1'}]})
|
||||
|
||||
def get_os_tenant_networks_1(self, **kw):
|
||||
return (200, {}, {'network': {"label": "1", "cidr": "10.0.0.0/24",
|
||||
'project_id': '4ffc664c198e435e9853f2538fbcd7a7',
|
||||
'id': '1'}})
|
||||
|
||||
def post_os_tenant_networks(self, **kw):
|
||||
return (201, {}, {'network': {"label": "1", "cidr": "10.0.0.0/24",
|
||||
'project_id': '4ffc664c198e435e9853f2538fbcd7a7',
|
||||
'id': '1'}})
|
||||
|
||||
def delete_os_tenant_networks_1(self, **kw):
|
||||
return (204, {}, None)
|
50
tests/v1_1/contrib/test_tenant_networks.py
Normal file
50
tests/v1_1/contrib/test_tenant_networks.py
Normal file
@ -0,0 +1,50 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from novaclient import extension
|
||||
from novaclient.v1_1.contrib import tenant_networks
|
||||
|
||||
from tests import utils
|
||||
from tests.v1_1.contrib import fakes
|
||||
|
||||
|
||||
extensions = [
|
||||
extension.Extension(tenant_networks.__name__.split(".")[-1],
|
||||
tenant_networks),
|
||||
]
|
||||
cs = fakes.FakeClient(extensions=extensions)
|
||||
|
||||
|
||||
class TenantNetworkExtensionTests(utils.TestCase):
|
||||
def test_list_tenant_networks(self):
|
||||
nets = cs.tenant_networks.list()
|
||||
cs.assert_called('GET', '/os-tenant-networks')
|
||||
self.assertTrue(len(nets) > 0)
|
||||
|
||||
def test_get_tenant_network(self):
|
||||
net = cs.tenant_networks.get(1)
|
||||
cs.assert_called('GET', '/os-tenant-networks/1')
|
||||
print net
|
||||
|
||||
def test_create_tenant_networks(self):
|
||||
cs.tenant_networks.create(label="net",
|
||||
cidr="10.0.0.0/24")
|
||||
cs.assert_called('POST', '/os-tenant-networks')
|
||||
|
||||
def test_delete_tenant_networks(self):
|
||||
cs.tenant_networks.delete(1)
|
||||
cs.assert_called('DELETE', '/os-tenant-networks/1')
|
@ -16,8 +16,6 @@
|
||||
from datetime import datetime
|
||||
import urlparse
|
||||
|
||||
import requests
|
||||
|
||||
from novaclient import client as base_client
|
||||
from novaclient.v1_1 import client
|
||||
from tests import fakes
|
||||
@ -65,10 +63,6 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
# Note the call
|
||||
self.callstack.append((method, url, kwargs.get('body', None)))
|
||||
|
||||
if 'body' in kwargs:
|
||||
b = kwargs['body']
|
||||
else:
|
||||
b = ''
|
||||
status, headers, body = getattr(self, callback)(**kwargs)
|
||||
r = utils.TestResponse({
|
||||
"status_code": status,
|
||||
@ -656,9 +650,6 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
{'id': 1, 'fixed_ip': '10.0.0.1', 'ip': '11.0.0.1'}
|
||||
})
|
||||
|
||||
def post_os_floating_ips(self, body, **kw):
|
||||
return (202, {}, self.get_os_floating_ips_1()[1])
|
||||
|
||||
def post_os_floating_ips(self, body):
|
||||
if body.get('pool'):
|
||||
return (200, {}, {'floating_ip':
|
||||
@ -1289,14 +1280,11 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
'project_id': '4ffc664c198e435e9853f2538fbcd7a7',
|
||||
'id': '1'}]})
|
||||
|
||||
def get_os_networks_1(self, **kw):
|
||||
return (200, {}, {'network': {"label": "1", "cidr": "10.0.0.0/24"}})
|
||||
|
||||
def post_os_networks(self, **kw):
|
||||
return (202, {}, {'network': kw})
|
||||
|
||||
def post_os_networks_1_action(self, **kw):
|
||||
return (202, {}, None)
|
||||
def get_os_networks_1(self, **kw):
|
||||
return (200, {}, {'network': {"label": "1", "cidr": "10.0.0.0/24"}})
|
||||
|
||||
def delete_os_networks_networkdelete(self, **kw):
|
||||
return (202, {}, None)
|
||||
@ -1336,8 +1324,13 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
}
|
||||
)
|
||||
|
||||
def post_os_networks(self, **kw):
|
||||
return (202, {}, {'network': kw})
|
||||
def post_os_coverage_action(self, body, **kw):
|
||||
if 'report' not in body:
|
||||
return (200, {}, None)
|
||||
else:
|
||||
return (200, {}, {
|
||||
'path': '/tmp/tmpdir/' + body['report']['file']
|
||||
})
|
||||
|
||||
def post_os_networks_1_action(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
@ -31,7 +31,8 @@ class NetworksTest(utils.TestCase):
|
||||
|
||||
def test_associate_project(self):
|
||||
cs.networks.associate_project('networktest')
|
||||
cs.assert_called('POST', '/os-networks/add', {'id': 'networktest'})
|
||||
cs.assert_called('POST', '/os-networks/add',
|
||||
{'id': 'networktest'})
|
||||
|
||||
def test_associate_host(self):
|
||||
cs.networks.associate_host('networktest', 'testHost')
|
||||
@ -40,17 +41,20 @@ class NetworksTest(utils.TestCase):
|
||||
|
||||
def test_disassociate(self):
|
||||
cs.networks.disassociate('networkdisassociate')
|
||||
cs.assert_called('POST', '/os-networks/networkdisassociate/action',
|
||||
cs.assert_called('POST',
|
||||
'/os-networks/networkdisassociate/action',
|
||||
{'disassociate': None})
|
||||
|
||||
def test_disassociate_host_only(self):
|
||||
cs.networks.disassociate('networkdisassociate', True, False)
|
||||
cs.assert_called('POST', '/os-networks/networkdisassociate/action',
|
||||
cs.assert_called('POST',
|
||||
'/os-networks/networkdisassociate/action',
|
||||
{'disassociate_host': None})
|
||||
|
||||
def test_disassociate_project(self):
|
||||
cs.networks.disassociate('networkdisassociate', False, True)
|
||||
cs.assert_called('POST', '/os-networks/networkdisassociate/action',
|
||||
cs.assert_called('POST',
|
||||
'/os-networks/networkdisassociate/action',
|
||||
{'disassociate_project': None})
|
||||
|
||||
def test_add(self):
|
||||
|
@ -738,11 +738,6 @@ class ShellTest(utils.TestCase):
|
||||
body = {'id': "1"}
|
||||
self.assert_called('POST', '/os-networks/add', body)
|
||||
|
||||
def test_network_disassociate(self):
|
||||
self.run_command('network-disassociate 1')
|
||||
body = {'disassociate': None}
|
||||
self.assert_called('POST', '/os-networks/1/action', body)
|
||||
|
||||
def test_network_disassociate_host(self):
|
||||
self.run_command('network-disassociate --host-only 1 2')
|
||||
body = {'disassociate_host': None}
|
||||
@ -753,12 +748,6 @@ class ShellTest(utils.TestCase):
|
||||
body = {'disassociate_project': None}
|
||||
self.assert_called('POST', '/os-networks/2/action', body)
|
||||
|
||||
def test_network_create_v4(self):
|
||||
self.run_command('network-create --fixed-range-v4 10.0.1.0/24 \
|
||||
new_network')
|
||||
body = {'cidr': '10.0.1.0/24', 'label': 'new_network'}
|
||||
self.assert_called('POST', '/os-networks', body)
|
||||
|
||||
def test_network_create_v4(self):
|
||||
self.run_command('network-create --fixed-range-v4 10.0.1.0/24 \
|
||||
--dns1 10.0.1.254 new_network')
|
||||
|
Loading…
x
Reference in New Issue
Block a user