diff options
-rw-r--r-- | .github/workflows/build-package.yml | 17 | ||||
-rw-r--r-- | .github/workflows/package-smoketest.yml | 106 | ||||
-rw-r--r-- | data/configd-include.json | 1 | ||||
-rw-r--r-- | data/templates/firewall/nftables.j2 | 2 | ||||
-rw-r--r-- | op-mode-definitions/restart-ssh.xml.in | 2 | ||||
-rw-r--r-- | python/vyos/config_mgmt.py | 4 | ||||
-rw-r--r-- | python/vyos/utils/system.py | 32 | ||||
-rwxr-xr-x | src/conf_mode/service_snmp.py | 28 | ||||
-rwxr-xr-x | src/op_mode/powerctrl.py | 2 | ||||
-rwxr-xr-x | src/op_mode/uptime.py | 33 |
10 files changed, 162 insertions, 65 deletions
diff --git a/.github/workflows/build-package.yml b/.github/workflows/build-package.yml deleted file mode 100644 index 0200aceb4..000000000 --- a/.github/workflows/build-package.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Debian Package Build -on: - pull_request: - branches: - - current - -jobs: - package-build: - runs-on: ubuntu-latest - container: - image: vyos/vyos-build:current - options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Build Debian package - run: dpkg-buildpackage -uc -us -tc -b diff --git a/.github/workflows/package-smoketest.yml b/.github/workflows/package-smoketest.yml new file mode 100644 index 000000000..49bd91669 --- /dev/null +++ b/.github/workflows/package-smoketest.yml @@ -0,0 +1,106 @@ +name: Package ISO Test + +on: + pull_request: + branches: + - current + +jobs: + build: + runs-on: ubuntu-24.04 + container: + image: vyos/vyos-build:current + options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged + env: + BUILD_BY: autobuild@vyos.net + DEBIAN_MIRROR: http://deb.debian.org/debian/ + outputs: + build_version: ${{ steps.version.outputs.build_version }} + steps: + - name: Clone vyos-build source code + uses: actions/checkout@v4 + with: + repository: vyos/vyos-build + - name: Clone vyos-1x source code + uses: actions/checkout@v4 + with: + repository: vyos/vyos-1x + path: packages/vyos-1x + fetch-tags: true # required for Debian package version + - name: Build vyos-1x package + run: | + cd packages/vyos-1x; dpkg-buildpackage -uc -us -tc -b + - name: Generate ISO version string + id: version + run: | + echo "build_version=1.5-integration-$(date -u +%Y%m%d%H%M)" >> $GITHUB_OUTPUT + - name: Build custom ISO image + run: | + sudo --preserve-env ./build-vyos-image \ + --architecture amd64 \ + --build-by $BUILD_BY \ + --debian-mirror $DEBIAN_MIRROR \ + --version ${{ steps.version.outputs.build_version }} \ + --build-type release \ + generic + - uses: actions/upload-artifact@v4 + with: + name: vyos-${{ steps.version.outputs.build_version }} + path: build/live-image-amd64.hybrid.iso + + cli-smoketests: + needs: build + runs-on: ubuntu-24.04 + container: + image: vyos/vyos-build:current + options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged + steps: + # We need the test script from vyos-build repo + - name: Clone vyos-build source code + uses: actions/checkout@v4 + with: + repository: vyos/vyos-build + - uses: actions/download-artifact@v4 + with: + name: vyos-${{ needs.build.outputs.build_version }} + path: build + - name: VyOS CLI smoketests + run: ls -al; ls -al build; sudo make test + + config-load-tests: + needs: build + runs-on: ubuntu-24.04 + container: + image: vyos/vyos-build:current + options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged + steps: + # We need the test script from vyos-build repo + - name: Clone vyos-build source code + uses: actions/checkout@v4 + with: + repository: vyos/vyos-build + - uses: actions/download-artifact@v4 + with: + name: vyos-${{ needs.build.outputs.build_version }} + path: build + - name: VyOS config tests + run: sudo make testc + + raid1-install-test: + needs: build + runs-on: ubuntu-24.04 + container: + image: vyos/vyos-build:current + options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged + steps: + # We need the test script from vyos-build repo + - name: Clone vyos-build source code + uses: actions/checkout@v4 + with: + repository: vyos/vyos-build + - uses: actions/download-artifact@v4 + with: + name: vyos-${{ needs.build.outputs.build_version }} + path: build + - name: VyOS RAID1 install test + run: sudo make testraid diff --git a/data/configd-include.json b/data/configd-include.json index 633d898a5..b92d58c72 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -79,6 +79,7 @@ "service_router-advert.py", "service_salt-minion.py", "service_sla.py", +"service_snmp.py", "service_ssh.py", "service_tftp-server.py", "service_webproxy.py", diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2 index 343917fee..ee34f58fc 100644 --- a/data/templates/firewall/nftables.j2 +++ b/data/templates/firewall/nftables.j2 @@ -86,7 +86,7 @@ table ip vyos_filter { {% for prior, conf in ipv4.output.items() %} chain VYOS_OUTPUT_{{ prior }} { type filter hook output priority {{ prior }}; policy accept; -{% if global_options.state_policy is vyos_defined %} +{% if global_options.state_policy is vyos_defined and prior == 'filter' %} jump VYOS_STATE_POLICY {% endif %} {% if conf.rule is vyos_defined %} diff --git a/op-mode-definitions/restart-ssh.xml.in b/op-mode-definitions/restart-ssh.xml.in index 6504cc18a..543cafc24 100644 --- a/op-mode-definitions/restart-ssh.xml.in +++ b/op-mode-definitions/restart-ssh.xml.in @@ -6,7 +6,7 @@ <properties> <help>Restart SSH service</help> </properties> - <command>if cli-shell-api existsActive service ssh; then sudo systemctl restart ssh.service; else echo "Service SSH not configured"; fi</command> + <command>if cli-shell-api existsActive service ssh; then sudo systemctl restart "ssh@*.service"; else echo "Service SSH not configured"; fi</command> </node> </children> </node> diff --git a/python/vyos/config_mgmt.py b/python/vyos/config_mgmt.py index 70b6ea203..d518737ca 100644 --- a/python/vyos/config_mgmt.py +++ b/python/vyos/config_mgmt.py @@ -81,9 +81,11 @@ def save_config(target, json_out=None): if rc != 0: logger.critical(f'save config failed: {out}') -def unsaved_commits() -> bool: +def unsaved_commits(allow_missing_config=False) -> bool: if get_full_version_data()['boot_via'] == 'livecd': return False + if allow_missing_config and not os.path.exists(config_file): + return True tmp_save = '/tmp/config.running' save_config(tmp_save) ret = not cmp(tmp_save, config_file, shallow=False) diff --git a/python/vyos/utils/system.py b/python/vyos/utils/system.py index 55813a5f7..f427032a4 100644 --- a/python/vyos/utils/system.py +++ b/python/vyos/utils/system.py @@ -1,4 +1,4 @@ -# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2023-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 @@ -98,3 +98,33 @@ def load_as_module(name: str, path: str): mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod + +def get_uptime_seconds(): + """ Returns system uptime in seconds """ + from re import search + from vyos.utils.file import read_file + + data = read_file("/proc/uptime") + seconds = search(r"([0-9\.]+)\s", data).group(1) + res = int(float(seconds)) + + return res + +def get_load_averages(): + """ Returns load averages for 1, 5, and 15 minutes as a dict """ + from re import search + from vyos.utils.file import read_file + from vyos.utils.cpu import get_core_count + + data = read_file("/proc/loadavg") + matches = search(r"\s*(?P<one>[0-9\.]+)\s+(?P<five>[0-9\.]+)\s+(?P<fifteen>[0-9\.]+)\s*", data) + + core_count = get_core_count() + + res = {} + res[1] = float(matches["one"]) / core_count + res[5] = float(matches["five"]) / core_count + res[15] = float(matches["fifteen"]) / core_count + + return res + diff --git a/src/conf_mode/service_snmp.py b/src/conf_mode/service_snmp.py index 6565ffd60..6f025cc23 100755 --- a/src/conf_mode/service_snmp.py +++ b/src/conf_mode/service_snmp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018-2023 VyOS maintainers and contributors +# Copyright (C) 2018-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 @@ -26,10 +26,12 @@ from vyos.snmpv3_hashgen import plaintext_to_md5 from vyos.snmpv3_hashgen import plaintext_to_sha1 from vyos.snmpv3_hashgen import random from vyos.template import render -from vyos.utils.process import call -from vyos.utils.permission import chmod_755 +from vyos.utils.configfs import delete_cli_node +from vyos.utils.configfs import add_cli_node from vyos.utils.dict import dict_search from vyos.utils.network import is_addr_assigned +from vyos.utils.process import call +from vyos.utils.permission import chmod_755 from vyos.version import get_version_data from vyos import ConfigError from vyos import airbag @@ -192,12 +194,8 @@ def generate(snmp): return None if 'v3' in snmp: - # net-snmp is now regenerating the configuration file in the background - # thus we need to re-open and re-read the file as the content changed. - # After that we can no read the encrypted password from the config and - # replace the CLI plaintext password with its encrypted version. - os.environ['vyos_libexec_dir'] = '/usr/libexec/vyos' - + # SNMPv3 uses a hashed password. If CLI defines a plaintext password, + # we will hash it in the background and replace the CLI node! if 'user' in snmp['v3']: for user, user_config in snmp['v3']['user'].items(): if dict_search('auth.type', user_config) == 'sha': @@ -212,8 +210,9 @@ def generate(snmp): snmp['v3']['user'][user]['auth']['encrypted_password'] = tmp del snmp['v3']['user'][user]['auth']['plaintext_password'] - call(f'/opt/vyatta/sbin/my_set service snmp v3 user "{user}" auth encrypted-password "{tmp}" > /dev/null') - call(f'/opt/vyatta/sbin/my_delete service snmp v3 user "{user}" auth plaintext-password > /dev/null') + cli_base = ['service', 'snmp', 'v3', 'user', user, 'auth'] + delete_cli_node(cli_base + ['plaintext-password']) + add_cli_node(cli_base + ['encrypted-password'], value=tmp) if dict_search('privacy.plaintext_password', user_config) is not None: tmp = hash(dict_search('privacy.plaintext_password', user_config), @@ -222,8 +221,9 @@ def generate(snmp): snmp['v3']['user'][user]['privacy']['encrypted_password'] = tmp del snmp['v3']['user'][user]['privacy']['plaintext_password'] - call(f'/opt/vyatta/sbin/my_set service snmp v3 user "{user}" privacy encrypted-password "{tmp}" > /dev/null') - call(f'/opt/vyatta/sbin/my_delete service snmp v3 user "{user}" privacy plaintext-password > /dev/null') + cli_base = ['service', 'snmp', 'v3', 'user', user, 'privacy'] + delete_cli_node(cli_base + ['plaintext-password']) + add_cli_node(cli_base + ['encrypted-password'], value=tmp) # Write client config file render(config_file_client, 'snmp/etc.snmp.conf.j2', snmp) @@ -246,7 +246,7 @@ def apply(snmp): return None # start SNMP daemon - call(f'systemctl restart {systemd_service}') + call(f'systemctl reload-or-restart {systemd_service}') # Enable AgentX in FRR # This should be done for each daemon individually because common command diff --git a/src/op_mode/powerctrl.py b/src/op_mode/powerctrl.py index 6c8f802b5..cb4a175dd 100755 --- a/src/op_mode/powerctrl.py +++ b/src/op_mode/powerctrl.py @@ -110,7 +110,7 @@ def check_unsaved_config(): from vyos.config_mgmt import unsaved_commits from vyos.utils.boot import boot_configuration_success - if unsaved_commits() and boot_configuration_success(): + if unsaved_commits(allow_missing_config=True) and boot_configuration_success(): print("Warning: there are unsaved configuration changes!") print("Run 'save' command if you do not want to lose those changes after reboot/shutdown.") else: diff --git a/src/op_mode/uptime.py b/src/op_mode/uptime.py index 559eed24c..1c1a149ec 100755 --- a/src/op_mode/uptime.py +++ b/src/op_mode/uptime.py @@ -18,39 +18,14 @@ import sys import vyos.opmode -def _get_uptime_seconds(): - from re import search - from vyos.utils.file import read_file - - data = read_file("/proc/uptime") - seconds = search("([0-9\.]+)\s", data).group(1) - - return int(float(seconds)) - -def _get_load_averages(): - from re import search - from vyos.utils.cpu import get_core_count - from vyos.utils.process import cmd - - 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) - - core_count = get_core_count() - - res = {} - res[1] = float(matches["one"]) / core_count - res[5] = float(matches["five"]) / core_count - res[15] = float(matches["fifteen"]) / core_count - - return res - def _get_raw_data(): + from vyos.utils.system import get_uptime_seconds, get_load_averages from vyos.utils.convert import seconds_to_human res = {} - res["uptime_seconds"] = _get_uptime_seconds() - res["uptime"] = seconds_to_human(_get_uptime_seconds(), separator=' ') - res["load_average"] = _get_load_averages() + uptime_seconds = get_uptime_seconds() + res["uptime"] = seconds_to_human(uptime_seconds, separator=' ') + res["load_average"] = get_load_averages() return res |