Skip to content

Commit

Permalink
[nvgre] Added auto-generated CLI plugins and test for NVGRE Tunnel fe…
Browse files Browse the repository at this point in the history
…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
vadymhlushko-mlnx committed Mar 20, 2022
1 parent a2e68a0 commit bf55ceb
Show file tree
Hide file tree
Showing 8 changed files with 895 additions and 0 deletions.
349 changes: 349 additions & 0 deletions config/plugins/nvgre_tunnel.py
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)

0 comments on commit bf55ceb

Please sign in to comment.