diff options
-rw-r--r-- | .github/workflows/pr-auto-close.yml | 18 | ||||
-rw-r--r-- | .github/workflows/trigger-rebuild-repo-package.yml | 32 | ||||
-rw-r--r-- | Jenkinsfile | 2 | ||||
-rw-r--r-- | data/templates/rsyslog/rsyslog.conf.j2 | 10 | ||||
-rw-r--r-- | interface-definitions/policy.xml.in | 48 | ||||
-rw-r--r-- | interface-definitions/service_lldp.xml.in | 4 | ||||
-rw-r--r-- | interface-definitions/system_option.xml.in | 8 | ||||
-rw-r--r-- | interface-definitions/system_syslog.xml.in | 6 | ||||
-rw-r--r-- | op-mode-definitions/date.xml.in | 2 | ||||
-rw-r--r-- | smoketest/scripts/cli/base_accel_ppp_test.py | 6 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_snmp.py | 14 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_syslog.py | 33 | ||||
-rwxr-xr-x | src/conf_mode/protocols_static.py | 2 | ||||
-rwxr-xr-x | src/conf_mode/service_snmp.py | 13 | ||||
-rwxr-xr-x | src/conf_mode/system_syslog.py | 20 | ||||
-rw-r--r-- | src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper | 18 |
16 files changed, 220 insertions, 16 deletions
diff --git a/.github/workflows/pr-auto-close.yml b/.github/workflows/pr-auto-close.yml new file mode 100644 index 000000000..947108805 --- /dev/null +++ b/.github/workflows/pr-auto-close.yml @@ -0,0 +1,18 @@ +name: Auto-Close Pull Requests Sagitta + +on: + pull_request_target: + types: + - opened + branches: + - sagitta + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + with: + # Optional. Post a issue comment just before closing a pull request. + comment: "Pull requests to this branch are not accepted and have been closed automatically." + github_token: ${{ secrets.PAT }} diff --git a/.github/workflows/trigger-rebuild-repo-package.yml b/.github/workflows/trigger-rebuild-repo-package.yml new file mode 100644 index 000000000..f267a6316 --- /dev/null +++ b/.github/workflows/trigger-rebuild-repo-package.yml @@ -0,0 +1,32 @@ +name: Trigger to build a deb package from repo + +on: + pull_request_target: + types: + - closed + branches: + - sagitta + workflow_dispatch: + +jobs: + get_repo_name: + runs-on: ubuntu-latest + outputs: + PACKAGE_NAME: ${{ steps.package_name.outputs.PACKAGE_NAME }} + steps: + - name: Set variables + id: package_name + run: | + echo "PACKAGE_NAME=$(basename ${{ github.repository }})" >> $GITHUB_OUTPUT + + trigger-build: + needs: get_repo_name + uses: vyos/.github/.github/workflows/trigger-rebuild-repo-package.yml@sagitta + with: + branch: ${{ github.ref_name }} + package_name: ${{ needs.get_repo_name.outputs.PACKAGE_NAME }} + secrets: + REMOTE_OWNER: ${{ secrets.REMOTE_OWNER }} + REMOTE_REUSE_REPO: ${{ secrets.REMOTE_REUSE_REPO }} + GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} + PAT: ${{ secrets.PAT }} diff --git a/Jenkinsfile b/Jenkinsfile index 21a6829c0..50a97e688 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,7 +17,7 @@ // Using a version specifier library, use 'current' branch. The underscore (_) // is not a typo! You need this underscore if the line immediately after the // @Library annotation is not an import statement! -@Library('vyos-build@current')_ +@Library('vyos-build@sagitta')_ // Start package build using library function from https://github.com/vyos/vyos-build buildPackage(null, null, null, true) diff --git a/data/templates/rsyslog/rsyslog.conf.j2 b/data/templates/rsyslog/rsyslog.conf.j2 index 97e0ee0b7..7fd592d1f 100644 --- a/data/templates/rsyslog/rsyslog.conf.j2 +++ b/data/templates/rsyslog/rsyslog.conf.j2 @@ -10,6 +10,10 @@ $MarkMessagePeriod {{ global.marker.interval }} $PreserveFQDN on {% endif %} +{% if global.local_host_name is vyos_defined %} +$LocalHostName {{ global.local_host_name }} +{% endif %} + # We always log to /var/log/messages $outchannel global,/var/log/messages,262144,/usr/sbin/logrotate {{ logrotate }} {% if global.facility is vyos_defined %} @@ -54,12 +58,10 @@ $outchannel {{ file_name }},/var/log/user/{{ file_name }},{{ file_options.archiv {% endif %} {% if host_options.protocol is vyos_defined('tcp') %} {% if host_options.format.octet_counted is vyos_defined %} -{{ tmp | join(';') }} @@(o){{ host_name | bracketize_ipv6 }}:{{ host_options.port }};RSYSLOG_SyslogProtocol23Format -{% else %} -{{ tmp | join(';') }} @@{{ host_name | bracketize_ipv6 }}:{{ host_options.port }} +{{ tmp | join(';') }} @@{{ '(o)' if host_options.format.octet_counted is vyos_defined }}{{ host_name | bracketize_ipv6 }}:{{ host_options.port }}{{ ';RSYSLOG_SyslogProtocol23Format' if host_options.format.include_timezone is vyos_defined }} {% endif %} {% else %} -{{ tmp | join(';') }} @{{ host_name | bracketize_ipv6 }}:{{ host_options.port }}{{ ';RSYSLOG_SyslogProtocol23Format' if host_options.format.octet_counted is vyos_defined }} +{{ tmp | join(';') }} @{{ host_name | bracketize_ipv6 }}:{{ host_options.port }}{{ ';RSYSLOG_SyslogProtocol23Format' if host_options.format.include_timezone is vyos_defined }} {% endif %} {% endfor %} {% endif %} diff --git a/interface-definitions/policy.xml.in b/interface-definitions/policy.xml.in index 791fa1d87..4b5b609c5 100644 --- a/interface-definitions/policy.xml.in +++ b/interface-definitions/policy.xml.in @@ -202,11 +202,11 @@ <properties> <help>Regular expression to match against a community-list</help> <completionHelp> - <list>local-AS no-advertise no-export internet additive</list> + <list>local-AS no-advertise no-export internet graceful-shutdown accept-own-nexthop accept-own route-filter-translated-v4 route-filter-v4 route-filter-translated-v6 route-filter-v6 llgr-stale no-llgr blackhole no-peer additive</list> </completionHelp> <valueHelp> <format><aa:nn></format> - <description>Community number in AA:NN format</description> + <description>Community number in AA:NN format where AA and NN are (0-65535)</description> </valueHelp> <valueHelp> <format>local-AS</format> @@ -225,6 +225,50 @@ <description>Well-known communities value 0</description> </valueHelp> <valueHelp> + <format>graceful-shutdown</format> + <description>Well-known communities value GRACEFUL_SHUTDOWN 0xFFFF0000</description> + </valueHelp> + <valueHelp> + <format>accept-own-nexthop</format> + <description>Well-known communities value ACCEPT_OWN_NEXTHOP 0xFFFF0008</description> + </valueHelp> + <valueHelp> + <format>accept-own</format> + <description>Well-known communities value ACCEPT_OWN 0xFFFF0001 65535:1</description> + </valueHelp> + <valueHelp> + <format>route-filter-translated-v4</format> + <description>Well-known communities value ROUTE_FILTER_TRANSLATED_v4 0xFFFF0002 65535:2</description> + </valueHelp> + <valueHelp> + <format>route-filter-v4</format> + <description>Well-known communities value ROUTE_FILTER_v4 0xFFFF0003 65535:3</description> + </valueHelp> + <valueHelp> + <format>route-filter-translated-v6</format> + <description>Well-known communities value ROUTE_FILTER_TRANSLATED_v6 0xFFFF0004 65535:4</description> + </valueHelp> + <valueHelp> + <format>route-filter-v6</format> + <description>Well-known communities value ROUTE_FILTER_v6 0xFFFF0005 65535:5</description> + </valueHelp> + <valueHelp> + <format>llgr-stale</format> + <description>Well-known communities value LLGR_STALE 0xFFFF0006 65535:6</description> + </valueHelp> + <valueHelp> + <format>no-llgr</format> + <description>Well-known communities value NO_LLGR 0xFFFF0007 65535:7</description> + </valueHelp> + <valueHelp> + <format>blackhole</format> + <description>Well-known communities value BLACKHOLE 0xFFFF029A 65535:666</description> + </valueHelp> + <valueHelp> + <format>no-peer</format> + <description>Well-known communities value NOPEER 0xFFFFFF04 65535:65284</description> + </valueHelp> + <valueHelp> <format>additive</format> <description>New value is appended to the existing value</description> </valueHelp> diff --git a/interface-definitions/service_lldp.xml.in b/interface-definitions/service_lldp.xml.in index 1a06e0cb3..51a9f9cce 100644 --- a/interface-definitions/service_lldp.xml.in +++ b/interface-definitions/service_lldp.xml.in @@ -23,6 +23,10 @@ <script>${vyos_completion_dir}/list_interfaces</script> <list>all</list> </completionHelp> + <constraint> + #include <include/constraint/interface-name.xml.i> + <regex>all</regex> + </constraint> </properties> <children> #include <include/generic-disable-node.xml.i> diff --git a/interface-definitions/system_option.xml.in b/interface-definitions/system_option.xml.in index e78a53552..1d2e8c880 100644 --- a/interface-definitions/system_option.xml.in +++ b/interface-definitions/system_option.xml.in @@ -68,7 +68,7 @@ <properties> <help>System keyboard layout, type ISO2</help> <completionHelp> - <list>us uk fr de es fi jp106 no dk se-latin1 dvorak</list> + <list>us uk fr de es fi it jp106 no dk se-latin1 dvorak</list> </completionHelp> <valueHelp> <format>us</format> @@ -95,6 +95,10 @@ <description>Finland</description> </valueHelp> <valueHelp> + <format>it</format> + <description>Italy</description> + </valueHelp> + <valueHelp> <format>jp106</format> <description>Japan</description> </valueHelp> @@ -115,7 +119,7 @@ <description>Dvorak</description> </valueHelp> <constraint> - <regex>(us|uk|fr|de|es|fi|jp106|no|dk|se-latin1|dvorak)</regex> + <regex>(us|uk|fr|de|es|fi|it|jp106|no|dk|se-latin1|dvorak)</regex> </constraint> <constraintErrorMessage>Invalid keyboard layout</constraintErrorMessage> </properties> diff --git a/interface-definitions/system_syslog.xml.in b/interface-definitions/system_syslog.xml.in index 3343e2c59..0a9a00572 100644 --- a/interface-definitions/system_syslog.xml.in +++ b/interface-definitions/system_syslog.xml.in @@ -66,6 +66,12 @@ <valueless/> </properties> </leafNode> + <leafNode name="include-timezone"> + <properties> + <help>Include system timezone in syslog message</help> + <valueless/> + </properties> + </leafNode> </children> </node> </children> diff --git a/op-mode-definitions/date.xml.in b/op-mode-definitions/date.xml.in index 6d8586025..4e62a8335 100644 --- a/op-mode-definitions/date.xml.in +++ b/op-mode-definitions/date.xml.in @@ -35,7 +35,7 @@ <list><MMDDhhmm> <MMDDhhmmYY> <MMDDhhmmCCYY> <MMDDhhmmCCYY.ss></list> </completionHelp> </properties> - <command>/bin/date "$3"</command> + <command>sudo bash -c "/bin/date '$3' && hwclock --systohc --localtime"</command> </tagNode> </children> </node> diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py index c6f6cb804..750702e98 100644 --- a/smoketest/scripts/cli/base_accel_ppp_test.py +++ b/smoketest/scripts/cli/base_accel_ppp_test.py @@ -14,6 +14,7 @@ import re +from time import sleep from base_vyostest_shim import VyOSUnitTestSHIM from configparser import ConfigParser @@ -641,6 +642,11 @@ delegate={delegate_2_prefix},{delegate_mask},name={pool_name}""" for log_level in range(0, 5): self.set(['log', 'level', str(log_level)]) self.cli_commit() + + # Systemd comes with a default of 5 restarts in 10 seconds policy, + # this limit can be hit by this reastart sequence, slow down a bit + sleep(5) + # Validate configuration values conf = ConfigParser(allow_no_value=True) conf.read(self._config_file) diff --git a/smoketest/scripts/cli/test_service_snmp.py b/smoketest/scripts/cli/test_service_snmp.py index b3daa90d0..7d5eaa440 100755 --- a/smoketest/scripts/cli/test_service_snmp.py +++ b/smoketest/scripts/cli/test_service_snmp.py @@ -246,5 +246,19 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): for excluded in snmpv3_view_oid_exclude: self.assertIn(f'view {snmpv3_view} excluded .{excluded}', tmp) + def test_snmp_script_extensions(self): + extensions = { + 'default': 'snmp_smoketest_extension_script.sh', + 'external': '/run/external_snmp_smoketest_extension_script.sh' + } + + for key, val in extensions.items(): + self.cli_set(base_path + ['script-extensions', 'extension-name', key, 'script', val]) + self.cli_commit() + + self.assertEqual(get_config_value('extend default'), f'/config/user-data/{extensions["default"]}') + self.assertEqual(get_config_value('extend external'), extensions["external"]) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_syslog.py b/smoketest/scripts/cli/test_system_syslog.py index 45a5b4087..c802ceeeb 100755 --- a/smoketest/scripts/cli/test_system_syslog.py +++ b/smoketest/scripts/cli/test_system_syslog.py @@ -20,6 +20,7 @@ import unittest from base_vyostest_shim import VyOSUnitTestSHIM from vyos.utils.file import read_file +from vyos.utils.process import cmd from vyos.utils.process import process_named_running PROCESS_NAME = 'rsyslogd' @@ -61,19 +62,45 @@ class TestRSYSLOGService(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['host', host2, 'facility', 'kern', 'level', 'err']) self.cli_set(base_path + ['console', 'facility', 'all', 'level', 'warning']) - self.cli_commit() # verify log level and facilities in config file # *.warning /dev/console # *.* @198.51.100.1:999 # kern.err @192.0.2.1:514 - config = [get_config_value('\*.\*'), get_config_value('kern.err'), get_config_value('\*.warning')] + config = [ + get_config_value('\*.\*'), + get_config_value('kern.err'), + get_config_value('\*.warning'), + ] expected = [f'@{host1}:999', f'@{host2}:514', '/dev/console'] - for i in range(0,3): + for i in range(0, 3): self.assertIn(expected[i], config[i]) # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) + def test_syslog_global(self): + self.cli_set(['system', 'host-name', 'vyos']) + self.cli_set(['system', 'domain-name', 'example.local']) + self.cli_set(base_path + ['global', 'marker', 'interval', '600']) + self.cli_set(base_path + ['global', 'preserve-fqdn']) + self.cli_set(base_path + ['global', 'facility', 'kern', 'level', 'err']) + + self.cli_commit() + + config = cmd(f'sudo cat {RSYSLOG_CONF}') + expected = [ + '$MarkMessagePeriod 600', + '$PreserveFQDN on', + 'kern.err', + '$LocalHostName vyos.example.local', + ] + + for e in expected: + self.assertIn(e, config) + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index a2373218a..430cc69d4 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -88,7 +88,7 @@ def verify(static): if {'blackhole', 'reject'} <= set(prefix_options): raise ConfigError(f'Can not use both blackhole and reject for '\ - 'prefix "{prefix}"!') + f'prefix "{prefix}"!') return None diff --git a/src/conf_mode/service_snmp.py b/src/conf_mode/service_snmp.py index f65d0d6bc..24c180b98 100755 --- a/src/conf_mode/service_snmp.py +++ b/src/conf_mode/service_snmp.py @@ -39,6 +39,7 @@ config_file_client = r'/etc/snmp/snmp.conf' config_file_daemon = r'/etc/snmp/snmpd.conf' config_file_access = r'/usr/share/snmp/snmpd.conf' config_file_user = r'/var/lib/snmp/snmpd.conf' +default_script_dir = r'/config/user-data/' systemd_override = r'/run/systemd/system/snmpd.service.d/override.conf' systemd_service = 'snmpd.service' @@ -83,8 +84,20 @@ def get_config(config=None): tmp = {'::1': {'port': '161'}} snmp['listen_address'] = dict_merge(tmp, snmp['listen_address']) + if 'script_extensions' in snmp and 'extension_name' in snmp['script_extensions']: + for key, val in snmp['script_extensions']['extension_name'].items(): + if 'script' not in val: + continue + script_path = val['script'] + # if script has not absolute path, use pre configured path + if not os.path.isabs(script_path): + script_path = os.path.join(default_script_dir, script_path) + + snmp['script_extensions']['extension_name'][key]['script'] = script_path + return snmp + def verify(snmp): if 'deleted' in snmp: return None diff --git a/src/conf_mode/system_syslog.py b/src/conf_mode/system_syslog.py index 07fbb0734..eb2f02eb3 100755 --- a/src/conf_mode/system_syslog.py +++ b/src/conf_mode/system_syslog.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 @@ -18,6 +18,7 @@ import os from sys import exit +from vyos.base import Warning from vyos.config import Config from vyos.configdict import is_node_changed from vyos.configverify import verify_vrf @@ -52,12 +53,29 @@ def get_config(config=None): if syslog.from_defaults(['global']): del syslog['global'] + if ( + 'global' in syslog + and 'preserve_fqdn' in syslog['global'] + and conf.exists(['system', 'host-name']) + and conf.exists(['system', 'domain-name']) + ): + hostname = conf.return_value(['system', 'host-name']) + domain = conf.return_value(['system', 'domain-name']) + fqdn = f'{hostname}.{domain}' + syslog['global']['local_host_name'] = fqdn + return syslog def verify(syslog): if not syslog: return None + if 'host' in syslog: + for host, host_options in syslog['host'].items(): + if 'protocol' in host_options and host_options['protocol'] == 'udp': + if 'format' in host_options and 'octet_counted' in host_options['format']: + Warning(f'Syslog UDP transport for "{host}" should not use octet-counted format!') + verify_vrf(syslog) def generate(syslog): diff --git a/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper index 5d879471d..2a1c5a7b2 100644 --- a/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper +++ b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper @@ -72,6 +72,22 @@ function delroute () { fi } +# try to communicate with vtysh +function vtysh_conf () { + # perform 10 attempts with 1 second delay for retries + for i in {1..10} ; do + if vtysh -c "conf t" -c "$1" ; then + logmsg info "Command was executed successfully via vtysh: \"$1\"" + return 0 + else + logmsg info "Failed to send command to vtysh, retrying in 1 second" + sleep 1 + fi + done + logmsg error "Failed to execute command via vtysh after 10 attempts: \"$1\"" + return 1 +} + # replace ip command with this wrapper function ip () { # pass comand to system `ip` if this is not related to routes change @@ -84,7 +100,7 @@ function ip () { delroute ${@:4} iptovtysh $@ logmsg info "Sending command to vtysh" - vtysh -c "conf t" -c "$VTYSH_CMD" + vtysh_conf "$VTYSH_CMD" else # add ip route to kernel logmsg info "Modifying routes in kernel: \"/usr/sbin/ip $@\"" |