summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/op-mode-standardized.json1
-rw-r--r--interface-definitions/high-availability.xml.in11
-rw-r--r--op-mode-definitions/generate-interfaces-debug-archive.xml.in20
-rw-r--r--op-mode-definitions/generate-openvpn-config-client.xml.in2
-rw-r--r--op-mode-definitions/generate-wireguard.xml.in2
-rw-r--r--op-mode-definitions/ipv6-route.xml.in2
-rw-r--r--op-mode-definitions/openvpn.xml.in4
-rw-r--r--op-mode-definitions/show-arp.xml.in2
-rw-r--r--op-mode-definitions/show-bridge.xml.in2
-rw-r--r--op-mode-definitions/show-interfaces-wireguard.xml.in2
-rw-r--r--op-mode-definitions/show-interfaces-wireless.xml.in2
-rw-r--r--op-mode-definitions/show-ip-multicast.xml.in8
-rw-r--r--op-mode-definitions/show-ip.xml.in2
-rw-r--r--op-mode-definitions/show-protocols.xml.in2
-rw-r--r--op-mode-definitions/show-system.xml.in4
-rw-r--r--op-mode-definitions/wireless.xml.in2
-rw-r--r--python/vyos/opmode.py16
-rwxr-xr-xsrc/op_mode/config_mgmt.py10
-rwxr-xr-xsrc/op_mode/generate_interfaces_debug_archive.py115
-rwxr-xr-xsrc/op_mode/igmp-proxy.py99
-rwxr-xr-xsrc/op_mode/show_igmpproxy.py241
-rwxr-xr-xsrc/services/api/graphql/generate/schema_from_op_mode.py5
-rw-r--r--src/services/api/graphql/graphql/mutations.py3
-rw-r--r--src/services/api/graphql/graphql/queries.py3
-rw-r--r--src/services/api/graphql/libs/op_mode.py5
-rw-r--r--src/services/api/graphql/session/errors/op_mode_errors.py4
26 files changed, 282 insertions, 287 deletions
diff --git a/data/op-mode-standardized.json b/data/op-mode-standardized.json
index 3205c7d20..abf562984 100644
--- a/data/op-mode-standardized.json
+++ b/data/op-mode-standardized.json
@@ -2,6 +2,7 @@
"accelppp.py",
"bgp.py",
"bridge.py",
+"config_mgmt.py",
"conntrack.py",
"container.py",
"cpu.py",
diff --git a/interface-definitions/high-availability.xml.in b/interface-definitions/high-availability.xml.in
index 4bb3b1537..6cb40247a 100644
--- a/interface-definitions/high-availability.xml.in
+++ b/interface-definitions/high-availability.xml.in
@@ -232,16 +232,15 @@
<properties>
<help>Virtual IP address</help>
<valueHelp>
- <format>ipv4</format>
- <description>IPv4 virtual address</description>
+ <format>ipv4net</format>
+ <description>IPv4 address and prefix length</description>
</valueHelp>
<valueHelp>
- <format>ipv6</format>
- <description>IPv6 virtual address</description>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
</valueHelp>
<constraint>
- <validator name="ipv4-host"/>
- <validator name="ipv6-host"/>
+ <validator name="ip-host"/>
</constraint>
</properties>
<children>
diff --git a/op-mode-definitions/generate-interfaces-debug-archive.xml.in b/op-mode-definitions/generate-interfaces-debug-archive.xml.in
new file mode 100644
index 000000000..5e4f4daad
--- /dev/null
+++ b/op-mode-definitions/generate-interfaces-debug-archive.xml.in
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="generate">
+ <children>
+ <node name="interfaces">
+ <properties>
+ <help>Interface specific commands</help>
+ </properties>
+ <children>
+ <node name="debug-archive">
+ <properties>
+ <help>Generate interfaces debug-archive</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/generate_interfaces_debug_archive.py</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/generate-openvpn-config-client.xml.in b/op-mode-definitions/generate-openvpn-config-client.xml.in
index 4f9f31bfe..baec0842b 100644
--- a/op-mode-definitions/generate-openvpn-config-client.xml.in
+++ b/op-mode-definitions/generate-openvpn-config-client.xml.in
@@ -16,7 +16,7 @@
<properties>
<help>Local interface used for connection</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py --type openvpn</script>
+ <path>interfaces openvpn</path>
</completionHelp>
</properties>
<children>
diff --git a/op-mode-definitions/generate-wireguard.xml.in b/op-mode-definitions/generate-wireguard.xml.in
index 0ef983cd2..6c01619be 100644
--- a/op-mode-definitions/generate-wireguard.xml.in
+++ b/op-mode-definitions/generate-wireguard.xml.in
@@ -19,7 +19,7 @@
<properties>
<help>Local interface used for connection</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py --type wireguard</script>
+ <path>interfaces wireguard</path>
</completionHelp>
</properties>
<children>
diff --git a/op-mode-definitions/ipv6-route.xml.in b/op-mode-definitions/ipv6-route.xml.in
index d75caf308..46e416a8a 100644
--- a/op-mode-definitions/ipv6-route.xml.in
+++ b/op-mode-definitions/ipv6-route.xml.in
@@ -26,7 +26,7 @@
<properties>
<help>Show IPv6 neighbor table for specified interface</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py -b</script>
+ <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/neighbor.py show --family inet6 --interface "$5"</command>
diff --git a/op-mode-definitions/openvpn.xml.in b/op-mode-definitions/openvpn.xml.in
index b2763da81..0a2657398 100644
--- a/op-mode-definitions/openvpn.xml.in
+++ b/op-mode-definitions/openvpn.xml.in
@@ -20,7 +20,7 @@
<properties>
<help>Reset OpenVPN process on interface</help>
<completionHelp>
- <script>sudo ${vyos_completion_dir}/list_interfaces.py --type openvpn</script>
+ <path>interfaces openvpn</path>
</completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/openvpn.py reset --interface $4</command>
@@ -51,7 +51,7 @@
<properties>
<help>Show OpenVPN interface information</help>
<completionHelp>
- <script>sudo ${vyos_completion_dir}/list_interfaces.py --type openvpn</script>
+ <path>interfaces openvpn</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/interfaces.py show --intf_name=$4</command>
diff --git a/op-mode-definitions/show-arp.xml.in b/op-mode-definitions/show-arp.xml.in
index 8662549fc..3680c20c6 100644
--- a/op-mode-definitions/show-arp.xml.in
+++ b/op-mode-definitions/show-arp.xml.in
@@ -12,7 +12,7 @@
<properties>
<help>Show Address Resolution Protocol (ARP) cache for specified interface</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py -b</script>
+ <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/neighbor.py show --family inet --interface "$4"</command>
diff --git a/op-mode-definitions/show-bridge.xml.in b/op-mode-definitions/show-bridge.xml.in
index dd2a28931..e7a646fdc 100644
--- a/op-mode-definitions/show-bridge.xml.in
+++ b/op-mode-definitions/show-bridge.xml.in
@@ -25,7 +25,7 @@
<properties>
<help>Show bridge information for a given bridge interface</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py --type bridge</script>
+ <path>interfaces bridge</path>
</completionHelp>
</properties>
<command>bridge -c link show | grep "master $3"</command>
diff --git a/op-mode-definitions/show-interfaces-wireguard.xml.in b/op-mode-definitions/show-interfaces-wireguard.xml.in
index eba8de568..75b0cc88e 100644
--- a/op-mode-definitions/show-interfaces-wireguard.xml.in
+++ b/op-mode-definitions/show-interfaces-wireguard.xml.in
@@ -8,7 +8,7 @@
<properties>
<help>Show specified WireGuard interface information</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py --type wireguard</script>
+ <path>interfaces wireguard</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireguard</command>
diff --git a/op-mode-definitions/show-interfaces-wireless.xml.in b/op-mode-definitions/show-interfaces-wireless.xml.in
index b0a272225..cdd591f82 100644
--- a/op-mode-definitions/show-interfaces-wireless.xml.in
+++ b/op-mode-definitions/show-interfaces-wireless.xml.in
@@ -28,7 +28,7 @@
<properties>
<help>Show specified wireless interface information</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py --type wireless</script>
+ <path>interfaces wireless</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireless</command>
diff --git a/op-mode-definitions/show-ip-multicast.xml.in b/op-mode-definitions/show-ip-multicast.xml.in
index 80d83b424..605d61e8d 100644
--- a/op-mode-definitions/show-ip-multicast.xml.in
+++ b/op-mode-definitions/show-ip-multicast.xml.in
@@ -13,13 +13,7 @@
<properties>
<help>Show multicast interfaces</help>
</properties>
- <command>if ps -C igmpproxy &amp;&gt;/dev/null; then ${vyos_op_scripts_dir}/show_igmpproxy.py --interface; else echo IGMP proxy not configured; fi</command>
- </leafNode>
- <leafNode name="mfc">
- <properties>
- <help>Show multicast fowarding cache</help>
- </properties>
- <command>if ps -C igmpproxy &amp;&gt;/dev/null; then ${vyos_op_scripts_dir}/show_igmpproxy.py --mfc; else echo IGMP proxy not configured; fi</command>
+ <command>${vyos_op_scripts_dir}/igmp-proxy.py show_interface</command>
</leafNode>
<leafNode name="summary">
<properties>
diff --git a/op-mode-definitions/show-ip.xml.in b/op-mode-definitions/show-ip.xml.in
index 0751c50cb..a710e33d2 100644
--- a/op-mode-definitions/show-ip.xml.in
+++ b/op-mode-definitions/show-ip.xml.in
@@ -17,7 +17,7 @@
<properties>
<help>Show IPv4 neighbor table for specified interface</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py -b</script>
+ <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/neighbor.py show --family inet --interface "$5"</command>
diff --git a/op-mode-definitions/show-protocols.xml.in b/op-mode-definitions/show-protocols.xml.in
index 698001b76..27146f90d 100644
--- a/op-mode-definitions/show-protocols.xml.in
+++ b/op-mode-definitions/show-protocols.xml.in
@@ -22,7 +22,7 @@
<properties>
<help>Show Address Resolution Protocol (ARP) cache for specified interface</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py -b</script>
+ <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>
</completionHelp>
</properties>
<command>/usr/sbin/arp -e -n -i "$6"</command>
diff --git a/op-mode-definitions/show-system.xml.in b/op-mode-definitions/show-system.xml.in
index 746601f43..85bfdcdba 100644
--- a/op-mode-definitions/show-system.xml.in
+++ b/op-mode-definitions/show-system.xml.in
@@ -29,13 +29,13 @@
<properties>
<help>Compare config file revisions</help>
</properties>
- <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_diff --rev "$5" --revb "$7"</command>
+ <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_diff --rev "$5" --rev2 "$7"</command>
<children>
<leafNode name="commands">
<properties>
<help>Compare config file revision commands</help>
</properties>
- <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_diff --rev "$5" --revb "$7" --commands</command>
+ <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_diff --rev "$5" --rev2 "$7" --commands</command>
</leafNode>
</children>
</tagNode>
diff --git a/op-mode-definitions/wireless.xml.in b/op-mode-definitions/wireless.xml.in
index 5d9db1544..f8e53ad21 100644
--- a/op-mode-definitions/wireless.xml.in
+++ b/op-mode-definitions/wireless.xml.in
@@ -21,7 +21,7 @@
<properties>
<help>Clear interface information for a given wireless interface</help>
<completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py --type wireless</script>
+ <path>interfaces wireless</path>
</completionHelp>
</properties>
<children>
diff --git a/python/vyos/opmode.py b/python/vyos/opmode.py
index 30e893d74..af2c7b28b 100644
--- a/python/vyos/opmode.py
+++ b/python/vyos/opmode.py
@@ -1,4 +1,4 @@
-# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2022-2023 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,10 @@ from humps import decamelize
class Error(Exception):
""" Any error that makes requested operation impossible to complete
for reasons unrelated to the user input or script logic.
+
+ This is the base class, scripts should not use it directly
+ and should raise more specific errors instead,
+ whenever possible.
"""
pass
@@ -45,6 +49,13 @@ class PermissionDenied(Error):
"""
pass
+class InsufficientResources(Error):
+ """ Requested operation and its arguments are valid but the system
+ does not have enough resources (such as drive space or memory)
+ to complete it.
+ """
+ pass
+
class UnsupportedOperation(Error):
""" Requested operation is technically valid but is not implemented yet. """
pass
@@ -217,6 +228,9 @@ def run(module):
if not args["raw"]:
return res
else:
+ if not isinstance(res, dict) and not isinstance(res, list):
+ raise InternalError(f"Bare literal is not an acceptable raw output, must be a list or an object.\
+ The output was:{res}")
res = decamelize(res)
res = _normalize_field_names(res)
from json import dumps
diff --git a/src/op_mode/config_mgmt.py b/src/op_mode/config_mgmt.py
index 0ffb1468b..66de26d1f 100755
--- a/src/op_mode/config_mgmt.py
+++ b/src/op_mode/config_mgmt.py
@@ -20,17 +20,17 @@ import typing
import vyos.opmode
from vyos.config_mgmt import ConfigMgmt
-def show_commit_diff(raw: bool, rev: int, revb: typing.Optional[int],
+def show_commit_diff(raw: bool, rev: int, rev2: typing.Optional[int],
commands: bool):
config_mgmt = ConfigMgmt()
- config_diff = config_mgmt.show_commit_diff(rev, revb, commands)
+ config_diff = config_mgmt.show_commit_diff(rev, rev2, commands)
if raw:
- revb = (rev+1) if revb is None else revb
+ rev2 = (rev+1) if rev2 is None else rev2
if commands:
- d = {f'config_command_diff_{revb}_{rev}': config_diff}
+ d = {f'config_command_diff_{rev2}_{rev}': config_diff}
else:
- d = {f'config_file_diff_{revb}_{rev}': config_diff}
+ d = {f'config_file_diff_{rev2}_{rev}': config_diff}
return d
return config_diff
diff --git a/src/op_mode/generate_interfaces_debug_archive.py b/src/op_mode/generate_interfaces_debug_archive.py
new file mode 100755
index 000000000..f5767080a
--- /dev/null
+++ b/src/op_mode/generate_interfaces_debug_archive.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from datetime import datetime
+from pathlib import Path
+from shutil import rmtree
+from socket import gethostname
+from sys import exit
+from tarfile import open as tar_open
+from vyos.util import rc_cmd
+import os
+
+# define a list of commands that needs to be executed
+
+CMD_LIST: list[str] = [
+ "journalctl -b -n 500",
+ "journalctl -b -k -n 500",
+ "ip -s l",
+ "cat /proc/interrupts",
+ "cat /proc/softirqs",
+ "top -b -d 1 -n 2 -1",
+ "netstat -l",
+ "cat /proc/net/dev",
+ "cat /proc/net/softnet_stat",
+ "cat /proc/net/icmp",
+ "cat /proc/net/udp",
+ "cat /proc/net/tcp",
+ "cat /proc/net/netstat",
+ "sysctl net",
+ "timeout 10 tcpdump -c 500 -eni any port not 22"
+]
+
+CMD_INTERFACES_LIST: list[str] = [
+ "ethtool -i ",
+ "ethtool -S ",
+ "ethtool -g ",
+ "ethtool -c ",
+ "ethtool -a ",
+ "ethtool -k ",
+ "ethtool -i ",
+ "ethtool --phy-statistics "
+]
+
+# get intefaces info
+interfaces_list = os.popen('ls /sys/class/net/').read().split()
+
+# modify CMD_INTERFACES_LIST for all interfaces
+CMD_INTERFACES_LIST_MOD=[]
+for command_interface in interfaces_list:
+ for command_interfacev2 in CMD_INTERFACES_LIST:
+ CMD_INTERFACES_LIST_MOD.append (f'{command_interfacev2}{command_interface}')
+
+# execute a command and save the output to a file
+
+def save_stdout(command: str, file: Path) -> None:
+ rc, stdout = rc_cmd(command)
+ body: str = f'''### {command} ###
+Command: {command}
+Exit code: {rc}
+Stdout:
+{stdout}
+
+'''
+ with file.open(mode='a') as f:
+ f.write(body)
+
+# get local host name
+hostname: str = gethostname()
+# get current time
+time_now: str = datetime.now().isoformat(timespec='seconds')
+
+# define a temporary directory for logs and collected data
+tmp_dir: Path = Path(f'/tmp/drops-debug_{time_now}')
+# set file paths
+drops_file: Path = Path(f'{tmp_dir}/drops.txt')
+interfaces_file: Path = Path(f'{tmp_dir}/interfaces.txt')
+archive_file: str = f'/tmp/packet-drops-debug_{time_now}.tar.bz2'
+
+# create files
+tmp_dir.mkdir()
+drops_file.touch()
+interfaces_file.touch()
+
+try:
+ # execute all commands
+ for command in CMD_LIST:
+ save_stdout(command, drops_file)
+ for command_interface in CMD_INTERFACES_LIST_MOD:
+ save_stdout(command_interface, interfaces_file)
+
+ # create an archive
+ with tar_open(name=archive_file, mode='x:bz2') as tar_file:
+ tar_file.add(tmp_dir)
+
+ # inform user about success
+ print(f'Debug file is generated and located in {archive_file}')
+except Exception as err:
+ print(f'Error during generating a debug file: {err}')
+finally:
+ # cleanup
+ rmtree(tmp_dir)
+ exit()
diff --git a/src/op_mode/igmp-proxy.py b/src/op_mode/igmp-proxy.py
new file mode 100755
index 000000000..0086c9aa6
--- /dev/null
+++ b/src/op_mode/igmp-proxy.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# File: show_igmpproxy.py
+# Purpose:
+# Display istatistics from IPv4 IGMP proxy.
+# Used by the "run show ip multicast" command tree.
+
+import ipaddress
+import json
+import socket
+import sys
+import tabulate
+
+import vyos.config
+import vyos.opmode
+
+from vyos.util import bytes_to_human, print_error
+
+def _is_configured():
+ """Check if IGMP proxy is configured"""
+ return vyos.config.Config().exists_effective('protocols igmp-proxy')
+
+def _is_running():
+ """Check if IGMP proxy is currently running"""
+ return not vyos.util.run('ps -C igmpproxy')
+
+def _kernel_to_ip(addr):
+ """
+ Convert any given address from Linux kernel to a proper, IPv4 address
+ using the correct host byte order.
+ """
+ # Convert from hex 'FE000A0A' to decimal '4261415434'
+ addr = int(addr, 16)
+ # Kernel ABI _always_ uses network byte order.
+ addr = socket.ntohl(addr)
+ return str(ipaddress.IPv4Address(addr))
+
+def _process_mr_vif():
+ """Read rows from /proc/net/ip_mr_vif into dicts."""
+ result = []
+ with open('/proc/net/ip_mr_vif', 'r') as f:
+ next(f)
+ for line in f:
+ result.append({
+ 'Interface': line.split()[1],
+ 'PktsIn' : int(line.split()[3]),
+ 'PktsOut' : int(line.split()[5]),
+ 'BytesIn' : int(line.split()[2]),
+ 'BytesOut' : int(line.split()[4]),
+ 'Local' : _kernel_to_ip(line.split()[7]),
+ })
+ return result
+
+def show_interface(raw: bool):
+ if data := _process_mr_vif():
+ if raw:
+ # Make the interface name the key for each row.
+ table = {}
+ for v in data:
+ table[v.pop('Interface')] = v
+ return json.loads(json.dumps(table))
+ # Make byte values human-readable for the table.
+ arr = []
+ for x in data:
+ arr.append({k: bytes_to_human(v) if k.startswith('Bytes') \
+ else v for k, v in x.items()})
+ return tabulate.tabulate(arr, headers='keys')
+
+
+if not _is_configured():
+ print_error('IGMP proxy is not configured.')
+ sys.exit(0)
+if not _is_running():
+ print_error('IGMP proxy is not running.')
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ try:
+ res = vyos.opmode.run(sys.modules[__name__])
+ if res:
+ print(res)
+ except (ValueError, vyos.opmode.Error) as e:
+ print_error(e)
+ sys.exit(1)
diff --git a/src/op_mode/show_igmpproxy.py b/src/op_mode/show_igmpproxy.py
deleted file mode 100755
index 4714e494b..000000000
--- a/src/op_mode/show_igmpproxy.py
+++ /dev/null
@@ -1,241 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2018 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# File: show_igmpproxy.py
-# Purpose:
-# Display istatistics from IPv4 IGMP proxy.
-# Used by the "run show ip multicast" command tree.
-
-import sys
-import jinja2
-import argparse
-import ipaddress
-import socket
-
-import vyos.config
-
-# Output Template for "show ip multicast interface" command
-#
-# Example:
-# Interface BytesIn PktsIn BytesOut PktsOut Local
-# eth0 0.0b 0 0.0b 0 xxx.xxx.xxx.65
-# eth1 0.0b 0 0.0b 0 xxx.xxx.xx.201
-# eth0.3 0.0b 0 0.0b 0 xxx.xxx.x.7
-# tun1 0.0b 0 0.0b 0 xxx.xxx.xxx.2
-vif_out_tmpl = """
-{% for r in data %}
-{{ "%-10s"|format(r.interface) }} {{ "%-12s"|format(r.bytes_in) }} {{ "%-12s"|format(r.pkts_in) }} {{ "%-12s"|format(r.bytes_out) }} {{ "%-12s"|format(r.pkts_out) }} {{ "%-15s"|format(r.loc) }}
-{% endfor %}
-"""
-
-# Output Template for "show ip multicast mfc" command
-#
-# Example:
-# Group Origin In Out Pkts Bytes Wrong
-# xxx.xxx.xxx.250 xxx.xx.xxx.75 --
-# xxx.xxx.xx.124 xx.xxx.xxx.26 --
-mfc_out_tmpl = """
-{% for r in data %}
-{{ "%-15s"|format(r.group) }} {{ "%-15s"|format(r.origin) }} {{ "%-12s"|format(r.pkts) }} {{ "%-12s"|format(r.bytes) }} {{ "%-12s"|format(r.wrong) }} {{ "%-10s"|format(r.iif) }} {{ "%-20s"|format(r.oifs|join(', ')) }}
-{% endfor %}
-"""
-
-parser = argparse.ArgumentParser()
-parser.add_argument("--interface", action="store_true", help="Interface Statistics")
-parser.add_argument("--mfc", action="store_true", help="Multicast Forwarding Cache")
-
-def byte_string(size):
- # convert size to integer
- size = int(size)
-
- # One Terrabyte
- s_TB = 1024 * 1024 * 1024 * 1024
- # One Gigabyte
- s_GB = 1024 * 1024 * 1024
- # One Megabyte
- s_MB = 1024 * 1024
- # One Kilobyte
- s_KB = 1024
- # One Byte
- s_B = 1
-
- if size > s_TB:
- return str(round((size/s_TB), 2)) + 'TB'
- elif size > s_GB:
- return str(round((size/s_GB), 2)) + 'GB'
- elif size > s_MB:
- return str(round((size/s_MB), 2)) + 'MB'
- elif size > s_KB:
- return str(round((size/s_KB), 2)) + 'KB'
- else:
- return str(round((size/s_B), 2)) + 'b'
-
- return None
-
-def kernel2ip(addr):
- """
- Convert any given addr from Linux Kernel to a proper, IPv4 address
- using the correct host byte order.
- """
-
- # Convert from hex 'FE000A0A' to decimal '4261415434'
- addr = int(addr, 16)
- # Kernel ABI _always_ uses network byteorder
- addr = socket.ntohl(addr)
-
- return ipaddress.IPv4Address( addr )
-
-def do_mr_vif():
- """
- Read contents of file /proc/net/ip_mr_vif and print a more human
- friendly version to the command line. IPv4 addresses present as
- 32bit integers in hex format are converted to IPv4 notation, too.
- """
-
- with open('/proc/net/ip_mr_vif', 'r') as f:
- lines = len(f.readlines())
- if lines < 2:
- return None
-
- result = {
- 'data': []
- }
-
- # Build up table format string
- table_format = {
- 'interface': 'Interface',
- 'pkts_in' : 'PktsIn',
- 'pkts_out' : 'PktsOut',
- 'bytes_in' : 'BytesIn',
- 'bytes_out': 'BytesOut',
- 'loc' : 'Local'
- }
- result['data'].append(table_format)
-
- # read and parse information from /proc filesystema
- with open('/proc/net/ip_mr_vif', 'r') as f:
- header_line = next(f)
- for line in f:
- data = {
- 'interface': line.split()[1],
- 'pkts_in' : line.split()[3],
- 'pkts_out' : line.split()[5],
-
- # convert raw byte number to something more human readable
- # Note: could be replaced by Python3 hurry.filesize module
- 'bytes_in' : byte_string( line.split()[2] ),
- 'bytes_out': byte_string( line.split()[4] ),
-
- # convert IP address from hex 'FE000A0A' to decimal '4261415434'
- 'loc' : kernel2ip( line.split()[7] ),
- }
- result['data'].append(data)
-
- return result
-
-def do_mr_mfc():
- """
- Read contents of file /proc/net/ip_mr_cache and print a more human
- friendly version to the command line. IPv4 addresses present as
- 32bit integers in hex format are converted to IPv4 notation, too.
- """
-
- with open('/proc/net/ip_mr_cache', 'r') as f:
- lines = len(f.readlines())
- if lines < 2:
- return None
-
- # We need this to convert from interface index to a real interface name
- # Thus we also skip the format identifier on list index 0
- vif = do_mr_vif()['data'][1:]
-
- result = {
- 'data': []
- }
-
- # Build up table format string
- table_format = {
- 'group' : 'Group',
- 'origin': 'Origin',
- 'iif' : 'In',
- 'oifs' : ['Out'],
- 'pkts' : 'Pkts',
- 'bytes' : 'Bytes',
- 'wrong' : 'Wrong'
- }
- result['data'].append(table_format)
-
- # read and parse information from /proc filesystem
- with open('/proc/net/ip_mr_cache', 'r') as f:
- header_line = next(f)
- for line in f:
- data = {
- # convert IP address from hex 'FE000A0A' to decimal '4261415434'
- 'group' : kernel2ip( line.split()[0] ),
- 'origin': kernel2ip( line.split()[1] ),
-
- 'iif' : '--',
- 'pkts' : '',
- 'bytes' : '',
- 'wrong' : '',
- 'oifs' : []
- }
-
- iif = int( line.split()[2] )
- if not ((iif == -1) or (iif == 65535)):
- data['pkts'] = line.split()[3]
- data['bytes'] = byte_string( line.split()[4] )
- data['wrong'] = line.split()[5]
-
- # convert index to real interface name
- data['iif'] = vif[iif]['interface']
-
- # convert each output interface index to a real interface name
- for oif in line.split()[6:]:
- idx = int( oif.split(':')[0] )
- data['oifs'].append( vif[idx]['interface'] )
-
- result['data'].append(data)
-
- return result
-
-if __name__ == '__main__':
- args = parser.parse_args()
-
- # Do nothing if service is not configured
- c = vyos.config.Config()
- if not c.exists_effective('protocols igmp-proxy'):
- print("IGMP proxy is not configured")
- sys.exit(0)
-
- if args.interface:
- data = do_mr_vif()
- if data:
- tmpl = jinja2.Template(vif_out_tmpl)
- print(tmpl.render(data))
-
- sys.exit(0)
- elif args.mfc:
- data = do_mr_mfc()
- if data:
- tmpl = jinja2.Template(mfc_out_tmpl)
- print(tmpl.render(data))
-
- sys.exit(0)
- else:
- parser.print_help()
- sys.exit(1)
-
diff --git a/src/services/api/graphql/generate/schema_from_op_mode.py b/src/services/api/graphql/generate/schema_from_op_mode.py
index fc63b0100..b320a529e 100755
--- a/src/services/api/graphql/generate/schema_from_op_mode.py
+++ b/src/services/api/graphql/generate/schema_from_op_mode.py
@@ -25,16 +25,17 @@ from inspect import signature, getmembers, isfunction, isclass, getmro
from jinja2 import Template
from vyos.defaults import directories
+from vyos.opmode import _is_op_mode_function_name as is_op_mode_function_name
from vyos.util import load_as_module
if __package__ is None or __package__ == '':
sys.path.append("/usr/libexec/vyos/services/api")
- from graphql.libs.op_mode import is_op_mode_function_name, is_show_function_name
+ from graphql.libs.op_mode import is_show_function_name
from graphql.libs.op_mode import snake_to_pascal_case, map_type_name
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.xml import defaults
else:
- from .. libs.op_mode import is_op_mode_function_name, is_show_function_name
+ from .. libs.op_mode import is_show_function_name
from .. libs.op_mode import snake_to_pascal_case, map_type_name
from .. import state
diff --git a/src/services/api/graphql/graphql/mutations.py b/src/services/api/graphql/graphql/mutations.py
index 87ea59c43..8254e22b1 100644
--- a/src/services/api/graphql/graphql/mutations.py
+++ b/src/services/api/graphql/graphql/mutations.py
@@ -15,7 +15,7 @@
from importlib import import_module
from typing import Any, Dict, Optional
-from ariadne import ObjectType, convert_kwargs_to_snake_case, convert_camel_case_to_snake
+from ariadne import ObjectType, convert_camel_case_to_snake
from graphql import GraphQLResolveInfo
from makefun import with_signature
@@ -45,7 +45,6 @@ def make_mutation_resolver(mutation_name, class_name, session_func):
func_sig = '(obj: Any, info: GraphQLResolveInfo, data: Optional[Dict]=None)'
@mutation.field(mutation_name)
- @convert_kwargs_to_snake_case
@with_signature(func_sig, func_name=resolver_name)
async def func_impl(*args, **kwargs):
try:
diff --git a/src/services/api/graphql/graphql/queries.py b/src/services/api/graphql/graphql/queries.py
index 1ad586428..daccc19b2 100644
--- a/src/services/api/graphql/graphql/queries.py
+++ b/src/services/api/graphql/graphql/queries.py
@@ -15,7 +15,7 @@
from importlib import import_module
from typing import Any, Dict, Optional
-from ariadne import ObjectType, convert_kwargs_to_snake_case, convert_camel_case_to_snake
+from ariadne import ObjectType, convert_camel_case_to_snake
from graphql import GraphQLResolveInfo
from makefun import with_signature
@@ -45,7 +45,6 @@ def make_query_resolver(query_name, class_name, session_func):
func_sig = '(obj: Any, info: GraphQLResolveInfo, data: Optional[Dict]=None)'
@query.field(query_name)
- @convert_kwargs_to_snake_case
@with_signature(func_sig, func_name=resolver_name)
async def func_impl(*args, **kwargs):
try:
diff --git a/src/services/api/graphql/libs/op_mode.py b/src/services/api/graphql/libs/op_mode.py
index c1eb493db..c553bbd67 100644
--- a/src/services/api/graphql/libs/op_mode.py
+++ b/src/services/api/graphql/libs/op_mode.py
@@ -29,11 +29,6 @@ def load_op_mode_as_module(name: str):
name = os.path.splitext(name)[0].replace('-', '_')
return load_as_module(name, path)
-def is_op_mode_function_name(name):
- if re.match(r"^(show|clear|reset|restart|add|delete)", name):
- return True
- return False
-
def is_show_function_name(name):
if re.match(r"^show", name):
return True
diff --git a/src/services/api/graphql/session/errors/op_mode_errors.py b/src/services/api/graphql/session/errors/op_mode_errors.py
index 4029fd0a1..18d555f2d 100644
--- a/src/services/api/graphql/session/errors/op_mode_errors.py
+++ b/src/services/api/graphql/session/errors/op_mode_errors.py
@@ -1,9 +1,8 @@
-
-
op_mode_err_msg = {
"UnconfiguredSubsystem": "subsystem is not configured or not running",
"DataUnavailable": "data currently unavailable",
"PermissionDenied": "client does not have permission",
+ "InsufficientResources": "insufficient system resources",
"IncorrectValue": "argument value is incorrect",
"UnsupportedOperation": "operation is not supported (yet)",
}
@@ -11,6 +10,7 @@ op_mode_err_msg = {
op_mode_err_code = {
"UnconfiguredSubsystem": 2000,
"DataUnavailable": 2001,
+ "InsufficientResources": 2002,
"PermissionDenied": 1003,
"IncorrectValue": 1002,
"UnsupportedOperation": 1004,