blob: ccc7d62efa5b0f95d2b0d1da723cb804e4563a7e [file] [log] [blame]
Alex Savatieiev9b2f6512019-02-20 18:05:00 -06001import json
2import os
3import sys
Alex Savatieieve9613992019-02-21 18:20:35 -06004import ipaddress
Alex Savatieiev9b2f6512019-02-20 18:05:00 -06005
6from copy import deepcopy
7
Alex Savatieievf526dc02019-03-06 10:11:32 -06008from cfg_checker.reports import reporter
Alex Savatieiev9b2f6512019-02-20 18:05:00 -06009from cfg_checker.common import utils, const
10from cfg_checker.common import config, logger, logger_cli, pkg_dir
11from cfg_checker.common import salt_utils
12from cfg_checker.nodes import SaltNodes, node_tmpl
13
14
15class NetworkChecker(SaltNodes):
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -060016 @staticmethod
17 def _map_network_for_host(host, if_class, net_list, data):
18 if not any(if_class.ip in net for net in net_list.keys()):
19 # IP not fits into existing networks
20 if if_class.network not in net_list.keys():
21 # create subnet key
22 net_list[if_class.network] = {}
23 # add the host to the dict
24 net_list[if_class.network][host] = data
25 else:
26 # There is a network that ip fits into
27 for _net in net_list.keys():
28 if if_class.ip in _net:
29 net_list[_net][host] = data
30
31 return net_list
32
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060033 def collect_network_info(self):
34 """
35 Collects info on the network using ifs_data.py script
36
37 :return: none
38 """
39 logger_cli.info("### Collecting network data")
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -060040 _result = self.execute_script_on_active_nodes("ifs_data.py", args=["json"])
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060041
42 for key in self.nodes.keys():
43 # due to much data to be passed from salt, it is happening in order
44 if key in _result:
45 _text = _result[key]
46 _dict = json.loads(_text[_text.find('{'):])
47 self.nodes[key]['networks'] = _dict
48 else:
49 self.nodes[key]['networks'] = {}
50 logger_cli.debug("# {} has {} networks".format(
51 key,
52 len(self.nodes[key]['networks'].keys())
53 ))
Alex Savatieievf808cd22019-03-01 13:17:59 -060054 logger_cli.info("-> done collecting networks data")
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060055
Alex Savatieieve9613992019-02-21 18:20:35 -060056 # dump collected data to speed up coding
57 # with open('dump.json', 'w+') as ff:
58 # ff.write(json.dumps(self.nodes))
59
60 # load dump data
61 # with open('dump.json', 'r') as ff:
62 # _nodes = json.loads(ff.read())
63
64 logger_cli.info("### Building network tree")
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -060065 # match interfaces by IP subnets
Alex Savatieieve9613992019-02-21 18:20:35 -060066 _all_nets = {}
Alex Savatieieva05921f2019-02-21 18:21:39 -060067 for host, node_data in self.nodes.iteritems():
Alex Savatieieve9613992019-02-21 18:20:35 -060068 for net_name, net_data in node_data['networks'].iteritems():
69 # get ips and calculate subnets
70 if net_name == 'lo':
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -060071 # skip the localhost
Alex Savatieieve9613992019-02-21 18:20:35 -060072 continue
73 _ip4s = net_data['ipv4']
74 for _ip_str in _ip4s.keys():
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -060075 # create interface class
Alex Savatieieve9613992019-02-21 18:20:35 -060076 _if = ipaddress.IPv4Interface(_ip_str)
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -060077 net_data['name'] = net_name
78 net_data['if'] = _if
79
80 _all_nets = self._map_network_for_host(
81 host,
82 _if,
83 _all_nets,
84 net_data
85 )
Alex Savatieieve9613992019-02-21 18:20:35 -060086
87 # save collected info
88 self.all_networks = _all_nets
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060089
Alex Savatieiev9c642112019-02-26 13:55:43 -060090
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -060091 def collect_reclass_networks(self):
92 # Get networks from reclass and mark them
93 _reclass_nets = {}
94 # Get required pillars
95 self.get_specific_pillar_for_nodes("linux:network")
96 for node in self.nodes.keys():
97 _pillar = self.nodes[node]['pillars']['linux']['network']['interface']
98 for _if_name, _if_data in _pillar.iteritems():
99 if 'address' in _if_data:
100 _if = ipaddress.IPv4Interface(
101 _if_data['address'] + '/' + _if_data['netmask']
102 )
103 _if_data['name'] = _if_name
104 _if_data['if'] = _if
105
106 _reclass_nets = self._map_network_for_host(
107 node,
108 _if,
109 _reclass_nets,
110 _if_data
111 )
112
113 self.reclass_nets = _reclass_nets
114
Alex Savatieiev9c642112019-02-26 13:55:43 -0600115
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600116 def print_network_report(self):
117 """
118 Create text report for CLI
119
120 :return: none
121 """
Alex Savatieieve9613992019-02-21 18:20:35 -0600122 for network, nodes in self.all_networks.iteritems():
123 logger_cli.info("-> {}".format(str(network)))
124 names = sorted(nodes.keys())
125
126 for hostname in names:
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -0600127 _text = "{0:30}: {1:19} {2:5} {3:4}".format(
128 nodes[hostname]['name'],
129 str(nodes[hostname]['if'].ip),
130 nodes[hostname]['mtu'],
131 nodes[hostname]['state']
132 )
Alex Savatieieve9613992019-02-21 18:20:35 -0600133 logger_cli.info(
Alex Savatieiev01f0d7f2019-03-07 17:53:29 -0600134 "\t{0:10} {1}".format(hostname.split('.')[0], _text)
Alex Savatieieve9613992019-02-21 18:20:35 -0600135 )
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600136
137 def create_html_report(self, filename):
138 """
139 Create static html showing network schema-like report
140
141 :return: none
142 """
143 logger_cli.info("### Generating report to '{}'".format(filename))
144 _report = reporter.ReportToFile(
145 reporter.HTMLNetworkReport(),
146 filename
147 )
148 _report({
149 "nodes": self.nodes,
150 "diffs": {}
151 })
152 logger_cli.info("-> Done")