Updates to mapper and network check
- support for proto types: DHCP, MANUAL, STATIC
- proper interface mappings reclass/runtime
- updated map
- first step in bridge check support
Change-Id: Idd9f2aa22e34bcaa59a18776c8ebb6be086d598f
Related-PROD: PROD-28199
diff --git a/cfg_checker/modules/network/mapper.py b/cfg_checker/modules/network/mapper.py
index 08cc99f..e0c3113 100644
--- a/cfg_checker/modules/network/mapper.py
+++ b/cfg_checker/modules/network/mapper.py
@@ -1,5 +1,6 @@
import ipaddress
import json
+from copy import deepcopy
from cfg_checker.common import logger_cli
from cfg_checker.common.exception import InvalidReturnException
@@ -12,6 +13,7 @@
"name": "unnamed interface",
"mac": "",
"routes": {},
+ "proto": "",
"ip": [],
"parameters": {}
}
@@ -31,8 +33,12 @@
def __init__(self, errors_class=None):
logger_cli.info("# Initializing mapper")
+ # init networks and nodes
self.networks = {}
self.nodes = salt_master.get_nodes()
+ # init and pre-populate interfaces
+ self.interfaces = {k: {} for k in self.nodes}
+ # Init errors class
if errors_class:
self.errors = errors_class
else:
@@ -111,8 +117,12 @@
)
continue
- # build map based on IPs
+ # build map based on IPs and save info too
for _if_name, _if_data in _pillar.iteritems():
+ if _if_name not in self.interfaces[node]:
+ self.interfaces[node][_if_name] = deepcopy(_network_item)
+ self.interfaces[node][_if_name]['reclass'] = deepcopy(_if_data)
+ # map network if any
if 'address' in _if_data:
_if = ipaddress.IPv4Interface(
_if_data['address'] + '/' + _if_data['netmask']
@@ -185,6 +195,14 @@
if net_name in ['lo']:
# skip the localhost
continue
+ else:
+ # add collected data to interface storage
+ if net_name not in self.interfaces[host]:
+ self.interfaces[host][net_name] = \
+ deepcopy(_network_item)
+ self.interfaces[host][net_name]['runtime'] = \
+ deepcopy(net_data)
+
# get data and make sure that wide mask goes first
_ip4s = sorted(
net_data['ipv4'],
@@ -237,22 +255,20 @@
"""
_runtime = self.networks[self.RUNTIME]
_reclass = self.networks[self.RECLASS]
- logger_cli.info("# Reclass networks")
+ logger_cli.info("# Networks")
logger_cli.info(
- " {0:17} {1:25}: "
- "{2:19} {3:5}{4:10} {5}{6} {7} / {8} / {9}".format(
- "Hostname",
+ " {0:8} {1:25} {2:25} {3:6} {4:10} {5:10} {6}/{7}".format(
+ "Host",
"IF",
"IP",
- "rtMTU",
- "rcMTU",
- "rtState",
- "rcState",
- "rtGate",
- "rtDef.Gate",
- "rcGate"
+ "Proto",
+ "MTU",
+ "State",
+ "Gate",
+ "Def.Gate"
)
)
+ # No matter of proto, at least one IP will be present for the network
for network in _reclass:
# shortcuts
_net = str(network)
@@ -265,105 +281,112 @@
)
logger_cli.info(" {:-^50}".format(" No runtime network "))
continue
+ # hostnames
names = sorted(_runtime[network].keys())
for hostname in names:
+ node = hostname.split('.')[0]
if not salt_master.is_node_available(hostname, log=False):
logger_cli.info(
- " {0:17} {1}".format(
- hostname.split('.')[0],
- "... no data for the node"
- )
+ " {0:8} {1}".format(node, "node not available")
)
# add non-responsive node erorr
self.errors.add_error(
self.errors.NET_NODE_NON_RESPONSIVE,
host=hostname
)
-
- # print empty row
- _text = " # node non-responsive"
- logger_cli.info(
- " {0:17} {1}".format(
- hostname.split('.')[0],
- _text
- )
- )
continue
- # get the gateway for current net
- _routes = salt_master.nodes[hostname]['routes']
- _route = _routes[_net] if _net in _routes else None
- if not _route:
- _gate = "no route!"
+ # lookup interface name on node using network CIDR
+ _if_name = _runtime[network][hostname][0]["name"]
+ # get proper reclass
+ _r = self.interfaces[hostname][_if_name]['reclass']
+ _if_rc = "+" if _r else "*"
+ _if_name_suffix = ""
+ # get the proto value
+ if "proto" in _r:
+ _proto = _r['proto']
else:
- _gate = _route['gateway'] if _route['gateway'] else "-"
+ _proto = "-"
- # get the default gateway
- if 'default' in _routes:
- _d_gate = ipaddress.IPv4Address(
- _routes['default']['gateway']
+ if "type" in _r:
+ _if_name_suffix += _r["type"]
+ if "use_interfaces" in _r:
+ _if_name_suffix += "->" + ",".join(_r["use_interfaces"])
+
+ if _if_name_suffix:
+ _if_name_suffix = "({})".format(_if_name_suffix)
+
+ # check reclass has this interface
+ if _proto != "-" and not _r:
+ self.errors.add_error(
+ self.errors.NET_NODE_UNEXPECTED_IF,
+ host=hostname,
+ if_name=_if_name
)
- else:
- _d_gate = None
- _d_gate_str = _d_gate if _d_gate else "No default gateway!"
+ # get gate and routes if proto is static
+ if _proto == 'static':
+ # get the gateway for current net
+ _routes = salt_master.nodes[hostname]['routes']
+ _route = _routes[_net] if _net in _routes else None
+ if not _route:
+ _gate = "no route!"
+ else:
+ _gate = _route['gateway'] if _route['gateway'] else "-"
+
+ # get the default gateway
+ if 'default' in _routes:
+ _d_gate = ipaddress.IPv4Address(
+ _routes['default']['gateway']
+ )
+ else:
+ _d_gate = None
+ _d_gate_str = _d_gate if _d_gate else "No default gateway!"
+ else:
+ # in case of manual and dhcp, no check possible
+ _gate = "-"
+ _d_gate = "-"
+ # iterate through interfaces
_a = _runtime[network][hostname]
for _host in _a:
for _if in _host['ifs']:
- # get proper reclass
_ip_str = str(_if.exploded)
- _r = {}
- if hostname in _reclass[network]:
- for _item in _reclass[network][hostname]:
- for _item_ifs in _item['ifs']:
- if _ip_str == str(_item_ifs.exploded):
- _r = _item
- else:
- self.errors.add_error(
- self.errors.NET_NODE_UNEXPECTED_IF,
- host=hostname,
- if_name=_host['name'],
- if_ip=_ip_str
- )
# check if node is UP
if not salt_master.is_node_available(hostname):
_r_gate = "-"
# get proper network from reclass
- else:
+ elif _proto == 'static':
# Lookup match for the ip
- _r_gate = "no IF in reclass!"
- # get all networks with this hostname
- _nets = filter(
- lambda n: hostname in _reclass[n].keys(),
- _reclass
- )
- _rd = None
- for _item in _nets:
- # match ip
- _r_dat = _reclass[_item][hostname]
- for _r_ifs in _r_dat:
- for _r_if in _r_ifs['ifs']:
- if _if.ip == _r_if.ip:
- _rd = _r_ifs
- break
- if _rd:
- _gs = 'gateway'
- _e = "empty"
- _r_gate = _rd[_gs] if _gs in _rd else _e
- break
+ _r_gate = "-"
+ if "gateway" in _r:
+ _r_gate = _r["gateway"]
+ # if values match, put + for reclass
+ if _gate == _r_gate:
+ _r_gate = "+"
+ else:
+ _r_gate = "*"
# IF status in reclass
- if 'enabled' not in _r:
- _enabled = "(no record!)"
- else:
- _e = "enabled"
- _d = "disabled"
- _enabled = "("+_e+")" if _r[_e] else "("+_d+")"
+ _e = "enabled"
+ _enabled = "*"
+ if _e in _r:
+ _enabled = "+" if _r[_e] else "-"
- _name = _host['name']
_rc_mtu = _r['mtu'] if 'mtu' in _r else None
- _rc_mtu_s = str(_rc_mtu) if _rc_mtu else '(-)'
+ if _rc_mtu:
+ # there is a reclass MTU, save it
+ _rc_mtu_s = str(_rc_mtu)
+ elif _host['mtu'] == 1500 \
+ or _proto == "-" \
+ or _proto == "dhcp":
+ # 1500 is a default value => reclass not have it
+ # or this is a fancy network
+ _rc_mtu_s = "-"
+ else:
+ # this is an error
+ _rc_mtu_s = "*"
+
# check if this is a VIP address
# no checks needed if yes.
if _host['vip'] != _ip_str:
@@ -373,7 +396,7 @@
self.errors.add_error(
self.errors.NET_MTU_MISMATCH,
host=hostname,
- if_name=_name,
+ if_name=_if_name,
if_cidr=_ip_str,
reclass_mtu=_rc_mtu,
runtime_mtu=_host['mtu']
@@ -384,32 +407,33 @@
self.errors.add_error(
self.errors.NET_MTU_EMPTY,
host=hostname,
- if_name=_name,
+ if_name=_if_name,
if_cidr=_ip_str,
if_mtu=_host['mtu']
)
else:
# this is a VIP
- _name = " "*20
+ _if_name = " "*7
+ _if_rc = ""
+ _if_name_suffix = ""
_ip_str += " VIP"
- _enabled = "(-)"
+ _enabled = "-"
_r_gate = "-"
-
- _text = "{0:25} {1:19} {2:5}{3:10} {4:4}{5:10} " \
- "{6} / {7} / {8}".format(
- _name,
+ # Host IF IP Proto MTU State Gate Def.Gate
+ _text = "{:7} {:18} {:25} {:6} {:10} " \
+ "{:10} {}/{}".format(
+ _if_name + _if_rc,
+ _if_name_suffix,
_ip_str,
- _host['mtu'],
- _rc_mtu_s,
- _host['state'],
- _enabled,
- _gate,
- _d_gate_str,
- _r_gate
+ _proto,
+ _host['mtu'] + "/" + _rc_mtu_s,
+ _host['state'] + _enabled,
+ _gate + _r_gate,
+ _d_gate_str
)
logger_cli.info(
- " {0:17} {1}".format(
- hostname.split('.')[0],
+ " {0:8} {1}".format(
+ node,
_text
)
)
@@ -432,3 +456,4 @@
logger_cli.info(
" {0:17} {1}".format(hostname.split('.')[0], _text)
)
+ logger_cli.info("\n")