Updates for network checker
- New checks for uniform MTU and Duplicate IPs
- Updated mapping for K8s envs
- K8s envs can skip networks using IF name keywords. Defaults to "docker"
- Network listing now gives details on Names and used MTU
Related-PROD: PROD-35288
Change-Id: Ida345ce1762038f744c460805d607d1439e434b8
diff --git a/cfg_checker/modules/network/__init__.py b/cfg_checker/modules/network/__init__.py
index 2b806d6..714c170 100644
--- a/cfg_checker/modules/network/__init__.py
+++ b/cfg_checker/modules/network/__init__.py
@@ -46,6 +46,14 @@
help="Print error details after summary"
)
+ net_check_parser.add_argument(
+ '--skip-ifs',
+ metavar='skip_ifs', default="docker",
+ help="String with keywords to skip networks which has interfaces "
+ "names with keywords as substrings. Example: 'eno' keyword will "
+ "cause to skip interface named 'eno1np0'. Example: 'docker'"
+ )
+
net_report_parser = net_subparsers.add_parser(
'report',
help="Generate network check report"
@@ -101,6 +109,15 @@
args,
config
)
+ # prepare skip keywords
+ _skip_ifs_keywords = []
+ for _str in args.skip_ifs.split(","):
+ _skip_ifs_keywords.append(_str)
+ logger_cli.info(
+ "-> Interface keywords skip list is '{}'".format(
+ ", ".join(_skip_ifs_keywords)
+ )
+ )
# Start command
logger_cli.info("# Network check to console")
_skip, _skip_file = args_utils.get_skip_args(args)
@@ -110,7 +127,7 @@
skip_list=_skip,
skip_list_file=_skip_file
)
- netChecker.check_networks()
+ netChecker.check_networks(skip_keywords=_skip_ifs_keywords)
# save what was collected
netChecker.errors.save_iteration_data()
@@ -199,10 +216,22 @@
logger_cli.info("\n".join(_s))
runtime = _map.map_network(_map.RUNTIME)
- _s = [str(_n) for _n in runtime.keys()]
logger_cli.info("\n# Runtime networks list")
- logger_cli.info("\n".join(_s))
-
+ for _net, _nodes in runtime.items():
+ _names = set()
+ _mtus = set()
+ for _node_name, _interfaces in _nodes.items():
+ for _if in _interfaces:
+ _names.add(_if["name"])
+ _mtus.add(_if["mtu"])
+ logger_cli.info(
+ "{:21}: {}, {}".format(
+ str(_net),
+ "/".join(list(_names)),
+ "/".join(list(_mtus))
+ )
+ )
+ # Done
return
diff --git a/cfg_checker/modules/network/checker.py b/cfg_checker/modules/network/checker.py
index b5809f3..0b336f2 100644
--- a/cfg_checker/modules/network/checker.py
+++ b/cfg_checker/modules/network/checker.py
@@ -10,9 +10,78 @@
logger_cli.debug("... init error logs folder")
self.errors = NetworkErrors()
- def check_networks(self, map=True):
+ def _check_duplicate_ips(self):
+ # shortcuts
+ logger_cli.debug("... checking for duplicate ips")
+ _map = self.mapper.map
+ for _net in _map.keys():
+ _ips = set()
+ for _node_name, _interfaces in _map[_net].items():
+ for _if in _interfaces:
+ if _if["ip_address"] not in _ips:
+ # there was no such ip yet
+ _ips.add(_if["ip_address"])
+ else:
+ # this ip already used
+ logger_cli.warning(
+ "Warning: Duplicate ip address: "
+ "'{}: {}' at {} -> {}".format(
+ _if["interface"],
+ _if["ip_address"],
+ _net,
+ _node_name
+ )
+ )
+ self.errors.add_error(
+ self.errors.NET_DUPLICATE_IP,
+ network=_net,
+ node_name=_node_name,
+ if_name=_if["interface"],
+ ip_address=_if["ip_address"]
+ )
+ return
+
+ def _check_non_uniform_mtu(self):
+ # shortcuts
+ logger_cli.debug("... checking for duplicate ips")
+ _map = self.mapper.map
+ for _net in _map.keys():
+ _mtus = set()
+ for _node_name, _interfaces in _map[_net].items():
+ for _if in _interfaces:
+ if len(_mtus) < 1:
+ # this is the 1st iteration
+ _mtus.add(_if["rt_mtu"])
+ elif _if["rt_mtu"] not in _mtus:
+ # this ip already used
+ logger_cli.warning(
+ "Non-uniform MTU value of '{}' in '{}': "
+ "{}:{}:{}".format(
+ _net,
+ _node_name,
+ _if["interface"],
+ _if["ip_address"],
+ _if["rt_mtu"]
+ )
+ )
+ self.errors.add_error(
+ self.errors.NET_DUPLICATE_IP,
+ network=_net,
+ node_name=_node_name,
+ if_name=_if["interface"],
+ ip_address=_if["ip_address"],
+ mtu=_if["rt_mtu"]
+ )
+ return
+
+ def check_networks(self, map=True, skip_keywords=None):
+ # Load map
self.mapper.map_networks()
- self.mapper.create_map()
+ self.mapper.create_map(skip_keywords=skip_keywords)
+ # Check for errors that is not detectable during mapping
+ self._check_duplicate_ips()
+ self._check_non_uniform_mtu()
+ # print map if requested
if map:
self.mapper.print_map()
diff --git a/cfg_checker/modules/network/mapper.py b/cfg_checker/modules/network/mapper.py
index fff6bb6..f0fd78d 100644
--- a/cfg_checker/modules/network/mapper.py
+++ b/cfg_checker/modules/network/mapper.py
@@ -196,7 +196,7 @@
))
logger_cli.info("-> done collecting networks data")
- logger_cli.info("-> mapping IPs")
+ logger_cli.info("-> mapping runtime network IPs")
# match interfaces by IP subnets
for host, node_data in self.master.nodes.items():
if not self.master.is_node_available(host):
@@ -437,7 +437,9 @@
return _result
def map_networks(self):
+ logger_cli.info("-> Mapping reclass networks")
self.map_network(self.RECLASS)
+ logger_cli.info("-> Mapping runtime networks")
self.map_network(self.RUNTIME)
def map_network(self, source):
@@ -455,7 +457,7 @@
self.networks[source] = _networks
return _networks
- def create_map(self):
+ def create_map(self, skip_keywords=None):
"""Create all needed elements for map output
:return: none
@@ -804,6 +806,7 @@
return _result
def map_networks(self):
+ logger_cli.info("-> Mapping runtime networks")
self.map_network(self.RUNTIME)
def map_network(self, source):
@@ -822,13 +825,15 @@
self.networks[source] = _networks
return _networks
- def create_map(self):
+ def create_map(self, skip_keywords=None):
"""Create all needed elements for map output
:return: none
"""
+ # shortcut
_runtime = self.networks[self.RUNTIME]
-
+ # networks to skip
+ _net_skip_list = []
# main networks, target vars
_map = {}
# No matter of proto, at least one IP will be present for the network
@@ -866,6 +871,11 @@
for _host in _a:
for _if in _host['ifs']:
_ip_str = str(_if.exploded)
+ # Make sure we print VIP properly
+ if _host['vip'] == _ip_str:
+ _if_name = " "*7
+ _if_name_suffix = ""
+ _ip_str += " VIP"
# Save all data
_values = {
@@ -876,6 +886,7 @@
"ip_address": _ip_str,
"rt_mtu": _host['mtu'],
"status": _host['state'],
+ "type": _host['type'],
"raw_data": _raw,
}
if node in _map[_net]:
@@ -884,7 +895,15 @@
else:
_map[_net][node] = [_values]
_notes = []
+ # process skips: if key substring found in interface name
+ # then skip the whole network.
+ if any([True for _w in skip_keywords if _w in _if_name]):
+ _net_skip_list.append(_net)
+ # remove skipped networks from list
+ _net_skip_list = list(set(_net_skip_list))
+ for _net in _net_skip_list:
+ _map.pop(_net)
# save map
self.map = _map
return
@@ -897,7 +916,7 @@
"""
logger_cli.info("# Networks")
logger_cli.info(
- " {0:8} {1:25} {2:25} {3:10} {4:10}".format(
+ " {0:47} {1:12} {2:25} {3:5} {4:4}".format(
"Host",
"IF",
"IP",
@@ -912,7 +931,7 @@
_n = self.map[network][hostname]
for _i in _n:
# Host IF IP Proto MTU State Gate Def.Gate
- _text = "{:7} {:17} {:25} {:5} {:10}".format(
+ _text = "{:10} {:2} {:25} {:5} {:4}".format(
_i['interface'],
_i['interface_note'],
_i['ip_address'],
@@ -920,7 +939,7 @@
_i['status']
)
logger_cli.info(
- " {0:8} {1}".format(
+ " {0:47} {1}".format(
node,
_text
)
diff --git a/cfg_checker/modules/network/network_errors.py b/cfg_checker/modules/network/network_errors.py
index 7159a36..63966a8 100644
--- a/cfg_checker/modules/network/network_errors.py
+++ b/cfg_checker/modules/network/network_errors.py
@@ -12,6 +12,7 @@
NET_MTU_EMPTY = next(_c)
NET_NO_RC_IF_STATUS = next(_c)
NET_DUPLICATE_IF = next(_c)
+ NET_DUPLICATE_IP = next(_c)
NET_SUBNET_INTERSECT = next(_c)
NET_MASK_MISMATCH = next(_c)
NET_NODE_NON_RESPONSIVE = next(_c)
@@ -43,6 +44,10 @@
"Duplicate interface specified"
)
self.add_error_type(
+ self.NET_DUPLICATE_IP,
+ "Duplicate ip address used on the subnet"
+ )
+ self.add_error_type(
self.NET_SUBNET_INTERSECT,
"Subnets intersection detected"
)