Python-way pentru un cal bătrân

Salut,

Cum probabil mulţi dintre voi aţi păţit, aterizând din senin într-un teritoriu necunoscut încercăm să ne descurcăm folosind deprinderile dobândite anterior, deseori în mod impropriu. În secţiunea asta o să-i rog pe cei experimentaţi cu Python să mă ghideze cum să fac corect anumite lucruri care nu funcţionează cum intuiesc că ar trebui să funcţioneze. Ştiu, RTFM, dar…

So, în acest moment m-am lovit de chestia asta, încerc să fac un array asociativ imbricat, cum eram obişnuit să fac în php/c++. Well, Python nu e de acord că aşa se face :slight_smile:

>>> blabla = {}
>>> blabla["x"]["y"] = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'x'

LE Nevemind, am inteles, trebuie initializat blabla["x"] prima data.

>>> blabla = {}
>>> blabla["x"] = {}
>>> blabla["x"]["y"] = 1
>>> print(blabla)
{'x': {'y': 1}}

sau aşa:

>>> blabla = { "x": {} }
>>> blabla["x"]["y"] = 1
>>> print(blabla)
{'x': {'y': 1}}

ar trebui sa poti initializa direct

blabla = { “x”: { “y”: 1 } }

Da, aia mi-am dat seama, că e la fel ca la JSON, problema e că valorile alea nu sunt disponibile încă, urmează să fi determinate.

Cam asta am făcut până acum, urmează să culeg multe alte chestii (parsez outputul de la dmidecode, sensors, mdadm etc).

import subprocess

def run(cmd):
    result = subprocess.run(cmd, capture_output=True, universal_newlines=True)
    return result.stdout.splitlines()

info = { 
    "storage": {} 
}

#### STORAGE
info["storage"]["avail"] = run(["df", "--output=avail", "/home"])[1]
    blabla = defaultdict(dict)
    blabla["x"]["y"] = 1
2 Likes

Well, uite chestia cu defaultdict mi-ar fi scăpat indiferent câte manuale aş fi citit :slight_smile: Este exact ce aveam nevoie:

defaultdict dict subclass that calls a factory function to supply missing values

Cam asta a rezultat în urma eforturilor mele de a descâlci meandrele Python-ului :slight_smile: Scriptul e rulat ca serviciu de systemd şi outputul citit de pe o maşină remote de phpstream_socket_client(). Ceva idei de pythonizare pentru a simplifica codul?

#!/usr/bin/python3

import json
import subprocess
import os.path

def run(cmd):
    result = subprocess.run(cmd, stdout=subprocess.PIPE, universal_newlines=True)
    return result.stdout.splitlines()

def read(path):
    file = open(path, mode="r")
    result = file.read()
    file.close()
    return result.splitlines()

def smart(dev):
    buffer = run(["smartctl", "-a", dev])

    prop_fields = {
        "Model Family:": "Model Family",
        "Device Model:": "Device Model",
        "Serial Number:": "Serial Number",
        "Firmware Version:": "Firmware Version",
        "User Capacity:": "Capacity",
        "Sector Sizes:": "Sector Sizes",
        "Rotation Rate:": "Rotation Rate",
        "Form Factor:": "Form Factor",
        "SATA Version is:": "SATA Version",
        "194 Temperature_Celsius": "Temperature",
        "  9 Power_On_Hours": "Power-On Hours",
        " 12 Power_Cycle_Count": "Power Cycle Count",
        "  4 Start_Stop_Count": "Start/Stop Count",
        " 10 Spin_Retry_Count": "Spin Retry Count",
        "  5 Reallocated_Sector_Ct": "Reallocated Sector Count",
        "199 UDMA_CRC_Error_Count": "UDMA CRC Error Count",
    }

    result = {
        "temp": 0,
        "props": []
    }

    for line in buffer:
        for key, label in prop_fields.items():
            if line.startswith(key):
                if ":" == key[-1]:
                    result["props"].append({ "label": label, "value": line.split(":", 1)[1].strip() })    
                else:
                    if "Temperature" == label:
                        result["temp"] = line.split()[9]
                    else:
                        result["props"].append({ "label": label, "value": line.split()[9] })
                break

    return result

info = {
    "storage": {
        "avail": {
        },
        "used": {
            "dirs": []
        },
        "raid": {
            "drives": []
        }
    }
}

#### STORAGE ####################################

#### available space
mb = run(["df", "-BM", "--output=avail", "/mnt/raid0"])[1]
info["storage"]["avail"] = round(int(mb[:-1]) / 1024, 1)

#### used space
buffer = read("/mnt/raid0/used_space.txt")

for line in buffer:
    size, path = line.split()

    size = round(int(size[:-1]) / 1024, 1)
    path = os.path.basename(path)

    if "bak-" != path[0:4]:
        continue

    info["storage"]["used"]["dirs"].append({"name": path, "size": size})

#### HDDs #######################################
mdadm = run(["mdadm", "--detail", "/dev/md0"])

state_pos = -1
for line in mdadm:
    #### drives section
    if state_pos != -1:
        dev_pos = line.find("/")
        if -1 != dev_pos:
            status = line[state_pos:dev_pos - 1].strip()
            dev = line[dev_pos:]
            smart_info = smart(dev)
            info["storage"]["raid"]["drives"].append(
                {
                    "dev": dev,
                    "status": status,
                    "temp": smart_info["temp"],  
                    "props": smart_info["props"] + [{"label": "RAID Status", "value": status}]
                }
            )
    else:
        state_pos = line.find("RaidDevice State")
        if state_pos != -1:
            state_pos += 11

#### OUTPUT JSON ################################
print(json.dumps(info, indent=4))

<?php

class SysInfo
{
	static function read($host)
	{
		$fd = stream_socket_client("tcp://$host", $errno, $errstr);
		stream_set_blocking($fd, false);

		$buf = "";
		for(;;)
		{
			$r = array($fd);
			$w  = $e = NULL;

			$status = stream_select($r, $w, $e, 5);

			if(feof($fd) || $status === false)
				break;

			$chunk = stream_get_contents($fd);
			$buf .= $chunk;
		}

		fclose($fd);

		return $buf;
	}
}

Json-ul rezultat:


{
    "storage": {
        "avail": 5892.6,
        "used": {
            "dirs": [
                {
                    "name": "bak-mainoffice-emailserver",
                    "size": 844.8
                },
                {
                    "name": "bak-mainoffice-fileserver",
                    "size": 654.6
                }
            ]
        },
        "raid": {
            "drives": [
                {
                    "dev": "/dev/sda1",
                    "status": "active sync",
                    "temp": "28",
                    "props": [
                        {
                            "label": "Model Family",
                            "value": "Seagate IronWolf"
                        },
                        {
                            "label": "Device Model",
                            "value": "ST8000VN004-2M2101"
                        },
                        {
                            "label": "Serial Number",
                            "value": "WKD199VQ"
                        },
                        {
                            "label": "Firmware Version",
                            "value": "SC60"
                        },
                        {
                            "label": "Capacity",
                            "value": "8,001,563,222,016 bytes [8.00 TB]"
                        },
                        {
                            "label": "Sector Sizes",
                            "value": "512 bytes logical, 4096 bytes physical"
                        },
                        {
                            "label": "Rotation Rate",
                            "value": "7200 rpm"
                        },
                        {
                            "label": "Form Factor",
                            "value": "3.5 inches"
                        },
                        {
                            "label": "SATA Version",
                            "value": "SATA 3.3, 6.0 Gb/s (current: 6.0 Gb/s)"
                        },
                        {
                            "label": "Start/Stop Count",
                            "value": "22"
                        },
                        {
                            "label": "Reallocated Sector Count",
                            "value": "0"
                        },
                        {
                            "label": "Power-On Hours",
                            "value": "604"
                        },
                        {
                            "label": "Spin Retry Count",
                            "value": "0"
                        },
                        {
                            "label": "Power Cycle Count",
                            "value": "23"
                        },
                        {
                            "label": "UDMA CRC Error Count",
                            "value": "0"
                        },
                        {
                            "label": "RAID Status",
                            "value": "active sync"
                        }
                    ]
                },
                {
                    "dev": "/dev/sdb1",
                    "status": "active sync",
                    "temp": "30",
                    "props": [
                        {
                            "label": "Model Family",
                            "value": "Seagate IronWolf"
                        },
                        {
                            "label": "Device Model",
                            "value": "ST8000VN004-2M2101"
                        },
                        {
                            "label": "Serial Number",
                            "value": "WKD19S5S"
                        },
                        {
                            "label": "Firmware Version",
                            "value": "SC60"
                        },
                        {
                            "label": "Capacity",
                            "value": "8,001,563,222,016 bytes [8.00 TB]"
                        },
                        {
                            "label": "Sector Sizes",
                            "value": "512 bytes logical, 4096 bytes physical"
                        },
                        {
                            "label": "Rotation Rate",
                            "value": "7200 rpm"
                        },
                        {
                            "label": "Form Factor",
                            "value": "3.5 inches"
                        },
                        {
                            "label": "SATA Version",
                            "value": "SATA 3.3, 6.0 Gb/s (current: 6.0 Gb/s)"
                        },
                        {
                            "label": "Start/Stop Count",
                            "value": "22"
                        },
                        {
                            "label": "Reallocated Sector Count",
                            "value": "0"
                        },
                        {
                            "label": "Power-On Hours",
                            "value": "604"
                        },
                        {
                            "label": "Spin Retry Count",
                            "value": "0"
                        },
                        {
                            "label": "Power Cycle Count",
                            "value": "23"
                        },
                        {
                            "label": "UDMA CRC Error Count",
                            "value": "0"
                        },
                        {
                            "label": "RAID Status",
                            "value": "active sync"
                        }
                    ]
                }
            ]
        }
    }
}

A rezultat chestia asta:

2 Likes

Citirea unui fisier: https://docs.python-guide.org/writing/style/#read-from-a-file

Metode alternative de a citi datele: https://github.com/prometheus/node_exporter/issues/473