diff --git a/neutronclient/osc/v2/dynamic_routing/bgp_dragent.py b/neutronclient/osc/v2/dynamic_routing/bgp_dragent.py index f7f1e836b..025022996 100644 --- a/neutronclient/osc/v2/dynamic_routing/bgp_dragent.py +++ b/neutronclient/osc/v2/dynamic_routing/bgp_dragent.py @@ -70,18 +70,25 @@ class RemoveBgpSpeakerFromDRAgent(command.Command): class ListDRAgentsHostingBgpSpeaker(command.Lister): - """List dynamic routing agents hosting a BGP speaker""" + """(Deprecated) List dynamic routing agents hosting a BGP speaker + + (Use "bgp dragent list" instead) + """ resource = 'agent' list_columns = ['id', 'host', 'admin_state_up', 'alive'] unknown_parts_flag = False def get_parser(self, prog_name): + self.log.warning("The 'openstack bgp speaker show dragents' CLI is " + "deprecated and will be removed in the future. Use " + "'openstack bgp dragent list' CLI instead.") parser = super(ListDRAgentsHostingBgpSpeaker, self).get_parser(prog_name) parser.add_argument('bgp_speaker', metavar='', - help=_("ID or name of the BGP speaker")) + help=_("List dynamic routing agents hosting a " + "BGP speaker (name or ID)")) return parser def take_action(self, parsed_args): @@ -97,3 +104,39 @@ class ListDRAgentsHostingBgpSpeaker(command.Lister): (utils.get_dict_properties( s, columns, formatters=_formatters, ) for s in data['agents'])) + + +class ListDRAgent(command.Lister): + """List dynamic routing agents""" + + resource = 'agent' + list_columns = ['id', 'host', 'admin_state_up', 'alive'] + unknown_parts_flag = False + + def get_parser(self, prog_name): + parser = super(ListDRAgent, + self).get_parser(prog_name) + parser.add_argument('--bgp-speaker', + metavar='', + help=_("List dynamic routing agents hosting a " + "BGP speaker (name or ID)")) + return parser + + def take_action(self, parsed_args): + search_opts = {} + client = self.app.client_manager.neutronclient + if parsed_args.bgp_speaker is not None: + search_opts = {} + speaker_id = client.find_resource(constants.BGP_SPEAKER, + parsed_args.bgp_speaker)['id'] + search_opts['bgp_speaker'] = speaker_id + data = client.list_dragents_hosting_bgp_speaker(**search_opts) + else: + attrs = {'agent_type': 'BGP dynamic routing agent'} + data = client.list_agents(**attrs) + headers = ('ID', 'Host', 'State', 'Alive') + columns = ('id', 'host', 'admin_state_up', 'alive') + return (headers, + (utils.get_dict_properties( + s, columns, formatters=_formatters, + ) for s in data['agents'])) diff --git a/neutronclient/tests/unit/osc/v2/dynamic_routing/fakes.py b/neutronclient/tests/unit/osc/v2/dynamic_routing/fakes.py index 42acbeefd..d425cd67b 100644 --- a/neutronclient/tests/unit/osc/v2/dynamic_routing/fakes.py +++ b/neutronclient/tests/unit/osc/v2/dynamic_routing/fakes.py @@ -57,7 +57,7 @@ class FakeBgpSpeaker(object): """ bgp_speakers = [] - for i in range(0, count): + for i in range(count): bgp_speaker = FakeBgpSpeaker.create_one_bgp_speaker(attrs) bgp_speakers.append(bgp_speaker) @@ -89,8 +89,42 @@ class FakeBgpPeer(object): def create_bgp_peers(attrs=None, count=1): """Create one or multiple fake bgp peers.""" bgp_peers = [] - for i in range(0, count): + for i in range(count): bgp_peer = FakeBgpPeer.create_one_bgp_peer(attrs) bgp_peers.append(bgp_peer) return {'bgp_peers': bgp_peers} + + +class FakeDRAgent(object): + """Fake one or more dynamic routing agents.""" + + @staticmethod + def create_one_dragent(attrs=None): + attrs = attrs or {} + # Set default attributes. + dragent_attrs = { + 'binary': 'neutron-bgp-dragent', + 'admin_state_up': True, + 'alive': True, + 'topic': 'bgp_dragent', + 'host': 'network-' + uuid.uuid4().hex, + 'name': 'bgp-dragent-' + uuid.uuid4().hex, + 'agent_type': 'BGP dynamic routing agent', + 'id': uuid.uuid4().hex, + } + + # Overwrite default attributes. + dragent_attrs.update(attrs) + + return copy.deepcopy(dragent_attrs) + + @staticmethod + def create_dragents(attrs=None, count=1): + """Create one or multiple fake dynamic routing agents.""" + agents = [] + for i in range(count): + agent = FakeDRAgent.create_one_dragent(attrs) + agents.append(agent) + + return {'agents': agents} diff --git a/neutronclient/tests/unit/osc/v2/dynamic_routing/test_bgp_dragent.py b/neutronclient/tests/unit/osc/v2/dynamic_routing/test_bgp_dragent.py new file mode 100644 index 000000000..1ec7c41f0 --- /dev/null +++ b/neutronclient/tests/unit/osc/v2/dynamic_routing/test_bgp_dragent.py @@ -0,0 +1,123 @@ +# 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 mock + +from neutronclient.osc.v2.dynamic_routing import bgp_dragent +from neutronclient.tests.unit.osc.v2.dynamic_routing import fakes + + +class TestAddBgpSpeakerToDRAgent(fakes.TestNeutronDynamicRoutingOSCV2): + _bgp_speaker = fakes.FakeBgpSpeaker.create_one_bgp_speaker() + _bgp_dragent = fakes.FakeDRAgent.create_one_dragent() + _bgp_speaker_id = _bgp_speaker['id'] + _bgp_dragent_id = _bgp_dragent['id'] + + def setUp(self): + super(TestAddBgpSpeakerToDRAgent, self).setUp() + + # Get the command object to test + self.cmd = bgp_dragent.AddBgpSpeakerToDRAgent(self.app, self.namespace) + + def test_add_bgp_speaker_to_dragent(self): + arglist = [ + self._bgp_dragent_id, + self._bgp_speaker_id, + ] + verifylist = [ + ('dragent_id', self._bgp_dragent_id), + ('bgp_speaker', self._bgp_speaker_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + with mock.patch.object(self.neutronclient, + "add_bgp_speaker_to_dragent", + return_value=None): + + result = self.cmd.take_action(parsed_args) + self.neutronclient.add_bgp_speaker_to_dragent.\ + assert_called_once_with( + self._bgp_dragent_id, + {'bgp_speaker_id': self._bgp_speaker_id}) + self.assertIsNone(result) + + +class TestRemoveBgpSpeakerFromDRAgent(fakes.TestNeutronDynamicRoutingOSCV2): + _bgp_speaker = fakes.FakeBgpSpeaker.create_one_bgp_speaker() + _bgp_dragent = fakes.FakeDRAgent.create_one_dragent() + _bgp_speaker_id = _bgp_speaker['id'] + _bgp_dragent_id = _bgp_dragent['id'] + + def setUp(self): + super(TestRemoveBgpSpeakerFromDRAgent, self).setUp() + + # Get the command object to test + self.cmd = bgp_dragent.RemoveBgpSpeakerFromDRAgent( + self.app, self.namespace) + + def test_remove_bgp_speaker_from_dragent(self): + arglist = [ + self._bgp_dragent_id, + self._bgp_speaker_id, + ] + verifylist = [ + ('dragent_id', self._bgp_dragent_id), + ('bgp_speaker', self._bgp_speaker_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + with mock.patch.object(self.neutronclient, + "remove_bgp_speaker_from_dragent", + return_value=None): + result = self.cmd.take_action(parsed_args) + self.neutronclient.remove_bgp_speaker_from_dragent.\ + assert_called_once_with(self._bgp_dragent_id, + self._bgp_speaker_id) + self.assertIsNone(result) + + +class TestListDRAgentsHostingBgpSpeaker(fakes.TestNeutronDynamicRoutingOSCV2): + _bgp_speaker = fakes.FakeBgpSpeaker.create_one_bgp_speaker() + _bgp_speaker_id = _bgp_speaker['id'] + attrs = {'bgp_speaker_id': _bgp_speaker_id} + _bgp_dragents = fakes.FakeDRAgent.create_dragents(attrs) + columns = ('ID', 'Host', 'State', 'Alive') + data = [(_bgp_dragent['id'], + _bgp_dragent['host'], + _bgp_dragent['admin_state_up'], + ':-)' if _bgp_dragent['alive'] else 'XXX') + for _bgp_dragent in _bgp_dragents['agents']] + + def setUp(self): + super(TestListDRAgentsHostingBgpSpeaker, self).setUp() + + # Get the command object to test + self.cmd = bgp_dragent.ListDRAgent(self.app, self.namespace) + + def test_list_dragents_hosting_bgp_speaker(self): + arglist = [ + '--bgp-speaker', self._bgp_speaker_id, + ] + verifylist = [ + ('bgp_speaker', self._bgp_speaker_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + with mock.patch.object(self.neutronclient, + "list_dragents_hosting_bgp_speaker", + return_value=self._bgp_dragents): + columns, data = self.cmd.take_action(parsed_args) + attrs = {'bgp_speaker': self._bgp_speaker_id} + self.neutronclient.list_dragents_hosting_bgp_speaker.\ + assert_called_once_with(**attrs) + self.assertEqual(self.columns, columns) + self.assertListEqual(self.data, list(data)) diff --git a/releasenotes/notes/deprecate-bgp-speaker-show-dragents-2fcce99cf6bb5b60.yaml b/releasenotes/notes/deprecate-bgp-speaker-show-dragents-2fcce99cf6bb5b60.yaml new file mode 100644 index 000000000..6233c6f4f --- /dev/null +++ b/releasenotes/notes/deprecate-bgp-speaker-show-dragents-2fcce99cf6bb5b60.yaml @@ -0,0 +1,10 @@ +--- +deprecations: + - | + The ``openstack bgp speaker show dragents`` CLI is deprecated and + will be removed in the future. Use ``openstack bgp dragent list + --bgp-speaker `` CLI instead. +features: + - | + The ``openstack bgp dragent list`` CLI is added to support showing + the list of dynamic routing agents. diff --git a/setup.cfg b/setup.cfg index 16cfc5aef..d1fb096c2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -70,6 +70,7 @@ openstack.neutronclient.v2 = sfc_service_graph_show = neutronclient.osc.v2.sfc.sfc_service_graph:ShowSfcServiceGraph bgp_dragent_add_speaker = neutronclient.osc.v2.dynamic_routing.bgp_dragent:AddBgpSpeakerToDRAgent + bgp_dragent_list = neutronclient.osc.v2.dynamic_routing.bgp_dragent:ListDRAgent bgp_dragent_remove_speaker = neutronclient.osc.v2.dynamic_routing.bgp_dragent:RemoveBgpSpeakerFromDRAgent bgp_peer_create = neutronclient.osc.v2.dynamic_routing.bgp_peer:CreateBgpPeer bgp_peer_delete = neutronclient.osc.v2.dynamic_routing.bgp_peer:DeleteBgpPeer