1#
2# (c) 2019, Ansible by Red Hat, inc
3# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
4#
5import re
6
7from ansible.module_utils.six import iteritems
8from ansible.module_utils.network.common.utils import to_list
9from ansible.module_utils.network.iosxr.providers.providers import register_provider
10from ansible.module_utils.network.iosxr.providers.providers import CliProvider
11from ansible.module_utils.network.iosxr.providers.cli.config.bgp.neighbors import Neighbors
12from ansible.module_utils.network.iosxr.providers.cli.config.bgp.address_family import AddressFamily
13
14REDISTRIBUTE_PROTOCOLS = frozenset(['ospf', 'ospfv3', 'eigrp', 'isis', 'static',
15                                    'connected', 'lisp', 'mobile', 'rip',
16                                    'subscriber'])
17
18
19@register_provider('iosxr', 'iosxr_bgp')
20class Provider(CliProvider):
21
22    def render(self, config=None):
23        commands = list()
24
25        existing_as = None
26        if config:
27            match = re.search(r'router bgp (\d+)', config, re.M)
28            if match:
29                existing_as = match.group(1)
30
31        operation = self.params['operation']
32
33        context = None
34
35        if self.params['config']:
36            context = 'router bgp %s' % self.get_value('config.bgp_as')
37
38        if operation == 'delete':
39            if existing_as:
40                commands.append('no router bgp %s' % existing_as)
41            elif context:
42                commands.append('no %s' % context)
43
44        else:
45            if operation == 'replace':
46                if existing_as and int(existing_as) != self.get_value('config.bgp_as'):
47                    # The negate command has to be committed before new BGP AS is used.
48                    self.connection.edit_config('no router bgp %s' % existing_as)
49                    config = None
50
51            elif operation == 'override':
52                if existing_as:
53                    # The negate command has to be committed before new BGP AS is used.
54                    self.connection.edit_config('no router bgp %s' % existing_as)
55                config = None
56
57            context_commands = list()
58
59            for key, value in iteritems(self.get_value('config')):
60                if value is not None:
61                    meth = getattr(self, '_render_%s' % key, None)
62                    if meth:
63                        resp = meth(config)
64                        if resp:
65                            context_commands.extend(to_list(resp))
66
67            if context and context_commands:
68                commands.append(context)
69                commands.extend(context_commands)
70                commands.append('exit')
71
72        return commands
73
74    def _render_router_id(self, config=None):
75        cmd = 'bgp router-id %s' % self.get_value('config.router_id')
76        if not config or cmd not in config:
77            return cmd
78
79    def _render_log_neighbor_changes(self, config=None):
80        cmd = 'bgp log neighbor changes'
81        log_neighbor_changes = self.get_value('config.log_neighbor_changes')
82        if log_neighbor_changes is True:
83            if not config or cmd not in config:
84                return '%s detail' % cmd
85        elif log_neighbor_changes is False:
86            if config and cmd in config:
87                return '%s disable' % cmd
88
89    def _render_neighbors(self, config):
90        """ generate bgp neighbor configuration
91        """
92        return Neighbors(self.params).render(config)
93
94    def _render_address_family(self, config):
95        """ generate address-family configuration
96        """
97        return AddressFamily(self.params).render(config)
98