Setup tests

This commit is contained in:
ramnes 2020-02-02 20:08:56 +01:00 committed by Guillaume Gelin
parent bdc2cbeb8f
commit bab2d26ad0
46 changed files with 11717 additions and 117 deletions

View file

@ -1,18 +1,18 @@
from netbox_agent.logging import logging # NOQA
from netbox_agent.vendors.dell import DellHost
import netbox_agent.dmidecode as dmidecode
from netbox_agent.config import config
from netbox_agent.logging import logging # NOQA
from netbox_agent.vendors.dell import DellHost
from netbox_agent.vendors.hp import HPHost
from netbox_agent.vendors.qct import QCTHost
from netbox_agent.vendors.supermicro import SupermicroHost
MANUFACTURERS = {
'Dell Inc.': DellHost,
'HP': HPHost,
'HPE': HPHost,
'Supermicro': SupermicroHost,
'Quanta Cloud Technology Inc.': QCTHost,
}
'Dell Inc.': DellHost,
'HP': HPHost,
'HPE': HPHost,
'Supermicro': SupermicroHost,
'Quanta Cloud Technology Inc.': QCTHost,
}
def run(config):

View file

@ -1,8 +1,9 @@
import logging
import pynetbox
import jsonargparse
import sys
import jsonargparse
import pynetbox
def get_config():
p = jsonargparse.ArgumentParser(
@ -13,6 +14,8 @@ def get_config():
],
prog='netbox_agent',
description="Netbox agent to run on your infrastructure's servers",
env_prefix='NETBOX_AGENT_',
default_env=True
)
p.add_argument('-c', '--config', action=jsonargparse.ActionConfigFile)

View file

@ -1,9 +1,9 @@
import logging
import re as _re
import subprocess as _subprocess
import sys
from netbox_agent.misc import is_tool
import logging
_handle_re = _re.compile('^Handle\\s+(.+),\\s+DMI\\s+type\\s+(\\d+),\\s+(\\d+)\\s+bytes$')
_in_block_re = _re.compile('^\\t\\t(.+)$')
@ -11,7 +11,7 @@ _record_re = _re.compile('\\t(.+):\\s+(.+)$')
_record2_re = _re.compile('\\t(.+):$')
_type2str = {
0: 'BIOS',
0: 'BIOS',
1: 'System',
2: 'Baseboard',
3: 'Chassis',
@ -60,19 +60,22 @@ for type_id, type_str in _type2str.items():
_str2type[type_str] = type_id
def parse():
def parse(output=None):
"""
parse the full output of the dmidecode
command and return a dic containing the parsed information
"""
buffer = _execute_cmd()
if output:
buffer = output
else:
buffer = _execute_cmd()
if isinstance(buffer, bytes):
buffer = buffer.decode('utf-8')
_data = _parse(buffer)
return _data
def get_by_type(type_id):
def get_by_type(data, type_id):
"""
filter the output of dmidecode per type
0 BIOS
@ -124,7 +127,6 @@ def get_by_type(type_id):
if type_id is None:
return None
data = parse()
result = []
for entry in data.values():
if entry['DMIType'] == type_id:

View file

@ -1,6 +1,6 @@
import re
from shutil import which
import subprocess
from shutil import which
# Originally from https://github.com/opencoff/useful-scripts/blob/master/linktest.py
@ -9,7 +9,7 @@ field_map = {
'Supported ports': 'ports',
'Supported link modes': 'sup_link_modes',
'Supports auto-negotiation': 'sup_autoneg',
'Advertised link modes': 'adv_link_modes',
'Advertised link modes': 'adv_link_modes',
'Advertised auto-negotiation': 'adv_autoneg',
'Speed': 'speed',
'Duplex': 'duplex',
@ -31,6 +31,7 @@ class Ethtool():
There is several bindings to have something proper, but it requires
compilation and other requirements.
"""
def __init__(self, interface, *args, **kwargs):
self.interface = interface
@ -54,7 +55,7 @@ class Ethtool():
if field not in field_map:
continue
field = field_map[field]
output = line[r+1:].strip()
output = line[r + 1:].strip()
fields[field] = output
else:
if len(field) > 0 and \

View file

@ -1,13 +1,15 @@
import logging
import pynetbox
import re
from netbox_agent.config import netbox_instance as nb, config
from netbox_agent.misc import is_tool, get_vendor
import pynetbox
from netbox_agent.config import config
from netbox_agent.config import netbox_instance as nb
from netbox_agent.lshw import LSHW
from netbox_agent.misc import get_vendor, is_tool
from netbox_agent.raid.hp import HPRaid
from netbox_agent.raid.omreport import OmreportRaid
from netbox_agent.raid.storcli import StorcliRaid
from netbox_agent.lshw import LSHW
INVENTORY_TAG = {
'cpu': {'name': 'hw:cpu', 'slug': 'hw-cpu'},
@ -16,7 +18,7 @@ INVENTORY_TAG = {
'memory': {'name': 'hw:memory', 'slug': 'hw-memory'},
'motherboard': {'name': 'hw:motherboard', 'slug': 'hw-motherboard'},
'raid_card': {'name': 'hw:raid_card', 'slug': 'hw-raid-card'},
}
}
class Inventory():
@ -132,8 +134,8 @@ class Inventory():
motherboards = self.get_hw_motherboards()
nb_motherboards = self.get_netbox_inventory(
device_id=self.device_id,
tag=INVENTORY_TAG['motherboard']['slug'])
device_id=self.device_id,
tag=INVENTORY_TAG['motherboard']['slug'])
for nb_motherboard in nb_motherboards:
if nb_motherboard.serial not in [x['serial'] for x in motherboards]:
@ -169,8 +171,8 @@ class Inventory():
def do_netbox_interfaces(self):
nb_interfaces = self.get_netbox_inventory(
device_id=self.device_id,
tag=INVENTORY_TAG['interface']['slug'])
device_id=self.device_id,
tag=INVENTORY_TAG['interface']['slug'])
interfaces = self.lshw.interfaces
# delete interfaces that are in netbox but not locally
@ -269,9 +271,9 @@ class Inventory():
"""
nb_raid_cards = self.get_netbox_inventory(
device_id=self.device_id,
tag=[INVENTORY_TAG['raid_card']['slug']]
)
device_id=self.device_id,
tag=[INVENTORY_TAG['raid_card']['slug']]
)
raid_cards = self.get_raid_cards()
# delete cards that are in netbox but not locally
@ -296,7 +298,7 @@ class Inventory():
non_raid_disks = [
'MR9361-8i',
]
]
if size is None and logicalname is None or \
'virtual' in product.lower() or 'logical' in product.lower() or \
@ -321,7 +323,7 @@ class Inventory():
d = {}
d["name"] = ""
d['Size'] = '{} GB'.format(int(size/1024/1024/1024))
d['Size'] = '{} GB'.format(int(size / 1024 / 1024 / 1024))
d['logicalname'] = logicalname
d['description'] = description
d['SN'] = serial
@ -378,8 +380,8 @@ class Inventory():
def do_netbox_disks(self):
nb_disks = self.get_netbox_inventory(
device_id=self.device_id,
tag=INVENTORY_TAG['disk']['slug'])
device_id=self.device_id,
tag=INVENTORY_TAG['disk']['slug'])
disks = self.get_hw_disks()
# delete disks that are in netbox but not locally
@ -421,9 +423,9 @@ class Inventory():
def do_netbox_memories(self):
memories = self.lshw.memories
nb_memories = self.get_netbox_inventory(
device_id=self.device_id,
tag=INVENTORY_TAG['memory']['slug']
)
device_id=self.device_id,
tag=INVENTORY_TAG['memory']['slug']
)
for nb_memory in nb_memories:
if nb_memory.serial not in [x['serial'] for x in memories]:

View file

@ -33,6 +33,7 @@ class IPMI():
: O=OEM
Bad Password Threshold : Not Available
"""
def __init__(self):
self.ret, self.output = subprocess.getstatusoutput('ipmitool lan print')
if self.ret != 0:

View file

@ -2,8 +2,11 @@ import subprocess
class LLDP():
def __init__(self):
self.output = subprocess.getoutput('lldpctl -f keyvalue')
def __init__(self, output=None):
if output:
self.output = output
else:
self.output = subprocess.getoutput('lldpctl -f keyvalue')
self.data = self.parse()
def parse(self):
@ -49,6 +52,8 @@ class LLDP():
# lldp.eth0.port.descr=GigabitEthernet1/0/1
if self.data['lldp'].get(interface) is None:
return None
if self.data['lldp'][interface]['port'].get('ifname'):
return self.data['lldp'][interface]['port']['ifname']
return self.data['lldp'][interface]['port']['descr']
def get_switch_vlan(self, interface):

View file

@ -17,6 +17,7 @@ class LocationBase():
There's also a support for an external driver file outside of this project in case
the logic isn't supported here.
"""
def __init__(self, driver, driver_value, driver_file, regex, *args, **kwargs):
self.driver = driver
self.driver_value = driver_value

View file

@ -2,7 +2,6 @@ import logging
from netbox_agent.config import config
logger = logging.getLogger()
if config.log_level == 'debug':

View file

@ -1,6 +1,6 @@
import subprocess
import json
import logging
import subprocess
import sys
from netbox_agent.misc import is_tool

View file

@ -24,7 +24,7 @@ def get_vendor(name):
'MD': 'Toshiba',
'MG': 'Toshiba',
'WD': 'WDC'
}
}
for key, value in vendors.items():
if name.upper().startswith(key):
return value

View file

@ -1,12 +1,13 @@
from itertools import chain
import logging
import os
import re
from itertools import chain
from netaddr import IPAddress, IPNetwork
import netifaces
from netaddr import IPAddress, IPNetwork
from netbox_agent.config import netbox_instance as nb, config
from netbox_agent.config import config
from netbox_agent.config import netbox_instance as nb
from netbox_agent.ethtool import Ethtool
from netbox_agent.ipmi import IPMI
from netbox_agent.lldp import LLDP
@ -95,7 +96,7 @@ class Network():
x['addr'],
IPAddress(x['netmask']).netmask_bits()
) for x in ip_addr
] if ip_addr else None, # FIXME: handle IPv6 addresses
] if ip_addr else None, # FIXME: handle IPv6 addresses
'ethtool': Ethtool(interface).parse(),
'vlan': vlan,
'bonding': bonding,
@ -242,7 +243,7 @@ class Network():
interface = nb.dcim.interfaces.get(
device_id=self.device.id,
mgmt_only=True,
)
)
nic = {
'name': 'IPMI',
'mac': mac,

View file

@ -34,13 +34,13 @@ class PowerSupply():
'allocated_draw': None,
'maximum_draw': max_power,
'device': self.device_id,
})
})
return power_supply
def get_netbox_power_supply(self):
return nb.dcim.power_ports.filter(
device_id=self.device_id
)
)
def create_or_update_power_supply(self):
nb_psus = self.get_netbox_power_supply()
@ -78,10 +78,10 @@ class PowerSupply():
if psu['name'] not in [x.name for x in nb_psus]:
logging.info('Creating PSU {name} ({description}), {maximum_draw}W'.format(
**psu
))
))
nb_psu = nb.dcim.power_ports.create(
**psu
)
)
return True

View file

@ -1,8 +1,8 @@
import re
import subprocess
from netbox_agent.raid.base import Raid, RaidController
from netbox_agent.misc import get_vendor
from netbox_agent.raid.base import Raid, RaidController
REGEXP_CONTROLLER_HP = re.compile(r'Smart Array ([a-zA-Z0-9- ]+) in Slot ([0-9]+)')

View file

@ -1,6 +1,6 @@
import re
import subprocess
import xml.etree.ElementTree as ET # NOQA
import xml.etree.ElementTree as ET # NOQA
from netbox_agent.misc import get_vendor
from netbox_agent.raid.base import Raid, RaidController
@ -43,7 +43,7 @@ class OmreportController(RaidController):
ret = []
output = subprocess.getoutput(
'omreport storage controller controller={} -fmt xml'.format(self.controller_index)
)
)
root = ET.fromstring(output)
et_array_disks = root.find('ArrayDisks')
if et_array_disks is not None:
@ -54,7 +54,7 @@ class OmreportController(RaidController):
'SN': get_field(obj, 'DeviceSerialNumber'),
'Size': '{:.0f}GB'.format(
int(get_field(obj, 'Length')) / 1024 / 1024 / 1024
),
),
'Type': 'HDD' if int(get_field(obj, 'MediaType')) == 1 else 'SSD',
'_src': self.__class__.__name__,
})

View file

@ -1,5 +1,5 @@
import subprocess
import json
import subprocess
from netbox_agent.misc import get_vendor
from netbox_agent.raid.base import Raid, RaidController
@ -47,7 +47,7 @@ class StorcliController(RaidController):
'Size': size,
'Type': media_type,
'_src': self.__class__.__name__,
})
})
return ret

View file

@ -1,12 +1,13 @@
import logging
from pprint import pprint
import socket
import subprocess
from pprint import pprint
from netbox_agent.config import netbox_instance as nb, config
import netbox_agent.dmidecode as dmidecode
from netbox_agent.location import Datacenter, Rack
from netbox_agent.config import config
from netbox_agent.config import netbox_instance as nb
from netbox_agent.inventory import Inventory
from netbox_agent.location import Datacenter, Rack
from netbox_agent.network import Network
from netbox_agent.power import PowerSupply
@ -36,10 +37,10 @@ class ServerBase():
else:
self.dmi = dmidecode.parse()
self.baseboard = self.dmi.get_by_type('Baseboard')
self.bios = self.dmi.get_by_type('BIOS')
self.chassis = self.dmi.get_by_type('Chassis')
self.system = self.dmi.get_by_type('System')
self.baseboard = dmidecode.get_by_type(self.dmi, 'Baseboard')
self.bios = dmidecode.get_by_type(self.dmi, 'BIOS')
self.chassis = dmidecode.get_by_type(self.dmi, 'Chassis')
self.system = dmidecode.get_by_type(self.dmi, 'System')
self.network = None
@ -229,7 +230,7 @@ class ServerBase():
# if it doesn't exist, create it
chassis = nb.dcim.devices.get(
serial=self.get_chassis_service_tag()
)
)
if not chassis:
chassis = self._netbox_create_blade_chassis(datacenter, rack)

View file

@ -1,8 +1,8 @@
import logging
import subprocess
from netbox_agent.server import ServerBase
from netbox_agent.misc import is_tool
from netbox_agent.server import ServerBase
class DellHost(ServerBase):

View file

@ -27,14 +27,14 @@ class HPHost(ServerBase):
'Enclosure Name': locator[0].strip(),
'Server Bay': locator[3].strip(),
'Enclosure Serial': locator[4].strip(),
}
}
return locator[0]
def get_blade_slot(self):
if self.is_blade():
return 'Bay {}'.format(
int(self.hp_rack_locator['Server Bay'].strip())
)
)
return None
def get_chassis(self):

View file

@ -2,6 +2,7 @@
from netbox_agent.location import Slot
from netbox_agent.server import ServerBase
"""
Supermicro DMI can be messed up. They depend on the vendor
to set the correct values. The endusers cannot