Add BGP VPN OSC commands

Change-Id: Ib1ba356e994a98712e00a11ff045df67fbe4c7ea
Closes-Bug: #1650204
This commit is contained in:
Édouard Thuleau 2016-12-23 19:30:20 +01:00
parent 30fdde8e4e
commit f2ace0415d
14 changed files with 2188 additions and 0 deletions

View File

@ -0,0 +1,383 @@
======
bgpvpn
======
A **bgpvpn** resource contains a set of parameters to define a BGP-based VPN.
BGP-based IP VPNs networks are widely used in the industry especially for
enterprises. The networking BGP VPN project aims at supporting inter-connection
between L3VPNs and Neutron resources, i.e. Networks, Routers and Ports.
Network v2
bgpvpn create
-------------
Create a BGP VPN resource for a given project
.. program:: bgpvpn create
.. code:: bash
openstack bgpvpn create
.. _bgpvpn_create-bgpvpn:
.. option:: --project <project>
Owner's project (name or ID)
.. option:: --project-domain <project-domain>
Domain the project belongs to (name or ID). This can be used in case
collisions between project names exist
.. option:: --name <name>
Name for the BGP VPN.
.. option:: --route-target <route-target>
Add Route Target to import list (repeat option for multiple Route Targets)
.. option:: --import-target <import-target>
Add Route Target to import list (repeat option for multiple Route Targets)
.. option:: --export-target <export-target>
Add Route Target to export list (repeat option for multiple RouteTargets)
.. option:: --route-distinguisher <route-distinguisher>
Add Route Distinguisher to the list of Route Distinguishers from which a
Route Distinguishers will be picked from to advertise a VPN route (repeat
option for multiple Route Distinguishers)
.. option:: --type {l2,l3}
BGP VPN type selection between IP VPN (l3) and Ethernet VPN (l2)
(default: l3)
bgpvpn set
----------
Set BGP VPN properties
.. program:: bgpvpn set
.. code:: bash
openstack bgpvpn set
.. _bgpvpn_set-bgpvpn:
.. describe:: <bgpvpn>
BGP VPN to update (name or ID)
.. option:: --name <name>
Name for the BGP VPN
.. option:: --route-target <route-target>
Add Route Target to import list (repeat option for multiple Route Targets)
.. option:: --no-route-target
Empty route target list.
.. option:: --import-target <import-target>
Add Route Target to import list (repeat option for multiple Route Targets)
.. option:: --no-import-target
Empty import route target list
.. option:: --export-target <export-target>
Add Route Target to export list (repeat option for multiple Route Targets)
.. option:: --no-export-target
Empty export route target list
.. option:: --route-distinguisher <route-distinguisher>
Add Route Distinguisher to the list of Route Distinguishers from which a
Route Distinguishers will be picked from to advertise a VPN route (repeat
option for multiple Route Distinguishers)
.. option:: --no-route-distinguisher
Empty route distinguisher list
bgpvpn unset
----------
Unset BGP VPN properties
.. program:: bgpvpn unset
.. code:: bash
openstack bgpvpn unset
.. _bgpvpn_unset-bgpvpn:
.. describe:: <bgpvpn>
BGP VPN to update (name or ID)
.. option:: --route-target <route-target>
Remove Route Target from import/export list (repeat option for multiple
Route Targets)
.. option:: --all-route-target
Empty route target list
.. option:: --import-target <import-target>
Remove Route Target from import list (repeat option for multiple Route
Targets)
.. option:: --all-import-target
Empty import route target list
.. option:: --export-target <export-target>
Remove Route Target from export list (repeat option for multiple Route
Targets)
.. option:: --all-export-target
Empty export route target list
.. option:: --route-distinguisher <route-distinguisher>
Remove Route Distinguisher from the list of Route Distinguishers from which
a Route Distinguishers will be picked from to advertise a VPN route
(repeat option for multiple Route Distinguishers)
.. option:: --all-route-distinguisher
Empty route distinguisher list
bgpvpn delete
-------------
Delete BGP VPN resource(s)
.. program:: bgpvpn delete
.. code:: bash
openstack bgpvpn delete
<bgpvpn> [<bgpvpn> ...]
.. _bgpvpn_delete-bgpvpn:
.. describe:: <bgpvpn>
BGP VPN(s) to delete (name or ID)
bgpvpn list
-----------
List BGP VPN resources
.. program:: bgpvpn list
.. code:: bash
openstack bgpvpn list
.. _bgpvpn_list-bgpvpn:
.. option:: --project <project>
Owner's project (name or ID)
.. option:: --project-domain <project-domain>
Domain the project belongs to (name or ID). This can be used in case
collisions between project names exist.
.. option:: --long
List additional fields in output
.. option:: --property <key=value>
Filter property to apply on returned BGP VPNs (repeat to filter on multiple
properties)
bgpvpn show
-----------
Show information of a given BGP VPN
.. program:: bgpvpn show
.. code:: bash
openstack bgpvpn show
.. _bgpvpn_show-bgpvpn:
.. describe:: <bgpvpn>
BGP VPN to display (name or ID)
bgpvpn network association create
---------------------------------
Create a BGP VPN network association
.. program:: bgpvpn network association create
.. code:: bash
openstack bgpvpn network association create
.. _bgpvpn_net-assoc_create-bgpvpn:
.. describe:: <bgpvpn>
ID or name of the BGP VPN
.. describe:: <network>
ID or name of the network
.. option:: --project <project>
Owner's project (name or ID)
.. option:: --project-domain <project-domain>
Domain the project belongs to (name or ID). This can be used in case
collisions between project names exist.
bgpvpn network association delete
---------------------------------
Remove a BGP VPN network association(s) for a given BGP VPN
.. program:: bgpvpn network association delete
.. code:: bash
openstack bgpvpn network association delete
<network association>[<network association> ...] <bgpvpn>
.. _bgpvpn_net-assoc_delete-bgpvpn:
.. describe:: <network association>
ID(s) of the network association(s) to remove
.. describe:: <bgpvpn>
ID or name of the BGP VPN
bgpvpn network association list
-------------------------------
List BGP VPN network associations for a given BGP VPN
.. program:: bgpvpn network association list
.. code:: bash
openstack bgpvpn network association list
.. _bgpvpn_net-assoc_list-bgpvpn:
.. describe:: <bgpvpn>
ID or name of the BGP VPN
.. option:: --long
List additional fields in output
bgpvpn network association show
-------------------------------
Show information of a given BGP VPN network association
.. program:: bgpvpn network association show
.. code:: bash
openstack bgpvpn network association show
.. _bgpvpn_net-assoc_show-bgpvpn:
.. describe:: <network association>
ID of the network association to look up
.. describe:: <bgpvpn>
BGP VPN the association belongs to (name or ID)
bgpvpn router association create
--------------------------------
Create a BGP VPN router association
.. program:: bgpvpn router association create
.. code:: bash
openstack bgpvpn router association create
.. _bgpvpn_router-assoc_create-bgpvpn:
.. describe:: <bgpvpn>
ID or name of the BGP VPN
.. describe:: <router>
ID or name of the router.
.. option:: --project <project>
Owner's project (name or ID)
.. option:: --project-domain <project-domain>
Domain the project belongs to (name or ID). This can be used in case
collisions between project names exist.
bgpvpn router association delete
--------------------------------
Delete a BGP VPN router association(s) for a given BGP VPN
.. program:: bgpvpn router association delete
.. code:: bash
openstack bgpvpn router association delete
<router association>[<router association> ...] <bgpvpn>
.. _bgpvpn_router-assoc_delete-bgpvpn:
.. describe:: <router association>
ID(s) of the router association(s) to delete.
.. describe:: <bgpvpn>
ID or name of the BGP VPN
bgpvpn router association list
------------------------------
List BGP VPN router associations for a given BGP VPN
.. program:: bgpvpn router association list
.. code:: bash
openstack bgpvpn router association list
.. _bgpvpn_router-assoc_list-bgpvpn:
.. describe:: <bgpvpn>
ID or name of the BGP VPN
.. option:: --long
List additional fields in output
bgpvpn router association show
------------------------------
Show information of a given BGP VPN router association
.. program:: bgpvpn router association show
.. code:: bash
openstack bgpvpn router association show
.. _bgpvpn_router-assoc_show-bgpvpn:
.. describe:: <router association>
ID of the router association to look up
.. describe:: <bgpvpn>
BGP VPN the association belongs to (name or ID)

View File

@ -0,0 +1,385 @@
# Copyright (c) 2016 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.parseractions import KeyValueAction
from osc_lib.command import command
from osc_lib import exceptions
from osc_lib import utils as osc_utils
from neutronclient._i18n import _
from neutronclient._i18n import _LE
from neutronclient._i18n import _LW
from neutronclient.osc import utils as nc_osc_utils
from neutronclient.osc.v2.networking_bgpvpn import constants
LOG = logging.getLogger(__name__)
_attr_map = (
('id', 'ID', nc_osc_utils.LIST_BOTH),
('tenant_id', 'Project ID', nc_osc_utils.LIST_LONG_ONLY),
('name', 'Name', nc_osc_utils.LIST_BOTH),
('type', 'Type', nc_osc_utils.LIST_BOTH),
('route_targets', 'Route Targets', nc_osc_utils.LIST_LONG_ONLY),
('import_targets', 'Import Targets', nc_osc_utils.LIST_LONG_ONLY),
('export_targets', 'Export Targets', nc_osc_utils.LIST_LONG_ONLY),
('route_distinguishers', 'Route Distinguishers',
nc_osc_utils.LIST_LONG_ONLY),
('networks', 'Associated Networks', nc_osc_utils.LIST_LONG_ONLY),
('routers', 'Associated Routers', nc_osc_utils.LIST_LONG_ONLY),
)
_formatters = {
'route_targets': osc_utils.format_list,
'import_targets': osc_utils.format_list,
'export_targets': osc_utils.format_list,
'route_distinguishers': osc_utils.format_list,
'networks': osc_utils.format_list,
'routers': osc_utils.format_list,
}
def _get_common_parser(parser, update=None):
"""Adds to parser arguments common to create, set and unset commands.
:params ArgumentParser parser: argparse object contains all command's
arguments
:params string update: Determines if it is a create command (value: None),
it is a set command (value: 'set') or if it is an
unset command (value: 'unset')
"""
ADD_RT = _("Add Route Target to import/export list")
REMOVE_RT = _("Remove Route Target from import/export list")
ADD_IMPORT_RT = _("Add Route Target to import list")
REMOVE_IMPORT_RT = _("Remove Route Target from import list")
ADD_EXPORT_RT = _("Add Route Target to export list")
REMOVE_EXPORT_RT = _("Remove Route Target from export list")
ADD_RD = _("Add Route Distinguisher to the list of Route Distinguishers "
"from which a Route Distinguishers will be picked from to "
"advertise a VPN route")
REMOVE_RD = _("Remove Route Distinguisher from the list of Route "
"Distinguishers from which a Route Distinguishers will be "
"picked from to advertise a VPN route")
REPEAT_RT = _("repeat option for multiple Route Targets")
REPEAT_RD = _("repeat option for multiple Route Distinguishers")
def is_appended():
return update is None or update == 'set'
if update is None or update == 'set':
parser.add_argument(
'--name',
metavar="<name>",
help=_("Name of the BGP VPN"),
)
parser.add_argument(
'--route-target',
dest='route_targets',
action='append',
metavar="<route-target>",
help="%s (%s)" % ((ADD_RT if is_appended() else REMOVE_RT), REPEAT_RT),
)
if update:
parser.add_argument(
'--no-route-target' if update == 'set' else '--all-route-target',
dest='purge_route_target',
action='store_true',
help=_('Empty route target list'),
)
parser.add_argument(
'--import-target',
dest='import_targets',
action='append',
metavar="<import-target>",
help="%s (%s)" % ((ADD_IMPORT_RT if is_appended() else
REMOVE_IMPORT_RT), REPEAT_RT),
)
if update:
parser.add_argument(
'--no-import-target' if update == 'set' else '--all-import-target',
dest='purge_import_target',
action='store_true',
help=_('Empty import route target list'),
)
parser.add_argument(
'--export-target',
dest='export_targets',
action='append',
metavar="<export-target>",
help="%s (%s)" % ((ADD_EXPORT_RT if is_appended() else
REMOVE_EXPORT_RT), REPEAT_RT),
)
if update:
parser.add_argument(
'--no-export-target' if update == 'set' else
'--all-export-target',
dest='purge_export_target',
action='store_true',
help=_('Empty export route target list'),
)
parser.add_argument(
'--route-distinguisher',
dest='route_distinguishers',
action='append',
metavar="<route-distinguisher>",
help="%s (%s)" % ((ADD_RD if is_appended() else REMOVE_RD), REPEAT_RD),
)
if update:
parser.add_argument(
'--no-route-distinguisher' if update == 'set' else
'--all-route-distinguisher',
dest='purge_route_distinguisher',
action='store_true',
help=_('Empty route distinguisher list'),
)
def _args2body(client_manager, id, action, args):
if (not (args.purge_route_target and args.purge_import_target and
args.purge_export_target and args.purge_route_distinguisher) and
(args.route_targets or args.import_targets or
args.export_targets or args.route_distinguishers)):
bgpvpn = client_manager.neutronclient.show_bgpvpn(id)['bgpvpn']
attrs = {}
if 'name' in args and args.name is not None:
attrs['name'] = str(args.name)
if args.purge_route_target:
attrs['route_targets'] = []
elif args.route_targets:
if action == 'set':
attrs['route_targets'] = list(set(bgpvpn['route_targets']) |
set(args.route_targets))
elif action == 'unset':
attrs['route_targets'] = list(set(bgpvpn['route_targets']) -
set(args.route_targets))
if args.purge_import_target:
attrs['import_targets'] = []
elif args.import_targets:
if action == 'set':
attrs['import_targets'] = list(set(bgpvpn['import_targets']) |
set(args.import_targets))
elif action == 'unset':
attrs['import_targets'] = list(set(bgpvpn['import_targets']) -
set(args.import_targets))
if args.purge_export_target:
attrs['export_targets'] = []
elif args.export_targets:
if action == 'set':
attrs['export_targets'] = list(set(bgpvpn['export_targets']) |
set(args.export_targets))
elif action == 'unset':
attrs['export_targets'] = list(set(bgpvpn['export_targets']) -
set(args.export_targets))
if args.purge_route_distinguisher:
attrs['route_distinguishers'] = []
elif args.route_distinguishers:
if action == 'set':
attrs['route_distinguishers'] = list(
set(bgpvpn['route_distinguishers']) |
set(args.route_distinguishers))
elif action == 'unset':
attrs['route_distinguishers'] = list(
set(bgpvpn['route_distinguishers']) -
set(args.route_distinguishers))
return {constants.BGPVPN: attrs}
class CreateBgpvpn(command.ShowOne):
_description = _("Create BGP VPN resource")
def get_parser(self, prog_name):
parser = super(CreateBgpvpn, self).get_parser(prog_name)
nc_osc_utils.add_project_owner_option_to_parser(parser)
_get_common_parser(parser)
parser.add_argument(
'--type',
default='l3',
choices=['l2', 'l3'],
help=_("BGP VPN type selection between IP VPN (l3) and Ethernet "
"VPN (l2) (default: %(default)s)"),
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
attrs = {}
if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name)
if parsed_args.type is not None:
attrs['type'] = parsed_args.type
if parsed_args.route_targets is not None:
attrs['route_targets'] = parsed_args.route_targets
if parsed_args.import_targets is not None:
attrs['import_targets'] = parsed_args.import_targets
if parsed_args.export_targets is not None:
attrs['export_targets'] = parsed_args.export_targets
if parsed_args.route_distinguishers is not None:
attrs['route_distinguishers'] = parsed_args.route_distinguishers
if 'project' in parsed_args and parsed_args.project is not None:
project_id = nc_osc_utils.find_project(
self.app.client_manager.identity,
parsed_args.project,
parsed_args.project_domain,
).id
attrs['tenant_id'] = project_id
body = {constants.BGPVPN: attrs}
obj = client.create_bgpvpn(body)[constants.BGPVPN]
columns, display_columns = nc_osc_utils.get_columns(obj, _attr_map)
data = osc_utils.get_dict_properties(obj, columns,
formatters=_formatters)
return display_columns, data
class SetBgpvpn(command.Command):
_description = _("Set BGP VPN properties")
def get_parser(self, prog_name):
parser = super(SetBgpvpn, self).get_parser(prog_name)
parser.add_argument(
'bgpvpn',
metavar="<bgpvpn>",
help=_("BGP VPN to update (name or ID)"),
)
_get_common_parser(parser, update='set')
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
id = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)['id']
body = _args2body(self.app.client_manager, id, 'set', parsed_args)
client.update_bgpvpn(id, body)
class UnsetBgpvpn(command.Command):
_description = _("Unset BGP VPN properties")
def get_parser(self, prog_name):
parser = super(UnsetBgpvpn, self).get_parser(prog_name)
parser.add_argument(
'bgpvpn',
metavar="<bgpvpn>",
help=_("BGP VPN to update (name or ID)"),
)
_get_common_parser(parser, update='unset')
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
id = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)['id']
body = _args2body(self.app.client_manager, id, 'unset', parsed_args)
client.update_bgpvpn(id, body)
class DeleteBgpvpn(command.Command):
_description = _("Delete BGP VPN resource(s)")
def get_parser(self, prog_name):
parser = super(DeleteBgpvpn, self).get_parser(prog_name)
parser.add_argument(
'bgpvpns',
metavar="<bgpvpn>",
nargs="+",
help=_("BGP VPN(s) to delete (name or ID)"),
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
fails = 0
for id_or_name in parsed_args.bgpvpns:
try:
id = client.find_resource(constants.BGPVPN, id_or_name)['id']
client.delete_bgpvpn(id)
LOG.warning(_LW("BGP VPN %(id)s deleted"), {'id': id})
except Exception as e:
fails += 1
LOG.error(_LE("Failed to delete BGP VPN with name or ID "
"'%(id_or_name)s': %(e)s"),
{'id_or_name': id_or_name, 'e': e})
if fails > 0:
msg = (_("Failed to delete %(fails)s of %(total)s BGP VPN.") %
{'fails': fails, 'total': len(parsed_args.bgpvpns)})
raise exceptions.CommandError(msg)
class ListBgpvpn(command.Lister):
_description = _("List BGP VPN resources")
def get_parser(self, prog_name):
parser = super(ListBgpvpn, self).get_parser(prog_name)
nc_osc_utils.add_project_owner_option_to_parser(parser)
parser.add_argument(
'--long',
action='store_true',
help=_("List additional fields in output"),
)
parser.add_argument(
'--property',
metavar="<key=value>",
default=dict(),
help=_("Filter property to apply on returned BGP VPNs (repeat to "
"filter on multiple properties)"),
action=KeyValueAction,
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
params = {}
if parsed_args.project is not None:
project_id = nc_osc_utils.find_project(
self.app.client_manager.identity,
parsed_args.project,
parsed_args.project_domain,
).id
params['tenant_id'] = project_id
if parsed_args.property:
params.update(parsed_args.property)
objs = client.list_bgpvpns(**params)[constants.BGPVPNS]
headers, columns = nc_osc_utils.get_column_definitions(
_attr_map, long_listing=parsed_args.long)
return (headers, (osc_utils.get_dict_properties(
s, columns, formatters=_formatters) for s in objs))
class ShowBgpvpn(command.ShowOne):
_description = _("Show information of a given BGP VPN")
def get_parser(self, prog_name):
parser = super(ShowBgpvpn, self).get_parser(prog_name)
parser.add_argument(
'bgpvpn',
metavar="<bgpvpn>",
help=_("BGP VPN to display (name or ID)"),
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
id = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)['id']
obj = client.show_bgpvpn(id)[constants.BGPVPN]
columns, display_columns = nc_osc_utils.get_columns(obj, _attr_map)
data = osc_utils.get_dict_properties(obj, columns,
formatters=_formatters)
return display_columns, data

View File

@ -0,0 +1,26 @@
# Copyright (c) 2016 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.
#
BGPVPN = 'bgpvpn'
BGPVPNS = '%ss' % BGPVPN
NETWORK_RESOURCE_NAME = 'network'
NETWORK_ASSOC = '%s_association' % NETWORK_RESOURCE_NAME
NETWORK_ASSOCS = '%ss' % NETWORK_ASSOC
ROUTER_RESOURCE_NAME = 'router'
ROUTER_ASSOC = '%s_association' % ROUTER_RESOURCE_NAME
ROUTER_ASSOCS = '%ss' % ROUTER_ASSOC

View File

@ -0,0 +1,63 @@
# Copyright (c) 2016 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.
#
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.resource_association import\
CreateBgpvpnResAssoc
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\
ShowBgpvpnResAssoc
class BgpvpnNetAssoc(object):
_assoc_res_name = constants.NETWORK_RESOURCE_NAME
_resource = constants.NETWORK_ASSOC
_resource_plural = constants.NETWORK_ASSOCS
_attr_map = (
('id', 'ID', nc_osc_utils.LIST_BOTH),
('tenant_id', 'Project ID', nc_osc_utils.LIST_LONG_ONLY),
('%s_id' % _assoc_res_name, '%s ID' % _assoc_res_name.capitalize(),
nc_osc_utils.LIST_BOTH),
)
_formatters = {}
class CreateBgpvpnNetAssoc(BgpvpnNetAssoc, CreateBgpvpnResAssoc):
_description = _("Create a BGP VPN network association")
pass
class DeleteBgpvpnNetAssoc(BgpvpnNetAssoc, DeleteBgpvpnResAssoc):
_description = _("Delete a BGP VPN network association(s) for a given BGP "
"VPN")
pass
class ListBgpvpnNetAssoc(BgpvpnNetAssoc, ListBgpvpnResAssoc):
_description = _("List BGP VPN network associations for a given BGP VPN")
pass
class ShowBgpvpnNetAssoc(BgpvpnNetAssoc, ShowBgpvpnResAssoc):
_description = _("Show information of a given BGP VPN network association")
pass

View File

@ -0,0 +1,190 @@
# Copyright (c) 2016 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.command import command
from osc_lib import exceptions
from osc_lib import utils as osc_utils
from neutronclient._i18n import _
from neutronclient._i18n import _LE
from neutronclient._i18n import _LW
from neutronclient.osc import utils as nc_osc_utils
from neutronclient.osc.v2.networking_bgpvpn import constants
LOG = logging.getLogger(__name__)
class CreateBgpvpnResAssoc(command.ShowOne):
"""Create a BGP VPN resource association"""
def get_parser(self, prog_name):
parser = super(CreateBgpvpnResAssoc, self).get_parser(prog_name)
nc_osc_utils.add_project_owner_option_to_parser(parser)
parser.add_argument(
'bgpvpn',
metavar="<bgpvpn>",
help=(_("BGP VPN to apply the %s association (name or ID)") %
self._assoc_res_name),
)
parser.add_argument(
'resource',
metavar="<%s>" % self._assoc_res_name,
help=(_("%s to associate the BGP VPN (name or ID)") %
self._assoc_res_name.capitalize()),
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
create_method = getattr(
client, 'create_bgpvpn_%s_assoc' % self._assoc_res_name)
bgpvpn = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)
assoc_res = client.find_resource(self._assoc_res_name,
parsed_args.resource)
body = {
self._resource: {
'%s_id' % self._assoc_res_name: assoc_res['id'],
},
}
if 'project' in parsed_args and parsed_args.project is not None:
project_id = nc_osc_utils.find_project(
self.app.client_manager.identity,
parsed_args.project,
parsed_args.project_domain,
).id
body[self._resource]['tenant_id'] = project_id
obj = create_method(bgpvpn['id'], body)[self._resource]
columns, display_columns = nc_osc_utils.get_columns(obj,
self._attr_map)
data = osc_utils.get_dict_properties(obj, columns,
formatters=self._formatters)
return display_columns, data
class DeleteBgpvpnResAssoc(command.Command):
"""Remove a BGP VPN resource association(s) for a given BGP VPN"""
def get_parser(self, prog_name):
parser = super(DeleteBgpvpnResAssoc, self).get_parser(prog_name)
parser.add_argument(
'resource_association_ids',
metavar="<%s association ID>" % self._assoc_res_name,
nargs="+",
help=(_("%s association ID(s) to remove") %
self._assoc_res_name.capitalize()),
)
parser.add_argument(
'bgpvpn',
metavar="<bgpvpn>",
help=_("BGP VPN the association belongs to (name or ID)"),
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
delete_method = getattr(
client, 'delete_bgpvpn_%s_assoc' % self._assoc_res_name)
bgpvpn = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)
fails = 0
for id in parsed_args.resource_association_ids:
try:
delete_method(bgpvpn['id'], id)
LOG.warning(
_LW("%(assoc_res_name)s association %(id)s deleted"),
{'assoc_res_name': self._assoc_res_name.capitalize(),
'id': id})
except Exception as e:
fails += 1
LOG.error(_LE("Failed to delete %(assoc_res_name)s "
"association with ID '%(id)s': %(e)s"),
{'assoc_res_name': self._assoc_res_name,
'id': id,
'e': e})
if fails > 0:
msg = (_("Failed to delete %(fails)s of %(total)s "
"%(assoc_res_name)s BGP VPN association(s).") %
{'fails': fails,
'total': len(parsed_args.resource_association_ids),
'assoc_res_name': self._assoc_res_name})
raise exceptions.CommandError(msg)
class ListBgpvpnResAssoc(command.Lister):
"""List BGP VPN resource associations for a given BGP VPN"""
def get_parser(self, prog_name):
parser = super(ListBgpvpnResAssoc, self).get_parser(prog_name)
parser.add_argument(
'bgpvpn',
metavar="<bgpvpn>",
help=_("BGP VPN listed associations belong to (name or ID)"),
)
parser.add_argument(
'--long',
action='store_true',
help=_("List additional fields in output"),
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
list_method = getattr(client,
'list_bgpvpn_%s_assocs' % self._assoc_res_name)
bgpvpn = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)
objs = list_method(bgpvpn['id'],
retrieve_all=True)[self._resource_plural]
headers, columns = nc_osc_utils.get_column_definitions(
self._attr_map, long_listing=parsed_args.long)
return (headers, (osc_utils.get_dict_properties(
s, columns, formatters=self._formatters) for s in objs))
class ShowBgpvpnResAssoc(command.ShowOne):
"""Show information of a given BGP VPN resource association"""
def get_parser(self, prog_name):
parser = super(ShowBgpvpnResAssoc, self).get_parser(prog_name)
parser.add_argument(
'resource_association_id',
metavar="<%s association ID>" % self._assoc_res_name,
help=(_("%s association ID to look up") %
self._assoc_res_name.capitalize()),
)
parser.add_argument(
'bgpvpn',
metavar="<bgpvpn>",
help=_("BGP VPN the association belongs to (name or ID)"),
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
show_method = getattr(client,
'show_bgpvpn_%s_assoc' % self._assoc_res_name)
bgpvpn = client.find_resource(constants.BGPVPN, parsed_args.bgpvpn)
assoc = client.find_resource_by_id(
self._resource,
parsed_args.resource_association_id,
cmd_resource='bgpvpn_%s_assoc' % self._assoc_res_name,
parent_id=bgpvpn['id'])
obj = show_method(bgpvpn['id'], assoc['id'])[self._resource]
columns, display_columns = nc_osc_utils.get_columns(obj,
self._attr_map)
data = osc_utils.get_dict_properties(obj, columns,
formatters=self._formatters)
return display_columns, data

View File

@ -0,0 +1,63 @@
# Copyright (c) 2016 Juniper Routerworks 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.osc import utils as nc_osc_utils
from neutronclient.osc.v2.networking_bgpvpn import constants
from neutronclient.osc.v2.networking_bgpvpn.resource_association import\
CreateBgpvpnResAssoc
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\
ShowBgpvpnResAssoc
class BgpvpnRouterAssoc(object):
_assoc_res_name = constants.ROUTER_RESOURCE_NAME
_resource = constants.ROUTER_ASSOC
_resource_plural = constants.ROUTER_ASSOCS
_attr_map = (
('id', 'ID', nc_osc_utils.LIST_BOTH),
('tenant_id', 'Project ID', nc_osc_utils.LIST_LONG_ONLY),
('%s_id' % _assoc_res_name, '%s ID' % _assoc_res_name.capitalize(),
nc_osc_utils.LIST_BOTH),
)
_formatters = {}
class CreateBgpvpnRouterAssoc(BgpvpnRouterAssoc, CreateBgpvpnResAssoc):
_description = _("Create a BGP VPN router association")
pass
class DeleteBgpvpnRouterAssoc(BgpvpnRouterAssoc, DeleteBgpvpnResAssoc):
_description = _("Delete a BGP VPN router association(s) for a given BGP "
"VPN")
pass
class ListBgpvpnRouterAssoc(BgpvpnRouterAssoc, ListBgpvpnResAssoc):
_description = _("List BGP VPN router associations for a given BGP VPN")
pass
class ShowBgpvpnRouterAssoc(BgpvpnRouterAssoc, ShowBgpvpnResAssoc):
_description = _("Show information of a given BGP VPN router association")
pass

View File

@ -0,0 +1,183 @@
# Copyright (c) 2016 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 copy
import mock
from neutronclient.osc import utils as nc_osc_utils
from neutronclient.osc.v2.networking_bgpvpn import constants
from neutronclient.osc.v2.networking_bgpvpn.resource_association import\
CreateBgpvpnResAssoc
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\
ShowBgpvpnResAssoc
from neutronclient.tests.unit.osc.v2 import fakes as test_fakes
class TestNeutronClientBgpvpn(test_fakes.TestNeutronClientOSCV2):
def setUp(self):
super(TestNeutronClientBgpvpn, self).setUp()
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})
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})
nc_osc_utils.find_project = mock.Mock(
side_effect=lambda _, name_or_id, __: mock.Mock(id=name_or_id))
class FakeBgpvpn(object):
"""Fake BGP VPN with attributes."""
@staticmethod
def create_one_bgpvpn(attrs=None):
"""Create a fake BGP VPN."""
attrs = attrs or {}
# Set default attributes.
bgpvpn_attrs = {
'id': 'fake_bgpvpn_id',
'tenant_id': 'fake_project_id',
'name': '',
'type': 'l3',
'route_targets': [],
'import_targets': [],
'export_targets': [],
'route_distinguishers': [],
'networks': [],
'routers': [],
}
# Overwrite default attributes.
bgpvpn_attrs.update(attrs)
return copy.deepcopy(bgpvpn_attrs)
@staticmethod
def create_bgpvpns(attrs=None, count=1):
"""Create multiple fake BGP VPN."""
bgpvpns = []
for i in range(0, count):
if attrs is None:
attrs = {'id': 'fake_id%d' % i}
elif getattr(attrs, 'id', None) is None:
attrs['id'] = 'fake_id%d' % i
bgpvpns.append(FakeBgpvpn.create_one_bgpvpn(attrs))
return {constants.BGPVPNS: bgpvpns}
class BgpvpnFakeAssoc(object):
_assoc_res_name = 'fake_resource'
_resource = '%s_association' % _assoc_res_name
_resource_plural = '%ss' % _resource
_attr_map = (
('id', 'ID', nc_osc_utils.LIST_BOTH),
('tenant_id', 'Project ID', nc_osc_utils.LIST_LONG_ONLY),
('%s_id' % _assoc_res_name, '%s ID' % _assoc_res_name.capitalize(),
nc_osc_utils.LIST_BOTH),
)
_formatters = {}
class CreateBgpvpnFakeResAssoc(BgpvpnFakeAssoc, CreateBgpvpnResAssoc):
pass
class DeleteBgpvpnFakeResAssoc(BgpvpnFakeAssoc, DeleteBgpvpnResAssoc):
pass
class ListBgpvpnFakeResAssoc(BgpvpnFakeAssoc, ListBgpvpnResAssoc):
pass
class ShowBgpvpnFakeResAssoc(BgpvpnFakeAssoc, ShowBgpvpnResAssoc):
pass
class FakeResource(object):
"""Fake resource with minimal attributes."""
@staticmethod
def create_one_resource(attrs=None):
"""Create a fake resource."""
attrs = attrs or {}
# Set default attributes.
res_attrs = {
'id': 'fake_resource_id',
'tenant_id': 'fake_project_id',
}
# Overwrite default attributes.
res_attrs.update(attrs)
return copy.deepcopy(res_attrs)
@staticmethod
def create_resources(attrs=None, count=1):
"""Create multiple fake resources."""
resources = []
for i in range(0, count):
if attrs is None:
attrs = {'id': 'fake_id%d' % i}
elif getattr(attrs, 'id', None) is None:
attrs['id'] = 'fake_id%d' % i
resources.append(FakeResource.create_one_resource(attrs))
return {'%ss' % BgpvpnFakeAssoc._assoc_res_name: resources}
class FakeResAssoc(object):
"""Fake resource association with minimal attributes."""
@staticmethod
def create_one_resource_association(resource):
"""Create a fake resource association."""
res_assoc_attrs = {
'id': 'fake_association_id',
'tenant_id': resource['tenant_id'],
'fake_resource_id': resource['id'],
}
return copy.deepcopy(res_assoc_attrs)
@staticmethod
def create_resource_associations(resources):
"""Create multiple fake resource associations."""
res_assocs = []
for idx, resource in enumerate(
resources['%ss' % BgpvpnFakeAssoc._assoc_res_name]):
res_assoc_attrs = {
'id': 'fake_association_id%d' % idx,
'tenant_id': resource['tenant_id'],
'fake_resource_id': resource['id'],
}
res_assocs.append(copy.deepcopy(res_assoc_attrs))
return {BgpvpnFakeAssoc._resource_plural: res_assocs}

View File

@ -0,0 +1,515 @@
# Copyright (c) 2016 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 copy
import mock
import operator
from osc_lib import exceptions
from osc_lib import utils as osc_utils
from neutronclient.osc import utils as nc_osc_utils
from neutronclient.osc.v2.networking_bgpvpn import bgpvpn
from neutronclient.osc.v2.networking_bgpvpn import constants
from neutronclient.tests.unit.osc.v2.networking_bgpvpn import fakes
columns_short = tuple(col for col, _, listing_mode in bgpvpn._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_SHORT_ONLY))
columns_long = tuple(col for col, _, listing_mode in bgpvpn._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_LONG_ONLY))
headers_short = tuple(head for _, head, listing_mode in bgpvpn._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_SHORT_ONLY))
headers_long = tuple(head for _, head, listing_mode in bgpvpn._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_LONG_ONLY))
sorted_attr_map = sorted(bgpvpn._attr_map, key=operator.itemgetter(1))
sorted_columns = tuple(col for col, _, _ in sorted_attr_map)
sorted_headers = tuple(head for _, head, _ in sorted_attr_map)
def _get_data(attrs, columns=sorted_columns):
return osc_utils.get_dict_properties(attrs, columns,
formatters=bgpvpn._formatters)
class TestCreateBgpvpn(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestCreateBgpvpn, self).setUp()
self.cmd = bgpvpn.CreateBgpvpn(self.app, self.namespace)
def test_create_bgpvpn_with_no_args(self):
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
self.neutronclient.create_bgpvpn = mock.Mock(
return_value={constants.BGPVPN: fake_bgpvpn})
arglist = []
verifylist = [
('project', None),
('name', None),
('type', 'l3'),
('route_targets', None),
('import_targets', None),
('export_targets', None),
('route_distinguishers', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
cols, data = self.cmd.take_action(parsed_args)
self.neutronclient.create_bgpvpn.assert_called_once_with(
{constants.BGPVPN: {'type': 'l3'}})
self.assertEqual(sorted_headers, cols)
self.assertEqual(_get_data(fake_bgpvpn), data)
def test_create_bgpvpn_with_all_args(self):
attrs = {
'tenant_id': 'new_fake_project_id',
'name': 'fake_name',
'type': 'l2',
'route_targets': ['fake_rt1', 'fake_rt2', 'fake_rt3'],
'import_targets': ['fake_irt1', 'fake_irt2', 'fake_irt3'],
'export_targets': ['fake_ert1', 'fake_ert2', 'fake_ert3'],
'route_distinguishers': ['fake_rd1', 'fake_rd2', 'fake_rd3'],
}
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn(attrs)
self.neutronclient.create_bgpvpn = mock.Mock(
return_value={constants.BGPVPN: fake_bgpvpn})
arglist = [
'--project', fake_bgpvpn['tenant_id'],
'--name', fake_bgpvpn['name'],
'--type', fake_bgpvpn['type'],
]
for rt in fake_bgpvpn['route_targets']:
arglist.extend(['--route-target', rt])
for rt in fake_bgpvpn['import_targets']:
arglist.extend(['--import-target', rt])
for rt in fake_bgpvpn['export_targets']:
arglist.extend(['--export-target', rt])
for rd in fake_bgpvpn['route_distinguishers']:
arglist.extend(['--route-distinguisher', rd])
verifylist = [
('project', fake_bgpvpn['tenant_id']),
('name', fake_bgpvpn['name']),
('type', fake_bgpvpn['type']),
('route_targets', fake_bgpvpn['route_targets']),
('import_targets', fake_bgpvpn['import_targets']),
('export_targets', fake_bgpvpn['export_targets']),
('route_distinguishers', fake_bgpvpn['route_distinguishers']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
cols, data = self.cmd.take_action(parsed_args)
fake_bgpvpn_call = copy.deepcopy(fake_bgpvpn)
fake_bgpvpn_call.pop('id')
fake_bgpvpn_call.pop('networks')
fake_bgpvpn_call.pop('routers')
self.neutronclient.create_bgpvpn.assert_called_once_with(
{constants.BGPVPN: fake_bgpvpn_call})
self.assertEqual(sorted_headers, cols)
self.assertEqual(_get_data(fake_bgpvpn), data)
class TestSetBgpvpn(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestSetBgpvpn, self).setUp()
self.cmd = bgpvpn.SetBgpvpn(self.app, self.namespace)
def test_set_bgpvpn(self):
attrs = {
'route_targets': ['set_rt1', 'set_rt2', 'set_rt3'],
'import_targets': ['set_irt1', 'set_irt2', 'set_irt3'],
'export_targets': ['set_ert1', 'set_ert2', 'set_ert3'],
'route_distinguishers': ['set_rd1', 'set_rd2', 'set_rd3'],
}
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn(attrs)
self.neutronclient.show_bgpvpn = mock.Mock(
return_value={constants.BGPVPN: fake_bgpvpn})
self.neutronclient.update_bgpvpn = mock.Mock()
arglist = [
fake_bgpvpn['id'],
'--name', 'set_name',
'--route-target', 'set_rt1',
'--import-target', 'set_irt1',
'--export-target', 'set_ert1',
'--route-distinguisher', 'set_rd1',
]
verifylist = [
('bgpvpn', fake_bgpvpn['id']),
('name', 'set_name'),
('route_targets', ['set_rt1']),
('purge_route_target', False),
('import_targets', ['set_irt1']),
('purge_import_target', False),
('export_targets', ['set_ert1']),
('purge_export_target', False),
('route_distinguishers', ['set_rd1']),
('purge_route_distinguisher', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'name': 'set_name',
'route_targets': list(set(fake_bgpvpn['route_targets']) |
set(['set_rt1'])),
'import_targets': list(set(fake_bgpvpn['import_targets']) |
set(['set_irt1'])),
'export_targets': list(set(fake_bgpvpn['export_targets']) |
set(['set_ert1'])),
'route_distinguishers': list(
set(fake_bgpvpn['route_distinguishers']) | set(['set_rd1'])),
}
self.neutronclient.update_bgpvpn.assert_called_once_with(
fake_bgpvpn['id'], {constants.BGPVPN: attrs})
self.assertIsNone(result)
def test_set_bgpvpn_with_purge_list(self):
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
self.neutronclient.show_bgpvpn = mock.Mock(
return_value={constants.BGPVPN: fake_bgpvpn})
self.neutronclient.update_bgpvpn = mock.Mock()
arglist = [
fake_bgpvpn['id'],
'--route-target', 'set_rt1',
'--no-route-target',
'--import-target', 'set_irt1',
'--no-import-target',
'--export-target', 'set_ert1',
'--no-export-target',
'--route-distinguisher', 'set_rd1',
'--no-route-distinguisher',
]
verifylist = [
('bgpvpn', fake_bgpvpn['id']),
('route_targets', ['set_rt1']),
('purge_route_target', True),
('import_targets', ['set_irt1']),
('purge_import_target', True),
('export_targets', ['set_ert1']),
('purge_export_target', True),
('route_distinguishers', ['set_rd1']),
('purge_route_distinguisher', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'route_targets': [],
'import_targets': [],
'export_targets': [],
'route_distinguishers': [],
}
self.neutronclient.update_bgpvpn.assert_called_once_with(
fake_bgpvpn['id'], {constants.BGPVPN: attrs})
self.assertIsNone(result)
class TestUnsetBgpvpn(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestUnsetBgpvpn, self).setUp()
self.cmd = bgpvpn.UnsetBgpvpn(self.app, self.namespace)
def test_unset_bgpvpn(self):
attrs = {
'route_targets': ['unset_rt1', 'unset_rt2', 'unset_rt3'],
'import_targets': ['unset_irt1', 'unset_irt2', 'unset_irt3'],
'export_targets': ['unset_ert1', 'unset_ert2', 'unset_ert3'],
'route_distinguishers': ['unset_rd1', 'unset_rd2', 'unset_rd3'],
}
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn(attrs)
self.neutronclient.show_bgpvpn = mock.Mock(
return_value={constants.BGPVPN: fake_bgpvpn})
self.neutronclient.update_bgpvpn = mock.Mock()
arglist = [
fake_bgpvpn['id'],
'--route-target', 'unset_rt1',
'--import-target', 'unset_irt1',
'--export-target', 'unset_ert1',
'--route-distinguisher', 'unset_rd1',
]
verifylist = [
('bgpvpn', fake_bgpvpn['id']),
('route_targets', ['unset_rt1']),
('purge_route_target', False),
('import_targets', ['unset_irt1']),
('purge_import_target', False),
('export_targets', ['unset_ert1']),
('purge_export_target', False),
('route_distinguishers', ['unset_rd1']),
('purge_route_distinguisher', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'route_targets': list(set(fake_bgpvpn['route_targets']) -
set(['unset_rt1'])),
'import_targets': list(set(fake_bgpvpn['import_targets']) -
set(['unset_irt1'])),
'export_targets': list(set(fake_bgpvpn['export_targets']) -
set(['unset_ert1'])),
'route_distinguishers': list(
set(fake_bgpvpn['route_distinguishers']) - set(['unset_rd1'])),
}
self.neutronclient.update_bgpvpn.assert_called_once_with(
fake_bgpvpn['id'], {constants.BGPVPN: attrs})
self.assertIsNone(result)
def test_unset_bgpvpn_with_purge_list(self):
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
self.neutronclient.show_bgpvpn = mock.Mock(
return_value={constants.BGPVPN: fake_bgpvpn})
self.neutronclient.update_bgpvpn = mock.Mock()
arglist = [
fake_bgpvpn['id'],
'--route-target', 'unset_rt1',
'--all-route-target',
'--import-target', 'unset_irt1',
'--all-import-target',
'--export-target', 'unset_ert1',
'--all-export-target',
'--route-distinguisher', 'unset_rd1',
'--all-route-distinguisher',
]
verifylist = [
('bgpvpn', fake_bgpvpn['id']),
('route_targets', ['unset_rt1']),
('purge_route_target', True),
('import_targets', ['unset_irt1']),
('purge_import_target', True),
('export_targets', ['unset_ert1']),
('purge_export_target', True),
('route_distinguishers', ['unset_rd1']),
('purge_route_distinguisher', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'route_targets': [],
'import_targets': [],
'export_targets': [],
'route_distinguishers': [],
}
self.neutronclient.update_bgpvpn.assert_called_once_with(
fake_bgpvpn['id'], {constants.BGPVPN: attrs})
self.assertIsNone(result)
class TestDeleteBgpvpn(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestDeleteBgpvpn, self).setUp()
self.neutronclient.find_resource = mock.Mock(
side_effect=lambda _, name_or_id: {'id': name_or_id})
self.cmd = bgpvpn.DeleteBgpvpn(self.app, self.namespace)
def test_delete_one_bgpvpn(self):
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
self.neutronclient.delete_bgpvpn = mock.Mock()
arglist = [
fake_bgpvpn['id'],
]
verifylist = [
('bgpvpns', [fake_bgpvpn['id']]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.neutronclient.delete_bgpvpn.assert_called_once_with(
fake_bgpvpn['id'])
self.assertIsNone(result)
def test_delete_multi_bpgvpn(self):
fake_bgpvpns = fakes.FakeBgpvpn.create_bgpvpns(count=3)
fake_bgpvpn_ids = [fake_bgpvpn['id'] for fake_bgpvpn in
fake_bgpvpns[constants.BGPVPNS]]
self.neutronclient.delete_bgpvpn = mock.Mock()
arglist = fake_bgpvpn_ids
verifylist = [
('bgpvpns', fake_bgpvpn_ids),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.neutronclient.delete_bgpvpn.assert_has_calls(
[mock.call(id) for id in fake_bgpvpn_ids])
self.assertIsNone(result)
def test_delete_multi_bpgvpn_with_unknown(self):
count = 3
fake_bgpvpns = fakes.FakeBgpvpn.create_bgpvpns(count=count)
fake_bgpvpn_ids = [fake_bgpvpn['id'] for fake_bgpvpn in
fake_bgpvpns[constants.BGPVPNS]]
def raise_unknonw_resource(resource_path, name_or_id):
if str(count - 2) in name_or_id:
raise Exception()
self.neutronclient.delete_bgpvpn = mock.Mock(
side_effect=raise_unknonw_resource)
arglist = fake_bgpvpn_ids
verifylist = [
('bgpvpns', fake_bgpvpn_ids),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
parsed_args)
self.neutronclient.delete_bgpvpn.assert_has_calls(
[mock.call(id) for id in fake_bgpvpn_ids])
class TestListBgpvpn(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestListBgpvpn, self).setUp()
self.cmd = bgpvpn.ListBgpvpn(self.app, self.namespace)
def test_list_all_bgpvpn(self):
count = 3
fake_bgpvpns = fakes.FakeBgpvpn.create_bgpvpns(count=count)
self.neutronclient.list_bgpvpns = mock.Mock(return_value=fake_bgpvpns)
arglist = []
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.list_bgpvpns.assert_called_once()
self.assertEqual(headers, list(headers_short))
self.assertEqual(list(data),
[_get_data(fake_bgpvpn, columns_short) for fake_bgpvpn
in fake_bgpvpns[constants.BGPVPNS]])
def test_list_all_bgpvpn_long_mode(self):
count = 3
fake_bgpvpns = fakes.FakeBgpvpn.create_bgpvpns(count=count)
self.neutronclient.list_bgpvpns = mock.Mock(return_value=fake_bgpvpns)
arglist = [
'--long',
]
verifylist = [
('long', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.list_bgpvpns.assert_called_once()
self.assertEqual(headers, list(headers_long))
self.assertEqual(list(data),
[_get_data(fake_bgpvpn, columns_long) for fake_bgpvpn
in fake_bgpvpns[constants.BGPVPNS]])
def test_list_project_bgpvpn(self):
count = 3
project_id = 'list_fake_project_id'
attrs = {'tenant_id': project_id}
fake_bgpvpns = fakes.FakeBgpvpn.create_bgpvpns(count=count,
attrs=attrs)
self.neutronclient.list_bgpvpns = mock.Mock(return_value=fake_bgpvpns)
arglist = [
'--project', project_id,
]
verifylist = [
('project', project_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.list_bgpvpns.assert_called_once_with(
tenant_id=project_id)
self.assertEqual(headers, list(headers_short))
self.assertEqual(list(data),
[_get_data(fake_bgpvpn, columns_short) for fake_bgpvpn
in fake_bgpvpns[constants.BGPVPNS]])
def test_list_bgpvpn_with_filters(self):
count = 3
name = 'fake_id0'
layer_type = 'l2'
attrs = {'type': layer_type}
fake_bgpvpns = fakes.FakeBgpvpn.create_bgpvpns(count=count,
attrs=attrs)
returned_bgpvpn = fake_bgpvpns[constants.BGPVPNS][0]
self.neutronclient.list_bgpvpns = mock.Mock(
return_value={constants.BGPVPNS: [returned_bgpvpn]})
arglist = [
'--property', 'name=%s' % name,
'--property', 'type=%s' % layer_type,
]
verifylist = [
('property', {'name': name, 'type': layer_type}),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.list_bgpvpns.assert_called_once_with(
name=name,
type=layer_type)
self.assertEqual(headers, list(headers_short))
self.assertEqual(list(data),
[_get_data(returned_bgpvpn, columns_short)])
class TestShowBgpvpn(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestShowBgpvpn, self).setUp()
self.cmd = bgpvpn.ShowBgpvpn(self.app, self.namespace)
def test_show_bgpvpn(self):
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
self.neutronclient.show_bgpvpn = mock.Mock(
return_value={constants.BGPVPN: fake_bgpvpn})
arglist = [
fake_bgpvpn['id'],
]
verifylist = [
('bgpvpn', fake_bgpvpn['id']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.show_bgpvpn.assert_called_once_with(
fake_bgpvpn['id'])
self.assertEqual(sorted_headers, headers)
self.assertEqual(_get_data(fake_bgpvpn), data)

View File

@ -0,0 +1,272 @@
# Copyright (c) 2016 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 copy
import mock
import operator
from osc_lib import exceptions
from osc_lib import utils as osc_utils
from neutronclient.osc import utils as nc_osc_utils
from neutronclient.tests.unit.osc.v2.networking_bgpvpn import fakes
columns_short = tuple(col for col, _, listing_mode
in fakes.BgpvpnFakeAssoc._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_SHORT_ONLY))
columns_long = tuple(col for col, _, listing_mode
in fakes.BgpvpnFakeAssoc._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_LONG_ONLY))
headers_short = tuple(head for _, head, listing_mode
in fakes.BgpvpnFakeAssoc._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_SHORT_ONLY))
headers_long = tuple(head for _, head, listing_mode
in fakes.BgpvpnFakeAssoc._attr_map
if listing_mode in (nc_osc_utils.LIST_BOTH,
nc_osc_utils.LIST_LONG_ONLY))
sorted_attr_map = sorted(fakes.BgpvpnFakeAssoc._attr_map,
key=operator.itemgetter(1))
sorted_columns = tuple(col for col, _, _ in sorted_attr_map)
sorted_headers = tuple(head for _, head, _ in sorted_attr_map)
def _get_data(attrs, columns=sorted_columns):
return osc_utils.get_dict_properties(
attrs, columns, formatters=fakes.BgpvpnFakeAssoc._formatters)
class TestCreateResAssoc(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestCreateResAssoc, self).setUp()
self.cmd = fakes.CreateBgpvpnFakeResAssoc(self.app, self.namespace)
def test_create_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.create_bgpvpn_fake_resource_assoc = mock.Mock(
return_value={fakes.BgpvpnFakeAssoc._resource: fake_res_assoc})
arglist = [
fake_bgpvpn['id'],
fake_res['id'],
'--project', fake_bgpvpn['tenant_id'],
]
verifylist = [
('bgpvpn', fake_bgpvpn['id']),
('resource', fake_res['id']),
('project', fake_bgpvpn['tenant_id'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
cols, data = self.cmd.take_action(parsed_args)
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'],
{fakes.BgpvpnFakeAssoc._resource: fake_res_assoc_call})
self.assertEqual(sorted_headers, cols)
self.assertEqual(_get_data(fake_res_assoc), data)
class TestDeleteResAssoc(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestDeleteResAssoc, self).setUp()
self.cmd = fakes.DeleteBgpvpnFakeResAssoc(self.app, self.namespace)
def test_delete_one_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.delete_bgpvpn_fake_resource_assoc = mock.Mock()
arglist = [
fake_res_assoc['id'],
fake_bgpvpn['id'],
]
verifylist = [
('resource_association_ids', [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.delete_bgpvpn_fake_resource_assoc.\
assert_called_once_with(fake_bgpvpn['id'], fake_res_assoc['id'])
self.assertIsNone(result)
def test_delete_multi_bpgvpn(self):
count = 3
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
fake_res = fakes.FakeResource.create_resources(count=count)
fake_res_assocs = fakes.FakeResAssoc.create_resource_associations(
fake_res)
fake_res_assoc_ids = [
fake_res_assoc['id'] for fake_res_assoc in
fake_res_assocs[fakes.BgpvpnFakeAssoc._resource_plural]
]
self.neutronclient.delete_bgpvpn_fake_resource_assoc = mock.Mock()
arglist = \
fake_res_assoc_ids + [
fake_bgpvpn['id']
]
verifylist = [
('resource_association_ids', fake_res_assoc_ids),
('bgpvpn', fake_bgpvpn['id']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.neutronclient.delete_bgpvpn_fake_resource_assoc.assert_has_calls(
[mock.call(fake_bgpvpn['id'], id) for id in fake_res_assoc_ids])
self.assertIsNone(result)
def test_delete_multi_bpgvpn_with_unknown(self):
count = 3
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
fake_res = fakes.FakeResource.create_resources(count=count)
fake_res_assocs = fakes.FakeResAssoc.create_resource_associations(
fake_res)
fake_res_assoc_ids = [
fake_res_assoc['id'] for fake_res_assoc in
fake_res_assocs[fakes.BgpvpnFakeAssoc._resource_plural]
]
def raise_unknonw_resource(resource_path, name_or_id):
if str(count - 2) in name_or_id:
raise Exception()
self.neutronclient.delete_bgpvpn_fake_resource_assoc = mock.Mock(
side_effect=raise_unknonw_resource)
arglist = \
fake_res_assoc_ids + [
fake_bgpvpn['id']
]
verifylist = [
('resource_association_ids', fake_res_assoc_ids),
('bgpvpn', fake_bgpvpn['id']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
parsed_args)
self.neutronclient.delete_bgpvpn_fake_resource_assoc.assert_has_calls(
[mock.call(fake_bgpvpn['id'], id) for id in fake_res_assoc_ids])
class TestListResAssoc(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestListResAssoc, self).setUp()
self.cmd = fakes.ListBgpvpnFakeResAssoc(self.app, self.namespace)
def test_list_bgpvpn_associations(self):
count = 3
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
fake_res = fakes.FakeResource.create_resources(count=count)
fake_res_assocs = fakes.FakeResAssoc.create_resource_associations(
fake_res)
self.neutronclient.list_bgpvpn_fake_resource_assocs = mock.Mock(
return_value=fake_res_assocs)
arglist = [
fake_bgpvpn['id'],
]
verifylist = [
('bgpvpn', fake_bgpvpn['id']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.list_bgpvpn_fake_resource_assocs.\
assert_called_once_with(fake_bgpvpn['id'], retrieve_all=True)
self.assertEqual(headers, list(headers_short))
self.assertEqual(
list(data),
[_get_data(fake_res_assoc, columns_short) for fake_res_assoc
in fake_res_assocs[fakes.BgpvpnFakeAssoc._resource_plural]])
def test_list_bgpvpn_associations_long_mode(self):
count = 3
fake_bgpvpn = fakes.FakeBgpvpn.create_one_bgpvpn()
fake_res = fakes.FakeResource.create_resources(count=count)
fake_res_assocs = fakes.FakeResAssoc.create_resource_associations(
fake_res)
self.neutronclient.list_bgpvpn_fake_resource_assocs = mock.Mock(
return_value=fake_res_assocs)
arglist = [
'--long',
fake_bgpvpn['id'],
]
verifylist = [
('long', True),
('bgpvpn', fake_bgpvpn['id']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.list_bgpvpn_fake_resource_assocs.\
assert_called_once_with(fake_bgpvpn['id'], retrieve_all=True)
self.assertEqual(headers, list(headers_long))
self.assertEqual(
list(data),
[_get_data(fake_res_assoc, columns_long) for fake_res_assoc
in fake_res_assocs[fakes.BgpvpnFakeAssoc._resource_plural]])
class TestShowResAssoc(fakes.TestNeutronClientBgpvpn):
def setUp(self):
super(TestShowResAssoc, self).setUp()
self.cmd = fakes.ShowBgpvpnFakeResAssoc(self.app, self.namespace)
def test_show_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.show_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)
headers, data = self.cmd.take_action(parsed_args)
self.neutronclient.show_bgpvpn_fake_resource_assoc.\
assert_called_once_with(fake_bgpvpn['id'], fake_res_assoc['id'])
self.assertEqual(sorted_headers, headers)
self.assertEqual(data, _get_data(fake_res_assoc))

View File

@ -630,6 +630,15 @@ class Client(ClientBase):
subports_path = "/trunks/%s/get_subports"
subports_add_path = "/trunks/%s/add_subports"
subports_remove_path = "/trunks/%s/remove_subports"
bgpvpns_path = "/bgpvpn/bgpvpns"
bgpvpn_path = "/bgpvpn/bgpvpns/%s"
bgpvpn_network_associations_path =\
"/bgpvpn/bgpvpns/%s/network_associations"
bgpvpn_network_association_path =\
"/bgpvpn/bgpvpns/%s/network_associations/%s"
bgpvpn_router_associations_path = "/bgpvpn/bgpvpns/%s/router_associations"
bgpvpn_router_association_path =\
"/bgpvpn/bgpvpns/%s/router_associations/%s"
# API has no way to report plurals, so we have to hard code them
EXTED_PLURALS = {'routers': 'router',
@ -680,6 +689,9 @@ class Client(ClientBase):
'bgp_peers': 'bgp_peer',
'network_ip_availabilities': 'network_ip_availability',
'trunks': 'trunk',
'bgpvpns': 'bgpvpn',
'network_associations': 'network_association',
'router_associations': 'router_association',
}
def list_ext(self, collection, path, retrieve_all, **_params):
@ -2071,6 +2083,82 @@ class Client(ClientBase):
"""Fetch a list of all subports attached to given trunk."""
return self.get(self.subports_path % (trunk), params=_params)
def list_bgpvpns(self, retrieve_all=True, **_params):
"""Fetches a list of all BGP VPNs for a project"""
return self.list('bgpvpns', self.bgpvpns_path, retrieve_all, **_params)
def show_bgpvpn(self, bgpvpn, **_params):
"""Fetches information of a certain BGP VPN"""
return self.get(self.bgpvpn_path % bgpvpn, params=_params)
def create_bgpvpn(self, body=None):
"""Creates a new BGP VPN"""
return self.post(self.bgpvpns_path, body=body)
def update_bgpvpn(self, bgpvpn, body=None):
"""Updates a BGP VPN"""
return self.put(self.bgpvpn_path % bgpvpn, body=body)
def delete_bgpvpn(self, bgpvpn):
"""Deletes the specified BGP VPN"""
return self.delete(self.bgpvpn_path % bgpvpn)
def list_bgpvpn_network_assocs(self, bgpvpn, retrieve_all=True, **_params):
"""Fetches a list of network associations for a given BGP VPN."""
return self.list('network_associations',
self.bgpvpn_network_associations_path % bgpvpn,
retrieve_all, **_params)
def show_bgpvpn_network_assoc(self, bgpvpn, net_assoc, **_params):
"""Fetches information of a certain BGP VPN's network association"""
return self.get(
self.bgpvpn_network_association_path % (bgpvpn, net_assoc),
params=_params)
def create_bgpvpn_network_assoc(self, bgpvpn, body=None):
"""Creates a new BGP VPN network association"""
return self.post(self.bgpvpn_network_associations_path % bgpvpn,
body=body)
def update_bgpvpn_network_assoc(self, bgpvpn, net_assoc, body=None):
"""Updates a BGP VPN network association"""
return self.put(
self.bgpvpn_network_association_path % (bgpvpn, net_assoc),
body=body)
def delete_bgpvpn_network_assoc(self, bgpvpn, net_assoc):
"""Deletes the specified BGP VPN network association"""
return self.delete(
self.bgpvpn_network_association_path % (bgpvpn, net_assoc))
def list_bgpvpn_router_assocs(self, bgpvpn, retrieve_all=True, **_params):
"""Fetches a list of router associations for a given BGP VPN."""
return self.list('router_associations',
self.bgpvpn_router_associations_path % bgpvpn,
retrieve_all, **_params)
def show_bgpvpn_router_assoc(self, bgpvpn, router_assoc, **_params):
"""Fetches information of a certain BGP VPN's router association"""
return self.get(
self.bgpvpn_router_association_path % (bgpvpn, router_assoc),
params=_params)
def create_bgpvpn_router_assoc(self, bgpvpn, body=None):
"""Creates a new BGP VPN router association"""
return self.post(self.bgpvpn_router_associations_path % bgpvpn,
body=body)
def update_bgpvpn_router_assoc(self, bgpvpn, router_assoc, body=None):
"""Updates a BGP VPN router association"""
return self.put(
self.bgpvpn_router_association_path % (bgpvpn, router_assoc),
body=body)
def delete_bgpvpn_router_assoc(self, bgpvpn, router_assoc):
"""Deletes the specified BGP VPN router association"""
return self.delete(
self.bgpvpn_router_association_path % (bgpvpn, router_assoc))
def __init__(self, **kwargs):
"""Initialize a new client for the Neutron v2.0 API."""
super(Client, self).__init__(**kwargs)

View File

@ -0,0 +1,5 @@
---
features:
- CLI support for the "Neutron BGP VPN Interconnection" feature,
which is an API extension to support inter-connection between
L3VPNs/E-VPNs and Neutron resources, as OSC plugin commands.

View File

@ -65,6 +65,21 @@ openstack.neutronclient.v2 =
firewall_group_rule_show = neutronclient.osc.v2.fwaas.firewallrule:ShowFirewallRule
firewall_group_rule_unset = neutronclient.osc.v2.fwaas.firewallrule:UnsetFirewallRule
bgpvpn_create = neutronclient.osc.v2.networking_bgpvpn.bgpvpn:CreateBgpvpn
bgpvpn_delete = neutronclient.osc.v2.networking_bgpvpn.bgpvpn:DeleteBgpvpn
bgpvpn_list = neutronclient.osc.v2.networking_bgpvpn.bgpvpn:ListBgpvpn
bgpvpn_set = neutronclient.osc.v2.networking_bgpvpn.bgpvpn:SetBgpvpn
bgpvpn_show = neutronclient.osc.v2.networking_bgpvpn.bgpvpn:ShowBgpvpn
bgpvpn_unset = neutronclient.osc.v2.networking_bgpvpn.bgpvpn:UnsetBgpvpn
bgpvpn_network_association_create = neutronclient.osc.v2.networking_bgpvpn.network_association:CreateBgpvpnNetAssoc
bgpvpn_network_association_delete = neutronclient.osc.v2.networking_bgpvpn.network_association:DeleteBgpvpnNetAssoc
bgpvpn_network_association_list = neutronclient.osc.v2.networking_bgpvpn.network_association:ListBgpvpnNetAssoc
bgpvpn_network_association_show = neutronclient.osc.v2.networking_bgpvpn.network_association:ShowBgpvpnNetAssoc
bgpvpn_router_association_create = neutronclient.osc.v2.networking_bgpvpn.router_association:CreateBgpvpnRouterAssoc
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
[build_sphinx]
all_files = 1
build-dir = doc/build