summaryrefslogtreecommitdiff
path: root/src/migration-scripts
diff options
context:
space:
mode:
Diffstat (limited to 'src/migration-scripts')
-rw-r--r--src/migration-scripts/bgp/5-to-639
-rw-r--r--src/migration-scripts/dhcp-server/7-to-86
-rw-r--r--src/migration-scripts/dns-dynamic/1-to-233
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/16-to-170
-rwxr-xr-xsrc/migration-scripts/firewall/17-to-1841
-rw-r--r--src/migration-scripts/flow-accounting/1-to-263
-rw-r--r--src/migration-scripts/https/6-to-743
-rw-r--r--src/migration-scripts/ids/1-to-230
-rw-r--r--src/migration-scripts/lldp/2-to-331
-rw-r--r--src/migration-scripts/monitoring/1-to-250
-rw-r--r--src/migration-scripts/nhrp/0-to-1129
-rw-r--r--src/migration-scripts/ntp/1-to-27
-rw-r--r--src/migration-scripts/policy/8-to-949
-rw-r--r--src/migration-scripts/qos/2-to-334
-rw-r--r--src/migration-scripts/quagga/11-to-1275
-rwxr-xr-xsrc/migration-scripts/reverse-proxy/1-to-227
-rwxr-xr-xsrc/migration-scripts/reverse-proxy/2-to-366
-rw-r--r--src/migration-scripts/system/27-to-2833
-rw-r--r--src/migration-scripts/system/28-to-2971
-rw-r--r--src/migration-scripts/vrf/1-to-25
-rw-r--r--src/migration-scripts/vrf/2-to-33
-rw-r--r--src/migration-scripts/wanloadbalance/3-to-433
22 files changed, 846 insertions, 22 deletions
diff --git a/src/migration-scripts/bgp/5-to-6 b/src/migration-scripts/bgp/5-to-6
new file mode 100644
index 000000000..e6fea6574
--- /dev/null
+++ b/src/migration-scripts/bgp/5-to-6
@@ -0,0 +1,39 @@
+# 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/>.
+
+# T7163: migrate "address-family ipv4|6-unicast redistribute table" from a multi
+# leafNode to a tagNode. This is needed to support per table definition of a
+# route-map and/or metric
+
+from vyos.configtree import ConfigTree
+
+def migrate(config: ConfigTree) -> None:
+ bgp_base = ['protocols', 'bgp']
+ if not config.exists(bgp_base):
+ return
+
+ for address_family in ['ipv4-unicast', 'ipv6-unicast']:
+ # there is no non-main routing table beeing redistributed under this addres family
+ # bail out early and continue with next AFI
+ table_path = bgp_base + ['address-family', address_family, 'redistribute', 'table']
+ if not config.exists(table_path):
+ continue
+
+ tables = config.return_values(table_path)
+ config.delete(table_path)
+
+ for table in tables:
+ config.set(table_path + [table])
+ config.set_tag(table_path)
diff --git a/src/migration-scripts/dhcp-server/7-to-8 b/src/migration-scripts/dhcp-server/7-to-8
index 7fcb62e86..d0f9455bb 100644
--- a/src/migration-scripts/dhcp-server/7-to-8
+++ b/src/migration-scripts/dhcp-server/7-to-8
@@ -41,9 +41,6 @@ def migrate(config: ConfigTree) -> None:
for network in config.list_nodes(base + ['shared-network-name']):
base_network = base + ['shared-network-name', network]
- if config.exists(base_network + ['ping-check']):
- config.delete(base_network + ['ping-check'])
-
if config.exists(base_network + ['shared-network-parameters']):
config.delete(base_network +['shared-network-parameters'])
@@ -57,9 +54,6 @@ def migrate(config: ConfigTree) -> None:
if config.exists(base_subnet + ['enable-failover']):
config.delete(base_subnet + ['enable-failover'])
- if config.exists(base_subnet + ['ping-check']):
- config.delete(base_subnet + ['ping-check'])
-
if config.exists(base_subnet + ['subnet-parameters']):
config.delete(base_subnet + ['subnet-parameters'])
diff --git a/src/migration-scripts/dns-dynamic/1-to-2 b/src/migration-scripts/dns-dynamic/1-to-2
index 5dca9e32f..7f4938147 100644
--- a/src/migration-scripts/dns-dynamic/1-to-2
+++ b/src/migration-scripts/dns-dynamic/1-to-2
@@ -20,6 +20,10 @@
# - migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
# to "service dns dynamic address <interface> service <service> protocol dnsexit2"
+# T6950:
+# - add if statement to prevent processing of "service dns dynamic address" options if they don't exist
+# due to the fact they are no longer valid syntax
+
from vyos.configtree import ConfigTree
base_path = ['service', 'dns', 'dynamic']
@@ -36,16 +40,19 @@ def migrate(config: ConfigTree) -> None:
if config.exists(timeout_path):
config.rename(timeout_path, 'interval')
- # Remove "service dns dynamic address <interface> web-options ..." when <interface> != "web"
- for address in config.list_nodes(address_path):
- if config.exists(address_path + [address, 'web-options']) and address != 'web':
- config.delete(address_path + [address, 'web-options'])
-
- # Migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
- # to "service dns dynamic address <interface> service <service> protocol dnsexit2"
- for address in config.list_nodes(address_path):
- for svc_cfg in config.list_nodes(address_path + [address, 'service']):
- if config.exists(address_path + [address, 'service', svc_cfg, 'protocol']):
- protocol = config.return_value(address_path + [address, 'service', svc_cfg, 'protocol'])
- if protocol == 'dnsexit':
- config.set(address_path + [address, 'service', svc_cfg, 'protocol'], 'dnsexit2')
+ # T6950: Can't migrate address if it doesn't exist
+ if config.exists(address_path):
+
+ # Remove "service dns dynamic address <interface> web-options ..." when <interface> != "web"
+ for address in config.list_nodes(address_path):
+ if config.exists(address_path + [address, 'web-options']) and address != 'web':
+ config.delete(address_path + [address, 'web-options'])
+
+ # Migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
+ # to "service dns dynamic address <interface> service <service> protocol dnsexit2"
+ for address in config.list_nodes(address_path):
+ for svc_cfg in config.list_nodes(address_path + [address, 'service']):
+ if config.exists(address_path + [address, 'service', svc_cfg, 'protocol']):
+ protocol = config.return_value(address_path + [address, 'service', svc_cfg, 'protocol'])
+ if protocol == 'dnsexit':
+ config.set(address_path + [address, 'service', svc_cfg, 'protocol'], 'dnsexit2')
diff --git a/src/migration-scripts/firewall/16-to-17 b/src/migration-scripts/firewall/16-to-17
index ad0706f04..ad0706f04 100755..100644
--- a/src/migration-scripts/firewall/16-to-17
+++ b/src/migration-scripts/firewall/16-to-17
diff --git a/src/migration-scripts/firewall/17-to-18 b/src/migration-scripts/firewall/17-to-18
new file mode 100755
index 000000000..34ce6aa07
--- /dev/null
+++ b/src/migration-scripts/firewall/17-to-18
@@ -0,0 +1,41 @@
+# Copyright (C) 2024-2025 VyOS maintainers and contributors
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# From
+# set firewall zone <zone> interface RED
+# set firewall zone <zone> interface eth0
+# To
+# set firewall zone <zone> member vrf RED
+# set firewall zone <zone> member interface eth0
+
+from vyos.configtree import ConfigTree
+
+base = ['firewall', 'zone']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for zone in config.list_nodes(base):
+ zone_iface_base = base + [zone, 'interface']
+ zone_member_base = base + [zone, 'member']
+ if config.exists(zone_iface_base):
+ for iface in config.return_values(zone_iface_base):
+ if config.exists(['vrf', 'name', iface]):
+ config.set(zone_member_base + ['vrf'], value=iface, replace=False)
+ else:
+ config.set(zone_member_base + ['interface'], value=iface, replace=False)
+ config.delete(zone_iface_base)
diff --git a/src/migration-scripts/flow-accounting/1-to-2 b/src/migration-scripts/flow-accounting/1-to-2
new file mode 100644
index 000000000..5ffb1eec8
--- /dev/null
+++ b/src/migration-scripts/flow-accounting/1-to-2
@@ -0,0 +1,63 @@
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# 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/>.
+
+# migrate 'system flow-accounting sflow' to 'system sflow'
+
+from vyos.configtree import ConfigTree
+
+base = ['system', 'flow-accounting']
+base_fa_sflow = base + ['sflow']
+base_sflow = ['system', 'sflow']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_fa_sflow):
+ # Nothing to do
+ return
+
+ if not config.exists(base_sflow):
+
+ for iface in config.return_values(base + ['interface']):
+ config.set(base_sflow + ['interface'], value=iface, replace=False)
+
+ if config.exists(base + ['vrf']):
+ vrf = config.return_value(base + ['vrf'])
+ config.set(base_sflow + ['vrf'], value=vrf)
+
+ if config.exists(base + ['enable-egress']):
+ config.set(base_sflow + ['enable-egress'])
+
+ if config.exists(base_fa_sflow + ['agent-address']):
+ address = config.return_value(base_fa_sflow + ['agent-address'])
+ config.set(base_sflow + ['agent-address'], value=address)
+
+ if config.exists(base_fa_sflow + ['sampling-rate']):
+ sr = config.return_value(base_fa_sflow + ['sampling-rate'])
+ config.set(base_sflow + ['sampling-rate'], value=sr)
+
+ for server in config.list_nodes(base_fa_sflow + ['server']):
+ config.set(base_sflow + ['server'])
+ config.set_tag(base_sflow + ['server'])
+ config.set(base_sflow + ['server', server])
+ tmp = base_fa_sflow + ['server', server]
+ if config.exists(tmp + ['port']):
+ port = config.return_value(tmp + ['port'])
+ config.set(base_sflow + ['server', server, 'port'], value=port)
+
+ if config.exists(base + ['netflow']):
+ # delete only sflow from flow-accounting if netflow is set
+ config.delete(base_fa_sflow)
+ else:
+ # delete all flow-accounting config otherwise
+ config.delete(base)
diff --git a/src/migration-scripts/https/6-to-7 b/src/migration-scripts/https/6-to-7
new file mode 100644
index 000000000..571f3b6ae
--- /dev/null
+++ b/src/migration-scripts/https/6-to-7
@@ -0,0 +1,43 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# T6736: move REST API to distinct node
+
+
+from vyos.configtree import ConfigTree
+
+
+base = ['service', 'https', 'api']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Move REST API configuration to new node
+ # REST API was previously enabled if base path exists
+ config.set(['service', 'https', 'api', 'rest'])
+ for entry in ('debug', 'strict'):
+ if config.exists(base + [entry]):
+ config.set(base + ['rest', entry])
+ config.delete(base + [entry])
+
+ # Move CORS settings under GraphQL
+ # CORS is not implemented for REST API
+ if config.exists(base + ['cors']):
+ old_base = base + ['cors']
+ new_base = base + ['graphql', 'cors']
+ config.copy(old_base, new_base)
+ config.delete(old_base)
diff --git a/src/migration-scripts/ids/1-to-2 b/src/migration-scripts/ids/1-to-2
new file mode 100644
index 000000000..4c0333c88
--- /dev/null
+++ b/src/migration-scripts/ids/1-to-2
@@ -0,0 +1,30 @@
+# 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/>.
+
+# T: Migrate threshold and add new threshold types
+
+from vyos.configtree import ConfigTree
+
+# The old 'service ids' path was only used for FastNetMon
+# Suricata is in 'service suricata',
+# so this isn't an overreach
+base = ['service', 'ids']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+ else:
+ config.delete(base)
diff --git a/src/migration-scripts/lldp/2-to-3 b/src/migration-scripts/lldp/2-to-3
new file mode 100644
index 000000000..93090756c
--- /dev/null
+++ b/src/migration-scripts/lldp/2-to-3
@@ -0,0 +1,31 @@
+# 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/>.
+
+# T7165: Migrate LLDP interface disable to 'mode disable'
+
+from vyos.configtree import ConfigTree
+
+base = ['service', 'lldp']
+
+def migrate(config: ConfigTree) -> None:
+ interface_base = base + ['interface']
+ if not config.exists(interface_base):
+ # Nothing to do
+ return
+
+ for interface in config.list_nodes(interface_base):
+ if config.exists(interface_base + [interface, 'disable']):
+ config.delete(interface_base + [interface, 'disable'])
+ config.set(interface_base + [interface, 'mode'], value='disable')
diff --git a/src/migration-scripts/monitoring/1-to-2 b/src/migration-scripts/monitoring/1-to-2
new file mode 100644
index 000000000..8bdaebae9
--- /dev/null
+++ b/src/migration-scripts/monitoring/1-to-2
@@ -0,0 +1,50 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# T6953: merge node and frr exporter under prometheus section
+
+from vyos.configtree import ConfigTree
+
+old_base = ['service', 'monitoring']
+new_base = ['service', 'monitoring', 'prometheus']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
+
+ if config.exists(old_base + ['node-exporter']):
+ if config.exists(old_base + ['node-exporter', 'listen-address']):
+ tmp = config.return_value(old_base + ['node-exporter', 'listen-address'])
+ config.set(new_base + ['node-exporter', 'listen-address'], value=tmp)
+ if config.exists(old_base + ['node-exporter', 'port']):
+ tmp = config.return_value(old_base + ['node-exporter', 'port'])
+ config.set(new_base + ['node-exporter', 'port'], value=tmp)
+ if config.exists(old_base + ['node-exporter', 'vrf']):
+ tmp = config.return_value(old_base + ['node-exporter', 'vrf'])
+ config.set(new_base + ['node-exporter', 'vrf'], value=tmp)
+ config.delete(old_base + ['node-exporter'])
+
+ if config.exists(old_base + ['frr-exporter']):
+ if config.exists(old_base + ['frr-exporter', 'listen-address']):
+ tmp = config.return_value(old_base + ['frr-exporter', 'listen-address'])
+ config.set(new_base + ['frr-exporter', 'listen-address'], value=tmp)
+ if config.exists(old_base + ['frr-exporter', 'port']):
+ tmp = config.return_value(old_base + ['frr-exporter', 'port'])
+ config.set(new_base + ['frr-exporter', 'port'], value=tmp)
+ if config.exists(old_base + ['frr-exporter', 'vrf']):
+ tmp = config.return_value(old_base + ['frr-exporter', 'vrf'])
+ config.set(new_base + ['frr-exporter', 'vrf'], value=tmp)
+ config.delete(old_base + ['frr-exporter'])
diff --git a/src/migration-scripts/nhrp/0-to-1 b/src/migration-scripts/nhrp/0-to-1
new file mode 100644
index 000000000..badd88e04
--- /dev/null
+++ b/src/migration-scripts/nhrp/0-to-1
@@ -0,0 +1,129 @@
+# 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/>.
+
+# Migration from Opennhrp to FRR NHRP
+import ipaddress
+
+from vyos.configtree import ConfigTree
+
+base = ['protocols', 'nhrp', 'tunnel']
+interface_base = ['interfaces', 'tunnel']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+ networkid = 1
+ for tunnel_name in config.list_nodes(base):
+ ## Cisco Authentication migration
+ if config.exists(base + [tunnel_name,'cisco-authentication']):
+ auth = config.return_value(base + [tunnel_name,'cisco-authentication'])
+ config.delete(base + [tunnel_name,'cisco-authentication'])
+ config.set(base + [tunnel_name,'authentication'], value=auth)
+ ## Delete Dynamic-map to fqdn
+ if config.exists(base + [tunnel_name,'dynamic-map']):
+ config.delete(base + [tunnel_name,'dynamic-map'])
+ ## Holdtime migration
+ if config.exists(base + [tunnel_name,'holding-time']):
+ holdtime = config.return_value(base + [tunnel_name,'holding-time'])
+ config.delete(base + [tunnel_name,'holding-time'])
+ config.set(base + [tunnel_name,'holdtime'], value=holdtime)
+ ## Add network-id
+ config.set(base + [tunnel_name, 'network-id'], value=networkid)
+ networkid+=1
+ ## Map and nhs migration
+ nhs_tunnelip_list = []
+ nhs_nbmaip_list = []
+ is_nhs = False
+ if config.exists(base + [tunnel_name,'map']):
+ is_map = False
+ for tunnel_ip in config.list_nodes(base + [tunnel_name, 'map']):
+ tunnel_ip_path = base + [tunnel_name, 'map', tunnel_ip]
+ tunnel_ip = tunnel_ip.split('/')[0]
+ if config.exists(tunnel_ip_path + ['cisco']):
+ config.delete(tunnel_ip_path + ['cisco'])
+ if config.exists(tunnel_ip_path + ['nbma-address']):
+ nbma = config.return_value(tunnel_ip_path + ['nbma-address'])
+ if config.exists (tunnel_ip_path + ['register']):
+ config.delete(tunnel_ip_path + ['register'])
+ config.delete(tunnel_ip_path + ['nbma-address'])
+ config.set(base + [tunnel_name, 'nhs', 'tunnel-ip', tunnel_ip, 'nbma'], value=nbma)
+ is_nhs = True
+ if tunnel_ip not in nhs_tunnelip_list:
+ nhs_tunnelip_list.append(tunnel_ip)
+ if nbma not in nhs_nbmaip_list:
+ nhs_nbmaip_list.append(nbma)
+ else:
+ config.delete(tunnel_ip_path + ['nbma-address'])
+ config.set(base + [tunnel_name, 'map_test', 'tunnel-ip', tunnel_ip, 'nbma'], value=nbma)
+ is_map = True
+ config.delete(base + [tunnel_name,'map'])
+
+ if is_nhs:
+ config.set_tag(base + [tunnel_name, 'nhs', 'tunnel-ip'])
+
+ if is_map:
+ config.copy(base + [tunnel_name, 'map_test'], base + [tunnel_name, 'map'])
+ config.delete(base + [tunnel_name, 'map_test'])
+ config.set_tag(base + [tunnel_name, 'map', 'tunnel-ip'])
+
+ #
+ # Change netmask to /32 on tunnel interface
+ # If nhs is alone, add static route tunnel network to nhs
+ #
+ if config.exists(interface_base + [tunnel_name, 'address']):
+ tunnel_ip_list = []
+ for tunnel_ip in config.return_values(
+ interface_base + [tunnel_name, 'address']):
+ tunnel_ip_ch = tunnel_ip.split('/')[0]+'/32'
+ if tunnel_ip_ch not in tunnel_ip_list:
+ tunnel_ip_list.append(tunnel_ip_ch)
+ for nhs in nhs_tunnelip_list:
+ config.set(['protocols', 'static', 'route', str(ipaddress.ip_network(tunnel_ip, strict=False)), 'next-hop', nhs, 'distance'], value='250')
+ if nhs_tunnelip_list:
+ if not config.is_tag(['protocols', 'static', 'route']):
+ config.set_tag(['protocols', 'static', 'route'])
+ if not config.is_tag(['protocols', 'static', 'route', str(ipaddress.ip_network(tunnel_ip, strict=False)), 'next-hop']):
+ config.set_tag(['protocols', 'static', 'route', str(ipaddress.ip_network(tunnel_ip, strict=False)), 'next-hop'])
+
+ config.delete(interface_base + [tunnel_name, 'address'])
+ for tunnel_ip in tunnel_ip_list:
+ config.set(
+ interface_base + [tunnel_name, 'address'], value=tunnel_ip, replace=False)
+
+ ## Map multicast migration
+ if config.exists(base + [tunnel_name, 'multicast']):
+ multicast_map = config.return_value(
+ base + [tunnel_name, 'multicast'])
+ if multicast_map == 'nhs':
+ config.delete(base + [tunnel_name, 'multicast'])
+ for nbma in nhs_nbmaip_list:
+ config.set(base + [tunnel_name, 'multicast'], value=nbma,
+ replace=False)
+
+ ## Delete non-cahching
+ if config.exists(base + [tunnel_name, 'non-caching']):
+ config.delete(base + [tunnel_name, 'non-caching'])
+ ## Delete shortcut-destination
+ if config.exists(base + [tunnel_name, 'shortcut-destination']):
+ if not config.exists(base + [tunnel_name, 'shortcut']):
+ config.set(base + [tunnel_name, 'shortcut'])
+ config.delete(base + [tunnel_name, 'shortcut-destination'])
+ ## Delete shortcut-target
+ if config.exists(base + [tunnel_name, 'shortcut-target']):
+ if not config.exists(base + [tunnel_name, 'shortcut']):
+ config.set(base + [tunnel_name, 'shortcut'])
+ config.delete(base + [tunnel_name, 'shortcut-target'])
+ ## Set registration-no-unique
+ config.set(base + [tunnel_name, 'registration-no-unique']) \ No newline at end of file
diff --git a/src/migration-scripts/ntp/1-to-2 b/src/migration-scripts/ntp/1-to-2
index fd7b08221..d5f800922 100644
--- a/src/migration-scripts/ntp/1-to-2
+++ b/src/migration-scripts/ntp/1-to-2
@@ -1,4 +1,4 @@
-# Copyright 2023-2024 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
@@ -25,6 +25,11 @@ def migrate(config: ConfigTree) -> None:
# Nothing to do
return
+ # T6911: do not migrate NTP configuration if mandatory server is missing
+ if not config.exists(base_path + ['server']):
+ config.delete(base_path)
+ return
+
# config.copy does not recursively create a path, so create ['service'] if
# it doesn't yet exist, such as for config.boot.default
if not config.exists(['service']):
diff --git a/src/migration-scripts/policy/8-to-9 b/src/migration-scripts/policy/8-to-9
new file mode 100644
index 000000000..355e48e00
--- /dev/null
+++ b/src/migration-scripts/policy/8-to-9
@@ -0,0 +1,49 @@
+# Copyright (C) 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/>.
+
+# T7116: Remove unsupported "internet" community following FRR removal
+# From
+ # set policy route-map <name> rule <ord> set community [add | replace] internet
+ # set policy community-list <name> rule <ord> regex internet
+# To
+ # set policy route-map <name> rule <ord> set community [add | replace] 0:0
+ # set policy community-list <name> rule <ord> regex _0:0_
+
+# NOTE: In FRR expanded community-lists, without the '_' delimiters, a regex of
+# "0:0" will match "65000:0" as well as "0:0". This doesn't line up with what
+# we want when replacing "internet".
+
+from vyos.configtree import ConfigTree
+
+rm_base = ['policy', 'route-map']
+cl_base = ['policy', 'community-list']
+
+def migrate(config: ConfigTree) -> None:
+ if config.exists(rm_base):
+ for policy_name in config.list_nodes(rm_base):
+ for rule_ord in config.list_nodes(rm_base + [policy_name, 'rule'], path_must_exist=False):
+ tmp_path = rm_base + [policy_name, 'rule', rule_ord, 'set', 'community']
+ if config.exists(tmp_path + ['add']) and config.return_value(tmp_path + ['add']) == 'internet':
+ config.set(tmp_path + ['add'], '0:0')
+ if config.exists(tmp_path + ['replace']) and config.return_value(tmp_path + ['replace']) == 'internet':
+ config.set(tmp_path + ['replace'], '0:0')
+
+ if config.exists(cl_base):
+ for policy_name in config.list_nodes(cl_base):
+ for rule_ord in config.list_nodes(cl_base + [policy_name, 'rule'], path_must_exist=False):
+ tmp_path = cl_base + [policy_name, 'rule', rule_ord, 'regex']
+ if config.exists(tmp_path) and config.return_value(tmp_path) == 'internet':
+ config.set(tmp_path, '_0:0_')
+
diff --git a/src/migration-scripts/qos/2-to-3 b/src/migration-scripts/qos/2-to-3
new file mode 100644
index 000000000..284fe828e
--- /dev/null
+++ b/src/migration-scripts/qos/2-to-3
@@ -0,0 +1,34 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+from vyos.configtree import ConfigTree
+
+
+def migrate(config: ConfigTree) -> None:
+ base = ['qos', 'policy', 'cake']
+ if config.exists(base):
+ for policy in config.list_nodes(base):
+ if config.exists(base + [policy, 'flow-isolation']):
+ isolation = None
+ for isol in config.list_nodes(base + [policy, 'flow-isolation']):
+ if isol == 'nat':
+ config.set(base + [policy, 'flow-isolation-nat'])
+ else:
+ isolation = isol
+
+ config.delete(base + [policy, 'flow-isolation'])
+
+ if isolation:
+ config.set(base + [policy, 'flow-isolation'], value=isolation)
diff --git a/src/migration-scripts/quagga/11-to-12 b/src/migration-scripts/quagga/11-to-12
new file mode 100644
index 000000000..8ae2023a1
--- /dev/null
+++ b/src/migration-scripts/quagga/11-to-12
@@ -0,0 +1,75 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# T6747:
+# - Migrate static BFD configuration to match FRR possibillities
+# - Consolidate static multicast routing configuration under a new node
+
+from vyos.configtree import ConfigTree
+
+static_base = ['protocols', 'static']
+
+def migrate(config: ConfigTree) -> None:
+ # Check for static route/route6 configuration
+ # Migrate static BFD configuration to match FRR possibillities
+ for route_route6 in ['route', 'route6']:
+ route_route6_base = static_base + [route_route6]
+ if not config.exists(route_route6_base):
+ continue
+
+ for prefix in config.list_nodes(route_route6_base):
+ next_hop_base = route_route6_base + [prefix, 'next-hop']
+ if not config.exists(next_hop_base):
+ continue
+
+ for next_hop in config.list_nodes(next_hop_base):
+ multi_hop_base = next_hop_base + [next_hop, 'bfd', 'multi-hop']
+
+ if not config.exists(multi_hop_base):
+ continue
+
+ mh_source_base = multi_hop_base + ['source']
+ source = None
+ profile = None
+ for src_ip in config.list_nodes(mh_source_base):
+ source = src_ip
+ if config.exists(mh_source_base + [source, 'profile']):
+ profile = config.return_value(mh_source_base + [source, 'profile'])
+ # FRR only supports one source, we will use the first one
+ break
+
+ config.delete(multi_hop_base)
+ config.set(multi_hop_base + ['source-address'], value=source)
+ config.set(next_hop_base + [next_hop, 'bfd', 'profile'], value=profile)
+
+ # Consolidate static multicast routing configuration under a new node
+ if config.exists(static_base + ['multicast']):
+ for mroute in ['interface-route', 'route']:
+ mroute_base = static_base + ['multicast', mroute]
+ if not config.exists(mroute_base):
+ continue
+ config.set(static_base + ['mroute'])
+ config.set_tag(static_base + ['mroute'])
+ for route in config.list_nodes(mroute_base):
+ config.copy(mroute_base + [route], static_base + ['mroute', route])
+
+ mroute_base = static_base + ['mroute']
+ if config.exists(mroute_base):
+ for mroute in config.list_nodes(mroute_base):
+ interface_path = mroute_base + [mroute, 'next-hop-interface']
+ if config.exists(interface_path):
+ config.rename(interface_path, 'interface')
+
+ config.delete(static_base + ['multicast'])
diff --git a/src/migration-scripts/reverse-proxy/1-to-2 b/src/migration-scripts/reverse-proxy/1-to-2
new file mode 100755
index 000000000..61612bc36
--- /dev/null
+++ b/src/migration-scripts/reverse-proxy/1-to-2
@@ -0,0 +1,27 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# T6745: Rename base node to haproxy
+
+from vyos.configtree import ConfigTree
+
+base = ['load-balancing', 'reverse-proxy']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ config.rename(base, 'haproxy')
diff --git a/src/migration-scripts/reverse-proxy/2-to-3 b/src/migration-scripts/reverse-proxy/2-to-3
new file mode 100755
index 000000000..ac539618e
--- /dev/null
+++ b/src/migration-scripts/reverse-proxy/2-to-3
@@ -0,0 +1,66 @@
+# 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/>.
+
+# T7429: logging facility "all" unavailable in code
+
+from vyos.configtree import ConfigTree
+
+base = ['load-balancing', 'haproxy']
+unsupported_facilities = ['all', 'authpriv', 'mark']
+
+def config_migrator(config, config_path: list) -> None:
+ if not config.exists(config_path):
+ return
+ # Remove unsupported backend HAProxy syslog facilities form CLI
+ # Works for both backend and service CLI nodes
+ for service_backend in config.list_nodes(config_path):
+ log_path = config_path + [service_backend, 'logging', 'facility']
+ if not config.exists(log_path):
+ continue
+ # Remove unsupported syslog facilities form CLI
+ for facility in config.list_nodes(log_path):
+ if facility in unsupported_facilities:
+ config.delete(log_path + [facility])
+ continue
+ # Remove unsupported facility log level form CLI. VyOS will fallback
+ # to default log level if not set
+ if config.exists(log_path + [facility, 'level']):
+ tmp = config.return_value(log_path + [facility, 'level'])
+ if tmp == 'all':
+ config.delete(log_path + [facility, 'level'])
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Remove unsupported syslog facilities form CLI
+ global_path = base + ['global-parameters', 'logging', 'facility']
+ if config.exists(global_path):
+ for facility in config.list_nodes(global_path):
+ if facility in unsupported_facilities:
+ config.delete(global_path + [facility])
+ continue
+ # Remove unsupported facility log level form CLI. VyOS will fallback
+ # to default log level if not set
+ if config.exists(global_path + [facility, 'level']):
+ tmp = config.return_value(global_path + [facility, 'level'])
+ if tmp == 'all':
+ config.delete(global_path + [facility, 'level'])
+
+ # Remove unsupported backend HAProxy syslog facilities from CLI
+ config_migrator(config, base + ['backend'])
+ # Remove unsupported service HAProxy syslog facilities from CLI
+ config_migrator(config, base + ['service'])
diff --git a/src/migration-scripts/system/27-to-28 b/src/migration-scripts/system/27-to-28
new file mode 100644
index 000000000..0a5be48ab
--- /dev/null
+++ b/src/migration-scripts/system/27-to-28
@@ -0,0 +1,33 @@
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# 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/>.
+
+# rename 'system option performance' leaf nodes to new names
+
+from vyos.configtree import ConfigTree
+
+base = ['system', 'option', 'performance']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ replace = {
+ 'throughput' : 'network-throughput',
+ 'latency' : 'network-latency'
+ }
+
+ for old_name, new_name in replace.items():
+ if config.return_value(base) == old_name:
+ config.set(base, new_name)
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/migration-scripts/vrf/1-to-2 b/src/migration-scripts/vrf/1-to-2
index 557a9ec58..89b0f708a 100644
--- a/src/migration-scripts/vrf/1-to-2
+++ b/src/migration-scripts/vrf/1-to-2
@@ -37,7 +37,10 @@ def migrate(config: ConfigTree) -> None:
new_static_base = vrf_base + [vrf, 'protocols']
config.set(new_static_base)
config.copy(static_base, new_static_base + ['static'])
- config.set_tag(new_static_base + ['static', 'route'])
+ if config.exists(new_static_base + ['static', 'route']):
+ config.set_tag(new_static_base + ['static', 'route'])
+ if config.exists(new_static_base + ['static', 'route6']):
+ config.set_tag(new_static_base + ['static', 'route6'])
# Now delete the old configuration
config.delete(base)
diff --git a/src/migration-scripts/vrf/2-to-3 b/src/migration-scripts/vrf/2-to-3
index acacffb41..5f396e7ed 100644
--- a/src/migration-scripts/vrf/2-to-3
+++ b/src/migration-scripts/vrf/2-to-3
@@ -76,7 +76,8 @@ def migrate(config: ConfigTree) -> None:
# Get a list of all currently used VRFs and tables
vrfs_current = {}
for vrf in config.list_nodes(base):
- vrfs_current[vrf] = int(config.return_value(base + [vrf, 'table']))
+ if config.exists(base + [vrf, 'table']):
+ vrfs_current[vrf] = int(config.return_value(base + [vrf, 'table']))
# Check VRF names and table numbers
name_regex = re.compile(r'^\d.*$')
diff --git a/src/migration-scripts/wanloadbalance/3-to-4 b/src/migration-scripts/wanloadbalance/3-to-4
new file mode 100644
index 000000000..e49f46a5b
--- /dev/null
+++ b/src/migration-scripts/wanloadbalance/3-to-4
@@ -0,0 +1,33 @@
+# 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/>.
+
+from vyos.configtree import ConfigTree
+
+base = ['load-balancing', 'wan']
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['rule']):
+ for rule in config.list_nodes(base + ['rule']):
+ rule_base = base + ['rule', rule]
+
+ if config.exists(rule_base + ['inbound-interface']):
+ ifname = config.return_value(rule_base + ['inbound-interface'])
+
+ if ifname.endswith('+'):
+ config.set(rule_base + ['inbound-interface'], value=ifname.replace('+', '*'))