From 9dbaab281856e760ea8f511b9d2f4acd843bbb2e Mon Sep 17 00:00:00 2001 From: d-dashkov Date: Fri, 5 Feb 2021 12:45:21 +0200 Subject: [PATCH 1/4] Initial dedublicate configlet Signed-off-by: d-dashkov --- scripts/configlet | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/configlet b/scripts/configlet index 0e201be432..1e2765ceee 100755 --- a/scripts/configlet +++ b/scripts/configlet @@ -93,6 +93,15 @@ def init(): db.connect(False) connected = True +def uniq(lst): + prv = object() + for item in lst: + if item == prv: + print(f"Duplicate found: {item}") + continue + yield item + prv = item + def db_update(t, k, lst): init() to_upd = False @@ -108,6 +117,8 @@ def db_update(t, k, lst): to_upd = True if to_upd: + for key, value in lst.items(): + lst[key] = list(uniq(list(value))) db.mod_entry(t, k, lst) def db_delete_fields(t, k, lst): @@ -159,7 +170,7 @@ def do_delete(t, k, lst): def do_operate(op_upd, t, k, lst): if lst: - if type(lst[lst.keys()[0]]) == dict: + if type(lst[list(lst.keys())[0]]) == dict: for i in lst: do_operate(op_upd, t, k+(i,), lst[i]) return From 7a485c123525777edd2d397fe10eecce5782f597 Mon Sep 17 00:00:00 2001 From: d-dashkov Date: Fri, 5 Feb 2021 13:57:46 +0200 Subject: [PATCH 2/4] Fixed single and unsorted values Signed-off-by: d-dashkov --- scripts/configlet | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/configlet b/scripts/configlet index 1e2765ceee..ab28270c82 100755 --- a/scripts/configlet +++ b/scripts/configlet @@ -118,7 +118,8 @@ def db_update(t, k, lst): if to_upd: for key, value in lst.items(): - lst[key] = list(uniq(list(value))) + if type(value) == list: + lst[key] = list(uniq(sorted(list(value)))) db.mod_entry(t, k, lst) def db_delete_fields(t, k, lst): From 17562cac673de60e6937712e06b5a13e22433e2f Mon Sep 17 00:00:00 2001 From: d-dashkov Date: Mon, 8 Feb 2021 11:50:35 +0200 Subject: [PATCH 3/4] Added comment Signed-off-by: d-dashkov --- scripts/configlet | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/configlet b/scripts/configlet index ab28270c82..f4161b1ed2 100755 --- a/scripts/configlet +++ b/scripts/configlet @@ -119,7 +119,8 @@ def db_update(t, k, lst): if to_upd: for key, value in lst.items(): if type(value) == list: - lst[key] = list(uniq(sorted(list(value)))) + # If value is list check its on dublicate + lst[key] = list(uniq(sorted(value))) db.mod_entry(t, k, lst) def db_delete_fields(t, k, lst): From 02cf5d909995ecfbba454bc8f8473e8c91be46a7 Mon Sep 17 00:00:00 2001 From: d-dashkov Date: Tue, 2 Mar 2021 16:25:27 +0200 Subject: [PATCH 4/4] Added YANG models Signed-off-by: d-dashkov --- scripts/configlet | 52 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/scripts/configlet b/scripts/configlet index f4161b1ed2..9a54139620 100755 --- a/scripts/configlet +++ b/scripts/configlet @@ -77,14 +77,21 @@ A sample for update: import argparse import json +import sonic_yang +import syslog from swsscommon.swsscommon import ConfigDBConnector +from sonic_py_common import logger +from json import load -test_only = False +YANG_DIR = "/usr/local/yang-models" +SYSLOG_IDENTIFIER = "configlet" +test_only = False connected = False db = ConfigDBConnector() +log = logger.Logger(SYSLOG_IDENTIFIER) def init(): global connected @@ -187,6 +194,27 @@ def process_entry(op_upd, data): for t in data: do_operate(op_upd, t, (), data[t]) +def readJsonFile(fileName): + try: + with open(fileName) as f: + result = load(f) + except Exception as e: + raise Exception(e) + return result + +def readConfigDBJson(source): + configdbJsonIn = readJsonFile(source) + if not configdbJsonIn: + raise Exception("Can not load config from config DB json file") + return configdbJsonIn + +def validateConfigData(sy): + try: + sy.validate_data_tree() + except Exception as e: + return False + return True + def main(): global test_only @@ -196,6 +224,7 @@ def main(): parser.add_argument("-p", "--parse", help="Parse JSON only", action='store_true', default=False) parser.add_argument("-u", "--update", help="Apply the JSON as update", action='store_true', default=False) parser.add_argument("-d", "--delete", help="Apply the JSON as delete", action='store_true', default=False) + parser.add_argument("-y", "--disable_yang", help="Disable YANG validation", action='store_true', default=False) args = parser.parse_args() @@ -203,6 +232,7 @@ def main(): parse_only = args.parse do_update = args.update do_delete = args.delete + disable_yang = args.disable_yang do_act = test_only | parse_only | do_update | do_delete if not do_act: @@ -210,7 +240,27 @@ def main(): parser.print_help() exit(-1) + if not disable_yang: + try: + sy = sonic_yang.SonicYang(YANG_DIR) + sy.loadYangModel() + except Exception as e: + print(f'Error: Cannot load YANG models.') + exit(-1) + for json_file in args.json: + + if not disable_yang: + try: + for entry in readConfigDBJson(json_file): + sy.loadData(entry) + if validateConfigData(sy) is False: + print(f'Error: {json_file} is not valide by YANG models.') + exit(-1) + except Exception as e: + print(f'Error: {e}') + exit(-1) + with open(json_file, 'r') as stream: data = json.load(stream) if parse_only == False: