diff --git a/config/main.py b/config/main.py index b35d507b1c..7a61f35e08 100644 --- a/config/main.py +++ b/config/main.py @@ -952,7 +952,7 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port, """ Check if SPAN mirror-session config is valid """ ctx = click.get_current_context() if len(config_db.get_entry('MIRROR_SESSION', session_name)) != 0: - click.echo("Error: {} already exists".format(session_name)) + click.echo("Error: {} already exists".format(session_name)) # TODO: MISSING CONSTRAINT IN YANG MODEL return False vlan_member_table = config_db.get_table('VLAN_MEMBER') @@ -2333,25 +2333,35 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer session_info['gre_type'] = gre_type session_info = gather_session_info(session_info, policer, queue, src_port, direction) + ctx = click.get_current_context() """ For multi-npu platforms we need to program all front asic namespaces """ namespaces = multi_asic.get_all_namespaces() if not namespaces['front_ns']: - config_db = ConfigDBConnector() + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) config_db.connect() - if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False: - return - config_db.set_entry("MIRROR_SESSION", session_name, session_info) + if ADHOC_VALIDATION: + if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False: + return + try: + config_db.set_entry("MIRROR_SESSION", session_name, session_info) + except ValueError as e: + ctx.fail("Invalid mirror session config. Error: {}".format(e)) + else: per_npu_configdb = {} for front_asic_namespaces in namespaces['front_ns']: - per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) + per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)) per_npu_configdb[front_asic_namespaces].connect() - if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False: - return - per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) + if ADHOC_VALIDATION: + if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False: + return + try: + per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) + except ValueError as e: + ctx.fail("Invalid mirror session config. Error: {}".format(e)) @mirror_session.group(cls=clicommon.AbbreviationGroup, name='span') @click.pass_context @@ -2383,25 +2393,34 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): } session_info = gather_session_info(session_info, policer, queue, src_port, direction) + ctx = click.get_current_context() """ For multi-npu platforms we need to program all front asic namespaces """ namespaces = multi_asic.get_all_namespaces() if not namespaces['front_ns']: - config_db = ConfigDBConnector() + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) config_db.connect() - if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False: - return - config_db.set_entry("MIRROR_SESSION", session_name, session_info) + if ADHOC_VALIDATION: + if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False: + return + try: + config_db.set_entry("MIRROR_SESSION", session_name, session_info) + except ValueError as e: + ctx.fail("Invalid mirror session config. Error: {}".format(e)) else: per_npu_configdb = {} for front_asic_namespaces in namespaces['front_ns']: - per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) + per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)) per_npu_configdb[front_asic_namespaces].connect() - if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False: - return - per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) + if ADHOC_VALIDATION: + if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False: + return + try: + per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) + except ValueError as e: + ctx.fail("Invalid mirror session config. Error: {}".format(e)) @mirror_session.command() @@ -2413,16 +2432,23 @@ def remove(session_name): For multi-npu platforms we need to program all front asic namespaces """ namespaces = multi_asic.get_all_namespaces() + ctx = click.get_current_context() if not namespaces['front_ns']: - config_db = ConfigDBConnector() + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) config_db.connect() - config_db.set_entry("MIRROR_SESSION", session_name, None) + try: + config_db.set_entry("MIRROR_SESSION", session_name, None) + except JsonPatchConflict: + ctx.fail("Failed to remove MIRROR_SESSION {}".format(session_name)) else: per_npu_configdb = {} for front_asic_namespaces in namespaces['front_ns']: - per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) + per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)) per_npu_configdb[front_asic_namespaces].connect() - per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, None) + try: + per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, None) + except JsonPatchConflict: + ctx.fail("Failed to remove MIRROR_SESSION {}".format(session_name)) # # 'pfcwd' group ('config pfcwd ...') diff --git a/config/validated_config_db_connector.py b/config/validated_config_db_connector.py index b94a2df4a5..c7352d29b3 100644 --- a/config/validated_config_db_connector.py +++ b/config/validated_config_db_connector.py @@ -1,4 +1,5 @@ import jsonpatch +import subprocess from jsonpointer import JsonPointer from sonic_py_common import device_info @@ -12,6 +13,15 @@ def ValidatedConfigDBConnector(config_db_connector): config_db_connector.delete_table = validated_delete_table return config_db_connector +def is_table_present_config_db(table): + cmd = "sonic-cfggen -d --print-data" + result = subprocess.Popen(cmd, shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + text, err = result.communicate() + return_code = result.returncode + if return_code: # non-zero means failure + raise Exception(f"Failed to get running config, Return code: {return_code}, Error: {err}") + return table in text + def make_path_value_jsonpatch_compatible(table, key, value): if type(key) == tuple: path = JsonPointer.from_parts([table, '|'.join(key)]).path @@ -22,6 +32,13 @@ def make_path_value_jsonpatch_compatible(table, key, value): return path, value def create_gcu_patch(op, table, key=None, value=None): + gcu_json_input = [] + if op == "add" and not is_table_present_config_db(table): + gcu_json = {"op": "{}".format(op), + "path": "/{}".format(table), + "value": {}} + gcu_json_input.append(gcu_json) + if key: path, value = make_path_value_jsonpatch_compatible(table, key, value) else: