summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Wendlandt <dan@nicira.com>2012-08-21 01:54:17 -0700
committerGary Kotton <gkotton@redhat.com>2012-08-22 06:14:51 -0400
commit38abece8a6a82c722b00d8ea46997aacecb463a5 (patch)
tree8e8a8ecda33fa32346dac9ccd4f55e0b74a16ae2
parentf574f77731ed3ee2123c2b8f8572c50e30810c43 (diff)
downloadpython-neutronclient-38abece8a6a82c722b00d8ea46997aacecb463a5.tar.gz
initial client + CLI support for routers + floating ips
bp quantum-client-l3-floating-ip The task also does the following: 1. Fixes alignment of the --help output 2. Ensures that a show command prints a dictionary correctly Change-Id: Ib61b3e8748a7bd476ec008ab6ce20ab852e92f58
-rw-r--r--quantumclient/quantum/v2_0/__init__.py3
-rw-r--r--quantumclient/quantum/v2_0/floatingip.py133
-rw-r--r--quantumclient/quantum/v2_0/router.py186
-rw-r--r--quantumclient/shell.py32
-rw-r--r--quantumclient/tests/unit/test_cli20.py24
-rw-r--r--quantumclient/tests/unit/test_cli20_floatingips.py96
-rw-r--r--quantumclient/tests/unit/test_cli20_router.py151
-rw-r--r--quantumclient/v2_0/client.py108
8 files changed, 731 insertions, 2 deletions
diff --git a/quantumclient/quantum/v2_0/__init__.py b/quantumclient/quantum/v2_0/__init__.py
index 78c5339..f2a458c 100644
--- a/quantumclient/quantum/v2_0/__init__.py
+++ b/quantumclient/quantum/v2_0/__init__.py
@@ -412,6 +412,9 @@ class ShowCommand(QuantumCommand, show.ShowOne):
else:
value += str(_item)
data[self.resource][k] = value
+ elif isinstance(v, dict):
+ value = utils.dumps(v)
+ data[self.resource][k] = value
elif v is None:
data[self.resource][k] = ''
return zip(*sorted(data[self.resource].iteritems()))
diff --git a/quantumclient/quantum/v2_0/floatingip.py b/quantumclient/quantum/v2_0/floatingip.py
new file mode 100644
index 0000000..cd1437e
--- /dev/null
+++ b/quantumclient/quantum/v2_0/floatingip.py
@@ -0,0 +1,133 @@
+# 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.
+#
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import logging
+
+from quantumclient.quantum.v2_0 import CreateCommand
+from quantumclient.quantum.v2_0 import DeleteCommand
+from quantumclient.quantum.v2_0 import ListCommand
+from quantumclient.quantum.v2_0 import QuantumCommand
+from quantumclient.quantum.v2_0 import ShowCommand
+
+
+class ListFloatingIP(ListCommand):
+ """List floating ips that belong to a given tenant."""
+
+ resource = 'floatingip'
+ log = logging.getLogger(__name__ + '.ListFloatingIP')
+ _formatters = {}
+
+
+class ShowFloatingIP(ShowCommand):
+ """Show information of a given floating ip."""
+
+ resource = 'floatingip'
+ log = logging.getLogger(__name__ + '.ShowFloatingIP')
+
+
+class CreateFloatingIP(CreateCommand):
+ """Create a floating ip for a given tenant."""
+
+ resource = 'floatingip'
+ log = logging.getLogger(__name__ + '.CreateFloatingIP')
+
+ def add_known_arguments(self, parser):
+ parser.add_argument(
+ 'floating_network_id',
+ help='Network to allocate floating IP from')
+ parser.add_argument(
+ '--port_id',
+ help='ID of the port to be associated with the floatingip')
+ parser.add_argument(
+ '--fixed_ip_address',
+ help=('IP address on the port (only required if port has multiple'
+ 'IPs)'))
+
+ def args2body(self, parsed_args):
+ body = {'floatingip': {
+ 'floating_network_id': parsed_args.floating_network_id}}
+ if parsed_args.tenant_id:
+ body['floatingip'].update({'tenant_id': parsed_args.tenant_id})
+ return body
+
+
+class DeleteFloatingIP(DeleteCommand):
+ """Delete a given floating ip."""
+
+ log = logging.getLogger(__name__ + '.DeleteFloatingIP')
+ resource = 'floatingip'
+
+
+class AssociateFloatingIP(QuantumCommand):
+ """Create a mapping between a floating ip and a fixed ip."""
+
+ api = 'network'
+ log = logging.getLogger(__name__ + '.AssociateFloatingIP')
+ resource = 'floatingip'
+
+ def get_parser(self, prog_name):
+ parser = super(AssociateFloatingIP, self).get_parser(prog_name)
+ parser.add_argument(
+ 'floatingip_id', metavar='floatingip_id',
+ help='IP address of the floating IP to associate')
+ parser.add_argument(
+ 'port_id',
+ help='ID of the port to be associated with the floatingip')
+ parser.add_argument(
+ '--fixed_ip_address',
+ help=('IP address on the port (only required if port has multiple'
+ 'IPs)'))
+ return parser
+
+ def run(self, parsed_args):
+ self.log.debug('run(%s)' % parsed_args)
+ quantum_client = self.get_client()
+ quantum_client.format = parsed_args.request_format
+ update_dict = {}
+ if parsed_args.port_id:
+ update_dict['port_id'] = parsed_args.port_id
+ if parsed_args.fixed_ip_address:
+ update_dict['fixed_ip_address'] = parsed_args.fixed_ip_address
+ quantum_client.update_floatingip(parsed_args.floatingip_id,
+ {'floatingip': update_dict})
+ print >>self.app.stdout, (
+ _('Associated floatingip %s') % parsed_args.floatingip_id)
+
+
+class DisassociateFloatingIP(QuantumCommand):
+ """Remove a mapping from a floating ip to a fixed ip.
+ """
+
+ api = 'network'
+ log = logging.getLogger(__name__ + '.DisassociateFloatingIP')
+ resource = 'floatingip'
+
+ def get_parser(self, prog_name):
+ parser = super(DisassociateFloatingIP, self).get_parser(prog_name)
+ parser.add_argument(
+ 'floatingip_id', metavar='floatingip_id',
+ help='IP address of the floating IP to associate')
+ return parser
+
+ def run(self, parsed_args):
+ self.log.debug('run(%s)' % parsed_args)
+ quantum_client = self.get_client()
+ quantum_client.format = parsed_args.request_format
+ quantum_client.update_floatingip(parsed_args.floatingip_id,
+ {'floatingip': {'port_id': None}})
+ print >>self.app.stdout, (
+ _('Disassociated floatingip %s') % parsed_args.floatingip_id)
diff --git a/quantumclient/quantum/v2_0/router.py b/quantumclient/quantum/v2_0/router.py
new file mode 100644
index 0000000..06afa34
--- /dev/null
+++ b/quantumclient/quantum/v2_0/router.py
@@ -0,0 +1,186 @@
+# 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.
+#
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import logging
+
+from quantumclient.common import utils
+from quantumclient.quantum.v2_0 import CreateCommand
+from quantumclient.quantum.v2_0 import DeleteCommand
+from quantumclient.quantum.v2_0 import ListCommand
+from quantumclient.quantum.v2_0 import QuantumCommand
+from quantumclient.quantum.v2_0 import ShowCommand
+from quantumclient.quantum.v2_0 import UpdateCommand
+
+
+def _format_external_gateway_info(router):
+ try:
+ return utils.dumps(router['external_gateway_info'])
+ except Exception:
+ return ''
+
+
+class ListRouter(ListCommand):
+ """List routers that belong to a given tenant."""
+
+ resource = 'router'
+ log = logging.getLogger(__name__ + '.ListRouter')
+ _formatters = {'external_gateway_info': _format_external_gateway_info, }
+
+
+class ShowRouter(ShowCommand):
+ """Show information of a given router."""
+
+ resource = 'router'
+ log = logging.getLogger(__name__ + '.ShowRouter')
+
+
+class CreateRouter(CreateCommand):
+ """Create a router for a given tenant."""
+
+ resource = 'router'
+ log = logging.getLogger(__name__ + '.CreateRouter')
+
+ def add_known_arguments(self, parser):
+ parser.add_argument(
+ '--admin_state_down',
+ default=True, action='store_false',
+ help='Set Admin State Up to false')
+ parser.add_argument(
+ 'name', metavar='name',
+ help='Name of router to create')
+
+ def args2body(self, parsed_args):
+ body = {'router': {
+ 'name': parsed_args.name,
+ 'admin_state_up': parsed_args.admin_state_down, }, }
+ if parsed_args.tenant_id:
+ body['router'].update({'tenant_id': parsed_args.tenant_id})
+ return body
+
+
+class DeleteRouter(DeleteCommand):
+ """Delete a given router."""
+
+ log = logging.getLogger(__name__ + '.DeleteRouter')
+ resource = 'router'
+
+
+class UpdateRouter(UpdateCommand):
+ """Update router's information."""
+
+ log = logging.getLogger(__name__ + '.UpdateRouter')
+ resource = 'router'
+
+
+class RouterInterfaceCommand(QuantumCommand):
+ """Based class to Add/Remove router interface."""
+
+ api = 'network'
+ log = logging.getLogger(__name__ + '.AddInterfaceRouter')
+ resource = 'router'
+
+ def get_parser(self, prog_name):
+ parser = super(RouterInterfaceCommand, self).get_parser(prog_name)
+ parser.add_argument(
+ 'router_id', metavar='router_id',
+ help='ID of the router')
+ parser.add_argument(
+ 'subnet_id', metavar='subnet_id',
+ help='ID of the internal subnet for the interface')
+ return parser
+
+
+class AddInterfaceRouter(RouterInterfaceCommand):
+ """Add an internal network interface to a router."""
+
+ def run(self, parsed_args):
+ self.log.debug('run(%s)' % parsed_args)
+ quantum_client = self.get_client()
+ quantum_client.format = parsed_args.request_format
+ #TODO(danwent): handle passing in port-id
+ quantum_client.add_interface_router(parsed_args.router_id,
+ {'subnet_id':
+ parsed_args.subnet_id})
+ #TODO(danwent): print port ID that is added
+ print >>self.app.stdout, (
+ _('Added interface to router %s') % parsed_args.router_id)
+
+
+class RemoveInterfaceRouter(RouterInterfaceCommand):
+ """Remove an internal network interface from a router."""
+
+ def run(self, parsed_args):
+ self.log.debug('run(%s)' % parsed_args)
+ quantum_client = self.get_client()
+ quantum_client.format = parsed_args.request_format
+ #TODO(danwent): handle passing in port-id
+ quantum_client.remove_interface_router(parsed_args.router_id,
+ {'subnet_id':
+ parsed_args.subnet_id})
+ print >>self.app.stdout, (
+ _('Removed interface from router %s') % parsed_args.router_id)
+
+
+class SetGatewayRouter(QuantumCommand):
+ """Set the external network gateway for a router."""
+
+ log = logging.getLogger(__name__ + '.SetGatewayRouter')
+ api = 'network'
+ resource = 'router'
+
+ def get_parser(self, prog_name):
+ parser = super(SetGatewayRouter, self).get_parser(prog_name)
+ parser.add_argument(
+ 'router_id', metavar='router_id',
+ help='ID of the router')
+ parser.add_argument(
+ 'external_network_id', metavar='external_network_id',
+ help='ID of the external network for the gateway')
+ return parser
+
+ def run(self, parsed_args):
+ self.log.debug('run(%s)' % parsed_args)
+ quantum_client = self.get_client()
+ quantum_client.format = parsed_args.request_format
+ quantum_client.add_gateway_router(parsed_args.router_id,
+ {'network_id':
+ parsed_args.external_network_id})
+ print >>self.app.stdout, (
+ _('Set gateway for router %s') % parsed_args.router_id)
+
+
+class RemoveGatewayRouter(QuantumCommand):
+ """Remove an external network gateway from a router."""
+
+ log = logging.getLogger(__name__ + '.RemoveGatewayRouter')
+ api = 'network'
+ resource = 'router'
+
+ def get_parser(self, prog_name):
+ parser = super(RemoveGatewayRouter, self).get_parser(prog_name)
+ parser.add_argument(
+ 'router_id', metavar='router_id',
+ help='ID of the router')
+ return parser
+
+ def run(self, parsed_args):
+ self.log.debug('run(%s)' % parsed_args)
+ quantum_client = self.get_client()
+ quantum_client.format = parsed_args.request_format
+ quantum_client.remove_gateway_router(parsed_args.router_id)
+ print >>self.app.stdout, (
+ _('Removed gateway from router %s') % parsed_args.router_id)
diff --git a/quantumclient/shell.py b/quantumclient/shell.py
index 952f56f..5ccc1c7 100644
--- a/quantumclient/shell.py
+++ b/quantumclient/shell.py
@@ -95,6 +95,36 @@ COMMAND_V2 = {
'quantumclient.quantum.v2_0.extension.ListExt'),
'ext-show': utils.import_class(
'quantumclient.quantum.v2_0.extension.ShowExt'),
+ 'router-list': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.ListRouter'),
+ 'router-show': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.ShowRouter'),
+ 'router-create': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.CreateRouter'),
+ 'router-delete': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.DeleteRouter'),
+ 'router-update': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.UpdateRouter'),
+ 'router-interface-add': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.AddInterfaceRouter'),
+ 'router-interface-delete': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.RemoveInterfaceRouter'),
+ 'router-gateway-set': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.SetGatewayRouter'),
+ 'router-gateway-clear': utils.import_class(
+ 'quantumclient.quantum.v2_0.router.RemoveGatewayRouter'),
+ 'floatingip-list': utils.import_class(
+ 'quantumclient.quantum.v2_0.floatingip.ListFloatingIP'),
+ 'floatingip-show': utils.import_class(
+ 'quantumclient.quantum.v2_0.floatingip.ShowFloatingIP'),
+ 'floatingip-create': utils.import_class(
+ 'quantumclient.quantum.v2_0.floatingip.CreateFloatingIP'),
+ 'floatingip-delete': utils.import_class(
+ 'quantumclient.quantum.v2_0.floatingip.DeleteFloatingIP'),
+ 'floatingip-associate': utils.import_class(
+ 'quantumclient.quantum.v2_0.floatingip.AssociateFloatingIP'),
+ 'floatingip-disassociate': utils.import_class(
+ 'quantumclient.quantum.v2_0.floatingip.DisassociateFloatingIP'),
}
COMMANDS = {'2.0': COMMAND_V2}
@@ -116,7 +146,7 @@ class HelpAction(argparse.Action):
factory = ep.load()
cmd = factory(self, None)
one_liner = cmd.get_description().split('\n')[0]
- app.stdout.write(' %-13s %s\n' % (name, one_liner))
+ app.stdout.write(' %-25s %s\n' % (name, one_liner))
sys.exit(0)
diff --git a/quantumclient/tests/unit/test_cli20.py b/quantumclient/tests/unit/test_cli20.py
index 3737061..6ed0afc 100644
--- a/quantumclient/tests/unit/test_cli20.py
+++ b/quantumclient/tests/unit/test_cli20.py
@@ -140,7 +140,7 @@ class CLITestV20Base(unittest.TestCase):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
- if resource == 'subnet':
+ if (resource == 'subnet' or resource == 'floatingip'):
body = {resource: {}, }
else:
body = {resource: {'admin_state_up': admin_state_up, }, }
@@ -293,3 +293,25 @@ class CLITestV20Base(unittest.TestCase):
self.mox.UnsetStubs()
_str = self.fake_stdout.make_string()
self.assertTrue(myid in _str)
+
+ def _test_update_resource_action(self, resource, cmd, myid, action, args,
+ body):
+ self.mox.StubOutWithMock(cmd, "get_client")
+ self.mox.StubOutWithMock(self.client.httpclient, "request")
+ cmd.get_client().MultipleTimes().AndReturn(self.client)
+ path = getattr(self.client, resource + "_path")
+ path_action = '%s/%s' % (myid, action)
+ self.client.httpclient.request(
+ end_url(path % path_action), 'PUT',
+ body=MyComparator(body, self.client),
+ headers=ContainsKeyValue('X-Auth-Token',
+ TOKEN)).AndReturn((MyResp(204), None))
+ self.mox.ReplayAll()
+ cmd_parser = cmd.get_parser("update_" + resource)
+
+ parsed_args = cmd_parser.parse_args(args)
+ cmd.run(parsed_args)
+ self.mox.VerifyAll()
+ self.mox.UnsetStubs()
+ _str = self.fake_stdout.make_string()
+ self.assertTrue(myid in _str)
diff --git a/quantumclient/tests/unit/test_cli20_floatingips.py b/quantumclient/tests/unit/test_cli20_floatingips.py
new file mode 100644
index 0000000..f9b63df
--- /dev/null
+++ b/quantumclient/tests/unit/test_cli20_floatingips.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Red Hat
+# 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.
+
+import sys
+
+from quantumclient.common import exceptions
+from quantumclient.quantum.v2_0.floatingip import AssociateFloatingIP
+from quantumclient.quantum.v2_0.floatingip import CreateFloatingIP
+from quantumclient.quantum.v2_0.floatingip import DeleteFloatingIP
+from quantumclient.quantum.v2_0.floatingip import DisassociateFloatingIP
+from quantumclient.quantum.v2_0.floatingip import ListFloatingIP
+from quantumclient.quantum.v2_0.floatingip import ShowFloatingIP
+from quantumclient.tests.unit.test_cli20 import CLITestV20Base
+from quantumclient.tests.unit.test_cli20 import MyApp
+
+
+class CLITestV20FloatingIps(CLITestV20Base):
+ def test_create_floatingip(self):
+ """Create floatingip: fip1."""
+ resource = 'floatingip'
+ cmd = CreateFloatingIP(MyApp(sys.stdout), None)
+ name = 'fip1'
+ myid = 'myid'
+ args = [name]
+ position_names = ['floating_network_id']
+ position_values = [name]
+ _str = self._test_create_resource(resource, cmd, name, myid, args,
+ position_names, position_values)
+
+ def test_create_floatingip_and_port(self):
+ """Create floatingip: fip1."""
+ resource = 'floatingip'
+ cmd = CreateFloatingIP(MyApp(sys.stdout), None)
+ name = 'fip1'
+ myid = 'myid'
+ pid = 'mypid'
+ args = [name, '--port_id', pid]
+ position_names = ['floating_network_id', 'port_id']
+ position_values = [name, pid]
+ _str = self._test_create_resource(resource, cmd, name, myid, args,
+ position_names, position_values)
+
+ def test_list_floatingips(self):
+ """list floatingips: -D."""
+ resources = 'floatingips'
+ cmd = ListFloatingIP(MyApp(sys.stdout), None)
+ self._test_list_resources(resources, cmd, True)
+
+ def test_delete_floatingip(self):
+ """Delete floatingip: fip1"""
+ resource = 'floatingip'
+ cmd = DeleteFloatingIP(MyApp(sys.stdout), None)
+ myid = 'myid'
+ args = [myid]
+ self._test_delete_resource(resource, cmd, myid, args)
+
+ def test_show_floatingip(self):
+ """Show floatingip: --fields id."""
+ resource = 'floatingip'
+ cmd = ShowFloatingIP(MyApp(sys.stdout), None)
+ args = ['--fields', 'id', self.test_id]
+ self._test_show_resource(resource, cmd, self.test_id,
+ args, ['id'])
+
+ def test_disassociate_ip(self):
+ """Disassociate floating IP: myid"""
+ resource = 'floatingip'
+ cmd = DisassociateFloatingIP(MyApp(sys.stdout), None)
+ args = ['myid']
+ self._test_update_resource(resource, cmd, 'myid',
+ args, {"port_id": None}
+ )
+
+ def test_associate_ip(self):
+ """Associate floating IP: myid portid"""
+ resource = 'floatingip'
+ cmd = AssociateFloatingIP(MyApp(sys.stdout), None)
+ args = ['myid', 'portid']
+ self._test_update_resource(resource, cmd, 'myid',
+ args, {"port_id": "portid"}
+ )
diff --git a/quantumclient/tests/unit/test_cli20_router.py b/quantumclient/tests/unit/test_cli20_router.py
new file mode 100644
index 0000000..502365d
--- /dev/null
+++ b/quantumclient/tests/unit/test_cli20_router.py
@@ -0,0 +1,151 @@
+# Copyright 2012 Nicira, Inc
+# 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.
+#
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import sys
+
+from quantumclient.common import exceptions
+from quantumclient.quantum.v2_0.router import AddInterfaceRouter
+from quantumclient.quantum.v2_0.router import CreateRouter
+from quantumclient.quantum.v2_0.router import DeleteRouter
+from quantumclient.quantum.v2_0.router import ListRouter
+from quantumclient.quantum.v2_0.router import RemoveGatewayRouter
+from quantumclient.quantum.v2_0.router import RemoveInterfaceRouter
+from quantumclient.quantum.v2_0.router import SetGatewayRouter
+from quantumclient.quantum.v2_0.router import ShowRouter
+from quantumclient.quantum.v2_0.router import UpdateRouter
+from quantumclient.tests.unit.test_cli20 import CLITestV20Base
+from quantumclient.tests.unit.test_cli20 import MyApp
+
+
+class CLITestV20Router(CLITestV20Base):
+ def test_create_router(self):
+ """Create router: router1."""
+ resource = 'router'
+ cmd = CreateRouter(MyApp(sys.stdout), None)
+ name = 'router1'
+ myid = 'myid'
+ args = [name, ]
+ position_names = ['name', ]
+ position_values = [name, ]
+ _str = self._test_create_resource(resource, cmd, name, myid, args,
+ position_names, position_values)
+
+ def test_create_router_tenant(self):
+ """Create router: --tenant_id tenantid myname."""
+ resource = 'router'
+ cmd = CreateRouter(MyApp(sys.stdout), None)
+ name = 'myname'
+ myid = 'myid'
+ args = ['--tenant_id', 'tenantid', name]
+ position_names = ['name', ]
+ position_values = [name, ]
+ _str = self._test_create_resource(resource, cmd, name, myid, args,
+ position_names, position_values,
+ tenant_id='tenantid')
+
+ def test_create_router_admin_state(self):
+ """Create router: --admin_state_down myname."""
+ resource = 'router'
+ cmd = CreateRouter(MyApp(sys.stdout), None)
+ name = 'myname'
+ myid = 'myid'
+ args = ['--admin_state_down', name, ]
+ position_names = ['name', ]
+ position_values = [name, ]
+ _str = self._test_create_resource(resource, cmd, name, myid, args,
+ position_names, position_values,
+ admin_state_up=False)
+
+ def test_list_routers_detail(self):
+ """list routers: -D."""
+ resources = "routers"
+ cmd = ListRouter(MyApp(sys.stdout), None)
+ self._test_list_resources(resources, cmd, True)
+
+ def test_update_router_exception(self):
+ """Update router: myid."""
+ resource = 'router'
+ cmd = UpdateRouter(MyApp(sys.stdout), None)
+ self.assertRaises(exceptions.CommandError, self._test_update_resource,
+ resource, cmd, 'myid', ['myid'], {})
+
+ def test_update_router(self):
+ """Update router: myid --name myname --tags a b."""
+ resource = 'router'
+ cmd = UpdateRouter(MyApp(sys.stdout), None)
+ self._test_update_resource(resource, cmd, 'myid',
+ ['myid', '--name', 'myname'],
+ {'name': 'myname'}
+ )
+
+ def test_delete_router(self):
+ """Delete router: myid."""
+ resource = 'router'
+ cmd = DeleteRouter(MyApp(sys.stdout), None)
+ myid = 'myid'
+ args = [myid]
+ self._test_delete_resource(resource, cmd, myid, args)
+
+ def test_show_router(self):
+ """Show router: myid."""
+ resource = 'router'
+ cmd = ShowRouter(MyApp(sys.stdout), None)
+ args = ['--fields', 'id', '--fields', 'name', self.test_id]
+ self._test_show_resource(resource, cmd, self.test_id, args,
+ ['id', 'name'])
+
+ def test_add_interface(self):
+ """Add interface to router: myid subnetid"""
+ resource = 'router'
+ cmd = AddInterfaceRouter(MyApp(sys.stdout), None)
+ args = ['myid', 'subnetid']
+ self._test_update_resource_action(resource, cmd, 'myid',
+ 'add_router_interface',
+ args,
+ {'subnet_id': 'subnetid'}
+ )
+
+ def test_del_interface(self):
+ """Delete interface from router: myid subnetid"""
+ resource = 'router'
+ cmd = RemoveInterfaceRouter(MyApp(sys.stdout), None)
+ args = ['myid', 'subnetid']
+ self._test_update_resource_action(resource, cmd, 'myid',
+ 'remove_router_interface',
+ args,
+ {'subnet_id': 'subnetid'}
+ )
+
+ def test_set_gateway(self):
+ """Set external gateway for router: myid externalid"""
+ resource = 'router'
+ cmd = SetGatewayRouter(MyApp(sys.stdout), None)
+ args = ['myid', 'externalid']
+ self._test_update_resource(resource, cmd, 'myid',
+ args,
+ {"external_gateway_info":
+ {"network_id": "externalid"}}
+ )
+
+ def test_remove_gateway(self):
+ """Remove external gateway from router: externalid"""
+ resource = 'router'
+ cmd = RemoveGatewayRouter(MyApp(sys.stdout), None)
+ args = ['externalid']
+ self._test_update_resource(resource, cmd, 'externalid',
+ args, {"external_gateway_info": {}}
+ )
diff --git a/quantumclient/v2_0/client.py b/quantumclient/v2_0/client.py
index 23766da..09712c9 100644
--- a/quantumclient/v2_0/client.py
+++ b/quantumclient/v2_0/client.py
@@ -158,6 +158,10 @@ class Client(object):
quota_path = "/quotas/%s"
exts_path = "/extensions"
ext_path = "/extensions/%s"
+ routers_path = "/routers"
+ router_path = "/routers/%s"
+ floatingips_path = "/floatingips"
+ floatingip_path = "/floatingips/%s"
@APIParamsCall
def get_quotas_tenant(self, **_params):
@@ -302,6 +306,110 @@ class Client(object):
"""
return self.delete(self.subnet_path % (subnet))
+ @APIParamsCall
+ def list_routers(self, **_params):
+ """
+ Fetches a list of all routers for a tenant
+ """
+ # Pass filters in "params" argument to do_request
+ return self.get(self.routers_path, params=_params)
+
+ @APIParamsCall
+ def show_router(self, router, **_params):
+ """
+ Fetches information of a certain router
+ """
+ return self.get(self.router_path % (router), params=_params)
+
+ @APIParamsCall
+ def create_router(self, body=None):
+ """
+ Creates a new router
+ """
+ return self.post(self.routers_path, body=body)
+
+ @APIParamsCall
+ def update_router(self, router, body=None):
+ """
+ Updates a router
+ """
+ return self.put(self.router_path % (router), body=body)
+
+ @APIParamsCall
+ def delete_router(self, router):
+ """
+ Deletes the specified router
+ """
+ return self.delete(self.router_path % (router))
+
+ @APIParamsCall
+ def add_interface_router(self, router, body=None):
+ """
+ Adds an internal network interface to the specified router
+ """
+ return self.put((self.router_path % router) + "/add_router_interface",
+ body=body)
+
+ @APIParamsCall
+ def remove_interface_router(self, router, body=None):
+ """
+ Removes an internal network interface from the specified router
+ """
+ return self.put((self.router_path % router) +
+ "/remove_router_interface", body=body)
+
+ @APIParamsCall
+ def add_gateway_router(self, router, body=None):
+ """
+ Adds an external network gateway to the specified router
+ """
+ return self.put((self.router_path % router),
+ body={'router': {'external_gateway_info': body}})
+
+ @APIParamsCall
+ def remove_gateway_router(self, router):
+ """
+ Removes an external network gateway from the specified router
+ """
+ return self.put((self.router_path % router),
+ body={'router': {'external_gateway_info': {}}})
+
+ @APIParamsCall
+ def list_floatingips(self, **_params):
+ """
+ Fetches a list of all floatingips for a tenant
+ """
+ # Pass filters in "params" argument to do_request
+ return self.get(self.floatingips_path, params=_params)
+
+ @APIParamsCall
+ def show_floatingip(self, floatingip, **_params):
+ """
+ Fetches information of a certain floatingip
+ """
+ return self.get(self.floatingip_path % (floatingip), params=_params)
+
+ @APIParamsCall
+ def create_floatingip(self, body=None):
+ """
+ Creates a new floatingip
+ """
+ return self.post(self.floatingips_path, body=body)
+
+ @APIParamsCall
+ def update_floatingip(self, floatingip, body=None):
+ """
+ Updates a floatingip
+ """
+ return self.put(self.floatingip_path % (floatingip), body=body)
+
+ @APIParamsCall
+ def delete_floatingip(self, floatingip):
+ """
+ Deletes the specified floatingip
+ """
+ return self.delete(self.floatingip_path % (floatingip))
+
def __init__(self, **kwargs):
""" Initialize a new client for the Quantum v2.0 API. """
super(Client, self).__init__()