Merge "Add commands to support BGP VPN route control new API extension"
This commit is contained in:
commit
95d64cef77
@ -32,3 +32,6 @@ Network v2
|
||||
|
||||
.. autoprogram-cliff:: openstack.neutronclient.v2
|
||||
:command: bgpvpn router association *
|
||||
|
||||
.. autoprogram-cliff:: openstack.neutronclient.v2
|
||||
:command: bgpvpn port association *
|
||||
|
@ -40,6 +40,7 @@ _attr_map = (
|
||||
nc_osc_utils.LIST_LONG_ONLY),
|
||||
('networks', 'Associated Networks', nc_osc_utils.LIST_LONG_ONLY),
|
||||
('routers', 'Associated Routers', nc_osc_utils.LIST_LONG_ONLY),
|
||||
('ports', 'Associated Ports', nc_osc_utils.LIST_LONG_ONLY),
|
||||
('vni', 'VNI', nc_osc_utils.LIST_LONG_ONLY),
|
||||
)
|
||||
_formatters = {
|
||||
@ -49,6 +50,7 @@ _formatters = {
|
||||
'route_distinguishers': format_columns.ListColumn,
|
||||
'networks': format_columns.ListColumn,
|
||||
'routers': format_columns.ListColumn,
|
||||
'ports': format_columns.ListColumn,
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,3 +24,7 @@ NETWORK_ASSOCS = '%ss' % NETWORK_ASSOC
|
||||
ROUTER_RESOURCE_NAME = 'router'
|
||||
ROUTER_ASSOC = '%s_association' % ROUTER_RESOURCE_NAME
|
||||
ROUTER_ASSOCS = '%ss' % ROUTER_ASSOC
|
||||
|
||||
PORT_RESOURCE_NAME = 'port'
|
||||
PORT_ASSOC = '%s_association' % PORT_RESOURCE_NAME
|
||||
PORT_ASSOCS = '%ss' % PORT_ASSOC
|
||||
|
315
neutronclient/osc/v2/networking_bgpvpn/port_association.py
Normal file
315
neutronclient/osc/v2/networking_bgpvpn/port_association.py
Normal file
@ -0,0 +1,315 @@
|
||||
# Copyright (c) 2017 Juniper networks 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 logging
|
||||
|
||||
from osc_lib.cli import format_columns
|
||||
from osc_lib.cli import parseractions
|
||||
|
||||
from neutronclient._i18n import _
|
||||
from neutronclient.osc import utils as nc_osc_utils
|
||||
from neutronclient.osc.v2.networking_bgpvpn import constants
|
||||
from neutronclient.osc.v2.networking_bgpvpn import resource_association
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BgpvpnPortAssoc(object):
|
||||
_assoc_res_name = constants.PORT_RESOURCE_NAME
|
||||
_resource = constants.PORT_ASSOC
|
||||
_resource_plural = constants.PORT_ASSOCS
|
||||
|
||||
_attr_map = (
|
||||
('id', 'ID', nc_osc_utils.LIST_BOTH),
|
||||
('tenant_id', 'Project', nc_osc_utils.LIST_LONG_ONLY),
|
||||
('%s_id' % _assoc_res_name, '%s ID' % _assoc_res_name.capitalize(),
|
||||
nc_osc_utils.LIST_BOTH),
|
||||
('prefix_routes', 'Prefix Routes (BGP LOCAL_PREF)',
|
||||
nc_osc_utils.LIST_LONG_ONLY),
|
||||
('bgpvpn_routes', 'BGP VPN Routes (BGP LOCAL_PREF)',
|
||||
nc_osc_utils.LIST_LONG_ONLY),
|
||||
('advertise_fixed_ips', "Advertise Port's Fixed IPs",
|
||||
nc_osc_utils.LIST_LONG_ONLY),
|
||||
)
|
||||
_formatters = {
|
||||
'prefix_routes': format_columns.ListColumn,
|
||||
'bgpvpn_routes': format_columns.ListColumn,
|
||||
}
|
||||
|
||||
def _transform_resource(self, data):
|
||||
"""Transforms BGP VPN port association routes property
|
||||
|
||||
That permits to easily format the command output with ListColumn
|
||||
formater and separate the two route types.
|
||||
|
||||
{'routes':
|
||||
[
|
||||
{
|
||||
'type': 'prefix',
|
||||
'local_pref': 100,
|
||||
'prefix': '8.8.8.0/27',
|
||||
},
|
||||
{
|
||||
'type': 'prefix',
|
||||
'local_pref': 42,
|
||||
'prefix': '80.50.30.0/28',
|
||||
},
|
||||
{
|
||||
'type': 'bgpvpn',
|
||||
'local_pref': 50,
|
||||
'bgpvpn': '157d72a9-9968-48e7-8087-6c9a9bc7a181',
|
||||
},
|
||||
{
|
||||
'type': 'bgpvpn',
|
||||
'bgpvpn': 'd5c7aaab-c7e8-48b3-85ca-a115c00d3603',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
to
|
||||
|
||||
{
|
||||
'prefix_routes': [
|
||||
'8.8.8.0/27 (100)',
|
||||
'80.50.30.0/28 (42)',
|
||||
],
|
||||
'bgpvpn_routes': [
|
||||
'157d72a9-9968-48e7-8087-6c9a9bc7a181 (50)',
|
||||
'd5c7aaab-c7e8-48b3-85ca-a115c00d3603',
|
||||
],
|
||||
}
|
||||
"""
|
||||
for route in data.get('routes', []):
|
||||
local_pref = ''
|
||||
if route.get('local_pref'):
|
||||
local_pref = ' (%d)' % route.get('local_pref')
|
||||
if route['type'] == 'prefix':
|
||||
data.setdefault('prefix_routes', []).append(
|
||||
'%s%s' % (route['prefix'], local_pref)
|
||||
)
|
||||
elif route['type'] == 'bgpvpn':
|
||||
data.setdefault('bgpvpn_routes', []).append(
|
||||
'%s%s' % (route['bgpvpn_id'], local_pref)
|
||||
)
|
||||
else:
|
||||
LOG.warning("Unknown route type %s (%s).", route['type'],
|
||||
route)
|
||||
data.pop('routes', None)
|
||||
|
||||
def _get_common_parser(self, parser):
|
||||
"""Adds to parser arguments common to create, set and unset commands.
|
||||
|
||||
:params ArgumentParser parser: argparse object contains all command's
|
||||
arguments
|
||||
"""
|
||||
ADVERTISE_ROUTE = _("Fixed IPs of the port will be advertised to the "
|
||||
"BGP VPN%s") % (
|
||||
_(' (default)') if self._action == 'create'
|
||||
else "")
|
||||
NOT_ADVERTISE_ROUTE = _("Fixed IPs of the port will not be advertised "
|
||||
"to the BGP VPN")
|
||||
|
||||
LOCAL_PREF_VALUE = _(". Optionally, can control the value of the BGP "
|
||||
"LOCAL_PREF of the routes that will be "
|
||||
"advertised")
|
||||
|
||||
ADD_PREFIX_ROUTE = _("Add prefix route in CIDR notation%s") %\
|
||||
LOCAL_PREF_VALUE
|
||||
REMOVE_PREFIX_ROUTE = _("Remove prefix route in CIDR notation")
|
||||
REPEAT_PREFIX_ROUTE = _("repeat option for multiple prefix routes")
|
||||
|
||||
ADD_BGVPVPN_ROUTE = _("Add BGP VPN route for route leaking%s") %\
|
||||
LOCAL_PREF_VALUE
|
||||
REMOVE_BGPVPN_ROUTE = _("Remove BGP VPN route")
|
||||
REPEAT_BGPVPN_ROUTE = _("repeat option for multiple BGP VPN routes")
|
||||
|
||||
group_advertise_fixed_ips = parser.add_mutually_exclusive_group()
|
||||
group_advertise_fixed_ips.add_argument(
|
||||
'--advertise-fixed-ips',
|
||||
action='store_true',
|
||||
help=NOT_ADVERTISE_ROUTE if self._action == 'unset'
|
||||
else ADVERTISE_ROUTE,
|
||||
)
|
||||
group_advertise_fixed_ips.add_argument(
|
||||
'--no-advertise-fixed-ips',
|
||||
action='store_true',
|
||||
help=ADVERTISE_ROUTE if self._action == 'unset'
|
||||
else NOT_ADVERTISE_ROUTE,
|
||||
)
|
||||
|
||||
if self._action in ['create', 'set']:
|
||||
parser.add_argument(
|
||||
'--prefix-route',
|
||||
metavar="prefix=<cidr>[,local_pref=<integer>]",
|
||||
dest='prefix_routes',
|
||||
action=parseractions.MultiKeyValueAction,
|
||||
required_keys=['prefix'],
|
||||
optional_keys=['local_pref'],
|
||||
help="%s (%s)" % (ADD_PREFIX_ROUTE, REPEAT_PREFIX_ROUTE),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--bgpvpn-route',
|
||||
metavar="bgpvpn=<BGP VPN ID or name>[,local_pref=<integer>]",
|
||||
dest='bgpvpn_routes',
|
||||
action=parseractions.MultiKeyValueAction,
|
||||
required_keys=['bgpvpn'],
|
||||
optional_keys=['local_pref'],
|
||||
help="%s (%s)" % (ADD_BGVPVPN_ROUTE, REPEAT_BGPVPN_ROUTE),
|
||||
)
|
||||
else:
|
||||
parser.add_argument(
|
||||
'--prefix-route',
|
||||
metavar="<cidr>",
|
||||
dest='prefix_routes',
|
||||
action='append',
|
||||
help="%s (%s)" % (REMOVE_PREFIX_ROUTE, REPEAT_PREFIX_ROUTE),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--bgpvpn-route',
|
||||
metavar="<BGP VPN ID or name>",
|
||||
dest='bgpvpn_routes',
|
||||
action='append',
|
||||
help="%s (%s)" % (REMOVE_BGPVPN_ROUTE, REPEAT_BGPVPN_ROUTE),
|
||||
)
|
||||
if self._action != 'create':
|
||||
parser.add_argument(
|
||||
'--no-prefix-route' if self._action == 'set' else
|
||||
'--all-prefix-routes',
|
||||
dest='purge_prefix_route',
|
||||
action='store_true',
|
||||
help=_('Empty prefix route list'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-bgpvpn-route' if self._action == 'set' else
|
||||
'--all-bgpvpn-routes',
|
||||
dest='purge_bgpvpn_route',
|
||||
action='store_true',
|
||||
help=_('Empty BGP VPN route list'),
|
||||
)
|
||||
|
||||
def _args2body(self, bgpvpn_id, args):
|
||||
client = self.app.client_manager.neutronclient
|
||||
attrs = {}
|
||||
|
||||
if self._action != 'create':
|
||||
assoc = client.find_resource_by_id(
|
||||
self._resource,
|
||||
args.resource_association_id,
|
||||
cmd_resource='bgpvpn_%s_assoc' % self._assoc_res_name,
|
||||
parent_id=bgpvpn_id)
|
||||
else:
|
||||
assoc = {'routes': []}
|
||||
|
||||
if args.advertise_fixed_ips:
|
||||
attrs['advertise_fixed_ips'] = self._action != 'unset'
|
||||
elif args.no_advertise_fixed_ips:
|
||||
attrs['advertise_fixed_ips'] = self._action == 'unset'
|
||||
|
||||
prefix_routes = None
|
||||
if 'purge_prefix_route' in args and args.purge_prefix_route:
|
||||
prefix_routes = []
|
||||
else:
|
||||
prefix_routes = {r['prefix']: r.get('local_pref')
|
||||
for r in assoc['routes']
|
||||
if r['type'] == 'prefix'}
|
||||
if args.prefix_routes:
|
||||
if self._action in ['create', 'set']:
|
||||
prefix_routes.update({r['prefix']: r.get('local_pref')
|
||||
for r in args.prefix_routes})
|
||||
elif self._action == 'unset':
|
||||
for prefix in args.prefix_routes:
|
||||
prefix_routes.pop(prefix, None)
|
||||
|
||||
bgpvpn_routes = None
|
||||
if 'purge_bgpvpn_route' in args and args.purge_bgpvpn_route:
|
||||
bgpvpn_routes = []
|
||||
else:
|
||||
bgpvpn_routes = {r['bgpvpn_id']: r.get('local_pref')
|
||||
for r in assoc['routes']
|
||||
if r['type'] == 'bgpvpn'}
|
||||
if args.bgpvpn_routes:
|
||||
if self._action == 'unset':
|
||||
routes = [
|
||||
{'bgpvpn': bgpvpn} for bgpvpn in args.bgpvpn_routes
|
||||
]
|
||||
else:
|
||||
routes = args.bgpvpn_routes
|
||||
args_bgpvpn_routes = {
|
||||
client.find_resource(constants.BGPVPN, r['bgpvpn'])['id']:
|
||||
r.get('local_pref')
|
||||
for r in routes
|
||||
}
|
||||
if self._action in ['create', 'set']:
|
||||
bgpvpn_routes.update(args_bgpvpn_routes)
|
||||
elif self._action == 'unset':
|
||||
for bgpvpn_id in args_bgpvpn_routes:
|
||||
bgpvpn_routes.pop(bgpvpn_id, None)
|
||||
|
||||
if prefix_routes is not None and not prefix_routes:
|
||||
attrs.setdefault('routes', [])
|
||||
elif prefix_routes is not None:
|
||||
for prefix, local_pref in prefix_routes.items():
|
||||
route = {
|
||||
'type': 'prefix',
|
||||
'prefix': prefix,
|
||||
}
|
||||
if local_pref:
|
||||
route['local_pref'] = int(local_pref)
|
||||
attrs.setdefault('routes', []).append(route)
|
||||
if bgpvpn_routes is not None and not bgpvpn_routes:
|
||||
attrs.setdefault('routes', [])
|
||||
elif bgpvpn_routes is not None:
|
||||
for bgpvpn_id, local_pref in bgpvpn_routes.items():
|
||||
route = {
|
||||
'type': 'bgpvpn',
|
||||
'bgpvpn_id': bgpvpn_id,
|
||||
}
|
||||
if local_pref:
|
||||
route['local_pref'] = int(local_pref)
|
||||
attrs.setdefault('routes', []).append(route)
|
||||
|
||||
return {self._resource: attrs}
|
||||
|
||||
|
||||
class CreateBgpvpnPortAssoc(BgpvpnPortAssoc,
|
||||
resource_association.CreateBgpvpnResAssoc):
|
||||
_description = _("Create a BGP VPN port association")
|
||||
|
||||
|
||||
class SetBgpvpnPortAssoc(BgpvpnPortAssoc,
|
||||
resource_association.SetBgpvpnResAssoc):
|
||||
_description = _("Set BGP VPN port association properties")
|
||||
|
||||
|
||||
class UnsetBgpvpnPortAssoc(BgpvpnPortAssoc,
|
||||
resource_association.UnsetBgpvpnResAssoc):
|
||||
_description = _("Unset BGP VPN port association properties")
|
||||
|
||||
|
||||
class DeleteBgpvpnPortAssoc(BgpvpnPortAssoc,
|
||||
resource_association.DeleteBgpvpnResAssoc):
|
||||
_description = _("Delete a BGP VPN port association(s) for a given BGP "
|
||||
"VPN")
|
||||
|
||||
|
||||
class ListBgpvpnPortAssoc(BgpvpnPortAssoc,
|
||||
resource_association.ListBgpvpnResAssoc):
|
||||
_description = _("List BGP VPN port associations for a given BGP VPN")
|
||||
|
||||
|
||||
class ShowBgpvpnPortAssoc(BgpvpnPortAssoc,
|
||||
resource_association.ShowBgpvpnResAssoc):
|
||||
_description = _("Show information of a given BGP VPN port association")
|
@ -16,6 +16,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from osc_lib.cli import parseractions
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib import utils as osc_utils
|
||||
@ -29,6 +30,7 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
class CreateBgpvpnResAssoc(command.ShowOne):
|
||||
"""Create a BGP VPN resource association"""
|
||||
_action = 'create'
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateBgpvpnResAssoc, self).get_parser(prog_name)
|
||||
@ -45,6 +47,11 @@ class CreateBgpvpnResAssoc(command.ShowOne):
|
||||
help=(_("%s to associate the BGP VPN (name or ID)") %
|
||||
self._assoc_res_name.capitalize()),
|
||||
)
|
||||
|
||||
get_common_parser = getattr(self, '_get_common_parser', None)
|
||||
if callable(get_common_parser):
|
||||
get_common_parser(parser)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
@ -66,7 +73,16 @@ class CreateBgpvpnResAssoc(command.ShowOne):
|
||||
parsed_args.project_domain,
|
||||
).id
|
||||
body[self._resource]['tenant_id'] = project_id
|
||||
|
||||
arg2body = getattr(self, '_args2body', None)
|
||||
if callable(arg2body):
|
||||
body[self._resource].update(
|
||||
arg2body(bgpvpn['id'], parsed_args)[self._resource])
|
||||
|
||||
obj = create_method(bgpvpn['id'], body)[self._resource]
|
||||
transform = getattr(self, '_transform_resource', None)
|
||||
if callable(transform):
|
||||
transform(obj)
|
||||
columns, display_columns = nc_osc_utils.get_columns(obj,
|
||||
self._attr_map)
|
||||
data = osc_utils.get_dict_properties(obj, columns,
|
||||
@ -74,6 +90,48 @@ class CreateBgpvpnResAssoc(command.ShowOne):
|
||||
return display_columns, data
|
||||
|
||||
|
||||
class SetBgpvpnResAssoc(command.Command):
|
||||
"""Set BGP VPN resource association properties"""
|
||||
_action = 'set'
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SetBgpvpnResAssoc, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'resource_association_id',
|
||||
metavar="<%s association ID>" % self._assoc_res_name,
|
||||
help=(_("%s association ID to update") %
|
||||
self._assoc_res_name.capitalize()),
|
||||
)
|
||||
parser.add_argument(
|
||||
'bgpvpn',
|
||||
metavar="<bgpvpn>",
|
||||
help=(_("BGP VPN the %s association belongs to (name or ID)") %
|
||||
self._assoc_res_name),
|
||||
)
|
||||
|
||||
get_common_parser = getattr(self, '_get_common_parser', None)
|
||||
if callable(get_common_parser):
|
||||
get_common_parser(parser)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.neutronclient
|
||||
update_method = getattr(
|
||||
client, 'update_bgpvpn_%s_assoc' % self._assoc_res_name)
|
||||
bgpvpn = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)
|
||||
arg2body = getattr(self, '_args2body', None)
|
||||
if callable(arg2body):
|
||||
body = arg2body(bgpvpn['id'], parsed_args)
|
||||
update_method(bgpvpn['id'], parsed_args.resource_association_id,
|
||||
body)
|
||||
|
||||
|
||||
class UnsetBgpvpnResAssoc(SetBgpvpnResAssoc):
|
||||
"""Unset BGP VPN resource association properties"""
|
||||
_action = 'unset'
|
||||
|
||||
|
||||
class DeleteBgpvpnResAssoc(command.Command):
|
||||
"""Remove a BGP VPN resource association(s) for a given BGP VPN"""
|
||||
|
||||
@ -89,7 +147,8 @@ class DeleteBgpvpnResAssoc(command.Command):
|
||||
parser.add_argument(
|
||||
'bgpvpn',
|
||||
metavar="<bgpvpn>",
|
||||
help=_("BGP VPN the association belongs to (name or ID)"),
|
||||
help=(_("BGP VPN the %s association belongs to (name or ID)") %
|
||||
self._assoc_res_name),
|
||||
)
|
||||
return parser
|
||||
|
||||
@ -137,6 +196,13 @@ class ListBgpvpnResAssoc(command.Lister):
|
||||
action='store_true',
|
||||
help=_("List additional fields in output"),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--property',
|
||||
metavar="<key=value>",
|
||||
help=_("Filter property to apply on returned BGP VPNs (repeat to "
|
||||
"filter on multiple properties)"),
|
||||
action=parseractions.KeyValueAction,
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
@ -144,8 +210,14 @@ class ListBgpvpnResAssoc(command.Lister):
|
||||
list_method = getattr(client,
|
||||
'list_bgpvpn_%s_assocs' % self._assoc_res_name)
|
||||
bgpvpn = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)
|
||||
params = {}
|
||||
if parsed_args.property:
|
||||
params.update(parsed_args.property)
|
||||
objs = list_method(bgpvpn['id'],
|
||||
retrieve_all=True)[self._resource_plural]
|
||||
retrieve_all=True, **params)[self._resource_plural]
|
||||
transform = getattr(self, '_transform_resource', None)
|
||||
if callable(transform):
|
||||
[transform(obj) for obj in objs]
|
||||
headers, columns = nc_osc_utils.get_column_definitions(
|
||||
self._attr_map, long_listing=parsed_args.long)
|
||||
return (headers, (osc_utils.get_dict_properties(
|
||||
@ -181,6 +253,9 @@ class ShowBgpvpnResAssoc(command.ShowOne):
|
||||
cmd_resource='bgpvpn_%s_assoc' % self._assoc_res_name,
|
||||
parent_id=bgpvpn['id'])
|
||||
obj = show_method(bgpvpn['id'], assoc['id'])[self._resource]
|
||||
transform = getattr(self, '_transform_resource', None)
|
||||
if callable(transform):
|
||||
transform(obj)
|
||||
columns, display_columns = nc_osc_utils.get_columns(obj,
|
||||
self._attr_map)
|
||||
data = osc_utils.get_dict_properties(obj, columns,
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016 Juniper Routerworks Inc.
|
||||
# Copyright (c) 2016 Juniper networks Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -26,11 +26,18 @@ from neutronclient.osc.v2.networking_bgpvpn.resource_association import\
|
||||
DeleteBgpvpnResAssoc
|
||||
from neutronclient.osc.v2.networking_bgpvpn.resource_association import\
|
||||
ListBgpvpnResAssoc
|
||||
from neutronclient.osc.v2.networking_bgpvpn.resource_association import\
|
||||
SetBgpvpnResAssoc
|
||||
from neutronclient.osc.v2.networking_bgpvpn.resource_association import\
|
||||
ShowBgpvpnResAssoc
|
||||
from neutronclient.osc.v2.networking_bgpvpn.resource_association import\
|
||||
UnsetBgpvpnResAssoc
|
||||
from neutronclient.tests.unit.osc.v2 import fakes as test_fakes
|
||||
|
||||
|
||||
_FAKE_PROJECT_ID = 'fake_project_id'
|
||||
|
||||
|
||||
class TestNeutronClientBgpvpn(test_fakes.TestNeutronClientOSCV2):
|
||||
|
||||
def setUp(self):
|
||||
@ -38,11 +45,11 @@ class TestNeutronClientBgpvpn(test_fakes.TestNeutronClientOSCV2):
|
||||
self.neutronclient.find_resource = mock.Mock(
|
||||
side_effect=lambda resource, name_or_id, project_id=None,
|
||||
cmd_resource=None, parent_id=None, fields=None:
|
||||
{'id': name_or_id})
|
||||
{'id': name_or_id, 'tenant_id': _FAKE_PROJECT_ID})
|
||||
self.neutronclient.find_resource_by_id = mock.Mock(
|
||||
side_effect=lambda resource, resource_id, cmd_resource=None,
|
||||
parent_id=None, fields=None:
|
||||
{'id': resource_id})
|
||||
{'id': resource_id, 'tenant_id': _FAKE_PROJECT_ID})
|
||||
nc_osc_utils.find_project = mock.Mock(
|
||||
side_effect=lambda _, name_or_id, __: mock.Mock(id=name_or_id))
|
||||
|
||||
@ -59,7 +66,7 @@ class FakeBgpvpn(object):
|
||||
# Set default attributes.
|
||||
bgpvpn_attrs = {
|
||||
'id': 'fake_bgpvpn_id',
|
||||
'tenant_id': 'fake_project_id',
|
||||
'tenant_id': _FAKE_PROJECT_ID,
|
||||
'name': '',
|
||||
'type': 'l3',
|
||||
'route_targets': [],
|
||||
@ -68,11 +75,13 @@ class FakeBgpvpn(object):
|
||||
'route_distinguishers': [],
|
||||
'networks': [],
|
||||
'routers': [],
|
||||
'ports': [],
|
||||
'vni': 100,
|
||||
}
|
||||
|
||||
# Overwrite default attributes.
|
||||
bgpvpn_attrs.update(attrs)
|
||||
|
||||
return copy.deepcopy(bgpvpn_attrs)
|
||||
|
||||
@staticmethod
|
||||
@ -108,6 +117,14 @@ class CreateBgpvpnFakeResAssoc(BgpvpnFakeAssoc, CreateBgpvpnResAssoc):
|
||||
pass
|
||||
|
||||
|
||||
class SetBgpvpnFakeResAssoc(BgpvpnFakeAssoc, SetBgpvpnResAssoc):
|
||||
pass
|
||||
|
||||
|
||||
class UnsetBgpvpnFakeResAssoc(BgpvpnFakeAssoc, UnsetBgpvpnResAssoc):
|
||||
pass
|
||||
|
||||
|
||||
class DeleteBgpvpnFakeResAssoc(BgpvpnFakeAssoc, DeleteBgpvpnResAssoc):
|
||||
pass
|
||||
|
||||
@ -132,7 +149,7 @@ class FakeResource(object):
|
||||
# Set default attributes.
|
||||
res_attrs = {
|
||||
'id': 'fake_resource_id',
|
||||
'tenant_id': 'fake_project_id',
|
||||
'tenant_id': _FAKE_PROJECT_ID,
|
||||
}
|
||||
|
||||
# Overwrite default attributes.
|
||||
|
@ -126,6 +126,8 @@ class TestCreateBgpvpn(fakes.TestNeutronClientBgpvpn):
|
||||
fake_bgpvpn_call.pop('id')
|
||||
fake_bgpvpn_call.pop('networks')
|
||||
fake_bgpvpn_call.pop('routers')
|
||||
fake_bgpvpn_call.pop('ports')
|
||||
|
||||
self.neutronclient.create_bgpvpn.assert_called_once_with(
|
||||
{constants.BGPVPN: fake_bgpvpn_call})
|
||||
self.assertEqual(sorted_headers, cols)
|
||||
|
@ -81,6 +81,7 @@ class TestCreateResAssoc(fakes.TestNeutronClientBgpvpn):
|
||||
|
||||
fake_res_assoc_call = copy.deepcopy(fake_res_assoc)
|
||||
fake_res_assoc_call.pop('id')
|
||||
|
||||
self.neutronclient.create_bgpvpn_fake_resource_assoc.\
|
||||
assert_called_once_with(
|
||||
fake_bgpvpn['id'],
|
||||
@ -89,6 +90,36 @@ class TestCreateResAssoc(fakes.TestNeutronClientBgpvpn):
|
||||
self.assertEqual(_get_data(fake_res_assoc), data)
|
||||
|
||||
|
||||
class TestSetResAssoc(fakes.TestNeutronClientBgpvpn):
|
||||
def setUp(self):
|
||||
super(TestSetResAssoc, self).setUp()
|
||||
self.cmd = fakes.SetBgpvpnFakeResAssoc(self.app, self.namespace)
|
||||
|
||||
def test_set_resource_association(self):
|
||||
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
|
||||
fake_res = fakes.FakeResource.create_one_resource()
|
||||
fake_res_assoc = fakes.FakeResAssoc.create_one_resource_association(
|
||||
fake_res)
|
||||
self.neutronclient.update_bgpvpn_fake_resource_assoc = mock.Mock(
|
||||
return_value={fakes.BgpvpnFakeAssoc._resource: fake_res_assoc})
|
||||
arglist = [
|
||||
fake_res_assoc['id'],
|
||||
fake_bgpvpn['id'],
|
||||
]
|
||||
verifylist = [
|
||||
('resource_association_id', fake_res_assoc['id']),
|
||||
('bgpvpn', fake_bgpvpn['id']),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.neutronclient.update_bgpvpn_fake_resource_assoc.\
|
||||
assert_not_called()
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestDeleteResAssoc(fakes.TestNeutronClientBgpvpn):
|
||||
def setUp(self):
|
||||
super(TestDeleteResAssoc, self).setUp()
|
||||
|
@ -651,6 +651,8 @@ class Client(ClientBase):
|
||||
bgpvpn_router_associations_path = "/bgpvpn/bgpvpns/%s/router_associations"
|
||||
bgpvpn_router_association_path =\
|
||||
"/bgpvpn/bgpvpns/%s/router_associations/%s"
|
||||
bgpvpn_port_associations_path = "/bgpvpn/bgpvpns/%s/port_associations"
|
||||
bgpvpn_port_association_path = "/bgpvpn/bgpvpns/%s/port_associations/%s"
|
||||
network_logs_path = "/log/logs"
|
||||
network_log_path = "/log/logs/%s"
|
||||
network_loggables_path = "/log/loggable-resources"
|
||||
@ -707,6 +709,7 @@ class Client(ClientBase):
|
||||
'bgpvpns': 'bgpvpn',
|
||||
'network_associations': 'network_association',
|
||||
'router_associations': 'router_association',
|
||||
'port_associations': 'port_association',
|
||||
'flow_classifiers': 'flow_classifier',
|
||||
'port_pairs': 'port_pair',
|
||||
'port_pair_groups': 'port_pair_group',
|
||||
@ -2193,6 +2196,34 @@ class Client(ClientBase):
|
||||
return self.delete(
|
||||
self.bgpvpn_router_association_path % (bgpvpn, router_assoc))
|
||||
|
||||
def list_bgpvpn_port_assocs(self, bgpvpn, retrieve_all=True, **_params):
|
||||
"""Fetches a list of port associations for a given BGP VPN."""
|
||||
return self.list('port_associations',
|
||||
self.bgpvpn_port_associations_path % bgpvpn,
|
||||
retrieve_all, **_params)
|
||||
|
||||
def show_bgpvpn_port_assoc(self, bgpvpn, port_assoc, **_params):
|
||||
"""Fetches information of a certain BGP VPN's port association"""
|
||||
return self.get(
|
||||
self.bgpvpn_port_association_path % (bgpvpn, port_assoc),
|
||||
params=_params)
|
||||
|
||||
def create_bgpvpn_port_assoc(self, bgpvpn, body=None):
|
||||
"""Creates a new BGP VPN port association"""
|
||||
return self.post(self.bgpvpn_port_associations_path % bgpvpn,
|
||||
body=body)
|
||||
|
||||
def update_bgpvpn_port_assoc(self, bgpvpn, port_assoc, body=None):
|
||||
"""Updates a BGP VPN port association"""
|
||||
return self.put(
|
||||
self.bgpvpn_port_association_path % (bgpvpn, port_assoc),
|
||||
body=body)
|
||||
|
||||
def delete_bgpvpn_port_assoc(self, bgpvpn, port_assoc):
|
||||
"""Deletes the specified BGP VPN port association"""
|
||||
return self.delete(
|
||||
self.bgpvpn_port_association_path % (bgpvpn, port_assoc))
|
||||
|
||||
def create_sfc_port_pair(self, body=None):
|
||||
"""Creates a new Port Pair."""
|
||||
return self.post(self.sfc_port_pairs_path, body=body)
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add BGP VPN `port association <https://developer.openstack.org/api-ref/network/v2/index.html#port-associations>`_
|
||||
support to the CLI, which are introduced for BGP VPN interconnections by the
|
||||
``bgpvpn-routes-control`` API extension.
|
@ -124,6 +124,12 @@ openstack.neutronclient.v2 =
|
||||
bgpvpn_router_association_delete = neutronclient.osc.v2.networking_bgpvpn.router_association:DeleteBgpvpnRouterAssoc
|
||||
bgpvpn_router_association_list = neutronclient.osc.v2.networking_bgpvpn.router_association:ListBgpvpnRouterAssoc
|
||||
bgpvpn_router_association_show = neutronclient.osc.v2.networking_bgpvpn.router_association:ShowBgpvpnRouterAssoc
|
||||
bgpvpn_port_association_create = neutronclient.osc.v2.networking_bgpvpn.port_association:CreateBgpvpnPortAssoc
|
||||
bgpvpn_port_association_set = neutronclient.osc.v2.networking_bgpvpn.port_association:SetBgpvpnPortAssoc
|
||||
bgpvpn_port_association_unset = neutronclient.osc.v2.networking_bgpvpn.port_association:UnsetBgpvpnPortAssoc
|
||||
bgpvpn_port_association_delete = neutronclient.osc.v2.networking_bgpvpn.port_association:DeleteBgpvpnPortAssoc
|
||||
bgpvpn_port_association_list = neutronclient.osc.v2.networking_bgpvpn.port_association:ListBgpvpnPortAssoc
|
||||
bgpvpn_port_association_show = neutronclient.osc.v2.networking_bgpvpn.port_association:ShowBgpvpnPortAssoc
|
||||
|
||||
network_loggable_resources_list = neutronclient.osc.v2.logging.network_log:ListLoggableResource
|
||||
network_log_create = neutronclient.osc.v2.logging.network_log:CreateNetworkLog
|
||||
|
Loading…
Reference in New Issue
Block a user