forked from platypush/platypush
Merged network_stats
into NetworkInterface
model.
This commit is contained in:
parent
f4036be52b
commit
374f936c1f
6 changed files with 106 additions and 66 deletions
|
@ -91,6 +91,33 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="child" v-if="value.speed">
|
||||||
|
<div class="col-s-12 col-m-6 label">
|
||||||
|
<div class="name">Speed</div>
|
||||||
|
</div>
|
||||||
|
<div class="value">
|
||||||
|
<div class="name" v-text="value.speed + ' Mbps'" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="child" v-if="value.mtu">
|
||||||
|
<div class="col-s-12 col-m-6 label">
|
||||||
|
<div class="name">MTU</div>
|
||||||
|
</div>
|
||||||
|
<div class="value">
|
||||||
|
<div class="name" v-text="value.mtu" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="child" v-if="value.flags?.length">
|
||||||
|
<div class="col-s-12 col-m-6 label">
|
||||||
|
<div class="name">Flags</div>
|
||||||
|
</div>
|
||||||
|
<div class="value">
|
||||||
|
<div class="name" v-text="value.flags.join(', ')" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="child head" :class="{expanded: !areAddressesCollapsed}"
|
<div class="child head" :class="{expanded: !areAddressesCollapsed}"
|
||||||
@click.stop="areAddressesCollapsed = !areAddressesCollapsed">
|
@click.stop="areAddressesCollapsed = !areAddressesCollapsed">
|
||||||
<div class="col-11 label">Addresses</div>
|
<div class="col-11 label">Addresses</div>
|
||||||
|
|
|
@ -3,6 +3,7 @@ from sqlalchemy import Column, Float, ForeignKey, Integer, JSON, String
|
||||||
from platypush.common.db import Base
|
from platypush.common.db import Base
|
||||||
|
|
||||||
from . import Entity
|
from . import Entity
|
||||||
|
from .devices import Device
|
||||||
|
|
||||||
|
|
||||||
if 'cpu' not in Base.metadata:
|
if 'cpu' not in Base.metadata:
|
||||||
|
@ -179,7 +180,7 @@ if 'disk' not in Base.metadata:
|
||||||
|
|
||||||
if 'network_interface' not in Base.metadata:
|
if 'network_interface' not in Base.metadata:
|
||||||
|
|
||||||
class NetworkInterface(Entity):
|
class NetworkInterface(Device):
|
||||||
"""
|
"""
|
||||||
``NetworkInterface`` ORM model.
|
``NetworkInterface`` ORM model.
|
||||||
"""
|
"""
|
||||||
|
@ -187,7 +188,7 @@ if 'network_interface' not in Base.metadata:
|
||||||
__tablename__ = 'network_interface'
|
__tablename__ = 'network_interface'
|
||||||
|
|
||||||
id = Column(
|
id = Column(
|
||||||
Integer, ForeignKey(Entity.id, ondelete='CASCADE'), primary_key=True
|
Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True
|
||||||
)
|
)
|
||||||
|
|
||||||
bytes_sent = Column(Integer)
|
bytes_sent = Column(Integer)
|
||||||
|
@ -199,6 +200,10 @@ if 'network_interface' not in Base.metadata:
|
||||||
drop_in = Column(Integer)
|
drop_in = Column(Integer)
|
||||||
drop_out = Column(Integer)
|
drop_out = Column(Integer)
|
||||||
addresses = Column(JSON)
|
addresses = Column(JSON)
|
||||||
|
speed = Column(Integer)
|
||||||
|
mtu = Column(Integer)
|
||||||
|
duplex = Column(String)
|
||||||
|
flags = Column(JSON)
|
||||||
|
|
||||||
__mapper_args__ = {
|
__mapper_args__ = {
|
||||||
'polymorphic_identity': __tablename__,
|
'polymorphic_identity': __tablename__,
|
||||||
|
|
|
@ -28,23 +28,6 @@ class SensorResponse(SystemResponse):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NetworkInterfaceStatsResponse(NetworkResponse):
|
|
||||||
def __init__(
|
|
||||||
self, nic: str, is_up: bool, duplex: str, speed: int, mtu: int, *args, **kwargs
|
|
||||||
):
|
|
||||||
super().__init__(
|
|
||||||
*args,
|
|
||||||
output={
|
|
||||||
'nic': nic,
|
|
||||||
'is_up': is_up,
|
|
||||||
'duplex': duplex,
|
|
||||||
'speed': speed,
|
|
||||||
'mtu': mtu,
|
|
||||||
},
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SensorTemperatureResponse(SensorResponse):
|
class SensorTemperatureResponse(SensorResponse):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -184,11 +167,6 @@ class SystemResponseList(SystemResponse):
|
||||||
super().__init__(output=[r.output for r in responses], *args, **kwargs)
|
super().__init__(output=[r.output for r in responses], *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class NetworkResponseList(NetworkResponse, SystemResponseList):
|
|
||||||
def __init__(self, responses: List[NetworkResponse], *args, **kwargs):
|
|
||||||
super().__init__(responses=responses, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class SensorResponseList(SensorResponse, SystemResponseList):
|
class SensorResponseList(SensorResponse, SystemResponseList):
|
||||||
def __init__(self, responses: List[SensorResponse], *args, **kwargs):
|
def __init__(self, responses: List[SensorResponse], *args, **kwargs):
|
||||||
super().__init__(responses=responses, *args, **kwargs)
|
super().__init__(responses=responses, *args, **kwargs)
|
||||||
|
|
|
@ -21,8 +21,6 @@ from platypush.entities.system import (
|
||||||
SwapStats as SwapStatsModel,
|
SwapStats as SwapStatsModel,
|
||||||
)
|
)
|
||||||
from platypush.message.response.system import (
|
from platypush.message.response.system import (
|
||||||
NetworkResponseList,
|
|
||||||
NetworkInterfaceStatsResponse,
|
|
||||||
SensorTemperatureResponse,
|
SensorTemperatureResponse,
|
||||||
SensorResponseList,
|
SensorResponseList,
|
||||||
SensorFanResponse,
|
SensorFanResponse,
|
||||||
|
@ -256,15 +254,18 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
|
|
||||||
def _network_info(self) -> List[NetworkInterface]:
|
def _network_info(self) -> List[NetworkInterface]:
|
||||||
addrs = psutil.net_if_addrs()
|
addrs = psutil.net_if_addrs()
|
||||||
|
stats = psutil.net_if_stats()
|
||||||
|
|
||||||
return NetworkInterfaceSchema().load( # type: ignore
|
return NetworkInterfaceSchema().load( # type: ignore
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
'interface': interface,
|
'interface': interface,
|
||||||
'addresses': addrs.get(interface, []),
|
'addresses': addrs.get(interface, []),
|
||||||
**stats._asdict(),
|
**(stats[interface]._asdict() if stats.get(interface) else {}),
|
||||||
|
**info._asdict(),
|
||||||
}
|
}
|
||||||
for interface, stats in psutil.net_io_counters(pernic=True).items()
|
for interface, info in psutil.net_io_counters(pernic=True).items()
|
||||||
if any(bool(val) for val in stats._asdict().values())
|
if any(bool(val) for val in info._asdict().values())
|
||||||
],
|
],
|
||||||
many=True,
|
many=True,
|
||||||
)
|
)
|
||||||
|
@ -331,37 +332,6 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
many=True,
|
many=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@action
|
|
||||||
def net_stats(
|
|
||||||
self, nic: Optional[str] = None
|
|
||||||
) -> Union[NetworkInterfaceStatsResponse, NetworkResponseList]:
|
|
||||||
"""
|
|
||||||
Get stats about the network interfaces.
|
|
||||||
|
|
||||||
:param nic: Select the stats for a specific network device (e.g. 'eth0'). Default: get stats for all NICs.
|
|
||||||
:return: :class:`platypush.message.response.system.NetworkInterfaceStatsResponse` or list of
|
|
||||||
:class:`platypush.message.response.system.NetworkInterfaceStatsResponse`.
|
|
||||||
"""
|
|
||||||
stats = psutil.net_if_stats()
|
|
||||||
|
|
||||||
def _expand_stats(_nic, _stats):
|
|
||||||
return NetworkInterfaceStatsResponse(
|
|
||||||
nic=_nic,
|
|
||||||
is_up=_stats.isup,
|
|
||||||
duplex=_stats.duplex.name,
|
|
||||||
speed=_stats.speed,
|
|
||||||
mtu=_stats.mtu,
|
|
||||||
)
|
|
||||||
|
|
||||||
if nic:
|
|
||||||
stats = [addr for name, addr in stats.items() if name == nic]
|
|
||||||
assert stats, 'No such network interface: {}'.format(nic)
|
|
||||||
return _expand_stats(nic, stats[0])
|
|
||||||
|
|
||||||
return NetworkResponseList(
|
|
||||||
[_expand_stats(nic, addr) for nic, addr in stats.items()]
|
|
||||||
)
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def sensors_temperature(
|
def sensors_temperature(
|
||||||
self, sensor: Optional[str] = None, fahrenheit: bool = False
|
self, sensor: Optional[str] = None, fahrenheit: bool = False
|
||||||
|
@ -706,6 +676,7 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
NetworkInterfaceModel(
|
NetworkInterfaceModel(
|
||||||
id=f'system:network_interface:{nic["interface"]}',
|
id=f'system:network_interface:{nic["interface"]}',
|
||||||
name=nic.pop('interface'),
|
name=nic.pop('interface'),
|
||||||
|
reachable=nic.pop('is_up'),
|
||||||
**nic,
|
**nic,
|
||||||
)
|
)
|
||||||
for nic in entities['network']
|
for nic in entities['network']
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from enum import Enum
|
||||||
from socket import AddressFamily
|
from socket import AddressFamily
|
||||||
|
|
||||||
from marshmallow import pre_load
|
from marshmallow import pre_load
|
||||||
|
@ -20,6 +21,7 @@ class NetworkInterfaceBaseSchema(SystemBaseSchema):
|
||||||
'errout': 'errors_out',
|
'errout': 'errors_out',
|
||||||
'dropin': 'drop_in',
|
'dropin': 'drop_in',
|
||||||
'dropout': 'drop_out',
|
'dropout': 'drop_out',
|
||||||
|
'isup': 'is_up',
|
||||||
}.items():
|
}.items():
|
||||||
if in_attr in data:
|
if in_attr in data:
|
||||||
data[out_attr] = data.pop(in_attr)
|
data[out_attr] = data.pop(in_attr)
|
||||||
|
@ -32,4 +34,10 @@ class NetworkInterfaceBaseSchema(SystemBaseSchema):
|
||||||
addr['family'] = addr['family'].name
|
addr['family'] = addr['family'].name
|
||||||
data['addresses'][i] = addr
|
data['addresses'][i] = addr
|
||||||
|
|
||||||
|
if isinstance(data.get('duplex'), Enum):
|
||||||
|
data['duplex'] = data['duplex'].name.split('_')[-1]
|
||||||
|
|
||||||
|
# Split the flags string
|
||||||
|
data['flags'] = data.get('flags', '').split(',')
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -2,6 +2,8 @@ from dataclasses import dataclass, field
|
||||||
from socket import AddressFamily
|
from socket import AddressFamily
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from marshmallow.validate import OneOf
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NetworkInterface:
|
class NetworkInterface:
|
||||||
|
@ -82,6 +84,55 @@ class NetworkInterface:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
is_up: bool = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Whether the interface is active',
|
||||||
|
'example': True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
speed: int = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Interface reported speed in Mbps',
|
||||||
|
'example': 10000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
mtu: int = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Interface maximum transmission unit expressed '
|
||||||
|
'in bytes',
|
||||||
|
'example': 65535,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
duplex: str = field(
|
||||||
|
metadata={
|
||||||
|
'validate': OneOf(['FULL', 'HALF', 'UNKNOWN']),
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Interface duplex configuration. Can be FULL, '
|
||||||
|
'HALF or UNKNOWN',
|
||||||
|
'example': 'FULL',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
flags: List[str] = field(
|
||||||
|
default_factory=list,
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'List of flags associated to the interface',
|
||||||
|
'example': ['up', 'broadcast', 'running'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
addresses: List['NetworkInterfaceAddress'] = field(
|
addresses: List['NetworkInterfaceAddress'] = field(
|
||||||
default_factory=list,
|
default_factory=list,
|
||||||
metadata={
|
metadata={
|
||||||
|
|
Loading…
Reference in a new issue