forked from platypush/platypush
Merged network addresses into NetworkInterface
model.
This commit is contained in:
parent
ebe79ac29a
commit
977b55dea9
6 changed files with 134 additions and 94 deletions
|
@ -90,6 +90,51 @@
|
||||||
<div class="name" v-text="value.drop_out" />
|
<div class="name" v-text="value.drop_out" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="child head" @click.stop="areAddressesCollapsed = !areAddressesCollapsed">
|
||||||
|
<div class="col-11 label">Addresses</div>
|
||||||
|
<div class="col-1 collapse-toggler pull-right">
|
||||||
|
<i class="fas"
|
||||||
|
:class="{'fa-chevron-down': areAddressesCollapsed, 'fa-chevron-up': !areAddressesCollapsed}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="body children attributes fade-in addresses"
|
||||||
|
v-if="value.addresses?.length && !areAddressesCollapsed">
|
||||||
|
<div class="address-container"
|
||||||
|
v-for="address in (value.addresses || [])"
|
||||||
|
:key="address.address"
|
||||||
|
>
|
||||||
|
<div class="child head"
|
||||||
|
@click.stop="displayedAddresses[address.address] = !displayedAddresses[address.address]"
|
||||||
|
>
|
||||||
|
<div class="col-11 label" v-text="address.address" />
|
||||||
|
<div class="col-1 collapse-toggler pull-right">
|
||||||
|
<i class="fas"
|
||||||
|
:class="{
|
||||||
|
'fa-chevron-down': !displayedAddresses[address.address],
|
||||||
|
'fa-chevron-up': displayedAddresses[address.address]
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="body children attributes fade-in address-details"
|
||||||
|
v-if="displayedAddresses[address.address]">
|
||||||
|
<div class="child" v-if="address.family">
|
||||||
|
<div class="label">Family</div>
|
||||||
|
<div class="value" v-text="address.family" />
|
||||||
|
</div>
|
||||||
|
<div class="child" v-if="address.netmask">
|
||||||
|
<div class="label">Netmask</div>
|
||||||
|
<div class="value" v-text="address.netmask" />
|
||||||
|
</div>
|
||||||
|
<div class="child" v-if="address.broadcast">
|
||||||
|
<div class="label">Broadcast</div>
|
||||||
|
<div class="value" v-text="address.broadcast" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -106,6 +151,8 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isCollapsed: true,
|
isCollapsed: true,
|
||||||
|
areAddressesCollapsed: true,
|
||||||
|
displayedAddresses: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -131,6 +178,12 @@ export default {
|
||||||
min-height: 3em;
|
min-height: 3em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
@include from($tablet) {
|
||||||
|
@include until($desktop) {
|
||||||
|
margin-left: 3.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $default-hover-fg;
|
color: $default-hover-fg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,7 @@ if 'network_interface' not in Base.metadata:
|
||||||
errors_out = Column(Integer)
|
errors_out = Column(Integer)
|
||||||
drop_in = Column(Integer)
|
drop_in = Column(Integer)
|
||||||
drop_out = Column(Integer)
|
drop_out = Column(Integer)
|
||||||
|
addresses = Column(JSON)
|
||||||
|
|
||||||
__mapper_args__ = {
|
__mapper_args__ = {
|
||||||
'polymorphic_identity': __tablename__,
|
'polymorphic_identity': __tablename__,
|
||||||
|
|
|
@ -28,40 +28,6 @@ class SensorResponse(SystemResponse):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NetworkAddressResponse(NetworkResponse):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
nic: str,
|
|
||||||
ipv4_address: Optional[str] = None,
|
|
||||||
ipv4_netmask: Optional[str] = None,
|
|
||||||
ipv4_broadcast: Optional[str] = None,
|
|
||||||
ipv6_address: Optional[str] = None,
|
|
||||||
ipv6_netmask: Optional[str] = None,
|
|
||||||
ipv6_broadcast: Optional[str] = None,
|
|
||||||
mac_address: Optional[str] = None,
|
|
||||||
mac_broadcast: Optional[str] = None,
|
|
||||||
ptp: Optional[str] = None,
|
|
||||||
*args,
|
|
||||||
**kwargs
|
|
||||||
):
|
|
||||||
super().__init__(
|
|
||||||
*args,
|
|
||||||
output={
|
|
||||||
'nic': nic,
|
|
||||||
'ipv4_address': ipv4_address,
|
|
||||||
'ipv4_netmask': ipv4_netmask,
|
|
||||||
'ipv4_broadcast': ipv4_broadcast,
|
|
||||||
'ipv6_address': ipv6_address,
|
|
||||||
'ipv6_netmask': ipv6_netmask,
|
|
||||||
'ipv6_broadcast': ipv6_broadcast,
|
|
||||||
'mac_address': mac_address,
|
|
||||||
'mac_broadcast': mac_broadcast,
|
|
||||||
'ptp': ptp,
|
|
||||||
},
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkInterfaceStatsResponse(NetworkResponse):
|
class NetworkInterfaceStatsResponse(NetworkResponse):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, nic: str, is_up: bool, duplex: str, speed: int, mtu: int, *args, **kwargs
|
self, nic: str, is_up: bool, duplex: str, speed: int, mtu: int, *args, **kwargs
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import os
|
import os
|
||||||
import socket
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Tuple, Union, List, Optional, Dict
|
from typing import Tuple, Union, List, Optional, Dict
|
||||||
|
@ -23,7 +22,6 @@ from platypush.entities.system import (
|
||||||
)
|
)
|
||||||
from platypush.message.response.system import (
|
from platypush.message.response.system import (
|
||||||
NetworkResponseList,
|
NetworkResponseList,
|
||||||
NetworkAddressResponse,
|
|
||||||
NetworkInterfaceStatsResponse,
|
NetworkInterfaceStatsResponse,
|
||||||
SensorTemperatureResponse,
|
SensorTemperatureResponse,
|
||||||
SensorResponseList,
|
SensorResponseList,
|
||||||
|
@ -257,9 +255,14 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
return DiskSchema().dump(self._disk_info(), many=True)
|
return DiskSchema().dump(self._disk_info(), many=True)
|
||||||
|
|
||||||
def _net_io_counters(self) -> List[NetworkInterface]:
|
def _net_io_counters(self) -> List[NetworkInterface]:
|
||||||
|
addrs = psutil.net_if_addrs()
|
||||||
return NetworkInterfaceSchema().load( # type: ignore
|
return NetworkInterfaceSchema().load( # type: ignore
|
||||||
[
|
[
|
||||||
{'interface': interface, **stats._asdict()}
|
{
|
||||||
|
'interface': interface,
|
||||||
|
'addresses': addrs.get(interface, []),
|
||||||
|
**stats._asdict(),
|
||||||
|
}
|
||||||
for interface, stats in psutil.net_io_counters(pernic=True).items()
|
for interface, stats 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 stats._asdict().values())
|
||||||
],
|
],
|
||||||
|
@ -328,62 +331,6 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
||||||
many=True,
|
many=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@action
|
|
||||||
def net_addresses(
|
|
||||||
self, nic: Optional[str] = None
|
|
||||||
) -> Union[NetworkAddressResponse, NetworkResponseList]:
|
|
||||||
"""
|
|
||||||
Get address info associated to 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.NetworkAddressResponse` or list of
|
|
||||||
:class:`platypush.message.response.system.NetworkAddressResponse`.
|
|
||||||
"""
|
|
||||||
addrs = psutil.net_if_addrs()
|
|
||||||
|
|
||||||
def _expand_addresses(_nic, _addrs):
|
|
||||||
args = {'nic': _nic}
|
|
||||||
|
|
||||||
for addr in _addrs:
|
|
||||||
if addr.family == socket.AddressFamily.AF_INET:
|
|
||||||
args.update(
|
|
||||||
{
|
|
||||||
'ipv4_address': addr.address,
|
|
||||||
'ipv4_netmask': addr.netmask,
|
|
||||||
'ipv4_broadcast': addr.broadcast,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
elif addr.family == socket.AddressFamily.AF_INET6:
|
|
||||||
args.update(
|
|
||||||
{
|
|
||||||
'ipv6_address': addr.address,
|
|
||||||
'ipv6_netmask': addr.netmask,
|
|
||||||
'ipv6_broadcast': addr.broadcast,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
elif addr.family == socket.AddressFamily.AF_PACKET:
|
|
||||||
args.update(
|
|
||||||
{
|
|
||||||
'mac_address': addr.address,
|
|
||||||
'mac_broadcast': addr.broadcast,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if addr.ptp and not args.get('ptp'):
|
|
||||||
args['ptp'] = addr.ptp
|
|
||||||
|
|
||||||
return NetworkAddressResponse(**args)
|
|
||||||
|
|
||||||
if nic:
|
|
||||||
addrs = [addr for name, addr in addrs.items() if name == nic]
|
|
||||||
assert addrs, 'No such network interface: {}'.format(nic)
|
|
||||||
addr = addrs[0]
|
|
||||||
return _expand_addresses(nic, addr)
|
|
||||||
|
|
||||||
return NetworkResponseList(
|
|
||||||
[_expand_addresses(nic, addr) for nic, addr in addrs.items()]
|
|
||||||
)
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def net_stats(
|
def net_stats(
|
||||||
self, nic: Optional[str] = None
|
self, nic: Optional[str] = None
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from socket import AddressFamily
|
||||||
|
|
||||||
from marshmallow import pre_load
|
from marshmallow import pre_load
|
||||||
|
|
||||||
from .._base import SystemBaseSchema
|
from .._base import SystemBaseSchema
|
||||||
|
@ -11,6 +13,8 @@ class NetworkInterfaceBaseSchema(SystemBaseSchema):
|
||||||
@pre_load
|
@pre_load
|
||||||
def pre_load(self, data: dict, **_) -> dict:
|
def pre_load(self, data: dict, **_) -> dict:
|
||||||
data = super().pre_load(data)
|
data = super().pre_load(data)
|
||||||
|
|
||||||
|
# Custom attribute mappings
|
||||||
for in_attr, out_attr in {
|
for in_attr, out_attr in {
|
||||||
'errin': 'errors_in',
|
'errin': 'errors_in',
|
||||||
'errout': 'errors_out',
|
'errout': 'errors_out',
|
||||||
|
@ -20,4 +24,12 @@ class NetworkInterfaceBaseSchema(SystemBaseSchema):
|
||||||
if in_attr in data:
|
if in_attr in data:
|
||||||
data[out_attr] = data.pop(in_attr)
|
data[out_attr] = data.pop(in_attr)
|
||||||
|
|
||||||
|
# Serialize enum values
|
||||||
|
for i, addr in enumerate(data.get('addresses', [])):
|
||||||
|
if hasattr(addr, '_asdict'):
|
||||||
|
addr = addr._asdict()
|
||||||
|
if isinstance(addr.get('family'), AddressFamily):
|
||||||
|
addr['family'] = addr['family'].name
|
||||||
|
data['addresses'][i] = addr
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Optional
|
from socket import AddressFamily
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -80,3 +81,63 @@ class NetworkInterface:
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addresses: List['NetworkInterfaceAddress'] = field(
|
||||||
|
default_factory=list,
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'List of addresses associated to the interface',
|
||||||
|
'example': [
|
||||||
|
{
|
||||||
|
'family': AddressFamily.AF_INET.name,
|
||||||
|
'address': '192.168.1.2',
|
||||||
|
'netmask': '255.255.255.0',
|
||||||
|
'broadcast': '192.168.1.255',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NetworkInterfaceAddress:
|
||||||
|
"""
|
||||||
|
Network interface address data class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
family: AddressFamily = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Address family',
|
||||||
|
'example': AddressFamily.AF_INET.name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
address: Optional[str] = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'IPv4 or IPv6 address of the interface',
|
||||||
|
'example': '192.168.1.2',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
netmask: Optional[str] = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Netmask for the interface address',
|
||||||
|
'example': '255.255.255.0',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
broadcast: Optional[str] = field(
|
||||||
|
metadata={
|
||||||
|
'metadata': {
|
||||||
|
'description': 'Broadcast address for the interface',
|
||||||
|
'example': '192.168.1.255',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in a new issue