浏览代码

Adding network resource grab script.

Useful during environment setup.

Change-Id: Ic8d4d82cc6f6afb0ac2a6e4285c3b681bb895b6d
pull/170/head
Dzmitry Stremkouski 6 年前
父节点
当前提交
d1a268baea
共有 2 个文件被更改,包括 513 次插入0 次删除
  1. +234
    -0
      README.rst
  2. +279
    -0
      _modules/net_checks.py

+ 234
- 0
README.rst 查看文件

@@ -2235,6 +2235,240 @@ and on-boot after an interface initialization.
interface: bond0
mac: "ff:ff:ff:ff:ff:ff" (optional)

Check network params on the environment
---------------------------------------

Grab nics and nics states

.. code-block:: bash

salt osd001\* net_checks.get_nics

**Example of system output:**

.. code-block:: bash

osd001.domain.com:
|_
- bond0
- None
- 1e:c8:64:42:23:b9
- 0
- 1500
|_
- bond1
- None
- 3c:fd:fe:27:3b:00
- 1
- 9100
|_
- fourty1
- None
- 3c:fd:fe:27:3b:00
- 1
- 9100
|_
- fourty2
- None
- 3c:fd:fe:27:3b:02
- 1
- 9100

Grab 10G nics PCI addresses for hugepages setup

.. code-block:: bash

salt cmp001\* net_checks.get_ten_pci

**Example of system output:**

.. code-block:: bash

cmp001.domain.com:
|_
- ten1
- 0000:19:00.0
|_
- ten2
- 0000:19:00.1
|_
- ten3
- 0000:19:00.2
|_
- ten4
- 0000:19:00.3

Grab ip address for an interface

.. code-block:: bash

salt cmp001\* net_checks.get_ip iface=one4

**Example of system output:**

.. code-block:: bash

cmp001.domain.com:
10.200.177.101

Grab ip addresses map

.. code-block:: bash

salt-call net_checks.nodes_addresses

**Example of system output:**

.. code-block:: bash

local:
|_
- cid01.domain.com
|_
|_
- pxe
- 10.200.177.91
|_
- control
- 10.200.178.91
|_
- cmn02.domain.com
|_
|_
- storage_access
- 10.200.181.67
|_
- pxe
- 10.200.177.67
|_
- control
- 10.200.178.67
|_
- cmp010.domain.com
|_
|_
- pxe
- 10.200.177.110
|_
- storage_access
- 10.200.181.110
|_
- control
- 10.200.178.110
|_
- vxlan
- 10.200.179.110

Verify full mesh connectivity

.. code-block:: bash

salt-call net_checks.ping_check

**Example of positive system output:**

.. code-block:: bash

['PASSED']
[INFO ] ['PASSED']
local:
True

**Example of system output in case of failure:**

.. code-block:: bash

FAILED
[ERROR ] FAILED
['control: 10.0.1.92 -> 10.0.1.224: Failed']
['control: 10.0.1.93 -> 10.0.1.224: Failed']
['control: 10.0.1.51 -> 10.0.1.224: Failed']
['control: 10.0.1.102 -> 10.0.1.224: Failed']
['control: 10.0.1.13 -> 10.0.1.224: Failed']
['control: 10.0.1.81 -> 10.0.1.224: Failed']
local:
False

For this feature to work, please mark addresses with some role.
Otherwise 'default' role is assumed and mesh would consist of all
addresses on the environment.

Mesh mark is needed only for interfaces which are enabled and have
ip address assigned.

Checking dhcp pxe network meaningless, as it is used for salt
master vs minion communications, therefore treated as checked.

.. code-block:: yaml

parameters:
linux:
network:
interface:
ens3:
enabled: true
type: eth
proto: static
address: ${_param:deploy_address}
netmask: ${_param:deploy_network_netmask}
gateway: ${_param:deploy_network_gateway}
mesh: pxe

Check pillars for ip address duplicates

.. code-block:: bash

salt-call net_checks.verify_addresses

**Example of positive system output:**

.. code-block:: bash

['PASSED']
[INFO ] ['PASSED']
local:
True

**Example of system output in case of failure:**

.. code-block:: bash

FAILED. Duplicates found
[ERROR ] FAILED. Duplicates found
['gtw01.domain.com', 'gtw02.domain.com', '10.0.1.224']
[ERROR ] ['gtw01.domain.com', 'gtw02.domain.com', '10.0.1.224']
local:
False

Generate csv report for the env

.. code-block:: bash

salt -C 'kvm* or cmp* or osd*' net_checks.get_nics_csv \
| grep '^\ ' | sed 's/\ *//g' | grep -Ev ^server \
| sed '1 i\server,nic_name,ip_addr,mac_addr,link,mtu,chassis_id,chassis_name,port_mac,port_descr'

**Example of system output:**

.. code-block:: bash

server,nic_name,ip_addr,mac_addr,link,mtu,chassis_id,chassis_name,port_mac,port_descr
cmp010.domain.com,bond0,None,b4:96:91:10:5b:3a,1,1500,,,,
cmp010.domain.com,bond0.21,10.200.178.110,b4:96:91:10:5b:3a,1,1500,,,,
cmp010.domain.com,bond0.22,10.200.179.110,b4:96:91:10:5b:3a,1,1500,,,,
cmp010.domain.com,bond1,None,3c:fd:fe:34:ad:22,0,1500,,,,
cmp010.domain.com,bond1.24,10.200.181.110,3c:fd:fe:34:ad:22,0,1500,,,,
cmp010.domain.com,fourty5,None,3c:fd:fe:34:ad:20,0,9000,,,,
cmp010.domain.com,fourty6,None,3c:fd:fe:34:ad:22,0,9000,,,,
cmp010.domain.com,one1,None,b4:96:91:10:5b:38,0,1500,,,,
cmp010.domain.com,one2,None,b4:96:91:10:5b:39,1,1500,f0:4b:3a:8f:75:40,exnfvaa18-20,548,ge-0/0/22
cmp010.domain.com,one3,None,b4:96:91:10:5b:3a,1,1500,f0:4b:3a:8f:75:40,exnfvaa18-20,547,ge-0/0/21
cmp010.domain.com,one4,10.200.177.110,b4:96:91:10:5b:3b,1,1500,f0:4b:3a:8f:75:40,exnfvaa18-20,546,ge-0/0/20
cmp011.domain.com,bond0,None,b4:96:91:13:6c:aa,1,1500,,,,
cmp011.domain.com,bond0.21,10.200.178.111,b4:96:91:13:6c:aa,1,1500,,,,
cmp011.domain.com,bond0.22,10.200.179.111,b4:96:91:13:6c:aa,1,1500,,,,
...

Usage
=====


+ 279
- 0
_modules/net_checks.py 查看文件

@@ -0,0 +1,279 @@
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

正在加载...
取消
保存