|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- from os import listdir, path
- from subprocess import Popen,PIPE
- from re import findall as refindall
- from re import search as research
- import salt.utils
- import socket, struct, fcntl
- import logging
-
- logger = logging.getLogger(__name__)
- stream = logging.StreamHandler()
- logger.addHandler(stream)
-
- def get_ip(iface='ens2'):
-
- ''' Get ip address from an interface if applicable
-
- :param iface: Interface name. Type: str
-
- '''
-
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sockfd = sock.fileno()
- SIOCGIFADDR = 0x8915
- ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
-
- try:
- res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
- except:
- logger.debug("No ip addresses assigned to %s" % iface)
- return None
-
- ip = struct.unpack('16sH2x4s8x', res)[2]
- return socket.inet_ntoa(ip)
-
- def get_nics():
-
- ''' List nics '''
-
- nics = []
- nics_list = listdir('/sys/class/net/')
- for nic_name in nics_list:
- if research('(br|bond|ens|enp|eth|one|ten|fourty)[0-9]+', nic_name):
-
- # Interface should be in "up" state in order to get carrier status
- Popen("ip li set dev " + nic_name + " up", shell=True, stdout=PIPE)
-
- with open("/sys/class/net/" + nic_name + "/carrier", 'r') as f:
- try:
- carrier = int(f.read())
- except:
- carrier = 0
-
- bond = ""
- if path.isfile("/sys/class/net/" + nic_name + "/master/uevent"):
- with open("/sys/class/net/" + nic_name + "/master/uevent", 'r') as f:
- for line in f:
- sline = line.strip()
- if 'INTERFACE=bond' in sline:
- bond = sline.split('=')[1]
- if len(bond) == 0:
- with open("/sys/class/net/" + nic_name + "/address", 'r') as f:
- macaddr = f.read().strip()
- else:
- with open("/proc/net/bonding/" + bond, 'r') as f:
- line = f.readline()
- if_struct = False
- while line:
- sline = line.strip()
- if 'Slave Interface: ' + nic_name in sline and not if_struct:
- if_struct = True
- if 'Permanent HW addr: ' in sline and if_struct:
- macaddr = sline.split()[3]
- break
- line = f.readline()
-
- with open("/sys/class/net/" + nic_name + "/mtu", 'r') as f:
- mtu = f.read()
-
- ip = str(get_ip(nic_name))
-
- nics.append([nic_name, ip, macaddr, carrier, mtu])
-
- return sorted(nics)
-
- def get_ten_pci():
-
- ''' List ten nics pci addresses '''
-
- nics = []
- nics_list = listdir('/sys/class/net/')
- for nic_name in nics_list:
- if research('ten[0-9]+', nic_name):
- with open("/sys/class/net/" + nic_name + "/device/uevent", 'r') as f:
- for line in f:
- sline = line.strip()
- if "PCI_SLOT_NAME=" in sline:
- nics.append([nic_name , sline.split("=")[1]])
-
- return sorted(nics)
-
- def mesh_ping(mesh):
-
- ''' One to many ICMP check
-
- :param hosts: Target hosts. Type: list of ip addresses
-
- '''
-
- io = []
- minion_id = __salt__['config.get']('id')
-
- for host, hostobj in mesh:
- if host == minion_id:
- for mesh_net, addr, targets in hostobj:
- if addr in targets:
- targets.remove(addr)
- for tgt in targets:
- # This one will run in parallel with everyone else
- worker = Popen("ping -c 1 -w 1 -W 1 " + str(tgt), \
- shell=True, stdout=PIPE, stderr=PIPE)
- ping_out = worker.communicate()[0]
- if worker.returncode != 0:
- io.append(mesh_net + ': ' + addr + ' -> ' + tgt + ': Failed')
-
- return io
-
- def minion_list():
-
- ''' List registered minions '''
-
- return listdir('/etc/salt/pki/master/minions/')
-
- def verify_addresses():
-
- ''' Verify addresses taken from pillars '''
-
- nodes = nodes_addresses()
- verifier = {}
- failed = []
-
- for node, nodeobj in nodes:
- for item in nodeobj:
- addr = item[1]
- if addr in verifier:
- failed.append([node,verifier[addr],addr])
- else:
- verifier[addr] = node
-
- if failed:
- logger.error("FAILED. Duplicates found")
- logger.error(failed)
- return False
- else:
- logger.setLevel(logging.INFO)
- logger.info(["PASSED"])
- return True
-
- def nodes_addresses():
-
- ''' List servers addresses '''
-
- compound = 'linux:network:interface'
- out = __salt__['saltutil.cmd']( tgt='I@' + compound,
- tgt_type='compound',
- fun='pillar.get',
- arg=[compound],
- timeout=10
- ) or None
-
- servers = []
- for minion in minion_list():
- addresses = []
- if minion in out:
- ifaces = out[minion]['ret']
- for iface in ifaces:
- ifobj = ifaces[iface]
- if ifobj['enabled'] and 'address' in ifobj:
- if 'mesh' in ifobj:
- mesh = ifobj['mesh']
- else:
- mesh = 'default'
- addresses.append([mesh, ifobj['address']])
- servers.append([minion,addresses])
-
- return servers
-
- def get_mesh():
-
- ''' Build addresses mesh '''
-
- full_mesh = {}
- nodes = nodes_addresses()
-
- for node, nodeobj in nodes:
- for item in nodeobj:
- mesh = item[0]
- addr = item[1]
- if not mesh in full_mesh:
- full_mesh[mesh] = []
- full_mesh[mesh].append(addr)
-
- for node, nodeobj in nodes:
- for item in nodeobj:
- mesh = item[0]
- tgts = full_mesh[mesh]
- item.append(tgts)
-
- return nodes
-
- def ping_check():
-
- ''' Ping addresses in a mesh '''
-
- mesh = get_mesh()
- out = __salt__['saltutil.cmd']( tgt='*',
- tgt_type='glob',
- fun='net_checks.mesh_ping',
- arg=[mesh],
- timeout=10
- ) or None
-
- failed = []
-
- if out:
- for minion in out:
- ret = out[minion]['ret']
- if ret:
- failed.append(ret)
- else:
- failed = ["No response from minions"]
-
- if failed:
- logger.error("FAILED")
- logger.error('\n'.join(str(x) for x in failed))
- return False
- else:
- logger.setLevel(logging.INFO)
- logger.info(["PASSED"])
- return True
-
- def get_nics_csv(delim=","):
-
- ''' List nics in csv format
-
- :param delim: Delimiter char. Type: str
-
- '''
-
- header = "server,nic_name,ip_addr,mac_addr,link,chassis_id,chassis_name,port_mac,port_descr\n"
- io = ""
-
- # Try to reuse lldp output if possible
- try:
- lldp_info = Popen("lldpcli -f keyvalue s n s", shell=True, stdout=PIPE).communicate()[0]
- except:
- lldp_info = ""
-
- for nic in get_nics():
- lldp = ""
- nic_name = nic[0]
- if research('(one|ten|fourty)[0-9]+', nic_name):
- # Check if we can fetch lldp data for that nic
- for line in lldp_info.splitlines():
- chassis = 'lldp.' + nic[0] + '.chassis'
- port = 'lldp.' + nic[0] + '.port'
- if chassis in line or port in line:
- lldp += delim + line.split('=')[1]
- if not lldp:
- lldp = delim + delim + delim + delim
-
- io += __salt__['config.get']('id') + \
- delim + nic_name + \
- delim + str(nic[1]).strip() + \
- delim + str(nic[2]).strip() + \
- delim + str(nic[3]).strip() + \
- delim + str(nic[4]).strip() + \
- lldp + "\n"
-
- return header + io
|