diff options
-rw-r--r-- | .github/workflows/chceck-pr-message.yml | 1 | ||||
-rw-r--r-- | .github/workflows/check-unused-imports.yml | 1 | ||||
-rw-r--r-- | .github/workflows/linit-j2.yml | 18 | ||||
-rw-r--r-- | interface-definitions/container.xml.in | 29 | ||||
-rw-r--r-- | interface-definitions/nat_cgnat.xml.in | 6 | ||||
-rw-r--r-- | python/vyos/configdict.py | 2 | ||||
-rw-r--r-- | python/vyos/configquery.py | 60 | ||||
-rw-r--r-- | python/vyos/utils/__init__.py | 3 | ||||
-rw-r--r-- | python/vyos/utils/cpu.py (renamed from python/vyos/cpu.py) | 1 | ||||
-rw-r--r-- | python/vyos/utils/dict.py | 7 | ||||
-rw-r--r-- | python/vyos/utils/error.py | 24 | ||||
-rw-r--r-- | smoketest/config-tests/container-simple | 1 | ||||
-rw-r--r-- | smoketest/configs/container-simple | 5 | ||||
-rw-r--r-- | smoketest/scripts/cli/base_accel_ppp_test.py | 2 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_container.py | 5 | ||||
-rwxr-xr-x | src/completion/list_container_sysctl_parameters.sh | 20 | ||||
-rwxr-xr-x | src/conf_mode/container.py | 57 | ||||
-rwxr-xr-x | src/conf_mode/nat_cgnat.py | 30 | ||||
-rwxr-xr-x | src/op_mode/cpu.py | 12 | ||||
-rwxr-xr-x | src/op_mode/uptime.py | 4 |
20 files changed, 240 insertions, 48 deletions
diff --git a/.github/workflows/chceck-pr-message.yml b/.github/workflows/chceck-pr-message.yml index 460662014..5eb2d840a 100644 --- a/.github/workflows/chceck-pr-message.yml +++ b/.github/workflows/chceck-pr-message.yml @@ -7,6 +7,7 @@ on: - current - crux - equuleus + - sagitta types: [opened, synchronize, edited] permissions: diff --git a/.github/workflows/check-unused-imports.yml b/.github/workflows/check-unused-imports.yml index aada264f7..0f0cff3ec 100644 --- a/.github/workflows/check-unused-imports.yml +++ b/.github/workflows/check-unused-imports.yml @@ -3,6 +3,7 @@ on: pull_request: branches: - current + - equuleus - sagitta workflow_dispatch: diff --git a/.github/workflows/linit-j2.yml b/.github/workflows/linit-j2.yml deleted file mode 100644 index 364a65a14..000000000 --- a/.github/workflows/linit-j2.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: J2 Lint - -on: - pull_request: - branches: - - current - - crux - - equuleus - -permissions: - pull-requests: write - contents: read - -jobs: - j2lint: - uses: vyos/.github/.github/workflows/lint-j2.yml@feature/T6349-reusable-workflows - secrets: inherit diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index 1ad7215e5..6ea44a6d4 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -71,6 +71,35 @@ <multi/> </properties> </leafNode> + <node name="sysctl"> + <properties> + <help>Configure namespaced kernel parameters of the container</help> + </properties> + <children> + <tagNode name="parameter"> + <properties> + <help>Sysctl key name</help> + <completionHelp> + <script>${vyos_completion_dir}/list_container_sysctl_parameters.sh</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Sysctl key name</description> + </valueHelp> + <constraint> + <validator name="sysctl"/> + </constraint> + </properties> + <children> + <leafNode name="value"> + <properties> + <help>Sysctl configuration value</help> + </properties> + </leafNode> + </children> + </tagNode> + </children> + </node> #include <include/generic-description.xml.i> <tagNode name="device"> <properties> diff --git a/interface-definitions/nat_cgnat.xml.in b/interface-definitions/nat_cgnat.xml.in index fce5e655d..71f4d67b0 100644 --- a/interface-definitions/nat_cgnat.xml.in +++ b/interface-definitions/nat_cgnat.xml.in @@ -8,6 +8,12 @@ <priority>221</priority> </properties> <children> + <leafNode name="log-allocation"> + <properties> + <help>Log IP address and port allocation</help> + <valueless/> + </properties> + </leafNode> <node name="pool"> <properties> <help>External and internal pool parameters</help> diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 870d7cfda..5a353b110 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -631,7 +631,7 @@ def get_accel_dict(config, base, chap_secrets, with_pki=False): Return a dictionary with the necessary interface config keys. """ - from vyos.cpu import get_core_count + from vyos.utils.cpu import get_core_count from vyos.template import is_ipv4 dict = config.get_config_dict(base, key_mangling=('-', '_'), diff --git a/python/vyos/configquery.py b/python/vyos/configquery.py index 71ad5b4f0..5d6ca9be9 100644 --- a/python/vyos/configquery.py +++ b/python/vyos/configquery.py @@ -1,4 +1,4 @@ -# Copyright 2021-2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2021-2024 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 @@ -19,6 +19,8 @@ settings from op mode, and execution of arbitrary op mode commands. ''' import os +import json +import subprocess from vyos.utils.process import STDOUT from vyos.utils.process import popen @@ -27,6 +29,14 @@ from vyos.utils.boot import boot_configuration_complete from vyos.config import Config from vyos.configsource import ConfigSourceSession, ConfigSourceString from vyos.defaults import directories +from vyos.configtree import ConfigTree +from vyos.utils.dict import embed_dict +from vyos.utils.dict import get_sub_dict +from vyos.utils.dict import mangle_dict_keys +from vyos.utils.error import cli_shell_api_err +from vyos.xml_ref import multi_to_list +from vyos.xml_ref import is_tag +from vyos.base import Warning config_file = os.path.join(directories['config'], 'config.boot') @@ -133,4 +143,50 @@ def query_context(config_query_class=CliShellApiConfigQuery, run = op_run_class() return query, run - +def verify_mangling(key_mangling): + if not (isinstance(key_mangling, tuple) and + len(key_mangling) == 2 and + isinstance(key_mangling[0], str) and + isinstance(key_mangling[1], str)): + raise ValueError("key_mangling must be a tuple of two strings") + +def op_mode_run(cmd): + """ low-level to avoid overhead """ + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + out = p.stdout.read() + p.wait() + return p.returncode, out.decode() + +def op_mode_config_dict(path=None, key_mangling=None, + no_tag_node_value_mangle=False, + no_multi_convert=False, get_first_key=False): + + if path is None: + path = [] + command = ['/bin/cli-shell-api', '--show-active-only', 'showConfig'] + + rc, out = op_mode_run(command + path) + if rc == cli_shell_api_err.VYOS_EMPTY_CONFIG: + out = '' + if rc == cli_shell_api_err.VYOS_INVALID_PATH: + Warning(out) + return {} + + ct = ConfigTree(out) + d = json.loads(ct.to_json()) + # cli-shell-api output includes last path component if tag node + if is_tag(path): + config_dict = embed_dict(path[:-1], d) + else: + config_dict = embed_dict(path, d) + + if not no_multi_convert: + config_dict = multi_to_list([], config_dict) + + if key_mangling is not None: + verify_mangling(key_mangling) + config_dict = mangle_dict_keys(config_dict, + key_mangling[0], key_mangling[1], + no_tag_node_value_mangle=no_tag_node_value_mangle) + + return get_sub_dict(config_dict, path, get_first_key=get_first_key) diff --git a/python/vyos/utils/__init__.py b/python/vyos/utils/__init__.py index 12ef2d3b8..1cd062a11 100644 --- a/python/vyos/utils/__init__.py +++ b/python/vyos/utils/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2024 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 @@ -18,6 +18,7 @@ from vyos.utils import auth from vyos.utils import boot from vyos.utils import commit from vyos.utils import convert +from vyos.utils import cpu from vyos.utils import dict from vyos.utils import file from vyos.utils import io diff --git a/python/vyos/cpu.py b/python/vyos/utils/cpu.py index cae5f5f4d..3bea5ac12 100644 --- a/python/vyos/cpu.py +++ b/python/vyos/utils/cpu.py @@ -28,7 +28,6 @@ but nothing is certain. import re - def _read_cpuinfo(): with open('/proc/cpuinfo', 'r') as f: lines = f.read().strip() diff --git a/python/vyos/utils/dict.py b/python/vyos/utils/dict.py index d36b6fcfb..062ab9c81 100644 --- a/python/vyos/utils/dict.py +++ b/python/vyos/utils/dict.py @@ -307,6 +307,13 @@ def dict_to_paths(d: dict) -> list: for r in func(d, []): yield r +def embed_dict(p: list[str], d: dict) -> dict: + path = p.copy() + ret = d + while path: + ret = {path.pop(): ret} + return ret + def check_mutually_exclusive_options(d, keys, required=False): """ Checks if a dict has at most one or only one of mutually exclusive keys. diff --git a/python/vyos/utils/error.py b/python/vyos/utils/error.py new file mode 100644 index 000000000..8d4709bff --- /dev/null +++ b/python/vyos/utils/error.py @@ -0,0 +1,24 @@ +# Copyright 2024 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 +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library. If not, see <http://www.gnu.org/licenses/>. + +from enum import IntEnum + +class cli_shell_api_err(IntEnum): + """ vyatta-cfg/src/vyos-errors.h """ + VYOS_SUCCESS = 0 + VYOS_GENERAL_FAILURE = 1 + VYOS_INVALID_PATH = 2 + VYOS_EMPTY_CONFIG = 3 + VYOS_CONFIG_PARSE_ERROR = 4 diff --git a/smoketest/config-tests/container-simple b/smoketest/config-tests/container-simple index cc80ef4cf..5af365cf9 100644 --- a/smoketest/config-tests/container-simple +++ b/smoketest/config-tests/container-simple @@ -11,3 +11,4 @@ set container name c02 allow-host-networks set container name c02 allow-host-pid set container name c02 capability 'sys-time' set container name c02 image 'busybox:stable' +set container name c02 sysctl parameter kernel.msgmax value '8192'
\ No newline at end of file diff --git a/smoketest/configs/container-simple b/smoketest/configs/container-simple index 82983afb7..b98a440b5 100644 --- a/smoketest/configs/container-simple +++ b/smoketest/configs/container-simple @@ -10,6 +10,11 @@ container { allow-host-pid cap-add sys-time image busybox:stable + sysctl { + parameter kernel.msgmax { + value "8192" + } + } } } interfaces { diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py index 212dc58ab..c6f6cb804 100644 --- a/smoketest/scripts/cli/base_accel_ppp_test.py +++ b/smoketest/scripts/cli/base_accel_ppp_test.py @@ -19,7 +19,7 @@ from configparser import ConfigParser from vyos.configsession import ConfigSessionError from vyos.template import is_ipv4 -from vyos.cpu import get_core_count +from vyos.utils.cpu import get_core_count from vyos.utils.process import process_named_running from vyos.utils.process import cmd diff --git a/smoketest/scripts/cli/test_container.py b/smoketest/scripts/cli/test_container.py index 90f821c60..3dd97a175 100755 --- a/smoketest/scripts/cli/test_container.py +++ b/smoketest/scripts/cli/test_container.py @@ -80,6 +80,7 @@ class TestContainer(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['name', cont_name, 'image', cont_image]) self.cli_set(base_path + ['name', cont_name, 'allow-host-networks']) + self.cli_set(base_path + ['name', cont_name, 'sysctl', 'parameter', 'kernel.msgmax', 'value', '4096']) # commit changes self.cli_commit() @@ -91,6 +92,10 @@ class TestContainer(VyOSUnitTestSHIM.TestCase): # Check for running process self.assertEqual(process_named_running(PROCESS_NAME), pid) + # verify + tmp = cmd(f'sudo podman exec -it {cont_name} sysctl kernel.msgmax') + self.assertEqual(tmp, 'kernel.msgmax = 4096') + def test_cpu_limit(self): cont_name = 'c2' diff --git a/src/completion/list_container_sysctl_parameters.sh b/src/completion/list_container_sysctl_parameters.sh new file mode 100755 index 000000000..cf8d006e5 --- /dev/null +++ b/src/completion/list_container_sysctl_parameters.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# +# Copyright (C) 2024 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/>. + +declare -a vals +eval "vals=($(/sbin/sysctl -N -a|grep -E '^(fs.mqueue|net)\.|^(kernel.msgmax|kernel.msgmnb|kernel.msgmni|kernel.sem|kernel.shmall|kernel.shmmax|kernel.shmmni|kernel.shm_rmid_forced)$'))" +echo ${vals[@]} +exit 0 diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 3efeb9b40..ded370a7a 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -29,7 +29,7 @@ from vyos.configdict import node_changed from vyos.configdict import is_node_changed from vyos.configverify import verify_vrf from vyos.ifconfig import Interface -from vyos.cpu import get_core_count +from vyos.utils.cpu import get_core_count from vyos.utils.file import write_file from vyos.utils.process import call from vyos.utils.process import cmd @@ -43,6 +43,7 @@ from vyos.template import render from vyos.xml_ref import default_value from vyos import ConfigError from vyos import airbag + airbag.enable() config_containers = '/etc/containers/containers.conf' @@ -50,16 +51,19 @@ config_registry = '/etc/containers/registries.conf' config_storage = '/etc/containers/storage.conf' systemd_unit_path = '/run/systemd/system' + def _cmd(command): if os.path.exists('/tmp/vyos.container.debug'): print(command) return cmd(command) + def network_exists(name): # Check explicit name for network, returns True if network exists c = _cmd(f'podman network ls --quiet --filter name=^{name}$') return bool(c) + # Common functions def get_config(config=None): if config: @@ -86,21 +90,22 @@ def get_config(config=None): # registry is a tagNode with default values - merge the list from # default_values['registry'] into the tagNode variables if 'registry' not in container: - container.update({'registry' : {}}) + container.update({'registry': {}}) default_values = default_value(base + ['registry']) for registry in default_values: - tmp = {registry : {}} + tmp = {registry: {}} container['registry'] = dict_merge(tmp, container['registry']) # Delete container network, delete containers tmp = node_changed(conf, base + ['network']) - if tmp: container.update({'network_remove' : tmp}) + if tmp: container.update({'network_remove': tmp}) tmp = node_changed(conf, base + ['name']) - if tmp: container.update({'container_remove' : tmp}) + if tmp: container.update({'container_remove': tmp}) return container + def verify(container): # bail out early - looks like removal from running config if not container: @@ -125,8 +130,8 @@ def verify(container): # of image upgrade and deletion. image = container_config['image'] if run(f'podman image exists {image}') != 0: - Warning(f'Image "{image}" used in container "{name}" does not exist '\ - f'locally. Please use "add container image {image}" to add it '\ + Warning(f'Image "{image}" used in container "{name}" does not exist ' \ + f'locally. Please use "add container image {image}" to add it ' \ f'to the system! Container "{name}" will not be started!') if 'cpu_quota' in container_config: @@ -167,11 +172,11 @@ def verify(container): # We can not use the first IP address of a network prefix as this is used by podman if ip_address(address) == ip_network(network)[1]: - raise ConfigError(f'IP address "{address}" can not be used for a container, '\ + raise ConfigError(f'IP address "{address}" can not be used for a container, ' \ 'reserved for the container engine!') if cnt_ipv4 > 1 or cnt_ipv6 > 1: - raise ConfigError(f'Only one IP address per address family can be used for '\ + raise ConfigError(f'Only one IP address per address family can be used for ' \ f'container "{name}". {cnt_ipv4} IPv4 and {cnt_ipv6} IPv6 address(es)!') if 'device' in container_config: @@ -186,6 +191,13 @@ def verify(container): if not os.path.exists(source): raise ConfigError(f'Device "{dev}" source path "{source}" does not exist!') + if 'sysctl' in container_config and 'parameter' in container_config['sysctl']: + for var, cfg in container_config['sysctl']['parameter'].items(): + if 'value' not in cfg: + raise ConfigError(f'sysctl parameter {var} has no value assigned!') + if var.startswith('net.') and 'allow_host_networks' in container_config: + raise ConfigError(f'sysctl parameter {var} cannot be set when using host networking!') + if 'environment' in container_config: for var, cfg in container_config['environment'].items(): if 'value' not in cfg: @@ -219,7 +231,8 @@ def verify(container): # Can not set both allow-host-networks and network at the same time if {'allow_host_networks', 'network'} <= set(container_config): - raise ConfigError(f'"allow-host-networks" and "network" for "{name}" cannot be both configured at the same time!') + raise ConfigError( + f'"allow-host-networks" and "network" for "{name}" cannot be both configured at the same time!') # gid cannot be set without uid if 'gid' in container_config and 'uid' not in container_config: @@ -235,8 +248,10 @@ def verify(container): raise ConfigError(f'prefix for network "{network}" must be defined!') for prefix in network_config['prefix']: - if is_ipv4(prefix): v4_prefix += 1 - elif is_ipv6(prefix): v6_prefix += 1 + if is_ipv4(prefix): + v4_prefix += 1 + elif is_ipv6(prefix): + v6_prefix += 1 if v4_prefix > 1: raise ConfigError(f'Only one IPv4 prefix can be defined for network "{network}"!') @@ -262,6 +277,7 @@ def verify(container): return None + def generate_run_arguments(name, container_config): image = container_config['image'] cpu_quota = container_config['cpu_quota'] @@ -269,6 +285,12 @@ def generate_run_arguments(name, container_config): shared_memory = container_config['shared_memory'] restart = container_config['restart'] + # Add sysctl options + sysctl_opt = '' + if 'sysctl' in container_config and 'parameter' in container_config['sysctl']: + for k, v in container_config['sysctl']['parameter'].items(): + sysctl_opt += f" --sysctl {k}={v['value']}" + # Add capability options. Should be in uppercase capabilities = '' if 'capability' in container_config: @@ -341,7 +363,7 @@ def generate_run_arguments(name, container_config): if 'allow_host_pid' in container_config: host_pid = '--pid host' - container_base_cmd = f'--detach --interactive --tty --replace {capabilities} --cpus {cpu_quota} ' \ + container_base_cmd = f'--detach --interactive --tty --replace {capabilities} --cpus {cpu_quota} {sysctl_opt} ' \ f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \ f'--name {name} {hostname} {device} {port} {volume} {env_opt} {label} {uid} {host_pid}' @@ -375,6 +397,7 @@ def generate_run_arguments(name, container_config): return f'{container_base_cmd} --no-healthcheck --net {networks} {ip_param} {entrypoint} {image} {command} {command_arguments}'.strip() + def generate(container): # bail out early - looks like removal from running config if not container: @@ -387,7 +410,7 @@ def generate(container): for network, network_config in container['network'].items(): tmp = { 'name': network, - 'id' : sha256(f'{network}'.encode()).hexdigest(), + 'id': sha256(f'{network}'.encode()).hexdigest(), 'driver': 'bridge', 'network_interface': f'pod-{network}', 'subnets': [], @@ -399,7 +422,7 @@ def generate(container): } } for prefix in network_config['prefix']: - net = {'subnet' : prefix, 'gateway' : inc_ip(prefix, 1)} + net = {'subnet': prefix, 'gateway': inc_ip(prefix, 1)} tmp['subnets'].append(net) if is_ipv6(prefix): @@ -418,11 +441,12 @@ def generate(container): file_path = os.path.join(systemd_unit_path, f'vyos-container-{name}.service') run_args = generate_run_arguments(name, container_config) - render(file_path, 'container/systemd-unit.j2', {'name': name, 'run_args': run_args,}, + render(file_path, 'container/systemd-unit.j2', {'name': name, 'run_args': run_args, }, formater=lambda _: _.replace(""", '"').replace("'", "'")) return None + def apply(container): # Delete old containers if needed. We can't delete running container # Option "--force" allows to delete containers with any status @@ -485,6 +509,7 @@ def apply(container): return None + if __name__ == '__main__': try: c = get_config() diff --git a/src/conf_mode/nat_cgnat.py b/src/conf_mode/nat_cgnat.py index d429f6e21..cb336a35c 100755 --- a/src/conf_mode/nat_cgnat.py +++ b/src/conf_mode/nat_cgnat.py @@ -16,9 +16,11 @@ import ipaddress import jmespath +import logging import os from sys import exit +from logging.handlers import SysLogHandler from vyos.config import Config from vyos.template import render @@ -32,6 +34,18 @@ airbag.enable() nftables_cgnat_config = '/run/nftables-cgnat.nft' +# Logging +logger = logging.getLogger('cgnat') +logger.setLevel(logging.DEBUG) + +syslog_handler = SysLogHandler(address="/dev/log") +syslog_handler.setLevel(logging.INFO) + +formatter = logging.Formatter('%(name)s: %(message)s') +syslog_handler.setFormatter(formatter) + +logger.addHandler(syslog_handler) + class IPOperations: def __init__(self, ip_prefix: str): @@ -356,6 +370,22 @@ def apply(config): return None cmd(f'nft --file {nftables_cgnat_config}') + # Logging allocations + if 'log_allocation' in config: + allocations = config['proto_map_elements'] + allocations = allocations.split(',') + for allocation in allocations: + try: + # Split based on the delimiters used in the nft data format + internal_host, rest = allocation.split(' : ') + external_host, port_range = rest.split(' . ') + # Log the parsed data + logger.info( + f"Internal host: {internal_host.lstrip()}, external host: {external_host}, Port range: {port_range}") + except ValueError as e: + # Log error message + logger.error(f"Error processing line '{allocation}': {e}") + if __name__ == '__main__': try: diff --git a/src/op_mode/cpu.py b/src/op_mode/cpu.py index d53663c17..1a0f7392f 100755 --- a/src/op_mode/cpu.py +++ b/src/op_mode/cpu.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2016-2022 VyOS maintainers and contributors +# Copyright (C) 2016-2024 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 @@ -16,8 +16,9 @@ import sys -import vyos.cpu import vyos.opmode +from vyos.utils.cpu import get_cpus +from vyos.utils.cpu import get_core_count from jinja2 import Template @@ -37,15 +38,15 @@ CPU model(s): {{models | join(", ")}} """) def _get_raw_data(): - return vyos.cpu.get_cpus() + return get_cpus() def _format_cpus(cpu_data): env = {'cpus': cpu_data} return cpu_template.render(env).strip() def _get_summary_data(): - count = vyos.cpu.get_core_count() - cpu_data = vyos.cpu.get_cpus() + count = get_core_count() + cpu_data = get_cpus() models = [c['model name'] for c in cpu_data] env = {'count': count, "models": models} @@ -79,4 +80,3 @@ if __name__ == '__main__': except (ValueError, vyos.opmode.Error) as e: print(e) sys.exit(1) - diff --git a/src/op_mode/uptime.py b/src/op_mode/uptime.py index 059a4c3f6..559eed24c 100755 --- a/src/op_mode/uptime.py +++ b/src/op_mode/uptime.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# Copyright (C) 2021-2024 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 as @@ -29,8 +29,8 @@ def _get_uptime_seconds(): def _get_load_averages(): from re import search + from vyos.utils.cpu import get_core_count from vyos.utils.process import cmd - from vyos.cpu import get_core_count data = cmd("uptime") matches = search(r"load average:\s*(?P<one>[0-9\.]+)\s*,\s*(?P<five>[0-9\.]+)\s*,\s*(?P<fifteen>[0-9\.]+)\s*", data) |