make sure lshw disks are backward compatible with raid disks, add get_vendor method and multiple fixes
This commit is contained in:
parent
cba23b31d9
commit
8432abef79
4 changed files with 84 additions and 57 deletions
|
|
@ -1,7 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
|
import pynetbox
|
||||||
|
|
||||||
from netbox_agent.config import netbox_instance as nb, config
|
from netbox_agent.config import netbox_instance as nb, config
|
||||||
from netbox_agent.misc import is_tool
|
from netbox_agent.misc import is_tool, get_vendor
|
||||||
from netbox_agent.raid.hp import HPRaid
|
from netbox_agent.raid.hp import HPRaid
|
||||||
from netbox_agent.raid.storcli import StorcliRaid
|
from netbox_agent.raid.storcli import StorcliRaid
|
||||||
from netbox_agent.lshw import LSHW
|
from netbox_agent.lshw import LSHW
|
||||||
|
|
@ -50,7 +51,7 @@ class Inventory():
|
||||||
|
|
||||||
self.lshw = LSHW()
|
self.lshw = LSHW()
|
||||||
|
|
||||||
def create_netbox_tags():
|
def create_netbox_tags(self):
|
||||||
for key, tag in INVENTORY_TAG.items():
|
for key, tag in INVENTORY_TAG.items():
|
||||||
nb_tag = nb.extras.tags.get(
|
nb_tag = nb.extras.tags.get(
|
||||||
name=tag['name']
|
name=tag['name']
|
||||||
|
|
@ -69,15 +70,11 @@ class Inventory():
|
||||||
manufacturer = nb.dcim.manufacturers.get(
|
manufacturer = nb.dcim.manufacturers.get(
|
||||||
name=name,
|
name=name,
|
||||||
)
|
)
|
||||||
|
|
||||||
"""
|
|
||||||
No spaces in the slug allowed.
|
|
||||||
"""
|
|
||||||
if not manufacturer:
|
if not manufacturer:
|
||||||
logging.info('Creating missing manufacturer {name}'.format(name=name))
|
logging.info('Creating missing manufacturer {name}'.format(name=name))
|
||||||
manufacturer = nb.dcim.manufacturers.create(
|
manufacturer = nb.dcim.manufacturers.create(
|
||||||
name=name,
|
name=name,
|
||||||
slug=name.replace(' ', '-').lower(),
|
slug=name.replace(' ', '-').replace('.', '').lower(),
|
||||||
)
|
)
|
||||||
|
|
||||||
logging.info('Creating missing manufacturer {name}'.format(name=name))
|
logging.info('Creating missing manufacturer {name}'.format(name=name))
|
||||||
|
|
@ -90,7 +87,7 @@ class Inventory():
|
||||||
device_id=device_id,
|
device_id=device_id,
|
||||||
tag=tag
|
tag=tag
|
||||||
)
|
)
|
||||||
except pynetbox.lib.query.RequestError as e:
|
except pynetbox.core.query.RequestError:
|
||||||
logging.info('Tag {tag} is missing, returning empty array.'.format(tag=tag))
|
logging.info('Tag {tag} is missing, returning empty array.'.format(tag=tag))
|
||||||
items = []
|
items = []
|
||||||
|
|
||||||
|
|
@ -149,9 +146,9 @@ class Inventory():
|
||||||
if motherboard.get('serial') not in [x.serial for x in nb_motherboards]:
|
if motherboard.get('serial') not in [x.serial for x in nb_motherboards]:
|
||||||
self.create_netbox_inventory_item(
|
self.create_netbox_inventory_item(
|
||||||
device_id=self.device_id,
|
device_id=self.device_id,
|
||||||
tags=[INVENTORY_TAG['motherboard']['slug']],
|
tags=[INVENTORY_TAG['motherboard']['name']],
|
||||||
vendor='{}'.format(motherboard.get('vendor', 'N/A')),
|
vendor='{}'.format(motherboard.get('vendor', 'N/A')),
|
||||||
serial='{}'.format(motherboard.get('serial', '000000')),
|
serial='{}'.format(motherboard.get('serial', 'No SN')),
|
||||||
name='{}'.format(motherboard.get('name')),
|
name='{}'.format(motherboard.get('name')),
|
||||||
description='{}'.format(motherboard.get('description'))
|
description='{}'.format(motherboard.get('description'))
|
||||||
)
|
)
|
||||||
|
|
@ -257,7 +254,7 @@ class Inventory():
|
||||||
def create_netbox_raid_cards(self):
|
def create_netbox_raid_cards(self):
|
||||||
for raid_card in self.get_netbox_inventory(
|
for raid_card in self.get_netbox_inventory(
|
||||||
device_id=self.device_id,
|
device_id=self.device_id,
|
||||||
tag=[INVENTORY_TAG['raid_card']['name']]
|
tag=[INVENTORY_TAG['raid_card']['slug']]
|
||||||
):
|
):
|
||||||
self.create_netbox_raid_card(raid_card)
|
self.create_netbox_raid_card(raid_card)
|
||||||
|
|
||||||
|
|
@ -272,9 +269,9 @@ class Inventory():
|
||||||
We only need to handle destroy and new cards
|
We only need to handle destroy and new cards
|
||||||
"""
|
"""
|
||||||
|
|
||||||
nb_raid_cards = self.self.get_netbox_inventory(
|
nb_raid_cards = self.get_netbox_inventory(
|
||||||
device_id=self.device_id,
|
device_id=self.device_id,
|
||||||
tag=[INVENTORY_TAG['raid_card']['name']]
|
tag=[INVENTORY_TAG['raid_card']['slug']]
|
||||||
)
|
)
|
||||||
raid_cards = self.get_raid_cards()
|
raid_cards = self.get_raid_cards()
|
||||||
|
|
||||||
|
|
@ -292,36 +289,33 @@ class Inventory():
|
||||||
if raid_card.get_serial_number() not in [x.serial for x in nb_raid_cards]:
|
if raid_card.get_serial_number() not in [x.serial for x in nb_raid_cards]:
|
||||||
self.create_netbox_raid_card(raid_card)
|
self.create_netbox_raid_card(raid_card)
|
||||||
|
|
||||||
|
def is_virtual_disk(self, product):
|
||||||
|
non_raid_disks = [
|
||||||
|
'MR9361-8i',
|
||||||
|
]
|
||||||
|
if 'virtual' in product or 'logical' in product or product in non_raid_disks:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def get_hw_disks(self):
|
def get_hw_disks(self):
|
||||||
disks = []
|
disks = []
|
||||||
|
|
||||||
for disk in self.lshw.get_hw_linux("storage"):
|
for disk in self.lshw.get_hw_linux("storage"):
|
||||||
|
product = disk.get('product')
|
||||||
|
if self.is_virtual_disk(product):
|
||||||
|
continue
|
||||||
|
|
||||||
d = {}
|
d = {}
|
||||||
d["name"] = ""
|
d["name"] = ""
|
||||||
d['size'] = '{} GB'.format(int(disk['size']/1024/1024/1024))
|
d['Size'] = '{} GB'.format(int(disk['size']/1024/1024/1024))
|
||||||
d['model'] = disk['product']
|
|
||||||
d['logicalname'] = disk['logicalname']
|
d['logicalname'] = disk['logicalname']
|
||||||
d['description'] = disk['description']
|
d['description'] = disk['description']
|
||||||
d['serial'] = disk['serial']
|
d['SN'] = disk.get('serial')
|
||||||
|
d['Model'] = disk.get('product')
|
||||||
if 'vendor' in disk:
|
if disk.get('vendor'):
|
||||||
d['vendor'] = disk['vendor']
|
d['Vendor'] = disk['vendor']
|
||||||
|
else:
|
||||||
if disk['product'].startswith('ST'):
|
d['Vendor'] = get_vendor(disk['product'])
|
||||||
d['vendor'] = 'Seagate'
|
|
||||||
|
|
||||||
if disk['product'].startswith('Crucial'):
|
|
||||||
d['vendor'] = 'Crucial'
|
|
||||||
|
|
||||||
if disk['product'].startswith('Micron'):
|
|
||||||
d['vendor'] = 'Micron'
|
|
||||||
|
|
||||||
if disk['product'].startswith('INTEL'):
|
|
||||||
d['vendor'] = 'Intel'
|
|
||||||
|
|
||||||
if disk['product'].startswith('Samsung'):
|
|
||||||
d['vendor'] = 'Samsung'
|
|
||||||
|
|
||||||
disks.append(d)
|
disks.append(d)
|
||||||
|
|
||||||
for raid_card in self.get_raid_cards():
|
for raid_card in self.get_raid_cards():
|
||||||
|
|
@ -330,27 +324,35 @@ class Inventory():
|
||||||
return disks
|
return disks
|
||||||
|
|
||||||
def create_netbox_disk(self, disk):
|
def create_netbox_disk(self, disk):
|
||||||
if "vendor" in disk:
|
manufacturer = None
|
||||||
manufacturer = self.find_or_create_manufacturer(disk["vendor"])
|
if "Vendor" in disk:
|
||||||
|
manufacturer = self.find_or_create_manufacturer(disk["Vendor"])
|
||||||
|
|
||||||
|
# nonraid disk
|
||||||
|
if disk.get('logicalname') and disk.get('description'):
|
||||||
|
name = '{} - {} ({})'.format(
|
||||||
|
disk.get('description'),
|
||||||
|
disk.get('logicalname'),
|
||||||
|
disk.get('Size', 0))
|
||||||
|
description = 'Device {}'.format(disk.get('logicalname', 'Unknown'))
|
||||||
|
else:
|
||||||
|
name = '{} ({})'.format(disk['Model'], disk['Size'])
|
||||||
|
description = '{}'.format(disk['Type'])
|
||||||
|
|
||||||
_ = nb.dcim.inventory_items.create(
|
_ = nb.dcim.inventory_items.create(
|
||||||
device=self.device_id,
|
device=self.device_id,
|
||||||
discovered=True,
|
discovered=True,
|
||||||
tags=[INVENTORY_TAG['disk']['name']],
|
tags=[INVENTORY_TAG['disk']['name']],
|
||||||
name='{} - {} ({})'.format(
|
name=name,
|
||||||
disk.get('description', 'Unknown'),
|
serial=disk['SN'],
|
||||||
disk.get('logicalname', 'Unknown'),
|
part_id=disk['Model'],
|
||||||
disk.get('size', 0)
|
description=description,
|
||||||
),
|
manufacturer=manufacturer.id if manufacturer else None
|
||||||
serial=disk['serial'],
|
|
||||||
part_id=disk['model'],
|
|
||||||
description='Device {}'.format(disk.get('logicalname', 'Unknown')),
|
|
||||||
manufacturer=manufacturer.id
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logging.info('Creating Disk {model} {serial}'.format(
|
logging.info('Creating Disk {model} {serial}'.format(
|
||||||
model=disk['model'],
|
model=disk['Model'],
|
||||||
serial=disk['serial'],
|
serial=disk['SN'],
|
||||||
))
|
))
|
||||||
|
|
||||||
def do_netbox_disks(self):
|
def do_netbox_disks(self):
|
||||||
|
|
@ -362,7 +364,7 @@ class Inventory():
|
||||||
# delete disks that are in netbox but not locally
|
# delete disks that are in netbox but not locally
|
||||||
# use the serial_number has the comparison element
|
# use the serial_number has the comparison element
|
||||||
for nb_disk in nb_disks:
|
for nb_disk in nb_disks:
|
||||||
if nb_disk.serial not in [x['serial'] for x in disks]:
|
if nb_disk.serial not in [x['SN'] for x in disks if x.get('SN')]:
|
||||||
logging.info('Deleting unknown locally Disk {serial}'.format(
|
logging.info('Deleting unknown locally Disk {serial}'.format(
|
||||||
serial=nb_disk.serial,
|
serial=nb_disk.serial,
|
||||||
))
|
))
|
||||||
|
|
@ -370,7 +372,7 @@ class Inventory():
|
||||||
|
|
||||||
# create disks that are not in netbox
|
# create disks that are not in netbox
|
||||||
for disk in disks:
|
for disk in disks:
|
||||||
if disk.get('serial') not in [x.serial for x in nb_disks]:
|
if disk.get('SN') not in [x.serial for x in nb_disks]:
|
||||||
self.create_netbox_disk(disk)
|
self.create_netbox_disk(disk)
|
||||||
|
|
||||||
def create_netbox_memory(self, memory):
|
def create_netbox_memory(self, memory):
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,21 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from netbox_agent.misc import is_tool
|
||||||
|
|
||||||
|
|
||||||
class LSHW():
|
class LSHW():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
if not is_tool('lshw'):
|
||||||
|
logging.error('lshw does not seem to be installed')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
self.hw_info = json.loads(
|
data = subprocess.getoutput(
|
||||||
subprocess.check_output(["lshw", "-quiet", "-json"],
|
'lshw -quiet -json'
|
||||||
encoding='utf8')) # noqa: E128
|
)
|
||||||
|
self.hw_info = json.loads(data)
|
||||||
self.info = {}
|
self.info = {}
|
||||||
self.memories = []
|
self.memories = []
|
||||||
self.interfaces = []
|
self.interfaces = []
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,18 @@ from shutil import which
|
||||||
def is_tool(name):
|
def is_tool(name):
|
||||||
'''Check whether `name` is on PATH and marked as executable.'''
|
'''Check whether `name` is on PATH and marked as executable.'''
|
||||||
return which(name) is not None
|
return which(name) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def get_vendor(name):
|
||||||
|
vendors = {
|
||||||
|
'ST': 'Seagate',
|
||||||
|
'Crucial': 'Crucial',
|
||||||
|
'Micron': 'Micron',
|
||||||
|
'Intel': 'Intel',
|
||||||
|
'Samsung': 'Samsung',
|
||||||
|
'HGST': 'HGST',
|
||||||
|
}
|
||||||
|
for key, value in vendors.items():
|
||||||
|
if name.startswith(key):
|
||||||
|
return value
|
||||||
|
return name
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from netbox_agent.misc import get_vendor
|
||||||
from netbox_agent.raid.base import Raid, RaidController
|
from netbox_agent.raid.base import Raid, RaidController
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -38,8 +39,10 @@ class StorcliController(RaidController):
|
||||||
)
|
)
|
||||||
drive_attr = drive_infos['{} - Detailed Information'.format(drive_identifier)][
|
drive_attr = drive_infos['{} - Detailed Information'.format(drive_identifier)][
|
||||||
'{} Device attributes'.format(drive_identifier)]
|
'{} Device attributes'.format(drive_identifier)]
|
||||||
|
model = drive_attr.get('Model Number', '').strip()
|
||||||
ret.append({
|
ret.append({
|
||||||
'Model': drive_attr.get('Model Number', '').strip(),
|
'Model': model,
|
||||||
|
'Vendor': get_vendor(model),
|
||||||
'SN': drive_attr.get('SN', '').strip(),
|
'SN': drive_attr.get('SN', '').strip(),
|
||||||
'Size': size,
|
'Size': size,
|
||||||
'Type': media_type,
|
'Type': media_type,
|
||||||
|
|
|
||||||
Loading…
Add table
editor.link_modal.header
Reference in a new issue