From e76d9a009632629e6a22b0d77eebc913c9268a6d Mon Sep 17 00:00:00 2001
From: John Estabrook <jestabro@vyos.io>
Date: Fri, 25 Sep 2020 11:49:30 -0500
Subject: syslog: T2899: shift system migration files +1 to allow for crux

---
 src/migration-scripts/system/10-to-11 |  61 ++++-------------
 src/migration-scripts/system/11-to-12 |  88 +++++++++++++++---------
 src/migration-scripts/system/12-to-13 |  85 +++++++++--------------
 src/migration-scripts/system/13-to-14 |  56 ++++++++++++----
 src/migration-scripts/system/14-to-15 |  21 +++---
 src/migration-scripts/system/15-to-16 |  34 +++-------
 src/migration-scripts/system/16-to-17 |  43 +++---------
 src/migration-scripts/system/17-to-18 | 123 +++++++++++++---------------------
 src/migration-scripts/system/18-to-19 | 105 +++++++++++++++++++++++++++++
 src/migration-scripts/system/9-to-10  |  36 ----------
 10 files changed, 326 insertions(+), 326 deletions(-)
 create mode 100755 src/migration-scripts/system/18-to-19
 delete mode 100755 src/migration-scripts/system/9-to-10

(limited to 'src')

diff --git a/src/migration-scripts/system/10-to-11 b/src/migration-scripts/system/10-to-11
index 1a0233c7d..3c49f0d95 100755
--- a/src/migration-scripts/system/10-to-11
+++ b/src/migration-scripts/system/10-to-11
@@ -1,9 +1,7 @@
 #!/usr/bin/env python3
 
-# 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.
+# 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
@@ -18,54 +16,21 @@ with open(file_name, 'r') as f:
     config_file = f.read()
 
 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
+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:
-    #
-    # Migrate "system login radius-source-address" to "system login radius"
-    #
-    if config.exists(cfg_base + ['radius-source-address']):
-        address = config.return_value(cfg_base + ['radius-source-address'])
-        # delete old configuration node
-        config.delete(cfg_base + ['radius-source-address'])
-        # write new configuration node
-        config.set(cfg_base + ['radius', 'source-address'], value=address)
-
-    #
-    # Migrate "system login radius-server" tag node to new
-    # "system login radius server" tag node and also rename the "secret" node to "key"
-    #
-    for server in config.list_nodes(cfg_base + ['radius-server']):
-        base_server = cfg_base + ['radius-server', server]
-        # "key" node is mandatory
-        key = config.return_value(base_server + ['secret'])
-        config.set(cfg_base + ['radius', 'server', server, 'key'], value=key)
-
-        # "port" is optional
-        if config.exists(base_server + ['port']):
-            port = config.return_value(base_server + ['port'])
-            config.set(cfg_base + ['radius', 'server', server, 'port'], value=port)
-
-        # "timeout is optional"
-        if config.exists(base_server + ['timeout']):
-            timeout = config.return_value(base_server + ['timeout'])
-            config.set(cfg_base + ['radius', 'server', server, 'timeout'], value=timeout)
-
-        # format as tag node
-        config.set_tag(cfg_base + ['radius', 'server'])
-
-        # delete old configuration node
-        config.delete(base_server)
-
-    # delete top level tag node
-    if config.exists(cfg_base + ['radius-server']):
-        config.delete(cfg_base + ['radius-server'])
+    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:
-        with open(file_name, 'w') as f:
-            f.write(config.to_string())
+        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 36311a19d..1a0233c7d 100755
--- a/src/migration-scripts/system/11-to-12
+++ b/src/migration-scripts/system/11-to-12
@@ -1,47 +1,71 @@
 #!/usr/bin/env python3
 
-# converts 'set system syslog host <address>:<port>'
-# to 'set system syslog host <address> port <port>'
+# 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
-import re
-
 from vyos.configtree import ConfigTree
 
 if (len(sys.argv) < 1):
-  print("Must specify file name!")
-  sys.exit(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()
+    config_file = f.read()
 
 config = ConfigTree(config_file)
-cbase = ['system', 'syslog', 'host']
-
-if not config.exists(cbase):
+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"
+    #
+    if config.exists(cfg_base + ['radius-source-address']):
+        address = config.return_value(cfg_base + ['radius-source-address'])
+        # delete old configuration node
+        config.delete(cfg_base + ['radius-source-address'])
+        # write new configuration node
+        config.set(cfg_base + ['radius', 'source-address'], value=address)
 
-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)
+    #
+    # Migrate "system login radius-server" tag node to new
+    # "system login radius server" tag node and also rename the "secret" node to "key"
+    #
+    for server in config.list_nodes(cfg_base + ['radius-server']):
+        base_server = cfg_base + ['radius-server', server]
+        # "key" node is mandatory
+        key = config.return_value(base_server + ['secret'])
+        config.set(cfg_base + ['radius', 'server', server, 'key'], value=key)
+
+        # "port" is optional
+        if config.exists(base_server + ['port']):
+            port = config.return_value(base_server + ['port'])
+            config.set(cfg_base + ['radius', 'server', server, 'port'], value=port)
+
+        # "timeout is optional"
+        if config.exists(base_server + ['timeout']):
+            timeout = config.return_value(base_server + ['timeout'])
+            config.set(cfg_base + ['radius', 'server', server, 'timeout'], value=timeout)
+
+        # format as tag node
+        config.set_tag(cfg_base + ['radius', 'server'])
+
+        # delete old configuration node
+        config.delete(base_server)
+
+    # 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 5b068f4fc..36311a19d 100755
--- a/src/migration-scripts/system/12-to-13
+++ b/src/migration-scripts/system/12-to-13
@@ -1,70 +1,47 @@
 #!/usr/bin/env python3
 
-# 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
-# assigned time zones. In the past they have been silently remapped.
-#
-# Time to clean it up!
-#
-# Migrate all configured timezones to real IANA assigned timezones!
+# converts 'set system syslog host <address>:<port>'
+# to 'set system syslog host <address> port <port>'
 
-import re
 import sys
+import re
 
 from vyos.configtree import ConfigTree
-from vyos.util import cmd
-
 
 if (len(sys.argv) < 1):
-    print("Must specify file name!")
-    sys.exit(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()
+  config_file = f.read()
 
 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)
+cbase = ['system', 'syslog', 'host']
 
-    # retrieve all valid timezones
-    try:
-        tz_datas = cmd('find /usr/share/zoneinfo/posix -type f -or -type l | sed -e s:/usr/share/zoneinfo/posix/::')
-    except OSError:
-        tz_datas = ''
-    tz_data = tz_datas.split('\n')
-
-    if re.match(r'[Ll][Oo][Ss].+', tz):
-        tz = 'America/Los_Angeles'
-    elif re.match(r'[Dd][Ee][Nn].+', tz):
-        tz = 'America/Denver'
-    elif re.match(r'[Hh][Oo][Nn][Oo].+', tz):
-        tz = 'Pacific/Honolulu'
-    elif re.match(r'[Nn][Ee][Ww].+', tz):
-        tz = 'America/New_York'
-    elif re.match(r'[Cc][Hh][Ii][Cc]*.+', tz):
-        tz = 'America/Chicago'
-    elif re.match(r'[Aa][Nn][Cc].+', tz):
-        tz = 'America/Anchorage'
-    elif re.match(r'[Pp][Hh][Oo].+', tz):
-        tz = 'America/Phoenix'
-    elif re.match(r'GMT(.+)?', tz):
-        tz = 'Etc/' + tz
-    elif tz not in tz_data:
-        # assign default UTC timezone
-        tz = 'UTC'
-
-    # replace timezone data is required
-    config.set(tz_base, value=tz)
+if not config.exists(cbase):
+    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)
+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)
diff --git a/src/migration-scripts/system/13-to-14 b/src/migration-scripts/system/13-to-14
index c055dad1f..5b068f4fc 100755
--- a/src/migration-scripts/system/13-to-14
+++ b/src/migration-scripts/system/13-to-14
@@ -1,15 +1,19 @@
 #!/usr/bin/env python3
+
+# 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
+# assigned time zones. In the past they have been silently remapped.
+#
+# Time to clean it up!
 #
-# 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.
+# Migrate all configured timezones to real IANA assigned timezones!
 
-import os
+import re
 import sys
 
-ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf'
-
 from vyos.configtree import ConfigTree
+from vyos.util import cmd
+
 
 if (len(sys.argv) < 1):
     print("Must specify file name!")
@@ -21,16 +25,42 @@ with open(file_name, 'r') as f:
     config_file = f.read()
 
 config = ConfigTree(config_file)
-ip_base = ['system', 'ipv6']
-if not config.exists(ip_base):
+tz_base = ['system', 'time-zone']
+if not config.exists(tz_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)
+    tz = config.return_value(tz_base)
+
+    # retrieve all valid timezones
+    try:
+        tz_datas = cmd('find /usr/share/zoneinfo/posix -type f -or -type l | sed -e s:/usr/share/zoneinfo/posix/::')
+    except OSError:
+        tz_datas = ''
+    tz_data = tz_datas.split('\n')
+
+    if re.match(r'[Ll][Oo][Ss].+', tz):
+        tz = 'America/Los_Angeles'
+    elif re.match(r'[Dd][Ee][Nn].+', tz):
+        tz = 'America/Denver'
+    elif re.match(r'[Hh][Oo][Nn][Oo].+', tz):
+        tz = 'Pacific/Honolulu'
+    elif re.match(r'[Nn][Ee][Ww].+', tz):
+        tz = 'America/New_York'
+    elif re.match(r'[Cc][Hh][Ii][Cc]*.+', tz):
+        tz = 'America/Chicago'
+    elif re.match(r'[Aa][Nn][Cc].+', tz):
+        tz = 'America/Anchorage'
+    elif re.match(r'[Pp][Hh][Oo].+', tz):
+        tz = 'America/Phoenix'
+    elif re.match(r'GMT(.+)?', tz):
+        tz = 'Etc/' + tz
+    elif tz not in tz_data:
+        # assign default UTC timezone
+        tz = 'UTC'
+
+    # replace timezone data is required
+    config.set(tz_base, value=tz)
 
     try:
         with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/system/14-to-15 b/src/migration-scripts/system/14-to-15
index 2491e3d0d..c055dad1f 100755
--- a/src/migration-scripts/system/14-to-15
+++ b/src/migration-scripts/system/14-to-15
@@ -1,10 +1,14 @@
 #!/usr/bin/env python3
 #
-# Make 'system options reboot-on-panic' valueless
+# 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) < 1):
@@ -17,17 +21,16 @@ with open(file_name, 'r') as f:
     config_file = f.read()
 
 config = ConfigTree(config_file)
-base = ['system', 'options']
-if not config.exists(base):
+ip_base = ['system', 'ipv6']
+if not config.exists(ip_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'])
+    # 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:
diff --git a/src/migration-scripts/system/15-to-16 b/src/migration-scripts/system/15-to-16
index e70893d55..2491e3d0d 100755
--- a/src/migration-scripts/system/15-to-16
+++ b/src/migration-scripts/system/15-to-16
@@ -1,24 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020 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/>.
-
-# * 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?
-# * remove "system login user <user> level" node
-#   This is the only privilege level left and also the default, what is the
-#   sense in keeping this orphaned node?
+# Make 'system options reboot-on-panic' valueless
 
 import os
 import sys
@@ -35,17 +17,17 @@ with open(file_name, 'r') as f:
     config_file = f.read()
 
 config = ConfigTree(config_file)
-base = ['system', 'login', 'user']
+base = ['system', 'options']
 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'])
+    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:
diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17
index 8f762c0e2..e70893d55 100755
--- a/src/migration-scripts/system/16-to-17
+++ b/src/migration-scripts/system/16-to-17
@@ -14,8 +14,11 @@
 # 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 "system console netconsole"
-# remove "system console device <device> modem"
+# * 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?
+# * remove "system login user <user> level" node
+#   This is the only privilege level left and also the default, what is the
+#   sense in keeping this orphaned node?
 
 import os
 import sys
@@ -32,41 +35,17 @@ with open(file_name, 'r') as f:
     config_file = f.read()
 
 config = ConfigTree(config_file)
-base = ['system', 'console']
+base = ['system', 'login', 'user']
 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'])
+    for user in config.list_nodes(base):
+        if config.exists(base + [user, 'group']):
+            config.delete(base + [user, 'group'])
 
-    if config.exists(base + ['device']):
-        for device in config.list_nodes(base + ['device']):
-            dev_path = base + ['device', device]
-            # remove "system console device <device> modem" (T2570)
-            if config.exists(dev_path + ['modem']):
-                config.delete(dev_path + ['modem'])
-
-            # Only continue on USB based serial consoles
-            if not 'ttyUSB' in device:
-                continue
-
-            # A serial console has been configured but it does no longer
-            # exist on the system - cleanup
-            if not os.path.exists(f'/dev/{device}'):
-                config.delete(dev_path)
-                continue
-
-            # migrate from ttyUSB device to new device in /dev/serial/by-bus
-            for root, dirs, files in os.walk('/dev/serial/by-bus'):
-                for usb_device in files:
-                    device_file = os.path.realpath(os.path.join(root, usb_device))
-                    # migrate to new USB device names (T2529)
-                    if os.path.basename(device_file) == device:
-                        config.copy(dev_path, base + ['device', usb_device])
-                        # Delete old USB node from config
-                        config.delete(dev_path)
+        if config.exists(base + [user, 'level']):
+            config.delete(base + [user, 'level'])
 
     try:
         with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/system/17-to-18 b/src/migration-scripts/system/17-to-18
index dd2abce00..8f762c0e2 100755
--- a/src/migration-scripts/system/17-to-18
+++ b/src/migration-scripts/system/17-to-18
@@ -13,93 +13,64 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  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
+# remove "system console netconsole"
+# remove "system console device <device> modem"
+
+import os
+import sys
 
-from sys import argv, exit
-from vyos.ifconfig import Interface
 from vyos.configtree import ConfigTree
 
-if (len(argv) < 1):
+if (len(sys.argv) < 1):
     print("Must specify file name!")
-    exit(1)
+    sys.exit(1)
 
-file_name = argv[1]
+file_name = sys.argv[1]
 
 with open(file_name, 'r') as f:
     config_file = f.read()
 
 config = ConfigTree(config_file)
-
-base = ['system']
+base = ['system', 'console']
 if not config.exists(base):
     # Nothing to do
-    exit(0)
-
-if config.exists(base + ['disable-dhcp-nameservers']):
-    config.delete(base + ['disable-dhcp-nameservers'])
+    sys.exit(0)
 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', vif_c]):
-                    for vif_c in config.list_nodes(vif_s_base + ['vif-c', 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)
-
-    # delete old node
-    config.delete(base + ['disable-dhcp-nameservers'])
-
-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)
+    # remove "system console netconsole" (T2561)
+    if config.exists(base + ['netconsole']):
+        config.delete(base + ['netconsole'])
+
+    if config.exists(base + ['device']):
+        for device in config.list_nodes(base + ['device']):
+            dev_path = base + ['device', device]
+            # remove "system console device <device> modem" (T2570)
+            if config.exists(dev_path + ['modem']):
+                config.delete(dev_path + ['modem'])
+
+            # Only continue on USB based serial consoles
+            if not 'ttyUSB' in device:
+                continue
+
+            # A serial console has been configured but it does no longer
+            # exist on the system - cleanup
+            if not os.path.exists(f'/dev/{device}'):
+                config.delete(dev_path)
+                continue
+
+            # migrate from ttyUSB device to new device in /dev/serial/by-bus
+            for root, dirs, files in os.walk('/dev/serial/by-bus'):
+                for usb_device in files:
+                    device_file = os.path.realpath(os.path.join(root, usb_device))
+                    # migrate to new USB device names (T2529)
+                    if os.path.basename(device_file) == device:
+                        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
new file mode 100755
index 000000000..dd2abce00
--- /dev/null
+++ b/src/migration-scripts/system/18-to-19
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2020 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/>.
+#
+
+# 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) < 1):
+    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', vif_c]):
+                    for vif_c in config.list_nodes(vif_s_base + ['vif-c', 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)
+
+    # delete old node
+    config.delete(base + ['disable-dhcp-nameservers'])
+
+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)
diff --git a/src/migration-scripts/system/9-to-10 b/src/migration-scripts/system/9-to-10
deleted file mode 100755
index 3c49f0d95..000000000
--- a/src/migration-scripts/system/9-to-10
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python3
-
-# 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) < 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()
-
-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:
-    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)
-- 
cgit v1.2.3