diff --git a/quantumclient/quantum/v2_0/nvpnetworkgateway.py b/quantumclient/quantum/v2_0/nvpnetworkgateway.py new file mode 100644 index 000000000..39573041c --- /dev/null +++ b/quantumclient/quantum/v2_0/nvpnetworkgateway.py @@ -0,0 +1,160 @@ +# Copyright 2013 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 argparse +import logging + +from quantumclient.common import utils +from quantumclient.quantum import v2_0 as quantumv20 + +RESOURCE = 'network_gateway' + + +class ListNetworkGateway(quantumv20.ListCommand): + """List network gateways for a given tenant.""" + + resource = RESOURCE + _formatters = {} + log = logging.getLogger(__name__ + '.ListNetworkGateway') + list_columns = ['id', 'name'] + + +class ShowNetworkGateway(quantumv20.ShowCommand): + """Show information of a given network gateway.""" + + resource = RESOURCE + log = logging.getLogger(__name__ + '.ShowNetworkGateway') + + +class CreateNetworkGateway(quantumv20.CreateCommand): + """Create a network gateway.""" + + resource = RESOURCE + log = logging.getLogger(__name__ + '.CreateNetworkGateway') + + def add_known_arguments(self, parser): + parser.add_argument( + 'name', metavar='NAME', + help='Name of network gateway to create') + parser.add_argument( + '--device', + action='append', + help='device info for this gateway ' + 'device_id=,' + 'interface_name= ' + 'It can be repeated for multiple devices for HA gateways') + + def args2body(self, parsed_args): + body = {self.resource: { + 'name': parsed_args.name}} + devices = [] + if parsed_args.device: + for device in parsed_args.device: + devices.append(utils.str2dict(device)) + if devices: + body[self.resource].update({'devices': devices}) + if parsed_args.tenant_id: + body[self.resource].update({'tenant_id': parsed_args.tenant_id}) + return body + + +class DeleteNetworkGateway(quantumv20.DeleteCommand): + """Delete a given network gateway.""" + + resource = RESOURCE + log = logging.getLogger(__name__ + '.DeleteNetworkGateway') + + +class UpdateNetworkGateway(quantumv20.UpdateCommand): + """Update the name for a network gateway.""" + + resource = RESOURCE + log = logging.getLogger(__name__ + '.UpdateNetworkGateway') + + +class NetworkGatewayInterfaceCommand(quantumv20.QuantumCommand): + """Base class for connecting/disconnecting networks to/from a gateway.""" + + resource = RESOURCE + + def get_parser(self, prog_name): + parser = super(NetworkGatewayInterfaceCommand, + self).get_parser(prog_name) + parser.add_argument( + 'net_gateway_id', metavar='NET-GATEWAY-ID', + help='ID of the network gateway') + parser.add_argument( + 'network_id', metavar='NETWORK-ID', + help='ID of the internal network to connect on the gateway') + parser.add_argument( + '--segmentation-type', + help=('L2 segmentation strategy on the external side of ' + 'the gateway (e.g.: VLAN, FLAT)')) + parser.add_argument( + '--segmentation-id', + help=('Identifier for the L2 segment on the external side ' + 'of the gateway')) + return parser + + def retrieve_ids(self, client, args): + gateway_id = quantumv20.find_resourceid_by_name_or_id( + client, self.resource, args.net_gateway_id) + network_id = quantumv20.find_resourceid_by_name_or_id( + client, 'network', args.network_id) + return (gateway_id, network_id) + + +class ConnectNetworkGateway(NetworkGatewayInterfaceCommand): + """Add an internal network interface to a router.""" + + log = logging.getLogger(__name__ + '.ConnectNetworkGateway') + + def run(self, parsed_args): + self.log.debug('run(%s)' % parsed_args) + quantum_client = self.get_client() + quantum_client.format = parsed_args.request_format + (gateway_id, network_id) = self.retrieve_ids(quantum_client, + parsed_args) + quantum_client.connect_network_gateway( + gateway_id, {'network_id': network_id, + 'segmentation_type': parsed_args.segmentation_type, + 'segmentation_id': parsed_args.segmentation_id}) + # TODO(Salvatore-Orlando): Do output formatting as + # any other command + print >>self.app.stdout, ( + _('Connected network to gateway %s') % gateway_id) + + +class DisconnectNetworkGateway(NetworkGatewayInterfaceCommand): + """Remove a network from a network gateway.""" + + log = logging.getLogger(__name__ + '.DisconnectNetworkGateway') + + def run(self, parsed_args): + self.log.debug('run(%s)' % parsed_args) + quantum_client = self.get_client() + quantum_client.format = parsed_args.request_format + (gateway_id, network_id) = self.retrieve_ids(quantum_client, + parsed_args) + quantum_client.disconnect_network_gateway( + gateway_id, {'network_id': network_id, + 'segmentation_type': parsed_args.segmentation_type, + 'segmentation_id': parsed_args.segmentation_id}) + # TODO(Salvatore-Orlando): Do output formatting as + # any other command + print >>self.app.stdout, ( + _('Disconnected network from gateway %s') % gateway_id) diff --git a/quantumclient/shell.py b/quantumclient/shell.py index 4b22e9837..feb69411e 100644 --- a/quantumclient/shell.py +++ b/quantumclient/shell.py @@ -220,6 +220,21 @@ def env(*_vars, **kwargs): 'quantumclient.quantum.v2_0.agent.DeleteAgent'), 'agent-update': utils.import_class( 'quantumclient.quantum.v2_0.agent.UpdateAgent'), + 'net-gateway-create': utils.import_class( + 'quantumclient.quantum.v2_0.nvpnetworkgateway.CreateNetworkGateway'), + 'net-gateway-update': utils.import_class( + 'quantumclient.quantum.v2_0.nvpnetworkgateway.UpdateNetworkGateway'), + 'net-gateway-delete': utils.import_class( + 'quantumclient.quantum.v2_0.nvpnetworkgateway.DeleteNetworkGateway'), + 'net-gateway-show': utils.import_class( + 'quantumclient.quantum.v2_0.nvpnetworkgateway.ShowNetworkGateway'), + 'net-gateway-list': utils.import_class( + 'quantumclient.quantum.v2_0.nvpnetworkgateway.ListNetworkGateway'), + 'net-gateway-connect': utils.import_class( + 'quantumclient.quantum.v2_0.nvpnetworkgateway.ConnectNetworkGateway'), + 'net-gateway-disconnect': utils.import_class( + 'quantumclient.quantum.v2_0.nvpnetworkgateway.' + 'DisconnectNetworkGateway') } COMMANDS = {'2.0': COMMAND_V2} diff --git a/quantumclient/tests/unit/test_cli20.py b/quantumclient/tests/unit/test_cli20.py index d2abaf94e..4e62edaad 100644 --- a/quantumclient/tests/unit/test_cli20.py +++ b/quantumclient/tests/unit/test_cli20.py @@ -159,12 +159,13 @@ def _test_create_resource(self, resource, cmd, name, myid, args, position_names, position_values, tenant_id=None, tags=None, admin_state_up=True, shared=False, - extra_body=None): + extra_body=None, **kwargs): self.mox.StubOutWithMock(cmd, "get_client") self.mox.StubOutWithMock(self.client.httpclient, "request") cmd.get_client().MultipleTimes().AndReturn(self.client) non_admin_status_resources = ['subnet', 'floatingip', 'security_group', - 'security_group_rule', 'qos_queue'] + 'security_group_rule', 'qos_queue', + 'network_gateway'] if (resource in non_admin_status_resources): body = {resource: {}, } else: @@ -177,6 +178,7 @@ def _test_create_resource(self, resource, cmd, body[resource].update({'shared': shared}) if extra_body: body[resource].update(extra_body) + body[resource].update(kwargs) for i in xrange(len(position_names)): body[resource].update({position_names[i]: position_values[i]}) diff --git a/quantumclient/tests/unit/test_cli20_nvpnetworkgateway.py b/quantumclient/tests/unit/test_cli20_nvpnetworkgateway.py new file mode 100644 index 000000000..7f17571d4 --- /dev/null +++ b/quantumclient/tests/unit/test_cli20_nvpnetworkgateway.py @@ -0,0 +1,108 @@ +# 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 import nvpnetworkgateway +from quantumclient.tests.unit.test_cli20 import CLITestV20Base +from quantumclient.tests.unit.test_cli20 import MyApp + + +class CLITestV20NetworkGateway(CLITestV20Base): + + resource = "network_gateway" + + def test_create_gateway(self): + cmd = nvpnetworkgateway.CreateNetworkGateway(MyApp(sys.stdout), None) + name = 'gw-test' + myid = 'myid' + args = [name, ] + position_names = ['name', ] + position_values = [name, ] + _str = self._test_create_resource(self.resource, cmd, name, myid, args, + position_names, position_values) + + def test_create_gateway_with_tenant(self): + cmd = nvpnetworkgateway.CreateNetworkGateway(MyApp(sys.stdout), None) + name = 'gw-test' + myid = 'myid' + args = ['--tenant_id', 'tenantid', name] + position_names = ['name', ] + position_values = [name, ] + _str = self._test_create_resource(self.resource, cmd, name, myid, args, + position_names, position_values, + tenant_id='tenantid') + + def test_create_gateway_with_device(self): + cmd = nvpnetworkgateway.CreateNetworkGateway(MyApp(sys.stdout), None) + name = 'gw-test' + myid = 'myid' + args = ['--device', 'device_id=test', name, ] + position_names = ['name', ] + position_values = [name, ] + _str = self._test_create_resource(self.resource, cmd, name, myid, args, + position_names, position_values, + devices=[{'device_id': 'test'}]) + + def test_list_gateways(self): + resources = '%ss' % self.resource + cmd = nvpnetworkgateway.ListNetworkGateway(MyApp(sys.stdout), None) + self._test_list_resources(resources, cmd, True) + + def test_update_gateway(self): + cmd = nvpnetworkgateway.UpdateNetworkGateway(MyApp(sys.stdout), None) + self._test_update_resource(self.resource, cmd, 'myid', + ['myid', '--name', 'cavani'], + {'name': 'cavani'}) + + def test_delete_gateway(self): + cmd = nvpnetworkgateway.DeleteNetworkGateway(MyApp(sys.stdout), None) + myid = 'myid' + args = [myid] + self._test_delete_resource(self.resource, cmd, myid, args) + + def test_show_gateway(self): + cmd = nvpnetworkgateway.ShowNetworkGateway(MyApp(sys.stdout), None) + args = ['--fields', 'id', '--fields', 'name', self.test_id] + self._test_show_resource(self.resource, cmd, self.test_id, args, + ['id', 'name']) + + def test_connect_network_to_gateway(self): + cmd = nvpnetworkgateway.ConnectNetworkGateway(MyApp(sys.stdout), None) + args = ['gw_id', 'net_id', + '--segmentation-type', 'edi', + '--segmentation-id', '7'] + self._test_update_resource_action(self.resource, cmd, 'gw_id', + 'connect_network', + args, + {'network_id': 'net_id', + 'segmentation_type': 'edi', + 'segmentation_id': '7'}) + + def test_disconnect_network_from_gateway(self): + cmd = nvpnetworkgateway.DisconnectNetworkGateway(MyApp(sys.stdout), + None) + args = ['gw_id', 'net_id', + '--segmentation-type', 'edi', + '--segmentation-id', '7'] + self._test_update_resource_action(self.resource, cmd, 'gw_id', + 'disconnect_network', + args, + {'network_id': 'net_id', + 'segmentation_type': 'edi', + 'segmentation_id': '7'}) diff --git a/quantumclient/v2_0/client.py b/quantumclient/v2_0/client.py index 883b208be..3ee26e989 100644 --- a/quantumclient/v2_0/client.py +++ b/quantumclient/v2_0/client.py @@ -174,6 +174,8 @@ class Client(object): qos_queue_path = "/qos-queues/%s" agents_path = "/agents" agent_path = "/agents/%s" + network_gateways_path = "/network-gateways" + network_gateway_path = "/network-gateways/%s" # API has no way to report plurals, so we have to hard code them EXTED_PLURALS = {'routers': 'router', @@ -735,6 +737,57 @@ def delete_agent(self, agent): """ return self.delete(self.agent_path % (agent)) + @APIParamsCall + def list_network_gateways(self, **_params): + """ + Retrieve network gateways + """ + return self.get(self.network_gateways_path, params=_params) + + @APIParamsCall + def show_network_gateway(self, gateway_id, **_params): + """ + Fetch a network gateway + """ + return self.get(self.network_gateway_path % gateway_id, params=_params) + + @APIParamsCall + def create_network_gateway(self, body=None): + """ + Create a new network gateway + """ + return self.post(self.network_gateways_path, body=body) + + @APIParamsCall + def update_network_gateway(self, gateway_id, body=None): + """ + Update a network gateway + """ + return self.put(self.network_gateway_path % gateway_id, body=body) + + @APIParamsCall + def delete_network_gateway(self, gateway_id): + """ + Delete the specified network gateway + """ + return self.delete(self.network_gateway_path % gateway_id) + + @APIParamsCall + def connect_network_gateway(self, gateway_id, body=None): + """ + Connect a network gateway to the specified network + """ + base_uri = self.network_gateway_path % gateway_id + return self.put("%s/connect_network" % base_uri, body=body) + + @APIParamsCall + def disconnect_network_gateway(self, gateway_id, body=None): + """ + Disconnect a network from the specified gateway + """ + base_uri = self.network_gateway_path % gateway_id + return self.put("%s/disconnect_network" % base_uri, body=body) + def __init__(self, **kwargs): """ Initialize a new client for the Quantum v2.0 API. """ super(Client, self).__init__()