From dc5d52f404f964fdd242ef1b6caab3d8bdb7437e Mon Sep 17 00:00:00 2001 From: Neetha John Date: Fri, 25 Jun 2021 09:19:14 -0700 Subject: [PATCH] [minigraph] Update parsing logic for Storage backend devices (#7944) Signed-off-by: Neetha John Why I did it The current logic generates 'VLAN_SUB_INTERFACE' table if the device type is backend and cluster name contains 'str'. This is not a reliable method to determine a storage backend device How I did it Updated the logic to generate 'VLAN_SUB_INTERFACE' table if any of the following conditions hold true - device is of type backend and ResourceType attribute is None - device is of type backend and ResourceType attribute contains "Storage" - device is of type backend and graph contains "Subinterface" section Also updated the logic to set "is_storage_device" to True - For Backend, if any of the above conditions hold true - For Frontend, if ResourceType attribute contains "Storage" How to verify it Added new tests to verify the code changes and built sonic_config_engine-1.0-py3-none-any.whl successfully --- src/sonic-config-engine/minigraph.py | 48 +- .../tests/sample-graph-resource-type.xml | 478 ++++++++++++++++++ .../tests/sample-graph-subintf.xml | 471 +++++++++++++++++ .../tests/simple-sample-graph-case.xml | 5 + src/sonic-config-engine/tests/test_cfggen.py | 127 +++-- .../tests/test_minigraph_case.py | 35 +- 6 files changed, 1104 insertions(+), 60 deletions(-) create mode 100644 src/sonic-config-engine/tests/sample-graph-resource-type.xml create mode 100644 src/sonic-config-engine/tests/sample-graph-subintf.xml diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index f1a54c1796de..a982f861edca 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -180,7 +180,6 @@ def parse_png(png, hname, dpg_ecmp_content = None): port_speeds = {} console_ports = {} mux_cable_ports = {} - is_storage_device = False port_device_map = {} png_ecmp_content = {} FG_NHG_MEMBER = {} @@ -253,10 +252,6 @@ def parse_png(png, hname, dpg_ecmp_content = None): device_data['lo_addr_v6'] = lo_prefix_v6 devices[name] = device_data - if name == hname: - if cluster and "str" in cluster.lower(): - is_storage_device = True - if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): if str(QName(ns3, "type")) in if_link.attrib: @@ -293,7 +288,7 @@ def parse_png(png, hname, dpg_ecmp_content = None): png_ecmp_content = {"FG_NHG_MEMBER": FG_NHG_MEMBER, "FG_NHG": FG_NHG, "NEIGH": NEIGH} - return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speeds, console_ports, mux_cable_ports, is_storage_device, png_ecmp_content) + return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speeds, console_ports, mux_cable_ports, png_ecmp_content) def parse_asic_external_link(link, asic_name, hostname): @@ -402,6 +397,7 @@ def parse_loopback_intf(child): def parse_dpg(dpg, hname): aclintfs = None mgmtintfs = None + subintfs = None tunnelintfs = defaultdict(dict) for child in dpg: """ @@ -441,6 +437,16 @@ def parse_dpg(dpg, hname): ip_intfs_map[ipprefix] = intfalias lo_intfs = parse_loopback_intf(child) + subintfs = child.find(str(QName(ns, "SubInterfaces"))) + if subintfs is not None: + for subintf in subintfs.findall(str(QName(ns, "SubInterface"))): + intfalias = subintf.find(str(QName(ns, "AttachTo"))).text + intfname = port_alias_map.get(intfalias, intfalias) + ipprefix = subintf.find(str(QName(ns, "Prefix"))).text + subintfvlan = subintf.find(str(QName(ns, "Vlan"))).text + subintfname = intfname + VLAN_SUB_INTERFACE_SEPARATOR + subintfvlan + intfs[(subintfname, ipprefix)] = {} + mvrfConfigs = child.find(str(QName(ns, "MgmtVrfConfigs"))) mvrf = {} if mvrfConfigs != None: @@ -1207,7 +1213,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_internal_sessions, bgp_voq_chassis_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): - (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speed_png, console_ports, mux_cable_ports, is_storage_device, png_ecmp_content) = parse_png(child, hostname, dpg_ecmp_content) + (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speed_png, console_ports, mux_cable_ports, png_ecmp_content) = parse_png(child, hostname, dpg_ecmp_content) elif child.tag == str(QName(ns, "UngDec")): (u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname, None) elif child.tag == str(QName(ns, "MetadataDeclaration")): @@ -1273,9 +1279,6 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw results['DEVICE_METADATA']['localhost']['peer_switch'] = list(results['PEER_SWITCH'].keys())[0] - if is_storage_device: - results['DEVICE_METADATA']['localhost']['storage_device'] = "true" - # for this hostname, if sub_role is defined, add sub_role in # device_metadata if sub_role is not None: @@ -1375,6 +1378,9 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw elif intf[0][0:11] == 'PortChannel': pc_intfs[intf] = {} pc_intfs[intf[0]] = {} + elif VLAN_SUB_INTERFACE_SEPARATOR in intf[0]: + vlan_sub_intfs[intf] = {} + vlan_sub_intfs[intf[0]] = {'admin_status': 'up'} else: phyport_intfs[intf] = {} phyport_intfs[intf[0]] = {} @@ -1457,6 +1463,13 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw if port[0] in ports: ports.get(port[0])['admin_status'] = 'up' + if len(vlan_sub_intfs): + for subintf in vlan_sub_intfs: + if not isinstance(subintf, tuple): + parent_port = subintf.split(".")[0] + if parent_port in ports: + ports.get(parent_port)['admin_status'] = 'up' + for member in list(pc_members.keys()) + list(vlan_members.keys()): port = ports.get(member[1]) if port: @@ -1497,9 +1510,16 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw results['PORTCHANNEL_INTERFACE'] = pc_intfs - if current_device['type'] in backend_device_types and is_storage_device: + # for storage backend subinterface info present in minigraph takes precedence over ResourceType + if current_device['type'] in backend_device_types and bool(vlan_sub_intfs): del results['INTERFACE'] del results['PORTCHANNEL_INTERFACE'] + is_storage_device = True + results['VLAN_SUB_INTERFACE'] = vlan_sub_intfs + elif current_device['type'] in backend_device_types and (resource_type is None or 'Storage' in resource_type): + del results['INTERFACE'] + del results['PORTCHANNEL_INTERFACE'] + is_storage_device = True for intf in phyport_intfs.keys(): if isinstance(intf, tuple): @@ -1520,8 +1540,12 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw else: sub_intf = pc_intf + VLAN_SUB_INTERFACE_SEPARATOR + VLAN_SUB_INTERFACE_VLAN_ID vlan_sub_intfs[sub_intf] = {"admin_status" : "up"} - results['VLAN_SUB_INTERFACE'] = vlan_sub_intfs + elif resource_type is not None and 'Storage' in resource_type: + is_storage_device = True + + if is_storage_device: + results['DEVICE_METADATA']['localhost']['storage_device'] = "true" results['VLAN'] = vlans results['VLAN_MEMBER'] = vlan_members diff --git a/src/sonic-config-engine/tests/sample-graph-resource-type.xml b/src/sonic-config-engine/tests/sample-graph-resource-type.xml new file mode 100644 index 000000000000..12961059251d --- /dev/null +++ b/src/sonic-config-engine/tests/sample-graph-resource-type.xml @@ -0,0 +1,478 @@ + + + + + + switch-t0 + 10.1.0.32 + BGPMonitor + 10.20.30.40 + 30 + 10 + 3 + + + false + switch-t0 + 10.0.0.56 + ARISTA01T1 + 10.0.0.57 + 1 + 180 + 60 + false + + + switch-t0 + FC00::71 + ARISTA01T1 + FC00::72 + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.58 + ARISTA02T1 + 10.0.0.59 + 1 + 180 + 60 + + + switch-t0 + FC00::75 + ARISTA02T1 + FC00::76 + 1 + 180 + 60 + + + switch-t0 + FC00::75 + ARISTA02T1 + FC00::76 + 1 + 180 + 60 + + + false + switch-t0 + 10.2.0.20 + CHASSIS_PEER + 10.2.0.21 + 1 + 180 + 60 + true + + + + + 0 + + BGPMonitor + + + BGPPeer +
10.1.0.32
+ + + +
+
+ +
+ + 65100 + switch-t0 + + +
10.0.0.57
+ + + +
+ +
10.0.0.59
+ + + +
+ +
10.2.0.21
+ + + +
+
+ +
+ + 64600 + ARISTA01T1 + + + + 64600 + ARISTA02T1 + + + + 64600 + ARISTA03T1 + + + + 64600 + ARISTA04T1 + + + + 65100 + CHASSIS_PEER + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + HostIP1 + Loopback0 + + FC00:1::32/128 + + FC00:1::32/128 + + + + + HostIP + eth0 + + 10.0.0.100/24 + + 10.0.0.100/24 + + + + + + + switch-t0 + + + PortChannel01 + fortyGigE0/4 + + + + PortChannel1001 + fortyGigE0/1;fortyGigE0/2 + + + + + + ab1 + fortyGigE0/8 + 192.0.0.1;192.0.0.2 + 1000 + 1000 + 192.168.0.0/27 + + + kk1 + fortyGigE0/12 + 192.0.0.1;192.0.0.2 + 2020 + 2020 + Tagged + 192.168.0.0/28 + + + ab2 + fortyGigE0/12 + 192.0.0.1;192.0.0.2 + 2000 + 2000 + 192.168.0.240/27 + + + ab3 + fortyGigE0/12 + 192.0.0.1;192.0.0.2 + 2001 + 2001 + 192.168.0.240/27 + + + + + + PortChannel01 + 10.0.0.56/31 + + + + PortChannel01 + FC00::71/126 + + + + PortChannel1001 + 10.0.0.57/31 + + + + PortChannel1001 + FC00::72/126 + + + + fortyGigE0/0 + 10.0.0.58/31 + + + + fortyGigE0/0 + FC00::75/126 + + + + ab1 + 192.168.0.1/27 + + + + + + PortChannel01 + DataAcl + DataPlane + + + SNMP + SNMP_ACL + SNMP + + + + + + + + + + DeviceInterfaceLink + 1000 + ARISTA01T1 + et1 + true + switch-t0 + fortyGigE0/8 + true + + + DeviceInterfaceLink + 10000 + switch-t0 + fortyGigE0/1 + true + ARISTA05T1 + Ethernet1/32 + true + + + DeviceInterfaceLink + 10000 + switch-t0 + fortyGigE0/2 + true + ARISTA06T1 + Ethernet1/33 + true + + + DeviceMgmtLink + 1000 + switch-t0 + fortyGigE0/16 + true + ChassisMTS1 + mgmt0 + true + + + DeviceMgmtLink + 1000 + switch-t0 + Management1 + switch-m0 + Management1 + true + + + + + switch-t0 + Force10-S6000 + AAA00PrdStr00 + + + ARISTA01T1 + Arista + + + ARISTA02T1 + Arista + + + ARISTA03T1 + Arista + + + ARISTA04T1 + Arista + + + + + + + + DeviceInterface + + true + 1 + fortyGigE0/0 + + false + 0 + 0 + 10000 + + + DeviceInterface + + true + 1 + Ethernet1 + + false + 0 + 0 + 10000 + + + DeviceInterface + + true + 1 + Ethernet2 + + false + 0 + 0 + 10000 + + + DeviceInterface + + true + 1 + fortyGigE0/4 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + 1 + fortyGigE0/8 + + false + 0 + 0 + 40000 + Interface description + + + DeviceInterface + + true + 1 + fortyGigE0/12 + + false + 0 + 0 + 100000 + Interface description + + + DeviceInterface + + true + 1 + fortyGigE0/16 + + false + 0 + 0 + 100000 + + + true + 0 + Force10-S6000 + + + DeviceInterface + + 1 + Management1 + false + mgmt1 + 1000 + + + + + + + + switch-t0 + + + ResourceType + + Storage + + + + + + + switch-t0 + Force10-S6000 +
diff --git a/src/sonic-config-engine/tests/sample-graph-subintf.xml b/src/sonic-config-engine/tests/sample-graph-subintf.xml new file mode 100644 index 000000000000..f487b989a138 --- /dev/null +++ b/src/sonic-config-engine/tests/sample-graph-subintf.xml @@ -0,0 +1,471 @@ + + + + + + switch-t0 + 10.1.0.32 + BGPMonitor + 10.20.30.40 + 30 + 10 + 3 + + + false + switch-t0 + 10.0.0.56 + ARISTA01T1 + 10.0.0.57 + 1 + 180 + 60 + false + + + switch-t0 + FC00::71 + ARISTA01T1 + FC00::72 + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.58 + ARISTA02T1 + 10.0.0.59 + 1 + 180 + 60 + + + switch-t0 + FC00::75 + ARISTA02T1 + FC00::76 + 1 + 180 + 60 + + + switch-t0 + FC00::75 + ARISTA02T1 + FC00::76 + 1 + 180 + 60 + + + false + switch-t0 + 10.2.0.20 + CHASSIS_PEER + 10.2.0.21 + 1 + 180 + 60 + true + + + + + 0 + + BGPMonitor + + + BGPPeer +
10.1.0.32
+ + + +
+
+ +
+ + 65100 + switch-t0 + + +
10.0.0.57
+ + + +
+ +
10.0.0.59
+ + + +
+ +
10.2.0.21
+ + + +
+
+ +
+ + 64600 + ARISTA01T1 + + + + 64600 + ARISTA02T1 + + + + 64600 + ARISTA03T1 + + + + 64600 + ARISTA04T1 + + + + 65100 + CHASSIS_PEER + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + HostIP1 + Loopback0 + + FC00:1::32/128 + + FC00:1::32/128 + + + + + HostIP + eth0 + + 10.0.0.100/24 + + 10.0.0.100/24 + + + + + + + switch-t0 + + + PortChannel01 + fortyGigE0/4 + + + + PortChannel1001 + fortyGigE0/1;fortyGigE0/2 + + + + + + + fortyGigE0/0 + 10 + dot1q + 10.0.0.58/31 + 10 + + + + fortyGigE0/0 + 10 + dot1q + FC00::75/126 + 10 + + + + + ab1 + fortyGigE0/8 + 192.0.0.1;192.0.0.2 + 1000 + 1000 + 192.168.0.0/27 + + + kk1 + fortyGigE0/12 + 192.0.0.1;192.0.0.2 + 2020 + 2020 + Tagged + 192.168.0.0/28 + + + ab2 + fortyGigE0/12 + 192.0.0.1;192.0.0.2 + 2000 + 2000 + 192.168.0.240/27 + + + ab3 + fortyGigE0/12 + 192.0.0.1;192.0.0.2 + 2001 + 2001 + 192.168.0.240/27 + + + + + + PortChannel01 + 10.0.0.56/31 + + + + PortChannel01 + FC00::71/126 + + + + PortChannel1001 + 10.0.0.57/31 + + + + PortChannel1001 + FC00::72/126 + + + + ab1 + 192.168.0.1/27 + + + + + + PortChannel01 + DataAcl + DataPlane + + + SNMP + SNMP_ACL + SNMP + + + + + + + + + + DeviceInterfaceLink + 1000 + ARISTA01T1 + et1 + true + switch-t0 + fortyGigE0/8 + true + + + DeviceInterfaceLink + 10000 + switch-t0 + fortyGigE0/1 + true + ARISTA05T1 + Ethernet1/32 + true + + + DeviceInterfaceLink + 10000 + switch-t0 + fortyGigE0/2 + true + ARISTA06T1 + Ethernet1/33 + true + + + DeviceMgmtLink + 1000 + switch-t0 + fortyGigE0/16 + true + ChassisMTS1 + mgmt0 + true + + + DeviceMgmtLink + 1000 + switch-t0 + Management1 + switch-m0 + Management1 + true + + + + + switch-t0 + Force10-S6000 + AAA00PrdStr00 + + + ARISTA01T1 + Arista + + + ARISTA02T1 + Arista + + + ARISTA03T1 + Arista + + + ARISTA04T1 + Arista + + + + + + + + DeviceInterface + + true + 1 + fortyGigE0/0 + + false + 0 + 0 + 10000 + + + DeviceInterface + + true + 1 + Ethernet1 + + false + 0 + 0 + 10000 + + + DeviceInterface + + true + 1 + Ethernet2 + + false + 0 + 0 + 10000 + + + DeviceInterface + + true + 1 + fortyGigE0/4 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + 1 + fortyGigE0/8 + + false + 0 + 0 + 40000 + Interface description + + + DeviceInterface + + true + 1 + fortyGigE0/12 + + false + 0 + 0 + 100000 + Interface description + + + DeviceInterface + + true + 1 + fortyGigE0/16 + + false + 0 + 0 + 100000 + + + true + 0 + Force10-S6000 + + + DeviceInterface + + 1 + Management1 + false + mgmt1 + 1000 + + + + + switch-t0 + Force10-S6000 +
diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case.xml b/src/sonic-config-engine/tests/simple-sample-graph-case.xml index 7717157f186e..c1015b6b5362 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph-case.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph-case.xml @@ -457,6 +457,11 @@ 10.10.10.10 + + ResourceType + + Storage + diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 8e78a2ebe4a9..eff8324d6fd2 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -29,6 +29,8 @@ def setUp(self): self.output_file = os.path.join(self.test_dir, 'output') self.output2_file = os.path.join(self.test_dir, 'output2') self.ecmp_graph = os.path.join(self.test_dir, 'fg-ecmp-sample-minigraph.xml') + self.sample_resource_graph = os.path.join(self.test_dir, 'sample-graph-resource-type.xml') + self.sample_subintf_graph = os.path.join(self.test_dir, 'sample-graph-subintf.xml') # To ensure that mock config_db data is used for unit-test cases os.environ["CFGGEN_UNIT_TESTING"] = "2" @@ -129,8 +131,9 @@ def test_additional_json_data_level2_key(self): output = self.run_script(argument) self.assertEqual(utils.to_dict(output.strip()), utils.to_dict('{\n "k11": "v11"\n}')) - def test_var_json_data(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" --var-json VLAN_MEMBER' + def test_var_json_data(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" --var-json VLAN_MEMBER' output = self.run_script(argument) self.assertEqual( utils.to_dict(output.strip()), @@ -216,8 +219,9 @@ def test_minigraph_interfaces(self): output = self.run_script(argument) self.assertEqual(output.strip(), "[('Ethernet0', '10.0.0.58/31'), 'Ethernet0', ('Ethernet0', 'FC00::75/126')]") - def test_minigraph_vlans(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN' + def test_minigraph_vlans(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v VLAN' output = self.run_script(argument) self.assertEqual( utils.to_dict(output.strip()), @@ -229,8 +233,9 @@ def test_minigraph_vlans(self): ) ) - def test_minigraph_vlan_members(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN_MEMBER' + def test_minigraph_vlan_members(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v VLAN_MEMBER' output = self.run_script(argument) self.assertEqual( utils.to_dict(output.strip()), @@ -242,8 +247,9 @@ def test_minigraph_vlan_members(self): ) ) - def test_minigraph_vlan_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VLAN_INTERFACE.keys()|list"' + def test_minigraph_vlan_interfaces(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "VLAN_INTERFACE.keys()|list"' output = self.run_script(argument) self.assertEqual(output.strip(), "[('Vlan1000', '192.168.0.1/27'), 'Vlan1000']") @@ -274,8 +280,9 @@ def test_minigraph_ecmp_neighbors(self): " 'Vlan31|200:200:200:200::2', 'Vlan31|200:200:200:200::3', 'Vlan31|200:200:200:200::4', 'Vlan31|200:200:200:200::5', " "'Vlan31|200:200:200:200::6', 'Vlan31|200:200:200:200::7', 'Vlan31|200:200:200:200::8', 'Vlan31|200:200:200:200::9']") - def test_minigraph_portchannels(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v PORTCHANNEL' + def test_minigraph_portchannels(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v PORTCHANNEL' output = self.run_script(argument) self.assertEqual( utils.to_dict(output.strip()), @@ -460,14 +467,15 @@ def test_minigraph_deployment_id(self): output = self.run_script(argument) self.assertEqual(output.strip(), "1") - def test_minigraph_ethernet_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORT[\'Ethernet8\']"' + def test_minigraph_ethernet_interfaces(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "PORT[\'Ethernet8\']"' output = self.run_script(argument) self.assertEqual( utils.to_dict(output.strip()), utils.to_dict("{'lanes': '37,38,39,40', 'description': 'Interface description', 'pfc_asym': 'off', 'mtu': '9100', 'alias': 'fortyGigE0/8', 'admin_status': 'up', 'speed': '1000', 'tpid': '0x8100'}") ) - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORT[\'Ethernet12\']"' + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "PORT[\'Ethernet12\']"' output = self.run_script(argument) self.assertEqual( utils.to_dict(output.strip()), @@ -559,8 +567,9 @@ def test_minigraph_neighbor_interfaces_config_db(self): ) ) - def test_minigraph_extra_ethernet_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORT"' + def test_minigraph_extra_ethernet_interfaces(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "PORT"' output = self.run_script(argument) self.assertEqual( @@ -620,13 +629,15 @@ def test_metadata_ntp(self): output = self.run_script(argument) self.assertEqual(utils.to_dict(output.strip()), utils.to_dict("{'10.0.10.1': {}, '10.0.10.2': {}}")) - def test_minigraph_vnet(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VNET"' + def test_minigraph_vnet(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "VNET"' output = self.run_script(argument) self.assertEqual(output.strip(), "") - def test_minigraph_vxlan(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' + def test_minigraph_vxlan(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' output = self.run_script(argument) self.assertEqual(output.strip(), "") @@ -652,61 +663,83 @@ def test_minigraph_bgp_voq_chassis_peer(self): self.assertEqual(output.strip(), "") def test_minigraph_sub_port_interfaces(self, check_stderr=True): + self.verify_sub_intf(check_stderr=check_stderr) + + def test_minigraph_sub_port_intf_resource_type(self, check_stderr=True): + self.verify_sub_intf(graph_file=self.sample_resource_graph, check_stderr=check_stderr) + + def test_minigraph_sub_port_intf_sub(self, check_stderr=True): + self.verify_sub_intf(graph_file=self.sample_subintf_graph, check_stderr=check_stderr) + + def verify_sub_intf(self, **kwargs): + graph_file = kwargs.get('graph_file', self.sample_graph_simple) + check_stderr = kwargs.get('check_stderr', True) try: print('\n Change device type to %s' % (BACKEND_TOR_ROUTER)) if check_stderr: - output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, self.sample_graph_simple), stderr=subprocess.STDOUT, shell=True) + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, graph_file), stderr=subprocess.STDOUT, shell=True) else: - output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, self.sample_graph_simple), shell=True) + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, graph_file), shell=True) - self.test_jinja_expression(self.sample_graph_simple, BACKEND_TOR_ROUTER) + self.test_jinja_expression(graph_file, BACKEND_TOR_ROUTER) # INTERFACE table does not exist - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "INTERFACE"' + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "INTERFACE"' output = self.run_script(argument) self.assertEqual(output.strip(), "") # PORTCHANNEL_INTERFACE table does not exist - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORTCHANNEL_INTERFACE"' + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "PORTCHANNEL_INTERFACE"' output = self.run_script(argument) self.assertEqual(output.strip(), "") # All the other tables stay unchanged - self.test_var_json_data() - self.test_minigraph_vlans() - self.test_minigraph_vlan_members() - self.test_minigraph_vlan_interfaces() - self.test_minigraph_portchannels() - self.test_minigraph_ethernet_interfaces() - self.test_minigraph_extra_ethernet_interfaces() - self.test_minigraph_vnet() - self.test_minigraph_vxlan() + self.test_var_json_data(graph_file=graph_file) + self.test_minigraph_vlans(graph_file=graph_file) + self.test_minigraph_vlan_members(graph_file=graph_file) + self.test_minigraph_vlan_interfaces(graph_file=graph_file) + self.test_minigraph_portchannels(graph_file=graph_file) + self.test_minigraph_ethernet_interfaces(graph_file=graph_file) + self.test_minigraph_extra_ethernet_interfaces(graph_file=graph_file) + self.test_minigraph_vnet(graph_file=graph_file) + self.test_minigraph_vxlan(graph_file=graph_file) # VLAN_SUB_INTERFACE - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN_SUB_INTERFACE' + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v VLAN_SUB_INTERFACE' output = self.run_script(argument) print(output.strip()) - self.assertEqual( - utils.to_dict(output.strip()), - utils.to_dict( - "{('PortChannel01.10', '10.0.0.56/31'): {}, " - "'Ethernet0.10': {'admin_status': 'up'}, " - "('Ethernet0.10', '10.0.0.58/31'): {}, " - "('PortChannel01.10', 'FC00::71/126'): {}, " - "'PortChannel01.10': {'admin_status': 'up'}, " - "('Ethernet0.10', 'FC00::75/126'): {}}" + # not a usecase to parse SubInterfaces under PortChannel + if 'subintf' in graph_file: + self.assertEqual( + utils.to_dict(output.strip()), + utils.to_dict( + "{'Ethernet0.10': {'admin_status': 'up'}, " + "('Ethernet0.10', '10.0.0.58/31'): {}, " + "('Ethernet0.10', 'FC00::75/126'): {}}" + ) + ) + else: + self.assertEqual( + utils.to_dict(output.strip()), + utils.to_dict( + "{('PortChannel01.10', '10.0.0.56/31'): {}, " + "'Ethernet0.10': {'admin_status': 'up'}, " + "('Ethernet0.10', '10.0.0.58/31'): {}, " + "('PortChannel01.10', 'FC00::71/126'): {}, " + "'PortChannel01.10': {'admin_status': 'up'}, " + "('Ethernet0.10', 'FC00::75/126'): {}}" + ) ) - ) finally: print('\n Change device type back to %s' % (TOR_ROUTER)) if check_stderr: - output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, self.sample_graph_simple), stderr=subprocess.STDOUT, shell=True) + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, graph_file), stderr=subprocess.STDOUT, shell=True) else: - output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, self.sample_graph_simple), shell=True) + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, graph_file), shell=True) - self.test_jinja_expression(self.sample_graph_simple, TOR_ROUTER) + self.test_jinja_expression(graph_file, TOR_ROUTER) def test_show_run_acl(self): argument = '-a \'{"key1":"value"}\' --var-json ACL_RULE' diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 24697f852624..08bde40af0cf 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -7,6 +7,8 @@ from unittest import TestCase +TOR_ROUTER = 'ToRRouter' +BACKEND_TOR_ROUTER = 'BackEndToRRouter' class TestCfgGenCaseInsensitive(TestCase): @@ -14,6 +16,9 @@ def setUp(self): self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') self.sample_graph = os.path.join(self.test_dir, 'simple-sample-graph-case.xml') + self.sample_simple_graph = os.path.join(self.test_dir, 'simple-sample-graph.xml') + self.sample_resource_graph = os.path.join(self.test_dir, 'sample-graph-resource-type.xml') + self.sample_subintf_graph = os.path.join(self.test_dir, 'sample-graph-subintf.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') def run_script(self, argument, check_stderr=False): @@ -284,7 +289,35 @@ def test_minigraph_storage_device(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'storage_device\']"' output = self.run_script(argument) self.assertEqual(output.strip(), "true") - + + def test_minigraph_storage_backend_no_resource_type(self): + self.verify_storage_device_set(self.sample_simple_graph) + + def test_minigraph_storage_backend_resource_type(self): + self.verify_storage_device_set(self.sample_resource_graph) + + def test_minigraph_storage_backend_subintf(self): + self.verify_storage_device_set(self.sample_subintf_graph) + + def verify_storage_device_set(self, graph_file, check_stderr=False): + try: + print('\n Change device type to %s' % (BACKEND_TOR_ROUTER)) + if check_stderr: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, graph_file), stderr=subprocess.STDOUT, shell=True) + else: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (TOR_ROUTER, BACKEND_TOR_ROUTER, graph_file), shell=True) + + argument = '-m "' + graph_file + '" -p "' + self.port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'storage_device\']"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "true") + + finally: + print('\n Change device type back to %s' % (TOR_ROUTER)) + if check_stderr: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, graph_file), stderr=subprocess.STDOUT, shell=True) + else: + output = subprocess.check_output("sed -i \'s/%s/%s/g\' %s" % (BACKEND_TOR_ROUTER, TOR_ROUTER, graph_file), shell=True) + def test_minigraph_tunnel_table(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "TUNNEL"' expected_tunnel = {