diff --git a/novaclient/v1_1/contrib/tenant_networks.py b/novaclient/v1_1/contrib/tenant_networks.py new file mode 100644 index 000000000..9f70634d9 --- /dev/null +++ b/novaclient/v1_1/contrib/tenant_networks.py @@ -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='', 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='', + help='Network label (ex. my_new_network)') +@utils.arg('cidr', metavar='', + 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='', help='ID of network') +def do_net_delete(cs, args): + """ + Delete a network + """ + cs.tenant_networks.delete(args.network_id) diff --git a/novaclient/v1_1/networks.py b/novaclient/v1_1/networks.py index 1d9496d40..b1fbb8886 100644 --- a/novaclient/v1_1/networks.py +++ b/novaclient/v1_1/networks.py @@ -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): diff --git a/tests/v1_1/contrib/fakes.py b/tests/v1_1/contrib/fakes.py new file mode 100644 index 000000000..dd7b889fe --- /dev/null +++ b/tests/v1_1/contrib/fakes.py @@ -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) diff --git a/tests/v1_1/contrib/test_tenant_networks.py b/tests/v1_1/contrib/test_tenant_networks.py new file mode 100644 index 000000000..0df914edc --- /dev/null +++ b/tests/v1_1/contrib/test_tenant_networks.py @@ -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') diff --git a/tests/v1_1/fakes.py b/tests/v1_1/fakes.py index 5cb6d2b4d..dbf7fc052 100644 --- a/tests/v1_1/fakes.py +++ b/tests/v1_1/fakes.py @@ -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) diff --git a/tests/v1_1/test_networks.py b/tests/v1_1/test_networks.py index d0af5471a..5481e908c 100644 --- a/tests/v1_1/test_networks.py +++ b/tests/v1_1/test_networks.py @@ -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): diff --git a/tests/v1_1/test_shell.py b/tests/v1_1/test_shell.py index a6903071c..1056c5bdb 100644 --- a/tests/v1_1/test_shell.py +++ b/tests/v1_1/test_shell.py @@ -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')