mirror of https://git.48k.eu/ogclient
Add utils modules
* disk.py Disk discovery * fs.py Uses psutil to fetch fs usage information * menu.py ogBrowser menu generation * net.py: gets nic status information IP address, MAC address and ethernet speed. * probe.py: probes mountpoints for operating systems Uses hivexget command to try fetching Windows installation information. Looks for /etc/os-release for probing linux systems.more_events
parent
79d3062f81
commit
902e019505
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# Copyright (C) 2022 Soleta Networks <info@soleta.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the
|
||||
# Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
import os
|
||||
|
||||
def get_disks():
|
||||
"""
|
||||
Walks /sys/block/ and returns files starting with 'sd',
|
||||
'nvme' or 'vd'
|
||||
"""
|
||||
return sorted([ dev for dev in os.listdir('/sys/block/')
|
||||
if dev.startswith('sd')
|
||||
or dev.startswith('nvme')
|
||||
or dev.startswith('vd')])
|
|
@ -0,0 +1,60 @@
|
|||
#
|
||||
# Copyright (C) 2022 Soleta Networks <info@soleta.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the
|
||||
# Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from subprocess import DEVNULL
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
def mount_mkdir(source, target):
|
||||
"""
|
||||
Mounts and creates the mountpoint directory if it's not present.
|
||||
"""
|
||||
if not os.path.exists(target):
|
||||
os.mkdir(target)
|
||||
if not os.path.ismount(target):
|
||||
return mount(source, target)
|
||||
return False
|
||||
|
||||
|
||||
def mount(source, target):
|
||||
"""
|
||||
Mounts source into target directoru using mount(8).
|
||||
|
||||
Return true if exit code is 0. False otherwise.
|
||||
"""
|
||||
cmd = f'mount {source} {target}'
|
||||
proc = subprocess.run(cmd.split(), stderr=DEVNULL)
|
||||
|
||||
return not proc.returncode
|
||||
|
||||
|
||||
def umount(target):
|
||||
"""
|
||||
Umounts target using umount(8).
|
||||
|
||||
Return true if exit code is 0. False otherwise.
|
||||
"""
|
||||
cmd = f'umount {target}'
|
||||
proc = subprocess.run(cmd.split(), stderr=DEVNULL)
|
||||
|
||||
return not proc.returncode
|
||||
|
||||
|
||||
def get_usedperc(mountpoint):
|
||||
"""
|
||||
Returns percetage of used filesystem as decimal number.
|
||||
"""
|
||||
try:
|
||||
total, used, free, perc = psutil.disk_usage(mountpoint)
|
||||
except FileNotFoundError:
|
||||
return '0'
|
||||
return str(perc)
|
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# Copyright (C) 2022 Soleta Networks <info@soleta.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the
|
||||
# Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
"""
|
||||
Utility module for ogBrowser menu generation
|
||||
"""
|
||||
|
||||
import os
|
||||
import socket
|
||||
|
||||
from src.utils.net import getifaddr, getifhwaddr, ethtool
|
||||
|
||||
MENU_TEMPLATE = """
|
||||
<div align="center" style="font-family: Arial, Helvetica, sans-serif;">
|
||||
<p style="color:#999999; font-size: 16px; margin: 2em;">
|
||||
<table border="1" width="100%">
|
||||
<tr>
|
||||
<td rowspan="2"><p align="left"><img border="0" src="../images/iconos/logoopengnsys.png"><p> </td>
|
||||
<td> Hostname </td> <td> IP </td> <td> MAC </td> <td> SPEED </td> </tr>
|
||||
<tr> <td>{hostname} </td> <td> {ip} </td> <td> {mac} </td> <td> {speed} </td> </tr>
|
||||
</table>
|
||||
</p>
|
||||
|
||||
{boot_list}
|
||||
|
||||
<p><a href="command:poweroff">Power Off</a></p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
MENU_OS_TEMPLATE = "<p><a href=\"command:bootOs {diskno} {partno}\">Boot {os} ({diskno}, {partno})</a></p>"
|
||||
|
||||
def generate_menu(part_setup):
|
||||
"""
|
||||
Writes html menu to /opt/opengnsys/log/{ip}.info.html based on a partition
|
||||
setup
|
||||
"""
|
||||
device = os.getenv('DEVICE')
|
||||
if not device:
|
||||
return False
|
||||
|
||||
ip = getifaddr(device)
|
||||
mac = getifhwaddr(device)
|
||||
speed = ethtool(device)
|
||||
hostname = socket.gethostname()
|
||||
menufile = f'/opt/opengnsys/log/{ip}.info.html'
|
||||
|
||||
l = [MENU_OS_TEMPLATE.format(diskno=part['disk'], partno=part['partition'], os=part['os'])
|
||||
for part in part_setup if part['os']]
|
||||
boot_list = '\n'.join(l)
|
||||
|
||||
with open(menufile, 'w') as f:
|
||||
f.write(MENU_TEMPLATE.format(hostname=hostname, ip=ip, mac=mac, speed=speed, boot_list=boot_list))
|
||||
return True
|
|
@ -0,0 +1,53 @@
|
|||
#
|
||||
# Copyright (C) 2022 Soleta Networks <info@soleta.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the
|
||||
# Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
import array
|
||||
import fcntl
|
||||
import socket
|
||||
import struct
|
||||
|
||||
def ethtool(interface):
|
||||
try:
|
||||
ETHTOOL_GSET = 0x00000001
|
||||
SIOCETHTOOL = 0x8946
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sockfd = sock.fileno()
|
||||
ecmd = array.array(
|
||||
"B", struct.pack("I39s", ETHTOOL_GSET, b"\x00" * 39)
|
||||
)
|
||||
interface = interface.encode("utf-8")
|
||||
ifreq = struct.pack("16sP", interface, ecmd.buffer_info()[0])
|
||||
fcntl.ioctl(sockfd, SIOCETHTOOL, ifreq)
|
||||
res = ecmd.tobytes()
|
||||
speed = struct.unpack("12xH29x", res)[0]
|
||||
except IOError:
|
||||
speed = 0
|
||||
finally:
|
||||
sock.close()
|
||||
return speed
|
||||
|
||||
def getifaddr(device):
|
||||
"""
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
return socket.inet_ntoa(fcntl.ioctl(
|
||||
s.fileno(),
|
||||
0x8915, # SIOCGIFADDR
|
||||
struct.pack('256s', bytes(device[:15], 'utf-8'))
|
||||
)[20:24])
|
||||
|
||||
def getifhwaddr(device):
|
||||
"""
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
hwaddr = fcntl.ioctl(
|
||||
s.fileno(),
|
||||
0x8927, # SIOCGIFHWADDR
|
||||
struct.pack('256s', bytes(device[:15], 'utf-8'))
|
||||
)[18:24]
|
||||
return "%02x:%02x:%02x:%02x:%02x:%02x" % struct.unpack("BBBBBB", hwaddr)
|
|
@ -0,0 +1,83 @@
|
|||
#
|
||||
# Copyright (C) 2022 Soleta Networks <info@soleta.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the
|
||||
# Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from subprocess import PIPE
|
||||
|
||||
def getlinuxversion(osrelease):
|
||||
"""
|
||||
Parses a os-release file to fetch 'PRETTY_NAME' key.
|
||||
If file or key are not found, then returns generic
|
||||
'Linux' string.
|
||||
"""
|
||||
with open(osrelease, 'r') as f:
|
||||
for line in f:
|
||||
if line.find('=') == -1:
|
||||
continue
|
||||
key, value = line.split('=')
|
||||
if key == 'PRETTY_NAME':
|
||||
value = value.replace('\n', '')
|
||||
value = value.strip('"')
|
||||
return value
|
||||
return 'Linux'
|
||||
|
||||
|
||||
def getwindowsversion(winreghives):
|
||||
"""
|
||||
Tries to obtain windows version information by
|
||||
querying the SOFTWARE registry hive. Registry
|
||||
hives path is a required parameter.
|
||||
|
||||
Runs hivexget(1) to fetch ProductName and
|
||||
ReleaseId. If something fails (hivexget is
|
||||
not installed, or registry is not found) it
|
||||
returns a generic "Microsoft Windows" string.
|
||||
"""
|
||||
|
||||
# XXX: 3.6 friendly
|
||||
try:
|
||||
proc_prodname = subprocess.run(['hivexget',
|
||||
f'{winreghives}/SOFTWARE',
|
||||
'microsoft\windows nt\currentversion',
|
||||
'ProductName'], stdout=PIPE)
|
||||
proc_releaseid = subprocess.run(['hivexget',
|
||||
f'{winreghives}/SOFTWARE',
|
||||
'microsoft\windows nt\currentversion',
|
||||
'ReleaseId'], stdout=PIPE)
|
||||
|
||||
proc_prodname = proc_releaseid.stdout.replace('\n', '')
|
||||
releaseid = proc_releaseid.stdout.replace('\n', '')
|
||||
|
||||
if proc_prodname.returncode == 0 and proc_releaseid.returncode == 0:
|
||||
return f'{prodname} {releaseid}'
|
||||
except FileNotFoundError: # hivexget command not found
|
||||
pass
|
||||
return 'Microsoft Windows'
|
||||
|
||||
|
||||
def os_probe(mountpoint):
|
||||
"""
|
||||
Probes mountpoint for typical OS dependant files.
|
||||
|
||||
Windows: Tries finding and querying the software
|
||||
registry hive.
|
||||
Linux: Looks for /etc/os-release file.
|
||||
|
||||
Returns a string depending on the OS it detects.
|
||||
"""
|
||||
winreghives = f'{mountpoint}Windows/System32/config'
|
||||
osrelease = f'{mountpoint}/etc/os-release'
|
||||
|
||||
if os.path.exists(osrelease):
|
||||
return getlinuxversion(osrelease)
|
||||
elif os.path.exists(winreghives):
|
||||
return getwindowsversion(winreghives)
|
||||
else:
|
||||
return ''
|
Loading…
Reference in New Issue