#!/usr/bin/env python3
#
# Copyright (C) 2022 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 .
# T4660: change cli
# from: set policy route-map FOO rule 10 set community 'TEXT'
# Multiple value
# to: set policy route-map FOO rule 10 set community replace
# Multiple value
# to: set policy route-map FOO rule 10 set community add
# to: set policy route-map FOO rule 10 set community none
#
# from: set policy route-map FOO rule 10 set large-community 'TEXT'
# Multiple value
# to: set policy route-map FOO rule 10 set large-community replace
# Multiple value
# to: set policy route-map FOO rule 10 set large-community add
# to: set policy route-map FOO rule 10 set large-community none
#
# from: set policy route-map FOO rule 10 set extecommunity [rt|soo] 'TEXT'
# Multiple value
# to: set policy route-map FOO rule 10 set extcommunity [rt|soo]
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
# Migration function for large and regular communities
def community_migrate(config: ConfigTree, rule: list[str]) -> bool:
"""
:param config: configuration object
:type config: ConfigTree
:param rule: Path to variable
:type rule: list[str]
:return: True if additive presents in community string
:rtype: bool
"""
community_list = list((config.return_value(rule)).split(" "))
if 'none' in community_list:
config.set(rule + ['none'])
return False
else:
community_action: str = 'replace'
if 'additive' in community_list:
community_action = 'add'
community_list.remove('additive')
for community in community_list:
if len(community):
config.set(rule + [community_action], value=community,
replace=False)
config.delete(rule)
if community_action == 'replace':
return False
else:
return True
# Migration function for extcommunities
def extcommunity_migrate(config: ConfigTree, rule: list[str]) -> None:
"""
:param config: configuration object
:type config: ConfigTree
:param rule: Path to variable
:type rule: list[str]
"""
# if config.exists(rule + ['bandwidth']):
# bandwidth: str = config.return_value(rule + ['bandwidth'])
# config.delete(rule + ['bandwidth'])
# config.set(rule + ['bandwidth'], value=bandwidth)
if config.exists(rule + ['rt']):
community_list = list((config.return_value(rule + ['rt'])).split(" "))
config.delete(rule + ['rt'])
for community in community_list:
config.set(rule + ['rt'], value=community, replace=False)
if config.exists(rule + ['soo']):
community_list = list((config.return_value(rule + ['soo'])).split(" "))
config.delete(rule + ['soo'])
for community in community_list:
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)