CRUD for VPN endpoint group API

This contains the create, delete, update, show, and list client APIs for
the new VPN endpoint group API.

The API syntax is:

vpn-endpoint-group-create [--name name] [--description desc] \
    --type {subnet|cidr|vlan} --value <value1> [--value <value2>...]

vpn-endpoint-group-delete <name-or-uuid>

vpn-endpoint-group-show <name-or-uuid>

vpn-endpoint-group-update <name-or-uuid> [--name name] [--description desc]

vpn-endpoint-group-list

Notes:

Using prefix "vpn-" on commands, so that there is no conflict with other
neutron commands.

Note: Using --type and --value, instead of --endpoint_type and --endpoint,
which are already used (and must be globally unique). For example, if latter
re used, see error "Must specify new values to update endpoint_group".

The --value may be repeated multiple times, as a list of endpoints can be
added to a group. There must be at least one.

For --type=subnet, the user may enter the name or UUID of subnet, which
must already exist. Client will translate names to UUIDs.

As shown, the endpoints cannot be modified. A new endpoint group must be
formed, and then can be used by VPN (once support is in place).

When updating, either name or description must be provided (otherwise
there is nothing to update).

Added unit tests for the new API.

DocImpact

Change-Id: Ic696674d97474f8bbf3f895aa21b1585a04dc2fe
Partial-Bug: 1459423
Depends-On: Ia729bd0c6967fa2b8c698495aa360f340b42d98a
Depends-On: I6e10590a988312eafca076a14be38b19e2d44a87
This commit is contained in:
Paul Michali
2015-09-01 17:04:58 -04:00
parent e40532a67f
commit 895680a825
4 changed files with 284 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
# (c) Copyright 2015 Cisco Systems, 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.
#
from neutronclient.i18n import _
from neutronclient.neutron import v2_0 as neutronv20
def add_known_endpoint_group_arguments(parser, is_create=True):
parser.add_argument(
'--name',
help=_('Set a name for the endpoint group.'))
parser.add_argument(
'--description',
help=_('Set a description for the endpoint group.'))
if is_create:
parser.add_argument(
'--type',
required=is_create,
help=_('Type of endpoints in group (e.g. subnet, cidr, vlan).'))
parser.add_argument(
'--value',
action='append', dest='endpoints',
required=is_create,
help=_('Endpoint(s) for the group. Must all be of the same type.'))
class ListEndpointGroup(neutronv20.ListCommand):
"""List VPN endpoint groups that belong to a given tenant."""
resource = 'endpoint_group'
list_columns = ['id', 'name', 'type', 'endpoints']
_formatters = {}
pagination_support = True
sorting_support = True
class ShowEndpointGroup(neutronv20.ShowCommand):
"""Show a specific VPN endpoint group."""
resource = 'endpoint_group'
class CreateEndpointGroup(neutronv20.CreateCommand):
"""Create a VPN endpoint group."""
resource = 'endpoint_group'
def add_known_arguments(self, parser):
add_known_endpoint_group_arguments(parser)
def subnet_name2id(self, endpoint):
return neutronv20.find_resourceid_by_name_or_id(self.get_client(),
'subnet', endpoint)
def args2body(self, parsed_args):
if parsed_args.type == 'subnet':
endpoints = [self.subnet_name2id(ep)
for ep in parsed_args.endpoints]
else:
endpoints = parsed_args.endpoints
body = {'endpoints': endpoints}
neutronv20.update_dict(parsed_args, body,
['name', 'description',
'tenant_id', 'type'])
return {self.resource: body}
class UpdateEndpointGroup(neutronv20.UpdateCommand):
"""Update a given VPN endpoint group."""
resource = 'endpoint_group'
def add_known_arguments(self, parser):
add_known_endpoint_group_arguments(parser, is_create=False)
def args2body(self, parsed_args):
body = {}
neutronv20.update_dict(parsed_args, body,
['name', 'description'])
return {self.resource: body}
class DeleteEndpointGroup(neutronv20.DeleteCommand):
"""Delete a given VPN endpoint group."""
resource = 'endpoint_group'

View File

@@ -78,6 +78,7 @@ from neutronclient.neutron.v2_0 import securitygroup
from neutronclient.neutron.v2_0 import servicetype
from neutronclient.neutron.v2_0 import subnet
from neutronclient.neutron.v2_0 import subnetpool
from neutronclient.neutron.v2_0.vpn import endpoint_group
from neutronclient.neutron.v2_0.vpn import ikepolicy
from neutronclient.neutron.v2_0.vpn import ipsec_site_connection
from neutronclient.neutron.v2_0.vpn import ipsecpolicy
@@ -317,6 +318,11 @@ COMMAND_V2 = {
'ipsec-site-connection-delete': (
ipsec_site_connection.DeleteIPsecSiteConnection
),
'vpn-endpoint-group-list': endpoint_group.ListEndpointGroup,
'vpn-endpoint-group-show': endpoint_group.ShowEndpointGroup,
'vpn-endpoint-group-create': endpoint_group.CreateEndpointGroup,
'vpn-endpoint-group-update': endpoint_group.UpdateEndpointGroup,
'vpn-endpoint-group-delete': endpoint_group.DeleteEndpointGroup,
'vpn-service-list': vpnservice.ListVPNService,
'vpn-service-show': vpnservice.ShowVPNService,
'vpn-service-create': vpnservice.CreateVPNService,

View File

@@ -0,0 +1,148 @@
# (c) Copyright 2015 Cisco Systems, 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.
#
import sys
from neutronclient.neutron.v2_0.vpn import endpoint_group
from neutronclient.tests.unit import test_cli20
class CLITestV20VpnEndpointGroupJSON(test_cli20.CLITestV20Base):
def setUp(self):
super(CLITestV20VpnEndpointGroupJSON, self).setUp()
self.register_non_admin_status_resource('endpoint_group')
def test_create_endpoint_group_with_cidrs(self):
"""vpn-endpoint-group-create with CIDR endpoints."""
resource = 'endpoint_group'
cmd = endpoint_group.CreateEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
tenant_id = 'mytenant-id'
my_id = 'my-id'
name = 'my-endpoint-group'
description = 'my endpoint group'
endpoint_type = 'cidr'
endpoints = ['10.0.0.0/24', '20.0.0.0/24']
args = ['--name', name,
'--description', description,
'--tenant-id', tenant_id,
'--type', endpoint_type,
'--value', '10.0.0.0/24',
'--value', '20.0.0.0/24']
position_names = ['name', 'description', 'tenant_id',
'type', 'endpoints']
position_values = [name, description, tenant_id,
endpoint_type, endpoints]
self._test_create_resource(resource, cmd, name, my_id, args,
position_names, position_values)
def test_create_endpoint_group_with_subnets(self):
"""vpn-endpoint-group-create with subnet endpoints."""
resource = 'endpoint_group'
cmd = endpoint_group.CreateEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
tenant_id = 'mytenant-id'
my_id = 'my-id'
endpoint_type = 'subnet'
subnet = 'subnet-id'
endpoints = [subnet]
args = ['--type', endpoint_type,
'--value', subnet,
'--tenant-id', tenant_id]
position_names = ['type', 'endpoints', 'tenant_id']
position_values = [endpoint_type, endpoints, tenant_id]
self._test_create_resource(resource, cmd, None, my_id, args,
position_names, position_values)
def test_list_endpoint_group(self):
"""vpn-endpoint-group-list."""
resources = "endpoint_groups"
cmd = endpoint_group.ListEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
self._test_list_resources(resources, cmd, True)
def test_list_endpoint_group_pagination(self):
"""vpn-endpoint-group-list."""
resources = "endpoint_groups"
cmd = endpoint_group.ListEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
self._test_list_resources_with_pagination(resources, cmd)
def test_list_endpoint_group_sort(self):
"""vpn-endpoint-group-list --sort-key name --sort-key id
--sort-key asc --sort-key desc
"""
resources = "endpoint_groups"
cmd = endpoint_group.ListEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
self._test_list_resources(resources, cmd,
sort_key=["name", "id"],
sort_dir=["asc", "desc"])
def test_list_endpoint_group_limit(self):
"""vpn-endpoint-group-list -P."""
resources = "endpoint_groups"
cmd = endpoint_group.ListEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
self._test_list_resources(resources, cmd, page_size=1000)
def test_show_endpoint_group_id(self):
"""vpn-endpoint-group-show test_id."""
resource = 'endpoint_group'
cmd = endpoint_group.ShowEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
args = ['--fields', 'id', self.test_id]
self._test_show_resource(resource, cmd, self.test_id, args, ['id'])
def test_show_endpoint_group_id_name(self):
"""vpn-endpoint-group-show."""
resource = 'endpoint_group'
cmd = endpoint_group.ShowEndpointGroup(test_cli20.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_update_endpoint_group(self):
"""vpn-endpoint-group-update myid --name newname
--description newdesc.
"""
resource = 'endpoint_group'
cmd = endpoint_group.UpdateEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
self._test_update_resource(resource, cmd, 'myid',
['myid', '--name', 'newname',
'--description', 'newdesc'],
{'name': 'newname',
'description': 'newdesc'})
def test_delete_endpoint_group(self):
"""vpn-endpoint-group-delete my-id."""
resource = 'endpoint_group'
cmd = endpoint_group.DeleteEndpointGroup(test_cli20.MyApp(sys.stdout),
None)
my_id = 'my-id'
args = [my_id]
self._test_delete_resource(resource, cmd, my_id, args)

View File

@@ -355,6 +355,8 @@ class Client(ClientBase):
security_group_path = "/security-groups/%s"
security_group_rules_path = "/security-group-rules"
security_group_rule_path = "/security-group-rules/%s"
endpoint_groups_path = "/vpn/endpoint-groups"
endpoint_group_path = "/vpn/endpoint-groups/%s"
vpnservices_path = "/vpn/vpnservices"
vpnservice_path = "/vpn/vpnservices/%s"
ipsecpolicies_path = "/vpn/ipsecpolicies"
@@ -439,6 +441,7 @@ class Client(ClientBase):
'ikepolicies': 'ikepolicy',
'ipsec_site_connections': 'ipsec_site_connection',
'vpnservices': 'vpnservice',
'endpoint_groups': 'endpoint_group',
'vips': 'vip',
'pools': 'pool',
'members': 'member',
@@ -794,6 +797,33 @@ class Client(ClientBase):
return self.get(self.security_group_rule_path % (security_group_rule),
params=_params)
@APIParamsCall
def list_endpoint_groups(self, retrieve_all=True, **_params):
"""Fetches a list of all VPN endpoint groups for a tenant."""
return self.list('endpoint_groups', self.endpoint_groups_path,
retrieve_all, **_params)
@APIParamsCall
def show_endpoint_group(self, endpointgroup, **_params):
"""Fetches information for a specific VPN endpoint group."""
return self.get(self.endpoint_group_path % endpointgroup,
params=_params)
@APIParamsCall
def create_endpoint_group(self, body=None):
"""Creates a new VPN endpoint group."""
return self.post(self.endpoint_groups_path, body=body)
@APIParamsCall
def update_endpoint_group(self, endpoint_group, body=None):
"""Updates a VPN endpoint group."""
return self.put(self.endpoint_group_path % endpoint_group, body=body)
@APIParamsCall
def delete_endpoint_group(self, endpoint_group):
"""Deletes the specified VPN endpoint group."""
return self.delete(self.endpoint_group_path % endpoint_group)
@APIParamsCall
def list_vpnservices(self, retrieve_all=True, **_params):
"""Fetches a list of all configured VPN services for a tenant."""