1#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2#    not use this file except in compliance with the License. You may obtain
3#    a copy of the License at
4#
5#         http://www.apache.org/licenses/LICENSE-2.0
6#
7#    Unless required by applicable law or agreed to in writing, software
8#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10#    License for the specific language governing permissions and limitations
11#    under the License.
12#
13
14from osc_lib.command import command
15from osc_lib import utils
16from osc_lib.utils import columns as column_util
17
18from neutronclient._i18n import _
19from neutronclient.osc import utils as nc_osc_utils
20from neutronclient.osc.v2.dynamic_routing import constants
21
22
23def _get_attrs(client_manager, parsed_args):
24    attrs = {}
25    if parsed_args.name is not None:
26        attrs['name'] = str(parsed_args.name)
27    if 'local_as' in parsed_args:
28        attrs['local_as'] = parsed_args.local_as
29    if 'ip_version' in parsed_args:
30        attrs['ip_version'] = parsed_args.ip_version
31    if parsed_args.advertise_tenant_networks:
32        attrs['advertise_tenant_networks'] = True
33    if parsed_args.no_advertise_tenant_networks:
34        attrs['advertise_tenant_networks'] = False
35    if parsed_args.advertise_floating_ip_host_routes:
36        attrs['advertise_floating_ip_host_routes'] = True
37    if parsed_args.no_advertise_floating_ip_host_routes:
38        attrs['advertise_floating_ip_host_routes'] = False
39
40    if 'project' in parsed_args and parsed_args.project is not None:
41        identity_client = client_manager.identity
42        project_id = nc_osc_utils.find_project(
43            identity_client,
44            parsed_args.project,
45            parsed_args.project_domain,
46        ).id
47        attrs['tenant_id'] = project_id
48    return attrs
49
50
51def add_common_arguments(parser):
52    parser.add_argument(
53        '--advertise-floating-ip-host-routes',
54        action='store_true',
55        help=_("Enable the advertisement of floating IP host routes "
56               "by the BGP speaker. (default)"))
57    parser.add_argument(
58        '--no-advertise-floating-ip-host-routes',
59        action='store_true',
60        help=_("Disable the advertisement of floating IP host routes "
61               "by the BGP speaker."))
62    parser.add_argument(
63        '--advertise-tenant-networks',
64        action='store_true',
65        help=_("Enable the advertisement of tenant network routes "
66               "by the BGP speaker. (default)"))
67    parser.add_argument(
68        '--no-advertise-tenant-networks',
69        action='store_true',
70        help=_("Disable the advertisement of tenant network routes "
71               "by the BGP speaker."))
72
73
74class AddNetworkToSpeaker(command.Command):
75    _description = _("Add a network to a BGP speaker")
76
77    def get_parser(self, prog_name):
78        parser = super(AddNetworkToSpeaker, self).get_parser(prog_name)
79        parser.add_argument(
80            'bgp_speaker',
81            metavar='<bgp-speaker>',
82            help=_("BGP speaker (name or ID)"))
83        parser.add_argument(
84            'network',
85            metavar='<network>',
86            help=_("Network to add (name or ID)"))
87        return parser
88
89    def take_action(self, parsed_args):
90        client = self.app.client_manager.neutronclient
91        speaker_id = client.find_resource(constants.BGP_SPEAKER,
92                                          parsed_args.bgp_speaker)['id']
93        net_id = client.find_resource('network',
94                                      parsed_args.network)['id']
95        client.add_network_to_bgp_speaker(speaker_id, {'network_id': net_id})
96
97
98class AddPeerToSpeaker(command.Command):
99    _description = _("Add a peer to a BGP speaker")
100
101    def get_parser(self, prog_name):
102        parser = super(AddPeerToSpeaker, self).get_parser(prog_name)
103        parser.add_argument(
104            'bgp_speaker',
105            metavar='<bgp-speaker>',
106            help=_("BGP speaker (name or ID)"))
107        parser.add_argument(
108            'bgp_peer',
109            metavar='<bgp-peer>',
110            help=_("BGP Peer to add (name or ID)"))
111        return parser
112
113    def take_action(self, parsed_args):
114        client = self.app.client_manager.neutronclient
115        speaker_id = client.find_resource(constants.BGP_SPEAKER,
116                                          parsed_args.bgp_speaker)['id']
117        peer_id = client.find_resource(constants.BGP_PEER,
118                                       parsed_args.bgp_peer)['id']
119        client.add_peer_to_bgp_speaker(speaker_id, {'bgp_peer_id': peer_id})
120
121
122class CreateBgpSpeaker(command.ShowOne):
123    _description = _("Create a BGP speaker")
124
125    def get_parser(self, prog_name):
126        parser = super(CreateBgpSpeaker, self).get_parser(prog_name)
127        parser.add_argument(
128            'name',
129            metavar='<name>',
130            help=_("Name of the BGP speaker to create"))
131        parser.add_argument(
132            '--local-as',
133            metavar='<local-as>',
134            required=True,
135            help=_("Local AS number. (Integer in [%(min_val)s, %(max_val)s] "
136                   "is allowed.)") % {'min_val': constants.MIN_AS_NUM,
137                                      'max_val': constants.MAX_AS_NUM})
138        parser.add_argument(
139            '--ip-version',
140            type=int, choices=[4, 6],
141            default=4,
142            help=_("IP version for the BGP speaker (default is 4)"))
143        add_common_arguments(parser)
144        nc_osc_utils.add_project_owner_option_to_parser(parser)
145        return parser
146
147    def take_action(self, parsed_args):
148        client = self.app.client_manager.neutronclient
149        attrs = _get_attrs(self.app.client_manager, parsed_args)
150        body = {}
151        body[constants.BGP_SPEAKER] = attrs
152        obj = client.create_bgp_speaker(body)[constants.BGP_SPEAKER]
153        columns, display_columns = column_util.get_columns(obj)
154        data = utils.get_dict_properties(obj, columns)
155        return display_columns, data
156
157
158class DeleteBgpSpeaker(command.Command):
159    _description = _("Delete a BGP speaker")
160
161    def get_parser(self, prog_name):
162        parser = super(DeleteBgpSpeaker, self).get_parser(prog_name)
163        parser.add_argument(
164            'bgp_speaker',
165            metavar="<bgp-speaker>",
166            help=_("BGP speaker to delete (name or ID)")
167        )
168        return parser
169
170    def take_action(self, parsed_args):
171        client = self.app.client_manager.neutronclient
172        id = client.find_resource(constants.BGP_SPEAKER,
173                                  parsed_args.bgp_speaker)['id']
174        client.delete_bgp_speaker(id)
175
176
177class ListBgpSpeaker(command.Lister):
178    _description = _("List BGP speakers")
179
180    def get_parser(self, prog_name):
181        parser = super(ListBgpSpeaker, self).get_parser(prog_name)
182        parser.add_argument(
183            '--agent',
184            metavar='<agent-id>',
185            help=_("List BGP speakers hosted by an agent (ID only)"))
186        return parser
187
188    def take_action(self, parsed_args):
189        client = self.app.client_manager.neutronclient
190        if parsed_args.agent is not None:
191            data = client.list_bgp_speaker_on_dragent(parsed_args.agent)
192        else:
193            data = client.list_bgp_speakers()
194
195        headers = ('ID', 'Name', 'Local AS', 'IP Version')
196        columns = ('id', 'name', 'local_as', 'ip_version')
197        return (headers, (utils.get_dict_properties(s, columns)
198                          for s in data[constants.BGP_SPEAKERS]))
199
200
201class ListRoutesAdvertisedBySpeaker(command.Lister):
202    _description = _("List routes advertised")
203
204    def get_parser(self, prog_name):
205        parser = super(ListRoutesAdvertisedBySpeaker,
206                       self).get_parser(prog_name)
207        parser.add_argument(
208            'bgp_speaker',
209            metavar='<bgp-speaker>',
210            help=_("BGP speaker (name or ID)"))
211        return parser
212
213    def take_action(self, parsed_args):
214        client = self.app.client_manager.neutronclient
215        speaker_id = client.find_resource(constants.BGP_SPEAKER,
216                                          parsed_args.bgp_speaker)['id']
217        data = client.list_route_advertised_from_bgp_speaker(speaker_id)
218        headers = ('Destination', 'Nexthop')
219        columns = ('destination', 'next_hop')
220        return (headers, (utils.get_dict_properties(s, columns)
221                          for s in data['advertised_routes']))
222
223
224class RemoveNetworkFromSpeaker(command.Command):
225    _description = _("Remove a network from a BGP speaker")
226
227    def get_parser(self, prog_name):
228        parser = super(RemoveNetworkFromSpeaker, self).get_parser(prog_name)
229        parser.add_argument(
230            'bgp_speaker',
231            metavar='<bgp-speaker>',
232            help=_("BGP speaker (name or ID)"))
233        parser.add_argument(
234            'network',
235            metavar='<network>',
236            help=_("Network to remove (name or ID)"))
237        return parser
238
239    def take_action(self, parsed_args):
240        client = self.app.client_manager.neutronclient
241        speaker_id = client.find_resource(constants.BGP_SPEAKER,
242                                          parsed_args.bgp_speaker)['id']
243        net_id = client.find_resource('network',
244                                      parsed_args.network)['id']
245        client.remove_network_from_bgp_speaker(speaker_id,
246                                               {'network_id': net_id})
247
248
249class RemovePeerFromSpeaker(command.Command):
250    _description = _("Remove a peer from a BGP speaker")
251
252    def get_parser(self, prog_name):
253        parser = super(RemovePeerFromSpeaker, self).get_parser(prog_name)
254        parser.add_argument(
255            'bgp_speaker',
256            metavar='<bgp-speaker>',
257            help=_("BGP speaker (name or ID)"))
258        parser.add_argument(
259            'bgp_peer',
260            metavar='<bgp-peer>',
261            help=_("BGP Peer to remove (name or ID)"))
262        return parser
263
264    def take_action(self, parsed_args):
265        client = self.app.client_manager.neutronclient
266        speaker_id = client.find_resource(constants.BGP_SPEAKER,
267                                          parsed_args.bgp_speaker)['id']
268        peer_id = client.find_resource(constants.BGP_PEER,
269                                       parsed_args.bgp_peer)['id']
270        client.remove_peer_from_bgp_speaker(speaker_id,
271                                            {'bgp_peer_id': peer_id})
272
273
274class SetBgpSpeaker(command.Command):
275    _description = _("Set BGP speaker properties")
276
277    resource = constants.BGP_SPEAKER
278
279    def get_parser(self, prog_name):
280        parser = super(SetBgpSpeaker, self).get_parser(prog_name)
281        parser.add_argument(
282            'bgp_speaker',
283            metavar="<bgp-speaker>",
284            help=_("BGP speaker to update (name or ID)")
285        )
286        parser.add_argument(
287            '--name',
288            help=_("New name for the BGP speaker"))
289        add_common_arguments(parser)
290        return parser
291
292    def take_action(self, parsed_args):
293        client = self.app.client_manager.neutronclient
294        id = client.find_resource(constants.BGP_SPEAKER,
295                                  parsed_args.bgp_speaker)['id']
296        attrs = _get_attrs(self.app.client_manager, parsed_args)
297        body = {}
298        body[constants.BGP_SPEAKER] = attrs
299        client.update_bgp_speaker(id, body)
300
301
302class ShowBgpSpeaker(command.ShowOne):
303    _description = _("Show a BGP speaker")
304
305    def get_parser(self, prog_name):
306        parser = super(ShowBgpSpeaker, self).get_parser(prog_name)
307        parser.add_argument(
308            'bgp_speaker',
309            metavar="<bgp-speaker>",
310            help=_("BGP speaker to display (name or ID)")
311        )
312        return parser
313
314    def take_action(self, parsed_args):
315        client = self.app.client_manager.neutronclient
316        id = client.find_resource(constants.BGP_SPEAKER,
317                                  parsed_args.bgp_speaker)['id']
318        obj = client.show_bgp_speaker(id)[constants.BGP_SPEAKER]
319        columns, display_columns = column_util.get_columns(obj)
320        data = utils.get_dict_properties(obj, columns)
321        return display_columns, data
322