Merge "BGP Dynamic Routing: neutronclient changes"
This commit is contained in:
commit
82ec2abb22
0
neutronclient/neutron/v2_0/bgp/__init__.py
Normal file
0
neutronclient/neutron/v2_0/bgp/__init__.py
Normal file
117
neutronclient/neutron/v2_0/bgp/dragentscheduler.py
Normal file
117
neutronclient/neutron/v2_0/bgp/dragentscheduler.py
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
|
||||||
|
# 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 __future__ import print_function
|
||||||
|
|
||||||
|
from neutronclient._i18n import _
|
||||||
|
from neutronclient.neutron import v2_0 as neutronV20
|
||||||
|
from neutronclient.neutron.v2_0.bgp import speaker as bgp_speaker
|
||||||
|
|
||||||
|
|
||||||
|
def add_common_args(parser):
|
||||||
|
parser.add_argument('dragent_id',
|
||||||
|
metavar='BGP_DRAGENT_ID',
|
||||||
|
help=_('ID of the Dynamic Routing agent.'))
|
||||||
|
parser.add_argument('bgp_speaker',
|
||||||
|
metavar='BGP_SPEAKER',
|
||||||
|
help=_('ID or name of the BGP speaker.'))
|
||||||
|
|
||||||
|
|
||||||
|
class AddBGPSpeakerToDRAgent(neutronV20.NeutronCommand):
|
||||||
|
"""Add a BGP speaker to a Dynamic Routing agent."""
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(AddBGPSpeakerToDRAgent, self).get_parser(prog_name)
|
||||||
|
add_common_args(parser)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
neutron_client = self.get_client()
|
||||||
|
_speaker_id = bgp_speaker.get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
neutron_client.add_bgp_speaker_to_dragent(
|
||||||
|
parsed_args.dragent_id, {'bgp_speaker_id': _speaker_id})
|
||||||
|
print(_('Associated BGP speaker %s to the Dynamic Routing agent.')
|
||||||
|
% parsed_args.bgp_speaker, file=self.app.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveBGPSpeakerFromDRAgent(neutronV20.NeutronCommand):
|
||||||
|
"""Removes a BGP speaker from a Dynamic Routing agent."""
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(RemoveBGPSpeakerFromDRAgent, self).get_parser(
|
||||||
|
prog_name)
|
||||||
|
add_common_args(parser)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
neutron_client = self.get_client()
|
||||||
|
_speaker_id = bgp_speaker.get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
neutron_client.remove_bgp_speaker_from_dragent(parsed_args.dragent_id,
|
||||||
|
_speaker_id)
|
||||||
|
print(_('Disassociated BGP speaker %s from the '
|
||||||
|
'Dynamic Routing agent.')
|
||||||
|
% parsed_args.bgp_speaker, file=self.app.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
class ListBGPSpeakersOnDRAgent(neutronV20.ListCommand):
|
||||||
|
"""List BGP speakers hosted by a Dynamic Routing agent."""
|
||||||
|
|
||||||
|
list_columns = ['id', 'name', 'local_as', 'ip_version']
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ListBGPSpeakersOnDRAgent,
|
||||||
|
self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'dragent_id',
|
||||||
|
metavar='BGP_DRAGENT_ID',
|
||||||
|
help=_('ID of the Dynamic Routing agent.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def call_server(self, neutron_client, search_opts, parsed_args):
|
||||||
|
data = neutron_client.list_bgp_speaker_on_dragent(
|
||||||
|
parsed_args.dragent_id, **search_opts)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class ListDRAgentsHostingBGPSpeaker(neutronV20.ListCommand):
|
||||||
|
"""List Dynamic Routing agents hosting a BGP speaker."""
|
||||||
|
|
||||||
|
resource = 'agent'
|
||||||
|
_formatters = {}
|
||||||
|
list_columns = ['id', 'host', 'admin_state_up', 'alive']
|
||||||
|
unknown_parts_flag = False
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ListDRAgentsHostingBGPSpeaker,
|
||||||
|
self).get_parser(prog_name)
|
||||||
|
parser.add_argument('bgp_speaker',
|
||||||
|
metavar='BGP_SPEAKER',
|
||||||
|
help=_('ID or name of the BGP speaker.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def extend_list(self, data, parsed_args):
|
||||||
|
for agent in data:
|
||||||
|
agent['alive'] = ":-)" if agent['alive'] else 'xxx'
|
||||||
|
|
||||||
|
def call_server(self, neutron_client, search_opts, parsed_args):
|
||||||
|
_speaker_id = bgp_speaker.get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
search_opts['bgp_speaker'] = _speaker_id
|
||||||
|
data = neutron_client.list_dragents_hosting_bgp_speaker(**search_opts)
|
||||||
|
return data
|
127
neutronclient/neutron/v2_0/bgp/peer.py
Normal file
127
neutronclient/neutron/v2_0/bgp/peer.py
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
|
||||||
|
# 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.common import exceptions
|
||||||
|
from neutronclient.common import utils
|
||||||
|
from neutronclient.common import validators
|
||||||
|
from neutronclient.neutron import v2_0 as neutronv20
|
||||||
|
|
||||||
|
|
||||||
|
def get_bgp_peer_id(client, id_or_name):
|
||||||
|
return neutronv20.find_resourceid_by_name_or_id(client,
|
||||||
|
'bgp_peer',
|
||||||
|
id_or_name)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_peer_attributes(parsed_args):
|
||||||
|
# Validate AS number
|
||||||
|
validators.validate_int_range(parsed_args, 'remote_as',
|
||||||
|
neutronv20.bgp.speaker.MIN_AS_NUM,
|
||||||
|
neutronv20.bgp.speaker.MAX_AS_NUM)
|
||||||
|
# Validate password
|
||||||
|
if parsed_args.auth_type != 'none' and parsed_args.password is None:
|
||||||
|
raise exceptions.CommandError(_('Must provide password if auth-type '
|
||||||
|
'is specified.'))
|
||||||
|
if parsed_args.auth_type == 'none' and parsed_args.password:
|
||||||
|
raise exceptions.CommandError(_('Must provide auth-type if password '
|
||||||
|
'is specified.'))
|
||||||
|
|
||||||
|
|
||||||
|
class ListPeers(neutronv20.ListCommand):
|
||||||
|
"""List BGP peers."""
|
||||||
|
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
list_columns = ['id', 'name', 'peer_ip', 'remote_as']
|
||||||
|
pagination_support = True
|
||||||
|
sorting_support = True
|
||||||
|
|
||||||
|
|
||||||
|
class ShowPeer(neutronv20.ShowCommand):
|
||||||
|
"""Show information of a given BGP peer."""
|
||||||
|
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
|
||||||
|
|
||||||
|
class CreatePeer(neutronv20.CreateCommand):
|
||||||
|
"""Create a BGP Peer."""
|
||||||
|
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'name',
|
||||||
|
metavar='NAME',
|
||||||
|
help=_('Name of the BGP peer to create.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'--peer-ip',
|
||||||
|
metavar='PEER_IP_ADDRESS',
|
||||||
|
required=True,
|
||||||
|
help=_('Peer IP address.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'--remote-as',
|
||||||
|
required=True,
|
||||||
|
metavar='PEER_REMOTE_AS',
|
||||||
|
help=_('Peer AS number. (Integer in [%(min_val)s, %(max_val)s] '
|
||||||
|
'is allowed.)') %
|
||||||
|
{'min_val': neutronv20.bgp.speaker.MIN_AS_NUM,
|
||||||
|
'max_val': neutronv20.bgp.speaker.MAX_AS_NUM})
|
||||||
|
parser.add_argument(
|
||||||
|
'--auth-type',
|
||||||
|
metavar='PEER_AUTH_TYPE',
|
||||||
|
choices=['none', 'md5'],
|
||||||
|
default='none',
|
||||||
|
type=utils.convert_to_lowercase,
|
||||||
|
help=_('Authentication algorithm. Supported algorithms: '
|
||||||
|
'none(default), md5'))
|
||||||
|
parser.add_argument(
|
||||||
|
'--password',
|
||||||
|
metavar='AUTH_PASSWORD',
|
||||||
|
help=_('Authentication password.'))
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {}
|
||||||
|
validate_peer_attributes(parsed_args)
|
||||||
|
neutronv20.update_dict(parsed_args, body,
|
||||||
|
['name', 'peer_ip',
|
||||||
|
'remote_as', 'auth_type', 'password'])
|
||||||
|
return {self.resource: body}
|
||||||
|
|
||||||
|
|
||||||
|
class UpdatePeer(neutronv20.UpdateCommand):
|
||||||
|
"""Update BGP Peer's information."""
|
||||||
|
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--name',
|
||||||
|
help=_('Updated name of the BGP peer.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'--password',
|
||||||
|
metavar='AUTH_PASSWORD',
|
||||||
|
help=_('Updated authentication password.'))
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {}
|
||||||
|
neutronv20.update_dict(parsed_args, body, ['name', 'password'])
|
||||||
|
return {self.resource: body}
|
||||||
|
|
||||||
|
|
||||||
|
class DeletePeer(neutronv20.DeleteCommand):
|
||||||
|
"""Delete a BGP peer."""
|
||||||
|
|
||||||
|
resource = 'bgp_peer'
|
277
neutronclient/neutron/v2_0/bgp/speaker.py
Executable file
277
neutronclient/neutron/v2_0/bgp/speaker.py
Executable file
@ -0,0 +1,277 @@
|
|||||||
|
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
|
||||||
|
# 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 __future__ import print_function
|
||||||
|
|
||||||
|
from neutronclient._i18n import _
|
||||||
|
from neutronclient.common import utils
|
||||||
|
from neutronclient.common import validators
|
||||||
|
from neutronclient.neutron import v2_0 as neutronv20
|
||||||
|
from neutronclient.neutron.v2_0.bgp import peer as bgp_peer
|
||||||
|
|
||||||
|
# Allowed BGP Autonomous number range
|
||||||
|
MIN_AS_NUM = 1
|
||||||
|
MAX_AS_NUM = 65535
|
||||||
|
|
||||||
|
|
||||||
|
def get_network_id(client, id_or_name):
|
||||||
|
return neutronv20.find_resourceid_by_name_or_id(client,
|
||||||
|
'network',
|
||||||
|
id_or_name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_bgp_speaker_id(client, id_or_name):
|
||||||
|
return neutronv20.find_resourceid_by_name_or_id(client,
|
||||||
|
'bgp_speaker',
|
||||||
|
id_or_name)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_speaker_attributes(parsed_args):
|
||||||
|
# Validate AS number
|
||||||
|
validators.validate_int_range(parsed_args, 'local_as',
|
||||||
|
MIN_AS_NUM, MAX_AS_NUM)
|
||||||
|
|
||||||
|
|
||||||
|
def add_common_arguments(parser):
|
||||||
|
utils.add_boolean_argument(
|
||||||
|
parser, '--advertise-floating-ip-host-routes',
|
||||||
|
help=_('Whether to enable or disable the advertisement '
|
||||||
|
'of floating-ip host routes by the BGP speaker. '
|
||||||
|
'By default floating ip host routes will be '
|
||||||
|
'advertised by the BGP speaker.'))
|
||||||
|
utils.add_boolean_argument(
|
||||||
|
parser, '--advertise-tenant-networks',
|
||||||
|
help=_('Whether to enable or disable the advertisement '
|
||||||
|
'of tenant network routes by the BGP speaker. '
|
||||||
|
'By default tenant network routes will be '
|
||||||
|
'advertised by the BGP speaker.'))
|
||||||
|
|
||||||
|
|
||||||
|
def args2body_common_arguments(body, parsed_args):
|
||||||
|
neutronv20.update_dict(parsed_args, body,
|
||||||
|
['name',
|
||||||
|
'advertise_floating_ip_host_routes',
|
||||||
|
'advertise_tenant_networks'])
|
||||||
|
|
||||||
|
|
||||||
|
class ListSpeakers(neutronv20.ListCommand):
|
||||||
|
"""List BGP speakers."""
|
||||||
|
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
list_columns = ['id', 'name', 'local_as', 'ip_version']
|
||||||
|
pagination_support = True
|
||||||
|
sorting_support = True
|
||||||
|
|
||||||
|
|
||||||
|
class ShowSpeaker(neutronv20.ShowCommand):
|
||||||
|
"""Show information of a given BGP speaker."""
|
||||||
|
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
|
||||||
|
|
||||||
|
class CreateSpeaker(neutronv20.CreateCommand):
|
||||||
|
"""Create a BGP Speaker."""
|
||||||
|
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'name',
|
||||||
|
metavar='NAME',
|
||||||
|
help=_('Name of the BGP speaker to create.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'--local-as',
|
||||||
|
metavar='LOCAL_AS',
|
||||||
|
required=True,
|
||||||
|
help=_('Local AS number. (Integer in [%(min_val)s, %(max_val)s] '
|
||||||
|
'is allowed.)') % {'min_val': MIN_AS_NUM,
|
||||||
|
'max_val': MAX_AS_NUM})
|
||||||
|
parser.add_argument(
|
||||||
|
'--ip-version',
|
||||||
|
type=int, choices=[4, 6],
|
||||||
|
default=4,
|
||||||
|
help=_('IP version for the BGP speaker (default is 4).'))
|
||||||
|
add_common_arguments(parser)
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {}
|
||||||
|
validate_speaker_attributes(parsed_args)
|
||||||
|
body['local_as'] = parsed_args.local_as
|
||||||
|
body['ip_version'] = parsed_args.ip_version
|
||||||
|
args2body_common_arguments(body, parsed_args)
|
||||||
|
return {self.resource: body}
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateSpeaker(neutronv20.UpdateCommand):
|
||||||
|
"""Update BGP Speaker's information."""
|
||||||
|
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--name',
|
||||||
|
help=_('Name of the BGP speaker to update.'))
|
||||||
|
add_common_arguments(parser)
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {}
|
||||||
|
args2body_common_arguments(body, parsed_args)
|
||||||
|
return {self.resource: body}
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteSpeaker(neutronv20.DeleteCommand):
|
||||||
|
"""Delete a BGP speaker."""
|
||||||
|
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
|
||||||
|
|
||||||
|
class AddPeerToSpeaker(neutronv20.NeutronCommand):
|
||||||
|
"""Add a peer to the BGP speaker."""
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(AddPeerToSpeaker, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'bgp_speaker',
|
||||||
|
metavar='BGP_SPEAKER',
|
||||||
|
help=_('ID or name of the BGP speaker.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'bgp_peer',
|
||||||
|
metavar='BGP_PEER',
|
||||||
|
help=_('ID or name of the BGP peer to add.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def run(self, parsed_args):
|
||||||
|
neutron_client = self.get_client()
|
||||||
|
_speaker_id = get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
_peer_id = bgp_peer.get_bgp_peer_id(neutron_client,
|
||||||
|
parsed_args.bgp_peer)
|
||||||
|
neutron_client.add_peer_to_bgp_speaker(_speaker_id,
|
||||||
|
{'bgp_peer_id': _peer_id})
|
||||||
|
print(_('Added BGP peer %(peer)s to BGP speaker %(speaker)s.') %
|
||||||
|
{'peer': parsed_args.bgp_peer,
|
||||||
|
'speaker': parsed_args.bgp_speaker},
|
||||||
|
file=self.app.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
class RemovePeerFromSpeaker(neutronv20.NeutronCommand):
|
||||||
|
"""Remove a peer from the BGP speaker."""
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(RemovePeerFromSpeaker, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'bgp_speaker',
|
||||||
|
metavar='BGP_SPEAKER',
|
||||||
|
help=_('ID or name of the BGP speaker.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'bgp_peer',
|
||||||
|
metavar='BGP_PEER',
|
||||||
|
help=_('ID or name of the BGP peer to remove.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def run(self, parsed_args):
|
||||||
|
neutron_client = self.get_client()
|
||||||
|
_speaker_id = get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
_peer_id = bgp_peer.get_bgp_peer_id(neutron_client,
|
||||||
|
parsed_args.bgp_peer)
|
||||||
|
neutron_client.remove_peer_from_bgp_speaker(_speaker_id,
|
||||||
|
{'bgp_peer_id': _peer_id})
|
||||||
|
print(_('Removed BGP peer %(peer)s from BGP speaker %(speaker)s.') %
|
||||||
|
{'peer': parsed_args.bgp_peer,
|
||||||
|
'speaker': parsed_args.bgp_speaker},
|
||||||
|
file=self.app.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
class AddNetworkToSpeaker(neutronv20.NeutronCommand):
|
||||||
|
"""Add a network to the BGP speaker."""
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(AddNetworkToSpeaker, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'bgp_speaker',
|
||||||
|
metavar='BGP_SPEAKER',
|
||||||
|
help=_('ID or name of the BGP speaker.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'network',
|
||||||
|
metavar='NETWORK',
|
||||||
|
help=_('ID or name of the network to add.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def run(self, parsed_args):
|
||||||
|
neutron_client = self.get_client()
|
||||||
|
_speaker_id = get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
_net_id = get_network_id(neutron_client,
|
||||||
|
parsed_args.network)
|
||||||
|
neutron_client.add_network_to_bgp_speaker(_speaker_id,
|
||||||
|
{'network_id': _net_id})
|
||||||
|
print(_('Added network %(net)s to BGP speaker %(speaker)s.') %
|
||||||
|
{'net': parsed_args.network, 'speaker': parsed_args.bgp_speaker},
|
||||||
|
file=self.app.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveNetworkFromSpeaker(neutronv20.NeutronCommand):
|
||||||
|
"""Remove a network from the BGP speaker."""
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(RemoveNetworkFromSpeaker, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'bgp_speaker',
|
||||||
|
metavar='BGP_SPEAKER',
|
||||||
|
help=_('ID or name of the BGP speaker.'))
|
||||||
|
parser.add_argument(
|
||||||
|
'network',
|
||||||
|
metavar='NETWORK',
|
||||||
|
help=_('ID or name of the network to remove.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def run(self, parsed_args):
|
||||||
|
neutron_client = self.get_client()
|
||||||
|
_speaker_id = get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
_net_id = get_network_id(neutron_client,
|
||||||
|
parsed_args.network)
|
||||||
|
neutron_client.remove_network_from_bgp_speaker(_speaker_id,
|
||||||
|
{'network_id': _net_id})
|
||||||
|
print(_('Removed network %(net)s from BGP speaker %(speaker)s.') %
|
||||||
|
{'net': parsed_args.network, 'speaker': parsed_args.bgp_speaker},
|
||||||
|
file=self.app.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
class ListRoutesAdvertisedBySpeaker(neutronv20.ListCommand):
|
||||||
|
"""List routes advertised by a given BGP speaker."""
|
||||||
|
|
||||||
|
list_columns = ['id', 'destination', 'next_hop']
|
||||||
|
resource = 'advertised_route'
|
||||||
|
pagination_support = True
|
||||||
|
sorting_support = True
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ListRoutesAdvertisedBySpeaker,
|
||||||
|
self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'bgp_speaker',
|
||||||
|
metavar='BGP_SPEAKER',
|
||||||
|
help=_('ID or name of the BGP speaker.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def call_server(self, neutron_client, search_opts, parsed_args):
|
||||||
|
_speaker_id = get_bgp_speaker_id(neutron_client,
|
||||||
|
parsed_args.bgp_speaker)
|
||||||
|
data = neutron_client.list_route_advertised_from_bgp_speaker(
|
||||||
|
_speaker_id, **search_opts)
|
||||||
|
return data
|
@ -45,6 +45,9 @@ from neutronclient.neutron.v2_0 import agent
|
|||||||
from neutronclient.neutron.v2_0 import agentscheduler
|
from neutronclient.neutron.v2_0 import agentscheduler
|
||||||
from neutronclient.neutron.v2_0 import auto_allocated_topology
|
from neutronclient.neutron.v2_0 import auto_allocated_topology
|
||||||
from neutronclient.neutron.v2_0 import availability_zone
|
from neutronclient.neutron.v2_0 import availability_zone
|
||||||
|
from neutronclient.neutron.v2_0.bgp import dragentscheduler as bgp_drsched
|
||||||
|
from neutronclient.neutron.v2_0.bgp import peer as bgp_peer
|
||||||
|
from neutronclient.neutron.v2_0.bgp import speaker as bgp_speaker
|
||||||
from neutronclient.neutron.v2_0 import extension
|
from neutronclient.neutron.v2_0 import extension
|
||||||
from neutronclient.neutron.v2_0.flavor import flavor
|
from neutronclient.neutron.v2_0.flavor import flavor
|
||||||
from neutronclient.neutron.v2_0.flavor import flavor_profile
|
from neutronclient.neutron.v2_0.flavor import flavor_profile
|
||||||
@ -395,6 +398,35 @@ COMMAND_V2 = {
|
|||||||
'availability-zone-list': availability_zone.ListAvailabilityZone,
|
'availability-zone-list': availability_zone.ListAvailabilityZone,
|
||||||
'auto-allocated-topology-show': (
|
'auto-allocated-topology-show': (
|
||||||
auto_allocated_topology.ShowAutoAllocatedTopology),
|
auto_allocated_topology.ShowAutoAllocatedTopology),
|
||||||
|
'bgp-dragent-speaker-add': (
|
||||||
|
bgp_drsched.AddBGPSpeakerToDRAgent
|
||||||
|
),
|
||||||
|
'bgp-dragent-speaker-remove': (
|
||||||
|
bgp_drsched.RemoveBGPSpeakerFromDRAgent
|
||||||
|
),
|
||||||
|
'bgp-speaker-list-on-dragent': (
|
||||||
|
bgp_drsched.ListBGPSpeakersOnDRAgent
|
||||||
|
),
|
||||||
|
'bgp-dragent-list-hosting-speaker': (
|
||||||
|
bgp_drsched.ListDRAgentsHostingBGPSpeaker
|
||||||
|
),
|
||||||
|
'bgp-speaker-list': bgp_speaker.ListSpeakers,
|
||||||
|
'bgp-speaker-advertiseroute-list': (
|
||||||
|
bgp_speaker.ListRoutesAdvertisedBySpeaker
|
||||||
|
),
|
||||||
|
'bgp-speaker-show': bgp_speaker.ShowSpeaker,
|
||||||
|
'bgp-speaker-create': bgp_speaker.CreateSpeaker,
|
||||||
|
'bgp-speaker-update': bgp_speaker.UpdateSpeaker,
|
||||||
|
'bgp-speaker-delete': bgp_speaker.DeleteSpeaker,
|
||||||
|
'bgp-speaker-peer-add': bgp_speaker.AddPeerToSpeaker,
|
||||||
|
'bgp-speaker-peer-remove': bgp_speaker.RemovePeerFromSpeaker,
|
||||||
|
'bgp-speaker-network-add': bgp_speaker.AddNetworkToSpeaker,
|
||||||
|
'bgp-speaker-network-remove': bgp_speaker.RemoveNetworkFromSpeaker,
|
||||||
|
'bgp-peer-list': bgp_peer.ListPeers,
|
||||||
|
'bgp-peer-show': bgp_peer.ShowPeer,
|
||||||
|
'bgp-peer-create': bgp_peer.CreatePeer,
|
||||||
|
'bgp-peer-update': bgp_peer.UpdatePeer,
|
||||||
|
'bgp-peer-delete': bgp_peer.DeletePeer,
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMANDS = {'2.0': COMMAND_V2}
|
COMMANDS = {'2.0': COMMAND_V2}
|
||||||
|
0
neutronclient/tests/unit/bgp/__init__.py
Normal file
0
neutronclient/tests/unit/bgp/__init__.py
Normal file
66
neutronclient/tests/unit/bgp/test_cli20_dragentscheduler.py
Normal file
66
neutronclient/tests/unit/bgp/test_cli20_dragentscheduler.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
|
||||||
|
# All Rights Reserved
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from neutronclient.neutron.v2_0.bgp import dragentscheduler as bgp_drsched
|
||||||
|
from neutronclient.tests.unit import test_cli20
|
||||||
|
from neutronclient.tests.unit import test_cli20_agentschedulers as test_as
|
||||||
|
|
||||||
|
|
||||||
|
BGP_DRAGENT_ID = 'bgp_dragent_id1'
|
||||||
|
BGP_SPEAKER = 'bgp_speaker_id1'
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV20DRAgentScheduler(test_as.CLITestV20AgentScheduler):
|
||||||
|
|
||||||
|
def test_add_bgp_speaker_to_dragent(self):
|
||||||
|
resource = 'agent'
|
||||||
|
cmd = bgp_drsched.AddBGPSpeakerToDRAgent(
|
||||||
|
test_cli20.MyApp(sys.stdout), None)
|
||||||
|
args = (BGP_DRAGENT_ID, BGP_SPEAKER)
|
||||||
|
body = {'bgp_speaker_id': BGP_SPEAKER}
|
||||||
|
result = {'bgp_speaker_id': 'bgp_speaker_id', }
|
||||||
|
self._test_add_to_agent(resource, cmd, args,
|
||||||
|
self.client.BGP_DRINSTANCES,
|
||||||
|
body, result)
|
||||||
|
|
||||||
|
def test_remove_bgp_speaker_from_dragent(self):
|
||||||
|
resource = 'agent'
|
||||||
|
cmd = bgp_drsched.RemoveBGPSpeakerFromDRAgent(
|
||||||
|
test_cli20.MyApp(sys.stdout), None)
|
||||||
|
args = (BGP_DRAGENT_ID, BGP_SPEAKER)
|
||||||
|
self._test_remove_from_agent(resource, cmd, args,
|
||||||
|
self.client.BGP_DRINSTANCES)
|
||||||
|
|
||||||
|
def test_list_bgp_speakers_on_dragent(self):
|
||||||
|
resources = 'bgp_speakers'
|
||||||
|
cmd = bgp_drsched.ListBGPSpeakersOnDRAgent(
|
||||||
|
test_cli20.MyApp(sys.stdout), None)
|
||||||
|
path = ((self.client.agent_path + self.client.BGP_DRINSTANCES) %
|
||||||
|
BGP_DRAGENT_ID)
|
||||||
|
self._test_list_resources(resources, cmd, base_args=[BGP_DRAGENT_ID],
|
||||||
|
path=path)
|
||||||
|
|
||||||
|
def test_list_dragents_hosting_bgp_speaker(self):
|
||||||
|
resources = 'agent'
|
||||||
|
cmd = bgp_drsched.ListDRAgentsHostingBGPSpeaker(
|
||||||
|
test_cli20.MyApp(sys.stdout), None)
|
||||||
|
path = ((self.client.bgp_speaker_path + self.client.BGP_DRAGENTS) %
|
||||||
|
BGP_DRAGENT_ID)
|
||||||
|
contents = {self.id_field: 'myid1', 'alive': True}
|
||||||
|
self._test_list_resources(resources, cmd, base_args=[BGP_DRAGENT_ID],
|
||||||
|
path=path, response_contents=contents)
|
223
neutronclient/tests/unit/bgp/test_cli20_peer.py
Normal file
223
neutronclient/tests/unit/bgp/test_cli20_peer.py
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
|
||||||
|
# All Rights Reserved
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from neutronclient.common import exceptions
|
||||||
|
from neutronclient.neutron.v2_0.bgp import peer as bgp_peer
|
||||||
|
from neutronclient.neutron.v2_0.bgp import speaker as bgp_speaker
|
||||||
|
from neutronclient.tests.unit import test_cli20
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV20BGPPeerJSON(test_cli20.CLITestV20Base):
|
||||||
|
|
||||||
|
non_admin_status_resources = ['bgp_peer']
|
||||||
|
|
||||||
|
def test_create_bgp_peer_with_mandatory_params(self):
|
||||||
|
# Create BGP peer with mandatory params.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.CreatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
peerip = '1.1.1.1'
|
||||||
|
remote_asnum = '1'
|
||||||
|
args = [name,
|
||||||
|
'--peer-ip', peerip,
|
||||||
|
'--remote-as', remote_asnum, ]
|
||||||
|
position_names = ['name', 'peer_ip', 'remote_as',
|
||||||
|
'auth_type']
|
||||||
|
position_values = [name, peerip, remote_asnum, 'none']
|
||||||
|
self._test_create_resource(resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
|
||||||
|
def test_create_bgp_peer_with_all_params(self):
|
||||||
|
# Create BGP peer with all params.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.CreatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
peerip = '1.1.1.1'
|
||||||
|
remote_asnum = '65535'
|
||||||
|
authType = 'md5'
|
||||||
|
password = 'abc'
|
||||||
|
args = [name,
|
||||||
|
'--peer-ip', peerip,
|
||||||
|
'--remote-as', remote_asnum,
|
||||||
|
'--auth-type', authType,
|
||||||
|
'--password', password]
|
||||||
|
position_names = ['name', 'peer_ip', 'remote_as',
|
||||||
|
'auth_type', 'password']
|
||||||
|
position_values = [name, peerip, remote_asnum, authType, password]
|
||||||
|
self._test_create_resource(resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
|
||||||
|
def test_create_bgp_peer_with_invalid_min_remote_asnum(self):
|
||||||
|
# Create BGP peer with invalid minimum remote-asnum.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.CreatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
peerip = '1.1.1.1'
|
||||||
|
remote_asnum = '0'
|
||||||
|
args = [name,
|
||||||
|
'--peer-ip', peerip,
|
||||||
|
'--remote-as', remote_asnum, ]
|
||||||
|
position_names = ['name', 'peer_ip', 'remote_as', ]
|
||||||
|
position_values = [name, peerip, remote_asnum, ]
|
||||||
|
exc = self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_create_resource,
|
||||||
|
resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
self.assertEqual('remote-as "0" should be an integer [%s:%s].' %
|
||||||
|
(bgp_speaker.MIN_AS_NUM, bgp_speaker.MAX_AS_NUM),
|
||||||
|
str(exc))
|
||||||
|
|
||||||
|
def test_create_bgp_peer_with_invalid_max_remote_asnum(self):
|
||||||
|
# Create BGP peer with invalid maximum remote-asnum.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.CreatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
peerip = '1.1.1.1'
|
||||||
|
remote_asnum = '65536'
|
||||||
|
args = [name,
|
||||||
|
'--peer-ip', peerip,
|
||||||
|
'--remote-as', remote_asnum, ]
|
||||||
|
position_names = ['name', 'peer_ip', 'remote_as',
|
||||||
|
'auth_type', 'password']
|
||||||
|
position_values = [name, peerip, remote_asnum, 'none', '']
|
||||||
|
exc = self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_create_resource,
|
||||||
|
resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
self.assertEqual('remote-as "65536" should be an integer [%s:%s].' %
|
||||||
|
(bgp_speaker.MIN_AS_NUM, bgp_speaker.MAX_AS_NUM),
|
||||||
|
str(exc))
|
||||||
|
|
||||||
|
def test_create_authenticated_bgp_peer_without_authtype(self):
|
||||||
|
# Create authenticated BGP peer without auth-type.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.CreatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
peerip = '1.1.1.1'
|
||||||
|
remote_asnum = '2048'
|
||||||
|
password = 'abc'
|
||||||
|
args = [name,
|
||||||
|
'--peer-ip', peerip,
|
||||||
|
'--remote-as', remote_asnum,
|
||||||
|
'--password', password]
|
||||||
|
position_names = ['name', 'peer_ip', 'remote_as', 'password']
|
||||||
|
position_values = [name, peerip, remote_asnum, password]
|
||||||
|
exc = self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_create_resource,
|
||||||
|
resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
self.assertEqual('Must provide auth-type if password is specified.',
|
||||||
|
str(exc))
|
||||||
|
|
||||||
|
def test_create_authenticated_bgp_peer_without_password(self):
|
||||||
|
# Create authenticated BGP peer without password.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.CreatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
peerip = '1.1.1.1'
|
||||||
|
remote_asnum = '2048'
|
||||||
|
authType = 'md5'
|
||||||
|
args = [name,
|
||||||
|
'--peer-ip', peerip,
|
||||||
|
'--remote-as', remote_asnum,
|
||||||
|
'--auth-type', authType]
|
||||||
|
position_names = ['name', 'peer_ip', 'remote_as', 'auth-type']
|
||||||
|
position_values = [name, peerip, remote_asnum, authType]
|
||||||
|
exc = self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_create_resource,
|
||||||
|
resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
self.assertEqual('Must provide password if auth-type is specified.',
|
||||||
|
str(exc))
|
||||||
|
|
||||||
|
def test_update_bgp_peer(self):
|
||||||
|
# Update BGP peer:
|
||||||
|
# myid --advertise-tenant-networks True
|
||||||
|
# --advertise-floating-ip-host-routes False
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.UpdatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_update_resource(resource, cmd, 'myid',
|
||||||
|
['myid', '--name', 'new-name',
|
||||||
|
'--password', 'abc'],
|
||||||
|
{'name': 'new-name', 'password': 'abc'})
|
||||||
|
|
||||||
|
def test_update_bgp_peer_exception(self):
|
||||||
|
# Update BGP peer: myid.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.UpdatePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_update_resource,
|
||||||
|
resource, cmd, 'myid', ['myid'], {})
|
||||||
|
|
||||||
|
def test_list_bgp_peer(self):
|
||||||
|
# List all BGP peers.
|
||||||
|
resources = "bgp_peers"
|
||||||
|
cmd = bgp_peer.ListPeers(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(resources, cmd, True)
|
||||||
|
|
||||||
|
# TODO(Vikram): Add test_list_bgp_peer_pagination
|
||||||
|
|
||||||
|
def test_list_bgp_peer_sort(self):
|
||||||
|
# sorted list: bgp-peer-list --sort-key name --sort-key id
|
||||||
|
# --sort-key asc --sort-key desc
|
||||||
|
resources = "bgp_peers"
|
||||||
|
cmd = bgp_peer.ListPeers(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(resources, cmd,
|
||||||
|
sort_key=["name", "id"],
|
||||||
|
sort_dir=["asc", "desc"])
|
||||||
|
|
||||||
|
def test_list_bgp_peer_limit(self):
|
||||||
|
# size (1000) limited list: bgp-peer-list -P.
|
||||||
|
resources = "bgp_peers"
|
||||||
|
cmd = bgp_peer.ListPeers(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(resources, cmd, page_size=1000)
|
||||||
|
|
||||||
|
def test_show_bgp_peer(self):
|
||||||
|
# Show BGP peer: --fields id --fields name myid.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.ShowPeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
args = ['--fields', 'id', '--fields', 'name', self.test_id]
|
||||||
|
self._test_show_resource(resource, cmd, self.test_id, args,
|
||||||
|
['id', 'name'])
|
||||||
|
|
||||||
|
def test_delete_bgp_peer(self):
|
||||||
|
# Delete BGP peer: bgp_peer_id.
|
||||||
|
resource = 'bgp_peer'
|
||||||
|
cmd = bgp_peer.DeletePeer(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
myid = 'myid'
|
||||||
|
args = [myid]
|
||||||
|
self._test_delete_resource(resource, cmd, myid, args)
|
267
neutronclient/tests/unit/bgp/test_cli20_speaker.py
Normal file
267
neutronclient/tests/unit/bgp/test_cli20_speaker.py
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
|
||||||
|
# All Rights Reserved
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from mox3 import mox
|
||||||
|
|
||||||
|
from neutronclient.common import exceptions
|
||||||
|
from neutronclient.neutron.v2_0.bgp import speaker as bgp_speaker
|
||||||
|
from neutronclient.tests.unit import test_cli20
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV20BGPSpeakerJSON(test_cli20.CLITestV20Base):
|
||||||
|
|
||||||
|
non_admin_status_resources = ['bgp_speaker']
|
||||||
|
|
||||||
|
def test_create_bgp_speaker_with_minimal_options(self):
|
||||||
|
# Create BGP Speaker with mandatory params.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.CreateSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
local_asnum = '1'
|
||||||
|
args = [name, '--local-as', local_asnum, ]
|
||||||
|
position_names = ['name', 'local_as', 'ip_version']
|
||||||
|
position_values = [name, local_asnum, 4]
|
||||||
|
self._test_create_resource(resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
|
||||||
|
def test_create_ipv4_bgp_speaker_with_all_params(self):
|
||||||
|
# Create BGP Speaker with all params.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.CreateSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
local_asnum = '1'
|
||||||
|
args = [name,
|
||||||
|
'--local-as', local_asnum,
|
||||||
|
'--ip-version', '4',
|
||||||
|
'--advertise-floating-ip-host-routes', 'True',
|
||||||
|
'--advertise-tenant-networks', 'True']
|
||||||
|
position_names = ['name', 'local_as', 'ip_version',
|
||||||
|
'advertise_floating_ip_host_routes',
|
||||||
|
'advertise_tenant_networks']
|
||||||
|
position_values = [name, local_asnum, 4, 'True', 'True']
|
||||||
|
self._test_create_resource(resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
|
||||||
|
def test_create_ipv6_bgp_speaker_with_all_params(self):
|
||||||
|
# Create BGP Speaker with all params.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.CreateSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
local_asnum = '65535'
|
||||||
|
args = [name,
|
||||||
|
'--local-as', local_asnum,
|
||||||
|
'--ip-version', '6',
|
||||||
|
'--advertise-floating-ip-host-routes', 'True',
|
||||||
|
'--advertise-tenant-networks', 'True']
|
||||||
|
position_names = ['name', 'local_as', 'ip_version',
|
||||||
|
'advertise_floating_ip_host_routes',
|
||||||
|
'advertise_tenant_networks']
|
||||||
|
position_values = [name, local_asnum, 6, 'True', 'True']
|
||||||
|
self._test_create_resource(resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
|
||||||
|
def test_create_bgp_speaker_with_invalid_min_local_asnum(self):
|
||||||
|
# Create BGP Speaker with invalid minimum local-asnum.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.CreateSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
local_asnum = '0'
|
||||||
|
args = [name,
|
||||||
|
'--local-as', local_asnum]
|
||||||
|
position_names = ['name', 'local_as']
|
||||||
|
position_values = [name, local_asnum]
|
||||||
|
exc = self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_create_resource,
|
||||||
|
resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
self.assertEqual('local-as "0" should be an integer [%s:%s].' %
|
||||||
|
(bgp_speaker.MIN_AS_NUM, bgp_speaker.MAX_AS_NUM),
|
||||||
|
str(exc))
|
||||||
|
|
||||||
|
def test_create_bgp_speaker_with_invalid_max_local_asnum(self):
|
||||||
|
# Create BGP Speaker with invalid maximum local-asnum.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.CreateSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
name = 'my-name'
|
||||||
|
my_id = 'my-id'
|
||||||
|
local_asnum = '65536'
|
||||||
|
args = [name,
|
||||||
|
'--local-as', local_asnum]
|
||||||
|
position_names = ['name', 'local_as', ]
|
||||||
|
position_values = [name, local_asnum, ]
|
||||||
|
exc = self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_create_resource,
|
||||||
|
resource, cmd, name, my_id, args,
|
||||||
|
position_names, position_values)
|
||||||
|
self.assertEqual('local-as "65536" should be an integer [%s:%s].' %
|
||||||
|
(bgp_speaker.MIN_AS_NUM, bgp_speaker.MAX_AS_NUM),
|
||||||
|
str(exc))
|
||||||
|
|
||||||
|
def test_update_bgp_speaker(self):
|
||||||
|
# Update BGP Speaker:
|
||||||
|
# myid --advertise-tenant-networks True
|
||||||
|
# --advertise-floating-ip-host-routes False
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.UpdateSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_update_resource(resource, cmd, 'myid',
|
||||||
|
['myid',
|
||||||
|
'--name', 'new-name',
|
||||||
|
'--advertise-tenant-networks', 'True',
|
||||||
|
'--advertise-floating-ip-host-routes',
|
||||||
|
'False'],
|
||||||
|
{'name': 'new-name',
|
||||||
|
'advertise_tenant_networks': 'True',
|
||||||
|
'advertise_floating_ip_host_routes':
|
||||||
|
'False'})
|
||||||
|
|
||||||
|
def test_update_bgp_speaker_exception(self):
|
||||||
|
# Update BGP Speaker: myid.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.UpdateSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self.assertRaises(exceptions.CommandError,
|
||||||
|
self._test_update_resource,
|
||||||
|
resource, cmd, 'myid', ['myid'], {})
|
||||||
|
|
||||||
|
def test_list_bgp_speaker(self):
|
||||||
|
# List all BGP Speakers.
|
||||||
|
resources = "bgp_speakers"
|
||||||
|
cmd = bgp_speaker.ListSpeakers(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(resources, cmd, True)
|
||||||
|
|
||||||
|
def test_list_bgp_speaker_pagination(self):
|
||||||
|
# List all BGP Speakers with pagination support.
|
||||||
|
cmd = bgp_speaker.ListSpeakers(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self.mox.StubOutWithMock(bgp_speaker.ListSpeakers,
|
||||||
|
"extend_list")
|
||||||
|
bgp_speaker.ListSpeakers.extend_list(mox.IsA(list),
|
||||||
|
mox.IgnoreArg())
|
||||||
|
self._test_list_resources_with_pagination("bgp_speakers",
|
||||||
|
cmd)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
self.mox.UnsetStubs()
|
||||||
|
|
||||||
|
def test_list_bgp_speaker_sort(self):
|
||||||
|
# sorted list: bgp-speaker-list --sort-key name --sort-key id
|
||||||
|
# --sort-key asc --sort-key desc
|
||||||
|
resources = "bgp_speakers"
|
||||||
|
cmd = bgp_speaker.ListSpeakers(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(resources, cmd,
|
||||||
|
sort_key=["name", "id"],
|
||||||
|
sort_dir=["asc", "desc"])
|
||||||
|
|
||||||
|
def test_list_bgp_speaker_limit(self):
|
||||||
|
# size (1000) limited list: bgp-speaker-list -P.
|
||||||
|
resources = "bgp_speakers"
|
||||||
|
cmd = bgp_speaker.ListSpeakers(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(resources, cmd, page_size=1000)
|
||||||
|
|
||||||
|
def test_show_bgp_speaker(self):
|
||||||
|
# Show BGP Speaker: --fields id --fields name myid.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.ShowSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
args = ['--fields', 'id', '--fields', 'name', self.test_id]
|
||||||
|
self._test_show_resource(resource, cmd, self.test_id, args,
|
||||||
|
['id', 'name'])
|
||||||
|
|
||||||
|
def test_delete_bgp_speaker(self):
|
||||||
|
# Delete BGP Speaker: bgp_speaker_id.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
cmd = bgp_speaker.DeleteSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
myid = 'myid'
|
||||||
|
args = [myid]
|
||||||
|
self._test_delete_resource(resource, cmd, myid, args)
|
||||||
|
|
||||||
|
def _test_add_remove_peer(self, action, cmd, args):
|
||||||
|
"""Add or Remove BGP Peer to/from a BGP Speaker."""
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
subcmd = '%s_bgp_peer' % action
|
||||||
|
body = {'bgp_peer_id': 'peerid'}
|
||||||
|
if action == 'add':
|
||||||
|
retval = {'bgp_peer': 'peerid'}
|
||||||
|
else:
|
||||||
|
retval = None
|
||||||
|
self._test_update_resource_action(resource, cmd, 'myid',
|
||||||
|
subcmd, args, body, retval)
|
||||||
|
|
||||||
|
def test_add_peer_to_bgp_speaker(self):
|
||||||
|
# Add peer to BGP speaker: myid peer_id=peerid
|
||||||
|
cmd = bgp_speaker.AddPeerToSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
args = ['myid', 'peerid']
|
||||||
|
self._test_add_remove_peer('add', cmd, args)
|
||||||
|
|
||||||
|
def test_remove_peer_from_bgp_speaker(self):
|
||||||
|
# Remove peer from BGP speaker: myid peer_id=peerid
|
||||||
|
cmd = bgp_speaker.RemovePeerFromSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
args = ['myid', 'peerid']
|
||||||
|
self._test_add_remove_peer('remove', cmd, args)
|
||||||
|
|
||||||
|
def _test_add_remove_network(self, action, cmd, args):
|
||||||
|
# Add or Remove network to/from a BGP Speaker.
|
||||||
|
resource = 'bgp_speaker'
|
||||||
|
subcmd = '%s_gateway_network' % action
|
||||||
|
body = {'network_id': 'netid'}
|
||||||
|
if action == 'add':
|
||||||
|
retval = {'network': 'netid'}
|
||||||
|
else:
|
||||||
|
retval = None
|
||||||
|
self._test_update_resource_action(resource, cmd, 'myid',
|
||||||
|
subcmd, args, body, retval)
|
||||||
|
|
||||||
|
def test_add_network_to_bgp_speaker(self):
|
||||||
|
# Add peer to BGP speaker: myid network_id=netid
|
||||||
|
cmd = bgp_speaker.AddNetworkToSpeaker(test_cli20.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
args = ['myid', 'netid']
|
||||||
|
self._test_add_remove_network('add', cmd, args)
|
||||||
|
|
||||||
|
def test_remove_network_from_bgp_speaker(self):
|
||||||
|
# Remove network from BGP speaker: myid network_id=netid
|
||||||
|
cmd = bgp_speaker.RemoveNetworkFromSpeaker(
|
||||||
|
test_cli20.MyApp(sys.stdout), None)
|
||||||
|
args = ['myid', 'netid']
|
||||||
|
self._test_add_remove_network('remove', cmd, args)
|
||||||
|
|
||||||
|
def test_list_routes_advertised_by_a_bgp_speaker(self):
|
||||||
|
# Retrieve advertised route list
|
||||||
|
resources = 'advertised_routes'
|
||||||
|
cmd = bgp_speaker.ListRoutesAdvertisedBySpeaker(
|
||||||
|
test_cli20.MyApp(sys.stdout), None)
|
||||||
|
bs_id = 'bgp_speaker_id1'
|
||||||
|
path = ((self.client.bgp_speaker_path + '/get_advertised_routes') %
|
||||||
|
bs_id)
|
||||||
|
self._test_list_resources(resources, cmd, base_args=[bs_id],
|
||||||
|
path=path)
|
@ -404,6 +404,14 @@ class Client(ClientBase):
|
|||||||
flavor_profile_binding_path = flavor_path + service_profile_path
|
flavor_profile_binding_path = flavor_path + service_profile_path
|
||||||
availability_zones_path = "/availability_zones"
|
availability_zones_path = "/availability_zones"
|
||||||
auto_allocated_topology_path = "/auto-allocated-topology/%s"
|
auto_allocated_topology_path = "/auto-allocated-topology/%s"
|
||||||
|
BGP_DRINSTANCES = "/bgp-drinstances"
|
||||||
|
BGP_DRINSTANCE = "/bgp-drinstance/%s"
|
||||||
|
BGP_DRAGENTS = "/bgp-dragents"
|
||||||
|
BGP_DRAGENT = "/bgp-dragents/%s"
|
||||||
|
bgp_speakers_path = "/bgp-speakers"
|
||||||
|
bgp_speaker_path = "/bgp-speakers/%s"
|
||||||
|
bgp_peers_path = "/bgp-peers"
|
||||||
|
bgp_peer_path = "/bgp-peers/%s"
|
||||||
|
|
||||||
# API has no way to report plurals, so we have to hard code them
|
# API has no way to report plurals, so we have to hard code them
|
||||||
EXTED_PLURALS = {'routers': 'router',
|
EXTED_PLURALS = {'routers': 'router',
|
||||||
@ -441,6 +449,8 @@ class Client(ClientBase):
|
|||||||
'bandwidth_limit_rules': 'bandwidth_limit_rule',
|
'bandwidth_limit_rules': 'bandwidth_limit_rule',
|
||||||
'rule_types': 'rule_type',
|
'rule_types': 'rule_type',
|
||||||
'flavors': 'flavor',
|
'flavors': 'flavor',
|
||||||
|
'bgp_speakers': 'bgp_speaker',
|
||||||
|
'bgp_peers': 'bgp_peer',
|
||||||
}
|
}
|
||||||
|
|
||||||
@APIParamsCall
|
@APIParamsCall
|
||||||
@ -1340,6 +1350,30 @@ class Client(ClientBase):
|
|||||||
return self.post((self.agent_path + self.L3_ROUTERS) % l3_agent,
|
return self.post((self.agent_path + self.L3_ROUTERS) % l3_agent,
|
||||||
body=body)
|
body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_dragents_hosting_bgp_speaker(self, bgp_speaker, **_params):
|
||||||
|
"""Fetches a list of Dynamic Routing agents hosting a BGP speaker."""
|
||||||
|
return self.get((self.bgp_speaker_path + self.BGP_DRAGENTS)
|
||||||
|
% bgp_speaker, params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def add_bgp_speaker_to_dragent(self, bgp_dragent, body):
|
||||||
|
"""Adds a BGP speaker to Dynamic Routing agent."""
|
||||||
|
return self.post((self.agent_path + self.BGP_DRINSTANCES)
|
||||||
|
% bgp_dragent, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def remove_bgp_speaker_from_dragent(self, bgp_dragent, bgpspeaker_id):
|
||||||
|
"""Removes a BGP speaker from Dynamic Routing agent."""
|
||||||
|
return self.delete((self.agent_path + self.BGP_DRINSTANCES + "/%s")
|
||||||
|
% (bgp_dragent, bgpspeaker_id))
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_bgp_speaker_on_dragent(self, bgp_dragent, **_params):
|
||||||
|
"""Fetches a list of BGP speakers hosted by Dynamic Routing agent."""
|
||||||
|
return self.get((self.agent_path + self.BGP_DRINSTANCES)
|
||||||
|
% bgp_dragent, params=_params)
|
||||||
|
|
||||||
@APIParamsCall
|
@APIParamsCall
|
||||||
def list_firewall_rules(self, retrieve_all=True, **_params):
|
def list_firewall_rules(self, retrieve_all=True, **_params):
|
||||||
"""Fetches a list of all firewall rules for a tenant."""
|
"""Fetches a list of all firewall rules for a tenant."""
|
||||||
@ -1695,6 +1729,89 @@ class Client(ClientBase):
|
|||||||
self.auto_allocated_topology_path % tenant_id,
|
self.auto_allocated_topology_path % tenant_id,
|
||||||
params=_params)
|
params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_bgp_speakers(self, retrieve_all=True, **_params):
|
||||||
|
"""Fetches a list of all BGP speakers for a tenant."""
|
||||||
|
return self.list('bgp_speakers', self.bgp_speakers_path, retrieve_all,
|
||||||
|
**_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def show_bgp_speaker(self, bgp_speaker_id, **_params):
|
||||||
|
"""Fetches information of a certain BGP speaker."""
|
||||||
|
return self.get(self.bgp_speaker_path % (bgp_speaker_id),
|
||||||
|
params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def create_bgp_speaker(self, body=None):
|
||||||
|
"""Creates a new BGP speaker."""
|
||||||
|
return self.post(self.bgp_speakers_path, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def update_bgp_speaker(self, bgp_speaker_id, body=None):
|
||||||
|
"""Update a BGP speaker."""
|
||||||
|
return self.put(self.bgp_speaker_path % bgp_speaker_id, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def delete_bgp_speaker(self, speaker_id):
|
||||||
|
"""Deletes the specified BGP speaker."""
|
||||||
|
return self.delete(self.bgp_speaker_path % (speaker_id))
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def add_peer_to_bgp_speaker(self, speaker_id, body=None):
|
||||||
|
"""Adds a peer to BGP speaker."""
|
||||||
|
return self.put((self.bgp_speaker_path % speaker_id) +
|
||||||
|
"/add_bgp_peer", body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def remove_peer_from_bgp_speaker(self, speaker_id, body=None):
|
||||||
|
"""Removes a peer from BGP speaker."""
|
||||||
|
return self.put((self.bgp_speaker_path % speaker_id) +
|
||||||
|
"/remove_bgp_peer", body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def add_network_to_bgp_speaker(self, speaker_id, body=None):
|
||||||
|
"""Adds a network to BGP speaker."""
|
||||||
|
return self.put((self.bgp_speaker_path % speaker_id) +
|
||||||
|
"/add_gateway_network", body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def remove_network_from_bgp_speaker(self, speaker_id, body=None):
|
||||||
|
"""Removes a network from BGP speaker."""
|
||||||
|
return self.put((self.bgp_speaker_path % speaker_id) +
|
||||||
|
"/remove_gateway_network", body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_route_advertised_from_bgp_speaker(self, speaker_id, **_params):
|
||||||
|
"""Fetches a list of all routes advertised by BGP speaker."""
|
||||||
|
return self.get((self.bgp_speaker_path % speaker_id) +
|
||||||
|
"/get_advertised_routes", params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_bgp_peers(self, **_params):
|
||||||
|
"""Fetches a list of all BGP peers."""
|
||||||
|
return self.get(self.bgp_peers_path, params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def show_bgp_peer(self, peer_id, **_params):
|
||||||
|
"""Fetches information of a certain BGP peer."""
|
||||||
|
return self.get(self.bgp_peer_path % peer_id,
|
||||||
|
params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def create_bgp_peer(self, body=None):
|
||||||
|
"""Create a new BGP peer."""
|
||||||
|
return self.post(self.bgp_peers_path, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def update_bgp_peer(self, bgp_peer_id, body=None):
|
||||||
|
"""Update a BGP peer."""
|
||||||
|
return self.put(self.bgp_peer_path % bgp_peer_id, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def delete_bgp_peer(self, peer_id):
|
||||||
|
"""Deletes the specified BGP peer."""
|
||||||
|
return self.delete(self.bgp_peer_path % peer_id)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Initialize a new client for the Neutron v2.0 API."""
|
"""Initialize a new client for the Neutron v2.0 API."""
|
||||||
super(Client, self).__init__(**kwargs)
|
super(Client, self).__init__(**kwargs)
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
CLI support for the BGP dynamic routing functionality will help
|
||||||
|
advertising neutron fixed-ips and dvr host routes via BGP.
|
Loading…
Reference in New Issue
Block a user