summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@vyos.io>2024-09-12 13:59:18 +0100
committerGitHub <noreply@github.com>2024-09-12 13:59:18 +0100
commit205d957d092ade5708cc2182381864c04e4c0aff (patch)
treee78636efaa1332c5d49e1c2f023721dc030f8d6a
parent9652bfda0a7f3e7932aecb32262c34f3fede72b2 (diff)
parenteaa9c82670fa5ee90835266e6f7a24f81c49d17e (diff)
downloadvyos-1x-205d957d092ade5708cc2182381864c04e4c0aff.tar.gz
vyos-1x-205d957d092ade5708cc2182381864c04e4c0aff.zip
Merge pull request #4050 from jestabro/revise-migration-circinus
T6007: revise migration system
-rw-r--r--python/vyos/base.py7
-rw-r--r--python/vyos/component_version.py277
-rw-r--r--python/vyos/compose_config.py12
-rw-r--r--python/vyos/configtree.py13
-rw-r--r--python/vyos/load_config.py31
-rw-r--r--python/vyos/migrate.py283
-rw-r--r--python/vyos/migrator.py226
-rw-r--r--python/vyos/utils/dict.py2
-rw-r--r--python/vyos/utils/system.py12
-rwxr-xr-xsrc/helpers/add-system-version.py (renamed from src/helpers/system-versions-foot.py)14
-rwxr-xr-xsrc/helpers/run-config-migration.py128
-rwxr-xr-xsrc/helpers/vyos-load-config.py21
-rwxr-xr-xsrc/helpers/vyos-merge-config.py17
-rwxr-xr-xsrc/helpers/vyos-save-config.py15
-rwxr-xr-xsrc/helpers/vyos_net_name10
-rwxr-xr-xsrc/init/vyos-router4
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/0-to-172
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/1-to-2112
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/2-to-363
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/3-to-487
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/bgp/4-to-577
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/cluster/1-to-265
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/config-management/0-to-143
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack-sync/1-to-250
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/1-to-240
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/2-to-351
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/3-to-456
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/conntrack/4-to-562
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/container/0-to-1102
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/container/1-to-256
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-relay/1-to-242
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/10-to-1152
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/4-to-5202
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/5-to-6132
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/6-to-794
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/7-to-898
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/8-to-982
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcp-server/9-to-1081
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/0-to-147
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/1-to-2100
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/2-to-3102
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/3-to-4101
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dhcpv6-server/4-to-5140
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/0-to-1161
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/1-to-285
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/2-to-3134
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-dynamic/3-to-487
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/0-to-149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/1-to-2111
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/2-to-357
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/dns-forwarding/3-to-454
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/10-to-11312
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/11-to-1288
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/12-to-13114
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/13-to-1464
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/14-to-1549
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/15-to-1639
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/5-to-6160
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/6-to-7444
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/7-to-8106
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/8-to-9126
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/firewall/9-to-10104
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/flow-accounting/0-to-194
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/0-to-149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/1-to-249
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/2-to-388
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/3-to-459
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/4-to-579
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/https/5-to-6156
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ids/0-to-174
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/0-to-1151
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/1-to-242
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/10-to-1143
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/11-to-1241
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/12-to-1342
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/13-to-1443
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/14-to-1542
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/15-to-1642
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/16-to-1743
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/17-to-1841
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/18-to-1945
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/19-to-2042
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/2-to-341
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/20-to-21202
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/21-to-2257
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/22-to-2347
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/23-to-2442
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/24-to-2543
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/25-to-26643
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/26-to-2767
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/27-to-2857
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/28-to-2963
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/29-to-3055
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/3-to-442
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/30-to-3195
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/31-to-3264
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/32-to-3353
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/4-to-536
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/5-to-641
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/6-to-742
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/7-to-842
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/8-to-941
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/interfaces/9-to-1041
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipoe-server/1-to-2162
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipoe-server/2-to-374
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/10-to-11126
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/11-to-1256
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/12-to-1350
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/4-to-555
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/5-to-6140
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/6-to-760
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/7-to-8137
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/8-to-950
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ipsec/9-to-10223
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/isis/0-to-164
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/isis/1-to-255
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/isis/2-to-382
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/0-to-146
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/1-to-247
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/2-to-353
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/3-to-4262
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/4-to-5105
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/5-to-6176
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/6-to-766
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/7-to-888
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/l2tp/8-to-950
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/lldp/0-to-148
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/lldp/1-to-254
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/monitoring/0-to-183
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/4-to-547
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/5-to-645
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/6-to-795
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat/7-to-881
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat66/0-to-159
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat66/1-to-276
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/nat66/2-to-386
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ntp/0-to-142
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ntp/1-to-2101
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ntp/2-to-369
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openconnect/0-to-1203
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openconnect/1-to-249
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openconnect/2-to-356
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openvpn/0-to-142
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/openvpn/1-to-227
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ospf/0-to-178
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ospf/1-to-2116
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pim/0-to-186
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/0-to-176
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/1-to-2111
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/2-to-370
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/3-to-4135
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/4-to-5115
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/5-to-680
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/6-to-798
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/policy/7-to-858
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/0-to-147
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/1-to-247
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/2-to-345
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/3-to-448
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/4-to-549
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/5-to-663
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/6-to-7172
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/7-to-874
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/8-to-990
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pppoe-server/9-to-1066
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/0-to-143
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/1-to-248
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/2-to-398
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/3-to-453
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/pptp/4-to-582
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/qos/1-to-2282
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/10-to-1156
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/2-to-354
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/3-to-456
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/4-to-555
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/5-to-655
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/6-to-7185
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/7-to-877
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/8-to-992
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/quagga/9-to-1082
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/reverse-proxy/0-to-155
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/rip/0-to-156
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/rpki/0-to-189
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/rpki/1-to-296
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/salt/0-to-150
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/snmp/0-to-148
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/snmp/1-to-281
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/snmp/2-to-355
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ssh/0-to-142
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/ssh/1-to-2118
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/0-to-149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/1-to-247
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/2-to-349
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/3-to-4203
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/4-to-566
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/sstp/5-to-674
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/10-to-1144
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/11-to-1241
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/12-to-1371
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/13-to-1441
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/14-to-1541
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/15-to-1642
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/16-to-1748
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/17-to-1847
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/18-to-19151
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/19-to-2074
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/20-to-2150
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/21-to-2273
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/22-to-2359
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/23-to-2492
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/24-to-2561
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/25-to-2699
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/26-to-2755
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/6-to-774
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/7-to-842
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/system/8-to-942
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrf/0-to-1223
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrf/1-to-281
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrf/2-to-3149
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrrp/1-to-2346
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrrp/2-to-386
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/vrrp/3-to-461
-rw-r--r--[-rwxr-xr-x]src/migration-scripts/webproxy/1-to-244
223 files changed, 7611 insertions, 11040 deletions
diff --git a/python/vyos/base.py b/python/vyos/base.py
index 054b1d837..ca96d96ce 100644
--- a/python/vyos/base.py
+++ b/python/vyos/base.py
@@ -63,3 +63,10 @@ class ConfigError(Exception):
message = fill(message, width=72)
# Call the base class constructor with the parameters it needs
super().__init__(message)
+
+class MigrationError(Exception):
+ def __init__(self, message):
+ # Reformat the message and trim it to 72 characters in length
+ message = fill(message, width=72)
+ # Call the base class constructor with the parameters it needs
+ super().__init__(message)
diff --git a/python/vyos/component_version.py b/python/vyos/component_version.py
index 9662ebfcf..94215531d 100644
--- a/python/vyos/component_version.py
+++ b/python/vyos/component_version.py
@@ -1,4 +1,4 @@
-# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2022-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
@@ -35,133 +35,170 @@ VyOS 1.2:
import os
import re
import sys
-import fileinput
+from dataclasses import dataclass
+from dataclasses import replace
+from typing import Optional
from vyos.xml_ref import component_version
+from vyos.utils.file import write_file
from vyos.version import get_version
from vyos.defaults import directories
DEFAULT_CONFIG_PATH = os.path.join(directories['config'], 'config.boot')
-def from_string(string_line, vintage='vyos'):
- """
- Get component version dictionary from string.
- Return empty dictionary if string contains no config information
- or raise error if component version string malformed.
- """
- version_dict = {}
-
- if vintage == 'vyos':
- if re.match(r'// vyos-config-version:.+', string_line):
- if not re.match(r'// vyos-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s*', string_line):
- raise ValueError(f"malformed configuration string: {string_line}")
+REGEX_WARN_VYOS = r'(// Warning: Do not remove the following line.)'
+REGEX_WARN_VYATTA = r'(/\* Warning: Do not remove the following line. \*/)'
+REGEX_COMPONENT_VERSION_VYOS = r'// vyos-config-version:\s+"([\w@:-]+)"\s*'
+REGEX_COMPONENT_VERSION_VYATTA = r'/\* === vyatta-config-version:\s+"([\w@:-]+)"\s+=== \*/'
+REGEX_RELEASE_VERSION_VYOS = r'// Release version:\s+(\S*)\s*'
+REGEX_RELEASE_VERSION_VYATTA = r'/\* Release version:\s+(\S*)\s*\*/'
- for pair in re.findall(r'([\w,-]+)@(\d+)', string_line):
- version_dict[pair[0]] = int(pair[1])
-
- elif vintage == 'vyatta':
- if re.match(r'/\* === vyatta-config-version:.+=== \*/$', string_line):
- if not re.match(r'/\* === vyatta-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s+=== \*/$', string_line):
- raise ValueError(f"malformed configuration string: {string_line}")
+CONFIG_FILE_VERSION = """\
+// Warning: Do not remove the following line.
+// vyos-config-version: "{}"
+// Release version: {}
+"""
- for pair in re.findall(r'([\w,-]+)@(\d+)', string_line):
- version_dict[pair[0]] = int(pair[1])
+warn_filter_vyos = re.compile(REGEX_WARN_VYOS)
+warn_filter_vyatta = re.compile(REGEX_WARN_VYATTA)
+
+regex_filter = { 'vyos': dict(zip(['component', 'release'],
+ [re.compile(REGEX_COMPONENT_VERSION_VYOS),
+ re.compile(REGEX_RELEASE_VERSION_VYOS)])),
+ 'vyatta': dict(zip(['component', 'release'],
+ [re.compile(REGEX_COMPONENT_VERSION_VYATTA),
+ re.compile(REGEX_RELEASE_VERSION_VYATTA)])) }
+
+@dataclass
+class VersionInfo:
+ component: Optional[dict[str,int]] = None
+ release: str = get_version()
+ vintage: str = 'vyos'
+ config_body: Optional[str] = None
+ footer_lines: Optional[list[str]] = None
+
+ def component_is_none(self) -> bool:
+ return bool(self.component is None)
+
+ def config_body_is_none(self) -> bool:
+ return bool(self.config_body is None)
+
+ def update_footer(self):
+ f = CONFIG_FILE_VERSION.format(component_to_string(self.component),
+ self.release)
+ self.footer_lines = f.splitlines()
+
+ def update_syntax(self):
+ self.vintage = 'vyos'
+ self.update_footer()
+
+ def update_release(self, release: str):
+ self.release = release
+ self.update_footer()
+
+ def update_component(self, key: str, version: int):
+ if not isinstance(version, int):
+ raise ValueError('version must be int')
+ if self.component is None:
+ self.component = {}
+ self.component[key] = version
+ self.component = dict(sorted(self.component.items(), key=lambda x: x[0]))
+ self.update_footer()
+
+ def update_config_body(self, config_str: str):
+ self.config_body = config_str
+
+ def write_string(self) -> str:
+ config_body = '' if self.config_body is None else self.config_body
+ footer_lines = [] if self.footer_lines is None else self.footer_lines
+
+ return config_body + '\n' + '\n'.join(footer_lines) + '\n'
+
+ def write(self, config_file):
+ string = self.write_string()
+ try:
+ write_file(config_file, string)
+ except Exception as e:
+ raise ValueError(e) from e
+
+def component_to_string(component: dict) -> str:
+ l = [f'{k}@{v}' for k, v in sorted(component.items(), key=lambda x: x[0])]
+ return ':'.join(l)
+
+def component_from_string(string: str) -> dict:
+ return {k: int(v) for k, v in re.findall(r'([\w,-]+)@(\d+)', string)}
+
+def version_info_from_file(config_file) -> VersionInfo:
+ """Return config file component and release version info."""
+ version_info = VersionInfo()
+ try:
+ with open(config_file) as f:
+ config_str = f.read()
+ except OSError:
+ return None
+
+ if len(parts := warn_filter_vyos.split(config_str)) > 1:
+ vintage = 'vyos'
+ elif len(parts := warn_filter_vyatta.split(config_str)) > 1:
+ vintage = 'vyatta'
else:
- raise ValueError("Unknown config string vintage")
-
- return version_dict
-
-def from_file(config_file_name=DEFAULT_CONFIG_PATH, vintage='vyos'):
- """
- Get component version dictionary parsing config file line by line
- """
- with open(config_file_name, 'r') as f:
- for line_in_config in f:
- version_dict = from_string(line_in_config, vintage=vintage)
- if version_dict:
- return version_dict
-
- # no version information
- return {}
-
-def from_system():
- """
- Get system component version dict.
- """
- return component_version()
-
-def format_string(ver: dict) -> str:
- """
- Version dict to string.
- """
- keys = list(ver)
- keys.sort()
- l = []
- for k in keys:
- v = ver[k]
- l.append(f'{k}@{v}')
- sep = ':'
- return sep.join(l)
-
-def version_footer(ver: dict, vintage='vyos') -> str:
- """
- Version footer as string.
- """
- ver_str = format_string(ver)
- release = get_version()
- if vintage == 'vyos':
- ret_str = (f'// Warning: Do not remove the following line.\n'
- + f'// vyos-config-version: "{ver_str}"\n'
- + f'// Release version: {release}\n')
- elif vintage == 'vyatta':
- ret_str = (f'/* Warning: Do not remove the following line. */\n'
- + f'/* === vyatta-config-version: "{ver_str}" === */\n'
- + f'/* Release version: {release} */\n')
- else:
- raise ValueError("Unknown config string vintage")
-
- return ret_str
-
-def system_footer(vintage='vyos') -> str:
- """
- System version footer as string.
- """
- ver_d = from_system()
- return version_footer(ver_d, vintage=vintage)
-
-def write_version_footer(ver: dict, file_name, vintage='vyos'):
- """
- Write version footer to file.
- """
- footer = version_footer(ver=ver, vintage=vintage)
- if file_name:
- with open(file_name, 'a') as f:
- f.write(footer)
+ version_info.config_body = parts[0] if parts else None
+ return version_info
+
+ version_info.vintage = vintage
+ version_info.config_body = parts[0]
+ version_lines = ''.join(parts[1:]).splitlines()
+ version_lines = [k for k in version_lines if k]
+ if len(version_lines) != 3:
+ raise ValueError(f'Malformed version strings: {version_lines}')
+
+ m = regex_filter[vintage]['component'].match(version_lines[1])
+ if not m:
+ raise ValueError(f'Malformed component string: {version_lines[1]}')
+ version_info.component = component_from_string(m.group(1))
+
+ m = regex_filter[vintage]['release'].match(version_lines[2])
+ if not m:
+ raise ValueError(f'Malformed component string: {version_lines[2]}')
+ version_info.release = m.group(1)
+
+ version_info.footer_lines = version_lines
+
+ return version_info
+
+def version_info_from_system() -> VersionInfo:
+ """Return system component and release version info."""
+ d = component_version()
+ sort_d = dict(sorted(d.items(), key=lambda x: x[0]))
+ version_info = VersionInfo(
+ component = sort_d,
+ release = get_version(),
+ vintage = 'vyos'
+ )
+
+ return version_info
+
+def version_info_copy(v: VersionInfo) -> VersionInfo:
+ """Make a copy of dataclass."""
+ return replace(v)
+
+def version_info_prune_component(x: VersionInfo, y: VersionInfo) -> VersionInfo:
+ """In place pruning of component keys of x not in y."""
+ if x.component is None or y.component is None:
+ return
+ x.component = { k: v for k,v in x.component.items() if k in y.component }
+
+def add_system_version(config_str: str = None, out_file: str = None):
+ """Wrap config string with system version and write to out_file.
+
+ For convenience, calling with no argument will write system version
+ string to stdout, for use in bash scripts.
+ """
+ version_info = version_info_from_system()
+ if config_str is not None:
+ version_info.update_config_body(config_str)
+ version_info.update_footer()
+ if out_file is not None:
+ version_info.write(out_file)
else:
- sys.stdout.write(footer)
-
-def write_system_footer(file_name, vintage='vyos'):
- """
- Write system version footer to file.
- """
- ver_d = from_system()
- return write_version_footer(ver_d, file_name=file_name, vintage=vintage)
-
-def remove_footer(file_name):
- """
- Remove old version footer.
- """
- for line in fileinput.input(file_name, inplace=True):
- if re.match(r'/\* Warning:.+ \*/$', line):
- continue
- if re.match(r'/\* === vyatta-config-version:.+=== \*/$', line):
- continue
- if re.match(r'/\* Release version:.+ \*/$', line):
- continue
- if re.match('// vyos-config-version:.+', line):
- continue
- if re.match('// Warning:.+', line):
- continue
- if re.match('// Release version:.+', line):
- continue
- sys.stdout.write(line)
+ sys.stdout.write(version_info.write_string())
diff --git a/python/vyos/compose_config.py b/python/vyos/compose_config.py
index efa28babe..79a8718c5 100644
--- a/python/vyos/compose_config.py
+++ b/python/vyos/compose_config.py
@@ -17,12 +17,13 @@
config.
"""
+import traceback
from pathlib import Path
from typing import TypeAlias, Union, Callable
from vyos.configtree import ConfigTree
from vyos.configtree import deep_copy as ct_deep_copy
-from vyos.utils.system import load_as_module
+from vyos.utils.system import load_as_module_source
ConfigObj: TypeAlias = Union[str, ConfigTree]
@@ -54,7 +55,8 @@ class ComposeConfig:
try:
func(self.config_tree)
except Exception as e:
- self.config_tree = self.checkpoint
+ if self.checkpoint_file is not None:
+ self.config_tree = self.checkpoint
raise ComposeConfigError(e) from e
def apply_file(self, func_file: str, func_name: str):
@@ -62,7 +64,7 @@ class ComposeConfig:
"""
try:
mod_name = Path(func_file).stem.replace('-', '_')
- mod = load_as_module(mod_name, func_file)
+ mod = load_as_module_source(mod_name, func_file)
func = getattr(mod, func_name)
except Exception as e:
raise ComposeConfigError(f'Error with {func_file}: {e}') from e
@@ -70,7 +72,9 @@ class ComposeConfig:
try:
self.apply_func(func)
except ComposeConfigError as e:
- raise ComposeConfigError(f'Error in {func_file}: {e}') from e
+ msg = str(e)
+ tb = f'{traceback.format_exc()}'
+ raise ComposeConfigError(f'Error in {func_file}: {msg}\n{tb}') from e
def to_string(self, with_version=False) -> str:
"""Return the rendered config tree.
diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py
index afd6e030b..5775070e2 100644
--- a/python/vyos/configtree.py
+++ b/python/vyos/configtree.py
@@ -15,6 +15,7 @@
import os
import re
import json
+import logging
from ctypes import cdll, c_char_p, c_void_p, c_int, c_bool
@@ -161,6 +162,8 @@ class ConfigTree(object):
self.__version = ''
self.__migration = os.environ.get('VYOS_MIGRATION')
+ if self.__migration:
+ self.migration_log = logging.getLogger('vyos.migrate')
def __del__(self):
if self.__config is not None:
@@ -215,7 +218,7 @@ class ConfigTree(object):
self.__set_add_value(self.__config, path_str, str(value).encode())
if self.__migration:
- print(f"- op: set path: {path} value: {value} replace: {replace}")
+ self.migration_log.info(f"- op: set path: {path} value: {value} replace: {replace}")
def delete(self, path):
check_path(path)
@@ -226,7 +229,7 @@ class ConfigTree(object):
raise ConfigTreeError(f"Path doesn't exist: {path}")
if self.__migration:
- print(f"- op: delete path: {path}")
+ self.migration_log.info(f"- op: delete path: {path}")
def delete_value(self, path, value):
check_path(path)
@@ -242,7 +245,7 @@ class ConfigTree(object):
raise ConfigTreeError()
if self.__migration:
- print(f"- op: delete_value path: {path} value: {value}")
+ self.migration_log.info(f"- op: delete_value path: {path} value: {value}")
def rename(self, path, new_name):
check_path(path)
@@ -258,7 +261,7 @@ class ConfigTree(object):
raise ConfigTreeError("Path [{}] doesn't exist".format(path))
if self.__migration:
- print(f"- op: rename old_path: {path} new_path: {new_path}")
+ self.migration_log.info(f"- op: rename old_path: {path} new_path: {new_path}")
def copy(self, old_path, new_path):
check_path(old_path)
@@ -275,7 +278,7 @@ class ConfigTree(object):
raise ConfigTreeError(msg)
if self.__migration:
- print(f"- op: copy old_path: {old_path} new_path: {new_path}")
+ self.migration_log.info(f"- op: copy old_path: {old_path} new_path: {new_path}")
def exists(self, path):
check_path(path)
diff --git a/python/vyos/load_config.py b/python/vyos/load_config.py
index af563614d..b910a2f92 100644
--- a/python/vyos/load_config.py
+++ b/python/vyos/load_config.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -28,9 +28,7 @@ from typing import Union, Literal, TypeAlias, get_type_hints, get_args
from vyos.config import Config
from vyos.configtree import ConfigTree, DiffTree
from vyos.configsource import ConfigSourceSession, VyOSError
-from vyos.component_version import from_string as version_from_string
-from vyos.component_version import from_system as version_from_system
-from vyos.migrator import Migrator, VirtualMigrator, MigratorError
+from vyos.migrate import ConfigMigrate, ConfigMigrateError
from vyos.utils.process import popen, DEVNULL
Variety: TypeAlias = Literal['explicit', 'batch', 'tree', 'legacy']
@@ -51,20 +49,6 @@ def get_proposed_config(config_file: str = None) -> ConfigTree:
config_str = Path(config_file).read_text()
return ConfigTree(config_str)
-def migration_needed(config_obj: ConfigObj) -> bool:
- """Check if a migration is needed for the config object.
- """
- if not isinstance(config_obj, ConfigTree):
- atree = get_proposed_config(config_obj)
- else:
- atree = config_obj
- version_str = atree.get_version_string()
- if not version_str:
- return True
- aversion = version_from_string(version_str.splitlines()[1])
- bversion = version_from_system()
- return aversion != bversion
-
def check_session(strict: bool, switch: Variety) -> None:
"""Check if we are in a config session, with no uncommitted changes, if
strict. This is not needed for legacy load, as these checks are
@@ -128,12 +112,10 @@ def migrate(config_obj: ConfigObj) -> ConfigObj:
else:
config_file = config_obj
- virtual_migration = VirtualMigrator(config_file)
- migration = Migrator(config_file)
+ config_migrate = ConfigMigrate(config_file)
try:
- virtual_migration.run()
- migration.run()
- except MigratorError as e:
+ config_migrate.run()
+ except ConfigMigrateError as e:
raise LoadConfigError(e) from e
else:
if isinstance(config_obj, ConfigTree):
@@ -193,8 +175,7 @@ def load(config_obj: ConfigObj, strict: bool = True,
check_session(strict, switch)
- if migration_needed(config_obj):
- config_obj = migrate(config_obj)
+ config_obj = migrate(config_obj)
func = getattr(thismod, f'load_{switch}')
func(config_obj)
diff --git a/python/vyos/migrate.py b/python/vyos/migrate.py
new file mode 100644
index 000000000..9d1613676
--- /dev/null
+++ b/python/vyos/migrate.py
@@ -0,0 +1,283 @@
+# Copyright 2019-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/>.
+
+import os
+import re
+import json
+import logging
+from pathlib import Path
+from grp import getgrnam
+
+from vyos.component_version import VersionInfo
+from vyos.component_version import version_info_from_system
+from vyos.component_version import version_info_from_file
+from vyos.component_version import version_info_copy
+from vyos.component_version import version_info_prune_component
+from vyos.compose_config import ComposeConfig
+from vyos.compose_config import ComposeConfigError
+from vyos.configtree import ConfigTree
+from vyos.defaults import directories as default_dir
+from vyos.defaults import component_version_json
+
+
+log_file = Path(default_dir['config']).joinpath('vyos-migrate.log')
+
+class ConfigMigrateError(Exception):
+ """Raised on error in config migration."""
+
+class ConfigMigrate:
+ # pylint: disable=too-many-instance-attributes
+ # the number is reasonable in this case
+ def __init__(self, config_file: str, force=False,
+ output_file: str = None, checkpoint_file: str = None):
+ self.config_file: str = config_file
+ self.force: bool = force
+ self.system_version: VersionInfo = version_info_from_system()
+ self.file_version: VersionInfo = version_info_from_file(self.config_file)
+ self.compose = None
+ self.output_file = output_file
+ self.checkpoint_file = checkpoint_file
+ self.logger = None
+ self.config_modified = True
+
+ if self.file_version is None:
+ raise ConfigMigrateError(f'failed to read config file {self.config_file}')
+
+ def migration_needed(self) -> bool:
+ return self.system_version.component != self.file_version.component
+
+ def release_update_needed(self) -> bool:
+ return self.system_version.release != self.file_version.release
+
+ def syntax_update_needed(self) -> bool:
+ return self.system_version.vintage != self.file_version.vintage
+
+ def update_release(self):
+ """
+ Update config file release version.
+ """
+ self.file_version.update_release(self.system_version.release)
+
+ def update_syntax(self):
+ """
+ Update config file syntax.
+ """
+ self.file_version.update_syntax()
+
+ @staticmethod
+ def normalize_config_body(version_info: VersionInfo):
+ """
+ This is an interim workaround for the cosmetic issue of node
+ ordering when composing operations on the internal config_tree:
+ ordering is performed on parsing, hence was maintained in the old
+ system which would parse/write on each application of a migration
+ script (~200). Here, we will take the cost of one extra parsing to
+ reorder before save, for easier review.
+ """
+ if not version_info.config_body_is_none():
+ ct = ConfigTree(version_info.config_body)
+ version_info.update_config_body(ct.to_string())
+
+ def write_config(self):
+ if self.output_file is not None:
+ config_file = self.output_file
+ else:
+ config_file = self.config_file
+
+ try:
+ self.file_version.write(config_file)
+ except ValueError as e:
+ raise ConfigMigrateError(f'failed to write {config_file}: {e}') from e
+
+ def init_logger(self):
+ self.logger = logging.getLogger(__name__)
+ self.logger.setLevel(logging.DEBUG)
+
+ fh = ConfigMigrate.group_perm_file_handler(log_file,
+ group='vyattacfg',
+ mode='w')
+ fh.setLevel(logging.INFO)
+ fh_formatter = logging.Formatter('%(message)s')
+ fh.setFormatter(fh_formatter)
+ self.logger.addHandler(fh)
+ ch = logging.StreamHandler()
+ ch.setLevel(logging.WARNING)
+ ch_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
+ ch.setFormatter(ch_formatter)
+ self.logger.addHandler(ch)
+
+ @staticmethod
+ def group_perm_file_handler(filename, group=None, mode='a'):
+ # pylint: disable=consider-using-with
+ if group is None:
+ return logging.FileHandler(filename, mode)
+ gid = getgrnam(group).gr_gid
+ if not os.path.exists(filename):
+ open(filename, 'a').close()
+ os.chown(filename, -1, gid)
+ os.chmod(filename, 0o664)
+ return logging.FileHandler(filename, mode)
+
+ @staticmethod
+ def sort_function():
+ """
+ Define sort function for migration files as tuples (n, m) for file
+ n-to-m.
+ """
+ numbers = re.compile(r'(\d+)')
+ def func(p: Path):
+ parts = numbers.split(p.stem)
+ return list(map(int, parts[1::2]))
+ return func
+
+ @staticmethod
+ def file_ext(file_path: Path) -> str:
+ """
+ Return an identifier from file name for checkpoint file extension.
+ """
+ return f'{file_path.parent.stem}_{file_path.stem}'
+
+ def run_migration_scripts(self):
+ """
+ Call migration files iteratively.
+ """
+ os.environ['VYOS_MIGRATION'] = '1'
+
+ self.init_logger()
+ self.logger.info("List of applied migration modules:")
+
+ components = list(self.system_version.component)
+ components.sort()
+
+ # T4382: 'bgp' needs to follow 'quagga':
+ if 'bgp' in components and 'quagga' in components:
+ components.insert(components.index('quagga'),
+ components.pop(components.index('bgp')))
+
+ revision: VersionInfo = version_info_copy(self.file_version)
+ # prune retired, for example, zone-policy
+ version_info_prune_component(revision, self.system_version)
+
+ migrate_dir = Path(default_dir['migrate'])
+ sort_func = ConfigMigrate.sort_function()
+
+ for key in components:
+ p = migrate_dir.joinpath(key)
+ script_list = list(p.glob('*-to-*'))
+ script_list = sorted(script_list, key=sort_func)
+
+ if not self.file_version.component_is_none() and not self.force:
+ start = self.file_version.component.get(key, 0)
+ script_list = list(filter(lambda x, st=start: sort_func(x)[0] >= st,
+ script_list))
+
+ if not script_list: # no applicable migration scripts
+ revision.update_component(key, self.system_version.component[key])
+ continue
+
+ for file in script_list:
+ f = file.as_posix()
+ self.logger.info(f'applying {f}')
+ try:
+ self.compose.apply_file(f, func_name='migrate')
+ except ComposeConfigError as e:
+ self.logger.error(e)
+ if self.checkpoint_file:
+ check = f'{self.checkpoint_file}_{ConfigMigrate.file_ext(file)}'
+ revision.update_config_body(self.compose.to_string())
+ ConfigMigrate.normalize_config_body(revision)
+ revision.write(check)
+ break
+ else:
+ revision.update_component(key, sort_func(file)[1])
+
+ revision.update_config_body(self.compose.to_string())
+ ConfigMigrate.normalize_config_body(revision)
+ self.file_version = version_info_copy(revision)
+
+ if revision.component != self.system_version.component:
+ raise ConfigMigrateError(f'incomplete migration: check {log_file} for error')
+
+ del os.environ['VYOS_MIGRATION']
+
+ def save_json_record(self):
+ """
+ Write component versions to a json file
+ """
+ version_file = component_version_json
+
+ try:
+ with open(version_file, 'w') as f:
+ f.write(json.dumps(self.system_version.component,
+ indent=2, sort_keys=True))
+ except OSError:
+ pass
+
+ def load_config(self):
+ """
+ Instantiate a ComposeConfig object with the config string.
+ """
+
+ self.compose = ComposeConfig(self.file_version.config_body, self.checkpoint_file)
+
+ def run(self):
+ """
+ If migration needed, run migration scripts and update config file.
+ If only release version update needed, update release version.
+ """
+ # save system component versions in json file for reference
+ self.save_json_record()
+
+ if not self.migration_needed():
+ if self.release_update_needed():
+ self.update_release()
+ self.write_config()
+ else:
+ self.config_modified = False
+ return
+
+ if self.syntax_update_needed():
+ self.update_syntax()
+ self.write_config()
+
+ self.load_config()
+
+ self.run_migration_scripts()
+
+ self.update_release()
+ self.write_config()
+
+ def run_script(self, test_script: str):
+ """
+ Run a single migration script. For testing this simply provides the
+ body for loading and writing the result; the component string is not
+ updated.
+ """
+
+ self.load_config()
+ self.init_logger()
+
+ os.environ['VYOS_MIGRATION'] = '1'
+
+ try:
+ self.compose.apply_file(test_script, func_name='migrate')
+ except ComposeConfigError as e:
+ self.logger.error(f'config-migration error in {test_script}: {e}')
+ else:
+ self.file_version.update_config_body(self.compose.to_string())
+
+ del os.environ['VYOS_MIGRATION']
+
+ self.write_config()
diff --git a/python/vyos/migrator.py b/python/vyos/migrator.py
deleted file mode 100644
index 872682bc0..000000000
--- a/python/vyos/migrator.py
+++ /dev/null
@@ -1,226 +0,0 @@
-# Copyright 2019-2022 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/>.
-
-import sys
-import os
-import json
-import logging
-
-import vyos.defaults
-import vyos.component_version as component_version
-from vyos.utils.process import cmd
-
-log_file = os.path.join(vyos.defaults.directories['config'], 'vyos-migrate.log')
-
-class MigratorError(Exception):
- pass
-
-class Migrator(object):
- def __init__(self, config_file, force=False, set_vintage='vyos'):
- self._config_file = config_file
- self._force = force
- self._set_vintage = set_vintage
- self._config_file_vintage = None
- self._changed = False
-
- def init_logger(self):
- self.logger = logging.getLogger(__name__)
- self.logger.setLevel(logging.DEBUG)
-
- # on adding the file handler, allow write permission for cfg_group;
- # restore original umask on exit
- mask = os.umask(0o113)
- fh = logging.FileHandler(log_file)
- formatter = logging.Formatter('%(message)s')
- fh.setFormatter(formatter)
- self.logger.addHandler(fh)
- os.umask(mask)
-
- def read_config_file_versions(self):
- """
- Get component versions from config file footer and set vintage;
- return empty dictionary if config string is missing.
- """
- cfg_file = self._config_file
- component_versions = {}
-
- cfg_versions = component_version.from_file(cfg_file, vintage='vyatta')
-
- if cfg_versions:
- self._config_file_vintage = 'vyatta'
- component_versions = cfg_versions
-
- cfg_versions = component_version.from_file(cfg_file, vintage='vyos')
-
- if cfg_versions:
- self._config_file_vintage = 'vyos'
- component_versions = cfg_versions
-
- return component_versions
-
- def update_vintage(self):
- old_vintage = self._config_file_vintage
-
- if self._set_vintage:
- self._config_file_vintage = self._set_vintage
-
- if self._config_file_vintage not in ['vyatta', 'vyos']:
- raise MigratorError("Unknown vintage.")
-
- if self._config_file_vintage == old_vintage:
- return False
- else:
- return True
-
- def run_migration_scripts(self, config_file_versions, system_versions):
- """
- Run migration scripts iteratively, until config file version equals
- system component version.
- """
- os.environ['VYOS_MIGRATION'] = '1'
- self.init_logger()
-
- self.logger.info("List of executed migration scripts:")
-
- cfg_versions = config_file_versions
- sys_versions = system_versions
-
- sys_keys = list(sys_versions.keys())
- sys_keys.sort()
-
- # XXX 'bgp' needs to follow 'quagga':
- if 'bgp' in sys_keys and 'quagga' in sys_keys:
- sys_keys.insert(sys_keys.index('quagga'),
- sys_keys.pop(sys_keys.index('bgp')))
-
- rev_versions = {}
-
- for key in sys_keys:
- sys_ver = sys_versions[key]
- if key in cfg_versions:
- cfg_ver = cfg_versions[key]
- else:
- cfg_ver = 0
-
- migrate_script_dir = os.path.join(
- vyos.defaults.directories['migrate'], key)
-
- while cfg_ver < sys_ver:
- next_ver = cfg_ver + 1
-
- migrate_script = os.path.join(migrate_script_dir,
- '{}-to-{}'.format(cfg_ver, next_ver))
-
- try:
- out = cmd([migrate_script, self._config_file])
- self.logger.info(f'{migrate_script}')
- if out: self.logger.info(out)
- except FileNotFoundError:
- pass
- except Exception as err:
- print("\nMigration script error: {0}: {1}."
- "".format(migrate_script, err))
- sys.exit(1)
-
- cfg_ver = next_ver
- rev_versions[key] = cfg_ver
-
- del os.environ['VYOS_MIGRATION']
- return rev_versions
-
- def write_config_file_versions(self, cfg_versions):
- """
- Write new versions string.
- """
- if self._config_file_vintage == 'vyatta':
- component_version.write_version_footer(cfg_versions,
- self._config_file,
- vintage='vyatta')
-
- if self._config_file_vintage == 'vyos':
- component_version.write_version_footer(cfg_versions,
- self._config_file,
- vintage='vyos')
-
- def save_json_record(self, component_versions: dict):
- """
- Write component versions to a json file
- """
- mask = os.umask(0o113)
- version_file = vyos.defaults.component_version_json
- try:
- with open(version_file, 'w') as f:
- f.write(json.dumps(component_versions, indent=2, sort_keys=True))
- except OSError:
- pass
- finally:
- os.umask(mask)
-
- def run(self):
- """
- Gather component versions from config file and system.
- Run migration scripts.
- Update vintage ('vyatta' or 'vyos'), if needed.
- If changed, remove old versions string from config file, and
- write new versions string.
- """
- cfg_file = self._config_file
-
- cfg_versions = self.read_config_file_versions()
- if self._force:
- # This will force calling all migration scripts:
- cfg_versions = {}
-
- sys_versions = component_version.from_system()
-
- # save system component versions in json file for easy reference
- self.save_json_record(sys_versions)
-
- rev_versions = self.run_migration_scripts(cfg_versions, sys_versions)
-
- if rev_versions != cfg_versions:
- self._changed = True
-
- if self.update_vintage():
- self._changed = True
-
- if not self._changed:
- return
-
- component_version.remove_footer(cfg_file)
-
- self.write_config_file_versions(rev_versions)
-
- def config_changed(self):
- return self._changed
-
-class VirtualMigrator(Migrator):
- def run(self):
- cfg_file = self._config_file
-
- cfg_versions = self.read_config_file_versions()
- if not cfg_versions:
- return
-
- if self.update_vintage():
- self._changed = True
-
- if not self._changed:
- return
-
- component_version.remove_footer(cfg_file)
-
- self.write_config_file_versions(cfg_versions)
-
diff --git a/python/vyos/utils/dict.py b/python/vyos/utils/dict.py
index 9a4671c5f..1a7a6b96f 100644
--- a/python/vyos/utils/dict.py
+++ b/python/vyos/utils/dict.py
@@ -34,7 +34,7 @@ def colon_separated_to_dict(data_string, uniquekeys=False):
otherwise they are always lists of strings.
"""
import re
- key_value_re = re.compile('([^:]+)\s*\:\s*(.*)')
+ key_value_re = re.compile(r'([^:]+)\s*\:\s*(.*)')
data_raw = re.split('\n', data_string)
diff --git a/python/vyos/utils/system.py b/python/vyos/utils/system.py
index 55813a5f7..cfd5b142c 100644
--- a/python/vyos/utils/system.py
+++ b/python/vyos/utils/system.py
@@ -98,3 +98,15 @@ def load_as_module(name: str, path: str):
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
+
+def load_as_module_source(name: str, path: str):
+ """ Necessary modification of load_as_module for files without *.py
+ extension """
+ import importlib.util
+ from importlib.machinery import SourceFileLoader
+
+ loader = SourceFileLoader(name, path)
+ spec = importlib.util.spec_from_loader(name, loader)
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ return mod
diff --git a/src/helpers/system-versions-foot.py b/src/helpers/add-system-version.py
index 9614f0d28..5270ee7d3 100755
--- a/src/helpers/system-versions-foot.py
+++ b/src/helpers/add-system-version.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
-# Copyright 2019, 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-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
@@ -15,14 +15,6 @@
# 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/>.
-import sys
-import vyos.defaults
-from vyos.component_version import write_system_footer
+from vyos.component_version import add_system_version
-sys.stdout.write("\n\n")
-if vyos.defaults.cfg_vintage == 'vyos':
- write_system_footer(None, vintage='vyos')
-elif vyos.defaults.cfg_vintage == 'vyatta':
- write_system_footer(None, vintage='vyatta')
-else:
- write_system_footer(None, vintage='vyos')
+add_system_version()
diff --git a/src/helpers/run-config-migration.py b/src/helpers/run-config-migration.py
index ce647ad0a..e6ce97363 100755
--- a/src/helpers/run-config-migration.py
+++ b/src/helpers/run-config-migration.py
@@ -1,86 +1,78 @@
-#!/usr/bin/python3
-
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019-2024 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 program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
#
-# This library is distributed in the hope that it will be useful,
+# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library. If not, see <http://www.gnu.org/licenses/>.
+# 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 os
import sys
-import argparse
-import datetime
-
-from vyos.utils.process import cmd
-from vyos.migrator import Migrator, VirtualMigrator
-
-def main():
- argparser = argparse.ArgumentParser(
- formatter_class=argparse.RawTextHelpFormatter)
- argparser.add_argument('config_file', type=str,
- help="configuration file to migrate")
- argparser.add_argument('--force', action='store_true',
- help="Force calling of all migration scripts.")
- argparser.add_argument('--set-vintage', type=str,
- choices=['vyatta', 'vyos'],
- help="Set the format for the config version footer in config"
- " file:\n"
- "set to 'vyatta':\n"
- "(for '/* === vyatta-config-version ... */' format)\n"
- "or 'vyos':\n"
- "(for '// vyos-config-version ...' format).")
- argparser.add_argument('--virtual', action='store_true',
- help="Update the format of the trailing comments in"
- " config file,\nfrom 'vyatta' to 'vyos'; no migration"
- " scripts are run.")
- args = argparser.parse_args()
+import time
+from argparse import ArgumentParser
+from shutil import copyfile
- config_file_name = args.config_file
- force_on = args.force
- vintage = args.set_vintage
- virtual = args.virtual
+from vyos.migrate import ConfigMigrate
+from vyos.migrate import ConfigMigrateError
- if not os.access(config_file_name, os.R_OK):
- print("Read error: {}.".format(config_file_name))
- sys.exit(1)
+parser = ArgumentParser()
+parser.add_argument('config_file', type=str,
+ help="configuration file to migrate")
+parser.add_argument('--test-script', type=str,
+ help="test named script")
+parser.add_argument('--output-file', type=str,
+ help="write to named output file instead of config file")
+parser.add_argument('--force', action='store_true',
+ help="force run of all migration scripts")
- if not os.access(config_file_name, os.W_OK):
- print("Write error: {}.".format(config_file_name))
- sys.exit(1)
+args = parser.parse_args()
- separator = "."
- backup_file_name = separator.join([config_file_name,
- '{0:%Y-%m-%d-%H%M%S}'.format(datetime.datetime.now()),
- 'pre-migration'])
+config_file = args.config_file
+out_file = args.output_file
+test_script = args.test_script
+force = args.force
- cmd(f'cp -p {config_file_name} {backup_file_name}')
+if not os.access(config_file, os.R_OK):
+ print(f"Config file '{config_file}' not readable")
+ sys.exit(1)
- if not virtual:
- virtual_migration = VirtualMigrator(config_file_name)
- virtual_migration.run()
+if out_file is None:
+ if not os.access(config_file, os.W_OK):
+ print(f"Config file '{config_file}' not writeable")
+ sys.exit(1)
+else:
+ try:
+ open(out_file, 'w').close()
+ except OSError:
+ print(f"Output file '{out_file}' not writeable")
+ sys.exit(1)
- migration = Migrator(config_file_name, force=force_on)
- migration.run()
+config_migrate = ConfigMigrate(config_file, force=force, output_file=out_file)
- if not migration.config_changed():
- os.remove(backup_file_name)
- else:
- virtual_migration = VirtualMigrator(config_file_name,
- set_vintage=vintage)
+if test_script:
+ # run_script and exit
+ config_migrate.run_script(test_script)
+ sys.exit(0)
- virtual_migration.run()
+backup = None
+if out_file is None:
+ timestr = time.strftime("%Y%m%d-%H%M%S")
+ backup = f'{config_file}.{timestr}.pre-migration'
+ copyfile(config_file, backup)
- if not virtual_migration.config_changed():
- os.remove(backup_file_name)
+try:
+ config_migrate.run()
+except ConfigMigrateError as e:
+ print(f'Error: {e}')
+ sys.exit(1)
-if __name__ == '__main__':
- main()
+if backup is not None and not config_migrate.config_modified:
+ os.unlink(backup)
diff --git a/src/helpers/vyos-load-config.py b/src/helpers/vyos-load-config.py
index 4ec865454..16083fd41 100755
--- a/src/helpers/vyos-load-config.py
+++ b/src/helpers/vyos-load-config.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -30,7 +30,8 @@ import tempfile
import vyos.defaults
import vyos.remote
from vyos.configsource import ConfigSourceSession, VyOSError
-from vyos.migrator import Migrator, VirtualMigrator, MigratorError
+from vyos.migrate import ConfigMigrate
+from vyos.migrate import ConfigMigrateError
class LoadConfig(ConfigSourceSession):
"""A subclass for calling 'loadFile'.
@@ -81,22 +82,16 @@ with tempfile.NamedTemporaryFile() as fp:
with open(fp.name, 'w') as fd:
fd.write(config_string)
- virtual_migration = VirtualMigrator(fp.name)
+ config_migrate = ConfigMigrate(fp.name)
try:
- virtual_migration.run()
- except MigratorError as err:
- sys.exit('{}'.format(err))
-
- migration = Migrator(fp.name)
- try:
- migration.run()
- except MigratorError as err:
- sys.exit('{}'.format(err))
+ config_migrate.run()
+ except ConfigMigrateError as err:
+ sys.exit(err)
try:
config.load_config(fp.name)
except VyOSError as err:
- sys.exit('{}'.format(err))
+ sys.exit(err)
if config.session_changed():
print("Load complete. Use 'commit' to make changes effective.")
diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py
index 35424626e..5ef845ac2 100755
--- a/src/helpers/vyos-merge-config.py
+++ b/src/helpers/vyos-merge-config.py
@@ -22,7 +22,8 @@ import vyos.remote
from vyos.config import Config
from vyos.configtree import ConfigTree
-from vyos.migrator import Migrator, VirtualMigrator
+from vyos.migrate import ConfigMigrate
+from vyos.migrate import ConfigMigrateError
from vyos.utils.process import cmd
from vyos.utils.process import DEVNULL
@@ -61,15 +62,11 @@ with tempfile.NamedTemporaryFile() as file_to_migrate:
with open(file_to_migrate.name, 'w') as fd:
fd.write(config_file)
- virtual_migration = VirtualMigrator(file_to_migrate.name)
- virtual_migration.run()
-
- migration = Migrator(file_to_migrate.name)
- migration.run()
-
- if virtual_migration.config_changed() or migration.config_changed():
- with open(file_to_migrate.name, 'r') as fd:
- config_file = fd.read()
+ config_migrate = ConfigMigrate(file_to_migrate.name)
+ try:
+ config_migrate.run()
+ except ConfigMigrateError as e:
+ sys.exit(e)
merge_config_tree = ConfigTree(config_file)
diff --git a/src/helpers/vyos-save-config.py b/src/helpers/vyos-save-config.py
index 518bd9864..fa2ea0ce4 100755
--- a/src/helpers/vyos-save-config.py
+++ b/src/helpers/vyos-save-config.py
@@ -23,7 +23,7 @@ from argparse import ArgumentParser
from vyos.config import Config
from vyos.remote import urlc
-from vyos.component_version import system_footer
+from vyos.component_version import add_system_version
from vyos.defaults import directories
DEFAULT_CONFIG_PATH = os.path.join(directories['config'], 'config.boot')
@@ -50,14 +50,13 @@ if re.match(r'\w+:/', save_file):
config = Config()
ct = config.get_config_tree(effective=True)
+# pylint: disable=consider-using-with
write_file = save_file if remote_save is None else NamedTemporaryFile(delete=False).name
-with open(write_file, 'w') as f:
- # config_tree is None before boot configuration is complete;
- # automated saves should check boot_configuration_complete
- if ct is not None:
- f.write(ct.to_string())
- f.write("\n")
- f.write(system_footer())
+
+# config_tree is None before boot configuration is complete;
+# automated saves should check boot_configuration_complete
+config_str = None if ct is None else ct.to_string()
+add_system_version(config_str, write_file)
if json_file is not None and ct is not None:
try:
diff --git a/src/helpers/vyos_net_name b/src/helpers/vyos_net_name
index 8c0992414..518e204f9 100755
--- a/src/helpers/vyos_net_name
+++ b/src/helpers/vyos_net_name
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -26,7 +26,7 @@ from vyos.configtree import ConfigTree
from vyos.defaults import directories
from vyos.utils.process import cmd
from vyos.utils.boot import boot_configuration_complete
-from vyos.migrator import VirtualMigrator
+from vyos.migrate import ConfigMigrate
vyos_udev_dir = directories['vyos_udev_dir']
vyos_log_dir = '/run/udev/log'
@@ -147,8 +147,10 @@ def get_configfile_interfaces() -> dict:
with tempfile.NamedTemporaryFile() as fp:
with open(fp.name, 'w') as fd:
fd.write(config_file)
- virtual_migration = VirtualMigrator(fp.name)
- virtual_migration.run()
+ config_migrate = ConfigMigrate(fp.name)
+ if config_migrate.syntax_update_needed():
+ config_migrate.update_syntax()
+ config_migrate.write_config()
with open(fp.name) as fd:
config_file = fd.read()
diff --git a/src/init/vyos-router b/src/init/vyos-router
index 59004fdc1..8825cc16a 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -134,14 +134,14 @@ init_bootfile () {
if [ ! -r $DEFAULT_BOOTFILE ]; then
if [ -f $vyos_data_dir/config.boot.default ]; then
cp $vyos_data_dir/config.boot.default $DEFAULT_BOOTFILE
- $vyos_libexec_dir/system-versions-foot.py >> $DEFAULT_BOOTFILE
+ $vyos_libexec_dir/add-system-version.py >> $DEFAULT_BOOTFILE
fi
fi
if [ ! -r $BOOTFILE ] ; then
if [ -f $DEFAULT_BOOTFILE ]; then
cp $DEFAULT_BOOTFILE $BOOTFILE
else
- $vyos_libexec_dir/system-versions-foot.py > $BOOTFILE
+ $vyos_libexec_dir/add-system-version.py > $BOOTFILE
fi
chgrp ${GROUP} $BOOTFILE
chmod 660 $BOOTFILE
diff --git a/src/migration-scripts/bgp/0-to-1 b/src/migration-scripts/bgp/0-to-1
index 5b8e8a163..a2f3343d8 100755..100644
--- a/src/migration-scripts/bgp/0-to-1
+++ b/src/migration-scripts/bgp/0-to-1
@@ -1,60 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3417: migrate BGP tagNode to node as we can only have one BGP process
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
-
-if not config.exists(base) or not config.is_tag(base):
- # Nothing to do
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ base = ['protocols', 'bgp']
-# Only one BGP process is supported, thus this operation is savea
-asn = config.list_nodes(base)
-bgp_base = base + asn
+ if not config.exists(base) or not config.is_tag(base):
+ # Nothing to do
+ return
-# We need a temporary copy of the config
-tmp_base = ['protocols', 'bgp2']
-config.copy(bgp_base, tmp_base)
+ # Only one BGP process is supported, thus this operation is savea
+ asn = config.list_nodes(base)
+ bgp_base = base + asn
-# Now it's save to delete the old configuration
-config.delete(base)
+ # We need a temporary copy of the config
+ tmp_base = ['protocols', 'bgp2']
+ config.copy(bgp_base, tmp_base)
-# Rename temporary copy to new final config and set new "local-as" option
-config.rename(tmp_base, 'bgp')
-config.set(base + ['local-as'], value=asn[0])
+ # Now it's save to delete the old configuration
+ config.delete(base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # Rename temporary copy to new final config and set new "local-as" option
+ config.rename(tmp_base, 'bgp')
+ config.set(base + ['local-as'], value=asn[0])
diff --git a/src/migration-scripts/bgp/1-to-2 b/src/migration-scripts/bgp/1-to-2
index a40d86e67..c0fc3b05a 100755..100644
--- a/src/migration-scripts/bgp/1-to-2
+++ b/src/migration-scripts/bgp/1-to-2
@@ -1,84 +1,64 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3741: no-ipv4-unicast is now enabled by default
# T5937: Migrate IPv6 BGP Neighbor Peer Groups
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['protocols', 'bgp']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
+ # This is now a default option - simply delete it.
+ # As it was configured explicitly - we can also bail out early as we need to
+ # do nothing!
+ if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']):
+ config.delete(base + ['parameters', 'default', 'no-ipv4-unicast'])
-if not config.exists(base):
- # Nothing to do
- exit(0)
+ # Check if the "default" node is now empty, if so - remove it
+ if len(config.list_nodes(base + ['parameters', 'default'])) == 0:
+ config.delete(base + ['parameters', 'default'])
-# This is now a default option - simply delete it.
-# As it was configured explicitly - we can also bail out early as we need to
-# do nothing!
-if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']):
- config.delete(base + ['parameters', 'default', 'no-ipv4-unicast'])
+ # Check if the "default" node is now empty, if so - remove it
+ if len(config.list_nodes(base + ['parameters'])) == 0:
+ config.delete(base + ['parameters'])
+ else:
+ # As we now install a new default option into BGP we need to migrate all
+ # existing BGP neighbors and restore the old behavior
+ if config.exists(base + ['neighbor']):
+ for neighbor in config.list_nodes(base + ['neighbor']):
+ peer_group = base + ['neighbor', neighbor, 'peer-group']
+ if config.exists(peer_group):
+ peer_group_name = config.return_value(peer_group)
+ # peer group enables old behavior for neighbor - bail out
+ if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']):
+ continue
- # Check if the "default" node is now empty, if so - remove it
- if len(config.list_nodes(base + ['parameters', 'default'])) == 0:
- config.delete(base + ['parameters', 'default'])
+ afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast']
+ if not config.exists(afi_ipv4):
+ config.set(afi_ipv4)
- # Check if the "default" node is now empty, if so - remove it
- if len(config.list_nodes(base + ['parameters'])) == 0:
- config.delete(base + ['parameters'])
-else:
- # As we now install a new default option into BGP we need to migrate all
- # existing BGP neighbors and restore the old behavior
+ # Migrate IPv6 AFI peer-group
if config.exists(base + ['neighbor']):
for neighbor in config.list_nodes(base + ['neighbor']):
- peer_group = base + ['neighbor', neighbor, 'peer-group']
- if config.exists(peer_group):
- peer_group_name = config.return_value(peer_group)
- # peer group enables old behavior for neighbor - bail out
- if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']):
- continue
-
- afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast']
- if not config.exists(afi_ipv4):
- config.set(afi_ipv4)
-
-# Migrate IPv6 AFI peer-group
-if config.exists(base + ['neighbor']):
- for neighbor in config.list_nodes(base + ['neighbor']):
- tmp_path = base + ['neighbor', neighbor, 'address-family', 'ipv6-unicast', 'peer-group']
- if config.exists(tmp_path):
- peer_group = config.return_value(tmp_path)
- config.set(base + ['neighbor', neighbor, 'peer-group'], value=peer_group)
- config.delete(tmp_path)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ tmp_path = base + ['neighbor', neighbor, 'address-family', 'ipv6-unicast', 'peer-group']
+ if config.exists(tmp_path):
+ peer_group = config.return_value(tmp_path)
+ config.set(base + ['neighbor', neighbor, 'peer-group'], value=peer_group)
+ config.delete(tmp_path)
diff --git a/src/migration-scripts/bgp/2-to-3 b/src/migration-scripts/bgp/2-to-3
index 34d321a96..d8bc34db6 100755..100644
--- a/src/migration-scripts/bgp/2-to-3
+++ b/src/migration-scripts/bgp/2-to-3
@@ -1,51 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4257: Discussion on changing BGP autonomous system number syntax
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-# Check if BGP is even configured. Then check if local-as exists, then add the system-as, then remove the local-as. This is for global configuration.
-if config.exists(['protocols', 'bgp']):
- if config.exists(['protocols', 'bgp', 'local-as']):
- config.rename(['protocols', 'bgp', 'local-as'], 'system-as')
-
-# Check if vrf names are configured. Then check if local-as exists inside of a name, then add the system-as, then remove the local-as. This is for vrf configuration.
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- if config.exists(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as']):
- config.rename(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as'], 'system-as')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if BGP is even configured. Then check if local-as exists, then add the system-as, then remove the local-as. This is for global configuration.
+ if config.exists(['protocols', 'bgp']):
+ if config.exists(['protocols', 'bgp', 'local-as']):
+ config.rename(['protocols', 'bgp', 'local-as'], 'system-as')
+
+ # Check if vrf names are configured. Then check if local-as exists inside of a name, then add the system-as, then remove the local-as. This is for vrf configuration.
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ if config.exists(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as']):
+ config.rename(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as'], 'system-as')
diff --git a/src/migration-scripts/bgp/3-to-4 b/src/migration-scripts/bgp/3-to-4
index 894cdda2b..842aef0ce 100755..100644
--- a/src/migration-scripts/bgp/3-to-4
+++ b/src/migration-scripts/bgp/3-to-4
@@ -1,64 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-bgp_base = ['protocols', 'bgp']
-# Check if BGP is configured - if so, migrate the CLI node
-if config.exists(bgp_base):
- if config.exists(bgp_base + ['route-map']):
- tmp = config.return_value(bgp_base + ['route-map'])
-
- config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(bgp_base + ['route-map'])
-
-
-# Check if vrf names are configured. Check if BGP is configured - if so, migrate
-# the CLI node(s)
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
- if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map'])
-
- config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ip', 'protocol', 'bgp'])
- config.delete(vrf_base + ['protocols', 'bgp', 'route-map'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ bgp_base = ['protocols', 'bgp']
+ # Check if BGP is configured - if so, migrate the CLI node
+ if config.exists(bgp_base):
+ if config.exists(bgp_base + ['route-map']):
+ tmp = config.return_value(bgp_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(bgp_base + ['route-map'])
+
+
+ # Check if vrf names are configured. Check if BGP is configured - if so, migrate
+ # the CLI node(s)
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'bgp'])
+ config.delete(vrf_base + ['protocols', 'bgp', 'route-map'])
diff --git a/src/migration-scripts/bgp/4-to-5 b/src/migration-scripts/bgp/4-to-5
index c4eb9ec72..d779eb11e 100755..100644
--- a/src/migration-scripts/bgp/4-to-5
+++ b/src/migration-scripts/bgp/4-to-5
@@ -1,67 +1,46 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete 'protocols bgp address-family ipv6-unicast route-target vpn
# import/export', if 'protocols bgp address-family ipv6-unicast
# route-target vpn both' exists
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-bgp_base = ['protocols', 'bgp']
-# Delete 'import/export' in default vrf if 'both' exists
-if config.exists(bgp_base):
- for address_family in ['ipv4-unicast', 'ipv6-unicast']:
- rt_path = bgp_base + ['address-family', address_family, 'route-target',
- 'vpn']
- if config.exists(rt_path + ['both']):
- if config.exists(rt_path + ['import']):
- config.delete(rt_path + ['import'])
- if config.exists(rt_path + ['export']):
- config.delete(rt_path + ['export'])
-
-# Delete import/export in vrfs if both exists
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
+def migrate(config: ConfigTree) -> None:
+ bgp_base = ['protocols', 'bgp']
+ # Delete 'import/export' in default vrf if 'both' exists
+ if config.exists(bgp_base):
for address_family in ['ipv4-unicast', 'ipv6-unicast']:
- rt_path = vrf_base + bgp_base + ['address-family', address_family,
- 'route-target', 'vpn']
+ rt_path = bgp_base + ['address-family', address_family, 'route-target',
+ 'vpn']
if config.exists(rt_path + ['both']):
if config.exists(rt_path + ['import']):
config.delete(rt_path + ['import'])
if config.exists(rt_path + ['export']):
config.delete(rt_path + ['export'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # Delete import/export in vrfs if both exists
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ for address_family in ['ipv4-unicast', 'ipv6-unicast']:
+ rt_path = vrf_base + bgp_base + ['address-family', address_family,
+ 'route-target', 'vpn']
+ if config.exists(rt_path + ['both']):
+ if config.exists(rt_path + ['import']):
+ config.delete(rt_path + ['import'])
+ if config.exists(rt_path + ['export']):
+ config.delete(rt_path + ['export'])
diff --git a/src/migration-scripts/cluster/1-to-2 b/src/migration-scripts/cluster/1-to-2
index a2e589155..5ca4531ea 100755..100644
--- a/src/migration-scripts/cluster/1-to-2
+++ b/src/migration-scripts/cluster/1-to-2
@@ -1,40 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
import re
import sys
from vyos.configtree import ConfigTree
+from vyos.base import MigrationError
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
if not config.exists(['cluster']):
# Cluster is not set -- nothing to do at all
- sys.exit(0)
+ return
# If at least one cluster group is defined, we have real work to do.
# If there are no groups, we remove the top-level cluster node at the end of this script anyway.
@@ -102,8 +90,9 @@ if __name__ == '__main__':
services["other"].append(s)
if services["other"]:
- print("Cluster config includes non-IP address services and cannot be migrated", file=sys.stderr)
- sys.exit(1)
+ err_str = "Cluster config includes non-IP address services and cannot be migrated"
+ print(err_str, file=sys.stderr)
+ raise MigrationError(err_str)
# Cluster allowed virtual IPs for different interfaces within a single group.
# VRRP groups are by definition bound to interfaces, so we cannot migrate such configurations.
@@ -123,14 +112,16 @@ if __name__ == '__main__':
if global_interface is not None:
ips.append({"ip": ip, "interface": global_interface})
else:
- print("Error: cluster has groups with IPs without interfaces and 'cluster interface' is not specified.", file=sys.stderr)
- sys.exit(1)
+ err_str = "Cluster group has addresses without interfaces and 'cluster interface' is not specified."
+ print(f'Error: {err_str}', file=sys.stderr)
+ raise MigrationError(err_str)
# Then we check if all addresses are for the same interface.
intfs_set = set(map(lambda i: i["interface"], ips))
if len(intfs_set) > 1:
- print("Error: cluster group has addresses for different interfaces", file=sys.stderr)
- sys.exit(1)
+ err_str = "Cluster group has addresses for different interfaces"
+ print(f'Error: {err_str}', file=sys.stderr)
+ raise MigrationError(err_str)
# If we got this far, the group is migratable.
@@ -143,8 +134,9 @@ if __name__ == '__main__':
# If there's already a VRRP group with exactly the same name,
# we probably shouldn't try to make up a unique name, just leave migration to the user...
if config.exists(vrrp_path):
- print("Error: VRRP group with the same name as a cluster group already exists", file=sys.stderr)
- sys.exit(1)
+ err_str = "VRRP group with the same name already exists"
+ print(f'Error: {err_str}', file=sys.stderr)
+ raise MigrationError(err_str)
config.set(vrrp_path + ['interface'], value=interface)
for a in addresses:
@@ -184,10 +176,3 @@ if __name__ == '__main__':
# Finally, clean up the old cluster node
config.delete(['cluster'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/config-management/0-to-1 b/src/migration-scripts/config-management/0-to-1
index 6528fd136..44c685630 100755..100644
--- a/src/migration-scripts/config-management/0-to-1
+++ b/src/migration-scripts/config-management/0-to-1
@@ -1,31 +1,24 @@
-#!/usr/bin/env python3
+# Copyright 2018-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/>.
# Add commit-revisions option if it doesn't exist
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if config.exists(['system', 'config-management', 'commit-revisions']):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if config.exists(['system', 'config-management', 'commit-revisions']):
+ # Nothing to do
+ return
config.set(['system', 'config-management', 'commit-revisions'], value='200')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/conntrack-sync/1-to-2 b/src/migration-scripts/conntrack-sync/1-to-2
index a8e1007f3..3e10e98c3 100755..100644
--- a/src/migration-scripts/conntrack-sync/1-to-2
+++ b/src/migration-scripts/conntrack-sync/1-to-2
@@ -1,44 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# VyOS 1.2 crux allowed configuring a lower or upper case loglevel. This
# is no longer supported as the input data is validated and will lead to
# an error. If user specifies an upper case logleve, make it lowercase
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'conntrack-sync']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
base_accept_proto = base + ['accept-protocol']
if config.exists(base_accept_proto):
tmp = config.return_value(base_accept_proto)
@@ -57,10 +44,3 @@ else:
base_cluster = base + ['failover-mechanism', 'cluster']
if config.exists(base_cluster):
config.delete(base_cluster)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/conntrack/1-to-2 b/src/migration-scripts/conntrack/1-to-2
index c4fe667fc..0a4fb3de9 100755..100644
--- a/src/migration-scripts/conntrack/1-to-2
+++ b/src/migration-scripts/conntrack/1-to-2
@@ -1,32 +1,26 @@
-#!/usr/bin/env python3
+# 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/>.
# Delete "set system conntrack modules gre" option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'conntrack', 'modules', 'gre']):
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'conntrack', 'modules', 'gre']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete abandoned node
config.delete(['system', 'conntrack', 'modules', 'gre'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/conntrack/2-to-3 b/src/migration-scripts/conntrack/2-to-3
index 6bb42be1e..5ad4e6350 100755..100644
--- a/src/migration-scripts/conntrack/2-to-3
+++ b/src/migration-scripts/conntrack/2-to-3
@@ -1,36 +1,31 @@
-#!/usr/bin/env python3
+# 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/>.
# Conntrack syntax version 3
# Enables all conntrack modules (previous default behaviour) and omits manually disabled modules.
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print('Must specify file name!')
- sys.exit(1)
-
-filename = sys.argv[1]
-
-with open(filename, 'r') as f:
- config = ConfigTree(f.read())
-
module_path = ['system', 'conntrack', 'modules']
-# Go over all conntrack modules available as of v1.3.0.
-for module in ['ftp', 'h323', 'nfs', 'pptp', 'sip', 'sqlnet', 'tftp']:
- # 'disable' is being phased out.
- if config.exists(module_path + [module, 'disable']):
- config.delete(module_path + [module])
- # If it wasn't manually 'disable'd, it was enabled by default.
- else:
- config.set(module_path + [module])
-
-try:
- if config.exists(module_path):
- with open(filename, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Go over all conntrack modules available as of v1.3.0.
+ for module in ['ftp', 'h323', 'nfs', 'pptp', 'sip', 'sqlnet', 'tftp']:
+ # 'disable' is being phased out.
+ if config.exists(module_path + [module, 'disable']):
+ config.delete(module_path + [module])
+ # If it wasn't manually 'disable'd, it was enabled by default.
+ else:
+ config.set(module_path + [module])
diff --git a/src/migration-scripts/conntrack/3-to-4 b/src/migration-scripts/conntrack/3-to-4
index e90c383af..679a260d5 100755..100644
--- a/src/migration-scripts/conntrack/3-to-4
+++ b/src/migration-scripts/conntrack/3-to-4
@@ -1,50 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Add support for IPv6 conntrack ignore, move existing nodes to `system conntrack ignore ipv4`
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'conntrack']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-if config.exists(base + ['ignore', 'rule']):
- config.set(base + ['ignore', 'ipv4'])
- config.copy(base + ['ignore', 'rule'], base + ['ignore', 'ipv4', 'rule'])
- config.delete(base + ['ignore', 'rule'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base + ['ignore', 'rule']):
+ config.set(base + ['ignore', 'ipv4'])
+ config.copy(base + ['ignore', 'rule'], base + ['ignore', 'ipv4', 'rule'])
+ config.delete(base + ['ignore', 'rule'])
diff --git a/src/migration-scripts/conntrack/4-to-5 b/src/migration-scripts/conntrack/4-to-5
index d2e5fc5fa..775fe7480 100755..100644
--- a/src/migration-scripts/conntrack/4-to-5
+++ b/src/migration-scripts/conntrack/4-to-5
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5779: system conntrack timeout custom
# Before:
@@ -23,37 +22,18 @@
# Extend functionality to ipv6 and move ipv4 custom rules to new node:
# set system conntrack timeout custom [ipv4 | ipv6] rule <rule> ...
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'conntrack']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['timeout', 'custom', 'rule']):
- for rule in config.list_nodes(base + ['timeout', 'custom', 'rule']):
- if config.exists(base + ['timeout', 'custom', 'rule', rule, 'protocol', 'tcp']):
- config.set(base + ['timeout', 'custom', 'ipv4', 'rule'])
- config.copy(base + ['timeout', 'custom', 'rule', rule], base + ['timeout', 'custom', 'ipv4', 'rule', rule])
- config.delete(base + ['timeout', 'custom', 'rule'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['timeout', 'custom', 'rule']):
+ for rule in config.list_nodes(base + ['timeout', 'custom', 'rule']):
+ if config.exists(base + ['timeout', 'custom', 'rule', rule, 'protocol', 'tcp']):
+ config.set(base + ['timeout', 'custom', 'ipv4', 'rule'])
+ config.copy(base + ['timeout', 'custom', 'rule', rule], base + ['timeout', 'custom', 'ipv4', 'rule', rule])
+ config.delete(base + ['timeout', 'custom', 'rule'])
diff --git a/src/migration-scripts/container/0-to-1 b/src/migration-scripts/container/0-to-1
index 6b282e082..99102a5e6 100755..100644
--- a/src/migration-scripts/container/0-to-1
+++ b/src/migration-scripts/container/0-to-1
@@ -1,77 +1,65 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4870: change underlaying container filesystem from vfs to overlay
import os
import shutil
-import sys
from vyos.configtree import ConfigTree
from vyos.utils.process import call
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['container', 'name']
-config = ConfigTree(config_file)
-
-# Check if containers exist and we need to perform image manipulation
-if config.exists(base):
- for container in config.list_nodes(base):
- # Stop any given container first
- call(f'sudo systemctl stop vyos-container-{container}.service')
- # Export container image for later re-import to new filesystem. We store
- # the backup on a real disk as a tmpfs (like /tmp) could probably lack
- # memory if a host has too many containers stored.
- image_name = config.return_value(base + [container, 'image'])
- call(f'sudo podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}')
-# No need to adjust the strage driver online (this is only used for testing and
-# debugging on a live system) - it is already overlay2 when the migration script
-# is run during system update. But the specified driver in the image is actually
-# overwritten by the still present VFS filesystem on disk. Thus podman still
-# thinks it uses VFS until we delete the libpod directory under:
-# /usr/lib/live/mount/persistence/container/storage
-#call('sed -i "s/vfs/overlay2/g" /etc/containers/storage.conf /usr/share/vyos/templates/container/storage.conf.j2')
+def migrate(config: ConfigTree) -> None:
+ # Check if containers exist and we need to perform image manipulation
+ if config.exists(base):
+ for container in config.list_nodes(base):
+ # Stop any given container first
+ call(f'sudo systemctl stop vyos-container-{container}.service')
+ # Export container image for later re-import to new filesystem. We store
+ # the backup on a real disk as a tmpfs (like /tmp) could probably lack
+ # memory if a host has too many containers stored.
+ image_name = config.return_value(base + [container, 'image'])
+ call(f'sudo podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}')
-base_path = '/usr/lib/live/mount/persistence/container/storage'
-for dir in ['libpod', 'vfs', 'vfs-containers', 'vfs-images', 'vfs-layers']:
- if os.path.exists(f'{base_path}/{dir}'):
- shutil.rmtree(f'{base_path}/{dir}')
+ # No need to adjust the strage driver online (this is only used for testing and
+ # debugging on a live system) - it is already overlay2 when the migration script
+ # is run during system update. But the specified driver in the image is actually
+ # overwritten by the still present VFS filesystem on disk. Thus podman still
+ # thinks it uses VFS until we delete the libpod directory under:
+ # /usr/lib/live/mount/persistence/container/storage
+ #call('sed -i "s/vfs/overlay2/g" /etc/containers/storage.conf /usr/share/vyos/templates/container/storage.conf.j2')
-# Now all remaining information about VFS is gone and we operate in overlayfs2
-# filesystem mode. Time to re-import the images.
-if config.exists(base):
- for container in config.list_nodes(base):
- # Export container image for later re-import to new filesystem
- image_name = config.return_value(base + [container, 'image'])
- image_path = f'/root/{container}.tar'
- call(f'sudo podman image load --quiet --input {image_path}')
+ base_path = '/usr/lib/live/mount/persistence/container/storage'
+ for dir in ['libpod', 'vfs', 'vfs-containers', 'vfs-images', 'vfs-layers']:
+ if os.path.exists(f'{base_path}/{dir}'):
+ shutil.rmtree(f'{base_path}/{dir}')
- # Start any given container first
- call(f'sudo systemctl start vyos-container-{container}.service')
+ # Now all remaining information about VFS is gone and we operate in overlayfs2
+ # filesystem mode. Time to re-import the images.
+ if config.exists(base):
+ for container in config.list_nodes(base):
+ # Export container image for later re-import to new filesystem
+ image_name = config.return_value(base + [container, 'image'])
+ image_path = f'/root/{container}.tar'
+ call(f'sudo podman image load --quiet --input {image_path}')
- # Delete temporary container image
- if os.path.exists(image_path):
- os.unlink(image_path)
+ # Start any given container first
+ call(f'sudo systemctl start vyos-container-{container}.service')
+ # Delete temporary container image
+ if os.path.exists(image_path):
+ os.unlink(image_path)
diff --git a/src/migration-scripts/container/1-to-2 b/src/migration-scripts/container/1-to-2
index 408faf978..c12dd8ebb 100755..100644
--- a/src/migration-scripts/container/1-to-2
+++ b/src/migration-scripts/container/1-to-2
@@ -1,50 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6208: container: rename "cap-add" CLI node to "capability"
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['container', 'name']
-config = ConfigTree(config_file)
-# Check if containers exist and we need to perform image manipulation
-if not config.exists(base):
- # Nothing to do
- exit(0)
+def migrate(config: ConfigTree) -> None:
-for container in config.list_nodes(base):
- cap_path = base + [container, 'cap-add']
- if config.exists(cap_path):
- config.rename(cap_path, 'capability')
+ # Check if containers exist and we need to perform image manipulation
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ for container in config.list_nodes(base):
+ cap_path = base + [container, 'cap-add']
+ if config.exists(cap_path):
+ config.rename(cap_path, 'capability')
diff --git a/src/migration-scripts/dhcp-relay/1-to-2 b/src/migration-scripts/dhcp-relay/1-to-2
index 508bac6be..54cd8d6c0 100755..100644
--- a/src/migration-scripts/dhcp-relay/1-to-2
+++ b/src/migration-scripts/dhcp-relay/1-to-2
@@ -1,35 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2018-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/>.
# Delete "set service dhcp-relay relay-options port" option
# Delete "set service dhcpv6-relay listen-port" option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not (config.exists(['service', 'dhcp-relay', 'relay-options', 'port']) or config.exists(['service', 'dhcpv6-relay', 'listen-port'])):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not (config.exists(['service', 'dhcp-relay', 'relay-options', 'port']) or config.exists(['service', 'dhcpv6-relay', 'listen-port'])):
- # Nothing to do
- sys.exit(0)
-else:
# Delete abandoned node
config.delete(['service', 'dhcp-relay', 'relay-options', 'port'])
# Delete abandoned node
config.delete(['service', 'dhcpv6-relay', 'listen-port'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/dhcp-server/10-to-11 b/src/migration-scripts/dhcp-server/10-to-11
index a0dc96ad0..f54a4c7b7 100755..100644
--- a/src/migration-scripts/dhcp-server/10-to-11
+++ b/src/migration-scripts/dhcp-server/10-to-11
@@ -1,48 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6171: rename "service dhcp-server failover" to "service dhcp-server high-availability"
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-if config.exists(base + ['failover']):
- config.rename(base + ['failover'],'high-availability')
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1) \ No newline at end of file
+ if config.exists(base + ['failover']):
+ config.rename(base + ['failover'],'high-availability')
diff --git a/src/migration-scripts/dhcp-server/4-to-5 b/src/migration-scripts/dhcp-server/4-to-5
index d15e0baf5..a655515dc 100755..100644
--- a/src/migration-scripts/dhcp-server/4-to-5
+++ b/src/migration-scripts/dhcp-server/4-to-5
@@ -1,122 +1,118 @@
#!/usr/bin/env python3
+# Copyright 2018-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/>.
+
# Removes boolean operator from:
# - "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable (true|false)"
# - "set service dhcp-server shared-network-name <xyz> authoritative (true|false)"
# - "set service dhcp-server disabled (true|false)"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['service', 'dhcp-server']):
- # Nothing to do
- sys.exit(0)
-else:
- base = ['service', 'dhcp-server']
- # Make node "set service dhcp-server dynamic-dns-update enable (true|false)" valueless
- if config.exists(base + ['dynamic-dns-update']):
- bool_val = config.return_value(base + ['dynamic-dns-update', 'enable'])
-
- # Delete the node with the old syntax
- config.delete(base + ['dynamic-dns-update'])
- if str(bool_val) == 'true':
- # Enable dynamic-dns-update with new syntax
- config.set(base + ['dynamic-dns-update'], value=None)
-
- # Make node "set service dhcp-server disabled (true|false)" valueless
- if config.exists(base + ['disabled']):
- bool_val = config.return_value(base + ['disabled'])
-
- # Delete the node with the old syntax
- config.delete(base + ['disabled'])
- if str(bool_val) == 'true':
- # Now disable DHCP server with the new syntax
- config.set(base + ['disable'], value=None)
-
- # Make node "set service dhcp-server hostfile-update (enable|disable) valueless
- if config.exists(base + ['hostfile-update']):
- bool_val = config.return_value(base + ['hostfile-update'])
-
- # Delete the node with the old syntax incl. all subnodes
- config.delete(base + ['hostfile-update'])
- if str(bool_val) == 'enable':
- # Enable hostfile update with new syntax
- config.set(base + ['hostfile-update'], value=None)
-
- # Run this for every instance if 'shared-network-name'
- for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
- # format as tag node to avoid loading problems
- config.set_tag(base + ['shared-network-name'])
-
- # Run this for every specified 'subnet'
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['service', 'dhcp-server']):
+ # Nothing to do
+ return
+ else:
+ base = ['service', 'dhcp-server']
+ # Make node "set service dhcp-server dynamic-dns-update enable (true|false)" valueless
+ if config.exists(base + ['dynamic-dns-update']):
+ bool_val = config.return_value(base + ['dynamic-dns-update', 'enable'])
+
+ # Delete the node with the old syntax
+ config.delete(base + ['dynamic-dns-update'])
+ if str(bool_val) == 'true':
+ # Enable dynamic-dns-update with new syntax
+ config.set(base + ['dynamic-dns-update'], value=None)
+
+ # Make node "set service dhcp-server disabled (true|false)" valueless
+ if config.exists(base + ['disabled']):
+ bool_val = config.return_value(base + ['disabled'])
+
+ # Delete the node with the old syntax
+ config.delete(base + ['disabled'])
+ if str(bool_val) == 'true':
+ # Now disable DHCP server with the new syntax
+ config.set(base + ['disable'], value=None)
+
+ # Make node "set service dhcp-server hostfile-update (enable|disable) valueless
+ if config.exists(base + ['hostfile-update']):
+ bool_val = config.return_value(base + ['hostfile-update'])
+
+ # Delete the node with the old syntax incl. all subnodes
+ config.delete(base + ['hostfile-update'])
+ if str(bool_val) == 'enable':
+ # Enable hostfile update with new syntax
+ config.set(base + ['hostfile-update'], value=None)
+
+ # Run this for every instance if 'shared-network-name'
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
# format as tag node to avoid loading problems
- config.set_tag(base_network + ['subnet'])
+ config.set_tag(base + ['shared-network-name'])
- # Make node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable" valueless
- if config.exists(base_subnet + ['ip-forwarding', 'enable']):
- bool_val = config.return_value(base_subnet + ['ip-forwarding', 'enable'])
- # Delete the node with the old syntax
- config.delete(base_subnet + ['ip-forwarding'])
- if str(bool_val) == 'true':
- # Recreate node with new syntax
- config.set(base_subnet + ['ip-forwarding'], value=None)
-
- # Rename node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 start <172.16.0.4> stop <172.16.0.9>
- if config.exists(base_subnet + ['start']):
- # This is the new "range" id for DHCP lease ranges
- r_id = 0
- for range in config.list_nodes(base_subnet + ['start']):
- range_start = range
- range_stop = config.return_value(base_subnet + ['start', range_start, 'stop'])
+ # Run this for every specified 'subnet'
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
+ # format as tag node to avoid loading problems
+ config.set_tag(base_network + ['subnet'])
+ # Make node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable" valueless
+ if config.exists(base_subnet + ['ip-forwarding', 'enable']):
+ bool_val = config.return_value(base_subnet + ['ip-forwarding', 'enable'])
# Delete the node with the old syntax
- config.delete(base_subnet + ['start', range_start])
+ config.delete(base_subnet + ['ip-forwarding'])
+ if str(bool_val) == 'true':
+ # Recreate node with new syntax
+ config.set(base_subnet + ['ip-forwarding'], value=None)
+
+ # Rename node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 start <172.16.0.4> stop <172.16.0.9>
+ if config.exists(base_subnet + ['start']):
+ # This is the new "range" id for DHCP lease ranges
+ r_id = 0
+ for range in config.list_nodes(base_subnet + ['start']):
+ range_start = range
+ range_stop = config.return_value(base_subnet + ['start', range_start, 'stop'])
+
+ # Delete the node with the old syntax
+ config.delete(base_subnet + ['start', range_start])
+
+ # Create the node for the new syntax
+ # Note: range is a tag node, counter is its child, not a value
+ config.set(base_subnet + ['range', r_id])
+ config.set(base_subnet + ['range', r_id, 'start'], value=range_start)
+ config.set(base_subnet + ['range', r_id, 'stop'], value=range_stop)
+
+ # format as tag node to avoid loading problems
+ config.set_tag(base_subnet + ['range'])
+
+ # increment range id for possible next range definition
+ r_id += 1
- # Create the node for the new syntax
- # Note: range is a tag node, counter is its child, not a value
- config.set(base_subnet + ['range', r_id])
- config.set(base_subnet + ['range', r_id, 'start'], value=range_start)
- config.set(base_subnet + ['range', r_id, 'stop'], value=range_stop)
+ # Delete the node with the old syntax
+ config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'subnet', subnet, 'start'])
- # format as tag node to avoid loading problems
- config.set_tag(base_subnet + ['range'])
- # increment range id for possible next range definition
- r_id += 1
+ # Make node "set service dhcp-server shared-network-name <xyz> authoritative" valueless
+ if config.exists(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']):
+ authoritative = config.return_value(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
# Delete the node with the old syntax
- config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'subnet', subnet, 'start'])
+ config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- # Make node "set service dhcp-server shared-network-name <xyz> authoritative" valueless
- if config.exists(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']):
- authoritative = config.return_value(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- # Delete the node with the old syntax
- config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- # Recreate node with new syntax - if required
- if authoritative == "enable":
- config.set(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ # Recreate node with new syntax - if required
+ if authoritative == "enable":
+ config.set(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative'])
diff --git a/src/migration-scripts/dhcp-server/5-to-6 b/src/migration-scripts/dhcp-server/5-to-6
index f5c766a09..9404cd038 100755..100644
--- a/src/migration-scripts/dhcp-server/5-to-6
+++ b/src/migration-scripts/dhcp-server/5-to-6
@@ -1,87 +1,69 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T1968: allow multiple static-routes to be configured
# T3838: rename dns-server -> name-server
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base + ['shared-network-name']):
- # Nothing to do
- exit(0)
-
-# Run this for every instance if 'shared-network-name'
-for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
-
- if not config.exists(base_network + ['subnet']):
- continue
-
- # Run this for every specified 'subnet'
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
-
- # T1968: allow multiple static-routes to be configured
- if config.exists(base_subnet + ['static-route']):
- prefix = config.return_value(base_subnet + ['static-route', 'destination-subnet'])
- router = config.return_value(base_subnet + ['static-route', 'router'])
- config.delete(base_subnet + ['static-route'])
-
- config.set(base_subnet + ['static-route', prefix, 'next-hop'], value=router)
- config.set_tag(base_subnet + ['static-route'])
-
- # T3838: rename dns-server -> name-server
- if config.exists(base_subnet + ['dns-server']):
- config.rename(base_subnet + ['dns-server'], 'name-server')
-
-
- # T3672: ISC DHCP server only supports one failover peer
- if config.exists(base_subnet + ['failover']):
- # There can only be one failover configuration, if none is present
- # we add the first one
- if not config.exists(base + ['failover']):
- local = config.return_value(base_subnet + ['failover', 'local-address'])
- remote = config.return_value(base_subnet + ['failover', 'peer-address'])
- status = config.return_value(base_subnet + ['failover', 'status'])
- name = config.return_value(base_subnet + ['failover', 'name'])
-
- config.set(base + ['failover', 'remote'], value=remote)
- config.set(base + ['failover', 'source-address'], value=local)
- config.set(base + ['failover', 'status'], value=status)
- config.set(base + ['failover', 'name'], value=name)
-
- config.delete(base_subnet + ['failover'])
- config.set(base_subnet + ['enable-failover'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['shared-network-name']):
+ # Nothing to do
+ return
+
+ # Run this for every instance if 'shared-network-name'
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
+
+ if not config.exists(base_network + ['subnet']):
+ continue
+
+ # Run this for every specified 'subnet'
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
+
+ # T1968: allow multiple static-routes to be configured
+ if config.exists(base_subnet + ['static-route']):
+ prefix = config.return_value(base_subnet + ['static-route', 'destination-subnet'])
+ router = config.return_value(base_subnet + ['static-route', 'router'])
+ config.delete(base_subnet + ['static-route'])
+
+ config.set(base_subnet + ['static-route', prefix, 'next-hop'], value=router)
+ config.set_tag(base_subnet + ['static-route'])
+
+ # T3838: rename dns-server -> name-server
+ if config.exists(base_subnet + ['dns-server']):
+ config.rename(base_subnet + ['dns-server'], 'name-server')
+
+
+ # T3672: ISC DHCP server only supports one failover peer
+ if config.exists(base_subnet + ['failover']):
+ # There can only be one failover configuration, if none is present
+ # we add the first one
+ if not config.exists(base + ['failover']):
+ local = config.return_value(base_subnet + ['failover', 'local-address'])
+ remote = config.return_value(base_subnet + ['failover', 'peer-address'])
+ status = config.return_value(base_subnet + ['failover', 'status'])
+ name = config.return_value(base_subnet + ['failover', 'name'])
+
+ config.set(base + ['failover', 'remote'], value=remote)
+ config.set(base + ['failover', 'source-address'], value=local)
+ config.set(base + ['failover', 'status'], value=status)
+ config.set(base + ['failover', 'name'], value=name)
+
+ config.delete(base_subnet + ['failover'])
+ config.set(base_subnet + ['enable-failover'])
diff --git a/src/migration-scripts/dhcp-server/6-to-7 b/src/migration-scripts/dhcp-server/6-to-7
index e6c298a60..4e6583a31 100755..100644
--- a/src/migration-scripts/dhcp-server/6-to-7
+++ b/src/migration-scripts/dhcp-server/6-to-7
@@ -1,76 +1,58 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6079: Disable duplicate static mappings
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base + ['shared-network-name']):
- # Nothing to do
- exit(0)
-# Run this for every instance if 'shared-network-name'
-for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['shared-network-name']):
+ # Nothing to do
+ return
- if not config.exists(base_network + ['subnet']):
- continue
+ # Run this for every instance if 'shared-network-name'
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
+ if not config.exists(base_network + ['subnet']):
+ continue
- if config.exists(base_subnet + ['static-mapping']):
- used_mac = []
- used_ip = []
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
- for mapping in config.list_nodes(base_subnet + ['static-mapping']):
- base_mapping = base_subnet + ['static-mapping', mapping]
+ if config.exists(base_subnet + ['static-mapping']):
+ used_mac = []
+ used_ip = []
- if config.exists(base_mapping + ['mac-address']):
- mac = config.return_value(base_mapping + ['mac-address'])
+ for mapping in config.list_nodes(base_subnet + ['static-mapping']):
+ base_mapping = base_subnet + ['static-mapping', mapping]
- if mac in used_mac:
- config.set(base_mapping + ['disable'])
- else:
- used_mac.append(mac)
+ if config.exists(base_mapping + ['mac-address']):
+ mac = config.return_value(base_mapping + ['mac-address'])
- if config.exists(base_mapping + ['ip-address']):
- ip = config.return_value(base_mapping + ['ip-address'])
+ if mac in used_mac:
+ config.set(base_mapping + ['disable'])
+ else:
+ used_mac.append(mac)
- if ip in used_ip:
- config.set(base_subnet + ['static-mapping', mapping, 'disable'])
- else:
- used_ip.append(ip)
+ if config.exists(base_mapping + ['ip-address']):
+ ip = config.return_value(base_mapping + ['ip-address'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if ip in used_ip:
+ config.set(base_subnet + ['static-mapping', mapping, 'disable'])
+ else:
+ used_ip.append(ip)
diff --git a/src/migration-scripts/dhcp-server/7-to-8 b/src/migration-scripts/dhcp-server/7-to-8
index ccf385a30..7fcb62e86 100755..100644
--- a/src/migration-scripts/dhcp-server/7-to-8
+++ b/src/migration-scripts/dhcp-server/7-to-8
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316: Migrate to Kea
# - global-parameters will not function
@@ -23,65 +22,48 @@
# - ping-check no longer supported
# - failover is default enabled on all subnets that exist on failover servers
-import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-if config.exists(base + ['host-decl-name']):
- config.delete(base + ['host-decl-name'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['global-parameters']):
- config.delete(base + ['global-parameters'])
+ if config.exists(base + ['host-decl-name']):
+ config.delete(base + ['host-decl-name'])
-if config.exists(base + ['shared-network-name']):
- for network in config.list_nodes(base + ['shared-network-name']):
- base_network = base + ['shared-network-name', network]
+ if config.exists(base + ['global-parameters']):
+ config.delete(base + ['global-parameters'])
- if config.exists(base_network + ['ping-check']):
- config.delete(base_network + ['ping-check'])
+ if config.exists(base + ['shared-network-name']):
+ for network in config.list_nodes(base + ['shared-network-name']):
+ base_network = base + ['shared-network-name', network]
- if config.exists(base_network + ['shared-network-parameters']):
- config.delete(base_network +['shared-network-parameters'])
+ if config.exists(base_network + ['ping-check']):
+ config.delete(base_network + ['ping-check'])
- if not config.exists(base_network + ['subnet']):
- continue
+ if config.exists(base_network + ['shared-network-parameters']):
+ config.delete(base_network +['shared-network-parameters'])
- # Run this for every specified 'subnet'
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
+ if not config.exists(base_network + ['subnet']):
+ continue
- if config.exists(base_subnet + ['enable-failover']):
- config.delete(base_subnet + ['enable-failover'])
+ # Run this for every specified 'subnet'
+ for subnet in config.list_nodes(base_network + ['subnet']):
+ base_subnet = base_network + ['subnet', subnet]
- if config.exists(base_subnet + ['ping-check']):
- config.delete(base_subnet + ['ping-check'])
+ if config.exists(base_subnet + ['enable-failover']):
+ config.delete(base_subnet + ['enable-failover'])
- if config.exists(base_subnet + ['subnet-parameters']):
- config.delete(base_subnet + ['subnet-parameters'])
+ if config.exists(base_subnet + ['ping-check']):
+ config.delete(base_subnet + ['ping-check'])
- if config.exists(base_subnet + ['static-mapping']):
- for mapping in config.list_nodes(base_subnet + ['static-mapping']):
- if config.exists(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']):
- config.delete(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters'])
+ if config.exists(base_subnet + ['subnet-parameters']):
+ config.delete(base_subnet + ['subnet-parameters'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base_subnet + ['static-mapping']):
+ for mapping in config.list_nodes(base_subnet + ['static-mapping']):
+ if config.exists(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']):
+ config.delete(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters'])
diff --git a/src/migration-scripts/dhcp-server/8-to-9 b/src/migration-scripts/dhcp-server/8-to-9
index 151aa6d7b..5843e9fda 100755..100644
--- a/src/migration-scripts/dhcp-server/8-to-9
+++ b/src/migration-scripts/dhcp-server/8-to-9
@@ -1,65 +1,47 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Adjust hostname to have valid FQDN characters only (underscores aren't allowed anymore)
# - Rename "service dhcp-server shared-network-name ... static-mapping <hostname> mac-address ..."
# to "service dhcp-server shared-network-name ... static-mapping <hostname> mac ..."
-import sys
import re
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-for network in config.list_nodes(base):
- # Run this for every specified 'subnet'
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
- if config.exists(base_subnet + ['static-mapping']):
- for hostname in config.list_nodes(base_subnet + ['static-mapping']):
- base_mapping = base_subnet + ['static-mapping', hostname]
-
- # Rename the 'mac-address' node to 'mac'
- if config.exists(base_mapping + ['mac-address']):
- config.rename(base_mapping + ['mac-address'], 'mac')
-
- # Adjust hostname to have valid FQDN characters only
- new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
- if new_hostname != hostname:
- config.rename(base_mapping, new_hostname)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for network in config.list_nodes(base):
+ # Run this for every specified 'subnet'
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
+ if config.exists(base_subnet + ['static-mapping']):
+ for hostname in config.list_nodes(base_subnet + ['static-mapping']):
+ base_mapping = base_subnet + ['static-mapping', hostname]
+
+ # Rename the 'mac-address' node to 'mac'
+ if config.exists(base_mapping + ['mac-address']):
+ config.rename(base_mapping + ['mac-address'], 'mac')
+
+ # Adjust hostname to have valid FQDN characters only
+ new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
+ if new_hostname != hostname:
+ config.rename(base_mapping, new_hostname)
diff --git a/src/migration-scripts/dhcp-server/9-to-10 b/src/migration-scripts/dhcp-server/9-to-10
index a459b65b5..eda97550d 100755..100644
--- a/src/migration-scripts/dhcp-server/9-to-10
+++ b/src/migration-scripts/dhcp-server/9-to-10
@@ -1,41 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Migrate dhcp options under new option node
# - Add subnet IDs to existing subnets
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcp-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-portal',
'client-prefix-length', 'default-router', 'domain-name', 'domain-search',
@@ -44,31 +28,30 @@ option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-po
'tftp-server-name', 'time-offset', 'time-server', 'time-zone',
'vendor-option', 'wins-server', 'wpad-url']
-subnet_id = 1
-for network in config.list_nodes(base):
- for option in option_nodes:
- if config.exists(base + [network, option]):
- config.set(base + [network, 'option'])
- config.copy(base + [network, option], base + [network, 'option', option])
- config.delete(base + [network, option])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ subnet_id = 1
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
+ for network in config.list_nodes(base):
+ for option in option_nodes:
+ if config.exists(base + [network, option]):
+ config.set(base + [network, 'option'])
+ config.copy(base + [network, option], base + [network, 'option', option])
+ config.delete(base + [network, option])
- for option in option_nodes:
- if config.exists(base_subnet + [option]):
- config.set(base_subnet + ['option'])
- config.copy(base_subnet + [option], base_subnet + ['option', option])
- config.delete(base_subnet + [option])
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
- config.set(base_subnet + ['subnet-id'], value=subnet_id)
- subnet_id += 1
+ for option in option_nodes:
+ if config.exists(base_subnet + [option]):
+ config.set(base_subnet + ['option'])
+ config.copy(base_subnet + [option], base_subnet + ['option', option])
+ config.delete(base_subnet + [option])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.set(base_subnet + ['subnet-id'], value=subnet_id)
+ subnet_id += 1
diff --git a/src/migration-scripts/dhcpv6-server/0-to-1 b/src/migration-scripts/dhcpv6-server/0-to-1
index deae1ca29..fd9b2d739 100755..100644
--- a/src/migration-scripts/dhcpv6-server/0-to-1
+++ b/src/migration-scripts/dhcpv6-server/0-to-1
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# combine both sip-server-address and sip-server-name nodes to common sip-server
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['service', 'dhcpv6-server', 'shared-network-name']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['service', 'dhcpv6-server', 'shared-network-name']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
# we need to run this for every configured network
for network in config.list_nodes(base):
for subnet in config.list_nodes(base + [network, 'subnet']):
@@ -52,10 +42,3 @@ else:
# Write new CLI value for sip-server
for server in sip_server:
config.set(base + [network, 'subnet', subnet, 'sip-server'], value=server, replace=False)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/dhcpv6-server/1-to-2 b/src/migration-scripts/dhcpv6-server/1-to-2
index cc5a8900a..ad307495c 100755..100644
--- a/src/migration-scripts/dhcpv6-server/1-to-2
+++ b/src/migration-scripts/dhcpv6-server/1-to-2
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316: Migrate to Kea
# - Kea was meant to have support for key "prefix-highest" under PD which would allow an address range
@@ -20,67 +19,50 @@
# Ref: https://lists.isc.org/pipermail/kea-users/2022-November/003686.html
# - Remove prefix temporary value, convert to multi leafNode (https://kea.readthedocs.io/en/kea-2.2.0/arm/dhcp6-srv.html#dhcpv6-server-limitations)
-import sys
from vyos.configtree import ConfigTree
from vyos.utils.network import ipv6_prefix_length
-if (len(sys.argv) < 1):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for network in config.list_nodes(base):
- if not config.exists(base + [network, 'subnet']):
- continue
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- for subnet in config.list_nodes(base + [network, 'subnet']):
- # Delete temporary value under address-range prefix, convert tagNode to leafNode multi
- if config.exists(base + [network, 'subnet', subnet, 'address-range', 'prefix']):
- prefix_base = base + [network, 'subnet', subnet, 'address-range', 'prefix']
- prefixes = config.list_nodes(prefix_base)
-
- config.delete(prefix_base)
+ for network in config.list_nodes(base):
+ if not config.exists(base + [network, 'subnet']):
+ continue
- for prefix in prefixes:
- config.set(prefix_base, value=prefix, replace=False)
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ # Delete temporary value under address-range prefix, convert tagNode to leafNode multi
+ if config.exists(base + [network, 'subnet', subnet, 'address-range', 'prefix']):
+ prefix_base = base + [network, 'subnet', subnet, 'address-range', 'prefix']
+ prefixes = config.list_nodes(prefix_base)
+
+ config.delete(prefix_base)
- if config.exists(base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']):
- prefix_base = base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']
+ for prefix in prefixes:
+ config.set(prefix_base, value=prefix, replace=False)
- config.set(prefix_base)
- config.set_tag(prefix_base)
+ if config.exists(base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']):
+ prefix_base = base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']
- for start in config.list_nodes(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']):
- path = base + [network, 'subnet', subnet, 'prefix-delegation', 'start', start]
+ config.set(prefix_base)
+ config.set_tag(prefix_base)
- delegated_length = config.return_value(path + ['prefix-length'])
- stop = config.return_value(path + ['stop'])
+ for start in config.list_nodes(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']):
+ path = base + [network, 'subnet', subnet, 'prefix-delegation', 'start', start]
- prefix_length = ipv6_prefix_length(start, stop)
+ delegated_length = config.return_value(path + ['prefix-length'])
+ stop = config.return_value(path + ['stop'])
- # This range could not be converted into a simple prefix length and must be skipped
- if not prefix_length:
- continue
+ prefix_length = ipv6_prefix_length(start, stop)
- config.set(prefix_base + [start, 'delegated-length'], value=delegated_length)
- config.set(prefix_base + [start, 'prefix-length'], value=prefix_length)
+ # This range could not be converted into a simple prefix length and must be skipped
+ if not prefix_length:
+ continue
- config.delete(base + [network, 'subnet', subnet, 'prefix-delegation', 'start'])
+ config.set(prefix_base + [start, 'delegated-length'], value=delegated_length)
+ config.set(prefix_base + [start, 'prefix-length'], value=prefix_length)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(base + [network, 'subnet', subnet, 'prefix-delegation', 'start'])
diff --git a/src/migration-scripts/dhcpv6-server/2-to-3 b/src/migration-scripts/dhcpv6-server/2-to-3
index f4bdc1d1e..b44798d18 100755..100644
--- a/src/migration-scripts/dhcpv6-server/2-to-3
+++ b/src/migration-scripts/dhcpv6-server/2-to-3
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Adjust hostname to have valid FQDN characters only (underscores aren't allowed anymore)
@@ -22,57 +21,40 @@
# - Rename "service dhcpv6-server shared-network-name ... static-mapping <hostname> mac-address ..."
# to "service dhcpv6-server shared-network-name ... static-mapping <hostname> mac ..."
-import sys
import re
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-for network in config.list_nodes(base):
- # Run this for every specified 'subnet'
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
- if config.exists(base_subnet + ['static-mapping']):
- for hostname in config.list_nodes(base_subnet + ['static-mapping']):
- base_mapping = base_subnet + ['static-mapping', hostname]
- if config.exists(base_mapping + ['identifier']):
-
- # Adjust duid to comply with duid format (a:3:b:04:... => 0a:03:0b:04:...)
- duid = config.return_value(base_mapping + ['identifier'])
- new_duid = ':'.join(x.rjust(2,'0') for x in duid.split(':'))
- if new_duid != duid:
- config.set(base_mapping + ['identifier'], new_duid)
-
- # Rename the 'identifier' node to 'duid'
- config.rename(base_mapping + ['identifier'], 'duid')
-
- # Rename the 'mac-address' node to 'mac'
- if config.exists(base_mapping + ['mac-address']):
- config.rename(base_mapping + ['mac-address'], 'mac')
-
- # Adjust hostname to have valid FQDN characters only
- new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
- if new_hostname != hostname:
- config.rename(base_mapping, new_hostname)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for network in config.list_nodes(base):
+ # Run this for every specified 'subnet'
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
+ if config.exists(base_subnet + ['static-mapping']):
+ for hostname in config.list_nodes(base_subnet + ['static-mapping']):
+ base_mapping = base_subnet + ['static-mapping', hostname]
+ if config.exists(base_mapping + ['identifier']):
+
+ # Adjust duid to comply with duid format (a:3:b:04:... => 0a:03:0b:04:...)
+ duid = config.return_value(base_mapping + ['identifier'])
+ new_duid = ':'.join(x.rjust(2,'0') for x in duid.split(':'))
+ if new_duid != duid:
+ config.set(base_mapping + ['identifier'], new_duid)
+
+ # Rename the 'identifier' node to 'duid'
+ config.rename(base_mapping + ['identifier'], 'duid')
+
+ # Rename the 'mac-address' node to 'mac'
+ if config.exists(base_mapping + ['mac-address']):
+ config.rename(base_mapping + ['mac-address'], 'mac')
+
+ # Adjust hostname to have valid FQDN characters only
+ new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname)
+ if new_hostname != hostname:
+ config.rename(base_mapping, new_hostname)
diff --git a/src/migration-scripts/dhcpv6-server/3-to-4 b/src/migration-scripts/dhcpv6-server/3-to-4
index 7efc492a5..e38e36505 100755..100644
--- a/src/migration-scripts/dhcpv6-server/3-to-4
+++ b/src/migration-scripts/dhcpv6-server/3-to-4
@@ -1,89 +1,72 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3316:
# - Add subnet IDs to existing subnets
# - Move options to option node
# - Migrate address-range to range tagNode
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
option_nodes = ['captive-portal', 'domain-search', 'name-server',
'nis-domain', 'nis-server', 'nisplus-domain', 'nisplus-server',
'sip-server', 'sntp-server', 'vendor-option']
-subnet_id = 1
-for network in config.list_nodes(base):
- if config.exists(base + [network, 'subnet']):
- for subnet in config.list_nodes(base + [network, 'subnet']):
- base_subnet = base + [network, 'subnet', subnet]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ subnet_id = 1
- if config.exists(base_subnet + ['address-range']):
- config.set(base_subnet + ['range'])
- config.set_tag(base_subnet + ['range'])
+ for network in config.list_nodes(base):
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
- range_id = 1
+ if config.exists(base_subnet + ['address-range']):
+ config.set(base_subnet + ['range'])
+ config.set_tag(base_subnet + ['range'])
- if config.exists(base_subnet + ['address-range', 'prefix']):
- for prefix in config.return_values(base_subnet + ['address-range', 'prefix']):
- config.set(base_subnet + ['range', range_id, 'prefix'], value=prefix)
+ range_id = 1
- range_id += 1
+ if config.exists(base_subnet + ['address-range', 'prefix']):
+ for prefix in config.return_values(base_subnet + ['address-range', 'prefix']):
+ config.set(base_subnet + ['range', range_id, 'prefix'], value=prefix)
- if config.exists(base_subnet + ['address-range', 'start']):
- for start in config.list_nodes(base_subnet + ['address-range', 'start']):
- stop = config.return_value(base_subnet + ['address-range', 'start', start, 'stop'])
+ range_id += 1
- config.set(base_subnet + ['range', range_id, 'start'], value=start)
- config.set(base_subnet + ['range', range_id, 'stop'], value=stop)
+ if config.exists(base_subnet + ['address-range', 'start']):
+ for start in config.list_nodes(base_subnet + ['address-range', 'start']):
+ stop = config.return_value(base_subnet + ['address-range', 'start', start, 'stop'])
- range_id += 1
+ config.set(base_subnet + ['range', range_id, 'start'], value=start)
+ config.set(base_subnet + ['range', range_id, 'stop'], value=stop)
- config.delete(base_subnet + ['address-range'])
+ range_id += 1
- for option in option_nodes:
- if config.exists(base_subnet + [option]):
- config.set(base_subnet + ['option'])
- config.copy(base_subnet + [option], base_subnet + ['option', option])
- config.delete(base_subnet + [option])
+ config.delete(base_subnet + ['address-range'])
- config.set(base_subnet + ['subnet-id'], value=subnet_id)
- subnet_id += 1
+ for option in option_nodes:
+ if config.exists(base_subnet + [option]):
+ config.set(base_subnet + ['option'])
+ config.copy(base_subnet + [option], base_subnet + ['option', option])
+ config.delete(base_subnet + [option])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.set(base_subnet + ['subnet-id'], value=subnet_id)
+ subnet_id += 1
diff --git a/src/migration-scripts/dhcpv6-server/4-to-5 b/src/migration-scripts/dhcpv6-server/4-to-5
index 55fda91b3..ad18e1a84 100755..100644
--- a/src/migration-scripts/dhcpv6-server/4-to-5
+++ b/src/migration-scripts/dhcpv6-server/4-to-5
@@ -1,91 +1,73 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5993: Check if subnet is locally accessible and assign interface to subnet
-import sys
from ipaddress import ip_network
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'dhcpv6-server', 'shared-network-name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-def find_subnet_interface(subnet):
- subnet_net = ip_network(subnet)
-
- def check_addr(if_path):
- if config.exists(if_path + ['address']):
- for addr in config.return_values(if_path + ['address']):
- try:
- if ip_network(addr, strict=False) == subnet_net:
- return True
- except:
- pass # interface address was probably "dhcp" or other magic string
- return None
-
- for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- if_base = ['interfaces', iftype, ifname]
-
- if check_addr(if_base):
- return ifname
-
- if config.exists(if_base + ['vif']):
- for vif in config.list_nodes(if_base + ['vif']):
- if check_addr(if_base + ['vif', vif]):
- return f'{ifname}.{vif}'
-
- if config.exists(if_base + ['vif-s']):
- for vifs in config.list_nodes(if_base + ['vif-s']):
- if check_addr(if_base + ['vif-s', vifs]):
- return f'{ifname}.{vifs}'
-
- if config.exists(if_base + ['vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(if_base + ['vif-s', vifs, 'vif-c']):
- if check_addr(if_base + ['vif-s', vifs, 'vif-c', vifc]):
- return f'{ifname}.{vifs}.{vifc}'
-
- return False
-
-for network in config.list_nodes(base):
- if not config.exists(base + [network, 'subnet']):
- continue
-
- for subnet in config.list_nodes(base + [network, 'subnet']):
- subnet_interface = find_subnet_interface(subnet)
-
- if subnet_interface:
- config.set(base + [network, 'subnet', subnet, 'interface'], value=subnet_interface)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ def find_subnet_interface(subnet):
+ subnet_net = ip_network(subnet)
+
+ def check_addr(if_path):
+ if config.exists(if_path + ['address']):
+ for addr in config.return_values(if_path + ['address']):
+ try:
+ if ip_network(addr, strict=False) == subnet_net:
+ return True
+ except:
+ pass # interface address was probably "dhcp" or other magic string
+ return None
+
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ if_base = ['interfaces', iftype, ifname]
+
+ if check_addr(if_base):
+ return ifname
+
+ if config.exists(if_base + ['vif']):
+ for vif in config.list_nodes(if_base + ['vif']):
+ if check_addr(if_base + ['vif', vif]):
+ return f'{ifname}.{vif}'
+
+ if config.exists(if_base + ['vif-s']):
+ for vifs in config.list_nodes(if_base + ['vif-s']):
+ if check_addr(if_base + ['vif-s', vifs]):
+ return f'{ifname}.{vifs}'
+
+ if config.exists(if_base + ['vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(if_base + ['vif-s', vifs, 'vif-c']):
+ if check_addr(if_base + ['vif-s', vifs, 'vif-c', vifc]):
+ return f'{ifname}.{vifs}.{vifc}'
+
+ return False
+
+ for network in config.list_nodes(base):
+ if not config.exists(base + [network, 'subnet']):
+ continue
+
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ subnet_interface = find_subnet_interface(subnet)
+
+ if subnet_interface:
+ config.set(base + [network, 'subnet', subnet, 'interface'], value=subnet_interface)
diff --git a/src/migration-scripts/dns-dynamic/0-to-1 b/src/migration-scripts/dns-dynamic/0-to-1
index b7674a9c8..6a91b36af 100755..100644
--- a/src/migration-scripts/dns-dynamic/0-to-1
+++ b/src/migration-scripts/dns-dynamic/0-to-1
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5144:
# - migrate "service dns dynamic interface ..."
@@ -27,7 +26,6 @@
# - apply service protocol mapping upfront, they are not 'auto-detected' anymore
# - migrate web-options url to stricter format
-import sys
import re
from vyos.configtree import ConfigTree
@@ -45,84 +43,67 @@ service_protocol_mapping = {
'zoneedit': 'zoneedit1'
}
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
old_base_path = ['service', 'dns', 'dynamic', 'interface']
new_base_path = ['service', 'dns', 'dynamic', 'address']
-if not config.exists(old_base_path):
- # Nothing to do
- sys.exit(0)
-
-# Migrate "service dns dynamic interface"
-# to "service dns dynamic address"
-config.rename(old_base_path, new_base_path[-1])
-
-for address in config.list_nodes(new_base_path):
- # Migrate "service dns dynamic interface <interface> rfc2136 <config> record"
- # to "service dns dynamic address <address> rfc2136 <config> host-name"
- if config.exists(new_base_path + [address, 'rfc2136']):
- for rfc_cfg in config.list_nodes(new_base_path + [address, 'rfc2136']):
- if config.exists(new_base_path + [address, 'rfc2136', rfc_cfg, 'record']):
- config.rename(new_base_path + [address, 'rfc2136', rfc_cfg, 'record'], 'host-name')
-
- # Migrate "service dns dynamic interface <interface> service <config> login"
- # to "service dns dynamic address <address> service <config> username"
- if config.exists(new_base_path + [address, 'service']):
- for svc_cfg in config.list_nodes(new_base_path + [address, 'service']):
- if config.exists(new_base_path + [address, 'service', svc_cfg, 'login']):
- config.rename(new_base_path + [address, 'service', svc_cfg, 'login'], 'username')
- # Apply global 'ipv6-enable' to per <config> 'ip-version: ipv6'
- if config.exists(new_base_path + [address, 'ipv6-enable']):
- config.set(new_base_path + [address, 'service', svc_cfg, 'ip-version'], 'ipv6')
- config.delete(new_base_path + [address, 'ipv6-enable'])
- # Apply service protocol mapping upfront, they are not 'auto-detected' anymore
- if svc_cfg in service_protocol_mapping:
- config.set(new_base_path + [address, 'service', svc_cfg, 'protocol'],
- service_protocol_mapping.get(svc_cfg))
-
- # If use-web is set, then:
- # Move "service dns dynamic address <address> <service|rfc2136> <service> ..."
- # to "service dns dynamic address web <service|rfc2136> <service>-<address> ..."
- # Move "service dns dynamic address web use-web ..."
- # to "service dns dynamic address web web-options ..."
- # Note: The config is named <service>-<address> to avoid name conflict with old entries
- if config.exists(new_base_path + [address, 'use-web']):
- for svc_type in ['rfc2136', 'service']:
- if config.exists(new_base_path + [address, svc_type]):
- config.set(new_base_path + ['web', svc_type])
- config.set_tag(new_base_path + ['web', svc_type])
- for svc_cfg in config.list_nodes(new_base_path + [address, svc_type]):
- config.copy(new_base_path + [address, svc_type, svc_cfg],
- new_base_path + ['web', svc_type, f'{svc_cfg}-{address}'])
-
- # Multiple web-options were not supported, so copy only the first one
- # Also, migrate web-options url to stricter format and transition
- # checkip.dyndns.org to https://domains.google.com/checkip for better
- # TLS support (see: https://github.com/ddclient/ddclient/issues/597)
- if not config.exists(new_base_path + ['web', 'web-options']):
- config.copy(new_base_path + [address, 'use-web'], new_base_path + ['web', 'web-options'])
- if config.exists(new_base_path + ['web', 'web-options', 'url']):
- url = config.return_value(new_base_path + ['web', 'web-options', 'url'])
- if re.search("^(https?://)?checkip\.dyndns\.org", url):
- config.set(new_base_path + ['web', 'web-options', 'url'], 'https://domains.google.com/checkip')
- if not url.startswith(('http://', 'https://')):
- config.set(new_base_path + ['web', 'web-options', 'url'], f'https://{url}')
-
- config.delete(new_base_path + [address])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base_path):
+ # Nothing to do
+ return
+
+ # Migrate "service dns dynamic interface"
+ # to "service dns dynamic address"
+ config.rename(old_base_path, new_base_path[-1])
+
+ for address in config.list_nodes(new_base_path):
+ # Migrate "service dns dynamic interface <interface> rfc2136 <config> record"
+ # to "service dns dynamic address <address> rfc2136 <config> host-name"
+ if config.exists(new_base_path + [address, 'rfc2136']):
+ for rfc_cfg in config.list_nodes(new_base_path + [address, 'rfc2136']):
+ if config.exists(new_base_path + [address, 'rfc2136', rfc_cfg, 'record']):
+ config.rename(new_base_path + [address, 'rfc2136', rfc_cfg, 'record'], 'host-name')
+
+ # Migrate "service dns dynamic interface <interface> service <config> login"
+ # to "service dns dynamic address <address> service <config> username"
+ if config.exists(new_base_path + [address, 'service']):
+ for svc_cfg in config.list_nodes(new_base_path + [address, 'service']):
+ if config.exists(new_base_path + [address, 'service', svc_cfg, 'login']):
+ config.rename(new_base_path + [address, 'service', svc_cfg, 'login'], 'username')
+ # Apply global 'ipv6-enable' to per <config> 'ip-version: ipv6'
+ if config.exists(new_base_path + [address, 'ipv6-enable']):
+ config.set(new_base_path + [address, 'service', svc_cfg, 'ip-version'], 'ipv6')
+ config.delete(new_base_path + [address, 'ipv6-enable'])
+ # Apply service protocol mapping upfront, they are not 'auto-detected' anymore
+ if svc_cfg in service_protocol_mapping:
+ config.set(new_base_path + [address, 'service', svc_cfg, 'protocol'],
+ service_protocol_mapping.get(svc_cfg))
+
+ # If use-web is set, then:
+ # Move "service dns dynamic address <address> <service|rfc2136> <service> ..."
+ # to "service dns dynamic address web <service|rfc2136> <service>-<address> ..."
+ # Move "service dns dynamic address web use-web ..."
+ # to "service dns dynamic address web web-options ..."
+ # Note: The config is named <service>-<address> to avoid name conflict with old entries
+ if config.exists(new_base_path + [address, 'use-web']):
+ for svc_type in ['rfc2136', 'service']:
+ if config.exists(new_base_path + [address, svc_type]):
+ config.set(new_base_path + ['web', svc_type])
+ config.set_tag(new_base_path + ['web', svc_type])
+ for svc_cfg in config.list_nodes(new_base_path + [address, svc_type]):
+ config.copy(new_base_path + [address, svc_type, svc_cfg],
+ new_base_path + ['web', svc_type, f'{svc_cfg}-{address}'])
+
+ # Multiple web-options were not supported, so copy only the first one
+ # Also, migrate web-options url to stricter format and transition
+ # checkip.dyndns.org to https://domains.google.com/checkip for better
+ # TLS support (see: https://github.com/ddclient/ddclient/issues/597)
+ if not config.exists(new_base_path + ['web', 'web-options']):
+ config.copy(new_base_path + [address, 'use-web'], new_base_path + ['web', 'web-options'])
+ if config.exists(new_base_path + ['web', 'web-options', 'url']):
+ url = config.return_value(new_base_path + ['web', 'web-options', 'url'])
+ if re.search("^(https?://)?checkip\.dyndns\.org", url):
+ config.set(new_base_path + ['web', 'web-options', 'url'], 'https://domains.google.com/checkip')
+ if not url.startswith(('http://', 'https://')):
+ config.set(new_base_path + ['web', 'web-options', 'url'], f'https://{url}')
+
+ config.delete(new_base_path + [address])
diff --git a/src/migration-scripts/dns-dynamic/1-to-2 b/src/migration-scripts/dns-dynamic/1-to-2
index 8b599b57a..5dca9e32f 100755..100644
--- a/src/migration-scripts/dns-dynamic/1-to-2
+++ b/src/migration-scripts/dns-dynamic/1-to-2
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5708:
# - migrate "service dns dynamic timeout ..."
@@ -21,50 +20,32 @@
# - migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
# to "service dns dynamic address <interface> service <service> protocol dnsexit2"
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'dns', 'dynamic']
timeout_path = base_path + ['timeout']
address_path = base_path + ['address']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-
-# Migrate "service dns dynamic timeout ..."
-# to "service dns dynamic interval ..."
-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')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
+
+ # Migrate "service dns dynamic timeout ..."
+ # to "service dns dynamic interval ..."
+ 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')
diff --git a/src/migration-scripts/dns-dynamic/2-to-3 b/src/migration-scripts/dns-dynamic/2-to-3
index 4e0aa37d5..9aafc41a4 100755..100644
--- a/src/migration-scripts/dns-dynamic/2-to-3
+++ b/src/migration-scripts/dns-dynamic/2-to-3
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5791:
# - migrate "service dns dynamic address web web-options ..."
@@ -23,7 +22,6 @@
# to "service dns dynamic name <service> address <interface> ..."
# - normalize the all service names to conform with name constraints
-import sys
import re
from unicodedata import normalize
from vyos.configtree import ConfigTree
@@ -41,79 +39,61 @@ def normalize_name(name):
return name
-
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'dns', 'dynamic']
address_path = base_path + ['address']
name_path = base_path + ['name']
-if not config.exists(address_path):
- # Nothing to do
- sys.exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(address_path):
+ # Nothing to do
+ return
-# config.copy does not recursively create a path, so initialize the name path as tagged node
-if not config.exists(name_path):
- config.set(name_path)
- config.set_tag(name_path)
+ # config.copy does not recursively create a path, so initialize the name path as tagged node
+ if not config.exists(name_path):
+ config.set(name_path)
+ config.set_tag(name_path)
-for address in config.list_nodes(address_path):
+ for address in config.list_nodes(address_path):
- address_path_tag = address_path + [address]
+ address_path_tag = address_path + [address]
+
+ # Move web-option as a configuration in each service instead of top level web-option
+ if config.exists(address_path_tag + ['web-options']) and address == 'web':
+ for svc_type in ['service', 'rfc2136']:
+ if config.exists(address_path_tag + [svc_type]):
+ for svc_cfg in config.list_nodes(address_path_tag + [svc_type]):
+ config.copy(address_path_tag + ['web-options'],
+ address_path_tag + [svc_type, svc_cfg, 'web-options'])
+ config.delete(address_path_tag + ['web-options'])
- # Move web-option as a configuration in each service instead of top level web-option
- if config.exists(address_path_tag + ['web-options']) and address == 'web':
for svc_type in ['service', 'rfc2136']:
if config.exists(address_path_tag + [svc_type]):
+ # Set protocol to 'nsupdate' for RFC2136 configuration
+ if svc_type == 'rfc2136':
+ for rfc_cfg in config.list_nodes(address_path_tag + ['rfc2136']):
+ config.set(address_path_tag + ['rfc2136', rfc_cfg, 'protocol'], 'nsupdate')
+
+ # Add address as config value in each service before moving the service path
+ # And then copy the services from 'address <interface> service <service>'
+ # to 'name (service|rfc2136)-<service>-<address>'
+ # Note: The new service is named (service|rfc2136)-<service>-<address>
+ # to avoid name conflict with old entries
for svc_cfg in config.list_nodes(address_path_tag + [svc_type]):
- config.copy(address_path_tag + ['web-options'],
- address_path_tag + [svc_type, svc_cfg, 'web-options'])
- config.delete(address_path_tag + ['web-options'])
-
- for svc_type in ['service', 'rfc2136']:
- if config.exists(address_path_tag + [svc_type]):
- # Set protocol to 'nsupdate' for RFC2136 configuration
- if svc_type == 'rfc2136':
- for rfc_cfg in config.list_nodes(address_path_tag + ['rfc2136']):
- config.set(address_path_tag + ['rfc2136', rfc_cfg, 'protocol'], 'nsupdate')
-
- # Add address as config value in each service before moving the service path
- # And then copy the services from 'address <interface> service <service>'
- # to 'name (service|rfc2136)-<service>-<address>'
- # Note: The new service is named (service|rfc2136)-<service>-<address>
- # to avoid name conflict with old entries
- for svc_cfg in config.list_nodes(address_path_tag + [svc_type]):
- config.set(address_path_tag + [svc_type, svc_cfg, 'address'], address)
- config.copy(address_path_tag + [svc_type, svc_cfg],
- name_path + ['-'.join([svc_type, svc_cfg, address])])
-
-# Finally cleanup the old address path
-config.delete(address_path)
-
-# Normalize the all service names to conform with name constraints
-index = 1
-for name in config.list_nodes(name_path):
- new_name = normalize_name(name)
- if new_name != name:
- # Append index if there is still a name conflicts after normalization
- # For example, "foo-?(" and "foo-!)" both normalize to "foo-"
- if config.exists(name_path + [new_name]):
- new_name = f'{new_name}-{index}'
- index += 1
- config.rename(name_path + [name], new_name)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.set(address_path_tag + [svc_type, svc_cfg, 'address'], address)
+ config.copy(address_path_tag + [svc_type, svc_cfg],
+ name_path + ['-'.join([svc_type, svc_cfg, address])])
+
+ # Finally cleanup the old address path
+ config.delete(address_path)
+
+ # Normalize the all service names to conform with name constraints
+ index = 1
+ for name in config.list_nodes(name_path):
+ new_name = normalize_name(name)
+ if new_name != name:
+ # Append index if there is still a name conflicts after normalization
+ # For example, "foo-?(" and "foo-!)" both normalize to "foo-"
+ if config.exists(name_path + [new_name]):
+ new_name = f'{new_name}-{index}'
+ index += 1
+ config.rename(name_path + [name], new_name)
diff --git a/src/migration-scripts/dns-dynamic/3-to-4 b/src/migration-scripts/dns-dynamic/3-to-4
index b888a3b6b..c8e1ffeee 100755..100644
--- a/src/migration-scripts/dns-dynamic/3-to-4
+++ b/src/migration-scripts/dns-dynamic/3-to-4
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5966:
# - migrate "service dns dynamic name <service> address <interface>"
@@ -22,55 +21,37 @@
# to "service dns dynamic name <service> address web ..."
# when <interface> == 'web'
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'dns', 'dynamic', 'name']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-
-for service in config.list_nodes(base_path):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
- service_path = base_path + [service]
+ for service in config.list_nodes(base_path):
- if config.exists(service_path + ['address']):
- address = config.return_value(service_path + ['address'])
- # 'address' is not a leaf node anymore, delete it first
- config.delete(service_path + ['address'])
+ service_path = base_path + [service]
- # When address is an interface (not 'web'), move it to 'address interface'
- if address != 'web':
- config.set(service_path + ['address', 'interface'], address)
+ if config.exists(service_path + ['address']):
+ address = config.return_value(service_path + ['address'])
+ # 'address' is not a leaf node anymore, delete it first
+ config.delete(service_path + ['address'])
- else: # address == 'web'
- # Relocate optional 'web-options' directly under 'address web'
- if config.exists(service_path + ['web-options']):
- # config.copy does not recursively create a path, so initialize it
- config.set(service_path + ['address'])
- config.copy(service_path + ['web-options'],
- service_path + ['address', 'web'])
- config.delete(service_path + ['web-options'])
+ # When address is an interface (not 'web'), move it to 'address interface'
+ if address != 'web':
+ config.set(service_path + ['address', 'interface'], address)
- # ensure that valueless 'address web' still exists even if there are no 'web-options'
- if not config.exists(service_path + ['address', 'web']):
- config.set(service_path + ['address', 'web'])
+ else: # address == 'web'
+ # Relocate optional 'web-options' directly under 'address web'
+ if config.exists(service_path + ['web-options']):
+ # config.copy does not recursively create a path, so initialize it
+ config.set(service_path + ['address'])
+ config.copy(service_path + ['web-options'],
+ service_path + ['address', 'web'])
+ config.delete(service_path + ['web-options'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ # ensure that valueless 'address web' still exists even if there are no 'web-options'
+ if not config.exists(service_path + ['address', 'web']):
+ config.set(service_path + ['address', 'web'])
diff --git a/src/migration-scripts/dns-forwarding/0-to-1 b/src/migration-scripts/dns-forwarding/0-to-1
index 7f4343652..264ffb40d 100755..100644
--- a/src/migration-scripts/dns-forwarding/0-to-1
+++ b/src/migration-scripts/dns-forwarding/0-to-1
@@ -1,50 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# This migration script will check if there is a allow-from directive configured
# for the dns forwarding service - if not, the node will be created with the old
# default values of 0.0.0.0/0 and ::/0
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+base = ['service', 'dns', 'forwarding']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree)-> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-base = ['service', 'dns', 'forwarding']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
if not config.exists(base + ['allow-from']):
config.set(base + ['allow-from'], value='0.0.0.0/0', replace=False)
config.set(base + ['allow-from'], value='::/0', replace=False)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/dns-forwarding/1-to-2 b/src/migration-scripts/dns-forwarding/1-to-2
index 7df2d47e2..15ed1e136 100755..100644
--- a/src/migration-scripts/dns-forwarding/1-to-2
+++ b/src/migration-scripts/dns-forwarding/1-to-2
@@ -1,19 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# This migration script will remove the deprecated 'listen-on' statement
# from the dns forwarding service and will add the corresponding
@@ -21,66 +19,49 @@
# on interface addresses and not on interface names.
from ipaddress import ip_interface
-from sys import argv, exit
from vyos.ifconfig import Interface
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'dns', 'forwarding']
-if not config.exists(base + ['listen-on']):
- # Nothing to do
- exit(0)
-listen_intf = config.return_values(base + ['listen-on'])
-# Delete node with abandoned command
-config.delete(base + ['listen-on'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['listen-on']):
+ # Nothing to do
+ return
-# retrieve interface addresses for every configured listen-on interface
-listen_addr = []
-for intf in listen_intf:
- # we need to evaluate the interface section before manipulating the 'intf' variable
- section = Interface.section(intf)
- if not section:
- raise ValueError(f'Invalid interface name {intf}')
+ listen_intf = config.return_values(base + ['listen-on'])
+ # Delete node with abandoned command
+ config.delete(base + ['listen-on'])
- # we need to treat vif and vif-s interfaces differently,
- # both "real interfaces" use dots for vlan identifiers - those
- # need to be exchanged with vif and vif-s identifiers
- if intf.count('.') == 1:
- # this is a regular VLAN interface
- intf = intf.split('.')[0] + ' vif ' + intf.split('.')[1]
- elif intf.count('.') == 2:
- # this is a QinQ VLAN interface
- intf = intf.split('.')[0] + ' vif-s ' + intf.split('.')[1] + ' vif-c ' + intf.split('.')[2]
+ # retrieve interface addresses for every configured listen-on interface
+ listen_addr = []
+ for intf in listen_intf:
+ # we need to evaluate the interface section before manipulating the 'intf' variable
+ section = Interface.section(intf)
+ if not section:
+ raise ValueError(f'Invalid interface name {intf}')
- # retrieve corresponding interface addresses in CIDR format
- # those need to be converted in pure IP addresses without network information
- path = ['interfaces', section, intf, 'address']
- try:
- for addr in config.return_values(path):
- listen_addr.append( ip_interface(addr).ip )
- except:
- # Some interface types do not use "address" option (e.g. OpenVPN)
- # and may not even have a fixed address
- print("Could not retrieve the address of the interface {} from the config".format(intf))
- print("You will need to update your DNS forwarding configuration manually")
+ # we need to treat vif and vif-s interfaces differently,
+ # both "real interfaces" use dots for vlan identifiers - those
+ # need to be exchanged with vif and vif-s identifiers
+ if intf.count('.') == 1:
+ # this is a regular VLAN interface
+ intf = intf.split('.')[0] + ' vif ' + intf.split('.')[1]
+ elif intf.count('.') == 2:
+ # this is a QinQ VLAN interface
+ intf = intf.split('.')[0] + ' vif-s ' + intf.split('.')[1] + ' vif-c ' + intf.split('.')[2]
-for addr in listen_addr:
- config.set(base + ['listen-address'], value=addr, replace=False)
+ # retrieve corresponding interface addresses in CIDR format
+ # those need to be converted in pure IP addresses without network information
+ path = ['interfaces', section, intf, 'address']
+ try:
+ for addr in config.return_values(path):
+ listen_addr.append( ip_interface(addr).ip )
+ except:
+ # Some interface types do not use "address" option (e.g. OpenVPN)
+ # and may not even have a fixed address
+ print("Could not retrieve the address of the interface {} from the config".format(intf))
+ print("You will need to update your DNS forwarding configuration manually")
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ for addr in listen_addr:
+ config.set(base + ['listen-address'], value=addr, replace=False)
diff --git a/src/migration-scripts/dns-forwarding/2-to-3 b/src/migration-scripts/dns-forwarding/2-to-3
index d7ff9e260..729c1f00a 100755..100644
--- a/src/migration-scripts/dns-forwarding/2-to-3
+++ b/src/migration-scripts/dns-forwarding/2-to-3
@@ -1,51 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Sets the new options "addnta" and "recursion-desired" for all
# 'dns forwarding domain' as this is usually desired
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'dns', 'forwarding']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-if config.exists(base + ['domain']):
- for domain in config.list_nodes(base + ['domain']):
- domain_base = base + ['domain', domain]
- config.set(domain_base + ['addnta'])
- config.set(domain_base + ['recursion-desired'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ if config.exists(base + ['domain']):
+ for domain in config.list_nodes(base + ['domain']):
+ domain_base = base + ['domain', domain]
+ config.set(domain_base + ['addnta'])
+ config.set(domain_base + ['recursion-desired'])
diff --git a/src/migration-scripts/dns-forwarding/3-to-4 b/src/migration-scripts/dns-forwarding/3-to-4
index 3d5316ed4..b02c0b7ca 100755..100644
--- a/src/migration-scripts/dns-forwarding/3-to-4
+++ b/src/migration-scripts/dns-forwarding/3-to-4
@@ -1,49 +1,31 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5115: migrate "service dns forwarding domain example.com server" to
# "service dns forwarding domain example.com name-server"
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'dns', 'forwarding', 'domain']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-for domain in config.list_nodes(base):
- if config.exists(base + [domain, 'server']):
- config.copy(base + [domain, 'server'], base + [domain, 'name-server'])
- config.delete(base + [domain, 'server'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ for domain in config.list_nodes(base):
+ if config.exists(base + [domain, 'server']):
+ config.copy(base + [domain, 'server'], base + [domain, 'name-server'])
+ config.delete(base + [domain, 'server'])
diff --git a/src/migration-scripts/firewall/10-to-11 b/src/migration-scripts/firewall/10-to-11
index 854d5a558..70a170940 100755..100644
--- a/src/migration-scripts/firewall/10-to-11
+++ b/src/migration-scripts/firewall/10-to-11
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5160: Firewall re-writing
@@ -37,171 +36,152 @@
# set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> action jump
# set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> jump-target <name>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-### Migration of state policies
-if config.exists(base + ['state-policy']):
- for state in config.list_nodes(base + ['state-policy']):
- action = config.return_value(base + ['state-policy', state, 'action'])
- config.set(base + ['global-options', 'state-policy', state, 'action'], value=action)
- if config.exists(base + ['state-policy', state, 'log']):
- config.set(base + ['global-options', 'state-policy', state, 'log'], value='enable')
- config.delete(base + ['state-policy'])
-
-## migration of global options:
-for option in ['all-ping', 'broadcast-ping', 'config-trap', 'ip-src-route', 'ipv6-receive-redirects', 'ipv6-src-route', 'log-martians',
- 'receive-redirects', 'resolver-cache', 'resolver-internal', 'send-redirects', 'source-validation', 'syn-cookies', 'twa-hazards-protection']:
- if config.exists(base + [option]):
- if option != 'config-trap':
- val = config.return_value(base + [option])
- config.set(base + ['global-options', option], value=val)
- config.delete(base + [option])
-
-### Migration of firewall name and ipv6-name
-### Also migrate legacy 'accept' behaviour
-if config.exists(base + ['name']):
- config.set(['firewall', 'ipv4', 'name'])
- config.set_tag(['firewall', 'ipv4', 'name'])
-
- for ipv4name in config.list_nodes(base + ['name']):
- config.copy(base + ['name', ipv4name], base + ['ipv4', 'name', ipv4name])
-
- if config.exists(base + ['ipv4', 'name', ipv4name, 'default-action']):
- action = config.return_value(base + ['ipv4', 'name', ipv4name, 'default-action'])
-
- if action == 'accept':
- config.set(base + ['ipv4', 'name', ipv4name, 'default-action'], value='return')
-
- if config.exists(base + ['ipv4', 'name', ipv4name, 'rule']):
- for rule_id in config.list_nodes(base + ['ipv4', 'name', ipv4name, 'rule']):
- action = config.return_value(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'])
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ ### Migration of state policies
+ if config.exists(base + ['state-policy']):
+ for state in config.list_nodes(base + ['state-policy']):
+ action = config.return_value(base + ['state-policy', state, 'action'])
+ config.set(base + ['global-options', 'state-policy', state, 'action'], value=action)
+ if config.exists(base + ['state-policy', state, 'log']):
+ config.set(base + ['global-options', 'state-policy', state, 'log'], value='enable')
+ config.delete(base + ['state-policy'])
+
+ ## migration of global options:
+ for option in ['all-ping', 'broadcast-ping', 'config-trap', 'ip-src-route', 'ipv6-receive-redirects', 'ipv6-src-route', 'log-martians',
+ 'receive-redirects', 'resolver-cache', 'resolver-internal', 'send-redirects', 'source-validation', 'syn-cookies', 'twa-hazards-protection']:
+ if config.exists(base + [option]):
+ if option != 'config-trap':
+ val = config.return_value(base + [option])
+ config.set(base + ['global-options', option], value=val)
+ config.delete(base + [option])
+
+ ### Migration of firewall name and ipv6-name
+ ### Also migrate legacy 'accept' behaviour
+ if config.exists(base + ['name']):
+ config.set(['firewall', 'ipv4', 'name'])
+ config.set_tag(['firewall', 'ipv4', 'name'])
+
+ for ipv4name in config.list_nodes(base + ['name']):
+ config.copy(base + ['name', ipv4name], base + ['ipv4', 'name', ipv4name])
+
+ if config.exists(base + ['ipv4', 'name', ipv4name, 'default-action']):
+ action = config.return_value(base + ['ipv4', 'name', ipv4name, 'default-action'])
if action == 'accept':
- config.set(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'], value='return')
+ config.set(base + ['ipv4', 'name', ipv4name, 'default-action'], value='return')
- config.delete(base + ['name'])
+ if config.exists(base + ['ipv4', 'name', ipv4name, 'rule']):
+ for rule_id in config.list_nodes(base + ['ipv4', 'name', ipv4name, 'rule']):
+ action = config.return_value(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'])
-if config.exists(base + ['ipv6-name']):
- config.set(['firewall', 'ipv6', 'name'])
- config.set_tag(['firewall', 'ipv6', 'name'])
+ if action == 'accept':
+ config.set(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'], value='return')
- for ipv6name in config.list_nodes(base + ['ipv6-name']):
- config.copy(base + ['ipv6-name', ipv6name], base + ['ipv6', 'name', ipv6name])
+ config.delete(base + ['name'])
- if config.exists(base + ['ipv6', 'name', ipv6name, 'default-action']):
- action = config.return_value(base + ['ipv6', 'name', ipv6name, 'default-action'])
+ if config.exists(base + ['ipv6-name']):
+ config.set(['firewall', 'ipv6', 'name'])
+ config.set_tag(['firewall', 'ipv6', 'name'])
- if action == 'accept':
- config.set(base + ['ipv6', 'name', ipv6name, 'default-action'], value='return')
+ for ipv6name in config.list_nodes(base + ['ipv6-name']):
+ config.copy(base + ['ipv6-name', ipv6name], base + ['ipv6', 'name', ipv6name])
- if config.exists(base + ['ipv6', 'name', ipv6name, 'rule']):
- for rule_id in config.list_nodes(base + ['ipv6', 'name', ipv6name, 'rule']):
- action = config.return_value(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'])
+ if config.exists(base + ['ipv6', 'name', ipv6name, 'default-action']):
+ action = config.return_value(base + ['ipv6', 'name', ipv6name, 'default-action'])
if action == 'accept':
- config.set(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'], value='return')
-
- config.delete(base + ['ipv6-name'])
-
-### Migration of firewall interface
-if config.exists(base + ['interface']):
- fwd_ipv4_rule = 5
- inp_ipv4_rule = 5
- fwd_ipv6_rule = 5
- inp_ipv6_rule = 5
- for direction in ['in', 'out', 'local']:
- for iface in config.list_nodes(base + ['interface']):
- if config.exists(base + ['interface', iface, direction]):
- if config.exists(base + ['interface', iface, direction, 'name']):
- target = config.return_value(base + ['interface', iface, direction, 'name'])
- if direction == 'in':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv4', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
- fwd_ipv4_rule = fwd_ipv4_rule + 5
- elif direction == 'out':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv4', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv4_rule, 'outbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
- fwd_ipv4_rule = fwd_ipv4_rule + 5
- else:
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv4', 'input', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [inp_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [inp_ipv4_rule, 'action'], value='jump')
- config.set(new_base + [inp_ipv4_rule, 'jump-target'], value=target)
- inp_ipv4_rule = inp_ipv4_rule + 5
-
- if config.exists(base + ['interface', iface, direction, 'ipv6-name']):
- target = config.return_value(base + ['interface', iface, direction, 'ipv6-name'])
- if direction == 'in':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv6', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
- fwd_ipv6_rule = fwd_ipv6_rule + 5
- elif direction == 'out':
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
- new_base = base + ['ipv6', 'forward', 'filter', 'rule']
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [fwd_ipv6_rule, 'outbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
- config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
- fwd_ipv6_rule = fwd_ipv6_rule + 5
- else:
- new_base = base + ['ipv6', 'input', 'filter', 'rule']
- # Add default-action== accept for compatibility reasons:
- config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept')
- config.set(new_base)
- config.set_tag(new_base)
- config.set(new_base + [inp_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
- config.set(new_base + [inp_ipv6_rule, 'action'], value='jump')
- config.set(new_base + [inp_ipv6_rule, 'jump-target'], value=target)
- inp_ipv6_rule = inp_ipv6_rule + 5
-
- config.delete(base + ['interface'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.set(base + ['ipv6', 'name', ipv6name, 'default-action'], value='return')
+
+ if config.exists(base + ['ipv6', 'name', ipv6name, 'rule']):
+ for rule_id in config.list_nodes(base + ['ipv6', 'name', ipv6name, 'rule']):
+ action = config.return_value(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'])
+
+ if action == 'accept':
+ config.set(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'], value='return')
+
+ config.delete(base + ['ipv6-name'])
+
+ ### Migration of firewall interface
+ if config.exists(base + ['interface']):
+ fwd_ipv4_rule = 5
+ inp_ipv4_rule = 5
+ fwd_ipv6_rule = 5
+ inp_ipv6_rule = 5
+ for direction in ['in', 'out', 'local']:
+ for iface in config.list_nodes(base + ['interface']):
+ if config.exists(base + ['interface', iface, direction]):
+ if config.exists(base + ['interface', iface, direction, 'name']):
+ target = config.return_value(base + ['interface', iface, direction, 'name'])
+ if direction == 'in':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ elif direction == 'out':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv4_rule, 'outbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ else:
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'input', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [inp_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [inp_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [inp_ipv4_rule, 'jump-target'], value=target)
+ inp_ipv4_rule = inp_ipv4_rule + 5
+
+ if config.exists(base + ['interface', iface, direction, 'ipv6-name']):
+ target = config.return_value(base + ['interface', iface, direction, 'ipv6-name'])
+ if direction == 'in':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv6', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+ elif direction == 'out':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv6', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv6_rule, 'outbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+ else:
+ new_base = base + ['ipv6', 'input', 'filter', 'rule']
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept')
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [inp_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [inp_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [inp_ipv6_rule, 'jump-target'], value=target)
+ inp_ipv6_rule = inp_ipv6_rule + 5
+
+ config.delete(base + ['interface'])
diff --git a/src/migration-scripts/firewall/11-to-12 b/src/migration-scripts/firewall/11-to-12
index f9122e74c..80a74cca9 100755..100644
--- a/src/migration-scripts/firewall/11-to-12
+++ b/src/migration-scripts/firewall/11-to-12
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5681: Firewall re-writing. Simplify cli when mathcing interface
# From
@@ -22,50 +21,31 @@
# set firewall ... rule <rule> [inbound-interface | outboubd-interface] name <iface>
# set firewall ... rule <rule> [inbound-interface | outboubd-interface] group <iface_group>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-## Migration from base chains
-#if config.exists(base + ['interface', iface, direction]):
-for family in ['ipv4', 'ipv6']:
- if config.exists(base + [family]):
- for hook in ['forward', 'input', 'output', 'name']:
- if config.exists(base + [family, hook]):
- for priority in config.list_nodes(base + [family, hook]):
- if config.exists(base + [family, hook, priority, 'rule']):
- for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
- for direction in ['inbound-interface', 'outbound-interface']:
- if config.exists(base + [family, hook, priority, 'rule', rule, direction]):
- if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']):
- iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
- config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface)
- config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
- elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']):
- group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
- config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group)
- config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ ## Migration from base chains
+ #if config.exists(base + ['interface', iface, direction]):
+ for family in ['ipv4', 'ipv6']:
+ if config.exists(base + [family]):
+ for hook in ['forward', 'input', 'output', 'name']:
+ if config.exists(base + [family, hook]):
+ for priority in config.list_nodes(base + [family, hook]):
+ if config.exists(base + [family, hook, priority, 'rule']):
+ for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
+ for direction in ['inbound-interface', 'outbound-interface']:
+ if config.exists(base + [family, hook, priority, 'rule', rule, direction]):
+ if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']):
+ iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
+ config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface)
+ config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name'])
+ elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']):
+ group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
+ config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group)
+ config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group'])
diff --git a/src/migration-scripts/firewall/12-to-13 b/src/migration-scripts/firewall/12-to-13
index d72ba834d..d7b801cd3 100755..100644
--- a/src/migration-scripts/firewall/12-to-13
+++ b/src/migration-scripts/firewall/12-to-13
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5729: Switch to valueless whenever is possible.
# From
@@ -25,65 +24,46 @@
# set firewall ... rule <rule> state <state>
# Remove command if log=disable or <state>=disable
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# State Policy logs:
-if config.exists(base + ['global-options', 'state-policy']):
- for state in config.list_nodes(base + ['global-options', 'state-policy']):
- if config.exists(base + ['global-options', 'state-policy', state, 'log']):
- log_value = config.return_value(base + ['global-options', 'state-policy', state, 'log'])
- config.delete(base + ['global-options', 'state-policy', state, 'log'])
- if log_value == 'enable':
- config.set(base + ['global-options', 'state-policy', state, 'log'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-for family in ['ipv4', 'ipv6', 'bridge']:
- if config.exists(base + [family]):
- for hook in ['forward', 'input', 'output', 'name']:
- if config.exists(base + [family, hook]):
- for priority in config.list_nodes(base + [family, hook]):
- if config.exists(base + [family, hook, priority, 'rule']):
- for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
- # Log
- if config.exists(base + [family, hook, priority, 'rule', rule, 'log']):
- log_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'log'])
- config.delete(base + [family, hook, priority, 'rule', rule, 'log'])
- if log_value == 'enable':
- config.set(base + [family, hook, priority, 'rule', rule, 'log'])
- # State
- if config.exists(base + [family, hook, priority, 'rule', rule, 'state']):
- flag_enable = 'False'
- for state in ['established', 'invalid', 'new', 'related']:
- if config.exists(base + [family, hook, priority, 'rule', rule, 'state', state]):
- state_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'state', state])
- config.delete(base + [family, hook, priority, 'rule', rule, 'state', state])
- if state_value == 'enable':
- config.set(base + [family, hook, priority, 'rule', rule, 'state'], value=state, replace=False)
- flag_enable = 'True'
- if flag_enable == 'False':
- config.delete(base + [family, hook, priority, 'rule', rule, 'state'])
+ # State Policy logs:
+ if config.exists(base + ['global-options', 'state-policy']):
+ for state in config.list_nodes(base + ['global-options', 'state-policy']):
+ if config.exists(base + ['global-options', 'state-policy', state, 'log']):
+ log_value = config.return_value(base + ['global-options', 'state-policy', state, 'log'])
+ config.delete(base + ['global-options', 'state-policy', state, 'log'])
+ if log_value == 'enable':
+ config.set(base + ['global-options', 'state-policy', state, 'log'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for family in ['ipv4', 'ipv6', 'bridge']:
+ if config.exists(base + [family]):
+ for hook in ['forward', 'input', 'output', 'name']:
+ if config.exists(base + [family, hook]):
+ for priority in config.list_nodes(base + [family, hook]):
+ if config.exists(base + [family, hook, priority, 'rule']):
+ for rule in config.list_nodes(base + [family, hook, priority, 'rule']):
+ # Log
+ if config.exists(base + [family, hook, priority, 'rule', rule, 'log']):
+ log_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'log'])
+ config.delete(base + [family, hook, priority, 'rule', rule, 'log'])
+ if log_value == 'enable':
+ config.set(base + [family, hook, priority, 'rule', rule, 'log'])
+ # State
+ if config.exists(base + [family, hook, priority, 'rule', rule, 'state']):
+ flag_enable = 'False'
+ for state in ['established', 'invalid', 'new', 'related']:
+ if config.exists(base + [family, hook, priority, 'rule', rule, 'state', state]):
+ state_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'state', state])
+ config.delete(base + [family, hook, priority, 'rule', rule, 'state', state])
+ if state_value == 'enable':
+ config.set(base + [family, hook, priority, 'rule', rule, 'state'], value=state, replace=False)
+ flag_enable = 'True'
+ if flag_enable == 'False':
+ config.delete(base + [family, hook, priority, 'rule', rule, 'state'])
diff --git a/src/migration-scripts/firewall/13-to-14 b/src/migration-scripts/firewall/13-to-14
index f45ff0674..723b0aea2 100755..100644
--- a/src/migration-scripts/firewall/13-to-14
+++ b/src/migration-scripts/firewall/13-to-14
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5834: Rename 'enable-default-log' to 'default-log'
# From
@@ -22,38 +21,19 @@
# set firewall ... filter default-log
# set firewall ... name <name> default-log
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for family in ['ipv4', 'ipv6', 'bridge']:
- if config.exists(base + [family]):
- for hook in ['forward', 'input', 'output', 'name']:
- if config.exists(base + [family, hook]):
- for priority in config.list_nodes(base + [family, hook]):
- if config.exists(base + [family, hook, priority, 'enable-default-log']):
- config.rename(base + [family, hook, priority, 'enable-default-log'], 'default-log')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for family in ['ipv4', 'ipv6', 'bridge']:
+ if config.exists(base + [family]):
+ for hook in ['forward', 'input', 'output', 'name']:
+ if config.exists(base + [family, hook]):
+ for priority in config.list_nodes(base + [family, hook]):
+ if config.exists(base + [family, hook, priority, 'enable-default-log']):
+ config.rename(base + [family, hook, priority, 'enable-default-log'], 'default-log')
diff --git a/src/migration-scripts/firewall/14-to-15 b/src/migration-scripts/firewall/14-to-15
index 735839365..e4a2aaee4 100755..100644
--- a/src/migration-scripts/firewall/14-to-15
+++ b/src/migration-scripts/firewall/14-to-15
@@ -1,46 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5535: Migrate <set system ip disable-directed-broadcast> to <set firewall global-options directed-broadcas [enable|disable]
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['firewall']
-if config.exists(['system', 'ip', 'disable-directed-broadcast']):
- config.set(['firewall', 'global-options', 'directed-broadcast'], value='disable')
- config.delete(['system', 'ip', 'disable-directed-broadcast'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+def migrate(config: ConfigTree) -> None:
+ if config.exists(['system', 'ip', 'disable-directed-broadcast']):
+ config.set(['firewall', 'global-options', 'directed-broadcast'], value='disable')
+ config.delete(['system', 'ip', 'disable-directed-broadcast'])
diff --git a/src/migration-scripts/firewall/15-to-16 b/src/migration-scripts/firewall/15-to-16
index 28df1256e..8e28bba6f 100755..100644
--- a/src/migration-scripts/firewall/15-to-16
+++ b/src/migration-scripts/firewall/15-to-16
@@ -18,39 +18,20 @@
# from: set system conntrack timeout ..
# to: set firewall global-options timeout ...
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
firewall_base = ['firewall', 'global-options']
conntrack_base = ['system', 'conntrack', 'timeout']
-config = ConfigTree(config_file)
-
-if not config.exists(conntrack_base):
- # Nothing to do
- exit(0)
-for protocol in ['icmp', 'tcp', 'udp', 'other']:
- if config.exists(conntrack_base + [protocol]):
- if not config.exists(firewall_base + ['timeout']):
- config.set(firewall_base + ['timeout'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(conntrack_base):
+ # Nothing to do
+ return
- config.copy(conntrack_base + [protocol], firewall_base + ['timeout', protocol])
- config.delete(conntrack_base + [protocol])
+ for protocol in ['icmp', 'tcp', 'udp', 'other']:
+ if config.exists(conntrack_base + [protocol]):
+ if not config.exists(firewall_base + ['timeout']):
+ config.set(firewall_base + ['timeout'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.copy(conntrack_base + [protocol], firewall_base + ['timeout', protocol])
+ config.delete(conntrack_base + [protocol])
diff --git a/src/migration-scripts/firewall/5-to-6 b/src/migration-scripts/firewall/5-to-6
index e1eaea7a1..d01684787 100755..100644
--- a/src/migration-scripts/firewall/5-to-6
+++ b/src/migration-scripts/firewall/5-to-6
@@ -1,105 +1,85 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3090: migrate "firewall options interface <name> adjust-mss" to the
# individual interface.
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall', 'options', 'interface']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for interface in config.list_nodes(base):
- if config.exists(base + [interface, 'disable']):
- continue
- if config.exists(base + [interface, 'adjust-mss']):
- section = Section.section(interface)
- tmp = config.return_value(base + [interface, 'adjust-mss'])
-
- vlan = interface.split('.')
- base_interface_path = ['interfaces', section, vlan[0]]
-
- if len(vlan) == 1:
- # Normal interface, no VLAN
- config.set(base_interface_path + ['ip', 'adjust-mss'], value=tmp)
- elif len(vlan) == 2:
- # Regular VIF or VIF-S interface - we need to check the config
- vif = vlan[1]
- if config.exists(base_interface_path + ['vif', vif]):
- config.set(base_interface_path + ['vif', vif, 'ip', 'adjust-mss'], value=tmp)
- elif config.exists(base_interface_path + ['vif-s', vif]):
- config.set(base_interface_path + ['vif-s', vif, 'ip', 'adjust-mss'], value=tmp)
- elif len(vlan) == 3:
- # VIF-S interface with VIF-C subinterface
- vif_s = vlan[1]
- vif_c = vlan[2]
- config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ip', 'adjust-mss'], value=tmp)
- config.set_tag(base_interface_path + ['vif-s'])
- config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
-
- if config.exists(base + [interface, 'adjust-mss6']):
- section = Section.section(interface)
- tmp = config.return_value(base + [interface, 'adjust-mss6'])
-
- vlan = interface.split('.')
- base_interface_path = ['interfaces', section, vlan[0]]
-
- if len(vlan) == 1:
- # Normal interface, no VLAN
- config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp)
- elif len(vlan) == 2:
- # Regular VIF or VIF-S interface - we need to check the config
- vif = vlan[1]
- if config.exists(base_interface_path + ['vif', vif]):
- config.set(base_interface_path + ['vif', vif, 'ipv6', 'adjust-mss'], value=tmp)
- config.set_tag(base_interface_path + ['vif'])
- elif config.exists(base_interface_path + ['vif-s', vif]):
- config.set(base_interface_path + ['vif-s', vif, 'ipv6', 'adjust-mss'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for interface in config.list_nodes(base):
+ if config.exists(base + [interface, 'disable']):
+ continue
+
+ if config.exists(base + [interface, 'adjust-mss']):
+ section = Section.section(interface)
+ tmp = config.return_value(base + [interface, 'adjust-mss'])
+
+ vlan = interface.split('.')
+ base_interface_path = ['interfaces', section, vlan[0]]
+
+ if len(vlan) == 1:
+ # Normal interface, no VLAN
+ config.set(base_interface_path + ['ip', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 2:
+ # Regular VIF or VIF-S interface - we need to check the config
+ vif = vlan[1]
+ if config.exists(base_interface_path + ['vif', vif]):
+ config.set(base_interface_path + ['vif', vif, 'ip', 'adjust-mss'], value=tmp)
+ elif config.exists(base_interface_path + ['vif-s', vif]):
+ config.set(base_interface_path + ['vif-s', vif, 'ip', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 3:
+ # VIF-S interface with VIF-C subinterface
+ vif_s = vlan[1]
+ vif_c = vlan[2]
+ config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ip', 'adjust-mss'], value=tmp)
config.set_tag(base_interface_path + ['vif-s'])
- elif len(vlan) == 3:
- # VIF-S interface with VIF-C subinterface
- vif_s = vlan[1]
- vif_c = vlan[2]
- config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ipv6', 'adjust-mss'], value=tmp)
- config.set_tag(base_interface_path + ['vif-s'])
- config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
-
-config.delete(['firewall', 'options'])
+ config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
+
+ if config.exists(base + [interface, 'adjust-mss6']):
+ section = Section.section(interface)
+ tmp = config.return_value(base + [interface, 'adjust-mss6'])
+
+ vlan = interface.split('.')
+ base_interface_path = ['interfaces', section, vlan[0]]
+
+ if len(vlan) == 1:
+ # Normal interface, no VLAN
+ config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 2:
+ # Regular VIF or VIF-S interface - we need to check the config
+ vif = vlan[1]
+ if config.exists(base_interface_path + ['vif', vif]):
+ config.set(base_interface_path + ['vif', vif, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif'])
+ elif config.exists(base_interface_path + ['vif-s', vif]):
+ config.set(base_interface_path + ['vif-s', vif, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif-s'])
+ elif len(vlan) == 3:
+ # VIF-S interface with VIF-C subinterface
+ vif_s = vlan[1]
+ vif_c = vlan[2]
+ config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif-s'])
+ config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(['firewall', 'options'])
diff --git a/src/migration-scripts/firewall/6-to-7 b/src/migration-scripts/firewall/6-to-7
index 938044c6d..1afbc780b 100755..100644
--- a/src/migration-scripts/firewall/6-to-7
+++ b/src/migration-scripts/firewall/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T2199: Remove unavailable nodes due to XML/Python implementation using nftables
# monthdays: nftables does not have a monthdays equivalent
@@ -23,28 +22,11 @@
import re
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
max_len_description = 255
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
icmp_remove = ['any']
icmp_translations = {
@@ -107,216 +89,216 @@ icmpv6_translations = {
'unknown-option': [4, 2]
}
-v4_found = False
-v6_found = False
v4_groups = ["address-group", "network-group", "port-group"]
v6_groups = ["ipv6-address-group", "ipv6-network-group", "port-group"]
-translated_dict = {}
-if config.exists(base + ['group']):
- for group_type in config.list_nodes(base + ['group']):
- for group_name in config.list_nodes(base + ['group', group_type]):
- name_description = base + ['group', group_type, group_name, 'description']
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ v4_found = False
+ v6_found = False
+ translated_dict = {}
+
+ if config.exists(base + ['group']):
+ for group_type in config.list_nodes(base + ['group']):
+ for group_name in config.list_nodes(base + ['group', group_type]):
+ name_description = base + ['group', group_type, group_name, 'description']
+ if config.exists(name_description):
+ tmp = config.return_value(name_description)
+ config.set(name_description, value=tmp[:max_len_description])
+ if '+' in group_name:
+ replacement_string = "_"
+ if group_type in v4_groups and not v4_found:
+ v4_found = True
+ if group_type in v6_groups and not v6_found:
+ v6_found = True
+ new_group_name = group_name.replace('+', replacement_string)
+ while config.exists(base + ['group', group_type, new_group_name]):
+ replacement_string = replacement_string + "_"
+ new_group_name = group_name.replace('+', replacement_string)
+ translated_dict[group_name] = new_group_name
+ config.copy(base + ['group', group_type, group_name], base + ['group', group_type, new_group_name])
+ config.delete(base + ['group', group_type, group_name])
+
+ if config.exists(base + ['name']):
+ for name in config.list_nodes(base + ['name']):
+ name_description = base + ['name', name, 'description']
if config.exists(name_description):
tmp = config.return_value(name_description)
config.set(name_description, value=tmp[:max_len_description])
- if '+' in group_name:
- replacement_string = "_"
- if group_type in v4_groups and not v4_found:
- v4_found = True
- if group_type in v6_groups and not v6_found:
- v6_found = True
- new_group_name = group_name.replace('+', replacement_string)
- while config.exists(base + ['group', group_type, new_group_name]):
- replacement_string = replacement_string + "_"
- new_group_name = group_name.replace('+', replacement_string)
- translated_dict[group_name] = new_group_name
- config.copy(base + ['group', group_type, group_name], base + ['group', group_type, new_group_name])
- config.delete(base + ['group', group_type, group_name])
-
-if config.exists(base + ['name']):
- for name in config.list_nodes(base + ['name']):
- name_description = base + ['name', name, 'description']
- if config.exists(name_description):
- tmp = config.return_value(name_description)
- config.set(name_description, value=tmp[:max_len_description])
-
- if not config.exists(base + ['name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['name', name, 'rule']):
- rule_description = base + ['name', name, 'rule', rule, 'description']
- if config.exists(rule_description):
- tmp = config.return_value(rule_description)
- config.set(rule_description, value=tmp[:max_len_description])
-
- rule_recent = base + ['name', name, 'rule', rule, 'recent']
- rule_time = base + ['name', name, 'rule', rule, 'time']
- rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags']
- rule_icmp = base + ['name', name, 'rule', rule, 'icmp']
-
- if config.exists(rule_time + ['monthdays']):
- config.delete(rule_time + ['monthdays'])
-
- if config.exists(rule_time + ['utc']):
- config.delete(rule_time + ['utc'])
-
- if config.exists(rule_recent + ['time']):
- tmp = int(config.return_value(rule_recent + ['time']))
- unit = 'minute'
- if tmp > 600:
- unit = 'hour'
- elif tmp < 10:
- unit = 'second'
- config.set(rule_recent + ['time'], value=unit)
-
- if config.exists(rule_tcp_flags):
- tmp = config.return_value(rule_tcp_flags)
- config.delete(rule_tcp_flags)
- for flag in tmp.split(","):
- if flag[0] == '!':
- config.set(rule_tcp_flags + ['not', flag[1:].lower()])
- else:
- config.set(rule_tcp_flags + [flag.lower()])
-
- if config.exists(rule_icmp + ['type-name']):
- tmp = config.return_value(rule_icmp + ['type-name'])
- if tmp in icmp_remove:
- config.delete(rule_icmp + ['type-name'])
- elif tmp in icmp_translations:
- translate = icmp_translations[tmp]
- if isinstance(translate, str):
- config.set(rule_icmp + ['type-name'], value=translate)
- elif isinstance(translate, list):
+
+ if not config.exists(base + ['name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['name', name, 'rule']):
+ rule_description = base + ['name', name, 'rule', rule, 'description']
+ if config.exists(rule_description):
+ tmp = config.return_value(rule_description)
+ config.set(rule_description, value=tmp[:max_len_description])
+
+ rule_recent = base + ['name', name, 'rule', rule, 'recent']
+ rule_time = base + ['name', name, 'rule', rule, 'time']
+ rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags']
+ rule_icmp = base + ['name', name, 'rule', rule, 'icmp']
+
+ if config.exists(rule_time + ['monthdays']):
+ config.delete(rule_time + ['monthdays'])
+
+ if config.exists(rule_time + ['utc']):
+ config.delete(rule_time + ['utc'])
+
+ if config.exists(rule_recent + ['time']):
+ tmp = int(config.return_value(rule_recent + ['time']))
+ unit = 'minute'
+ if tmp > 600:
+ unit = 'hour'
+ elif tmp < 10:
+ unit = 'second'
+ config.set(rule_recent + ['time'], value=unit)
+
+ if config.exists(rule_tcp_flags):
+ tmp = config.return_value(rule_tcp_flags)
+ config.delete(rule_tcp_flags)
+ for flag in tmp.split(","):
+ if flag[0] == '!':
+ config.set(rule_tcp_flags + ['not', flag[1:].lower()])
+ else:
+ config.set(rule_tcp_flags + [flag.lower()])
+
+ if config.exists(rule_icmp + ['type-name']):
+ tmp = config.return_value(rule_icmp + ['type-name'])
+ if tmp in icmp_remove:
config.delete(rule_icmp + ['type-name'])
- config.set(rule_icmp + ['type'], value=translate[0])
- config.set(rule_icmp + ['code'], value=translate[1])
-
- for direction in ['destination', 'source']:
- if config.exists(base + ['name', name, 'rule', rule, direction]):
- if config.exists(base + ['name', name, 'rule', rule, direction, 'group']) and v4_found:
- for group_type in config.list_nodes(base + ['name', name, 'rule', rule, direction, 'group']):
- group_name = config.return_value(base + ['name', name, 'rule', rule, direction, 'group', group_type])
- if '+' in group_name:
- if group_name[0] == "!":
- new_group_name = "!" + translated_dict[group_name[1:]]
- else:
- new_group_name = translated_dict[group_name]
- config.set(base + ['name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
-
- pg_base = base + ['name', name, 'rule', rule, direction, 'group', 'port-group']
- proto_base = base + ['name', name, 'rule', rule, 'protocol']
- if config.exists(pg_base) and not config.exists(proto_base):
- config.set(proto_base, value='tcp_udp')
-
- if '+' in name:
- replacement_string = "_"
- new_name = name.replace('+', replacement_string)
- while config.exists(base + ['name', new_name]):
- replacement_string = replacement_string + "_"
+ elif tmp in icmp_translations:
+ translate = icmp_translations[tmp]
+ if isinstance(translate, str):
+ config.set(rule_icmp + ['type-name'], value=translate)
+ elif isinstance(translate, list):
+ config.delete(rule_icmp + ['type-name'])
+ config.set(rule_icmp + ['type'], value=translate[0])
+ config.set(rule_icmp + ['code'], value=translate[1])
+
+ for direction in ['destination', 'source']:
+ if config.exists(base + ['name', name, 'rule', rule, direction]):
+ if config.exists(base + ['name', name, 'rule', rule, direction, 'group']) and v4_found:
+ for group_type in config.list_nodes(base + ['name', name, 'rule', rule, direction, 'group']):
+ group_name = config.return_value(base + ['name', name, 'rule', rule, direction, 'group', group_type])
+ if '+' in group_name:
+ if group_name[0] == "!":
+ new_group_name = "!" + translated_dict[group_name[1:]]
+ else:
+ new_group_name = translated_dict[group_name]
+ config.set(base + ['name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
+
+ pg_base = base + ['name', name, 'rule', rule, direction, 'group', 'port-group']
+ proto_base = base + ['name', name, 'rule', rule, 'protocol']
+ if config.exists(pg_base) and not config.exists(proto_base):
+ config.set(proto_base, value='tcp_udp')
+
+ if '+' in name:
+ replacement_string = "_"
new_name = name.replace('+', replacement_string)
- config.copy(base + ['name', name], base + ['name', new_name])
- config.delete(base + ['name', name])
-
-if config.exists(base + ['ipv6-name']):
- for name in config.list_nodes(base + ['ipv6-name']):
- name_description = base + ['ipv6-name', name, 'description']
- if config.exists(name_description):
- tmp = config.return_value(name_description)
- config.set(name_description, value=tmp[:max_len_description])
-
- if not config.exists(base + ['ipv6-name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
- rule_description = base + ['ipv6-name', name, 'rule', rule, 'description']
- if config.exists(rule_description):
- tmp = config.return_value(rule_description)
- config.set(rule_description, value=tmp[:max_len_description])
-
- rule_recent = base + ['ipv6-name', name, 'rule', rule, 'recent']
- rule_time = base + ['ipv6-name', name, 'rule', rule, 'time']
- rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags']
- rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6']
-
- if config.exists(rule_time + ['monthdays']):
- config.delete(rule_time + ['monthdays'])
-
- if config.exists(rule_time + ['utc']):
- config.delete(rule_time + ['utc'])
-
- if config.exists(rule_recent + ['time']):
- tmp = int(config.return_value(rule_recent + ['time']))
- unit = 'minute'
- if tmp > 600:
- unit = 'hour'
- elif tmp < 10:
- unit = 'second'
- config.set(rule_recent + ['time'], value=unit)
-
- if config.exists(rule_tcp_flags):
- tmp = config.return_value(rule_tcp_flags)
- config.delete(rule_tcp_flags)
- for flag in tmp.split(","):
- if flag[0] == '!':
- config.set(rule_tcp_flags + ['not', flag[1:].lower()])
- else:
- config.set(rule_tcp_flags + [flag.lower()])
-
- if config.exists(base + ['ipv6-name', name, 'rule', rule, 'protocol']):
- tmp = config.return_value(base + ['ipv6-name', name, 'rule', rule, 'protocol'])
- if tmp == 'icmpv6':
- config.set(base + ['ipv6-name', name, 'rule', rule, 'protocol'], value='ipv6-icmp')
-
- if config.exists(rule_icmp + ['type']):
- tmp = config.return_value(rule_icmp + ['type'])
- type_code_match = re.match(r'^(\d+)(?:/(\d+))?$', tmp)
-
- if type_code_match:
- config.set(rule_icmp + ['type'], value=type_code_match[1])
- if type_code_match[2]:
- config.set(rule_icmp + ['code'], value=type_code_match[2])
- elif tmp in icmpv6_remove:
- config.delete(rule_icmp + ['type'])
- elif tmp in icmpv6_translations:
- translate = icmpv6_translations[tmp]
- if isinstance(translate, str):
+ while config.exists(base + ['name', new_name]):
+ replacement_string = replacement_string + "_"
+ new_name = name.replace('+', replacement_string)
+ config.copy(base + ['name', name], base + ['name', new_name])
+ config.delete(base + ['name', name])
+
+ if config.exists(base + ['ipv6-name']):
+ for name in config.list_nodes(base + ['ipv6-name']):
+ name_description = base + ['ipv6-name', name, 'description']
+ if config.exists(name_description):
+ tmp = config.return_value(name_description)
+ config.set(name_description, value=tmp[:max_len_description])
+
+ if not config.exists(base + ['ipv6-name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
+ rule_description = base + ['ipv6-name', name, 'rule', rule, 'description']
+ if config.exists(rule_description):
+ tmp = config.return_value(rule_description)
+ config.set(rule_description, value=tmp[:max_len_description])
+
+ rule_recent = base + ['ipv6-name', name, 'rule', rule, 'recent']
+ rule_time = base + ['ipv6-name', name, 'rule', rule, 'time']
+ rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags']
+ rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6']
+
+ if config.exists(rule_time + ['monthdays']):
+ config.delete(rule_time + ['monthdays'])
+
+ if config.exists(rule_time + ['utc']):
+ config.delete(rule_time + ['utc'])
+
+ if config.exists(rule_recent + ['time']):
+ tmp = int(config.return_value(rule_recent + ['time']))
+ unit = 'minute'
+ if tmp > 600:
+ unit = 'hour'
+ elif tmp < 10:
+ unit = 'second'
+ config.set(rule_recent + ['time'], value=unit)
+
+ if config.exists(rule_tcp_flags):
+ tmp = config.return_value(rule_tcp_flags)
+ config.delete(rule_tcp_flags)
+ for flag in tmp.split(","):
+ if flag[0] == '!':
+ config.set(rule_tcp_flags + ['not', flag[1:].lower()])
+ else:
+ config.set(rule_tcp_flags + [flag.lower()])
+
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, 'protocol']):
+ tmp = config.return_value(base + ['ipv6-name', name, 'rule', rule, 'protocol'])
+ if tmp == 'icmpv6':
+ config.set(base + ['ipv6-name', name, 'rule', rule, 'protocol'], value='ipv6-icmp')
+
+ if config.exists(rule_icmp + ['type']):
+ tmp = config.return_value(rule_icmp + ['type'])
+ type_code_match = re.match(r'^(\d+)(?:/(\d+))?$', tmp)
+
+ if type_code_match:
+ config.set(rule_icmp + ['type'], value=type_code_match[1])
+ if type_code_match[2]:
+ config.set(rule_icmp + ['code'], value=type_code_match[2])
+ elif tmp in icmpv6_remove:
config.delete(rule_icmp + ['type'])
- config.set(rule_icmp + ['type-name'], value=translate)
- elif isinstance(translate, list):
- config.set(rule_icmp + ['type'], value=translate[0])
- config.set(rule_icmp + ['code'], value=translate[1])
- else:
- config.rename(rule_icmp + ['type'], 'type-name')
-
- for direction in ['destination', 'source']:
- if config.exists(base + ['ipv6-name', name, 'rule', rule, direction]):
- if config.exists(base + ['ipv6-name', name, 'rule', rule, direction, 'group']) and v6_found:
- for group_type in config.list_nodes(base + ['ipv6-name', name, 'rule', rule, direction, 'group']):
- group_name = config.return_value(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type])
- if '+' in group_name:
- if group_name[0] == "!":
- new_group_name = "!" + translated_dict[group_name[1:]]
- else:
- new_group_name = translated_dict[group_name]
- config.set(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
-
- pg_base = base + ['ipv6-name', name, 'rule', rule, direction, 'group', 'port-group']
- proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol']
- if config.exists(pg_base) and not config.exists(proto_base):
- config.set(proto_base, value='tcp_udp')
-
- if '+' in name:
- replacement_string = "_"
- new_name = name.replace('+', replacement_string)
- while config.exists(base + ['ipv6-name', new_name]):
- replacement_string = replacement_string + "_"
+ elif tmp in icmpv6_translations:
+ translate = icmpv6_translations[tmp]
+ if isinstance(translate, str):
+ config.delete(rule_icmp + ['type'])
+ config.set(rule_icmp + ['type-name'], value=translate)
+ elif isinstance(translate, list):
+ config.set(rule_icmp + ['type'], value=translate[0])
+ config.set(rule_icmp + ['code'], value=translate[1])
+ else:
+ config.rename(rule_icmp + ['type'], 'type-name')
+
+ for direction in ['destination', 'source']:
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, direction]):
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, direction, 'group']) and v6_found:
+ for group_type in config.list_nodes(base + ['ipv6-name', name, 'rule', rule, direction, 'group']):
+ group_name = config.return_value(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type])
+ if '+' in group_name:
+ if group_name[0] == "!":
+ new_group_name = "!" + translated_dict[group_name[1:]]
+ else:
+ new_group_name = translated_dict[group_name]
+ config.set(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
+
+ pg_base = base + ['ipv6-name', name, 'rule', rule, direction, 'group', 'port-group']
+ proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol']
+ if config.exists(pg_base) and not config.exists(proto_base):
+ config.set(proto_base, value='tcp_udp')
+
+ if '+' in name:
+ replacement_string = "_"
new_name = name.replace('+', replacement_string)
- config.copy(base + ['ipv6-name', name], base + ['ipv6-name', new_name])
- config.delete(base + ['ipv6-name', name])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ while config.exists(base + ['ipv6-name', new_name]):
+ replacement_string = replacement_string + "_"
+ new_name = name.replace('+', replacement_string)
+ config.copy(base + ['ipv6-name', name], base + ['ipv6-name', new_name])
+ config.delete(base + ['ipv6-name', name])
diff --git a/src/migration-scripts/firewall/7-to-8 b/src/migration-scripts/firewall/7-to-8
index 17af0f355..b8bcc52cc 100755..100644
--- a/src/migration-scripts/firewall/7-to-8
+++ b/src/migration-scripts/firewall/7-to-8
@@ -1,43 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T2199: Migrate interface firewall nodes to firewall interfaces <ifname> <direction> name/ipv6-name <name>
# T2199: Migrate zone-policy to firewall node
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
zone_base = ['zone-policy']
-config = ConfigTree(config_file)
-
-if not config.exists(base) and not config.exists(zone_base):
- # Nothing to do
- exit(0)
def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
if_path = ['interfaces', iftype, ifname]
@@ -63,39 +45,37 @@ def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
config.copy(if_path + ['firewall'], ['firewall', 'interface', ifname_full])
config.delete(if_path + ['firewall'])
-for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- migrate_interface(config, iftype, ifname)
-
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- migrate_interface(config, iftype, ifname, vif=vif)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- migrate_interface(config, iftype, ifname, vifs=vifs)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
-
-if config.exists(zone_base + ['zone']):
- config.set(['firewall', 'zone'])
- config.set_tag(['firewall', 'zone'])
-
- for zone in config.list_nodes(zone_base + ['zone']):
- if 'interface' in config.list_nodes(zone_base + ['zone', zone]):
- for iface in config.return_values(zone_base + ['zone', zone, 'interface']):
- if '+' in iface:
- config.delete_value(zone_base + ['zone', zone, 'interface'], value=iface)
- iface = iface.replace('+', '*')
- config.set(zone_base + ['zone', zone, 'interface'], value=iface, replace=False)
- config.copy(zone_base + ['zone', zone], ['firewall', 'zone', zone])
- config.delete(zone_base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base) and not config.exists(zone_base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ migrate_interface(config, iftype, ifname)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ migrate_interface(config, iftype, ifname, vif=vif)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ migrate_interface(config, iftype, ifname, vifs=vifs)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
+
+ if config.exists(zone_base + ['zone']):
+ config.set(['firewall', 'zone'])
+ config.set_tag(['firewall', 'zone'])
+
+ for zone in config.list_nodes(zone_base + ['zone']):
+ if 'interface' in config.list_nodes(zone_base + ['zone', zone]):
+ for iface in config.return_values(zone_base + ['zone', zone, 'interface']):
+ if '+' in iface:
+ config.delete_value(zone_base + ['zone', zone, 'interface'], value=iface)
+ iface = iface.replace('+', '*')
+ config.set(zone_base + ['zone', zone, 'interface'], value=iface, replace=False)
+ config.copy(zone_base + ['zone', zone], ['firewall', 'zone', zone])
+ config.delete(zone_base) \ No newline at end of file
diff --git a/src/migration-scripts/firewall/8-to-9 b/src/migration-scripts/firewall/8-to-9
index 6e019beb2..3c9e84662 100755..100644
--- a/src/migration-scripts/firewall/8-to-9
+++ b/src/migration-scripts/firewall/8-to-9
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4780: Add firewall interface group
# cli changes from:
@@ -20,69 +19,50 @@
# To
# set firewall [name | ipv6-name] <name> rule <number> [inbound-interface | outbound-interface] [interface-name | interface-group] <interface_name | interface_group>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['name']):
- for name in config.list_nodes(base + ['name']):
- if not config.exists(base + ['name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['name', name, 'rule']):
- rule_iiface = base + ['name', name, 'rule', rule, 'inbound-interface']
- rule_oiface = base + ['name', name, 'rule', rule, 'outbound-interface']
-
- if config.exists(rule_iiface):
- tmp = config.return_value(rule_iiface)
- config.delete(rule_iiface)
- config.set(rule_iiface + ['interface-name'], value=tmp)
-
- if config.exists(rule_oiface):
- tmp = config.return_value(rule_oiface)
- config.delete(rule_oiface)
- config.set(rule_oiface + ['interface-name'], value=tmp)
-
-
-if config.exists(base + ['ipv6-name']):
- for name in config.list_nodes(base + ['ipv6-name']):
- if not config.exists(base + ['ipv6-name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
- rule_iiface = base + ['ipv6-name', name, 'rule', rule, 'inbound-interface']
- rule_oiface = base + ['ipv6-name', name, 'rule', rule, 'outbound-interface']
-
- if config.exists(rule_iiface):
- tmp = config.return_value(rule_iiface)
- config.delete(rule_iiface)
- config.set(rule_iiface + ['interface-name'], value=tmp)
-
- if config.exists(rule_oiface):
- tmp = config.return_value(rule_oiface)
- config.delete(rule_oiface)
- config.set(rule_oiface + ['interface-name'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['name']):
+ for name in config.list_nodes(base + ['name']):
+ if not config.exists(base + ['name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['name', name, 'rule']):
+ rule_iiface = base + ['name', name, 'rule', rule, 'inbound-interface']
+ rule_oiface = base + ['name', name, 'rule', rule, 'outbound-interface']
+
+ if config.exists(rule_iiface):
+ tmp = config.return_value(rule_iiface)
+ config.delete(rule_iiface)
+ config.set(rule_iiface + ['interface-name'], value=tmp)
+
+ if config.exists(rule_oiface):
+ tmp = config.return_value(rule_oiface)
+ config.delete(rule_oiface)
+ config.set(rule_oiface + ['interface-name'], value=tmp)
+
+
+ if config.exists(base + ['ipv6-name']):
+ for name in config.list_nodes(base + ['ipv6-name']):
+ if not config.exists(base + ['ipv6-name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
+ rule_iiface = base + ['ipv6-name', name, 'rule', rule, 'inbound-interface']
+ rule_oiface = base + ['ipv6-name', name, 'rule', rule, 'outbound-interface']
+
+ if config.exists(rule_iiface):
+ tmp = config.return_value(rule_iiface)
+ config.delete(rule_iiface)
+ config.set(rule_iiface + ['interface-name'], value=tmp)
+
+ if config.exists(rule_oiface):
+ tmp = config.return_value(rule_oiface)
+ config.delete(rule_oiface)
+ config.set(rule_oiface + ['interface-name'], value=tmp)
diff --git a/src/migration-scripts/firewall/9-to-10 b/src/migration-scripts/firewall/9-to-10
index ce509a731..306a53a86 100755..100644
--- a/src/migration-scripts/firewall/9-to-10
+++ b/src/migration-scripts/firewall/9-to-10
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5050: Log options
# cli changes from:
@@ -20,58 +19,39 @@
# To
# set firewall [name | ipv6-name] <name> rule <number> log-options level <log_level>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['firewall']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['name']):
- for name in config.list_nodes(base + ['name']):
- if not config.exists(base + ['name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['name', name, 'rule']):
- log_options_base = base + ['name', name, 'rule', rule, 'log-options']
- rule_log_level = base + ['name', name, 'rule', rule, 'log-level']
-
- if config.exists(rule_log_level):
- tmp = config.return_value(rule_log_level)
- config.delete(rule_log_level)
- config.set(log_options_base + ['level'], value=tmp)
-
-if config.exists(base + ['ipv6-name']):
- for name in config.list_nodes(base + ['ipv6-name']):
- if not config.exists(base + ['ipv6-name', name, 'rule']):
- continue
-
- for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
- log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options']
- rule_log_level = base + ['ipv6-name', name, 'rule', rule, 'log-level']
-
- if config.exists(rule_log_level):
- tmp = config.return_value(rule_log_level)
- config.delete(rule_log_level)
- config.set(log_options_base + ['level'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['name']):
+ for name in config.list_nodes(base + ['name']):
+ if not config.exists(base + ['name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['name', name, 'rule']):
+ log_options_base = base + ['name', name, 'rule', rule, 'log-options']
+ rule_log_level = base + ['name', name, 'rule', rule, 'log-level']
+
+ if config.exists(rule_log_level):
+ tmp = config.return_value(rule_log_level)
+ config.delete(rule_log_level)
+ config.set(log_options_base + ['level'], value=tmp)
+
+ if config.exists(base + ['ipv6-name']):
+ for name in config.list_nodes(base + ['ipv6-name']):
+ if not config.exists(base + ['ipv6-name', name, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
+ log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options']
+ rule_log_level = base + ['ipv6-name', name, 'rule', rule, 'log-level']
+
+ if config.exists(rule_log_level):
+ tmp = config.return_value(rule_log_level)
+ config.delete(rule_log_level)
+ config.set(log_options_base + ['level'], value=tmp)
diff --git a/src/migration-scripts/flow-accounting/0-to-1 b/src/migration-scripts/flow-accounting/0-to-1
index 0f790fd9c..77670e3ef 100755..100644
--- a/src/migration-scripts/flow-accounting/0-to-1
+++ b/src/migration-scripts/flow-accounting/0-to-1
@@ -1,69 +1,51 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4099: flow-accounting: sync "source-ip" and "source-address" between netflow
# and sflow ion CLI
# T4105: flow-accounting: drop "sflow agent-address auto"
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'flow-accounting']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# T4099
-tmp = base + ['netflow', 'source-ip']
-if config.exists(tmp):
- config.rename(tmp, 'source-address')
-
-# T4105
-tmp = base + ['sflow', 'agent-address']
-if config.exists(tmp):
- value = config.return_value(tmp)
- if value == 'auto':
- # delete the "auto"
- config.delete(tmp)
-
- # 1) check if BGP router-id is set
- # 2) check if OSPF router-id is set
- # 3) check if OSPFv3 router-id is set
- router_id = None
- for protocol in ['bgp', 'ospf', 'ospfv3']:
- if config.exists(['protocols', protocol, 'parameters', 'router-id']):
- router_id = config.return_value(['protocols', protocol, 'parameters', 'router-id'])
- break
- if router_id:
- config.set(tmp, value=router_id)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # T4099
+ tmp = base + ['netflow', 'source-ip']
+ if config.exists(tmp):
+ config.rename(tmp, 'source-address')
+
+ # T4105
+ tmp = base + ['sflow', 'agent-address']
+ if config.exists(tmp):
+ value = config.return_value(tmp)
+ if value == 'auto':
+ # delete the "auto"
+ config.delete(tmp)
+
+ # 1) check if BGP router-id is set
+ # 2) check if OSPF router-id is set
+ # 3) check if OSPFv3 router-id is set
+ router_id = None
+ for protocol in ['bgp', 'ospf', 'ospfv3']:
+ if config.exists(['protocols', protocol, 'parameters', 'router-id']):
+ router_id = config.return_value(['protocols', protocol, 'parameters', 'router-id'])
+ break
+ if router_id:
+ config.set(tmp, value=router_id)
diff --git a/src/migration-scripts/https/0-to-1 b/src/migration-scripts/https/0-to-1
index 23809f5ad..52fe3f2ad 100755..100644
--- a/src/migration-scripts/https/0-to-1
+++ b/src/migration-scripts/https/0-to-1
@@ -1,42 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# * Move server block directives under 'virtual-host' tag node, instead of
# relying on 'listen-address' tag node
-import sys
-
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+old_base = ['service', 'https', 'listen-address']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
-old_base = ['service', 'https', 'listen-address']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-else:
new_base = ['service', 'https', 'virtual-host']
config.set(new_base)
config.set_tag(new_base)
@@ -60,10 +48,3 @@ else:
index += 1
config.delete(old_base)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/https/1-to-2 b/src/migration-scripts/https/1-to-2
index 1a2cdc1e7..dad7ac1f0 100755..100644
--- a/src/migration-scripts/https/1-to-2
+++ b/src/migration-scripts/https/1-to-2
@@ -1,42 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# * Move 'api virtual-host' list to 'api-restrict virtual-host' so it
# is owned by service_https.py
-import sys
-
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+old_base = ['service', 'https', 'api', 'virtual-host']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
-old_base = ['service', 'https', 'api', 'virtual-host']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-else:
new_base = ['service', 'https', 'api-restrict', 'virtual-host']
config.set(new_base)
@@ -45,10 +33,3 @@ else:
config.set(new_base, value=name, replace=False)
config.delete(old_base)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/https/2-to-3 b/src/migration-scripts/https/2-to-3
index 2beba6d2b..1125caebf 100755..100644
--- a/src/migration-scripts/https/2-to-3
+++ b/src/migration-scripts/https/2-to-3
@@ -1,23 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 signed certificate to use PKI
-import sys
-
from vyos.configtree import ConfigTree
from vyos.pki import create_certificate
from vyos.pki import create_certificate_request
@@ -25,23 +22,9 @@ from vyos.pki import create_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'https', 'certificates']
pki_base = ['pki']
-if not config.exists(base + ['system-generated-certificate']):
- sys.exit(0)
-
def wrapped_pem_to_config_value(pem):
out = []
for line in pem.strip().split("\n"):
@@ -50,37 +33,34 @@ def wrapped_pem_to_config_value(pem):
out.append(line)
return "".join(out)
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['system-generated-certificate']):
+ return
-valid_days = 365
-if config.exists(base + ['system-generated-certificate', 'lifetime']):
- valid_days = int(config.return_value(base + ['system-generated-certificate', 'lifetime']))
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
-key = create_private_key('rsa', 2048)
-subject = {'country': 'GB', 'state': 'N/A', 'locality': 'N/A', 'organization': 'VyOS', 'common_name': 'vyos'}
-cert_req = create_certificate_request(subject, key, ['vyos'])
-cert = create_certificate(cert_req, cert_req, key, valid_days)
+ valid_days = 365
+ if config.exists(base + ['system-generated-certificate', 'lifetime']):
+ valid_days = int(config.return_value(base + ['system-generated-certificate', 'lifetime']))
-if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', 'generated_https', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ key = create_private_key('rsa', 2048)
+ subject = {'country': 'GB', 'state': 'N/A', 'locality': 'N/A', 'organization': 'VyOS', 'common_name': 'vyos'}
+ cert_req = create_certificate_request(subject, key, ['vyos'])
+ cert = create_certificate(cert_req, cert_req, key, valid_days)
-if key:
- key_pem = encode_private_key(key)
- config.set(pki_base + ['certificate', 'generated_https', 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', 'generated_https', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
-if cert and key:
- config.set(base + ['certificate'], value='generated_https')
-else:
- print('Failed to migrate system-generated-certificate from https service')
+ if key:
+ key_pem = encode_private_key(key)
+ config.set(pki_base + ['certificate', 'generated_https', 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
-config.delete(base + ['system-generated-certificate'])
+ if cert and key:
+ config.set(base + ['certificate'], value='generated_https')
+ else:
+ print('Failed to migrate system-generated-certificate from https service')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(base + ['system-generated-certificate'])
diff --git a/src/migration-scripts/https/3-to-4 b/src/migration-scripts/https/3-to-4
index b3cfca201..c01236cc6 100755..100644
--- a/src/migration-scripts/https/3-to-4
+++ b/src/migration-scripts/https/3-to-4
@@ -1,53 +1,34 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4768 rename node 'gql' to 'graphql'.
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
old_base = ['service', 'https', 'api', 'gql']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-
new_base = ['service', 'https', 'api', 'graphql']
-config.set(new_base)
-nodes = config.list_nodes(old_base)
-for node in nodes:
- config.copy(old_base + [node], new_base + [node])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
+
+ config.set(new_base)
-config.delete(old_base)
+ nodes = config.list_nodes(old_base)
+ for node in nodes:
+ config.copy(old_base + [node], new_base + [node])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(old_base)
diff --git a/src/migration-scripts/https/4-to-5 b/src/migration-scripts/https/4-to-5
index 0dfb6ac19..0f1c7901f 100755..100644
--- a/src/migration-scripts/https/4-to-5
+++ b/src/migration-scripts/https/4-to-5
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5762: http: api: smoketests fail as they can not establish IPv6 connection
# to uvicorn backend server, always make the UNIX domain socket the
# default way of communication
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'https']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-# Delete "socket" CLI option - we always use UNIX domain sockets for
-# NGINX <-> API server communication
-if config.exists(base + ['api', 'socket']):
- config.delete(base + ['api', 'socket'])
-
-# There is no need for an API service port, as UNIX domain sockets
-# are used
-if config.exists(base + ['api', 'port']):
- config.delete(base + ['api', 'port'])
-
-# rename listen-port -> port ver virtual-host
-if config.exists(base + ['virtual-host']):
- for vhost in config.list_nodes(base + ['virtual-host']):
- if config.exists(base + ['virtual-host', vhost, 'listen-port']):
- config.rename(base + ['virtual-host', vhost, 'listen-port'], 'port')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Delete "socket" CLI option - we always use UNIX domain sockets for
+ # NGINX <-> API server communication
+ if config.exists(base + ['api', 'socket']):
+ config.delete(base + ['api', 'socket'])
+
+ # There is no need for an API service port, as UNIX domain sockets
+ # are used
+ if config.exists(base + ['api', 'port']):
+ config.delete(base + ['api', 'port'])
+
+ # rename listen-port -> port ver virtual-host
+ if config.exists(base + ['virtual-host']):
+ for vhost in config.list_nodes(base + ['virtual-host']):
+ if config.exists(base + ['virtual-host', vhost, 'listen-port']):
+ config.rename(base + ['virtual-host', vhost, 'listen-port'], 'port')
diff --git a/src/migration-scripts/https/5-to-6 b/src/migration-scripts/https/5-to-6
index 72e9e31f7..6ef6976b6 100755..100644
--- a/src/migration-scripts/https/5-to-6
+++ b/src/migration-scripts/https/5-to-6
@@ -1,25 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5886: Add support for ACME protocol (LetsEncrypt), migrate https certbot
# to new "pki certificate" CLI tree
# T5902: Remove virtual-host
import os
-import sys
from vyos.configtree import ConfigTree
from vyos.defaults import directories
@@ -27,81 +25,65 @@ from vyos.utils.process import cmd
vyos_certbot_dir = directories['certbot']
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'https']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
-if config.exists(base + ['certificates', 'certbot']):
- # both domain-name and email must be set on CLI - ensured by previous verify()
- domain_names = config.return_values(base + ['certificates', 'certbot', 'domain-name'])
- email = config.return_value(base + ['certificates', 'certbot', 'email'])
- config.delete(base + ['certificates', 'certbot'])
-
- # Set default certname based on domain-name
- cert_name = 'https-' + domain_names[0].split('.')[0]
- # Overwrite certname from previous certbot calls if available
- # We can not use python code like os.scandir due to filesystem permissions.
- # This must be run as root
- certbot_live = f'{vyos_certbot_dir}/live/' # we need the trailing /
- if os.path.exists(certbot_live):
- tmp = cmd(f'sudo find {certbot_live} -maxdepth 1 -type d')
- tmp = tmp.split() # tmp = ['/config/auth/letsencrypt/live', '/config/auth/letsencrypt/live/router.vyos.net']
- tmp.remove(certbot_live)
- cert_name = tmp[0].replace(certbot_live, '')
- config.set(['pki', 'certificate', cert_name, 'acme', 'email'], value=email)
- config.set_tag(['pki', 'certificate'])
- for domain in domain_names:
- config.set(['pki', 'certificate', cert_name, 'acme', 'domain-name'], value=domain, replace=False)
-
- # Update Webserver certificate
- config.set(base + ['certificates', 'certificate'], value=cert_name)
-
-if config.exists(base + ['virtual-host']):
- allow_client = []
- listen_port = []
- listen_address = []
- for virtual_host in config.list_nodes(base + ['virtual-host']):
- allow_path = base + ['virtual-host', virtual_host, 'allow-client', 'address']
- if config.exists(allow_path):
- tmp = config.return_values(allow_path)
- allow_client.extend(tmp)
-
- port_path = base + ['virtual-host', virtual_host, 'port']
- if config.exists(port_path):
- tmp = config.return_value(port_path)
- listen_port.append(tmp)
-
- listen_address_path = base + ['virtual-host', virtual_host, 'listen-address']
- if config.exists(listen_address_path):
- tmp = config.return_value(listen_address_path)
- listen_address.append(tmp)
-
- config.delete(base + ['virtual-host'])
- for client in allow_client:
- config.set(base + ['allow-client', 'address'], value=client, replace=False)
-
- # clear listen-address if "all" were specified
- if '*' in listen_address:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['certificates', 'certbot']):
+ # both domain-name and email must be set on CLI - ensured by previous verify()
+ domain_names = config.return_values(base + ['certificates', 'certbot', 'domain-name'])
+ email = config.return_value(base + ['certificates', 'certbot', 'email'])
+ config.delete(base + ['certificates', 'certbot'])
+
+ # Set default certname based on domain-name
+ cert_name = 'https-' + domain_names[0].split('.')[0]
+ # Overwrite certname from previous certbot calls if available
+ # We can not use python code like os.scandir due to filesystem permissions.
+ # This must be run as root
+ certbot_live = f'{vyos_certbot_dir}/live/' # we need the trailing /
+ if os.path.exists(certbot_live):
+ tmp = cmd(f'sudo find {certbot_live} -maxdepth 1 -type d')
+ tmp = tmp.split() # tmp = ['/config/auth/letsencrypt/live', '/config/auth/letsencrypt/live/router.vyos.net']
+ tmp.remove(certbot_live)
+ cert_name = tmp[0].replace(certbot_live, '')
+
+ config.set(['pki', 'certificate', cert_name, 'acme', 'email'], value=email)
+ config.set_tag(['pki', 'certificate'])
+ for domain in domain_names:
+ config.set(['pki', 'certificate', cert_name, 'acme', 'domain-name'], value=domain, replace=False)
+
+ # Update Webserver certificate
+ config.set(base + ['certificates', 'certificate'], value=cert_name)
+
+ if config.exists(base + ['virtual-host']):
+ allow_client = []
+ listen_port = []
listen_address = []
- for address in listen_address:
- config.set(base + ['listen-address'], value=address, replace=False)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ for virtual_host in config.list_nodes(base + ['virtual-host']):
+ allow_path = base + ['virtual-host', virtual_host, 'allow-client', 'address']
+ if config.exists(allow_path):
+ tmp = config.return_values(allow_path)
+ allow_client.extend(tmp)
+
+ port_path = base + ['virtual-host', virtual_host, 'port']
+ if config.exists(port_path):
+ tmp = config.return_value(port_path)
+ listen_port.append(tmp)
+
+ listen_address_path = base + ['virtual-host', virtual_host, 'listen-address']
+ if config.exists(listen_address_path):
+ tmp = config.return_value(listen_address_path)
+ listen_address.append(tmp)
+
+ config.delete(base + ['virtual-host'])
+ for client in allow_client:
+ config.set(base + ['allow-client', 'address'], value=client, replace=False)
+
+ # clear listen-address if "all" were specified
+ if '*' in listen_address:
+ listen_address = []
+ for address in listen_address:
+ config.set(base + ['listen-address'], value=address, replace=False)
diff --git a/src/migration-scripts/ids/0-to-1 b/src/migration-scripts/ids/0-to-1
index 8b7850a1a..1b963e839 100755..100644
--- a/src/migration-scripts/ids/0-to-1
+++ b/src/migration-scripts/ids/0-to-1
@@ -1,56 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
+# T4557: Migrate threshold and add new threshold types
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'ids', 'ddos-protection']
-config = ConfigTree(config_file)
-
-if not config.exists(base + ['threshold']):
- # Nothing to do
- exit(0)
-else:
- if config.exists(base + ['threshold', 'fps']):
- tmp = config.return_value(base + ['threshold', 'fps'])
- config.delete(base + ['threshold', 'fps'])
- config.set(base + ['threshold', 'general', 'fps'], value=tmp)
- if config.exists(base + ['threshold', 'mbps']):
- tmp = config.return_value(base + ['threshold', 'mbps'])
- config.delete(base + ['threshold', 'mbps'])
- config.set(base + ['threshold', 'general', 'mbps'], value=tmp)
- if config.exists(base + ['threshold', 'pps']):
- tmp = config.return_value(base + ['threshold', 'pps'])
- config.delete(base + ['threshold', 'pps'])
- config.set(base + ['threshold', 'general', 'pps'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base + ['threshold']):
+ # Nothing to do
+ return
+ else:
+ if config.exists(base + ['threshold', 'fps']):
+ tmp = config.return_value(base + ['threshold', 'fps'])
+ config.delete(base + ['threshold', 'fps'])
+ config.set(base + ['threshold', 'general', 'fps'], value=tmp)
+ if config.exists(base + ['threshold', 'mbps']):
+ tmp = config.return_value(base + ['threshold', 'mbps'])
+ config.delete(base + ['threshold', 'mbps'])
+ config.set(base + ['threshold', 'general', 'mbps'], value=tmp)
+ if config.exists(base + ['threshold', 'pps']):
+ tmp = config.return_value(base + ['threshold', 'pps'])
+ config.delete(base + ['threshold', 'pps'])
+ config.set(base + ['threshold', 'general', 'pps'], value=tmp)
diff --git a/src/migration-scripts/interfaces/0-to-1 b/src/migration-scripts/interfaces/0-to-1
index 25f6842eb..7c135e76e 100755..100644
--- a/src/migration-scripts/interfaces/0-to-1
+++ b/src/migration-scripts/interfaces/0-to-1
@@ -1,11 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Change syntax of bridge interface
# - move interface based bridge-group to actual bridge (de-nest)
# - make stp and igmp-snooping nodes valueless
# https://vyos.dev/T1556
-import sys
from vyos.configtree import ConfigTree
def migrate_bridge(config, tree, intf):
@@ -36,83 +48,66 @@ def migrate_bridge(config, tree, intf):
config.delete(tree_bridge)
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'bridge']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
- else:
- #
- # make stp and igmp-snooping nodes valueless
- #
- for br in config.list_nodes(base):
- # STP: check if enabled
- if config.exists(base + [br, 'stp']):
- stp_val = config.return_value(base + [br, 'stp'])
- # STP: delete node with old syntax
- config.delete(base + [br, 'stp'])
- # STP: set new node - if enabled
- if stp_val == "true":
- config.set(base + [br, 'stp'], value=None)
-
- # igmp-snooping: check if enabled
- if config.exists(base + [br, 'igmp-snooping', 'querier']):
- igmp_val = config.return_value(base + [br, 'igmp-snooping', 'querier'])
- # igmp-snooping: delete node with old syntax
- config.delete(base + [br, 'igmp-snooping', 'querier'])
- # igmp-snooping: set new node - if enabled
- if igmp_val == "enable":
- config.set(base + [br, 'igmp', 'querier'], value=None)
-
- #
- # move interface based bridge-group to actual bridge (de-nest)
- #
- bridge_types = ['bonding', 'ethernet', 'l2tpv3', 'openvpn', 'vxlan', 'wireless']
- for type in bridge_types:
- if not config.exists(['interfaces', type]):
- continue
-
- for interface in config.list_nodes(['interfaces', type]):
- # check if bridge-group exists
- bridge_group = ['interfaces', type, interface]
- if config.exists(bridge_group + ['bridge-group']):
- migrate_bridge(config, bridge_group, interface)
-
- # We also need to migrate VLAN interfaces
- vlan_base = ['interfaces', type, interface, 'vif']
- if config.exists(vlan_base):
- for vlan in config.list_nodes(vlan_base):
- intf = "{}.{}".format(interface, vlan)
- migrate_bridge(config, vlan_base + [vlan], intf)
-
- # And then we have service VLANs (vif-s) interfaces
- vlan_base = ['interfaces', type, interface, 'vif-s']
- if config.exists(vlan_base):
- for vif_s in config.list_nodes(vlan_base):
- intf = "{}.{}".format(interface, vif_s)
- migrate_bridge(config, vlan_base + [vif_s], intf)
-
- # Every service VLAN can have multiple customer VLANs (vif-c)
- vlan_c = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
- if config.exists(vlan_c):
- for vif_c in config.list_nodes(vlan_c):
- intf = "{}.{}.{}".format(interface, vif_s, vif_c)
- migrate_bridge(config, vlan_c + [vif_c], intf)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ return
+
+ #
+ # make stp and igmp-snooping nodes valueless
+ #
+ for br in config.list_nodes(base):
+ # STP: check if enabled
+ if config.exists(base + [br, 'stp']):
+ stp_val = config.return_value(base + [br, 'stp'])
+ # STP: delete node with old syntax
+ config.delete(base + [br, 'stp'])
+ # STP: set new node - if enabled
+ if stp_val == "true":
+ config.set(base + [br, 'stp'], value=None)
+
+ # igmp-snooping: check if enabled
+ if config.exists(base + [br, 'igmp-snooping', 'querier']):
+ igmp_val = config.return_value(base + [br, 'igmp-snooping', 'querier'])
+ # igmp-snooping: delete node with old syntax
+ config.delete(base + [br, 'igmp-snooping', 'querier'])
+ # igmp-snooping: set new node - if enabled
+ if igmp_val == "enable":
+ config.set(base + [br, 'igmp', 'querier'], value=None)
+
+ #
+ # move interface based bridge-group to actual bridge (de-nest)
+ #
+ bridge_types = ['bonding', 'ethernet', 'l2tpv3', 'openvpn', 'vxlan', 'wireless']
+ for type in bridge_types:
+ if not config.exists(['interfaces', type]):
+ continue
+
+ for interface in config.list_nodes(['interfaces', type]):
+ # check if bridge-group exists
+ bridge_group = ['interfaces', type, interface]
+ if config.exists(bridge_group + ['bridge-group']):
+ migrate_bridge(config, bridge_group, interface)
+
+ # We also need to migrate VLAN interfaces
+ vlan_base = ['interfaces', type, interface, 'vif']
+ if config.exists(vlan_base):
+ for vlan in config.list_nodes(vlan_base):
+ intf = "{}.{}".format(interface, vlan)
+ migrate_bridge(config, vlan_base + [vlan], intf)
+
+ # And then we have service VLANs (vif-s) interfaces
+ vlan_base = ['interfaces', type, interface, 'vif-s']
+ if config.exists(vlan_base):
+ for vif_s in config.list_nodes(vlan_base):
+ intf = "{}.{}".format(interface, vif_s)
+ migrate_bridge(config, vlan_base + [vif_s], intf)
+
+ # Every service VLAN can have multiple customer VLANs (vif-c)
+ vlan_c = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
+ if config.exists(vlan_c):
+ for vif_c in config.list_nodes(vlan_c):
+ intf = "{}.{}.{}".format(interface, vif_s, vif_c)
+ migrate_bridge(config, vlan_c + [vif_c], intf)
diff --git a/src/migration-scripts/interfaces/1-to-2 b/src/migration-scripts/interfaces/1-to-2
index c95623c2b..ebf02b028 100755..100644
--- a/src/migration-scripts/interfaces/1-to-2
+++ b/src/migration-scripts/interfaces/1-to-2
@@ -1,28 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Change syntax of bond interface
# - move interface based bond-group to actual bond (de-nest)
# https://vyos.dev/T1614
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['interfaces', 'bonding']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
#
# move interface based bond-group to actual bond (de-nest)
#
@@ -54,10 +57,3 @@ else:
#
# so we simply disable arp_interval by setting it to 0 and miimon will take care about the link
config.set(base + [bond, 'arp-monitor', 'interval'], value='0')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/10-to-11 b/src/migration-scripts/interfaces/10-to-11
index cafaa3fa4..8a562f2d0 100755..100644
--- a/src/migration-scripts/interfaces/10-to-11
+++ b/src/migration-scripts/interfaces/10-to-11
@@ -1,41 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 WWAN (wirelessmodem) serial interface from non persistent ttyUSB2 to
# a bus like name, e.g. "usb0b1.3p1.3"
import os
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
+base = ['interfaces', 'wirelessmodem']
- config = ConfigTree(config_file)
- base = ['interfaces', 'wirelessmodem']
+def migrate(config: ConfigTree) -> None:
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
for wwan in config.list_nodes(base):
if config.exists(base + [wwan, 'device']):
@@ -46,10 +36,3 @@ if __name__ == '__main__':
device_file = os.path.realpath(os.path.join(root, file))
if os.path.basename(device_file) == device:
config.set(base + [wwan, 'device'], value=file, replace=True)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/11-to-12 b/src/migration-scripts/interfaces/11-to-12
index e9eb7f939..132cecbb7 100755..100644
--- a/src/migration-scripts/interfaces/11-to-12
+++ b/src/migration-scripts/interfaces/11-to-12
@@ -1,37 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 'dhcpv6-options prefix-delegation' from single node to a new tag node
# 'dhcpv6-options pd 0'
# - delete 'sla-len' from CLI - value is calculated on demand
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for type in config.list_nodes(['interfaces']):
for interface in config.list_nodes(['interfaces', type]):
# cache current config tree
@@ -49,10 +37,3 @@ if __name__ == '__main__':
sla_config = new_base + [pd, 'interface', tmp, 'sla-len']
if config.exists(sla_config):
config.delete(sla_config)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/12-to-13 b/src/migration-scripts/interfaces/12-to-13
index ef1d93903..585deb898 100755..100644
--- a/src/migration-scripts/interfaces/12-to-13
+++ b/src/migration-scripts/interfaces/12-to-13
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T2903: Change vif-s ethertype from numeric number to literal
# - 0x88a8 -> 802.1ad
@@ -20,20 +19,9 @@
# - T2905: Change WWAN "ondemand" node to "connect-on-demand" to have identical
# CLI nodes for both types of dialer interfaces
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
#
# T2903
#
@@ -61,11 +49,3 @@ if __name__ == '__main__':
for interface in config.list_nodes(wwan_base):
if config.exists(wwan_base + [interface, 'ondemand']):
config.rename(wwan_base + [interface, 'ondemand'], 'connect-on-demand')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
diff --git a/src/migration-scripts/interfaces/13-to-14 b/src/migration-scripts/interfaces/13-to-14
index b20d8b4db..45d8e3b5f 100755..100644
--- a/src/migration-scripts/interfaces/13-to-14
+++ b/src/migration-scripts/interfaces/13-to-14
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3043: rename Wireless interface security mode 'both' to 'wpa+wpa2'
# T3043: move "system wifi-regulatory-domain" to indicidual wireless interface
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wireless']
+
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
country_code = ''
cc_cli = ['system', 'wifi-regulatory-domain']
@@ -50,10 +40,3 @@ if __name__ == '__main__':
if country_code:
config.set(base + [wifi, 'country-code'], value=country_code)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/14-to-15 b/src/migration-scripts/interfaces/14-to-15
index e21251f86..d45d59bba 100755..100644
--- a/src/migration-scripts/interfaces/14-to-15
+++ b/src/migration-scripts/interfaces/14-to-15
@@ -1,39 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3048: remove smp-affinity node from ethernet and use tuned instead
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'ethernet']
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
migrate = False
for interface in config.list_nodes(base):
@@ -47,10 +36,3 @@ if __name__ == '__main__':
if migrate:
config.set(['system', 'options', 'performance'], value='throughput')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/15-to-16 b/src/migration-scripts/interfaces/15-to-16
index ae3441b9f..c9abdb5f8 100755..100644
--- a/src/migration-scripts/interfaces/15-to-16
+++ b/src/migration-scripts/interfaces/15-to-16
@@ -1,48 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# remove pppoe "ipv6 enable" option
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'pppoe']
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
for interface in config.list_nodes(base):
ipv6_enable = base + [interface, 'ipv6', 'enable']
if config.exists(ipv6_enable):
config.delete(ipv6_enable)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/16-to-17 b/src/migration-scripts/interfaces/16-to-17
index 75f160686..7d241ac68 100755..100644
--- a/src/migration-scripts/interfaces/16-to-17
+++ b/src/migration-scripts/interfaces/16-to-17
@@ -1,40 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Command line migration of port mirroring
# https://vyos.dev/T3089
-import sys
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'ethernet']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
for interface in config.list_nodes(base):
mirror_old_base = base + [interface, 'mirror']
@@ -43,10 +31,3 @@ if __name__ == '__main__':
if config.exists(mirror_old_base):
config.delete(mirror_old_base)
config.set(mirror_old_base + ['ingress'],intf[0])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/17-to-18 b/src/migration-scripts/interfaces/17-to-18
index 51486ac37..f45695a88 100755..100644
--- a/src/migration-scripts/interfaces/17-to-18
+++ b/src/migration-scripts/interfaces/17-to-18
@@ -1,37 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3043: Move "system wifi-regulatory-domain" to indicidual wireless interface.
# Country Code will be migratred from upper to lower case.
# T3140: Relax ethernet interface offload-options
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
# T3140: Cleanup ethernet offload-options, remove on/off value and use
# valueless nodes instead.
eth_base = ['interfaces', 'ethernet']
@@ -62,10 +50,3 @@ if __name__ == '__main__':
if config.exists(ccode):
tmp = config.return_value(ccode)
config.set(ccode, value=tmp.lower(), replace=True)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19
index c3209f250..ae1a07adb 100755..100644
--- a/src/migration-scripts/interfaces/18-to-19
+++ b/src/migration-scripts/interfaces/18-to-19
@@ -1,24 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
import os
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
def replace_nat_interfaces(config, old, new):
@@ -40,21 +36,11 @@ def replace_nat_interfaces(config, old, new):
config.set(conf_rule + ['outbound-interface'], value=new)
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wirelessmodem']
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
new_base = ['interfaces', 'wwan']
config.set(new_base)
@@ -98,10 +84,3 @@ if __name__ == '__main__':
# the new wwan interface use regular IP addressing
config.set(new_base + [interface, 'address'], value='dhcp')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20
index 05abae898..7ee6302e2 100755..100644
--- a/src/migration-scripts/interfaces/19-to-20
+++ b/src/migration-scripts/interfaces/19-to-20
@@ -1,34 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for type in ['tunnel', 'l2tpv3']:
base = ['interfaces', type]
if not config.exists(base):
@@ -52,10 +39,3 @@ if __name__ == '__main__':
remote_ip_path = base + [interface, 'remote-ip']
if config.exists(remote_ip_path):
config.rename(remote_ip_path, 'remote')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/2-to-3 b/src/migration-scripts/interfaces/2-to-3
index 15c3bc8be..695dcbf7a 100755..100644
--- a/src/migration-scripts/interfaces/2-to-3
+++ b/src/migration-scripts/interfaces/2-to-3
@@ -1,28 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Change syntax of openvpn encryption settings
# - move cipher from encryption to encryption cipher
# https://vyos.dev/T1704
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['interfaces', 'openvpn']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+
+ if not config.exists(base):
+ # Nothing to do
+ return
#
# move cipher from "encryption" to "encryption cipher"
#
@@ -35,9 +38,3 @@ else:
config.delete(['interfaces', 'openvpn', intf, 'encryption'])
# Add new syntax to config
config.set(['interfaces', 'openvpn', intf, 'encryption', 'cipher'], value=cipher)
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/20-to-21 b/src/migration-scripts/interfaces/20-to-21
index 05a0c7237..0b6895177 100755..100644
--- a/src/migration-scripts/interfaces/20-to-21
+++ b/src/migration-scripts/interfaces/20-to-21
@@ -1,125 +1,107 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3619: mirror Linux Kernel defaults for ethernet offloading options into VyOS
# CLI. See https://vyos.dev/T3619#102254 for all the details.
# T3787: Remove deprecated UDP fragmentation offloading option
-from sys import argv
-
from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
from vyos.utils.network import interface_exists
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['interfaces', 'ethernet']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-
-for ifname in config.list_nodes(base):
- # Bail out early if interface vanished from system
- if not interface_exists(ifname):
- continue
-
- eth = Ethtool(ifname)
-
- # If GRO is enabled by the Kernel - we reflect this on the CLI. If GRO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'gro'])
- enabled, fixed = eth.get_generic_receive_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'gro'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'gro'])
-
- # If GSO is enabled by the Kernel - we reflect this on the CLI. If GSO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'gso'])
- enabled, fixed = eth.get_generic_segmentation_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'gso'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'gso'])
-
- # If LRO is enabled by the Kernel - we reflect this on the CLI. If LRO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'lro'])
- enabled, fixed = eth.get_large_receive_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'lro'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'lro'])
-
- # If SG is enabled by the Kernel - we reflect this on the CLI. If SG is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'sg'])
- enabled, fixed = eth.get_scatter_gather()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'sg'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'sg'])
-
- # If TSO is enabled by the Kernel - we reflect this on the CLI. If TSO is
- # enabled via CLI but not supported by the NIC - we remove it from the CLI
- configured = config.exists(base + [ifname, 'offload', 'tso'])
- enabled, fixed = eth.get_tcp_segmentation_offload()
- if configured and fixed:
- config.delete(base + [ifname, 'offload', 'tso'])
- elif enabled and not fixed:
- config.set(base + [ifname, 'offload', 'tso'])
-
- # Remove deprecated UDP fragmentation offloading option
- if config.exists(base + [ifname, 'offload', 'ufo']):
- config.delete(base + [ifname, 'offload', 'ufo'])
-
- # Also while processing the interface configuration, not all adapters support
- # changing the speed and duplex settings. If the desired speed and duplex
- # values do not work for the NIC driver, we change them back to the default
- # value of "auto" - which will be applied if the CLI node is deleted.
- speed_path = base + [ifname, 'speed']
- duplex_path = base + [ifname, 'duplex']
- # speed and duplex must always be set at the same time if not set to "auto"
- if config.exists(speed_path) and config.exists(duplex_path):
- speed = config.return_value(speed_path)
- duplex = config.return_value(duplex_path)
- if speed != 'auto' and duplex != 'auto':
- if not eth.check_speed_duplex(speed, duplex):
- config.delete(speed_path)
- config.delete(duplex_path)
-
- # Also while processing the interface configuration, not all adapters support
- # changing disabling flow-control - or change this setting. If disabling
- # flow-control is not supported by the NIC, we remove the setting from CLI
- flow_control_path = base + [ifname, 'disable-flow-control']
- if config.exists(flow_control_path):
- if not eth.check_flow_control():
- config.delete(flow_control_path)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ for ifname in config.list_nodes(base):
+ # Bail out early if interface vanished from system
+ if not interface_exists(ifname):
+ continue
+
+ eth = Ethtool(ifname)
+
+ # If GRO is enabled by the Kernel - we reflect this on the CLI. If GRO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'gro'])
+ enabled, fixed = eth.get_generic_receive_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'gro'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'gro'])
+
+ # If GSO is enabled by the Kernel - we reflect this on the CLI. If GSO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'gso'])
+ enabled, fixed = eth.get_generic_segmentation_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'gso'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'gso'])
+
+ # If LRO is enabled by the Kernel - we reflect this on the CLI. If LRO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'lro'])
+ enabled, fixed = eth.get_large_receive_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'lro'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'lro'])
+
+ # If SG is enabled by the Kernel - we reflect this on the CLI. If SG is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'sg'])
+ enabled, fixed = eth.get_scatter_gather()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'sg'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'sg'])
+
+ # If TSO is enabled by the Kernel - we reflect this on the CLI. If TSO is
+ # enabled via CLI but not supported by the NIC - we remove it from the CLI
+ configured = config.exists(base + [ifname, 'offload', 'tso'])
+ enabled, fixed = eth.get_tcp_segmentation_offload()
+ if configured and fixed:
+ config.delete(base + [ifname, 'offload', 'tso'])
+ elif enabled and not fixed:
+ config.set(base + [ifname, 'offload', 'tso'])
+
+ # Remove deprecated UDP fragmentation offloading option
+ if config.exists(base + [ifname, 'offload', 'ufo']):
+ config.delete(base + [ifname, 'offload', 'ufo'])
+
+ # Also while processing the interface configuration, not all adapters support
+ # changing the speed and duplex settings. If the desired speed and duplex
+ # values do not work for the NIC driver, we change them back to the default
+ # value of "auto" - which will be applied if the CLI node is deleted.
+ speed_path = base + [ifname, 'speed']
+ duplex_path = base + [ifname, 'duplex']
+ # speed and duplex must always be set at the same time if not set to "auto"
+ if config.exists(speed_path) and config.exists(duplex_path):
+ speed = config.return_value(speed_path)
+ duplex = config.return_value(duplex_path)
+ if speed != 'auto' and duplex != 'auto':
+ if not eth.check_speed_duplex(speed, duplex):
+ config.delete(speed_path)
+ config.delete(duplex_path)
+
+ # Also while processing the interface configuration, not all adapters support
+ # changing disabling flow-control - or change this setting. If disabling
+ # flow-control is not supported by the NIC, we remove the setting from CLI
+ flow_control_path = base + [ifname, 'disable-flow-control']
+ if config.exists(flow_control_path):
+ if not eth.check_flow_control():
+ config.delete(flow_control_path)
diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22
index 1838eb1c0..046eb10c6 100755..100644
--- a/src/migration-scripts/interfaces/21-to-22
+++ b/src/migration-scripts/interfaces/21-to-22
@@ -1,46 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-base = ['interfaces', 'tunnel']
-
-if not config.exists(base):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ base = ['interfaces', 'tunnel']
-for interface in config.list_nodes(base):
- path = base + [interface, 'dhcp-interface']
- if config.exists(path):
- tmp = config.return_value(path)
- config.delete(path)
- config.set(base + [interface, 'source-interface'], value=tmp)
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for interface in config.list_nodes(base):
+ path = base + [interface, 'dhcp-interface']
+ if config.exists(path):
+ tmp = config.return_value(path)
+ config.delete(path)
+ config.set(base + [interface, 'source-interface'], value=tmp)
diff --git a/src/migration-scripts/interfaces/22-to-23 b/src/migration-scripts/interfaces/22-to-23
index 04e023e77..31f7fa2ff 100755..100644
--- a/src/migration-scripts/interfaces/22-to-23
+++ b/src/migration-scripts/interfaces/22-to-23
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# Deletes Wireguard peers if they have the same public key as the router has.
-import sys
+
from vyos.configtree import ConfigTree
from vyos.utils.network import is_wireguard_key_pair
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wireguard']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
+
for interface in config.list_nodes(base):
if not config.exists(base + [interface, 'private-key']):
continue
@@ -48,10 +38,3 @@ if __name__ == '__main__':
if not config.exists(peer_base + ['disable']) \
and is_wireguard_key_pair(private_key, peer_public_key):
config.set(peer_base + ['disable'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/23-to-24 b/src/migration-scripts/interfaces/23-to-24
index 8b21fce51..b72ceee49 100755..100644
--- a/src/migration-scripts/interfaces/23-to-24
+++ b/src/migration-scripts/interfaces/23-to-24
@@ -1,21 +1,18 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
def migrate_ospf(config, path, interface):
@@ -74,17 +71,7 @@ def migrate_ripng(config, path, interface):
if len(config.list_nodes(path[:-1])) == 0:
config.delete(path[:-1])
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
#
# Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0"
#
@@ -136,10 +123,3 @@ if __name__ == '__main__':
migrate_ripng(config, vif_s_ipv6_base, ifname)
migrate_ospf(config, vif_s_ip_base, ifname)
migrate_ospfv3(config, vif_s_ipv6_base, ifname)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25
index 8fd79ecc6..9f8cc80ec 100755..100644
--- a/src/migration-scripts/interfaces/24-to-25
+++ b/src/migration-scripts/interfaces/24-to-25
@@ -1,41 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported
# having a VTI interface in the CLI but no IPSec configuration - drop VTI
# configuration if this is the case for VyOS 1.4
-import sys
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'vti']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
for interface in config.list_nodes(base):
@@ -51,10 +39,3 @@ if __name__ == '__main__':
break
if not found:
config.delete(base + [interface])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26
index 9aa6ea5e3..7a4032d10 100755..100644
--- a/src/migration-scripts/interfaces/25-to-26
+++ b/src/migration-scripts/interfaces/25-to-26
@@ -1,24 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 Wireguard to store keys in CLI
# Migrate EAPoL to PKI configuration
import os
-import sys
from vyos.configtree import ConfigTree
from vyos.pki import CERT_BEGIN
@@ -53,335 +51,318 @@ def read_file_for_pki(config_auth_path):
return output
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
AUTH_DIR = '/config/auth'
pki_base = ['pki']
-# OpenVPN
-base = ['interfaces', 'openvpn']
+def migrate(config: ConfigTree) -> None:
+ # OpenVPN
+ base = ['interfaces', 'openvpn']
+
+ if config.exists(base):
+ for interface in config.list_nodes(base):
+ x509_base = base + [interface, 'tls']
+ pki_name = f'openvpn_{interface}'
+
+ if config.exists(base + [interface, 'shared-secret-key-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'shared-secret-key-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_shared'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate shared-secret-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'shared-secret-key-file'])
+
+ if not config.exists(base + [interface, 'tls']):
+ continue
+
+ if config.exists(base + [interface, 'tls', 'auth-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'tls', 'auth-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_auth'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate auth-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'tls', 'auth-file'])
+
+ if config.exists(base + [interface, 'tls', 'crypt-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'tls', 'crypt-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_crypt'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate crypt-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'tls', 'crypt-file'])
+
+ ca_certs = {}
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ certs_str = f.read()
+ certs_data = certs_str.split(CERT_BEGIN)
+ index = 1
+ for cert_data in certs_data[1:]:
+ cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False)
+
+ if cert:
+ ca_certs[f'{pki_name}_{index}'] = cert
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False)
+ else:
+ print(f'Failed to migrate CA certificate on openvpn interface {interface}')
+
+ index += 1
+ else:
+ print(f'Failed to migrate CA certificate on openvpn interface {interface}')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['crl-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ crl_file = config.return_value(x509_base + ['crl-file'])
+ crl_path = os.path.join(AUTH_DIR, crl_file)
+ crl = None
+ crl_ca_name = None
+
+ if os.path.isfile(crl_path):
+ if not os.access(crl_path, os.R_OK):
+ run(f'sudo chmod 644 {crl_path}')
+
+ with open(crl_path, 'r') as f:
+ crl_data = f.read()
+ crl = load_crl(crl_data, wrap_tags=False)
+
+ for ca_name, ca_cert in ca_certs.items():
+ if verify_crl(crl, ca_cert):
+ crl_ca_name = ca_name
+ break
+
+ if crl and crl_ca_name:
+ crl_pem = encode_certificate(crl)
+ config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ else:
+ print(f'Failed to migrate CRL on openvpn interface {interface}')
+
+ config.delete(x509_base + ['crl-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on openvpn interface {interface}')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on openvpn interface {interface}')
+
+ config.delete(x509_base + ['key-file'])
+
+ if config.exists(x509_base + ['dh-file']):
+ if not config.exists(pki_base + ['dh']):
+ config.set(pki_base + ['dh'])
+ config.set_tag(pki_base + ['dh'])
+
+ dh_file = config.return_value(x509_base + ['dh-file'])
+ dh_path = os.path.join(AUTH_DIR, dh_file)
+ dh = None
+
+ if os.path.isfile(dh_path):
+ if not os.access(dh_path, os.R_OK):
+ run(f'sudo chmod 644 {dh_path}')
+
+ with open(dh_path, 'r') as f:
+ dh_data = f.read()
+ dh = load_dh_parameters(dh_data, wrap_tags=False)
+
+ if dh:
+ dh_pem = encode_dh_parameters(dh)
+ config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
+ config.set(x509_base + ['dh-params'], value=pki_name)
+ else:
+ print(f'Failed to migrate DH parameters on openvpn interface {interface}')
+
+ config.delete(x509_base + ['dh-file'])
+
+ # Wireguard
+ base = ['interfaces', 'wireguard']
+
+ if config.exists(base):
+ for interface in config.list_nodes(base):
+ private_key_path = base + [interface, 'private-key']
+
+ key_file = 'default'
+ if config.exists(private_key_path):
+ key_file = config.return_value(private_key_path)
+
+ full_key_path = f'/config/auth/wireguard/{key_file}/private.key'
+
+ if not os.path.exists(full_key_path):
+ print(f'Could not find wireguard private key for migration on interface "{interface}"')
+ continue
+
+ with open(full_key_path, 'r') as f:
+ key_data = f.read().strip()
+ config.set(private_key_path, value=key_data)
+
+ for peer in config.list_nodes(base + [interface, 'peer']):
+ config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key')
+
+ # Ethernet EAPoL
+ base = ['interfaces', 'ethernet']
+
+ if config.exists(base):
+ for interface in config.list_nodes(base):
+ if not config.exists(base + [interface, 'eapol']):
+ continue
+
+ x509_base = base + [interface, 'eapol']
+ pki_name = f'eapol_{interface}'
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on eapol config for interface {interface}')
+
+ config.delete(x509_base + ['ca-cert-file'])
-if config.exists(base):
- for interface in config.list_nodes(base):
- x509_base = base + [interface, 'tls']
- pki_name = f'openvpn_{interface}'
+ if config.exists(x509_base + ['cert-file']):
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
- if config.exists(base + [interface, 'shared-secret-key-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
- key_file = config.return_value(base + [interface, 'shared-secret-key-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_shared'
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate shared-secret-key on openvpn interface {interface}')
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
- config.delete(base + [interface, 'shared-secret-key-file'])
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on eapol config for interface {interface}')
- if not config.exists(base + [interface, 'tls']):
- continue
+ config.delete(x509_base + ['cert-file'])
- if config.exists(base + [interface, 'tls', 'auth-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
-
- key_file = config.return_value(base + [interface, 'tls', 'auth-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_auth'
-
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate auth-key on openvpn interface {interface}')
-
- config.delete(base + [interface, 'tls', 'auth-file'])
-
- if config.exists(base + [interface, 'tls', 'crypt-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
-
- key_file = config.return_value(base + [interface, 'tls', 'crypt-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_crypt'
-
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate crypt-key on openvpn interface {interface}')
-
- config.delete(base + [interface, 'tls', 'crypt-file'])
-
- ca_certs = {}
-
- if config.exists(x509_base + ['ca-cert-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- certs_str = f.read()
- certs_data = certs_str.split(CERT_BEGIN)
- index = 1
- for cert_data in certs_data[1:]:
- cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False)
-
- if cert:
- ca_certs[f'{pki_name}_{index}'] = cert
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False)
- else:
- print(f'Failed to migrate CA certificate on openvpn interface {interface}')
-
- index += 1
- else:
- print(f'Failed to migrate CA certificate on openvpn interface {interface}')
-
- config.delete(x509_base + ['ca-cert-file'])
-
- if config.exists(x509_base + ['crl-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- crl_file = config.return_value(x509_base + ['crl-file'])
- crl_path = os.path.join(AUTH_DIR, crl_file)
- crl = None
- crl_ca_name = None
-
- if os.path.isfile(crl_path):
- if not os.access(crl_path, os.R_OK):
- run(f'sudo chmod 644 {crl_path}')
-
- with open(crl_path, 'r') as f:
- crl_data = f.read()
- crl = load_crl(crl_data, wrap_tags=False)
-
- for ca_name, ca_cert in ca_certs.items():
- if verify_crl(crl, ca_cert):
- crl_ca_name = ca_name
- break
-
- if crl and crl_ca_name:
- crl_pem = encode_certificate(crl)
- config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
- else:
- print(f'Failed to migrate CRL on openvpn interface {interface}')
-
- config.delete(x509_base + ['crl-file'])
-
- if config.exists(x509_base + ['cert-file']):
- if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on openvpn interface {interface}')
-
- config.delete(x509_base + ['cert-file'])
-
- if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on openvpn interface {interface}')
-
- config.delete(x509_base + ['key-file'])
-
- if config.exists(x509_base + ['dh-file']):
- if not config.exists(pki_base + ['dh']):
- config.set(pki_base + ['dh'])
- config.set_tag(pki_base + ['dh'])
-
- dh_file = config.return_value(x509_base + ['dh-file'])
- dh_path = os.path.join(AUTH_DIR, dh_file)
- dh = None
-
- if os.path.isfile(dh_path):
- if not os.access(dh_path, os.R_OK):
- run(f'sudo chmod 644 {dh_path}')
-
- with open(dh_path, 'r') as f:
- dh_data = f.read()
- dh = load_dh_parameters(dh_data, wrap_tags=False)
-
- if dh:
- dh_pem = encode_dh_parameters(dh)
- config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
- config.set(x509_base + ['dh-params'], value=pki_name)
- else:
- print(f'Failed to migrate DH parameters on openvpn interface {interface}')
-
- config.delete(x509_base + ['dh-file'])
-
-# Wireguard
-base = ['interfaces', 'wireguard']
-
-if config.exists(base):
- for interface in config.list_nodes(base):
- private_key_path = base + [interface, 'private-key']
-
- key_file = 'default'
- if config.exists(private_key_path):
- key_file = config.return_value(private_key_path)
-
- full_key_path = f'/config/auth/wireguard/{key_file}/private.key'
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
- if not os.path.exists(full_key_path):
- print(f'Could not find wireguard private key for migration on interface "{interface}"')
- continue
-
- with open(full_key_path, 'r') as f:
- key_data = f.read().strip()
- config.set(private_key_path, value=key_data)
-
- for peer in config.list_nodes(base + [interface, 'peer']):
- config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key')
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-# Ethernet EAPoL
-base = ['interfaces', 'ethernet']
-
-if config.exists(base):
- for interface in config.list_nodes(base):
- if not config.exists(base + [interface, 'eapol']):
- continue
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on eapol config for interface {interface}')
- x509_base = base + [interface, 'eapol']
- pki_name = f'eapol_{interface}'
-
- if config.exists(x509_base + ['ca-cert-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on eapol config for interface {interface}')
-
- config.delete(x509_base + ['ca-cert-file'])
-
- if config.exists(x509_base + ['cert-file']):
- if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on eapol config for interface {interface}')
-
- config.delete(x509_base + ['cert-file'])
-
- if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on eapol config for interface {interface}')
-
- config.delete(x509_base + ['key-file'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(x509_base + ['key-file'])
diff --git a/src/migration-scripts/interfaces/26-to-27 b/src/migration-scripts/interfaces/26-to-27
index 429ab650f..3f58de02c 100755..100644
--- a/src/migration-scripts/interfaces/26-to-27
+++ b/src/migration-scripts/interfaces/26-to-27
@@ -1,52 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4384: pppoe: replace default-route CLI option with common CLI nodes already
# present for DHCP
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-base = ['interfaces', 'pppoe']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-
-for ifname in config.list_nodes(base):
- tmp_config = base + [ifname, 'default-route']
- if config.exists(tmp_config):
- # Retrieve current config value
- value = config.return_value(tmp_config)
- # Delete old Config node
- config.delete(tmp_config)
- if value == 'none':
- config.set(base + [ifname, 'no-default-route'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ base = ['interfaces', 'pppoe']
+
+ if not config.exists(base):
+ return
+
+ for ifname in config.list_nodes(base):
+ tmp_config = base + [ifname, 'default-route']
+ if config.exists(tmp_config):
+ # Retrieve current config value
+ value = config.return_value(tmp_config)
+ # Delete old Config node
+ config.delete(tmp_config)
+ if value == 'none':
+ config.set(base + [ifname, 'no-default-route'])
diff --git a/src/migration-scripts/interfaces/27-to-28 b/src/migration-scripts/interfaces/27-to-28
index 9f5e93b5f..eb9363e39 100755..100644
--- a/src/migration-scripts/interfaces/27-to-28
+++ b/src/migration-scripts/interfaces/27-to-28
@@ -1,48 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4995: pppoe, wwan, sstpc-client rename "authentication user" CLI node
# to "authentication username"
-from sys import argv
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-for type in ['pppoe', 'sstpc-client', 'wwam']:
- base = ['interfaces', type]
- if not config.exists(base):
- continue
- for interface in config.list_nodes(base):
- auth_base = base + [interface, 'authentication', 'user']
- if config.exists(auth_base):
- config.rename(auth_base, 'username')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ for type in ['pppoe', 'sstpc-client', 'wwam']:
+ base = ['interfaces', type]
+ if not config.exists(base):
+ continue
+ for interface in config.list_nodes(base):
+ auth_base = base + [interface, 'authentication', 'user']
+ if config.exists(auth_base):
+ config.rename(auth_base, 'username')
diff --git a/src/migration-scripts/interfaces/28-to-29 b/src/migration-scripts/interfaces/28-to-29
index 0437977dc..886d49e2c 100755..100644
--- a/src/migration-scripts/interfaces/28-to-29
+++ b/src/migration-scripts/interfaces/28-to-29
@@ -1,52 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5034: tunnel: rename "multicast enable" CLI node to "enable-multicast"
# valueless node.
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['interfaces', 'tunnel']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-
-for ifname in config.list_nodes(base):
- multicast_base = base + [ifname, 'multicast']
- if config.exists(multicast_base):
- tmp = config.return_value(multicast_base)
- print(tmp)
- # Delete old Config node
- config.delete(multicast_base)
- if tmp == 'enable':
- config.set(base + [ifname, 'enable-multicast'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ for ifname in config.list_nodes(base):
+ multicast_base = base + [ifname, 'multicast']
+ if config.exists(multicast_base):
+ tmp = config.return_value(multicast_base)
+ print(tmp)
+ # Delete old Config node
+ config.delete(multicast_base)
+ if tmp == 'enable':
+ config.set(base + [ifname, 'enable-multicast'])
diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30
index 80aad1d44..7b32d871e 100755..100644
--- a/src/migration-scripts/interfaces/29-to-30
+++ b/src/migration-scripts/interfaces/29-to-30
@@ -1,47 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5286: remove XDP support in favour of VPP
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
supports_xdp = ['bonding', 'ethernet']
-config = ConfigTree(config_file)
-
-for if_type in supports_xdp:
- base = ['interfaces', if_type]
- if not config.exists(base):
- continue
- for interface in config.list_nodes(base):
- if_base = base + [interface]
- if config.exists(if_base + ['xdp']):
- config.delete(if_base + ['xdp'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ for if_type in supports_xdp:
+ base = ['interfaces', if_type]
+ if not config.exists(base):
+ continue
+ for interface in config.list_nodes(base):
+ if_base = base + [interface]
+ if config.exists(if_base + ['xdp']):
+ config.delete(if_base + ['xdp'])
diff --git a/src/migration-scripts/interfaces/3-to-4 b/src/migration-scripts/interfaces/3-to-4
index c7fd7d01d..4e56200e1 100755..100644
--- a/src/migration-scripts/interfaces/3-to-4
+++ b/src/migration-scripts/interfaces/3-to-4
@@ -1,27 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Change syntax of wireless interfaces
# Migrate boolean nodes to valueless
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['interfaces', 'wireless']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
for wifi in config.list_nodes(base):
# as converting a node to bool is always the same, we can script it
to_bool_nodes = ['capabilities ht 40MHz-incapable',
@@ -88,10 +91,3 @@ else:
# delete old radius-server nodes
config.delete(base + [wifi, 'security', 'wpa', 'radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/30-to-31 b/src/migration-scripts/interfaces/30-to-31
index 894106ef4..7e509dd86 100755..100644
--- a/src/migration-scripts/interfaces/30-to-31
+++ b/src/migration-scripts/interfaces/30-to-31
@@ -1,71 +1,56 @@
#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-# Deletes Wireguard peers if they have the same public key as the router has.
+# 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/>.
+
+# T5254: Fixed changing ethernet when it is a bond member
import json
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import EthernetIf
from vyos.ifconfig import BondIf
from vyos.utils.dict import dict_to_paths_values
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['interfaces', 'bonding']
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
- base = ['interfaces', 'bonding']
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for bond in config.list_nodes(base):
- member_base = base + [bond, 'member', 'interface']
- if config.exists(member_base):
- for interface in config.return_values(member_base):
- if_base = ['interfaces', 'ethernet', interface]
- if config.exists(if_base):
- config_ethernet = json.loads(config.get_subtree(if_base).to_json())
- eth_dict_paths = dict_to_paths_values(config_ethernet)
- for option_path, option_value in eth_dict_paths.items():
- # If option is allowed for changing then continue
- converted_path = option_path.replace('-','_')
- if converted_path in EthernetIf.get_bond_member_allowed_options():
- continue
- # if option is inherited from bond then continue
- if converted_path in BondIf.get_inherit_bond_options():
- continue
- option_path_list = option_path.split('.')
- config.delete(if_base + option_path_list)
- del option_path_list[-1]
- # delete empty node from config
- while len(option_path_list) > 0:
- if config.list_nodes(if_base + option_path_list):
- break
+ for bond in config.list_nodes(base):
+ member_base = base + [bond, 'member', 'interface']
+ if config.exists(member_base):
+ for interface in config.return_values(member_base):
+ if_base = ['interfaces', 'ethernet', interface]
+ if config.exists(if_base):
+ config_ethernet = json.loads(config.get_subtree(if_base).to_json())
+ eth_dict_paths = dict_to_paths_values(config_ethernet)
+ for option_path, option_value in eth_dict_paths.items():
+ # If option is allowed for changing then continue
+ converted_path = option_path.replace('-','_')
+ if converted_path in EthernetIf.get_bond_member_allowed_options():
+ continue
+ # if option is inherited from bond then continue
+ if converted_path in BondIf.get_inherit_bond_options():
+ continue
+ option_path_list = option_path.split('.')
config.delete(if_base + option_path_list)
del option_path_list[-1]
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # delete empty node from config
+ while len(option_path_list) > 0:
+ if config.list_nodes(if_base + option_path_list):
+ break
+ config.delete(if_base + option_path_list)
+ del option_path_list[-1]
diff --git a/src/migration-scripts/interfaces/31-to-32 b/src/migration-scripts/interfaces/31-to-32
index 0fc27b70a..24077ed24 100755..100644
--- a/src/migration-scripts/interfaces/31-to-32
+++ b/src/migration-scripts/interfaces/31-to-32
@@ -1,55 +1,37 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# T5671: change port to IANA assigned default port
# T5759: change default MTU 1450 -> 1500
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['interfaces', 'vxlan']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for vxlan in config.list_nodes(base):
- if config.exists(base + [vxlan, 'external']):
- config.delete(base + [vxlan, 'external'])
- config.set(base + [vxlan, 'parameters', 'external'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- if not config.exists(base + [vxlan, 'port']):
- config.set(base + [vxlan, 'port'], value='8472')
+ for vxlan in config.list_nodes(base):
+ if config.exists(base + [vxlan, 'external']):
+ config.delete(base + [vxlan, 'external'])
+ config.set(base + [vxlan, 'parameters', 'external'])
- if not config.exists(base + [vxlan, 'mtu']):
- config.set(base + [vxlan, 'mtu'], value='1450')
+ if not config.exists(base + [vxlan, 'port']):
+ config.set(base + [vxlan, 'port'], value='8472')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if not config.exists(base + [vxlan, 'mtu']):
+ config.set(base + [vxlan, 'mtu'], value='1450')
diff --git a/src/migration-scripts/interfaces/32-to-33 b/src/migration-scripts/interfaces/32-to-33
index caf588474..c7b1c5b36 100755..100644
--- a/src/migration-scripts/interfaces/32-to-33
+++ b/src/migration-scripts/interfaces/32-to-33
@@ -16,42 +16,25 @@
#
# T6318: WiFi country-code should be set system-wide instead of per-device
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['interfaces', 'wireless']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-installed = False
-for interface in config.list_nodes(base):
- cc_path = base + [interface, 'country-code']
- if config.exists(cc_path):
- tmp = config.return_value(cc_path)
- config.delete(cc_path)
-
- # There can be only ONE wireless country-code per device, everything
- # else makes no sense as a WIFI router can not operate in two
- # different countries
- if not installed:
- config.set(['system', 'wireless', 'country-code'], value=tmp)
- installed = True
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ installed = False
+ for interface in config.list_nodes(base):
+ cc_path = base + [interface, 'country-code']
+ if config.exists(cc_path):
+ tmp = config.return_value(cc_path)
+ config.delete(cc_path)
+
+ # There can be only ONE wireless country-code per device, everything
+ # else makes no sense as a WIFI router can not operate in two
+ # different countries
+ if not installed:
+ config.set(['system', 'wireless', 'country-code'], value=tmp)
+ installed = True
diff --git a/src/migration-scripts/interfaces/4-to-5 b/src/migration-scripts/interfaces/4-to-5
index 68d81e846..93fa7c393 100755..100644
--- a/src/migration-scripts/interfaces/4-to-5
+++ b/src/migration-scripts/interfaces/4-to-5
@@ -1,9 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# De-nest PPPoE interfaces
# Migrate boolean nodes to valueless
-import sys
from vyos.configtree import ConfigTree
def migrate_dialer(config, tree, intf):
@@ -55,18 +67,7 @@ def migrate_dialer(config, tree, intf):
if config.exists(ipv6_ra):
config.delete(ipv6_ra)
-
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = sys.argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
pppoe_links = ['bonding', 'ethernet']
for link_type in pppoe_links:
@@ -103,10 +104,3 @@ if __name__ == '__main__':
# Add interface description that this is required for PPPoE
if not config.exists(vlan_if + ['description']):
config.set(vlan_if + ['description'], value='PPPoE link interface')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/5-to-6 b/src/migration-scripts/interfaces/5-to-6
index 9d9a49c2d..44c32ba63 100755..100644
--- a/src/migration-scripts/interfaces/5-to-6
+++ b/src/migration-scripts/interfaces/5-to-6
@@ -1,23 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 IPv6 router advertisments from a nested interface configuration to
# a denested "service router-advert"
-import sys
from vyos.configtree import ConfigTree
def copy_rtradv(c, old_base, interface):
@@ -97,17 +95,7 @@ def copy_rtradv(c, old_base, interface):
if tmp == '0':
c.delete(new_base + ['link-mtu'])
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = sys.argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
# list all individual interface types like dummy, ethernet and so on
for if_type in config.list_nodes(['interfaces']):
base_if_type = ['interfaces', if_type]
@@ -124,10 +112,3 @@ if __name__ == '__main__':
old_base = vif_base + [vif, 'ipv6', 'router-advert']
vlan_name = f'{intf}.{vif}'
copy_rtradv(config, old_base, vlan_name)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/6-to-7 b/src/migration-scripts/interfaces/6-to-7
index 49b853d90..e60121eec 100755..100644
--- a/src/migration-scripts/interfaces/6-to-7
+++ b/src/migration-scripts/interfaces/6-to-7
@@ -1,39 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Remove network provider name from CLI and rather use provider APN from CLI
-import sys
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = sys.argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wirelessmodem']
if not config.exists(base):
# Nothing to do
- sys.exit(0)
+ return
# list all individual wwan/wireless modem interfaces
for i in config.list_nodes(base):
@@ -54,10 +43,3 @@ if __name__ == '__main__':
# uniform CLI experience
if config.exists(iface + ['no-dns']):
config.rename(iface + ['no-dns'], 'no-peer-dns')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/interfaces/7-to-8 b/src/migration-scripts/interfaces/7-to-8
index 9343a48a8..43ae320ab 100755..100644
--- a/src/migration-scripts/interfaces/7-to-8
+++ b/src/migration-scripts/interfaces/7-to-8
@@ -1,25 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Split WireGuard endpoint into address / port nodes to make use of common
# validators
import os
-from sys import exit, argv
from vyos.configtree import ConfigTree
from vyos.utils.permission import chown
from vyos.utils.permission import chmod_750
@@ -36,23 +34,14 @@ def migrate_default_keys():
os.rename(f'{kdir}/private.key', f'{location}/private.key')
os.rename(f'{kdir}/public.key', f'{location}/public.key')
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
base = ['interfaces', 'wireguard']
migrate_default_keys()
if not config.exists(base):
# Nothing to do
- exit(0)
+ return
# list all individual wireguard interface isntance
for i in config.list_nodes(base):
@@ -68,10 +57,3 @@ if __name__ == '__main__':
# setup new nodes
config.set(base_peer + ['address'], value=address)
config.set(base_peer + ['port'], value=port)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/8-to-9 b/src/migration-scripts/interfaces/8-to-9
index 960962be7..bae1b34fa 100755..100644
--- a/src/migration-scripts/interfaces/8-to-9
+++ b/src/migration-scripts/interfaces/8-to-9
@@ -1,37 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 link nodes to source-interface for the following interface types:
# - vxlan
# - pseudo-ethernet
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for if_type in ['vxlan', 'pseudo-ethernet']:
base = ['interfaces', if_type]
if not config.exists(base):
@@ -43,10 +31,3 @@ if __name__ == '__main__':
iface = base + [i]
if config.exists(iface + ['link']):
config.rename(iface + ['link'], 'source-interface')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/interfaces/9-to-10 b/src/migration-scripts/interfaces/9-to-10
index e9b8cb784..cdfd7d432 100755..100644
--- a/src/migration-scripts/interfaces/9-to-10
+++ b/src/migration-scripts/interfaces/9-to-10
@@ -1,38 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 CLI node 'dhcpv6-options delgate' to 'dhcpv6-options prefix-delegation
# interface'
# - rename CLI node 'interface-id' for prefix-delegation to 'address' as it
# represents the local interface IPv6 address assigned by DHCPv6-PD
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
for intf_type in config.list_nodes(['interfaces']):
for intf in config.list_nodes(['interfaces', intf_type]):
# cache current config tree
@@ -55,10 +43,3 @@ if __name__ == '__main__':
# delete old noe
config.delete(base_path)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/ipoe-server/1-to-2 b/src/migration-scripts/ipoe-server/1-to-2
index 6a7111541..034eacb10 100755..100644
--- a/src/migration-scripts/ipoe-server/1-to-2
+++ b/src/migration-scripts/ipoe-server/1-to-2
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T4703: merge vlan-id and vlan-range to vlan CLI node
# L2|L3 -> l2|l3
@@ -28,87 +27,68 @@
# 1. The first pool that contains next-poll.
# 2. Else, the first pool in the list
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'ipoe-server']
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['authentication', 'interface']):
- for interface in config.list_nodes(base + ['authentication', 'interface']):
- config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac')
-
- mac_base = base + ['authentication', 'interface', interface, 'mac']
- for mac in config.list_nodes(mac_base):
- vlan_config = mac_base + [mac, 'vlan-id']
- if config.exists(vlan_config):
- config.rename(vlan_config, 'vlan')
-
-for interface in config.list_nodes(base + ['interface']):
- base_path = base + ['interface', interface]
- for vlan in ['vlan-id', 'vlan-range']:
- if config.exists(base_path + [vlan]):
- for tmp in config.return_values(base_path + [vlan]):
- config.set(base_path + ['vlan'], value=tmp, replace=False)
- config.delete(base_path + [vlan])
-
- if config.exists(base_path + ['network-mode']):
- tmp = config.return_value(base_path + ['network-mode'])
- config.delete(base_path + ['network-mode'])
- # Change L2|L3 to lower case l2|l3
- config.set(base_path + ['mode'], value=tmp.lower())
-
-pool_base = base + ['client-ip-pool']
-if config.exists(pool_base):
- default_pool = ''
- gateway = ''
-
- #named pool migration
- namedpools_base = pool_base + ['name']
-
- for pool_name in config.list_nodes(namedpools_base):
- pool_path = namedpools_base + [pool_name]
- if config.exists(pool_path + ['subnet']):
- subnet = config.return_value(pool_path + ['subnet'])
- config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
- # Get netmask from subnet
- mask = subnet.split("/")[1]
- if config.exists(pool_path + ['next-pool']):
- next_pool = config.return_value(pool_path + ['next-pool'])
- config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
- if not default_pool:
- default_pool = pool_name
- if config.exists(pool_path + ['gateway-address']) and mask:
- gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}'
- config.set(base + ['gateway-address'], value=gateway, replace=False)
-
- if not default_pool and config.list_nodes(namedpools_base):
- default_pool = config.list_nodes(namedpools_base)[0]
-
- config.delete(namedpools_base)
-
- if default_pool:
- config.set(base + ['default-pool'], value=default_pool)
- # format as tag node
- config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if config.exists(base + ['authentication', 'interface']):
+ for interface in config.list_nodes(base + ['authentication', 'interface']):
+ config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac')
+
+ mac_base = base + ['authentication', 'interface', interface, 'mac']
+ for mac in config.list_nodes(mac_base):
+ vlan_config = mac_base + [mac, 'vlan-id']
+ if config.exists(vlan_config):
+ config.rename(vlan_config, 'vlan')
+
+ for interface in config.list_nodes(base + ['interface']):
+ base_path = base + ['interface', interface]
+ for vlan in ['vlan-id', 'vlan-range']:
+ if config.exists(base_path + [vlan]):
+ for tmp in config.return_values(base_path + [vlan]):
+ config.set(base_path + ['vlan'], value=tmp, replace=False)
+ config.delete(base_path + [vlan])
+
+ if config.exists(base_path + ['network-mode']):
+ tmp = config.return_value(base_path + ['network-mode'])
+ config.delete(base_path + ['network-mode'])
+ # Change L2|L3 to lower case l2|l3
+ config.set(base_path + ['mode'], value=tmp.lower())
+
+ pool_base = base + ['client-ip-pool']
+ if config.exists(pool_base):
+ default_pool = ''
+ gateway = ''
+
+ #named pool migration
+ namedpools_base = pool_base + ['name']
+
+ for pool_name in config.list_nodes(namedpools_base):
+ pool_path = namedpools_base + [pool_name]
+ if config.exists(pool_path + ['subnet']):
+ subnet = config.return_value(pool_path + ['subnet'])
+ config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
+ # Get netmask from subnet
+ mask = subnet.split("/")[1]
+ if config.exists(pool_path + ['next-pool']):
+ next_pool = config.return_value(pool_path + ['next-pool'])
+ config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
+ if not default_pool:
+ default_pool = pool_name
+ if config.exists(pool_path + ['gateway-address']) and mask:
+ gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}'
+ config.set(base + ['gateway-address'], value=gateway, replace=False)
+
+ if not default_pool and config.list_nodes(namedpools_base):
+ default_pool = config.list_nodes(namedpools_base)[0]
+
+ config.delete(namedpools_base)
+
+ if default_pool:
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/ipoe-server/2-to-3 b/src/migration-scripts/ipoe-server/2-to-3
index 0909315a8..dcd15e595 100755..100644
--- a/src/migration-scripts/ipoe-server/2-to-3
+++ b/src/migration-scripts/ipoe-server/2-to-3
@@ -1,58 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['service', 'ipoe-server']
+pool_base = base + ['client-ipv6-pool']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ if not config.exists(pool_base):
+ return
-config = ConfigTree(config_file)
-base = ['service', 'ipoe-server']
-pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
-
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/ipsec/10-to-11 b/src/migration-scripts/ipsec/10-to-11
index 509216267..6c4ccb553 100755..100644
--- a/src/migration-scripts/ipsec/10-to-11
+++ b/src/migration-scripts/ipsec/10-to-11
@@ -1,83 +1,63 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
+# T4916: Rewrite IPsec peer authentication and psk migration
from vyos.configtree import ConfigTree
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# PEER changes
-if config.exists(base + ['site-to-site', 'peer']):
- for peer in config.list_nodes(base + ['site-to-site', 'peer']):
- peer_base = base + ['site-to-site', 'peer', peer]
-
- # replace: 'ipsec site-to-site peer <tag> authentication pre-shared-secret xxx'
- # => 'ipsec authentication psk <tag> secret xxx'
- if config.exists(peer_base + ['authentication', 'pre-shared-secret']):
- tmp = config.return_value(peer_base + ['authentication', 'pre-shared-secret'])
- config.delete(peer_base + ['authentication', 'pre-shared-secret'])
- config.set(base + ['authentication', 'psk', peer, 'secret'], value=tmp)
- # format as tag node to avoid loading problems
- config.set_tag(base + ['authentication', 'psk'])
-
- # Get id's from peers for "ipsec auth psk <tag> id xxx"
- if config.exists(peer_base + ['authentication', 'local-id']):
- local_id = config.return_value(peer_base + ['authentication', 'local-id'])
- config.set(base + ['authentication', 'psk', peer, 'id'], value=local_id, replace=False)
- if config.exists(peer_base + ['authentication', 'remote-id']):
- remote_id = config.return_value(peer_base + ['authentication', 'remote-id'])
- config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_id, replace=False)
-
- if config.exists(peer_base + ['local-address']):
- tmp = config.return_value(peer_base + ['local-address'])
- config.set(base + ['authentication', 'psk', peer, 'id'], value=tmp, replace=False)
- if config.exists(peer_base + ['remote-address']):
- tmp = config.return_values(peer_base + ['remote-address'])
- if tmp:
- for remote_addr in tmp:
- if remote_addr == 'any':
- remote_addr = '%any'
- config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_addr, replace=False)
-
- # get DHCP peer interface as psk dhcp-interface
- if config.exists(peer_base + ['dhcp-interface']):
- tmp = config.return_value(peer_base + ['dhcp-interface'])
- config.set(base + ['authentication', 'psk', peer, 'dhcp-interface'], value=tmp)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # PEER changes
+ if config.exists(base + ['site-to-site', 'peer']):
+ for peer in config.list_nodes(base + ['site-to-site', 'peer']):
+ peer_base = base + ['site-to-site', 'peer', peer]
+
+ # replace: 'ipsec site-to-site peer <tag> authentication pre-shared-secret xxx'
+ # => 'ipsec authentication psk <tag> secret xxx'
+ if config.exists(peer_base + ['authentication', 'pre-shared-secret']):
+ tmp = config.return_value(peer_base + ['authentication', 'pre-shared-secret'])
+ config.delete(peer_base + ['authentication', 'pre-shared-secret'])
+ config.set(base + ['authentication', 'psk', peer, 'secret'], value=tmp)
+ # format as tag node to avoid loading problems
+ config.set_tag(base + ['authentication', 'psk'])
+
+ # Get id's from peers for "ipsec auth psk <tag> id xxx"
+ if config.exists(peer_base + ['authentication', 'local-id']):
+ local_id = config.return_value(peer_base + ['authentication', 'local-id'])
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=local_id, replace=False)
+ if config.exists(peer_base + ['authentication', 'remote-id']):
+ remote_id = config.return_value(peer_base + ['authentication', 'remote-id'])
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_id, replace=False)
+
+ if config.exists(peer_base + ['local-address']):
+ tmp = config.return_value(peer_base + ['local-address'])
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=tmp, replace=False)
+ if config.exists(peer_base + ['remote-address']):
+ tmp = config.return_values(peer_base + ['remote-address'])
+ if tmp:
+ for remote_addr in tmp:
+ if remote_addr == 'any':
+ remote_addr = '%any'
+ config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_addr, replace=False)
+
+ # get DHCP peer interface as psk dhcp-interface
+ if config.exists(peer_base + ['dhcp-interface']):
+ tmp = config.return_value(peer_base + ['dhcp-interface'])
+ config.set(base + ['authentication', 'psk', peer, 'dhcp-interface'], value=tmp)
diff --git a/src/migration-scripts/ipsec/11-to-12 b/src/migration-scripts/ipsec/11-to-12
index 4833d0876..fc65f1825 100755..100644
--- a/src/migration-scripts/ipsec/11-to-12
+++ b/src/migration-scripts/ipsec/11-to-12
@@ -1,51 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Remove legacy ipsec.conf and ipsec.secrets - Not supported with swanctl
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-if config.exists(base + ['include-ipsec-conf']):
- config.delete(base + ['include-ipsec-conf'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['include-ipsec-secrets']):
- config.delete(base + ['include-ipsec-secrets'])
+ if config.exists(base + ['include-ipsec-conf']):
+ config.delete(base + ['include-ipsec-conf'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base + ['include-ipsec-secrets']):
+ config.delete(base + ['include-ipsec-secrets'])
diff --git a/src/migration-scripts/ipsec/12-to-13 b/src/migration-scripts/ipsec/12-to-13
index d90c70314..ffe766eb2 100755..100644
--- a/src/migration-scripts/ipsec/12-to-13
+++ b/src/migration-scripts/ipsec/12-to-13
@@ -1,43 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Changed value of dead-peer-detection.action from hold to trap
# Changed value of close-action from hold to trap and from restart to start
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec', 'ike-group']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
for ike_group in config.list_nodes(base):
base_dpd_action = base + [ike_group, 'dead-peer-detection', 'action']
base_close_action = base + [ike_group, 'close-action']
@@ -48,10 +35,3 @@ else:
config.set(base_close_action, 'trap', replace=True)
if config.return_value(base_close_action) == 'restart':
config.set(base_close_action, 'start', replace=True)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
diff --git a/src/migration-scripts/ipsec/4-to-5 b/src/migration-scripts/ipsec/4-to-5
index 772d05787..a88a543d3 100755..100644
--- a/src/migration-scripts/ipsec/4-to-5
+++ b/src/migration-scripts/ipsec/4-to-5
@@ -1,47 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# log-modes have changed, keyword all to any
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-ctree = ConfigTree(config_file)
-
-if not ctree.exists(['vpn', 'ipsec', 'logging','log-modes']):
- # Nothing to do
- sys.exit(0)
-else:
- lmodes = ctree.return_values(['vpn', 'ipsec', 'logging','log-modes'])
- for mode in lmodes:
- if mode == 'all':
- ctree.set(['vpn', 'ipsec', 'logging','log-modes'], value='any', replace=True)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['vpn', 'ipsec', 'logging','log-modes']):
+ # Nothing to do
+ return
- try:
- open(file_name,'w').write(ctree.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ lmodes = config.return_values(['vpn', 'ipsec', 'logging','log-modes'])
+ for mode in lmodes:
+ if mode == 'all':
+ config.set(['vpn', 'ipsec', 'logging','log-modes'], value='any', replace=True)
diff --git a/src/migration-scripts/ipsec/5-to-6 b/src/migration-scripts/ipsec/5-to-6
index 7d7c777c6..373428d61 100755..100644
--- a/src/migration-scripts/ipsec/5-to-6
+++ b/src/migration-scripts/ipsec/5-to-6
@@ -1,93 +1,73 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Remove deprecated strongSwan options from VyOS CLI
# - vpn ipsec nat-traversal enable
# - vpn ipsec nat-networks allowed-network
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# Delete CLI nodes whose config options got removed by strongSwan
-for cli_node in ['nat-traversal', 'nat-networks']:
- if config.exists(base + [cli_node]):
- config.delete(base + [cli_node])
-
-# Remove options only valid in Openswan
-if config.exists(base + ['site-to-site', 'peer']):
- for peer in config.list_nodes(base + ['site-to-site', 'peer']):
- if not config.exists(base + ['site-to-site', 'peer', peer, 'tunnel']):
- continue
- for tunnel in config.list_nodes(base + ['site-to-site', 'peer', peer, 'tunnel']):
- # allow-public-networks - Sets a value in ipsec.conf that was only ever valid in Openswan on kernel 2.6
- nat_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-nat-networks']
- if config.exists(nat_networks):
- config.delete(nat_networks)
-
- # allow-nat-networks - Also sets a value only valid in Openswan
- public_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-public-networks']
- if config.exists(public_networks):
- config.delete(public_networks)
-
-# Rename "logging log-level" and "logging log-modes" to something more human friendly
-log = base + ['logging']
-if config.exists(log):
- config.rename(log, 'log')
- log = base + ['log']
-
-log_level = log + ['log-level']
-if config.exists(log_level):
- config.rename(log_level, 'level')
-
-log_mode = log + ['log-modes']
-if config.exists(log_mode):
- config.rename(log_mode, 'subsystem')
-
-# Rename "ipsec-interfaces interface" to "interface"
-base_interfaces = base + ['ipsec-interfaces', 'interface']
-if config.exists(base_interfaces):
- config.copy(base_interfaces, base + ['interface'])
- config.delete(base + ['ipsec-interfaces'])
-
-# Remove deprecated "auto-update" option
-tmp = base + ['auto-update']
-if config.exists(tmp):
- config.delete(tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Delete CLI nodes whose config options got removed by strongSwan
+ for cli_node in ['nat-traversal', 'nat-networks']:
+ if config.exists(base + [cli_node]):
+ config.delete(base + [cli_node])
+
+ # Remove options only valid in Openswan
+ if config.exists(base + ['site-to-site', 'peer']):
+ for peer in config.list_nodes(base + ['site-to-site', 'peer']):
+ if not config.exists(base + ['site-to-site', 'peer', peer, 'tunnel']):
+ continue
+ for tunnel in config.list_nodes(base + ['site-to-site', 'peer', peer, 'tunnel']):
+ # allow-public-networks - Sets a value in ipsec.conf that was only ever valid in Openswan on kernel 2.6
+ nat_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-nat-networks']
+ if config.exists(nat_networks):
+ config.delete(nat_networks)
+
+ # allow-nat-networks - Also sets a value only valid in Openswan
+ public_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-public-networks']
+ if config.exists(public_networks):
+ config.delete(public_networks)
+
+ # Rename "logging log-level" and "logging log-modes" to something more human friendly
+ log = base + ['logging']
+ if config.exists(log):
+ config.rename(log, 'log')
+ log = base + ['log']
+
+ log_level = log + ['log-level']
+ if config.exists(log_level):
+ config.rename(log_level, 'level')
+
+ log_mode = log + ['log-modes']
+ if config.exists(log_mode):
+ config.rename(log_mode, 'subsystem')
+
+ # Rename "ipsec-interfaces interface" to "interface"
+ base_interfaces = base + ['ipsec-interfaces', 'interface']
+ if config.exists(base_interfaces):
+ config.copy(base_interfaces, base + ['interface'])
+ config.delete(base + ['ipsec-interfaces'])
+
+ # Remove deprecated "auto-update" option
+ tmp = base + ['auto-update']
+ if config.exists(tmp):
+ config.delete(tmp)
diff --git a/src/migration-scripts/ipsec/6-to-7 b/src/migration-scripts/ipsec/6-to-7
index f8b6de560..5679477c0 100755..100644
--- a/src/migration-scripts/ipsec/6-to-7
+++ b/src/migration-scripts/ipsec/6-to-7
@@ -1,26 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 /config/auth certificates and keys into PKI configuration
import os
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_crl
@@ -29,27 +25,27 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
pki_base = ['pki']
ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
-config = ConfigTree(config_file)
-changes_made = False
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if config.exists(ipsec_site_base):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(ipsec_site_base):
+ return
+
+ migration_needed = False
+ for peer in config.list_nodes(ipsec_site_base):
+ if config.exists(ipsec_site_base + [peer, 'authentication', 'x509']):
+ migration_needed = True
+ break
+
+ if not migration_needed:
+ return
+
config.set(pki_base + ['ca'])
config.set_tag(pki_base + ['ca'])
@@ -60,8 +56,6 @@ if config.exists(ipsec_site_base):
if not config.exists(ipsec_site_base + [peer, 'authentication', 'x509']):
continue
- changes_made = True
-
peer_x509_base = ipsec_site_base + [peer, 'authentication', 'x509']
pki_name = 'peer_' + peer.replace(".", "-").replace("@", "")
@@ -159,11 +153,3 @@ if config.exists(ipsec_site_base):
print(f'Failed to migrate private key on peer "{peer}"')
config.delete(peer_x509_base + ['key'])
-
-if changes_made:
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ipsec/7-to-8 b/src/migration-scripts/ipsec/7-to-8
index 9acc737d5..481f00d29 100755..100644
--- a/src/migration-scripts/ipsec/7-to-8
+++ b/src/migration-scripts/ipsec/7-to-8
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 rsa keys into PKI configuration
@@ -22,29 +21,15 @@ import struct
from cryptography.hazmat.primitives.asymmetric import rsa
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
from vyos.pki import load_private_key
from vyos.pki import encode_public_key
from vyos.pki import encode_private_key
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
pki_base = ['pki']
ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
rsa_keys_base = ['vpn', 'rsa-keys']
-config = ConfigTree(config_file)
-
LOCAL_KEY_PATHS = ['/config/auth/', '/config/ipsec.d/rsa-keys/']
def migrate_from_vyatta_key(data):
@@ -60,65 +45,59 @@ def wrapped_pem_to_config_value(pem):
local_key_name = 'localhost'
-if config.exists(rsa_keys_base):
- if not config.exists(pki_base + ['key-pair']):
- config.set(pki_base + ['key-pair'])
- config.set_tag(pki_base + ['key-pair'])
-
- if config.exists(rsa_keys_base + ['local-key', 'file']):
- local_file = config.return_value(rsa_keys_base + ['local-key', 'file'])
- local_path = None
- local_key = None
-
- for path in LOCAL_KEY_PATHS:
- full_path = os.path.join(path, local_file)
- if os.path.exists(full_path):
- local_path = full_path
- break
-
- if local_path:
- with open(local_path, 'r') as f:
- local_key_data = f.read()
- local_key = load_private_key(local_key_data, wrap_tags=False)
-
- if local_key:
- local_key_pem = encode_private_key(local_key)
- config.set(pki_base + ['key-pair', local_key_name, 'private', 'key'], value=wrapped_pem_to_config_value(local_key_pem))
- else:
- print('Failed to migrate local RSA key')
-
- if config.exists(rsa_keys_base + ['rsa-key-name']):
- for rsa_name in config.list_nodes(rsa_keys_base + ['rsa-key-name']):
- if not config.exists(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']):
- continue
+def migrate(config: ConfigTree) -> None:
+ if config.exists(rsa_keys_base):
+ if not config.exists(pki_base + ['key-pair']):
+ config.set(pki_base + ['key-pair'])
+ config.set_tag(pki_base + ['key-pair'])
+
+ if config.exists(rsa_keys_base + ['local-key', 'file']):
+ local_file = config.return_value(rsa_keys_base + ['local-key', 'file'])
+ local_path = None
+ local_key = None
+
+ for path in LOCAL_KEY_PATHS:
+ full_path = os.path.join(path, local_file)
+ if os.path.exists(full_path):
+ local_path = full_path
+ break
+
+ if local_path:
+ with open(local_path, 'r') as f:
+ local_key_data = f.read()
+ local_key = load_private_key(local_key_data, wrap_tags=False)
+
+ if local_key:
+ local_key_pem = encode_private_key(local_key)
+ config.set(pki_base + ['key-pair', local_key_name, 'private', 'key'], value=wrapped_pem_to_config_value(local_key_pem))
+ else:
+ print('Failed to migrate local RSA key')
- vyatta_key = config.return_value(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key'])
- public_key = migrate_from_vyatta_key(vyatta_key)
+ if config.exists(rsa_keys_base + ['rsa-key-name']):
+ for rsa_name in config.list_nodes(rsa_keys_base + ['rsa-key-name']):
+ if not config.exists(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']):
+ continue
- if public_key:
- public_key_pem = encode_public_key(public_key)
- config.set(pki_base + ['key-pair', rsa_name, 'public', 'key'], value=wrapped_pem_to_config_value(public_key_pem))
- else:
- print(f'Failed to migrate rsa-key "{rsa_name}"')
+ vyatta_key = config.return_value(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key'])
+ public_key = migrate_from_vyatta_key(vyatta_key)
- config.delete(rsa_keys_base)
+ if public_key:
+ public_key_pem = encode_public_key(public_key)
+ config.set(pki_base + ['key-pair', rsa_name, 'public', 'key'], value=wrapped_pem_to_config_value(public_key_pem))
+ else:
+ print(f'Failed to migrate rsa-key "{rsa_name}"')
-if config.exists(ipsec_site_base):
- for peer in config.list_nodes(ipsec_site_base):
- mode = config.return_value(ipsec_site_base + [peer, 'authentication', 'mode'])
+ config.delete(rsa_keys_base)
- if mode != 'rsa':
- continue
+ if config.exists(ipsec_site_base):
+ for peer in config.list_nodes(ipsec_site_base):
+ mode = config.return_value(ipsec_site_base + [peer, 'authentication', 'mode'])
- config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'local-key'], value=local_key_name)
+ if mode != 'rsa':
+ continue
- remote_key_name = config.return_value(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
- config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'remote-key'], value=remote_key_name)
- config.delete(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
+ config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'local-key'], value=local_key_name)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ remote_key_name = config.return_value(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
+ config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'remote-key'], value=remote_key_name)
+ config.delete(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
diff --git a/src/migration-scripts/ipsec/8-to-9 b/src/migration-scripts/ipsec/8-to-9
index c08411f83..7f325139f 100755..100644
--- a/src/migration-scripts/ipsec/8-to-9
+++ b/src/migration-scripts/ipsec/8-to-9
@@ -1,48 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
+# T4288 : close-action is missing in swanctl.conf
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec', 'ike-group']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
for ike_group in config.list_nodes(base):
base_closeaction = base + [ike_group, 'close-action']
if config.exists(base_closeaction) and config.return_value(base_closeaction) == 'clear':
config.set(base_closeaction, 'none', replace=True)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
diff --git a/src/migration-scripts/ipsec/9-to-10 b/src/migration-scripts/ipsec/9-to-10
index bc10e1997..321a75973 100755..100644
--- a/src/migration-scripts/ipsec/9-to-10
+++ b/src/migration-scripts/ipsec/9-to-10
@@ -1,131 +1,114 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-import re
+# T4118: Change vpn ipsec syntax for IKE ESP and peer
+# T4879: IPsec migration script remote-id for peer name eq address
-from sys import argv
-from sys import exit
+import re
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vpn', 'ipsec']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# IKE changes, T4118:
-if config.exists(base + ['ike-group']):
- for ike_group in config.list_nodes(base + ['ike-group']):
- # replace 'ipsec ike-group <tag> mobike disable'
- # => 'ipsec ike-group <tag> disable-mobike'
- mobike = base + ['ike-group', ike_group, 'mobike']
- if config.exists(mobike):
- if config.return_value(mobike) == 'disable':
- config.set(base + ['ike-group', ike_group, 'disable-mobike'])
- config.delete(mobike)
-
- # replace 'ipsec ike-group <tag> ikev2-reauth yes'
- # => 'ipsec ike-group <tag> ikev2-reauth'
- reauth = base + ['ike-group', ike_group, 'ikev2-reauth']
- if config.exists(reauth):
- if config.return_value(reauth) == 'yes':
- config.delete(reauth)
- config.set(reauth)
- else:
- config.delete(reauth)
-
-# ESP changes
-# replace 'ipsec esp-group <tag> compression enable'
-# => 'ipsec esp-group <tag> compression'
-if config.exists(base + ['esp-group']):
- for esp_group in config.list_nodes(base + ['esp-group']):
- compression = base + ['esp-group', esp_group, 'compression']
- if config.exists(compression):
- if config.return_value(compression) == 'enable':
- config.delete(compression)
- config.set(compression)
- else:
- config.delete(compression)
-
-# PEER changes
-if config.exists(base + ['site-to-site', 'peer']):
- for peer in config.list_nodes(base + ['site-to-site', 'peer']):
- peer_base = base + ['site-to-site', 'peer', peer]
-
- # replace: 'peer <tag> id x'
- # => 'peer <tag> local-id x'
- if config.exists(peer_base + ['authentication', 'id']):
- config.rename(peer_base + ['authentication', 'id'], 'local-id')
-
- # For the peer '@foo' set remote-id 'foo' if remote-id is not defined
- # For the peer '192.0.2.1' set remote-id '192.0.2.1' if remote-id is not defined
- if not config.exists(peer_base + ['authentication', 'remote-id']):
- tmp = peer.replace('@', '') if peer.startswith('@') else peer
- config.set(peer_base + ['authentication', 'remote-id'], value=tmp)
-
- # replace: 'peer <tag> force-encapsulation enable'
- # => 'peer <tag> force-udp-encapsulation'
- force_enc = peer_base + ['force-encapsulation']
- if config.exists(force_enc):
- if config.return_value(force_enc) == 'enable':
- config.delete(force_enc)
- config.set(peer_base + ['force-udp-encapsulation'])
- else:
- config.delete(force_enc)
-
- # add option: 'peer <tag> remote-address x.x.x.x'
- remote_address = peer
- if peer.startswith('@'):
- remote_address = 'any'
- config.set(peer_base + ['remote-address'], value=remote_address)
- # Peer name it is swanctl connection name and shouldn't contain dots or colons
- # rename peer:
- # peer 192.0.2.1 => peer peer_192-0-2-1
- # peer 2001:db8::2 => peer peer_2001-db8--2
- # peer @foo => peer peer_foo
- re_peer_name = re.sub(':|\.', '-', peer)
- if re_peer_name.startswith('@'):
- re_peer_name = re.sub('@', '', re_peer_name)
- new_peer_name = f'peer_{re_peer_name}'
-
- config.rename(peer_base, new_peer_name)
-
-# remote-access/road-warrior changes
-if config.exists(base + ['remote-access', 'connection']):
- for connection in config.list_nodes(base + ['remote-access', 'connection']):
- ra_base = base + ['remote-access', 'connection', connection]
- # replace: 'remote-access connection <tag> authentication id x'
- # => 'remote-access connection <tag> authentication local-id x'
- if config.exists(ra_base + ['authentication', 'id']):
- config.rename(ra_base + ['authentication', 'id'], 'local-id')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # IKE changes, T4118:
+ if config.exists(base + ['ike-group']):
+ for ike_group in config.list_nodes(base + ['ike-group']):
+ # replace 'ipsec ike-group <tag> mobike disable'
+ # => 'ipsec ike-group <tag> disable-mobike'
+ mobike = base + ['ike-group', ike_group, 'mobike']
+ if config.exists(mobike):
+ if config.return_value(mobike) == 'disable':
+ config.set(base + ['ike-group', ike_group, 'disable-mobike'])
+ config.delete(mobike)
+
+ # replace 'ipsec ike-group <tag> ikev2-reauth yes'
+ # => 'ipsec ike-group <tag> ikev2-reauth'
+ reauth = base + ['ike-group', ike_group, 'ikev2-reauth']
+ if config.exists(reauth):
+ if config.return_value(reauth) == 'yes':
+ config.delete(reauth)
+ config.set(reauth)
+ else:
+ config.delete(reauth)
+
+ # ESP changes
+ # replace 'ipsec esp-group <tag> compression enable'
+ # => 'ipsec esp-group <tag> compression'
+ if config.exists(base + ['esp-group']):
+ for esp_group in config.list_nodes(base + ['esp-group']):
+ compression = base + ['esp-group', esp_group, 'compression']
+ if config.exists(compression):
+ if config.return_value(compression) == 'enable':
+ config.delete(compression)
+ config.set(compression)
+ else:
+ config.delete(compression)
+
+ # PEER changes
+ if config.exists(base + ['site-to-site', 'peer']):
+ for peer in config.list_nodes(base + ['site-to-site', 'peer']):
+ peer_base = base + ['site-to-site', 'peer', peer]
+
+ # replace: 'peer <tag> id x'
+ # => 'peer <tag> local-id x'
+ if config.exists(peer_base + ['authentication', 'id']):
+ config.rename(peer_base + ['authentication', 'id'], 'local-id')
+
+ # For the peer '@foo' set remote-id 'foo' if remote-id is not defined
+ # For the peer '192.0.2.1' set remote-id '192.0.2.1' if remote-id is not defined
+ if not config.exists(peer_base + ['authentication', 'remote-id']):
+ tmp = peer.replace('@', '') if peer.startswith('@') else peer
+ config.set(peer_base + ['authentication', 'remote-id'], value=tmp)
+
+ # replace: 'peer <tag> force-encapsulation enable'
+ # => 'peer <tag> force-udp-encapsulation'
+ force_enc = peer_base + ['force-encapsulation']
+ if config.exists(force_enc):
+ if config.return_value(force_enc) == 'enable':
+ config.delete(force_enc)
+ config.set(peer_base + ['force-udp-encapsulation'])
+ else:
+ config.delete(force_enc)
+
+ # add option: 'peer <tag> remote-address x.x.x.x'
+ remote_address = peer
+ if peer.startswith('@'):
+ remote_address = 'any'
+ config.set(peer_base + ['remote-address'], value=remote_address)
+ # Peer name it is swanctl connection name and shouldn't contain dots or colons
+ # rename peer:
+ # peer 192.0.2.1 => peer peer_192-0-2-1
+ # peer 2001:db8::2 => peer peer_2001-db8--2
+ # peer @foo => peer peer_foo
+ re_peer_name = re.sub(':|\.', '-', peer)
+ if re_peer_name.startswith('@'):
+ re_peer_name = re.sub('@', '', re_peer_name)
+ new_peer_name = f'peer_{re_peer_name}'
+
+ config.rename(peer_base, new_peer_name)
+
+ # remote-access/road-warrior changes
+ if config.exists(base + ['remote-access', 'connection']):
+ for connection in config.list_nodes(base + ['remote-access', 'connection']):
+ ra_base = base + ['remote-access', 'connection', connection]
+ # replace: 'remote-access connection <tag> authentication id x'
+ # => 'remote-access connection <tag> authentication local-id x'
+ if config.exists(ra_base + ['authentication', 'id']):
+ config.rename(ra_base + ['authentication', 'id'], 'local-id')
diff --git a/src/migration-scripts/isis/0-to-1 b/src/migration-scripts/isis/0-to-1
index 0149c0c1f..e24288558 100755..100644
--- a/src/migration-scripts/isis/0-to-1
+++ b/src/migration-scripts/isis/0-to-1
@@ -1,56 +1,36 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'isis']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# We need a temporary copy of the config
-tmp_base = ['protocols', 'isis2']
-config.copy(base, tmp_base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-# Now it's save to delete the old configuration
-config.delete(base)
+ # We need a temporary copy of the config
+ tmp_base = ['protocols', 'isis2']
+ config.copy(base, tmp_base)
-# Rename temporary copy to new final config (IS-IS domain key is static and no
-# longer required to be set via CLI)
-config.rename(tmp_base, 'isis')
+ # Now it's save to delete the old configuration
+ config.delete(base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # Rename temporary copy to new final config (IS-IS domain key is static and no
+ # longer required to be set via CLI)
+ config.rename(tmp_base, 'isis')
diff --git a/src/migration-scripts/isis/1-to-2 b/src/migration-scripts/isis/1-to-2
index 9c110bf2a..0fc92a6de 100755..100644
--- a/src/migration-scripts/isis/1-to-2
+++ b/src/migration-scripts/isis/1-to-2
@@ -1,46 +1,27 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4739 refactor, and remove "on" from segment routing from the configuration
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-# Check if ISIS segment routing is configured. Then check if segment routing "on" exists, then delete the "on" as it is no longer needed. This is for global configuration.
-if config.exists(['protocols', 'isis']):
- if config.exists(['protocols', 'isis', 'segment-routing']):
- if config.exists(['protocols', 'isis', 'segment-routing', 'enable']):
- config.delete(['protocols', 'isis', 'segment-routing', 'enable'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if ISIS segment routing is configured. Then check if segment
+ # routing "on" exists, then delete the "on" as it is no longer needed.
+ # This is for global configuration.
+ if config.exists(['protocols', 'isis']):
+ if config.exists(['protocols', 'isis', 'segment-routing']):
+ if config.exists(['protocols', 'isis', 'segment-routing', 'enable']):
+ config.delete(['protocols', 'isis', 'segment-routing', 'enable'])
diff --git a/src/migration-scripts/isis/2-to-3 b/src/migration-scripts/isis/2-to-3
index 78e3c1715..afb9f2340 100755..100644
--- a/src/migration-scripts/isis/2-to-3
+++ b/src/migration-scripts/isis/2-to-3
@@ -1,63 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
isis_base = ['protocols', 'isis']
-# Check if IS-IS is configured - if so, migrate the CLI node
-if config.exists(isis_base):
- if config.exists(isis_base + ['route-map']):
- tmp = config.return_value(isis_base + ['route-map'])
-
- config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(isis_base + ['route-map'])
-
-# Check if vrf names are configured. Check if IS-IS is configured - if so,
-# migrate the CLI node(s)
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
- if config.exists(vrf_base + ['protocols', 'isis', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map'])
-
- config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ip', 'protocol', 'isis'])
- config.delete(vrf_base + ['protocols', 'isis', 'route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if IS-IS is configured - if so, migrate the CLI node
+ if config.exists(isis_base):
+ if config.exists(isis_base + ['route-map']):
+ tmp = config.return_value(isis_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(isis_base + ['route-map'])
+
+ # Check if vrf names are configured. Check if IS-IS is configured - if so,
+ # migrate the CLI node(s)
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'isis', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'isis'])
+ config.delete(vrf_base + ['protocols', 'isis', 'route-map'])
diff --git a/src/migration-scripts/l2tp/0-to-1 b/src/migration-scripts/l2tp/0-to-1
index 15d229822..f0cb6af96 100755..100644
--- a/src/migration-scripts/l2tp/0-to-1
+++ b/src/migration-scripts/l2tp/0-to-1
@@ -1,29 +1,32 @@
-#!/usr/bin/env python3
-
+# Copyright 2018-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/>.
+
+# T987: Unclutter L2TP/IPSec RADIUS configuration nodes
# Unclutter L2TP VPN configuiration - move radius-server top level tag
# nodes to a regular node which now also configures the radius source address
# used when querying a radius server
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_base = ['vpn', 'l2tp', 'remote-access', 'authentication']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
-cfg_base = ['vpn', 'l2tp', 'remote-access', 'authentication']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
# Migrate "vpn l2tp authentication radius-source-address" to new
# "vpn l2tp authentication radius source-address"
if config.exists(cfg_base + ['radius-source-address']):
@@ -51,10 +54,3 @@ else:
# delete top level tag node
if config.exists(cfg_base + ['radius-server']):
config.delete(cfg_base + ['radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/l2tp/1-to-2 b/src/migration-scripts/l2tp/1-to-2
index 2ffb91c53..468d564ac 100755..100644
--- a/src/migration-scripts/l2tp/1-to-2
+++ b/src/migration-scripts/l2tp/1-to-2
@@ -1,33 +1,28 @@
-#!/usr/bin/env python3
-
-# Delete depricated outside-nexthop address
-
-import sys
+# Copyright 2019-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/>.
+
+# T1858: Delete deprecated outside-nexthop
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_base = ['vpn', 'l2tp', 'remote-access']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
-cfg_base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
if config.exists(cfg_base + ['outside-nexthop']):
config.delete(cfg_base + ['outside-nexthop'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/l2tp/2-to-3 b/src/migration-scripts/l2tp/2-to-3
index 8527c2d4a..00fabb6b6 100755..100644
--- a/src/migration-scripts/l2tp/2-to-3
+++ b/src/migration-scripts/l2tp/2-to-3
@@ -1,40 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-# - remove primary/secondary identifier from nameserver
-# - TODO: remove radius server req-limit
+# T2264: combine IPv4/IPv6 name-server CLI syntax
+# T2264: combine WINS CLI syntax
+# T2264: remove RADIUS req-limit node
+# T2264: migrate IPv6 prefix node to common CLI style
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['vpn', 'l2tp', 'remote-access']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
if config.exists(dns_base):
@@ -98,10 +90,3 @@ else:
prefix = p.split(',')[0]
mask = p.split(',')[1]
config.set(ipv6_base + ['delegate', prefix, 'delegate-prefix'], value=mask)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/l2tp/3-to-4 b/src/migration-scripts/l2tp/3-to-4
index 14b86ff04..01c3fa844 100755..100644
--- a/src/migration-scripts/l2tp/3-to-4
+++ b/src/migration-scripts/l2tp/3-to-4
@@ -1,26 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-# - remove primary/secondary identifier from nameserver
-# - TODO: remove radius server req-limit
+# T2816: T3642: Move IPSec/L2TP code into vpn_ipsec.py and update to use PKI.
import os
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_private_key
@@ -28,141 +24,125 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access', 'ipsec-settings']
pki_base = ['pki']
-if not config.exists(base):
- exit(0)
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if not config.exists(base + ['authentication', 'x509']):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(base + ['authentication', 'x509']):
+ return
+
+ x509_base = base + ['authentication', 'x509']
+ pki_name = 'l2tp_remote_access'
+
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on l2tp remote-access config')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['crl-file']):
+ crl_file = config.return_value(x509_base + ['crl-file'])
+ crl_path = os.path.join(AUTH_DIR, crl_file)
+ crl = None
+
+ if os.path.isfile(crl_path):
+ if not os.access(crl_path, os.R_OK):
+ run(f'sudo chmod 644 {crl_path}')
+
+ with open(crl_path, 'r') as f:
+ crl_data = f.read()
+ crl = load_certificate(crl_data, wrap_tags=False)
+
+ if crl:
+ crl_pem = encode_certificate(crl)
+ config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ else:
+ print(f'Failed to migrate CRL on l2tp remote-access config')
+
+ config.delete(x509_base + ['crl-file'])
+
+ if config.exists(x509_base + ['server-cert-file']):
+ cert_file = config.return_value(x509_base + ['server-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on l2tp remote-access config')
+
+ config.delete(x509_base + ['server-cert-file'])
+
+ if config.exists(x509_base + ['server-key-file']):
+ key_file = config.return_value(x509_base + ['server-key-file'])
+ key_passphrase = None
-x509_base = base + ['authentication', 'x509']
-pki_name = 'l2tp_remote_access'
+ if config.exists(x509_base + ['server-key-password']):
+ key_passphrase = config.return_value(x509_base + ['server-key-password'])
-if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
-if config.exists(x509_base + ['ca-cert-file']):
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on l2tp remote-access config')
-
- config.delete(x509_base + ['ca-cert-file'])
-
-if config.exists(x509_base + ['crl-file']):
- crl_file = config.return_value(x509_base + ['crl-file'])
- crl_path = os.path.join(AUTH_DIR, crl_file)
- crl = None
-
- if os.path.isfile(crl_path):
- if not os.access(crl_path, os.R_OK):
- run(f'sudo chmod 644 {crl_path}')
-
- with open(crl_path, 'r') as f:
- crl_data = f.read()
- crl = load_certificate(crl_data, wrap_tags=False)
-
- if crl:
- crl_pem = encode_certificate(crl)
- config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
- else:
- print(f'Failed to migrate CRL on l2tp remote-access config')
-
- config.delete(x509_base + ['crl-file'])
-
-if config.exists(x509_base + ['server-cert-file']):
- cert_file = config.return_value(x509_base + ['server-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on l2tp remote-access config')
-
- config.delete(x509_base + ['server-cert-file'])
-
-if config.exists(x509_base + ['server-key-file']):
- key_file = config.return_value(x509_base + ['server-key-file'])
- key_passphrase = None
-
- if config.exists(x509_base + ['server-key-password']):
- key_passphrase = config.return_value(x509_base + ['server-key-password'])
-
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=key_passphrase)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
-
- if key_passphrase:
- config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected'])
- config.set(x509_base + ['private-key-passphrase'], value=key_passphrase)
- else:
- print(f'Failed to migrate private key on l2tp remote-access config')
-
- config.delete(x509_base + ['server-key-file'])
- if config.exists(x509_base + ['server-key-password']):
- config.delete(x509_base + ['server-key-password'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=key_passphrase)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+
+ if key_passphrase:
+ config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected'])
+ config.set(x509_base + ['private-key-passphrase'], value=key_passphrase)
+ else:
+ print(f'Failed to migrate private key on l2tp remote-access config')
+
+ config.delete(x509_base + ['server-key-file'])
+ if config.exists(x509_base + ['server-key-password']):
+ config.delete(x509_base + ['server-key-password'])
diff --git a/src/migration-scripts/l2tp/4-to-5 b/src/migration-scripts/l2tp/4-to-5
index b7f4d2677..56d451b8d 100755..100644
--- a/src/migration-scripts/l2tp/4-to-5
+++ b/src/migration-scripts/l2tp/4-to-5
@@ -1,85 +1,68 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'start-stop' migrate to namedpool 'default-range-pool'
# 'subnet' migrate to namedpool 'default-subnet-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.base import Warning
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-if not config.exists(pool_base):
- exit(0)
-default_pool = ''
-range_pool_name = 'default-range-pool'
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
- def is_legalrange(ip1: str, ip2: str, mask: str):
- from ipaddress import IPv4Interface
- interface1 = IPv4Interface(f'{ip1}/{mask}')
+ if not config.exists(pool_base):
+ return
- interface2 = IPv4Interface(f'{ip2}/{mask}')
- return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+ default_pool = ''
+ range_pool_name = 'default-range-pool'
- start_ip = config.return_value(pool_base + ['start'])
- stop_ip = config.return_value(pool_base + ['stop'])
- if is_legalrange(start_ip, stop_ip,'24'):
- ip_range = f'{start_ip}-{stop_ip}'
- config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
- default_pool = range_pool_name
- else:
- Warning(
- f'L2TP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+ def is_legalrange(ip1: str, ip2: str, mask: str):
+ from ipaddress import IPv4Interface
+ interface1 = IPv4Interface(f'{ip1}/{mask}')
+
+ interface2 = IPv4Interface(f'{ip2}/{mask}')
+ return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
- config.delete(pool_base + ['start'])
- config.delete(pool_base + ['stop'])
+ start_ip = config.return_value(pool_base + ['start'])
+ stop_ip = config.return_value(pool_base + ['stop'])
+ if is_legalrange(start_ip, stop_ip,'24'):
+ ip_range = f'{start_ip}-{stop_ip}'
+ config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+ default_pool = range_pool_name
+ else:
+ Warning(
+ f'L2TP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
-if config.exists(pool_base + ['subnet']):
- for subnet in config.return_values(pool_base + ['subnet']):
- config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+ config.delete(pool_base + ['start'])
+ config.delete(pool_base + ['stop'])
- config.delete(pool_base + ['subnet'])
- default_pool = range_pool_name
+ if config.exists(pool_base + ['subnet']):
+ for subnet in config.return_values(pool_base + ['subnet']):
+ config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
-if default_pool:
- config.set(base + ['default-pool'], value=default_pool)
-# format as tag node
-config.set_tag(pool_base)
+ config.delete(pool_base + ['subnet'])
+ default_pool = range_pool_name
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if default_pool:
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/l2tp/5-to-6 b/src/migration-scripts/l2tp/5-to-6
index ac40b89c8..cc9f948a6 100755..100644
--- a/src/migration-scripts/l2tp/5-to-6
+++ b/src/migration-scripts/l2tp/5-to-6
@@ -1,106 +1,88 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-#migrate idle to ppp option lcp-echo-timeout
-idle_path = base + ['idle']
-if config.exists(idle_path):
- config.set(base + ['ppp-options', 'lcp-echo-timeout'],
- value=config.return_value(idle_path))
- config.delete(idle_path)
-
-#migrate mppe from authentication to ppp-otion
-mppe_path = base + ['authentication', 'mppe']
-if config.exists(mppe_path):
- config.set(base + ['ppp-options', 'mppe'],
- value=config.return_value(mppe_path))
- config.delete(mppe_path)
-
-#migrate require to protocol
-require_path = base + ['authentication', 'require']
-if config.exists(require_path):
- protocols = list(config.return_values(require_path))
- for protocol in protocols:
- config.set(base + ['authentication', 'protocols'], value=protocol,
- replace=False)
- config.delete(require_path)
-else:
- config.set(base + ['authentication', 'protocols'], value='mschap-v2')
-
-#migrate default gateway if not exist
-if not config.exists(base + ['gateway-address']):
- config.set(base + ['gateway-address'], value='10.255.255.0')
-
-#migrate authentication radius timeout
-rad_timeout_path = base + ['authentication', 'radius', 'timeout']
-if config.exists(rad_timeout_path):
- if int(config.return_value(rad_timeout_path)) > 60:
- config.set(rad_timeout_path, value=60)
-
-#migrate authentication radius acct timeout
-rad_acct_timeout_path = base + ['authentication', 'radius', 'acct-timeout']
-if config.exists(rad_acct_timeout_path):
- if int(config.return_value(rad_acct_timeout_path)) > 60:
- config.set(rad_acct_timeout_path,value=60)
-
-#migrate authentication radius max-try
-rad_max_try_path = base + ['authentication', 'radius', 'max-try']
-if config.exists(rad_max_try_path):
- if int(config.return_value(rad_max_try_path)) > 20:
- config.set(rad_max_try_path, value=20)
-
-#migrate dae-server to dynamic-author
-dae_path_old = base + ['authentication', 'radius', 'dae-server']
-dae_path_new = base + ['authentication', 'radius', 'dynamic-author']
-
-if config.exists(dae_path_old + ['ip-address']):
- config.set(dae_path_new + ['server'],
- value=config.return_value(dae_path_old + ['ip-address']))
-
-if config.exists(dae_path_old + ['port']):
- config.set(dae_path_new + ['port'],
- value=config.return_value(dae_path_old + ['port']))
-
-if config.exists(dae_path_old + ['secret']):
- config.set(dae_path_new + ['key'],
- value=config.return_value(dae_path_old + ['secret']))
-
-if config.exists(dae_path_old):
- config.delete(dae_path_old)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #migrate idle to ppp option lcp-echo-timeout
+ idle_path = base + ['idle']
+ if config.exists(idle_path):
+ config.set(base + ['ppp-options', 'lcp-echo-timeout'],
+ value=config.return_value(idle_path))
+ config.delete(idle_path)
+
+ #migrate mppe from authentication to ppp-otion
+ mppe_path = base + ['authentication', 'mppe']
+ if config.exists(mppe_path):
+ config.set(base + ['ppp-options', 'mppe'],
+ value=config.return_value(mppe_path))
+ config.delete(mppe_path)
+
+ #migrate require to protocol
+ require_path = base + ['authentication', 'require']
+ if config.exists(require_path):
+ protocols = list(config.return_values(require_path))
+ for protocol in protocols:
+ config.set(base + ['authentication', 'protocols'], value=protocol,
+ replace=False)
+ config.delete(require_path)
+ else:
+ config.set(base + ['authentication', 'protocols'], value='mschap-v2')
+
+ #migrate default gateway if not exist
+ if not config.exists(base + ['gateway-address']):
+ config.set(base + ['gateway-address'], value='10.255.255.0')
+
+ #migrate authentication radius timeout
+ rad_timeout_path = base + ['authentication', 'radius', 'timeout']
+ if config.exists(rad_timeout_path):
+ if int(config.return_value(rad_timeout_path)) > 60:
+ config.set(rad_timeout_path, value=60)
+
+ #migrate authentication radius acct timeout
+ rad_acct_timeout_path = base + ['authentication', 'radius', 'acct-timeout']
+ if config.exists(rad_acct_timeout_path):
+ if int(config.return_value(rad_acct_timeout_path)) > 60:
+ config.set(rad_acct_timeout_path,value=60)
+
+ #migrate authentication radius max-try
+ rad_max_try_path = base + ['authentication', 'radius', 'max-try']
+ if config.exists(rad_max_try_path):
+ if int(config.return_value(rad_max_try_path)) > 20:
+ config.set(rad_max_try_path, value=20)
+
+ #migrate dae-server to dynamic-author
+ dae_path_old = base + ['authentication', 'radius', 'dae-server']
+ dae_path_new = base + ['authentication', 'radius', 'dynamic-author']
+
+ if config.exists(dae_path_old + ['ip-address']):
+ config.set(dae_path_new + ['server'],
+ value=config.return_value(dae_path_old + ['ip-address']))
+
+ if config.exists(dae_path_old + ['port']):
+ config.set(dae_path_new + ['port'],
+ value=config.return_value(dae_path_old + ['port']))
+
+ if config.exists(dae_path_old + ['secret']):
+ config.set(dae_path_new + ['key'],
+ value=config.return_value(dae_path_old + ['secret']))
+
+ if config.exists(dae_path_old):
+ config.delete(dae_path_old)
diff --git a/src/migration-scripts/l2tp/6-to-7 b/src/migration-scripts/l2tp/6-to-7
index 1c536585c..4dba5974e 100755..100644
--- a/src/migration-scripts/l2tp/6-to-7
+++ b/src/migration-scripts/l2tp/6-to-7
@@ -1,57 +1,39 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-if not config.exists(pool_base):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
+ if not config.exists(pool_base):
+ return
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-# format as tag node
-config.set_tag(pool_base)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/l2tp/7-to-8 b/src/migration-scripts/l2tp/7-to-8
index e429ed057..527906fc8 100755..100644
--- a/src/migration-scripts/l2tp/7-to-8
+++ b/src/migration-scripts/l2tp/7-to-8
@@ -1,65 +1,47 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 from 'ccp-disable' to 'ppp-options.disable-ccp'
# Migration ipv6 options
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-#CCP migration
-if config.exists(base + ['ccp-disable']):
- config.delete(base + ['ccp-disable'])
- config.set(base + ['ppp-options', 'disable-ccp'])
-
-#IPV6 options migrations
-if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
- intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
- if intf_peer_id == 'ipv4':
- intf_peer_id = 'ipv4-addr'
- config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-intf-id']):
- intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
- config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
- config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
- config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #CCP migration
+ if config.exists(base + ['ccp-disable']):
+ config.delete(base + ['ccp-disable'])
+ config.set(base + ['ppp-options', 'disable-ccp'])
+
+ #IPV6 options migrations
+ if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
+ intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
+ if intf_peer_id == 'ipv4':
+ intf_peer_id = 'ipv4-addr'
+ config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-intf-id']):
+ intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
+ config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
+ config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
+ config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
diff --git a/src/migration-scripts/l2tp/8-to-9 b/src/migration-scripts/l2tp/8-to-9
index 672180e25..e6b689e80 100755..100644
--- a/src/migration-scripts/l2tp/8-to-9
+++ b/src/migration-scripts/l2tp/8-to-9
@@ -1,46 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Deleted 'dhcp-interface' from l2tp
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access']
-if not config.exists(base):
- exit(0)
-# deleting unused dhcp-interface
-if config.exists(base + ['dhcp-interface']):
- config.delete(base + ['dhcp-interface'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # deleting unused dhcp-interface
+ if config.exists(base + ['dhcp-interface']):
+ config.delete(base + ['dhcp-interface'])
diff --git a/src/migration-scripts/lldp/0-to-1 b/src/migration-scripts/lldp/0-to-1
index a99356062..c16e7e84b 100755..100644
--- a/src/migration-scripts/lldp/0-to-1
+++ b/src/migration-scripts/lldp/0-to-1
@@ -1,49 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete "set service lldp interface <interface> location civic-based" option
# as it was broken most of the time anyways
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['service', 'lldp', 'interface']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['service', 'lldp', 'interface']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
# Delete nodes with abandoned CLI syntax
for interface in config.list_nodes(base):
if config.exists(base + [interface, 'location', 'civic-based']):
config.delete(base + [interface, 'location', 'civic-based'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/lldp/1-to-2 b/src/migration-scripts/lldp/1-to-2
index 35efb25db..7f233a725 100755..100644
--- a/src/migration-scripts/lldp/1-to-2
+++ b/src/migration-scripts/lldp/1-to-2
@@ -1,48 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5855: migrate "set service lldp snmp enable" -> `set service lldp snmp"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'lldp']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-if config.exists(base + ['snmp']):
- enabled = config.exists(base + ['snmp', 'enable'])
- config.delete(base + ['snmp'])
- if enabled: config.set(base + ['snmp'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ if config.exists(base + ['snmp']):
+ enabled = config.exists(base + ['snmp', 'enable'])
+ config.delete(base + ['snmp'])
+ if enabled: config.set(base + ['snmp'])
diff --git a/src/migration-scripts/monitoring/0-to-1 b/src/migration-scripts/monitoring/0-to-1
index 384d22f8c..92f824325 100755..100644
--- a/src/migration-scripts/monitoring/0-to-1
+++ b/src/migration-scripts/monitoring/0-to-1
@@ -14,58 +14,53 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process
+# Copyright 2022-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 sys import argv
-from sys import exit
+# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'monitoring', 'telegraf']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['authentication', 'organization']):
- tmp = config.return_value(base + ['authentication', 'organization'])
- config.delete(base + ['authentication', 'organization'])
- config.set(base + ['influxdb', 'authentication', 'organization'], value=tmp)
-if config.exists(base + ['authentication', 'token']):
- tmp = config.return_value(base + ['authentication', 'token'])
- config.delete(base + ['authentication', 'token'])
- config.set(base + ['influxdb', 'authentication', 'token'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['bucket']):
- tmp = config.return_value(base + ['bucket'])
- config.delete(base + ['bucket'])
- config.set(base + ['influxdb', 'bucket'], value=tmp)
+ if config.exists(base + ['authentication', 'organization']):
+ tmp = config.return_value(base + ['authentication', 'organization'])
+ config.delete(base + ['authentication', 'organization'])
+ config.set(base + ['influxdb', 'authentication', 'organization'], value=tmp)
-if config.exists(base + ['port']):
- tmp = config.return_value(base + ['port'])
- config.delete(base + ['port'])
- config.set(base + ['influxdb', 'port'], value=tmp)
+ if config.exists(base + ['authentication', 'token']):
+ tmp = config.return_value(base + ['authentication', 'token'])
+ config.delete(base + ['authentication', 'token'])
+ config.set(base + ['influxdb', 'authentication', 'token'], value=tmp)
-if config.exists(base + ['url']):
- tmp = config.return_value(base + ['url'])
- config.delete(base + ['url'])
- config.set(base + ['influxdb', 'url'], value=tmp)
+ if config.exists(base + ['bucket']):
+ tmp = config.return_value(base + ['bucket'])
+ config.delete(base + ['bucket'])
+ config.set(base + ['influxdb', 'bucket'], value=tmp)
+ if config.exists(base + ['port']):
+ tmp = config.return_value(base + ['port'])
+ config.delete(base + ['port'])
+ config.set(base + ['influxdb', 'port'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base + ['url']):
+ tmp = config.return_value(base + ['url'])
+ config.delete(base + ['url'])
+ config.set(base + ['influxdb', 'url'], value=tmp)
diff --git a/src/migration-scripts/nat/4-to-5 b/src/migration-scripts/nat/4-to-5
index ce215d455..e1919da50 100755..100644
--- a/src/migration-scripts/nat/4-to-5
+++ b/src/migration-scripts/nat/4-to-5
@@ -1,40 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Drop the enable/disable from the nat "log" node. If log node is specified
# it is "enabled"
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['nat']):
- # Nothing to do
- exit(0)
-else:
for direction in ['source', 'destination']:
# If a node doesn't exist, we obviously have nothing to do.
if not config.exists(['nat', direction]):
@@ -55,10 +43,3 @@ else:
config.delete(base + ['log'])
if tmp == 'enable':
config.set(base + ['log'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/nat/5-to-6 b/src/migration-scripts/nat/5-to-6
index cfe98ddcf..a583d4eb6 100755..100644
--- a/src/migration-scripts/nat/5-to-6
+++ b/src/migration-scripts/nat/5-to-6
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5643: move from 'set nat [source|destination] rule X [inbound-interface|outbound interface] <iface>'
# to
@@ -23,7 +22,7 @@
# 'set nat [source|destination] rule X [source| destination| translation] address <IP/Netmask| !IP/Netmask>'
import ipaddress
-from sys import argv,exit
+
from vyos.configtree import ConfigTree
@@ -62,21 +61,10 @@ def _func_T6100(conf, base_path):
return
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
+def migrate(config: ConfigTree) -> None:
if not config.exists(['nat']):
# Nothing to do
- exit(0)
+ return
for direction in ['source', 'destination']:
# If a node doesn't exist, we obviously have nothing to do.
@@ -92,10 +80,3 @@ if __name__ == '__main__':
base = ['nat', direction, 'rule', rule]
_func_T5643(config,base)
_func_T6100(config,base)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/nat/6-to-7 b/src/migration-scripts/nat/6-to-7
index 25640dec2..e9b90fc98 100755..100644
--- a/src/migration-scripts/nat/6-to-7
+++ b/src/migration-scripts/nat/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5681: Firewall re-writing. Simplify cli when mathcing interface
# From
@@ -23,51 +22,33 @@
# 'set nat [source|destination] rule X [inbound-interface|outbound interface] group <iface_group>'
# Also remove command if interface == any
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['nat']):
- # Nothing to do
- exit(0)
-
-for direction in ['source', 'destination']:
- # If a node doesn't exist, we obviously have nothing to do.
- if not config.exists(['nat', direction]):
- continue
-
- # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
- # but there are no rules under it.
- if not config.list_nodes(['nat', direction]):
- continue
-
- for rule in config.list_nodes(['nat', direction, 'rule']):
- base = ['nat', direction, 'rule', rule]
- for iface in ['inbound-interface','outbound-interface']:
- if config.exists(base + [iface]):
- if config.exists(base + [iface, 'interface-name']):
- tmp = config.return_value(base + [iface, 'interface-name'])
- if tmp != 'any':
- config.delete(base + [iface, 'interface-name'])
- if '+' in tmp:
- tmp = tmp.replace('+', '*')
- config.set(base + [iface, 'name'], value=tmp)
- else:
- config.delete(base + [iface])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat']):
+ # Nothing to do
+ return
+
+ for direction in ['source', 'destination']:
+ # If a node doesn't exist, we obviously have nothing to do.
+ if not config.exists(['nat', direction]):
+ continue
+
+ # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
+ # but there are no rules under it.
+ if not config.list_nodes(['nat', direction]):
+ continue
+
+ for rule in config.list_nodes(['nat', direction, 'rule']):
+ base = ['nat', direction, 'rule', rule]
+ for iface in ['inbound-interface','outbound-interface']:
+ if config.exists(base + [iface]):
+ if config.exists(base + [iface, 'interface-name']):
+ tmp = config.return_value(base + [iface, 'interface-name'])
+ if tmp != 'any':
+ config.delete(base + [iface, 'interface-name'])
+ if '+' in tmp:
+ tmp = tmp.replace('+', '*')
+ config.set(base + [iface, 'name'], value=tmp)
+ else:
+ config.delete(base + [iface])
diff --git a/src/migration-scripts/nat/7-to-8 b/src/migration-scripts/nat/7-to-8
index ab2ffa6d3..9ae389ef1 100755..100644
--- a/src/migration-scripts/nat/7-to-8
+++ b/src/migration-scripts/nat/7-to-8
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6345: random - In kernel 5.0 and newer this is the same as fully-random.
# In earlier kernels the port mapping will be randomized using a seeded
# MD5 hash mix using source and destination address and destination port.
# drop fully-random from CLI
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['nat']):
- # Nothing to do
- exit(0)
-
-for direction in ['source', 'destination']:
- # If a node doesn't exist, we obviously have nothing to do.
- if not config.exists(['nat', direction]):
- continue
-
- # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
- # but there are no rules under it.
- if not config.list_nodes(['nat', direction]):
- continue
-
- for rule in config.list_nodes(['nat', direction, 'rule']):
- port_mapping = ['nat', direction, 'rule', rule, 'translation', 'options', 'port-mapping']
- if config.exists(port_mapping):
- tmp = config.return_value(port_mapping)
- if tmp == 'fully-random':
- config.set(port_mapping, value='random')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat']):
+ # Nothing to do
+ return
+
+ for direction in ['source', 'destination']:
+ # If a node doesn't exist, we obviously have nothing to do.
+ if not config.exists(['nat', direction]):
+ continue
+
+ # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
+ # but there are no rules under it.
+ if not config.list_nodes(['nat', direction]):
+ continue
+
+ for rule in config.list_nodes(['nat', direction, 'rule']):
+ port_mapping = ['nat', direction, 'rule', rule, 'translation', 'options', 'port-mapping']
+ if config.exists(port_mapping):
+ tmp = config.return_value(port_mapping)
+ if tmp == 'fully-random':
+ config.set(port_mapping, value='random')
diff --git a/src/migration-scripts/nat66/0-to-1 b/src/migration-scripts/nat66/0-to-1
index 444b2315f..b3c6bf4cc 100755..100644
--- a/src/migration-scripts/nat66/0-to-1
+++ b/src/migration-scripts/nat66/0-to-1
@@ -1,33 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
def merge_npt(config,base,rule):
merge_base = ['nat66','source','rule',rule]
# Configure migration functions
@@ -51,21 +38,15 @@ def merge_npt(config,base,rule):
tmp = config.return_value(base + ['translation','prefix'])
config.set(merge_base + ['translation','address'],value=tmp)
-if not config.exists(['nat', 'nptv6']):
- # Nothing to do
- exit(0)
-
-for rule in config.list_nodes(['nat', 'nptv6', 'rule']):
- base = ['nat', 'nptv6', 'rule', rule]
- # Merge 'nat nptv6' to 'nat66 source'
- merge_npt(config,base,rule)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat', 'nptv6']):
+ # Nothing to do
+ return
-# Delete the original NPT configuration
-config.delete(['nat','nptv6']);
+ for rule in config.list_nodes(['nat', 'nptv6', 'rule']):
+ base = ['nat', 'nptv6', 'rule', rule]
+ # Merge 'nat nptv6' to 'nat66 source'
+ merge_npt(config,base,rule)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Delete the original NPT configuration
+ config.delete(['nat','nptv6']);
diff --git a/src/migration-scripts/nat66/1-to-2 b/src/migration-scripts/nat66/1-to-2
index b7d4e3f6b..f49940ae0 100755..100644
--- a/src/migration-scripts/nat66/1-to-2
+++ b/src/migration-scripts/nat66/1-to-2
@@ -14,50 +14,48 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# T5681: Firewall re-writing. Simplify cli when mathcing interface
# From
# 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] <iface>'
# to
# 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] name <iface>'
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-if not config.exists(['nat66']):
- # Nothing to do
- exit(0)
-
-for direction in ['source', 'destination']:
- # If a node doesn't exist, we obviously have nothing to do.
- if not config.exists(['nat66', direction]):
- continue
-
- # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
- # but there are no rules under it.
- if not config.list_nodes(['nat66', direction]):
- continue
-
- for rule in config.list_nodes(['nat66', direction, 'rule']):
- base = ['nat66', direction, 'rule', rule]
- for iface in ['inbound-interface','outbound-interface']:
- if config.exists(base + [iface]):
- tmp = config.return_value(base + [iface])
- config.delete(base + [iface])
- config.set(base + [iface, 'name'], value=tmp)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['nat66']):
+ # Nothing to do
+ return
+
+ for direction in ['source', 'destination']:
+ # If a node doesn't exist, we obviously have nothing to do.
+ if not config.exists(['nat66', direction]):
+ continue
+
+ # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
+ # but there are no rules under it.
+ if not config.list_nodes(['nat66', direction]):
+ continue
+
+ for rule in config.list_nodes(['nat66', direction, 'rule']):
+ base = ['nat66', direction, 'rule', rule]
+ for iface in ['inbound-interface','outbound-interface']:
+ if config.exists(base + [iface]):
+ tmp = config.return_value(base + [iface])
+ config.delete(base + [iface])
+ config.set(base + [iface, 'name'], value=tmp)
diff --git a/src/migration-scripts/nat66/2-to-3 b/src/migration-scripts/nat66/2-to-3
index f34f170b3..55d5f4b2b 100755..100644
--- a/src/migration-scripts/nat66/2-to-3
+++ b/src/migration-scripts/nat66/2-to-3
@@ -1,61 +1,45 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from sys import argv,exit
-from vyos.configtree import ConfigTree
+# 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/>.
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+# T2898: add ndp-proxy service
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+from vyos.configtree import ConfigTree
base = ['nat66', 'source']
new_base = ['service', 'ndp-proxy', 'interface']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for rule in config.list_nodes(base + ['rule']):
- base_rule = base + ['rule', rule]
-
- interface = None
- if config.exists(base_rule + ['outbound-interface', 'name']):
- interface = config.return_value(base_rule + ['outbound-interface', 'name'])
- else:
- continue
-
- prefix_base = base_rule + ['source', 'prefix']
- if config.exists(prefix_base):
- prefix = config.return_value(prefix_base)
- config.set(new_base + [interface, 'prefix', prefix, 'mode'], value='static')
- config.set_tag(new_base)
- config.set_tag(new_base + [interface, 'prefix'])
-
- if config.exists(base_rule + ['disable']):
- config.set(new_base + [interface, 'prefix', prefix, 'disable'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for rule in config.list_nodes(base + ['rule']):
+ base_rule = base + ['rule', rule]
+
+ interface = None
+ if config.exists(base_rule + ['outbound-interface', 'name']):
+ interface = config.return_value(base_rule + ['outbound-interface', 'name'])
+ else:
+ continue
+
+ prefix_base = base_rule + ['source', 'prefix']
+ if config.exists(prefix_base):
+ prefix = config.return_value(prefix_base)
+ config.set(new_base + [interface, 'prefix', prefix, 'mode'], value='static')
+ config.set_tag(new_base)
+ config.set_tag(new_base + [interface, 'prefix'])
+
+ if config.exists(base_rule + ['disable']):
+ config.set(new_base + [interface, 'prefix', prefix, 'disable'])
diff --git a/src/migration-scripts/ntp/0-to-1 b/src/migration-scripts/ntp/0-to-1
index cbce45b9b..01f5a460a 100755..100644
--- a/src/migration-scripts/ntp/0-to-1
+++ b/src/migration-scripts/ntp/0-to-1
@@ -1,36 +1,32 @@
#!/usr/bin/env python3
-# Delete "set system ntp server <n> dynamic" option
+# Copyright 2018-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/>.
-import sys
+# Delete "set system ntp server <n> dynamic" option
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'ntp', 'server']):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'ntp', 'server']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete abandoned leaf node if found inside tag node for
# "set system ntp server <n> dynamic"
base = ['system', 'ntp', 'server']
for server in config.list_nodes(base):
if config.exists(base + [server, 'dynamic']):
config.delete(base + [server, 'dynamic'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ntp/1-to-2 b/src/migration-scripts/ntp/1-to-2
index fd1f15d91..fd7b08221 100755..100644
--- a/src/migration-scripts/ntp/1-to-2
+++ b/src/migration-scripts/ntp/1-to-2
@@ -1,72 +1,53 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3008: move from ntpd to chrony and migrate "system ntp" to "service ntp"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['system', 'ntp']
new_base_path = ['service', 'ntp']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-
-# 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']):
- config.set(['service'])
-
-# copy "system ntp" to "service ntp"
-config.copy(base_path, new_base_path)
-config.delete(base_path)
-
-# chrony does not support the preempt option, drop it
-for server in config.list_nodes(new_base_path + ['server']):
- server_base = new_base_path + ['server', server]
- if config.exists(server_base + ['preempt']):
- config.delete(server_base + ['preempt'])
-
-# Rename "allow-clients" -> "allow-client"
-if config.exists(new_base_path + ['allow-clients']):
- config.rename(new_base_path + ['allow-clients'], 'allow-client')
-
-# By default VyOS 1.3 allowed NTP queries for all networks - in chrony we
-# explicitly disable this behavior and clients need to be specified using the
-# allow-client CLI option. In order to be fully backwards compatible, we specify
-# 0.0.0.0/0 and ::/0 as allow networks if not specified otherwise explicitly.
-if not config.exists(new_base_path + ['allow-client']):
- config.set(new_base_path + ['allow-client', 'address'], value='0.0.0.0/0', replace=False)
- config.set(new_base_path + ['allow-client', 'address'], value='::/0', replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ 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']):
+ config.set(['service'])
+
+ # copy "system ntp" to "service ntp"
+ config.copy(base_path, new_base_path)
+ config.delete(base_path)
+
+ # chrony does not support the preempt option, drop it
+ for server in config.list_nodes(new_base_path + ['server']):
+ server_base = new_base_path + ['server', server]
+ if config.exists(server_base + ['preempt']):
+ config.delete(server_base + ['preempt'])
+
+ # Rename "allow-clients" -> "allow-client"
+ if config.exists(new_base_path + ['allow-clients']):
+ config.rename(new_base_path + ['allow-clients'], 'allow-client')
+
+ # By default VyOS 1.3 allowed NTP queries for all networks - in chrony we
+ # explicitly disable this behavior and clients need to be specified using the
+ # allow-client CLI option. In order to be fully backwards compatible, we specify
+ # 0.0.0.0/0 and ::/0 as allow networks if not specified otherwise explicitly.
+ if not config.exists(new_base_path + ['allow-client']):
+ config.set(new_base_path + ['allow-client', 'address'], value='0.0.0.0/0', replace=False)
+ config.set(new_base_path + ['allow-client', 'address'], value='::/0', replace=False)
diff --git a/src/migration-scripts/ntp/2-to-3 b/src/migration-scripts/ntp/2-to-3
index a4351845e..bbda90351 100755..100644
--- a/src/migration-scripts/ntp/2-to-3
+++ b/src/migration-scripts/ntp/2-to-3
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
+# This 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 program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5154: allow only one ip address per family for parameter 'listen-address'
# Allow only one interface for parameter 'interface'
# If more than one are specified, remove such entries
-import sys
-
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base_path = ['service', 'ntp']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv4(addr)]) > 1):
- for addr in config.return_values(base_path + ['listen-address']):
- if is_ipv4(addr):
- config.delete_value(base_path + ['listen-address'], addr)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv6(addr)]) > 1):
- for addr in config.return_values(base_path + ['listen-address']):
- if is_ipv6(addr):
- config.delete_value(base_path + ['listen-address'], addr)
+ if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv4(addr)]) > 1):
+ for addr in config.return_values(base_path + ['listen-address']):
+ if is_ipv4(addr):
+ config.delete_value(base_path + ['listen-address'], addr)
-if config.exists(base_path + ['interface']):
- if len(config.return_values(base_path + ['interface'])) > 1:
- config.delete(base_path + ['interface'])
+ if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv6(addr)]) > 1):
+ for addr in config.return_values(base_path + ['listen-address']):
+ if is_ipv6(addr):
+ config.delete_value(base_path + ['listen-address'], addr)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ if config.exists(base_path + ['interface']):
+ if len(config.return_values(base_path + ['interface'])) > 1:
+ config.delete(base_path + ['interface'])
diff --git a/src/migration-scripts/openconnect/0-to-1 b/src/migration-scripts/openconnect/0-to-1
index c64b16cb2..aa5a97eee 100755..100644
--- a/src/migration-scripts/openconnect/0-to-1
+++ b/src/migration-scripts/openconnect/0-to-1
@@ -1,25 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Update SSL to use PKI configuration
import os
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_private_key
@@ -27,109 +24,93 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'openconnect']
pki_base = ['pki']
-if not config.exists(base):
- exit(0)
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if not config.exists(base + ['ssl']):
- exit(0)
-
-x509_base = base + ['ssl']
-pki_name = 'openconnect'
-
-if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
-if config.exists(x509_base + ['ca-cert-file']):
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on openconnect config')
-
- config.delete(x509_base + ['ca-cert-file'])
-
-if config.exists(x509_base + ['cert-file']):
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on openconnect config')
-
- config.delete(x509_base + ['cert-file'])
-
-if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on openconnect config')
-
- config.delete(x509_base + ['key-file'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(base + ['ssl']):
+ return
+
+ x509_base = base + ['ssl']
+ pki_name = 'openconnect'
+
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on openconnect config')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on openconnect config')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on openconnect config')
+
+ config.delete(x509_base + ['key-file'])
diff --git a/src/migration-scripts/openconnect/1-to-2 b/src/migration-scripts/openconnect/1-to-2
index 7978aa56e..4f74b44df 100755..100644
--- a/src/migration-scripts/openconnect/1-to-2
+++ b/src/migration-scripts/openconnect/1-to-2
@@ -1,42 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete depricated outside-nexthop address
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
cfg_base = ['vpn', 'openconnect']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
+
if config.exists(cfg_base + ['authentication', 'mode']):
if config.return_value(cfg_base + ['authentication', 'mode']) == 'radius':
# if "mode value radius", change to "mode + valueless node radius"
@@ -46,9 +33,3 @@ else:
# if "mode local", change to "mode + node local value password"
config.delete_value(cfg_base + ['authentication', 'mode'], 'local')
config.set(cfg_base + ['authentication', 'mode', 'local'], value='password')
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/openconnect/2-to-3 b/src/migration-scripts/openconnect/2-to-3
index e78fc8a91..00e13ecb0 100755..100644
--- a/src/migration-scripts/openconnect/2-to-3
+++ b/src/migration-scripts/openconnect/2-to-3
@@ -1,50 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4982: Retain prior default TLS version (v1.0) when upgrading installations with existing openconnect configurations
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-
-config = ConfigTree(config_file)
cfg_base = ['vpn', 'openconnect']
-# bail out early if service is unconfigured
-if not config.exists(cfg_base):
- sys.exit(0)
-
-# new default is TLS 1.2 - set explicit old default value of TLS 1.0 for upgraded configurations to keep compatibility
-tls_min_path = cfg_base + ['tls-version-min']
-if not config.exists(tls_min_path):
- config.set(tls_min_path, value='1.0')
+def migrate(config: ConfigTree) -> None:
+ # bail out early if service is unconfigured
+ if not config.exists(cfg_base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ # new default is TLS 1.2 - set explicit old default value of TLS 1.0 for upgraded configurations to keep compatibility
+ tls_min_path = cfg_base + ['tls-version-min']
+ if not config.exists(tls_min_path):
+ config.set(tls_min_path, value='1.0')
diff --git a/src/migration-scripts/openvpn/0-to-1 b/src/migration-scripts/openvpn/0-to-1
index 24bb38d3c..e5db731ed 100755..100644
--- a/src/migration-scripts/openvpn/0-to-1
+++ b/src/migration-scripts/openvpn/0-to-1
@@ -1,26 +1,27 @@
-#!/usr/bin/env python3
+# 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/>.
# Removes outdated ciphers (DES and Blowfish) from OpenVPN configs
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['interfaces', 'openvpn']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['interfaces', 'openvpn']):
- # Nothing to do
- sys.exit(0)
-else:
ovpn_intfs = config.list_nodes(['interfaces', 'openvpn'])
for i in ovpn_intfs:
# Remove DES and Blowfish from 'encryption cipher'
@@ -40,10 +41,3 @@ else:
if config.exists(['interfaces', 'openvpn', i, 'encryption']) and \
(config.list_nodes(['interfaces', 'openvpn', i, 'encryption']) == []):
config.delete(['interfaces', 'openvpn', i, 'encryption'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/openvpn/1-to-2 b/src/migration-scripts/openvpn/1-to-2
index 1f82a2128..b7b7d4c77 100755..100644
--- a/src/migration-scripts/openvpn/1-to-2
+++ b/src/migration-scripts/openvpn/1-to-2
@@ -17,25 +17,13 @@
# Removes --cipher option (deprecated) from OpenVPN configs
# and moves it to --data-ciphers for server and client modes
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['interfaces', 'openvpn']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['interfaces', 'openvpn']):
- # Nothing to do
- sys.exit(0)
-else:
ovpn_intfs = config.list_nodes(['interfaces', 'openvpn'])
for i in ovpn_intfs:
# Remove 'encryption cipher' and add this value to 'encryption ncp-ciphers'
@@ -65,10 +53,3 @@ else:
for c in ncp_ciphers:
config.set(ncp_cipher_path, value=c, replace=False)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ospf/0-to-1 b/src/migration-scripts/ospf/0-to-1
index 4085423a2..a1f810960 100755..100644
--- a/src/migration-scripts/ospf/0-to-1
+++ b/src/migration-scripts/ospf/0-to-1
@@ -1,22 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3753: upgrade to FRR8 and move CLI options to better fit with the new FRR CLI
-from sys import argv
from vyos.configtree import ConfigTree
def ospf_passive_migration(config, ospf_base):
@@ -40,45 +38,29 @@ def ospf_passive_migration(config, ospf_base):
config.set_tag(ospf_base + ['interface'])
config.delete(ospf_base + ['passive-interface-exclude'])
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
ospfv3_base = ['protocols', 'ospfv3']
-if config.exists(ospfv3_base):
- area_base = ospfv3_base + ['area']
- if config.exists(area_base):
- for area in config.list_nodes(area_base):
- if not config.exists(area_base + [area, 'interface']):
- continue
- for interface in config.return_values(area_base + [area, 'interface']):
- config.set(ospfv3_base + ['interface', interface, 'area'], value=area)
- config.set_tag(ospfv3_base + ['interface'])
+def migrate(config: ConfigTree) -> None:
+ if config.exists(ospfv3_base):
+ area_base = ospfv3_base + ['area']
+ if config.exists(area_base):
+ for area in config.list_nodes(area_base):
+ if not config.exists(area_base + [area, 'interface']):
+ continue
- config.delete(area_base + [area, 'interface'])
+ for interface in config.return_values(area_base + [area, 'interface']):
+ config.set(ospfv3_base + ['interface', interface, 'area'], value=area)
+ config.set_tag(ospfv3_base + ['interface'])
-# Migrate OSPF syntax in default VRF
-ospf_base = ['protocols', 'ospf']
-ospf_passive_migration(config, ospf_base)
+ config.delete(area_base + [area, 'interface'])
-vrf_base = ['vrf', 'name']
-if config.exists(vrf_base):
- for vrf in config.list_nodes(vrf_base):
- vrf_ospf_base = vrf_base + [vrf, 'protocols', 'ospf']
- if config.exists(vrf_ospf_base):
- ospf_passive_migration(config, vrf_ospf_base)
+ # Migrate OSPF syntax in default VRF
+ ospf_base = ['protocols', 'ospf']
+ ospf_passive_migration(config, ospf_base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ vrf_base = ['vrf', 'name']
+ if config.exists(vrf_base):
+ for vrf in config.list_nodes(vrf_base):
+ vrf_ospf_base = vrf_base + [vrf, 'protocols', 'ospf']
+ if config.exists(vrf_ospf_base):
+ ospf_passive_migration(config, vrf_ospf_base)
diff --git a/src/migration-scripts/ospf/1-to-2 b/src/migration-scripts/ospf/1-to-2
index ba9499c60..5368d8dd7 100755..100644
--- a/src/migration-scripts/ospf/1-to-2
+++ b/src/migration-scripts/ospf/1-to-2
@@ -1,80 +1,60 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
ospf_base = ['protocols', 'ospf']
-# Check if OSPF is configured - if so, migrate the CLI node
-if config.exists(ospf_base):
- if config.exists(ospf_base + ['route-map']):
- tmp = config.return_value(ospf_base + ['route-map'])
-
- config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(ospf_base + ['route-map'])
-
-ospfv3_base = ['protocols', 'ospfv3']
-# Check if OSPFv3 is configured - if so, migrate the CLI node
-if config.exists(ospfv3_base):
- if config.exists(ospfv3_base + ['route-map']):
- tmp = config.return_value(ospfv3_base + ['route-map'])
-
- config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
- config.set_tag(['system', 'ipv6', 'protocol'])
- config.delete(ospfv3_base + ['route-map'])
-
-# Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so,
-# migrate the CLI node(s)
-if config.exists(['vrf', 'name']):
- for vrf in config.list_nodes(['vrf', 'name']):
- vrf_base = ['vrf', 'name', vrf]
- if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map'])
-
- config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ip', 'protocol', 'ospf'])
- config.delete(vrf_base + ['protocols', 'ospf', 'route-map'])
-
- if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']):
- tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map'])
-
- config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
- config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6'])
- config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Check if OSPF is configured - if so, migrate the CLI node
+ if config.exists(ospf_base):
+ if config.exists(ospf_base + ['route-map']):
+ tmp = config.return_value(ospf_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(ospf_base + ['route-map'])
+
+ ospfv3_base = ['protocols', 'ospfv3']
+ # Check if OSPFv3 is configured - if so, migrate the CLI node
+ if config.exists(ospfv3_base):
+ if config.exists(ospfv3_base + ['route-map']):
+ tmp = config.return_value(ospfv3_base + ['route-map'])
+
+ config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ipv6', 'protocol'])
+ config.delete(ospfv3_base + ['route-map'])
+
+ # Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so,
+ # migrate the CLI node(s)
+ if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'ospf'])
+ config.delete(vrf_base + ['protocols', 'ospf', 'route-map'])
+
+ if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map'])
+
+ config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6'])
+ config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map'])
diff --git a/src/migration-scripts/pim/0-to-1 b/src/migration-scripts/pim/0-to-1
index bf8af733c..ce24b23ba 100755..100644
--- a/src/migration-scripts/pim/0-to-1
+++ b/src/migration-scripts/pim/0-to-1
@@ -1,72 +1,54 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5736: igmp: migrate "protocols igmp" to "protocols pim"
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['protocols', 'igmp']
pim_base = ['protocols', 'pim']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-for interface in config.list_nodes(base + ['interface']):
- base_igmp_iface = base + ['interface', interface]
- pim_base_iface = pim_base + ['interface', interface]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- # Create IGMP note under PIM interface
- if not config.exists(pim_base_iface + ['igmp']):
- config.set(pim_base_iface + ['igmp'])
+ for interface in config.list_nodes(base + ['interface']):
+ base_igmp_iface = base + ['interface', interface]
+ pim_base_iface = pim_base + ['interface', interface]
- if config.exists(base_igmp_iface + ['join']):
- config.copy(base_igmp_iface + ['join'], pim_base_iface + ['igmp', 'join'])
- config.set_tag(pim_base_iface + ['igmp', 'join'])
+ # Create IGMP note under PIM interface
+ if not config.exists(pim_base_iface + ['igmp']):
+ config.set(pim_base_iface + ['igmp'])
- new_join_base = pim_base_iface + ['igmp', 'join']
- for address in config.list_nodes(new_join_base):
- if config.exists(new_join_base + [address, 'source']):
- config.rename(new_join_base + [address, 'source'], 'source-address')
+ if config.exists(base_igmp_iface + ['join']):
+ config.copy(base_igmp_iface + ['join'], pim_base_iface + ['igmp', 'join'])
+ config.set_tag(pim_base_iface + ['igmp', 'join'])
- if config.exists(base_igmp_iface + ['query-interval']):
- config.copy(base_igmp_iface + ['query-interval'], pim_base_iface + ['igmp', 'query-interval'])
+ new_join_base = pim_base_iface + ['igmp', 'join']
+ for address in config.list_nodes(new_join_base):
+ if config.exists(new_join_base + [address, 'source']):
+ config.rename(new_join_base + [address, 'source'], 'source-address')
- if config.exists(base_igmp_iface + ['query-max-response-time']):
- config.copy(base_igmp_iface + ['query-max-response-time'], pim_base_iface + ['igmp', 'query-max-response-time'])
+ if config.exists(base_igmp_iface + ['query-interval']):
+ config.copy(base_igmp_iface + ['query-interval'], pim_base_iface + ['igmp', 'query-interval'])
- if config.exists(base_igmp_iface + ['version']):
- config.copy(base_igmp_iface + ['version'], pim_base_iface + ['igmp', 'version'])
+ if config.exists(base_igmp_iface + ['query-max-response-time']):
+ config.copy(base_igmp_iface + ['query-max-response-time'], pim_base_iface + ['igmp', 'query-max-response-time'])
-config.delete(base)
+ if config.exists(base_igmp_iface + ['version']):
+ config.copy(base_igmp_iface + ['version'], pim_base_iface + ['igmp', 'version'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ config.delete(base)
diff --git a/src/migration-scripts/policy/0-to-1 b/src/migration-scripts/policy/0-to-1
index 8508b734a..837946c37 100755..100644
--- a/src/migration-scripts/policy/0-to-1
+++ b/src/migration-scripts/policy/0-to-1
@@ -1,65 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3631: route-map: migrate "set extcommunity-rt" and "set extcommunity-soo"
# to "set extcommunity rt|soo" to match FRR syntax
-
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy', 'route-map']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- if not config.exists(base + [route_map, 'rule']):
- continue
- for rule in config.list_nodes(base + [route_map, 'rule']):
- base_rule = base + [route_map, 'rule', rule]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- if config.exists(base_rule + ['set', 'extcommunity-rt']):
- tmp = config.return_value(base_rule + ['set', 'extcommunity-rt'])
- config.delete(base_rule + ['set', 'extcommunity-rt'])
- config.set(base_rule + ['set', 'extcommunity', 'rt'], value=tmp)
+ for route_map in config.list_nodes(base):
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ base_rule = base + [route_map, 'rule', rule]
+ if config.exists(base_rule + ['set', 'extcommunity-rt']):
+ tmp = config.return_value(base_rule + ['set', 'extcommunity-rt'])
+ config.delete(base_rule + ['set', 'extcommunity-rt'])
+ config.set(base_rule + ['set', 'extcommunity', 'rt'], value=tmp)
- if config.exists(base_rule + ['set', 'extcommunity-soo']):
- tmp = config.return_value(base_rule + ['set', 'extcommunity-soo'])
- config.delete(base_rule + ['set', 'extcommunity-soo'])
- config.set(base_rule + ['set', 'extcommunity', 'soo'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base_rule + ['set', 'extcommunity-soo']):
+ tmp = config.return_value(base_rule + ['set', 'extcommunity-soo'])
+ config.delete(base_rule + ['set', 'extcommunity-soo'])
+ config.set(base_rule + ['set', 'extcommunity', 'soo'], value=tmp)
diff --git a/src/migration-scripts/policy/1-to-2 b/src/migration-scripts/policy/1-to-2
index c7a983bba..ba3e48db0 100755..100644
--- a/src/migration-scripts/policy/1-to-2
+++ b/src/migration-scripts/policy/1-to-2
@@ -1,86 +1,67 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4170: rename "policy ipv6-route" to "policy route6" to match common
# IPv4/IPv6 schema
# T4178: Update tcp flags to use multi value node
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-if config.exists(base + ['ipv6-route']):
- config.rename(base + ['ipv6-route'],'route6')
- config.set_tag(['policy', 'route6'])
+ if config.exists(base + ['ipv6-route']):
+ config.rename(base + ['ipv6-route'],'route6')
+ config.set_tag(['policy', 'route6'])
-for route in ['route', 'route6']:
- if config.exists(base + [route]):
- for name in config.list_nodes(base + [route]):
- if config.exists(base + [route, name, 'rule']):
- for rule in config.list_nodes(base + [route, name, 'rule']):
- rule_tcp_flags = base + [route, name, 'rule', rule, 'tcp', 'flags']
+ for route in ['route', 'route6']:
+ if config.exists(base + [route]):
+ for name in config.list_nodes(base + [route]):
+ if config.exists(base + [route, name, 'rule']):
+ for rule in config.list_nodes(base + [route, name, 'rule']):
+ rule_tcp_flags = base + [route, name, 'rule', rule, 'tcp', 'flags']
- if config.exists(rule_tcp_flags):
- tmp = config.return_value(rule_tcp_flags)
- config.delete(rule_tcp_flags)
- for flag in tmp.split(","):
+ if config.exists(rule_tcp_flags):
+ tmp = config.return_value(rule_tcp_flags)
+ config.delete(rule_tcp_flags)
for flag in tmp.split(","):
- if flag[0] == '!':
- config.set(rule_tcp_flags + ['not', flag[1:].lower()])
- else:
- config.set(rule_tcp_flags + [flag.lower()])
+ for flag in tmp.split(","):
+ if flag[0] == '!':
+ config.set(rule_tcp_flags + ['not', flag[1:].lower()])
+ else:
+ config.set(rule_tcp_flags + [flag.lower()])
-if config.exists(['interfaces']):
- def if_policy_rename(config, path):
- if config.exists(path + ['policy', 'ipv6-route']):
- config.rename(path + ['policy', 'ipv6-route'], 'route6')
+ if config.exists(['interfaces']):
+ def if_policy_rename(config, path):
+ if config.exists(path + ['policy', 'ipv6-route']):
+ config.rename(path + ['policy', 'ipv6-route'], 'route6')
- for if_type in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', if_type]):
- if_path = ['interfaces', if_type, ifname]
- if_policy_rename(config, if_path)
+ for if_type in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', if_type]):
+ if_path = ['interfaces', if_type, ifname]
+ if_policy_rename(config, if_path)
- for vif_type in ['vif', 'vif-s']:
- if config.exists(if_path + [vif_type]):
- for vifname in config.list_nodes(if_path + [vif_type]):
- if_policy_rename(config, if_path + [vif_type, vifname])
+ for vif_type in ['vif', 'vif-s']:
+ if config.exists(if_path + [vif_type]):
+ for vifname in config.list_nodes(if_path + [vif_type]):
+ if_policy_rename(config, if_path + [vif_type, vifname])
- if config.exists(if_path + [vif_type, vifname, 'vif-c']):
- for vifcname in config.list_nodes(if_path + [vif_type, vifname, 'vif-c']):
- if_policy_rename(config, if_path + [vif_type, vifname, 'vif-c', vifcname])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(if_path + [vif_type, vifname, 'vif-c']):
+ for vifcname in config.list_nodes(if_path + [vif_type, vifname, 'vif-c']):
+ if_policy_rename(config, if_path + [vif_type, vifname, 'vif-c', vifcname])
diff --git a/src/migration-scripts/policy/2-to-3 b/src/migration-scripts/policy/2-to-3
index 8a62c8e6f..399a55387 100755..100644
--- a/src/migration-scripts/policy/2-to-3
+++ b/src/migration-scripts/policy/2-to-3
@@ -1,58 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3976: change cli
# from: set policy route-map FOO rule 10 match ipv6 nexthop 'h:h:h:h:h:h:h:h'
# to: set policy route-map FOO rule 10 match ipv6 nexthop address 'h:h:h:h:h:h:h:h'
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy', 'route-map']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- if not config.exists(base + [route_map, 'rule']):
- continue
- for rule in config.list_nodes(base + [route_map, 'rule']):
- base_rule = base + [route_map, 'rule', rule]
-
- if config.exists(base_rule + ['match', 'ipv6', 'nexthop']):
- tmp = config.return_value(base_rule + ['match', 'ipv6', 'nexthop'])
- config.delete(base_rule + ['match', 'ipv6', 'nexthop'])
- config.set(base_rule + ['match', 'ipv6', 'nexthop', 'address'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1) \ No newline at end of file
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for route_map in config.list_nodes(base):
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ base_rule = base + [route_map, 'rule', rule]
+
+ if config.exists(base_rule + ['match', 'ipv6', 'nexthop']):
+ tmp = config.return_value(base_rule + ['match', 'ipv6', 'nexthop'])
+ config.delete(base_rule + ['match', 'ipv6', 'nexthop'])
+ config.set(base_rule + ['match', 'ipv6', 'nexthop', 'address'], value=tmp)
diff --git a/src/migration-scripts/policy/3-to-4 b/src/migration-scripts/policy/3-to-4
index 476fa3af2..5d4959def 100755..100644
--- a/src/migration-scripts/policy/3-to-4
+++ b/src/migration-scripts/policy/3-to-4
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4660: change cli
# from: set policy route-map FOO rule 10 set community 'TEXT'
@@ -33,9 +32,6 @@
# Multiple value
# to: set policy route-map FOO rule 10 set extcommunity [rt|soo] <community>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
@@ -96,67 +92,52 @@ def extcommunity_migrate(config: ConfigTree, rule: list[str]) -> None:
config.set(rule + ['soo'], value=community, replace=False)
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name: str = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base: list[str] = ['policy', 'route-map']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- if not config.exists(base + [route_map, 'rule']):
- continue
- for rule in config.list_nodes(base + [route_map, 'rule']):
- base_rule: list[str] = base + [route_map, 'rule', rule, 'set']
-
- # IF additive presents in coummunity then comm-list is redundant
- isAdditive: bool = True
- #### Change Set community ########
- if config.exists(base_rule + ['community']):
- isAdditive = community_migrate(config,
- base_rule + ['community'])
-
- #### Change Set community-list delete migrate ########
- if config.exists(base_rule + ['comm-list', 'comm-list']):
- if isAdditive:
- tmp = config.return_value(
- base_rule + ['comm-list', 'comm-list'])
- config.delete(base_rule + ['comm-list'])
- config.set(base_rule + ['community', 'delete'], value=tmp)
- else:
- config.delete(base_rule + ['comm-list'])
-
- isAdditive = False
- #### Change Set large-community ########
- if config.exists(base_rule + ['large-community']):
- isAdditive = community_migrate(config,
- base_rule + ['large-community'])
-
- #### Change Set large-community delete by List ########
- if config.exists(base_rule + ['large-comm-list-delete']):
- if isAdditive:
- tmp = config.return_value(
- base_rule + ['large-comm-list-delete'])
- config.delete(base_rule + ['large-comm-list-delete'])
- config.set(base_rule + ['large-community', 'delete'],
- value=tmp)
- else:
- config.delete(base_rule + ['large-comm-list-delete'])
-
- #### Change Set extcommunity ########
- extcommunity_migrate(config, base_rule + ['extcommunity'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for route_map in config.list_nodes(base):
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ base_rule: list[str] = base + [route_map, 'rule', rule, 'set']
+
+ # IF additive presents in coummunity then comm-list is redundant
+ isAdditive: bool = True
+ #### Change Set community ########
+ if config.exists(base_rule + ['community']):
+ isAdditive = community_migrate(config,
+ base_rule + ['community'])
+
+ #### Change Set community-list delete migrate ########
+ if config.exists(base_rule + ['comm-list', 'comm-list']):
+ if isAdditive:
+ tmp = config.return_value(
+ base_rule + ['comm-list', 'comm-list'])
+ config.delete(base_rule + ['comm-list'])
+ config.set(base_rule + ['community', 'delete'], value=tmp)
+ else:
+ config.delete(base_rule + ['comm-list'])
+
+ isAdditive = False
+ #### Change Set large-community ########
+ if config.exists(base_rule + ['large-community']):
+ isAdditive = community_migrate(config,
+ base_rule + ['large-community'])
+
+ #### Change Set large-community delete by List ########
+ if config.exists(base_rule + ['large-comm-list-delete']):
+ if isAdditive:
+ tmp = config.return_value(
+ base_rule + ['large-comm-list-delete'])
+ config.delete(base_rule + ['large-comm-list-delete'])
+ config.set(base_rule + ['large-community', 'delete'],
+ value=tmp)
+ else:
+ config.delete(base_rule + ['large-comm-list-delete'])
+
+ #### Change Set extcommunity ########
+ extcommunity_migrate(config, base_rule + ['extcommunity'])
diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5
index 738850f67..0ecfdfd5e 100755..100644
--- a/src/migration-scripts/policy/4-to-5
+++ b/src/migration-scripts/policy/4-to-5
@@ -1,39 +1,24 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T2199: Migrate interface policy nodes to policy route <name> interface <ifname>
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base4 = ['policy', 'route']
base6 = ['policy', 'route6']
-config = ConfigTree(config_file)
-
def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None, vifc=None):
"""Delete unexpected policy on interfaces in cases when
@@ -55,35 +40,6 @@ def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None
config.delete(if_path + ['policy'])
-
-if not config.exists(base4) and not config.exists(base6):
- # Delete orphaned nodes on interfaces T5941
- for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- delete_orphaned_interface_policy(config, iftype, ifname)
-
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
- # Nothing to do
- exit(0)
-
def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
if_path = ['interfaces', iftype, ifname]
ifname_full = ifname
@@ -111,25 +67,40 @@ def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
config.delete(if_path + ['policy'])
-for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- migrate_interface(config, iftype, ifname)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base4) and not config.exists(base6):
+ # Delete orphaned nodes on interfaces T5941
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ delete_orphaned_interface_policy(config, iftype, ifname)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- migrate_interface(config, iftype, ifname, vif=vif)
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- migrate_interface(config, iftype, ifname, vifs=vifs)
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
+ # Nothing to do
+ return
+
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ migrate_interface(config, iftype, ifname)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ migrate_interface(config, iftype, ifname, vif=vif)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ migrate_interface(config, iftype, ifname, vifs=vifs)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
diff --git a/src/migration-scripts/policy/5-to-6 b/src/migration-scripts/policy/5-to-6
index 86287d578..acba0b4be 100755..100644
--- a/src/migration-scripts/policy/5-to-6
+++ b/src/migration-scripts/policy/5-to-6
@@ -1,62 +1,42 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5165: Migrate policy local-route rule <tag> destination|source
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base4 = ['policy', 'local-route']
base6 = ['policy', 'local-route6']
-config = ConfigTree(config_file)
-
-if not config.exists(base4) and not config.exists(base6):
- # Nothing to do
- exit(0)
-
-# replace 'policy local-route{v6} rule <tag> destination|source <x.x.x.x>'
-# => 'policy local-route{v6} rule <tag> destination|source address <x.x.x.x>'
-for base in [base4, base6]:
- if config.exists(base + ['rule']):
- for rule in config.list_nodes(base + ['rule']):
- dst_path = base + ['rule', rule, 'destination']
- src_path = base + ['rule', rule, 'source']
- # Destination
- if config.exists(dst_path):
- for dst_addr in config.return_values(dst_path):
- config.set(dst_path + ['address'], value=dst_addr, replace=False)
- # Source
- if config.exists(src_path):
- for src_addr in config.return_values(src_path):
- config.set(src_path + ['address'], value=src_addr, replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base4) and not config.exists(base6):
+ # Nothing to do
+ return
+
+ # replace 'policy local-route{v6} rule <tag> destination|source <x.x.x.x>'
+ # => 'policy local-route{v6} rule <tag> destination|source address <x.x.x.x>'
+ for base in [base4, base6]:
+ if config.exists(base + ['rule']):
+ for rule in config.list_nodes(base + ['rule']):
+ dst_path = base + ['rule', rule, 'destination']
+ src_path = base + ['rule', rule, 'source']
+ # Destination
+ if config.exists(dst_path):
+ for dst_addr in config.return_values(dst_path):
+ config.set(dst_path + ['address'], value=dst_addr, replace=False)
+ # Source
+ if config.exists(src_path):
+ for src_addr in config.return_values(src_path):
+ config.set(src_path + ['address'], value=src_addr, replace=False)
diff --git a/src/migration-scripts/policy/6-to-7 b/src/migration-scripts/policy/6-to-7
index cdefc6837..69aa703c5 100755..100644
--- a/src/migration-scripts/policy/6-to-7
+++ b/src/migration-scripts/policy/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5729: Switch to valueless whenever is possible.
# From
@@ -22,55 +21,36 @@
# set policy [route | route6] ... rule <rule> log
# Remove command if log=disable
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for family in ['route', 'route6']:
- if config.exists(base + [family]):
-
- for policy_name in config.list_nodes(base + [family]):
- if config.exists(base + [family, policy_name, 'rule']):
- for rule in config.list_nodes(base + [family, policy_name, 'rule']):
- # Log
- if config.exists(base + [family, policy_name, 'rule', rule, 'log']):
- log_value = config.return_value(base + [family, policy_name, 'rule', rule, 'log'])
- config.delete(base + [family, policy_name, 'rule', rule, 'log'])
- if log_value == 'enable':
- config.set(base + [family, policy_name, 'rule', rule, 'log'])
- # State
- if config.exists(base + [family, policy_name, 'rule', rule, 'state']):
- flag_enable = 'False'
- for state in ['established', 'invalid', 'new', 'related']:
- if config.exists(base + [family, policy_name, 'rule', rule, 'state', state]):
- state_value = config.return_value(base + [family, policy_name, 'rule', rule, 'state', state])
- config.delete(base + [family, policy_name, 'rule', rule, 'state', state])
- if state_value == 'enable':
- config.set(base + [family, policy_name, 'rule', rule, 'state'], value=state, replace=False)
- flag_enable = 'True'
- if flag_enable == 'False':
- config.delete(base + [family, policy_name, 'rule', rule, 'state'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for family in ['route', 'route6']:
+ if config.exists(base + [family]):
+
+ for policy_name in config.list_nodes(base + [family]):
+ if config.exists(base + [family, policy_name, 'rule']):
+ for rule in config.list_nodes(base + [family, policy_name, 'rule']):
+ # Log
+ if config.exists(base + [family, policy_name, 'rule', rule, 'log']):
+ log_value = config.return_value(base + [family, policy_name, 'rule', rule, 'log'])
+ config.delete(base + [family, policy_name, 'rule', rule, 'log'])
+ if log_value == 'enable':
+ config.set(base + [family, policy_name, 'rule', rule, 'log'])
+ # State
+ if config.exists(base + [family, policy_name, 'rule', rule, 'state']):
+ flag_enable = 'False'
+ for state in ['established', 'invalid', 'new', 'related']:
+ if config.exists(base + [family, policy_name, 'rule', rule, 'state', state]):
+ state_value = config.return_value(base + [family, policy_name, 'rule', rule, 'state', state])
+ config.delete(base + [family, policy_name, 'rule', rule, 'state', state])
+ if state_value == 'enable':
+ config.set(base + [family, policy_name, 'rule', rule, 'state'], value=state, replace=False)
+ flag_enable = 'True'
+ if flag_enable == 'False':
+ config.delete(base + [family, policy_name, 'rule', rule, 'state'])
diff --git a/src/migration-scripts/policy/7-to-8 b/src/migration-scripts/policy/7-to-8
index 73eece1a6..a887f37fe 100755..100644
--- a/src/migration-scripts/policy/7-to-8
+++ b/src/migration-scripts/policy/7-to-8
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5834: Rename 'enable-default-log' to 'default-log'
# From
@@ -20,37 +19,18 @@
# To
# set policy [route | route 6] <route> default-log
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for family in ['route', 'route6']:
- if config.exists(base + [family]):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
- for policy_name in config.list_nodes(base + [family]):
- if config.exists(base + [family, policy_name, 'enable-default-log']):
- config.rename(base + [family, policy_name, 'enable-default-log'], 'default-log')
+ for family in ['route', 'route6']:
+ if config.exists(base + [family]):
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for policy_name in config.list_nodes(base + [family]):
+ if config.exists(base + [family, policy_name, 'enable-default-log']):
+ config.rename(base + [family, policy_name, 'enable-default-log'], 'default-log')
diff --git a/src/migration-scripts/pppoe-server/0-to-1 b/src/migration-scripts/pppoe-server/0-to-1
index 4d36f8545..8c9a24fbe 100755..100644
--- a/src/migration-scripts/pppoe-server/0-to-1
+++ b/src/migration-scripts/pppoe-server/0-to-1
@@ -1,50 +1,33 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Convert "service pppoe-server authentication radius-server node key"
# to: "service pppoe-server authentication radius-server node secret"
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-ctree = ConfigTree(config_file)
base = ['service', 'pppoe-server', 'authentication', 'radius-server']
-if not ctree.exists(base):
- # Nothing to do
- exit(0)
-else:
+def migrate(ctree: ConfigTree) -> None:
+ if not ctree.exists(base):
+ # Nothing to do
+ return
+
nodes = ctree.list_nodes(base)
for node in nodes:
if ctree.exists(base + [node, 'key']):
val = ctree.return_value(base + [node, 'key'])
ctree.set(base + [node, 'secret'], value=val, replace=False)
ctree.delete(base + [node, 'key'])
-
- try:
- open(file_name,'w').write(ctree.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/1-to-2 b/src/migration-scripts/pppoe-server/1-to-2
index b266893c0..c9c968bff 100755..100644
--- a/src/migration-scripts/pppoe-server/1-to-2
+++ b/src/migration-scripts/pppoe-server/1-to-2
@@ -1,39 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# change mppe node to a leaf node with value prefer
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['service', 'pppoe-server']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['service', 'pppoe-server']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
mppe_base = base + ['ppp-options', 'mppe']
if config.exists(mppe_base):
# get current values
@@ -49,10 +39,3 @@ else:
config.set(mppe_base, value='prefer')
elif 'deny' in tmp:
config.set(mppe_base, value='deny')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/2-to-3 b/src/migration-scripts/pppoe-server/2-to-3
index a7be060df..160cffdf8 100755..100644
--- a/src/migration-scripts/pppoe-server/2-to-3
+++ b/src/migration-scripts/pppoe-server/2-to-3
@@ -1,48 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Convert "service pppoe-server interface ethX" to: "service pppoe-server interface ethX {}"
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-ctree = ConfigTree(config_file)
cbase = ['service', 'pppoe-server','interface']
-if not ctree.exists(cbase):
- exit(0)
-else:
+def migrate(ctree: ConfigTree) -> None:
+ if not ctree.exists(cbase):
+ return
+
nics = ctree.return_values(cbase)
# convert leafNode to a tagNode
ctree.set(cbase)
ctree.set_tag(cbase)
for nic in nics:
ctree.set(cbase + [nic])
-
- try:
- open(file_name,'w').write(ctree.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/3-to-4 b/src/migration-scripts/pppoe-server/3-to-4
index 477ed6f22..29dd62201 100755..100644
--- a/src/migration-scripts/pppoe-server/3-to-4
+++ b/src/migration-scripts/pppoe-server/3-to-4
@@ -1,39 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - remove primary/secondary identifier from nameserver
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
@@ -130,10 +119,3 @@ else:
prefix = p.split(',')[0]
mask = p.split(',')[1]
config.set(ipv6_base + ['delegate', prefix, 'delegation-prefix'], value=mask)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pppoe-server/4-to-5 b/src/migration-scripts/pppoe-server/4-to-5
index 5850db673..03fbfb247 100755..100644
--- a/src/migration-scripts/pppoe-server/4-to-5
+++ b/src/migration-scripts/pppoe-server/4-to-5
@@ -1,49 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 local-ip to gateway-address
from vyos.configtree import ConfigTree
-from sys import argv
-from sys import exit
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-file_name = argv[1]
+base_path = ['service', 'pppoe-server']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base_path = ['service', 'pppoe-server']
-if not config.exists(base_path):
- # Nothing to do
- exit(0)
-else:
config_gw = base_path + ['local-ip']
if config.exists(config_gw):
config.rename(config_gw, 'gateway-address')
config.delete(config_gw)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
diff --git a/src/migration-scripts/pppoe-server/5-to-6 b/src/migration-scripts/pppoe-server/5-to-6
index e079ae684..13de8f8d2 100755..100644
--- a/src/migration-scripts/pppoe-server/5-to-6
+++ b/src/migration-scripts/pppoe-server/5-to-6
@@ -1,52 +1,33 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T4703: merge vlan-id and vlan-range to vlan CLI node
from vyos.configtree import ConfigTree
-from sys import argv
-from sys import exit
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base_path = ['service', 'pppoe-server', 'interface']
-if not config.exists(base_path):
- # Nothing to do
- exit(0)
-
-for interface in config.list_nodes(base_path):
- for vlan in ['vlan-id', 'vlan-range']:
- if config.exists(base_path + [interface, vlan]):
- print(interface, vlan)
- for tmp in config.return_values(base_path + [interface, vlan]):
- config.set(base_path + [interface, 'vlan'], value=tmp, replace=False)
- config.delete(base_path + [interface, vlan])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
+
+ for interface in config.list_nodes(base_path):
+ for vlan in ['vlan-id', 'vlan-range']:
+ if config.exists(base_path + [interface, vlan]):
+ print(interface, vlan)
+ for tmp in config.return_values(base_path + [interface, vlan]):
+ config.set(base_path + [interface, 'vlan'], value=tmp, replace=False)
+ config.delete(base_path + [interface, vlan])
diff --git a/src/migration-scripts/pppoe-server/6-to-7 b/src/migration-scripts/pppoe-server/6-to-7
index d51c1c9d8..79745a0c6 100755..100644
--- a/src/migration-scripts/pppoe-server/6-to-7
+++ b/src/migration-scripts/pppoe-server/6-to-7
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'start-stop' migrate to namedpool 'default-range-pool'
@@ -24,94 +23,77 @@
# If there are not named pools, namedless pool will be default.
# 2. If authentication mode = 'radius' then namedless pool will be default
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.base import Warning
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-default_pool = ''
-range_pool_name = 'default-range-pool'
-
-#Default nameless pools migrations
-if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
- def is_legalrange(ip1: str, ip2: str, mask: str):
- from ipaddress import IPv4Interface
- interface1 = IPv4Interface(f'{ip1}/{mask}')
- interface2 = IPv4Interface(f'{ip2}/{mask}')
- return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
- start_ip = config.return_value(pool_base + ['start'])
- stop_ip = config.return_value(pool_base + ['stop'])
- if is_legalrange(start_ip, stop_ip, '24'):
- ip_range = f'{start_ip}-{stop_ip}'
- config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(pool_base):
+ return
+
+ default_pool = ''
+ range_pool_name = 'default-range-pool'
+
+ #Default nameless pools migrations
+ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+ def is_legalrange(ip1: str, ip2: str, mask: str):
+ from ipaddress import IPv4Interface
+ interface1 = IPv4Interface(f'{ip1}/{mask}')
+ interface2 = IPv4Interface(f'{ip2}/{mask}')
+ return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+
+ start_ip = config.return_value(pool_base + ['start'])
+ stop_ip = config.return_value(pool_base + ['stop'])
+ if is_legalrange(start_ip, stop_ip, '24'):
+ ip_range = f'{start_ip}-{stop_ip}'
+ config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+ default_pool = range_pool_name
+ else:
+ Warning(
+ f'PPPoE client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+ config.delete(pool_base + ['start'])
+ config.delete(pool_base + ['stop'])
+
+ if config.exists(pool_base + ['subnet']):
default_pool = range_pool_name
- else:
- Warning(
- f'PPPoE client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
- config.delete(pool_base + ['start'])
- config.delete(pool_base + ['stop'])
-
-if config.exists(pool_base + ['subnet']):
- default_pool = range_pool_name
- for subnet in config.return_values(pool_base + ['subnet']):
- config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
- config.delete(pool_base + ['subnet'])
-
-gateway = ''
-if config.exists(base + ['gateway-address']):
- gateway = config.return_value(base + ['gateway-address'])
-
-#named pool migration
-namedpools_base = pool_base + ['name']
-if config.exists(namedpools_base):
- if config.exists(base + ['authentication', 'mode']):
- if config.return_value(base + ['authentication', 'mode']) == 'local':
- if config.list_nodes(namedpools_base):
- default_pool = config.list_nodes(namedpools_base)[0]
-
- for pool_name in config.list_nodes(namedpools_base):
- pool_path = namedpools_base + [pool_name]
- if config.exists(pool_path + ['subnet']):
- subnet = config.return_value(pool_path + ['subnet'])
- config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
- if config.exists(pool_path + ['next-pool']):
- next_pool = config.return_value(pool_path + ['next-pool'])
- config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
- if not gateway:
- if config.exists(pool_path + ['gateway-address']):
- gateway = config.return_value(pool_path + ['gateway-address'])
-
- config.delete(namedpools_base)
-
-if gateway:
- config.set(base + ['gateway-address'], value=gateway)
-if default_pool:
- config.set(base + ['default-pool'], value=default_pool)
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ for subnet in config.return_values(pool_base + ['subnet']):
+ config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+ config.delete(pool_base + ['subnet'])
+
+ gateway = ''
+ if config.exists(base + ['gateway-address']):
+ gateway = config.return_value(base + ['gateway-address'])
+
+ #named pool migration
+ namedpools_base = pool_base + ['name']
+ if config.exists(namedpools_base):
+ if config.exists(base + ['authentication', 'mode']):
+ if config.return_value(base + ['authentication', 'mode']) == 'local':
+ if config.list_nodes(namedpools_base):
+ default_pool = config.list_nodes(namedpools_base)[0]
+
+ for pool_name in config.list_nodes(namedpools_base):
+ pool_path = namedpools_base + [pool_name]
+ if config.exists(pool_path + ['subnet']):
+ subnet = config.return_value(pool_path + ['subnet'])
+ config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
+ if config.exists(pool_path + ['next-pool']):
+ next_pool = config.return_value(pool_path + ['next-pool'])
+ config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
+ if not gateway:
+ if config.exists(pool_path + ['gateway-address']):
+ gateway = config.return_value(pool_path + ['gateway-address'])
+
+ config.delete(namedpools_base)
+
+ if gateway:
+ config.set(base + ['gateway-address'], value=gateway)
+ if default_pool:
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/pppoe-server/7-to-8 b/src/migration-scripts/pppoe-server/7-to-8
index 0381f0bf9..90e4fa053 100755..100644
--- a/src/migration-scripts/pppoe-server/7-to-8
+++ b/src/migration-scripts/pppoe-server/7-to-8
@@ -1,58 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['service', 'pppoe-server']
+pool_base = base + ['client-ipv6-pool']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ if not config.exists(pool_base):
+ return
-config = ConfigTree(config_file)
-base = ['service', 'pppoe-server']
-pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
-
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/pppoe-server/8-to-9 b/src/migration-scripts/pppoe-server/8-to-9
index 4932a766f..e7e0aaa2c 100755..100644
--- a/src/migration-scripts/pppoe-server/8-to-9
+++ b/src/migration-scripts/pppoe-server/8-to-9
@@ -1,66 +1,48 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Change from 'ccp' to 'disable-ccp' in ppp-option section
# Migration ipv6 options
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server']
-if not config.exists(base):
- exit(0)
-
-#CCP migration
-if config.exists(base + ['ppp-options', 'ccp']):
- config.delete(base + ['ppp-options', 'ccp'])
-else:
- config.set(base + ['ppp-options', 'disable-ccp'])
-
-#IPV6 options migrations
-if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
- intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
- if intf_peer_id == 'ipv4':
- intf_peer_id = 'ipv4-addr'
- config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-intf-id']):
- intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
- config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
- config.delete(base + ['ppp-options','ipv6-intf-id'])
-
-if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
- config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
- config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #CCP migration
+ if config.exists(base + ['ppp-options', 'ccp']):
+ config.delete(base + ['ppp-options', 'ccp'])
+ else:
+ config.set(base + ['ppp-options', 'disable-ccp'])
+
+ #IPV6 options migrations
+ if config.exists(base + ['ppp-options','ipv6-peer-intf-id']):
+ intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id'])
+ if intf_peer_id == 'ipv4':
+ intf_peer_id = 'ipv4-addr'
+ config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-peer-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-intf-id']):
+ intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id'])
+ config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True)
+ config.delete(base + ['ppp-options','ipv6-intf-id'])
+
+ if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']):
+ config.set(base + ['ppp-options','ipv6-accept-peer-interface-id'])
+ config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id'])
diff --git a/src/migration-scripts/pppoe-server/9-to-10 b/src/migration-scripts/pppoe-server/9-to-10
index e0c782f04..d3475e8ff 100755..100644
--- a/src/migration-scripts/pppoe-server/9-to-10
+++ b/src/migration-scripts/pppoe-server/9-to-10
@@ -1,56 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 of pado-delay options
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['service', 'pppoe-server', 'pado-delay']
-if not config.exists(base):
- exit(0)
-pado_delay = {}
-for delay in config.list_nodes(base):
- sessions = config.return_value(base + [delay, 'sessions'])
- pado_delay[delay] = sessions
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-# need to define delay for latest sessions
-sorted_delays = dict(sorted(pado_delay.items(), key=lambda k_v: int(k_v[1])))
-last_delay = list(sorted_delays)[-1]
+ pado_delay = {}
+ for delay in config.list_nodes(base):
+ sessions = config.return_value(base + [delay, 'sessions'])
+ pado_delay[delay] = sessions
-# Rename last delay -> disable
-tmp = base + [last_delay]
-if config.exists(tmp):
- config.rename(tmp, 'disable')
+ # need to define delay for latest sessions
+ sorted_delays = dict(sorted(pado_delay.items(), key=lambda k_v: int(k_v[1])))
+ last_delay = list(sorted_delays)[-1]
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Rename last delay -> disable
+ tmp = base + [last_delay]
+ if config.exists(tmp):
+ config.rename(tmp, 'disable')
diff --git a/src/migration-scripts/pptp/0-to-1 b/src/migration-scripts/pptp/0-to-1
index 1b7697c11..dd0b6f57e 100755..100644
--- a/src/migration-scripts/pptp/0-to-1
+++ b/src/migration-scripts/pptp/0-to-1
@@ -1,29 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2018-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/>.
# Unclutter PPTP VPN configuiration - move radius-server top level tag
# nodes to a regular node which now also configures the radius source address
# used when querying a radius server
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_base = ['vpn', 'pptp', 'remote-access', 'authentication']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_base):
+ # Nothing to do
+ return
-cfg_base = ['vpn', 'pptp', 'remote-access', 'authentication']
-if not config.exists(cfg_base):
- # Nothing to do
- sys.exit(0)
-else:
# Migrate "vpn pptp authentication radius-source-address" to new
# "vpn pptp authentication radius source-address"
if config.exists(cfg_base + ['radius-source-address']):
@@ -50,10 +52,3 @@ else:
# delete top level tag node
if config.exists(cfg_base + ['radius-server']):
config.delete(cfg_base + ['radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/pptp/1-to-2 b/src/migration-scripts/pptp/1-to-2
index 99624dceb..1e7601193 100755..100644
--- a/src/migration-scripts/pptp/1-to-2
+++ b/src/migration-scripts/pptp/1-to-2
@@ -1,41 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 dns-servers node to common name-servers
# - remove radios req-limit node
-from sys import argv, exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
+base = ['vpn', 'pptp', 'remote-access']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['vpn', 'pptp', 'remote-access']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
if config.exists(dns_base):
@@ -62,10 +51,3 @@ else:
for server in config.list_nodes(radius_base + ['server']):
if config.exists(radius_base + ['server', server, 'req-limit']):
config.delete(radius_base + ['server', server, 'req-limit'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/pptp/2-to-3 b/src/migration-scripts/pptp/2-to-3
index 42c4dedf4..8b0d6d865 100755..100644
--- a/src/migration-scripts/pptp/2-to-3
+++ b/src/migration-scripts/pptp/2-to-3
@@ -1,73 +1,55 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'start-stop' migrate to namedpool 'default-range-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.base import Warning
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'pptp', 'remote-access']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-range_pool_name = 'default-range-pool'
-
-if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
- def is_legalrange(ip1: str, ip2: str, mask: str):
- from ipaddress import IPv4Interface
- interface1 = IPv4Interface(f'{ip1}/{mask}')
- interface2 = IPv4Interface(f'{ip2}/{mask}')
- return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
-
- start_ip = config.return_value(pool_base + ['start'])
- stop_ip = config.return_value(pool_base + ['stop'])
- if is_legalrange(start_ip, stop_ip, '24'):
- ip_range = f'{start_ip}-{stop_ip}'
- config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
- config.set(base + ['default-pool'], value=range_pool_name)
- else:
- Warning(
- f'PPTP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
-
- config.delete(pool_base + ['start'])
- config.delete(pool_base + ['stop'])
-# format as tag node
-config.set_tag(pool_base)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(pool_base):
+ return
+
+ range_pool_name = 'default-range-pool'
+
+ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+ def is_legalrange(ip1: str, ip2: str, mask: str):
+ from ipaddress import IPv4Interface
+ interface1 = IPv4Interface(f'{ip1}/{mask}')
+ interface2 = IPv4Interface(f'{ip2}/{mask}')
+ return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+
+ start_ip = config.return_value(pool_base + ['start'])
+ stop_ip = config.return_value(pool_base + ['stop'])
+ if is_legalrange(start_ip, stop_ip, '24'):
+ ip_range = f'{start_ip}-{stop_ip}'
+ config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+ config.set(base + ['default-pool'], value=range_pool_name)
+ else:
+ Warning(
+ f'PPTP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+
+ config.delete(pool_base + ['start'])
+ config.delete(pool_base + ['stop'])
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/pptp/3-to-4 b/src/migration-scripts/pptp/3-to-4
index ebd343028..2dabd8475 100755..100644
--- a/src/migration-scripts/pptp/3-to-4
+++ b/src/migration-scripts/pptp/3-to-4
@@ -1,48 +1,29 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Move 'mppe' from 'authentication' node to 'ppp-options'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'pptp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['authentication','mppe']):
- mppe = config.return_value(base + ['authentication','mppe'])
- config.set(base + ['ppp-options', 'mppe'], value=mppe, replace=True)
- config.delete(base + ['authentication','mppe'])
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base + ['authentication','mppe']):
+ mppe = config.return_value(base + ['authentication','mppe'])
+ config.set(base + ['ppp-options', 'mppe'], value=mppe, replace=True)
+ config.delete(base + ['authentication','mppe'])
diff --git a/src/migration-scripts/pptp/4-to-5 b/src/migration-scripts/pptp/4-to-5
index 83632b6d8..c906f58c4 100755..100644
--- a/src/migration-scripts/pptp/4-to-5
+++ b/src/migration-scripts/pptp/4-to-5
@@ -1,63 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Move 'require' from 'protocols' in 'authentication' node
# - Migrate to new default values in radius timeout and acct-timeout
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'pptp', 'remote-access']
-if not config.exists(base):
- exit(0)
-
-#migrate require to protocols
-require_path = base + ['authentication', 'require']
-if config.exists(require_path):
- protocols = list(config.return_values(require_path))
- for protocol in protocols:
- config.set(base + ['authentication', 'protocols'], value=protocol,
- replace=False)
- config.delete(require_path)
-else:
- config.set(base + ['authentication', 'protocols'], value='mschap-v2')
-
-radius_path = base + ['authentication', 'radius']
-if config.exists(radius_path):
- if not config.exists(radius_path + ['timeout']):
- config.set(radius_path + ['timeout'], value=3)
- if not config.exists(radius_path + ['acct-timeout']):
- config.set(radius_path + ['acct-timeout'], value=3)
-
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ #migrate require to protocols
+ require_path = base + ['authentication', 'require']
+ if config.exists(require_path):
+ protocols = list(config.return_values(require_path))
+ for protocol in protocols:
+ config.set(base + ['authentication', 'protocols'], value=protocol,
+ replace=False)
+ config.delete(require_path)
+ else:
+ config.set(base + ['authentication', 'protocols'], value='mschap-v2')
+
+ radius_path = base + ['authentication', 'radius']
+ if config.exists(radius_path):
+ if not config.exists(radius_path + ['timeout']):
+ config.set(radius_path + ['timeout'], value=3)
+ if not config.exists(radius_path + ['acct-timeout']):
+ config.set(radius_path + ['acct-timeout'], value=3)
diff --git a/src/migration-scripts/qos/1-to-2 b/src/migration-scripts/qos/1-to-2
index 666811e5a..c43d8fa47 100755..100644
--- a/src/migration-scripts/qos/1-to-2
+++ b/src/migration-scripts/qos/1-to-2
@@ -1,20 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from sys import argv,exit
+# 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.base import Warning
from vyos.configtree import ConfigTree
@@ -28,18 +25,6 @@ def bandwidth_percent_to_val(interface, percent) -> int:
speed = int(speed) *1000000 # convert to MBit/s
return speed * int(percent) // 100 # integer division
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-base = ['traffic-policy']
-config = ConfigTree(config_file)
-
def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None, vifc=None):
"""Delete unexpected traffic-policy on interfaces in cases when
@@ -62,133 +47,122 @@ def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None
config.delete(if_path + ['traffic-policy'])
-if not config.exists(base):
- # Delete orphaned nodes on interfaces T5941
- for iftype in config.list_nodes(['interfaces']):
- for ifname in config.list_nodes(['interfaces', iftype]):
- delete_orphaned_interface_policy(config, iftype, ifname)
-
- if config.exists(['interfaces', iftype, ifname, 'vif']):
- for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
- delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s']):
- for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
-
- if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
- delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
- # Nothing to do
- exit(0)
-
-iface_config = {}
-
-if config.exists(['interfaces']):
- def get_qos(config, interface, interface_base):
- if config.exists(interface_base):
- tmp = { interface : {} }
- if config.exists(interface_base + ['in']):
- tmp[interface]['ingress'] = config.return_value(interface_base + ['in'])
- if config.exists(interface_base + ['out']):
- tmp[interface]['egress'] = config.return_value(interface_base + ['out'])
- config.delete(interface_base)
- return tmp
- return None
-
- # Migrate "interface ethernet eth0 traffic-policy in|out" to "qos interface eth0 ingress|egress"
- for type in config.list_nodes(['interfaces']):
- for interface in config.list_nodes(['interfaces', type]):
- interface_base = ['interfaces', type, interface, 'traffic-policy']
- tmp = get_qos(config, interface, interface_base)
- if tmp: iface_config.update(tmp)
-
- vif_path = ['interfaces', type, interface, 'vif']
- if config.exists(vif_path):
- for vif in config.list_nodes(vif_path):
- vif_interface_base = vif_path + [vif, 'traffic-policy']
- ifname = f'{interface}.{vif}'
- tmp = get_qos(config, ifname, vif_interface_base)
- if tmp: iface_config.update(tmp)
-
- vif_s_path = ['interfaces', type, interface, 'vif-s']
- if config.exists(vif_s_path):
- for vif_s in config.list_nodes(vif_s_path):
- vif_s_interface_base = vif_s_path + [vif_s, 'traffic-policy']
- ifname = f'{interface}.{vif_s}'
- tmp = get_qos(config, ifname, vif_s_interface_base)
- if tmp: iface_config.update(tmp)
-
- # vif-c interfaces MUST be migrated before their parent vif-s
- # interface as the migrate_*() functions delete the path!
- vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
- if config.exists(vif_c_path):
- for vif_c in config.list_nodes(vif_c_path):
- vif_c_interface_base = vif_c_path + [vif_c, 'traffic-policy']
- ifname = f'{interface}.{vif_s}.{vif_c}'
- tmp = get_qos(config, ifname, vif_s_interface_base)
- if tmp: iface_config.update(tmp)
-
-
-# Now we have the information which interface uses which QoS policy.
-# Interface binding will be moved to the qos CLi tree
-config.set(['qos'])
-config.copy(base, ['qos', 'policy'])
-config.delete(base)
-
-# Now map the interface policy binding to the new CLI syntax
-if len(iface_config):
- config.set(['qos', 'interface'])
- config.set_tag(['qos', 'interface'])
-
-for interface, interface_config in iface_config.items():
- config.set(['qos', 'interface', interface])
- config.set_tag(['qos', 'interface', interface])
- if 'ingress' in interface_config:
- config.set(['qos', 'interface', interface, 'ingress'], value=interface_config['ingress'])
- if 'egress' in interface_config:
- config.set(['qos', 'interface', interface, 'egress'], value=interface_config['egress'])
-
-# Remove "burst" CLI node from network emulator
-netem_base = ['qos', 'policy', 'network-emulator']
-if config.exists(netem_base):
- for policy_name in config.list_nodes(netem_base):
- if config.exists(netem_base + [policy_name, 'burst']):
- config.delete(netem_base + [policy_name, 'burst'])
-
-# Change bandwidth unit MBit -> mbit as tc only supports mbit
-base = ['qos', 'policy']
-if config.exists(base):
- for policy_type in config.list_nodes(base):
- for policy in config.list_nodes(base + [policy_type]):
- policy_base = base + [policy_type, policy]
- if config.exists(policy_base + ['bandwidth']):
- tmp = config.return_value(policy_base + ['bandwidth'])
- config.set(policy_base + ['bandwidth'], value=tmp.lower())
-
- if config.exists(policy_base + ['class']):
- for cls in config.list_nodes(policy_base + ['class']):
- cls_base = policy_base + ['class', cls]
- if config.exists(cls_base + ['bandwidth']):
- tmp = config.return_value(cls_base + ['bandwidth'])
- config.set(cls_base + ['bandwidth'], value=tmp.lower())
-
- if config.exists(policy_base + ['default', 'bandwidth']):
+def migrate(config: ConfigTree) -> None:
+ base = ['traffic-policy']
+
+ if not config.exists(base):
+ # Delete orphaned nodes on interfaces T5941
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ delete_orphaned_interface_policy(config, iftype, ifname)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
+
+ # Nothing to do
+ return
+
+ iface_config = {}
+
+ if config.exists(['interfaces']):
+ def get_qos(config, interface, interface_base):
+ if config.exists(interface_base):
+ tmp = { interface : {} }
+ if config.exists(interface_base + ['in']):
+ tmp[interface]['ingress'] = config.return_value(interface_base + ['in'])
+ if config.exists(interface_base + ['out']):
+ tmp[interface]['egress'] = config.return_value(interface_base + ['out'])
+ config.delete(interface_base)
+ return tmp
+ return None
+
+ # Migrate "interface ethernet eth0 traffic-policy in|out" to "qos interface eth0 ingress|egress"
+ for type in config.list_nodes(['interfaces']):
+ for interface in config.list_nodes(['interfaces', type]):
+ interface_base = ['interfaces', type, interface, 'traffic-policy']
+ tmp = get_qos(config, interface, interface_base)
+ if tmp: iface_config.update(tmp)
+
+ vif_path = ['interfaces', type, interface, 'vif']
+ if config.exists(vif_path):
+ for vif in config.list_nodes(vif_path):
+ vif_interface_base = vif_path + [vif, 'traffic-policy']
+ ifname = f'{interface}.{vif}'
+ tmp = get_qos(config, ifname, vif_interface_base)
+ if tmp: iface_config.update(tmp)
+
+ vif_s_path = ['interfaces', type, interface, 'vif-s']
+ if config.exists(vif_s_path):
+ for vif_s in config.list_nodes(vif_s_path):
+ vif_s_interface_base = vif_s_path + [vif_s, 'traffic-policy']
+ ifname = f'{interface}.{vif_s}'
+ tmp = get_qos(config, ifname, vif_s_interface_base)
+ if tmp: iface_config.update(tmp)
+
+ # vif-c interfaces MUST be migrated before their parent vif-s
+ # interface as the migrate_*() functions delete the path!
+ vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
+ if config.exists(vif_c_path):
+ for vif_c in config.list_nodes(vif_c_path):
+ vif_c_interface_base = vif_c_path + [vif_c, 'traffic-policy']
+ ifname = f'{interface}.{vif_s}.{vif_c}'
+ tmp = get_qos(config, ifname, vif_s_interface_base)
+ if tmp: iface_config.update(tmp)
+
+
+ # Now we have the information which interface uses which QoS policy.
+ # Interface binding will be moved to the qos CLi tree
+ config.set(['qos'])
+ config.copy(base, ['qos', 'policy'])
+ config.delete(base)
+
+ # Now map the interface policy binding to the new CLI syntax
+ if len(iface_config):
+ config.set(['qos', 'interface'])
+ config.set_tag(['qos', 'interface'])
+
+ for interface, interface_config in iface_config.items():
+ config.set(['qos', 'interface', interface])
+ config.set_tag(['qos', 'interface', interface])
+ if 'ingress' in interface_config:
+ config.set(['qos', 'interface', interface, 'ingress'], value=interface_config['ingress'])
+ if 'egress' in interface_config:
+ config.set(['qos', 'interface', interface, 'egress'], value=interface_config['egress'])
+
+ # Remove "burst" CLI node from network emulator
+ netem_base = ['qos', 'policy', 'network-emulator']
+ if config.exists(netem_base):
+ for policy_name in config.list_nodes(netem_base):
+ if config.exists(netem_base + [policy_name, 'burst']):
+ config.delete(netem_base + [policy_name, 'burst'])
+
+ # Change bandwidth unit MBit -> mbit as tc only supports mbit
+ base = ['qos', 'policy']
+ if config.exists(base):
+ for policy_type in config.list_nodes(base):
+ for policy in config.list_nodes(base + [policy_type]):
+ policy_base = base + [policy_type, policy]
+ if config.exists(policy_base + ['bandwidth']):
+ tmp = config.return_value(policy_base + ['bandwidth'])
+ config.set(policy_base + ['bandwidth'], value=tmp.lower())
+
+ if config.exists(policy_base + ['class']):
+ for cls in config.list_nodes(policy_base + ['class']):
+ cls_base = policy_base + ['class', cls]
+ if config.exists(cls_base + ['bandwidth']):
+ tmp = config.return_value(cls_base + ['bandwidth'])
+ config.set(cls_base + ['bandwidth'], value=tmp.lower())
+
if config.exists(policy_base + ['default', 'bandwidth']):
- tmp = config.return_value(policy_base + ['default', 'bandwidth'])
- config.set(policy_base + ['default', 'bandwidth'], value=tmp.lower())
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(policy_base + ['default', 'bandwidth']):
+ tmp = config.return_value(policy_base + ['default', 'bandwidth'])
+ config.set(policy_base + ['default', 'bandwidth'], value=tmp.lower())
diff --git a/src/migration-scripts/quagga/10-to-11 b/src/migration-scripts/quagga/10-to-11
index 0ed4f5df6..15dbbb193 100755..100644
--- a/src/migration-scripts/quagga/10-to-11
+++ b/src/migration-scripts/quagga/10-to-11
@@ -1,51 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
static_base = ['protocols', 'static']
-# Check if static routes are configured - if so, migrate the CLI node
-if config.exists(static_base):
- if config.exists(static_base + ['route-map']):
- tmp = config.return_value(static_base + ['route-map'])
- config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp)
- config.set_tag(['system', 'ip', 'protocol'])
- config.delete(static_base + ['route-map'])
+def migrate(config: ConfigTree) -> None:
+ # Check if static routes are configured - if so, migrate the CLI node
+ if config.exists(static_base):
+ if config.exists(static_base + ['route-map']):
+ tmp = config.return_value(static_base + ['route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(static_base + ['route-map'])
diff --git a/src/migration-scripts/quagga/2-to-3 b/src/migration-scripts/quagga/2-to-3
index 96b56da70..d62c387ba 100755..100644
--- a/src/migration-scripts/quagga/2-to-3
+++ b/src/migration-scripts/quagga/2-to-3
@@ -1,37 +1,21 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2018 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-
-import sys
+# 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
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
def migrate_neighbor(config, neighbor_path, neighbor):
if config.exists(neighbor_path):
neighbors = config.list_nodes(neighbor_path)
@@ -117,10 +101,11 @@ def migrate_neighbor(config, neighbor_path, neighbor):
config.delete(neighbor_path + [neighbor, 'disable-send-community'])
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
+
# Just to avoid writing it so many times
af_path = ['address-family', 'ipv4-unicast']
@@ -132,7 +117,7 @@ else:
bgp_path = ['protocols', 'bgp', asn]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
## Move global IPv4-specific BGP options to "address-family ipv4-unicast"
@@ -194,10 +179,3 @@ else:
config.set(bgp_path + af_path + ['redistribute', redistribute, 'route-map'], value=redist_route_map)
config.delete(redistribute_path)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/quagga/3-to-4 b/src/migration-scripts/quagga/3-to-4
index 1e8c8e2f2..81cf139f6 100755..100644
--- a/src/migration-scripts/quagga/3-to-4
+++ b/src/migration-scripts/quagga/3-to-4
@@ -1,20 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
+# 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/>.
# Between 1.2.3 and 1.2.4, FRR added per-neighbor enforce-first-as option.
# Unfortunately they also removed the global enforce-first-as option,
@@ -23,26 +20,14 @@
# To emulate the effect of the original option, we insert it in every neighbor
# if the config used to have the original global option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
# Check if BGP is actually configured and obtain the ASN
asn_list = config.list_nodes(['protocols', 'bgp'])
if asn_list:
@@ -50,7 +35,7 @@ else:
asn = asn_list[0]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
# Check if BGP enforce-first-as option is set
enforce_first_as_path = ['protocols', 'bgp', asn, 'parameters', 'enforce-first-as']
@@ -64,13 +49,4 @@ else:
config.set(['protocols', 'bgp', asn, 'neighbor', p, 'enforce-first-as'])
else:
# Do nothing
- sys.exit(0)
-
- # Save a new configuration file
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
-
+ return
diff --git a/src/migration-scripts/quagga/4-to-5 b/src/migration-scripts/quagga/4-to-5
index fcb496a9c..27b995431 100755..100644
--- a/src/migration-scripts/quagga/4-to-5
+++ b/src/migration-scripts/quagga/4-to-5
@@ -1,41 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-#
-
-import sys
+# 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
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
# Check if BGP is actually configured and obtain the ASN
asn_list = config.list_nodes(['protocols', 'bgp'])
if asn_list:
@@ -43,7 +28,7 @@ else:
asn = asn_list[0]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
# Check if BGP scan-time parameter exist
scan_time_param = ['protocols', 'bgp', asn, 'parameters', 'scan-time']
@@ -52,12 +37,4 @@ else:
config.delete(scan_time_param)
else:
# Do nothing
- sys.exit(0)
-
- # Save a new configuration file
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ return
diff --git a/src/migration-scripts/quagga/5-to-6 b/src/migration-scripts/quagga/5-to-6
index f075fc2e7..08fd070de 100755..100644
--- a/src/migration-scripts/quagga/5-to-6
+++ b/src/migration-scripts/quagga/5-to-6
@@ -1,42 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# * Remove parameter 'disable-network-import-check' which, as implemented,
-# had no effect on boot.
-
-import sys
+# 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
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['protocols', 'bgp']):
- # Nothing to do
- sys.exit(0)
-else:
# Check if BGP is actually configured and obtain the ASN
asn_list = config.list_nodes(['protocols', 'bgp'])
if asn_list:
@@ -44,7 +28,7 @@ else:
asn = asn_list[0]
else:
# There's actually no BGP, just its empty shell
- sys.exit(0)
+ return
# Check if BGP parameter disable-network-import-check exists
param = ['protocols', 'bgp', asn, 'parameters', 'disable-network-import-check']
@@ -53,11 +37,4 @@ else:
config.delete(param)
else:
# Do nothing
- sys.exit(0)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ return
diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7
index ed295a95c..095baac03 100755..100644
--- a/src/migration-scripts/quagga/6-to-7
+++ b/src/migration-scripts/quagga/6-to-7
@@ -1,116 +1,97 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T3037, BGP address-family ipv6-unicast capability dynamic does not exist in
# FRR, there is only a base, per neighbor dynamic capability, migrate config
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# Check if BGP is actually configured and obtain the ASN
-asn_list = config.list_nodes(base)
-if asn_list:
- # There's always just one BGP node, if any
- bgp_base = base + [asn_list[0]]
-
- for neighbor_type in ['neighbor', 'peer-group']:
- if not config.exists(bgp_base + [neighbor_type]):
- continue
- for neighbor in config.list_nodes(bgp_base + [neighbor_type]):
- # T2844 - add IPv4 AFI disable-send-community support
- send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community']
- if config.exists(send_comm_path):
- new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast']
- config.set(new_base)
- config.copy(send_comm_path, new_base + ['disable-send-community'])
- config.delete(send_comm_path)
-
- cap_dynamic = False
- peer_group = None
- for afi in ['ipv4-unicast', 'ipv6-unicast']:
- afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi]
- # Exit loop early if AFI does not exist
- if not config.exists(afi_path):
- continue
-
- cap_path = afi_path + ['capability', 'dynamic']
- if config.exists(cap_path):
- cap_dynamic = True
- config.delete(cap_path)
-
- # We have now successfully migrated the address-family
- # specific dynamic capability to the neighbor/peer-group
- # level. If this has been the only option under the
- # address-family nodes, we can clean them up by checking if
- # no other nodes are left under that tree and if so, delete
- # the parent.
- #
- # We walk from the most inner node to the most outer one.
- cleanup = -1
- while len(config.list_nodes(cap_path[:cleanup])) == 0:
- config.delete(cap_path[:cleanup])
- cleanup -= 1
-
- peer_group_path = afi_path + ['peer-group']
- if config.exists(peer_group_path):
- if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or
- (is_ipv6(neighbor) and afi == 'ipv6-unicast')):
- peer_group = config.return_value(peer_group_path)
-
- config.delete(peer_group_path)
-
- # We have now successfully migrated the address-family
- # specific peer-group to the neighbor level. If this has
- # been the only option under the address-family nodes, we
- # can clean them up by checking if no other nodes are left
- # under that tree and if so, delete the parent.
- #
- # We walk from the most inner node to the most outer one.
- cleanup = -1
- while len(config.list_nodes(peer_group_path[:cleanup])) == 0:
- config.delete(peer_group_path[:cleanup])
- cleanup -= 1
-
- if cap_dynamic:
- config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic'])
- if peer_group:
- config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Check if BGP is actually configured and obtain the ASN
+ asn_list = config.list_nodes(base)
+ if asn_list:
+ # There's always just one BGP node, if any
+ bgp_base = base + [asn_list[0]]
+
+ for neighbor_type in ['neighbor', 'peer-group']:
+ if not config.exists(bgp_base + [neighbor_type]):
+ continue
+ for neighbor in config.list_nodes(bgp_base + [neighbor_type]):
+ # T2844 - add IPv4 AFI disable-send-community support
+ send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community']
+ if config.exists(send_comm_path):
+ new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast']
+ config.set(new_base)
+ config.copy(send_comm_path, new_base + ['disable-send-community'])
+ config.delete(send_comm_path)
+
+ cap_dynamic = False
+ peer_group = None
+ for afi in ['ipv4-unicast', 'ipv6-unicast']:
+ afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi]
+ # Exit loop early if AFI does not exist
+ if not config.exists(afi_path):
+ continue
+
+ cap_path = afi_path + ['capability', 'dynamic']
+ if config.exists(cap_path):
+ cap_dynamic = True
+ config.delete(cap_path)
+
+ # We have now successfully migrated the address-family
+ # specific dynamic capability to the neighbor/peer-group
+ # level. If this has been the only option under the
+ # address-family nodes, we can clean them up by checking if
+ # no other nodes are left under that tree and if so, delete
+ # the parent.
+ #
+ # We walk from the most inner node to the most outer one.
+ cleanup = -1
+ while len(config.list_nodes(cap_path[:cleanup])) == 0:
+ config.delete(cap_path[:cleanup])
+ cleanup -= 1
+
+ peer_group_path = afi_path + ['peer-group']
+ if config.exists(peer_group_path):
+ if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or
+ (is_ipv6(neighbor) and afi == 'ipv6-unicast')):
+ peer_group = config.return_value(peer_group_path)
+
+ config.delete(peer_group_path)
+
+ # We have now successfully migrated the address-family
+ # specific peer-group to the neighbor level. If this has
+ # been the only option under the address-family nodes, we
+ # can clean them up by checking if no other nodes are left
+ # under that tree and if so, delete the parent.
+ #
+ # We walk from the most inner node to the most outer one.
+ cleanup = -1
+ while len(config.list_nodes(peer_group_path[:cleanup])) == 0:
+ config.delete(peer_group_path[:cleanup])
+ cleanup -= 1
+
+ if cap_dynamic:
+ config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic'])
+ if peer_group:
+ config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group)
diff --git a/src/migration-scripts/quagga/7-to-8 b/src/migration-scripts/quagga/7-to-8
index 8f11bf390..d9de26d15 100755..100644
--- a/src/migration-scripts/quagga/7-to-8
+++ b/src/migration-scripts/quagga/7-to-8
@@ -1,61 +1,42 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T3391: Migrate "maximum-paths" setting from "protocols bgp asn maximum-paths"
# under the IPv4 address-family tree. Reason is we currently have no way in
# configuring this for IPv6 address-family. This mimics the FRR configuration.
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'bgp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# Check if BGP is actually configured and obtain the ASN
-asn_list = config.list_nodes(base)
-if asn_list:
- # There's always just one BGP node, if any
- bgp_base = base + [asn_list[0]]
-
- maximum_paths = bgp_base + ['maximum-paths']
- if config.exists(maximum_paths):
- for bgp_type in ['ebgp', 'ibgp']:
- if config.exists(maximum_paths + [bgp_type]):
- new_base = bgp_base + ['address-family', 'ipv4-unicast', 'maximum-paths']
- config.set(new_base)
- config.copy(maximum_paths + [bgp_type], new_base + [bgp_type])
- config.delete(maximum_paths)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # Check if BGP is actually configured and obtain the ASN
+ asn_list = config.list_nodes(base)
+ if asn_list:
+ # There's always just one BGP node, if any
+ bgp_base = base + [asn_list[0]]
+
+ maximum_paths = bgp_base + ['maximum-paths']
+ if config.exists(maximum_paths):
+ for bgp_type in ['ebgp', 'ibgp']:
+ if config.exists(maximum_paths + [bgp_type]):
+ new_base = bgp_base + ['address-family', 'ipv4-unicast', 'maximum-paths']
+ config.set(new_base)
+ config.copy(maximum_paths + [bgp_type], new_base + [bgp_type])
+ config.delete(maximum_paths)
diff --git a/src/migration-scripts/quagga/8-to-9 b/src/migration-scripts/quagga/8-to-9
index 0f683d5a1..eece6c15d 100755..100644
--- a/src/migration-scripts/quagga/8-to-9
+++ b/src/migration-scripts/quagga/8-to-9
@@ -1,24 +1,20 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T2450: drop interface-route and interface-route6 from "protocols static"
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
def migrate_interface_route(config, base, path, route_route6):
@@ -84,54 +80,38 @@ def migrate_route(config, base, path, route_route6):
config.rename(vrf_path, 'vrf')
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['protocols', 'static']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ # Migrate interface-route into route
+ migrate_interface_route(config, base, ['interface-route'], 'route')
-base = ['protocols', 'static']
+ # Migrate interface-route6 into route6
+ migrate_interface_route(config, base, ['interface-route6'], 'route6')
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
+ # Cleanup nodes inside route
+ migrate_route(config, base, ['route'], 'route')
-# Migrate interface-route into route
-migrate_interface_route(config, base, ['interface-route'], 'route')
+ # Cleanup nodes inside route6
+ migrate_route(config, base, ['route6'], 'route6')
-# Migrate interface-route6 into route6
-migrate_interface_route(config, base, ['interface-route6'], 'route6')
+ #
+ # PBR table cleanup
+ table_path = base + ['table']
+ if config.exists(table_path):
+ for table in config.list_nodes(table_path):
+ # Migrate interface-route into route
+ migrate_interface_route(config, table_path + [table], ['interface-route'], 'route')
-# Cleanup nodes inside route
-migrate_route(config, base, ['route'], 'route')
+ # Migrate interface-route6 into route6
+ migrate_interface_route(config, table_path + [table], ['interface-route6'], 'route6')
-# Cleanup nodes inside route6
-migrate_route(config, base, ['route6'], 'route6')
+ # Cleanup nodes inside route
+ migrate_route(config, table_path + [table], ['route'], 'route')
-#
-# PBR table cleanup
-table_path = base + ['table']
-if config.exists(table_path):
- for table in config.list_nodes(table_path):
- # Migrate interface-route into route
- migrate_interface_route(config, table_path + [table], ['interface-route'], 'route')
-
- # Migrate interface-route6 into route6
- migrate_interface_route(config, table_path + [table], ['interface-route6'], 'route6')
-
- # Cleanup nodes inside route
- migrate_route(config, table_path + [table], ['route'], 'route')
-
- # Cleanup nodes inside route6
- migrate_route(config, table_path + [table], ['route6'], 'route6')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Cleanup nodes inside route6
+ migrate_route(config, table_path + [table], ['route6'], 'route6')
diff --git a/src/migration-scripts/quagga/9-to-10 b/src/migration-scripts/quagga/9-to-10
index 3731762f7..4ac1f0b7d 100755..100644
--- a/src/migration-scripts/quagga/9-to-10
+++ b/src/migration-scripts/quagga/9-to-10
@@ -1,62 +1,42 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# re-organize route-map as-path
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['policy', 'route-map']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for route_map in config.list_nodes(base):
- # Bail out Early
- if not config.exists(base + [route_map, 'rule']):
- continue
-
- for rule in config.list_nodes(base + [route_map, 'rule']):
- rule_base = base + [route_map, 'rule', rule]
- if config.exists(rule_base + ['set', 'as-path-exclude']):
- tmp = config.return_value(rule_base + ['set', 'as-path-exclude'])
- config.delete(rule_base + ['set', 'as-path-exclude'])
- config.set(rule_base + ['set', 'as-path', 'exclude'], value=tmp)
-
- if config.exists(rule_base + ['set', 'as-path-prepend']):
- tmp = config.return_value(rule_base + ['set', 'as-path-prepend'])
- config.delete(rule_base + ['set', 'as-path-prepend'])
- config.set(rule_base + ['set', 'as-path', 'prepend'], value=tmp)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for route_map in config.list_nodes(base):
+ # Bail out Early
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ rule_base = base + [route_map, 'rule', rule]
+ if config.exists(rule_base + ['set', 'as-path-exclude']):
+ tmp = config.return_value(rule_base + ['set', 'as-path-exclude'])
+ config.delete(rule_base + ['set', 'as-path-exclude'])
+ config.set(rule_base + ['set', 'as-path', 'exclude'], value=tmp)
+
+ if config.exists(rule_base + ['set', 'as-path-prepend']):
+ tmp = config.return_value(rule_base + ['set', 'as-path-prepend'])
+ config.delete(rule_base + ['set', 'as-path-prepend'])
+ config.set(rule_base + ['set', 'as-path', 'prepend'], value=tmp)
diff --git a/src/migration-scripts/reverse-proxy/0-to-1 b/src/migration-scripts/reverse-proxy/0-to-1
index d61493815..b495474a6 100755..100644
--- a/src/migration-scripts/reverse-proxy/0-to-1
+++ b/src/migration-scripts/reverse-proxy/0-to-1
@@ -1,48 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6409: Remove unused 'backend bk-example parameters' node
-from sys import argv, exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['load-balancing', 'reverse-proxy', 'backend']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# we need to run this for every configured network
-for backend in config.list_nodes(base):
- param_node = base + [backend, 'parameters']
- if config.exists(param_node):
- config.delete(param_node)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # we need to run this for every configured network
+ for backend in config.list_nodes(base):
+ param_node = base + [backend, 'parameters']
+ if config.exists(param_node):
+ config.delete(param_node)
diff --git a/src/migration-scripts/rip/0-to-1 b/src/migration-scripts/rip/0-to-1
index 08a866374..6d41bcf58 100755..100644
--- a/src/migration-scripts/rip/0-to-1
+++ b/src/migration-scripts/rip/0-to-1
@@ -1,51 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T5150: Rework CLI definitions to apply route-maps between routing daemons
# and zebra/kernel
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
ripng_base = ['protocols', 'ripng']
-# Check if RIPng is configured - if so, migrate the CLI node
-if config.exists(ripng_base):
- if config.exists(ripng_base + ['route-map']):
- tmp = config.return_value(ripng_base + ['route-map'])
- config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp)
- config.set_tag(['system', 'ipv6', 'protocol'])
- config.delete(ripng_base + ['route-map'])
+def migrate(config: ConfigTree) -> None:
+ # Check if RIPng is configured - if so, migrate the CLI node
+ if config.exists(ripng_base):
+ if config.exists(ripng_base + ['route-map']):
+ tmp = config.return_value(ripng_base + ['route-map'])
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ipv6', 'protocol'])
+ config.delete(ripng_base + ['route-map'])
diff --git a/src/migration-scripts/rpki/0-to-1 b/src/migration-scripts/rpki/0-to-1
index a7b5d07d5..b6e781fa9 100755..100644
--- a/src/migration-scripts/rpki/0-to-1
+++ b/src/migration-scripts/rpki/0-to-1
@@ -1,63 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import exit
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'rpki']
-config = ConfigTree(config_file)
-
-# Nothing to do
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['cache']):
- preference = 1
- for cache in config.list_nodes(base + ['cache']):
- address_node = base + ['cache', cache, 'address']
- if config.exists(address_node):
- address = config.return_value(address_node)
- # We do not longer support the address leafNode, RPKI cache server
- # IP address is now used from the tagNode
- config.delete(address_node)
- # VyOS 1.2 had no per instance preference, setting new defaults
- config.set(base + ['cache', cache, 'preference'], value=preference)
- # Increase preference for the next caching peer - actually VyOS 1.2
- # supported only one but better save then sorry (T3253)
- preference += 1
-
- # T3293: If the RPKI cache name equals the configured address,
- # renaming is not possible, as rename expects the new path to not
- # exist.
- if not config.exists(base + ['cache', address]):
- config.rename(base + ['cache', cache], address)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Nothing to do
+ if not config.exists(base):
+ return
+
+ if config.exists(base + ['cache']):
+ preference = 1
+ for cache in config.list_nodes(base + ['cache']):
+ address_node = base + ['cache', cache, 'address']
+ if config.exists(address_node):
+ address = config.return_value(address_node)
+ # We do not longer support the address leafNode, RPKI cache server
+ # IP address is now used from the tagNode
+ config.delete(address_node)
+ # VyOS 1.2 had no per instance preference, setting new defaults
+ config.set(base + ['cache', cache, 'preference'], value=preference)
+ # Increase preference for the next caching peer - actually VyOS 1.2
+ # supported only one but better save then sorry (T3253)
+ preference += 1
+
+ # T3293: If the RPKI cache name equals the configured address,
+ # renaming is not possible, as rename expects the new path to not
+ # exist.
+ if not config.exists(base + ['cache', address]):
+ config.rename(base + ['cache', cache], address)
diff --git a/src/migration-scripts/rpki/1-to-2 b/src/migration-scripts/rpki/1-to-2
index 50d4a3dfc..855236d6c 100755..100644
--- a/src/migration-scripts/rpki/1-to-2
+++ b/src/migration-scripts/rpki/1-to-2
@@ -1,73 +1,53 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T6011: rpki: known-hosts-file is no longer supported bxy FRR CLI,
# remove VyOS CLI node
-from sys import exit
-from sys import argv
-
from vyos.configtree import ConfigTree
from vyos.pki import OPENSSH_KEY_BEGIN
from vyos.pki import OPENSSH_KEY_END
from vyos.utils.file import read_file
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'rpki']
-config = ConfigTree(config_file)
-
-# Nothing to do
-if not config.exists(base):
- exit(0)
-
-if config.exists(base + ['cache']):
- for cache in config.list_nodes(base + ['cache']):
- ssh_node = base + ['cache', cache, 'ssh']
- if config.exists(ssh_node + ['known-hosts-file']):
- config.delete(ssh_node + ['known-hosts-file'])
-
- if config.exists(base + ['cache', cache, 'ssh']):
- private_key_node = base + ['cache', cache, 'ssh', 'private-key-file']
- private_key_file = config.return_value(private_key_node)
- private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','')
-
- public_key_node = base + ['cache', cache, 'ssh', 'public-key-file']
- public_key_file = config.return_value(public_key_node)
- public_key = read_file(public_key_file).split()
-
- config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key)
- config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1])
- config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0])
- config.set_tag(['pki', 'openssh'])
- config.set(ssh_node + ['key'], value=f'rpki-{cache}')
-
- config.delete(private_key_node)
- config.delete(public_key_node)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ # Nothing to do
+ if not config.exists(base):
+ return
+
+ if config.exists(base + ['cache']):
+ for cache in config.list_nodes(base + ['cache']):
+ ssh_node = base + ['cache', cache, 'ssh']
+ if config.exists(ssh_node + ['known-hosts-file']):
+ config.delete(ssh_node + ['known-hosts-file'])
+
+ if config.exists(base + ['cache', cache, 'ssh']):
+ private_key_node = base + ['cache', cache, 'ssh', 'private-key-file']
+ private_key_file = config.return_value(private_key_node)
+ private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','')
+
+ public_key_node = base + ['cache', cache, 'ssh', 'public-key-file']
+ public_key_file = config.return_value(public_key_node)
+ public_key = read_file(public_key_file).split()
+
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key)
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1])
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0])
+ config.set_tag(['pki', 'openssh'])
+ config.set(ssh_node + ['key'], value=f'rpki-{cache}')
+
+ config.delete(private_key_node)
+ config.delete(public_key_node)
diff --git a/src/migration-scripts/salt/0-to-1 b/src/migration-scripts/salt/0-to-1
index 481d9de8f..3990a88dc 100755..100644
--- a/src/migration-scripts/salt/0-to-1
+++ b/src/migration-scripts/salt/0-to-1
@@ -1,43 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Delete log_file, log_level and user nodes
# rename hash_type to hash
# rename mine_interval to interval
-from sys import argv,exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['service', 'salt-minion']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-else:
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
# delete nodes which are now populated with sane defaults
for node in ['log_file', 'log_level', 'user']:
@@ -49,10 +36,3 @@ else:
if config.exists(base + ['mine_interval']):
config.rename(base + ['mine_interval'], 'interval')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/snmp/0-to-1 b/src/migration-scripts/snmp/0-to-1
index b1e61b958..03b190cb7 100755..100644
--- a/src/migration-scripts/snmp/0-to-1
+++ b/src/migration-scripts/snmp/0-to-1
@@ -1,38 +1,27 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2019 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
config_base = ['service', 'snmp', 'v3']
-if not config.exists(config_base):
- # Nothing to do
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(config_base):
+ # Nothing to do
+ return
+
# we no longer support a per trap target engine ID (https://vyos.dev/T818)
if config.exists(config_base + ['v3', 'trap-target']):
for target in config.list_nodes(config_base + ['v3', 'trap-target']):
@@ -47,10 +36,3 @@ else:
# https://vyos.dev/T1769
if config.exists(config_base + ['v3', 'tsm']):
config.delete(config_base + ['v3', 'tsm'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/snmp/1-to-2 b/src/migration-scripts/snmp/1-to-2
index e02cd1aa1..0120f8acb 100755..100644
--- a/src/migration-scripts/snmp/1-to-2
+++ b/src/migration-scripts/snmp/1-to-2
@@ -1,22 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv, exit
from vyos.configtree import ConfigTree
+# We no longer support hashed values prefixed with '0x' to unclutter
+# CLI and also calculate the hases in advance instead of retrieving
+# them after service startup - which was always a bad idea
+prefix = '0x'
+
def migrate_keys(config, path):
# authentication: rename node 'encrypted-key' -> 'encrypted-password'
config_path_auth = path + ['auth', 'encrypted-key']
@@ -42,48 +45,26 @@ def migrate_keys(config, path):
tmp = tmp.replace(prefix, '')
config.set(config_path_priv, value=tmp)
-if __name__ == '__main__':
- if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
-
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
config_base = ['service', 'snmp', 'v3']
if not config.exists(config_base):
# Nothing to do
- exit(0)
- else:
- # We no longer support hashed values prefixed with '0x' to unclutter
- # CLI and also calculate the hases in advance instead of retrieving
- # them after service startup - which was always a bad idea
- prefix = '0x'
-
- config_engineid = config_base + ['engineid']
- if config.exists(config_engineid):
- tmp = config.return_value(config_engineid)
- if tmp.startswith(prefix):
- tmp = tmp.replace(prefix, '')
- config.set(config_engineid, value=tmp)
+ return
- config_user = config_base + ['user']
- if config.exists(config_user):
- for user in config.list_nodes(config_user):
- migrate_keys(config, config_user + [user])
+ config_engineid = config_base + ['engineid']
+ if config.exists(config_engineid):
+ tmp = config.return_value(config_engineid)
+ if tmp.startswith(prefix):
+ tmp = tmp.replace(prefix, '')
+ config.set(config_engineid, value=tmp)
- config_trap = config_base + ['trap-target']
- if config.exists(config_trap):
- for trap in config.list_nodes(config_trap):
- migrate_keys(config, config_trap + [trap])
+ config_user = config_base + ['user']
+ if config.exists(config_user):
+ for user in config.list_nodes(config_user):
+ migrate_keys(config, config_user + [user])
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config_trap = config_base + ['trap-target']
+ if config.exists(config_trap):
+ for trap in config.list_nodes(config_trap):
+ migrate_keys(config, config_trap + [trap])
diff --git a/src/migration-scripts/snmp/2-to-3 b/src/migration-scripts/snmp/2-to-3
index ab9b5dcba..6d828b619 100755..100644
--- a/src/migration-scripts/snmp/2-to-3
+++ b/src/migration-scripts/snmp/2-to-3
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T4857: Implement FRR SNMP recomendations
# cli changes from:
@@ -20,35 +19,15 @@
# To
# set service snmp oid-enable ip-forward
-from sys import argv
-from sys import exit
-
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service snmp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['oid-enable']):
- config.delete(base + ['oid-enable'])
- config.set(base + ['oid-enable'], 'ip-forward')
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(base + ['oid-enable']):
+ config.delete(base + ['oid-enable'])
+ config.set(base + ['oid-enable'], 'ip-forward')
diff --git a/src/migration-scripts/ssh/0-to-1 b/src/migration-scripts/ssh/0-to-1
index 2595599ac..65b68f509 100755..100644
--- a/src/migration-scripts/ssh/0-to-1
+++ b/src/migration-scripts/ssh/0-to-1
@@ -1,32 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2020-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/>.
# Delete "service ssh allow-root" option
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['service', 'ssh', 'allow-root']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['service', 'ssh', 'allow-root']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete node with abandoned command
config.delete(['service', 'ssh', 'allow-root'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/ssh/1-to-2 b/src/migration-scripts/ssh/1-to-2
index 79d65d7d4..b601db3b4 100755..100644
--- a/src/migration-scripts/ssh/1-to-2
+++ b/src/migration-scripts/ssh/1-to-2
@@ -1,81 +1,63 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# VyOS 1.2 crux allowed configuring a lower or upper case loglevel. This
# is no longer supported as the input data is validated and will lead to
# an error. If user specifies an upper case logleve, make it lowercase
-from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['service', 'ssh']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-path_loglevel = base + ['loglevel']
-if config.exists(path_loglevel):
- # red in configured loglevel and convert it to lower case
- tmp = config.return_value(path_loglevel).lower()
- # VyOS 1.2 had no proper value validation on the CLI thus the
- # user could use any arbitrary values - sanitize them
- if tmp not in ['quiet', 'fatal', 'error', 'info', 'verbose']:
- tmp = 'info'
- config.set(path_loglevel, value=tmp)
-
-# T4273: migrate ssh cipher list to multi node
-path_ciphers = base + ['ciphers']
-if config.exists(path_ciphers):
- tmp = []
- # get curtrent cipher list - comma delimited
- for cipher in config.return_values(path_ciphers):
- tmp.extend(cipher.split(','))
- # delete old cipher suite representation
- config.delete(path_ciphers)
-
- for cipher in tmp:
- config.set(path_ciphers, value=cipher, replace=False)
-
-# T4273: migrate ssh key-exchange list to multi node
-path_kex = base + ['key-exchange']
-if config.exists(path_kex):
- tmp = []
- # get curtrent cipher list - comma delimited
- for kex in config.return_values(path_kex):
- tmp.extend(kex.split(','))
- # delete old cipher suite representation
- config.delete(path_kex)
-
- for kex in tmp:
- config.set(path_kex, value=kex, replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ path_loglevel = base + ['loglevel']
+ if config.exists(path_loglevel):
+ # red in configured loglevel and convert it to lower case
+ tmp = config.return_value(path_loglevel).lower()
+ # VyOS 1.2 had no proper value validation on the CLI thus the
+ # user could use any arbitrary values - sanitize them
+ if tmp not in ['quiet', 'fatal', 'error', 'info', 'verbose']:
+ tmp = 'info'
+ config.set(path_loglevel, value=tmp)
+
+ # T4273: migrate ssh cipher list to multi node
+ path_ciphers = base + ['ciphers']
+ if config.exists(path_ciphers):
+ tmp = []
+ # get curtrent cipher list - comma delimited
+ for cipher in config.return_values(path_ciphers):
+ tmp.extend(cipher.split(','))
+ # delete old cipher suite representation
+ config.delete(path_ciphers)
+
+ for cipher in tmp:
+ config.set(path_ciphers, value=cipher, replace=False)
+
+ # T4273: migrate ssh key-exchange list to multi node
+ path_kex = base + ['key-exchange']
+ if config.exists(path_kex):
+ tmp = []
+ # get curtrent cipher list - comma delimited
+ for kex in config.return_values(path_kex):
+ tmp.extend(kex.split(','))
+ # delete old cipher suite representation
+ config.delete(path_kex)
+
+ for kex in tmp:
+ config.set(path_kex, value=kex, replace=False)
diff --git a/src/migration-scripts/sstp/0-to-1 b/src/migration-scripts/sstp/0-to-1
index 150127aaf..1bd7d6c6b 100755..100644
--- a/src/migration-scripts/sstp/0-to-1
+++ b/src/migration-scripts/sstp/0-to-1
@@ -1,19 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
+# 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 from "service sstp-server" to "vpn sstp"
# - remove primary/secondary identifier from nameserver
@@ -23,25 +21,15 @@
# - do not migrate radius server req-limit, use default of unlimited
# - migrate SSL certificate path
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+old_base = ['service', 'sstp-server']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(old_base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-old_base = ['service', 'sstp-server']
-if not config.exists(old_base):
- # Nothing to do
- sys.exit(0)
-else:
# ensure new base path exists
if not config.exists(['vpn']):
config.set(['vpn'])
@@ -119,10 +107,3 @@ else:
if config.exists(new_ssl + ['server-key']):
config.rename(new_ssl + ['server-key'], 'key-file')
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/sstp/1-to-2 b/src/migration-scripts/sstp/1-to-2
index f7ecbb6d4..2349e3c9f 100755..100644
--- a/src/migration-scripts/sstp/1-to-2
+++ b/src/migration-scripts/sstp/1-to-2
@@ -1,45 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 relative path SSL certificate to absolute path, as certs are only
# allowed to stored in /config/user-data/sstp/ this is pretty straight
# forward move. Delete certificates from source directory
import os
-import sys
from shutil import copy2
from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base_path = ['vpn', 'sstp', 'ssl']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base_path = ['vpn', 'sstp', 'ssl']
-if not config.exists(base_path):
- # Nothing to do
- sys.exit(0)
-else:
cert_path_old ='/config/user-data/sstp/'
cert_path_new ='/config/auth/sstp/'
@@ -101,10 +91,3 @@ else:
# check if old certificate directory exists but is empty
if os.path.isdir(cert_path_old) and not os.listdir(cert_path_old):
os.rmdir(cert_path_old)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/sstp/2-to-3 b/src/migration-scripts/sstp/2-to-3
index 245db7ad6..4255a896e 100755..100644
--- a/src/migration-scripts/sstp/2-to-3
+++ b/src/migration-scripts/sstp/2-to-3
@@ -1,41 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 SSTP ppp-settings node to ppp-options to make use of a common
# Jinja Template to render Accel-PPP services
from vyos.configtree import ConfigTree
-from sys import argv
-from sys import exit
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-file_name = argv[1]
+base_path = ['vpn', 'sstp']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_path):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base_path = ['vpn', 'sstp']
-if not config.exists(base_path):
- # Nothing to do
- exit(0)
-else:
if config.exists(base_path + ['ppp-settings']):
config.rename(base_path + ['ppp-settings'], 'ppp-options')
@@ -68,11 +57,3 @@ else:
config_nw_settings = base_path + ['network-settings']
if config.exists(config_nw_settings):
config.delete(config_nw_settings)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
diff --git a/src/migration-scripts/sstp/3-to-4 b/src/migration-scripts/sstp/3-to-4
index 5b7757e60..fd10985de 100755..100644
--- a/src/migration-scripts/sstp/3-to-4
+++ b/src/migration-scripts/sstp/3-to-4
@@ -1,25 +1,22 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - Update SSL to use PKI configuration
import os
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_private_key
@@ -27,109 +24,93 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'sstp']
pki_base = ['pki']
-if not config.exists(base):
- exit(0)
-
AUTH_DIR = '/config/auth'
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
-if not config.exists(base + ['ssl']):
- exit(0)
-
-x509_base = base + ['ssl']
-pki_name = 'sstp'
-
-if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
-if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
-if config.exists(x509_base + ['ca-cert-file']):
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on sstp config')
-
- config.delete(x509_base + ['ca-cert-file'])
-
-if config.exists(x509_base + ['cert-file']):
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on sstp config')
-
- config.delete(x509_base + ['cert-file'])
-
-if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on sstp config')
-
- config.delete(x509_base + ['key-file'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ if not config.exists(base + ['ssl']):
+ return
+
+ x509_base = base + ['ssl']
+ pki_name = 'sstp'
+
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on sstp config')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on sstp config')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on sstp config')
+
+ config.delete(x509_base + ['key-file'])
diff --git a/src/migration-scripts/sstp/4-to-5 b/src/migration-scripts/sstp/4-to-5
index 6907240a0..254e828af 100755..100644
--- a/src/migration-scripts/sstp/4-to-5
+++ b/src/migration-scripts/sstp/4-to-5
@@ -1,59 +1,41 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - move all pool to named pools
# 'subnet' migrate to namedpool 'default-subnet-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base = ['vpn', 'sstp']
pool_base = base + ['client-ip-pool']
-if not config.exists(base):
- exit(0)
-if not config.exists(pool_base):
- exit(0)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-range_pool_name = 'default-range-pool'
+ if not config.exists(pool_base):
+ return
-if config.exists(pool_base + ['subnet']):
- default_pool = range_pool_name
- for subnet in config.return_values(pool_base + ['subnet']):
- config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
- config.delete(pool_base + ['subnet'])
- config.set(base + ['default-pool'], value=default_pool)
-# format as tag node
-config.set_tag(pool_base)
+ range_pool_name = 'default-range-pool'
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ if config.exists(pool_base + ['subnet']):
+ default_pool = range_pool_name
+ for subnet in config.return_values(pool_base + ['subnet']):
+ config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+ config.delete(pool_base + ['subnet'])
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/sstp/5-to-6 b/src/migration-scripts/sstp/5-to-6
index 43b99044d..fc3cc29b2 100755..100644
--- a/src/migration-scripts/sstp/5-to-6
+++ b/src/migration-scripts/sstp/5-to-6
@@ -1,58 +1,40 @@
-#!/usr/bin/env python3
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Migrating to named ipv6 pools
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['vpn', 'sstp']
+pool_base = base + ['client-ipv6-pool']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ if not config.exists(pool_base):
+ return
-config = ConfigTree(config_file)
-base = ['vpn', 'sstp']
-pool_base = base + ['client-ipv6-pool']
-if not config.exists(base):
- exit(0)
-
-if not config.exists(pool_base):
- exit(0)
-
-ipv6_pool_name = 'ipv6-pool'
-config.copy(pool_base, pool_base + [ipv6_pool_name])
-
-if config.exists(pool_base + ['prefix']):
- config.delete(pool_base + ['prefix'])
- config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
-if config.exists(pool_base + ['delegate']):
- config.delete(pool_base + ['delegate'])
-
-# format as tag node
-config.set_tag(pool_base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ ipv6_pool_name = 'ipv6-pool'
+ config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+ if config.exists(pool_base + ['prefix']):
+ config.delete(pool_base + ['prefix'])
+ config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+ if config.exists(pool_base + ['delegate']):
+ config.delete(pool_base + ['delegate'])
+
+ # format as tag node
+ config.set_tag(pool_base)
diff --git a/src/migration-scripts/system/10-to-11 b/src/migration-scripts/system/10-to-11
index 5d662af40..76d7f23cb 100755..100644
--- a/src/migration-scripts/system/10-to-11
+++ b/src/migration-scripts/system/10-to-11
@@ -1,36 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Operator accounts have been deprecated due to a security issue. Those accounts
# will be converted to regular admin accounts.
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
base_level = ['system', 'login', 'user']
-if not config.exists(base_level):
- # Nothing to do, which shouldn't happen anyway
- # only if you wipe the config and reboot.
- sys.exit(0)
-else:
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base_level):
+ # Nothing to do, which shouldn't happen anyway
+ # only if you wipe the config and reboot.
+ return
+
for user in config.list_nodes(base_level):
if config.exists(base_level + [user, 'level']):
if config.return_value(base_level + [user, 'level']) == 'operator':
config.set(base_level + [user, 'level'], value="admin", replace=True)
-
- try:
- open(file_name,'w').write(config.to_string())
-
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/11-to-12 b/src/migration-scripts/system/11-to-12
index 880ab56dc..71c359b7e 100755..100644
--- a/src/migration-scripts/system/11-to-12
+++ b/src/migration-scripts/system/11-to-12
@@ -1,28 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Unclutter RADIUS configuration
#
# Move radius-server top level tag nodes to a regular node which allows us
# to specify additional general features for the RADIUS client.
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+cfg_base = ['system', 'login']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-cfg_base = ['system', 'login']
-if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])):
- # Nothing to do
- sys.exit(0)
-else:
#
# Migrate "system login radius-source-address" to "system login radius"
#
@@ -63,10 +67,3 @@ else:
# delete top level tag node
if config.exists(cfg_base + ['radius-server']):
config.delete(cfg_base + ['radius-server'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/12-to-13 b/src/migration-scripts/system/12-to-13
index e6c4e3802..014edba91 100755..100644
--- a/src/migration-scripts/system/12-to-13
+++ b/src/migration-scripts/system/12-to-13
@@ -1,47 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# converts 'set system syslog host <address>:<port>'
# to 'set system syslog host <address> port <port>'
-import sys
import re
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
cbase = ['system', 'syslog', 'host']
-if not config.exists(cbase):
- sys.exit(0)
-
-for host in config.list_nodes(cbase):
- if re.search(':[0-9]{1,5}$',host):
- h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0)
- p = re.sub(':', '', re.search(':[0-9]+$', host).group(0))
- config.set(cbase + [h])
- config.set(cbase + [h, 'port'], value=p)
- for fac in config.list_nodes(cbase + [host, 'facility']):
- config.set(cbase + [h, 'facility', fac])
- config.set_tag(cbase + [h, 'facility'])
- if config.exists(cbase + [host, 'facility', fac, 'protocol']):
- proto = config.return_value(cbase + [host, 'facility', fac, 'protocol'])
- config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto)
- if config.exists(cbase + [host, 'facility', fac, 'level']):
- lvl = config.return_value(cbase + [host, 'facility', fac, 'level'])
- config.set(cbase + [h, 'facility', fac, 'level'], value=lvl)
- config.delete(cbase + [host])
-
-try:
- open(file_name,'w').write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cbase):
+ return
+
+ for host in config.list_nodes(cbase):
+ if re.search(':[0-9]{1,5}$',host):
+ h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0)
+ p = re.sub(':', '', re.search(':[0-9]+$', host).group(0))
+ config.set(cbase + [h])
+ config.set(cbase + [h, 'port'], value=p)
+ for fac in config.list_nodes(cbase + [host, 'facility']):
+ config.set(cbase + [h, 'facility', fac])
+ config.set_tag(cbase + [h, 'facility'])
+ if config.exists(cbase + [host, 'facility', fac, 'protocol']):
+ proto = config.return_value(cbase + [host, 'facility', fac, 'protocol'])
+ config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto)
+ if config.exists(cbase + [host, 'facility', fac, 'level']):
+ lvl = config.return_value(cbase + [host, 'facility', fac, 'level'])
+ config.set(cbase + [h, 'facility', fac, 'level'], value=lvl)
+ config.delete(cbase + [host])
diff --git a/src/migration-scripts/system/13-to-14 b/src/migration-scripts/system/13-to-14
index 5b781158b..fbbecbcd3 100755..100644
--- a/src/migration-scripts/system/13-to-14
+++ b/src/migration-scripts/system/13-to-14
@@ -1,4 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Fixup non existent time-zones. Some systems have time-zone set to: Los*
# (Los_Angeles), Den* (Denver), New* (New_York) ... but those are no real IANA
@@ -9,27 +22,18 @@
# Migrate all configured timezones to real IANA assigned timezones!
import re
-import sys
from vyos.configtree import ConfigTree
from vyos.utils.process import cmd
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+tz_base = ['system', 'time-zone']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(tz_base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-tz_base = ['system', 'time-zone']
-if not config.exists(tz_base):
- # Nothing to do
- sys.exit(0)
-else:
tz = config.return_value(tz_base)
# retrieve all valid timezones
@@ -61,10 +65,3 @@ else:
# replace timezone data is required
config.set(tz_base, value=tz)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/14-to-15 b/src/migration-scripts/system/14-to-15
index feaac37de..281809460 100755..100644
--- a/src/migration-scripts/system/14-to-15
+++ b/src/migration-scripts/system/14-to-15
@@ -1,40 +1,37 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
+
# Delete 'system ipv6 blacklist' option as the IPv6 module can no longer be
# blacklisted as it is required by e.g. WireGuard and thus will always be
# loaded.
import os
-import sys
ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf'
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+ip_base = ['system', 'ipv6']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(ip_base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-ip_base = ['system', 'ipv6']
-if not config.exists(ip_base):
- # Nothing to do
- sys.exit(0)
-else:
# delete 'system ipv6 blacklist' node
if config.exists(ip_base + ['blacklist']):
config.delete(ip_base + ['blacklist'])
if os.path.isfile(ipv6_blacklist_file):
os.unlink(ipv6_blacklist_file)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/15-to-16 b/src/migration-scripts/system/15-to-16
index 2944cdb1e..7db042930 100755..100644
--- a/src/migration-scripts/system/15-to-16
+++ b/src/migration-scripts/system/15-to-16
@@ -1,36 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Make 'system options reboot-on-panic' valueless
+# 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/>.
-import sys
+# Make 'system options reboot-on-panic' valueless
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['system', 'options']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['system', 'options']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
if config.exists(base + ['reboot-on-panic']):
reboot = config.return_value(base + ['reboot-on-panic'])
config.delete(base + ['reboot-on-panic'])
# create new valueless node if action was true
if reboot == "true":
config.set(base + ['reboot-on-panic'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17
index afa171a9b..9fb86af88 100755..100644
--- a/src/migration-scripts/system/16-to-17
+++ b/src/migration-scripts/system/16-to-17
@@ -1,18 +1,17 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# * remove "system login user <user> group" node, Why should be add a user to a
# 3rd party group when the system is fully managed by CLI?
@@ -20,35 +19,18 @@
# This is the only privilege level left and also the default, what is the
# sense in keeping this orphaned node?
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['system', 'login', 'user']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['system', 'login', 'user']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
for user in config.list_nodes(base):
if config.exists(base + [user, 'group']):
config.delete(base + [user, 'group'])
if config.exists(base + [user, 'level']):
config.delete(base + [user, 'level'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/17-to-18 b/src/migration-scripts/system/17-to-18
index f6adebb06..323ef4e65 100755..100644
--- a/src/migration-scripts/system/17-to-18
+++ b/src/migration-scripts/system/17-to-18
@@ -1,42 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# remove "system console netconsole"
# remove "system console device <device> modem"
import os
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
+base = ['system', 'console']
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-base = ['system', 'console']
-if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-else:
# remove "system console netconsole" (T2561)
if config.exists(base + ['netconsole']):
config.delete(base + ['netconsole'])
@@ -67,10 +57,3 @@ else:
config.copy(dev_path, base + ['device', usb_device])
# Delete old USB node from config
config.delete(dev_path)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/18-to-19 b/src/migration-scripts/system/18-to-19
index fad1d17a4..5d9788d70 100755..100644
--- a/src/migration-scripts/system/18-to-19
+++ b/src/migration-scripts/system/18-to-19
@@ -1,102 +1,81 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 disable-dhcp-nameservers (boolean) to name-servers-dhcp <interface>
# if disable-dhcp-nameservers is set, just remove it
# else retrieve all interface names that have configured dhcp(v6) address and
# add them to the new name-servers-dhcp node
-from sys import argv, exit
from vyos.ifconfig import Interface
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
base = ['system']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['disable-dhcp-nameservers']):
- config.delete(base + ['disable-dhcp-nameservers'])
-else:
- dhcp_interfaces = []
-
- # go through all interfaces searching for 'address dhcp(v6)?'
- for sect in Interface.sections():
- sect_base = ['interfaces', sect]
-
- if not config.exists(sect_base):
- continue
- for intf in config.list_nodes(sect_base):
- intf_base = sect_base + [intf]
-
- # try without vlans
- if config.exists(intf_base + ['address']):
- for addr in config.return_values(intf_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(intf)
-
- # try vif
- if config.exists(intf_base + ['vif']):
- for vif in config.list_nodes(intf_base + ['vif']):
- vif_base = intf_base + ['vif', vif]
- if config.exists(vif_base + ['address']):
- for addr in config.return_values(vif_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif}')
-
- # try vif-s
- if config.exists(intf_base + ['vif-s']):
- for vif_s in config.list_nodes(intf_base + ['vif-s']):
- vif_s_base = intf_base + ['vif-s', vif_s]
- if config.exists(vif_s_base + ['address']):
- for addr in config.return_values(vif_s_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif_s}')
-
- # try vif-c
- if config.exists(intf_base + ['vif-c']):
- for vif_c in config.list_nodes(vif_s_base + ['vif-c']):
- vif_c_base = vif_s_base + ['vif-c', vif_c]
- if config.exists(vif_c_base + ['address']):
- for addr in config.return_values(vif_c_base + ['address']):
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['disable-dhcp-nameservers']):
+ config.delete(base + ['disable-dhcp-nameservers'])
+ else:
+ dhcp_interfaces = []
+
+ # go through all interfaces searching for 'address dhcp(v6)?'
+ for sect in Interface.sections():
+ sect_base = ['interfaces', sect]
+
+ if not config.exists(sect_base):
+ continue
+
+ for intf in config.list_nodes(sect_base):
+ intf_base = sect_base + [intf]
+
+ # try without vlans
+ if config.exists(intf_base + ['address']):
+ for addr in config.return_values(intf_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(intf)
+
+ # try vif
+ if config.exists(intf_base + ['vif']):
+ for vif in config.list_nodes(intf_base + ['vif']):
+ vif_base = intf_base + ['vif', vif]
+ if config.exists(vif_base + ['address']):
+ for addr in config.return_values(vif_base + ['address']):
if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}')
-
- # set new config nodes
- for intf in dhcp_interfaces:
- config.set(base + ['name-servers-dhcp'], value=intf, replace=False)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
-
-exit(0)
+ dhcp_interfaces.append(f'{intf}.{vif}')
+
+ # try vif-s
+ if config.exists(intf_base + ['vif-s']):
+ for vif_s in config.list_nodes(intf_base + ['vif-s']):
+ vif_s_base = intf_base + ['vif-s', vif_s]
+ if config.exists(vif_s_base + ['address']):
+ for addr in config.return_values(vif_s_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(f'{intf}.{vif_s}')
+
+ # try vif-c
+ if config.exists(intf_base + ['vif-c']):
+ for vif_c in config.list_nodes(vif_s_base + ['vif-c']):
+ vif_c_base = vif_s_base + ['vif-c', vif_c]
+ if config.exists(vif_c_base + ['address']):
+ for addr in config.return_values(vif_c_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}')
+
+ # set new config nodes
+ for intf in dhcp_interfaces:
+ config.set(base + ['name-servers-dhcp'], value=intf, replace=False)
diff --git a/src/migration-scripts/system/19-to-20 b/src/migration-scripts/system/19-to-20
index 177173c50..cb84e11fc 100755..100644
--- a/src/migration-scripts/system/19-to-20
+++ b/src/migration-scripts/system/19-to-20
@@ -1,62 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2020-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3048: remove smp-affinity node from ethernet and use tuned instead
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'options']
base_new = ['system', 'option']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base_new):
- for node in config.list_nodes(base):
- config.copy(base + [node], base_new + [node])
-else:
- config.copy(base, base_new)
-config.delete(base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-# Rename "system option beep-if-fully-booted" -> "system option startup-beep"
-base_beep = base_new + ['beep-if-fully-booted']
-if config.exists(base_beep):
- config.rename(base_beep, 'startup-beep')
+ if config.exists(base_new):
+ for node in config.list_nodes(base):
+ config.copy(base + [node], base_new + [node])
+ else:
+ config.copy(base, base_new)
-# Rename "system option ctrl-alt-del-action" -> "system option ctrl-alt-delete"
-base_ctrl_alt_del = base_new + ['ctrl-alt-del-action']
-if config.exists(base_ctrl_alt_del):
- config.rename(base_ctrl_alt_del, 'ctrl-alt-delete')
+ config.delete(base)
+ # Rename "system option beep-if-fully-booted" -> "system option startup-beep"
+ base_beep = base_new + ['beep-if-fully-booted']
+ if config.exists(base_beep):
+ config.rename(base_beep, 'startup-beep')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Rename "system option ctrl-alt-del-action" -> "system option ctrl-alt-delete"
+ base_ctrl_alt_del = base_new + ['ctrl-alt-del-action']
+ if config.exists(base_ctrl_alt_del):
+ config.rename(base_ctrl_alt_del, 'ctrl-alt-delete')
diff --git a/src/migration-scripts/system/20-to-21 b/src/migration-scripts/system/20-to-21
index 24e042ce2..71c283da6 100755..100644
--- a/src/migration-scripts/system/20-to-21
+++ b/src/migration-scripts/system/20-to-21
@@ -1,46 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3795: merge "system name-servers-dhcp" into "system name-server"
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'name-servers-dhcp']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-for interface in config.return_values(base):
- config.set(['system', 'name-server'], value=interface, replace=False)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-config.delete(base)
+ for interface in config.return_values(base):
+ config.set(['system', 'name-server'], value=interface, replace=False)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(base)
diff --git a/src/migration-scripts/system/21-to-22 b/src/migration-scripts/system/21-to-22
index 2a1b603c6..0e68a6856 100755..100644
--- a/src/migration-scripts/system/21-to-22
+++ b/src/migration-scripts/system/21-to-22
@@ -1,55 +1,38 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'sysctl']
-config = ConfigTree(config_file)
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for all_custom in ['all', 'custom']:
- if config.exists(base + [all_custom]):
- for key in config.list_nodes(base + [all_custom]):
- tmp = config.return_value(base + [all_custom, key, 'value'])
- config.set(base + ['parameter', key, 'value'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for all_custom in ['all', 'custom']:
+ if config.exists(base + [all_custom]):
+ for key in config.list_nodes(base + [all_custom]):
+ tmp = config.return_value(base + [all_custom, key, 'value'])
+ config.set(base + ['parameter', key, 'value'], value=tmp)
+ config.set_tag(base + ['parameter'])
+ config.delete(base + [all_custom])
+
+ for ipv4_param in ['net.ipv4.igmp_max_memberships', 'net.ipv4.ipfrag_time']:
+ if config.exists(base + [ipv4_param]):
+ tmp = config.return_value(base + [ipv4_param])
+ config.set(base + ['parameter', ipv4_param, 'value'], value=tmp)
config.set_tag(base + ['parameter'])
- config.delete(base + [all_custom])
-
-for ipv4_param in ['net.ipv4.igmp_max_memberships', 'net.ipv4.ipfrag_time']:
- if config.exists(base + [ipv4_param]):
- tmp = config.return_value(base + [ipv4_param])
- config.set(base + ['parameter', ipv4_param, 'value'], value=tmp)
- config.set_tag(base + ['parameter'])
- config.delete(base + [ipv4_param])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.delete(base + [ipv4_param])
diff --git a/src/migration-scripts/system/22-to-23 b/src/migration-scripts/system/22-to-23
index f83279b88..e49094e4a 100755..100644
--- a/src/migration-scripts/system/22-to-23
+++ b/src/migration-scripts/system/22-to-23
@@ -1,48 +1,31 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'ipv6']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-# T4346: drop support to disbale IPv6 address family within the OS Kernel
-if config.exists(base + ['disable']):
- config.delete(base + ['disable'])
- # IPv6 address family disable was the only CLI option set - we can cleanup
- # the entire tree
- if len(config.list_nodes(base)) == 0:
- config.delete(base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # T4346: drop support to disbale IPv6 address family within the OS Kernel
+ if config.exists(base + ['disable']):
+ config.delete(base + ['disable'])
+ # IPv6 address family disable was the only CLI option set - we can cleanup
+ # the entire tree
+ if len(config.list_nodes(base)) == 0:
+ config.delete(base)
diff --git a/src/migration-scripts/system/23-to-24 b/src/migration-scripts/system/23-to-24
index 1fd61d83b..feb62bc32 100755..100644
--- a/src/migration-scripts/system/23-to-24
+++ b/src/migration-scripts/system/23-to-24
@@ -1,38 +1,28 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022-2024 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 ipaddress import ip_interface
from ipaddress import ip_address
-from sys import exit, argv
+
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'static', 'arp']
tmp_base = ['protocols', 'static', 'arp-tmp']
-config = ConfigTree(config_file)
-def fixup_cli(config, path, interface):
+def fixup_cli(config, path, interface, host):
if config.exists(path + ['address']):
for address in config.return_values(path + ['address']):
tmp = ip_interface(address)
@@ -47,41 +37,35 @@ def fixup_cli(config, path, interface):
config.set_tag(iface_path + [interface, 'address'])
continue
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# We need a temporary copy of the config tree as the original one needs to be
-# deleted first due to a change iun thge tagNode structure.
-config.copy(base, tmp_base)
-config.delete(base)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-for host in config.list_nodes(tmp_base):
- for type in config.list_nodes(['interfaces']):
- for interface in config.list_nodes(['interfaces', type]):
- if_base = ['interfaces', type, interface]
- fixup_cli(config, if_base, interface)
+ # We need a temporary copy of the config tree as the original one needs to be
+ # deleted first due to a change iun thge tagNode structure.
+ config.copy(base, tmp_base)
+ config.delete(base)
- if config.exists(if_base + ['vif']):
- for vif in config.list_nodes(if_base + ['vif']):
- vif_base = ['interfaces', type, interface, 'vif', vif]
- fixup_cli(config, vif_base, f'{interface}.{vif}')
+ for host in config.list_nodes(tmp_base):
+ for type in config.list_nodes(['interfaces']):
+ for interface in config.list_nodes(['interfaces', type]):
+ if_base = ['interfaces', type, interface]
+ fixup_cli(config, if_base, interface, host)
- if config.exists(if_base + ['vif-s']):
- for vif_s in config.list_nodes(if_base + ['vif-s']):
- vif_s_base = ['interfaces', type, interface, 'vif-s', vif_s]
- fixup_cli(config, vif_s_base, f'{interface}.{vif_s}')
+ if config.exists(if_base + ['vif']):
+ for vif in config.list_nodes(if_base + ['vif']):
+ vif_base = ['interfaces', type, interface, 'vif', vif]
+ fixup_cli(config, vif_base, f'{interface}.{vif}', host)
- if config.exists(if_base + ['vif-s', vif_s, 'vif-c']):
- for vif_c in config.list_nodes(if_base + ['vif-s', vif_s, 'vif-c']):
- vif_c_base = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c', vif_c]
- fixup_cli(config, vif_c_base, f'{interface}.{vif_s}.{vif_c}')
+ if config.exists(if_base + ['vif-s']):
+ for vif_s in config.list_nodes(if_base + ['vif-s']):
+ vif_s_base = ['interfaces', type, interface, 'vif-s', vif_s]
+ fixup_cli(config, vif_s_base, f'{interface}.{vif_s}', host)
-config.delete(tmp_base)
+ if config.exists(if_base + ['vif-s', vif_s, 'vif-c']):
+ for vif_c in config.list_nodes(if_base + ['vif-s', vif_s, 'vif-c']):
+ vif_c_base = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c', vif_c]
+ fixup_cli(config, vif_c_base, f'{interface}.{vif_s}.{vif_c}', host)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.delete(tmp_base)
diff --git a/src/migration-scripts/system/24-to-25 b/src/migration-scripts/system/24-to-25
index 1c81a76e7..bdb89902e 100755..100644
--- a/src/migration-scripts/system/24-to-25
+++ b/src/migration-scripts/system/24-to-25
@@ -1,52 +1,35 @@
-#!/usr/bin/env python3
+# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2022 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 syslog global archive to system logs logrotate messages
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'syslog', 'global', 'archive']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-if config.exists(base + ['file']):
- tmp = config.return_value(base + ['file'])
- config.set(['system', 'logs', 'logrotate', 'messages', 'rotate'], value=tmp)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-if config.exists(base + ['size']):
- tmp = config.return_value(base + ['size'])
- tmp = max(round(int(tmp) / 1024), 1) # kb -> mb
- config.set(['system', 'logs', 'logrotate', 'messages', 'max-size'], value=tmp)
+ if config.exists(base + ['file']):
+ tmp = config.return_value(base + ['file'])
+ config.set(['system', 'logs', 'logrotate', 'messages', 'rotate'], value=tmp)
-config.delete(base)
+ if config.exists(base + ['size']):
+ tmp = config.return_value(base + ['size'])
+ tmp = max(round(int(tmp) / 1024), 1) # kb -> mb
+ config.set(['system', 'logs', 'logrotate', 'messages', 'max-size'], value=tmp)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ config.delete(base)
diff --git a/src/migration-scripts/system/25-to-26 b/src/migration-scripts/system/25-to-26
index 7bdf3be98..8832f48e5 100755..100644
--- a/src/migration-scripts/system/25-to-26
+++ b/src/migration-scripts/system/25-to-26
@@ -1,39 +1,25 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# syslog: migrate deprecated CLI options
# - protocols -> local7
# - security -> auth
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'syslog']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
def rename_facilities(config, base_tree, facility, facility_new) -> None:
if config.exists(base + [base_tree, 'facility', facility]):
@@ -44,39 +30,36 @@ def rename_facilities(config, base_tree, facility, facility_new) -> None:
# delete old duplicate facility config
config.delete(base + [base_tree, 'facility', facility])
-#
-# Rename protocols and securityy facility to common ones
-#
-replace = {
- 'protocols' : 'local7',
- 'security' : 'auth'
-}
-for facility, facility_new in replace.items():
- rename_facilities(config, 'console', facility, facility_new)
- rename_facilities(config, 'global', facility, facility_new)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
- if config.exists(base + ['host']):
- for host in config.list_nodes(base + ['host']):
- rename_facilities(config, f'host {host}', facility, facility_new)
+ #
+ # Rename protocols and securityy facility to common ones
+ #
+ replace = {
+ 'protocols' : 'local7',
+ 'security' : 'auth'
+ }
+ for facility, facility_new in replace.items():
+ rename_facilities(config, 'console', facility, facility_new)
+ rename_facilities(config, 'global', facility, facility_new)
-#
-# It makes no sense to configure udp/tcp transport per individual facility
-#
-if config.exists(base + ['host']):
- for host in config.list_nodes(base + ['host']):
- protocol = None
- for facility in config.list_nodes(base + ['host', host, 'facility']):
- tmp_path = base + ['host', host, 'facility', facility, 'protocol']
- if config.exists(tmp_path):
- # We can only change the first one
- if protocol == None:
- protocol = config.return_value(tmp_path)
- config.set(base + ['host', host, 'protocol'], value=protocol)
- config.delete(tmp_path)
+ if config.exists(base + ['host']):
+ for host in config.list_nodes(base + ['host']):
+ rename_facilities(config, f'host {host}', facility, facility_new)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ #
+ # It makes no sense to configure udp/tcp transport per individual facility
+ #
+ if config.exists(base + ['host']):
+ for host in config.list_nodes(base + ['host']):
+ protocol = None
+ for facility in config.list_nodes(base + ['host', host, 'facility']):
+ tmp_path = base + ['host', host, 'facility', facility, 'protocol']
+ if config.exists(tmp_path):
+ # We can only change the first one
+ if protocol == None:
+ protocol = config.return_value(tmp_path)
+ config.set(base + ['host', host, 'protocol'], value=protocol)
+ config.delete(tmp_path)
diff --git a/src/migration-scripts/system/26-to-27 b/src/migration-scripts/system/26-to-27
index 80bb82cbd..499e16e08 100755..100644
--- a/src/migration-scripts/system/26-to-27
+++ b/src/migration-scripts/system/26-to-27
@@ -1,47 +1,30 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
+
# T5877: migrate 'system domain-search domain' to 'system domain-search'
-from sys import exit, argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['system', 'domain-search']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- exit(0)
-if config.exists(base + ['domain']):
- entries = config.return_values(base + ['domain'])
- config.delete(base + ['domain'])
- for entry in entries:
- config.set(base, value=entry, replace=False)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ if config.exists(base + ['domain']):
+ entries = config.return_values(base + ['domain'])
+ config.delete(base + ['domain'])
+ for entry in entries:
+ config.set(base, value=entry, replace=False)
diff --git a/src/migration-scripts/system/6-to-7 b/src/migration-scripts/system/6-to-7
index d24521134..e91ccc4e9 100755..100644
--- a/src/migration-scripts/system/6-to-7
+++ b/src/migration-scripts/system/6-to-7
@@ -1,48 +1,36 @@
-#!/usr/bin/env python3
+# Copyright 2019-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/>.
# Change smp_affinity to smp-affinity
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-update_required = False
-
-intf_types = config.list_nodes(["interfaces"])
-
-for intf_type in intf_types:
- intf_type_path = ["interfaces", intf_type]
- intfs = config.list_nodes(intf_type_path)
-
- for intf in intfs:
- intf_path = intf_type_path + [intf]
- if not config.exists(intf_path + ["smp_affinity"]):
- # Nothing to do.
- continue
- else:
- # Rename the node.
- old_smp_affinity_path = intf_path + ["smp_affinity"]
- config.rename(old_smp_affinity_path, "smp-affinity")
- update_required = True
-
-if update_required:
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("failed to save the modified config: {}".format(e))
- sys.exit(1)
-
-
-
+def migrate(config: ConfigTree) -> None:
+ intf_types = config.list_nodes(["interfaces"])
+
+ for intf_type in intf_types:
+ intf_type_path = ["interfaces", intf_type]
+ intfs = config.list_nodes(intf_type_path)
+
+ for intf in intfs:
+ intf_path = intf_type_path + [intf]
+ if not config.exists(intf_path + ["smp_affinity"]):
+ # Nothing to do.
+ continue
+ else:
+ # Rename the node.
+ old_smp_affinity_path = intf_path + ["smp_affinity"]
+ config.rename(old_smp_affinity_path, "smp-affinity")
+ update_required = True
diff --git a/src/migration-scripts/system/7-to-8 b/src/migration-scripts/system/7-to-8
index 5d084d2bf..64dd4dc93 100755..100644
--- a/src/migration-scripts/system/7-to-8
+++ b/src/migration-scripts/system/7-to-8
@@ -1,26 +1,27 @@
-#!/usr/bin/env python3
+# Copyright 2018-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/>.
# Converts "system gateway-address" option to "protocols static route 0.0.0.0/0 next-hop $gw"
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'gateway-address']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'gateway-address']):
- # Nothing to do
- sys.exit(0)
-else:
# Save the address
gw = config.return_value(['system', 'gateway-address'])
@@ -36,10 +37,3 @@ else:
# They must be formatted as such to load correctly.
config.set_tag(['protocols', 'static', 'route'])
config.set_tag(['protocols', 'static', 'route', '0.0.0.0/0', 'next-hop'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/system/8-to-9 b/src/migration-scripts/system/8-to-9
index e3bb2bca8..ea5f7af81 100755..100644
--- a/src/migration-scripts/system/8-to-9
+++ b/src/migration-scripts/system/8-to-9
@@ -1,32 +1,26 @@
-#!/usr/bin/env python3
+# Copyright 2018-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/>.
# Deletes "system package" option as it is deprecated
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(['system', 'package']):
+ # Nothing to do
+ return
-config = ConfigTree(config_file)
-
-if not config.exists(['system', 'package']):
- # Nothing to do
- sys.exit(0)
-else:
# Delete the node with the old syntax
config.delete(['system', 'package'])
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/migration-scripts/vrf/0-to-1 b/src/migration-scripts/vrf/0-to-1
index 8187138d9..70abae2a8 100755..100644
--- a/src/migration-scripts/vrf/0-to-1
+++ b/src/migration-scripts/vrf/0-to-1
@@ -1,132 +1,113 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T2450: drop interface-route and interface-route6 from "protocols vrf"
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['protocols', 'vrf']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-for vrf in config.list_nodes(base):
- static_base = base + [vrf, 'static']
- if not config.exists(static_base):
- continue
-
- #
- # Migrate interface-route into route
- #
- interface_route_path = static_base + ['interface-route']
- if config.exists(interface_route_path):
- for route in config.list_nodes(interface_route_path):
- interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
-
- tmp = interface_route_path + [route, 'next-hop-interface']
- for interface in config.list_nodes(tmp):
- new_base = static_base + ['route', route, 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(tmp + [interface], new_base + [interface])
-
- config.delete(interface_route_path)
-
- #
- # Migrate interface-route6 into route6
- #
- interface_route_path = static_base + ['interface-route6']
- if config.exists(interface_route_path):
- for route in config.list_nodes(interface_route_path):
- interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
-
- tmp = interface_route_path + [route, 'next-hop-interface']
- for interface in config.list_nodes(tmp):
- new_base = static_base + ['route6', route, 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(tmp + [interface], new_base + [interface])
-
- config.delete(interface_route_path)
-
- #
- # Cleanup nodes inside route
- #
- route_path = static_base + ['route']
- if config.exists(route_path):
- for route in config.list_nodes(route_path):
- next_hop = route_path + [route, 'next-hop']
- if config.exists(next_hop):
- for gateway in config.list_nodes(next_hop):
- interface_path = next_hop + [gateway, 'next-hop-interface']
- if config.exists(interface_path):
- config.rename(interface_path, 'interface')
- vrf_path = next_hop + [gateway, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-
- next_hop = route_path + [route, 'interface']
- if config.exists(next_hop):
- for interface in config.list_nodes(next_hop):
- interface_path = next_hop + [interface, 'next-hop-interface']
- if config.exists(interface_path):
- config.rename(interface_path, 'interface')
- vrf_path = next_hop + [interface, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-
- #
- # Cleanup nodes inside route6
- #
- route_path = static_base + ['route6']
- if config.exists(route_path):
- for route in config.list_nodes(route_path):
- next_hop = route_path + [route, 'next-hop']
- if config.exists(next_hop):
- for gateway in config.list_nodes(next_hop):
- vrf_path = next_hop + [gateway, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-
- next_hop = route_path + [route, 'interface']
- if config.exists(next_hop):
- for interface in config.list_nodes(next_hop):
- interface_path = next_hop + [interface, 'next-hop-interface']
- if config.exists(interface_path):
- config.rename(interface_path, 'interface')
- vrf_path = next_hop + [interface, 'next-hop-vrf']
- if config.exists(vrf_path):
- config.rename(vrf_path, 'vrf')
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ for vrf in config.list_nodes(base):
+ static_base = base + [vrf, 'static']
+ if not config.exists(static_base):
+ continue
+
+ #
+ # Migrate interface-route into route
+ #
+ interface_route_path = static_base + ['interface-route']
+ if config.exists(interface_route_path):
+ for route in config.list_nodes(interface_route_path):
+ interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
+
+ tmp = interface_route_path + [route, 'next-hop-interface']
+ for interface in config.list_nodes(tmp):
+ new_base = static_base + ['route', route, 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(tmp + [interface], new_base + [interface])
+
+ config.delete(interface_route_path)
+
+ #
+ # Migrate interface-route6 into route6
+ #
+ interface_route_path = static_base + ['interface-route6']
+ if config.exists(interface_route_path):
+ for route in config.list_nodes(interface_route_path):
+ interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface'])
+
+ tmp = interface_route_path + [route, 'next-hop-interface']
+ for interface in config.list_nodes(tmp):
+ new_base = static_base + ['route6', route, 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(tmp + [interface], new_base + [interface])
+
+ config.delete(interface_route_path)
+
+ #
+ # Cleanup nodes inside route
+ #
+ route_path = static_base + ['route']
+ if config.exists(route_path):
+ for route in config.list_nodes(route_path):
+ next_hop = route_path + [route, 'next-hop']
+ if config.exists(next_hop):
+ for gateway in config.list_nodes(next_hop):
+ interface_path = next_hop + [gateway, 'next-hop-interface']
+ if config.exists(interface_path):
+ config.rename(interface_path, 'interface')
+ vrf_path = next_hop + [gateway, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
+
+ next_hop = route_path + [route, 'interface']
+ if config.exists(next_hop):
+ for interface in config.list_nodes(next_hop):
+ interface_path = next_hop + [interface, 'next-hop-interface']
+ if config.exists(interface_path):
+ config.rename(interface_path, 'interface')
+ vrf_path = next_hop + [interface, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
+
+ #
+ # Cleanup nodes inside route6
+ #
+ route_path = static_base + ['route6']
+ if config.exists(route_path):
+ for route in config.list_nodes(route_path):
+ next_hop = route_path + [route, 'next-hop']
+ if config.exists(next_hop):
+ for gateway in config.list_nodes(next_hop):
+ vrf_path = next_hop + [gateway, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
+
+ next_hop = route_path + [route, 'interface']
+ if config.exists(next_hop):
+ for interface in config.list_nodes(next_hop):
+ interface_path = next_hop + [interface, 'next-hop-interface']
+ if config.exists(interface_path):
+ config.rename(interface_path, 'interface')
+ vrf_path = next_hop + [interface, 'next-hop-vrf']
+ if config.exists(vrf_path):
+ config.rename(vrf_path, 'vrf')
diff --git a/src/migration-scripts/vrf/1-to-2 b/src/migration-scripts/vrf/1-to-2
index 52d4c2c7b..557a9ec58 100755..100644
--- a/src/migration-scripts/vrf/1-to-2
+++ b/src/migration-scripts/vrf/1-to-2
@@ -1,62 +1,43 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# - T3344: migrate routing options from "protocols vrf" to "vrf <name> protocols"
-from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
+base = ['protocols', 'vrf']
-file_name = argv[1]
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
-with open(file_name, 'r') as f:
- config_file = f.read()
+ vrf_base = ['vrf', 'name']
+ config.set(vrf_base)
+ config.set_tag(vrf_base)
-base = ['protocols', 'vrf']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-vrf_base = ['vrf', 'name']
-config.set(vrf_base)
-config.set_tag(vrf_base)
-
-# Copy all existing static routes to the new base node under "vrf name <name> protocols static"
-for vrf in config.list_nodes(base):
- static_base = base + [vrf, 'static']
- if not config.exists(static_base):
- continue
-
- 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'])
-
-# Now delete the old configuration
-config.delete(base)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ # Copy all existing static routes to the new base node under "vrf name <name> protocols static"
+ for vrf in config.list_nodes(base):
+ static_base = base + [vrf, 'static']
+ if not config.exists(static_base):
+ continue
+
+ 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'])
+
+ # 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 d45b185ee..acacffb41 100755..100644
--- a/src/migration-scripts/vrf/2-to-3
+++ b/src/migration-scripts/vrf/2-to-3
@@ -1,26 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# Since connection tracking zones are int16, VRFs tables maximum value must
# be limited to 65535
# Also, interface names in nftables cannot start from numbers,
# so VRF name should not start from a number
-from sys import argv
-from sys import exit
from random import randrange
from random import choice
from string import ascii_lowercase
@@ -69,76 +66,60 @@ def _search_tables(config_commands, table_num):
return table_items
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['vrf', 'name']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-# 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']))
-
-# Check VRF names and table numbers
-name_regex = re.compile(r'^\d.*$')
-for vrf_name, vrf_table in vrfs_current.items():
- # Check table number
- if vrf_table > 65535:
- # Find new unused table number
- vrfs_current[vrf_name] = None
- while not vrfs_current[vrf_name]:
- table_random = randrange(100, 65535)
- if table_random not in vrfs_current.values():
- vrfs_current[vrf_name] = table_random
- # Update number to a new one
- config.set(['vrf', 'name', vrf_name, 'table'],
- vrfs_current[vrf_name],
- replace=True)
- # Check config items with old table number and replace to new one
- config_commands = config.to_commands().split('\n')
- table_config_lines = _search_tables(config_commands, vrf_table)
- # Rename table nodes
- if table_config_lines.get('table_tags'):
- for table_config_path in table_config_lines.get('table_tags'):
- config.rename(table_config_path, f'{vrfs_current[vrf_name]}')
- # Replace table values
- if table_config_lines.get('table_values'):
- for table_config_path in table_config_lines.get('table_values'):
- config.set(table_config_path,
- f'{vrfs_current[vrf_name]}',
- replace=True)
-
- # Check VRF name
- if name_regex.match(vrf_name):
- vrf_name_new = None
- while not vrf_name_new:
- vrf_name_rand = f'{choice(ascii_lowercase)}{vrf_name}'[:15]
- if vrf_name_rand not in vrfs_current:
- vrf_name_new = vrf_name_rand
- # Update VRF name to a new one
- config.rename(['vrf', 'name', vrf_name], vrf_name_new)
- # Check config items with old VRF name and replace to new one
- config_commands = config.to_commands().split('\n')
- vrf_config_lines = _search_vrfs(config_commands, vrf_name)
- # Rename VRF to a new name
- if vrf_config_lines:
- for vrf_value_path in vrf_config_lines:
- config.set(vrf_value_path, vrf_name_new, replace=True)
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ # 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']))
+
+ # Check VRF names and table numbers
+ name_regex = re.compile(r'^\d.*$')
+ for vrf_name, vrf_table in vrfs_current.items():
+ # Check table number
+ if vrf_table > 65535:
+ # Find new unused table number
+ vrfs_current[vrf_name] = None
+ while not vrfs_current[vrf_name]:
+ table_random = randrange(100, 65535)
+ if table_random not in vrfs_current.values():
+ vrfs_current[vrf_name] = table_random
+ # Update number to a new one
+ config.set(['vrf', 'name', vrf_name, 'table'],
+ vrfs_current[vrf_name],
+ replace=True)
+ # Check config items with old table number and replace to new one
+ config_commands = config.to_commands().split('\n')
+ table_config_lines = _search_tables(config_commands, vrf_table)
+ # Rename table nodes
+ if table_config_lines.get('table_tags'):
+ for table_config_path in table_config_lines.get('table_tags'):
+ config.rename(table_config_path, f'{vrfs_current[vrf_name]}')
+ # Replace table values
+ if table_config_lines.get('table_values'):
+ for table_config_path in table_config_lines.get('table_values'):
+ config.set(table_config_path,
+ f'{vrfs_current[vrf_name]}',
+ replace=True)
+
+ # Check VRF name
+ if name_regex.match(vrf_name):
+ vrf_name_new = None
+ while not vrf_name_new:
+ vrf_name_rand = f'{choice(ascii_lowercase)}{vrf_name}'[:15]
+ if vrf_name_rand not in vrfs_current:
+ vrf_name_new = vrf_name_rand
+ # Update VRF name to a new one
+ config.rename(['vrf', 'name', vrf_name], vrf_name_new)
+ # Check config items with old VRF name and replace to new one
+ config_commands = config.to_commands().split('\n')
+ vrf_config_lines = _search_vrfs(config_commands, vrf_name)
+ # Rename VRF to a new name
+ if vrf_config_lines:
+ for vrf_value_path in vrf_config_lines:
+ config.set(vrf_value_path, vrf_name_new, replace=True)
diff --git a/src/migration-scripts/vrrp/1-to-2 b/src/migration-scripts/vrrp/1-to-2
index dba5af81c..8639a7553 100755..100644
--- a/src/migration-scripts/vrrp/1-to-2
+++ b/src/migration-scripts/vrrp/1-to-2
@@ -1,37 +1,23 @@
-#!/usr/bin/env python3
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2018 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
import re
-import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
# Convert the old VRRP syntax to the new syntax
# The old approach was to put VRRP groups inside interfaces,
@@ -109,162 +95,156 @@ def get_vrrp_group(path):
# Only if no data is collected from any interface we can conclude that VRRP is not configured
# and exit.
-groups = []
-base_paths = []
-
-if config.exists(["interfaces", "ethernet"]):
- base_paths.append("ethernet")
-if config.exists(["interfaces", "bonding"]):
- base_paths.append("bonding")
-
-for bp in base_paths:
- parent_path = ["interfaces", bp]
-
- parent_intfs = config.list_nodes(parent_path)
-
- for pi in parent_intfs:
- # Extract VRRP groups from the parent interface
- vg_path =[pi, "vrrp", "vrrp-group"]
- if config.exists(parent_path + vg_path):
- pgroups = config.list_nodes(parent_path + vg_path)
- for pg in pgroups:
- g = get_vrrp_group(parent_path + vg_path + [pg])
- g["interface"] = pi
- g["vrid"] = pg
- groups.append(g)
-
- # Delete the VRRP subtree
- # If left in place, configs will not load correctly
- config.delete(parent_path + [pi, "vrrp"])
-
- # Extract VRRP groups from 802.1q VLAN interfaces
- if config.exists(parent_path + [pi, "vif"]):
- vifs = config.list_nodes(parent_path + [pi, "vif"])
- for vif in vifs:
- vif_vg_path = [pi, "vif", vif, "vrrp", "vrrp-group"]
- if config.exists(parent_path + vif_vg_path):
- vifgroups = config.list_nodes(parent_path + vif_vg_path)
- for vif_group in vifgroups:
- g = get_vrrp_group(parent_path + vif_vg_path + [vif_group])
- g["interface"] = "{0}.{1}".format(pi, vif)
- g["vrid"] = vif_group
- groups.append(g)
-
- config.delete(parent_path + [pi, "vif", vif, "vrrp"])
-
- # Extract VRRP groups from 802.3ad QinQ service VLAN interfaces
- if config.exists(parent_path + [pi, "vif-s"]):
- vif_ss = config.list_nodes(parent_path + [pi, "vif-s"])
- for vif_s in vif_ss:
- vifs_vg_path = [pi, "vif-s", vif_s, "vrrp", "vrrp-group"]
- if config.exists(parent_path + vifs_vg_path):
- vifsgroups = config.list_nodes(parent_path + vifs_vg_path)
- for vifs_group in vifsgroups:
- g = get_vrrp_group(parent_path + vifs_vg_path + [vifs_group])
- g["interface"] = "{0}.{1}".format(pi, vif_s)
- g["vrid"] = vifs_group
- groups.append(g)
-
- config.delete(parent_path + [pi, "vif-s", vif_s, "vrrp"])
-
- # Extract VRRP groups from QinQ client VLAN interfaces nested in the vif-s
- if config.exists(parent_path + [pi, "vif-s", vif_s, "vif-c"]):
- vif_cs = config.list_nodes(parent_path + [pi, "vif-s", vif_s, "vif-c"])
- for vif_c in vif_cs:
- vifc_vg_path = [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp", "vrrp-group"]
- vifcgroups = config.list_nodes(parent_path + vifc_vg_path)
- for vifc_group in vifcgroups:
- g = get_vrrp_group(parent_path + vifc_vg_path + [vifc_group])
- g["interface"] = "{0}.{1}.{2}".format(pi, vif_s, vif_c)
- g["vrid"] = vifc_group
- groups.append(g)
-
- config.delete(parent_path + [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp"])
-
-# If nothing was collected before this point, it means the config has no VRRP setup
-if not groups:
- sys.exit(0)
-
-# Otherwise, there is VRRP to convert
-
-# Now convert the collected groups to the new syntax
-base_group_path = ["high-availability", "vrrp", "group"]
-sync_path = ["high-availability", "vrrp", "sync-group"]
-
-for g in groups:
- group_name = "{0}-{1}".format(g["interface"], g["vrid"])
- group_path = base_group_path + [group_name]
-
- config.set(group_path + ["interface"], value=g["interface"])
- config.set(group_path + ["vrid"], value=g["vrid"])
-
- if "advertise_interval" in g:
- config.set(group_path + ["advertise-interval"], value=g["advertise_interval"])
-
- if "priority" in g:
- config.set(group_path + ["priority"], value=g["priority"])
-
- if not g["preempt"]:
- config.set(group_path + ["no-preempt"], value=None)
-
- if "preempt_delay" in g:
- config.set(group_path + ["preempt-delay"], value=g["preempt_delay"])
-
- if g["rfc_compatibility"]:
- config.set(group_path + ["rfc3768-compatibility"], value=None)
-
- if g["disable"]:
- config.set(group_path + ["disable"], value=None)
-
- if "hello_source" in g:
- config.set(group_path + ["hello-source-address"], value=g["hello_source"])
-
- if "peer_address" in g:
- config.set(group_path + ["peer-address"], value=g["peer_address"])
-
- if "auth_password" in g:
- config.set(group_path + ["authentication", "password"], value=g["auth_password"])
- if "auth_type" in g:
- config.set(group_path + ["authentication", "type"], value=g["auth_type"])
-
- if "master_script" in g:
- config.set(group_path + ["transition-script", "master"], value=g["master_script"])
- if "backup_script" in g:
- config.set(group_path + ["transition-script", "backup"], value=g["backup_script"])
- if "fault_script" in g:
- config.set(group_path + ["transition-script", "fault"], value=g["fault_script"])
-
- if "health_check_interval" in g:
- config.set(group_path + ["health-check", "interval"], value=g["health_check_interval"])
- if "health_check_count" in g:
- config.set(group_path + ["health-check", "failure-count"], value=g["health_check_count"])
- if "health_check_script" in g:
- config.set(group_path + ["health-check", "script"], value=g["health_check_script"])
-
- # Not that it should ever be absent...
- if "virtual_addresses" in g:
- # The new CLI disallows addresses without prefix length
- # Pre-rewrite configs didn't support IPv6 VRRP, but handle it anyway
- for va in g["virtual_addresses"]:
- if not re.search(r'/', va):
- if re.search(r':', va):
- va = "{0}/128".format(va)
- else:
- va = "{0}/32".format(va)
- config.set(group_path + ["virtual-address"], value=va, replace=False)
-
- # Sync group
- if "sync_group" in g:
- config.set(sync_path + [g["sync_group"], "member"], value=group_name, replace=False)
-
-# Set the tag flag
-config.set_tag(base_group_path)
-if config.exists(sync_path):
- config.set_tag(sync_path)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+def migrate(config: ConfigTree) -> None:
+ groups = []
+ base_paths = []
+
+ if config.exists(["interfaces", "ethernet"]):
+ base_paths.append("ethernet")
+ if config.exists(["interfaces", "bonding"]):
+ base_paths.append("bonding")
+
+ for bp in base_paths:
+ parent_path = ["interfaces", bp]
+
+ parent_intfs = config.list_nodes(parent_path)
+
+ for pi in parent_intfs:
+ # Extract VRRP groups from the parent interface
+ vg_path =[pi, "vrrp", "vrrp-group"]
+ if config.exists(parent_path + vg_path):
+ pgroups = config.list_nodes(parent_path + vg_path)
+ for pg in pgroups:
+ g = get_vrrp_group(parent_path + vg_path + [pg])
+ g["interface"] = pi
+ g["vrid"] = pg
+ groups.append(g)
+
+ # Delete the VRRP subtree
+ # If left in place, configs will not load correctly
+ config.delete(parent_path + [pi, "vrrp"])
+
+ # Extract VRRP groups from 802.1q VLAN interfaces
+ if config.exists(parent_path + [pi, "vif"]):
+ vifs = config.list_nodes(parent_path + [pi, "vif"])
+ for vif in vifs:
+ vif_vg_path = [pi, "vif", vif, "vrrp", "vrrp-group"]
+ if config.exists(parent_path + vif_vg_path):
+ vifgroups = config.list_nodes(parent_path + vif_vg_path)
+ for vif_group in vifgroups:
+ g = get_vrrp_group(parent_path + vif_vg_path + [vif_group])
+ g["interface"] = "{0}.{1}".format(pi, vif)
+ g["vrid"] = vif_group
+ groups.append(g)
+
+ config.delete(parent_path + [pi, "vif", vif, "vrrp"])
+
+ # Extract VRRP groups from 802.3ad QinQ service VLAN interfaces
+ if config.exists(parent_path + [pi, "vif-s"]):
+ vif_ss = config.list_nodes(parent_path + [pi, "vif-s"])
+ for vif_s in vif_ss:
+ vifs_vg_path = [pi, "vif-s", vif_s, "vrrp", "vrrp-group"]
+ if config.exists(parent_path + vifs_vg_path):
+ vifsgroups = config.list_nodes(parent_path + vifs_vg_path)
+ for vifs_group in vifsgroups:
+ g = get_vrrp_group(parent_path + vifs_vg_path + [vifs_group])
+ g["interface"] = "{0}.{1}".format(pi, vif_s)
+ g["vrid"] = vifs_group
+ groups.append(g)
+
+ config.delete(parent_path + [pi, "vif-s", vif_s, "vrrp"])
+
+ # Extract VRRP groups from QinQ client VLAN interfaces nested in the vif-s
+ if config.exists(parent_path + [pi, "vif-s", vif_s, "vif-c"]):
+ vif_cs = config.list_nodes(parent_path + [pi, "vif-s", vif_s, "vif-c"])
+ for vif_c in vif_cs:
+ vifc_vg_path = [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp", "vrrp-group"]
+ vifcgroups = config.list_nodes(parent_path + vifc_vg_path)
+ for vifc_group in vifcgroups:
+ g = get_vrrp_group(parent_path + vifc_vg_path + [vifc_group])
+ g["interface"] = "{0}.{1}.{2}".format(pi, vif_s, vif_c)
+ g["vrid"] = vifc_group
+ groups.append(g)
+
+ config.delete(parent_path + [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp"])
+
+ # If nothing was collected before this point, it means the config has no VRRP setup
+ if not groups:
+ return
+
+ # Otherwise, there is VRRP to convert
+
+ # Now convert the collected groups to the new syntax
+ base_group_path = ["high-availability", "vrrp", "group"]
+ sync_path = ["high-availability", "vrrp", "sync-group"]
+
+ for g in groups:
+ group_name = "{0}-{1}".format(g["interface"], g["vrid"])
+ group_path = base_group_path + [group_name]
+
+ config.set(group_path + ["interface"], value=g["interface"])
+ config.set(group_path + ["vrid"], value=g["vrid"])
+
+ if "advertise_interval" in g:
+ config.set(group_path + ["advertise-interval"], value=g["advertise_interval"])
+
+ if "priority" in g:
+ config.set(group_path + ["priority"], value=g["priority"])
+
+ if not g["preempt"]:
+ config.set(group_path + ["no-preempt"], value=None)
+
+ if "preempt_delay" in g:
+ config.set(group_path + ["preempt-delay"], value=g["preempt_delay"])
+
+ if g["rfc_compatibility"]:
+ config.set(group_path + ["rfc3768-compatibility"], value=None)
+
+ if g["disable"]:
+ config.set(group_path + ["disable"], value=None)
+
+ if "hello_source" in g:
+ config.set(group_path + ["hello-source-address"], value=g["hello_source"])
+
+ if "peer_address" in g:
+ config.set(group_path + ["peer-address"], value=g["peer_address"])
+
+ if "auth_password" in g:
+ config.set(group_path + ["authentication", "password"], value=g["auth_password"])
+ if "auth_type" in g:
+ config.set(group_path + ["authentication", "type"], value=g["auth_type"])
+
+ if "master_script" in g:
+ config.set(group_path + ["transition-script", "master"], value=g["master_script"])
+ if "backup_script" in g:
+ config.set(group_path + ["transition-script", "backup"], value=g["backup_script"])
+ if "fault_script" in g:
+ config.set(group_path + ["transition-script", "fault"], value=g["fault_script"])
+
+ if "health_check_interval" in g:
+ config.set(group_path + ["health-check", "interval"], value=g["health_check_interval"])
+ if "health_check_count" in g:
+ config.set(group_path + ["health-check", "failure-count"], value=g["health_check_count"])
+ if "health_check_script" in g:
+ config.set(group_path + ["health-check", "script"], value=g["health_check_script"])
+
+ # Not that it should ever be absent...
+ if "virtual_addresses" in g:
+ # The new CLI disallows addresses without prefix length
+ # Pre-rewrite configs didn't support IPv6 VRRP, but handle it anyway
+ for va in g["virtual_addresses"]:
+ if not re.search(r'/', va):
+ if re.search(r':', va):
+ va = "{0}/128".format(va)
+ else:
+ va = "{0}/32".format(va)
+ config.set(group_path + ["virtual-address"], value=va, replace=False)
+
+ # Sync group
+ if "sync_group" in g:
+ config.set(sync_path + [g["sync_group"], "member"], value=group_name, replace=False)
+
+ # Set the tag flag
+ config.set_tag(base_group_path)
+ if config.exists(sync_path):
+ config.set_tag(sync_path)
diff --git a/src/migration-scripts/vrrp/2-to-3 b/src/migration-scripts/vrrp/2-to-3
index ed583b489..468918f91 100755..100644
--- a/src/migration-scripts/vrrp/2-to-3
+++ b/src/migration-scripts/vrrp/2-to-3
@@ -1,62 +1,44 @@
-#!/usr/bin/env python3
+# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2021 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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/>.
# T3847: vrrp config cleanup
-from sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print('Must specify file name!')
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['high-availability', 'vrrp']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['group']):
- for group in config.list_nodes(base + ['group']):
- group_base = base + ['group', group]
-
- # Deprecated option
- tmp = group_base + ['transition-script', 'mode-force']
- if config.exists(tmp):
- config.delete(tmp)
-
- # Rename virtual-address -> address
- tmp = group_base + ['virtual-address']
- if config.exists(tmp):
- config.rename(tmp, 'address')
-
- # Rename virtual-address-excluded -> excluded-address
- tmp = group_base + ['virtual-address-excluded']
- if config.exists(tmp):
- config.rename(tmp, 'excluded-address')
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+
+ if config.exists(base + ['group']):
+ for group in config.list_nodes(base + ['group']):
+ group_base = base + ['group', group]
+
+ # Deprecated option
+ tmp = group_base + ['transition-script', 'mode-force']
+ if config.exists(tmp):
+ config.delete(tmp)
+
+ # Rename virtual-address -> address
+ tmp = group_base + ['virtual-address']
+ if config.exists(tmp):
+ config.rename(tmp, 'address')
+
+ # Rename virtual-address-excluded -> excluded-address
+ tmp = group_base + ['virtual-address-excluded']
+ if config.exists(tmp):
+ config.rename(tmp, 'excluded-address')
diff --git a/src/migration-scripts/vrrp/3-to-4 b/src/migration-scripts/vrrp/3-to-4
index e5d93578c..9f05cf7a1 100755..100644
--- a/src/migration-scripts/vrrp/3-to-4
+++ b/src/migration-scripts/vrrp/3-to-4
@@ -1,51 +1,32 @@
-#!/usr/bin/env python3
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Copyright (C) 2023 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 program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
+# 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 General Public License for more details.
+# 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 General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 sys import argv
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print('Must specify file name!')
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
base = ['high-availability', 'virtual-server']
-config = ConfigTree(config_file)
-
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base):
- for vs in config.list_nodes(base):
- vs_base = base + [vs]
- # If the fwmark is used, the address is not required
- if not config.exists(vs_base + ['fwmark']):
- # add option: 'virtual-server <tag> address x.x.x.x'
- config.set(vs_base + ['address'], value=vs)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ # Nothing to do
+ return
+ if config.exists(base):
+ for vs in config.list_nodes(base):
+ vs_base = base + [vs]
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print(f'Failed to save the modified config: {e}')
- exit(1)
+ # If the fwmark is used, the address is not required
+ if not config.exists(vs_base + ['fwmark']):
+ # add option: 'virtual-server <tag> address x.x.x.x'
+ config.set(vs_base + ['address'], value=vs)
diff --git a/src/migration-scripts/webproxy/1-to-2 b/src/migration-scripts/webproxy/1-to-2
index 03f357878..5a4847474 100755..100644
--- a/src/migration-scripts/webproxy/1-to-2
+++ b/src/migration-scripts/webproxy/1-to-2
@@ -1,39 +1,33 @@
-#!/usr/bin/env python3
+# Copyright 2018-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 old style `webproxy proxy-bypass 1.2.3.4/24`
# to new style `webproxy whitelist destination-address 1.2.3.4/24`
-import sys
-
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
+cfg_webproxy_base = ['service', 'webproxy']
-config = ConfigTree(config_file)
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(cfg_webproxy_base + ['proxy-bypass']):
+ # Nothing to do
+ return
-cfg_webproxy_base = ['service', 'webproxy']
-if not config.exists(cfg_webproxy_base + ['proxy-bypass']):
- # Nothing to do
- sys.exit(0)
-else:
bypass_addresses = config.return_values(cfg_webproxy_base + ['proxy-bypass'])
# delete old configuration node
config.delete(cfg_webproxy_base + ['proxy-bypass'])
for bypass_address in bypass_addresses:
# add data to new configuration node
config.set(cfg_webproxy_base + ['whitelist', 'destination-address'], value=bypass_address, replace=False)
-
- # save updated configuration
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)