summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert <rgingras@mieweb.com>2025-02-10 10:51:12 -0500
committerGitHub <noreply@github.com>2025-02-10 10:51:12 -0500
commitf400eec4f40a814baba82f8a6d5755bdfd69f120 (patch)
tree729d57c54de53bc7d2f97d436496dd636d5b4045
parenta24d2f87fdde466625d9b6173657f07cf4401f30 (diff)
parent41e9b8b362faedc0c20316255d59d7f90e848a4c (diff)
downloadvyos-1x-f400eec4f40a814baba82f8a6d5755bdfd69f120.tar.gz
vyos-1x-f400eec4f40a814baba82f8a6d5755bdfd69f120.zip
Merge branch 'current' into T7095_vrf-fix
-rw-r--r--CODEOWNERS2
-rw-r--r--data/templates/frr/nhrpd.frr.j22
-rw-r--r--data/templates/frr/staticd.frr.j24
-rw-r--r--data/templates/load-balancing/haproxy.cfg.j25
-rw-r--r--data/templates/rsyslog/override.conf.j211
-rw-r--r--data/templates/rsyslog/rsyslog.conf.j2164
-rw-r--r--debian/control8
-rw-r--r--debian/vyos-1x.install1
-rw-r--r--debian/vyos-1x.preinst1
-rw-r--r--interface-definitions/include/version/system-version.xml.i2
-rw-r--r--interface-definitions/load-balancing_haproxy.xml.in32
-rw-r--r--interface-definitions/system_syslog.xml.in118
-rw-r--r--python/vyos/configdict.py12
-rw-r--r--python/vyos/configsession.py4
-rw-r--r--python/vyos/defaults.py7
-rw-r--r--python/vyos/ifconfig/interface.py69
-rw-r--r--python/vyos/ifconfig/wireguard.py5
-rw-r--r--python/vyos/utils/cpu.py15
-rw-r--r--python/vyos/utils/misc.py2
-rw-r--r--python/vyos/utils/process.py2
-rwxr-xr-xpython/vyos/xml_ref/generate_op_cache.py95
-rw-r--r--smoketest/config-tests/basic-api-service4
-rw-r--r--smoketest/config-tests/basic-syslog25
-rw-r--r--smoketest/config-tests/basic-vyos18
-rw-r--r--smoketest/config-tests/basic-vyos-no-ntp4
-rw-r--r--smoketest/config-tests/bgp-azure-ipsec-gateway8
-rw-r--r--smoketest/config-tests/bgp-bfd-communities4
-rw-r--r--smoketest/config-tests/bgp-big-as-cloud4
-rw-r--r--smoketest/config-tests/bgp-dmvpn-hub4
-rw-r--r--smoketest/config-tests/bgp-dmvpn-spoke4
-rw-r--r--smoketest/config-tests/bgp-evpn-l2vpn-leaf4
-rw-r--r--smoketest/config-tests/bgp-evpn-l2vpn-spine4
-rw-r--r--smoketest/config-tests/bgp-evpn-l3vpn-pe-router4
-rw-r--r--smoketest/config-tests/bgp-medium-confederation4
-rw-r--r--smoketest/config-tests/bgp-rpki4
-rw-r--r--smoketest/config-tests/bgp-small-internet-exchange4
-rw-r--r--smoketest/config-tests/bgp-small-ipv4-unicast4
-rw-r--r--smoketest/config-tests/cluster-basic4
-rw-r--r--smoketest/config-tests/dialup-router-complex6
-rw-r--r--smoketest/config-tests/dialup-router-medium-vpn6
-rw-r--r--smoketest/config-tests/dialup-router-wireguard-ipv66
-rw-r--r--smoketest/config-tests/egp-igp-route-maps2
-rw-r--r--smoketest/config-tests/igmp-pim-small4
-rw-r--r--smoketest/config-tests/ipoe-server4
-rw-r--r--smoketest/config-tests/ipv6-disable4
-rw-r--r--smoketest/config-tests/isis-small4
-rw-r--r--smoketest/config-tests/nat-basic4
-rw-r--r--smoketest/config-tests/ospf-simple4
-rw-r--r--smoketest/config-tests/ospf-small4
-rw-r--r--smoketest/config-tests/pppoe-server4
-rw-r--r--smoketest/config-tests/qos-basic4
-rw-r--r--smoketest/config-tests/rip-router4
-rw-r--r--smoketest/config-tests/rpki-only4
-rw-r--r--smoketest/config-tests/static-route-basic4
-rw-r--r--smoketest/config-tests/tunnel-broker4
-rw-r--r--smoketest/config-tests/vpn-openconnect-sstp4
-rw-r--r--smoketest/config-tests/vrf-basic4
-rw-r--r--smoketest/config-tests/vrf-bgp-pppoe-underlay4
-rw-r--r--smoketest/config-tests/vrf-ospf4
-rw-r--r--smoketest/config-tests/wireless-basic4
-rw-r--r--smoketest/configs/basic-syslog70
-rw-r--r--smoketest/configs/basic-vyos4
-rw-r--r--smoketest/scripts/cli/base_interfaces_test.py47
-rw-r--r--smoketest/scripts/cli/base_vyostest_shim.py7
-rwxr-xr-xsmoketest/scripts/cli/test_load-balancing_haproxy.py23
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_nhrp.py3
-rwxr-xr-xsmoketest/scripts/cli/test_system_syslog.py260
-rw-r--r--src/conf_mode/load-balancing_haproxy.py7
-rwxr-xr-xsrc/conf_mode/service_snmp.py3
-rwxr-xr-xsrc/conf_mode/system_host-name.py9
-rwxr-xr-xsrc/conf_mode/system_option.py2
-rwxr-xr-xsrc/conf_mode/system_syslog.py86
-rwxr-xr-xsrc/etc/netplug/vyos-netplug-dhcp-client32
-rw-r--r--src/etc/rsyslog.conf67
-rw-r--r--src/etc/systemd/system/rsyslog.service.d/override.conf10
-rwxr-xr-xsrc/init/vyos-router1
-rw-r--r--src/migration-scripts/system/28-to-2971
-rwxr-xr-xsrc/op_mode/image_installer.py70
-rwxr-xr-xsrc/services/vyos-configd44
-rwxr-xr-xsrc/services/vyos-domain-resolver65
-rw-r--r--src/validators/ethernet-interface13
81 files changed, 1057 insertions, 597 deletions
diff --git a/CODEOWNERS b/CODEOWNERS
index 4891a0325..2b5fe1299 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,2 +1,2 @@
# Users from reviewers github team
-* @dmbaturin @sarthurdev @jestabro @sever-sever @c-po @fett0 @nicolas-fort @zdc
+* @dmbaturin @sarthurdev @jestabro @sever-sever @c-po
diff --git a/data/templates/frr/nhrpd.frr.j2 b/data/templates/frr/nhrpd.frr.j2
index 2b2aba256..813a9384b 100644
--- a/data/templates/frr/nhrpd.frr.j2
+++ b/data/templates/frr/nhrpd.frr.j2
@@ -58,5 +58,3 @@ exit
{% endfor %}
{% endif %}
!
-exit
-!
diff --git a/data/templates/frr/staticd.frr.j2 b/data/templates/frr/staticd.frr.j2
index 90d17ec14..18d300dae 100644
--- a/data/templates/frr/staticd.frr.j2
+++ b/data/templates/frr/staticd.frr.j2
@@ -94,14 +94,14 @@ vrf {{ vrf }}
{% if pppoe is vyos_defined %}
{% for interface, interface_config in pppoe.items() if interface_config.no_default_route is not vyos_defined %}
{{ ip_prefix }} route 0.0.0.0/0 {{ interface }} tag 210 {{ interface_config.default_route_distance if interface_config.default_route_distance is vyos_defined }}
-{%- endfor %}
+{% endfor %}
{% endif %}
{# IPv6 routing #}
{% if route6 is vyos_defined %}
{% for prefix, prefix_config in route6.items() %}
{{ static_routes(ipv6_prefix, prefix, prefix_config) }}
{# j2lint: disable=jinja-statements-delimeter #}
-{%- endfor %}
+{% endfor %}
{% endif %}
{% if vrf is vyos_defined %}
exit-vrf
diff --git a/data/templates/load-balancing/haproxy.cfg.j2 b/data/templates/load-balancing/haproxy.cfg.j2
index 786ebfb21..c98b739e2 100644
--- a/data/templates/load-balancing/haproxy.cfg.j2
+++ b/data/templates/load-balancing/haproxy.cfg.j2
@@ -93,6 +93,11 @@ frontend {{ front }}
http-response set-header {{ header }} '{{ header_config['value'] }}'
{% endfor %}
{% endif %}
+{% if front_config.http_compression is vyos_defined %}
+ filter compression
+ compression algo {{ front_config.http_compression.algorithm }}
+ compression type {{ front_config.http_compression.mime_type | join(' ') }}
+{% endif %}
{% if front_config.rule is vyos_defined %}
{% for rule, rule_config in front_config.rule.items() %}
# rule {{ rule }}
diff --git a/data/templates/rsyslog/override.conf.j2 b/data/templates/rsyslog/override.conf.j2
deleted file mode 100644
index 5f6a87edf..000000000
--- a/data/templates/rsyslog/override.conf.j2
+++ /dev/null
@@ -1,11 +0,0 @@
-{% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' ' if vrf is vyos_defined else '' %}
-[Unit]
-StartLimitIntervalSec=0
-
-[Service]
-ExecStart=
-ExecStart={{ vrf_command }}/usr/sbin/rsyslogd -n -iNONE
-Restart=always
-RestartPreventExitStatus=
-RestartSec=10
-RuntimeDirectoryPreserve=yes
diff --git a/data/templates/rsyslog/rsyslog.conf.j2 b/data/templates/rsyslog/rsyslog.conf.j2
index 253a4bee2..c6eb6430c 100644
--- a/data/templates/rsyslog/rsyslog.conf.j2
+++ b/data/templates/rsyslog/rsyslog.conf.j2
@@ -1,78 +1,122 @@
### Autogenerated by system_syslog.py ###
-{% if global.marker is vyos_defined %}
-$ModLoad immark
-{% if global.marker.interval is vyos_defined %}
-$MarkMessagePeriod {{ global.marker.interval }}
-{% endif %}
-{% endif %}
-{% if global.preserve_fqdn is vyos_defined %}
-$PreserveFQDN on
-{% endif %}
+#### MODULES ####
+# Load input modules for local logging and kernel logging
-{% if global.local_host_name is vyos_defined %}
-$LocalHostName {{ global.local_host_name }}
-{% endif %}
+# Old-style log file format with low-precision timestamps
+# A modern-style logfile format with high-precision timestamps and timezone info
+# RSYSLOG_FileFormat
+module(load="builtin:omfile" Template="RSYSLOG_TraditionalFileFormat")
+module(load="imuxsock") # provides support for local system logging
+module(load="imklog") # provides kernel logging support
-# We always log to /var/log/messages
-$outchannel global,/var/log/messages,262144,/usr/sbin/logrotate {{ logrotate }}
-{% if global.facility is vyos_defined %}
-{% set tmp = [] %}
-{% for facility, facility_options in global.facility.items() %}
-{% set _ = tmp.append(facility.replace('all', '*') + '.' + facility_options.level.replace('all', '*')) %}
-{% endfor %}
-{{ tmp | join(';') }} :omfile:$global
+# Import logs from journald
+module(
+ load="imjournal"
+ StateFile="/var/spool/rsyslog/imjournal.state" # Persistent state file to track the journal cursor
+ Ratelimit.Interval="0" # Disable rate limiting (set to "0" for no limit)
+ RateLimit.Burst="0"
+)
+
+###########################
+#### GLOBAL DIRECTIVES ####
+###########################
+# Log specific programs to auth.log, then stop further processing
+if (
+ $programname == "CRON" or
+ $programname == "sudo" or
+ $programname == "su"
+) then {
+ action(type="omfile" file="/var/log/auth.log")
+ stop
+}
+
+global(workDirectory="/var/spool/rsyslog")
+
+###############
+#### RULES ####
+###############
+
+# Send emergency messages to all logged-in users
+*.emerg action(type="omusrmsg" users="*")
+
+{% if marker is vyos_defined %}
+# Load the immark module for periodic --MARK-- message capability
+module(load="immark" interval="{{ marker.interval }}")
+{% endif %}
+{% if preserve_fqdn is vyos_defined %}
+# Preserve the fully qualified domain name (FQDN) in log messages
+global(preserveFQDN="on")
+{% if preserve_fqdn.host_name is vyos_defined and preserve_fqdn.domain_name is vyos_defined %}
+# Set the local hostname for log messages
+global(localHostname="{{ preserve_fqdn.host_name }}.{{ preserve_fqdn.domain_name }}")
+{% endif %}
{% endif %}
-{% if file is vyos_defined %}
-# File based configuration section
-{% for file_name, file_options in file.items() %}
-{% set tmp = [] %}
-$outchannel {{ file_name }},/var/log/user/{{ file_name }},{{ file_options.archive.size }},/usr/sbin/logrotate {{ logrotate }}
-{% if file_options.facility is vyos_defined %}
-{% for facility, facility_options in file_options.facility.items() %}
-{% set _ = tmp.append(facility.replace('all', '*') + '.' + facility_options.level.replace('all', '*')) %}
-{% endfor %}
-{% endif %}
-{{ tmp | join(';') }} :omfile:${{ file }}
-{% endfor %}
+#### GLOBAL LOGGING ####
+{% if local.facility is vyos_defined %}
+{% set tmp = [] %}
+{% if local.facility is vyos_defined %}
+{% for facility, facility_options in local.facility.items() %}
+{% set _ = tmp.append(facility.replace('all', '*') ~ "." ~ facility_options.level.replace('all', 'debug')) %}
+{% endfor %}
+if prifilt("{{ tmp | join(',') }}") then {
+ action(
+ type="omfile"
+ file="/var/log/messages"
+ rotation.sizeLimit="524288" # 512Kib - maximum filesize before rotation
+ rotation.sizeLimitCommand="/usr/sbin/logrotate {{ logrotate }}"
+ )
+}
+{% endif %}
{% endif %}
+#### CONSOLE LOGGING ####
{% if console.facility is vyos_defined %}
-# Console logging
{% set tmp = [] %}
-{% for facility, facility_options in console.facility.items() %}
-{% set _ = tmp.append(facility.replace('all', '*') + '.' + facility_options.level.replace('all', '*')) %}
-{% endfor %}
-{{ tmp | join(';') }} /dev/console
+{% if console.facility is vyos_defined %}
+{% for facility, facility_options in console.facility.items() %}
+{% set _ = tmp.append(facility.replace('all', '*') ~ "." ~ facility_options.level.replace('all', 'debug')) %}
+{% endfor %}
+if prifilt("{{ tmp | join(',') }}") then {
+ action(type="omfile" file="/dev/console")
+}
+{% endif %}
{% endif %}
-{% if host is vyos_defined %}
-# Remote logging
-{% for host_name, host_options in host.items() %}
+#### REMOTE LOGGING ####
+{% if remote is vyos_defined %}
+{% for remote_name, remote_options in remote.items() %}
{% set tmp = [] %}
-{% if host_options.facility is vyos_defined %}
-{% for facility, facility_options in host_options.facility.items() %}
-{% set _ = tmp.append(facility.replace('all', '*') + '.' + facility_options.level.replace('all', '*')) %}
+{% if remote_options.facility is vyos_defined %}
+{% for facility, facility_options in remote_options.facility.items() %}
+{% set _ = tmp.append(facility.replace('all', '*') ~ "." ~ facility_options.level.replace('all', 'debug')) %}
{% endfor %}
-{% endif %}
-{% if host_options.protocol is vyos_defined('tcp') %}
-{{ 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 }}
-{% else %}
-{{ tmp | join(';') }} @{{ host_name | bracketize_ipv6 }}:{{ host_options.port }}{{ ';RSYSLOG_SyslogProtocol23Format' if host_options.format.include_timezone is vyos_defined }}
+{% set _ = tmp.sort() %}
+# Remote syslog to {{ remote_name }}
+if prifilt("{{ tmp | join(',') }}") then {
+ action(
+ type="omfwd"
+ # Remote syslog server where we send our logs to
+ target="{{ remote_name | bracketize_ipv6 }}"
+ # Port on the remote syslog server
+ port="{{ remote_options.port }}"
+ protocol="{{ remote_options.protocol }}"
+{% if remote_options.format.include_timezone is vyos_defined %}
+ template="SyslogProtocol23Format"
+{% endif %}
+ TCP_Framing="{{ 'octed-counted' if remote_options.format.octet_counted is vyos_defined else 'traditional' }}"
+{% if remote_options.source_address is vyos_defined %}
+ Address="{{ remote_options.source_address }}"
+{% endif %}
+{% if remote_options.vrf is vyos_defined %}
+ Device="{{ remote_options.vrf }}"
+{% endif %}
+ )
+}
{% endif %}
{% endfor %}
{% endif %}
-{% if user is defined and user is not none %}
-# Log to user terminal
-{% for username, user_options in user.items() %}
-{% set tmp = [] %}
-{% if user_options.facility is vyos_defined %}
-{% for facility, facility_options in user_options.facility.items() %}
-{% set _ = tmp.append(facility.replace('all', '*') + '.' + facility_options.level.replace('all', '*')) %}
-{% endfor %}
-{% endif %}
-{{ tmp | join(';') }} :omusrmsg:{{ username }}
-{% endfor %}
-{% endif %}
+# Include all configuration files in /etc/rsyslog.d/
+include(file="/etc/rsyslog.d/*.conf")
diff --git a/debian/control b/debian/control
index 76fe5c331..57709ea24 100644
--- a/debian/control
+++ b/debian/control
@@ -325,6 +325,14 @@ Depends:
# iptables is only used for containers now, not the the firewall CLI
iptables,
# End container
+# For "vpp"
+ libvppinfra,
+ python3-vpp-api,
+ vpp,
+ vpp-dev,
+ vpp-plugin-core,
+ vpp-plugin-dpdk,
+# End "vpp"
## End Configuration mode
## Operational mode
# Used for hypervisor model in "run show version"
diff --git a/debian/vyos-1x.install b/debian/vyos-1x.install
index 5fcff959a..4e312a648 100644
--- a/debian/vyos-1x.install
+++ b/debian/vyos-1x.install
@@ -9,7 +9,6 @@ etc/netplug
etc/opennhrp
etc/modprobe.d
etc/ppp
-etc/rsyslog.conf
etc/securetty
etc/security
etc/skel
diff --git a/debian/vyos-1x.preinst b/debian/vyos-1x.preinst
index fbfc85566..08f48cac2 100644
--- a/debian/vyos-1x.preinst
+++ b/debian/vyos-1x.preinst
@@ -5,6 +5,7 @@ dpkg-divert --package vyos-1x --add --no-rename /etc/logrotate.d/conntrackd
dpkg-divert --package vyos-1x --add --no-rename /etc/rsyslog.conf
dpkg-divert --package vyos-1x --add --no-rename /etc/skel/.bashrc
dpkg-divert --package vyos-1x --add --no-rename /etc/skel/.profile
+dpkg-divert --package vyos-1x --add --no-rename /etc/sysctl.d/80-vpp.conf
dpkg-divert --package vyos-1x --add --no-rename /etc/netplug/netplugd.conf
dpkg-divert --package vyos-1x --add --no-rename /etc/netplug/netplug
dpkg-divert --package vyos-1x --add --no-rename /etc/rsyslog.d/45-frr.conf
diff --git a/interface-definitions/include/version/system-version.xml.i b/interface-definitions/include/version/system-version.xml.i
index 3ecf124c7..5cdece74a 100644
--- a/interface-definitions/include/version/system-version.xml.i
+++ b/interface-definitions/include/version/system-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/system-version.xml.i -->
-<syntaxVersion component='system' version='28'></syntaxVersion>
+<syntaxVersion component='system' version='29'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/load-balancing_haproxy.xml.in b/interface-definitions/load-balancing_haproxy.xml.in
index 742272436..ca089d3f0 100644
--- a/interface-definitions/load-balancing_haproxy.xml.in
+++ b/interface-definitions/load-balancing_haproxy.xml.in
@@ -48,6 +48,38 @@
<valueless/>
</properties>
</leafNode>
+ <node name="http-compression">
+ <properties>
+ <help>Compress HTTP responses</help>
+ </properties>
+ <children>
+ <leafNode name="algorithm">
+ <properties>
+ <help>Compression algorithm</help>
+ <completionHelp>
+ <list>gzip deflate identity raw-deflate</list>
+ </completionHelp>
+ <constraint>
+ <regex>(gzip|deflate|identity|raw-deflate)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="mime-type">
+ <properties>
+ <help>MIME types to compress</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>MIME type to compress</description>
+ </valueHelp>
+ <multi/>
+ <constraint>
+ <regex>\w+\/[-+.\w]+</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid MIME type specified</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<node name="ssl">
<properties>
<help>SSL Certificate, SSL Key and CA</help>
diff --git a/interface-definitions/system_syslog.xml.in b/interface-definitions/system_syslog.xml.in
index 0a9a00572..91fb680e0 100644
--- a/interface-definitions/system_syslog.xml.in
+++ b/interface-definitions/system_syslog.xml.in
@@ -8,28 +8,17 @@
<priority>400</priority>
</properties>
<children>
- <tagNode name="user">
+ <node name="console">
<properties>
- <help>Logging to specific terminal of given user</help>
- <completionHelp>
- <path>system login user</path>
- </completionHelp>
- <valueHelp>
- <format>txt</format>
- <description>Local user account</description>
- </valueHelp>
- <constraint>
- #include <include/constraint/login-username.xml.i>
- </constraint>
- <constraintErrorMessage>illegal characters in user</constraintErrorMessage>
+ <help>Log to system console (/dev/console)</help>
</properties>
<children>
#include <include/syslog-facility.xml.i>
</children>
- </tagNode>
- <tagNode name="host">
+ </node>
+ <tagNode name="remote">
<properties>
- <help>Logging to remote host</help>
+ <help>Log to remote host</help>
<constraint>
<validator name="ip-address"/>
<validator name="fqdn"/>
@@ -49,11 +38,6 @@
</valueHelp>
</properties>
<children>
- #include <include/port-number.xml.i>
- <leafNode name="port">
- <defaultValue>514</defaultValue>
- </leafNode>
- #include <include/protocol-tcp-udp.xml.i>
#include <include/syslog-facility.xml.i>
<node name="format">
<properties>
@@ -74,86 +58,50 @@
</leafNode>
</children>
</node>
+ #include <include/port-number.xml.i>
+ <leafNode name="port">
+ <defaultValue>514</defaultValue>
+ </leafNode>
+ #include <include/protocol-tcp-udp.xml.i>
+ #include <include/source-address-ipv4-ipv6.xml.i>
+ #include <include/interface/vrf.xml.i>
</children>
</tagNode>
- <node name="global">
+ <node name="local">
<properties>
- <help>Logging to system standard location</help>
+ <help>Log to standard system location /var/log/messages</help>
</properties>
<children>
#include <include/syslog-facility.xml.i>
- <node name="marker">
- <properties>
- <help>mark messages sent to syslog</help>
- </properties>
- <children>
- <leafNode name="interval">
- <properties>
- <help>time interval how often a mark message is being sent in seconds</help>
- <constraint>
- <validator name="numeric" argument="--positive"/>
- </constraint>
- </properties>
- <defaultValue>1200</defaultValue>
- </leafNode>
- </children>
- </node>
- <leafNode name="preserve-fqdn">
- <properties>
- <help>uses FQDN for logging</help>
- <valueless/>
- </properties>
- </leafNode>
</children>
</node>
- <tagNode name="file">
+ <node name="marker">
<properties>
- <help>Logging to a file</help>
- <constraint>
- <regex>[a-zA-Z0-9\-_.]{1,255}</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in filename or filename longer than 255 characters</constraintErrorMessage>
+ <help>Mark messages sent to syslog</help>
</properties>
<children>
- <node name="archive">
+ <leafNode name="interval">
<properties>
- <help>Log file size and rotation characteristics</help>
+ <help>Mark message interval</help>
+ <valueHelp>
+ <format>u32:1-65535</format>
+ <description>Time in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-86400"/>
+ </constraint>
+ <constraintErrorMessage>Port number must be in range 1 to 86400</constraintErrorMessage>
</properties>
- <children>
- <leafNode name="file">
- <properties>
- <help>Number of saved files</help>
- <constraint>
- <regex>[0-9]+</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in number of files</constraintErrorMessage>
- </properties>
- <defaultValue>5</defaultValue>
- </leafNode>
- <leafNode name="size">
- <properties>
- <help>Size of log files in kbytes</help>
- <constraint>
- <regex>[0-9]+</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in size</constraintErrorMessage>
- </properties>
- <defaultValue>256</defaultValue>
- </leafNode>
- </children>
- </node>
- #include <include/syslog-facility.xml.i>
+ <defaultValue>1200</defaultValue>
+ </leafNode>
</children>
- </tagNode>
- <node name="console">
+ </node>
+ <leafNode name="preserve-fqdn">
<properties>
- <help>logging to serial console</help>
+ <help>Always include domain portion in hostname</help>
+ <valueless/>
</properties>
- <children>
- #include <include/syslog-facility.xml.i>
- </children>
- </node>
- #include <include/interface/vrf.xml.i>
+ </leafNode>
</children>
</node>
</children>
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index 5a353b110..78b98a3eb 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -491,10 +491,8 @@ def get_interface_dict(config, base, ifname='', recursive_defaults=True, with_pk
# Check if any DHCP options changed which require a client restat
dhcp = is_node_changed(config, base + [ifname, 'dhcp-options'])
if dhcp: dict.update({'dhcp_options_changed' : {}})
-
- # Changine interface VRF assignemnts require a DHCP restart, too
- dhcp = is_node_changed(config, base + [ifname, 'vrf'])
- if dhcp: dict.update({'dhcp_options_changed' : {}})
+ dhcpv6 = is_node_changed(config, base + [ifname, 'dhcpv6-options'])
+ if dhcpv6: dict.update({'dhcpv6_options_changed' : {}})
# Some interfaces come with a source_interface which must also not be part
# of any other bond or bridge interface as it is exclusivly assigned as the
@@ -543,6 +541,8 @@ def get_interface_dict(config, base, ifname='', recursive_defaults=True, with_pk
# Check if any DHCP options changed which require a client restat
dhcp = is_node_changed(config, base + [ifname, 'vif', vif, 'dhcp-options'])
if dhcp: dict['vif'][vif].update({'dhcp_options_changed' : {}})
+ dhcpv6 = is_node_changed(config, base + [ifname, 'vif', vif, 'dhcpv6-options'])
+ if dhcpv6: dict['vif'][vif].update({'dhcpv6_options_changed' : {}})
for vif_s, vif_s_config in dict.get('vif_s', {}).items():
# Add subinterface name to dictionary
@@ -569,6 +569,8 @@ def get_interface_dict(config, base, ifname='', recursive_defaults=True, with_pk
# Check if any DHCP options changed which require a client restat
dhcp = is_node_changed(config, base + [ifname, 'vif-s', vif_s, 'dhcp-options'])
if dhcp: dict['vif_s'][vif_s].update({'dhcp_options_changed' : {}})
+ dhcpv6 = is_node_changed(config, base + [ifname, 'vif-s', vif_s, 'dhcpv6-options'])
+ if dhcpv6: dict['vif_s'][vif_s].update({'dhcpv6_options_changed' : {}})
for vif_c, vif_c_config in vif_s_config.get('vif_c', {}).items():
# Add subinterface name to dictionary
@@ -597,6 +599,8 @@ def get_interface_dict(config, base, ifname='', recursive_defaults=True, with_pk
# Check if any DHCP options changed which require a client restat
dhcp = is_node_changed(config, base + [ifname, 'vif-s', vif_s, 'vif-c', vif_c, 'dhcp-options'])
if dhcp: dict['vif_s'][vif_s]['vif_c'][vif_c].update({'dhcp_options_changed' : {}})
+ dhcpv6 = is_node_changed(config, base + [ifname, 'vif-s', vif_s, 'vif-c', vif_c, 'dhcpv6-options'])
+ if dhcpv6: dict['vif_s'][vif_s]['vif_c'][vif_c].update({'dhcpv6_options_changed' : {}})
# Check vif, vif-s/vif-c VLAN interfaces for removal
dict = get_removed_vlans(config, base + [ifname], dict)
diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py
index dd3ad1e3d..90b96b88c 100644
--- a/python/vyos/configsession.py
+++ b/python/vyos/configsession.py
@@ -23,8 +23,8 @@ from vyos.utils.process import is_systemd_service_running
from vyos.utils.dict import dict_to_paths
CLI_SHELL_API = '/bin/cli-shell-api'
-SET = '/usr/libexec/vyos/vyconf/vy_set'
-DELETE = '/usr/libexec/vyos/vyconf/vy_delete'
+SET = '/opt/vyatta/sbin/my_set'
+DELETE = '/opt/vyatta/sbin/my_delete'
COMMENT = '/opt/vyatta/sbin/my_comment'
COMMIT = '/opt/vyatta/sbin/my_commit'
DISCARD = '/opt/vyatta/sbin/my_discard'
diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py
index 9757a34df..89e51707b 100644
--- a/python/vyos/defaults.py
+++ b/python/vyos/defaults.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2018-2025 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
@@ -40,6 +40,11 @@ directories = {
'ca_certificates' : '/usr/local/share/ca-certificates/vyos'
}
+systemd_services = {
+ 'rsyslog' : 'rsyslog.service',
+ 'snmpd' : 'snmpd.service',
+}
+
config_status = '/tmp/vyos-config-status'
api_config_state = '/run/http-api-state'
frr_debug_enable = '/tmp/vyos.frr.debug'
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index cb73e2597..979b62578 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -595,12 +595,16 @@ class Interface(Control):
"""
Add/Remove interface from given VRF instance.
+ Keyword arguments:
+ vrf: VRF instance name or empty string (default VRF)
+
+ Return True if VRF was changed, False otherwise
+
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_vrf('foo')
>>> Interface('eth0').set_vrf()
"""
-
# Don't allow for netns yet
if 'netns' in self.config:
return False
@@ -611,21 +615,33 @@ class Interface(Control):
# Get current VRF table ID
old_vrf_tableid = get_vrf_tableid(self.ifname)
- self.set_interface('vrf', vrf)
+ # Always stop the DHCP client process to clean up routes within the VRF
+ # where the process was originally started. There is no need to add a
+ # condition to only call the method if "address dhcp" was defined, as
+ # this is handled inside set_dhcp(v6) by only stopping if the daemon is
+ # running. DHCP client process restart will be handled later on once the
+ # interface is moved to the new VRF.
+ self.set_dhcp(False)
+ self.set_dhcpv6(False)
+
+ # Move interface in/out of VRF
+ self.set_interface('vrf', vrf)
if vrf:
# Get routing table ID number for VRF
vrf_table_id = get_vrf_tableid(vrf)
# Add map element with interface and zone ID
- if vrf_table_id:
+ if vrf_table_id and old_vrf_tableid != vrf_table_id:
# delete old table ID from nftables if it has changed, e.g. interface moved to a different VRF
- if old_vrf_tableid and old_vrf_tableid != int(vrf_table_id):
- self._del_interface_from_ct_iface_map()
+ self._del_interface_from_ct_iface_map()
self._add_interface_to_ct_iface_map(vrf_table_id)
+ return True
else:
- self._del_interface_from_ct_iface_map()
+ if old_vrf_tableid != get_vrf_tableid(self.ifname):
+ self._del_interface_from_ct_iface_map()
+ return True
- return True
+ return False
def set_arp_cache_tmo(self, tmo):
"""
@@ -1181,7 +1197,7 @@ class Interface(Control):
"""
return self.get_addr_v4() + self.get_addr_v6()
- def add_addr(self, addr):
+ def add_addr(self, addr: str, vrf_changed: bool=False) -> bool:
"""
Add IP(v6) address to interface. Address is only added if it is not
already assigned to that interface. Address format must be validated
@@ -1214,15 +1230,14 @@ class Interface(Control):
# add to interface
if addr == 'dhcp':
- self.set_dhcp(True)
+ self.set_dhcp(True, vrf_changed=vrf_changed)
elif addr == 'dhcpv6':
- self.set_dhcpv6(True)
+ self.set_dhcpv6(True, vrf_changed=vrf_changed)
elif not is_intf_addr_assigned(self.ifname, addr, netns=netns):
netns_cmd = f'ip netns exec {netns}' if netns else ''
tmp = f'{netns_cmd} ip addr add {addr} dev {self.ifname}'
# Add broadcast address for IPv4
if is_ipv4(addr): tmp += ' brd +'
-
self._cmd(tmp)
else:
return False
@@ -1232,7 +1247,7 @@ class Interface(Control):
return True
- def del_addr(self, addr):
+ def del_addr(self, addr: str) -> bool:
"""
Delete IP(v6) address from interface. Address is only deleted if it is
assigned to that interface. Address format must be exactly the same as
@@ -1356,7 +1371,7 @@ class Interface(Control):
cmd = f'bridge vlan add dev {ifname} vid {native_vlan_id} pvid untagged master'
self._cmd(cmd)
- def set_dhcp(self, enable):
+ def set_dhcp(self, enable: bool, vrf_changed: bool=False):
"""
Enable/Disable DHCP client on a given interface.
"""
@@ -1396,7 +1411,9 @@ class Interface(Control):
# the old lease is released a new one is acquired (T4203). We will
# only restart DHCP client if it's option changed, or if it's not
# running, but it should be running (e.g. on system startup)
- if 'dhcp_options_changed' in self.config or not is_systemd_service_active(systemd_service):
+ if (vrf_changed or
+ ('dhcp_options_changed' in self.config) or
+ (not is_systemd_service_active(systemd_service))):
return self._cmd(f'systemctl restart {systemd_service}')
else:
if is_systemd_service_active(systemd_service):
@@ -1423,7 +1440,7 @@ class Interface(Control):
return None
- def set_dhcpv6(self, enable):
+ def set_dhcpv6(self, enable: bool, vrf_changed: bool=False):
"""
Enable/Disable DHCPv6 client on a given interface.
"""
@@ -1452,7 +1469,10 @@ class Interface(Control):
# We must ignore any return codes. This is required to enable
# DHCPv6-PD for interfaces which are yet not up and running.
- return self._popen(f'systemctl restart {systemd_service}')
+ if (vrf_changed or
+ ('dhcpv6_options_changed' in self.config) or
+ (not is_systemd_service_active(systemd_service))):
+ return self._popen(f'systemctl restart {systemd_service}')
else:
if is_systemd_service_active(systemd_service):
self._cmd(f'systemctl stop {systemd_service}')
@@ -1669,30 +1689,31 @@ class Interface(Control):
else:
self.del_addr(addr)
- # start DHCPv6 client when only PD was configured
- if dhcpv6pd:
- self.set_dhcpv6(True)
-
# XXX: Bind interface to given VRF or unbind it if vrf is not set. Unbinding
# will call 'ip link set dev eth0 nomaster' which will also drop the
# interface out of any bridge or bond - thus this is checked before.
+ vrf_changed = False
if 'is_bond_member' in config:
bond_if = next(iter(config['is_bond_member']))
tmp = get_interface_config(config['ifname'])
if 'master' in tmp and tmp['master'] != bond_if:
- self.set_vrf('')
+ vrf_changed = self.set_vrf('')
elif 'is_bridge_member' in config:
bridge_if = next(iter(config['is_bridge_member']))
tmp = get_interface_config(config['ifname'])
if 'master' in tmp and tmp['master'] != bridge_if:
- self.set_vrf('')
+ vrf_changed = self.set_vrf('')
else:
- self.set_vrf(config.get('vrf', ''))
+ vrf_changed = self.set_vrf(config.get('vrf', ''))
+
+ # start DHCPv6 client when only PD was configured
+ if dhcpv6pd:
+ self.set_dhcpv6(True, vrf_changed=vrf_changed)
# Add this section after vrf T4331
for addr in new_addr:
- self.add_addr(addr)
+ self.add_addr(addr, vrf_changed=vrf_changed)
# Configure MSS value for IPv4 TCP connections
tmp = dict_search('ip.adjust_mss', config)
diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py
index 341fd32ff..fed7a5f84 100644
--- a/python/vyos/ifconfig/wireguard.py
+++ b/python/vyos/ifconfig/wireguard.py
@@ -14,14 +14,9 @@
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
-import time
-from datetime import timedelta
from tempfile import NamedTemporaryFile
-from hurry.filesize import size
-from hurry.filesize import alternative
-
from vyos.configquery import ConfigTreeQuery
from vyos.ifconfig import Interface
from vyos.ifconfig import Operational
diff --git a/python/vyos/utils/cpu.py b/python/vyos/utils/cpu.py
index 3bea5ac12..8ace77d15 100644
--- a/python/vyos/utils/cpu.py
+++ b/python/vyos/utils/cpu.py
@@ -99,3 +99,18 @@ def get_core_count():
core_count += 1
return core_count
+
+
+def get_available_cpus():
+ """ List of cpus with ids that are available in the system
+ Uses 'lscpu' command
+
+ Returns: list[dict[str, str | int | bool]]: cpus details
+ """
+ import json
+
+ from vyos.utils.process import cmd
+
+ out = json.loads(cmd('lscpu --extended -b --json'))
+
+ return out['cpus']
diff --git a/python/vyos/utils/misc.py b/python/vyos/utils/misc.py
index ac8011b8d..d82655914 100644
--- a/python/vyos/utils/misc.py
+++ b/python/vyos/utils/misc.py
@@ -52,7 +52,7 @@ def install_into_config(conf, config_paths, override_prompt=True):
continue
try:
- cmd(f'/usr/libexec/vyos/vyconf/vy_set {path}')
+ cmd(f'/opt/vyatta/sbin/my_set {path}')
count += 1
except:
failed.append(path)
diff --git a/python/vyos/utils/process.py b/python/vyos/utils/process.py
index faed8f1b0..21335e6b3 100644
--- a/python/vyos/utils/process.py
+++ b/python/vyos/utils/process.py
@@ -83,13 +83,13 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None,
use_shell = True
# Must be run as root to execute command in VRF or network namespace
+ wrapper = get_wrapper(vrf, netns)
if vrf or netns:
if os.getuid() != 0:
raise OSError(
'Permission denied: cannot execute commands in VRF and netns contexts as an unprivileged user'
)
- wrapper = get_wrapper(vrf, netns)
if use_shell:
command = f'{shlex.join(wrapper)} {command}'
else:
diff --git a/python/vyos/xml_ref/generate_op_cache.py b/python/vyos/xml_ref/generate_op_cache.py
index cd2ac890e..95779d066 100755
--- a/python/vyos/xml_ref/generate_op_cache.py
+++ b/python/vyos/xml_ref/generate_op_cache.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright (C) 2024-2025 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
@@ -33,9 +33,9 @@ _here = dirname(__file__)
sys.path.append(join(_here, '..'))
from defaults import directories
-from op_definition import NodeData
from op_definition import PathData
+
xml_op_cache_json = 'xml_op_cache.json'
xml_op_tmp = join('/tmp', xml_op_cache_json)
op_ref_cache = abspath(join(_here, 'op_cache.py'))
@@ -74,7 +74,7 @@ def translate_op_script(s: str) -> str:
return s
-def insert_node(n: Element, l: list[PathData], path = None) -> None:
+def insert_node(n: Element, l: list[PathData], path=None) -> None:
# pylint: disable=too-many-locals,too-many-branches
prop: OptElement = n.find('properties')
children: OptElement = n.find('children')
@@ -95,65 +95,67 @@ def insert_node(n: Element, l: list[PathData], path = None) -> None:
if command_text is not None:
command_text = translate_command(command_text, path)
- comp_help = None
+ comp_help = {}
if prop is not None:
- che = prop.findall("completionHelp")
+ che = prop.findall('completionHelp')
+
for c in che:
- lists = c.findall("list")
- paths = c.findall("path")
- scripts = c.findall("script")
-
- comp_help = {}
- list_l = []
- for i in lists:
- list_l.append(i.text)
- path_l = []
- for i in paths:
- path_str = re.sub(r'\s+', '/', i.text)
- path_l.append(path_str)
- script_l = []
- for i in scripts:
- script_str = translate_op_script(i.text)
- script_l.append(script_str)
-
- comp_help['list'] = list_l
- comp_help['fs_path'] = path_l
- comp_help['script'] = script_l
-
- for d in l:
- if name in list(d):
- break
- else:
- d = {}
- l.append(d)
-
- inner_l = d.setdefault(name, [])
-
- inner_d: PathData = {'node_data': NodeData(node_type=node_type,
- help_text=help_text,
- comp_help=comp_help,
- command=command_text,
- path=path)}
- inner_l.append(inner_d)
+ comp_list_els = c.findall('list')
+ comp_path_els = c.findall('path')
+ comp_script_els = c.findall('script')
+
+ comp_lists = []
+ for i in comp_list_els:
+ comp_lists.append(i.text)
+
+ comp_paths = []
+ for i in comp_path_els:
+ comp_paths.append(i.text)
+
+ comp_scripts = []
+ for i in comp_script_els:
+ comp_script_str = translate_op_script(i.text)
+ comp_scripts.append(comp_script_str)
+
+ if comp_lists:
+ comp_help['list'] = comp_lists
+ if comp_paths:
+ comp_help['path'] = comp_paths
+ if comp_scripts:
+ comp_help['script'] = comp_scripts
+
+ cur_node_dict = {}
+ cur_node_dict['name'] = name
+ cur_node_dict['type'] = node_type
+ cur_node_dict['comp_help'] = comp_help
+ cur_node_dict['help'] = help_text
+ cur_node_dict['command'] = command_text
+ cur_node_dict['path'] = path
+ cur_node_dict['children'] = []
+ l.append(cur_node_dict)
if children is not None:
- inner_nodes = children.iterfind("*")
+ inner_nodes = children.iterfind('*')
for inner_n in inner_nodes:
inner_path = path[:]
- insert_node(inner_n, inner_l, inner_path)
+ insert_node(inner_n, cur_node_dict['children'], inner_path)
def parse_file(file_path, l):
tree = ET.parse(file_path)
root = tree.getroot()
- for n in root.iterfind("*"):
+ for n in root.iterfind('*'):
insert_node(n, l)
def main():
parser = ArgumentParser(description='generate dict from xml defintions')
- parser.add_argument('--xml-dir', type=str, required=True,
- help='transcluded xml op-mode-definition file')
+ parser.add_argument(
+ '--xml-dir',
+ type=str,
+ required=True,
+ help='transcluded xml op-mode-definition file',
+ )
args = vars(parser.parse_args())
@@ -170,5 +172,6 @@ def main():
with open(op_ref_cache, 'w') as f:
f.write(f'op_reference = {str(l)}')
+
if __name__ == '__main__':
main()
diff --git a/smoketest/config-tests/basic-api-service b/smoketest/config-tests/basic-api-service
index 3f796f35d..ca10cf4e9 100644
--- a/smoketest/config-tests/basic-api-service
+++ b/smoketest/config-tests/basic-api-service
@@ -24,5 +24,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/basic-syslog b/smoketest/config-tests/basic-syslog
new file mode 100644
index 000000000..349d642fd
--- /dev/null
+++ b/smoketest/config-tests/basic-syslog
@@ -0,0 +1,25 @@
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 address '172.16.33.154/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth1 vrf 'red'
+set system console device ttyS0 speed '115200'
+set system domain-name 'vyos-ci-test.net'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
+set system syslog marker interval '999'
+set system syslog preserve-fqdn
+set system syslog remote syslog01.vyos.net facility local7 level 'notice'
+set system syslog remote syslog01.vyos.net port '8000'
+set system syslog remote syslog01.vyos.net vrf 'red'
+set system syslog remote syslog02.vyos.net facility all level 'debug'
+set system syslog remote syslog02.vyos.net format include-timezone
+set system syslog remote syslog02.vyos.net format octet-counted
+set system syslog remote syslog02.vyos.net port '8001'
+set system syslog remote syslog02.vyos.net protocol 'tcp'
+set system syslog remote syslog02.vyos.net vrf 'red'
+set vrf name red table '12321'
diff --git a/smoketest/config-tests/basic-vyos b/smoketest/config-tests/basic-vyos
index 6ff28ec2e..4793e069e 100644
--- a/smoketest/config-tests/basic-vyos
+++ b/smoketest/config-tests/basic-vyos
@@ -92,12 +92,14 @@ set system login user vyos authentication plaintext-password ''
set system name-server '192.168.0.1'
set system syslog console facility all level 'emerg'
set system syslog console facility mail level 'info'
-set system syslog global facility all level 'info'
-set system syslog global facility auth level 'info'
-set system syslog global facility local7 level 'debug'
-set system syslog global preserve-fqdn
-set system syslog host syslog.vyos.net facility auth level 'warning'
-set system syslog host syslog.vyos.net facility local7 level 'notice'
-set system syslog host syslog.vyos.net format octet-counted
-set system syslog host syslog.vyos.net port '8000'
+set system syslog local facility all level 'info'
+set system syslog local facility auth level 'info'
+set system syslog local facility local7 level 'debug'
+set system syslog marker interval '1000'
+set system syslog preserve-fqdn
+set system syslog remote syslog.vyos.net facility auth level 'warning'
+set system syslog remote syslog.vyos.net facility local7 level 'notice'
+set system syslog remote syslog.vyos.net format octet-counted
+set system syslog remote syslog.vyos.net port '8000'
+set system syslog remote syslog.vyos.net protocol 'tcp'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/basic-vyos-no-ntp b/smoketest/config-tests/basic-vyos-no-ntp
index a18260108..f00dea5d4 100644
--- a/smoketest/config-tests/basic-vyos-no-ntp
+++ b/smoketest/config-tests/basic-vyos-no-ntp
@@ -48,6 +48,6 @@ set system host-name 'no-ntp'
set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
set system login user vyos authentication plaintext-password ''
set system name-server '172.16.254.30'
-set system syslog global facility all level 'debug'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'debug'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/bgp-azure-ipsec-gateway b/smoketest/config-tests/bgp-azure-ipsec-gateway
index bbd7b961f..0d683c921 100644
--- a/smoketest/config-tests/bgp-azure-ipsec-gateway
+++ b/smoketest/config-tests/bgp-azure-ipsec-gateway
@@ -135,10 +135,10 @@ set system login user vyos authentication plaintext-password ''
set system logs logrotate messages max-size '20'
set system logs logrotate messages rotate '10'
set system name-server '192.0.2.254'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
-set system syslog host 10.0.9.188 facility all level 'info'
-set system syslog host 10.0.9.188 protocol 'udp'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
+set system syslog remote 10.0.9.188 facility all level 'info'
+set system syslog remote 10.0.9.188 protocol 'udp'
set system time-zone 'Europe/Berlin'
set vpn ipsec authentication psk peer_51-105-0-1 id '51.105.0.1'
set vpn ipsec authentication psk peer_51-105-0-1 id '192.0.2.189'
diff --git a/smoketest/config-tests/bgp-bfd-communities b/smoketest/config-tests/bgp-bfd-communities
index 6eee0137e..06e412c55 100644
--- a/smoketest/config-tests/bgp-bfd-communities
+++ b/smoketest/config-tests/bgp-bfd-communities
@@ -196,6 +196,6 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/bgp-big-as-cloud b/smoketest/config-tests/bgp-big-as-cloud
index d6c17b3d2..f71a51be3 100644
--- a/smoketest/config-tests/bgp-big-as-cloud
+++ b/smoketest/config-tests/bgp-big-as-cloud
@@ -847,6 +847,6 @@ set system name-server '192.0.2.2'
set system sflow interface 'eth0.4088'
set system sflow interface 'eth0.4089'
set system sflow server 1.2.3.4 port '1234'
-set system syslog global facility all level 'all'
-set system syslog global preserve-fqdn
+set system syslog local facility all level 'all'
+set system syslog preserve-fqdn
set system time-zone 'Europe/Zurich'
diff --git a/smoketest/config-tests/bgp-dmvpn-hub b/smoketest/config-tests/bgp-dmvpn-hub
index 99f3799a4..f9ceba11c 100644
--- a/smoketest/config-tests/bgp-dmvpn-hub
+++ b/smoketest/config-tests/bgp-dmvpn-hub
@@ -50,8 +50,8 @@ set system login user vyos authentication plaintext-password ''
set system name-server '1.1.1.1'
set system name-server '8.8.8.8'
set system name-server '9.9.9.9'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set vpn ipsec esp-group ESP-DMVPN lifetime '1800'
set vpn ipsec esp-group ESP-DMVPN mode 'transport'
set vpn ipsec esp-group ESP-DMVPN pfs 'dh-group2'
diff --git a/smoketest/config-tests/bgp-dmvpn-spoke b/smoketest/config-tests/bgp-dmvpn-spoke
index e4fb82a0e..a98275ba4 100644
--- a/smoketest/config-tests/bgp-dmvpn-spoke
+++ b/smoketest/config-tests/bgp-dmvpn-spoke
@@ -56,8 +56,8 @@ set system login user vyos authentication plaintext-password ''
set system name-server '1.1.1.1'
set system name-server '8.8.8.8'
set system name-server '9.9.9.9'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set vpn ipsec esp-group ESP-DMVPN lifetime '1800'
set vpn ipsec esp-group ESP-DMVPN mode 'transport'
set vpn ipsec esp-group ESP-DMVPN pfs 'dh-group2'
diff --git a/smoketest/config-tests/bgp-evpn-l2vpn-leaf b/smoketest/config-tests/bgp-evpn-l2vpn-leaf
index 315cb9e06..5e42a269e 100644
--- a/smoketest/config-tests/bgp-evpn-l2vpn-leaf
+++ b/smoketest/config-tests/bgp-evpn-l2vpn-leaf
@@ -48,8 +48,8 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set vrf name MGMT protocols static route 0.0.0.0/0 next-hop 192.0.2.62
set vrf name MGMT protocols static route6 ::/0 next-hop 2001:db8::1
set vrf name MGMT table '1000'
diff --git a/smoketest/config-tests/bgp-evpn-l2vpn-spine b/smoketest/config-tests/bgp-evpn-l2vpn-spine
index dee29e021..e6d876af6 100644
--- a/smoketest/config-tests/bgp-evpn-l2vpn-spine
+++ b/smoketest/config-tests/bgp-evpn-l2vpn-spine
@@ -41,8 +41,8 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set vrf name MGMT protocols static route 0.0.0.0/0 next-hop 192.0.2.62
set vrf name MGMT protocols static route6 ::/0 next-hop 2001:db8::1
set vrf name MGMT table '1000'
diff --git a/smoketest/config-tests/bgp-evpn-l3vpn-pe-router b/smoketest/config-tests/bgp-evpn-l3vpn-pe-router
index 7a2ec9f91..f867c221e 100644
--- a/smoketest/config-tests/bgp-evpn-l3vpn-pe-router
+++ b/smoketest/config-tests/bgp-evpn-l3vpn-pe-router
@@ -101,8 +101,8 @@ set system login user vyos authentication plaintext-password ''
set system name-server '192.0.2.251'
set system name-server '192.0.2.252'
set system name-server '2001:db8::1'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set vrf name blue protocols bgp address-family ipv4-unicast redistribute connected
set vrf name blue protocols bgp address-family l2vpn-evpn advertise ipv4 unicast
set vrf name blue protocols bgp system-as '100'
diff --git a/smoketest/config-tests/bgp-medium-confederation b/smoketest/config-tests/bgp-medium-confederation
index 582e28047..71797fe93 100644
--- a/smoketest/config-tests/bgp-medium-confederation
+++ b/smoketest/config-tests/bgp-medium-confederation
@@ -69,5 +69,5 @@ set system host-name 'vyos'
set system ip protocol bgp route-map 'DEFAULT-ZEBRA-IN'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'notice'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'notice'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/bgp-rpki b/smoketest/config-tests/bgp-rpki
index 44e95ae98..587de67c6 100644
--- a/smoketest/config-tests/bgp-rpki
+++ b/smoketest/config-tests/bgp-rpki
@@ -39,5 +39,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/bgp-small-internet-exchange b/smoketest/config-tests/bgp-small-internet-exchange
index a9dce4dd5..2adb3fbb5 100644
--- a/smoketest/config-tests/bgp-small-internet-exchange
+++ b/smoketest/config-tests/bgp-small-internet-exchange
@@ -205,5 +205,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/bgp-small-ipv4-unicast b/smoketest/config-tests/bgp-small-ipv4-unicast
index b8c0e1246..f8820cb3c 100644
--- a/smoketest/config-tests/bgp-small-ipv4-unicast
+++ b/smoketest/config-tests/bgp-small-ipv4-unicast
@@ -28,5 +28,5 @@ set system domain-name 'vyos.net'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'notice'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'notice'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/cluster-basic b/smoketest/config-tests/cluster-basic
index 744c117eb..871b40bbb 100644
--- a/smoketest/config-tests/cluster-basic
+++ b/smoketest/config-tests/cluster-basic
@@ -16,6 +16,6 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Antarctica/South_Pole'
diff --git a/smoketest/config-tests/dialup-router-complex b/smoketest/config-tests/dialup-router-complex
index c693cc382..c356c73c0 100644
--- a/smoketest/config-tests/dialup-router-complex
+++ b/smoketest/config-tests/dialup-router-complex
@@ -734,7 +734,7 @@ set system name-server '172.16.254.30'
set system option ctrl-alt-delete 'ignore'
set system option reboot-on-panic
set system option startup-beep
-set system syslog global facility all level 'debug'
-set system syslog global facility local7 level 'debug'
-set system syslog host 172.16.100.1 facility all level 'warning'
+set system syslog local facility all level 'debug'
+set system syslog local facility local7 level 'debug'
+set system syslog remote 172.16.100.1 facility all level 'warning'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/dialup-router-medium-vpn b/smoketest/config-tests/dialup-router-medium-vpn
index d6b00c678..ba3ed29f4 100644
--- a/smoketest/config-tests/dialup-router-medium-vpn
+++ b/smoketest/config-tests/dialup-router-medium-vpn
@@ -314,9 +314,9 @@ set system static-host-mapping host-name host107.vyos.net inet '192.168.0.107'
set system static-host-mapping host-name host109.vyos.net inet '192.168.0.109'
set system sysctl parameter net.core.default_qdisc value 'fq'
set system sysctl parameter net.ipv4.tcp_congestion_control value 'bbr'
-set system syslog global facility all level 'info'
-set system syslog host 192.168.0.252 facility all level 'debug'
-set system syslog host 192.168.0.252 protocol 'udp'
+set system syslog local facility all level 'info'
+set system syslog remote 192.168.0.252 facility all level 'debug'
+set system syslog remote 192.168.0.252 protocol 'udp'
set system task-scheduler task Update-Blacklists executable path '/config/scripts/vyos-foo-update.script'
set system task-scheduler task Update-Blacklists interval '3h'
set system time-zone 'Pacific/Auckland'
diff --git a/smoketest/config-tests/dialup-router-wireguard-ipv6 b/smoketest/config-tests/dialup-router-wireguard-ipv6
index 3e298fb82..269e9d722 100644
--- a/smoketest/config-tests/dialup-router-wireguard-ipv6
+++ b/smoketest/config-tests/dialup-router-wireguard-ipv6
@@ -691,7 +691,7 @@ set system option ctrl-alt-delete 'ignore'
set system option performance 'network-latency'
set system option reboot-on-panic
set system option startup-beep
-set system syslog global facility all level 'debug'
-set system syslog global facility local7 level 'debug'
-set system syslog host 172.16.100.1 facility all level 'warning'
+set system syslog local facility all level 'debug'
+set system syslog local facility local7 level 'debug'
+set system syslog remote 172.16.100.1 facility all level 'warning'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/egp-igp-route-maps b/smoketest/config-tests/egp-igp-route-maps
index fc46d25ff..222325cd7 100644
--- a/smoketest/config-tests/egp-igp-route-maps
+++ b/smoketest/config-tests/egp-igp-route-maps
@@ -42,5 +42,5 @@ set system login user vyos authentication plaintext-password ''
set system logs logrotate messages max-size '1'
set system logs logrotate messages rotate '5'
set system name-server '192.168.0.1'
-set system syslog global facility all level 'info'
+set system syslog local facility all level 'info'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/igmp-pim-small b/smoketest/config-tests/igmp-pim-small
index 909c3d67b..06051af41 100644
--- a/smoketest/config-tests/igmp-pim-small
+++ b/smoketest/config-tests/igmp-pim-small
@@ -32,6 +32,6 @@ set system domain-name 'vyos.io'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/ipoe-server b/smoketest/config-tests/ipoe-server
index f4a12f502..c21495ab2 100644
--- a/smoketest/config-tests/ipoe-server
+++ b/smoketest/config-tests/ipoe-server
@@ -44,5 +44,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/ipv6-disable b/smoketest/config-tests/ipv6-disable
index 40e34fa0c..5f906b5f7 100644
--- a/smoketest/config-tests/ipv6-disable
+++ b/smoketest/config-tests/ipv6-disable
@@ -27,5 +27,5 @@ set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX
set system login user vyos authentication plaintext-password ''
set system name-server '172.16.254.20'
set system name-server '172.16.254.30'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/isis-small b/smoketest/config-tests/isis-small
index b322f4e29..e61d0362e 100644
--- a/smoketest/config-tests/isis-small
+++ b/smoketest/config-tests/isis-small
@@ -39,6 +39,6 @@ set system login user vyos authentication plaintext-password ''
set service ntp server time1.vyos.net
set service ntp server time2.vyos.net
set service ntp server time3.vyos.net
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/nat-basic b/smoketest/config-tests/nat-basic
index 471add3b3..ba2b1b838 100644
--- a/smoketest/config-tests/nat-basic
+++ b/smoketest/config-tests/nat-basic
@@ -84,5 +84,5 @@ set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX
set system login user vyos authentication plaintext-password ''
set system name-server '1.1.1.1'
set system name-server '9.9.9.9'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/ospf-simple b/smoketest/config-tests/ospf-simple
index 355709448..4273e4b8f 100644
--- a/smoketest/config-tests/ospf-simple
+++ b/smoketest/config-tests/ospf-simple
@@ -20,5 +20,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'lab-vyos-r1'
set system login user vyos authentication encrypted-password '$6$R.OnGzfXSfl6J$Iba/hl9bmjBs0VPtZ2zdW.Snh/nHuvxUwi0R6ruypgW63iKEbicJH.uUst8xZCyByURblxRtjAC1lAnYfIt.b0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/ospf-small b/smoketest/config-tests/ospf-small
index a7f8b682c..af69e5702 100644
--- a/smoketest/config-tests/ospf-small
+++ b/smoketest/config-tests/ospf-small
@@ -77,6 +77,6 @@ set system sysctl parameter net.ipv4.igmp_max_memberships value '5'
set system sysctl parameter net.ipv4.ipfrag_time value '4'
set system sysctl parameter net.mpls.default_ttl value '10'
set system sysctl parameter net.mpls.ip_ttl_propagate value '0'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/pppoe-server b/smoketest/config-tests/pppoe-server
index 34fbea215..e488fc746 100644
--- a/smoketest/config-tests/pppoe-server
+++ b/smoketest/config-tests/pppoe-server
@@ -43,5 +43,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/qos-basic b/smoketest/config-tests/qos-basic
index 0e198b80c..655a5794e 100644
--- a/smoketest/config-tests/qos-basic
+++ b/smoketest/config-tests/qos-basic
@@ -71,5 +71,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/rip-router b/smoketest/config-tests/rip-router
index 829aafbd5..d22f424a5 100644
--- a/smoketest/config-tests/rip-router
+++ b/smoketest/config-tests/rip-router
@@ -79,5 +79,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/rpki-only b/smoketest/config-tests/rpki-only
index dcbc7673d..f3e2a74b9 100644
--- a/smoketest/config-tests/rpki-only
+++ b/smoketest/config-tests/rpki-only
@@ -38,5 +38,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'debug'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'debug'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/static-route-basic b/smoketest/config-tests/static-route-basic
index d2d33d043..a6135d2c4 100644
--- a/smoketest/config-tests/static-route-basic
+++ b/smoketest/config-tests/static-route-basic
@@ -32,6 +32,6 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Asia/Macau'
diff --git a/smoketest/config-tests/tunnel-broker b/smoketest/config-tests/tunnel-broker
index ee6301c85..5518c303b 100644
--- a/smoketest/config-tests/tunnel-broker
+++ b/smoketest/config-tests/tunnel-broker
@@ -71,5 +71,5 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
diff --git a/smoketest/config-tests/vpn-openconnect-sstp b/smoketest/config-tests/vpn-openconnect-sstp
index 28d7d5daa..e7969f633 100644
--- a/smoketest/config-tests/vpn-openconnect-sstp
+++ b/smoketest/config-tests/vpn-openconnect-sstp
@@ -16,8 +16,8 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set vpn openconnect authentication local-users username test password 'test'
set vpn openconnect authentication mode local 'password'
set vpn openconnect network-settings client-ip-settings subnet '192.168.160.0/24'
diff --git a/smoketest/config-tests/vrf-basic b/smoketest/config-tests/vrf-basic
index 1d2874a60..0c4e49c52 100644
--- a/smoketest/config-tests/vrf-basic
+++ b/smoketest/config-tests/vrf-basic
@@ -35,8 +35,8 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
set vrf name green protocols static route 20.0.0.0/8 next-hop 1.1.1.1 interface 'eth1'
set vrf name green protocols static route 20.0.0.0/8 next-hop 1.1.1.1 vrf 'default'
diff --git a/smoketest/config-tests/vrf-bgp-pppoe-underlay b/smoketest/config-tests/vrf-bgp-pppoe-underlay
index bd64c914a..e3c765a9a 100644
--- a/smoketest/config-tests/vrf-bgp-pppoe-underlay
+++ b/smoketest/config-tests/vrf-bgp-pppoe-underlay
@@ -143,8 +143,8 @@ set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
set system name-server '192.168.0.1'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
set vrf bind-to-all
set vrf name vyos-test-01 protocols bgp address-family ipv4-unicast network 100.64.50.0/23
diff --git a/smoketest/config-tests/vrf-ospf b/smoketest/config-tests/vrf-ospf
index fd14615e0..53207d565 100644
--- a/smoketest/config-tests/vrf-ospf
+++ b/smoketest/config-tests/vrf-ospf
@@ -28,8 +28,8 @@ set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system time-zone 'Europe/Berlin'
set vrf name blue protocols ospf area 0 network '172.18.201.0/24'
set vrf name blue protocols ospf interface eth2 authentication md5 key-id 30 md5-key 'vyoskey456'
diff --git a/smoketest/config-tests/wireless-basic b/smoketest/config-tests/wireless-basic
index d9e6c8fac..e424b2b0f 100644
--- a/smoketest/config-tests/wireless-basic
+++ b/smoketest/config-tests/wireless-basic
@@ -20,6 +20,6 @@ set system console device ttyS0 speed '115200'
set system domain-name 'dev.vyos.net'
set system host-name 'WR1'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
-set system syslog global facility all level 'info'
-set system syslog global facility local7 level 'debug'
+set system syslog local facility all level 'info'
+set system syslog local facility local7 level 'debug'
set system wireless country-code 'es'
diff --git a/smoketest/configs/basic-syslog b/smoketest/configs/basic-syslog
new file mode 100644
index 000000000..9336b73bc
--- /dev/null
+++ b/smoketest/configs/basic-syslog
@@ -0,0 +1,70 @@
+interfaces {
+ ethernet eth0 {
+ duplex "auto"
+ speed "auto"
+ }
+ ethernet eth1 {
+ address 172.16.33.154/24
+ duplex auto
+ speed auto
+ vrf red
+ }
+}
+system {
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos-ci-test.net
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility local7 {
+ level debug
+ }
+ marker {
+ interval 999
+ }
+ preserve-fqdn
+ }
+ host syslog01.vyos.net {
+ facility local7 {
+ level notice
+ }
+ port 8000
+ }
+ host syslog02.vyos.net {
+ facility all {
+ level debug
+ }
+ format {
+ include-timezone
+ octet-counted
+ }
+ protocol tcp
+ port 8001
+ }
+ vrf red
+ }
+}
+vrf {
+ name red {
+ table 12321
+ }
+}
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "bgp@5:broadcast-relay@1:cluster@2:config-management@1:conntrack@5:conntrack-sync@2:container@2:dhcp-relay@2:dhcp-server@8:dhcpv6-server@1:dns-dynamic@4:dns-forwarding@4:firewall@15:flow-accounting@1:https@6:ids@1:interfaces@32:ipoe-server@3:ipsec@13:isis@3:l2tp@9:lldp@2:mdns@1:monitoring@1:nat@8:nat66@3:ntp@3:openconnect@3:ospf@2:pim@1:policy@8:pppoe-server@10:pptp@5:qos@2:quagga@11:reverse-proxy@1:rip@1:rpki@2:salt@1:snmp@3:ssh@2:sstp@6:system@27:vrf@3:vrrp@4:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2"
+// Release version: 1.4.0
diff --git a/smoketest/configs/basic-vyos b/smoketest/configs/basic-vyos
index 242f3d1de..a6cd3b6e1 100644
--- a/smoketest/configs/basic-vyos
+++ b/smoketest/configs/basic-vyos
@@ -236,6 +236,9 @@ system {
facility security {
level info
}
+ marker {
+ interval 1000
+ }
preserve-fqdn
}
host syslog.vyos.net {
@@ -251,6 +254,7 @@ system {
format {
octet-counted
}
+ protocol tcp
port 8000
}
}
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index c19bfcfe2..78c807d59 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -38,6 +38,7 @@ from vyos.utils.network import is_intf_addr_assigned
from vyos.utils.network import is_ipv6_link_local
from vyos.utils.network import get_nft_vrf_zone_mapping
from vyos.xml_ref import cli_defined
+from vyos.xml_ref import default_value
dhclient_base_dir = directories['isc_dhclient_dir']
dhclient_process_name = 'dhclient'
@@ -282,6 +283,9 @@ class BasicInterfaceTest:
if not self._test_dhcp or not self._test_vrf:
self.skipTest('not supported')
+ cli_default_metric = default_value(self._base_path + [self._interfaces[0],
+ 'dhcp-options', 'default-route-distance'])
+
vrf_name = 'purple4'
self.cli_set(['vrf', 'name', vrf_name, 'table', '65000'])
@@ -307,7 +311,28 @@ class BasicInterfaceTest:
self.assertIn(str(dhclient_pid), vrf_pids)
# and the commandline has the appropriate options
cmdline = read_file(f'/proc/{dhclient_pid}/cmdline')
- self.assertIn('-e\x00IF_METRIC=210', cmdline) # 210 is the default value
+ self.assertIn(f'-e\x00IF_METRIC={cli_default_metric}', cmdline)
+
+ # T5103: remove interface from VRF instance and move DHCP client
+ # back to default VRF. This must restart the DHCP client process
+ for interface in self._interfaces:
+ self.cli_delete(self._base_path + [interface, 'vrf'])
+
+ self.cli_commit()
+
+ # Validate interface state
+ for interface in self._interfaces:
+ tmp = get_interface_vrf(interface)
+ self.assertEqual(tmp, 'default')
+ # Check if dhclient process runs
+ dhclient_pid = process_named_running(dhclient_process_name, cmdline=interface, timeout=10)
+ self.assertTrue(dhclient_pid)
+ # .. inside the appropriate VRF instance
+ vrf_pids = cmd(f'ip vrf pids {vrf_name}')
+ self.assertNotIn(str(dhclient_pid), vrf_pids)
+ # and the commandline has the appropriate options
+ cmdline = read_file(f'/proc/{dhclient_pid}/cmdline')
+ self.assertIn(f'-e\x00IF_METRIC={cli_default_metric}', cmdline)
self.cli_delete(['vrf', 'name', vrf_name])
@@ -341,6 +366,26 @@ class BasicInterfaceTest:
vrf_pids = cmd(f'ip vrf pids {vrf_name}')
self.assertIn(str(tmp), vrf_pids)
+ # T7135: remove interface from VRF instance and move DHCP client
+ # back to default VRF. This must restart the DHCP client process
+ for interface in self._interfaces:
+ self.cli_delete(self._base_path + [interface, 'vrf'])
+
+ self.cli_commit()
+
+ # Validate interface state
+ for interface in self._interfaces:
+ tmp = get_interface_vrf(interface)
+ self.assertEqual(tmp, 'default')
+
+ # Check if dhclient process runs
+ tmp = process_named_running(dhcp6c_process_name, cmdline=interface, timeout=10)
+ self.assertTrue(tmp)
+ # .. inside the appropriate VRF instance
+ vrf_pids = cmd(f'ip vrf pids {vrf_name}')
+ self.assertNotIn(str(tmp), vrf_pids)
+
+
self.cli_delete(['vrf', 'name', vrf_name])
def test_move_interface_between_vrf_instances(self):
diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py
index a54622700..a89b8dce5 100644
--- a/smoketest/scripts/cli/base_vyostest_shim.py
+++ b/smoketest/scripts/cli/base_vyostest_shim.py
@@ -75,10 +75,11 @@ class VyOSUnitTestSHIM:
cls._session.discard()
cls.fail(cls)
- def cli_set(self, config):
+ def cli_set(self, path, value=None):
if self.debug:
- print('set ' + ' '.join(config))
- self._session.set(config)
+ str = f'set {" ".join(path)} {value}' if value else f'set {" ".join(path)}'
+ print(str)
+ self._session.set(path, value)
def cli_delete(self, config):
if self.debug:
diff --git a/smoketest/scripts/cli/test_load-balancing_haproxy.py b/smoketest/scripts/cli/test_load-balancing_haproxy.py
index 967eb3869..9f412aa95 100755
--- a/smoketest/scripts/cli/test_load-balancing_haproxy.py
+++ b/smoketest/scripts/cli/test_load-balancing_haproxy.py
@@ -498,5 +498,28 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase):
self.assertIn('log /dev/log local5 notice', config)
self.assertIn('log /dev/log local6 crit', config)
+ def test_10_lb_reverse_proxy_http_compression(self):
+ # Setup base
+ self.configure_pki()
+ self.base_config()
+
+ # Configure compression in frontend
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'algorithm', 'gzip'])
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'mime-type', 'text/html'])
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'mime-type', 'text/javascript'])
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'mime-type', 'text/plain'])
+ self.cli_commit()
+
+ # Test compression is present in generated configuration file
+ config = read_file(HAPROXY_CONF)
+ self.assertIn('filter compression', config)
+ self.assertIn('compression algo gzip', config)
+ self.assertIn('compression type text/html text/javascript text/plain', config)
+
+ # Test setting compression without specifying any mime-types fails verification
+ self.cli_delete(base_path + ['service', 'https_front', 'http-compression', 'mime-type'])
+ with self.assertRaises(ConfigSessionError) as e:
+ self.cli_commit()
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_nhrp.py b/smoketest/scripts/cli/test_protocols_nhrp.py
index f6d1f1da5..73a760945 100755
--- a/smoketest/scripts/cli/test_protocols_nhrp.py
+++ b/smoketest/scripts/cli/test_protocols_nhrp.py
@@ -17,10 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-
-from vyos.firewall import find_nftables_rule
from vyos.utils.process import process_named_running
-from vyos.utils.file import read_file
tunnel_path = ['interfaces', 'tunnel']
nhrp_path = ['protocols', 'nhrp']
diff --git a/smoketest/scripts/cli/test_system_syslog.py b/smoketest/scripts/cli/test_system_syslog.py
index a86711119..c3b14e1c0 100755
--- a/smoketest/scripts/cli/test_system_syslog.py
+++ b/smoketest/scripts/cli/test_system_syslog.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright (C) 2019-2025 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
@@ -14,24 +14,29 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import re
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
from vyos.xml_ref import default_value
PROCESS_NAME = 'rsyslogd'
-RSYSLOG_CONF = '/etc/rsyslog.d/00-vyos.conf'
+RSYSLOG_CONF = '/run/rsyslog/rsyslog.conf'
base_path = ['system', 'syslog']
-def get_config_value(key):
- tmp = read_file(RSYSLOG_CONF)
- tmp = re.findall(r'\n?{}\s+(.*)'.format(key), tmp)
- return tmp[0]
+def get_config(string=''):
+ """
+ Retrieve current "running configuration" from FRR
+ string: search for a specific start string in the configuration
+ """
+ command = 'cat /run/rsyslog/rsyslog.conf'
+ if string:
+ command += f' | sed -n "/^{string}$/,/}}/p"' # }} required to escape } in f-string
+ return cmd(command)
class TestRSYSLOGService(VyOSUnitTestSHIM.TestCase):
@classmethod
@@ -41,6 +46,7 @@ class TestRSYSLOGService(VyOSUnitTestSHIM.TestCase):
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
+ cls.cli_delete(cls, ['vrf'])
def tearDown(self):
# Check for running process
@@ -53,79 +59,217 @@ class TestRSYSLOGService(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertFalse(process_named_running(PROCESS_NAME))
- def test_syslog_basic(self):
- host1 = '127.0.0.10'
- host2 = '127.0.0.20'
-
- self.cli_set(base_path + ['host', host1, 'port', '999'])
- self.cli_set(base_path + ['host', host1, 'facility', 'all', 'level', 'all'])
- self.cli_set(base_path + ['host', host2, 'facility', 'kern', 'level', 'err'])
- self.cli_set(base_path + ['console', 'facility', 'all', 'level', 'warning'])
-
+ def test_console(self):
+ level = 'warning'
+ self.cli_set(base_path + ['console', 'facility', 'all', 'level'], value=level)
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
+
+ rsyslog_conf = get_config()
config = [
- get_config_value('\*.\*'),
- get_config_value('kern.err'),
- get_config_value('\*.warning'),
+ f'if prifilt("*.{level}") then {{', # {{ required to escape { in f-string
+ 'action(type="omfile" file="/dev/console")',
]
- expected = [f'@{host1}:999', f'@{host2}:514', '/dev/console']
+ for tmp in config:
+ self.assertIn(tmp, rsyslog_conf)
- 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):
+ def test_basic(self):
hostname = 'vyos123'
- domainname = 'example.local'
- self.cli_set(['system', 'host-name', hostname])
- self.cli_set(['system', 'domain-name', domainname])
- 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'])
+ domain_name = 'example.local'
+ default_marker_interval = default_value(base_path + ['marker', 'interval'])
+
+ facility = {
+ 'auth': {'level': 'info'},
+ 'kern': {'level': 'debug'},
+ 'all': {'level': 'notice'},
+ }
+
+ self.cli_set(['system', 'host-name'], value=hostname)
+ self.cli_set(['system', 'domain-name'], value=domain_name)
+ self.cli_set(base_path + ['preserve-fqdn'])
+
+ for tmp, tmp_options in facility.items():
+ level = tmp_options['level']
+ self.cli_set(base_path + ['local', 'facility', tmp, 'level'], value=level)
self.cli_commit()
- config = read_file(RSYSLOG_CONF)
+ config = get_config('')
expected = [
- '$MarkMessagePeriod 600',
- '$PreserveFQDN on',
- 'kern.err',
- f'$LocalHostName {hostname}.{domainname}',
+ f'module(load="immark" interval="{default_marker_interval}")',
+ 'global(preserveFQDN="on")',
+ f'global(localHostname="{hostname}.{domain_name}")',
]
-
for e in expected:
self.assertIn(e, config)
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
- def test_syslog_remote(self):
- rhost = '169.254.0.1'
- default_port = default_value(base_path + ['host', rhost, 'port'])
+ config = get_config('#### GLOBAL LOGGING ####')
+ prifilt = []
+ for tmp, tmp_options in facility.items():
+ if tmp == 'all':
+ tmp = '*'
+ level = tmp_options['level']
+ prifilt.append(f'{tmp}.{level}')
+
+ prifilt.sort()
+ prifilt = ','.join(prifilt)
+
+ self.assertIn(f'if prifilt("{prifilt}") then {{', config)
+ self.assertIn( ' action(', config)
+ self.assertIn( ' type="omfile"', config)
+ self.assertIn( ' file="/var/log/messages"', config)
+ self.assertIn( ' rotation.sizeLimit="524288"', config)
+ self.assertIn( ' rotation.sizeLimitCommand="/usr/sbin/logrotate /etc/logrotate.d/vyos-rsyslog"', config)
+
+ def test_remote(self):
+ rhosts = {
+ '169.254.0.1': {
+ 'facility': {'auth' : {'level': 'info'}},
+ 'protocol': 'udp',
+ },
+ '169.254.0.2': {
+ 'port': '1514',
+ 'protocol': 'udp',
+ },
+ '169.254.0.3': {
+ 'facility': {'auth' : {'level': 'info'},
+ 'kern' : {'level': 'debug'},
+ 'all' : {'level': 'notice'},
+ },
+ 'format': ['include-timezone', 'octet-counted'],
+ 'protocol': 'tcp',
+ 'port': '10514',
+ },
+ }
+ default_port = default_value(base_path + ['remote', next(iter(rhosts)), 'port'])
+ default_protocol = default_value(base_path + ['remote', next(iter(rhosts)), 'protocol'])
+
+ for remote, remote_options in rhosts.items():
+ remote_base = base_path + ['remote', remote]
+
+ if 'port' in remote_options:
+ self.cli_set(remote_base + ['port'], value=remote_options['port'])
- self.cli_set(base_path + ['global', 'facility', 'all', 'level', 'info'])
- self.cli_set(base_path + ['global', 'facility', 'local7', 'level', 'debug'])
- self.cli_set(base_path + ['host', rhost, 'facility', 'all', 'level', 'all'])
- self.cli_set(base_path + ['host', rhost, 'protocol', 'tcp'])
+ if 'facility' in remote_options:
+ for facility, facility_options in remote_options['facility'].items():
+ level = facility_options['level']
+ self.cli_set(remote_base + ['facility', facility, 'level'],
+ value=level)
+
+ if 'format' in remote_options:
+ for format in remote_options['format']:
+ self.cli_set(remote_base + ['format'], value=format)
+
+ if 'protocol' in remote_options:
+ protocol = remote_options['protocol']
+ self.cli_set(remote_base + ['protocol'], value=protocol)
self.cli_commit()
config = read_file(RSYSLOG_CONF)
- self.assertIn(f'*.* @@{rhost}:{default_port}', config)
+ for remote, remote_options in rhosts.items():
+ config = get_config(f'# Remote syslog to {remote}')
+ prifilt = []
+ if 'facility' in remote_options:
+ for facility, facility_options in remote_options['facility'].items():
+ level = facility_options['level']
+ if facility == 'all':
+ facility = '*'
+ prifilt.append(f'{facility}.{level}')
- # Change default port and enable "octet-counting" mode
- port = '10514'
- self.cli_set(base_path + ['host', rhost, 'port', port])
- self.cli_set(base_path + ['host', rhost, 'format', 'octet-counted'])
- self.cli_commit()
+ prifilt.sort()
+ prifilt = ','.join(prifilt)
+ if not prifilt:
+ # Skip test - as we do not render anything if no facility is set
+ continue
+
+ self.assertIn(f'if prifilt("{prifilt}") then {{', config)
+ self.assertIn( ' type="omfwd"', config)
+ self.assertIn(f' target="{remote}"', config)
+
+ port = default_port
+ if 'port' in remote_options:
+ port = remote_options['port']
+ self.assertIn(f'port="{port}"', config)
+
+ protocol = default_protocol
+ if 'protocol' in remote_options:
+ protocol = remote_options['protocol']
+ self.assertIn(f'protocol="{protocol}"', config)
+
+ if 'format' in remote_options:
+ if 'include-timezone' in remote_options['format']:
+ self.assertIn( ' template="SyslogProtocol23Format"', config)
+
+ if 'octet-counted' in remote_options['format']:
+ self.assertIn( ' TCP_Framing="octed-counted"', config)
+ else:
+ self.assertIn( ' TCP_Framing="traditional"', config)
+
+ def test_vrf_source_address(self):
+ rhosts = {
+ '169.254.0.10': { },
+ '169.254.0.11': {
+ 'vrf': {'name' : 'red', 'table' : '12321'},
+ 'source_address' : '169.254.0.11',
+ },
+ '169.254.0.12': {
+ 'vrf': {'name' : 'green', 'table' : '12322'},
+ 'source_address' : '169.254.0.12',
+ },
+ '169.254.0.13': {
+ 'vrf': {'name' : 'blue', 'table' : '12323'},
+ 'source_address' : '169.254.0.13',
+ },
+ }
+ for remote, remote_options in rhosts.items():
+ remote_base = base_path + ['remote', remote]
+ self.cli_set(remote_base + ['facility', 'all'])
+
+ vrf = None
+ if 'vrf' in remote_options:
+ vrf = remote_options['vrf']['name']
+ self.cli_set(['vrf', 'name', vrf, 'table'],
+ value=remote_options['vrf']['table'])
+ self.cli_set(remote_base + ['vrf'], value=vrf)
+
+ if 'source_address' in remote_options:
+ source_address = remote_options['source_address']
+ self.cli_set(remote_base + ['source-address'],
+ value=source_address)
+
+ idx = source_address.split('.')[-1]
+ self.cli_set(['interfaces', 'dummy', f'dum{idx}', 'address'],
+ value=f'{source_address}/32')
+ if vrf:
+ self.cli_set(['interfaces', 'dummy', f'dum{idx}', 'vrf'],
+ value=vrf)
+
+ self.cli_commit()
config = read_file(RSYSLOG_CONF)
- self.assertIn(f'*.* @@(o){rhost}:{port}', config)
+ for remote, remote_options in rhosts.items():
+ config = get_config(f'# Remote syslog to {remote}')
+
+ self.assertIn(f'target="{remote}"', config)
+ if 'vrf' in remote_options:
+ vrf = remote_options['vrf']['name']
+ self.assertIn(f'Device="{vrf}"', config)
+
+ if 'source_address' in remote_options:
+ source_address = remote_options['source_address']
+ self.assertIn(f'Address="{source_address}"', config)
+
+ # Cleanup VRF/Dummy interfaces
+ for remote, remote_options in rhosts.items():
+ if 'vrf' in remote_options:
+ vrf = remote_options['vrf']['name']
+ self.cli_delete(['vrf', 'name', vrf])
+
+ if 'source_address' in remote_options:
+ source_address = remote_options['source_address']
+ idx = source_address.split('.')[-1]
+ self.cli_delete(['interfaces', 'dummy', f'dum{idx}'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/load-balancing_haproxy.py b/src/conf_mode/load-balancing_haproxy.py
index 45042dd52..5fd1beec9 100644
--- a/src/conf_mode/load-balancing_haproxy.py
+++ b/src/conf_mode/load-balancing_haproxy.py
@@ -78,6 +78,13 @@ def verify(lb):
not is_listen_port_bind_service(int(tmp_port), 'haproxy'):
raise ConfigError(f'"TCP" port "{tmp_port}" is used by another service')
+ if 'http_compression' in front_config:
+ if front_config['mode'] != 'http':
+ raise ConfigError(f'service {front} must be set to http mode to use http-compression!')
+ if len(front_config['http_compression']['mime_type']) == 0:
+ raise ConfigError(f'service {front} must have at least one mime-type configured to use'
+ f'http_compression!')
+
for back, back_config in lb['backend'].items():
if 'http_check' in back_config:
http_check = back_config['http_check']
diff --git a/src/conf_mode/service_snmp.py b/src/conf_mode/service_snmp.py
index 1174b1238..d85f20820 100755
--- a/src/conf_mode/service_snmp.py
+++ b/src/conf_mode/service_snmp.py
@@ -22,6 +22,7 @@ from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
+from vyos.defaults import systemd_services
from vyos.snmpv3_hashgen import plaintext_to_md5
from vyos.snmpv3_hashgen import plaintext_to_sha1
from vyos.snmpv3_hashgen import random
@@ -43,7 +44,7 @@ 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'
+systemd_service = systemd_services['snmpd']
def get_config(config=None):
if config:
diff --git a/src/conf_mode/system_host-name.py b/src/conf_mode/system_host-name.py
index 3f245f166..fef034d1c 100755
--- a/src/conf_mode/system_host-name.py
+++ b/src/conf_mode/system_host-name.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright (C) 2018-2025 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
@@ -23,6 +23,7 @@ import vyos.hostsd_client
from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import leaf_node_changed
+from vyos.defaults import systemd_services
from vyos.ifconfig import Section
from vyos.template import is_ip
from vyos.utils.process import cmd
@@ -174,11 +175,13 @@ def apply(config):
# Restart services that use the hostname
if hostname_new != hostname_old:
- call("systemctl restart rsyslog.service")
+ tmp = systemd_services['rsyslog']
+ call(f'systemctl restart {tmp}')
# If SNMP is running, restart it too
if process_named_running('snmpd') and config['snmpd_restart_reqired']:
- call('systemctl restart snmpd.service')
+ tmp = systemd_services['snmpd']
+ call(f'systemctl restart {tmp}')
return None
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index e2832cde6..064a1aa91 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -86,7 +86,7 @@ def verify(options):
if 'source_address' in config:
if not is_addr_assigned(config['source_address']):
- raise ConfigError('No interface with give address specified!')
+ raise ConfigError('No interface with given address specified!')
if 'ssh_client' in options:
config = options['ssh_client']
diff --git a/src/conf_mode/system_syslog.py b/src/conf_mode/system_syslog.py
index eb2f02eb3..414bd4b6b 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-2024 VyOS maintainers and contributors
+# Copyright (C) 2018-2025 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
@@ -20,17 +20,22 @@ 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
+from vyos.defaults import systemd_services
+from vyos.utils.network import is_addr_assigned
from vyos.utils.process import call
from vyos.template import render
+from vyos.template import is_ipv4
+from vyos.template import is_ipv6
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-rsyslog_conf = '/etc/rsyslog.d/00-vyos.conf'
+rsyslog_conf = '/run/rsyslog/rsyslog.conf'
logrotate_conf = '/etc/logrotate.d/vyos-rsyslog'
-systemd_override = r'/run/systemd/system/rsyslog.service.d/override.conf'
+
+systemd_socket = 'syslog.socket'
+systemd_service = systemd_services['rsyslog']
def get_config(config=None):
if config:
@@ -46,23 +51,17 @@ def get_config(config=None):
syslog.update({ 'logrotate' : logrotate_conf })
- tmp = is_node_changed(conf, base + ['vrf'])
- if tmp: syslog.update({'restart_required': {}})
-
syslog = conf.merge_defaults(syslog, recursive=True)
- 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
+ if syslog.from_defaults(['local']):
+ del syslog['local']
+
+ if 'preserve_fqdn' in syslog:
+ if conf.exists(['system', 'host-name']):
+ tmp = conf.return_value(['system', 'host-name'])
+ syslog['preserve_fqdn']['host_name'] = tmp
+ if conf.exists(['system', 'domain-name']):
+ tmp = conf.return_value(['system', 'domain-name'])
+ syslog['preserve_fqdn']['domain_name'] = tmp
return syslog
@@ -70,13 +69,33 @@ 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)
+ if 'preserve_fqdn' in syslog:
+ if 'host_name' not in syslog['preserve_fqdn']:
+ Warning('No "system host-name" defined - cannot set syslog FQDN!')
+ if 'domain_name' not in syslog['preserve_fqdn']:
+ Warning('No "system domain-name" defined - cannot set syslog FQDN!')
+
+ if 'remote' in syslog:
+ for remote, remote_options in syslog['remote'].items():
+ if 'protocol' in remote_options and remote_options['protocol'] == 'udp':
+ if 'format' in remote_options and 'octet_counted' in remote_options['format']:
+ Warning(f'Syslog UDP transport for "{remote}" should not use octet-counted format!')
+
+ if 'vrf' in remote_options:
+ verify_vrf(remote_options)
+
+ if 'source_address' in remote_options:
+ vrf = None
+ if 'vrf' in remote_options:
+ vrf = remote_options['vrf']
+ if not is_addr_assigned(remote_options['source_address'], vrf):
+ raise ConfigError('No interface with given address specified!')
+
+ source_address = remote_options['source_address']
+ if ((is_ipv4(remote) and is_ipv6(source_address)) or
+ (is_ipv6(remote) and is_ipv4(source_address))):
+ raise ConfigError(f'Source-address "{source_address}" does not match '\
+ f'address-family of remote "{remote}"!')
def generate(syslog):
if not syslog:
@@ -88,26 +107,15 @@ def generate(syslog):
return None
render(rsyslog_conf, 'rsyslog/rsyslog.conf.j2', syslog)
- render(systemd_override, 'rsyslog/override.conf.j2', syslog)
render(logrotate_conf, 'rsyslog/logrotate.j2', syslog)
-
- # Reload systemd manager configuration
- call('systemctl daemon-reload')
return None
def apply(syslog):
- systemd_socket = 'syslog.socket'
- systemd_service = 'syslog.service'
if not syslog:
call(f'systemctl stop {systemd_service} {systemd_socket}')
return None
- # we need to restart the service if e.g. the VRF name changed
- systemd_action = 'reload-or-restart'
- if 'restart_required' in syslog:
- systemd_action = 'restart'
-
- call(f'systemctl {systemd_action} {systemd_service}')
+ call(f'systemctl reload-or-restart {systemd_service}')
return None
if __name__ == '__main__':
diff --git a/src/etc/netplug/vyos-netplug-dhcp-client b/src/etc/netplug/vyos-netplug-dhcp-client
index 55d15a163..83fed70f0 100755
--- a/src/etc/netplug/vyos-netplug-dhcp-client
+++ b/src/etc/netplug/vyos-netplug-dhcp-client
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2025 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
@@ -20,10 +20,11 @@ import sys
from time import sleep
from vyos.configquery import ConfigTreeQuery
+from vyos.configdict import get_interface_dict
+from vyos.ifconfig import Interface
from vyos.ifconfig import Section
from vyos.utils.boot import boot_configuration_complete
from vyos.utils.commit import commit_in_progress
-from vyos.utils.process import call
from vyos import airbag
airbag.enable()
@@ -35,28 +36,19 @@ if not boot_configuration_complete():
airbag.noteworthy("System bootup not yet finished...")
sys.exit(1)
+interface = sys.argv[1]
+# helper scripts should only work on physical interfaces not on individual
+# sub-interfaces. Moving e.g. a VLAN interface in/out a VRF will also trigger
+# this script which should be prohibited - bail out early
+if '.' in interface:
+ sys.exit(0)
+
while commit_in_progress():
sleep(1)
-interface = sys.argv[1]
in_out = sys.argv[2]
config = ConfigTreeQuery()
interface_path = ['interfaces'] + Section.get_config_path(interface).split()
-
-for _, interface_config in config.get_config_dict(interface_path).items():
- # Bail out early if we do not have an IP address configured
- if 'address' not in interface_config:
- continue
- # Bail out early if interface ist administrative down
- if 'disable' in interface_config:
- continue
- systemd_action = 'start'
- if in_out == 'out':
- systemd_action = 'stop'
- # Start/Stop DHCP service
- if 'dhcp' in interface_config['address']:
- call(f'systemctl {systemd_action} dhclient@{interface}.service')
- # Start/Stop DHCPv6 service
- if 'dhcpv6' in interface_config['address']:
- call(f'systemctl {systemd_action} dhcp6c@{interface}.service')
+_, interface_config = get_interface_dict(config, interface_path[:-1], ifname=interface, with_pki=True)
+Interface(interface).update(interface_config)
diff --git a/src/etc/rsyslog.conf b/src/etc/rsyslog.conf
deleted file mode 100644
index b3f41acb6..000000000
--- a/src/etc/rsyslog.conf
+++ /dev/null
@@ -1,67 +0,0 @@
-#################
-#### MODULES ####
-#################
-
-$ModLoad imuxsock # provides support for local system logging
-$ModLoad imklog # provides kernel logging support (previously done by rklogd)
-#$ModLoad immark # provides --MARK-- message capability
-
-$OmitLocalLogging off
-$SystemLogSocketName /run/systemd/journal/syslog
-
-$KLogPath /proc/kmsg
-
-###########################
-#### GLOBAL DIRECTIVES ####
-###########################
-
-# Use traditional timestamp format.
-# To enable high precision timestamps, comment out the following line.
-# A modern-style logfile format similar to TraditionalFileFormat, buth with high-precision timestamps and timezone information
-#$ActionFileDefaultTemplate RSYSLOG_FileFormat
-# The "old style" default log file format with low-precision timestamps
-$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
-
-# Filter duplicated messages
-$RepeatedMsgReduction on
-
-#
-# Set the default permissions for all log files.
-#
-$FileOwner root
-$FileGroup adm
-$FileCreateMode 0640
-$DirCreateMode 0755
-$Umask 0022
-
-#
-# Stop excessive logging of sudo
-#
-:msg, contains, " pam_unix(sudo:session): session opened for user root(uid=0) by" stop
-:msg, contains, "pam_unix(sudo:session): session closed for user root" stop
-
-#
-# Include all config files in /etc/rsyslog.d/
-#
-$IncludeConfig /etc/rsyslog.d/*.conf
-
-# The lines below cause all listed daemons/processes to be logged into
-# /var/log/auth.log, then drops the message so it does not also go to the
-# regular syslog so that messages are not duplicated
-
-$outchannel auth_log,/var/log/auth.log
-if $programname == 'CRON' or
- $programname == 'sudo' or
- $programname == 'su'
- then :omfile:$auth_log
-
-if $programname == 'CRON' or
- $programname == 'sudo' or
- $programname == 'su'
- then stop
-
-###############
-#### RULES ####
-###############
-# Emergencies are sent to everybody logged in.
-*.emerg :omusrmsg:* \ No newline at end of file
diff --git a/src/etc/systemd/system/rsyslog.service.d/override.conf b/src/etc/systemd/system/rsyslog.service.d/override.conf
new file mode 100644
index 000000000..665b994d9
--- /dev/null
+++ b/src/etc/systemd/system/rsyslog.service.d/override.conf
@@ -0,0 +1,10 @@
+[Unit]
+StartLimitIntervalSec=0
+
+[Service]
+ExecStart=
+ExecStart=/usr/sbin/rsyslogd -n -iNONE -f /run/rsyslog/rsyslog.conf
+Restart=always
+RestartPreventExitStatus=
+RestartSec=10
+RuntimeDirectoryPreserve=yes
diff --git a/src/init/vyos-router b/src/init/vyos-router
index 00136309b..ab3cc42cb 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -461,6 +461,7 @@ start ()
# As VyOS does not execute commands that are not present in the CLI we call
# the script by hand to have a single source for the login banner and MOTD
+ ${vyos_conf_scripts_dir}/system_syslog.py || log_failure_msg "could not reset syslog"
${vyos_conf_scripts_dir}/system_console.py || log_failure_msg "could not reset serial console"
${vyos_conf_scripts_dir}/system_login_banner.py || log_failure_msg "could not reset motd and issue files"
${vyos_conf_scripts_dir}/system_option.py || log_failure_msg "could not reset system option files"
diff --git a/src/migration-scripts/system/28-to-29 b/src/migration-scripts/system/28-to-29
new file mode 100644
index 000000000..ccf7056c4
--- /dev/null
+++ b/src/migration-scripts/system/28-to-29
@@ -0,0 +1,71 @@
+# Copyright 2025 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/>.
+
+# T6989:
+# - remove syslog arbitrary file logging
+# - remove syslog user console logging
+# - move "global preserve-fqdn" one CLI level up
+# - rename "host" to "remote"
+
+from vyos.configtree import ConfigTree
+
+base = ['system', 'syslog']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+ # Drop support for custom file logging
+ if config.exists(base + ['file']):
+ config.delete(base + ['file'])
+
+ # Drop support for logging to a user tty
+ # This should be dynamically added via an op-mode command like "terminal monitor"
+ if config.exists(base + ['user']):
+ config.delete(base + ['user'])
+
+ # Move "global preserve-fqdn" one CLI level up, as it relates to all
+ # logging targets (console, global and remote)
+ preserve_fqdn_base = base + ['global', 'preserve-fqdn']
+ if config.exists(preserve_fqdn_base):
+ config.delete(preserve_fqdn_base)
+ config.set(base + ['preserve-fqdn'])
+
+ # Move "global marker" one CLI level up, as it relates to all
+ # logging targets (console, global and remote)
+ marker_base = base + ['global', 'marker']
+ if config.exists(marker_base):
+ config.copy(marker_base, base + ['marker'])
+ config.delete(marker_base)
+
+ # Rename "global" -> "local" as this describes what is logged locally
+ # on the router to a file on the filesystem
+ if config.exists(base + ['global']):
+ config.rename(base + ['global'], 'local')
+
+ vrf = ''
+ if config.exists(base + ['vrf']):
+ vrf = config.return_value(base + ['vrf'])
+ config.delete(base + ['vrf'])
+
+ # Rename host x.x.x.x -> remote x.x.x.x
+ if config.exists(base + ['host']):
+ config.set(base + ['remote'])
+ config.set_tag(base + ['remote'])
+ for remote in config.list_nodes(base + ['host']):
+ config.copy(base + ['host', remote], base + ['remote', remote])
+ config.set_tag(base + ['remote'])
+ if vrf:
+ config.set(base + ['remote', remote, 'vrf'], value=vrf)
+ config.delete(base + ['host'])
diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py
index 1da112673..609b0b347 100755
--- a/src/op_mode/image_installer.py
+++ b/src/op_mode/image_installer.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2025 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This file is part of VyOS.
#
@@ -46,7 +46,12 @@ MSG_ERR_NOT_LIVE: str = 'The system is already installed. Please use "add system
MSG_ERR_LIVE: str = 'The system is in live-boot mode. Please use "install image" instead.'
MSG_ERR_NO_DISK: str = 'No suitable disk was found. There must be at least one disk of 2GB or greater size.'
MSG_ERR_IMPROPER_IMAGE: str = 'Missing sha256sum.txt.\nEither this image is corrupted, or of era 1.2.x (md5sum) and would downgrade image tools;\ndisallowed in either case.'
-MSG_ERR_ARCHITECTURE_MISMATCH: str = 'Upgrading to a different image architecture will break your system.'
+MSG_ERR_INCOMPATIBLE_IMAGE: str = 'Image compatibility check failed, aborting installation.'
+MSG_ERR_ARCHITECTURE_MISMATCH: str = 'The current architecture is "{0}", the new image is for "{1}". Upgrading to a different image architecture will break your system.'
+MSG_ERR_FLAVOR_MISMATCH: str = 'The current image flavor is "{0}", the new image is "{1}". Upgrading to a non-matching flavor can have unpredictable consequences.'
+MSG_ERR_MISSING_ARCHITECTURE: str = 'The new image version data does not specify architecture, cannot check compatibility (is it a legacy release image?)'
+MSG_ERR_MISSING_FLAVOR: str = 'The new image version data does not specify flavor, cannot check compatibility (is it a legacy release image?)'
+MSG_ERR_CORRUPT_CURRENT_IMAGE: str = 'Version data in the current image is malformed: missing flavor and/or architecture fields. Upgrade compatibility cannot be checked.'
MSG_INFO_INSTALL_WELCOME: str = 'Welcome to VyOS installation!\nThis command will install VyOS to your permanent storage.'
MSG_INFO_INSTALL_EXIT: str = 'Exiting from VyOS installation'
MSG_INFO_INSTALL_SUCCESS: str = 'The image installed successfully; please reboot now.'
@@ -79,7 +84,6 @@ MSG_WARN_ROOT_SIZE_TOOSMALL: str = 'The size is too small. Try again'
MSG_WARN_IMAGE_NAME_WRONG: str = 'The suggested name is unsupported!\n'\
'It must be between 1 and 64 characters long and contains only the next characters: .+-_ a-z A-Z 0-9'
MSG_WARN_PASSWORD_CONFIRM: str = 'The entered values did not match. Try again'
-MSG_WARN_FLAVOR_MISMATCH: str = 'The running image flavor is "{0}". The new image flavor is "{1}".\n' \
'Installing a different image flavor may cause functionality degradation or break your system.\n' \
'Do you want to continue with installation?'
CONST_MIN_DISK_SIZE: int = 2147483648 # 2 GB
@@ -95,7 +99,7 @@ DIR_ISO_MOUNT: str = f'{DIR_INSTALLATION}/iso_src'
DIR_DST_ROOT: str = f'{DIR_INSTALLATION}/disk_dst'
DIR_KERNEL_SRC: str = '/boot/'
FILE_ROOTFS_SRC: str = '/usr/lib/live/mount/medium/live/filesystem.squashfs'
-ISO_DOWNLOAD_PATH: str = '/tmp/vyos_installation.iso'
+ISO_DOWNLOAD_PATH: str = ''
external_download_script = '/usr/libexec/vyos/simple-download.py'
external_latest_image_url_script = '/usr/libexec/vyos/latest-image-url.py'
@@ -548,6 +552,11 @@ def image_fetch(image_path: str, vrf: str = None,
Returns:
Path: a path to a local file
"""
+ import os.path
+ from uuid import uuid4
+
+ global ISO_DOWNLOAD_PATH
+
# Latest version gets url from configured "system update-check url"
if image_path == 'latest':
command = external_latest_image_url_script
@@ -564,6 +573,7 @@ def image_fetch(image_path: str, vrf: str = None,
# check a type of path
if urlparse(image_path).scheme:
# download an image
+ ISO_DOWNLOAD_PATH = os.path.join(os.path.expanduser("~"), '{0}.iso'.format(uuid4()))
download_file(ISO_DOWNLOAD_PATH, image_path, vrf,
username, password,
progressbar=True, check_space=True)
@@ -701,30 +711,48 @@ def is_raid_install(install_object: Union[disk.DiskDetails, raid.RaidDetails]) -
return False
-def validate_compatibility(iso_path: str) -> None:
+def validate_compatibility(iso_path: str, force: bool = False) -> None:
"""Check architecture and flavor compatibility with the running image
Args:
iso_path (str): a path to the mounted ISO image
"""
- old_data = get_version_data()
- old_flavor = old_data.get('flavor', '')
- old_architecture = old_data.get('architecture') or cmd('dpkg --print-architecture')
+ current_data = get_version_data()
+ current_flavor = current_data.get('flavor')
+ current_architecture = current_data.get('architecture') or cmd('dpkg --print-architecture')
new_data = get_version_data(f'{iso_path}/version.json')
- new_flavor = new_data.get('flavor', '')
- new_architecture = new_data.get('architecture', '')
+ new_flavor = new_data.get('flavor')
+ new_architecture = new_data.get('architecture')
- if not old_architecture == new_architecture:
- print(MSG_ERR_ARCHITECTURE_MISMATCH)
+ if not current_flavor or not current_architecture:
+ # This may only happen if someone modified the version file.
+ # Unlikely but not impossible.
+ print(MSG_ERR_CORRUPT_CURRENT_IMAGE)
cleanup()
exit(MSG_INFO_INSTALL_EXIT)
- if not old_flavor == new_flavor:
- if not ask_yes_no(MSG_WARN_FLAVOR_MISMATCH.format(old_flavor, new_flavor), default=False):
- cleanup()
- exit(MSG_INFO_INSTALL_EXIT)
+ success = True
+ if current_architecture != new_architecture:
+ success = False
+ if not new_architecture:
+ print(MSG_ERR_MISSING_ARCHITECTURE)
+ else:
+ print(MSG_ERR_ARCHITECTURE_MISMATCH.format(current_architecture, new_architecture))
+
+ if current_flavor != new_flavor:
+ if not force:
+ success = False
+ if not new_flavor:
+ print(MSG_ERR_MISSING_FLAVOR)
+ else:
+ print(MSG_ERR_FLAVOR_MISMATCH.format(current_flavor, new_flavor))
+
+ if not success:
+ print(MSG_ERR_INCOMPATIBLE_IMAGE)
+ cleanup()
+ exit(MSG_INFO_INSTALL_EXIT)
def install_image() -> None:
"""Install an image to a disk
@@ -893,7 +921,7 @@ def install_image() -> None:
@compat.grub_cfg_update
def add_image(image_path: str, vrf: str = None, username: str = '',
- password: str = '', no_prompt: bool = False) -> None:
+ password: str = '', no_prompt: bool = False, force: bool = False) -> None:
"""Add a new image
Args:
@@ -910,7 +938,7 @@ def add_image(image_path: str, vrf: str = None, username: str = '',
disk.partition_mount(iso_path, DIR_ISO_MOUNT, 'iso9660')
print('Validating image compatibility')
- validate_compatibility(DIR_ISO_MOUNT)
+ validate_compatibility(DIR_ISO_MOUNT, force=force)
# check sums
print('Validating image checksums')
@@ -1031,6 +1059,9 @@ def parse_arguments() -> Namespace:
parser.add_argument('--image-path',
help='a path (HTTP or local file) to an image that needs to be installed'
)
+ parser.add_argument('--force', action='store_true',
+ help='Ignore flavor compatibility requirements.'
+ )
# parser.add_argument('--image_new_name', help='a new name for image')
args: Namespace = parser.parse_args()
# Validate arguments
@@ -1047,7 +1078,8 @@ if __name__ == '__main__':
install_image()
if args.action == 'add':
add_image(args.image_path, args.vrf,
- args.username, args.password, args.no_prompt)
+ args.username, args.password,
+ args.no_prompt, args.force)
exit()
diff --git a/src/services/vyos-configd b/src/services/vyos-configd
index b161fe6ba..28acccd2c 100755
--- a/src/services/vyos-configd
+++ b/src/services/vyos-configd
@@ -28,6 +28,7 @@ import traceback
import importlib.util
import io
from contextlib import redirect_stdout
+from enum import Enum
import zmq
@@ -60,11 +61,14 @@ SOCKET_PATH = 'ipc:///run/vyos-configd.sock'
MAX_MSG_SIZE = 65535
PAD_MSG_SIZE = 6
+
# Response error codes
-R_SUCCESS = 1
-R_ERROR_COMMIT = 2
-R_ERROR_DAEMON = 4
-R_PASS = 8
+class Response(Enum):
+ SUCCESS = 1
+ ERROR_COMMIT = 2
+ ERROR_DAEMON = 4
+ PASS = 8
+
vyos_conf_scripts_dir = directories['conf_mode']
configd_include_file = os.path.join(directories['data'], 'configd-include.json')
@@ -73,12 +77,15 @@ configd_env_unset_file = os.path.join(directories['data'], 'vyos-configd-env-uns
# sourced on entering config session
configd_env_file = '/etc/default/vyos-configd-env'
+
def key_name_from_file_name(f):
return os.path.splitext(f)[0]
+
def module_name_from_key(k):
return k.replace('-', '_')
+
def path_from_file_name(f):
return os.path.join(vyos_conf_scripts_dir, f)
@@ -126,7 +133,7 @@ def write_stdout_log(file_name, msg):
f.write(msg)
-def run_script(script_name, config, args) -> tuple[int, str]:
+def run_script(script_name, config, args) -> tuple[Response, str]:
# pylint: disable=broad-exception-caught
script = conf_mode_scripts[script_name]
@@ -139,13 +146,13 @@ def run_script(script_name, config, args) -> tuple[int, str]:
script.apply(c)
except ConfigError as e:
logger.error(e)
- return R_ERROR_COMMIT, str(e)
+ return Response.ERROR_COMMIT, str(e)
except Exception:
tb = traceback.format_exc()
logger.error(tb)
- return R_ERROR_COMMIT, tb
+ return Response.ERROR_COMMIT, tb
- return R_SUCCESS, ''
+ return Response.SUCCESS, ''
def initialization(socket):
@@ -195,8 +202,9 @@ def initialization(socket):
os.environ['VYATTA_CHANGES_ONLY_DIR'] = changes_only_dir_string
try:
- configsource = ConfigSourceString(running_config_text=active_string,
- session_config_text=session_string)
+ configsource = ConfigSourceString(
+ running_config_text=active_string, session_config_text=session_string
+ )
except ConfigSourceError as e:
logger.debug(e)
return None
@@ -214,11 +222,11 @@ def initialization(socket):
return config
-def process_node_data(config, data, _last: bool = False) -> tuple[int, str]:
+def process_node_data(config, data, _last: bool = False) -> tuple[Response, str]:
if not config:
out = 'Empty config'
logger.critical(out)
- return R_ERROR_DAEMON, out
+ return Response.ERROR_DAEMON, out
script_name = None
os.environ['VYOS_TAGNODE_VALUE'] = ''
@@ -234,7 +242,7 @@ def process_node_data(config, data, _last: bool = False) -> tuple[int, str]:
if not script_name:
out = 'Missing script_name'
logger.critical(out)
- return R_ERROR_DAEMON, out
+ return Response.ERROR_DAEMON, out
if res.group(3):
args = res.group(3).split()
args.insert(0, f'{script_name}.py')
@@ -246,7 +254,7 @@ def process_node_data(config, data, _last: bool = False) -> tuple[int, str]:
scripts_called.append(script_record)
if script_name not in include_set:
- return R_PASS, ''
+ return Response.PASS, ''
with redirect_stdout(io.StringIO()) as o:
result, err_out = run_script(script_name, config, args)
@@ -259,13 +267,15 @@ def process_node_data(config, data, _last: bool = False) -> tuple[int, str]:
def send_result(sock, err, msg):
+ err_no = err.value
+ err_name = err.name
msg = msg if msg else ''
msg_size = min(MAX_MSG_SIZE, len(msg))
- err_rep = err.to_bytes(1)
+ err_rep = err_no.to_bytes(1)
msg_size_rep = f'{msg_size:#0{PAD_MSG_SIZE}x}'
- logger.debug(f'Sending reply: error_code {err} with output')
+ logger.debug(f'Sending reply: {err_name} with output')
sock.send_multipart([err_rep, msg_size_rep.encode(), msg.encode()])
write_stdout_log(script_stdout_log, msg)
@@ -331,7 +341,7 @@ if __name__ == '__main__':
scripts_called = getattr(config, 'scripts_called', [])
logger.debug(f'scripts_called: {scripts_called}')
- if res == R_SUCCESS:
+ if res == Response.SUCCESS:
tmp = get_frrender_dict(config)
if frr.generate(tmp):
# only apply a new FRR configuration if anything changed
diff --git a/src/services/vyos-domain-resolver b/src/services/vyos-domain-resolver
index fe0f40a07..bfc8caa0a 100755
--- a/src/services/vyos-domain-resolver
+++ b/src/services/vyos-domain-resolver
@@ -177,39 +177,40 @@ def update_fqdn(config, node):
def update_interfaces(config, node):
if node == 'interfaces':
wg_interfaces = dict_search_args(config, 'wireguard')
+ if wg_interfaces:
+
+ peer_public_keys = {}
+ # for each wireguard interfaces
+ for interface, wireguard in wg_interfaces.items():
+ peer_public_keys[interface] = []
+ for peer, peer_config in wireguard['peer'].items():
+ # check peer if peer host-name or address is set
+ if 'host_name' in peer_config or 'address' in peer_config:
+ # check latest handshake
+ peer_public_keys[interface].append(
+ peer_config['public_key']
+ )
+
+ now_time = time.time()
+ for (interface, check_peer_public_keys) in peer_public_keys.items():
+ if len(check_peer_public_keys) == 0:
+ continue
- peer_public_keys = {}
- # for each wireguard interfaces
- for interface, wireguard in wg_interfaces.items():
- peer_public_keys[interface] = []
- for peer, peer_config in wireguard['peer'].items():
- # check peer if peer host-name or address is set
- if 'host_name' in peer_config or 'address' in peer_config:
- # check latest handshake
- peer_public_keys[interface].append(
- peer_config['public_key']
- )
-
- now_time = time.time()
- for (interface, check_peer_public_keys) in peer_public_keys.items():
- if len(check_peer_public_keys) == 0:
- continue
-
- intf = WireGuardIf(interface, create=False, debug=False)
- handshakes = intf.operational.get_latest_handshakes()
-
- # WireGuard performs a handshake every WIREGUARD_REKEY_AFTER_TIME
- # if data is being transmitted between the peers. If no data is
- # transmitted, the handshake will not be initiated unless new
- # data begins to flow. Each handshake generates a new session
- # key, and the key is rotated at least every 120 seconds or
- # upon data transmission after a prolonged silence.
- for public_key, handshake_time in handshakes.items():
- if public_key in check_peer_public_keys and (
- handshake_time == 0
- or (now_time - handshake_time > 3*WIREGUARD_REKEY_AFTER_TIME)
- ):
- intf.operational.reset_peer(public_key=public_key)
+ intf = WireGuardIf(interface, create=False, debug=False)
+ handshakes = intf.operational.get_latest_handshakes()
+
+ # WireGuard performs a handshake every WIREGUARD_REKEY_AFTER_TIME
+ # if data is being transmitted between the peers. If no data is
+ # transmitted, the handshake will not be initiated unless new
+ # data begins to flow. Each handshake generates a new session
+ # key, and the key is rotated at least every 120 seconds or
+ # upon data transmission after a prolonged silence.
+ for public_key, handshake_time in handshakes.items():
+ if public_key in check_peer_public_keys and (
+ handshake_time == 0
+ or (now_time - handshake_time > 3*WIREGUARD_REKEY_AFTER_TIME)
+ ):
+ intf.operational.reset_peer(public_key=public_key)
if __name__ == '__main__':
logger.info('VyOS domain resolver')
diff --git a/src/validators/ethernet-interface b/src/validators/ethernet-interface
new file mode 100644
index 000000000..1bf958697
--- /dev/null
+++ b/src/validators/ethernet-interface
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+if [[ "$1" != ^(lan|eth|eno|ens|enp|enx)[0-9]+$ ]]; then
+ echo "Error: $1 is not an ethernet interface"
+ exit 1
+fi
+
+if ! [ -d "/sys/class/net/$1" ]; then
+ echo "Error: $1 interface does not exist in the system"
+ exit 1
+fi
+
+exit 0