summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/include/version/dhcp-server-version.xml.i2
-rw-r--r--smoketest/config-tests/basic-vyos69
-rw-r--r--smoketest/configs/basic-vyos18
-rwxr-xr-xsrc/migration-scripts/dhcp-server/6-to-769
-rwxr-xr-xsrc/migration-scripts/dhcp-server/7-to-866
-rwxr-xr-xsrc/migration-scripts/dhcp-server/8-to-942
-rwxr-xr-xsrc/migration-scripts/dhcp-server/9-to-1075
7 files changed, 227 insertions, 114 deletions
diff --git a/interface-definitions/include/version/dhcp-server-version.xml.i b/interface-definitions/include/version/dhcp-server-version.xml.i
index d83172e72..3dcbc513a 100644
--- a/interface-definitions/include/version/dhcp-server-version.xml.i
+++ b/interface-definitions/include/version/dhcp-server-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/dhcp-server-version.xml.i -->
-<syntaxVersion component='dhcp-server' version='9'></syntaxVersion>
+<syntaxVersion component='dhcp-server' version='10'></syntaxVersion>
<!-- include end -->
diff --git a/smoketest/config-tests/basic-vyos b/smoketest/config-tests/basic-vyos
index 0bb68b75d..d676c663d 100644
--- a/smoketest/config-tests/basic-vyos
+++ b/smoketest/config-tests/basic-vyos
@@ -1,13 +1,9 @@
set interfaces ethernet eth0 address '192.168.0.1/24'
-set interfaces ethernet eth0 duplex 'auto'
-set interfaces ethernet eth0 speed 'auto'
-set interfaces ethernet eth1 duplex 'auto'
-set interfaces ethernet eth1 speed 'auto'
-set interfaces ethernet eth2 duplex 'auto'
-set interfaces ethernet eth2 speed 'auto'
+set interfaces ethernet eth0 address 'fe88::1/56'
set interfaces ethernet eth2 vif 100 address '100.100.0.1/24'
set interfaces ethernet eth2 vif-s 200 address '100.64.200.254/24'
set interfaces ethernet eth2 vif-s 200 vif-c 201 address '100.64.201.254/24'
+set interfaces ethernet eth2 vif-s 200 vif-c 201 address 'fe89::1/56'
set interfaces ethernet eth2 vif-s 200 vif-c 202 address '100.64.202.254/24'
set interfaces loopback lo
set protocols static arp interface eth0 address 192.168.0.20 mac '00:50:00:00:00:20'
@@ -23,18 +19,6 @@ set protocols static arp interface eth2.200.201 address 100.64.201.20 mac '00:50
set protocols static arp interface eth2.200.202 address 100.64.202.30 mac '00:50:00:00:00:30'
set protocols static arp interface eth2.200.202 address 100.64.202.40 mac '00:50:00:00:00:40'
set protocols static route 0.0.0.0/0 next-hop 100.64.0.1
-set service dhcp-server shared-network-name LAN authoritative
-set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option default-router '192.168.0.1'
-set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option domain-name 'vyos.net'
-set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option domain-search 'vyos.net'
-set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option name-server '192.168.0.1'
-set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic start '192.168.0.20'
-set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic stop '192.168.0.240'
-set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 subnet-id '1'
-set service dns forwarding allow-from '192.168.0.0/16'
-set service dns forwarding cache-size '10000'
-set service dns forwarding dnssec 'off'
-set service dns forwarding listen-address '192.168.0.1'
set service ssh ciphers 'aes128-ctr'
set service ssh ciphers 'aes192-ctr'
set service ssh ciphers 'aes256-ctr'
@@ -46,18 +30,55 @@ set service ssh key-exchange 'diffie-hellman-group-exchange-sha1'
set service ssh key-exchange 'diffie-hellman-group-exchange-sha256'
set service ssh listen-address '192.168.0.1'
set service ssh port '22'
+set service dhcp-server shared-network-name LAN authoritative
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option default-router '192.168.0.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option domain-name 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option domain-search 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option name-server '192.168.0.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic start '192.168.0.30'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic stop '192.168.0.240'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST1-1 ip-address '192.168.0.11'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST1-1 mac '00:01:02:03:04:05'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST1-2 disable
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST1-2 ip-address '192.168.0.12'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST1-2 mac '00:01:02:03:04:05'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST2-1 ip-address '192.168.0.21'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST2-1 mac '00:01:02:03:04:21'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST2-2 disable
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST2-2 ip-address '192.168.0.21'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping TEST2-2 mac '00:01:02:03:04:22'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 subnet-id '1'
+set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 interface 'eth0'
+set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 option domain-search 'vyos.net'
+set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 option name-server 'fe88::1'
+set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 range 1 prefix 'fe88::/60'
+set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 range 2 start 'fe88:0000:0000:fe::'
+set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 range 2 stop 'fe88:0000:0000:ff::'
+set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 subnet-id '1'
+set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 interface 'eth2.200.201'
+set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 option domain-search 'vyos.net'
+set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 option name-server 'fe89::1'
+set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 range 1 prefix 'fe89::/60'
+set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 range 2 start 'fe89:0000:0000:fe::'
+set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 range 2 stop 'fe89:0000:0000:ff::'
+set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 subnet-id '2'
+set service dns forwarding allow-from '192.168.0.0/16'
+set service dns forwarding cache-size '10000'
+set service dns forwarding dnssec 'off'
+set service dns forwarding listen-address '192.168.0.1'
set system config-management commit-revisions '100'
-set system console device ttyS0 speed '115200'
+set system conntrack ignore ipv4 rule 1 destination address '192.0.2.2'
+set system conntrack ignore ipv4 rule 1 source address '192.0.2.1'
set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
set system name-server '192.168.0.1'
-set system syslog console facility all level 'emerg'
-set system syslog console facility mail level 'info'
-set system syslog global facility all level 'info'
set system syslog global facility auth level 'info'
-set system syslog global facility local7 level 'debug'
set system syslog global preserve-fqdn
+set system syslog console facility all level 'emerg'
+set system syslog console facility mail level 'info'
set system syslog host syslog.vyos.net facility auth level 'warning'
set system syslog host syslog.vyos.net facility local7 level 'notice'
set system syslog host syslog.vyos.net format octet-counted
set system syslog host syslog.vyos.net port '8000'
-set system time-zone 'Europe/Berlin'
+set system console device ttyS0 speed '115200'
diff --git a/smoketest/configs/basic-vyos b/smoketest/configs/basic-vyos
index 76aa52039..e95d7458f 100644
--- a/smoketest/configs/basic-vyos
+++ b/smoketest/configs/basic-vyos
@@ -86,9 +86,25 @@ service {
domain-name vyos.net
domain-search vyos.net
range LANDynamic {
- start 192.168.0.20
+ start 192.168.0.30
stop 192.168.0.240
}
+ static-mapping TEST1-1 {
+ ip-address 192.168.0.11
+ mac-address 00:01:02:03:04:05
+ }
+ static-mapping TEST1-2 {
+ ip-address 192.168.0.12
+ mac-address 00:01:02:03:04:05
+ }
+ static-mapping TEST2-1 {
+ ip-address 192.168.0.21
+ mac-address 00:01:02:03:04:21
+ }
+ static-mapping TEST2-2 {
+ ip-address 192.168.0.21
+ mac-address 00:01:02:03:04:22
+ }
}
}
}
diff --git a/src/migration-scripts/dhcp-server/6-to-7 b/src/migration-scripts/dhcp-server/6-to-7
index ccf385a30..e6c298a60 100755
--- a/src/migration-scripts/dhcp-server/6-to-7
+++ b/src/migration-scripts/dhcp-server/6-to-7
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 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
@@ -14,19 +14,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# T3316: Migrate to Kea
-# - global-parameters will not function
-# - shared-network-parameters will not function
-# - subnet-parameters will not function
-# - static-mapping-parameters will not function
-# - host-decl-name is on by default, option removed
-# - ping-check no longer supported
-# - failover is default enabled on all subnets that exist on failover servers
+# T6079: Disable duplicate static mappings
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
@@ -38,46 +31,42 @@ with open(file_name, 'r') as f:
base = ['service', 'dhcp-server']
config = ConfigTree(config_file)
-if not config.exists(base):
+if not config.exists(base + ['shared-network-name']):
# Nothing to do
- sys.exit(0)
+ exit(0)
-if config.exists(base + ['host-decl-name']):
- config.delete(base + ['host-decl-name'])
+# 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 config.exists(base + ['global-parameters']):
- config.delete(base + ['global-parameters'])
+ if not config.exists(base_network + ['subnet']):
+ continue
-if config.exists(base + ['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 config.exists(base_network + ['ping-check']):
- config.delete(base_network + ['ping-check'])
+ if config.exists(base_subnet + ['static-mapping']):
+ used_mac = []
+ used_ip = []
- if config.exists(base_network + ['shared-network-parameters']):
- config.delete(base_network +['shared-network-parameters'])
+ for mapping in config.list_nodes(base_subnet + ['static-mapping']):
+ base_mapping = base_subnet + ['static-mapping', mapping]
- if not config.exists(base_network + ['subnet']):
- continue
+ if config.exists(base_mapping + ['mac-address']):
+ mac = config.return_value(base_mapping + ['mac-address'])
- # Run this for every specified 'subnet'
- for subnet in config.list_nodes(base_network + ['subnet']):
- base_subnet = base_network + ['subnet', subnet]
+ if mac in used_mac:
+ config.set(base_mapping + ['disable'])
+ else:
+ used_mac.append(mac)
- if config.exists(base_subnet + ['enable-failover']):
- config.delete(base_subnet + ['enable-failover'])
+ if config.exists(base_mapping + ['ip-address']):
+ ip = config.return_value(base_mapping + ['ip-address'])
- if config.exists(base_subnet + ['ping-check']):
- config.delete(base_subnet + ['ping-check'])
-
- if config.exists(base_subnet + ['subnet-parameters']):
- config.delete(base_subnet + ['subnet-parameters'])
-
- 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 ip in used_ip:
+ config.set(base_subnet + ['static-mapping', mapping, 'disable'])
+ else:
+ used_ip.append(ip)
try:
with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/dhcp-server/7-to-8 b/src/migration-scripts/dhcp-server/7-to-8
index 151aa6d7b..ccf385a30 100755
--- a/src/migration-scripts/dhcp-server/7-to-8
+++ b/src/migration-scripts/dhcp-server/7-to-8
@@ -14,16 +14,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. 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 ..."
+# T3316: Migrate to Kea
+# - global-parameters will not function
+# - shared-network-parameters will not function
+# - subnet-parameters will not function
+# - static-mapping-parameters will not function
+# - host-decl-name is on by default, option removed
+# - ping-check no longer supported
+# - failover is default enabled on all subnets that exist on failover servers
import sys
-import re
from vyos.configtree import ConfigTree
-if len(sys.argv) < 2:
+if (len(sys.argv) < 2):
print("Must specify file name!")
sys.exit(1)
@@ -32,30 +35,49 @@ file_name = sys.argv[1]
with open(file_name, 'r') as f:
config_file = f.read()
-base = ['service', 'dhcp-server', 'shared-network-name']
+base = ['service', 'dhcp-server']
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 + ['host-decl-name']):
+ config.delete(base + ['host-decl-name'])
+
+if config.exists(base + ['global-parameters']):
+ config.delete(base + ['global-parameters'])
+
+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 + ['ping-check']):
+ config.delete(base_network + ['ping-check'])
+
+ if config.exists(base_network + ['shared-network-parameters']):
+ config.delete(base_network +['shared-network-parameters'])
- # Rename the 'mac-address' node to 'mac'
- if config.exists(base_mapping + ['mac-address']):
- config.rename(base_mapping + ['mac-address'], 'mac')
+ if not config.exists(base_network + ['subnet']):
+ continue
- # 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)
+ # 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 + ['enable-failover']):
+ config.delete(base_subnet + ['enable-failover'])
+
+ if config.exists(base_subnet + ['ping-check']):
+ config.delete(base_subnet + ['ping-check'])
+
+ if config.exists(base_subnet + ['subnet-parameters']):
+ config.delete(base_subnet + ['subnet-parameters'])
+
+ 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'])
try:
with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/dhcp-server/8-to-9 b/src/migration-scripts/dhcp-server/8-to-9
index 810e403a6..151aa6d7b 100755
--- a/src/migration-scripts/dhcp-server/8-to-9
+++ b/src/migration-scripts/dhcp-server/8-to-9
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright (C) 2023 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
@@ -15,8 +15,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# T3316:
-# - Migrate dhcp options under new option node
-# - Add subnet IDs to existing subnets
+# - 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
@@ -38,34 +39,23 @@ 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',
- 'name-server', 'ip-forwarding', 'ipv6-only-preferred', 'ntp-server',
- 'pop-server', 'server-identifier', 'smtp-server', 'static-route',
- '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])
-
+ # 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]
-
- 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_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')
- config.set(base_subnet + ['subnet-id'], value=subnet_id)
- subnet_id += 1
+ # 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:
diff --git a/src/migration-scripts/dhcp-server/9-to-10 b/src/migration-scripts/dhcp-server/9-to-10
new file mode 100755
index 000000000..810e403a6
--- /dev/null
+++ b/src/migration-scripts/dhcp-server/9-to-10
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 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
+# published by the Free Software Foundation.
+#
+# 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 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/>.
+
+# T3316:
+# - Migrate dhcp options under new option node
+# - Add subnet IDs to existing subnets
+
+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)
+
+option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-portal',
+ 'client-prefix-length', 'default-router', 'domain-name', 'domain-search',
+ 'name-server', 'ip-forwarding', 'ipv6-only-preferred', 'ntp-server',
+ 'pop-server', 'server-identifier', 'smtp-server', 'static-route',
+ '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])
+
+ if config.exists(base + [network, 'subnet']):
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ base_subnet = base + [network, 'subnet', subnet]
+
+ 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.set(base_subnet + ['subnet-id'], value=subnet_id)
+ subnet_id += 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)