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#
5from __future__ import absolute_import, division, print_function
6
7__metaclass__ = type
8import re
9
10from ansible.module_utils.six import iteritems
11from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
12    to_list,
13)
14from ansible_collections.arista.eos.plugins.module_utils.network.eos.providers.providers import (
15    CliProvider,
16)
17from ansible_collections.arista.eos.plugins.module_utils.network.eos.providers.cli.config.bgp.neighbors import (
18    AFNeighbors,
19)
20
21
22class AddressFamily(CliProvider):
23    def render(self, config=None):
24        commands = list()
25        safe_list = list()
26
27        router_context = "router bgp %s" % self.get_value("config.bgp_as")
28        context_config = None
29
30        for item in self.get_value("config.address_family"):
31            context = "address-family %s" % item["afi"]
32            context_commands = list()
33
34            if config:
35                context_path = [router_context, context]
36                context_config = self.get_config_context(
37                    config, context_path, indent=2
38                )
39
40            for key, value in iteritems(item):
41                if value is not None:
42                    meth = getattr(self, "_render_%s" % key, None)
43                    if meth:
44                        resp = meth(item, context_config)
45                        if resp:
46                            context_commands.extend(to_list(resp))
47
48            if context_commands:
49                commands.append(context)
50                commands.extend(context_commands)
51                commands.append("exit")
52
53            safe_list.append(context)
54
55        if self.params["operation"] == "replace":
56            if config:
57                resp = self._negate_config(config, safe_list)
58                commands.extend(resp)
59
60        return commands
61
62    def _negate_config(self, config, safe_list=None):
63        commands = list()
64        matches = re.findall(r"(address-family .+)$", config, re.M)
65        for item in set(matches).difference(safe_list):
66            commands.append("no %s" % item)
67        return commands
68
69    def _render_auto_summary(self, item, config=None):
70        cmd = "auto-summary"
71        if item["auto_summary"] is False:
72            cmd = "no %s" % cmd
73        if not config or cmd not in config:
74            return cmd
75
76    def _render_synchronization(self, item, config=None):
77        cmd = "synchronization"
78        if item["synchronization"] is False:
79            cmd = "no %s" % cmd
80        if not config or cmd not in config:
81            return cmd
82
83    def _render_networks(self, item, config=None):
84        commands = list()
85        safe_list = list()
86
87        for entry in item["networks"]:
88            network = entry["prefix"]
89            if entry["masklen"]:
90                network = "%s/%s" % (entry["prefix"], entry["masklen"])
91            safe_list.append(network)
92
93            cmd = "network %s" % network
94
95            if entry["route_map"]:
96                cmd += " route-map %s" % entry["route_map"]
97
98            if not config or cmd not in config:
99                commands.append(cmd)
100
101        if self.params["operation"] == "replace":
102            if config:
103                matches = re.findall(r"network (\S+)", config, re.M)
104                for entry in set(matches).difference(safe_list):
105                    commands.append("no network %s" % entry)
106
107        return commands
108
109    def _render_redistribute(self, item, config=None):
110        commands = list()
111        safe_list = list()
112
113        for entry in item["redistribute"]:
114            option = entry["protocol"]
115
116            cmd = "redistribute %s" % entry["protocol"]
117
118            if entry["route_map"]:
119                cmd += " route-map %s" % entry["route_map"]
120
121            if not config or cmd not in config:
122                commands.append(cmd)
123
124            safe_list.append(option)
125
126        if self.params["operation"] == "replace":
127            if config:
128                matches = re.findall(
129                    r"redistribute (\S+)(?:\s*)(\d*)", config, re.M
130                )
131                for i in range(0, len(matches)):
132                    matches[i] = " ".join(matches[i]).strip()
133                for entry in set(matches).difference(safe_list):
134                    commands.append("no redistribute %s" % entry)
135
136        return commands
137
138    def _render_neighbors(self, item, config):
139        """generate bgp neighbor configuration"""
140        return AFNeighbors(self.params).render(
141            config, nbr_list=item["neighbors"]
142        )
143