Skip to content

Commit

Permalink
CLI support for network gateway feature
Browse files Browse the repository at this point in the history
Blueprint nvp-nwgw-extension-client

Adds commands for gateway management, and for connecting
networks to gateways. These commands use the nicira-specific
extension 'nvp-network-gateway'

Change-Id: Iefcba201bc9fd8dce35762514af0f56b29430ccd
  • Loading branch information
Salvatore Orlando authored and salv-orlando committed Feb 20, 2013
1 parent ee4cb43 commit d77f862
Show file tree
Hide file tree
Showing 5 changed files with 340 additions and 2 deletions.
160 changes: 160 additions & 0 deletions 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=<device identifier>,'
'interface_name=<name_or_identifier> '
'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)
15 changes: 15 additions & 0 deletions quantumclient/shell.py
Expand Up @@ -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}
Expand Down
6 changes: 4 additions & 2 deletions quantumclient/tests/unit/test_cli20.py
Expand Up @@ -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:
Expand All @@ -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]})
Expand Down
108 changes: 108 additions & 0 deletions 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'})
53 changes: 53 additions & 0 deletions quantumclient/v2_0/client.py
Expand Up @@ -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',
Expand Down Expand Up @@ -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__()
Expand Down

0 comments on commit d77f862

Please sign in to comment.