1# -*- coding: utf-8 -*-
2# Copyright 2020 Red Hat
3# GNU General Public License v3.0+
4# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6from __future__ import absolute_import, division, print_function
7
8__metaclass__ = type
9
10"""
11The iosxr ospf_interfaces fact class
12It is in this file the configuration is collected from the device
13for a given resource, parsed, and the facts tree is populated
14based on the configuration.
15"""
16
17from copy import deepcopy
18import re
19from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
20    utils,
21)
22from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ospf_interfaces import (
23    Ospf_interfacesTemplate,
24)
25from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ospf_interfaces.ospf_interfaces import (
26    Ospf_interfacesArgs,
27)
28
29
30class Ospf_interfacesFacts(object):
31    """ The iosxr ospf_interfaces facts class
32    """
33
34    def __init__(self, module, subspec="config", options="options"):
35        self._module = module
36        self.argument_spec = Ospf_interfacesArgs.argument_spec
37        spec = deepcopy(self.argument_spec)
38        if subspec:
39            if options:
40                facts_argument_spec = spec[subspec][options]
41            else:
42                facts_argument_spec = spec[subspec]
43        else:
44            facts_argument_spec = spec
45
46        self.generated_spec = utils.generate_dict(facts_argument_spec)
47
48    def get_ospf_interfaces(self, connection, flag):
49        cmd = "show running-config router " + flag
50        return connection.get(cmd)
51
52    def populate_facts(self, connection, ansible_facts, data=None):
53        """ Populate the facts for Ospf_interfaces network resource
54
55        :param connection: the device connection
56        :param ansible_facts: Facts dictionary
57        :param data: previously collected conf
58
59        :rtype: dictionary
60        :returns: facts
61        """
62        facts = {}
63        objs = []
64        if not data:
65            data = self.get_ospf_interfaces(connection, flag="ospf")
66            data += "\n" + self.get_ospf_interfaces(connection, flag="ospfv3")
67        end_flag, end_mark, count, v_read = 0, 0, 0, False
68        areas, config_commands = [], []
69        area_str, process, curr_process = "", "", ""
70        data = data.splitlines()
71
72        for line in data:
73            if (
74                line.startswith("router")
75                and curr_process != ""
76                and curr_process != line
77            ):
78                end_mark, count, end_flag, area_str = 0, 0, 0, ""
79            if end_mark == 0 and count == 0 and line.startswith("router ospf"):
80                curr_process = line
81                process = re.sub("\n", "", line)
82                count += 1
83                config_commands.append(process)
84            else:
85                if line.startswith(" area") or line.startswith(" vrf"):
86                    area_str = process + re.sub("\n", "", line)
87                    config_commands.append(area_str.replace("  ", " "))
88                    end_flag += 1
89                elif line.startswith("  interface"):
90                    ospf_int = area_str + re.sub("\n", "", line)
91                    # default output format has more spaces with default identation
92                    # reset the spaces with replace
93                    config_commands.append(ospf_int.replace("  ", " "))
94                    v_read = True
95                elif v_read:
96                    if "!" not in line:
97                        command = ospf_int.replace("  ", " ") + re.sub(
98                            "\n", "", line
99                        )
100                        config_commands.append(command.replace("   ", " "))
101                    else:
102                        v_read = False
103                elif end_flag > 0 and "!" not in line:
104                    command = area_str + re.sub("\n", "", line)
105                    config_commands.append(command.replace("  ", " "))
106                elif "!" in line:
107                    end_flag = 0
108                    end_mark += 1
109                    if end_mark == 3:
110                        end_mark, count = 0, 0
111                    area_str = ""
112                else:
113                    command = process + line
114                    command.replace("  ", " ")
115                    config_commands.append(re.sub("\n", "", command))
116                    areas.append(re.sub("\n", "", command))
117        data = config_commands
118
119        ospf_interfaces_parser = Ospf_interfacesTemplate(
120            lines=data, module=self._module
121        )
122        objs = list(ospf_interfaces_parser.parse().values())
123        if objs:
124            for item in objs:
125                item["address_family"] = list(item["address_family"].values())
126                for af in item["address_family"]:
127                    if af.get("processes"):
128                        af["processes"] = list(af["processes"].values())
129
130        ansible_facts["ansible_network_resources"].pop("ospf_interfaces", None)
131
132        params = utils.remove_empties(
133            ospf_interfaces_parser.validate_config(
134                self.argument_spec, {"config": objs}, redact=True
135            )
136        )
137
138        facts["ospf_interfaces"] = params.get("config", [])
139        ansible_facts["ansible_network_resources"].update(facts)
140
141        return ansible_facts
142