Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 3ab82c1
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Wed Sep 7 18:33:46 2022 +0000

    add VLAN_MEMBER case

commit 74b22e5
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Fri Sep 2 04:28:35 2022 +0000

    fix typo, syntax

commit e888493
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Fri Sep 2 03:52:21 2022 +0000

    remove remaining mod_entry reference

commit dee4a70
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Tue Aug 23 08:36:29 2022 +0000

    set ADHOC_VALIDATION to True by default

commit 09a2ec9
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Tue Aug 23 08:35:59 2022 +0000

    remove validated_mod_entry - save for future PR

commit 7370198
Merge: 975717b 9f6d79d
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Tue Aug 23 08:34:54 2022 +0000

    resolve merge conflict

commit 975717b
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Tue Aug 23 08:33:50 2022 +0000

    address PR comments

commit 4bcd2d2
Author: isabelmsft <isabel.li@microsoft.com>
Date:   Wed Aug 10 23:18:43 2022 +0000

    re-add removed adhoc validation

commit 9f6d79d
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Wed Aug 10 23:18:43 2022 +0000

    re-add removed adhoc validation

commit 405dd9b
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Fri Aug 5 00:02:44 2022 +0000

    Add note for missing constraints in YANG model

commit b5b15bb
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Wed Aug 3 18:15:45 2022 +0000

    address PR comment

commit 443b2c3
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue Aug 2 08:35:00 2022 +0000

    fix decorator

commit e01c295
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue Aug 2 07:29:28 2022 +0000

    vlan add remove

commit 8829d96
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue Jul 19 09:27:19 2022 +0000

    add loopback interfaces config case

commit eacc138
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Sat Jul 9 05:51:58 2022 +0000

    remove unused import

commit 74e8431
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Sat Jul 9 05:22:03 2022 +0000

    small fixes

commit a40c351
Author: Ubuntu <isl@isl-dev-9.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Sat Jul 9 05:17:50 2022 +0000

    fix portchannel unit tests, update decorator name

commit 3c69396
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue Jun 28 18:11:47 2022 +0000

    adjust error handling

commit dd2e2fd
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue Jun 21 00:28:21 2022 +0000

    Address LGTM, formatting fixes

commit f0b7fb5
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Mon Jun 20 16:36:05 2022 +0000

    Add error specific error handling

commit d9c069e
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Mon Jun 20 15:10:10 2022 +0000

    fix imports

commit 98888f4
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Sun Jun 19 23:35:55 2022 +0000

    keep one ConfigDBConnector instance

commit e9f0baf
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue Jun 14 17:46:00 2022 +0000

    re add comment

commit 1df71b3
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue Jun 14 16:14:43 2022 +0000

    Revert to just db.set_entry()

commit 57ab896
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Sat Jun 4 03:53:59 2022 +0000

    remove portchannel member changes

commit 42051c9
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Fri Jun 3 22:20:15 2022 +0000

    Fix unit tests, LGTM

commit 6b6feda
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Fri Jun 3 06:31:08 2022 +0000

    separate db and validated_db

commit 6bb9189
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Fri Jun 3 00:22:30 2022 +0000

    simplify wrapper

commit ac45e07
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Thu Jun 2 05:56:57 2022 +0000

    fix quotes

commit 8259894
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Thu Jun 2 04:58:48 2022 +0000

    change to decorated

commit e4db00c
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Wed Jun 1 22:21:09 2022 +0000

    Keep original method signature

commit d4ab077
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Wed Jun 1 06:23:52 2022 +0000

    Move GCU to subclass

commit 220a605
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue May 31 07:32:29 2022 +0000

    remove yvs

commit cb9cb94
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue May 31 07:30:33 2022 +0000

    portchannel add and remove

commit e5d3687
Merge: 95afe70 2513da1
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Mon May 30 20:49:25 2022 +0000

    Merge branch 'master' of https://github.com/Azure/sonic-utilities

commit 95afe70
Merge: 8909517 2f53bd4
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue May 24 21:53:43 2022 +0000

    Merge branch 'master' of https://github.com/Azure/sonic-utilities

commit 8909517
Author: Ubuntu <isl@isl-dev-6.gccxvha3jmperpu0bogtupfduf.jx.internal.cloudapp.net>
Date:   Tue May 10 10:55:19 2022 +0000

    Add portchannel YANG validation
  • Loading branch information
isabelmsft committed Sep 7, 2022
1 parent 28926b0 commit f338049
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 113 deletions.
92 changes: 57 additions & 35 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import click
import ipaddress
import json
import jsonpatch
import netaddr
import netifaces
import os
Expand All @@ -13,6 +12,7 @@
import time
import itertools

from jsonpatch import JsonPatchConflict
from collections import OrderedDict
from generic_config_updater.generic_updater import GenericUpdater, ConfigFormat
from minigraph import parse_device_desc_xml, minigraph_encoder
Expand All @@ -29,6 +29,7 @@
import utilities_common.cli as clicommon
from utilities_common.helper import get_port_pbh_binding, get_port_acl_binding
from utilities_common.general import load_db_config, load_module_from_source
from .validated_config_db_connector import ValidatedConfigDBConnector
import utilities_common.multi_asic as multi_asic_util

from .utils import log
Expand Down Expand Up @@ -101,6 +102,7 @@
TTL_RANGE = click.IntRange(min=0, max=255)
QUEUE_RANGE = click.IntRange(min=0, max=255)
GRE_TYPE_RANGE = click.IntRange(min=0, max=65535)
ADHOC_VALIDATION = True

# Load sonic-cfggen from source since /usr/local/bin/sonic-cfggen does not have .py extension.
sonic_cfggen = load_module_from_source('sonic_cfggen', '/usr/local/bin/sonic-cfggen')
Expand Down Expand Up @@ -1949,38 +1951,45 @@ def portchannel(db, ctx, namespace):
@click.pass_context
def add_portchannel(ctx, portchannel_name, min_links, fallback):
"""Add port channel"""
if is_portchannel_name_valid(portchannel_name) != True:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix '{}'"
.format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))

db = ctx.obj['db']


if ADHOC_VALIDATION:
if is_portchannel_name_valid(portchannel_name) != True:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix '{}'"
.format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))

db = ValidatedConfigDBConnector(ctx.obj['db'], ADHOC_VALIDATION)

if is_portchannel_present_in_db(db, portchannel_name):
ctx.fail("{} already exists!".format(portchannel_name))

fvs = {'admin_status': 'up',
'mtu': '9100',
'lacp_key': 'auto'}
if min_links != 0:
fvs['min_links'] = str(min_links)
if fallback != 'false':
fvs['fallback'] = 'true'
db.set_entry('PORTCHANNEL', portchannel_name, fvs)

try:
db.set_entry('PORTCHANNEL', portchannel_name, fvs)
except ValueError:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix '{}'".format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))

@portchannel.command('del')
@click.argument('portchannel_name', metavar='<portchannel_name>', required=True)
@click.pass_context
def remove_portchannel(ctx, portchannel_name):
"""Remove port channel"""
if is_portchannel_name_valid(portchannel_name) != True:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix '{}'"
.format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))

if ADHOC_VALIDATION:
if is_portchannel_name_valid(portchannel_name) != True:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix'{}'"
.format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))

db = ctx.obj['db']
# Don't proceed if the port channel does not exist
if is_portchannel_present_in_db(db, portchannel_name) is False:
ctx.fail("{} is not present.".format(portchannel_name))

# Dont proceed if the port channel does not exist
if is_portchannel_present_in_db(db, portchannel_name) is False:
ctx.fail("{} is not present.".format(portchannel_name))
db = ValidatedConfigDBConnector(ctx.obj['db'], ADHOC_VALIDATION)

# Dont let to remove port channel if vlan membership exists
for k,v in db.get_table('VLAN_MEMBER'):
Expand All @@ -1990,7 +1999,10 @@ def remove_portchannel(ctx, portchannel_name):
if len([(k, v) for k, v in db.get_table('PORTCHANNEL_MEMBER') if k == portchannel_name]) != 0:
click.echo("Error: Portchannel {} contains members. Remove members before deleting Portchannel!".format(portchannel_name))
else:
db.set_entry('PORTCHANNEL', portchannel_name, None)
try:
db.set_entry('PORTCHANNEL', portchannel_name, None)
except JsonPatchConflict:
ctx.fail("{} is not present.".format(portchannel_name))

@portchannel.group(cls=clicommon.AbbreviationGroup, name='member')
@click.pass_context
Expand Down Expand Up @@ -2019,8 +2031,8 @@ def add_portchannel_member(ctx, portchannel_name, port_name):
# Dont proceed if the port channel does not exist
if is_portchannel_present_in_db(db, portchannel_name) is False:
ctx.fail("{} is not present.".format(portchannel_name))

# Dont allow a port to be member of port channel if it is configured with an IP address
# Don't allow a port to be member of port channel if it is configured with an IP address
for key,value in db.get_table('INTERFACE').items():
if type(key) == tuple:
continue
Expand Down Expand Up @@ -6016,36 +6028,46 @@ def loopback(ctx, redis_unix_socket_path):
@click.argument('loopback_name', metavar='<loopback_name>', required=True)
@click.pass_context
def add_loopback(ctx, loopback_name):
config_db = ctx.obj['db']
if is_loopback_name_valid(loopback_name) is False:
ctx.fail("{} is invalid, name should have prefix '{}' and suffix '{}' "
.format(loopback_name, CFG_LOOPBACK_PREFIX, CFG_LOOPBACK_NO))
config_db = ValidatedConfigDBConnector(ctx.obj['db'], ADHOC_VALIDATION)

if ADHOC_VALIDATION:
if is_loopback_name_valid(loopback_name) is False:
ctx.fail("{} is invalid, name should have prefix '{}' and suffix '{}' "
.format(loopback_name, CFG_LOOPBACK_PREFIX, CFG_LOOPBACK_NO))

lo_intfs = [k for k, v in config_db.get_table('LOOPBACK_INTERFACE').items() if type(k) != tuple]
if loopback_name in lo_intfs:
ctx.fail("{} already exists".format(loopback_name))

config_db.set_entry('LOOPBACK_INTERFACE', loopback_name, {"NULL" : "NULL"})

try:
config_db.set_entry('LOOPBACK_INTERFACE', loopback_name, {"NULL" : "NULL"})
except ValueError:
ctx.fail("{} is invalid, name should have prefix '{}' and suffix'{}' ".format(loopback_name, CFG_LOOPBACK_PREFIX, CFG_LOOPBACK_NO))

@loopback.command('del')
@click.argument('loopback_name', metavar='<loopback_name>', required=True)
@click.pass_context
def del_loopback(ctx, loopback_name):
config_db = ctx.obj['db']
if is_loopback_name_valid(loopback_name) is False:
ctx.fail("{} is invalid, name should have prefix '{}' and suffix '{}' "
.format(loopback_name, CFG_LOOPBACK_PREFIX, CFG_LOOPBACK_NO))

config_db = ValidatedConfigDBConnector(ctx.obj['db'], ADHOC_VALIDATION)

lo_config_db = config_db.get_table('LOOPBACK_INTERFACE')
lo_intfs = [k for k, v in lo_config_db.items() if type(k) != tuple]
if loopback_name not in lo_intfs:
ctx.fail("{} does not exists".format(loopback_name))

if ADHOC_VALIDATION:
if is_loopback_name_valid(loopback_name) is False:
ctx.fail("{} is invalid, name should have prefix '{}' and suffix '{}' "
.format(loopback_name, CFG_LOOPBACK_PREFIX, CFG_LOOPBACK_NO))
lo_intfs = [k for k, v in lo_config_db.items() if type(k) != tuple]
if loopback_name not in lo_intfs:
ctx.fail("{} does not exist".format(loopback_name))

ips = [ k[1] for k in lo_config_db if type(k) == tuple and k[0] == loopback_name ]
for ip in ips:
config_db.set_entry('LOOPBACK_INTERFACE', (loopback_name, ip), None)

config_db.set_entry('LOOPBACK_INTERFACE', loopback_name, None)
try:
config_db.set_entry('LOOPBACK_INTERFACE', loopback_name, None)
except JsonPatchConflict:
ctx.fail("{} does not exist".format(loopback_name))


@config.group(cls=clicommon.AbbreviationGroup)
Expand Down
45 changes: 45 additions & 0 deletions config/validated_config_db_connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import jsonpatch
from jsonpointer import JsonPointer

from generic_config_updater.generic_updater import GenericUpdater, ConfigFormat
from generic_config_updater.gu_common import EmptyTableError
from swsscommon.swsscommon import ConfigDBConnector

def ValidatedConfigDBConnector(config_db_connector, fallback_adhoc_validation):
if not fallback_adhoc_validation:
config_db_connector.set_entry = validated_set_entry
return config_db_connector

def make_path_value_jsonpatch_compatible(table, key, value):
if type(key) == tuple:
path = JsonPointer.from_parts([table, '|'.join(key)]).path
else:
path = JsonPointer.from_parts([table, key]).path
if value == {"NULL" : "NULL"}:
value = {}
return path, value

def validated_set_entry(table, key, value):
if value is not None:
op = "add"
else:
op = "remove"
path, value = make_path_value_jsonpatch_compatible(table, key, value)

gcu_json_input = []
gcu_json = {"op": "{}".format(op),
"path": "{}".format(path)}
if op == "add":
gcu_json["value"] = value

gcu_json_input.append(gcu_json)
gcu_patch = jsonpatch.JsonPatch(gcu_json_input)
format = ConfigFormat.CONFIGDB.name
config_format = ConfigFormat[format.upper()]
try:
GenericUpdater().apply_patch(patch=gcu_patch, config_format=config_format, verbose=False, dry_run=False, ignore_non_yang_tables=False, ignore_paths=None)
except EmptyTableError:
config_db = ConfigDBConnector()
config_db.connect()
config_db.set_entry(table, key, None)

Loading

0 comments on commit f338049

Please sign in to comment.