2022-03-24 12:13:28 +00:00
|
|
|
import json
|
2022-03-28 17:14:19 +00:00
|
|
|
import logging
|
2022-04-04 17:07:26 +00:00
|
|
|
import uuid
|
2023-07-12 12:18:11 +00:00
|
|
|
from datetime import datetime
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2023-07-11 12:06:16 +00:00
|
|
|
import numpy
|
2022-03-24 12:13:28 +00:00
|
|
|
from dmidecode import DMIParse
|
2022-04-26 08:47:04 +00:00
|
|
|
from flask import request
|
|
|
|
from marshmallow.exceptions import ValidationError
|
2022-04-08 09:40:39 +00:00
|
|
|
|
2023-07-12 12:18:11 +00:00
|
|
|
from ereuse_devicehub.ereuse_utils.nested_lookup import get_nested_dicts_with_key_value
|
|
|
|
from ereuse_devicehub.parser import base2, unit
|
2022-03-28 17:14:19 +00:00
|
|
|
from ereuse_devicehub.parser.computer import Computer
|
2022-05-18 09:03:58 +00:00
|
|
|
from ereuse_devicehub.parser.models import SnapshotsLog
|
2022-04-07 19:01:56 +00:00
|
|
|
from ereuse_devicehub.resources.action.schemas import Snapshot
|
2022-04-08 09:40:39 +00:00
|
|
|
from ereuse_devicehub.resources.enums import DataStorageInterface, Severity
|
2022-03-28 17:14:19 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ParseSnapshot:
|
|
|
|
def __init__(self, snapshot, default="n/a"):
|
|
|
|
self.default = default
|
2023-07-03 16:49:15 +00:00
|
|
|
self.dmidecode_raw = snapshot["hwmd"]["dmidecode"]
|
|
|
|
self.smart_raw = snapshot["hwmd"]["smart"]
|
|
|
|
self.hwinfo_raw = snapshot["hwmd"]["hwinfo"]
|
|
|
|
self.lshw_raw = snapshot["hwmd"]["lshw"]
|
|
|
|
self.lscpi_raw = snapshot["hwmd"]["lspci"]
|
2023-07-14 15:40:18 +00:00
|
|
|
self.sanitize_raw = snapshot["sanitize"]
|
2022-03-24 12:13:28 +00:00
|
|
|
self.device = {"actions": []}
|
|
|
|
self.components = []
|
2023-07-11 12:06:16 +00:00
|
|
|
self.monitors = []
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
self.dmi = DMIParse(self.dmidecode_raw)
|
|
|
|
self.smart = self.loads(self.smart_raw)
|
2023-07-03 16:49:15 +00:00
|
|
|
self.lshw = self.loads(self.lshw_raw)
|
2022-03-24 12:13:28 +00:00
|
|
|
self.hwinfo = self.parse_hwinfo()
|
|
|
|
|
2023-07-04 14:45:04 +00:00
|
|
|
self.set_computer()
|
2023-07-11 12:06:16 +00:00
|
|
|
self.get_hwinfo_monitors()
|
2022-03-25 12:55:05 +00:00
|
|
|
self.set_components()
|
2022-03-24 12:30:53 +00:00
|
|
|
self.snapshot_json = {
|
2022-03-24 12:13:28 +00:00
|
|
|
"device": self.device,
|
2023-07-03 16:49:15 +00:00
|
|
|
"software": "UsodyOS",
|
2022-03-25 12:55:05 +00:00
|
|
|
"components": self.components,
|
2022-03-24 12:13:28 +00:00
|
|
|
"uuid": snapshot['uuid'],
|
2023-07-11 12:06:16 +00:00
|
|
|
"version": snapshot['version'],
|
|
|
|
"settings_version": snapshot['settings_version'],
|
2022-03-25 12:55:05 +00:00
|
|
|
"endTime": snapshot["timestamp"],
|
|
|
|
"elapsed": 1,
|
2022-04-25 09:45:25 +00:00
|
|
|
"sid": snapshot["sid"],
|
2022-03-24 12:13:28 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 19:01:56 +00:00
|
|
|
def get_snapshot(self):
|
|
|
|
return Snapshot().load(self.snapshot_json)
|
|
|
|
|
2023-07-04 14:45:04 +00:00
|
|
|
def set_computer(self):
|
2022-03-24 12:13:28 +00:00
|
|
|
self.device['manufacturer'] = self.dmi.manufacturer()
|
|
|
|
self.device['model'] = self.dmi.model()
|
|
|
|
self.device['serialNumber'] = self.dmi.serial_number()
|
|
|
|
self.device['type'] = self.get_type()
|
|
|
|
self.device['sku'] = self.get_sku()
|
|
|
|
self.device['version'] = self.get_version()
|
2022-06-15 10:18:44 +00:00
|
|
|
self.device['system_uuid'] = self.get_uuid()
|
2023-07-04 14:45:04 +00:00
|
|
|
self.device['family'] = self.get_family()
|
|
|
|
self.device['chassis'] = self.get_chassis_dh()
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def set_components(self):
|
|
|
|
self.get_cpu()
|
|
|
|
self.get_ram()
|
|
|
|
self.get_mother_board()
|
2023-07-11 12:06:16 +00:00
|
|
|
self.get_graphic()
|
2022-03-25 12:55:05 +00:00
|
|
|
self.get_data_storage()
|
2023-07-11 12:06:16 +00:00
|
|
|
self.get_display()
|
|
|
|
self.get_sound_card()
|
2022-03-25 12:55:05 +00:00
|
|
|
self.get_networks()
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_cpu(self):
|
|
|
|
for cpu in self.dmi.get('Processor'):
|
2023-07-04 14:45:04 +00:00
|
|
|
serial = cpu.get('Serial Number')
|
|
|
|
if serial == 'Not Specified' or not serial:
|
2023-07-05 07:21:29 +00:00
|
|
|
serial = cpu.get('ID').replace(' ', '')
|
2022-03-24 12:13:28 +00:00
|
|
|
self.components.append(
|
|
|
|
{
|
2022-03-29 09:19:29 +00:00
|
|
|
"actions": [],
|
2022-03-24 12:13:28 +00:00
|
|
|
"type": "Processor",
|
2022-03-25 12:55:05 +00:00
|
|
|
"speed": self.get_cpu_speed(cpu),
|
2022-03-24 12:13:28 +00:00
|
|
|
"cores": int(cpu.get('Core Count', 1)),
|
|
|
|
"model": cpu.get('Version'),
|
|
|
|
"threads": int(cpu.get('Thread Count', 1)),
|
|
|
|
"manufacturer": cpu.get('Manufacturer'),
|
2023-07-04 14:45:04 +00:00
|
|
|
"serialNumber": serial,
|
|
|
|
"generation": None,
|
|
|
|
"brand": cpu.get('Family'),
|
|
|
|
"address": self.get_cpu_address(cpu),
|
2022-03-24 12:13:28 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_ram(self):
|
|
|
|
for ram in self.dmi.get("Memory Device"):
|
2023-07-19 16:26:21 +00:00
|
|
|
if ram.get('size') == 'No Module Installed':
|
|
|
|
continue
|
|
|
|
if not ram.get("Speed"):
|
|
|
|
continue
|
|
|
|
|
2022-03-24 12:13:28 +00:00
|
|
|
self.components.append(
|
|
|
|
{
|
2022-03-29 09:19:29 +00:00
|
|
|
"actions": [],
|
2022-03-24 12:13:28 +00:00
|
|
|
"type": "RamModule",
|
|
|
|
"size": self.get_ram_size(ram),
|
|
|
|
"speed": self.get_ram_speed(ram),
|
|
|
|
"manufacturer": ram.get("Manufacturer", self.default),
|
|
|
|
"serialNumber": ram.get("Serial Number", self.default),
|
2023-07-12 12:18:11 +00:00
|
|
|
"interface": ram.get("Type", "DDR"),
|
2023-07-05 07:21:29 +00:00
|
|
|
"format": ram.get("Form Factor", "DIMM"),
|
2023-07-11 12:06:16 +00:00
|
|
|
"model": ram.get("Part Number", self.default),
|
2022-03-24 12:13:28 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_mother_board(self):
|
|
|
|
for moder_board in self.dmi.get("Baseboard"):
|
|
|
|
self.components.append(
|
|
|
|
{
|
2022-03-29 09:19:29 +00:00
|
|
|
"actions": [],
|
2022-03-24 12:13:28 +00:00
|
|
|
"type": "Motherboard",
|
|
|
|
"version": moder_board.get("Version"),
|
|
|
|
"serialNumber": moder_board.get("Serial Number"),
|
|
|
|
"manufacturer": moder_board.get("Manufacturer"),
|
|
|
|
"biosDate": self.get_bios_date(),
|
2022-03-25 12:55:05 +00:00
|
|
|
"ramMaxSize": self.get_max_ram_size(),
|
|
|
|
"ramSlots": len(self.dmi.get("Memory Device")),
|
|
|
|
"slots": self.get_ram_slots(),
|
2023-07-11 12:06:16 +00:00
|
|
|
"model": moder_board.get("Product Name"),
|
|
|
|
"firewire": self.get_firmware_num(),
|
|
|
|
"pcmcia": self.get_pcmcia_num(),
|
|
|
|
"serial": self.get_serial_num(),
|
2022-03-24 12:13:28 +00:00
|
|
|
"usb": self.get_usb_num(),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2023-07-11 12:06:16 +00:00
|
|
|
def get_graphic(self):
|
2023-07-12 12:18:11 +00:00
|
|
|
nodes = get_nested_dicts_with_key_value(self.lshw, 'class', 'display')
|
|
|
|
for c in nodes:
|
|
|
|
if not c['configuration'].get('driver', None):
|
|
|
|
continue
|
|
|
|
|
|
|
|
self.components.append(
|
|
|
|
{
|
|
|
|
"actions": [],
|
|
|
|
"type": "GraphicCard",
|
|
|
|
"memory": self.get_memory_video(c),
|
|
|
|
"manufacturer": c.get("vendor", self.default),
|
|
|
|
"model": c.get("product", self.default),
|
|
|
|
"serialNumber": c.get("serial", self.default),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_memory_video(self, c):
|
|
|
|
# get info of lspci
|
|
|
|
# pci_id = c['businfo'].split('@')[1]
|
|
|
|
# lspci.get(pci_id) | grep size
|
|
|
|
# lspci -v -s 00:02.0
|
|
|
|
return None
|
2023-07-11 12:06:16 +00:00
|
|
|
|
|
|
|
def get_data_storage(self):
|
|
|
|
for sm in self.smart:
|
|
|
|
if sm.get('smartctl', {}).get('exit_status') == 1:
|
|
|
|
continue
|
|
|
|
model = sm.get('model_name')
|
|
|
|
manufacturer = None
|
|
|
|
if model and len(model.split(" ")) > 1:
|
|
|
|
mm = model.split(" ")
|
|
|
|
model = mm[-1]
|
|
|
|
manufacturer = " ".join(mm[:-1])
|
|
|
|
|
|
|
|
self.components.append(
|
|
|
|
{
|
2023-07-14 15:40:18 +00:00
|
|
|
"actions": self.sanitize(sm),
|
2023-07-11 12:06:16 +00:00
|
|
|
"type": self.get_data_storage_type(sm),
|
|
|
|
"model": model,
|
|
|
|
"manufacturer": manufacturer,
|
|
|
|
"serialNumber": sm.get('serial_number'),
|
|
|
|
"size": self.get_data_storage_size(sm),
|
|
|
|
"variant": sm.get("firmware_version"),
|
|
|
|
"interface": self.get_data_storage_interface(sm),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2023-07-14 15:40:18 +00:00
|
|
|
def sanitize(self, disk):
|
|
|
|
disk_sanitize = None
|
2023-07-19 16:26:21 +00:00
|
|
|
# import pdb; pdb.set_trace()
|
2023-07-14 15:40:18 +00:00
|
|
|
for d in self.sanitize_raw:
|
|
|
|
s = d.get('device_info', {}).get('export_data', {})
|
|
|
|
s = s.get('block', {}).get('serial')
|
|
|
|
if s == disk.get('serial_number'):
|
|
|
|
disk_sanitize = d
|
|
|
|
break
|
|
|
|
if not disk_sanitize:
|
|
|
|
return []
|
|
|
|
|
|
|
|
steps = []
|
2023-07-19 16:26:21 +00:00
|
|
|
step_type = 'EraseBasic'
|
|
|
|
if disk.get('name') == 'Baseline Cryptographic':
|
|
|
|
step_type = 'EraseCrypto'
|
|
|
|
|
|
|
|
if disk.get('type') == 'EraseCrypto':
|
|
|
|
step_type = 'EraseCrypto'
|
|
|
|
|
2023-07-14 15:40:18 +00:00
|
|
|
erase = {
|
2023-07-19 16:26:21 +00:00
|
|
|
'type': step_type,
|
2023-07-14 15:40:18 +00:00
|
|
|
'severity': disk_sanitize['severity'].name,
|
|
|
|
'steps': steps,
|
|
|
|
'startTime': None,
|
|
|
|
'endTime': None,
|
|
|
|
}
|
|
|
|
|
|
|
|
for step in disk_sanitize.get('steps', []):
|
|
|
|
steps.append(
|
|
|
|
{
|
|
|
|
'severity': step['severity'].name,
|
|
|
|
'startTime': step['start_time'].isoformat(),
|
|
|
|
'endTime': step['end_time'].isoformat(),
|
|
|
|
'type': 'StepRandom',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
erase['endTime'] = step['end_time'].isoformat()
|
|
|
|
if not erase['startTime']:
|
|
|
|
erase['startTime'] = step['start_time'].isoformat()
|
|
|
|
return [erase]
|
|
|
|
|
2023-07-11 12:06:16 +00:00
|
|
|
def get_networks(self):
|
2023-07-12 12:18:11 +00:00
|
|
|
nodes = get_nested_dicts_with_key_value(self.lshw, 'class', 'network')
|
|
|
|
for c in nodes:
|
|
|
|
capacity = c.get('capacity')
|
|
|
|
units = c.get('units')
|
|
|
|
speed = None
|
|
|
|
if capacity and units:
|
|
|
|
speed = unit.Quantity(capacity, units).to('Mbit/s').m
|
|
|
|
wireless = bool(c.get('configuration', {}).get('wireless', False))
|
|
|
|
self.components.append(
|
|
|
|
{
|
|
|
|
"actions": [],
|
|
|
|
"type": "NetworkAdapter",
|
|
|
|
"model": c.get('product'),
|
|
|
|
"manufacturer": c.get('vendor'),
|
|
|
|
"serialNumber": c.get('serial'),
|
|
|
|
"speed": speed,
|
|
|
|
"variant": c.get('version', 1),
|
|
|
|
"wireless": wireless,
|
|
|
|
}
|
|
|
|
)
|
2023-07-11 12:06:16 +00:00
|
|
|
|
|
|
|
def get_sound_card(self):
|
2023-07-12 12:18:11 +00:00
|
|
|
nodes = get_nested_dicts_with_key_value(self.lshw, 'class', 'multimedia')
|
|
|
|
for c in nodes:
|
|
|
|
self.components.append(
|
|
|
|
{
|
|
|
|
"actions": [],
|
|
|
|
"type": "SoundCard",
|
|
|
|
"model": c.get('product'),
|
|
|
|
"manufacturer": c.get('vendor'),
|
|
|
|
"serialNumber": c.get('serial'),
|
|
|
|
}
|
|
|
|
)
|
2023-07-11 12:06:16 +00:00
|
|
|
|
|
|
|
def get_display(self): # noqa: C901
|
|
|
|
TECHS = 'CRT', 'TFT', 'LED', 'PDP', 'LCD', 'OLED', 'AMOLED'
|
|
|
|
|
|
|
|
for c in self.monitors:
|
|
|
|
resolution_width, resolution_height = (None,) * 2
|
|
|
|
refresh, serial, model, manufacturer, size = (None,) * 5
|
2023-07-12 12:18:11 +00:00
|
|
|
year, week, production_date = (None,) * 3
|
2023-07-11 12:06:16 +00:00
|
|
|
|
|
|
|
for x in c:
|
|
|
|
if "Vendor: " in x:
|
|
|
|
manufacturer = x.split('Vendor: ')[-1].strip()
|
|
|
|
if "Model: " in x:
|
|
|
|
model = x.split('Model: ')[-1].strip()
|
|
|
|
if "Serial ID: " in x:
|
|
|
|
serial = x.split('Serial ID: ')[-1].strip()
|
|
|
|
if " Resolution: " in x:
|
|
|
|
rs = x.split(' Resolution: ')[-1].strip()
|
|
|
|
if 'x' in rs:
|
|
|
|
resolution_width, resolution_height = [
|
|
|
|
int(r) for r in rs.split('x')
|
|
|
|
]
|
|
|
|
if "Frequencies: " in x:
|
|
|
|
try:
|
|
|
|
refresh = int(float(x.split(',')[-1].strip()[:-3]))
|
|
|
|
except Exception:
|
|
|
|
pass
|
2023-07-12 12:18:11 +00:00
|
|
|
if 'Year of Manufacture' in x:
|
|
|
|
year = x.split(': ')[1]
|
|
|
|
|
|
|
|
if 'Week of Manufacture' in x:
|
|
|
|
week = x.split(': ')[1]
|
2023-07-11 12:06:16 +00:00
|
|
|
|
|
|
|
if "Size: " in x:
|
|
|
|
size = self.get_size_monitor(x)
|
|
|
|
technology = next((t for t in TECHS if t in c[0]), None)
|
2023-07-12 12:18:11 +00:00
|
|
|
|
|
|
|
if year and week:
|
|
|
|
d = '{} {} 0'.format(year, week)
|
|
|
|
production_date = datetime.strptime(d, '%Y %W %w').isoformat()
|
|
|
|
|
2023-07-11 12:06:16 +00:00
|
|
|
self.components.append(
|
|
|
|
{
|
|
|
|
"actions": [],
|
|
|
|
"type": "Display",
|
|
|
|
"model": model,
|
|
|
|
"manufacturer": manufacturer,
|
|
|
|
"serialNumber": serial,
|
|
|
|
'size': size,
|
2023-07-12 12:18:11 +00:00
|
|
|
'resolutionWidth': resolution_width,
|
|
|
|
'resolutionHeight': resolution_height,
|
|
|
|
"productionDate": production_date,
|
2023-07-11 12:06:16 +00:00
|
|
|
'technology': technology,
|
2023-07-12 12:18:11 +00:00
|
|
|
'refreshRate': refresh,
|
2023-07-11 12:06:16 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_hwinfo_monitors(self):
|
|
|
|
for c in self.hwinfo:
|
|
|
|
monitor = None
|
|
|
|
external = None
|
|
|
|
for x in c:
|
|
|
|
if 'Hardware Class: monitor' in x:
|
|
|
|
monitor = c
|
|
|
|
if 'Driver Info' in x:
|
|
|
|
external = c
|
|
|
|
|
|
|
|
if monitor and not external:
|
|
|
|
self.monitors.append(c)
|
|
|
|
|
|
|
|
def get_size_monitor(self, x):
|
|
|
|
i = 1 / 25.4
|
|
|
|
t = x.split('Size: ')[-1].strip()
|
|
|
|
tt = t.split('mm')
|
|
|
|
if not tt:
|
|
|
|
return 0
|
|
|
|
sizes = tt[0].strip()
|
|
|
|
if 'x' not in sizes:
|
|
|
|
return 0
|
|
|
|
w, h = [int(x) for x in sizes.split('x')]
|
|
|
|
return numpy.sqrt(w**2 + h**2) * i
|
|
|
|
|
|
|
|
def get_cpu_address(self, cpu):
|
|
|
|
default = 64
|
|
|
|
for ch in self.lshw.get('children', []):
|
|
|
|
for c in ch.get('children', []):
|
|
|
|
if c['class'] == 'processor':
|
|
|
|
return c.get('width', default)
|
|
|
|
return default
|
|
|
|
|
2022-03-24 12:13:28 +00:00
|
|
|
def get_usb_num(self):
|
|
|
|
return len(
|
2022-04-18 15:14:26 +00:00
|
|
|
[
|
|
|
|
u
|
|
|
|
for u in self.dmi.get("Port Connector")
|
|
|
|
if "USB" in u.get("Port Type", "").upper()
|
|
|
|
]
|
2022-03-24 12:13:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def get_serial_num(self):
|
|
|
|
return len(
|
2022-03-25 12:55:05 +00:00
|
|
|
[
|
|
|
|
u
|
|
|
|
for u in self.dmi.get("Port Connector")
|
2022-04-18 15:14:26 +00:00
|
|
|
if "SERIAL" in u.get("Port Type", "").upper()
|
2022-03-25 12:55:05 +00:00
|
|
|
]
|
2022-03-24 12:13:28 +00:00
|
|
|
)
|
|
|
|
|
2023-07-11 12:06:16 +00:00
|
|
|
def get_firmware_num(self):
|
|
|
|
return len(
|
|
|
|
[
|
|
|
|
u
|
|
|
|
for u in self.dmi.get("Port Connector")
|
|
|
|
if "FIRMWARE" in u.get("Port Type", "").upper()
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2022-03-24 12:13:28 +00:00
|
|
|
def get_pcmcia_num(self):
|
|
|
|
return len(
|
2022-03-25 12:55:05 +00:00
|
|
|
[
|
|
|
|
u
|
|
|
|
for u in self.dmi.get("Port Connector")
|
2022-04-18 15:14:26 +00:00
|
|
|
if "PCMCIA" in u.get("Port Type", "").upper()
|
2022-03-25 12:55:05 +00:00
|
|
|
]
|
2022-03-24 12:13:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def get_bios_date(self):
|
2022-03-25 12:55:05 +00:00
|
|
|
return self.dmi.get("BIOS")[0].get("Release Date", self.default)
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_firmware(self):
|
2022-03-29 10:23:51 +00:00
|
|
|
return self.dmi.get("BIOS")[0].get("Firmware Revision", '1')
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_max_ram_size(self):
|
2022-03-25 12:55:05 +00:00
|
|
|
size = 0
|
|
|
|
for slot in self.dmi.get("Physical Memory Array"):
|
|
|
|
capacity = slot.get("Maximum Capacity", '0').split(" ")[0]
|
|
|
|
size += int(capacity)
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-25 12:55:05 +00:00
|
|
|
return size
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_ram_slots(self):
|
2022-03-25 12:55:05 +00:00
|
|
|
slots = 0
|
|
|
|
for x in self.dmi.get("Physical Memory Array"):
|
|
|
|
slots += int(x.get("Number Of Devices", 0))
|
|
|
|
return slots
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_ram_size(self, ram):
|
2023-07-19 16:26:21 +00:00
|
|
|
try:
|
|
|
|
memory = ram.get("Size", "0")
|
|
|
|
memory = memory.split(' ')
|
|
|
|
if len(memory) > 1:
|
|
|
|
size = int(memory[0])
|
|
|
|
units = memory[1]
|
|
|
|
return base2.Quantity(size, units).to('MiB').m
|
|
|
|
return int(size.split(" ")[0])
|
|
|
|
except Exception as err:
|
|
|
|
logger.error("get_ram_size error: {}".format(err))
|
|
|
|
return 0
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_ram_speed(self, ram):
|
2022-03-25 12:55:05 +00:00
|
|
|
size = ram.get("Speed", "0")
|
|
|
|
return int(size.split(" ")[0])
|
|
|
|
|
|
|
|
def get_cpu_speed(self, cpu):
|
|
|
|
speed = cpu.get('Max Speed', "0")
|
|
|
|
return float(speed.split(" ")[0]) / 1024
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_sku(self):
|
2022-03-25 12:55:05 +00:00
|
|
|
return self.dmi.get("System")[0].get("SKU Number", self.default)
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_version(self):
|
2022-03-25 12:55:05 +00:00
|
|
|
return self.dmi.get("System")[0].get("Version", self.default)
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_uuid(self):
|
2023-07-04 14:45:04 +00:00
|
|
|
return self.dmi.get("System")[0].get("UUID", '')
|
|
|
|
|
|
|
|
def get_family(self):
|
|
|
|
return self.dmi.get("System")[0].get("Family", '')
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_chassis(self):
|
2023-07-04 14:45:04 +00:00
|
|
|
return self.dmi.get("Chassis")[0].get("Type", '_virtual')
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_type(self):
|
|
|
|
chassis_type = self.get_chassis()
|
|
|
|
return self.translation_to_devicehub(chassis_type)
|
|
|
|
|
|
|
|
def translation_to_devicehub(self, original_type):
|
|
|
|
lower_type = original_type.lower()
|
|
|
|
CHASSIS_TYPE = {
|
|
|
|
'Desktop': [
|
|
|
|
'desktop',
|
|
|
|
'low-profile',
|
|
|
|
'tower',
|
|
|
|
'docking',
|
|
|
|
'all-in-one',
|
|
|
|
'pizzabox',
|
|
|
|
'mini-tower',
|
|
|
|
'space-saving',
|
|
|
|
'lunchbox',
|
|
|
|
'mini',
|
|
|
|
'stick',
|
|
|
|
],
|
|
|
|
'Laptop': [
|
|
|
|
'portable',
|
|
|
|
'laptop',
|
|
|
|
'convertible',
|
|
|
|
'tablet',
|
|
|
|
'detachable',
|
|
|
|
'notebook',
|
|
|
|
'handheld',
|
|
|
|
'sub-notebook',
|
|
|
|
],
|
|
|
|
'Server': ['server'],
|
|
|
|
'Computer': ['_virtual'],
|
|
|
|
}
|
|
|
|
for k, v in CHASSIS_TYPE.items():
|
|
|
|
if lower_type in v:
|
|
|
|
return k
|
|
|
|
return self.default
|
|
|
|
|
2023-07-04 14:45:04 +00:00
|
|
|
def get_chassis_dh(self):
|
|
|
|
CHASSIS_DH = {
|
|
|
|
'Tower': {'desktop', 'low-profile', 'tower', 'server'},
|
|
|
|
'Docking': {'docking'},
|
|
|
|
'AllInOne': {'all-in-one'},
|
|
|
|
'Microtower': {'mini-tower', 'space-saving', 'mini'},
|
|
|
|
'PizzaBox': {'pizzabox'},
|
|
|
|
'Lunchbox': {'lunchbox'},
|
|
|
|
'Stick': {'stick'},
|
|
|
|
'Netbook': {'notebook', 'sub-notebook'},
|
|
|
|
'Handheld': {'handheld'},
|
|
|
|
'Laptop': {'portable', 'laptop'},
|
|
|
|
'Convertible': {'convertible'},
|
|
|
|
'Detachable': {'detachable'},
|
|
|
|
'Tablet': {'tablet'},
|
|
|
|
'Virtual': {'_virtual'},
|
|
|
|
}
|
|
|
|
|
|
|
|
chassis = self.get_chassis()
|
|
|
|
lower_type = chassis.lower()
|
|
|
|
for k, v in CHASSIS_DH.items():
|
|
|
|
if lower_type in v:
|
|
|
|
return k
|
|
|
|
return self.default
|
|
|
|
|
2022-03-24 12:13:28 +00:00
|
|
|
def get_data_storage_type(self, x):
|
|
|
|
# TODO @cayop add more SSDS types
|
|
|
|
SSDS = ["nvme"]
|
|
|
|
SSD = 'SolidStateDrive'
|
|
|
|
HDD = 'HardDrive'
|
|
|
|
type_dev = x.get('device', {}).get('type')
|
2023-07-11 12:06:16 +00:00
|
|
|
trim = x.get('trim', {}).get("supported") in [True, "true"]
|
|
|
|
return SSD if type_dev in SSDS or trim else HDD
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_data_storage_interface(self, x):
|
2023-07-11 12:06:16 +00:00
|
|
|
interface = x.get('device', {}).get('protocol', 'ATA')
|
|
|
|
try:
|
|
|
|
DataStorageInterface(interface.upper())
|
|
|
|
except ValueError as err:
|
|
|
|
txt = "Sid: {}, interface {} is not in DataStorageInterface Enum".format(
|
|
|
|
self.sid, interface
|
|
|
|
)
|
|
|
|
self.errors("{}".format(err))
|
|
|
|
self.errors(txt, severity=Severity.Warning)
|
|
|
|
return "ATA"
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def get_data_storage_size(self, x):
|
2023-07-11 12:06:16 +00:00
|
|
|
total_capacity = x.get('user_capacity', {}).get('bytes')
|
|
|
|
if not total_capacity:
|
|
|
|
return 1
|
2022-03-24 12:13:28 +00:00
|
|
|
# convert bytes to Mb
|
2023-07-11 12:06:16 +00:00
|
|
|
return total_capacity / 1024**2
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
def parse_hwinfo(self):
|
|
|
|
hw_blocks = self.hwinfo_raw.split("\n\n")
|
|
|
|
return [x.split("\n") for x in hw_blocks]
|
|
|
|
|
|
|
|
def loads(self, x):
|
2022-03-25 12:55:05 +00:00
|
|
|
if isinstance(x, str):
|
|
|
|
return json.loads(x)
|
|
|
|
return x
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2023-07-04 14:45:04 +00:00
|
|
|
def errors(self, txt=None, severity=Severity.Error):
|
|
|
|
if not txt:
|
|
|
|
return self._errors
|
|
|
|
|
|
|
|
logger.error(txt)
|
|
|
|
self._errors.append(txt)
|
|
|
|
error = SnapshotsLog(
|
|
|
|
description=txt,
|
|
|
|
snapshot_uuid=self.uuid,
|
|
|
|
severity=severity,
|
|
|
|
sid=self.sid,
|
|
|
|
version=self.version,
|
|
|
|
)
|
|
|
|
error.save()
|
|
|
|
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
class ParseSnapshotLsHw:
|
|
|
|
def __init__(self, snapshot, default="n/a"):
|
2022-03-24 12:13:28 +00:00
|
|
|
self.default = default
|
2022-04-01 16:25:58 +00:00
|
|
|
self.uuid = snapshot.get("uuid")
|
2022-04-25 09:45:25 +00:00
|
|
|
self.sid = snapshot.get("sid")
|
2022-05-20 16:31:47 +00:00
|
|
|
self.version = str(snapshot.get("version"))
|
2023-07-03 16:49:15 +00:00
|
|
|
self.dmidecode_raw = snapshot["hwmd"]["dmidecode"]
|
|
|
|
self.smart = snapshot["hwmd"]["smart"]
|
|
|
|
self.hwinfo_raw = snapshot["hwmd"]["hwinfo"]
|
|
|
|
self.lshw = snapshot["hwmd"]["lshw"]
|
2022-03-28 17:14:19 +00:00
|
|
|
self.device = {"actions": []}
|
|
|
|
self.components = []
|
|
|
|
self.components_obj = []
|
2022-04-01 16:25:58 +00:00
|
|
|
self._errors = []
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
self.dmi = DMIParse(self.dmidecode_raw)
|
|
|
|
self.hwinfo = self.parse_hwinfo()
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
self.set_basic_datas()
|
|
|
|
self.set_components()
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
self.snapshot_json = {
|
2022-04-07 19:01:56 +00:00
|
|
|
"type": "Snapshot",
|
2022-03-28 17:14:19 +00:00
|
|
|
"device": self.device,
|
|
|
|
"software": "Workbench",
|
|
|
|
"components": self.components,
|
|
|
|
"uuid": snapshot['uuid'],
|
2022-04-11 08:59:15 +00:00
|
|
|
"version": "14.0.0",
|
2022-12-15 09:18:22 +00:00
|
|
|
"settings_version": snapshot.get("settings_version"),
|
2022-03-28 17:14:19 +00:00
|
|
|
"endTime": snapshot["timestamp"],
|
|
|
|
"elapsed": 1,
|
2022-04-25 09:45:25 +00:00
|
|
|
"sid": snapshot["sid"],
|
2022-03-28 17:14:19 +00:00
|
|
|
}
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-04-07 19:01:56 +00:00
|
|
|
def get_snapshot(self):
|
2022-04-22 07:51:17 +00:00
|
|
|
return Snapshot().load(self.snapshot_json)
|
2022-04-07 19:01:56 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
def parse_hwinfo(self):
|
|
|
|
hw_blocks = self.hwinfo_raw.split("\n\n")
|
|
|
|
return [x.split("\n") for x in hw_blocks]
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
def loads(self, x):
|
|
|
|
if isinstance(x, str):
|
|
|
|
return json.loads(x)
|
|
|
|
return x
|
|
|
|
|
|
|
|
def set_basic_datas(self):
|
2022-04-26 08:47:04 +00:00
|
|
|
try:
|
|
|
|
pc, self.components_obj = Computer.run(
|
2022-05-18 16:00:54 +00:00
|
|
|
self.lshw, self.hwinfo_raw, self.uuid, self.sid, self.version
|
2022-04-26 08:47:04 +00:00
|
|
|
)
|
|
|
|
pc = pc.dump()
|
|
|
|
minimum_hid = None in [pc['manufacturer'], pc['model'], pc['serialNumber']]
|
|
|
|
if minimum_hid and not self.components_obj:
|
|
|
|
# if no there are hid and any components return 422
|
|
|
|
raise Exception
|
|
|
|
except Exception:
|
|
|
|
msg = """It has not been possible to create the device because we lack data.
|
|
|
|
You can find more information at: {}""".format(
|
|
|
|
request.url_root
|
|
|
|
)
|
|
|
|
txt = json.dumps({'sid': self.sid, 'message': msg})
|
|
|
|
raise ValidationError(txt)
|
|
|
|
|
|
|
|
self.device = pc
|
2022-06-15 10:18:44 +00:00
|
|
|
self.device['system_uuid'] = self.get_uuid()
|
2022-03-28 17:14:19 +00:00
|
|
|
|
|
|
|
def set_components(self):
|
|
|
|
memory = None
|
|
|
|
|
|
|
|
for x in self.components_obj:
|
|
|
|
if x.type == 'RamModule':
|
|
|
|
memory = 1
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
if x.type == 'Motherboard':
|
|
|
|
x.slots = self.get_ram_slots()
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
self.components.append(x.dump())
|
|
|
|
|
|
|
|
if not memory:
|
|
|
|
self.get_ram()
|
|
|
|
|
|
|
|
self.get_data_storage()
|
|
|
|
|
|
|
|
def get_ram(self):
|
|
|
|
for ram in self.dmi.get("Memory Device"):
|
2023-07-19 16:26:21 +00:00
|
|
|
if ram.get('size') == 'No Module Installed':
|
|
|
|
continue
|
|
|
|
if not ram.get("Speed"):
|
|
|
|
continue
|
|
|
|
|
2022-03-24 12:13:28 +00:00
|
|
|
self.components.append(
|
|
|
|
{
|
2022-03-29 09:19:29 +00:00
|
|
|
"actions": [],
|
2022-03-28 17:14:19 +00:00
|
|
|
"type": "RamModule",
|
|
|
|
"size": self.get_ram_size(ram),
|
|
|
|
"speed": self.get_ram_speed(ram),
|
|
|
|
"manufacturer": ram.get("Manufacturer", self.default),
|
|
|
|
"serialNumber": ram.get("Serial Number", self.default),
|
|
|
|
"interface": self.get_ram_type(ram),
|
|
|
|
"format": self.get_ram_format(ram),
|
|
|
|
"model": ram.get("Part Number", self.default),
|
2022-03-24 12:13:28 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
def get_ram_size(self, ram):
|
2022-04-01 16:25:58 +00:00
|
|
|
size = ram.get("Size")
|
|
|
|
if not len(size.split(" ")) == 2:
|
2022-04-25 09:45:25 +00:00
|
|
|
txt = (
|
2022-05-20 11:44:11 +00:00
|
|
|
"Error: Snapshot: {uuid}, Sid: {sid} have this ram Size: {size}".format(
|
2022-04-25 09:45:25 +00:00
|
|
|
uuid=self.uuid, size=size, sid=self.sid
|
|
|
|
)
|
2022-04-01 16:25:58 +00:00
|
|
|
)
|
2022-05-18 16:26:01 +00:00
|
|
|
self.errors(txt, severity=Severity.Warning)
|
2022-04-01 16:25:58 +00:00
|
|
|
return 128
|
|
|
|
size, units = size.split(" ")
|
|
|
|
return base2.Quantity(float(size), units).to('MiB').m
|
2022-03-28 17:14:19 +00:00
|
|
|
|
|
|
|
def get_ram_speed(self, ram):
|
2022-04-01 16:25:58 +00:00
|
|
|
speed = ram.get("Speed", "100")
|
|
|
|
if not len(speed.split(" ")) == 2:
|
2022-05-20 11:44:11 +00:00
|
|
|
txt = "Error: Snapshot: {uuid}, Sid: {sid} have this ram Speed: {speed}".format(
|
2022-04-25 09:45:25 +00:00
|
|
|
uuid=self.uuid, speed=speed, sid=self.sid
|
2022-04-01 16:25:58 +00:00
|
|
|
)
|
2022-05-18 16:26:01 +00:00
|
|
|
self.errors(txt, severity=Severity.Warning)
|
2022-04-01 16:25:58 +00:00
|
|
|
return 100
|
|
|
|
speed, units = speed.split(" ")
|
2022-04-04 17:07:26 +00:00
|
|
|
return float(speed)
|
|
|
|
# TODO @cayop is neccesary change models for accept sizes more high of speed or change to string
|
|
|
|
# return base2.Quantity(float(speed), units).to('MHz').m
|
2022-03-28 17:14:19 +00:00
|
|
|
|
|
|
|
def get_ram_slots(self):
|
|
|
|
slots = 0
|
|
|
|
for x in self.dmi.get("Physical Memory Array"):
|
|
|
|
slots += int(x.get("Number Of Devices", 0))
|
|
|
|
return slots
|
|
|
|
|
|
|
|
def get_ram_type(self, ram):
|
|
|
|
TYPES = {'ddr', 'sdram', 'sodimm'}
|
|
|
|
for t in TYPES:
|
|
|
|
if t in ram.get("Type", "DDR"):
|
|
|
|
return t
|
|
|
|
|
|
|
|
def get_ram_format(self, ram):
|
|
|
|
channel = ram.get("Locator", "DIMM")
|
|
|
|
return 'SODIMM' if 'SODIMM' in channel else 'DIMM'
|
|
|
|
|
2022-04-01 16:25:58 +00:00
|
|
|
def get_uuid(self):
|
2022-04-05 09:04:16 +00:00
|
|
|
dmi_uuid = 'undefined'
|
|
|
|
if self.dmi.get("System"):
|
|
|
|
dmi_uuid = self.dmi.get("System")[0].get("UUID")
|
|
|
|
|
2022-04-01 16:25:58 +00:00
|
|
|
try:
|
2022-04-04 17:07:26 +00:00
|
|
|
uuid.UUID(dmi_uuid)
|
|
|
|
except (ValueError, AttributeError) as err:
|
2022-04-04 11:27:04 +00:00
|
|
|
self.errors("{}".format(err))
|
2022-05-20 11:44:11 +00:00
|
|
|
txt = "Error: Snapshot: {uuid} sid: {sid} have this uuid: {device}".format(
|
2022-04-25 09:45:25 +00:00
|
|
|
uuid=self.uuid, device=dmi_uuid, sid=self.sid
|
2022-04-01 16:25:58 +00:00
|
|
|
)
|
2022-05-18 16:26:01 +00:00
|
|
|
self.errors(txt, severity=Severity.Warning)
|
2022-04-04 17:07:26 +00:00
|
|
|
dmi_uuid = None
|
|
|
|
return dmi_uuid
|
2022-04-01 16:25:58 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
def get_data_storage(self):
|
|
|
|
|
|
|
|
for sm in self.smart:
|
2022-04-18 17:09:03 +00:00
|
|
|
if sm.get('smartctl', {}).get('exit_status') == 1:
|
2022-04-18 15:14:26 +00:00
|
|
|
continue
|
2022-03-28 17:14:19 +00:00
|
|
|
model = sm.get('model_name')
|
|
|
|
manufacturer = None
|
2022-04-01 16:25:58 +00:00
|
|
|
if model and len(model.split(" ")) > 1:
|
2022-03-28 17:14:19 +00:00
|
|
|
mm = model.split(" ")
|
|
|
|
model = mm[-1]
|
|
|
|
manufacturer = " ".join(mm[:-1])
|
2022-03-24 12:13:28 +00:00
|
|
|
|
|
|
|
self.components.append(
|
|
|
|
{
|
2023-07-12 12:18:11 +00:00
|
|
|
"actions": [],
|
2022-03-28 17:14:19 +00:00
|
|
|
"type": self.get_data_storage_type(sm),
|
|
|
|
"model": model,
|
|
|
|
"manufacturer": manufacturer,
|
|
|
|
"serialNumber": sm.get('serial_number'),
|
|
|
|
"size": self.get_data_storage_size(sm),
|
|
|
|
"variant": sm.get("firmware_version"),
|
|
|
|
"interface": self.get_data_storage_interface(sm),
|
2022-03-24 12:13:28 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
def get_data_storage_type(self, x):
|
|
|
|
# TODO @cayop add more SSDS types
|
|
|
|
SSDS = ["nvme"]
|
|
|
|
SSD = 'SolidStateDrive'
|
|
|
|
HDD = 'HardDrive'
|
|
|
|
type_dev = x.get('device', {}).get('type')
|
2022-04-18 15:14:26 +00:00
|
|
|
trim = x.get('trim', {}).get("supported") in [True, "true"]
|
2022-04-01 16:25:58 +00:00
|
|
|
return SSD if type_dev in SSDS or trim else HDD
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
def get_data_storage_interface(self, x):
|
|
|
|
interface = x.get('device', {}).get('protocol', 'ATA')
|
|
|
|
try:
|
2022-04-08 09:40:39 +00:00
|
|
|
DataStorageInterface(interface.upper())
|
2022-03-28 17:14:19 +00:00
|
|
|
except ValueError as err:
|
2022-05-20 11:44:11 +00:00
|
|
|
txt = "Sid: {}, interface {} is not in DataStorageInterface Enum".format(
|
|
|
|
self.sid, interface
|
2022-04-12 08:24:32 +00:00
|
|
|
)
|
2022-04-04 11:27:04 +00:00
|
|
|
self.errors("{}".format(err))
|
2022-05-18 16:26:01 +00:00
|
|
|
self.errors(txt, severity=Severity.Warning)
|
2022-04-01 16:25:58 +00:00
|
|
|
return "ATA"
|
2022-03-24 12:13:28 +00:00
|
|
|
|
2022-03-28 17:14:19 +00:00
|
|
|
def get_data_storage_size(self, x):
|
2022-04-18 15:14:26 +00:00
|
|
|
total_capacity = x.get('user_capacity', {}).get('bytes')
|
|
|
|
if not total_capacity:
|
2022-04-01 16:25:58 +00:00
|
|
|
return 1
|
2022-03-28 17:14:19 +00:00
|
|
|
# convert bytes to Mb
|
2022-04-18 15:14:26 +00:00
|
|
|
return total_capacity / 1024**2
|
2022-03-29 09:19:29 +00:00
|
|
|
|
|
|
|
def get_test_data_storage(self, smart):
|
2022-04-18 15:14:26 +00:00
|
|
|
hours = smart.get("power_on_time", {}).get('hours', 0)
|
2022-03-29 09:19:29 +00:00
|
|
|
action = {
|
|
|
|
"status": "Completed without error",
|
|
|
|
"reallocatedSectorCount": smart.get("reallocated_sector_count", 0),
|
|
|
|
"currentPendingSectorCount": smart.get("current_pending_sector_count", 0),
|
|
|
|
"assessment": True,
|
|
|
|
"severity": "Info",
|
|
|
|
"offlineUncorrectable": smart.get("offline_uncorrectable", 0),
|
2022-04-18 15:14:26 +00:00
|
|
|
"lifetime": hours,
|
|
|
|
"powerOnHours": hours,
|
2022-03-29 09:19:29 +00:00
|
|
|
"type": "TestDataStorage",
|
|
|
|
"length": "Short",
|
|
|
|
"elapsed": 0,
|
|
|
|
"reportedUncorrectableErrors": smart.get(
|
|
|
|
"reported_uncorrectable_errors", 0
|
|
|
|
),
|
|
|
|
"powerCycleCount": smart.get("power_cycle_count", 0),
|
|
|
|
}
|
|
|
|
|
|
|
|
return action
|
2022-04-01 16:25:58 +00:00
|
|
|
|
2022-11-16 10:51:31 +00:00
|
|
|
def get_hid_datas(self):
|
|
|
|
self.device.family = self.get_family()
|
|
|
|
|
|
|
|
def get_family(self):
|
|
|
|
return self.dmi.get("System", [{}])[0].get("Family", '')
|
|
|
|
|
2022-05-18 16:00:54 +00:00
|
|
|
def errors(self, txt=None, severity=Severity.Error):
|
2022-04-01 16:25:58 +00:00
|
|
|
if not txt:
|
|
|
|
return self._errors
|
|
|
|
|
|
|
|
logger.error(txt)
|
|
|
|
self._errors.append(txt)
|
2022-05-18 09:03:58 +00:00
|
|
|
error = SnapshotsLog(
|
2022-05-18 16:00:54 +00:00
|
|
|
description=txt,
|
|
|
|
snapshot_uuid=self.uuid,
|
|
|
|
severity=severity,
|
|
|
|
sid=self.sid,
|
|
|
|
version=self.version,
|
2022-04-04 11:27:04 +00:00
|
|
|
)
|
|
|
|
error.save()
|