* new dmidecode code
* move netbox creation server to ServerBase class * HP blades support
This commit is contained in:
parent
94e0437427
commit
8960df61dc
5 changed files with 321 additions and 158 deletions
|
@ -2,7 +2,6 @@ import socket
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
from netbox_agent.server import ServerBase
|
from netbox_agent.server import ServerBase
|
||||||
from netbox_agent.config import netbox_instance as nb
|
|
||||||
|
|
||||||
class DellHost(ServerBase):
|
class DellHost(ServerBase):
|
||||||
def is_blade(self):
|
def is_blade(self):
|
||||||
|
@ -15,72 +14,16 @@ class DellHost(ServerBase):
|
||||||
` Location In Chassis: Slot 03`
|
` Location In Chassis: Slot 03`
|
||||||
'''
|
'''
|
||||||
if self.is_blade():
|
if self.is_blade():
|
||||||
return int(self.dmi.get('base board')[0].get('Location In Chassis').split()[1])
|
return int(self.dmi.get_by_type('Baseboard')[0].get('Location In Chassis').split()[1])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_chassis(self):
|
def get_chassis(self):
|
||||||
if self.is_blade():
|
if self.is_blade():
|
||||||
return self.dmi.get('chassis')[0]['Version']
|
return self.dmi.get_by_type('Chassis')[0]['Version']
|
||||||
return self.get_product_name()
|
return self.get_product_name()
|
||||||
|
|
||||||
def get_chassis_service_tag(self):
|
def get_chassis_service_tag(self):
|
||||||
if self.is_blade():
|
if self.is_blade():
|
||||||
return self.dmi.get('chassis')[0]['Serial Number']
|
return self.dmi.get_by_type('chassis')[0]['Serial Number']
|
||||||
return self.get_service_tag
|
return self.get_service_tag()
|
||||||
|
|
||||||
def netbox_create(self):
|
|
||||||
if self.is_blade():
|
|
||||||
# let's find the bblade
|
|
||||||
blade = nb.dcim.devices.get(serial=self.get_service_tag())
|
|
||||||
chassis = nb.dcim.devices.get(serial=self.get_chassis_service_tag())
|
|
||||||
# if it doesn't exist, create it
|
|
||||||
if not blade:
|
|
||||||
# check if the chassis exist before
|
|
||||||
# if it doesn't exist, create it
|
|
||||||
if not chassis:
|
|
||||||
device_type = nb.dcim.device_types.get(
|
|
||||||
model=self.get_chassis(),
|
|
||||||
)
|
|
||||||
device_role = nb.dcim.device_roles.get(
|
|
||||||
name='Server Chassis',
|
|
||||||
)
|
|
||||||
datacenter = nb.dcim.sites.get(
|
|
||||||
name='DC3'
|
|
||||||
)
|
|
||||||
new_chassis = nb.dcim.devices.create(
|
|
||||||
name=''.format(),
|
|
||||||
device_type=device_type.id,
|
|
||||||
serial=self.get_chassis_service_tag(),
|
|
||||||
device_role=device_role.id,
|
|
||||||
site=datacenter.id,
|
|
||||||
)
|
|
||||||
chassis = new_chassis
|
|
||||||
|
|
||||||
device_role = nb.dcim.device_roles.get(
|
|
||||||
name='Blade',
|
|
||||||
)
|
|
||||||
device_type = nb.dcim.device_types.get(
|
|
||||||
model=self.get_product_name(),
|
|
||||||
)
|
|
||||||
|
|
||||||
new_blade = nb.dcim.devices.create(
|
|
||||||
name='{}'.format(socket.gethostname()),
|
|
||||||
serial=self.get_service_tag(),
|
|
||||||
device_role=device_role.id,
|
|
||||||
device_type=device_type.id,
|
|
||||||
parent_device=chassis.id,
|
|
||||||
site='1',
|
|
||||||
)
|
|
||||||
blade = new_blade
|
|
||||||
|
|
||||||
# Find the slot and update it with our blade
|
|
||||||
device_bays = nb.dcim.device_bays.filter(
|
|
||||||
device_id=chassis.id,
|
|
||||||
name='Blade {}'.format(self.get_blade_slot()),
|
|
||||||
)
|
|
||||||
if len(device_bays) > 0:
|
|
||||||
device_bay = device_bays[0]
|
|
||||||
device_bay.installed_device = blade
|
|
||||||
device_bay.save()
|
|
||||||
else:
|
|
||||||
# FIXME : handle pizza box
|
|
||||||
|
|
|
@ -1,96 +1,211 @@
|
||||||
import subprocess
|
import re as _re
|
||||||
|
import subprocess as _subprocess
|
||||||
|
|
||||||
class Dmidecode():
|
|
||||||
def __init__(self):
|
|
||||||
self.types = {
|
|
||||||
0: 'bios',
|
|
||||||
1: 'system',
|
|
||||||
2: 'base board',
|
|
||||||
3: 'chassis',
|
|
||||||
4: 'processor',
|
|
||||||
7: 'cache',
|
|
||||||
8: 'port connector',
|
|
||||||
9: 'system slot',
|
|
||||||
10: 'on board device',
|
|
||||||
11: 'OEM strings',
|
|
||||||
#13: 'bios language',
|
|
||||||
15: 'system event log',
|
|
||||||
16: 'physical memory array',
|
|
||||||
17: 'memory device',
|
|
||||||
19: 'memory array mapped address',
|
|
||||||
24: 'hardware security',
|
|
||||||
25: 'system power controls',
|
|
||||||
27: 'cooling device',
|
|
||||||
32: 'system boot',
|
|
||||||
41: 'onboard device',
|
|
||||||
}
|
|
||||||
self.content = self._get_output()
|
|
||||||
self.info = self.parse_dmi()
|
|
||||||
|
|
||||||
def parse_dmi(self):
|
_handle_re = _re.compile("^Handle\\s+(.+),\\s+DMI\\s+type\\s+(\\d+),\\s+(\\d+)\\s+bytes$")
|
||||||
"""
|
_in_block_re = _re.compile("^\\t\\t(.+)$")
|
||||||
Parse the whole dmidecode output.
|
_record_re = _re.compile("\\t(.+):\\s+(.+)$")
|
||||||
Returns a list of tuples of (type int, value dict).
|
_record2_re = _re.compile("\\t(.+):$")
|
||||||
"""
|
|
||||||
self.info = []
|
_type2str = {
|
||||||
lines = iter(self.content.strip().splitlines())
|
0: 'BIOS',
|
||||||
while True:
|
1: 'System',
|
||||||
try:
|
2: 'Baseboard',
|
||||||
line = next(lines)
|
3: 'Chassis',
|
||||||
except StopIteration:
|
4: 'Processor',
|
||||||
|
5: 'Memory Controller',
|
||||||
|
6: 'Memory Module',
|
||||||
|
7: 'Cache',
|
||||||
|
8: 'Port Connector',
|
||||||
|
9: 'System Slots',
|
||||||
|
10: ' On Board Devices',
|
||||||
|
11: ' OEM Strings',
|
||||||
|
12: ' System Configuration Options',
|
||||||
|
13: ' BIOS Language',
|
||||||
|
14: ' Group Associations',
|
||||||
|
15: ' System Event Log',
|
||||||
|
16: ' Physical Memory Array',
|
||||||
|
17: ' Memory Device',
|
||||||
|
18: ' 32-bit Memory Error',
|
||||||
|
19: ' Memory Array Mapped Address',
|
||||||
|
20: ' Memory Device Mapped Address',
|
||||||
|
21: ' Built-in Pointing Device',
|
||||||
|
22: ' Portable Battery',
|
||||||
|
23: ' System Reset',
|
||||||
|
24: ' Hardware Security',
|
||||||
|
25: ' System Power Controls',
|
||||||
|
26: ' Voltage Probe',
|
||||||
|
27: ' Cooling Device',
|
||||||
|
28: ' Temperature Probe',
|
||||||
|
29: ' Electrical Current Probe',
|
||||||
|
30: ' Out-of-band Remote Access',
|
||||||
|
31: ' Boot Integrity Services',
|
||||||
|
32: ' System Boot',
|
||||||
|
33: ' 64-bit Memory Error',
|
||||||
|
34: ' Management Device',
|
||||||
|
35: ' Management Device Component',
|
||||||
|
36: ' Management Device Threshold Data',
|
||||||
|
37: ' Memory Channel',
|
||||||
|
38: ' IPMI Device',
|
||||||
|
39: ' Power Supply',
|
||||||
|
40: ' Additional Information',
|
||||||
|
41: ' Onboard Devices Extended Information',
|
||||||
|
42: ' Management Controller Host Interface'
|
||||||
|
}
|
||||||
|
_str2type = {}
|
||||||
|
for type_id, type_str in _type2str.items():
|
||||||
|
_str2type[type_str] = type_id
|
||||||
|
|
||||||
|
|
||||||
|
def parse():
|
||||||
|
"""
|
||||||
|
parse the full output of the dmidecode
|
||||||
|
command and return a dic containing the parsed information
|
||||||
|
"""
|
||||||
|
buffer = _execute_cmd()
|
||||||
|
if isinstance(buffer, bytes):
|
||||||
|
buffer = buffer.decode('utf-8')
|
||||||
|
_data = _parse(buffer)
|
||||||
|
return _data
|
||||||
|
|
||||||
|
|
||||||
|
def get_by_type(type_id):
|
||||||
|
"""
|
||||||
|
filter the output of dmidecode per type
|
||||||
|
0 BIOS
|
||||||
|
1 System
|
||||||
|
2 Baseboard
|
||||||
|
3 Chassis
|
||||||
|
4 Processor
|
||||||
|
5 Memory Controller
|
||||||
|
6 Memory Module
|
||||||
|
7 Cache
|
||||||
|
8 Port Connector
|
||||||
|
9 System Slots
|
||||||
|
10 On Board Devices
|
||||||
|
11 OEM Strings
|
||||||
|
12 System Configuration Options
|
||||||
|
13 BIOS Language
|
||||||
|
14 Group Associations
|
||||||
|
15 System Event Log
|
||||||
|
16 Physical Memory Array
|
||||||
|
17 Memory Device
|
||||||
|
18 32-bit Memory Error
|
||||||
|
19 Memory Array Mapped Address
|
||||||
|
20 Memory Device Mapped Address
|
||||||
|
21 Built-in Pointing Device
|
||||||
|
22 Portable Battery
|
||||||
|
23 System Reset
|
||||||
|
24 Hardware Security
|
||||||
|
25 System Power Controls
|
||||||
|
26 Voltage Probe
|
||||||
|
27 Cooling Device
|
||||||
|
28 Temperature Probe
|
||||||
|
29 Electrical Current Probe
|
||||||
|
30 Out-of-band Remote Access
|
||||||
|
31 Boot Integrity Services
|
||||||
|
32 System Boot
|
||||||
|
33 64-bit Memory Error
|
||||||
|
34 Management Device
|
||||||
|
35 Management Device Component
|
||||||
|
36 Management Device Threshold Data
|
||||||
|
37 Memory Channel
|
||||||
|
38 IPMI Device
|
||||||
|
39 Power Supply
|
||||||
|
40 Additional Information
|
||||||
|
41 Onboard Devices Extended Information
|
||||||
|
42 Management Controller Host Interface
|
||||||
|
"""
|
||||||
|
if isinstance(type_id, str):
|
||||||
|
type_id = _str2type[type_id]
|
||||||
|
|
||||||
|
data = parse()
|
||||||
|
result = []
|
||||||
|
for entry in data.values():
|
||||||
|
if entry['DMIType'] == type_id:
|
||||||
|
result.append(entry)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _execute_cmd():
|
||||||
|
return _subprocess.check_output("dmidecode", stderr=_subprocess.PIPE)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse(buffer):
|
||||||
|
output_data = {}
|
||||||
|
# Each record is separated by double newlines
|
||||||
|
split_output = buffer.split('\n\n')
|
||||||
|
|
||||||
|
for record in split_output:
|
||||||
|
record_element = record.splitlines()
|
||||||
|
|
||||||
|
# Entries with less than 3 lines are incomplete / inactive; skip them
|
||||||
|
if len(record_element) < 3:
|
||||||
|
continue
|
||||||
|
|
||||||
|
handle_data = _handle_re.findall(record_element[0])
|
||||||
|
|
||||||
|
if not handle_data:
|
||||||
|
continue
|
||||||
|
handle_data = handle_data[0]
|
||||||
|
|
||||||
|
dmi_handle = handle_data[0]
|
||||||
|
|
||||||
|
output_data[dmi_handle] = {}
|
||||||
|
output_data[dmi_handle]["DMIType"] = int(handle_data[1])
|
||||||
|
output_data[dmi_handle]["DMISize"] = int(handle_data[2])
|
||||||
|
|
||||||
|
# Okay, we know 2nd line == name
|
||||||
|
output_data[dmi_handle]["DMIName"] = record_element[1]
|
||||||
|
|
||||||
|
in_block_elemet = ""
|
||||||
|
in_block_list = ""
|
||||||
|
|
||||||
|
# Loop over the rest of the record, gathering values
|
||||||
|
for i in range(2, len(record_element), 1):
|
||||||
|
if i >= len(record_element):
|
||||||
break
|
break
|
||||||
|
# Check whether we are inside a \t\t block
|
||||||
|
if in_block_elemet != "":
|
||||||
|
|
||||||
if line.startswith('Handle 0x'):
|
in_block_data = _in_block_re.findall(record_element[1])
|
||||||
typ = int(line.split(',', 2)[1].strip()[len('DMI type'):])
|
|
||||||
if typ in self.types:
|
|
||||||
self.info.append(
|
|
||||||
(self.types[typ], self._parse_handle_section(lines))
|
|
||||||
)
|
|
||||||
return self.info
|
|
||||||
|
|
||||||
|
if in_block_data:
|
||||||
|
if not in_block_list:
|
||||||
|
in_block_list = in_block_data[0][0]
|
||||||
|
else:
|
||||||
|
in_block_list = in_block_list + "\t\t" + in_block_data[0][1]
|
||||||
|
|
||||||
def _parse_handle_section(self, lines):
|
output_data[dmi_handle][in_block_elemet] = in_block_list
|
||||||
"""
|
continue
|
||||||
Parse a section of dmidecode output
|
|
||||||
* 1st line contains address, type and size
|
|
||||||
* 2nd line is title
|
|
||||||
* line started with one tab is one option and its value
|
|
||||||
* line started with two tabs is a member of list
|
|
||||||
"""
|
|
||||||
data = {
|
|
||||||
'_title': next(lines).rstrip(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
line = line.rstrip()
|
|
||||||
if line.startswith('\t\t'):
|
|
||||||
if isinstance(data[k], list):
|
|
||||||
data[k].append(line.lstrip())
|
|
||||||
elif line.startswith('\t'):
|
|
||||||
k, v = [i.strip() for i in line.lstrip().split(':', 1)]
|
|
||||||
if v:
|
|
||||||
data[k] = v
|
|
||||||
else:
|
else:
|
||||||
data[k] = []
|
# We are out of the \t\t block; reset it again, and let
|
||||||
else:
|
# the parsing continue
|
||||||
break
|
in_block_elemet = ""
|
||||||
|
|
||||||
return data
|
record_data = _record_re.findall(record_element[i])
|
||||||
|
|
||||||
|
# Is this the line containing handle identifier, type, size?
|
||||||
|
if record_data:
|
||||||
|
output_data[dmi_handle][record_data[0][0]] = record_data[0][1]
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Didn't findall regular entry, maybe an array of data?
|
||||||
|
|
||||||
|
record_data2 = _record2_re.findall(record_element[i])
|
||||||
|
|
||||||
|
if record_data2:
|
||||||
|
# This is an array of data - let the loop know we are inside
|
||||||
|
# an array block
|
||||||
|
in_block_elemet = record_data2[0][0]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not output_data:
|
||||||
|
raise ParseError("Unable to parse 'dmidecode' output")
|
||||||
|
|
||||||
|
return output_data
|
||||||
|
|
||||||
|
|
||||||
def _get_output(self):
|
class ParseError(Exception):
|
||||||
try:
|
pass
|
||||||
output = subprocess.check_output(
|
|
||||||
'PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin '
|
|
||||||
'sudo dmidecode', shell=True)
|
|
||||||
except Exception as e:
|
|
||||||
print(e, file=sys.stderr)
|
|
||||||
if str(e).find("command not found") == -1:
|
|
||||||
print("please install dmidecode", file=sys.stderr)
|
|
||||||
print("e.g. sudo apt install dmidecode",file=sys.stderr)
|
|
||||||
|
|
||||||
sys.exit(1)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
def get(self, i):
|
|
||||||
return [v for j, v in self.info if j == i]
|
|
||||||
|
|
|
@ -1,4 +1,37 @@
|
||||||
from netbox_agent.server import ServerBase
|
from netbox_agent.server import ServerBase
|
||||||
|
|
||||||
class HPHost():
|
class HPHost(ServerBase):
|
||||||
pass
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(HPHost, self).__init__(*args, **kwargs)
|
||||||
|
if self.is_blade():
|
||||||
|
self.hp_rack_locator = self._find_rack_locator()
|
||||||
|
|
||||||
|
def is_blade(self):
|
||||||
|
return self.get_product_name().startswith('ProLiant BL')
|
||||||
|
|
||||||
|
def _find_rack_locator(self):
|
||||||
|
'''
|
||||||
|
Depending on the server, the type of the `HP ProLiant System/Rack Locator`
|
||||||
|
can change.
|
||||||
|
So we need to find it every time
|
||||||
|
'''
|
||||||
|
# FIXME: make a dmidecode function get_by_dminame() ?
|
||||||
|
if self.is_blade():
|
||||||
|
for key, value in self.dmi.parse().items():
|
||||||
|
if value['DMIName'] == 'HP ProLiant System/Rack Locator':
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_blade_slot(self):
|
||||||
|
if self.is_blade():
|
||||||
|
return int(self.hp_rack_locator['Server Bay'].strip())
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_chassis(self):
|
||||||
|
if self.is_blade():
|
||||||
|
return self.hp_rack_locator['Enclosure Model'].strip()
|
||||||
|
return self.get_product_name()
|
||||||
|
|
||||||
|
def get_chassis_service_tag(self):
|
||||||
|
if self.is_blade():
|
||||||
|
return self.hp_rack_locator['Enclosure Serial'].strip()
|
||||||
|
return self.get_service_tag()
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from netbox_agent.dmidecode import Dmidecode
|
import sys
|
||||||
|
from pprint import pprint
|
||||||
|
import netbox_agent.dmidecode as dmidecode
|
||||||
from netbox_agent.dell.dell import DellHost
|
from netbox_agent.dell.dell import DellHost
|
||||||
from netbox_agent.hp.hp import HPHost
|
from netbox_agent.hp.hp import HPHost
|
||||||
|
|
||||||
|
@ -9,14 +11,16 @@ MANUFACTURERS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
dmi = Dmidecode()
|
manufacturer = dmidecode.get_by_type('Chassis')[0].get('Manufacturer')
|
||||||
manufacturer = dmi.get('chassis')[0].get('Manufacturer')
|
server = MANUFACTURERS[manufacturer](dmidecode)
|
||||||
server = MANUFACTURERS[manufacturer](dmi)
|
pprint(dmidecode.parse())
|
||||||
|
print(server.get_product_name())
|
||||||
|
print(server.get_blade_slot())
|
||||||
print(server.get_chassis())
|
print(server.get_chassis())
|
||||||
print(server.get_service_tag())
|
print(server.get_service_tag())
|
||||||
print(server.get_chassis_service_tag())
|
print(server.get_chassis_service_tag())
|
||||||
server.netbox_create()
|
server.netbox_create()
|
||||||
print(server.get_network_cards())
|
# print(server.get_network_cards())
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
from netbox_agent.dmidecode import Dmidecode
|
import socket
|
||||||
|
import netbox_agent.dmidecode as dmidecode
|
||||||
|
from netbox_agent.config import netbox_instance as nb
|
||||||
|
|
||||||
# Regex to match base interface name
|
# Regex to match base interface name
|
||||||
# Doesn't match vlan interfaces and other loopback etc
|
# Doesn't match vlan interfaces and other loopback etc
|
||||||
|
@ -11,9 +13,9 @@ class ServerBase():
|
||||||
if dmi:
|
if dmi:
|
||||||
self.dmi = dmi
|
self.dmi = dmi
|
||||||
else:
|
else:
|
||||||
self.dmi = Dmidecode()
|
self.dmi = dmidecode.parse()
|
||||||
self.system = self.dmi.get('system')
|
self.system = self.dmi.get_by_type('System')
|
||||||
self.bios = self.dmi.get('bios')
|
self.bios = self.dmi.get_by_type('BIOS')
|
||||||
|
|
||||||
self.network_cards = []
|
self.network_cards = []
|
||||||
|
|
||||||
|
@ -61,3 +63,69 @@ class ServerBase():
|
||||||
}
|
}
|
||||||
nics.append(nic)
|
nics.append(nic)
|
||||||
return nics
|
return nics
|
||||||
|
|
||||||
|
def _netbox_create_blade_chassis(self):
|
||||||
|
device_type = nb.dcim.device_types.get(
|
||||||
|
model=self.get_chassis(),
|
||||||
|
)
|
||||||
|
if not device_type:
|
||||||
|
raise Exception('Chassis "{}" doesn\'t exist'.format(self.get_chassis()))
|
||||||
|
device_role = nb.dcim.device_roles.get(
|
||||||
|
name='Server Chassis',
|
||||||
|
)
|
||||||
|
datacenter = nb.dcim.sites.get(
|
||||||
|
name='DC3'
|
||||||
|
)
|
||||||
|
new_chassis = nb.dcim.devices.create(
|
||||||
|
name=''.format(),
|
||||||
|
device_type=device_type.id,
|
||||||
|
serial=self.get_chassis_service_tag(),
|
||||||
|
device_role=device_role.id,
|
||||||
|
site=datacenter.id,
|
||||||
|
)
|
||||||
|
return new_chassis
|
||||||
|
|
||||||
|
def _netbox_create_blade(self, chassis):
|
||||||
|
device_role = nb.dcim.device_roles.get(
|
||||||
|
name='Blade',
|
||||||
|
)
|
||||||
|
device_type = nb.dcim.device_types.get(
|
||||||
|
model=self.get_product_name(),
|
||||||
|
)
|
||||||
|
|
||||||
|
new_blade = nb.dcim.devices.create(
|
||||||
|
name='{}'.format(socket.gethostname()),
|
||||||
|
serial=self.get_service_tag(),
|
||||||
|
device_role=device_role.id,
|
||||||
|
device_type=device_type.id,
|
||||||
|
parent_device=chassis.id,
|
||||||
|
site='1',
|
||||||
|
)
|
||||||
|
return new_blade
|
||||||
|
|
||||||
|
def netbox_create(self):
|
||||||
|
if self.is_blade():
|
||||||
|
# let's find the blade
|
||||||
|
blade = nb.dcim.devices.get(serial=self.get_service_tag())
|
||||||
|
chassis = nb.dcim.devices.get(serial=self.get_chassis_service_tag())
|
||||||
|
# if it doesn't exist, create it
|
||||||
|
if not blade:
|
||||||
|
# check if the chassis exist before
|
||||||
|
# if it doesn't exist, create it
|
||||||
|
if not chassis:
|
||||||
|
chassis = self._netbox_create_blade_chassis()
|
||||||
|
|
||||||
|
blade = self._netbox_create_blade(chassis)
|
||||||
|
|
||||||
|
# Find the slot and update it with our blade
|
||||||
|
device_bays = nb.dcim.device_bays.filter(
|
||||||
|
device_id=chassis.id,
|
||||||
|
name='Blade {}'.format(self.get_blade_slot()),
|
||||||
|
)
|
||||||
|
if len(device_bays) > 0:
|
||||||
|
device_bay = device_bays[0]
|
||||||
|
device_bay.installed_device = blade
|
||||||
|
device_bay.save()
|
||||||
|
else:
|
||||||
|
# FIXME : handle pizza box
|
||||||
|
pass
|
||||||
|
|
Loading…
Add table
Reference in a new issue