From 4eafd797258ec8e51682a0ebbd3054967d4786a5 Mon Sep 17 00:00:00 2001 From: sabarivel sakthivel Date: Mon, 28 Sep 2020 15:37:29 -0700 Subject: [PATCH] mclagsyncd enhancements as per HLD at Azure/SONIC#596 --- CLI/actioner/sonic_cli_mclag.py | 468 +++++++++++++++++++++ CLI/clitree/cli-xml/mclag.xml | 97 +++++ CLI/renderer/templates/show_mclag_brief.j2 | 61 +++ CLI/renderer/templates/show_mclag_iface.j2 | 17 + 4 files changed, 643 insertions(+) create mode 100755 CLI/actioner/sonic_cli_mclag.py create mode 100644 CLI/clitree/cli-xml/mclag.xml create mode 100755 CLI/renderer/templates/show_mclag_brief.j2 create mode 100755 CLI/renderer/templates/show_mclag_iface.j2 diff --git a/CLI/actioner/sonic_cli_mclag.py b/CLI/actioner/sonic_cli_mclag.py new file mode 100755 index 0000000000..f4c38581a2 --- /dev/null +++ b/CLI/actioner/sonic_cli_mclag.py @@ -0,0 +1,468 @@ +#!/usr/bin/python +########################################################################### +# +# Copyright 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or +# its subsidiaries. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +########################################################################### + +import sys +import json +import collections +import re +#import pdb +import cli_client as cc +from rpipe_utils import pipestr +from scripts.render_cli import show_cli_output + +def invoke(func, args): + body = None + aa = cc.ApiClient() + + ####################################### + # Configure MCLAG Domain Table - START + ####################################### + + #[un]configure local IP Address + if (func == 'patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_source_ip' or + func == 'delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_source_ip'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_DOMAIN/MCLAG_DOMAIN_LIST={domain_id}/source_ip', domain_id=args[0]) + + if (func.startswith("patch") is True): + body = { + "sonic-mclag:source_ip": args[1] + } + return aa.patch(keypath, body) + else: + return aa.delete(keypath) + + #[un]configure Peer IP Address + if (func == 'patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_ip' or + func == 'delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_ip'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_DOMAIN/MCLAG_DOMAIN_LIST={domain_id}/peer_ip', domain_id=args[0]) + + if (func.startswith("patch") is True): + body = { + "sonic-mclag:peer_ip": args[1] + } + return aa.patch(keypath, body) + else: + return aa.delete(keypath) + + #[un]configure Peer Link + if (func == 'patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_link' or + func == 'delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_link'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_DOMAIN/MCLAG_DOMAIN_LIST={domain_id}/peer_link', domain_id=args[0]) + + if (func.startswith("patch") is True): + if_name = None + if args[2] == 'PortChannel': + if_name = "PortChannel" + args[1] + else: + if_name = "Ethernet" + args[1] + body = { + "sonic-mclag:peer_link": if_name + } + return aa.patch(keypath, body) + else: + return aa.delete(keypath) + + #[un]configure Keepalive interval + if (func == 'patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_keepalive_interval' or + func == 'delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_keepalive_interval'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_DOMAIN/MCLAG_DOMAIN_LIST={domain_id}/keepalive_interval', domain_id=args[0]) + + if (func.startswith("patch") is True): + body = { + "sonic-mclag:keepalive_interval": int(args[1]) + } + return aa.patch(keypath, body) + else: + return aa.delete(keypath) + + #configure session Timeout + if (func == 'patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_session_timeout' or + func == 'delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_session_timeout'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_DOMAIN/MCLAG_DOMAIN_LIST={domain_id}/session_timeout', domain_id=args[0]) + + if (func.startswith("patch") is True): + body = { + "sonic-mclag:session_timeout": int(args[1]) + } + return aa.patch(keypath, body) + else: + return aa.delete(keypath) + + #delete MCLAG Domain + if (func == 'delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_DOMAIN/MCLAG_DOMAIN_LIST={domain_id}', domain_id=args[0]) + return aa.delete(keypath) + + + + ####################################### + # Configure MCLAG Domain Table - END + ####################################### + + + ####################################### + # Configure MCLAG Interface Table - START + ####################################### + if (func == 'patch_sonic_mclag_sonic_mclag_mclag_interface_mclag_interface_list'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_INTERFACE/MCLAG_INTERFACE_LIST={domain_id},{if_name}', + domain_id=args[0], if_name=args[1]) + body = { + "sonic-mclag:MCLAG_INTERFACE_LIST": [ + { + "domain_id":int(args[0]), + "if_name":args[1], + "if_type":"PortChannel" + } + ] + } + return aa.patch(keypath, body) + + if (func == 'delete_sonic_mclag_sonic_mclag_mclag_interface_mclag_interface_list'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_INTERFACE/MCLAG_INTERFACE_LIST={domain_id},{if_name}', + domain_id=(args[0]), if_name=args[1]) + return aa.delete(keypath) + + ####################################### + # Configure MCLAG Domain Table - END + ####################################### + + ####################################### + # Configure MCLAG Unique IP Table - START + ####################################### + if (func == 'patch_sonic_mclag_seperate_ip_list'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_UNIQUE_IP/MCLAG_UNIQUE_IP_LIST={if_name}', + if_name=args[0]) + body = { + "sonic-mclag:MCLAG_UNIQUE_IP_LIST": [ + { + "if_name":args[0], + "unique_ip":"enable" + } + ] + } + return aa.patch(keypath, body) + + if (func == 'delete_sonic_mclag_seperate_ip_list'): + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_UNIQUE_IP/MCLAG_UNIQUE_IP_LIST={if_name}', + if_name=args[0]) + return aa.delete(keypath) + + ####################################### + # Configure MCLAG Unique IP Table - END + ####################################### + + ####################################### + # Get APIs - START + ####################################### + if func == 'get_sonic_mclag_sonic_mclag': + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag') + return aa.get(keypath) + + if func == 'get_sonic_mclag_sonic_mclag_mclag_domain': + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_DOMAIN') + return aa.get(keypath) + + if func == 'get_sonic_mclag_sonic_mclag_mclag_interface_mclag_interface_list': + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_INTERFACE/MCLAG_INTERFACE_LIST={domain_id},{if_name}', domain_id=args[1], if_name=args[0]) + return aa.get(keypath) + + if func == 'get_sonic_mclag_sonic_mclag_mclag_local_intf_table_mclag_local_intf_table_list': + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_LOCAL_INTF_TABLE/MCLAG_LOCAL_INTF_TABLE_LIST={if_name}', if_name=args[0]) + return aa.get(keypath) + + if func == 'get_sonic_mclag_sonic_mclag_mclag_remote_intf_table_mclag_remote_intf_table_list': + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_REMOTE_INTF_TABLE/MCLAG_REMOTE_INTF_TABLE_LIST={domain_id},{if_name}', domain_id=args[1], if_name=args[0]) + return aa.get(keypath) + + if func == 'get_sonic_mclag_sonic_mclag_mclag_table': + keypath = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_TABLE') + return aa.get(keypath) + + ####################################### + # Get APIs - END + ####################################### + + else: + print("%Error: not implemented") + exit(1) + +def mclag_get_portchannel_traffic_disable(po_name): + ''' call LAG Table Rest API to get LAG Admin Status ''' + traffic_disable = 'No' + + aa = cc.ApiClient() + path = cc.Path('/restconf/data/sonic-portchannel:sonic-portchannel/LAG_TABLE/LAG_TABLE_LIST={lagname}/traffic_disable', lagname=po_name) + api_response = aa.get(path) + if api_response.ok(): + response = api_response.content + if len(response) != 0: + if response['sonic-portchannel:traffic_disable']: + traffic_disable = 'Yes' + + return traffic_disable + + +def mclag_get_local_if_port_isolate(po_name): + ''' call MCLAG Local Interface state Table Rest API to get Port isolate property setting ''' + port_isolate = 'No' + + aa = cc.ApiClient() + path = cc.Path('/restconf/data/sonic-mclag:sonic-mclag/MCLAG_LOCAL_INTF_TABLE/MCLAG_LOCAL_INTF_TABLE_LIST={if_name}/port_isolate_peer_link', if_name=po_name) + api_response = aa.get(path) + if api_response.ok(): + response = api_response.content + if len(response) != 0: + if response['sonic-mclag:port_isolate_peer_link']: + port_isolate = 'Yes' + + return port_isolate + + + + +def mclag_get_portchannel_oper_status(po_name): + ''' call LAG Table Rest API to get LAG Admin Status ''' + po_oper_status = 'down' + + aa = cc.ApiClient() + path = cc.Path('/restconf/data/sonic-portchannel:sonic-portchannel/LAG_TABLE/LAG_TABLE_LIST={lagname}/oper_status', lagname=po_name) + api_response = aa.get(path) + if api_response.ok(): + response = api_response.content + if len(response) != 0: + po_oper_status = response['sonic-portchannel:oper_status'] + return po_oper_status + + + +def mclag_get_ethernet_if_oper_status(if_name): + ''' call Ethernet iface Rest API to get Ethernet if Admin Status ''' + if_oper_status = 'down' + + aa = cc.ApiClient() + path = cc.Path('/restconf/data/sonic-port:sonic-port/PORT_TABLE/PORT_TABLE_LIST={ifname}/oper_status', ifname=if_name) + api_response = aa.get(path) + if api_response.ok(): + response = api_response.content + if len(response) != 0: + if_oper_status = response['sonic-port:oper_status'] + return if_oper_status + + + +def mclag_get_remote_if_oper_status(if_name, remote_if_list): + if_oper_status = "down" + + for list_item in remote_if_list: + if list_item["if_name"] == if_name: + for k,v in list_item.iteritems(): + if k == "oper_status": + if_oper_status = v + return if_oper_status + + +#returns True or False and also returns value corresponding to the field +def mclag_is_element_in_list(list_to_search, field): + for list_item in list_to_search: + for k,v in list_item.iteritems(): + if (k == field): + return True + return False + + + +def mclag_convert_list_to_dict(list_to_converted, field = None, value = None): + converted_dict = {} + for list_item in list_to_converted: + if ((field is None) or list_item[field] == value): + for k, v in list_item.iteritems(): + converted_dict[k] = v + return converted_dict; + +def mclag_get_peer_link_status(peer_link_name): + peer_link_status = "" + if peer_link_name is not None: + if peer_link_name.startswith("Ethernet"): + peer_link_status = mclag_get_ethernet_if_oper_status(peer_link_name) + elif peer_link_name.startswith("PortChannel"): + peer_link_status = mclag_get_portchannel_oper_status(peer_link_name) + return peer_link_status + +def mclag_get_mclag_intf_dict(local_if_list, remote_if_list): + mclag_intf_dict = {} + count = 0 + + for list_item in local_if_list: + for k,v in list_item.iteritems(): + if k == "if_name": + mclag_intf_dict[v] = {} + if_local_status = mclag_get_portchannel_oper_status(v) + if_remote_status = mclag_get_remote_if_oper_status(v, remote_if_list) + mclag_intf_dict[v]["local_if_status"] = if_local_status + mclag_intf_dict[v]["remote_if_status"] = if_remote_status + mclag_intf_dict[v]["if_name"] = v + mclag_intf_dict[v]["traffic_disable"] = mclag_get_portchannel_traffic_disable(v) + mclag_intf_dict[v]["port_isolate"] = mclag_get_local_if_port_isolate(v) + count += 1 + return count, mclag_intf_dict + +#show mclag interface command +def mclag_show_mclag_interface(args): + mclag_iface_info = {} + + api_response = invoke("get_sonic_mclag_sonic_mclag_mclag_interface_mclag_interface_list", args[1:]) + if api_response.ok(): + response = api_response.content + if len(response) != 0: + mclag_local_if = [] + mclag_remote_if = [] + mclag_local_if = response['sonic-mclag:MCLAG_INTERFACE_LIST'] + if not mclag_is_element_in_list(mclag_local_if, "if_type"): + print("MCLAG Interface not configured in this domain") + return + + api_response = invoke("get_sonic_mclag_sonic_mclag_mclag_remote_intf_table_mclag_remote_intf_table_list", args[1:]) + if api_response.ok(): + response = api_response.content + if len(response) != 0: + mclag_remote_if = response['sonic-mclag:MCLAG_REMOTE_INTF_TABLE_LIST'] + + count, mclag_iface_info = mclag_get_mclag_intf_dict(mclag_local_if, mclag_remote_if) + show_cli_output(args[0], mclag_iface_info) + else: + print("No MCLAG Interface " + args[1] + " in MCLAG domain " + args[2] + " or domain not found") + + else: + #error response + print api_response + print api_response.error_message() + + return + +#show mclag brief +def mclag_show_mclag_brief(args): + mclag_info = {} + mclag_info['domain_info'] = {} + mclag_info['domain_info'] = {} + mclag_info['mclag_iface_info'] = {} + count_of_mclag_ifaces = 0 + + api_response = invoke("get_sonic_mclag_sonic_mclag", args[1:]) + response = {} + if api_response.ok(): + response = api_response.content + if len(response) != 0 and 'MCLAG_DOMAIN' in response['sonic-mclag:sonic-mclag']: + #{"MCLAG_DOMAIN_LIST":[{"domain_id":"5","peer_ip":"192.168.1.2","peer_link":"PortChannel30","source_ip":"192.168.1.1"}]} + domain_cfg_info = {} + #set default values - somehow it is not picking up from rest API, need to check + domain_cfg_info = mclag_convert_list_to_dict(response['sonic-mclag:sonic-mclag']['MCLAG_DOMAIN']['MCLAG_DOMAIN_LIST']) + #set default values if the values are filled - somehow get rest api not returning default values + if domain_cfg_info.get("keepalive_interval") is None: + domain_cfg_info['keepalive_interval'] = 1; + if domain_cfg_info.get("session_timeout") is None: + domain_cfg_info['session_timeout'] = 30; + peer_link_name = domain_cfg_info.get("peer_link") + domain_cfg_info['peer_link_status'] = mclag_get_peer_link_status(peer_link_name) + + domain_state_info = {} + #domain_state_info = {"oper_status":"down", "role":"", "system_mac":""} + if "MCLAG_TABLE" in response["sonic-mclag:sonic-mclag"]: + domain_state_info = mclag_convert_list_to_dict(response['sonic-mclag:sonic-mclag']['MCLAG_TABLE']['MCLAG_TABLE_LIST'], "domain_id", domain_cfg_info['domain_id']) + mclag_info['domain_info'] = domain_cfg_info.copy() + mclag_info['domain_info'].update(domain_state_info) + + mclag_local_if_list = [] + if "MCLAG_INTERFACE" in response["sonic-mclag:sonic-mclag"]: + mclag_local_if_list = response['sonic-mclag:sonic-mclag']['MCLAG_INTERFACE']['MCLAG_INTERFACE_LIST'] + + mclag_remote_if_list = [] + #mclag_remote_if_list = [{"domain_id":"5", "if_name":"PortChannel50", "oper_status":"down"}, {"domain_id":"5", "if_name":"PortChannel60", "oper_status":"up"}] + if "MCLAG_REMOTE_INTF_TABLE" in response["sonic-mclag:sonic-mclag"]: + mclag_remote_if_list = response['sonic-mclag:sonic-mclag']['MCLAG_REMOTE_INTF_TABLE']['MCLAG_REMOTE_INTF_TABLE_LIST'] + + mclag_info['mclag_iface_info'] = {} + count_of_mclag_ifaces, mclag_info['mclag_iface_info'] = mclag_get_mclag_intf_dict(mclag_local_if_list, mclag_remote_if_list) + mclag_info['domain_info']['number_of_mclag_ifaces'] = count_of_mclag_ifaces + show_cli_output(args[0], mclag_info) + else: + print("MCLAG Not Configured") + + else: + #error response + print api_response + print api_response.error_message() + + return + + +def run(func, args): + + #show commands + try: + #show mclag brief command + if func == 'show_mclag_brief': + mclag_show_mclag_brief(args) + return + if func == 'show_mclag_interface': + mclag_show_mclag_interface(args) + return + + except Exception as e: + print sys.exc_value + return + + + #config commands + try: + api_response = invoke(func, args) + + if api_response.ok(): + response = api_response.content + if response is not None: + print("Error: {}".format(str(response))) + else: + try: + error_data = api_response.content['ietf-restconf:errors']['error'][0] + if 'error-message' in error_data: + err_msg = error_data['error-message'] + if err_msg == 'Entry not found': + print("Entry not found") + else: + print("Error: {}".format(str(api_response.error_message()))) + elif 'error-type' in error_data and error_data['error-type'] == 'application': + if 'error-tag' in error_data and error_data['error-tag'] == 'invalid-value': + if func == 'delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list': + print("{} Possibily Dependent MCLAG config not removed".format(str(api_response.error_message()))) + else: + print("Error: Application/CVL Failure {}".format(str(api_response.error_message()))) + else: + print("Error: {}".format(str(api_response.error_message()))) + except Exception as e: + print("%Error: {}".format(str(e))) + except Exception as e: + print("%Error: {}".format(str(e))) + + return + +if __name__ == '__main__': + pipestr().write(sys.argv) + #pdb.set_trace() + run(sys.argv[1], sys.argv[2:]) + diff --git a/CLI/clitree/cli-xml/mclag.xml b/CLI/clitree/cli-xml/mclag.xml new file mode 100644 index 0000000000..5ed5296bdb --- /dev/null +++ b/CLI/clitree/cli-xml/mclag.xml @@ -0,0 +1,97 @@ + + + + + + +]> + + + + + + + + + + + + sonic_cli_mclag delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list ${mclag-domain-id} + + + + + + + + + + + + + + + + + sonic_cli_mclag patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_source_ip ${id} ${SIP} + + + sonic_cli_mclag delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_source_ip ${id} + + + + sonic_cli_mclag patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_ip ${id} ${PIP} + + + sonic_cli_mclag delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_ip ${id} + + + + + + + + + + + sonic_cli_mclag patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_link ${id} ${PLK} ${if-subcommands} + + + sonic_cli_mclag delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_peer_link ${id} + + + + sonic_cli_mclag patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_keepalive_interval ${id} ${KA} + + + + sonic_cli_mclag delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_keepalive_interval ${id} + + + + sonic_cli_mclag patch_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_session_timeout ${id} ${ST} + + + sonic_cli_mclag delete_sonic_mclag_sonic_mclag_mclag_domain_mclag_domain_list_session_timeout ${id} + + + + + + + + + sonic_cli_mclag show_mclag_brief show_mclag_brief.j2 + + + + + + + + sonic_cli_mclag show_mclag_interface show_mclag_iface.j2 PortChannel${ifid} ${domain_id} + + + + diff --git a/CLI/renderer/templates/show_mclag_brief.j2 b/CLI/renderer/templates/show_mclag_brief.j2 new file mode 100755 index 0000000000..ca4f9725a2 --- /dev/null +++ b/CLI/renderer/templates/show_mclag_brief.j2 @@ -0,0 +1,61 @@ +{% if json_output %} + +{% set vars = {'domain_id': ""} %} + +{% set number_of_mclag_ifaces = 0 %} + +{% if "domain_info" is in json_output %} +{% set domain_info = json_output["domain_info"] %} +{% set number_of_mclag_ifaces = json_output["domain_info"]["number_of_mclag_ifaces"] %} +{% endif %} + +{% if "mclag_iface_info" in json_output %} +{% set mclag_iface_info = json_output["mclag_iface_info"] %} +{% endif %} + +{{ ' ' }} + +{% if domain_info -%} + +{% if vars.update({'domain_id':domain_info["domain_id"]}) %}{% endif %} +{% if vars.update({'role':domain_info["role"]}) %}{% endif %} +{% if vars.update({'session_status':domain_info["oper_status"]}) %}{% endif %} +{% if vars.update({'peer_link_status':domain_info["peer_link_status"]}) %}{% endif %} +{% if vars.update({'source_ip':domain_info["source_ip"]}) %}{% endif %} +{% if vars.update({'peer_ip':domain_info["peer_ip"]}) %}{% endif %} +{% if vars.update({'peer_link':domain_info["peer_link"]}) %}{% endif %} +{% if vars.update({'keepalive_interval':domain_info["keepalive_interval"]}) %} {% endif %} +{% if vars.update({'session_timeout':domain_info["session_timeout"]}) %}{% endif %} +{% if vars.update({'system_mac':domain_info["system_mac"]}) %}{% endif %} + + +{{'Domain ID'.ljust(20)}} : {{ vars.domain_id }} +{{'Role'.ljust(20)}} : {{ vars.role}} +{{'Session Status'.ljust(20)}} : {{ vars.session_status}} +{{'Peer Link Status'.ljust(20)}} : {{ vars.peer_link_status}} +{{'Source Address'.ljust(20)}} : {{ vars.source_ip}} +{{'Peer Address'.ljust(20)}} : {{ vars.peer_ip}} +{{'Peer Link'.ljust(20)}} : {{ vars.peer_link}} +{{'Keepalive Interval'.ljust(20)}} : {{ vars.keepalive_interval}} {{'secs'}} +{{'Session Timeout'.ljust(20)}} : {{ vars.session_timeout}} {{'secs'}} +{{'System Mac'.ljust(20)}} : {{ vars.system_mac}} + +{{ ' \n ' }} +Number of MLAG Interfaces:{{ number_of_mclag_ifaces }} + +{% if mclag_iface_info -%} +{{'-----------------------------------------------------------'}} +{{'MLAG Interface'.ljust(20)}} {{'Local/Remote Status'.ljust(20)}} +{{'-----------------------------------------------------------'}} +{% for key in mclag_iface_info %} +{% if vars.update({'if_name':mclag_iface_info[key]["if_name"]}) %}{% endif %} +{% if vars.update({'local_if_status':mclag_iface_info[key]["local_if_status"]}) %}{% endif %} +{% if vars.update({'remote_if_status':mclag_iface_info[key]["remote_if_status"]}) %}{% endif %} + +{{(vars.if_name).ljust(25)}}{{vars.local_if_status}}{{'/'}}{{vars.remote_if_status}} +{% endfor %} +{% endif %} + +{% endif %} + +{% endif %} diff --git a/CLI/renderer/templates/show_mclag_iface.j2 b/CLI/renderer/templates/show_mclag_iface.j2 new file mode 100755 index 0000000000..076e9319a5 --- /dev/null +++ b/CLI/renderer/templates/show_mclag_iface.j2 @@ -0,0 +1,17 @@ +{% set vars = {'if_name': ""} %} +{% set mclag_iface_info = json_output %} + +{% if mclag_iface_info -%} +{% for key in mclag_iface_info %} +{{ ' ' }} +{% if vars.update({'if_name':mclag_iface_info[key]["if_name"]}) %}{% endif %} +{% if vars.update({'local_if_status':mclag_iface_info[key]["local_if_status"]}) %}{% endif %} +{% if vars.update({'remote_if_status':mclag_iface_info[key]["remote_if_status"]}) %}{% endif %} +{% if vars.update({'traffic_disable':mclag_iface_info[key]["traffic_disable"]}) %}{% endif %} +{% if vars.update({'port_isolate':mclag_iface_info[key]["port_isolate"]}) %}{% endif %} + +{{'Local/Remote Status'.ljust(20)}} : {{vars.local_if_status}}{{'/'}}{{vars.remote_if_status}} +{{'TrafficDisable'.ljust(20)}} : {{ vars.traffic_disable}} +{{'IsolateWithPeerLink'.ljust(20)}} : {{ vars.port_isolate}} +{% endfor %} +{% endif %}