mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-08-06 22:32:54 +02:00
feat(iftop): add iftop-scanning (#484)
* feat(iftop): add iftop-scanning this is not even an MVP, but I would like it to exist to allow per client json aggregation also, a future use is a stream response * fix typos and test first regex * add more iftop fun * Update iftop.py * add tests and json Signed-off-by: Ron Green <11993626+georgettica@users.noreply.github.com> * feat: make work and add tests Signed-off-by: Ron Green <11993626+georgettica@users.noreply.github.com> * add completion * change schema for query looping * fix: tests * fix review comments * feat: add byte parsing * add no-port to options * remove completion and format dep Signed-off-by: Ron Green <11993626+georgettica@users.noreply.github.com> * Update setup.py * Update iftop.py --------- Signed-off-by: Ron Green <11993626+georgettica@users.noreply.github.com> Co-authored-by: Kelly Brazil <kellyjonbrazil@gmail.com>
This commit is contained in:
623
jc/parsers/iftop.py
Normal file
623
jc/parsers/iftop.py
Normal file
@ -0,0 +1,623 @@
|
||||
"""jc - JSON Convert `iftop` command output parser
|
||||
|
||||
Some of `iftop` options are supported.
|
||||
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ iftop -i <device> -t -P -s 1 | jc --iftop
|
||||
$ iftop -i <device> -t -B -s1 | jc --iftop
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('iftop', iftop_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"device": string,
|
||||
"ip_address": string,
|
||||
"mac_address": string,
|
||||
"clients": [
|
||||
{
|
||||
"index": integer,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": string,
|
||||
"host_port": string, # can be service or missing
|
||||
"last_2s": string,
|
||||
"last_10s": string,
|
||||
"last_40s": string,
|
||||
"cumulative": string,
|
||||
"direction": string
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"total_send_rate": {
|
||||
"last_2s": string,
|
||||
"last_10s": string,
|
||||
"last_40s": string
|
||||
}
|
||||
"total_receive_rate": {
|
||||
"last_2s": string,
|
||||
"last_10s": string,
|
||||
"last_40s": string
|
||||
}
|
||||
"total_send_and_receive_rate": {
|
||||
"last_2s": string,
|
||||
"last_10s": string,
|
||||
"last_40s": string
|
||||
}
|
||||
"peak_rate": {
|
||||
"last_2s": string,
|
||||
"last_10s": string,
|
||||
"last_40s": string
|
||||
}
|
||||
"cumulative_rate": {
|
||||
"last_2s": string,
|
||||
"last_10s": string,
|
||||
"last_40s": string
|
||||
}
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
$ iftop -i eno0 -t -P -s 1 | jc --iftop -p -r
|
||||
[
|
||||
{
|
||||
"device": "enp0s3",
|
||||
"ip_address": "10.10.15.129",
|
||||
"mac_address": "11:22:33:44:55:66",
|
||||
"clients": [
|
||||
{
|
||||
"index": 1,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "ssh",
|
||||
"last_2s": "448b",
|
||||
"last_10s": "448b",
|
||||
"last_40s": "448b",
|
||||
"cumulative": "112B",
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.72",
|
||||
"host_port": "40876",
|
||||
"last_2s": "208b",
|
||||
"last_10s": "208b",
|
||||
"last_40s": "208b",
|
||||
"cumulative": "52B",
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total_send_rate": {
|
||||
"last_2s": "448b",
|
||||
"last_10s": "448b",
|
||||
"last_40s": "448b"
|
||||
},
|
||||
"total_receive_rate": {
|
||||
"last_2s": "208b",
|
||||
"last_10s": "208b",
|
||||
"last_40s": "208b"
|
||||
},
|
||||
"total_send_and_receive_rate": {
|
||||
"last_2s": "656b",
|
||||
"last_10s": "656b",
|
||||
"last_40s": "656b"
|
||||
},
|
||||
"peak_rate": {
|
||||
"last_2s": "448b",
|
||||
"last_10s": "208b",
|
||||
"last_40s": "656b"
|
||||
},
|
||||
"cumulative_rate": {
|
||||
"last_2s": "112B",
|
||||
"last_10s": "52B",
|
||||
"last_40s": "164B"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
"""
|
||||
import re
|
||||
from typing import List, Dict
|
||||
from jc.jc_types import JSONDictType
|
||||
import jc.utils
|
||||
from collections import namedtuple
|
||||
from numbers import Number
|
||||
|
||||
|
||||
class info:
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
|
||||
version = "0.1"
|
||||
description = "`iftop` command parser"
|
||||
author = "Ron Green"
|
||||
author_email = "11993626+georgettica@users.noreply.github.com"
|
||||
compatible = ["linux"]
|
||||
tags = ["command"]
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def _process(proc_data: List[JSONDictType], quiet: bool = False) -> List[JSONDictType]:
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (List of Dictionaries) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Structured to conform to the schema.
|
||||
"""
|
||||
string_to_bytes_fields = ["last_2s", "last_10s", "last_40s", "cumulative"]
|
||||
one_nesting = [
|
||||
"total_send_rate",
|
||||
"total_receive_rate",
|
||||
"total_send_and_receive_rate",
|
||||
"peak_rate",
|
||||
"cumulative_rate",
|
||||
]
|
||||
if not proc_data:
|
||||
return proc_data
|
||||
for entry in proc_data:
|
||||
# print(f"{entry=}")
|
||||
for entry_key in entry:
|
||||
# print(f"{entry_key=}")
|
||||
if entry_key in one_nesting:
|
||||
# print(f"{entry[entry_key]=}")
|
||||
for one_nesting_item_key in entry[entry_key]:
|
||||
# print(f"{one_nesting_item_key=}")
|
||||
if one_nesting_item_key in string_to_bytes_fields:
|
||||
entry[entry_key][one_nesting_item_key] = humanfriendly_parse_size(entry[entry_key][one_nesting_item_key])
|
||||
elif entry_key == "clients":
|
||||
for client in entry[entry_key]:
|
||||
# print(f"{client=}")
|
||||
if "connections" not in client:
|
||||
continue
|
||||
for connection in client["connections"]:
|
||||
# print(f"{connection=}")
|
||||
for connection_key in connection:
|
||||
# print(f"{connection_key=}")
|
||||
if connection_key in string_to_bytes_fields:
|
||||
connection[connection_key] = humanfriendly_parse_size(connection[connection_key])
|
||||
return proc_data
|
||||
|
||||
|
||||
# Named tuples to define units of size.
|
||||
SizeUnit = namedtuple('SizeUnit', 'divider, symbol, name')
|
||||
CombinedUnit = namedtuple('CombinedUnit', 'decimal, binary')
|
||||
|
||||
# Differences between Python 2 and 3.
|
||||
try:
|
||||
# Python 2.
|
||||
basestring = basestring
|
||||
except (ImportError, NameError):
|
||||
# Python 3.
|
||||
basestring = str
|
||||
|
||||
def humanfriendly_is_string(value):
|
||||
"""
|
||||
Check if a value is a :func:`python2:basestring` (in Python 2) or :class:`python3:str` (in Python 3) object.
|
||||
|
||||
:param value: The value to check.
|
||||
:returns: :data:`True` if the value is a string, :data:`False` otherwise.
|
||||
"""
|
||||
return isinstance(value, basestring)
|
||||
|
||||
# Common disk size units in binary (base-2) and decimal (base-10) multiples.
|
||||
disk_size_units = (
|
||||
CombinedUnit(SizeUnit(1000**1, 'KB', 'kilobyte'), SizeUnit(1024**1, 'KiB', 'kibibyte')),
|
||||
CombinedUnit(SizeUnit(1000**2, 'MB', 'megabyte'), SizeUnit(1024**2, 'MiB', 'mebibyte')),
|
||||
CombinedUnit(SizeUnit(1000**3, 'GB', 'gigabyte'), SizeUnit(1024**3, 'GiB', 'gibibyte')),
|
||||
CombinedUnit(SizeUnit(1000**4, 'TB', 'terabyte'), SizeUnit(1024**4, 'TiB', 'tebibyte')),
|
||||
CombinedUnit(SizeUnit(1000**5, 'PB', 'petabyte'), SizeUnit(1024**5, 'PiB', 'pebibyte')),
|
||||
CombinedUnit(SizeUnit(1000**6, 'EB', 'exabyte'), SizeUnit(1024**6, 'EiB', 'exbibyte')),
|
||||
CombinedUnit(SizeUnit(1000**7, 'ZB', 'zettabyte'), SizeUnit(1024**7, 'ZiB', 'zebibyte')),
|
||||
CombinedUnit(SizeUnit(1000**8, 'YB', 'yottabyte'), SizeUnit(1024**8, 'YiB', 'yobibyte')),
|
||||
)
|
||||
|
||||
class HumanfriendlyInvalidSize(Exception):
|
||||
pass
|
||||
|
||||
def humanfriendly_parse_size(size, binary=False):
|
||||
"""
|
||||
Parse a human readable data size and return the number of bytes.
|
||||
|
||||
:param size: The human readable file size to parse (a string).
|
||||
:param binary: :data:`True` to use binary multiples of bytes (base-2) for
|
||||
ambiguous unit symbols and names, :data:`False` to use
|
||||
decimal multiples of bytes (base-10).
|
||||
:returns: The corresponding size in bytes (an integer).
|
||||
:raises: :exc:`InvalidSize` when the input can't be parsed.
|
||||
|
||||
This function knows how to parse sizes in bytes, kilobytes, megabytes,
|
||||
gigabytes, terabytes and petabytes. Some examples:
|
||||
|
||||
>>> from humanfriendly import parse_size
|
||||
>>> parse_size('42')
|
||||
42
|
||||
>>> parse_size('13b')
|
||||
13
|
||||
>>> parse_size('5 bytes')
|
||||
5
|
||||
>>> parse_size('1 KB')
|
||||
1000
|
||||
>>> parse_size('1 kilobyte')
|
||||
1000
|
||||
>>> parse_size('1 KiB')
|
||||
1024
|
||||
>>> parse_size('1 KB', binary=True)
|
||||
1024
|
||||
>>> parse_size('1.5 GB')
|
||||
1500000000
|
||||
>>> parse_size('1.5 GB', binary=True)
|
||||
1610612736
|
||||
"""
|
||||
tokens = humanfriendly_tokenize(size)
|
||||
if tokens and isinstance(tokens[0], Number):
|
||||
# Get the normalized unit (if any) from the tokenized input.
|
||||
normalized_unit = tokens[1].lower() if len(tokens) == 2 and humanfriendly_is_string(tokens[1]) else ''
|
||||
# If the input contains only a number, it's assumed to be the number of
|
||||
# bytes. The second token can also explicitly reference the unit bytes.
|
||||
if len(tokens) == 1 or normalized_unit.startswith('b'):
|
||||
return int(tokens[0])
|
||||
# Otherwise we expect two tokens: A number and a unit.
|
||||
if normalized_unit:
|
||||
# Convert plural units to singular units, for details:
|
||||
# https://github.com/xolox/python-humanfriendly/issues/26
|
||||
normalized_unit = normalized_unit.rstrip('s')
|
||||
for unit in disk_size_units:
|
||||
# First we check for unambiguous symbols (KiB, MiB, GiB, etc)
|
||||
# and names (kibibyte, mebibyte, gibibyte, etc) because their
|
||||
# handling is always the same.
|
||||
if normalized_unit in (unit.binary.symbol.lower(), unit.binary.name.lower()):
|
||||
return int(tokens[0] * unit.binary.divider)
|
||||
# Now we will deal with ambiguous prefixes (K, M, G, etc),
|
||||
# symbols (KB, MB, GB, etc) and names (kilobyte, megabyte,
|
||||
# gigabyte, etc) according to the caller's preference.
|
||||
if (normalized_unit in (unit.decimal.symbol.lower(), unit.decimal.name.lower()) or
|
||||
normalized_unit.startswith(unit.decimal.symbol[0].lower())):
|
||||
return int(tokens[0] * (unit.binary.divider if binary else unit.decimal.divider))
|
||||
# We failed to parse the size specification.
|
||||
msg = "Failed to parse size! (input %r was tokenized as %r)"
|
||||
raise HumanfriendlyInvalidSize(format(msg, size, tokens))
|
||||
|
||||
|
||||
# taken from https://github.com/xolox/python-humanfriendly/blob/master/humanfriendly/text.py#L402
|
||||
# so there are no dependencies on the humanfriendly package
|
||||
def humanfriendly_tokenize(text):
|
||||
tokenized_input = []
|
||||
for token in re.split(r'(\d+(?:\.\d+)?)', text):
|
||||
token = token.strip()
|
||||
if re.match(r'\d+\.\d+', token):
|
||||
tokenized_input.append(float(token))
|
||||
elif token.isdigit():
|
||||
tokenized_input.append(int(token))
|
||||
elif token:
|
||||
tokenized_input.append(token)
|
||||
return tokenized_input
|
||||
|
||||
|
||||
def parse(data: str, raw: bool = False, quiet: bool = False) -> List[JSONDictType]:
|
||||
"""
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output: List[Dict] = []
|
||||
|
||||
interface_item: Dict = {}
|
||||
|
||||
clients: List = []
|
||||
|
||||
before_arrow = r"\s+(?P<index>\d+)\s+(?P<host_name>[^\s]+):(?P<host_port>[^\s]+)\s+"
|
||||
before_arrow_no_port = r"\s+(?P<index>\d+)\s+(?P<host_name>[^\s]+)\s+"
|
||||
after_arrow_before_newline = r"\s+(?P<send_last_2s>[^\s]+)\s+(?P<send_last_10s>[^\s]+)\s+(?P<send_last_40s>[^\s]+)\s+(?P<send_cumulative>[^\s]+)"
|
||||
newline_before_arrow = r"\s+(?P<receive_ip>.+):(?P<receive_port>\w+)\s+"
|
||||
newline_before_arrow_no_port = r"\s+(?P<receive_ip>.+)\s+"
|
||||
after_arrow_till_end = r"\s+(?P<receive_last_2s>[^\s]+)\s+(?P<receive_last_10s>[^\s]+)\s+(?P<receive_last_40s>[^\s]+)\s+(?P<receive_cumulative>[^\s]+)"
|
||||
re_linux_clients_before_newline = re.compile(
|
||||
rf"{before_arrow}=>{after_arrow_before_newline}"
|
||||
)
|
||||
re_linux_clients_before_newline_no_port = re.compile(
|
||||
rf"{before_arrow_no_port}=>{after_arrow_before_newline}"
|
||||
)
|
||||
re_linux_clients_after_newline_no_port = re.compile(
|
||||
rf"{newline_before_arrow_no_port}<={after_arrow_till_end}"
|
||||
)
|
||||
|
||||
re_linux_clients_after_newline = re.compile(
|
||||
rf"{newline_before_arrow}<={after_arrow_till_end}"
|
||||
)
|
||||
|
||||
re_total_send_rate = re.compile(
|
||||
r"Total send rate:\s+(?P<total_send_rate_last_2s>[^\s]+)\s+(?P<total_send_rate_last_10s>[^\s]+)\s+(?P<total_send_rate_last_40s>[^\s]+)"
|
||||
)
|
||||
re_total_receive_rate = re.compile(
|
||||
r"Total receive rate:\s+(?P<total_receive_rate_last_2s>[^\s]+)\s+(?P<total_receive_rate_last_10s>[^\s]+)\s+(?P<total_receive_rate_last_40s>[^\s]+)"
|
||||
)
|
||||
re_total_send_and_receive_rate = re.compile(
|
||||
r"Total send and receive rate:\s+(?P<total_send_and_receive_rate_last_2s>[^\s]+)\s+(?P<total_send_and_receive_rate_last_10s>[^\s]+)\s+(?P<total_send_and_receive_rate_last_40s>[^\s]+)"
|
||||
)
|
||||
re_peak_rate = re.compile(
|
||||
r"Peak rate \(sent/received/total\):\s+(?P<peak_rate_sent>[^\s]+)\s+(?P<peak_rate_received>[^\s]+)\s+(?P<peak_rate_total>[^\s]+)"
|
||||
)
|
||||
re_cumulative_rate = re.compile(
|
||||
r"Cumulative \(sent/received/total\):\s+(?P<cumulative_rate_sent>[^\s]+)\s+(?P<cumulative_rate_received>[^\s]+)\s+(?P<cumulative_rate_total>[^\s]+)"
|
||||
)
|
||||
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output: List[Dict] = []
|
||||
current_client: Dict = {}
|
||||
|
||||
if not jc.utils.has_data(data):
|
||||
return raw_output if raw else _process(raw_output, quiet=quiet)
|
||||
|
||||
is_previous_line_interface = False
|
||||
saw_already_host_line = False
|
||||
for line in filter(None, data.splitlines()):
|
||||
if line.startswith("interface:"):
|
||||
# Example:
|
||||
# interface: enp0s3
|
||||
|
||||
interface_item["device"] = line.split(":")[1].strip()
|
||||
elif line.startswith("IP address is:"):
|
||||
# Example:
|
||||
# IP address is: 10.10.15.129
|
||||
|
||||
interface_item["ip_address"] = line.split(":")[1].strip()
|
||||
elif line.startswith("MAC address is:"):
|
||||
# Example:
|
||||
# MAC address is: 08:00:27:c0:4a:4f
|
||||
|
||||
# strip off the "MAC address is: " part
|
||||
data_without_front = line.split(":")[1:]
|
||||
# join the remaining parts back together
|
||||
data_without_front = ":".join(data_without_front)
|
||||
interface_item["mac_address"] = data_without_front.strip()
|
||||
|
||||
elif line.startswith("Listening on"):
|
||||
# Example:
|
||||
# Listening on enp0s3
|
||||
pass
|
||||
elif (
|
||||
line.startswith("# Host name (port/service if enabled)")
|
||||
and not saw_already_host_line
|
||||
):
|
||||
saw_already_host_line = True
|
||||
# Example:
|
||||
# # Host name (port/service if enabled) last 2s last 10s last 40s cumulative
|
||||
pass
|
||||
elif (
|
||||
line.startswith("# Host name (port/service if enabled)")
|
||||
and saw_already_host_line
|
||||
):
|
||||
old_interface_item, interface_item = interface_item, {}
|
||||
interface_item.update(
|
||||
{
|
||||
"device": old_interface_item["device"],
|
||||
"ip_address": old_interface_item["ip_address"],
|
||||
"mac_address": old_interface_item["mac_address"],
|
||||
}
|
||||
)
|
||||
|
||||
elif "=>" in line and is_previous_line_interface and ":" in line:
|
||||
# should not happen
|
||||
pass
|
||||
elif "=>" in line and not is_previous_line_interface and ":" in line:
|
||||
# Example:
|
||||
# 1 ubuntu-2004-clean-01:ssh => 448b 448b 448b 112B
|
||||
|
||||
is_previous_line_interface = True
|
||||
match_raw = re_linux_clients_before_newline.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
current_client = {}
|
||||
current_client["index"] = int(match_dict["index"])
|
||||
current_client["connections"] = []
|
||||
current_client_send = {
|
||||
"host_name": match_dict["host_name"],
|
||||
"host_port": match_dict["host_port"],
|
||||
"last_2s": match_dict["send_last_2s"],
|
||||
"last_10s": match_dict["send_last_10s"],
|
||||
"last_40s": match_dict["send_last_40s"],
|
||||
"cumulative": match_dict["send_cumulative"],
|
||||
"direction": "send",
|
||||
}
|
||||
current_client["connections"].append(current_client_send)
|
||||
# not adding yet as the receive part is not yet parsed
|
||||
elif "=>" in line and not is_previous_line_interface and ":" not in line:
|
||||
# should not happen
|
||||
pass
|
||||
elif "=>" in line and is_previous_line_interface and ":" not in line:
|
||||
is_previous_line_interface = True
|
||||
match_raw = re_linux_clients_before_newline_no_port.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
current_client = {}
|
||||
current_client["index"] = int(match_dict["index"])
|
||||
current_client["connections"] = []
|
||||
current_client_send = {
|
||||
"host_name": match_dict["host_name"],
|
||||
"last_2s": match_dict["send_last_2s"],
|
||||
"last_10s": match_dict["send_last_10s"],
|
||||
"last_40s": match_dict["send_last_40s"],
|
||||
"cumulative": match_dict["send_cumulative"],
|
||||
"direction": "send",
|
||||
}
|
||||
current_client["connections"].append(current_client_send)
|
||||
# not adding yet as the receive part is not yet parsed
|
||||
elif "<=" in line and not is_previous_line_interface and ":" in line:
|
||||
# should not happen
|
||||
pass
|
||||
elif "<=" in line and is_previous_line_interface and ":" in line:
|
||||
# Example:
|
||||
# 10.10.15.72:40876 <= 208b 208b 208b 52B
|
||||
|
||||
is_previous_line_interface = False
|
||||
|
||||
match_raw = re_linux_clients_after_newline.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
current_client_receive = {
|
||||
"host_name": match_dict["receive_ip"],
|
||||
"host_port": match_dict["receive_port"],
|
||||
"last_2s": match_dict["receive_last_2s"],
|
||||
"last_10s": match_dict["receive_last_10s"],
|
||||
"last_40s": match_dict["receive_last_40s"],
|
||||
"cumulative": match_dict["receive_cumulative"],
|
||||
"direction": "receive",
|
||||
}
|
||||
|
||||
current_client["connections"].append(current_client_receive)
|
||||
clients.append(current_client)
|
||||
elif "<=" in line and not is_previous_line_interface and ":" not in line:
|
||||
# should not happen
|
||||
pass
|
||||
elif "<=" in line and is_previous_line_interface and ":" not in line:
|
||||
# Example:
|
||||
# 10.10.15.72:40876 <= 208b 208b 208b 52B
|
||||
|
||||
is_previous_line_interface = False
|
||||
|
||||
match_raw = re_linux_clients_after_newline_no_port.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
current_client_receive = {
|
||||
"host_name": match_dict["receive_ip"],
|
||||
"last_2s": match_dict["receive_last_2s"],
|
||||
"last_10s": match_dict["receive_last_10s"],
|
||||
"last_40s": match_dict["receive_last_40s"],
|
||||
"cumulative": match_dict["receive_cumulative"],
|
||||
"direction": "receive",
|
||||
}
|
||||
|
||||
current_client["connections"].append(current_client_receive)
|
||||
clients.append(current_client)
|
||||
# check if all of the characters are dashes or equal signs
|
||||
elif all(c == "-" for c in line):
|
||||
pass
|
||||
elif line.startswith("Total send rate"):
|
||||
# Example:
|
||||
# Total send rate: 448b 448b 448b
|
||||
match_raw = re_total_send_rate.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
interface_item["total_send_rate"] = {}
|
||||
interface_item["total_send_rate"].update(
|
||||
{
|
||||
"last_2s": match_dict["total_send_rate_last_2s"],
|
||||
"last_10s": match_dict["total_send_rate_last_10s"],
|
||||
"last_40s": match_dict["total_send_rate_last_40s"],
|
||||
}
|
||||
)
|
||||
elif line.startswith("Total receive rate"):
|
||||
# Example:
|
||||
# Total receive rate: 208b 208b 208b
|
||||
match_raw = re_total_receive_rate.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
interface_item["total_receive_rate"] = {}
|
||||
interface_item["total_receive_rate"].update(
|
||||
{
|
||||
"last_2s": match_dict["total_receive_rate_last_2s"],
|
||||
"last_10s": match_dict["total_receive_rate_last_10s"],
|
||||
"last_40s": match_dict["total_receive_rate_last_40s"],
|
||||
}
|
||||
)
|
||||
elif line.startswith("Total send and receive rate"):
|
||||
# Example:
|
||||
# Total send and receive rate: 656b 656b 656b
|
||||
match_raw = re_total_send_and_receive_rate.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
interface_item["total_send_and_receive_rate"] = {}
|
||||
interface_item["total_send_and_receive_rate"].update(
|
||||
{
|
||||
"last_2s": match_dict["total_send_and_receive_rate_last_2s"],
|
||||
"last_10s": match_dict["total_send_and_receive_rate_last_10s"],
|
||||
"last_40s": match_dict["total_send_and_receive_rate_last_40s"],
|
||||
}
|
||||
)
|
||||
elif line.startswith("Peak rate"):
|
||||
match_raw = re_peak_rate.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
interface_item["peak_rate"] = {}
|
||||
interface_item["peak_rate"].update(
|
||||
{
|
||||
"last_2s": match_dict["peak_rate_sent"],
|
||||
"last_10s": match_dict["peak_rate_received"],
|
||||
"last_40s": match_dict["peak_rate_total"],
|
||||
}
|
||||
)
|
||||
elif line.startswith("Cumulative"):
|
||||
match_raw = re_cumulative_rate.match(line)
|
||||
if not match_raw:
|
||||
# this is a bug in iftop
|
||||
#
|
||||
continue
|
||||
match_dict = match_raw.groupdict()
|
||||
interface_item["cumulative_rate"] = {}
|
||||
interface_item["cumulative_rate"].update(
|
||||
{
|
||||
"last_2s": match_dict["cumulative_rate_sent"],
|
||||
"last_10s": match_dict["cumulative_rate_received"],
|
||||
"last_40s": match_dict["cumulative_rate_total"],
|
||||
}
|
||||
)
|
||||
elif all(c == "=" for c in line):
|
||||
interface_item["clients"] = clients
|
||||
clients = []
|
||||
raw_output.append(interface_item.copy()) # keep the copy here as without it keeps the objects linked
|
||||
else:
|
||||
pass
|
||||
|
||||
return raw_output if raw else _process(raw_output, quiet=quiet)
|
33
tests/fixtures/ubuntu-20.10/iftop-b-n1-noport.json
vendored
Normal file
33
tests/fixtures/ubuntu-20.10/iftop-b-n1-noport.json
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"device": "enp0s3",
|
||||
"ip_address": "10.10.15.129",
|
||||
"mac_address": "08:00:27:c0:4a:4f",
|
||||
"total_send_rate": {
|
||||
"last_2s": 4820,
|
||||
"last_10s": 4820,
|
||||
"last_40s": 4820
|
||||
},
|
||||
"total_receive_rate": {
|
||||
"last_2s": 16600,
|
||||
"last_10s": 16600,
|
||||
"last_40s": 16600
|
||||
},
|
||||
"total_send_and_receive_rate": {
|
||||
"last_2s": 21400,
|
||||
"last_10s": 21400,
|
||||
"last_40s": 21400
|
||||
},
|
||||
"peak_rate": {
|
||||
"last_2s": 4820,
|
||||
"last_10s": 16600,
|
||||
"last_40s": 21400
|
||||
},
|
||||
"cumulative_rate": {
|
||||
"last_2s": 9630,
|
||||
"last_10s": 33100,
|
||||
"last_40s": 42800
|
||||
},
|
||||
"clients": []
|
||||
}
|
||||
]
|
18
tests/fixtures/ubuntu-20.10/iftop-b-n1-noport.out
vendored
Normal file
18
tests/fixtures/ubuntu-20.10/iftop-b-n1-noport.out
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
interface: enp0s3
|
||||
IP address is: 10.10.15.129
|
||||
MAC address is: 08:00:27:c0:4a:4f
|
||||
Listening on enp0s3
|
||||
# Host name (port/service if enabled) last 2s last 10s last 40s cumulative
|
||||
--------------------------------------------------------------------------------------------
|
||||
1 ubuntu-2004-clean-01 => 4.82KB 4.82KB 4.82KB 9.63KB
|
||||
10.10.15.72 <= 14.5KB 14.5KB 14.5KB 29.1KB
|
||||
2 ubuntu-2004-clean-02 => 0B 0B 0B 0B
|
||||
10.10.15.72 <= 2.02KB 2.02KB 2.02KB 4.04KB
|
||||
--------------------------------------------------------------------------------------------
|
||||
Total send rate: 4.82KB 4.82KB 4.82KB
|
||||
Total receive rate: 16.6KB 16.6KB 16.6KB
|
||||
Total send and receive rate: 21.4KB 21.4KB 21.4KB
|
||||
--------------------------------------------------------------------------------------------
|
||||
Peak rate (sent/received/total): 4.82KB 16.6KB 21.4KB
|
||||
Cumulative (sent/received/total): 9.63KB 33.1KB 42.8KB
|
||||
============================================================================================
|
57
tests/fixtures/ubuntu-20.10/iftop-b-n1.json
vendored
Normal file
57
tests/fixtures/ubuntu-20.10/iftop-b-n1.json
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
[
|
||||
{
|
||||
"device": "enp0s3",
|
||||
"ip_address": "10.10.15.129",
|
||||
"mac_address": "08:00:27:c0:4a:4f",
|
||||
"clients": [
|
||||
{
|
||||
"index": 1,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "ssh",
|
||||
"last_2s": 448,
|
||||
"last_10s": 448,
|
||||
"last_40s": 448,
|
||||
"cumulative": 112,
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.72",
|
||||
"host_port": "40876",
|
||||
"last_2s": 208,
|
||||
"last_10s": 208,
|
||||
"last_40s": 208,
|
||||
"cumulative": 52,
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total_send_rate": {
|
||||
"last_2s": 448,
|
||||
"last_10s": 448,
|
||||
"last_40s": 448
|
||||
},
|
||||
"total_receive_rate": {
|
||||
"last_2s": 208,
|
||||
"last_10s": 208,
|
||||
"last_40s": 208
|
||||
},
|
||||
"total_send_and_receive_rate": {
|
||||
"last_2s": 656,
|
||||
"last_10s": 656,
|
||||
"last_40s": 656
|
||||
},
|
||||
"peak_rate": {
|
||||
"last_2s": 448,
|
||||
"last_10s": 208,
|
||||
"last_40s": 656
|
||||
},
|
||||
"cumulative_rate": {
|
||||
"last_2s": 112,
|
||||
"last_10s": 52,
|
||||
"last_40s": 164
|
||||
}
|
||||
}
|
||||
]
|
16
tests/fixtures/ubuntu-20.10/iftop-b-n1.out
vendored
Normal file
16
tests/fixtures/ubuntu-20.10/iftop-b-n1.out
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
interface: enp0s3
|
||||
IP address is: 10.10.15.129
|
||||
MAC address is: 08:00:27:c0:4a:4f
|
||||
Listening on enp0s3
|
||||
# Host name (port/service if enabled) last 2s last 10s last 40s cumulative
|
||||
--------------------------------------------------------------------------------------------
|
||||
1 ubuntu-2004-clean-01:ssh => 448b 448b 448b 112B
|
||||
10.10.15.72:40876 <= 208b 208b 208b 52B
|
||||
--------------------------------------------------------------------------------------------
|
||||
Total send rate: 448b 448b 448b
|
||||
Total receive rate: 208b 208b 208b
|
||||
Total send and receive rate: 656b 656b 656b
|
||||
--------------------------------------------------------------------------------------------
|
||||
Peak rate (sent/received/total): 448b 208b 656b
|
||||
Cumulative (sent/received/total): 112B 52B 164B
|
||||
============================================================================================
|
236
tests/fixtures/ubuntu-20.10/iftop-b-n3.json
vendored
Normal file
236
tests/fixtures/ubuntu-20.10/iftop-b-n3.json
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
[
|
||||
{
|
||||
"device": "enp0s3",
|
||||
"ip_address": "10.10.15.129",
|
||||
"mac_address": "08:00:27:c0:4a:4f",
|
||||
"total_send_rate": {
|
||||
"last_2s": 23200000,
|
||||
"last_10s": 23200000,
|
||||
"last_40s": 23200000
|
||||
},
|
||||
"total_receive_rate": {
|
||||
"last_2s": 5650000,
|
||||
"last_10s": 5650000,
|
||||
"last_40s": 5650000
|
||||
},
|
||||
"total_send_and_receive_rate": {
|
||||
"last_2s": 28800000,
|
||||
"last_10s": 28800000,
|
||||
"last_40s": 28800000
|
||||
},
|
||||
"peak_rate": {
|
||||
"last_2s": 23200000,
|
||||
"last_10s": 5650000,
|
||||
"last_40s": 28800000
|
||||
},
|
||||
"cumulative_rate": {
|
||||
"last_2s": 5790000,
|
||||
"last_10s": 1410000,
|
||||
"last_40s": 7200000
|
||||
},
|
||||
"clients": [
|
||||
{
|
||||
"index": 1,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "33222",
|
||||
"last_2s": 4720,
|
||||
"last_10s": 4720,
|
||||
"last_40s": 4720,
|
||||
"cumulative": 1180,
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.72",
|
||||
"host_port": "https",
|
||||
"last_2s": 1990000,
|
||||
"last_10s": 1990000,
|
||||
"last_40s": 1990000,
|
||||
"cumulative": 508000,
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "https",
|
||||
"last_2s": 1980000,
|
||||
"last_10s": 1980000,
|
||||
"last_40s": 1980000,
|
||||
"cumulative": 507000,
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.73",
|
||||
"host_port": "34562",
|
||||
"last_2s": 3170,
|
||||
"last_10s": 3170,
|
||||
"last_40s": 3170,
|
||||
"cumulative": 811,
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"device": "enp0s3",
|
||||
"ip_address": "10.10.15.129",
|
||||
"mac_address": "08:00:27:c0:4a:4f",
|
||||
"total_send_rate": {
|
||||
"last_2s": 23200000,
|
||||
"last_10s": 23200000,
|
||||
"last_40s": 23200000
|
||||
},
|
||||
"total_receive_rate": {
|
||||
"last_2s": 5650000,
|
||||
"last_10s": 5650000,
|
||||
"last_40s": 5650000
|
||||
},
|
||||
"total_send_and_receive_rate": {
|
||||
"last_2s": 28800000,
|
||||
"last_10s": 28800000,
|
||||
"last_40s": 28800000
|
||||
},
|
||||
"peak_rate": {
|
||||
"last_2s": 23200000,
|
||||
"last_10s": 5650000,
|
||||
"last_40s": 28800000
|
||||
},
|
||||
"cumulative_rate": {
|
||||
"last_2s": 5790000,
|
||||
"last_10s": 1410000,
|
||||
"last_40s": 7200000
|
||||
},
|
||||
"clients": [
|
||||
{
|
||||
"index": 1,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "33222",
|
||||
"last_2s": 4720,
|
||||
"last_10s": 4720,
|
||||
"last_40s": 4720,
|
||||
"cumulative": 1180,
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.72",
|
||||
"host_port": "https",
|
||||
"last_2s": 1990000,
|
||||
"last_10s": 1990000,
|
||||
"last_40s": 1990000,
|
||||
"cumulative": 508000,
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "https",
|
||||
"last_2s": 1980000,
|
||||
"last_10s": 1980000,
|
||||
"last_40s": 1980000,
|
||||
"cumulative": 507000,
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.73",
|
||||
"host_port": "34562",
|
||||
"last_2s": 3170,
|
||||
"last_10s": 3170,
|
||||
"last_40s": 3170,
|
||||
"cumulative": 811,
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"device": "enp0s3",
|
||||
"ip_address": "10.10.15.129",
|
||||
"mac_address": "08:00:27:c0:4a:4f",
|
||||
"total_send_rate": {
|
||||
"last_2s": 23200000,
|
||||
"last_10s": 23200000,
|
||||
"last_40s": 23200000
|
||||
},
|
||||
"total_receive_rate": {
|
||||
"last_2s": 5650000,
|
||||
"last_10s": 5650000,
|
||||
"last_40s": 5650000
|
||||
},
|
||||
"total_send_and_receive_rate": {
|
||||
"last_2s": 28800000,
|
||||
"last_10s": 28800000,
|
||||
"last_40s": 28800000
|
||||
},
|
||||
"peak_rate": {
|
||||
"last_2s": 23200000,
|
||||
"last_10s": 5650000,
|
||||
"last_40s": 28800000
|
||||
},
|
||||
"cumulative_rate": {
|
||||
"last_2s": 5790000,
|
||||
"last_10s": 1410000,
|
||||
"last_40s": 7200000
|
||||
},
|
||||
"clients": [
|
||||
{
|
||||
"index": 1,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "33222",
|
||||
"last_2s": 4720,
|
||||
"last_10s": 4720,
|
||||
"last_40s": 4720,
|
||||
"cumulative": 1180,
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.72",
|
||||
"host_port": "https",
|
||||
"last_2s": 1990000,
|
||||
"last_10s": 1990000,
|
||||
"last_40s": 1990000,
|
||||
"cumulative": 508000,
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"connections": [
|
||||
{
|
||||
"host_name": "ubuntu-2004-clean-01",
|
||||
"host_port": "https",
|
||||
"last_2s": 1980000,
|
||||
"last_10s": 1980000,
|
||||
"last_40s": 1980000,
|
||||
"cumulative": 507000,
|
||||
"direction": "send"
|
||||
},
|
||||
{
|
||||
"host_name": "10.10.15.73",
|
||||
"host_port": "34562",
|
||||
"last_2s": 3170,
|
||||
"last_10s": 3170,
|
||||
"last_40s": 3170,
|
||||
"cumulative": 811,
|
||||
"direction": "receive"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
48
tests/fixtures/ubuntu-20.10/iftop-b-n3.out
vendored
Normal file
48
tests/fixtures/ubuntu-20.10/iftop-b-n3.out
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
interface: enp0s3
|
||||
IP address is: 10.10.15.129
|
||||
MAC address is: 08:00:27:c0:4a:4f
|
||||
Listening on enp0s3
|
||||
# Host name (port/service if enabled) last 2s last 10s last 40s cumulative
|
||||
--------------------------------------------------------------------------------------------
|
||||
1 ubuntu-2004-clean-01:33222 => 4.72Kb 4.72Kb 4.72Kb 1.18KB
|
||||
10.10.15.72:https <= 1.99Mb 1.99Mb 1.99Mb 508KB
|
||||
2 ubuntu-2004-clean-01:https => 1.98Mb 1.98Mb 1.98Mb 507KB
|
||||
10.10.15.73:34562 <= 3.17Kb 3.17Kb 3.17Kb 811B
|
||||
--------------------------------------------------------------------------------------------
|
||||
Total send rate: 23.2Mb 23.2Mb 23.2Mb
|
||||
Total receive rate: 5.65Mb 5.65Mb 5.65Mb
|
||||
Total send and receive rate: 28.8Mb 28.8Mb 28.8Mb
|
||||
--------------------------------------------------------------------------------------------
|
||||
Peak rate (sent/received/total): 23.2Mb 5.65Mb 28.8Mb
|
||||
Cumulative (sent/received/total): 5.79MB 1.41MB 7.20MB
|
||||
============================================================================================
|
||||
|
||||
# Host name (port/service if enabled) last 2s last 10s last 40s cumulative
|
||||
--------------------------------------------------------------------------------------------
|
||||
1 ubuntu-2004-clean-01:33222 => 4.72Kb 4.72Kb 4.72Kb 1.18KB
|
||||
10.10.15.72:https <= 1.99Mb 1.99Mb 1.99Mb 508KB
|
||||
2 ubuntu-2004-clean-01:https => 1.98Mb 1.98Mb 1.98Mb 507KB
|
||||
10.10.15.73:34562 <= 3.17Kb 3.17Kb 3.17Kb 811B
|
||||
--------------------------------------------------------------------------------------------
|
||||
Total send rate: 23.2Mb 23.2Mb 23.2Mb
|
||||
Total receive rate: 5.65Mb 5.65Mb 5.65Mb
|
||||
Total send and receive rate: 28.8Mb 28.8Mb 28.8Mb
|
||||
--------------------------------------------------------------------------------------------
|
||||
Peak rate (sent/received/total): 23.2Mb 5.65Mb 28.8Mb
|
||||
Cumulative (sent/received/total): 5.79MB 1.41MB 7.20MB
|
||||
============================================================================================
|
||||
|
||||
# Host name (port/service if enabled) last 2s last 10s last 40s cumulative
|
||||
--------------------------------------------------------------------------------------------
|
||||
1 ubuntu-2004-clean-01:33222 => 4.72Kb 4.72Kb 4.72Kb 1.18KB
|
||||
10.10.15.72:https <= 1.99Mb 1.99Mb 1.99Mb 508KB
|
||||
2 ubuntu-2004-clean-01:https => 1.98Mb 1.98Mb 1.98Mb 507KB
|
||||
10.10.15.73:34562 <= 3.17Kb 3.17Kb 3.17Kb 811B
|
||||
--------------------------------------------------------------------------------------------
|
||||
Total send rate: 23.2Mb 23.2Mb 23.2Mb
|
||||
Total receive rate: 5.65Mb 5.65Mb 5.65Mb
|
||||
Total send and receive rate: 28.8Mb 28.8Mb 28.8Mb
|
||||
--------------------------------------------------------------------------------------------
|
||||
Peak rate (sent/received/total): 23.2Mb 5.65Mb 28.8Mb
|
||||
Cumulative (sent/received/total): 5.79MB 1.41MB 7.20MB
|
||||
============================================================================================
|
57
tests/test_iftop.py
Normal file
57
tests/test_iftop.py
Normal file
@ -0,0 +1,57 @@
|
||||
import os
|
||||
import unittest
|
||||
import json
|
||||
import jc.parsers.iftop
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class MyTests(unittest.TestCase):
|
||||
|
||||
# input
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-20.10/iftop-b-n1.out'), 'r', encoding='utf-8') as f:
|
||||
ubuntu_20_10_iftop_b_n1 = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-20.10/iftop-b-n3.out'), 'r', encoding='utf-8') as f:
|
||||
ubuntu_20_10_iftop_b_n3 = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-20.10/iftop-b-n1-noport.out'), 'r', encoding='utf-8') as f:
|
||||
ubuntu_20_10_iftop_b_n1_noport = f.read()
|
||||
|
||||
# output
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-20.10/iftop-b-n1.json'), 'r', encoding='utf-8') as f:
|
||||
ubuntu_20_10_iftop_b_n1_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-20.10/iftop-b-n3.json'), 'r', encoding='utf-8') as f:
|
||||
ubuntu_20_10_iftop_b_n3_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-20.10/iftop-b-n1-noport.json'), 'r', encoding='utf-8') as f:
|
||||
ubuntu_20_10_iftop_b_n1_noport_json = json.loads(f.read())
|
||||
|
||||
|
||||
def test_iftop_nodata(self):
|
||||
"""
|
||||
Test 'iftop -b' with no data
|
||||
"""
|
||||
self.assertEqual(jc.parsers.iftop.parse('', quiet=True), [])
|
||||
|
||||
def test_iftop_ubuntu_20_10(self):
|
||||
"""
|
||||
Test 'iftop -i <device> -t -P -s 1' with units as MiB on Ubuntu 20.10
|
||||
"""
|
||||
self.assertEqual(jc.parsers.iftop.parse(self.ubuntu_20_10_iftop_b_n1, quiet=True), self.ubuntu_20_10_iftop_b_n1_json)
|
||||
|
||||
def test_iftop_multiple_runs_ubuntu_20_10(self):
|
||||
"""
|
||||
Test 'iftop -i <device> -t -P -s 1' with units as MiB on Ubuntu 20.10
|
||||
"""
|
||||
self.assertEqual(jc.parsers.iftop.parse(self.ubuntu_20_10_iftop_b_n3, quiet=True), self.ubuntu_20_10_iftop_b_n3_json)
|
||||
|
||||
def test_iftop_ubuntu_20_10_no_port(self):
|
||||
"""
|
||||
Test 'iftop -i <device> -t -B -s 1' with units as MiB on Ubuntu 20.10
|
||||
"""
|
||||
self.assertEqual(jc.parsers.iftop.parse(self.ubuntu_20_10_iftop_b_n1_noport, quiet=True), self.ubuntu_20_10_iftop_b_n1_noport_json)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Reference in New Issue
Block a user