diff options
Diffstat (limited to 'src/migration-scripts')
-rwxr-xr-x | src/migration-scripts/conntrack/1-to-2 | 32 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/18-to-19 | 145 | ||||
-rwxr-xr-x | src/migration-scripts/nat/4-to-5 | 6 | ||||
-rwxr-xr-x | src/migration-scripts/quagga/6-to-7 | 116 | ||||
-rwxr-xr-x | src/migration-scripts/quagga/7-to-8 | 122 | ||||
-rwxr-xr-x | src/migration-scripts/rpki/0-to-1 | 63 | ||||
-rwxr-xr-x | src/migration-scripts/system/18-to-19 | 4 | ||||
-rwxr-xr-x | src/migration-scripts/vrf/0-to-1 | 112 |
8 files changed, 598 insertions, 2 deletions
diff --git a/src/migration-scripts/conntrack/1-to-2 b/src/migration-scripts/conntrack/1-to-2 new file mode 100755 index 000000000..4fc88a1ed --- /dev/null +++ b/src/migration-scripts/conntrack/1-to-2 @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Delete "set system conntrack modules gre" option + +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) + +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/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 new file mode 100755 index 000000000..06e07572f --- /dev/null +++ b/src/migration-scripts/interfaces/18-to-19 @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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/>. + +from sys import argv +from sys import exit +from vyos.configtree import ConfigTree + +def migrate_ospf(config, path, interface): + path = path + ['ospf'] + if config.exists(path): + new_base = ['protocols', 'ospf', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip ospf" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ospfv3(config, path, interface): + path = path + ['ospfv3'] + if config.exists(path): + new_base = ['protocols', 'ospfv3', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ospfv3" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_rip(config, path, interface): + path = path + ['rip'] + if config.exists(path): + new_base = ['protocols', 'rip', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip rip" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ripng(config, path, interface): + path = path + ['ripng'] + if config.exists(path): + new_base = ['protocols', 'ripng', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ripng" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +if __name__ == '__main__': + 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) + + # + # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" + # + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + ip_base = ['interfaces', type, interface, 'ip'] + ipv6_base = ['interfaces', type, interface, 'ipv6'] + migrate_rip(config, ip_base, interface) + migrate_ripng(config, ipv6_base, interface) + migrate_ospf(config, ip_base, interface) + migrate_ospfv3(config, ipv6_base, interface) + + vif_path = ['interfaces', type, interface, 'vif'] + if config.exists(vif_path): + for vif in config.list_nodes(vif_path): + vif_ip_base = vif_path + [vif, 'ip'] + vif_ipv6_base = vif_path + [vif, 'ipv6'] + ifname = f'{interface}.{vif}' + + migrate_rip(config, vif_ip_base, ifname) + migrate_ripng(config, vif_ipv6_base, ifname) + migrate_ospf(config, vif_ip_base, ifname) + migrate_ospfv3(config, vif_ipv6_base, ifname) + + + 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_ip_base = vif_s_path + [vif_s, 'ip'] + vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6'] + + # 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_ip_base = vif_c_path + [vif_c, 'ip'] + vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6'] + ifname = f'{interface}.{vif_s}.{vif_c}' + + migrate_rip(config, vif_c_ip_base, ifname) + migrate_ripng(config, vif_c_ipv6_base, ifname) + migrate_ospf(config, vif_c_ip_base, ifname) + migrate_ospfv3(config, vif_c_ipv6_base, ifname) + + + ifname = f'{interface}.{vif_s}' + migrate_rip(config, vif_s_ip_base, ifname) + 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/nat/4-to-5 b/src/migration-scripts/nat/4-to-5 index dda191719..b791996e2 100755 --- a/src/migration-scripts/nat/4-to-5 +++ b/src/migration-scripts/nat/4-to-5 @@ -36,9 +36,15 @@ if not config.exists(['nat']): 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]): 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] diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7 new file mode 100755 index 000000000..25cf5eebd --- /dev/null +++ b/src/migration-scripts/quagga/6-to-7 @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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/>. + +# - 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) diff --git a/src/migration-scripts/quagga/7-to-8 b/src/migration-scripts/quagga/7-to-8 new file mode 100755 index 000000000..9c277a6f1 --- /dev/null +++ b/src/migration-scripts/quagga/7-to-8 @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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/>. + +# - 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): + """ Generic migration function which can be called on every instance of + interface-route, beeing it ipv4, ipv6 or nested under the "static table" nodes. + + What we do? + - Drop 'interface-route' or 'interface-route6' and migrate the route unter the + 'route' or 'route6' tag node. + """ + if config.exists(base + path): + for route in config.list_nodes(base + path): + interface = config.list_nodes(base + path + [route, 'next-hop-interface']) + + tmp = base + path + [route, 'next-hop-interface'] + for interface in config.list_nodes(tmp): + new_base = base + [route_route6, route, 'interface'] + config.set(new_base) + config.set_tag(base + [route_route6]) + config.set_tag(new_base) + config.copy(tmp + [interface], new_base + [interface]) + + config.delete(base + path) + +def migrate_route(config, base, path, route_route6): + """ Generic migration function which can be called on every instance of + route, beeing it ipv4, ipv6 or even nested under the static table nodes. + + What we do? + - for consistency reasons rename next-hop-interface to interface + - for consistency reasons rename next-hop-vrf to vrf + """ + if config.exists(base + path): + for route in config.list_nodes(base + path): + next_hop = base + path + [route, 'next-hop'] + if config.exists(next_hop): + for gateway in config.list_nodes(next_hop): + # IPv4 routes calls it next-hop-interface, rename this to + # interface instead so it's consitent with IPv6 + interface_path = next_hop + [gateway, 'next-hop-interface'] + if config.exists(interface_path): + config.rename(interface_path, 'interface') + + # When VRFs got introduced, I (c-po) named it next-hop-vrf, + # we can also call it vrf which is simply shorter. + vrf_path = next_hop + [gateway, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') + + +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'] + +config = ConfigTree(config_file) +if not config.exists(base): + # Nothing to do + exit(0) + +# Migrate interface-route into route +migrate_interface_route(config, base, ['interface-route'], 'route') + +# Migrate interface-route6 into route6 +migrate_interface_route(config, base, ['interface-route6'], 'route6') + +# Cleanup nodes inside route +migrate_route(config, base, ['route'], 'route') + +# Cleanup nodes inside route6 +migrate_route(config, base, ['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') + + # 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) diff --git a/src/migration-scripts/rpki/0-to-1 b/src/migration-scripts/rpki/0-to-1 new file mode 100755 index 000000000..5b4893205 --- /dev/null +++ b/src/migration-scripts/rpki/0-to-1 @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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/>. + +from sys import exit +from sys import argv +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() + +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) diff --git a/src/migration-scripts/system/18-to-19 b/src/migration-scripts/system/18-to-19 index dd2abce00..fd0e15d42 100755 --- a/src/migration-scripts/system/18-to-19 +++ b/src/migration-scripts/system/18-to-19 @@ -80,8 +80,8 @@ else: 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]): + 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']): diff --git a/src/migration-scripts/vrf/0-to-1 b/src/migration-scripts/vrf/0-to-1 new file mode 100755 index 000000000..29b2fab74 --- /dev/null +++ b/src/migration-scripts/vrf/0-to-1 @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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/>. + +# - 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') + + # + # 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') + +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) |