forked from sonic-net/sonic-buildimage
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[nvgre] Added auto-generated CLI plugins and test for NVGRE Tunnel fe…
…ature (sonic-net#1915) - What I did Added a click CLI plugins for NVGRE Tunnel feature - How I did it The CLI plugins were auto-generated (by using the sonic-cli-gen) for the show and config CLI groups. - How to verify it Added UT. Signed-off-by: Vadym Hlushko <vadymh@nvidia.com>
- Loading branch information
1 parent
a2e68a0
commit bf55ceb
Showing
8 changed files
with
895 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,349 @@ | ||
""" | ||
Autogenerated config CLI plugin for NVGRE Tunnel feature. | ||
""" | ||
|
||
import copy | ||
import click | ||
import utilities_common.cli as clicommon | ||
import utilities_common.general as general | ||
from config import config_mgmt | ||
|
||
|
||
# Load sonic-cfggen from source since /usr/local/bin/sonic-cfggen does not have .py extension. | ||
sonic_cfggen = general.load_module_from_source('sonic_cfggen', '/usr/local/bin/sonic-cfggen') | ||
|
||
|
||
def exit_with_error(*args, **kwargs): | ||
""" Print a message with click.secho and abort CLI. | ||
Args: | ||
args: Positional arguments to pass to click.secho | ||
kwargs: Keyword arguments to pass to click.secho | ||
""" | ||
|
||
click.secho(*args, **kwargs) | ||
raise click.Abort() | ||
|
||
|
||
def validate_config_or_raise(cfg): | ||
""" Validate config db data using ConfigMgmt. | ||
Args: | ||
cfg (Dict): Config DB data to validate. | ||
Raises: | ||
Exception: when cfg does not satisfy YANG schema. | ||
""" | ||
|
||
try: | ||
cfg = sonic_cfggen.FormatConverter.to_serialized(copy.deepcopy(cfg)) | ||
config_mgmt.ConfigMgmt().loadData(cfg) | ||
except Exception as err: | ||
raise Exception('Failed to validate configuration: {}'.format(err)) | ||
|
||
|
||
def add_entry_validated(db, table, key, data): | ||
""" Add new entry in table and validate configuration. | ||
Args: | ||
db (swsscommon.ConfigDBConnector): Config DB connector obect. | ||
table (str): Table name to add new entry to. | ||
key (Union[str, Tuple]): Key name in the table. | ||
data (Dict): Entry data. | ||
Raises: | ||
Exception: when cfg does not satisfy YANG schema. | ||
""" | ||
|
||
cfg = db.get_config() | ||
cfg.setdefault(table, {}) | ||
if key in cfg[table]: | ||
raise Exception(f"{key} already exists") | ||
|
||
cfg[table][key] = data | ||
|
||
validate_config_or_raise(cfg) | ||
db.set_entry(table, key, data) | ||
|
||
|
||
def update_entry_validated(db, table, key, data, create_if_not_exists=False): | ||
""" Update entry in table and validate configuration. | ||
If attribute value in data is None, the attribute is deleted. | ||
Args: | ||
db (swsscommon.ConfigDBConnector): Config DB connector obect. | ||
table (str): Table name to add new entry to. | ||
key (Union[str, Tuple]): Key name in the table. | ||
data (Dict): Entry data. | ||
create_if_not_exists (bool): | ||
In case entry does not exists already a new entry | ||
is not created if this flag is set to False and | ||
creates a new entry if flag is set to True. | ||
Raises: | ||
Exception: when cfg does not satisfy YANG schema. | ||
""" | ||
|
||
cfg = db.get_config() | ||
cfg.setdefault(table, {}) | ||
|
||
if not data: | ||
raise Exception(f"No field/values to update {key}") | ||
|
||
if create_if_not_exists: | ||
cfg[table].setdefault(key, {}) | ||
|
||
if key not in cfg[table]: | ||
raise Exception(f"{key} does not exist") | ||
|
||
entry_changed = False | ||
for attr, value in data.items(): | ||
if value == cfg[table][key][attr]: | ||
continue | ||
entry_changed = True | ||
if value is None: | ||
cfg[table][key].pop(attr, None) | ||
else: | ||
cfg[table][key][attr] = value | ||
|
||
if not entry_changed: | ||
return | ||
|
||
validate_config_or_raise(cfg) | ||
db.set_entry(table, key, cfg[table][key]) | ||
|
||
|
||
def del_entry_validated(db, table, key): | ||
""" Delete entry in table and validate configuration. | ||
Args: | ||
db (swsscommon.ConfigDBConnector): Config DB connector obect. | ||
table (str): Table name to add new entry to. | ||
key (Union[str, Tuple]): Key name in the table. | ||
Raises: | ||
Exception: when cfg does not satisfy YANG schema. | ||
""" | ||
|
||
cfg = db.get_config() | ||
cfg.setdefault(table, {}) | ||
if key not in cfg[table]: | ||
raise Exception(f"{key} does not exist") | ||
|
||
cfg[table].pop(key) | ||
|
||
validate_config_or_raise(cfg) | ||
db.set_entry(table, key, None) | ||
|
||
|
||
def add_list_entry_validated(db, table, key, attr, data): | ||
""" Add new entry into list in table and validate configuration. | ||
Args: | ||
db (swsscommon.ConfigDBConnector): Config DB connector obect. | ||
table (str): Table name to add data to. | ||
key (Union[str, Tuple]): Key name in the table. | ||
attr (str): Attribute name which represents a list the data needs to be added to. | ||
data (List): Data list to add to config DB. | ||
Raises: | ||
Exception: when cfg does not satisfy YANG schema. | ||
""" | ||
|
||
cfg = db.get_config() | ||
cfg.setdefault(table, {}) | ||
if key not in cfg[table]: | ||
raise Exception(f"{key} does not exist") | ||
cfg[table][key].setdefault(attr, []) | ||
for entry in data: | ||
if entry in cfg[table][key][attr]: | ||
raise Exception(f"{entry} already exists") | ||
cfg[table][key][attr].append(entry) | ||
|
||
validate_config_or_raise(cfg) | ||
db.set_entry(table, key, cfg[table][key]) | ||
|
||
|
||
def del_list_entry_validated(db, table, key, attr, data): | ||
""" Delete entry from list in table and validate configuration. | ||
Args: | ||
db (swsscommon.ConfigDBConnector): Config DB connector obect. | ||
table (str): Table name to remove data from. | ||
key (Union[str, Tuple]): Key name in the table. | ||
attr (str): Attribute name which represents a list the data needs to be removed from. | ||
data (Dict): Data list to remove from config DB. | ||
Raises: | ||
Exception: when cfg does not satisfy YANG schema. | ||
""" | ||
|
||
cfg = db.get_config() | ||
cfg.setdefault(table, {}) | ||
if key not in cfg[table]: | ||
raise Exception(f"{key} does not exist") | ||
cfg[table][key].setdefault(attr, []) | ||
for entry in data: | ||
if entry not in cfg[table][key][attr]: | ||
raise Exception(f"{entry} does not exist") | ||
cfg[table][key][attr].remove(entry) | ||
if not cfg[table][key][attr]: | ||
cfg[table][key].pop(attr) | ||
|
||
validate_config_or_raise(cfg) | ||
db.set_entry(table, key, cfg[table][key]) | ||
|
||
|
||
def clear_list_entry_validated(db, table, key, attr): | ||
""" Clear list in object and validate configuration. | ||
Args: | ||
db (swsscommon.ConfigDBConnector): Config DB connector obect. | ||
table (str): Table name to remove the list attribute from. | ||
key (Union[str, Tuple]): Key name in the table. | ||
attr (str): Attribute name which represents a list that needs to be removed. | ||
Raises: | ||
Exception: when cfg does not satisfy YANG schema. | ||
""" | ||
|
||
update_entry_validated(db, table, key, {attr: None}) | ||
|
||
|
||
@click.group( | ||
name="nvgre-tunnel", | ||
cls=clicommon.AliasedGroup) | ||
def NVGRE_TUNNEL(): | ||
""" NVGRE_TUNNEL part of config_db.json """ | ||
|
||
pass | ||
|
||
|
||
@NVGRE_TUNNEL.command(name="add") | ||
@click.argument( | ||
"tunnel-name", | ||
nargs=1, | ||
required=True, | ||
) | ||
@click.option( | ||
"--src-ip", | ||
required=True, | ||
help="Source IP address[mandatory]", | ||
) | ||
@clicommon.pass_db | ||
def NVGRE_TUNNEL_add(db, tunnel_name, src_ip): | ||
""" Add object in NVGRE_TUNNEL. """ | ||
|
||
table = "NVGRE_TUNNEL" | ||
key = tunnel_name | ||
data = {} | ||
if src_ip is not None: | ||
data["src_ip"] = src_ip | ||
|
||
try: | ||
add_entry_validated(db.cfgdb, table, key, data) | ||
except Exception as err: | ||
exit_with_error(f"Error: {err}", fg="red") | ||
|
||
|
||
@NVGRE_TUNNEL.command(name="delete") | ||
@click.argument( | ||
"tunnel-name", | ||
nargs=1, | ||
required=True, | ||
) | ||
@clicommon.pass_db | ||
def NVGRE_TUNNEL_delete(db, tunnel_name): | ||
""" Delete object in NVGRE_TUNNEL. """ | ||
|
||
table = "NVGRE_TUNNEL" | ||
key = tunnel_name | ||
try: | ||
del_entry_validated(db.cfgdb, table, key) | ||
except Exception as err: | ||
exit_with_error(f"Error: {err}", fg="red") | ||
|
||
|
||
@click.group( | ||
name="nvgre-tunnel-map", | ||
cls=clicommon.AliasedGroup) | ||
def NVGRE_TUNNEL_MAP(): | ||
""" NVGRE_TUNNEL_MAP part of config_db.json """ | ||
|
||
pass | ||
|
||
|
||
@NVGRE_TUNNEL_MAP.command(name="add") | ||
@click.argument( | ||
"tunnel-name", | ||
nargs=1, | ||
required=True, | ||
) | ||
@click.argument( | ||
"tunnel-map-name", | ||
nargs=1, | ||
required=True, | ||
) | ||
|
||
@click.option( | ||
"--vlan-id", | ||
required=True, | ||
help="VLAN identifier[mandatory]", | ||
) | ||
@click.option( | ||
"--vsid", | ||
required=True, | ||
help="Virtual Subnet Identifier[mandatory]", | ||
) | ||
@clicommon.pass_db | ||
def NVGRE_TUNNEL_MAP_add(db, tunnel_name, tunnel_map_name, vlan_id, vsid): | ||
""" Add object in NVGRE_TUNNEL_MAP. """ | ||
|
||
table = "NVGRE_TUNNEL_MAP" | ||
key = tunnel_name, tunnel_map_name | ||
data = {} | ||
if vlan_id is not None: | ||
data["vlan_id"] = vlan_id | ||
if vsid is not None: | ||
data["vsid"] = vsid | ||
|
||
try: | ||
add_entry_validated(db.cfgdb, table, key, data) | ||
except Exception as err: | ||
exit_with_error(f"Error: {err}", fg="red") | ||
|
||
|
||
@NVGRE_TUNNEL_MAP.command(name="delete") | ||
@click.argument( | ||
"tunnel-name", | ||
nargs=1, | ||
required=True, | ||
) | ||
@click.argument( | ||
"tunnel-map-name", | ||
nargs=1, | ||
required=True, | ||
) | ||
@clicommon.pass_db | ||
def NVGRE_TUNNEL_MAP_delete(db, tunnel_name, tunnel_map_name): | ||
""" Delete object in NVGRE_TUNNEL_MAP. """ | ||
|
||
table = "NVGRE_TUNNEL_MAP" | ||
key = tunnel_name, tunnel_map_name | ||
try: | ||
del_entry_validated(db.cfgdb, table, key) | ||
except Exception as err: | ||
exit_with_error(f"Error: {err}", fg="red") | ||
|
||
|
||
def register(cli): | ||
""" Register new CLI nodes in root CLI. | ||
Args: | ||
cli: Root CLI node. | ||
Raises: | ||
Exception: when root CLI already has a command | ||
we are trying to register. | ||
""" | ||
cli_node = NVGRE_TUNNEL | ||
if cli_node.name in cli.commands: | ||
raise Exception(f"{cli_node.name} already exists in CLI") | ||
cli.add_command(NVGRE_TUNNEL) | ||
cli_node = NVGRE_TUNNEL_MAP | ||
if cli_node.name in cli.commands: | ||
raise Exception(f"{cli_node.name} already exists in CLI") | ||
cli.add_command(NVGRE_TUNNEL_MAP) | ||
|
Oops, something went wrong.