forked from platypush/platypush
Added NetworkInterface
entities to system
plugin.
Plus, `platypush.schemas.system` has now been split into multiple submodules to avoid a single-file mega-module with all the system schemas definitions.
This commit is contained in:
parent
44b8fd4b34
commit
98a300c4b1
26 changed files with 1006 additions and 595 deletions
|
@ -0,0 +1,167 @@
|
|||
<template>
|
||||
<div class="entity network-interface-container">
|
||||
<div class="head" @click.stop="isCollapsed = !isCollapsed">
|
||||
<div class="col-1 icon">
|
||||
<EntityIcon
|
||||
:entity="value"
|
||||
:loading="loading"
|
||||
:error="error" />
|
||||
</div>
|
||||
|
||||
<div class="col-10 label">
|
||||
<div class="name" v-text="value.name" />
|
||||
</div>
|
||||
|
||||
<div class="col-1 collapse-toggler" @click.stop="isCollapsed = !isCollapsed">
|
||||
<i class="fas"
|
||||
:class="{'fa-chevron-down': isCollapsed, 'fa-chevron-up': !isCollapsed}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body children attributes fade-in" v-if="!isCollapsed">
|
||||
<div class="child" v-if="value.bytes_sent">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Bytes sent</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="convertSize(value.bytes_sent)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="child" v-if="value.bytes_recv">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Bytes received</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="convertSize(value.bytes_recv)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="child" v-if="value.packets_sent">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Packets sent</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="value.packets_sent" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="child" v-if="value.packets_recv">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Packets received</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="value.packets_recv" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="child" v-if="value.errors_in">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Inbound errors</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="value.errors_in" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="child" v-if="value.errors_out">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Outbound errors</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="value.errors_out" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="child" v-if="value.drop_in">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Dropped inbound packets</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="value.drop_in" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="child" v-if="value.drop_out">
|
||||
<div class="col-s-12 col-m-6 label">
|
||||
<div class="name">Dropped outbound packets</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="name" v-text="value.drop_out" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EntityMixin from "./EntityMixin"
|
||||
import EntityIcon from "./EntityIcon"
|
||||
|
||||
export default {
|
||||
name: 'NetworkInterface',
|
||||
components: {EntityIcon},
|
||||
mixins: [EntityMixin],
|
||||
|
||||
data() {
|
||||
return {
|
||||
isCollapsed: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "common";
|
||||
|
||||
.entity {
|
||||
.head {
|
||||
padding: 0.25em;
|
||||
|
||||
.icon {
|
||||
margin-right: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.collapse-toggler {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-height: 3em;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: $default-hover-fg;
|
||||
}
|
||||
}
|
||||
|
||||
.attributes .child {
|
||||
margin: 0 -0.5em;
|
||||
padding: 0.5em 1em;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $border-color-1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: bold;
|
||||
@include from($tablet) {
|
||||
@extend .col-m-6;
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 0.95em;
|
||||
text-align: right;
|
||||
|
||||
@include from($tablet) {
|
||||
@extend .col-m-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -71,6 +71,14 @@
|
|||
}
|
||||
},
|
||||
|
||||
"network_interface": {
|
||||
"name": "System",
|
||||
"name_plural": "System",
|
||||
"icon": {
|
||||
"class": "fas fa-ethernet"
|
||||
}
|
||||
},
|
||||
|
||||
"current_sensor": {
|
||||
"name": "Sensor",
|
||||
"name_plural": "Sensors",
|
||||
|
|
|
@ -175,3 +175,30 @@ if 'disk' not in Base.metadata:
|
|||
__mapper_args__ = {
|
||||
'polymorphic_identity': __tablename__,
|
||||
}
|
||||
|
||||
|
||||
if 'network_interface' not in Base.metadata:
|
||||
|
||||
class NetworkInterface(Entity):
|
||||
"""
|
||||
``NetworkInterface`` ORM model.
|
||||
"""
|
||||
|
||||
__tablename__ = 'network_interface'
|
||||
|
||||
id = Column(
|
||||
Integer, ForeignKey(Entity.id, ondelete='CASCADE'), primary_key=True
|
||||
)
|
||||
|
||||
bytes_sent = Column(Integer)
|
||||
bytes_recv = Column(Integer)
|
||||
packets_sent = Column(Integer)
|
||||
packets_recv = Column(Integer)
|
||||
errors_in = Column(Integer)
|
||||
errors_out = Column(Integer)
|
||||
drop_in = Column(Integer)
|
||||
drop_out = Column(Integer)
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': __tablename__,
|
||||
}
|
||||
|
|
|
@ -28,38 +28,6 @@ class SensorResponse(SystemResponse):
|
|||
pass
|
||||
|
||||
|
||||
class NetworkIoCountersResponse(NetworkResponse):
|
||||
def __init__(
|
||||
self,
|
||||
bytes_sent: int,
|
||||
bytes_recv: int,
|
||||
packets_sent: int,
|
||||
packets_recv: int,
|
||||
errin: int,
|
||||
errout: int,
|
||||
dropin: int,
|
||||
dropout: int,
|
||||
nic: Optional[str] = None,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
*args,
|
||||
output={
|
||||
'bytes_sent': bytes_sent,
|
||||
'bytes_recv': bytes_recv,
|
||||
'packets_sent': packets_sent,
|
||||
'packets_recv': packets_recv,
|
||||
'errin': errin,
|
||||
'errout': errout,
|
||||
'dropin': dropin,
|
||||
'dropout': dropout,
|
||||
'nic': nic,
|
||||
},
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class NetworkConnectionResponse(NetworkResponse):
|
||||
# noinspection PyShadowingBuiltins
|
||||
def __init__(
|
||||
|
|
|
@ -18,10 +18,10 @@ from platypush.entities.system import (
|
|||
CpuTimes as CpuTimesModel,
|
||||
Disk as DiskModel,
|
||||
MemoryStats as MemoryStatsModel,
|
||||
NetworkInterface as NetworkInterfaceModel,
|
||||
SwapStats as SwapStatsModel,
|
||||
)
|
||||
from platypush.message.response.system import (
|
||||
NetworkIoCountersResponse,
|
||||
NetworkResponseList,
|
||||
NetworkConnectionResponse,
|
||||
NetworkAddressResponse,
|
||||
|
@ -50,6 +50,8 @@ from platypush.schemas.system import (
|
|||
DiskSchema,
|
||||
MemoryStats,
|
||||
MemoryStatsSchema,
|
||||
NetworkInterface,
|
||||
NetworkInterfaceSchema,
|
||||
SwapStats,
|
||||
SwapStatsSchema,
|
||||
SystemInfoSchema,
|
||||
|
@ -257,47 +259,44 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
|||
"""
|
||||
return DiskSchema().dump(self._disk_info(), many=True)
|
||||
|
||||
def _net_io_counters(self) -> List[NetworkInterface]:
|
||||
return NetworkInterfaceSchema().load( # type: ignore
|
||||
[
|
||||
{'interface': interface, **stats._asdict()}
|
||||
for interface, stats in psutil.net_io_counters(pernic=True).items()
|
||||
if any(bool(val) for val in stats._asdict().values())
|
||||
],
|
||||
many=True,
|
||||
)
|
||||
|
||||
def _net_io_counters_avg(self) -> NetworkInterface:
|
||||
stats = psutil.net_io_counters(pernic=False)
|
||||
return NetworkInterfaceSchema().load( # type: ignore
|
||||
{
|
||||
'interface': None,
|
||||
**stats._asdict(),
|
||||
}
|
||||
)
|
||||
|
||||
@action
|
||||
def net_io_counters(
|
||||
self, nic: Optional[str] = None, per_nic: bool = False
|
||||
) -> Union[NetworkIoCountersResponse, NetworkResponseList]:
|
||||
def net_io_counters(self, per_nic: bool = False):
|
||||
"""
|
||||
Get the I/O counters stats for the network interfaces.
|
||||
Get the information and statistics for the network interfaces.
|
||||
|
||||
:param nic: Select the stats for a specific network device (e.g. 'eth0'). Default: get stats for all NICs.
|
||||
:param per_nic: Return the stats broken down per interface (default: False).
|
||||
:return: :class:`platypush.message.response.system.NetIoCountersResponse` or list of
|
||||
:class:`platypush.message.response.system.NetIoCountersResponse`.
|
||||
:param per_nic: Return the stats grouped by interface (default: False).
|
||||
:return: If ``per_nic=False``:
|
||||
|
||||
.. schema:: system.NetworkInterfaceSchema
|
||||
|
||||
If ``per_nic=True`` then a list will be returned, where each item
|
||||
identifies the statistics per network interface:
|
||||
|
||||
.. schema:: system.NetworkInterfaceSchema(many=True)
|
||||
"""
|
||||
|
||||
def _expand_response(_nic, _stats):
|
||||
return NetworkIoCountersResponse(
|
||||
bytes_sent=_stats.bytes_sent,
|
||||
bytes_recv=_stats.bytes_recv,
|
||||
packets_sent=_stats.packets_sent,
|
||||
packets_recv=_stats.packets_recv,
|
||||
errin=_stats.errin,
|
||||
errout=_stats.errout,
|
||||
dropin=_stats.dropin,
|
||||
dropout=_stats.dropout,
|
||||
nic=_nic,
|
||||
)
|
||||
|
||||
if nic:
|
||||
per_nic = True
|
||||
|
||||
io = psutil.net_io_counters(pernic=per_nic)
|
||||
if nic:
|
||||
stats = [d for name, d in io.items() if name == nic]
|
||||
assert stats, 'No such network interface: {}'.format(nic)
|
||||
return _expand_response(nic, stats[0])
|
||||
|
||||
if not per_nic:
|
||||
return _expand_response(nic, io)
|
||||
|
||||
return NetworkResponseList(
|
||||
[_expand_response(nic, stats) for nic, stats in io.items()]
|
||||
)
|
||||
if per_nic:
|
||||
return NetworkInterfaceSchema().dump(self._net_io_counters(), many=True)
|
||||
return NetworkInterfaceSchema().dump(self._net_io_counters_avg())
|
||||
|
||||
@action
|
||||
def net_connections(
|
||||
|
@ -688,6 +687,7 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
|||
'memory': self._mem_virtual(),
|
||||
'swap': self._mem_swap(),
|
||||
'disks': self._disk_info(),
|
||||
'network': self._net_io_counters(),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -772,6 +772,14 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
|||
)
|
||||
for disk in entities['disks']
|
||||
],
|
||||
*[
|
||||
NetworkInterfaceModel(
|
||||
id=f'system:network_interface:{nic["interface"]}',
|
||||
name=nic.pop('interface'),
|
||||
**nic,
|
||||
)
|
||||
for nic in entities['network']
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -1,522 +0,0 @@
|
|||
from dataclasses import dataclass, field
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from marshmallow import pre_load
|
||||
from marshmallow.validate import Range
|
||||
from marshmallow_dataclass import class_schema
|
||||
|
||||
from platypush.schemas.dataclasses import DataClassSchema
|
||||
|
||||
|
||||
def percent_field(**kwargs):
|
||||
"""
|
||||
Field used to model percentage float fields between 0 and 1.
|
||||
"""
|
||||
return field(
|
||||
default_factory=float,
|
||||
metadata={
|
||||
'validate': Range(min=0, max=1),
|
||||
**kwargs,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class CpuInfoBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for CPU info.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data: dict, **_) -> dict:
|
||||
if data.get('hz_advertised'):
|
||||
data['frequency_advertised'] = data.pop('hz_advertised')[0]
|
||||
if data.get('hz_actual'):
|
||||
data['frequency_actual'] = data.pop('hz_actual')[0]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class MemoryStatsBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for memory stats.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data: dict, **_) -> dict:
|
||||
# Normalize the percentage between 0 and 1
|
||||
if data.get('percent') is not None:
|
||||
data['percent'] /= 100
|
||||
return data
|
||||
|
||||
|
||||
class CpuTimesBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for CPU times.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data, **_) -> dict:
|
||||
"""
|
||||
Convert the underlying object to dict and normalize all the percentage
|
||||
values from [0, 100] to [0, 1].
|
||||
"""
|
||||
return {
|
||||
key: value / 100.0
|
||||
for key, value in (
|
||||
data if isinstance(data, dict) else data._asdict()
|
||||
).items()
|
||||
}
|
||||
|
||||
|
||||
class DiskBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for disk stats.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data: dict, **_) -> dict:
|
||||
# Convert read/write/busy times from milliseconds to seconds
|
||||
for attr in ['read_time', 'write_time', 'busy_time']:
|
||||
if data.get(attr) is not None:
|
||||
data[attr] /= 1000
|
||||
|
||||
# Normalize the percentage between 0 and 1
|
||||
if data.get('percent') is not None:
|
||||
data['percent'] /= 100
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuInfo:
|
||||
"""
|
||||
CPU info data class.
|
||||
"""
|
||||
|
||||
architecture: Optional[str] = field(
|
||||
metadata={
|
||||
'data_key': 'arch_string_raw',
|
||||
'metadata': {
|
||||
'description': 'CPU architecture',
|
||||
'example': 'x86_64',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
bits: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'CPU bits / register size',
|
||||
'example': 64,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
cores: int = field(
|
||||
metadata={
|
||||
'data_key': 'count',
|
||||
'metadata': {
|
||||
'description': 'Number of cores',
|
||||
'example': 4,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
vendor: Optional[str] = field(
|
||||
metadata={
|
||||
'data_key': 'vendor_id_raw',
|
||||
'metadata': {
|
||||
'description': 'Vendor string',
|
||||
'example': 'GenuineIntel',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
brand: Optional[str] = field(
|
||||
metadata={
|
||||
'data_key': 'brand_raw',
|
||||
'metadata': {
|
||||
'description': 'CPU brand string',
|
||||
'example': 'Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
frequency_advertised: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Advertised CPU frequency, in Hz',
|
||||
'example': 2400000000,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
frequency_actual: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Actual CPU frequency, in Hz',
|
||||
'example': 2350000000,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
flags: List[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'CPU flags',
|
||||
'example': ['acpi', 'aes', 'cpuid'],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l1_instruction_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L1 instruction cache, in bytes',
|
||||
'example': 65536,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l1_data_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L1 data cache, in bytes',
|
||||
'example': 65536,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l2_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L2 cache, in bytes',
|
||||
'example': 524288,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l3_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L2 cache, in bytes',
|
||||
'example': 4194304,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuTimes:
|
||||
"""
|
||||
CPU times data class.
|
||||
"""
|
||||
|
||||
user: Optional[float] = percent_field()
|
||||
nice: Optional[float] = percent_field()
|
||||
system: Optional[float] = percent_field()
|
||||
idle: Optional[float] = percent_field()
|
||||
iowait: Optional[float] = percent_field()
|
||||
irq: Optional[float] = percent_field()
|
||||
softirq: Optional[float] = percent_field()
|
||||
steal: Optional[float] = percent_field()
|
||||
guest: Optional[float] = percent_field()
|
||||
guest_nice: Optional[float] = percent_field()
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuStats:
|
||||
"""
|
||||
CPU stats data class.
|
||||
"""
|
||||
|
||||
ctx_switches: int
|
||||
interrupts: int
|
||||
soft_interrupts: int
|
||||
syscalls: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuFrequency:
|
||||
"""
|
||||
CPU frequency data class.
|
||||
"""
|
||||
|
||||
current: float
|
||||
min: float
|
||||
max: float
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuData:
|
||||
"""
|
||||
CPU data aggregate dataclass.
|
||||
"""
|
||||
|
||||
info: CpuInfo
|
||||
times: CpuTimes
|
||||
frequency: CpuFrequency
|
||||
stats: CpuStats
|
||||
load_avg: Tuple[float, float, float]
|
||||
percent: float = percent_field()
|
||||
|
||||
|
||||
@dataclass
|
||||
class MemoryStats:
|
||||
"""
|
||||
Memory stats data class.
|
||||
"""
|
||||
|
||||
total: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total available memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
available: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Available memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
used: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Used memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
free: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Free memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
active: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the active memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
inactive: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the inactive memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
buffers: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the buffered memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
cached: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the cached memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
shared: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the shared memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
percent: float = percent_field()
|
||||
|
||||
|
||||
@dataclass
|
||||
class SwapStats:
|
||||
"""
|
||||
Swap memory stats data class.
|
||||
"""
|
||||
|
||||
total: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total available memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
used: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Used memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
free: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Free memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
percent: float = percent_field()
|
||||
|
||||
|
||||
@dataclass
|
||||
class Disk:
|
||||
"""
|
||||
Disk data class.
|
||||
"""
|
||||
|
||||
device: str = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Path/identifier of the disk/partition',
|
||||
'example': '/dev/sda1',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
mountpoint: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Where the disk is mounted',
|
||||
'example': '/home',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
fstype: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Filesystem type',
|
||||
'example': 'ext4',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
opts: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Extra mount options passed to the partition',
|
||||
'example': 'rw,relatime,fmask=0022,dmask=0022,utf8',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
total: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total available space, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
used: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Used disk space, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
free: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Free disk space, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
read_count: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of recorded read operations',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
write_count: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of recorded write operations',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
read_bytes: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of read bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
write_bytes: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of written bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
read_time: float = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Time spent reading, in seconds',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
write_time: float = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Time spent writing, in seconds',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
busy_time: float = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total disk busy time, in seconds',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
percent: float = percent_field()
|
||||
|
||||
|
||||
@dataclass
|
||||
class SystemInfo:
|
||||
"""
|
||||
Aggregate system info dataclass.
|
||||
"""
|
||||
|
||||
cpu: CpuData
|
||||
memory: MemoryStats
|
||||
swap: SwapStats
|
||||
disks: List[Disk]
|
||||
|
||||
|
||||
CpuFrequencySchema = class_schema(CpuFrequency, base_schema=DataClassSchema)
|
||||
CpuInfoSchema = class_schema(CpuInfo, base_schema=CpuInfoBaseSchema)
|
||||
CpuTimesSchema = class_schema(CpuTimes, base_schema=CpuTimesBaseSchema)
|
||||
CpuStatsSchema = class_schema(CpuStats, base_schema=DataClassSchema)
|
||||
DiskSchema = class_schema(Disk, base_schema=DiskBaseSchema)
|
||||
MemoryStatsSchema = class_schema(MemoryStats, base_schema=MemoryStatsBaseSchema)
|
||||
SwapStatsSchema = class_schema(SwapStats, base_schema=MemoryStatsBaseSchema)
|
||||
SystemInfoSchema = class_schema(SystemInfo, base_schema=DataClassSchema)
|
39
platypush/schemas/system/__init__.py
Normal file
39
platypush/schemas/system/__init__.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from ._cpu import (
|
||||
Cpu,
|
||||
CpuFrequency,
|
||||
CpuFrequencySchema,
|
||||
CpuInfo,
|
||||
CpuInfoSchema,
|
||||
CpuStats,
|
||||
CpuStatsSchema,
|
||||
CpuTimes,
|
||||
CpuTimesSchema,
|
||||
)
|
||||
from ._disk import Disk, DiskSchema
|
||||
from ._memory import MemoryStats, MemoryStatsSchema, SwapStats, SwapStatsSchema
|
||||
from ._model import SystemInfo
|
||||
from ._network import NetworkInterface, NetworkInterfaceSchema
|
||||
from ._schemas import SystemInfoSchema
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Cpu",
|
||||
"CpuFrequency",
|
||||
"CpuFrequencySchema",
|
||||
"CpuInfo",
|
||||
"CpuInfoSchema",
|
||||
"CpuStats",
|
||||
"CpuStatsSchema",
|
||||
"CpuTimes",
|
||||
"CpuTimesSchema",
|
||||
"Disk",
|
||||
"DiskSchema",
|
||||
"MemoryStats",
|
||||
"MemoryStatsSchema",
|
||||
"SwapStats",
|
||||
"SwapStatsSchema",
|
||||
"NetworkInterface",
|
||||
"NetworkInterfaceSchema",
|
||||
"SystemInfo",
|
||||
"SystemInfoSchema",
|
||||
]
|
16
platypush/schemas/system/_base.py
Normal file
16
platypush/schemas/system/_base.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from dataclasses import field
|
||||
|
||||
from marshmallow.validate import Range
|
||||
|
||||
|
||||
def percent_field(**kwargs):
|
||||
"""
|
||||
Field used to model percentage float fields between 0 and 1.
|
||||
"""
|
||||
return field(
|
||||
default_factory=float,
|
||||
metadata={
|
||||
'validate': Range(min=0, max=1),
|
||||
**kwargs,
|
||||
},
|
||||
)
|
15
platypush/schemas/system/_cpu/__init__.py
Normal file
15
platypush/schemas/system/_cpu/__init__.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from ._model import Cpu, CpuFrequency, CpuInfo, CpuStats, CpuTimes
|
||||
from ._schemas import CpuFrequencySchema, CpuInfoSchema, CpuStatsSchema, CpuTimesSchema
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Cpu",
|
||||
"CpuFrequency",
|
||||
"CpuFrequencySchema",
|
||||
"CpuInfo",
|
||||
"CpuInfoSchema",
|
||||
"CpuStats",
|
||||
"CpuStatsSchema",
|
||||
"CpuTimes",
|
||||
"CpuTimesSchema",
|
||||
]
|
37
platypush/schemas/system/_cpu/_base.py
Normal file
37
platypush/schemas/system/_cpu/_base.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
from marshmallow import pre_load
|
||||
|
||||
from platypush.schemas.dataclasses import DataClassSchema
|
||||
|
||||
|
||||
class CpuInfoBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for CPU info.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data: dict, **_) -> dict:
|
||||
if data.get('hz_advertised'):
|
||||
data['frequency_advertised'] = data.pop('hz_advertised')[0]
|
||||
if data.get('hz_actual'):
|
||||
data['frequency_actual'] = data.pop('hz_actual')[0]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class CpuTimesBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for CPU times.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data, **_) -> dict:
|
||||
"""
|
||||
Convert the underlying object to dict and normalize all the percentage
|
||||
values from [0, 100] to [0, 1].
|
||||
"""
|
||||
return {
|
||||
key: value / 100.0
|
||||
for key, value in (
|
||||
data if isinstance(data, dict) else data._asdict()
|
||||
).items()
|
||||
}
|
178
platypush/schemas/system/_cpu/_model.py
Normal file
178
platypush/schemas/system/_cpu/_model.py
Normal file
|
@ -0,0 +1,178 @@
|
|||
from dataclasses import dataclass, field
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from .._base import percent_field
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuInfo:
|
||||
"""
|
||||
CPU info data class.
|
||||
"""
|
||||
|
||||
architecture: Optional[str] = field(
|
||||
metadata={
|
||||
'data_key': 'arch_string_raw',
|
||||
'metadata': {
|
||||
'description': 'CPU architecture',
|
||||
'example': 'x86_64',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
bits: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'CPU bits / register size',
|
||||
'example': 64,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
cores: int = field(
|
||||
metadata={
|
||||
'data_key': 'count',
|
||||
'metadata': {
|
||||
'description': 'Number of cores',
|
||||
'example': 4,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
vendor: Optional[str] = field(
|
||||
metadata={
|
||||
'data_key': 'vendor_id_raw',
|
||||
'metadata': {
|
||||
'description': 'Vendor string',
|
||||
'example': 'GenuineIntel',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
brand: Optional[str] = field(
|
||||
metadata={
|
||||
'data_key': 'brand_raw',
|
||||
'metadata': {
|
||||
'description': 'CPU brand string',
|
||||
'example': 'Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
frequency_advertised: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Advertised CPU frequency, in Hz',
|
||||
'example': 2400000000,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
frequency_actual: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Actual CPU frequency, in Hz',
|
||||
'example': 2350000000,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
flags: List[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'CPU flags',
|
||||
'example': ['acpi', 'aes', 'cpuid'],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l1_instruction_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L1 instruction cache, in bytes',
|
||||
'example': 65536,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l1_data_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L1 data cache, in bytes',
|
||||
'example': 65536,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l2_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L2 cache, in bytes',
|
||||
'example': 524288,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
l3_cache_size: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the L2 cache, in bytes',
|
||||
'example': 4194304,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuTimes:
|
||||
"""
|
||||
CPU times data class.
|
||||
"""
|
||||
|
||||
user: Optional[float] = percent_field()
|
||||
nice: Optional[float] = percent_field()
|
||||
system: Optional[float] = percent_field()
|
||||
idle: Optional[float] = percent_field()
|
||||
iowait: Optional[float] = percent_field()
|
||||
irq: Optional[float] = percent_field()
|
||||
softirq: Optional[float] = percent_field()
|
||||
steal: Optional[float] = percent_field()
|
||||
guest: Optional[float] = percent_field()
|
||||
guest_nice: Optional[float] = percent_field()
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuStats:
|
||||
"""
|
||||
CPU stats data class.
|
||||
"""
|
||||
|
||||
ctx_switches: int
|
||||
interrupts: int
|
||||
soft_interrupts: int
|
||||
syscalls: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class CpuFrequency:
|
||||
"""
|
||||
CPU frequency data class.
|
||||
"""
|
||||
|
||||
current: float
|
||||
min: float
|
||||
max: float
|
||||
|
||||
|
||||
@dataclass
|
||||
class Cpu:
|
||||
"""
|
||||
CPU data aggregate dataclass.
|
||||
"""
|
||||
|
||||
info: CpuInfo
|
||||
times: CpuTimes
|
||||
frequency: CpuFrequency
|
||||
stats: CpuStats
|
||||
load_avg: Tuple[float, float, float]
|
||||
percent: float = percent_field()
|
12
platypush/schemas/system/_cpu/_schemas.py
Normal file
12
platypush/schemas/system/_cpu/_schemas.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from marshmallow_dataclass import class_schema
|
||||
|
||||
from platypush.schemas.dataclasses import DataClassSchema
|
||||
|
||||
from ._base import CpuInfoBaseSchema, CpuTimesBaseSchema
|
||||
from ._model import CpuFrequency, CpuInfo, CpuStats, CpuTimes
|
||||
|
||||
|
||||
CpuFrequencySchema = class_schema(CpuFrequency, base_schema=DataClassSchema)
|
||||
CpuInfoSchema = class_schema(CpuInfo, base_schema=CpuInfoBaseSchema)
|
||||
CpuTimesSchema = class_schema(CpuTimes, base_schema=CpuTimesBaseSchema)
|
||||
CpuStatsSchema = class_schema(CpuStats, base_schema=DataClassSchema)
|
5
platypush/schemas/system/_disk/__init__.py
Normal file
5
platypush/schemas/system/_disk/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from ._model import Disk
|
||||
from ._schemas import DiskSchema
|
||||
|
||||
|
||||
__all__ = ["Disk", "DiskSchema"]
|
22
platypush/schemas/system/_disk/_base.py
Normal file
22
platypush/schemas/system/_disk/_base.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from marshmallow import pre_load
|
||||
|
||||
from platypush.schemas.dataclasses import DataClassSchema
|
||||
|
||||
|
||||
class DiskBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for disk stats.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data: dict, **_) -> dict:
|
||||
# Convert read/write/busy times from milliseconds to seconds
|
||||
for attr in ['read_time', 'write_time', 'busy_time']:
|
||||
if data.get(attr) is not None:
|
||||
data[attr] /= 1000
|
||||
|
||||
# Normalize the percentage between 0 and 1
|
||||
if data.get('percent') is not None:
|
||||
data['percent'] /= 100
|
||||
|
||||
return data
|
129
platypush/schemas/system/_disk/_model.py
Normal file
129
platypush/schemas/system/_disk/_model.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
from .._base import percent_field
|
||||
|
||||
|
||||
@dataclass
|
||||
class Disk:
|
||||
"""
|
||||
Disk data class.
|
||||
"""
|
||||
|
||||
device: str = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Path/identifier of the disk/partition',
|
||||
'example': '/dev/sda1',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
mountpoint: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Where the disk is mounted',
|
||||
'example': '/home',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
fstype: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Filesystem type',
|
||||
'example': 'ext4',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
opts: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Extra mount options passed to the partition',
|
||||
'example': 'rw,relatime,fmask=0022,dmask=0022,utf8',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
total: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total available space, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
used: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Used disk space, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
free: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Free disk space, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
read_count: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of recorded read operations',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
write_count: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of recorded write operations',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
read_bytes: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of read bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
write_bytes: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of written bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
read_time: float = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Time spent reading, in seconds',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
write_time: float = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Time spent writing, in seconds',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
busy_time: float = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total disk busy time, in seconds',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
percent: float = percent_field()
|
7
platypush/schemas/system/_disk/_schemas.py
Normal file
7
platypush/schemas/system/_disk/_schemas.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from marshmallow_dataclass import class_schema
|
||||
|
||||
from ._base import DiskBaseSchema
|
||||
from ._model import Disk
|
||||
|
||||
|
||||
DiskSchema = class_schema(Disk, base_schema=DiskBaseSchema)
|
5
platypush/schemas/system/_memory/__init__.py
Normal file
5
platypush/schemas/system/_memory/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from ._model import MemoryStats, SwapStats
|
||||
from ._schemas import MemoryStatsSchema, SwapStatsSchema
|
||||
|
||||
|
||||
__all__ = ["MemoryStats", "MemoryStatsSchema", "SwapStats", "SwapStatsSchema"]
|
16
platypush/schemas/system/_memory/_base.py
Normal file
16
platypush/schemas/system/_memory/_base.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from marshmallow import pre_load
|
||||
|
||||
from platypush.schemas.dataclasses import DataClassSchema
|
||||
|
||||
|
||||
class MemoryStatsBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for memory stats.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data: dict, **_) -> dict:
|
||||
# Normalize the percentage between 0 and 1
|
||||
if data.get('percent') is not None:
|
||||
data['percent'] /= 100
|
||||
return data
|
117
platypush/schemas/system/_memory/_model.py
Normal file
117
platypush/schemas/system/_memory/_model.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
from dataclasses import dataclass, field
|
||||
|
||||
from .._base import percent_field
|
||||
|
||||
|
||||
@dataclass
|
||||
class MemoryStats:
|
||||
"""
|
||||
Memory stats data class.
|
||||
"""
|
||||
|
||||
total: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total available memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
available: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Available memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
used: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Used memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
free: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Free memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
active: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the active memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
inactive: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the inactive memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
buffers: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the buffered memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
cached: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the cached memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
shared: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Size of the shared memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
percent: float = percent_field()
|
||||
|
||||
|
||||
@dataclass
|
||||
class SwapStats:
|
||||
"""
|
||||
Swap memory stats data class.
|
||||
"""
|
||||
|
||||
total: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Total available memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
used: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Used memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
free: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Free memory, in bytes',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
percent: float = percent_field()
|
8
platypush/schemas/system/_memory/_schemas.py
Normal file
8
platypush/schemas/system/_memory/_schemas.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from marshmallow_dataclass import class_schema
|
||||
|
||||
from ._base import MemoryStatsBaseSchema
|
||||
from ._model import MemoryStats, SwapStats
|
||||
|
||||
|
||||
MemoryStatsSchema = class_schema(MemoryStats, base_schema=MemoryStatsBaseSchema)
|
||||
SwapStatsSchema = class_schema(SwapStats, base_schema=MemoryStatsBaseSchema)
|
20
platypush/schemas/system/_model.py
Normal file
20
platypush/schemas/system/_model.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
from ._cpu import Cpu
|
||||
from ._disk import Disk
|
||||
from ._memory import MemoryStats, SwapStats
|
||||
from ._network import NetworkInterface
|
||||
|
||||
|
||||
@dataclass
|
||||
class SystemInfo:
|
||||
"""
|
||||
Aggregate system info dataclass.
|
||||
"""
|
||||
|
||||
cpu: Cpu
|
||||
memory: MemoryStats
|
||||
swap: SwapStats
|
||||
disks: List[Disk]
|
||||
network: List[NetworkInterface]
|
8
platypush/schemas/system/_network/__init__.py
Normal file
8
platypush/schemas/system/_network/__init__.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from ._model import NetworkInterface
|
||||
from ._schemas import NetworkInterfaceSchema
|
||||
|
||||
|
||||
__all__ = [
|
||||
"NetworkInterface",
|
||||
"NetworkInterfaceSchema",
|
||||
]
|
22
platypush/schemas/system/_network/_base.py
Normal file
22
platypush/schemas/system/_network/_base.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from marshmallow import pre_load
|
||||
|
||||
from platypush.schemas.dataclasses import DataClassSchema
|
||||
|
||||
|
||||
class NetworkInterfaceBaseSchema(DataClassSchema):
|
||||
"""
|
||||
Base schema for network interface stats.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data: dict, **_) -> dict:
|
||||
for in_attr, out_attr in {
|
||||
'errin': 'errors_in',
|
||||
'errout': 'errors_out',
|
||||
'dropin': 'drop_in',
|
||||
'dropout': 'drop_out',
|
||||
}.items():
|
||||
if in_attr in data:
|
||||
data[out_attr] = data.pop(in_attr)
|
||||
|
||||
return data
|
82
platypush/schemas/system/_network/_model.py
Normal file
82
platypush/schemas/system/_network/_model.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class NetworkInterface:
|
||||
"""
|
||||
Network interface statistics data class.
|
||||
"""
|
||||
|
||||
interface: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Network interface identifier',
|
||||
'example': 'eth0',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
bytes_sent: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of bytes sent',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
bytes_recv: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of bytes received',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
packets_sent: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of packets sent',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
packets_recv: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of packets received',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
errors_in: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of errors on incoming traffic',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
errors_out: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of errors on outgoing traffic',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
drop_in: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of packets dropped on incoming traffic',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
drop_out: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Number of packets dropped on outgoing traffic',
|
||||
},
|
||||
}
|
||||
)
|
9
platypush/schemas/system/_network/_schemas.py
Normal file
9
platypush/schemas/system/_network/_schemas.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from marshmallow_dataclass import class_schema
|
||||
|
||||
from ._base import NetworkInterfaceBaseSchema
|
||||
from ._model import NetworkInterface
|
||||
|
||||
|
||||
NetworkInterfaceSchema = class_schema(
|
||||
NetworkInterface, base_schema=NetworkInterfaceBaseSchema
|
||||
)
|
8
platypush/schemas/system/_schemas.py
Normal file
8
platypush/schemas/system/_schemas.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from marshmallow_dataclass import class_schema
|
||||
|
||||
from platypush.schemas.dataclasses import DataClassSchema
|
||||
|
||||
from ._model import SystemInfo
|
||||
|
||||
|
||||
SystemInfoSchema = class_schema(SystemInfo, base_schema=DataClassSchema)
|
Loading…
Reference in a new issue