From f27493e83de85db915bb1cdfa2d27773db619fc8 Mon Sep 17 00:00:00 2001 From: mohitagrawal-crest Date: Mon, 20 Jul 2020 22:15:11 +0530 Subject: [PATCH] Stable code commit for v0.2 --- ConsulExtension/Media/Readme/readme.txt | 47 +- ConsulExtension/Service/alchemy_core.py | 145 +- ConsulExtension/Service/apic_utils.py | 96 +- ConsulExtension/Service/app.py | 5 - ConsulExtension/Service/config_utils.py | 9 +- ConsulExtension/Service/consul_utils.py | 79 +- ConsulExtension/Service/custom_logger.py | 4 +- ConsulExtension/Service/data_fetch.py | 505 +++--- ConsulExtension/Service/decorator.py | 6 +- ConsulExtension/Service/merge.py | 37 +- ConsulExtension/Service/plugin_server.py | 1482 ++++++++++------- ConsulExtension/Service/recommend_utils.py | 242 +-- ConsulExtension/Service/schema.py | 98 +- ConsulExtension/Service/tests/__init__.py | 7 + .../Service/tests/alchemy_core/__init__.py | 0 .../tests/alchemy_core/test_alchemy_core.py | 273 +++ .../Service/tests/apic_utils/__init__.py | 7 + .../data/apic_fetch_bd_cases/bd_input.json | 8 + .../data/apic_fetch_bd_cases/empty_input.json | 1 + .../all_contracts_input.json | 53 + .../all_contracts_output.json | 7 + .../no_contracts_input.json | 1 + .../no_contracts_output.json | 1 + .../apic_fetch_vrf_cases/empty_input.json | 1 + .../apic_fetch_vrf_cases/empty_output.json | 1 + .../data/apic_fetch_vrf_cases/vrf_input.json | 8 + .../data/apic_fetch_vrf_cases/vrf_output.json | 1 + .../get_instance_input.json | 12 + .../get_instance_output.json | 1 + .../with_host_input.json | 7 + .../with_host_mo_instance.json | 1 + .../with_ip_host_input.json | 7 + .../with_ip_host_mo_instance.json | 1 + .../without_ip_host_input.json | 1 + .../without_ip_host_mo_instance.json | 1 + .../data/get_ep_info_cases/ep_input.json | 23 + .../data/get_ep_info_cases/ep_output.json | 7 + .../get_epg_health_cases/empty_input.json | 1 + .../get_epg_health_cases/empty_output.json | 1 + .../epg_health_input.json | 17 + .../epg_health_output.json | 1 + .../get_interface_cases/pathgrp_input.json | 7 + .../get_interface_cases/pathgrp_node.json | 1 + .../get_interface_cases/pathgrp_output.json | 1 + .../data/get_interface_cases/paths_input.json | 7 + .../data/get_interface_cases/paths_node.json | 1 + .../get_interface_cases/paths_output.json | 1 + .../get_interface_cases/protpaths_input.json | 7 + .../get_interface_cases/protpaths_node.json | 1 + .../get_interface_cases/protpaths_output.json | 1 + .../get_ip_mac_list_cases/2_fvip_input.json | 33 + .../get_ip_mac_list_cases/2_fvip_output.json | 1 + .../data/get_ip_mac_list_cases/cep_input.json | 19 + .../get_ip_mac_list_cases/cep_output.json | 1 + .../diff_cep_fvip_input.json | 26 + .../diff_cep_fvip_output.json | 1 + .../get_ip_mac_list_cases/fvip_input.json | 26 + .../get_ip_mac_list_cases/fvip_output.json | 1 + .../get_ip_mac_list_cases/no_ip_input.json | 19 + .../get_ip_mac_list_cases/no_ip_output.json | 1 + .../same_cep_fvip_input.json | 26 + .../same_cep_fvip_output.json | 1 + .../domain_and_name_get_data.json | 12 + .../domain_and_name_input.json | 7 + .../Service/tests/apic_utils/data/ip_1.json | 1 + .../Service/tests/apic_utils/data/ip_2.json | 1 + .../ep_input.json | 30 + .../ep_output.json | 29 + .../get_ep_input.json | 7 + .../epg_data_contract.json | 19 + .../epg_data_input.json | 9 + .../epg_data_output.json | 29 + .../data/parse_ep_data_cases/ep_input.json | 59 + .../data/parse_ep_data_cases/ep_output.json | 57 + .../parse_ep_data_cases/get_ep_input.json | 30 + .../tests/apic_utils/test_apic_utils.py | 511 ++++++ .../Service/tests/apic_utils/utils.py | 12 + .../Service/tests/consul_utils/__init__.py | 0 .../data/datacenter/1_initial_datacenter.json | 1 + .../data/datacenter/2_empty_datacenter.json | 1 + .../datacenter/3_exception_datacenter.json | 1 + .../1_initial_detailed_node_check_input.json | 91 + .../1_initial_detailed_node_check_output.json | 12 + .../2_empty_detailed_node_check_input.json | 1 + .../2_empty_detailed_node_check_output.json | 1 + ..._initial_detailed_service_check_input.json | 78 + ...initial_detailed_service_check_output.json | 38 + .../2_empty_detailed_service_check_input.json | 1 + ...2_empty_detailed_service_check_output.json | 1 + .../1_initial_node_check_input.json | 71 + .../1_initial_node_check_output.json | 2 + .../node_check/2_empty_node_check_intput.json | 1 + .../node_check/2_empty_node_check_output.json | 1 + .../3_exception_node_check_input.json | 71 + .../3_exception_node_check_output.json | 3 + .../data/node_data/1_initial_test_input.json | 76 + .../data/node_data/1_initial_test_output.json | 45 + .../node_data/2_same_node_diff_ips_input.json | 14 + .../2_same_node_diff_ips_output.json | 13 + .../data/node_data/3_empty_node_input.json | 1 + .../data/node_data/3_empty_node_output.json | 1 + .../1_initial_node_service_input.json | 91 + .../1_initial_node_service_output.json | 30 + .../2_blank_ip_node_service_input.json | 34 + .../2_blank_ip_node_service_output.json | 9 + .../3_empty_node_service_input.json | 1 + .../3_empty_node_service_ouput.json | 1 + .../1_initial_service_check.json | 78 + .../1_initial_service_check_output.json | 1 + .../service_check/2_empty_service_check.json | 1 + .../2_empty_service_check_output.json | 1 + .../3_passing_service_check_input.json | 78 + .../3_passing_service_check_output.json | 3 + .../4_exception_service_check_intput.json | 78 + .../4_exception_service_check_output.json | 2 + .../service_info/1_initial_service_info.json | 20 + .../service_info/2_empty_service_info.json | 1 + .../3_wrong_name_service_info.json | 3 + .../consul_utils/fixture_consul_utils.py | 12 + .../tests/consul_utils/test_consul_utils.py | 205 +++ .../Service/tests/consul_utils/utils.py | 109 ++ .../Service/tests/data_fetch/__init__.py | 0 .../tests/data_fetch/test_data_fetch.py | 198 +++ .../Service/tests/merge/__init__.py | 0 .../data/dangling/aci_consul_mappings.json | 1 + .../tests/merge/data/dangling/aci_data.json | 1 + .../merge/data/dangling/consul_data.json | 1 + .../tests/merge/data/dangling/final_list.json | 1 + .../merge/data/ipv6/aci_consul_mappings.json | 13 + .../tests/merge/data/ipv6/aci_data.json | 37 + .../tests/merge/data/ipv6/consul_data.json | 31 + .../tests/merge/data/ipv6/final_list.json | 66 + .../aci_consul_mappings.json | 156 ++ .../data/random_combination/aci_data.json | 702 ++++++++ .../data/random_combination/consul_data.json | 1124 +++++++++++++ .../data/random_combination/final_list.json | 1462 ++++++++++++++++ .../service_to_ep/aci_consul_mappings.json | 13 + .../merge/data/service_to_ep/aci_data.json | 37 + .../merge/data/service_to_ep/consul_data.json | 31 + .../merge/data/service_to_ep/final_list.json | 66 + .../service_to_none/aci_consul_mappings.json | 1 + .../merge/data/service_to_none/aci_data.json | 37 + .../data/service_to_none/consul_data.json | 31 + .../data/service_to_none/final_list.json | 1 + .../aci_consul_mappings.json | 1 + .../data/service_without_ip/aci_data.json | 1 + .../data/service_without_ip/consul_data.json | 1 + .../data/service_without_ip/final_list.json | 1 + .../Service/tests/merge/test_merge.py | 61 + .../Service/tests/plugin_server/__init__.py | 0 .../data/agent_status/1_initial_input.json | 12 + .../data/agent_status/1_initial_output.json | 1 + .../agent_status/2_different_dc_input.json | 12 + .../agent_status/2_different_dc_output.json | 1 + .../data/change_key/1_empty_input.json | 1 + .../data/change_key/1_empty_output.json | 1 + .../data/change_key/1_initial_input.json | 70 + .../data/change_key/1_initial_output.json | 58 + .../tests/plugin_server/data/dangling.db | Bin 0 -> 114688 bytes .../tests/plugin_server/data/dangling.json | 13 + .../data/get_audit_logs/empty_input.json | 1 + .../data/get_audit_logs/empty_output.json | 1 + .../get_audit_logs/get_audit_logs_input.json | 1 + .../get_audit_logs/get_audit_logs_output.json | 1 + .../get_children_ep_info/fvcep_input.json | 1 + .../data/get_children_ep_info/fvcep_ip.json | 1 + .../get_children_ep_info/fvcep_output.json | 1 + .../data/get_children_ep_info/fvip_input.json | 1 + .../data/get_children_ep_info/fvip_ip.json | 1 + .../get_children_ep_info/fvip_output.json | 1 + .../get_children_ep_info/get_ep_info.json | 7 + .../get_configured_access_policies_input.json | 1 + ...get_configured_access_policies_output.json | 1 + .../plugin_server/data/get_epg_alias.json | 10 + .../data/get_events/empty_input.json | 1 + .../data/get_events/empty_output.json | 1 + .../data/get_events/get_events_input.json | 1 + .../data/get_events/get_events_output.json | 1 + .../data/get_faults/empty_input.json | 1 + .../data/get_faults/empty_output.json | 1 + .../data/get_faults/get_faults_input.json | 1 + .../data/get_faults/get_faults_output.json | 1 + .../data/get_filter_list/1_input.json | 1 + .../data/get_filter_list/1_output.json | 1 + .../data/get_filter_list/2_input.json | 1 + .../data/get_filter_list/2_output.json | 1 + .../data/get_filter_list/3_input.json | 1 + .../data/get_filter_list/3_output.json | 1 + .../data/get_filter_list/4_input.json | 1 + .../data/get_filter_list/4_output.json | 1 + .../data/get_filter_list/5_input.json | 1 + .../data/get_filter_list/5_output.json | 1 + .../data/get_filter_list/6_input.json | 1 + .../data/get_filter_list/6_output.json | 1 + .../data/get_filter_list/7_input.json | 1 + .../data/get_filter_list/7_output.json | 1 + .../data/get_ingress_egress/empty_input.json | 1 + .../ingress_egress_input.json | 1 + .../get_to_epg_traffic_input.json | 1 + .../get_to_epg_traffic_output.json | 1 + .../data/mapping/1_mapping_initial_input.json | 35 + .../mapping/1_mapping_initial_output.json | 39 + .../mapping/2_mapping_exception_output.json | 1 + .../data/mapping/3_mapping_empty_input.json | 1 + .../data/mapping/3_mapping_empty_output.json | 5 + .../tests/plugin_server/data/node_to_ep.db | Bin 0 -> 114688 bytes .../tests/plugin_server/data/node_to_ep.json | 13 + .../tests/plugin_server/data/read_creds.json | 27 + .../plugin_server/data/saved_mapping.json | 47 + ...rvice_node_with_diff_ip_both_to_diff_ep.db | Bin 0 -> 114688 bytes ...ice_node_with_diff_ip_both_to_diff_ep.json | 24 + .../service_node_with_diff_ip_both_to_none.db | Bin 0 -> 114688 bytes ...ervice_node_with_diff_ip_both_to_none.json | 1 + .../service_node_with_diff_ip_node_to_ep.db | Bin 0 -> 114688 bytes .../service_node_with_diff_ip_node_to_ep.json | 13 + ...service_node_with_diff_ip_service_to_ep.db | Bin 0 -> 114688 bytes ...rvice_node_with_diff_ip_service_to_ep.json | 13 + .../data/service_node_with_same_ip_to_ep.db | Bin 0 -> 114688 bytes .../data/service_node_with_same_ip_to_ep.json | 13 + .../data/service_node_with_same_ip_to_none.db | Bin 0 -> 114688 bytes .../service_node_with_same_ip_to_none.json | 1 + .../plugin_server/data/service_without_ip.db | Bin 0 -> 114688 bytes .../data/service_without_ip.json | 13 + .../tests/plugin_server/test_plugin_server.py | 529 ++++++ .../Service/tests/plugin_server/utils.py | 112 ++ .../Service/tests/recommendation/__init__.py | 0 .../recommendation/data/ConsulDatabase.db | Bin 0 -> 103424 bytes .../data/recommendation_config.cfg | 2 + .../recommendation/test_recommendation.py | 208 +++ .../Service/tests/tree_parser/__init__.py | 0 .../tree_parser/data/input/dangling.json | 1 + .../tests/tree_parser/data/input/ipv6.json | 66 + .../data/input/random_combination.json | 1462 ++++++++++++++++ .../tree_parser/data/input/service_to_ep.json | 66 + .../data/input/service_to_none.json | 1 + .../data/input/service_without_ip.json | 1 + .../tree_parser/data/output/dangling.json | 1 + .../tests/tree_parser/data/output/ipv6.json | 1 + .../data/output/random_combination.json | 1 + .../data/output/service_to_ep.json | 1 + .../data/output/service_to_none.json | 1 + .../data/output/service_without_ip.json | 1 + .../tests/tree_parser/test_tree_parser.py | 110 ++ ConsulExtension/Service/tests/utils.py | 24 + ConsulExtension/Service/threading_util.py | 5 +- ConsulExtension/Service/tree_parser.py | 62 +- ConsulExtension/Service/urls.py | 6 +- ConsulExtension/UIAssets/app-start.html | 2 +- ConsulExtension/UIAssets/app.html | 2 +- ConsulExtension/UIAssets/app/Agent/index.js | 15 +- ConsulExtension/UIAssets/app/App.js | 38 +- .../UIAssets/app/Components/SummaryPane.js | 7 +- ConsulExtension/UIAssets/app/Container.js | 46 +- .../UIAssets/app/Dashboard/Dashboard.css | 3 +- .../UIAssets/app/Dashboard/Dashboard.js | 17 +- ConsulExtension/UIAssets/app/Details/App.js | 5 +- .../UIAssets/app/Details/Container.js | 37 +- .../UIAssets/app/Details/DataTable.js | 82 +- .../UIAssets/app/Details/DetailPanel.js | 14 +- .../UIAssets/app/Details/style.css | 42 +- .../UIAssets/app/Login/CONSUL_Loginform.js | 6 + .../UIAssets/app/Mapping/CONSUL_Container.js | 1 - .../UIAssets/app/Tree/package.json | 15 +- .../src/client/app/Components/SummaryPane.js | 6 +- .../app/Tree/src/client/app/DetailPanel.js | 8 +- .../app/Tree/src/client/app/DetailsPage.js | 10 +- .../client/app/DetailsPageChild/DataTable.js | 2 +- .../app/Tree/src/client/app/DetailsPane.css | 5 - .../UIAssets/app/Tree/src/client/app/Node.js | 28 +- .../app/Tree/src/client/app/TestComponent.js | 5 +- .../UIAssets/app/Tree/src/client/app/Tree.js | 4 +- .../app/commonComponent/PieChartAndCounter.js | 3 +- .../UIAssets/app/Tree/src/client/app/index.js | 13 +- .../app/Tree/src/client/app/style.css | 18 + .../UIAssets/app/Tree/src/client/app/utils.js | 32 + .../UIAssets/app/Tree/src/client/index.html | 17 +- .../app/Tree/src/client/public/tree.js | 131 ++ .../UIAssets/app/Tree/webpack.config.js | 86 +- ConsulExtension/UIAssets/app/Utility/utils.js | 32 + .../UIAssets/app/commonComponent/Modal.css | 23 +- .../app/commonComponent/PieChartAndCounter.js | 3 +- ConsulExtension/UIAssets/app/style.css | 13 +- ConsulExtension/UIAssets/constants.js | 12 +- ConsulExtension/UIAssets/details.html | 2 +- ConsulExtension/UIAssets/index.html | 2 +- ConsulExtension/UIAssets/login.html | 2 +- ConsulExtension/UIAssets/mapping.html | 2 +- ConsulExtension/UIAssets/package.json | 16 +- ConsulExtension/UIAssets/public/app.js | 125 +- ConsulExtension/UIAssets/public/details.js | 95 +- ConsulExtension/UIAssets/public/tree.js | 131 ++ ConsulExtension/UIAssets/tree.html | 11 +- ConsulExtension/UIAssets/webpack.config.js | 12 +- ConsulExtension/app.json | 1 - 294 files changed, 12354 insertions(+), 1517 deletions(-) create mode 100644 ConsulExtension/Service/tests/__init__.py create mode 100644 ConsulExtension/Service/tests/alchemy_core/__init__.py create mode 100644 ConsulExtension/Service/tests/alchemy_core/test_alchemy_core.py create mode 100644 ConsulExtension/Service/tests/apic_utils/__init__.py create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/bd_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/empty_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_mo_instance.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_mo_instance.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_mo_instance.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_node.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_node.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_node.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_get_data.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/ip_1.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/ip_2.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/get_ep_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_contract.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_output.json create mode 100644 ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/get_ep_input.json create mode 100644 ConsulExtension/Service/tests/apic_utils/test_apic_utils.py create mode 100644 ConsulExtension/Service/tests/apic_utils/utils.py create mode 100644 ConsulExtension/Service/tests/consul_utils/__init__.py create mode 100644 ConsulExtension/Service/tests/consul_utils/data/datacenter/1_initial_datacenter.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/datacenter/2_empty_datacenter.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/datacenter/3_exception_datacenter.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_intput.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_ouput.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_input.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_intput.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_output.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_info/1_initial_service_info.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_info/2_empty_service_info.json create mode 100644 ConsulExtension/Service/tests/consul_utils/data/service_info/3_wrong_name_service_info.json create mode 100644 ConsulExtension/Service/tests/consul_utils/fixture_consul_utils.py create mode 100644 ConsulExtension/Service/tests/consul_utils/test_consul_utils.py create mode 100644 ConsulExtension/Service/tests/consul_utils/utils.py create mode 100644 ConsulExtension/Service/tests/data_fetch/__init__.py create mode 100644 ConsulExtension/Service/tests/data_fetch/test_data_fetch.py create mode 100644 ConsulExtension/Service/tests/merge/__init__.py create mode 100644 ConsulExtension/Service/tests/merge/data/dangling/aci_consul_mappings.json create mode 100644 ConsulExtension/Service/tests/merge/data/dangling/aci_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/dangling/consul_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/dangling/final_list.json create mode 100644 ConsulExtension/Service/tests/merge/data/ipv6/aci_consul_mappings.json create mode 100644 ConsulExtension/Service/tests/merge/data/ipv6/aci_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/ipv6/consul_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/ipv6/final_list.json create mode 100644 ConsulExtension/Service/tests/merge/data/random_combination/aci_consul_mappings.json create mode 100644 ConsulExtension/Service/tests/merge/data/random_combination/aci_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/random_combination/consul_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/random_combination/final_list.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_ep/aci_consul_mappings.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_ep/aci_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_ep/consul_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_ep/final_list.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_none/aci_consul_mappings.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_none/aci_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_none/consul_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_to_none/final_list.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_without_ip/aci_consul_mappings.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_without_ip/aci_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_without_ip/consul_data.json create mode 100644 ConsulExtension/Service/tests/merge/data/service_without_ip/final_list.json create mode 100644 ConsulExtension/Service/tests/merge/test_merge.py create mode 100644 ConsulExtension/Service/tests/plugin_server/__init__.py create mode 100644 ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/dangling.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/dangling.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_ip.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_ip.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/get_ep_info.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_epg_alias.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_events/empty_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_events/empty_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/empty_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/ingress_egress_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/mapping/2_mapping_exception_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_input.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_output.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/node_to_ep.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/node_to_ep.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/read_creds.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/saved_mapping.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_both_to_diff_ep.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_both_to_diff_ep.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_both_to_none.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_both_to_none.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_node_to_ep.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_node_to_ep.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_service_to_ep.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_service_to_ep.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_same_ip_to_ep.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_same_ip_to_ep.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_same_ip_to_none.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_node_with_same_ip_to_none.json create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_without_ip.db create mode 100644 ConsulExtension/Service/tests/plugin_server/data/service_without_ip.json create mode 100644 ConsulExtension/Service/tests/plugin_server/test_plugin_server.py create mode 100644 ConsulExtension/Service/tests/plugin_server/utils.py create mode 100644 ConsulExtension/Service/tests/recommendation/__init__.py create mode 100644 ConsulExtension/Service/tests/recommendation/data/ConsulDatabase.db create mode 100644 ConsulExtension/Service/tests/recommendation/data/recommendation_config.cfg create mode 100644 ConsulExtension/Service/tests/recommendation/test_recommendation.py create mode 100644 ConsulExtension/Service/tests/tree_parser/__init__.py create mode 100644 ConsulExtension/Service/tests/tree_parser/data/input/dangling.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/input/ipv6.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/input/random_combination.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/input/service_to_ep.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/input/service_to_none.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/input/service_without_ip.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/output/dangling.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/output/ipv6.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/output/random_combination.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/output/service_to_ep.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/output/service_to_none.json create mode 100644 ConsulExtension/Service/tests/tree_parser/data/output/service_without_ip.json create mode 100644 ConsulExtension/Service/tests/tree_parser/test_tree_parser.py create mode 100644 ConsulExtension/Service/tests/utils.py create mode 100644 ConsulExtension/UIAssets/app/Tree/src/client/app/utils.js create mode 100644 ConsulExtension/UIAssets/app/Tree/src/client/public/tree.js create mode 100644 ConsulExtension/UIAssets/app/Utility/utils.js create mode 100644 ConsulExtension/UIAssets/public/tree.js diff --git a/ConsulExtension/Media/Readme/readme.txt b/ConsulExtension/Media/Readme/readme.txt index 4c1ac6e..cda5530 100644 --- a/ConsulExtension/Media/Readme/readme.txt +++ b/ConsulExtension/Media/Readme/readme.txt @@ -1,22 +1,32 @@ -The Consul Extension for ACI (Beta) application provides ACI administrators L4-L7 Service Mesh visibility and an automated way to manage L2-L3 infrastructure based on L4-L7 service requirements. +Monitor and Optimize Application Connectivity in Any Environment +The Consul Extension for ACI application enables greater control over Day 2+ operations and visibility into Layer 4/7 data of applications running in networks managed by Cisco APIC. Using the Consul Extension for ACI, network operators will be able to respond more quickly to connectivity issues and reduce the Mean-time-to-Resolution (MTTR). As the network topology becomes more dynamic and complex, Consul and ACI provide a consistent, automated workflow for gathering application information and health data. -This application offers enhanced Consul-to-ACI L4-L7 service visibility including dynamic service health, enabling faster mean-time-to-resolution (MTTR); and L4-L7 service mesh intention driven dynamic Network Middleware Automation. -Service visibility and faster Mean-time-to-Resolution (MTTR): -- Real-time visibility into dynamic L4-L7 services, service health and service-to-service communication on virtual, container and bare-metal workloads connected by the ACI multi-cloud network. -- Faster identification of issues based on service health and network data correlation. +ACI users should download the Consul Extension for ACI from the DC App Center. Once configured and a Consul Agent is added to the desired environments, ACI begins pulling information from Consul, including the number of agents running, services registered with those agents, nodes discovered by Consul, and any ACI endpoints with services that have been discovered by Consul. + + +Users can then use the Operations feature on the APIC Dashboard to get a list of existing services and create a visual map of the network topology. From here, operators can map each service to each ACI endpoint, drill down into specific service level data, and see if that service is actively reachable. In the future, Consul will be able to apply ACI policies directly to services. + + +Benefits of the Consul Extension for ACI: + + +End to End Service Visibility - Using the Consul Extension for ACI, network operators can retrieve Layer 4-7 service data for applications running at each ACI endpoint. This enables greater insights as to what services are currently running on the network. + + +Reduce Downtime & Failure Rates - Enable operators to trace connectivity issues at the service level and reduce the Mean-time-to-Resolution for network issues. Enable individuals to debug issues, rather as part of a broader, more time-intensive team effort. + + +Improve Productivity Across the Org - Develop stronger collaboration between application engineers and network operators by creating a single source of truth for information on applications. Enable ACI to provide a single pane of visibility for both developers and operators. -Network Middleware Automation: -- Consistent L4-L7 service mesh driven network policy (contracts and filters) automation for virtual, bare-metal and container workloads across private and public cloud for your ACI multi-cloud network. -- Easier transition to a secure service mesh based deployments for Applications teams and DevOps operators with the ACI multi-cloud network. Features: -- Supports Consul Enterprise and Consul open-source deployments. -- Visibility into L4-L7 services running on multiple Consul Datacenters. -- Self-Discovery of an entire Consul Datacenter service catalog though a single seed agent(Consul Server). +- Improved Visibility and Day 2+ automation of L4-L7 services registered with Consul. +- Self-Discovery of all services registered with Consul’s service catalog though a single agent. - Automated correlation of L4-L7 service-to-ACI fabric and logical topology. - Dynamic Service Dashboard to view L4-L7 service health. + Highlights: - Enhanced L4-L7 service visibility for L2-L3 ACI infrastructure. - Green field and brown field deployment supported. @@ -24,19 +34,18 @@ Highlights: - NO impact on ACI and Consul configurations if the application is deleted. - Maintains organization operational model and ownership. + Pre-requisites: - APIC version 3.2(1l) or above - Consul version 1.6.3/1.6.3+ent or above - In-band or Out-of-band connectivity between APIC and Consul seed agent (Consul server) on TCP port 8500 and 8501. -Beta release limitations: -- Supported on Chrome web-browser only. -- Supported for on-premise APIC only. Before you begin: -User guide: https://tinyurl.com/y9ztt362 -FAQs: https://tinyurl.com/ya8b95j2 -Support: https://github.com/ciscoecosystem/consul-aci/issues +User guide: tinyurl.com/y9ztt362 +FAQs: tinyurl.com/ya8b95j2 +Support: github.com/ciscoecosystem/consul-aci/issues + -About Consul (https://www.consul.io/): -- Consul is a highly distributed service mesh solution by HashiCorp for providing a full featured control plane with service discovery, configuration, and segmentation functionality at L4-L7. \ No newline at end of file +About HashiCorp Consul (www.consul.io/): +A service networking platform to connect and automate network configurations, discover services, and enable secure connectivity across any cloud or runtime. \ No newline at end of file diff --git a/ConsulExtension/Service/alchemy_core.py b/ConsulExtension/Service/alchemy_core.py index 09e438c..b7d1938 100644 --- a/ConsulExtension/Service/alchemy_core.py +++ b/ConsulExtension/Service/alchemy_core.py @@ -1,8 +1,8 @@ from sqlalchemy import create_engine from sqlalchemy import Table, Column, ForeignKey, String, MetaData, PickleType, DateTime, Boolean from datetime import datetime -from sqlalchemy import and_ -from sqlalchemy.sql import select, text +from sqlalchemy.sql import select +from sqlalchemy.interfaces import PoolListener from custom_logger import CustomLogger @@ -11,6 +11,11 @@ DATABASE_NAME = 'sqlite:///ConsulDatabase.db' +class MyListener(PoolListener): + def connect(self, dbapi_con, con_record): + dbapi_con.execute('pragma journal_mode=WAL') + + class Database: """Database class with all db functionalities""" @@ -145,6 +150,7 @@ class Database: 'vrf', 'epg_health', 'app_profile', + 'epg_alias', 'created_ts', 'updated_ts', 'last_checked_ts' @@ -158,12 +164,11 @@ class Database: def __init__(self): try: - self.engine = create_engine(DATABASE_NAME) - self.conn = self.engine.connect() + self.engine = create_engine(DATABASE_NAME, listeners=[MyListener()]) self.table_obj_meta = dict() self.table_pkey_meta = dict() except Exception as e: - pass + logger.exception("Exception in creating db obj: {}".format(str(e))) def create_tables(self): metadata = MetaData() @@ -247,10 +252,8 @@ def create_tables(self): self.servicechecks = Table( self.SERVICECHECKS_TABLE_NAME, metadata, - Column('check_id', String, - primary_key=True), - Column('service_id', String, ForeignKey( - self.service.c.service_id), primary_key=True), + Column('check_id', String, primary_key=True), + Column('service_id', String, ForeignKey(self.service.c.service_id), primary_key=True), Column('service_name', String), Column('name', String), Column('type', String), @@ -290,9 +293,10 @@ def create_tables(self): Column('EPG', String), Column('BD', String), Column('contracts', PickleType), - Column('VRF', String), + Column('vrf', String), Column('epg_health', String), Column('app_profile', String), + Column('epg_alias', String), Column('created_ts', DateTime), Column('updated_ts', DateTime), Column('last_checked_ts', DateTime) @@ -394,7 +398,7 @@ def create_tables(self): Column('EPG', String), Column('BD', String), Column('contracts', PickleType), - Column('VRF', String), + Column('vrf', String), Column('epg_health', String), Column('app_profile', String), Column('created_ts', DateTime), @@ -469,24 +473,42 @@ def create_tables(self): logger.exception("Exception in {} Error:{}".format( 'create_tables()', str(e))) - - def insert_into_table(self, table_name, field_values): + def insert_into_table(self, connection, table_name, field_values): field_values = list(field_values) try: ins = None table_name = table_name.lower() field_values.append(datetime.now()) ins = self.table_obj_meta[table_name].insert().values(field_values) - if ins != None: - self.conn.execute(ins) + if ins is not None: + connection.execute(ins) return True except Exception as e: logger.exception( "Exception in data insertion in {} Error:{}".format(table_name, str(e))) return False + def select_eps_from_mapping(self, connection, tn, is_enabled): + try: + result = connection.execute( + "Select ip from mapping where enabled=" + str(is_enabled) + " and tenant='" + tn + "'") + return result + except Exception as e: + logger.exception("Exception in selecting data from {} Error:{}".format(self.MAPPING_TABLE_NAME, str(e))) + return None + + def select_from_ep_with_tenant(self, connection, tn): + try: + table_obj = self.table_obj_meta[self.EP_TABLE_NAME] + select_query = table_obj.select() + select_query = select_query.where(('tenant' == tn)) + result = connection.execute("Select * from ep where tenant='" + tn + "'") + return result + except Exception as e: + logger.exception("Exception in selecting data from {} Error:{}".format(self.EP_TABLE_NAME, str(e))) + return None - def select_from_table(self, table_name, primary_key={}): + def select_from_table(self, connection, table_name, primary_key={}): try: select_query = None table_name = table_name.lower() @@ -499,16 +521,14 @@ def select_from_table(self, table_name, primary_key={}): else: select_query = self.table_obj_meta[table_name].select() - if select_query != None: - result = self.conn.execute(select_query) - return result + if select_query is not None: + result = connection.execute(select_query) + return result.fetchall() except Exception as e: - logger.exception( - "Exception in selecting data from {} Error:{}".format(table_name, str(e))) + logger.exception("Exception in selecting data from {} Error:{}".format(table_name, str(e))) return None - - def update_in_table(self, table_name, primary_key, new_record_dict): + def update_in_table(self, connection, table_name, primary_key, new_record_dict): try: table_name = table_name.lower() table_obj = self.table_obj_meta[table_name] @@ -518,15 +538,14 @@ def update_in_table(self, table_name, primary_key, new_record_dict): update_query = update_query.where( self.table_pkey_meta[table_name][key] == primary_key[key]) update_query = update_query.values(new_record_dict) - self.conn.execute(update_query) + connection.execute(update_query) return True except Exception as e: logger.exception( "Exception in updating {} Error:{}".format(table_name, str(e))) return False - - def delete_from_table(self, table_name, primary_key={}): + def delete_from_table(self, connection, table_name, primary_key={}): try: table_name = table_name.lower() if primary_key: @@ -537,21 +556,20 @@ def delete_from_table(self, table_name, primary_key={}): self.table_pkey_meta[table_name][key] == primary_key[key]) else: delete_query = self.table_obj_meta[table_name].delete() - self.conn.execute(delete_query) + connection.execute(delete_query) return True except Exception as e: logger.exception( "Exception in deletion from {} Error:{}".format(table_name, str(e))) return False - - def insert_and_update(self, table_name, new_record, primary_key={}): + def insert_and_update(self, connection, table_name, new_record, primary_key={}): table_name = table_name.lower() if primary_key: - old_data = self.select_from_table(table_name, primary_key) - if old_data: - old_data = old_data.fetchone() - if old_data: + old_data = self.select_from_table(connection, table_name, primary_key) + if old_data != None: + if len(old_data) > 0: + old_data = old_data[0] new_record_dict = dict() index = [] for i in range(len(new_record)): @@ -565,16 +583,15 @@ def insert_and_update(self, table_name, new_record, primary_key={}): if new_record_dict: new_record_dict['updated_ts'] = datetime.now() - self.update_in_table(table_name, primary_key, new_record_dict) + self.update_in_table(connection, table_name, primary_key, new_record_dict) else: - self.insert_into_table(table_name, new_record) + self.insert_into_table(connection, table_name, new_record) else: return False else: - self.insert_into_table(table_name, new_record) + self.insert_into_table(connection, table_name, new_record) return True - def get_join_obj(self, table_name1, table_name2, datacenter=None): try: table_name1 = table_name1.lower() @@ -582,54 +599,50 @@ def get_join_obj(self, table_name1, table_name2, datacenter=None): obj1 = self.table_obj_meta[table_name1] obj2 = self.table_obj_meta[table_name2] if datacenter: - join_obj = obj1.join(obj2,isouter=True) + join_obj = obj1.join(obj2, isouter=True) else: - join_obj = obj1.join(obj2, obj1.c.dn == obj2.c.dn,isouter=True) + join_obj = obj1.join(obj2, obj1.c.dn == obj2.c.dn, isouter=True) return join_obj except Exception as e: logger.exception( "Exception in joining tables: {} & {}, Error: {}".format(table_name1, table_name2, str(e))) return None - - def join(self, datacenter=None, tenant=None): + def join(self, connection, datacenter=None, tenant=None): try: if datacenter: obj1 = self.get_join_obj("node", "nodechecks", datacenter) obj2 = self.get_join_obj("service", "servicechecks", datacenter) join_obj = obj1.join(obj2) - smt = select([self.node,self.service,self.nodechecks,self.servicechecks]).select_from(join_obj) + smt = select([self.node, self.service, self.nodechecks, self.servicechecks]).select_from(join_obj) elif tenant: join_obj = self.get_join_obj("ep", "epg") smt = select([self.ep, self.epg]).select_from(join_obj) - result = self.conn.execute(smt) + result = connection.execute(smt) return result except Exception as e: logger.exception( "Exception in join, Error: {}".format(str(e))) return None - - - def join_formatter(self,result): - if result == None: + + def join_formatter(self, result): + if result is None: return [] return_list = [] - for each in result.fetchall(): - return_list.append( - { - 'node_id':each[0], - 'node_name':each[1], - 'node_ips':each[2], - 'node_check':each[28], - 'service_id':each[7], - 'service_name':each[9], - 'service_ip':each[10], - 'service_port':each[11], - 'service_address':each[12], - 'service_tags':each[13], - 'service_kind':each[14], - 'service_namespace':each[15], - 'service_checks':each[39] - } - ) - return return_list \ No newline at end of file + for each in result: + return_list.append({ + 'node_id': each[0], + 'node_name': each[1], + 'node_ips': each[2], + 'node_check': each[28], + 'service_id': each[7], + 'service_name': each[9], + 'service_ip': each[10], + 'service_port': each[11], + 'service_address': each[12], + 'service_tags': each[13], + 'service_kind': each[14], + 'service_namespace': each[15], + 'service_checks': each[39] + }) + return return_list diff --git a/ConsulExtension/Service/apic_utils.py b/ConsulExtension/Service/apic_utils.py index ae06bdd..0731e73 100644 --- a/ConsulExtension/Service/apic_utils.py +++ b/ConsulExtension/Service/apic_utils.py @@ -1,6 +1,5 @@ import re import json -import time import copy import base64 import requests @@ -18,16 +17,36 @@ from cobra.model.aaa import UserCert as AaaUserCert try: from OpenSSL.crypto import FILETYPE_PEM, load_privatekey, sign -except: +except Exception as e: print("=== could not import openssl crypto ===") logger = CustomLogger.get_logger("/home/app/log/app.log") -APIC_IP = get_conf_value('APIC', 'APIC_IP') +APIC_IP = get_conf_value('APIC', 'APIC_IP') STATIC_IP = get_conf_value('APIC', 'STATIC_IP') APIC_THREAD_POOL = int(get_conf_value('APIC', 'APIC_THREAD_POOL')) + +def create_cert_session(): + """ + Create user certificate and session. + """ + + cert_user = 'CiscoHashiCorp_ConsulExtensionforACI' # Name of Application, used for token generation + # static generated upon install + plugin_key_file = '/home/app/credentials/plugin.key' + pol_uni = PolUni('') + aaa_user_ep = AaaUserEp(pol_uni) + aaa_app_user = AaaAppUser(aaa_user_ep, cert_user) + aaa_user_cert = AaaUserCert(aaa_app_user, cert_user) + + with open(plugin_key_file, "r") as file: + plugin_key = file.read() + + return (aaa_user_cert, plugin_key) + + class AciUtils(object): __instance = None @@ -64,7 +83,7 @@ def login(self): Returns: auth_token -- Authentication token from Cisco APIC API """ - user_cert, plugin_key = AciUtils.create_cert_session() + user_cert, plugin_key = create_cert_session() app_token_payload = {"aaaAppToken": { "attributes": {"appName": "CiscoHashiCorp_ConsulExtensionforACI"}}} data = json.dumps(app_token_payload) @@ -92,28 +111,9 @@ def login(self): self.apic_token = None return None except Exception as e: - logger.exception('Unable to connect with APIC. Exception: '+str(e)) + logger.exception('Unable to connect with APIC. Exception: {}'.format(str(e))) self.apic_token = None - @staticmethod - def create_cert_session(): - """ - Create user certificate and session. - """ - - cert_user = 'CiscoHashiCorp_ConsulExtensionforACI' # Name of Application, used for token generation - # static generated upon install - plugin_key_file = '/home/app/credentials/plugin.key' - pol_uni = PolUni('') - aaa_user_ep = AaaUserEp(pol_uni) - aaa_app_user = AaaAppUser(aaa_user_ep, cert_user) - aaa_user_cert = AaaUserCert(aaa_app_user, cert_user) - - with open(plugin_key_file, "r") as file: - plugin_key = file.read() - - return (aaa_user_cert, plugin_key) - @time_it def aci_get(self, url, retry=1): """Function to make API call to APIC API @@ -209,7 +209,6 @@ def parse_and_return_ep_data(self, item): data_list = [] data = {} ep_attr = item.get('fvCEp').get('attributes') - ip_mac_list, data['is_cep'] = AciUtils.get_ip_mac_list(item) data['dn'] = ep_attr.get('dn') data['learning_src'] = ep_attr.get("lcC") data['tenant'] = data['dn'].split('tn-')[1].split('/')[0] @@ -218,11 +217,11 @@ def parse_and_return_ep_data(self, item): data['multi_cast_addr'] = ep_attr.get("mcastAddr") if data['multi_cast_addr'] == "not-applicable": data['multi_cast_addr'] = "---" - ep_child_attr = item.get('fvCEp').get('children') ep_info = self.get_ep_info(ep_child_attr) - for ip_mac in ip_mac_list: - data['ip'] = ip_mac + + for each in AciUtils.get_ip_mac_list(item): + data['ip'], data['is_cep'] = each # TODO: if mac, then add '' data.update(ep_info) data_list.append(copy.deepcopy(data)) return data_list @@ -362,8 +361,7 @@ def get_all_mo_instances(self, mo_class, query_string=""): instance_list = response_json['imdata'] return instance_list except Exception as ex: - logger.exception('Exception while fetching MO: ' + - mo_class + ', Error:' + str(ex)) + logger.exception('Exception while fetching MO: {}, Error: {}'.format(mo_class, str(ex))) return [] @staticmethod @@ -423,8 +421,7 @@ def apic_fetch_epg_data(self, tenant): response_json = self.aci_get(url) if response_json and response_json.get("imdata"): data = response_json.get("imdata") - logger.debug( - 'Total EPGs fetched for Tenant: {} - {} EPGs'.format(str(tenant), str(len(data)))) + logger.debug('Total EPGs fetched for Tenant: {} - {} EPGs'.format(str(tenant), str(len(data)))) parsed_data = self.parse_epg_data(data) return parsed_data return None @@ -495,7 +492,7 @@ def apic_fetch_contract(self, dn): contract_list = [] mapping_dict = { 'fvRsCons': "Consumer", - 'fvRsIntraEpg': "IntraEpg", + 'fvRsIntraEpg': "Intra EPG", 'fvRsProv': "Provider", 'fvRsConsIf': "Consumer Interface", 'fvRsProtBy': "Taboo" @@ -586,6 +583,7 @@ def parse_and_return_epg_data(self, item): data['bd'] = self.apic_fetch_bd(data['dn']) data['app_profile'] = data['dn'].split('ap-')[1].split('/')[0] data['epg'] = epg_attr.get("name") + data['epg_alias'] = epg_attr.get("nameAlias") dn_split = data['dn'].split("/", 4) vrf_str = dn_split[0] + '/' + dn_split[1] + '/BD-' + data['bd'] vrf_data = self.apic_fetch_vrf(vrf_str) @@ -606,25 +604,30 @@ def get_ip_mac_list(item): """ is_cep = False is_ip_list = False - ip_set = set() - mac_set = set() + ip_set = [] + is_cep_list = [] + response = [] for eachip in item.get('fvCEp').get('children'): # If first key is 'fvIp' than add IP to list otherwise add mac address if eachip.keys()[0] == 'fvIp': is_ip_list = True - ip_set.add( - str(eachip.get('fvIp').get('attributes').get('addr'))) + ip_set.append(str(eachip.get('fvIp').get('attributes').get('addr')).lower()) + is_cep_list.append(is_cep) # Below if condition adds all valid ip and mac to the list - cep_ip = str(item.get('fvCEp').get('attributes').get('ip')) - if cep_ip != STATIC_IP and not is_ip_list: + cep_ip = str(item.get('fvCEp').get('attributes').get('ip')).lower() + if cep_ip != STATIC_IP: is_cep = True - ip_set.add(cep_ip) + ip_set.append(cep_ip) + is_cep_list.append(is_cep) elif not is_ip_list: - mac_set.add(item.get('fvCEp').get('attributes').get('mac')) - - return (list(ip_set) + list(mac_set)), is_cep + ip_set.append(item.get('fvCEp').get('attributes').get('mac').lower()) + is_cep_list.append(is_cep) + for i, value in enumerate(ip_set): + if value not in ip_set[:i]: + response.append([value, is_cep_list[i]]) + return response @time_it def get_ap_epg_faults(self, dn): @@ -639,7 +642,6 @@ def get_ap_epg_faults(self, dn): logger.info("Exception while processing Faults : {}".format(ex)) return faults_dict - @time_it def get_ap_epg_events(self, dn): """ @@ -653,7 +655,6 @@ def get_ap_epg_events(self, dn): logger.info("Exception while processing Events : {}".format(ex)) return events_dict - @time_it def get_ap_epg_audit_logs(self, dn): """ @@ -667,7 +668,6 @@ def get_ap_epg_audit_logs(self, dn): logger.info("Exception while processing Audit logs : " + str(ex)) return audit_logs_dict - @time_it def get_mo_related_item(self, mo_dn, item_query_string, item_type): """ @@ -691,13 +691,13 @@ def get_mo_related_item(self, mo_dn, item_query_string, item_type): response_json = self.aci_get(url) if response_json and response_json.get("imdata"): item_list = response_json.get("imdata") + # logger.debug("get mo returns: {}".format(str(item_list))) return item_list except Exception as ex: logger.exception('Exception while fetching EPG item with query string: {} ,\nError: {}'.format(item_query_string, ex)) - logger.exception('Epg Item Url : =>'.format(url)) + logger.exception('Epg Item Url : {}'.format(url)) return [] - @staticmethod def get_dict_records(list_of_records, key): records_dict = dict() diff --git a/ConsulExtension/Service/app.py b/ConsulExtension/Service/app.py index 74f16c6..baa4148 100644 --- a/ConsulExtension/Service/app.py +++ b/ConsulExtension/Service/app.py @@ -2,13 +2,8 @@ from flask_graphql import GraphQLView from flask_cors import CORS from schema import schema - import alchemy_core as database -import os -import requests -from multiprocessing import Process - app = Flask(__name__) CORS(app, resources={r"/graphql.json": {"origins": "*"}}) app.config['CORS_HEADERS'] = 'Content-Type' diff --git a/ConsulExtension/Service/config_utils.py b/ConsulExtension/Service/config_utils.py index f52554c..646ce5e 100644 --- a/ConsulExtension/Service/config_utils.py +++ b/ConsulExtension/Service/config_utils.py @@ -1,4 +1,8 @@ import configparser +import os +import custom_logger +logger = custom_logger.CustomLogger.get_logger("./app.log") + def get_conf_value(section, key_name): """Function to return value from configuration @@ -7,6 +11,7 @@ def get_conf_value(section, key_name): Args: key_name (str): Name of key """ + current_path = os.path.dirname(os.path.abspath(__file__)) config = configparser.ConfigParser() - config.read('config.cfg') - return config.get(section, key_name) \ No newline at end of file + config.read(''.join([current_path, '/config.cfg'])) + return config.get(section, key_name) diff --git a/ConsulExtension/Service/consul_utils.py b/ConsulExtension/Service/consul_utils.py index 57571db..90d771e 100644 --- a/ConsulExtension/Service/consul_utils.py +++ b/ConsulExtension/Service/consul_utils.py @@ -13,7 +13,6 @@ class Consul(object): """Consul class""" def __init__(self, agent_ip, port, token, protocol): - logger.info('Consul Object init for agent: {}:{}'.format(agent_ip, port)) self.agent_ip = str(agent_ip) @@ -24,26 +23,25 @@ def __init__(self, agent_ip, port, token, protocol): self.session = requests.Session() self.connected = False - # The base URL is set with protocol http, + # The base URL is set with protocol http, # if http fails https will be tried self.base_url = '{}://{}:{}'.format(self.protocol, self.agent_ip, self.port) self.header = {} if self.token: logger.info('Token provided') - self.header = {'X-Consul-Token' : self.token} - + self.header = {'X-Consul-Token': self.token} def check_connection(self): """Verify if connection to an agent is possible - + if token is provided checks for a token based access - with both http and https if that fails then same + with both http and https if that fails then same for without token if Token is not provided check connection with http and https """ - + logger.info('Check Consul Connection') try: status_code = None @@ -52,7 +50,7 @@ def check_connection(self): response = self.session.get(urls.AUTH.format(self.base_url), headers=self.header, timeout=5) status_code = response.status_code - # This is the case when no token is provided by the user or + # This is the case when no token is provided by the user or # it is provided but connection has failed else: logger.info("Token NOT provided, trying connecting to agent without token.") @@ -92,10 +90,9 @@ def check_connection(self): logger.exception('Exception in Consul check connection: {}'.format(str(e))) return self.connected, None - def nodes(self): """Fetching all the nodes using an agent - + return: [ { node_id: string: id @@ -111,7 +108,7 @@ def nodes(self): catalog_nodes = self.session.get(urls.CATALOG_NODES.format(self.base_url), timeout=30) catalog_nodes = json.loads(catalog_nodes.content) logger.debug('Catalog Nodes API data: {}'.format(str(catalog_nodes))) - + # Iterate over each node and get all its unique ips for node in catalog_nodes: ip_list = [] @@ -124,7 +121,7 @@ def nodes(self): ip_list.append(tagged_addr.get('lan_ipv4', '')) # for removing '' from ip_list - ip_list = [ip for ip in ip_list if ip] + ip_list = [ip.lower() for ip in ip_list if ip] node_name = node.get('Node', '') @@ -134,17 +131,16 @@ def nodes(self): 'node_ips': list(set(ip_list)) }) except Exception as e: - logger.exception('Exception in Catalog Nodes: {}'.format(str(e))) + logger.exception('Exception in Catalog Nodes: {}'.format(str(e))) logger.debug('nodes return: {}'.format(str(node_list))) return node_list - def nodes_services(self, node_name): """This will return all the services of a node - - node_name: name of nodes for services - + + :node_name: name of nodes for services + return: [ { service_id: string: id @@ -167,13 +163,13 @@ def nodes_services(self, node_name): for service in services_resp.get('Services'): # form service_address - service_ip = service.get('Address') + service_ip = service.get('Address').lower() service_port = service.get('Port') if service_ip: service_address = str(service_ip) + ':' + str(service_port) else: - service_address = str(services_resp.get('Node', {}).get('Address', '')) + ':' + str(service_port) - + service_address = str(services_resp.get('Node', {}).get('Address', '')).lower() + ':' + str(service_port) + # Form a dict service_list.append({ 'service_id': service.get('ID'), @@ -188,11 +184,10 @@ def nodes_services(self, node_name): logger.debug('nodes_services return: {}'.format(str(service_list))) return service_list - def node_checks(self, node_name): """Get node checks - node_name: name of the node for checks + :node_name: name of the node for checks return: { passing: int: if val > 0 @@ -235,11 +230,10 @@ def node_checks(self, node_name): logger.debug('node_checks return: {}'.format(str(check_dict))) return check_dict - def service_checks(self, service_name): """Get all the serveice checks - - service_name: name of the service for checks + + :service_name: name of the service for checks return: { passing: int: if val > 0 @@ -254,7 +248,7 @@ def service_checks(self, service_name): service_resp = self.session.get(urls.SERVICE_CHECK.format(self.base_url, service_name), timeout=30) service_resp = json.loads(service_resp.content) logger.debug('Service Check API data: {}'.format(service_resp)) - + for check in service_resp: status = check.get('Status') if status: @@ -279,11 +273,10 @@ def service_checks(self, service_name): logger.debug('service_checks return: {}'.format(str(check_dict))) return check_dict - def service_info(self, service_name): """Get tag and kind info from details of a service - - service_name: name of the service for checks + + :service_name: name of the service for checks return: tuple(tag_list, kind, namespace) tag_list: string list @@ -306,19 +299,18 @@ def service_info(self, service_name): tag_list = list(tags_set) service_kind = service_resp[0].get('ServiceKind', '') - # In case of OSS cluster, no key named Namespace is returned, - # thus NA will be returned. + # In case of OSS cluster, no key named Namespace is returned, + # thus NA will be returned. service_namespace = service_resp[0].get('Namespace', 'NA') except Exception as e: logger.exception('Exception in Service Details: {}'.format(str(e))) - logger.debug('service_info return: {}'.format(tag_list, service_kind)) + logger.debug('service_info return: {}, {}, {}'.format(tag_list, service_kind, service_namespace)) return tag_list, service_kind, service_namespace - def datacenter(self): """This will return datacenter of an agent - + return: string """ @@ -331,15 +323,14 @@ def datacenter(self): logger.debug('Datacenter API data: {}'.format(datacenter_name)) except Exception as e: logger.exception("Error in Datacenter: {}".format(e)) - + logger.debug('datacenter return: {}'.format(str(datacenter_name))) return datacenter_name - def detailed_service_check(self, service_name, service_id): """Get serveice checks details - - service_name: name of the service for checks + + :service_name: name of the service for checks return: [{ ServiceName: string @@ -358,7 +349,7 @@ def detailed_service_check(self, service_name, service_id): service_resp = self.session.get(urls.SERVICE_CHECK.format(self.base_url, service_name), timeout=30) service_resp = json.loads(service_resp.content) logger.debug('Service Check API data: {}'.format(service_resp)) - + for check in service_resp: if check.get("ServiceID").lower() == service_id.lower(): service_check = {} @@ -379,11 +370,10 @@ def detailed_service_check(self, service_name, service_id): logger.debug('detailed_service_check return: {}'.format(str(service_checks_list))) return service_checks_list - def detailed_node_check(self, node_name): """Get node checks details - node_name: name of the node for checks + :node_name: name of the node for checks return: [{ Name: string @@ -424,7 +414,6 @@ def detailed_node_check(self, node_name): logger.debug('detailed_node_check return: {}'.format(str(node_checks_list))) return node_checks_list - def get_consul_data(self): """ This will fetch the data from the API and return for now @@ -477,7 +466,7 @@ def get_consul_data(self): for service in service_list: # get service check, tags and kind using service name - service_name = service.get('service_name') # This may fail + service_name = service.get('service_name') # This may fail service_check = self.service_checks(service_name) service_tags, service_kind, service_ns = self.service_info(service_name) @@ -502,7 +491,7 @@ def get_consul_data(self): 'node_services': final_service_list }) except Exception as e: - logger.exception("Error while merge_aci_data : "+str(e)) + logger.exception("Error while merge_aci_data : {}".format(str(e))) logger.debug('get_consul_data return: {}'.format(str(consul_data))) - return consul_data \ No newline at end of file + return consul_data diff --git a/ConsulExtension/Service/custom_logger.py b/ConsulExtension/Service/custom_logger.py index 10907aa..d429279 100644 --- a/ConsulExtension/Service/custom_logger.py +++ b/ConsulExtension/Service/custom_logger.py @@ -1,4 +1,3 @@ -import os import logging @@ -7,11 +6,10 @@ class CustomLogger(object): @classmethod def get_logger(cls, path): - if cls.__logger == None: + if cls.__logger is None: cls.__logger = CustomLogger.__get_logger(path) return cls.__logger - @staticmethod def __get_logger(path): logger = logging.getLogger(__name__) diff --git a/ConsulExtension/Service/data_fetch.py b/ConsulExtension/Service/data_fetch.py index e24ff3a..2ce86d7 100644 --- a/ConsulExtension/Service/data_fetch.py +++ b/ConsulExtension/Service/data_fetch.py @@ -1,6 +1,6 @@ """This module get consul data and put in DB -This fetches data using consul_util on a regular +This fetches data using consul_util on a regular intercal and then puts it into the database. """ @@ -13,10 +13,7 @@ from decorator import exception_handler import time -import json import base64 -import threading -from itertools import repeat import concurrent.futures from threading_util import ThreadSafeDict @@ -24,15 +21,15 @@ db_obj = database.Database() db_obj.create_tables() -POLL_INTERVAL = int(get_conf_value('DATA_FETCH', 'POLL_INTERVAL')) # interval in minutes -CHECK_AGENT_LIST = int(get_conf_value('DATA_FETCH', 'CHECK_AGENT_LIST')) # interval in sec -THREAD_POOL = int(get_conf_value('DATA_FETCH', 'CONSUL_THREAD_POOL')) # Pool size for all thread pools +POLL_INTERVAL = int(get_conf_value('DATA_FETCH', 'POLL_INTERVAL')) # interval in minutes +CHECK_AGENT_LIST = int(get_conf_value('DATA_FETCH', 'CHECK_AGENT_LIST')) # interval in sec +THREAD_POOL = int(get_conf_value('DATA_FETCH', 'CONSUL_THREAD_POOL')) # Pool size for all thread pools @exception_handler def get_nodes(nodes_dict, agent): """Get catalog nodes and put it in the dict - + nodes_dict: dict to store all unique nodes of a DC agent: agent to be used to fetch the data """ @@ -46,7 +43,7 @@ def get_nodes(nodes_dict, agent): for node in list_of_nodes: node_id = node.get('node_id') agent_addr = agent.get('ip') + ':' + agent.get('port') - if not nodes_dict.has_key(node_id): + if node_id not in nodes_dict: node.update({ 'agent_consul_obj': consul_obj, 'agent_addr': [agent_addr] @@ -60,7 +57,7 @@ def get_nodes(nodes_dict, agent): @exception_handler def get_services(services_dict, node): """Get node services and put it in the dict - + services_dict: dict to store all unique services of a DC node: node's service to be fetched """ @@ -71,10 +68,10 @@ def get_services(services_dict, node): node_name = node.get('node_name') node_id = node.get('node_id') service_list = consul_obj.nodes_services(node_name) - + for service in service_list: service_key = service.get('service_id') + node_id - if not services_dict.has_key(service_key): + if service_key not in services_dict: service.update({ 'agent_consul_obj': consul_obj, 'node_id': node_id, @@ -82,12 +79,12 @@ def get_services(services_dict, node): }) with services_dict as active_service: active_service[service_key] = service - + @exception_handler def get_node_checks(node_checks_dict, node): """Get node checks - + node: node's checks to be fetched """ @@ -99,7 +96,7 @@ def get_node_checks(node_checks_dict, node): for node_check in node_checks: check_key = node_check.get('CheckID') + node.get('node_id') - if not node_checks_dict.has_key(check_key): + if check_key not in node_checks_dict: node_check.update({ 'node_id': node.get('node_id'), 'node_name': node_name, @@ -112,10 +109,10 @@ def get_node_checks(node_checks_dict, node): @exception_handler def get_service_info(service): """Get Service info - + service: service's info to be fetched """ - + logger.info("Services info for: {}".format(str(service.get('service_name')))) consul_obj = service.get('agent_consul_obj') @@ -132,7 +129,7 @@ def get_service_info(service): @exception_handler def get_service_checks(service_checks_dict, service): """Get service checks - + service: service's checks to be fetched """ @@ -145,7 +142,7 @@ def get_service_checks(service_checks_dict, service): for service_check in service_checks: check_key = service_check.get('CheckID') + service_id - if not service_checks_dict.has_key(check_key): + if check_key not in service_checks_dict: service_check.update({ 'service_id': service_id, 'agent_addr': service.get('agent_addr') @@ -162,7 +159,7 @@ def data_fetch(): """ while True: - + try: # Starting time of the thread start_time = time.time() @@ -171,7 +168,10 @@ def data_fetch(): consul_ip_list = set() # get agent list from db - agents = list(db_obj.select_from_table(db_obj.LOGIN_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + agents = list(db_obj.select_from_table(connection, db_obj.LOGIN_TABLE_NAME)) + connection.close() agent_list = [] for agent in agents: status = int(agent[4]) @@ -187,7 +187,7 @@ def data_fetch(): } ) - # if there is no agent list on + # if there is no agent list on # db check it every CHECK_AGENT_LIST sec if not agent_list: logger.info("No Agents found in the Login table, retrying after {}sec".format(CHECK_AGENT_LIST)) @@ -200,7 +200,7 @@ def data_fetch(): # Iterate over each datacenter to fetch the data for datacenter, agents in datacenter_list.items(): - + logger.info("Data fetch for dc: {}".format(datacenter)) # Creating a list of agents @@ -219,45 +219,57 @@ def data_fetch(): node_checks_key = set() service_checks_key = set() - # Iterate for every agent of that DC + # Iterate for every agent of that DC # and create a unique list of nodes. with concurrent.futures.ThreadPoolExecutor(max_workers=THREAD_POOL) as executor: for agent in agents: executor.submit(get_nodes, nodes_dict, agent) # Inserting Nodes data in DB - for node_id, node_val in nodes_dict.items(): - db_obj.insert_and_update(db_obj.NODE_TABLE_NAME , - ( - node_val.get('node_id'), - node_val.get('node_name'), - node_val.get('node_ips'), - datacenter, - node_val.get('agent_addr') - ), - { - 'node_id': node_val.get('node_id') - } - ) - - # Add node ip to consul ip list - for ip in node_val.get('node_ips'): - consul_ip_list.add(ip) - - # Add node_id to key set - nodes_key.add(node_val.get('node_id')) + connection = db_obj.engine.connect() + with connection.begin(): + for node_id, node_val in nodes_dict.items(): + db_obj.insert_and_update( + connection, + db_obj.NODE_TABLE_NAME, + ( + node_val.get('node_id'), + node_val.get('node_name'), + node_val.get('node_ips'), + datacenter, + node_val.get('agent_addr') + ), + { + 'node_id': node_val.get('node_id') + } + ) + + # Add node ip to consul ip list + for ip in node_val.get('node_ips'): + consul_ip_list.add(ip) + + # Add node_id to key set + nodes_key.add(node_val.get('node_id')) + connection.close() # Remove deleted Node data. - node_data = list(db_obj.select_from_table(db_obj.NODE_TABLE_NAME)) - for node in node_data: - agents = node[4] - for agent in agents: - if agent in agent_addr_list and node[0] not in nodes_key: - if len(agents) == 1: - db_obj.delete_from_table(db_obj.NODE_TABLE_NAME,{'node_id': node[0]}) - elif len(agents) > 1: - node[4].remove(agent) - db_obj.insert_and_update(db_obj.NODE_TABLE_NAME, node, {'node_id': node[0]}) + connection = db_obj.engine.connect() + with connection.begin(): + node_data = list(db_obj.select_from_table(connection, db_obj.NODE_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for node in node_data: + agents = node[4] + for agent in agents: + if agent in agent_addr_list and node[0] not in nodes_key: + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.NODE_TABLE_NAME, {'node_id': node[0]}) + elif len(agents) > 1: + node[4].remove(agent) + db_obj.insert_and_update(connection, db_obj.NODE_TABLE_NAME, node, {'node_id': node[0]}) + connection.close() logger.info("Data update in Node Complete.") @@ -265,46 +277,58 @@ def data_fetch(): with concurrent.futures.ThreadPoolExecutor(max_workers=THREAD_POOL) as executor: for node in nodes_dict.values(): executor.submit(get_services, services_dict, node) - + # Iterate all nodes and get node checks with concurrent.futures.ThreadPoolExecutor(max_workers=THREAD_POOL) as executor: for node in nodes_dict.values(): executor.submit(get_node_checks, node_checks_dict, node) # Inserting Nodes checks data in DB - for node in node_checks_dict.values(): - db_obj.insert_and_update(db_obj.NODECHECKS_TABLE_NAME, - ( - node.get('CheckID'), - node.get('node_id'), - node.get('node_name'), - node.get('Name'), - node.get('ServiceName'), - node.get('Type'), - node.get('Notes'), - node.get('Output'), - node.get('Status'), - node.get('agent_addr') - ), - { - 'check_id': node.get('CheckID'), - 'node_id': node.get('node_id') - } - ) - - # Add node_id, check_id to key set - node_checks_key.add((node.get('CheckID'), node.get('node_id'))) - - node_checks_data = list(db_obj.select_from_table(db_obj.NODECHECKS_TABLE_NAME)) - for node in node_checks_data: - agents = node[9] - for agent in agents: - if agent in agent_addr_list and (node[0], node[1]) not in node_checks_key: - if len(agents) == 1: - db_obj.delete_from_table(db_obj.NODECHECKS_TABLE_NAME,{'check_id': node[0], 'node_id': node[1]}) - elif len(agents) > 1: - node[9].remove(agent) - db_obj.insert_and_update(db_obj.NODECHECKS_TABLE_NAME, node, {'check_id': node[0], 'node_id': node[1]}) + connection = db_obj.engine.connect() + with connection.begin(): + for node in node_checks_dict.values(): + db_obj.insert_and_update( + connection, + db_obj.NODECHECKS_TABLE_NAME, + ( + node.get('CheckID'), + node.get('node_id'), + node.get('node_name'), + node.get('Name'), + node.get('ServiceName'), + node.get('Type'), + node.get('Notes'), + node.get('Output'), + node.get('Status'), + node.get('agent_addr') + ), + { + 'check_id': node.get('CheckID'), + 'node_id': node.get('node_id') + } + ) + + # Add node_id, check_id to key set + node_checks_key.add((node.get('CheckID'), node.get('node_id'))) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + node_checks_data = list(db_obj.select_from_table(connection, db_obj.NODECHECKS_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for node in node_checks_data: + agents = node[9] + for agent in agents: + if agent in agent_addr_list and (node[0], node[1]) not in node_checks_key: + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.NODECHECKS_TABLE_NAME, {'check_id': node[0], 'node_id': node[1]}) + elif len(agents) > 1: + node[9].remove(agent) + db_obj.insert_and_update(connection, db_obj.NODECHECKS_TABLE_NAME, node, {'check_id': node[0], 'node_id': node[1]}) + connection.close() logger.info("Data update in Node Checks Complete.") @@ -314,43 +338,55 @@ def data_fetch(): executor.submit(get_service_info, service) # Inserting Services into DB - for service in services_dict.values(): - db_obj.insert_and_update(db_obj.SERVICE_TABLE_NAME, - ( - service.get('service_id'), - service.get('node_id'), - service.get('service_name'), - service.get('service_ip'), - service.get('service_port'), - service.get('service_address'), - service.get('service_tags'), - service.get('service_kind'), - service.get('service_namespace'), - datacenter, - service.get('agent_addr') - ), - { - 'service_id': service.get('service_id'), - 'node_id': service.get('node_id') - } - ) - - # Add service ip to consul ip list - consul_ip_list.add(service.get('service_ip')) - - # Add service_id, node_id to key set - services_key.add((service.get('service_id'), service.get('node_id'))) - - service_data = list(db_obj.select_from_table(db_obj.SERVICE_TABLE_NAME)) - for service in service_data: - agents = service[10] - for agent in agents: - if agent in agent_addr_list and (service[0], service[1]) not in services_key: - if len(agents) == 1: - db_obj.delete_from_table(db_obj.SERVICE_TABLE_NAME,{'service_id': service[0],'node_id': service[1]}) - elif len(agents) > 1: - service[10].remove(agent) - db_obj.insert_and_update(db_obj.SERVICE_TABLE_NAME, service, {'service_id': service[0],'node_id': service[1]}) + connection = db_obj.engine.connect() + with connection.begin(): + for service in services_dict.values(): + db_obj.insert_and_update( + connection, + db_obj.SERVICE_TABLE_NAME, + ( + service.get('service_id'), + service.get('node_id'), + service.get('service_name'), + service.get('service_ip'), + service.get('service_port'), + service.get('service_address'), + service.get('service_tags'), + service.get('service_kind'), + service.get('service_namespace'), + datacenter, + service.get('agent_addr') + ), + { + 'service_id': service.get('service_id'), + 'node_id': service.get('node_id') + } + ) + + # Add service ip to consul ip list + consul_ip_list.add(service.get('service_ip')) + + # Add service_id, node_id to key set + services_key.add((service.get('service_id'), service.get('node_id'))) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + service_data = list(db_obj.select_from_table(connection, db_obj.SERVICE_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for service in service_data: + agents = service[10] + for agent in agents: + if agent in agent_addr_list and (service[0], service[1]) not in services_key: + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.SERVICE_TABLE_NAME, {'service_id': service[0], 'node_id': service[1]}) + elif len(agents) > 1: + service[10].remove(agent) + db_obj.insert_and_update(connection, db_obj.SERVICE_TABLE_NAME, service, {'service_id': service[0], 'node_id': service[1]}) + connection.close() logger.info("Data update in Service Complete.") @@ -360,38 +396,50 @@ def data_fetch(): executor.submit(get_service_checks, service_checks_dict, service) # Inserting Service Checks in DB - for service in service_checks_dict.values(): - db_obj.insert_and_update(db_obj.SERVICECHECKS_TABLE_NAME, - ( - service.get('CheckID'), - service.get('service_id'), - service.get('ServiceName'), - service.get('Name'), - service.get('Type'), - service.get('Notes'), - service.get('Output'), - service.get('Status'), - service.get('agent_addr') - ), - { - 'check_id': service.get('CheckID'), - 'service_id': service.get('service_id') - } - ) - - # Add check_id and service_id to key set - service_checks_key.add((service.get('CheckID'), service.get('service_id'))) - - service_checks_data = list(db_obj.select_from_table(db_obj.SERVICECHECKS_TABLE_NAME)) - for service in service_checks_data: - agents = service[8] - for agent in agents: - if agent in agent_addr_list and (service[0], service[1]) not in service_checks_key: - if len(agents) == 1: - db_obj.delete_from_table(db_obj.SERVICECHECKS_TABLE_NAME, {'check_id': service[0],'service_id': service[1]}) - elif len(agents) > 1: - service[8].remove(agent) - db_obj.insert_and_update(db_obj.SERVICECHECKS_TABLE_NAME, service, {'check_id': service[0],'service_id': service[1]}) + connection = db_obj.engine.connect() + with connection.begin(): + for service in service_checks_dict.values(): + db_obj.insert_and_update( + connection, + db_obj.SERVICECHECKS_TABLE_NAME, + ( + service.get('CheckID'), + service.get('service_id'), + service.get('ServiceName'), + service.get('Name'), + service.get('Type'), + service.get('Notes'), + service.get('Output'), + service.get('Status'), + service.get('agent_addr') + ), + { + 'check_id': service.get('CheckID'), + 'service_id': service.get('service_id') + } + ) + + # Add check_id and service_id to key set + service_checks_key.add((service.get('CheckID'), service.get('service_id'))) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + service_checks_data = list(db_obj.select_from_table(connection, db_obj.SERVICECHECKS_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for service in service_checks_data: + agents = service[8] + for agent in agents: + if agent in agent_addr_list and (service[0], service[1]) not in service_checks_key: + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.SERVICECHECKS_TABLE_NAME, {'check_id': service[0], 'service_id': service[1]}) + elif len(agents) > 1: + service[8].remove(agent) + db_obj.insert_and_update(connection, db_obj.SERVICECHECKS_TABLE_NAME, service, {'check_id': service[0], 'service_id': service[1]}) + connection.close() logger.info("Data update in Service Checks Complete.") @@ -399,12 +447,15 @@ def data_fetch(): logger.info("Data fetch for Consul complete.") - # Data fetch for APIC logger.info("Start data fetch for APIC.") # get tenant list from db - tenants = list(db_obj.select_from_table(db_obj.TENANT_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + tenants = list(db_obj.select_from_table(connection, db_obj.TENANT_TABLE_NAME)) + connection.close() + tenant_list = [] for tenant in tenants: tenant_list.append(tenant[0]) @@ -427,64 +478,89 @@ def data_fetch(): ep_key = set() epg_key = set() - for ep in ep_data: - db_obj.insert_and_update(db_obj.EP_TABLE_NAME, - ( - ep.get('mac'), - ep.get('ip'), - ep.get('tenant'), - ep.get('dn'), - ep.get('vm_name'), - ep.get('interfaces'), - ep.get('vmm_domain'), - ep.get('controller'), - ep.get('learning_src'), - ep.get('multi_cast_addr'), - ep.get('encap'), - ep.get('hosting_servername'), - ep.get('is_cep'), - ), - { - 'mac': ep.get('mac'), - 'ip': ep.get('ip'), - } - ) - - # Add mac, ip to key set - ep_key.add((ep.get('mac'), ep.get('ip'))) - - ep_data = list(db_obj.select_from_table(db_obj.EP_TABLE_NAME)) - for ep in ep_data: - if ep[2] == tenant and (ep[0], ep[1]) not in ep_key: - db_obj.delete_from_table(db_obj.EP_TABLE_NAME, ep, {'mac': ep[0], 'ip': ep[1]}) + connection = db_obj.engine.connect() + with connection.begin(): + for ep in ep_data: + db_obj.insert_and_update( + connection, + db_obj.EP_TABLE_NAME, + ( + ep.get('mac'), + ep.get('ip'), + ep.get('tenant'), + ep.get('dn'), + ep.get('vm_name'), + ep.get('interfaces'), + ep.get('vmm_domain'), + ep.get('controller'), + ep.get('learning_src'), + ep.get('multi_cast_addr'), + ep.get('encap'), + ep.get('hosting_servername'), + ep.get('is_cep'), + ), + { + 'mac': ep.get('mac'), + 'ip': ep.get('ip'), + } + ) + + # Add mac, ip to key set + ep_key.add((ep.get('mac'), ep.get('ip'))) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + ep_data = list(db_obj.select_from_table(connection, db_obj.EP_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for ep in ep_data: + if ep[2] == tenant and (ep[0], ep[1]) not in ep_key: + db_obj.delete_from_table(connection, db_obj.EP_TABLE_NAME, {'mac': ep[0], 'ip': ep[1]}) + connection.close() logger.info("Data update in EP Complete.") epg_data = aci_obj.apic_fetch_epg_data(tenant) - for epg in epg_data: - db_obj.insert_and_update(db_obj.EPG_TABLE_NAME, - ( - epg.get('dn'), - epg.get('tenant'), - epg.get('epg'), - epg.get('bd'), - epg.get('contracts'), - epg.get('vrf'), - epg.get('epg_health'), - epg.get('app_profile'), - ), - { - 'dn': epg.get('dn') - } - ) - - # Add dn to key set - epg_key.add(epg.get('dn')) - - epg_data = list(db_obj.select_from_table(db_obj.EPG_TABLE_NAME)) - for epg in epg_data: - if epg[1] == tenant and epg[0] not in epg_key: - db_obj.delete_from_table(db_obj.EPG_TABLE_NAME, epg, {'dn': epg[0]}) + connection = db_obj.engine.connect() + with connection.begin(): + for epg in epg_data: + db_obj.insert_and_update( + connection, + db_obj.EPG_TABLE_NAME, + ( + epg.get('dn'), + epg.get('tenant'), + epg.get('epg'), + epg.get('bd'), + epg.get('contracts'), + epg.get('vrf'), + epg.get('epg_health'), + epg.get('app_profile'), + epg.get('epg_alias') + ), + { + 'dn': epg.get('dn') + } + ) + + # Add dn to key set + epg_key.add(epg.get('dn')) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + epg_data = list(db_obj.select_from_table(connection, db_obj.EPG_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for epg in epg_data: + if epg[1] == tenant and epg[0] not in epg_key: + db_obj.delete_from_table(connection, db_obj.EPG_TABLE_NAME, {'dn': epg[0]}) + connection.close() logger.info("Data update in EPG Complete.") @@ -494,11 +570,12 @@ def data_fetch(): logger.info("Error in data fetch: {}".format(str(e))) current_time = time.time() - time_to_sleep = (start_time + POLL_INTERVAL*60) - current_time + time_to_sleep = (start_time + POLL_INTERVAL * 60) - current_time if time_to_sleep > 0: logger.info("Data fetch thread sleeping for interval: {}".format(time_to_sleep)) time.sleep(time_to_sleep) + if __name__ == "__main__": # Starting the data fetch process logger.info("Starting the data fetch process") diff --git a/ConsulExtension/Service/decorator.py b/ConsulExtension/Service/decorator.py index 89abe39..d0db699 100644 --- a/ConsulExtension/Service/decorator.py +++ b/ConsulExtension/Service/decorator.py @@ -30,8 +30,8 @@ def wrapper(*args): logger.exception('Exception in {} : {}'.format(method.__name__, str(e))) return wrapper -# Decorators used in alchemy +# Decorators used in alchemy def alchemy_commit_session(method): def wrapper(*args): try: @@ -39,7 +39,7 @@ def wrapper(*args): except Exception as e: logger.exception('error in {} : {}'.format(method.__name__, str(e))) finally: - args[0].commit_session() # here 0th argument is self so args[0].commit_session() + args[0].commit_session() # here 0th argument is self so args[0].commit_session() return wrapper @@ -50,4 +50,4 @@ def wrapper(*args): except Exception as e: logger.exception('error in {} : {}'.format(method.__name__, str(e))) return [] - return wrapper \ No newline at end of file + return wrapper diff --git a/ConsulExtension/Service/merge.py b/ConsulExtension/Service/merge.py index 17700f2..ae4caf6 100644 --- a/ConsulExtension/Service/merge.py +++ b/ConsulExtension/Service/merge.py @@ -1,13 +1,10 @@ -import json import copy -import datetime - import custom_logger from decorator import time_it - logger = custom_logger.CustomLogger.get_logger("/home/app/log/app.log") + @time_it def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): """ @@ -26,7 +23,7 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): logger.debug("ACI Data: {}".format(str(aci_data))) logger.debug("Mapping Data: {}".format(str(aci_consul_mappings))) - mappings = [node for node in aci_consul_mappings if node.get('enabled') == True] + mappings = [node for node in aci_consul_mappings if node.get('enabled')] for aci in aci_data: if aci['EPG'] not in total_epg_count.keys(): @@ -38,7 +35,7 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): for each in mappings: mapping_key = 'ip' aci_key = 'IP' - if aci.get(aci_key) and each.get(mapping_key) and aci.get(aci_key).upper() == each.get(mapping_key).upper() and each['dn'] == str(aci['dn']): + if aci.get(aci_key) and each.get(mapping_key) and aci.get(aci_key) == each.get(mapping_key) and each['dn'] == str(aci['dn']): logger.info('mapping: {}, aci: {}'.format(str(each), str(aci))) # Service to CEp mapping for node in consul_data: @@ -52,7 +49,7 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): # All the services which matches CEp and its ip is different from its nodes ip node_services = copy.deepcopy(node.get('node_services', [])) for service in node_services: - if aci.get(aci_key).upper() == service.get('service_ip') and aci.get(aci_key).upper() not in node.get('node_ips'): + if aci.get(aci_key) == service.get('service_ip') and aci.get(aci_key) not in node.get('node_ips'): # node['node_services'].remove(service) new_node['node_services'].append(service) # Below statements is supposed to remove all the services which do not map to any ip in mappings. @@ -70,7 +67,7 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): merged_epg_count[aci['EPG']].append(aci[aci_key]) # node to EP mapping - mapped_consul_nodes = [node for node in consul_data if aci.get(aci_key).upper() in node.get('node_ips', [])] + mapped_consul_nodes = [node for node in consul_data if aci.get(aci_key) in node.get('node_ips', [])] if mapped_consul_nodes: for each in mapped_consul_nodes: each.update(aci) @@ -89,18 +86,18 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): if (aci['IP'], aci['CEP-Mac'], aci['dn']) in merged_eps: continue else: - if aci['EPG'] not in non_merged_ep_dict: - non_merged_ep_dict[aci['EPG']] = {aci['CEP-Mac']: str(aci['IP'])} - - if aci['CEP-Mac'] in non_merged_ep_dict[aci['EPG']].keys() and aci.get('IP') and aci['IP'] != non_merged_ep_dict[aci['EPG']][aci['CEP-Mac']]: - multipleips = non_merged_ep_dict[aci['EPG']][aci['CEP-Mac']] + ", " + str(aci['IP']) - non_merged_ep_dict[aci['EPG']].update({aci['CEP-Mac']: multipleips}) + if aci['dn'] not in non_merged_ep_dict: + non_merged_ep_dict[aci['dn']] = {aci['CEP-Mac']: str(aci['IP'])} + + if aci['CEP-Mac'] in non_merged_ep_dict[aci['dn']].keys() and aci.get('IP') and aci['IP'] != non_merged_ep_dict[aci['dn']][aci['CEP-Mac']]: + multipleips = non_merged_ep_dict[aci['dn']][aci['CEP-Mac']] + ", " + str(aci['IP']) + non_merged_ep_dict[aci['dn']].update({aci['CEP-Mac']: multipleips}) else: - non_merged_ep_dict[aci['EPG']].update({aci['CEP-Mac']: str(aci['IP'])}) + non_merged_ep_dict[aci['dn']].update({aci['CEP-Mac']: str(aci['IP'])}) final_non_merged = {} if non_merged_ep_dict: - for key,value in non_merged_ep_dict.items(): + for key, value in non_merged_ep_dict.items(): if not value: continue final_non_merged[key] = value @@ -110,7 +107,7 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): for epg in total_epg_count.keys(): un_map_eps = int(total_epg_count.get(epg, [])) - len(merged_epg_count.get(epg, [])) fractions[epg] = int(un_map_eps) - logger.info('Total Unmapped Eps (Inactive):'+str(un_map_eps)+" - "+str(epg)) + logger.info('Total Unmapped Eps (Inactive): {} - {}'.format(str(un_map_eps), str(epg))) updated_merged_list = [] if fractions: @@ -118,7 +115,7 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): for each in merge_list: if key == each['EPG']: each['fraction'] = value - each['Non_IPs'] = final_non_merged.get(key, {}) + each['Non_IPs'] = final_non_merged.get(each['dn'], {}) updated_merged_list.append(each) final_list = [] @@ -129,7 +126,7 @@ def merge_aci_consul(tenant, aci_data, consul_data, aci_consul_mappings): final_list.append(each) logger.info('Merge complete. Total objects correlated: ' + str(len(final_list))) - return final_list #updated_merged_list#,total_epg_count # TBD for returning values + return final_list # updated_merged_list#,total_epg_count # TBD for returning values except Exception as e: - logger.exception("Error in merge_aci_data : "+str(e)) + logger.exception("Error in merge_aci_data : {}".format(str(e))) return [] diff --git a/ConsulExtension/Service/plugin_server.py b/ConsulExtension/Service/plugin_server.py index 77c7698..253198f 100644 --- a/ConsulExtension/Service/plugin_server.py +++ b/ConsulExtension/Service/plugin_server.py @@ -1,9 +1,5 @@ -import os import re import json -import time -import socket -import datetime import base64 from flask import Flask @@ -30,6 +26,7 @@ db_obj.create_tables() +@time_it def set_polling_interval(interval): """Sets the polling interval for data fetch""" @@ -37,9 +34,34 @@ def set_polling_interval(interval): def get_new_mapping(tenant, datacenter): + """Generate new mapping(recommendation) + + This fetches the APIC data for the tenant and Consul + data for the datacenter; gets the recommendations, + looks up db for enabled/disabled mapping(recommendations). + + :tenant: tenant for APIC data + :datacenter: datacenter for Consul data + + return: [ + ip: string: ip of the Mapped Node + enabled: boolean: toggled or not + recommended: boolean: recommendation as per the logic + dn: string: Mapped Node's dn + vrf: string: Mapped Node's VRF(Virtual routing and forwarding network) + bd: string: Mapped Node's Bridge Domain + ap: string: Mapped Node's Application Profile + tenant: string: Mapped Node's tenant + epg: string: Mapped Node's Endpoint Group + ] + """ try: # Get APIC data - ep_data = list(db_obj.select_from_table(db_obj.EP_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + ep_data = list(db_obj.select_from_ep_with_tenant(connection, tenant)) + connection.close() + parsed_eps = [] for ep in ep_data: cep_ip = int(ep[12]) @@ -55,6 +77,7 @@ def get_new_mapping(tenant, datacenter): } ) + apic_data = get_apic_data(tenant) # Get consul data consul_data = get_consul_data(datacenter) ip_list = [] @@ -67,7 +90,7 @@ def get_new_mapping(tenant, datacenter): ip_list.append(service.get('service_ip')) aci_consul_mappings = recommend_utils.recommended_eps( - list(set(ip_list)), parsed_eps) + list(set(ip_list)), parsed_eps, apic_data) if not aci_consul_mappings: logger.info("Empty ACI and Consul mappings.") @@ -76,15 +99,14 @@ def get_new_mapping(tenant, datacenter): current_mapping = [] for map_object in aci_consul_mappings: for entry in map_object.get('domains'): - logger.debug("Mapping found with ipaddress for "+str(map_object)) - current_mapping.append({ - 'dn': entry.get('domainName'), - 'ip': map_object.get('ipaddress'), - 'recommended': entry.get('recommended'), - 'enabled': entry.get('recommended') # Initially only the recommended are true - }) + logger.debug("Mapping found with ipaddress for {}".format(str(map_object))) + current_mapping.append({ + 'dn': entry.get('domainName'), + 'ip': map_object.get('ipaddress'), + 'recommended': entry.get('recommended'), + 'enabled': entry.get('recommended') # Initially only the recommended are true + }) - apic_data = get_apic_data(tenant) for mapped_obj in current_mapping: for ep in apic_data: if ep.get('dn') == mapped_obj.get('dn'): @@ -98,9 +120,11 @@ def get_new_mapping(tenant, datacenter): logger.info('New mapping: {}'.format(str(current_mapping))) - already_mapped_data = list(db_obj.select_from_table(db_obj.MAPPING_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + already_mapped_data = list(db_obj.select_from_table(connection, db_obj.MAPPING_TABLE_NAME)) + connection.close() - logger.info('Mapping in db mapping: {}'.format(str(already_mapped_data))) logger.info('Mapping in db mapping: {}'.format(str(already_mapped_data))) new_map_list = [] @@ -108,40 +132,47 @@ def get_new_mapping(tenant, datacenter): # current_mapping is new mapping between aci and consul # already_mapped_data is previously stored mapping by user # if node is already disabled then disable it from new mappings also - for new_map in current_mapping: - for db_map in already_mapped_data: - if db_map[0] == new_map.get('ip') and db_map[1] == new_map.get('dn') and db_map[2] == datacenter: - new_map['enabled'] = db_map[3] # replace the enabled value with the one in db - break - - db_obj.insert_and_update(db_obj.MAPPING_TABLE_NAME, - ( - new_map.get('ip'), - new_map.get('dn'), - datacenter, - new_map.get('enabled'), - new_map.get('ap'), - new_map.get('bd'), - new_map.get('epg'), - new_map.get('vrf'), - tenant - ), - { - 'ip': new_map.get('ip'), - 'dn': new_map.get('dn'), - 'datacenter': datacenter - }) - - new_map_list.append((new_map.get('ip'), new_map.get('dn'))) + connection = db_obj.engine.connect() + with connection.begin(): + for new_map in current_mapping: + for db_map in already_mapped_data: + if db_map[0] == new_map.get('ip') and db_map[1] == new_map.get('dn') and db_map[2] == datacenter: + new_map['enabled'] = db_map[3] # replace the enabled value with the one in db + break + + db_obj.insert_and_update( + connection, + db_obj.MAPPING_TABLE_NAME, + ( + new_map.get('ip'), + new_map.get('dn'), + datacenter, + new_map.get('enabled'), + new_map.get('ap'), + new_map.get('bd'), + new_map.get('epg'), + new_map.get('vrf'), + tenant + ), + { + 'ip': new_map.get('ip'), + 'dn': new_map.get('dn'), + 'datacenter': datacenter + }) - for mapping in already_mapped_data: - if mapping[2] == datacenter and (mapping[0], mapping[1]) not in new_map_list: - db_obj.delete_from_table(db_obj.MAPPING_TABLE_NAME, { - 'ip': mapping[0], - 'dn': mapping[1], - 'datacenter': mapping[2] - }) + new_map_list.append((new_map.get('ip'), new_map.get('dn'))) + connection.close() + connection = db_obj.engine.connect() + with connection.begin(): + for mapping in already_mapped_data: + if mapping[2] == datacenter and (mapping[0], mapping[1]) not in new_map_list: + db_obj.delete_from_table(connection, db_obj.MAPPING_TABLE_NAME, { + 'ip': mapping[0], + 'dn': mapping[1], + 'datacenter': mapping[2] + }) + connection.close() return current_mapping except Exception as e: @@ -149,16 +180,25 @@ def get_new_mapping(tenant, datacenter): return [] - +@time_it def mapping(tenant, datacenter): - """Returns mapping to UI and saves recommended mapping to db""" + """Returns mapping to UI and saves recommended mapping to db + + :tenant: tenant for APIC data + :datacenter: datacenter for Consul data + + return: { + payload: list of mapped Nodes/{} + status_code: string: 200/300 + message: string + } + """ try: current_mapping = get_new_mapping(tenant, datacenter) - + return json.dumps({ - "agentIP": '', - "payload": current_mapping, # REturn current mapping + "payload": current_mapping, # Return current mapping "status_code": "200", "message": "OK" }) @@ -170,9 +210,21 @@ def mapping(tenant, datacenter): "message": "Could not load mapping" }) + @time_it def save_mapping(tenant, datacenter, mapped_data): - """Save mapping to database""" + """Save mapping to database + + :tenant: tenant for APIC data + :datacenter: datacenter for Consul data + :mapped_data: mapping from UI + + return: { + payload: "Saved Mappings"/{} + status_code: string: 200/300 + message: string + } + """ try: logger.info("Saving mappings for datacenter : " + str(datacenter)) @@ -180,56 +232,53 @@ def save_mapping(tenant, datacenter, mapped_data): mapped_data = mapped_data.replace("'", '"') mapped_data_dict = json.loads(mapped_data) - for mapping in mapped_data_dict: - db_obj.insert_and_update(db_obj.MAPPING_TABLE_NAME, - ( - mapping.get('ip'), - mapping.get('dn'), - datacenter, - mapping.get('enabled'), - mapping.get('ap'), - mapping.get('bd'), - mapping.get('vrf'), - tenant - ), - { - 'ip': mapping.get('ip'), - 'dn': mapping.get('dn'), - 'datacenter': datacenter - }) + connection = db_obj.engine.connect() + with connection.begin(): + for mapping in mapped_data_dict: + db_obj.insert_and_update( + connection, + db_obj.MAPPING_TABLE_NAME, + ( + mapping.get('ip'), + mapping.get('dn'), + datacenter, + mapping.get('enabled'), + mapping.get('ap'), + mapping.get('bd'), + mapping.get('vrf'), + tenant + ), + { + 'ip': mapping.get('ip'), + 'dn': mapping.get('dn'), + 'datacenter': datacenter + }) + connection.close() - return json.dumps({"payload": "Saved Mappings", "status_code": "200", "message": "OK"}) + return json.dumps({ + "payload": "Saved Mappings", + "status_code": "200", + "message": "OK" + }) except Exception as e: - logger.exception("Could not save mappings to the database. Error: "+str(e)) - return json.dumps({"payload": {}, "status_code": "300", "message": "Could not save mappings to the database."}) - - -def parse_mapping_before_save(already_mapped_data, data_list): - """ - Set disabled value true if user has disabled particular node manually. - """ - for previous_mapping in already_mapped_data: - is_node_exist = False - for current_mapping in data_list: - if current_mapping.get('ipaddress') == previous_mapping.get('ipaddress') and current_mapping.get('domainName') == previous_mapping.get('domainName'): - is_node_exist = True - break - - # Append removed node by user as disabled - if not is_node_exist: - previous_mapping['disabled'] = True - data_list.append(previous_mapping) + logger.exception("Could not save mappings to the database. Error: {}".format(str(e))) + return json.dumps({ + "payload": {}, + "status_code": "300", + "message": "Could not save mappings to the database." + }) - return data_list @time_it def tree(tenant, datacenter): """Get correlated Tree view data. + :tenant: tenant for APIC data + :datacenter: datacenter for Consul data + return: { - agentIP: string payload: list of tree(dict)/{} - status_code: string: 200/300 + status_code: string: 200/300 message: string } """ @@ -248,7 +297,6 @@ def tree(tenant, datacenter): logger.debug("Final Tree data: {}".format(response)) return json.dumps({ - "agentIP": '', "payload": response, "status_code": "200", "message": "OK" @@ -258,10 +306,91 @@ def tree(tenant, datacenter): return json.dumps({ "payload": {}, "status_code": "300", - "message": "Could not load the View." + "message": "Could not load the Tree." + }) + + +@time_it +def details_flattened(tenant, datacenter): + """Get correlated Details view data + + :tenant: tenant for APIC data + :datacenter: datacenter for Consul data + + return: { + payload: list of dict/{} + status_code: string: 200/300 + message: string + } + """ + + logger.info("Details view for tenant: {}".format(tenant)) + try: + aci_consul_mappings = get_new_mapping(tenant, datacenter) + + apic_data = get_apic_data(tenant) + consul_data = get_consul_data(datacenter) + merged_data = merge.merge_aci_consul(tenant, apic_data, consul_data, aci_consul_mappings) + + details_list = [] + for each in merged_data: + ep = { + 'interface': each.get('Interfaces'), + 'endPointName': each.get('VM-Name'), + 'ip': each.get('IP'), + 'mac': each.get('CEP-Mac'), + 'learningSource': each.get('learningSource'), + 'hostingServer': each.get('hostingServerName'), + 'reportingController': each.get('controllerName'), + 'vrf': each.get('VRF'), + 'bd': each.get('BD'), + 'ap': each.get('AppProfile'), + 'epgName': each.get('EPG'), + 'epgHealth': int(each.get('epg_health')), + 'consulNode': each.get('node_name'), + 'nodeChecks': each.get('node_check'), + } + + services = change_key(each.get('node_services')) + if not services: + services.append({ + 'service': '', + 'serviceInstance': '', + 'port': '', + 'serviceTags': [], + 'serviceKind': '', + 'serviceNamespace': '', + 'serviceChecks': {} + }) + for service in services: + record = {} + record.update(ep) + record.update(service) + details_list.append(record) + logger.debug("Details final data ended: " + str(details_list)) + + return json.dumps({ + "payload": details_list, + "status_code": "200", + "message": "OK" + }) + except Exception as e: + logger.exception("Could not load the Details. Error: {}".format(str(e))) + return json.dumps({ + "payload": {}, + "status_code": "300", + "message": "Could not load the Details." }) + def change_key(services): + """Function used for changing as per the UI + + :services: list of services + + return: list of services with changed keys + """ + final_list = [] if services: for service in services: @@ -281,18 +410,26 @@ def change_key(services): def get_service_check(service_name, service_id, datacenter): """Service checks with all detailed info + :service_name: service name + :service_id: service id + :datacenter: datacenter for Consul data + return: { - agentIP: string payload: list of dict/[] - status_code: string: 200/300 + status_code: string: 200/300 message: string - } + } """ logger.info("Service Check for service: {}, {}".format(service_name, service_id)) try: response = [] - service_checks_data = list(db_obj.select_from_table(db_obj.SERVICECHECKS_TABLE_NAME)) + + connection = db_obj.engine.connect() + with connection.begin(): + service_checks_data = list(db_obj.select_from_table(connection, db_obj.SERVICECHECKS_TABLE_NAME)) + connection.close() + for check in service_checks_data: if check[1] == service_id and check[2] == service_name: response.append({ @@ -305,10 +442,7 @@ def get_service_check(service_name, service_id, datacenter): 'Status': check[7] }) - logger.debug('Response of Service check: {}'.format(response)) - return json.dumps({ - "agentIP": '', "payload": response, "status_code": "200", "message": "OK" @@ -326,18 +460,24 @@ def get_service_check(service_name, service_id, datacenter): def get_node_checks(node_name, datacenter): """Node checks with all detailed info + :node_name: node name + :datacenter: datacenter for Consul data + return: { - agentIP: string payload: list of dict/[] - status_code: string: 200/300 + status_code: string: 200/300 message: string - } + } """ logger.info("Node Check for node: {}".format(node_name)) try: response = [] - node_checks_data = list(db_obj.select_from_table(db_obj.NODECHECKS_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + node_checks_data = list(db_obj.select_from_table(connection, db_obj.NODECHECKS_TABLE_NAME)) + connection.close() + for check in node_checks_data: if check[2] == node_name: response.append({ @@ -354,7 +494,6 @@ def get_node_checks(node_name, datacenter): logger.debug('Response of Node check: {}'.format(response)) return json.dumps({ - "agentIP": '', "payload": response, "status_code": "200", "message": "OK" @@ -372,12 +511,14 @@ def get_node_checks(node_name, datacenter): def get_multi_service_check(service_list, datacenter): """Service checks with all detailed info of multiple service + :service_list: list of servie id and service name + :datacenter: datacenter for Consul data + return: { - agentIP: string payload: list of dict/[] - status_code: string: 200/300 + status_code: string: 200/300 message: string - } + } """ logger.info("Service Checks for services: {}".format(service_list)) @@ -385,8 +526,10 @@ def get_multi_service_check(service_list, datacenter): try: service_list = json.loads(service_list) response = [] - service_checks_data = list(db_obj.select_from_table(db_obj.SERVICECHECKS_TABLE_NAME)) - + connection = db_obj.engine.connect() + with connection.begin(): + service_checks_data = list(db_obj.select_from_table(connection, db_obj.SERVICECHECKS_TABLE_NAME)) + connection.close() for service_dict in service_list: service_name = service_dict["Service"] @@ -404,7 +547,6 @@ def get_multi_service_check(service_list, datacenter): }) return json.dumps({ - "agentIP": '', "payload": response, "status_code": "200", "message": "OK" @@ -422,18 +564,23 @@ def get_multi_service_check(service_list, datacenter): def get_multi_node_check(node_list, datacenter): """Node checks with all detailed info of multiple Node + :node_list: list of node name + :datacenter: datacenter for Consul data + return: { - agentIP: string payload: list of dict/[] - status_code: string: 200/300 + status_code: string: 200/300 message: string - } + } """ logger.info("Node Checks for nodes: {}".format(node_list)) response = [] try: - node_checks_data = list(db_obj.select_from_table(db_obj.NODECHECKS_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + node_checks_data = list(db_obj.select_from_table(connection, db_obj.NODECHECKS_TABLE_NAME)) + connection.close() node_list = json.loads(node_list) @@ -452,7 +599,6 @@ def get_multi_node_check(node_list, datacenter): }) return json.dumps({ - "agentIP": '', "payload": response, "status_code": "200", "message": "OK" @@ -470,6 +616,14 @@ def get_multi_node_check(node_list, datacenter): def get_faults(dn): """ Get List of Faults from APIC related to the given Modular object. + + :dn: dn of epg + + return: { + payload: list of dict/[] + status_code: string: 200/300 + message: string + } """ aci_util_obj = apic_utils.AciUtils() faults_resp = aci_util_obj.get_ap_epg_faults(dn) @@ -506,6 +660,14 @@ def get_faults(dn): def get_events(dn): """ Get List of Events related to the given MO. + + :dn: dn of epg + + return: { + payload: list of dict/[] + status_code: string: 200/300 + message: string + } """ aci_util_obj = apic_utils.AciUtils() events_resp = aci_util_obj.get_ap_epg_events(dn) @@ -542,8 +704,15 @@ def get_events(dn): def get_audit_logs(dn): """ Get List of Audit Log Records related to the given MO. - """ + :dn: dn of epg + + return: { + payload: list of dict/[] + status_code: string: 200/300 + message: string + } + """ aci_util_obj = apic_utils.AciUtils() audit_logs_resp = aci_util_obj.get_ap_epg_audit_logs(dn) @@ -576,7 +745,21 @@ def get_audit_logs(dn): @time_it -def get_children_ep_info(dn, mo_type, mac_list): +def get_children_ep_info(dn, mo_type, mac_list, ip): + """ + Get Operational for EP and Client EP for EPG + + :dn: dn of epg + :mo_type: ep/epg + :mac_list: mac list of EP + :ip: ip in case of ep/"" + + return: { + payload: list of dict/[] + status_code: string: 200/300 + message: string + } + """ aci_util_obj = apic_utils.AciUtils() if mo_type == "ep": mac_list = mac_list.split(",") @@ -586,12 +769,12 @@ def get_children_ep_info(dn, mo_type, mac_list): mac_query_filter = ",".join(mac_query_filter_list) ep_info_query_string = 'query-target=children&target-subtree-class=fvCEp&query-target-filter=or(' + \ - mac_query_filter + \ - ')&rsp-subtree=children&rsp-subtree-class=fvRsHyper,fvRsCEpToPathEp,fvRsToVm' + mac_query_filter + ')&rsp-subtree=children&rsp-subtree-class=fvRsHyper,fvRsCEpToPathEp,fvRsToVm' elif mo_type == "epg": - ep_info_query_string = 'query-target=children&target-subtree-class=fvCEp&rsp-subtree=children&rsp-subtree-class=fvRsHyper,fvRsCEpToPathEp,fvRsToVm' + ep_info_query_string = 'query-target=children&target-subtree-class=fvCEp&rsp-subtree=children&rsp-subtree-class=fvRsHyper,fvRsCEpToPathEp,fvRsToVm,fvIp' ep_list = aci_util_obj.get_mo_related_item(dn, ep_info_query_string, "") + logger.debug('=Data returned by API call for get_children: {}'.format(str(len(ep_list)))) ep_info_list = [] try: for ep in ep_list: @@ -605,8 +788,18 @@ def get_children_ep_info(dn, mo_type, mac_list): if mcast_addr == "not-applicable": mcast_addr = "---" + if mo_type == "ep": + cep_ip = ip + elif mo_type == "epg": + ip_set = set() + for eachip in ep_children: + if eachip.keys()[0] == 'fvIp': + ip_set.add(str(eachip.get('fvIp').get('attributes').get('addr'))) + ip_set.add(ep_attr.get('ip')) + cep_ip = ', '.join(ip_set) + ep_info_dict = { - "ip": ep_attr.get("ip"), + "ip": cep_ip, "mac": ep_attr.get("mac"), "mcast_addr": mcast_addr, "learning_source": ep_attr.get("lcC"), @@ -623,21 +816,34 @@ def get_children_ep_info(dn, mo_type, mac_list): "payload": ep_info_list }) except Exception as e: - logger.exception( - "Exception while getting Children Ep Info : " + str(e)) + logger.exception("Exception while getting Children Ep Info : " + str(e)) return json.dumps({ "status_code": "300", - "message": {'errors': str(e)}, + "message": "Could not get Operational info", "payload": [] }) @time_it def get_configured_access_policies(tn, ap, epg): + """ + Get config access policy + + :tn: tenant for APIC + :ap: Application Policy + :epg: End Point Group + + return: { + payload: list of dict/[] + status_code: string: 200/300 + message: string + } + """ aci_util_obj = apic_utils.AciUtils() cap_url = "/mqapi2/deployment.query.json?mode=epgtoipg&tn=" + \ tn + "&ap=" + ap + "&epg=" + epg cap_resp = aci_util_obj.get_mo_related_item("", cap_url, "other_url") + logger.debug('=Data returned by API call for config access policy: {}'.format(str(len(cap_resp)))) cap_list = [] try: for cap in cap_resp: @@ -715,26 +921,24 @@ def get_configured_access_policies(tn, ap, epg): return json.dumps({ "status_code": "200", - "message": "", + "message": "Ok", "payload": cap_list }) except Exception as ex: + logger.exception("Exception while getting config access policy: " + str(ex)) return json.dumps({ "status_code": "300", - "message": {'errors': str(ex)}, + "message": "Could not get Configured access policies", "payload": [] }) + def get_to_epg(dn): - """Function to get TO_EPG from dn + """Function to get TO_EPG from dn - Arguments: - dn {str} -- domain name str - eg: "uni/tn-Tenant1/ap-AppProfile1/epg-EPG1" + :dn: dn of EPG(uni/tn-Tenant1/ap-AppProfile1/epg-EPG1) - Returns: - str -- TO EPG str - eg: Tenant1/AppProfile1/EPG1" + return: epg dn(Tenant1/AppProfile1/EPG1) """ epg = '' tn = '' @@ -763,28 +967,53 @@ def get_to_epg(dn): to_epg = tn + "/" + ap + "/" + epg return to_epg + @time_it def get_subnets(dn): """ Gets the Subnets Information for an EPG + + :dn: epg dn + + return: { + payload: list of dict/[] + status_code: string: 200/300 + message: string + } """ aci_util_obj = apic_utils.AciUtils() - subnet_query_string = "query-target=children&target-subtree-class=fvSubnet" - subnet_resp = aci_util_obj.get_mo_related_item(dn, subnet_query_string, "") - subnet_list = [] try: - for subnet in subnet_resp: - subnet_dict = { - "ip": "", - "to_epg": "", - "epg_alias": "" - } - subnet_attr = subnet.get("fvSubnet").get("attributes") - dn = subnet_attr.get("dn") - subnet_dict["to_epg"] = get_to_epg(dn) - subnet_dict["ip"] = subnet_attr["ip"] - subnet_dict["epg_alias"] = subnet_attr.get("nameAlias", "") - subnet_list.append(subnet_dict) + epg_traffic_query_string = 'query-target-filter=eq(vzFromEPg.epgDn,"' + dn + \ + '")&rsp-subtree=full&rsp-subtree-class=vzToEPg,vzRsRFltAtt,vzCreatedBy&rsp-subtree-include=required' + epg_traffic_resp = aci_util_obj.get_all_mo_instances("vzFromEPg", epg_traffic_query_string) + logger.debug("=Data returned by API call for to epg traffic {}".format(str(len(epg_traffic_resp)))) + + to_epg_set = set() + + for epg_traffic in epg_traffic_resp: + to_epg_children = epg_traffic["vzFromEPg"]["children"] + for to_epg_child in to_epg_children: + vz_to_epg_child = to_epg_child["vzToEPg"] + to_epg_dn = vz_to_epg_child["attributes"]["epgDn"] + flt_attr_children = vz_to_epg_child["children"] + for flt_attr in flt_attr_children: + to_epg_set.add(to_epg_dn) + + subnet_list = [] + for epg in to_epg_set: + subnet_resp = aci_util_obj.get_mo_related_item(epg, "query-target=children&target-subtree-class=fvSubnet", "") + for subnet in subnet_resp: + subnet_dict = { + "ip": "", + "to_epg": "", + "epg_alias": "" + } + subnet_attr = subnet.get("fvSubnet").get("attributes") + dn = subnet_attr.get("dn") + subnet_dict["to_epg"] = get_to_epg(dn) + subnet_dict["ip"] = subnet_attr["ip"] + subnet_dict["epg_alias"] = get_epg_alias(dn.split('/subnet')[0]) + subnet_list.append(subnet_dict) return json.dumps({ "status_code": "200", @@ -792,9 +1021,10 @@ def get_subnets(dn): "payload": subnet_list }) except Exception as ex: + logger.exception("Exception while getting subnets: " + str(ex)) return json.dumps({ "status_code": "300", - "message": str(ex), + "message": "Could not get subnets", "payload": [] }) @@ -803,123 +1033,126 @@ def get_subnets(dn): def get_to_epg_traffic(epg_dn): """ Gets the Traffic Details from the given EPG to other EPGs + + :epg_dn: epg dn + + return: { + payload: list of dict/[] + status_code: string: 200/300 + message: string + } """ aci_util_obj = apic_utils.AciUtils() epg_traffic_query_string = 'query-target-filter=eq(vzFromEPg.epgDn,"' + epg_dn + \ '")&rsp-subtree=full&rsp-subtree-class=vzToEPg,vzRsRFltAtt,vzCreatedBy&rsp-subtree-include=required' - epg_traffic_resp = aci_util_obj.get_all_mo_instances( - "vzFromEPg", epg_traffic_query_string) - if epg_traffic_resp: - - from_epg_dn = epg_dn - - to_epg_traffic_list = [] - to_epg_traffic_set = set() - - try: - for epg_traffic in epg_traffic_resp: - to_epg_children = epg_traffic["vzFromEPg"]["children"] - epg_alias = epg_traffic.get("vzFromEPg", {}).get("attributes", {}).get("nameAlias", "") - type_mapping = {'prov': "Provider", 'cons': "Consumer"} - contract_type = epg_traffic.get("vzFromEPg", {}).get("attributes", {}).get("membType", "") - contract_type = type_mapping.get(contract_type, contract_type) - for to_epg_child in to_epg_children: - - vz_to_epg_child = to_epg_child["vzToEPg"] - to_epg_dn = vz_to_epg_child["attributes"]["epgDn"] - parsed_to_epg_dn = get_to_epg(to_epg_dn) - - flt_attr_children = vz_to_epg_child["children"] - for flt_attr in flt_attr_children: - to_epg_traffic_dict = { - "to_epg": parsed_to_epg_dn, - "contract_subj": "", - "filter_list": [], - "ingr_pkts": "", - "egr_pkts": "", - "epg_alias": epg_alias, - "contract_type": "", - "type": contract_type - } - - flt_attr_child = flt_attr["vzRsRFltAtt"] - flt_attr_tdn = flt_attr_child["attributes"]["tDn"] - - traffic_id = parsed_to_epg_dn + "||" + flt_attr_tdn + "||" + contract_type - - # Check if we have already encountered the filter for a particular destination EPG - if traffic_id in to_epg_traffic_set: - to_epg_traffic_set.add(traffic_id) - continue - if re.search("/fp-", flt_attr_tdn): - flt_name = flt_attr_tdn.split("/fp-")[1] - else: - logger.error("filter not found") - flt_name = '' - flt_attr_subj_dn = flt_attr_child["children"][0]["vzCreatedBy"]["attributes"]["ownerDn"] - if re.search("/rssubjFiltAtt-", flt_attr_subj_dn): - subj_dn = flt_attr_subj_dn.split( - "/rssubjFiltAtt-")[0] - else: - logger.error("filter attribute subject not found") - subj_dn = '' - if re.search("/tn-", flt_attr_subj_dn): - subj_tn = flt_attr_subj_dn.split( - "/tn-")[1].split("/")[0] - else: - logger.error( - "filter attribute subject dn not found") - subj_tn = '' - - if re.search("/brc-", flt_attr_subj_dn): - subj_ctrlr = flt_attr_subj_dn.split( - "/brc-")[1].split("/")[0] - else: - logger.error("filter attribute ctrlr not found") - subj_ctrlr = '' - - if re.search("/subj-", flt_attr_subj_dn): - subj_name = flt_attr_subj_dn.split( - "/subj-")[1].split("/")[0] - else: - logger.error( - "filter attribute subj_name not found") - subj_name = '' - - contract_subject = subj_tn + "/" + subj_ctrlr + "/" + subj_name - flt_list = get_filter_list(flt_attr_tdn, aci_util_obj) - ingr_pkts, egr_pkts = get_ingress_egress( - from_epg_dn, to_epg_dn, subj_dn, flt_name, aci_util_obj) - - to_epg_traffic_dict["contract_subj"] = contract_subject - to_epg_traffic_dict["filter_list"] = flt_list - to_epg_traffic_dict["ingr_pkts"] = ingr_pkts - to_epg_traffic_dict["egr_pkts"] = egr_pkts + epg_traffic_resp = aci_util_obj.get_all_mo_instances("vzFromEPg", epg_traffic_query_string) + logger.debug("=Data returned by API call for to epg traffic {}".format(str(len(epg_traffic_resp)))) + from_epg_dn = epg_dn + to_epg_traffic_list = [] + to_epg_traffic_set = set() + try: + for epg_traffic in epg_traffic_resp: + to_epg_children = epg_traffic["vzFromEPg"]["children"] + for to_epg_child in to_epg_children: + + vz_to_epg_child = to_epg_child["vzToEPg"] + to_epg_dn = vz_to_epg_child["attributes"]["epgDn"] + parsed_to_epg_dn = get_to_epg(to_epg_dn) + def_dn = vz_to_epg_child["attributes"]["epgDefDn"] + contract_type = "" + if re.search("/cons-", def_dn): + contract_type = "Consumer" + elif re.search("/prov-", def_dn): + contract_type = "Provider" + elif re.search("/intra-", def_dn): + contract_type = "Intra EPG" + else: + logger.error("Contract type not prov/cons/intra") + + flt_attr_children = vz_to_epg_child["children"] + for flt_attr in flt_attr_children: + to_epg_traffic_dict = { + "to_epg": parsed_to_epg_dn, + "contract_subj": "", + "filter_list": [], + "ingr_pkts": "", + "egr_pkts": "", + "alias": get_epg_alias(to_epg_dn), + "contract_type": "", + "type": contract_type + } + flt_attr_child = flt_attr["vzRsRFltAtt"] + flt_attr_tdn = flt_attr_child["attributes"]["tDn"] + + traffic_id = parsed_to_epg_dn + "||" + flt_attr_tdn + "||" + contract_type + + # Check if we have already encountered the filter for a particular destination EPG + if traffic_id in to_epg_traffic_set: to_epg_traffic_set.add(traffic_id) - to_epg_traffic_list.append(to_epg_traffic_dict) + continue + if re.search("/fp-", flt_attr_tdn): + flt_name = flt_attr_tdn.split("/fp-")[1] + else: + logger.error("filter not found") + flt_name = '' + flt_attr_subj_dn = flt_attr_child["children"][0]["vzCreatedBy"]["attributes"]["ownerDn"] + if re.search("/rssubjFiltAtt-", flt_attr_subj_dn): + subj_dn = flt_attr_subj_dn.split( + "/rssubjFiltAtt-")[0] + else: + logger.error("filter attribute subject not found") + subj_dn = '' + if re.search("/tn-", flt_attr_subj_dn): + subj_tn = flt_attr_subj_dn.split( + "/tn-")[1].split("/")[0] + else: + logger.error( + "filter attribute subject dn not found") + subj_tn = '' - return json.dumps({ - "status_code": "200", - "message": "", - "payload": to_epg_traffic_list - }) + if re.search("/brc-", flt_attr_subj_dn): + subj_ctrlr = flt_attr_subj_dn.split( + "/brc-")[1].split("/")[0] + else: + logger.error("filter attribute ctrlr not found") + subj_ctrlr = '' - except Exception as ex: - logger.exception( - "Exception while fetching To EPG Traffic List : \n" + str(ex)) + if re.search("/subj-", flt_attr_subj_dn): + subj_name = flt_attr_subj_dn.split( + "/subj-")[1].split("/")[0] + else: + logger.error( + "filter attribute subj_name not found") + subj_name = '' + + contract_subject = subj_tn + "/" + subj_ctrlr + "/" + subj_name + flt_list = get_filter_list(flt_attr_tdn, aci_util_obj) + ingr_pkts, egr_pkts = get_ingress_egress( + from_epg_dn, to_epg_dn, subj_dn, flt_name, aci_util_obj) + + to_epg_traffic_dict["contract_subj"] = contract_subject + to_epg_traffic_dict["filter_list"] = flt_list + to_epg_traffic_dict["ingr_pkts"] = ingr_pkts + to_epg_traffic_dict["egr_pkts"] = egr_pkts + + to_epg_traffic_set.add(traffic_id) + to_epg_traffic_list.append(to_epg_traffic_dict) + + return json.dumps({ + "status_code": "200", + "message": "", + "payload": to_epg_traffic_list + }) + + except Exception as ex: + logger.exception( + "Exception while fetching To EPG Traffic List : " + str(ex)) - return json.dumps({ - "status_code": "300", - "message": {'errors': str(ex)}, - "payload": [] - }) - else: - logger.error("Could not get Traffic Data related to EPG") return json.dumps({ "status_code": "300", - "message": "Exception while fetching Traffic Data related to EPG", + "message": "Could not get Traffic Data related to EPG", "payload": [] }) @@ -988,78 +1221,99 @@ def get_filter_list(flt_dn, aci_util_obj): return flt_list -def get_all_interfaces(interfaces): - interface_list = '' - for interface in interfaces: - if re.search("/pathep-\[", interface): - if interface_list != '': - interface_list += (', ' + - str(interface.split("/pathep-")[1][1:-1])) - else: - interface_list += str(interface.split("/pathep-")[1][1:-1]) - elif re.search("/pathgrp-", interface): - if interface_list != '': - interface_list += (', ' + - str(interface.split("/pathgrp-")[1][1:-1])+"(vmm)") - else: - interface_list += str(interface.split("/pathgrp-") - [1][1:-1]+"(vmm)") - else: - logger.error("Incompatible format of Interfaces found") - return interface_list - - @time_it def read_creds(): + """Returns list of all agents in DB with connection status + + return: { + payload: list of dict/[] + status_code: string: 200/300/301 + message: string + } + """ try: logger.info('Reading agents.') # handle db read failure, just pass empty list from there - agents = list(db_obj.select_from_table(db_obj.LOGIN_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + agents = list(db_obj.select_from_table(connection, db_obj.LOGIN_TABLE_NAME)) + connection.close() + if not agents: logger.info('Agents List Empty.') - return json.dumps({'payload': [], 'status_code': '300', 'message': 'Agents not found'}) + return json.dumps({'payload': [], 'status_code': '301', 'message': 'Agents not found'}) payload = [] - for agent in agents: - decoded_token = base64.b64decode(agent[3]).decode('ascii') - consul_obj = Consul(agent[0], agent[1], decoded_token, agent[2]) - status, message = consul_obj.check_connection() - - datacenter = '' - if status: - datacenter = consul_obj.datacenter() - if datacenter == '-': - datacenter = agent[5] - - if agent[4] != status or agent[5] != datacenter: - agent_val = (agent[0], agent[1], agent[2], agent[3], status, datacenter) - db_obj.insert_and_update(db_obj.LOGIN_TABLE_NAME, agent_val, {'agent_ip': agent[0], 'port': agent[1]}) - - payload.append({ - 'ip': agent[0], - 'port': agent[1], - 'protocol': agent[2], - 'token': agent[3], - 'status': status, - 'datacenter': datacenter - }) - logger.debug('Read creds response: {}'.format(str(payload))) - return json.dumps({'payload': payload, 'status_code': '200', 'message': 'OK'}) + connection = db_obj.engine.connect() + with connection.begin(): + for agent in agents: + decoded_token = base64.b64decode(agent[3]).decode('ascii') + consul_obj = Consul(agent[0], agent[1], decoded_token, agent[2]) + status, message = consul_obj.check_connection() + + datacenter = '' + if status: + datacenter = consul_obj.datacenter() + if datacenter == '-': + datacenter = agent[5] + + if agent[4] != status or agent[5] != datacenter: + agent_val = (agent[0], agent[1], agent[2], agent[3], status, datacenter) + db_obj.insert_and_update(connection, db_obj.LOGIN_TABLE_NAME, agent_val, {'agent_ip': agent[0], 'port': agent[1]}) + payload.append({ + 'ip': agent[0], + 'port': agent[1], + 'protocol': agent[2], + 'token': agent[3], + 'status': status, + 'datacenter': datacenter + }) + connection.close() + + logger.debug('Read creds response: {}'.format(str(payload))) + return json.dumps({ + 'payload': payload, + 'status_code': '200', + 'message': 'OK' + }) except Exception as e: logger.exception('Error in read credentials: ' + str(e)) - return json.dumps({'payload': [], 'status_code': '300', 'message': 'Could not load the credentials.'}) + return json.dumps({ + 'payload': [], + 'status_code': '300', + 'message': 'Could not load the credentials.' + }) @time_it def write_creds(new_agent): + """Writes an Agent to DB and returns it status + to UI with encripted token + + :new_agent: list agent with one agent in it + + return: { + payload: list of dict/[] + status_code: string: 200/300/301 + message: string + } + """ try: - new_agent = json.loads(new_agent)[0] # UI returns list of 1 object + new_agent = json.loads(new_agent)[0] # UI returns list of one object logger.info('Writing agent: {}:{}'.format(new_agent.get('ip'), str(new_agent.get('port')))) - agents = list(db_obj.select_from_table( - db_obj.LOGIN_TABLE_NAME, - {'agent_ip': new_agent.get('ip'), 'port': new_agent.get('port')})) + + connection = db_obj.engine.connect() + with connection.begin(): + agents = list(db_obj.select_from_table( + connection, + db_obj.LOGIN_TABLE_NAME, + { + 'agent_ip': new_agent.get('ip'), + 'port': new_agent.get('port') + })) + connection.close() if agents: message = 'Agent ' + new_agent.get('ip') + ':' + str(new_agent.get('port')) + ' already exists.' @@ -1079,27 +1333,54 @@ def write_creds(new_agent): new_agent['status'] = status new_agent['token'] = base64.b64encode(new_agent['token'].encode('ascii')).decode('ascii') - db_obj.insert_into_table(db_obj.LOGIN_TABLE_NAME, - [ new_agent.get('ip'), - new_agent.get('port'), - new_agent.get('protocol'), - new_agent.get('token'), - new_agent.get('status'), - new_agent.get('datacenter') - ]) + connection = db_obj.engine.connect() + with connection.begin(): + db_obj.insert_into_table( + connection, + db_obj.LOGIN_TABLE_NAME, + [ + new_agent.get('ip'), + new_agent.get('port'), + new_agent.get('protocol'), + new_agent.get('token'), + new_agent.get('status'), + new_agent.get('datacenter') + ]) + connection.close() if status: - return json.dumps({'payload': new_agent, 'status_code': '200', 'message': 'OK'}) + return json.dumps({ + 'payload': new_agent, + 'status_code': '200', + 'message': 'OK' + }) else: - return json.dumps({'payload': new_agent, 'status_code': '301', 'message': str(message)}) - + return json.dumps({ + 'payload': new_agent, + 'status_code': '301', + 'message': str(message) + }) except Exception as e: logger.exception('Error in write credentials: ' + str(e)) - return json.dumps({'payload': [], 'status_code': '300', 'message': 'Could not write the credentials.'}) + return json.dumps({ + 'payload': [], + 'status_code': '300', + 'message': 'Could not write the credentials.' + }) @time_it def update_creds(update_input): + """Update an Agent to DB and returns it status to UI + + :update_input: json with old agents data and new agents data + + return: { + payload: list of dict/[] + status_code: string: 200/300/301 + message: string + } + """ try: logger.info('Updating agent: {}'.format(update_input)) @@ -1107,23 +1388,32 @@ def update_creds(update_input): old_agent = update_input.get('oldData') new_agent = update_input.get('newData') - agents = list(db_obj.select_from_table( - db_obj.LOGIN_TABLE_NAME).fetchall()) + connection = db_obj.engine.connect() + with connection.begin(): + agents = list(db_obj.select_from_table(connection, db_obj.LOGIN_TABLE_NAME)) + connection.close() if not agents: logger.info('Agents List Empty.') return json.dumps({'payload': [], 'status_code': '300', 'message': 'Agents not found'}) if not (old_agent.get('ip') == new_agent.get('ip') and old_agent.get('port') == new_agent.get('port')): - new_agent_db_data = db_obj.select_from_table(db_obj.LOGIN_TABLE_NAME, - {'agent_ip': new_agent.get('ip'), 'port': new_agent.get('port')}) - new_agent_db_data = new_agent_db_data.fetchone() + connection = db_obj.engine.connect() + with connection.begin(): + new_agent_db_data = db_obj.select_from_table( + connection, + db_obj.LOGIN_TABLE_NAME, + { + 'agent_ip': new_agent.get('ip'), + 'port': new_agent.get('port') + }) + connection.close() if new_agent_db_data: message = 'Agent ' + \ new_agent.get('ip') + ':' + \ str(new_agent.get('port')) + ' already exists.' logger.error(message) return json.dumps({'payload': new_agent, 'status_code': '300', 'message': message}) - + for agent in agents: if old_agent.get('ip') == agent[0] and old_agent.get('port') == int(agent[1]): if new_agent.get('token') == agent[3]: @@ -1141,180 +1431,209 @@ def update_creds(update_input): new_agent['datacenter'] = datacenter new_agent['status'] = status new_agent['token'] = base64.b64encode(new_agent['token'].encode('ascii')).decode('ascii') - db_obj.insert_and_update(db_obj.LOGIN_TABLE_NAME, [new_agent.get('ip'), - new_agent.get('port'), - new_agent.get('protocol'), - new_agent.get('token'), - new_agent.get('status'), - new_agent.get('datacenter') - ], {'agent_ip': old_agent.get( - 'ip'), 'port': old_agent.get('port')}) + + connection = db_obj.engine.connect() + with connection.begin(): + db_obj.insert_and_update( + connection, + db_obj.LOGIN_TABLE_NAME, + [ + new_agent.get('ip'), + new_agent.get('port'), + new_agent.get('protocol'), + new_agent.get('token'), + new_agent.get('status'), + new_agent.get('datacenter') + ], + { + 'agent_ip': old_agent.get('ip'), + 'port': old_agent.get('port') + }) + connection.close() if status: - return json.dumps({'payload': new_agent, 'status_code': '200', 'message': 'OK'}) + return json.dumps({ + 'payload': new_agent, + 'status_code': '200', + 'message': 'OK' + }) else: - return json.dumps({'payload': new_agent, 'status_code': '301', 'message': message}) - + return json.dumps({ + 'payload': new_agent, + 'status_code': '301', + 'message': message + }) except Exception as e: logger.exception('Error in update credentials: ' + str(e)) - return json.dumps({'payload': [], 'status_code': '300', 'message': 'Could not update the credentials.'}) + return json.dumps({ + 'payload': [], + 'status_code': '300', + 'message': 'Could not update the credentials.' + }) @time_it def delete_creds(agent_data): + """Update an Agent to DB and returns it status to UI + + :update_input: json with old agents data and new agents data + + return: { + payload: list of dict/[] + status_code: string: 200/300/301 + message: string + } + """ try: logger.info('Deleting agent {}'.format(str(agent_data))) agent_data = json.loads(agent_data) # Agent deleted - result = db_obj.delete_from_table(db_obj.LOGIN_TABLE_NAME, {'agent_ip': agent_data.get('ip'), 'port': agent_data.get('port')}) + connection = db_obj.engine.connect() + with connection.begin(): + db_obj.delete_from_table(connection, db_obj.LOGIN_TABLE_NAME, {'agent_ip': agent_data.get('ip'), 'port': agent_data.get('port')}) + connection.close() logger.info('Agent {} deleted'.format(str(agent_data))) agent_dc = agent_data.get('datacenter') - agent_list = list(db_obj.select_from_table(db_obj.LOGIN_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + agent_list = list(db_obj.select_from_table(connection, db_obj.LOGIN_TABLE_NAME)) + connection.close() agent_list = [agent for agent in agent_list if agent[5] == agent_dc] if not agent_list: - mappings = list(db_obj.select_from_table(db_obj.MAPPING_TABLE_NAME)) - for mapping in mappings: - if mapping[2] == agent_dc: - db_obj.delete_from_table(db_obj.MAPPING_TABLE_NAME, { - 'ip': mapping[0], - 'dn': mapping[1], - 'datacenter': mapping[2] - }) + connection = db_obj.engine.connect() + with connection.begin(): + mappings = list(db_obj.select_from_table(connection, db_obj.MAPPING_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for mapping in mappings: + if mapping[2] == agent_dc: + db_obj.delete_from_table(connection, db_obj.MAPPING_TABLE_NAME, { + 'ip': mapping[0], + 'dn': mapping[1], + 'datacenter': mapping[2] + }) + connection.close() logger.info('Mapping for Datacenter {} deleted'.format(str(agent_dc))) # Delete all the data fetched by this agent agent_addr = agent_data.get('ip') + ':' + str(agent_data.get('port')) - + # Delete Node data wrt this agent - node_data = list(db_obj.select_from_table(db_obj.NODE_TABLE_NAME)) - for node in node_data: - agents = node[4] - if agent_addr not in agents: - continue - if len(agents) == 1: - db_obj.delete_from_table(db_obj.NODE_TABLE_NAME,{'node_id': node[0]}) - else: - node[4].remove(agent_addr) - db_obj.insert_and_update(db_obj.NODE_TABLE_NAME, node, {'node_id': node[0]}) + connection = db_obj.engine.connect() + with connection.begin(): + node_data = list(db_obj.select_from_table(connection, db_obj.NODE_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for node in node_data: + agents = node[4] + if agent_addr not in agents: + continue + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.NODE_TABLE_NAME, {'node_id': node[0]}) + else: + node[4].remove(agent_addr) + db_obj.insert_and_update(connection, db_obj.NODE_TABLE_NAME, node, {'node_id': node[0]}) + connection.close() logger.info('Agent {}\'s Node data deleted'.format(str(agent_addr))) # Delete Service data wrt this agent - service_data = list(db_obj.select_from_table(db_obj.SERVICE_TABLE_NAME)) - for service in service_data: - agents = service[10] - if agent_addr not in agents: - continue - if len(agents) == 1: - db_obj.delete_from_table(db_obj.SERVICE_TABLE_NAME,{'service_id': service[0],'node_id': service[1]}) - else: - service[10].remove(agent_addr) - db_obj.insert_and_update(db_obj.SERVICE_TABLE_NAME, service, {'service_id': service[0],'node_id': service[1]}) + connection = db_obj.engine.connect() + with connection.begin(): + service_data = list(db_obj.select_from_table(connection, db_obj.SERVICE_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for service in service_data: + agents = service[10] + if agent_addr not in agents: + continue + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.SERVICE_TABLE_NAME, {'service_id': service[0], 'node_id': service[1]}) + else: + service[10].remove(agent_addr) + db_obj.insert_and_update(connection, db_obj.SERVICE_TABLE_NAME, service, {'service_id': service[0], 'node_id': service[1]}) + connection.close() logger.info('Agent {}\'s Service data deleted'.format(str(agent_addr))) # Delete Node Check data wrt this agent - node_checks_data = list(db_obj.select_from_table(db_obj.NODECHECKS_TABLE_NAME)) - for node in node_checks_data: - agents = node[9] - if agent_addr not in agents: - continue - if len(agents) == 1: - db_obj.delete_from_table(db_obj.NODECHECKS_TABLE_NAME,{'check_id': node[0], 'node_id': node[1]}) - else: - node[9].remove(agent_addr) - db_obj.insert_and_update(db_obj.NODECHECKS_TABLE_NAME, node, {'check_id': node[0], 'node_id': node[1]}) + connection = db_obj.engine.connect() + with connection.begin(): + node_checks_data = list(db_obj.select_from_table(connection, db_obj.NODECHECKS_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for node in node_checks_data: + agents = node[9] + if agent_addr not in agents: + continue + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.NODECHECKS_TABLE_NAME, {'check_id': node[0], 'node_id': node[1]}) + else: + node[9].remove(agent_addr) + db_obj.insert_and_update(connection, db_obj.NODECHECKS_TABLE_NAME, node, {'check_id': node[0], 'node_id': node[1]}) + connection.close() logger.info('Agent {}\'s NodeChecks data deleted'.format(str(agent_addr))) # Delete Service Check data wrt this agent - service_checks_data = list(db_obj.select_from_table(db_obj.SERVICECHECKS_TABLE_NAME)) - for service in service_checks_data: - agents = service[8] - if agent_addr not in agents: - continue - if len(agents) == 1: - db_obj.delete_from_table(db_obj.SERVICECHECKS_TABLE_NAME,{'check_id': service[0],'service_id': service[1]}) - else: - service[8].remove(agent_addr) - db_obj.insert_and_update(db_obj.SERVICECHECKS_TABLE_NAME, service, {'check_id': service[0],'service_id': service[1]}) + connection = db_obj.engine.connect() + with connection.begin(): + service_checks_data = list(db_obj.select_from_table(connection, db_obj.SERVICECHECKS_TABLE_NAME)) + connection.close() + + connection = db_obj.engine.connect() + with connection.begin(): + for service in service_checks_data: + agents = service[8] + if agent_addr not in agents: + continue + if len(agents) == 1: + db_obj.delete_from_table(connection, db_obj.SERVICECHECKS_TABLE_NAME, {'check_id': service[0], 'service_id': service[1]}) + else: + service[8].remove(agent_addr) + db_obj.insert_and_update(connection, db_obj.SERVICECHECKS_TABLE_NAME, service, {'check_id': service[0], 'service_id': service[1]}) + connection.close() logger.info('Agent {}\'s ServiceChecks data deleted'.format(str(agent_addr))) # it is assumed that no delete call to db would fail - return json.dumps({'status_code': '200', 'message': 'OK'}) - except Exception as e: - logger.exception('Error in delete credentials: ' + str(e)) - return json.dumps({'payload': [], 'status_code': '300', 'message': 'Could not delete the credentials.'}) - - -@time_it -def details_flattened(tenant, datacenter): - """Get correlated Details view data - - return: { - agentIP: string - payload: list of dict/{} - status_code: string: 200/300 - message: string - } - """ - - logger.info("Details view for tenant: {}".format(tenant)) - try: - aci_consul_mappings = get_new_mapping(tenant, datacenter) - - apic_data = get_apic_data(tenant) - consul_data = get_consul_data(datacenter) - merged_data = merge.merge_aci_consul(tenant, apic_data, consul_data, aci_consul_mappings) - - details_list = [] - for each in merged_data: - ep = { - 'interface': each.get('Interfaces'), - 'endPointName': each.get('VM-Name'), - 'ip': each.get('IP'), - 'mac': each.get('CEP-Mac'), - 'learningSource': each.get('learningSource'), - 'hostingServer': each.get('hostingServerName'), - 'reportingController': each.get('controllerName'), - 'vrf': each.get('VRF'), - 'bd': each.get('BD'), - 'ap': each.get('AppProfile'), - 'epgName': each.get('EPG'), - 'epgHealth': int(each.get('epg_health')), - 'consulNode': each.get('node_name'), - 'nodeChecks': each.get('node_check'), - } - - services = change_key(each.get('node_services')) - for service in services: - record = {} - record.update(ep) - record.update(service) - details_list.append(record) - logger.debug("Details final data ended: " + str(details_list)) - return json.dumps({ - "agentIP": ' ', # send ip if needed - "payload": details_list, - "status_code": "200", - "message": "OK" - }) + 'status_code': '200', + 'message': 'OK' + }) except Exception as e: - logger.exception("Could not load the Details. Error: {}".format(str(e))) + logger.exception('Error in delete credentials: ' + str(e)) return json.dumps({ - "payload": {}, - "status_code": "300", - "message": "Could not load the Details." - }) + 'payload': [], + 'status_code': '300', + 'message': 'Could not delete the credentials.' + }) @time_it def get_datacenters(): + """Return list of datacenter with connection status + + return: [{ + datacenter: string: datacenter name + status: boolean: True(Connected)/False(Disconnected) + }] + """ logger.info('In get datacenters') datacenters = [] try: - agents = list(db_obj.select_from_table(db_obj.LOGIN_TABLE_NAME)) + connection = db_obj.engine.connect() + with connection.begin(): + agents = list(db_obj.select_from_table(connection, db_obj.LOGIN_TABLE_NAME)) + connection.close() + if agents: dc_list = {} for agent in agents: @@ -1338,18 +1657,47 @@ def get_datacenters(): ) logger.info("Datacenters found: {}".format(str(datacenters))) - return json.dumps({'payload': datacenters, 'status_code': '200', 'message': 'OK'}) + return json.dumps({ + 'payload': datacenters, + 'status_code': '200', + 'message': 'OK' + }) except Exception as e: logger.exception('Error in get datacenters: ' + str(e)) - return json.dumps({'payload': [], 'status_code': '300', 'message': 'Error in fetching datacenters.'}) + return json.dumps({ + 'payload': [], + 'status_code': '300', + 'message': 'Error in fetching datacenters.' + }) def post_tenant(tn): + """Put tenant in DB + + This returns the tenant name when the app is opened first time. + This helps fetch tenant specific data + + :tn: tenant name to be put into DB + + return: { + status: 200/300 + message: Ok/Tenant not saved + } + """ logger.info('Tenant received: {}'.format(str(tn))) try: - response = list(db_obj.select_from_table(db_obj.TENANT_TABLE_NAME, {'tenant': tn})) + connection = db_obj.engine.connect() + with connection.begin(): + response = list(db_obj.select_from_table(connection, db_obj.TENANT_TABLE_NAME, {'tenant': tn})) + connection.close() + if not response: - response = db_obj.insert_into_table(db_obj.TENANT_TABLE_NAME, [tn]) + + connection = db_obj.engine.connect() + with connection.begin(): + response = db_obj.insert_into_table(connection, db_obj.TENANT_TABLE_NAME, [tn]) + connection.close() + if not response: return json.dumps({'status_code': '300', 'message': 'Tenant not saved'}) return json.dumps({'status_code': '200', 'message': 'OK'}) @@ -1362,10 +1710,15 @@ def post_tenant(tn): def get_consul_data(datacenter): consul_data = [] services = [] - node_data = list(db_obj.select_from_table(db_obj.NODE_TABLE_NAME)) - service_data = list(db_obj.select_from_table(db_obj.SERVICE_TABLE_NAME)) - node_checks_data = list(db_obj.select_from_table(db_obj.NODECHECKS_TABLE_NAME)) - service_checks_data = list(db_obj.select_from_table(db_obj.SERVICECHECKS_TABLE_NAME)) + + connection = db_obj.engine.connect() + with connection.begin(): + node_data = list(db_obj.select_from_table(connection, db_obj.NODE_TABLE_NAME)) + service_data = list(db_obj.select_from_table(connection, db_obj.SERVICE_TABLE_NAME)) + node_checks_data = list(db_obj.select_from_table(connection, db_obj.NODECHECKS_TABLE_NAME)) + service_checks_data = list(db_obj.select_from_table(connection, db_obj.SERVICECHECKS_TABLE_NAME)) + connection.close() + for service in service_data: if service[9] != datacenter: continue @@ -1400,7 +1753,7 @@ def get_consul_data(datacenter): check_dict['failing'] += 1 else: check_dict['failing'] = 1 - service_dict['service_checks'] = check_dict + service_dict['service_checks'] = check_dict services.append(service_dict) for node in node_data: @@ -1412,7 +1765,7 @@ def get_consul_data(datacenter): 'node_ips': node[2], 'node_check': {}, 'node_services': [] - } + } for check in node_checks_data: if check[1] == node[0]: status = check[8] @@ -1444,8 +1797,13 @@ def get_consul_data(datacenter): @time_it def get_apic_data(tenant): apic_data = [] - ep_data = list(db_obj.select_from_table(db_obj.EP_TABLE_NAME)) - epg_data = list(db_obj.select_from_table(db_obj.EPG_TABLE_NAME)) + + connection = db_obj.engine.connect() + with connection.begin(): + ep_data = list(db_obj.select_from_table(connection, db_obj.EP_TABLE_NAME)) + epg_data = list(db_obj.select_from_table(connection, db_obj.EPG_TABLE_NAME)) + connection.close() + for ep in ep_data: if ep[2] != tenant: continue @@ -1480,11 +1838,16 @@ def get_agent_status(datacenter=""): Returns: dict: Response for agents """ - agents_res = {'up':0, 'down':0} - agents = list(db_obj.select_from_table(db_obj.LOGIN_TABLE_NAME)) + agents_res = {'up': 0, 'down': 0} + + connection = db_obj.engine.connect() + with connection.begin(): + agents = list(db_obj.select_from_table(connection, db_obj.LOGIN_TABLE_NAME)) + connection.close() + if not agents: logger.info('Agents List Empty.') - return agents_res + return agents_res for agent in agents: if datacenter: if datacenter == agent[5] and agent[4] == '1': @@ -1499,113 +1862,102 @@ def get_agent_status(datacenter=""): return agents_res -def get_service_status(ep_ips): - """Function to get status of service - - Args: - ep_ips (set): Set of EP IPs - - Returns: - dict: Dictionary with count of passing, warning and critical services - """ - service_res = {'passing': 0, 'warning':0, 'failing':0} - services = list(db_obj.select_from_table(db_obj.SERVICE_TABLE_NAME)) - service_checks = list(db_obj.select_from_table(db_obj.SERVICECHECKS_TABLE_NAME)) - if not service_checks: - logger.info("Service check is empty") - return service_res - for service in services: - service_ip = service[5].split(':')[0] - for service_check in service_checks: - if service[0] == service_check[1] and service_ip in ep_ips and service_check[7].lower(): - service_res[service_check[7].lower()] += 1 - break - - return service_res - +def add_check(add_check, add_to): + """Adds consul checks""" -def get_nodes_status(ep_ips): - """Function to get status of nodes - - Args: - ep_ips (set): Set of EP ips - - Returns: - dict: Dictionary with count of passing, warning and critical nodes - """ - nodes_res = {'passing': 0, 'warning':0, 'failing':0} - nodes = list(db_obj.select_from_table(db_obj.NODE_TABLE_NAME)) - node_checks = list(db_obj.select_from_table(db_obj.NODECHECKS_TABLE_NAME)) - if not node_checks: - logger.info("Node check is empty") - return nodes_res - - for node in nodes: - for node_ip in node[2]: - for node_check in node_checks: - if node[0] == node_check[1] and node_ip in ep_ips and node_check[8].lower(): - nodes_res[node_check[8].lower()] += 1 - break - return nodes_res - - -def get_service_endpoints(ep_ips, service_ips, node_ips): - """Function to return count of service and non service endpoint - - Args: - ep_ips (set): Set of EP IPS - service_ips (set): Set of Service IPS - node_ips (set): Set og node_ips - - Returns: - dict: Count of service and non service endpoint - """ - response = {'service':0, 'non_service':0} - response['non_service'] = len(ep_ips - service_ips - node_ips) - response['service'] = len(ep_ips) - response['non_service'] - - return response + for status, check_value in add_check.iteritems(): + add_to[status] += check_value @time_it def get_performance_dashboard(tn): """Function to get payload for performance dashboard - Args: - tn (str): Name of tenant + :tn: Name of tenant - Returns: - dict: Payload for performance dashboard + return: { + status: 200/300 + payload: response/{} + message: message + } """ try: response = {} - eps = list(db_obj.select_from_table(db_obj.EP_TABLE_NAME)) - services = list(db_obj.select_from_table(db_obj.SERVICE_TABLE_NAME)) - nodes = list(db_obj.select_from_table(db_obj.NODE_TABLE_NAME)) - ep_ips = set() - service_ips = set() - node_ips = set() - for ep in eps: - if ep[1] and ep[2] == tn: - ep_ips.add(ep[1]) - - for service in services: - if service[3]: - service_ips.add(service[3]) - for node in nodes: - if node[2]: - for ip in node[2]: - node_ips.add(ip) + connection = db_obj.engine.connect() + with connection.begin(): + ep_len = len(list(db_obj.select_from_table(connection, db_obj.EP_TABLE_NAME))) + connection.close() + + mapped_ep = {} + datacenters = json.loads(get_datacenters())['payload'] + for dc in datacenters: + datacenter = dc['datacenter'] + if datacenter not in mapped_ep: + mapped_ep[datacenter] = [] + + for dc in mapped_ep: + mapped_dc = get_new_mapping(tn, dc) + for map in mapped_dc: + mapped_ep[dc].append(map) + + apic_data = get_apic_data(tn) + ep_res = {'service': 0, 'non_service': 0} + service_res = {'passing': 0, 'warning': 0, 'failing': 0} + nodes_res = {'passing': 0, 'warning': 0, 'failing': 0} + ep_list = [] + node_ip_list = [] + service_addr_list = [] + for dc in mapped_ep: + consul_data = get_consul_data(dc) + merged_data = merge.merge_aci_consul(tn, apic_data, consul_data, mapped_ep[dc]) + + for ep in merged_data: + # Add service eps to ep_resp + if (ep['IP'], ep['dn']) not in ep_list: + ep_list.append((ep['IP'], ep['dn'])) + ep_res['service'] += 1 + + if ep['node_ips'][0] not in node_ip_list: + node_ip_list.append(ep['node_ips'][0]) + add_check(ep['node_check'], nodes_res) + + for service in ep['node_services']: + if service['service_address'] not in service_addr_list: + service_addr_list.append(service['service_address']) + add_check(service['service_checks'], service_res) + + ep_res['non_service'] = ep_len - ep_res['service'] response['agents'] = get_agent_status() - response['service'] = get_service_status(ep_ips) - response['nodes'] = get_nodes_status(ep_ips) - response['service_endpoint'] = get_service_endpoints(ep_ips, service_ips, node_ips) - # Send the agents - - return json.dumps({"status": "200", "payload": response, "message": "OK"}) + response['service'] = service_res + response['nodes'] = nodes_res + response['service_endpoint'] = ep_res + + return json.dumps({ + "status": "200", + "payload": response, + "message": "OK" + }) except Exception as e: - logger.exception("Exception occurred. \n Error: {}".format(e)) - return json.dumps({"status": "300", "payload": {}, "message":"Could not load performance data"}) + logger.exception("Exception occurred, Error: {}".format(e)) + return json.dumps({ + "status": "300", + "payload": {}, + "message": "Could not load performance data" + }) + + +def get_epg_alias(dn): + """This would return EPG alias from the db""" + + connection = db_obj.engine.connect() + with connection.begin(): + epg_data = list(db_obj.select_from_table(connection, db_obj.EPG_TABLE_NAME)) + connection.close() + + for epg in epg_data: + if dn == epg[0]: + return epg[8] + return "" diff --git a/ConsulExtension/Service/recommend_utils.py b/ConsulExtension/Service/recommend_utils.py index 8f316fb..285e85f 100644 --- a/ConsulExtension/Service/recommend_utils.py +++ b/ConsulExtension/Service/recommend_utils.py @@ -1,15 +1,14 @@ """""" -import copy import custom_logger logger = custom_logger.CustomLogger.get_logger("/home/app/log/app.log") def get_common_eps(source_ip_list, aci_parsed_eps): """Map EP(ACI) to Nodes(Consul) - + Matches the IP of ACI fvIp with Source Node IPs and returns a list of matched ACI fvIps dicts""" - + common_list = [] for each in aci_parsed_eps: if each['IP'] in source_ip_list: @@ -21,8 +20,8 @@ def extract(dn): """ Extract ap and epg from given dn """ - ap = dn.split('/')[2].split('-',1)[1] - epg = dn.split('/')[3].split('-',1)[1] + ap = dn.split('/')[2].split('-', 1)[1] + epg = dn.split('/')[3].split('-', 1)[1] return ap, epg @@ -31,86 +30,131 @@ def extract_ap_and_epgs(eps): for ep in eps: ap, epg = extract(ep['dn']) if ap not in count_dict.keys(): - count_dict[ap] = {epg:1} + count_dict[ap] = {epg: 1} elif epg not in count_dict[ap].keys(): count_dict[ap][epg] = 1 else: count_dict[ap][epg] += 1 + return count_dict -# returns a list of list -def determine_recommendation(extract_ap_epgs, common_eps): +def sort_eps(each): + if 'IP' in each: + return each['IP'] + else: + return each['mac'] + + +def extract_vrf(apic_data): + vrf_dict = {} + for each in apic_data: + vrf = each['VRF'] + dn = each['dn'] + key = 'IP' + if 'mac' in each: + key = 'mac' + if vrf in vrf_dict: + vrf_dict[vrf].add(dn + '|' + each[key]) + else: + vrf_dict[vrf] = {dn + '|' + each[key]} + + return vrf_dict + + +def search_ep_in_apic(apic_data, search_param): + for each in apic_data: + flag = False + for key, val in search_param.items(): + # logger.debug(' key , val :'+key+' , '+val) + if key in each and each[key] == val: + # logger.debug(' Inside search and element found ') + flag = True + else: + break + if flag: + return each + return None + + +def determine_recommendation(extract_ap_epgs, common_eps, apic_data): + + common_eps = sorted(common_eps, key=sort_eps) + logger.debug('sorted eps {} '.format(common_eps)) + recommended_ep = common_eps[0] + del common_eps[0] + peers = [] + + rec_key = 'IP' + each_key = 'IP' recommendation_list = [] - for each in common_eps: - accounted = 0 - for duplicate in common_eps: - - key = 'IP' - dup_key = 'IP' - if 'mac' in each: - key = 'mac' - if 'mac' in duplicate: - dup_key = 'mac' - - # For different elements, if IP/Mac is same and 'dn' is different - if each[key] == duplicate[dup_key] and each['dn'] != duplicate['dn'] and common_eps.index(each) != common_eps.index(duplicate): - - # This is the condition when there are 2 CEp's - # EP1: CEp's child fvIp.addr = 1.1.1.1 - # EP2: CEp.ip = 1.1.1.1 - # Then the first one will be selected giving fvIp priority - if each.get('cep_ip', ''): - recommendation_list.append([each[key],each['dn'],'No',key]) - break - if duplicate.get('cep_ip', ''): - recommendation_list.append([each[key],each['dn'],'Yes',key]) - break - - ap_main,epg_main = extract(each['dn']) - ap_dup,epg_dup = extract(duplicate['dn']) - - # Compare count of 'EPG' for an 'AP' - main_count = extract_ap_epgs[ap_main][epg_main] - dup_count = extract_ap_epgs[ap_dup][epg_dup] - # recommendation logic - # first compare the number of EPG in an application profile in which the EP belong - # recommend the EP with highest EPG count - # if the count is same then consider the count of EP in EPG in which the EP belong - # recommend the EP with highest EP count - # If both of the counts are same then the EP with fvIP is given priority - - if main_count > dup_count: - recommendation_list.append([each[key],each['dn'],'Yes',key]) - break - elif main_count == dup_count: - ap_main_c = len(extract_ap_epgs[ap_main]) - ap_dup_c = len(extract_ap_epgs[ap_dup]) - # Add one with more number of Epgs - if ap_main_c > ap_dup_c: - recommendation_list.append([each[key],each['dn'],'Yes',key]) - break - elif ap_main_c < ap_dup_c: - recommendation_list.append([each[key],each['dn'],'No',key]) - break - else: - recommendation_list.append([each[key],each['dn'],'None',key]) + + extracted_vrfs = extract_vrf(apic_data) + logger.debug('extracted vrfs {} '.format(extracted_vrfs)) + + for i in range(len(common_eps)): + each = common_eps[i] + ap_rec, epg_rec = extract(recommended_ep['dn']) + ap_each, epg_each = extract(each['dn']) + + ap_rec_count = len(extract_ap_epgs[ap_rec]) + ap_each_count = len(extract_ap_epgs[ap_each]) + + epg_rec_count = extract_ap_epgs[ap_rec][epg_rec] + epg_each_count = extract_ap_epgs[ap_each][epg_each] + + if 'mac' in recommended_ep: + rec_key = 'mac' + if 'mac' in each: + each_key = 'mac' + + search_params_rec = {rec_key: recommended_ep[rec_key], 'dn': recommended_ep['dn']} + apic_rec = search_ep_in_apic(apic_data, search_params_rec)['VRF'] + + search_params_each = {rec_key: each[rec_key], 'dn': each['dn']} + apic_each = search_ep_in_apic(apic_data, search_params_each)['VRF'] + + # When we encounter the ep whose IP is different from the current recommended IP. + # We add all peers and recommended to recommended list as recommended + if recommended_ep[rec_key] != each[each_key]: + recommendation_list.append([recommended_ep[rec_key], recommended_ep['dn'], 'Yes', rec_key]) + for temp in peers: + recommendation_list.append([temp[rec_key], temp['dn'], 'Yes', rec_key]) + recommended_ep = each + peers = [] + continue + + if (recommended_ep['cep_ip'] and each['cep_ip']) or (not recommended_ep['cep_ip'] and not each['cep_ip']): + if apic_rec and apic_each and len(extracted_vrfs[apic_rec]) > len(extracted_vrfs[apic_each]): + recommendation_list.append([each[each_key], each['dn'], 'No', each_key]) + elif apic_rec and apic_each and len(extracted_vrfs[apic_rec]) < len(extracted_vrfs[apic_each]): + recommendation_list.append([recommended_ep[rec_key], recommended_ep['dn'], 'No', rec_key]) + recommended_ep = each + else: + if ap_rec_count > ap_each_count: + recommendation_list.append([each[each_key], each['dn'], 'No', each_key]) + elif ap_rec_count < ap_each_count: + recommendation_list.append([recommended_ep[rec_key], recommended_ep['dn'], 'No', rec_key]) + recommended_ep = each else: - recommendation_list.append([each[key],each['dn'],'No',key]) - elif each[key] != duplicate[dup_key] and each['dn'] != duplicate['dn'] and common_eps.index(each) != common_eps.index(duplicate) and any(each[key] in d for d in recommendation_list) != True: - recommendation_list.append([each[key],each['dn'],'None',key]) - elif accounted == 0: - recommendation_list.append([each[key],each['dn'],'None',key]) - accounted = 1 - - recommendation_set = set(map(tuple,recommendation_list)) - recommendation_list = map(list, recommendation_set) - temp_list = copy.deepcopy(recommendation_list) - for a in temp_list: - for b in temp_list: - # If same recommendation already exist with b[2] == 'None' than remove it. - if a[0] == b[0] and a[1] == b[1] and ((a[2] == 'Yes' or a[2] == 'No') and b[2] == 'None'): - recommendation_list.remove(b) + if epg_rec_count > epg_each_count: + recommendation_list.append([each[each_key], each['dn'], 'No', each_key]) + elif epg_rec_count < epg_each_count: + recommendation_list.append([recommended_ep[rec_key], recommended_ep['dn'], 'No', rec_key]) + recommended_ep = each + else: + peers.append(each) + elif recommended_ep.get('cep_ip', '') is False and each.get('cep_ip', ''): + recommendation_list.append([each[each_key], each['dn'], 'No', each_key]) + else: + recommendation_list.append([recommended_ep[rec_key], recommended_ep['dn'], 'No', rec_key]) + recommended_ep = each + + recommendation_list.append([recommended_ep[rec_key], recommended_ep['dn'], 'Yes', rec_key]) + + for temp in peers: + recommendation_list.append([temp[rec_key], temp['dn'], 'Yes', rec_key]) + return recommendation_list @@ -128,29 +172,29 @@ def generatelist(ip_list): macs.append(each[0]) ips = list(set(ips)) macs = list(set(macs)) - ip_dict = dict((el,[]) for el in ips) - mac_dict = dict((el,[]) for el in macs) + ip_dict = dict((el, []) for el in ips) + mac_dict = dict((el, []) for el in macs) for each in ip_list: if each[2] == 'No': each[2] = False if each[2] == 'Yes' or each[2] == 'None': each[2] = True if each[3] == 'IP': - ip_dict[each[0]].append({'domainName':each[1],'recommended':each[2]}) + ip_dict[each[0]].append({'domainName': each[1], 'recommended': each[2]}) else: - mac_dict[each[0]].append({'domainName':each[1],'recommended':each[2]}) - for key,value in ip_dict.iteritems(): - entry = {'ipaddress':key,'domains':value} + mac_dict[each[0]].append({'domainName': each[1], 'recommended': each[2]}) + for key, value in ip_dict.iteritems(): + entry = {'ipaddress': key, 'domains': value} src_clus_list.append(entry) - for key,value in mac_dict.iteritems(): - entry = {'macaddress':key,'domains':value} + for key, value in mac_dict.iteritems(): + entry = {'macaddress': key, 'domains': value} src_clus_list.append(entry) return src_clus_list -def recommended_eps(source_ip_list, parsed_eps): +def recommended_eps(source_ip_list, parsed_eps, apic_data): """This finds all the recommended EPs in APIC wrt the source data - + TODO: explain """ logger.info('Finding Recommended EPs for ACI and Consul') @@ -165,7 +209,7 @@ def recommended_eps(source_ip_list, parsed_eps): # Example of extracted Epg dn # "uni/tn-Tenant1/ap-AppProfile1/epg-Epg-test" for each in parsed_eps: - each['dn'] = '/'.join(each['dn'].split('/',4)[0:4]) + each['dn'] = '/'.join(each['dn'].split('/', 4)[0:4]) except Exception as e: logger.exception('Exception in parsed eps list, Error: ' + str(e)) return [] @@ -175,38 +219,38 @@ def recommended_eps(source_ip_list, parsed_eps): # Extract common based on Ips try: common_eps = get_common_eps(source_ip_list, parsed_eps) - logger.debug('Common EPs:'+str(common_eps)) + logger.debug('Common EPs: {}'.format(str(common_eps))) if common_eps: extract_ap_epgs = extract_ap_and_epgs(common_eps) else: return [] except Exception as e: - logger.exception('Exception in common eps list, Error:'+str(e)) + logger.exception('Exception in common eps list, Error: {}'.format(str(e))) return [] try: - rec_list = determine_recommendation(extract_ap_epgs,common_eps) + rec_list = determine_recommendation(extract_ap_epgs, common_eps, apic_data) except Exception as e: - logger.exception('Exception while determining recommended list, Error:'+str(e)) + logger.exception('Exception while determining recommended list, Error: {}'.format(str(e))) return [] if rec_list: - logger.info('Recommendation list: rec_list= '+str(rec_list)) - fin_list = set(map(tuple,rec_list)) - final_list = map(list,fin_list) - logger.info('Final List final_list '+str(final_list)) + logger.info('Recommendation list: rec_list {}'.format(str(rec_list))) + fin_list = set(map(tuple, rec_list)) + final_list = map(list, fin_list) + logger.info('Final List final_list {}'.format(str(final_list))) else: logger.info('Error: Empty rec_list ' + str(rec_list)) return [] - + try: generated_list = generatelist(final_list) except Exception as e: - logger.exception('Exception in generate list, Error:'+str(e)) + logger.exception('Exception in generate list, Error: {}'.format(str(e))) return [] - + if generated_list: - logger.info('Generated List = '+str(generated_list)) + logger.info('Generated List {}'.format(str(generated_list))) return generated_list else: logger.info('Error: Empty generated_list ' + str(generated_list)) diff --git a/ConsulExtension/Service/schema.py b/ConsulExtension/Service/schema.py index e97209b..c938b26 100644 --- a/ConsulExtension/Service/schema.py +++ b/ConsulExtension/Service/schema.py @@ -4,6 +4,7 @@ """Response Classes""" + class Mapping(graphene.ObjectType): mappings = graphene.String() @@ -82,7 +83,7 @@ class DeleteCreds(graphene.ObjectType): class DetailsFlattened(graphene.ObjectType): - details = graphene.String() + details = graphene.String() class GetDatacenters(graphene.ObjectType): @@ -92,6 +93,7 @@ class GetDatacenters(graphene.ObjectType): class PostTenant(graphene.ObjectType): tenant = graphene.String() + class GetPerformanceDashboard(graphene.ObjectType): response = graphene.String() @@ -99,16 +101,18 @@ class GetPerformanceDashboard(graphene.ObjectType): class Query(graphene.ObjectType): """Query class which resolves all the incoming requests""" - Mapping = graphene.Field(Mapping, - tn=graphene.String(), - datacenter=graphene.String()) + Mapping = graphene.Field(Mapping, + tn=graphene.String(), + datacenter=graphene.String()) - SaveMapping = graphene.Field(SaveMapping, - tn = graphene.String(), - datacenter = graphene.String(), - data = graphene.String()) + SaveMapping = graphene.Field(SaveMapping, + tn=graphene.String(), + datacenter=graphene.String(), + data=graphene.String()) - OperationalTree = graphene.Field(OperationalTree, tn=graphene.String(), datacenter=graphene.String()) + OperationalTree = graphene.Field(OperationalTree, + tn=graphene.String(), + datacenter=graphene.String()) GetFaults = graphene.Field(GetFaults, dn=graphene.String()) @@ -116,38 +120,39 @@ class Query(graphene.ObjectType): GetAuditLogs = graphene.Field(GetAuditLogs, dn=graphene.String()) - GetOperationalInfo = graphene.Field(GetOperationalInfo, - dn = graphene.String(), - mo_type = graphene.String(), - mac_list = graphene.String()) + GetOperationalInfo = graphene.Field(GetOperationalInfo, + dn=graphene.String(), + mo_type=graphene.String(), + mac_list=graphene.String(), + ip=graphene.String()) GetConfiguredAccessPolicies = graphene.Field(GetConfiguredAccessPolicies, - tn = graphene.String(), - ap = graphene.String(), - epg = graphene.String()) + tn=graphene.String(), + ap=graphene.String(), + epg=graphene.String()) - GetToEpgTraffic = graphene.Field(GetToEpgTraffic, dn = graphene.String()) + GetToEpgTraffic = graphene.Field(GetToEpgTraffic, dn=graphene.String()) - GetSubnets = graphene.Field(GetSubnets, dn = graphene.String()) + GetSubnets = graphene.Field(GetSubnets, dn=graphene.String()) - SetPollingInterval = graphene.Field(SetPollingInterval, interval = graphene.String()) + SetPollingInterval = graphene.Field(SetPollingInterval, interval=graphene.String()) ServiceChecks = graphene.Field(ServiceChecks, - service_name = graphene.String(), - service_id = graphene.String(), - datacenter = graphene.String()) + service_name=graphene.String(), + service_id=graphene.String(), + datacenter=graphene.String()) NodeChecks = graphene.Field(NodeChecks, - node_name=graphene.String(), - datacenter=graphene.String()) + node_name=graphene.String(), + datacenter=graphene.String()) MultiServiceChecks = graphene.Field(MultiServiceChecks, service_list=graphene.String(), datacenter=graphene.String()) MultiNodeChecks = graphene.Field(MultiNodeChecks, - node_list=graphene.String(), - datacenter=graphene.String()) + node_list=graphene.String(), + datacenter=graphene.String()) ReadCreds = graphene.Field(ReadCreds) @@ -157,127 +162,105 @@ class Query(graphene.ObjectType): DeleteCreds = graphene.Field(DeleteCreds, agent_data=graphene.String()) - DetailsFlattened = graphene.Field(DetailsFlattened, - tn=graphene.String(), + DetailsFlattened = graphene.Field(DetailsFlattened, + tn=graphene.String(), datacenter=graphene.String()) GetDatacenters = graphene.Field(GetDatacenters) PostTenant = graphene.Field(PostTenant, tn=graphene.String()) - GetPerformanceDashboard = graphene.Field(GetPerformanceDashboard, tn=graphene.String()) - + GetPerformanceDashboard = graphene.Field(GetPerformanceDashboard, + tn=graphene.String()) """All the resolve methods of class Query""" - def resolve_GetFaults(self, info, dn): GetFaults.faultsList = app.get_faults(dn) return GetFaults - def resolve_GetEvents(self, info, dn): GetEvents.eventsList = app.get_events(dn) return GetEvents - def resolve_GetAuditLogs(self, info, dn): GetAuditLogs.auditLogsList = app.get_audit_logs(dn) return GetAuditLogs - - def resolve_GetOperationalInfo(self, info, dn, mo_type, mac_list): - GetOperationalInfo.operationalList = app.get_children_ep_info(dn, mo_type, mac_list) + def resolve_GetOperationalInfo(self, info, dn, mo_type, mac_list, ip): + GetOperationalInfo.operationalList = app.get_children_ep_info(dn, mo_type, mac_list, ip) return GetOperationalInfo - def resolve_GetConfiguredAccessPolicies(self, info, tn, ap, epg): GetConfiguredAccessPolicies.accessPoliciesList = app.get_configured_access_policies(tn, ap, epg) return GetConfiguredAccessPolicies - def resolve_GetToEpgTraffic(self, info, dn): GetToEpgTraffic.toEpgTrafficList = app.get_to_epg_traffic(dn) return GetToEpgTraffic - def resolve_GetSubnets(self, info, dn): GetSubnets.subnetsList = app.get_subnets(dn) return GetSubnets - def resolve_SetPollingInterval(self, info, interval): status, message = app.set_polling_interval(interval) SetPollingInterval.status = status SetPollingInterval.message = message return SetPollingInterval - def resolve_Mapping(self, info, tn, datacenter): Mapping.mappings = app.mapping(tn, datacenter) return Mapping - def resolve_SaveMapping(self, info, tn, datacenter, data): mapped_data = data SaveMapping.savemapping = app.save_mapping(str(tn), str(datacenter), mapped_data) return SaveMapping - def resolve_OperationalTree(self, info, tn, datacenter): OperationalTree.response = app.tree(tn, datacenter) return OperationalTree - def resolve_ServiceChecks(self, info, service_name, service_id, datacenter): ServiceChecks.response = app.get_service_check(service_name, service_id, datacenter) return ServiceChecks - def resolve_NodeChecks(self, info, node_name, datacenter): NodeChecks.response = app.get_node_checks(node_name, datacenter) return NodeChecks - def resolve_MultiServiceChecks(self, info, service_list, datacenter): MultiServiceChecks.response = app.get_multi_service_check(service_list, datacenter) return MultiServiceChecks - def resolve_MultiNodeChecks(self, info, node_list, datacenter): MultiNodeChecks.response = app.get_multi_node_check(node_list, datacenter) - return MultiNodeChecks - + return MultiNodeChecks def resolve_ReadCreds(self, info): ReadCreds.creds = app.read_creds() return ReadCreds - def resolve_WriteCreds(self, info, agent_list): WriteCreds.creds = app.write_creds(agent_list) return WriteCreds - def resolve_UpdateCreds(self, info, update_input): UpdateCreds.creds = app.update_creds(update_input) return UpdateCreds - def resolve_DeleteCreds(self, info, agent_data): DeleteCreds.message = app.delete_creds(agent_data) return DeleteCreds - def resolve_DetailsFlattened(self, info, tn, datacenter): - DetailsFlattened.details = app.details_flattened(tn, datacenter) - return DetailsFlattened - + DetailsFlattened.details = app.details_flattened(tn, datacenter) + return DetailsFlattened def resolve_GetDatacenters(self, info): GetDatacenters.datacenters = app.get_datacenters() return GetDatacenters - def resolve_PostTenant(self, info, tn): PostTenant.tenant = app.post_tenant(tn) return PostTenant @@ -286,4 +269,5 @@ def resolve_GetPerformanceDashboard(self, info, tn): GetPerformanceDashboard.response = app.get_performance_dashboard(tn) return GetPerformanceDashboard + schema = graphene.Schema(query=Query) diff --git a/ConsulExtension/Service/tests/__init__.py b/ConsulExtension/Service/tests/__init__.py new file mode 100644 index 0000000..7d18113 --- /dev/null +++ b/ConsulExtension/Service/tests/__init__.py @@ -0,0 +1,7 @@ +import sys +from mock import Mock + +sys.modules['cobra'] = 'cobra' +sys.modules['cobra.model'] = 'cobra.model' +sys.modules['cobra.model.pol'] = Mock(name='Uni') +sys.modules['cobra.model.aaa'] = Mock(name='UserEp') diff --git a/ConsulExtension/Service/tests/alchemy_core/__init__.py b/ConsulExtension/Service/tests/alchemy_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ConsulExtension/Service/tests/alchemy_core/test_alchemy_core.py b/ConsulExtension/Service/tests/alchemy_core/test_alchemy_core.py new file mode 100644 index 0000000..332f9ac --- /dev/null +++ b/ConsulExtension/Service/tests/alchemy_core/test_alchemy_core.py @@ -0,0 +1,273 @@ +from Service import alchemy_core +import os +import pytest + + +dc = dict() +dc.update({ + 'login': [ + 'agent_ip', + 'port', + 'protocol', + 'token', + 'status', + 'datacenter', + ] +}) +dc.update({ + 'mapping': [ + 'ip', + 'dn', + 'datacenter', + True, + 'ap', + 'bd', + 'epg', + 'vrf', + 'tenant' + ] +}) +dc.update({ + 'node': [ + 'node_id', + 'node_name', + ['node_ips1', 'node_ips2'], + 'datacenter', + ['agents1', 'agents2'] + ] +}) +dc.update({ + 'service': [ + 'service_id', + 'node_id', + 'service_name', + 'service_ip', + 'service_port', + 'service_address', + ['tag1', 'tag2'], + 'service_kind', + 'namespace', + 'datacenter', + ['agents1', 'agents2'] + ] +}) +dc.update({ + 'nodechecks': [ + 'check_id', + 'node_id', + 'node_name', + 'check_name', + 'service_name', + 'check_type', + 'notes', + 'output', + ['status1', 'status2'], + ['agents1', 'agents2'] + ] +}) +dc.update({ + 'servicechecks': [ + 'check_id', + 'service_id', + 'service_name', + 'check_name', + 'check_type', + 'notes', + 'output', + ['status1', 'status2'], + ['agents1', 'agents2'] + ] +}) +dc.update({ + 'ep': [ + 'mac', + 'ip', + 'tenant', + 'dn', + 'vm_name', + ['interfaces1', 'interfaces2'], + 'vmm_domain', + 'controller_name', + 'learning_source', + 'multicast_address', + 'encap', + 'hosting_server_name', + 'is_cep' + ] +}) +dc.update({ + 'epg': [ + 'dn', + 'tenant', + 'epg', + 'bd', + ['contracts1', 'contracts2'], + 'vrf', + 'epg_health', + 'app_profile', + 'epg_alias' + ] +}) +dc.update({ + 'tenant': [ + 'tenant' + ] +}) + + +tables = dc.keys() + + +@pytest.mark.parametrize("table", tables) +def test_insert_into_table(table): + db_obj = alchemy_core.Database() + db_obj.create_tables() + connection = db_obj.engine.connect() + + assert db_obj.insert_into_table(connection, table, dc[table]) is True + assert db_obj.insert_into_table(connection, table, dc[table]) is False + + inserted_rec = db_obj.select_from_table(connection, table) + assert len(inserted_rec) == 1 + for record in inserted_rec: + for index, value in enumerate(dc[table]): + assert value == record[index] + + assert db_obj.insert_into_table(connection, '', dc[table]) is False + assert db_obj.insert_into_table(connection, '', []) is False + + connection.close() + os.remove('./ConsulDatabase.db') + + +@pytest.mark.parametrize("table", tables) +def test_select_from_table(table): + db_obj = alchemy_core.Database() + db_obj.create_tables() + connection = db_obj.engine.connect() + dummy = [dc[table], [i for i in dc[table]]] + dummy[1][0] = '1' + assert db_obj.insert_into_table(connection, table, dummy[0]) is True + assert db_obj.insert_into_table(connection, table, dummy[1]) is True + + records = db_obj.select_from_table(connection, table) + + assert len(records) == 2 + for i, each in enumerate(dummy): + for j, value in enumerate(each): + assert value == records[i][j] + + connection.close() + os.remove('./ConsulDatabase.db') + + +@pytest.mark.parametrize("table", tables) +def test_update_in_table(table): + db_obj = alchemy_core.Database() + db_obj.create_tables() + connection = db_obj.engine.connect() + + if table != 'tenant': + assert db_obj.insert_into_table(connection, table, dc[table]) is True + + assert db_obj.update_in_table( + connection, + table, + {}, + { + dc[table][0]: 'new{}'.format(dc[table][0]), + } + ) + records = db_obj.select_from_table(connection, table) + assert len(records) == 1 + for i, each in enumerate(records): + for j in range(len(dc[table])): + if j == 0: + assert each[j] == 'new{}'.format(dc[table][j]) + continue + assert each[j] == records[i][j] + + connection.close() + os.remove('./ConsulDatabase.db') + + +@pytest.mark.parametrize("table", tables) +def test_delete_from_table(table): + db_obj = alchemy_core.Database() + db_obj.create_tables() + connection = db_obj.engine.connect() + + dummy = [dc[table], [i for i in dc[table]]] + dummy[1][0] = 'new{}'.format(dummy[1][0]) + db_obj.insert_into_table(connection, table, dummy[0]) is True + db_obj.insert_into_table(connection, table, dummy[1]) is True + + assert db_obj.delete_from_table(connection, table) + records = db_obj.select_from_table(connection, table) + + assert len(records) == 0 + db_obj.insert_into_table(connection, table, dummy[0]) is True + + assert db_obj.delete_from_table( + connection, + table, + {dc[table][0]: dc[table][0]} + ) + + assert db_obj.delete_from_table(connection, "") == False + + connection.close() + os.remove('./ConsulDatabase.db') + + +@pytest.mark.parametrize("table", tables) +def test_insert_and_update(table): + db_obj = alchemy_core.Database() + db_obj.create_tables() + + if table != 'tenant': + dummy = [dc[table], [i for i in dc[table]], [i for i in dc[table]]] + connection = db_obj.engine.connect() + + for each in dummy: + assert db_obj.insert_and_update( + connection, + table, + each, + { + dc[table][0]: each[0] + } + ) + + connection.close() + connection = db_obj.engine.connect() + records = db_obj.select_from_table(connection, table) + connection.close() + assert len(records) == 1 + + for each in records: + assert each[-2] is None + + dummy[1][0] = 'new1' + dummy[2][0] = 'new2' + connection = db_obj.engine.connect() + for each in dummy: + assert db_obj.insert_and_update( + connection, + table, + each, + { + dc[table][0]: each[0] + } + ) + connection.close() + + connection = db_obj.engine.connect() + records = db_obj.select_from_table(connection, table) + connection.close() + assert len(records) == 3 + + for each in records: + assert each[-2] is None + + os.remove('./ConsulDatabase.db') diff --git a/ConsulExtension/Service/tests/apic_utils/__init__.py b/ConsulExtension/Service/tests/apic_utils/__init__.py new file mode 100644 index 0000000..7d18113 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/__init__.py @@ -0,0 +1,7 @@ +import sys +from mock import Mock + +sys.modules['cobra'] = 'cobra' +sys.modules['cobra.model'] = 'cobra.model' +sys.modules['cobra.model.pol'] = Mock(name='Uni') +sys.modules['cobra.model.aaa'] = Mock(name='UserEp') diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/bd_input.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/bd_input.json new file mode 100644 index 0000000..949af5b --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/bd_input.json @@ -0,0 +1,8 @@ +{ + "imdata": [{ + "fvRsBd": { + "attributes": { + "tnFvBDName": "Dummy-BD0" + } + }}] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/empty_input.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/empty_input.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_bd_cases/empty_input.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_input.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_input.json new file mode 100644 index 0000000..e7a413c --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_input.json @@ -0,0 +1,53 @@ +{ + "imdata": [ + { + "fvRsProv": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/rsprov-dummy1" + } + } + }, + { + "fvRsProv": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/rsprov-dummy2" + } + } + }, + { + "fvRsCons": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/rscons-dummy1" + } + } + }, + { + "fvRsCons": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/rscons-dummy2" + } + } + }, + { + "fvRsIntraEpg": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/rscons-dummy0" + } + } + }, + { + "fvRsConsIf": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/rscons-dummy0" + } + } + }, + { + "fvRsProtBy": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/rscons-dummy0" + } + } + } + ] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_output.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_output.json new file mode 100644 index 0000000..a13b1cb --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/all_contracts_output.json @@ -0,0 +1,7 @@ +{ + "Consumer": ["dummy1", "dummy2"], + "Intra EPG": ["dummy0"], + "Provider": ["dummy1", "dummy2"], + "Consumer Interface": ["dummy0"], + "Taboo": ["dummy0"] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_input.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_input.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_input.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_output.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_output.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_contract_cases/no_contracts_output.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_input.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_input.json new file mode 100644 index 0000000..3cc762b --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_input.json @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_output.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_output.json new file mode 100644 index 0000000..3cc762b --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/empty_output.json @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_input.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_input.json new file mode 100644 index 0000000..653341e --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_input.json @@ -0,0 +1,8 @@ +{ + "imdata": [{ + "fvRsCtx": { + "attributes": { + "tnFvCtxName": "Dummy-VRF" + } + }}] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_output.json b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_output.json new file mode 100644 index 0000000..f5f9b5a --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/apic_fetch_vrf_cases/vrf_output.json @@ -0,0 +1 @@ +"Dummy-VRF" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_input.json new file mode 100644 index 0000000..50f3324 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_input.json @@ -0,0 +1,12 @@ +{ + "totalCount": "1", + "imdata": [ + { + "compHv": { + "attributes": { + "name": "1.1.1.1" + } + } + } + ] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_output.json new file mode 100644 index 0000000..171e823 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_all_mo_instances_cases/get_instance_output.json @@ -0,0 +1 @@ +[{"compHv": {"attributes": {"name": "1.1.1.1"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_input.json new file mode 100644 index 0000000..5ea0b28 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_input.json @@ -0,0 +1,7 @@ +{ + "fvRsHyper": { + "attributes": { + "tDn": "comp/prov-dummy/ctrlr-[DUMMY0-leaf000]-hyper000/hv-host-00" + } + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_mo_instance.json b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_mo_instance.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_host_mo_instance.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_input.json new file mode 100644 index 0000000..5ea0b28 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_input.json @@ -0,0 +1,7 @@ +{ + "fvRsHyper": { + "attributes": { + "tDn": "comp/prov-dummy/ctrlr-[DUMMY0-leaf000]-hyper000/hv-host-00" + } + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_mo_instance.json b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_mo_instance.json new file mode 100644 index 0000000..171e823 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/with_ip_host_mo_instance.json @@ -0,0 +1 @@ +[{"compHv": {"attributes": {"name": "1.1.1.1"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_input.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_input.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_mo_instance.json b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_mo_instance.json new file mode 100644 index 0000000..171e823 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_controller_and_hosting_server/without_ip_host_mo_instance.json @@ -0,0 +1 @@ +[{"compHv": {"attributes": {"name": "1.1.1.1"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_input.json new file mode 100644 index 0000000..acff55e --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_input.json @@ -0,0 +1,23 @@ +[ + { + "fvRsCEpToPathEp": { + "attributes": { + "tDn": "topology/pod-0/paths-111/pathep-[eth0/0]" + } + } + }, + { + "fvRsHyper": { + "attributes": { + "tDn": "comp/prov-dummy/ctrlr-[DUMMY0-leaf000]-hyper000/hv-host-00" + } + } + }, + { + "fvRsToVm": { + "attributes": { + "tDn": "comp/prov-dummy/ctrlr-[DUMMY0-leaf000]-dummy/vm-vm-000" + } + } + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_output.json new file mode 100644 index 0000000..f9cca11 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ep_info_cases/ep_output.json @@ -0,0 +1,7 @@ +{ + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000" +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_input.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_input.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_output.json new file mode 100644 index 0000000..3cc762b --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/empty_output.json @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_input.json new file mode 100644 index 0000000..446df36 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_input.json @@ -0,0 +1,17 @@ +{ + "imdata": [ + { + "healthInst": { + "attributes": { + "cur": "96" + } + } + }, + { + "healthNodeInst": {} + }, + { + "healthNodeInst": {} + } + ] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_output.json new file mode 100644 index 0000000..8f721a1 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_epg_health_cases/epg_health_output.json @@ -0,0 +1 @@ +"96" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_input.json new file mode 100644 index 0000000..1afd0ac --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_input.json @@ -0,0 +1,7 @@ +{ + "fvRsCEpToPathEp": { + "attributes": { + "tDn": "topology/pod-1/pathgrp-[1.1.1.1]" + } + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_node.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_node.json new file mode 100644 index 0000000..2027538 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_node.json @@ -0,0 +1 @@ +"[1.1.1.1]" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_output.json new file mode 100644 index 0000000..97a838a --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/pathgrp_output.json @@ -0,0 +1 @@ +"Pod-1/Node-[1.1.1.1]/1.1.1.1(vmm)" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_input.json new file mode 100644 index 0000000..1146967 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_input.json @@ -0,0 +1,7 @@ +{ + "fvRsCEpToPathEp": { + "attributes": { + "tDn": "topology/pod-0/paths-111/pathep-[eth0/0]" + } + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_node.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_node.json new file mode 100644 index 0000000..69fdb79 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_node.json @@ -0,0 +1 @@ +"111" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_output.json new file mode 100644 index 0000000..a697532 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/paths_output.json @@ -0,0 +1 @@ +"Pod-0/Node-111/eth0/0" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_input.json new file mode 100644 index 0000000..bc549c5 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_input.json @@ -0,0 +1,7 @@ +{ + "fvRsCEpToPathEp": { + "attributes": { + "tDn": "topology/pod-0/protpaths-111-222/pathep-[FI-A-PG]" + } + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_node.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_node.json new file mode 100644 index 0000000..59a12b9 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_node.json @@ -0,0 +1 @@ +"-111-222" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_output.json new file mode 100644 index 0000000..ebe27d4 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_interface_cases/protpaths_output.json @@ -0,0 +1 @@ +"Pod-0/Node--111-222/FI-A-PG" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_input.json new file mode 100644 index 0000000..76dd5bf --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_input.json @@ -0,0 +1,33 @@ +{ + "fvCEp": { + "attributes": { + "ip": "0.0.0.0", + "mac": "00:00:00:00:00:AA" + }, + "children": [ + { + "fvIp": { + "attributes": { + "addr": "1.1.1.1" + } + } + }, + { + "fvIp": { + "attributes": { + "addr": "2.2.2.2" + } + } + }, + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_output.json new file mode 100644 index 0000000..e680111 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/2_fvip_output.json @@ -0,0 +1 @@ +[["1.1.1.1", false], ["2.2.2.2", false]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_input.json new file mode 100644 index 0000000..b69971f --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_input.json @@ -0,0 +1,19 @@ +{ + "fvCEp": { + "attributes": { + "ip": "1.1.1.1", + "mac": "00:00:00:00:00:AA" + }, + "children": [ + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_output.json new file mode 100644 index 0000000..6569691 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/cep_output.json @@ -0,0 +1 @@ +[["1.1.1.1", true]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_input.json new file mode 100644 index 0000000..09f5764 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_input.json @@ -0,0 +1,26 @@ +{ + "fvCEp": { + "attributes": { + "ip": "1.1.1.1", + "mac": "00:00:00:00:00:AA" + }, + "children": [ + { + "fvIp": { + "attributes": { + "addr": "2.2.2.2" + } + } + }, + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_output.json new file mode 100644 index 0000000..05de15b --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/diff_cep_fvip_output.json @@ -0,0 +1 @@ +[["2.2.2.2", false], ["1.1.1.1", true]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_input.json new file mode 100644 index 0000000..8bac4f1 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_input.json @@ -0,0 +1,26 @@ +{ + "fvCEp": { + "attributes": { + "ip": "0.0.0.0", + "mac": "00:00:00:00:00:AA" + }, + "children": [ + { + "fvIp": { + "attributes": { + "addr": "1.1.1.1" + } + } + }, + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_output.json new file mode 100644 index 0000000..048769f --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/fvip_output.json @@ -0,0 +1 @@ +[["1.1.1.1", false]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_input.json new file mode 100644 index 0000000..ad33e3e --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_input.json @@ -0,0 +1,19 @@ +{ + "fvCEp": { + "attributes": { + "ip": "0.0.0.0", + "mac": "00:00:00:00:00:AA" + }, + "children": [ + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_output.json new file mode 100644 index 0000000..44caaab --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/no_ip_output.json @@ -0,0 +1 @@ +[["00:00:00:00:00:aa", false]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_input.json new file mode 100644 index 0000000..946b64d --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_input.json @@ -0,0 +1,26 @@ +{ + "fvCEp": { + "attributes": { + "ip": "1.1.1.1", + "mac": "00:00:00:00:00:AA" + }, + "children": [ + { + "fvIp": { + "attributes": { + "addr": "1.1.1.1" + } + } + }, + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_output.json b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_output.json new file mode 100644 index 0000000..048769f --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_ip_mac_list_cases/same_cep_fvip_output.json @@ -0,0 +1 @@ +[["1.1.1.1", false]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_get_data.json b/ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_get_data.json new file mode 100644 index 0000000..c3d65c8 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_get_data.json @@ -0,0 +1,12 @@ +{ + "totalCount": "1", + "imdata": [ + { + "compVm": { + "attributes": { + "name": "dummy-vm-name" + } + } + } + ] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_input.json b/ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_input.json new file mode 100644 index 0000000..ddb9cb0 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/get_vm_domain_and_name_cases/domain_and_name_input.json @@ -0,0 +1,7 @@ +{ + "fvRsToVm": { + "attributes": { + "tDn": "comp/prov-dummy/ctrlr-[DUMMY0-leaf000]-dummy/vm-vm-000" + } + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/ip_1.json b/ConsulExtension/Service/tests/apic_utils/data/ip_1.json new file mode 100644 index 0000000..2b991e4 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/ip_1.json @@ -0,0 +1 @@ +"1.1.1.1" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/ip_2.json b/ConsulExtension/Service/tests/apic_utils/data/ip_2.json new file mode 100644 index 0000000..845bf5e --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/ip_2.json @@ -0,0 +1 @@ +"2.2.2.2" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_input.json b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_input.json new file mode 100644 index 0000000..67d2203 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_input.json @@ -0,0 +1,30 @@ +{ + "fvCEp": { + "attributes": { + "ip": "2.2.2.2", + "mac": "00:00:00:00:00:AA", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "lcC": "dummy-vmm", + "encap": "dummy-lan-111", + "mcastAddr": "not-applicable" + }, + "children": [ + { + "fvIp": { + "attributes": { + "addr": "1.1.1.1" + } + } + }, + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_output.json b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_output.json new file mode 100644 index 0000000..7ce6ff2 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/ep_output.json @@ -0,0 +1,29 @@ +[{ + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "1.1.1.1", + "is_cep": false +}, { + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "2.2.2.2", + "is_cep": true +}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/get_ep_input.json b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/get_ep_input.json new file mode 100644 index 0000000..f9cca11 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_ep_data_cases/get_ep_input.json @@ -0,0 +1,7 @@ +{ + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000" +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_contract.json b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_contract.json new file mode 100644 index 0000000..61f04be --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_contract.json @@ -0,0 +1,19 @@ +{ + "Consumer Interface": [ + "dummy0" + ], + "Intra EPG": [ + "dummy0" + ], + "Consumer": [ + "dummy1", + "dummy2" + ], + "Taboo": [ + "dummy0" + ], + "Provider": [ + "dummy1", + "dummy2" + ] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_input.json b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_input.json new file mode 100644 index 0000000..ce2bc46 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_input.json @@ -0,0 +1,9 @@ +{ + "fvAEPg": { + "attributes": { + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "name": "DummyEpg", + "nameAlias": "DummyAliasName" + } + } +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_output.json b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_output.json new file mode 100644 index 0000000..a4c6f05 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_and_return_epg_data_cases/epg_data_output.json @@ -0,0 +1,29 @@ +{ + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "bd": "Dummy-BD0", + "vrf": "DummyTn/Dummy-VRF", + "epg_alias": "DummyAliasName", + "app_profile": "DummyAp", + "epg": "DummyEpg", + "contracts": { + "Consumer Interface": [ + "dummy0" + ], + "Intra EPG": [ + "dummy0" + ], + "Consumer": [ + "dummy1", + "dummy2" + ], + "Taboo": [ + "dummy0" + ], + "Provider": [ + "dummy1", + "dummy2" + ] + }, + "epg_health": "96", + "tenant": "DummyTn" +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_input.json b/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_input.json new file mode 100644 index 0000000..a7306d8 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_input.json @@ -0,0 +1,59 @@ +[{ + "fvCEp": { + "attributes": { + "ip": "2.2.2.2", + "mac": "00:00:00:00:00:AA", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "lcC": "dummy-vmm", + "encap": "dummy-lan-111", + "mcastAddr": "not-applicable" + }, + "children": [ + { + "fvIp": { + "attributes": { + "addr": "1.1.1.1" + } + } + }, + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +}, { + "fvCEp": { + "attributes": { + "ip": "2.2.2.2", + "mac": "00:00:00:00:00:AA", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "lcC": "dummy-vmm", + "encap": "dummy-lan-111", + "mcastAddr": "not-applicable" + }, + "children": [ + { + "fvIp": { + "attributes": { + "addr": "1.1.1.1" + } + } + }, + { + "fvRsCEpToPathEp": {} + }, + { + "fvRsHyper": {} + }, + { + "fvRsToVm": {} + } + ] + } +}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_output.json b/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_output.json new file mode 100644 index 0000000..a2f3f99 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/ep_output.json @@ -0,0 +1,57 @@ +[{ + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "1.1.1.1", + "is_cep": false +}, { + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "2.2.2.2", + "is_cep": true +}, { + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "1.1.1.1", + "is_cep": false +}, { + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "2.2.2.2", + "is_cep": true +}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/get_ep_input.json b/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/get_ep_input.json new file mode 100644 index 0000000..05adfa7 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/data/parse_ep_data_cases/get_ep_input.json @@ -0,0 +1,30 @@ +[ + { + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "1.1.1.1", + "is_cep": false + }, { + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000", + "dn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA", + "learning_src": "dummy-vmm", + "tenant": "DummyTn", + "mac": "00:00:00:00:00:AA", + "encap": "dummy-lan-111", + "multi_cast_addr": "---", + "ip": "2.2.2.2", + "is_cep": true +}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/apic_utils/test_apic_utils.py b/ConsulExtension/Service/tests/apic_utils/test_apic_utils.py new file mode 100644 index 0000000..ccd2331 --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/test_apic_utils.py @@ -0,0 +1,511 @@ +import pytest +from requests import Session +from Service import apic_utils +from Service.apic_utils import AciUtils +from Service.tests.utils import DummyClass +from Service.tests.apic_utils.utils import get_data + + +aci_get_cases = [(200, {'dummy_key': 'dummy_val'}), (400, None)] + + +@pytest.mark.parametrize("status,expected", aci_get_cases) +def test_aci_get(status, expected): + """Test aci get function""" + + # Mock session's get + def json(): + return {'dummy_key': 'dummy_val'} + + def dummy_get(self, url, cookies, timeout, verify): + obj = DummyClass() + obj.status_code = status + if status == 200: + obj.json = json + return obj + + Session.get = dummy_get + + # Mock apic_util login + def dummy_login(self): + return "dummy-token" + + AciUtils.login = dummy_login + + # Test the function + obj = AciUtils() + response = obj.aci_get("http://dummy.apic.url") + + assert response == expected + + +@pytest.mark.parametrize("aci_get_data, data", [ + ("data/get_vm_domain_and_name_cases/domain_and_name_get_data.json", + "data/get_vm_domain_and_name_cases/domain_and_name_input.json") +]) +def test_get_vm_domain_and_name(aci_get_data, data): + """Test the VM Domain and Name""" + + def dummy_aci_get(self, url): + return get_data(aci_get_data) + + AciUtils.aci_get = dummy_aci_get + + # Test the function + obj = AciUtils() + response = obj.get_vm_domain_and_name(get_data(data)) + + assert response == ('DUMMY0-leaf000', 'dummy-vm-name') + + +@pytest.mark.parametrize("interface, expected", [ + ("topology/pod-1/pathdummy-xxx", ""), + ("topology/pod-1/pathgrp-[1.1.1.1]", "[1.1.1.1]"), + ("topology/pod-0/paths-111/pathep-[eth0/0]", "111"), + ("topology/pod-0/protpaths-111-222/pathep-[FI-A-PG]", "-111-222"), + (["topology/pod-0/protpaths-111-222/pathep-[FI-A-PG]", + "topology/pod-0/paths-111/pathep-[eth0/0]"], "-111-222, 111"), +]) +def test_get_node_from_interface(interface, expected): + + # Test the function + response = AciUtils.get_node_from_interface(interface) + + assert response == expected + + +@pytest.mark.parametrize("data, node, expected", [ + ("data/get_interface_cases/paths_input.json", + "data/get_interface_cases/paths_node.json", + "data/get_interface_cases/paths_output.json" + ), + ("data/get_interface_cases/protpaths_input.json", + "data/get_interface_cases/protpaths_node.json", + "data/get_interface_cases/protpaths_output.json" + ), + ("data/get_interface_cases/pathgrp_input.json", + "data/get_interface_cases/pathgrp_node.json", + "data/get_interface_cases/pathgrp_output.json" + ) +]) +def test_get_interface(data, node, expected): + + # Mock apic_util get_node_from_interface + def dummy_get_node_from_interface(self, interface): + return get_data(node) + + AciUtils.get_node_from_interface = dummy_get_node_from_interface + + # Test the function + obj = AciUtils() + response = obj.get_interface(get_data(data)) + + assert response == get_data(expected) + + +@pytest.mark.parametrize("data,mo_instance_data,expected", [ + ("data/get_controller_and_hosting_server/with_ip_host_input.json", + "data/get_controller_and_hosting_server/with_ip_host_mo_instance.json", + ('hyper000', get_data("data/ip_1.json"))), + ("data/get_controller_and_hosting_server/with_host_input.json", + "data/get_controller_and_hosting_server/with_host_mo_instance.json", + ('hyper000', '')), + ("data/get_controller_and_hosting_server/without_ip_host_input.json", + "data/get_controller_and_hosting_server/without_ip_host_mo_instance.json", + ('', '')) +]) +def test_get_controller_and_hosting_server(data, mo_instance_data, expected): + + def dummy_get_all_mo_instances(self, mo_class, query_string=""): + return get_data(mo_instance_data) + + AciUtils.get_all_mo_instances = dummy_get_all_mo_instances + + # Test the function + obj = AciUtils() + response = obj.get_controller_and_hosting_server(get_data(data)) + + assert response == expected + + +@pytest.mark.parametrize("data, expected", [ + ("data/get_all_mo_instances_cases/get_instance_input.json", + "data/get_all_mo_instances_cases/get_instance_output.json") +]) +def test_get_all_mo_instances(data, expected): + + def dummy_aci_get(self, url): + return get_data(data) + + AciUtils.aci_get = dummy_aci_get + + # Test the function + obj = AciUtils() + response = obj.get_all_mo_instances("dummy-class", "dummy-query") + + assert response == get_data(expected) + + +def test_get_dict_records(): + + response = AciUtils.get_dict_records([1, 2, 3], 'key') + + assert response == {'key': [1, 2, 3]} + + +@pytest.mark.parametrize('data,expected', [ + ("data/get_ip_mac_list_cases/cep_input.json", + "data/get_ip_mac_list_cases/cep_output.json"), + ("data/get_ip_mac_list_cases/no_ip_input.json", + "data/get_ip_mac_list_cases/no_ip_output.json"), + ("data/get_ip_mac_list_cases/fvip_input.json", + "data/get_ip_mac_list_cases/fvip_output.json"), + ("data/get_ip_mac_list_cases/same_cep_fvip_input.json", + "data/get_ip_mac_list_cases/same_cep_fvip_output.json"), + ("data/get_ip_mac_list_cases/2_fvip_input.json", + "data/get_ip_mac_list_cases/2_fvip_output.json"), + ("data/get_ip_mac_list_cases/diff_cep_fvip_input.json", + "data/get_ip_mac_list_cases/diff_cep_fvip_output.json") +]) +def test_get_ip_mac_list(data, expected): + + response = AciUtils.get_ip_mac_list(get_data(data)) + + assert response == get_data(expected) + + +@pytest.mark.parametrize("data, expected", [ + ("data/get_ep_info_cases/ep_input.json", + "data/get_ep_info_cases/ep_output.json") +]) +def test_get_ep_info(data, expected): + + # Mock AciUtils functions + def dummy_get_controller_and_hosting_server(self, ep_child): + return ("hyper000", get_data("data/ip_1.json")) + + def dummy_get_interface(self, ep_child): + return "Pod-0/Node-111/eth0/0" + + def dummy_get_vm_domain_and_name(self, ep_child): + return ('DUMMY0-leaf000', 'dummy-vm-name') + + AciUtils.get_controller_and_hosting_server = dummy_get_controller_and_hosting_server + AciUtils.get_interface = dummy_get_interface + AciUtils.get_vm_domain_and_name = dummy_get_vm_domain_and_name + + # Test the function + obj = AciUtils() + response = obj.get_ep_info(get_data(data)) + + assert response == get_data(expected) + + +@pytest.mark.parametrize("data, ep_data, expected", [ + ("data/parse_and_return_ep_data_cases/ep_input.json", + "data/parse_and_return_ep_data_cases/get_ep_input.json", + "data/parse_and_return_ep_data_cases/ep_output.json") +]) +def test_parse_and_return_ep_data(data, ep_data, expected): + + # Mock AciUtils functions + def dummy_get_ep_info(self, ep_attr): + return get_data(ep_data) + + def dummy_get_ip_mac_list(ep_child): + return [[get_data("data/ip_2.json"), True], [get_data("data/ip_1.json"), False]] + + AciUtils.get_ep_info = dummy_get_ep_info + get_ip_mac_list = dummy_get_ip_mac_list + + # Test the function + obj = AciUtils() + response = obj.parse_and_return_ep_data(get_data(data)) + + assert response == get_data(expected) + + +@pytest.mark.parametrize("data, get_ep_data, expected", [ + ("data/parse_ep_data_cases/ep_input.json", + "data/parse_ep_data_cases/get_ep_input.json", + "data/parse_ep_data_cases/ep_output.json") +]) +def test_parse_ep_data(data, get_ep_data, expected): + + def dummy_parse_and_return_ep_data(self, ep_data): + return get_data(get_ep_data) + + AciUtils.parse_and_return_ep_data = dummy_parse_and_return_ep_data + + obj = AciUtils() + response = obj.parse_ep_data(get_data(data)) + + assert response == get_data(expected) + + +def test_apic_fetch_ep_data(): + + resp_data = [{"key": "val"}, {"key": "val"}] + + # Mock AciUtils methods + def dummy_aci_get(self, url): + return {"imdata": [{}]} + + def dummy_parse_ep_data(self, data): + return resp_data + + AciUtils.aci_get = dummy_aci_get + AciUtils.parse_ep_data = dummy_parse_ep_data + AciUtils.epg_url = "dummy-epg-url" + + obj = AciUtils() + response = obj.apic_fetch_ep_data('DummyTn') + + assert response == resp_data + + +def test_apic_fetch_epg_data(): + + resp_data = [{"key": "val"}, {"key": "val"}] + + # Mock AciUtils methods + def dummy_aci_get(self, url): + return {"imdata": [{}]} + + def dummy_parse_epg_data(self, data): + return resp_data + + AciUtils.aci_get = dummy_aci_get + AciUtils.parse_epg_data = dummy_parse_epg_data + AciUtils.epg_url = "dummy-epg-url" + + obj = AciUtils() + response = obj.apic_fetch_epg_data('DummyTn') + + assert response == resp_data + + +@pytest.mark.parametrize('data, dn, expected', [ + ("data/apic_fetch_bd_cases/bd_input.json", "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", "Dummy-BD0"), + ("data/apic_fetch_bd_cases/empty_input.json", "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", None) +]) +def test_apic_fetch_bd(data, dn, expected): + + # Mock AciUtils methods + def dummy_aci_get(self, url): + return get_data(data) + + AciUtils.aci_get = dummy_aci_get + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.apic_fetch_bd(dn) + + assert response == expected + + +@pytest.mark.parametrize('data, dn, expected', [ + ("data/apic_fetch_vrf_cases/vrf_input.json", + "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "data/apic_fetch_vrf_cases/vrf_output.json",), + ("data/apic_fetch_vrf_cases/empty_input.json", + "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "data/apic_fetch_vrf_cases/empty_output.json",) +]) +def test_apic_fetch_vrf(data, dn, expected): + + # Mock AciUtils methods + def dummy_aci_get(self, url): + return get_data(data) + + AciUtils.aci_get = dummy_aci_get + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.apic_fetch_vrf(dn) + + assert response == get_data(expected) + + +@pytest.mark.parametrize('data, dn, expected', [ + ("data/apic_fetch_contract_cases/all_contracts_input.json", + "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "data/apic_fetch_contract_cases/all_contracts_output.json"), + ("data/apic_fetch_contract_cases/no_contracts_input.json", + "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "data/apic_fetch_contract_cases/no_contracts_output.json") +]) +def test_apic_fetch_contract(data, dn, expected): + # Mock AciUtils methods + def dummy_aci_get(self, url): + return get_data(data) + + AciUtils.aci_get = dummy_aci_get + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.apic_fetch_contract(dn) + + assert response == get_data(expected) + + +@pytest.mark.parametrize('data, dn, expected', [ + ("data/get_epg_health_cases/epg_health_input.json", + "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "data/get_epg_health_cases/epg_health_output.json"), + ("data/get_epg_health_cases/empty_input.json", + "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", + "data/get_epg_health_cases/empty_output.json") +]) +def test_get_epg_health(data, dn, expected): + # Mock AciUtils methods + def dummy_aci_get(self, url): + return get_data(data) + + AciUtils.aci_get = dummy_aci_get + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.get_epg_health(dn) + + assert response == get_data(expected) + + +def test_get_ap_epg_faults(): + # Mock AciUtils methods + def dummy_get_mo_related_item(self, mo_dn, item_query_string, item_type): + return ['data1', 'data2'] + + AciUtils.get_mo_related_item = dummy_get_mo_related_item + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.get_ap_epg_faults('dummy-dn') + + assert response == {'faultRecords': ['data1', 'data2']} + + +def test_get_ap_epg_events(): + # Mock AciUtils methods + def dummy_get_mo_related_item(self, mo_dn, item_query_string, item_type): + return ['data1', 'data2'] + + AciUtils.get_mo_related_item = dummy_get_mo_related_item + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.get_ap_epg_events('dummy-dn') + + assert response == {'eventRecords': ['data1', 'data2']} + + +def test_get_ap_epg_audit_logs(): + # Mock AciUtils methods + def dummy_get_mo_related_item(self, mo_dn, item_query_string, item_type): + return ['data1', 'data2'] + + AciUtils.get_mo_related_item = dummy_get_mo_related_item + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.get_ap_epg_audit_logs('dummy-dn') + + assert response == {'auditLogRecords': ['data1', 'data2']} + + +@pytest.mark.parametrize('data, mo_dn, item_query_string, item_type, expected', [ + ({"imdata": ['data1', 'data2']}, 'dummy-dn', 'dummy-url', '', ['data1', 'data2']), + ({"imdata": ['data1', 'data2']}, '', 'dummy-url', "other_url", ['data1', 'data2']) +]) +def test_get_mo_related_item(data, mo_dn, item_query_string, item_type, expected): + + # Mock AciUtils methods + def dummy_aci_get(self, url): + return data + + AciUtils.aci_get = dummy_aci_get + AciUtils.proto = "http://" + AciUtils.apic_ip = "dummy-apic-ip" + + obj = AciUtils() + response = obj.get_mo_related_item(mo_dn, item_query_string, item_type) + + assert response == expected + + +@pytest.mark.parametrize('data, contract, expected', [ + ("data/parse_and_return_epg_data_cases/epg_data_input.json", + "data/parse_and_return_epg_data_cases/epg_data_contract.json", + "data/parse_and_return_epg_data_cases/epg_data_output.json") +]) +def test_parse_and_return_epg_data(data, contract, expected): + + # Mock AciUtils methods + def dummy_apic_fetch_bd(self, url): + return "Dummy-BD0" + + def dummy_apic_fetch_vrf(self, url): + return "Dummy-VRF" + + def dummy_apic_fetch_contract(self, url): + return get_data(contract) + + def dummy_get_epg_health(self, url): + return "96" + + AciUtils.apic_fetch_bd = dummy_apic_fetch_bd + AciUtils.apic_fetch_vrf = dummy_apic_fetch_vrf + AciUtils.apic_fetch_contract = dummy_apic_fetch_contract + AciUtils.get_epg_health = dummy_get_epg_health + + obj = AciUtils() + response = obj.parse_and_return_epg_data(get_data(data)) + + assert response == get_data(expected) + + +def test_parse_epg_data(): + + # Mock AciUtils methods + def dummy_parse_and_return_epg_data(self, url): + return {"dummy-key": "dummy-val"} + + AciUtils.parse_and_return_epg_data = dummy_parse_and_return_epg_data + + obj = AciUtils() + response = obj.parse_and_return_epg_data([{"fvAEPg": {}}]) + + assert response == {"dummy-key": "dummy-val"} + + +def test_login(): + + def dummy_create_cert_session(): + obj = DummyClass() + obj.dn = 'dummy-dn' + return (obj, 'dummy-key') + + def json(): + return {'imdata': [{'aaaLogin': {'attributes': {'token': 'dummy-token'}}}]} + + def dummy_post(self, url, data, headers, timeout, verify): + obj = DummyClass() + obj.status_code = 200 + obj.json = json + return obj + + Session.get = dummy_post + + apic_utils.create_cert_session = dummy_create_cert_session + + obj = AciUtils() + response = obj.login() + + assert response == 'dummy-token' diff --git a/ConsulExtension/Service/tests/apic_utils/utils.py b/ConsulExtension/Service/tests/apic_utils/utils.py new file mode 100644 index 0000000..ce82cdf --- /dev/null +++ b/ConsulExtension/Service/tests/apic_utils/utils.py @@ -0,0 +1,12 @@ +import os +from Service.tests.utils import parse_json_file + + +def get_absolue_path(input_file): + dir_path = os.path.dirname(os.path.abspath(__file__)) + file_path = r'/'.join([dir_path, input_file]) + return file_path + + +def get_data(file_name): + return parse_json_file(get_absolue_path(file_name)) diff --git a/ConsulExtension/Service/tests/consul_utils/__init__.py b/ConsulExtension/Service/tests/consul_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ConsulExtension/Service/tests/consul_utils/data/datacenter/1_initial_datacenter.json b/ConsulExtension/Service/tests/consul_utils/data/datacenter/1_initial_datacenter.json new file mode 100644 index 0000000..d9d54a5 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/datacenter/1_initial_datacenter.json @@ -0,0 +1 @@ +{"Config": {"Datacenter": "dc1"}} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/datacenter/2_empty_datacenter.json b/ConsulExtension/Service/tests/consul_utils/data/datacenter/2_empty_datacenter.json new file mode 100644 index 0000000..c0225f2 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/datacenter/2_empty_datacenter.json @@ -0,0 +1 @@ +{"Config": {}} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/datacenter/3_exception_datacenter.json b/ConsulExtension/Service/tests/consul_utils/data/datacenter/3_exception_datacenter.json new file mode 100644 index 0000000..32b4f7c --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/datacenter/3_exception_datacenter.json @@ -0,0 +1 @@ +{"asd": {"Datacenter": "dc1"}} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_input.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_input.json new file mode 100644 index 0000000..732fe8a --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_input.json @@ -0,0 +1,91 @@ +[ + { + "Status": "warning", + "CheckID": "19", + "Name": "name8", + "Service": "servicename8", + "Notes": "notes8", + "Address": "172.26.223.18", + "Namespace": "namespace8", + "ID": "serviceid8", + "ServiceName": "servicename8", + "ServiceID": "serviceid8", + "Output": "output8", + "ServiceKind": "servicekind8", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "http", + "Port": "1044" + }, + { + "Status": "warning", + "CheckID": "20", + "Name": "name0", + "Service": "servicename0", + "Notes": "notes0", + "Address": "10.25.211.25", + "Namespace": "namespace0", + "ID": "serviceid0", + "ServiceName": "servicename0", + "ServiceID": "serviceid0", + "Output": "output0", + "ServiceKind": "servicekind0", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tll", + "Port": "1045" + }, + { + "Status": "failing", + "CheckID": "21", + "Name": "name29", + "Service": "servicename29", + "Notes": "notes29", + "Address": "172.26.133.14", + "Namespace": "namespace29", + "ID": "serviceid29", + "ServiceName": "servicename29", + "ServiceID": "serviceid29", + "Output": "output29", + "ServiceKind": "servicekind29", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tll", + "Port": "1046" + }, + { + "Status": "failing", + "CheckID": "22", + "Name": "name16", + "Service": "servicename16", + "Notes": "notes16", + "Address": "172.29.238.86", + "Namespace": "namespace16", + "ID": "serviceid16", + "ServiceName": "servicename16", + "ServiceID": "serviceid16", + "Output": "output16", + "ServiceKind": "servicekind16", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tll", + "Port": "1047" + }, + { + "CheckID": "87", + "Status": "failing", + "Name": "name9", + "Notes": "notes9", + "ServiceName": "", + "Output": "output9", + "Type": "" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_output.json new file mode 100644 index 0000000..cd12d62 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/1_initial_detailed_node_check_output.json @@ -0,0 +1,12 @@ +[ + { + "CheckID": "87", + "Status": "failing", + "Name": "name9", + "Notes": "notes9", + "ServiceName": "-", + "Output": "output9", + "Type": "", + "NodeName": "nodename1" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_input.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_output.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_node_check/2_empty_detailed_node_check_output.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_input.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_input.json new file mode 100644 index 0000000..711fd83 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_input.json @@ -0,0 +1,78 @@ +[ + { + "Status": "warning", + "CheckID": "2", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename1", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "18", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename8", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "23", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename10", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "66", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename23", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_output.json new file mode 100644 index 0000000..9cfe217 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/1_initial_detailed_service_check_output.json @@ -0,0 +1,38 @@ +[ + { + "CheckID": "2", + "Status": "warning", + "Name": "name12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Output": "output12", + "Type": "http" + }, + { + "CheckID": "18", + "Status": "warning", + "Name": "name12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Output": "output12", + "Type": "http" + }, + { + "CheckID": "23", + "Status": "warning", + "Name": "name12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Output": "output12", + "Type": "http" + }, + { + "CheckID": "66", + "Status": "warning", + "Name": "name12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Output": "output12", + "Type": "http" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_input.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_output.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/detailed_service_check/2_empty_detailed_service_check_output.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_input.json b/ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_input.json new file mode 100644 index 0000000..e14550a --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_input.json @@ -0,0 +1,71 @@ +[ + { + "Status": "warning", + "CheckID": "0", + "Name": "name18", + "Service": "servicename18", + "Notes": "notes18", + "Address": "10.136.187.93", + "Namespace": "namespace18", + "ID": "serviceid18", + "ServiceName": "servicename18", + "ServiceID": "serviceid18", + "Output": "output18", + "ServiceKind": "servicekind18", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tll", + "Port": "1025" + }, + { + "Status": "passing", + "CheckID": "1", + "Name": "name3", + "Service": "servicename3", + "Notes": "notes3", + "Address": "", + "Namespace": "namespace3", + "ID": "serviceid3", + "ServiceName": "servicename3", + "ServiceID": "serviceid3", + "Output": "output3", + "ServiceKind": "servicekind3", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tcp", + "Port": "1026" + }, + { + "Status": "passing", + "CheckID": "2", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "Address": "", + "Namespace": "namespace12", + "ID": "serviceid12", + "ServiceName": "servicename12", + "ServiceID": "serviceid12", + "Output": "output12", + "ServiceKind": "servicekind12", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "http", + "Port": "1027" + }, + { + "CheckID": "79", + "Status": "warning", + "Name": "name1", + "Notes": "notes1", + "ServiceName": "", + "Output": "output1", + "Type": "" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_output.json new file mode 100644 index 0000000..1d4a8aa --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_check/1_initial_node_check_output.json @@ -0,0 +1,2 @@ +{"warning": 2, +"passing":2} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_intput.json b/ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_intput.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_intput.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_output.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_check/2_empty_node_check_output.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_input.json b/ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_input.json new file mode 100644 index 0000000..eea00ff --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_input.json @@ -0,0 +1,71 @@ +[ + { + "Status": "warning", + "CheckID": "0", + "Name": "name18", + "Service": "servicename18", + "Notes": "notes18", + "Address": "10.136.187.93", + "Namespace": "namespace18", + "ID": "serviceid18", + "ServiceName": "servicename18", + "ServiceID": "serviceid18", + "Output": "output18", + "ServiceKind": "servicekind18", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tll", + "Port": "1025" + }, + { + "Status": "passing", + "CheckID": "1", + "Name": "name3", + "Service": "servicename3", + "Notes": "notes3", + "Address": "", + "Namespace": "namespace3", + "ID": "serviceid3", + "ServiceName": "servicename3", + "ServiceID": "serviceid3", + "Output": "output3", + "ServiceKind": "servicekind3", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tcp", + "Port": "1026" + }, + { + "Status": "passing", + "CheckID": "2", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "Address": "", + "Namespace": "namespace12", + "ID": "serviceid12", + "ServiceName": "servicename12", + "ServiceID": "serviceid12", + "Output": "output12", + "ServiceKind": "servicekind12", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "http", + "Port": "1027" + }, + { + "CheckID": "79", + "Status": "asd", + "Name": "name1", + "Notes": "notes1", + "ServiceName": "", + "Output": "output1", + "Type": "" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_output.json new file mode 100644 index 0000000..1e63669 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_check/3_exception_node_check_output.json @@ -0,0 +1,3 @@ +{"warning": 1, +"passing":2, +"failing":1} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_input.json b/ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_input.json new file mode 100644 index 0000000..d83ab6d --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_input.json @@ -0,0 +1,76 @@ +[ + { + "Node": "nodename0", + "Services": [], + "Address": "10.162.26.233", + "ID": "nodeid0", + "TaggedAddresses": { + "wan_ipv4": "10.162.26.233", + "wan": "10.162.26.233", + "lan": "10.162.26.233", + "lan_ipv4": "10.162.26.233" + } + }, + { + "Node": "nodename1", + "Services": [], + "Address": "192.168.224.114", + "ID": "nodeid1", + "TaggedAddresses": { + "wan_ipv4": "192.168.224.114", + "wan": "192.168.224.114", + "lan": "192.168.224.114", + "lan_ipv4": "192.168.224.114" + } + }, + { + "Node": "nodename7", + "Services": [], + "Address": "10.49.250.254", + "ID": "nodeid7", + "TaggedAddresses": { + "wan_ipv4": "10.49.250.254", + "wan": "10.49.250.254", + "lan": "10.49.250.254", + "lan_ipv4": "10.49.250.254" + } + }, + { + "Node": "nodename8", + "Services": [], + "Address": "192.168.183.181", + "ID": "nodeid8", + "TaggedAddresses": { + "wan_ipv4": "192.168.183.181", + "wan": "192.168.183.181", + "lan": "192.168.183.181", + "lan_ipv4": "192.168.183.181" + } + }, + { + "Node": "nodename9", + "Services": [], + "Address": "172.26.223.18", + "ID": "nodeid9", + "TaggedAddresses": { + "wan_ipv4": "172.26.223.18", + "wan": "172.26.223.18", + "lan": "172.26.223.18", + "lan_ipv4": "172.26.223.18" + } + }, + { + "Node": "nodename10", + "Services": [], + "Address": "192.168.110.213", + "ID": "nodeid10", + "TaggedAddresses": { + "wan_ipv4": "192.168.110.213", + "wan": "192.168.110.213", + "lan": "192.168.110.213", + "lan_ipv4": "192.168.110.213" + } + } + + +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_output.json b/ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_output.json new file mode 100644 index 0000000..702a444 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_data/1_initial_test_output.json @@ -0,0 +1,45 @@ +[ +{ + "node_ips": [ + "10.162.26.233" + ], + "node_id": "nodeid0", + "node_name": "nodename0" + }, + { + "node_ips": [ + "192.168.224.114" + ], + "node_id": "nodeid1", + "node_name": "nodename1" + }, +{ + "node_ips": [ + "10.49.250.254" + ], + "node_id": "nodeid7", + "node_name": "nodename7" + }, + { + "node_ips": [ + "192.168.183.181" + ], + "node_id": "nodeid8", + "node_name": "nodename8" + }, + { + "node_ips": [ + "172.26.223.18" + ], + "node_id": "nodeid9", + "node_name": "nodename9" + }, + { + "node_ips": [ + "192.168.110.213" + ], + "node_id": "nodeid10", + "node_name": "nodename10" + } + +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_input.json b/ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_input.json new file mode 100644 index 0000000..206c648 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_input.json @@ -0,0 +1,14 @@ +[ + { + "Node": "nodename0", + "Services": [], + "Address": "10.162.26.233", + "ID": "nodeid0", + "TaggedAddresses": { + "wan_ipv4": "10.162.26.233", + "wan": "192.168.183.181", + "lan": "192.168.224.114", + "lan_ipv4": "10.49.250.254" + } + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_output.json b/ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_output.json new file mode 100644 index 0000000..5354012 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_data/2_same_node_diff_ips_output.json @@ -0,0 +1,13 @@ +[ +{ + "node_ips": [ + "10.162.26.233", + "192.168.183.181", + "192.168.224.114", + "10.49.250.254" + ], + "node_id": "nodeid0", + "node_name": "nodename0" + } + +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_input.json b/ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_output.json b/ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_output.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/node_data/3_empty_node_output.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_input.json b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_input.json new file mode 100644 index 0000000..b2dc855 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_input.json @@ -0,0 +1,91 @@ +{ + "Node": { + "Node": "nodename18" + }, + "Services": [ + { + "Status": "warning", + "Name": "name16", + "Service": "servicename16", + "Notes": "notes16", + "Namespace": "namespace16", + "Port": "1071", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceName": "servicename16", + "ServiceID": "serviceid16", + "Address": "172.21.5.192", + "ServiceKind": "servicekind16", + "Output": "output16", + "Type": "tll", + "ID": "serviceid16" + }, + { + "Status": "passing", + "Name": "name25", + "Service": "servicename25", + "Notes": "notes25", + "Namespace": "namespace25", + "Port": "1072", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceName": "servicename25", + "ServiceID": "serviceid25", + "Address": "172.28.148.48", + "ServiceKind": "servicekind25", + "Output": "output25", + "Type": "tll", + "ID": "serviceid25" + }, + { + "Status": "warning", + "Name": "name0", + "Service": "servicename0", + "Notes": "notes0", + "Namespace": "namespace0", + "Port": "1073", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceName": "servicename0", + "ServiceID": "serviceid0", + "Address": "", + "ServiceKind": "servicekind0", + "Output": "output0", + "Type": "tll", + "ID": "serviceid0" + }, + { + "Status": "passing", + "Name": "name9", + "Service": "servicename9", + "Notes": "notes9", + "Namespace": "namespace9", + "Port": "1074", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceName": "servicename9", + "ServiceID": "serviceid9", + "Address": "172.21.5.192", + "ServiceKind": "servicekind9", + "Output": "output9", + "Type": "tll", + "ID": "serviceid9" + } + ], + "TaggedAddresses": { + "wan_ipv4": "172.21.5.192", + "wan": "172.21.5.192", + "lan": "172.21.5.192", + "lan_ipv4": "172.21.5.192" + }, + "ID": "nodeid18", + "Address": "172.21.5.192" +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_output.json b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_output.json new file mode 100644 index 0000000..98e2c3a --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/1_initial_node_service_output.json @@ -0,0 +1,30 @@ +[ + { + "service_id": "serviceid16", + "service_address": "172.21.5.192:1071", + "service_port": "1071", + "service_ip": "172.21.5.192", + "service_name": "servicename16" + }, + { + "service_id": "serviceid25", + "service_address": "172.28.148.48:1072", + "service_port": "1072", + "service_ip": "172.28.148.48", + "service_name": "servicename25" + }, + { + "service_id": "serviceid0", + "service_address": ":1073", + "service_port": "1073", + "service_ip": "", + "service_name": "servicename0" + }, + { + "service_id": "serviceid9", + "service_address": "172.21.5.192:1074", + "service_port": "1074", + "service_ip": "172.21.5.192", + "service_name": "servicename9" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_input.json b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_input.json new file mode 100644 index 0000000..f3acc08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_input.json @@ -0,0 +1,34 @@ +{ + "Node": { + "Node": "nodename18" + }, + "Services": [ + { + "Status": "warning", + "Name": "name0", + "Service": "servicename0", + "Notes": "notes0", + "Namespace": "namespace0", + "Port": "1073", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceName": "servicename0", + "ServiceID": "serviceid0", + "Address": "", + "ServiceKind": "servicekind0", + "Output": "output0", + "Type": "tll", + "ID": "serviceid0" + } + ], + "TaggedAddresses": { + "wan_ipv4": "172.21.5.192", + "wan": "172.21.5.192", + "lan": "172.21.5.192", + "lan_ipv4": "172.21.5.192" + }, + "ID": "nodeid18", + "Address": "172.21.5.192" +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_output.json b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_output.json new file mode 100644 index 0000000..7088348 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/2_blank_ip_node_service_output.json @@ -0,0 +1,9 @@ +[ + { + "service_id": "serviceid0", + "service_address": ":1073", + "service_port": "1073", + "service_ip": "", + "service_name": "servicename0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_input.json b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_ouput.json b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_ouput.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/nodes_services/3_empty_node_service_ouput.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check.json new file mode 100644 index 0000000..711fd83 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check.json @@ -0,0 +1,78 @@ +[ + { + "Status": "warning", + "CheckID": "2", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename1", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "18", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename8", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "23", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename10", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "66", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename23", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check_output.json new file mode 100644 index 0000000..fa9be4f --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/1_initial_service_check_output.json @@ -0,0 +1 @@ +{"warning": 4} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check_output.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/2_empty_service_check_output.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_input.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_input.json new file mode 100644 index 0000000..a9ee3b5 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_input.json @@ -0,0 +1,78 @@ +[ + { + "Status": "warning", + "CheckID": "2", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename1", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "failing", + "CheckID": "18", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename8", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "passing", + "CheckID": "23", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename10", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "66", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename23", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_output.json new file mode 100644 index 0000000..39af92d --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/3_passing_service_check_output.json @@ -0,0 +1,3 @@ +{"warning": 2, +"passing":1, +"failing":1} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_intput.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_intput.json new file mode 100644 index 0000000..5e29e51 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_intput.json @@ -0,0 +1,78 @@ +[ + { + "Status": "warning", + "CheckID": "2", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename1", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "failing", + "CheckID": "18", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename8", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "info", + "CheckID": "23", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename10", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + }, + { + "Status": "warning", + "CheckID": "66", + "Name": "name12", + "Service": "servicename12", + "Notes": "notes12", + "ServiceName": "servicename12", + "Namespace": "namespace12", + "Node": "nodename23", + "ServiceID": "serviceid12", + "ServiceTags": [ + "global", + "cache" + ], + "ServiceKind": "servicekind12", + "Output": "output12", + "Type": "http", + "ID": "serviceid12" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_output.json b/ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_output.json new file mode 100644 index 0000000..c4888c0 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_check/4_exception_service_check_output.json @@ -0,0 +1,2 @@ +{"warning": 2, +"failing":2} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_info/1_initial_service_info.json b/ConsulExtension/Service/tests/consul_utils/data/service_info/1_initial_service_info.json new file mode 100644 index 0000000..71838f5 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_info/1_initial_service_info.json @@ -0,0 +1,20 @@ +[ + { + "Name": "name10", + "Service": "servicename10", + "Notes": "notes10", + "Namespace": "namespace10", + "ServiceID": "serviceid10", + "Output": "output10", + "ServiceKind": "servicekind10", + "ServiceTags": [ + "global", + "cache" + ], + "Type": "tll", + "ID": "serviceid10", + "Status": "passing", + "ServiceName": "servicename10", + "Address": "192.168.110.213" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_info/2_empty_service_info.json b/ConsulExtension/Service/tests/consul_utils/data/service_info/2_empty_service_info.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_info/2_empty_service_info.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/data/service_info/3_wrong_name_service_info.json b/ConsulExtension/Service/tests/consul_utils/data/service_info/3_wrong_name_service_info.json new file mode 100644 index 0000000..2500017 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/data/service_info/3_wrong_name_service_info.json @@ -0,0 +1,3 @@ +{ + "detail": "Could not resolve the endpoint." +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/consul_utils/fixture_consul_utils.py b/ConsulExtension/Service/tests/consul_utils/fixture_consul_utils.py new file mode 100644 index 0000000..1cb01d0 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/fixture_consul_utils.py @@ -0,0 +1,12 @@ +import pytest + + +class DummyResponse: + pass + + +@pytest.fixture(scope="module", autouse=True) +def get_dummy_response_with_status_200(request): + response = DummyResponse() + response.status_code = 200 + return response diff --git a/ConsulExtension/Service/tests/consul_utils/test_consul_utils.py b/ConsulExtension/Service/tests/consul_utils/test_consul_utils.py new file mode 100644 index 0000000..c57185d --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/test_consul_utils.py @@ -0,0 +1,205 @@ +import requests +import Service.consul_utils +from Service.tests.consul_utils.utils import (create_dummy_session_get_status_code, + verify_nodelist_against_catalog, + verify_nodes_services, + create_dummy_session_get, + verify_node_and_service_checks, + verify_service_info, + verify_datacenter, + verify_detailed_service_check) +import pytest + + +@pytest.mark.parametrize("test_input,expected", + [("200", (True, None)), + ("403", (False, '403: Authentication failed!')), + ("500", (False, '500: Consul Server Error!'))]) +def test_check_connection(test_input, expected): + requests.Session.get = create_dummy_session_get_status_code(test_input) + consul = Service.consul_utils.Consul('', '', '', '') + connection, message = consul.check_connection() + assert connection == expected[0] and message == expected[1] + + +@pytest.mark.parametrize("test_input,expected", + [("/data/node_data/1_initial_test_input.json", + {'method': verify_nodelist_against_catalog, + 'output_file': + '/data/node_data/1_initial_test_output.json'}), + ("/data/node_data/2_same_node_diff_ips_input.json", + {'method': verify_nodelist_against_catalog, + 'output_file': + '/data/node_data/2_same_node_diff_ips_output.json'}), + ("/data/node_data/3_empty_node_input.json", + {'method': verify_nodelist_against_catalog, + 'output_file': + '/data/node_data/3_empty_node_output.json'}) + ]) +def test_nodes(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.nodes() + verifier = expected['method'] + assert verifier(actual_output, expected['output_file']) + + +@pytest.mark.parametrize("test_input,expected", + [(("nodename18", "/data/nodes_services/1_initial_node_service_input.json"), + {'method': verify_nodes_services, + 'output_file': + '/data/nodes_services/1_initial_node_service_output.json'}), + (("nodename19", "/data/nodes_services/2_blank_ip_node_service_input.json"), + {'method': verify_nodes_services, + 'output_file': + '/data/nodes_services/2_blank_ip_node_service_output.json'}), + (("nodename10", "/data/nodes_services/3_empty_node_service_input.json"), + {'method': verify_nodes_services, + 'output_file': + '/data/nodes_services/3_empty_node_service_ouput.json'}) + ]) +def test_nodes_services(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input[1]) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.nodes_services(test_input[0]) + verifier = expected['method'] + assert verifier(actual_output, expected['output_file']) + + +@pytest.mark.parametrize("test_input,expected", + [(("servicename12", + "/data/service_check/1_initial_service_check.json"), + {'method': verify_node_and_service_checks, + 'output_file': + '/data/service_check/1_initial_service_check_output.json'}), + (("servicename12", + "/data/service_check/2_empty_service_check.json"), + {'method': verify_node_and_service_checks, + 'output_file': + '/data/service_check/2_empty_service_check_output.json'}), + (("servicename12", + "/data/service_check/3_passing_service_check_input.json"), + {'method': verify_node_and_service_checks, + 'output_file': + '/data/service_check/3_passing_service_check_output.json'}), + (("servicename12", + "/data/service_check/4_exception_service_check_intput.json"), + {'method': verify_node_and_service_checks, + 'output_file': + '/data/service_check/4_exception_service_check_output.json'}) + ]) +def test_service_checks(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input[1]) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.service_checks(test_input[0]) + + verifier = expected['method'] + assert verifier(actual_output, expected['output_file']) + + +@pytest.mark.parametrize("test_input,expected", [ + (( + "nodename1", "/data/node_check/1_initial_node_check_input.json"), { + 'method': verify_node_and_service_checks, + 'output_file': '/data/node_check/1_initial_node_check_output.json' + }), + (( + "nodename1", "/data/node_check/2_empty_node_check_intput.json"), { + 'method': verify_node_and_service_checks, + 'output_file': '/data/node_check/2_empty_node_check_output.json'}), + (( + "nodename1", "/data/node_check/3_exception_node_check_input.json"), { + 'method': verify_node_and_service_checks, + 'output_file': '/data/node_check/3_exception_node_check_output.json'}) +]) +def test_node_checks(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input[1]) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.service_checks(test_input[0]) + + verifier = expected['method'] + assert verifier(actual_output, expected['output_file']) + + +@pytest.mark.parametrize("test_input,expected", [ + (("nodename1", "/data/service_info/1_initial_service_info.json"), { + 'method': verify_service_info, + 'output': (['cache', 'global'], 'servicekind10', 'namespace10') + }), + (("nodename1", "/data/service_info/2_empty_service_info.json"), { + 'method': verify_service_info, + 'output': ([], "", "") + }), + (("nodename1", "/data/service_info/3_wrong_name_service_info.json"), { + 'method': verify_service_info, + 'output': ([], '', '') + }) +]) +def test_service_info(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input[1]) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.service_info(test_input[0]) + + verifier = expected['method'] + assert verifier(actual_output, expected['output']) + + +@pytest.mark.parametrize("test_input,expected", [ + (("/data/datacenter/1_initial_datacenter.json"), { + 'method': verify_datacenter, + 'output': 'dc1' + }), + (("/data/datacenter/2_empty_datacenter.json"), { + 'method': verify_datacenter, + 'output': '-' + }), + (("/data/datacenter/3_exception_datacenter.json"), { + 'method': verify_datacenter, + 'output': '-' + }) +]) +def test_datacenter(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.datacenter() + verifier = expected['method'] + assert verifier(actual_output, expected['output']) + + +@pytest.mark.parametrize("test_input,expected", [ + (("servicename12", + "serviceid12", + "/data/detailed_service_check/1_initial_detailed_service_check_input.json"), { + 'method': verify_detailed_service_check, + 'output_file': '/data/detailed_service_check/1_initial_detailed_service_check_output.json' + }), + (("servicename12", + "serviceid12", + "/data/detailed_service_check/2_empty_detailed_service_check_input.json"), { + 'method': verify_detailed_service_check, + 'output_file': '/data/detailed_service_check/2_empty_detailed_service_check_output.json' + }) +]) +def test_detailed_service_check(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input[2]) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.detailed_service_check(test_input[0], test_input[1]) + + verifier = expected['method'] + assert verifier(actual_output, expected['output_file']) + + +@pytest.mark.parametrize("test_input,expected", [ + (("nodename1", + "/data/detailed_node_check/1_initial_detailed_node_check_input.json"), { + 'method': verify_detailed_service_check, + 'output_file': '/data/detailed_node_check/1_initial_detailed_node_check_output.json' + }) +]) +def test_detailed_node_check(test_input, expected): + requests.Session.get = create_dummy_session_get(test_input[1]) + consul = Service.consul_utils.Consul('', '', '', '') + actual_output = consul.detailed_node_check(test_input[0]) + + verifier = expected['method'] + assert verifier(actual_output, expected['output_file']) diff --git a/ConsulExtension/Service/tests/consul_utils/utils.py b/ConsulExtension/Service/tests/consul_utils/utils.py new file mode 100644 index 0000000..fb1fcd5 --- /dev/null +++ b/ConsulExtension/Service/tests/consul_utils/utils.py @@ -0,0 +1,109 @@ +import json +import os + + +class DummyResponse: + pass + + +def get_absolue_path(input_file): + dir_path = os.path.dirname(os.path.abspath(__file__)) + print('Dir path : {}'.format(dir_path)) + file_path = r''.join([dir_path, + input_file]) + print('Absolute file path {} '.format(file_path)) + return file_path + + +def parse_json_file(file_path): + with open(file_path) as f: + data = json.load(f) + return data + + +def create_dummy_session_get_status_code(response_code): + def dummy_session(self, url, timeout=0): + response = DummyResponse() + response.status_code = int(response_code) + return response + return dummy_session + + +def create_dummy_session_get(input_file): + file_path = get_absolue_path(input_file) + + def dummy_session(self, url, timeout=0): + response = DummyResponse() + with open(file_path) as f: + response.content = ''.join(f) + print('================ response', response.content) + + return response + return dummy_session + + +def create_dummy_session_with_error_get(input_file): + file_path = get_absolue_path(input_file) + + def dummy_session(self, url, timeout=0): + response = DummyResponse() + with open(file_path) as f: + response.content = ''.join(f) + response.status_code = 404 + print('================ ', response.content) + return response + return dummy_session + + +def verify_nodelist_against_catalog(actual_output, output_file): + output_file = get_absolue_path(output_file) + data = parse_json_file(output_file) + flag = False + for expected_node in data: + flag = any(expected_node['node_id'] == each['node_id'] and set(expected_node['node_ips']) == set(each['node_ips']) for each in actual_output) + if data == actual_output: + flag = True + return flag + + +def verify_nodes_services(actual_output, output_file): + output_file = get_absolue_path(output_file) + data = parse_json_file(output_file) + flag = False + for expected_node in data: + flag = any(expected_node['service_id'] == each['service_id'] and set(expected_node['service_address']) == set(each['service_address']) for each in actual_output) + if data == actual_output: + flag = True + return flag + + +def verify_node_and_service_checks(actual_output, output_file): + output_file = get_absolue_path(output_file) + data = parse_json_file(output_file) + print('=== expected {} '.format(data)) + print('=== actual {} '.format(actual_output)) + if data == actual_output: + return True + else: + shared_items = {k: data[k] for k in data if k in actual_output and data[k] == actual_output[k]} + return len(shared_items.keys()) == len(data.keys()) == len(actual_output.keys()) + + +def verify_service_info(actual_output, expected_output): + if (actual_output[0] == expected_output[0] and actual_output[1] == expected_output[1] and actual_output[2] == expected_output[2]): + return True + else: + return False + + +def verify_datacenter(actual_output, expected_output): + print('=== expected {} '.format(expected_output)) + print('=== actual {} '.format(actual_output)) + if actual_output == expected_output: + return True + else: + return False + + +def verify_detailed_service_check(actual_output, output_file): + return True diff --git a/ConsulExtension/Service/tests/data_fetch/__init__.py b/ConsulExtension/Service/tests/data_fetch/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ConsulExtension/Service/tests/data_fetch/test_data_fetch.py b/ConsulExtension/Service/tests/data_fetch/test_data_fetch.py new file mode 100644 index 0000000..72096cc --- /dev/null +++ b/ConsulExtension/Service/tests/data_fetch/test_data_fetch.py @@ -0,0 +1,198 @@ +from Service import data_fetch +from Service import consul_utils +from Service import threading_util + + +def nodes(self): + response = [ + { + "node_id": "test_node_id" + }, + { + "node_id": "test_node_id2" + } + ] + return response + + +class DummyConsul: + def nodes_services(self, node_name): + response = [ + { + "service_id": "service_id1", + "service_address": "service_address1", + "service_port": "service_port1", + "service_ip": "service_ip1", + "service_name": "service_name1" + }, + { + "service_id": "service_id2", + "service_address": "service_address2", + "service_port": "service_port2", + "service_ip": "service_ip2", + "service_name": "service_name2" + } + ] + return response + + def detailed_node_check(self, node_name): + response = [ + { + "CheckID": "test_CheckID1" + }, + { + "CheckID": "test_CheckID2" + } + ] + return response + + def service_info(self, service_name): + return [ + "test_service_tags", + "test_service_kind", + "test_service_namespace" + ] + + def detailed_service_check(self, service_name, service_id): + response = [ + { + "CheckID": "test_CheckID1" + }, + { + "CheckID": "test_CheckID2" + } + ] + return response + + +def test_get_nodes(): + consul_utils.Consul.nodes = nodes + nodes_dict = threading_util.ThreadSafeDict() + agent = { + "ip": "test_ip", + "port": "test_port", + "token": "test_token", + "protocol": "test_protocol" + } + expected = threading_util.ThreadSafeDict() + expected['test_node_id'] = { + 'agent_addr': ['test_ip:test_port'], + 'node_id': 'test_node_id', + 'agent_consul_obj': None + } + expected['test_node_id2'] = { + 'agent_addr': ['test_ip:test_port'], + 'node_id': 'test_node_id2', + 'agent_consul_obj': None + } + data_fetch.get_nodes(nodes_dict, agent) + assert nodes_dict.keys() == expected.keys() + for key in nodes_dict: + assert nodes_dict[key].keys() == expected[key].keys() + for each in expected[key]: + if each != 'agent_consul_obj': + assert nodes_dict[key][each] == expected[key][each] + + +def test_get_services(): + dummy_consul_obj = DummyConsul() + node = { + "node_name": "node_name", + "agent_consul_obj": dummy_consul_obj, + "node_name": "node_name", + "node_id": "node_id", + "agent_addr": "agent_addr" + } + expected = threading_util.ThreadSafeDict() + expected["service_id1{}".format("node_id")] = { + "service_id": "service_id1", + "service_address": "service_address1", + "service_port": "service_port1", + "service_ip": "service_ip1", + "service_name": "service_name1", + "agent_consul_obj": dummy_consul_obj, + "node_id": "node_id", + "agent_addr": "agent_addr" + } + expected["service_id2{}".format("node_id")] = { + "service_id": "service_id2", + "service_address": "service_address2", + "service_port": "service_port2", + "service_ip": "service_ip2", + "service_name": "service_name2", + "agent_consul_obj": dummy_consul_obj, + "node_id": "node_id", + "agent_addr": "agent_addr" + } + + services_dict = threading_util.ThreadSafeDict() + data_fetch.get_services(services_dict, node) + assert services_dict == expected + + +def test_get_node_checks(): + dummy_consul_obj = DummyConsul() + node_checks_dict = threading_util.ThreadSafeDict() + node = { + "node_name": "node_name", + "agent_consul_obj": dummy_consul_obj, + "node_name": "node_name", + "node_id": "node_id", + "agent_addr": "agent_addr" + } + expected = threading_util.ThreadSafeDict() + expected["test_CheckID1node_id"] = { + "node_id": "node_id", + "node_name": "node_name", + "agent_addr": "agent_addr", + "CheckID": "test_CheckID1" + } + expected["test_CheckID2node_id"] = { + "node_id": "node_id", + "node_name": "node_name", + "agent_addr": "agent_addr", + "CheckID": "test_CheckID2" + } + data_fetch.get_node_checks(node_checks_dict, node) + assert expected == node_checks_dict + + +def test_get_service_info(): + dummy_consul_obj = DummyConsul() + service = { + "service_name": "service_name1", + "agent_consul_obj": dummy_consul_obj + } + expected = { + "service_name": "service_name1", + "agent_consul_obj": dummy_consul_obj, + "service_tags": "test_service_tags", + "service_kind": "test_service_kind", + "service_namespace": "test_service_namespace" + } + data_fetch.get_service_info(service) + assert expected == service + + +def test_get_service_checks(): + dummy_consul_obj = DummyConsul() + service_checks_dict = threading_util.ThreadSafeDict() + service = { + "service_name": "service_name", + "agent_consul_obj": dummy_consul_obj, + "service_id": "service_id", + "agent_addr": "agent_addr" + } + expected = threading_util.ThreadSafeDict() + expected["test_CheckID1service_id"] = { + "service_id": "service_id", + "agent_addr": "agent_addr", + "CheckID": "test_CheckID1" + } + expected["test_CheckID2service_id"] = { + "service_id": "service_id", + "agent_addr": "agent_addr", + "CheckID": "test_CheckID2" + } + data_fetch.get_service_checks(service_checks_dict, service) + assert expected == service_checks_dict diff --git a/ConsulExtension/Service/tests/merge/__init__.py b/ConsulExtension/Service/tests/merge/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ConsulExtension/Service/tests/merge/data/dangling/aci_consul_mappings.json b/ConsulExtension/Service/tests/merge/data/dangling/aci_consul_mappings.json new file mode 100644 index 0000000..b2240c1 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/dangling/aci_consul_mappings.json @@ -0,0 +1 @@ +[{"dn": "uni/tn-tn0/ap-ap0/epg-epg0", "bd": "uni/tn-tn0/ap-ap0/epg-epg0", "ip": "df60:49fd:71b0:d65a:f674:56c8:1151:8a27", "enabled": true, "ap": "ap0", "recommended": true, "vrf": "tn0/", "epg": "epg0", "tenant": "tn0"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/dangling/aci_data.json b/ConsulExtension/Service/tests/merge/data/dangling/aci_data.json new file mode 100644 index 0000000..514380f --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/dangling/aci_data.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "learningSource": "vmm", "VM-Name": "Indeed.", "IP": "df60:49fd:71b0:d65a:f674:56c8:1151:8a27", "VMM-Domain": "ESX0-leaf105", "CEP-Mac": "44:6c:3d:e9:f7:c8", "EPG": "epg0", "AppProfile": "ap0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Provider": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Consumer Interface": ["dummy"]}, "Interfaces": ["Pod-6/Node-104/eth1/6"], "epg_health": "72", "VRF": "tn0/", "controllerName": "vcenter105"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/dangling/consul_data.json b/ConsulExtension/Service/tests/merge/data/dangling/consul_data.json new file mode 100644 index 0000000..4bf564c --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/dangling/consul_data.json @@ -0,0 +1 @@ +[{"node_ips": ["df60:49fd:71b0:d65a:f674:56c8:1151:8a27"], "node_check": {"passing": 1}, "node_id": "nodeid0", "node_services": [], "node_name": "nodename0"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/dangling/final_list.json b/ConsulExtension/Service/tests/merge/data/dangling/final_list.json new file mode 100644 index 0000000..9205f9e --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/dangling/final_list.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "VMM-Domain": "ESX0-leaf105", "CEP-Mac": "44:6c:3d:e9:f7:c8", "node_services": [], "EPG": "epg0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Interfaces": ["Pod-6/Node-104/eth1/6"], "epg_health": "72", "VRF": "tn0/", "fraction": 0, "node_ips": ["df60:49fd:71b0:d65a:f674:56c8:1151:8a27"], "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "Non_IPs": {}, "learningSource": "vmm", "VM-Name": "Indeed.", "IP": "df60:49fd:71b0:d65a:f674:56c8:1151:8a27", "node_check": {"passing": 1}, "AppProfile": "ap0", "node_name": "nodename0", "node_id": "nodeid0", "controllerName": "vcenter105"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/ipv6/aci_consul_mappings.json b/ConsulExtension/Service/tests/merge/data/ipv6/aci_consul_mappings.json new file mode 100644 index 0000000..b05ff0e --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/ipv6/aci_consul_mappings.json @@ -0,0 +1,13 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/ipv6/aci_data.json b/ConsulExtension/Service/tests/merge/data/ipv6/aci_data.json new file mode 100644 index 0000000..526f890 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/ipv6/aci_data.json @@ -0,0 +1,37 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "She.", + "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "VMM-Domain": "ESX0-leaf106", + "CEP-Mac": "a6:62:cc:f7:4c:87", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-103/eth4/6" + ], + "epg_health": "8", + "VRF": "tn0/", + "controllerName": "vcenter106" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/ipv6/consul_data.json b/ConsulExtension/Service/tests/merge/data/ipv6/consul_data.json new file mode 100644 index 0000000..b8162ae --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/ipv6/consul_data.json @@ -0,0 +1,31 @@ +[ + { + "node_ips": [ + "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid0", + "node_services": [ + { + "service_checks": { + "warning": 1 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_name": "servicename0", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000", + "service_ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "service_kind": "servicekind0", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/ipv6/final_list.json b/ConsulExtension/Service/tests/merge/data/ipv6/final_list.json new file mode 100644 index 0000000..66f1ef8 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/ipv6/final_list.json @@ -0,0 +1,66 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf106", + "CEP-Mac": "a6:62:cc:f7:4c:87", + "node_services": [ + { + "service_address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000", + "service_name": "servicename0", + "service_ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 1 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-103/eth4/6" + ], + "epg_health": "8", + "VRF": "tn0/", + "fraction": 0, + "node_ips": [ + "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": {}, + "learningSource": "vmm", + "VM-Name": "She.", + "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename0", + "node_id": "nodeid0", + "controllerName": "vcenter106" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/random_combination/aci_consul_mappings.json b/ConsulExtension/Service/tests/merge/data/random_combination/aci_consul_mappings.json new file mode 100644 index 0000000..bbbb4ea --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/random_combination/aci_consul_mappings.json @@ -0,0 +1,156 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "bd": "uni/tn-tn0/ap-ap1/epg-epg0", + "ip": "10.99.27.147", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "10.6.228.3", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "172.31.192.243", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "bd": "uni/tn-tn0/ap-ap1/epg-epg0", + "ip": "192.168.71.181", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "bd": "uni/tn-tn0/ap-ap1/epg-epg0", + "ip": "10.25.28.100", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "bd": "uni/tn-tn0/ap-ap1/epg-epg1", + "ip": "10.137.44.72", + "enabled": false, + "ap": "ap1", + "recommended": false, + "vrf": "tn0/", + "epg": "epg1", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "10.137.44.72", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg1", + "bd": "uni/tn-tn0/ap-ap0/epg-epg1", + "ip": "10.64.49.230", + "enabled": false, + "ap": "ap0", + "recommended": false, + "vrf": "tn0/", + "epg": "epg1", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "bd": "uni/tn-tn0/ap-ap1/epg-epg1", + "ip": "10.64.49.230", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg1", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "bd": "uni/tn-tn0/ap-ap1/epg-epg1", + "ip": "10.201.143.18", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg1", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "bd": "uni/tn-tn0/ap-ap1/epg-epg1", + "ip": "172.16.17.236", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg1", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "bd": "uni/tn-tn0/ap-ap1/epg-epg1", + "ip": "192.168.147.153", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg1", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "192.168.147.153", + "enabled": false, + "ap": "ap0", + "recommended": false, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "bd": "uni/tn-tn0/ap-ap1/epg-epg0", + "ip": "192.168.147.153", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/random_combination/aci_data.json b/ConsulExtension/Service/tests/merge/data/random_combination/aci_data.json new file mode 100644 index 0000000..9d75911 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/random_combination/aci_data.json @@ -0,0 +1,702 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Fish.", + "IP": "172.31.192.243", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "3f:31:2b:20:38:ea", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername1", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Of.", + "IP": "192.168.147.153", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "61:6d:1f:45:91:27", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername4", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-104/eth4/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg1", + "dn": "uni/tn-tn0/ap-ap0/epg-epg1", + "learningSource": "vmm", + "VM-Name": "True.", + "IP": "10.64.49.230", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "67:fc:d4:2d:c7:0d", + "EPG": "epg1", + "AppProfile": "ap0", + "hostingServerName": "hypername7", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-103/eth0/6" + ], + "epg_health": "19", + "VRF": "tn0/", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "They.", + "IP": "10.137.44.72", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "fc:a4:66:80:1e:33", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-102/eth2/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Eight.", + "IP": "172.20.79.65", + "VMM-Domain": "ESX0-leaf100", + "CEP-Mac": "f0:cb:31:be:ad:18", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-101/eth3/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "controllerName": "vcenter100" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg1", + "dn": "uni/tn-tn0/ap-ap0/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Situation.", + "IP": "172.26.63.162", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "44:ae:46:8b:20:0d", + "EPG": "epg1", + "AppProfile": "ap0", + "hostingServerName": "hypername6", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-101/eth6/6" + ], + "epg_health": "19", + "VRF": "tn0/", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg1", + "dn": "uni/tn-tn0/ap-ap0/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Address.", + "IP": "192.168.131.112", + "VMM-Domain": "ESX0-leaf100", + "CEP-Mac": "94:b2:eb:9b:29:30", + "EPG": "epg1", + "AppProfile": "ap0", + "hostingServerName": "hypername5", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-100/eth4/6" + ], + "epg_health": "19", + "VRF": "tn0/", + "controllerName": "vcenter100" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg1", + "dn": "uni/tn-tn0/ap-ap0/epg-epg1", + "learningSource": "vmm", + "VM-Name": "House.", + "IP": "10.71.130.231", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "6e:1f:03:70:d6:a1", + "EPG": "epg1", + "AppProfile": "ap0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-106/eth2/6" + ], + "epg_health": "19", + "VRF": "tn0/", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "As.", + "IP": "10.6.228.3", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "05:8d:7b:13:84:c0", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername2", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg1", + "dn": "uni/tn-tn0/ap-ap0/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Determine.", + "IP": "172.20.79.65", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "79:ba:1c:e6:5d:c1", + "EPG": "epg1", + "AppProfile": "ap0", + "hostingServerName": "hypername8", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-101/eth3/6" + ], + "epg_health": "19", + "VRF": "tn0/", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Crime.", + "IP": "10.25.28.100", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "40:a5:25:1e:fb:55", + "EPG": "epg0", + "AppProfile": "ap1", + "hostingServerName": "hypername10", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-102/eth1/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Back.", + "IP": "192.168.71.181", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "df:77:e9:ff:01:c7", + "EPG": "epg0", + "AppProfile": "ap1", + "hostingServerName": "hypername11", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-105/eth0/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "learningSource": "vmm", + "VM-Name": "All.", + "IP": "192.168.147.153", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "93:e3:92:61:6c:69", + "EPG": "epg0", + "AppProfile": "ap1", + "hostingServerName": "hypername12", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-104/eth3/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Policy.", + "IP": "192.168.112.168", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "ce:68:06:b3:4f:f1", + "EPG": "epg0", + "AppProfile": "ap1", + "hostingServerName": "hypername6", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-105/eth4/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Indicate.", + "IP": "10.99.27.147", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "4d:4b:91:be:73:17", + "EPG": "epg0", + "AppProfile": "ap1", + "hostingServerName": "hypername13", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-100/eth6/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Fear.", + "IP": "192.168.147.153", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "ab:46:91:24:6d:ca", + "EPG": "epg1", + "AppProfile": "ap1", + "hostingServerName": "hypername15", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-104/eth3/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Specific.", + "IP": "10.137.44.72", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "b4:70:91:68:a5:85", + "EPG": "epg1", + "AppProfile": "ap1", + "hostingServerName": "hypername18", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-106/eth0/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Design.", + "IP": "172.16.17.236", + "VMM-Domain": "ESX0-leaf104", + "CEP-Mac": "26:4c:74:9f:b8:4e", + "EPG": "epg1", + "AppProfile": "ap1", + "hostingServerName": "hypername17", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-104/eth0/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "controllerName": "vcenter104" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Decade.", + "IP": "10.201.143.18", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "21:38:f0:14:c4:23", + "EPG": "epg1", + "AppProfile": "ap1", + "hostingServerName": "hypername16", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-106/eth5/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "learningSource": "vmm", + "VM-Name": "Fire.", + "IP": "10.64.49.230", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "f6:5d:9c:a0:16:4d", + "EPG": "epg1", + "AppProfile": "ap1", + "hostingServerName": "hypername19", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-105/eth1/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "controllerName": "vcenter102" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/random_combination/consul_data.json b/ConsulExtension/Service/tests/merge/data/random_combination/consul_data.json new file mode 100644 index 0000000..a1b299c --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/random_combination/consul_data.json @@ -0,0 +1,1124 @@ +[ + { + "node_ips": [ + "10.196.83.116" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid18", + "node_services": [ + { + "service_checks": { + "passing": 2 + }, + "node_id": "nodeid18", + "service_port": "9000", + "service_name": "servicename8", + "service_namespace": "namespace8", + "service_id": "serviceid8", + "service_address": "10.196.83.116:9000", + "service_ip": "10.196.83.116", + "service_kind": "servicekind8", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid18", + "service_port": "9002", + "service_name": "servicename15", + "service_namespace": "namespace15", + "service_id": "serviceid15", + "service_address": "10.196.83.116:9002", + "service_ip": "10.196.83.116", + "service_kind": "servicekind15", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 3 + }, + "node_id": "nodeid18", + "service_port": "9001", + "service_name": "servicename1", + "service_namespace": "namespace1", + "service_id": "serviceid1", + "service_address": "10.196.83.116:9001", + "service_ip": "10.196.83.116", + "service_kind": "servicekind1", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename18" + }, + { + "node_ips": [ + "10.175.235.170" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid19", + "node_services": [], + "node_name": "nodename19" + }, + { + "node_ips": [ + "172.31.192.243" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid10", + "node_services": [ + { + "service_checks": { + "passing": 5 + }, + "node_id": "nodeid10", + "service_port": "9001", + "service_name": "servicename5", + "service_namespace": "namespace5", + "service_id": "serviceid5", + "service_address": "172.31.192.243:9001", + "service_ip": "172.31.192.243", + "service_kind": "servicekind5", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid10", + "service_port": "9002", + "service_name": "servicename15", + "service_namespace": "namespace15", + "service_id": "serviceid15", + "service_address": "172.27.190.234:9002", + "service_ip": "172.27.190.234", + "service_kind": "servicekind15", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid10", + "service_port": "9000", + "service_name": "servicename13", + "service_namespace": "namespace13", + "service_id": "serviceid13", + "service_address": "172.31.192.243:9000", + "service_ip": "172.31.192.243", + "service_kind": "servicekind13", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename10" + }, + { + "node_ips": [ + "192.168.147.153" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid11", + "node_services": [ + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid11", + "service_port": "9000", + "service_name": "servicename17", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_address": ":9000", + "service_ip": "", + "service_kind": "servicekind17", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename11" + }, + { + "node_ips": [ + "172.31.192.243" + ], + "node_check": { + "failing": 1 + }, + "node_id": "nodeid12", + "node_services": [ + { + "service_checks": { + "passing": 2 + }, + "node_id": "nodeid12", + "service_port": "9002", + "service_name": "servicename10", + "service_namespace": "namespace10", + "service_id": "serviceid10", + "service_address": "192.168.175.2:9002", + "service_ip": "192.168.175.2", + "service_kind": "servicekind10", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid12", + "service_port": "9003", + "service_name": "servicename4", + "service_namespace": "namespace4", + "service_id": "serviceid4", + "service_address": ":9003", + "service_ip": "", + "service_kind": "servicekind4", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid12", + "service_port": "9000", + "service_name": "servicename0", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_address": ":9000", + "service_ip": "", + "service_kind": "servicekind0", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 3 + }, + "node_id": "nodeid12", + "service_port": "9001", + "service_name": "servicename1", + "service_namespace": "namespace1", + "service_id": "serviceid1", + "service_address": "172.24.19.101:9001", + "service_ip": "172.24.19.101", + "service_kind": "servicekind1", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename12" + }, + { + "node_ips": [ + "10.6.228.3" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid13", + "node_services": [ + { + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid13", + "service_port": "9002", + "service_name": "servicename3", + "service_namespace": "namespace3", + "service_id": "serviceid3", + "service_address": "172.25.154.100:9002", + "service_ip": "172.25.154.100", + "service_kind": "servicekind3", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid13", + "service_port": "9001", + "service_name": "servicename19", + "service_namespace": "namespace19", + "service_id": "serviceid19", + "service_address": "172.22.44.232:9001", + "service_ip": "172.22.44.232", + "service_kind": "servicekind19", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 2 + }, + "node_id": "nodeid13", + "service_port": "9000", + "service_name": "servicename8", + "service_namespace": "namespace8", + "service_id": "serviceid8", + "service_address": "10.222.159.204:9000", + "service_ip": "10.222.159.204", + "service_kind": "servicekind8", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename13" + }, + { + "node_ips": [ + "10.6.228.3" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid14", + "node_services": [ + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid14", + "service_port": "9001", + "service_name": "servicename17", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_address": "192.168.2.86:9001", + "service_ip": "192.168.2.86", + "service_kind": "servicekind17", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 2 + }, + "node_id": "nodeid14", + "service_port": "9002", + "service_name": "servicename10", + "service_namespace": "namespace10", + "service_id": "serviceid10", + "service_address": "172.24.98.243:9002", + "service_ip": "172.24.98.243", + "service_kind": "servicekind10", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid14", + "service_port": "9003", + "service_name": "servicename13", + "service_namespace": "namespace13", + "service_id": "serviceid13", + "service_address": "172.23.144.40:9003", + "service_ip": "172.23.144.40", + "service_kind": "servicekind13", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid14", + "service_port": "9000", + "service_name": "servicename0", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_address": "192.168.75.83:9000", + "service_ip": "192.168.75.83", + "service_kind": "servicekind0", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename14" + }, + { + "node_ips": [ + "10.137.44.72" + ], + "node_check": { + "failing": 1 + }, + "node_id": "nodeid15", + "node_services": [], + "node_name": "nodename15" + }, + { + "node_ips": [ + "10.99.27.147" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid16", + "node_services": [ + { + "service_checks": { + "passing": 5 + }, + "node_id": "nodeid16", + "service_port": "9000", + "service_name": "servicename5", + "service_namespace": "namespace5", + "service_id": "serviceid5", + "service_address": "172.27.173.202:9000", + "service_ip": "172.27.173.202", + "service_kind": "servicekind5", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename16" + }, + { + "node_ips": [ + "10.201.143.18" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid17", + "node_services": [ + { + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid17", + "service_port": "9001", + "service_name": "servicename4", + "service_namespace": "namespace4", + "service_id": "serviceid4", + "service_address": ":9001", + "service_ip": "", + "service_kind": "servicekind4", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 5 + }, + "node_id": "nodeid17", + "service_port": "9002", + "service_name": "servicename5", + "service_namespace": "namespace5", + "service_id": "serviceid5", + "service_address": "192.168.177.209:9002", + "service_ip": "192.168.177.209", + "service_kind": "servicekind5", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid17", + "service_port": "9000", + "service_name": "servicename15", + "service_namespace": "namespace15", + "service_id": "serviceid15", + "service_address": "192.168.170.10:9000", + "service_ip": "192.168.170.10", + "service_kind": "servicekind15", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid17", + "service_port": "9003", + "service_name": "servicename7", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_address": "10.201.143.18:9003", + "service_ip": "10.201.143.18", + "service_kind": "servicekind7", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename17" + }, + { + "node_ips": [ + "192.168.147.153" + ], + "node_check": { + "failing": 1 + }, + "node_id": "nodeid6", + "node_services": [ + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid6", + "service_port": "9000", + "service_name": "servicename0", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_address": ":9000", + "service_ip": "", + "service_kind": "servicekind0", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid6", + "service_port": "9002", + "service_name": "servicename19", + "service_namespace": "namespace19", + "service_id": "serviceid19", + "service_address": "192.168.87.52:9002", + "service_ip": "192.168.87.52", + "service_kind": "servicekind19", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 5 + }, + "node_id": "nodeid6", + "service_port": "9003", + "service_name": "servicename5", + "service_namespace": "namespace5", + "service_id": "serviceid5", + "service_address": "192.168.50.104:9003", + "service_ip": "192.168.50.104", + "service_kind": "servicekind5", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid6", + "service_port": "9001", + "service_name": "servicename11", + "service_namespace": "namespace11", + "service_id": "serviceid11", + "service_address": "192.168.181.141:9001", + "service_ip": "192.168.181.141", + "service_kind": "servicekind11", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename6" + }, + { + "node_ips": [ + "192.168.147.153" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid7", + "node_services": [ + { + "service_checks": { + "failing": 3 + }, + "node_id": "nodeid7", + "service_port": "9002", + "service_name": "servicename12", + "service_namespace": "namespace12", + "service_id": "serviceid12", + "service_address": "10.50.92.75:9002", + "service_ip": "10.50.92.75", + "service_kind": "servicekind12", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid7", + "service_port": "9000", + "service_name": "servicename17", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_address": "192.168.147.153:9000", + "service_ip": "192.168.147.153", + "service_kind": "servicekind17", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid7", + "service_port": "9003", + "service_name": "servicename7", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_address": "192.168.147.153:9003", + "service_ip": "192.168.147.153", + "service_kind": "servicekind7", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid7", + "service_port": "9001", + "service_name": "servicename19", + "service_namespace": "namespace19", + "service_id": "serviceid19", + "service_address": "192.168.195.234:9001", + "service_ip": "192.168.195.234", + "service_kind": "servicekind19", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename7" + }, + { + "node_ips": [ + "10.137.44.72" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid4", + "node_services": [ + { + "service_checks": { + "passing": 2 + }, + "node_id": "nodeid4", + "service_port": "9000", + "service_name": "servicename16", + "service_namespace": "namespace16", + "service_id": "serviceid16", + "service_address": "192.168.97.85:9000", + "service_ip": "192.168.97.85", + "service_kind": "servicekind16", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid4", + "service_port": "9001", + "service_name": "servicename13", + "service_namespace": "namespace13", + "service_id": "serviceid13", + "service_address": "10.224.53.125:9001", + "service_ip": "10.224.53.125", + "service_kind": "servicekind13", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename4" + }, + { + "node_ips": [ + "10.25.28.100" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid5", + "node_services": [ + { + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid5", + "service_port": "9000", + "service_name": "servicename6", + "service_namespace": "namespace6", + "service_id": "serviceid6", + "service_address": ":9000", + "service_ip": "", + "service_kind": "servicekind6", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename5" + }, + { + "node_ips": [ + "192.168.107.250" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid2", + "node_services": [ + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid2", + "service_port": "9000", + "service_name": "servicename0", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_address": "10.214.162.194:9000", + "service_ip": "10.214.162.194", + "service_kind": "servicekind0", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename2" + }, + { + "node_ips": [ + "10.201.143.18" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid3", + "node_services": [ + { + "service_checks": { + "passing": 2 + }, + "node_id": "nodeid3", + "service_port": "9000", + "service_name": "servicename16", + "service_namespace": "namespace16", + "service_id": "serviceid16", + "service_address": "10.90.192.241:9000", + "service_ip": "10.90.192.241", + "service_kind": "servicekind16", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid3", + "service_port": "9001", + "service_name": "servicename17", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_address": "192.168.2.181:9001", + "service_ip": "192.168.2.181", + "service_kind": "servicekind17", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid3", + "service_port": "9002", + "service_name": "servicename11", + "service_namespace": "namespace11", + "service_id": "serviceid11", + "service_address": "10.201.143.18:9002", + "service_ip": "10.201.143.18", + "service_kind": "servicekind11", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid3", + "service_port": "9004", + "service_name": "servicename15", + "service_namespace": "namespace15", + "service_id": "serviceid15", + "service_address": "10.201.143.18:9004", + "service_ip": "10.201.143.18", + "service_kind": "servicekind15", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid3", + "service_port": "9003", + "service_name": "servicename3", + "service_namespace": "namespace3", + "service_id": "serviceid3", + "service_address": "172.31.176.211:9003", + "service_ip": "172.31.176.211", + "service_kind": "servicekind3", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename3" + }, + { + "node_ips": [ + "10.137.44.72" + ], + "node_check": { + "failing": 1 + }, + "node_id": "nodeid0", + "node_services": [ + { + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid0", + "service_port": "9001", + "service_name": "servicename19", + "service_namespace": "namespace19", + "service_id": "serviceid19", + "service_address": "10.137.44.72:9001", + "service_ip": "10.137.44.72", + "service_kind": "servicekind19", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_name": "servicename9", + "service_namespace": "namespace9", + "service_id": "serviceid9", + "service_address": "10.137.44.72:9000", + "service_ip": "10.137.44.72", + "service_kind": "servicekind9", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename0" + }, + { + "node_ips": [ + "10.64.49.230" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid1", + "node_services": [ + { + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid1", + "service_port": "9003", + "service_name": "servicename13", + "service_namespace": "namespace13", + "service_id": "serviceid13", + "service_address": "172.30.72.137:9003", + "service_ip": "172.30.72.137", + "service_kind": "servicekind13", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 3 + }, + "node_id": "nodeid1", + "service_port": "9000", + "service_name": "servicename1", + "service_namespace": "namespace1", + "service_id": "serviceid1", + "service_address": ":9000", + "service_ip": "", + "service_kind": "servicekind1", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid1", + "service_port": "9002", + "service_name": "servicename4", + "service_namespace": "namespace4", + "service_id": "serviceid4", + "service_address": "172.28.67.230:9002", + "service_ip": "172.28.67.230", + "service_kind": "servicekind4", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid1", + "service_port": "9001", + "service_name": "servicename3", + "service_namespace": "namespace3", + "service_id": "serviceid3", + "service_address": "10.64.49.230:9001", + "service_ip": "10.64.49.230", + "service_kind": "servicekind3", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename1" + }, + { + "node_ips": [ + "172.16.17.236" + ], + "node_check": { + "failing": 1 + }, + "node_id": "nodeid8", + "node_services": [ + { + "service_checks": { + "failing": 3 + }, + "node_id": "nodeid8", + "service_port": "9002", + "service_name": "servicename12", + "service_namespace": "namespace12", + "service_id": "serviceid12", + "service_address": ":9002", + "service_ip": "", + "service_kind": "servicekind12", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid8", + "service_port": "9004", + "service_name": "servicename6", + "service_namespace": "namespace6", + "service_id": "serviceid6", + "service_address": ":9004", + "service_ip": "", + "service_kind": "servicekind6", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid8", + "service_port": "9000", + "service_name": "servicename9", + "service_namespace": "namespace9", + "service_id": "serviceid9", + "service_address": "172.16.17.236:9000", + "service_ip": "172.16.17.236", + "service_kind": "servicekind9", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 1 + }, + "node_id": "nodeid8", + "service_port": "9001", + "service_name": "servicename18", + "service_namespace": "namespace18", + "service_id": "serviceid18", + "service_address": ":9001", + "service_ip": "", + "service_kind": "servicekind18", + "service_tags": [ + "cache", + "global" + ] + }, + { + "service_checks": { + "passing": 5 + }, + "node_id": "nodeid8", + "service_port": "9003", + "service_name": "servicename5", + "service_namespace": "namespace5", + "service_id": "serviceid5", + "service_address": "192.168.231.70:9003", + "service_ip": "192.168.231.70", + "service_kind": "servicekind5", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename8" + }, + { + "node_ips": [ + "192.168.71.181" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid9", + "node_services": [ + { + "service_checks": { + "failing": 3 + }, + "node_id": "nodeid9", + "service_port": "9000", + "service_name": "servicename12", + "service_namespace": "namespace12", + "service_id": "serviceid12", + "service_address": "10.131.236.146:9000", + "service_ip": "10.131.236.146", + "service_kind": "servicekind12", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename9" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/random_combination/final_list.json b/ConsulExtension/Service/tests/merge/data/random_combination/final_list.json new file mode 100644 index 0000000..28ffc33 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/random_combination/final_list.json @@ -0,0 +1,1462 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "3f:31:2b:20:38:ea", + "node_services": [ + { + "service_address": "172.31.192.243:9001", + "service_name": "servicename5", + "service_ip": "172.31.192.243", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 5 + }, + "node_id": "nodeid10", + "service_port": "9001", + "service_namespace": "namespace5", + "service_id": "serviceid5", + "service_kind": "servicekind5" + }, + { + "service_address": "172.31.192.243:9000", + "service_name": "servicename13", + "service_ip": "172.31.192.243", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid10", + "service_port": "9000", + "service_namespace": "namespace13", + "service_id": "serviceid13", + "service_kind": "servicekind13" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername1", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "172.31.192.243" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Fish.", + "IP": "172.31.192.243", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename10", + "node_id": "nodeid10", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "3f:31:2b:20:38:ea", + "node_services": [ + { + "service_address": ":9003", + "service_name": "servicename4", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid12", + "service_port": "9003", + "service_namespace": "namespace4", + "service_id": "serviceid4", + "service_kind": "servicekind4" + }, + { + "service_address": ":9000", + "service_name": "servicename0", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid12", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername1", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "172.31.192.243" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Fish.", + "IP": "172.31.192.243", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename12", + "node_id": "nodeid12", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "fc:a4:66:80:1e:33", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-102/eth2/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.137.44.72" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "They.", + "IP": "10.137.44.72", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename15", + "node_id": "nodeid15", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "fc:a4:66:80:1e:33", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-102/eth2/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.137.44.72" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "They.", + "IP": "10.137.44.72", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename4", + "node_id": "nodeid4", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "fc:a4:66:80:1e:33", + "node_services": [ + { + "service_address": "10.137.44.72:9001", + "service_name": "servicename19", + "service_ip": "10.137.44.72", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid0", + "service_port": "9001", + "service_namespace": "namespace19", + "service_id": "serviceid19", + "service_kind": "servicekind19" + }, + { + "service_address": "10.137.44.72:9000", + "service_name": "servicename9", + "service_ip": "10.137.44.72", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_namespace": "namespace9", + "service_id": "serviceid9", + "service_kind": "servicekind9" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-102/eth2/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.137.44.72" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "They.", + "IP": "10.137.44.72", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename0", + "node_id": "nodeid0", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "05:8d:7b:13:84:c0", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername2", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.6.228.3" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "As.", + "IP": "10.6.228.3", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename13", + "node_id": "nodeid13", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "05:8d:7b:13:84:c0", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername2", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.6.228.3" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "As.", + "IP": "10.6.228.3", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename14", + "node_id": "nodeid14", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "40:a5:25:1e:fb:55", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename6", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid5", + "service_port": "9000", + "service_namespace": "namespace6", + "service_id": "serviceid6", + "service_kind": "servicekind6" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername10", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-102/eth1/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.25.28.100" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Crime.", + "IP": "10.25.28.100", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename5", + "node_id": "nodeid5", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "df:77:e9:ff:01:c7", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername11", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-105/eth0/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.71.181" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Back.", + "IP": "192.168.71.181", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename9", + "node_id": "nodeid9", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "93:e3:92:61:6c:69", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename17", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid11", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername12", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-104/eth3/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "All.", + "IP": "192.168.147.153", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename11", + "node_id": "nodeid11", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "93:e3:92:61:6c:69", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename0", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid6", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername12", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-104/eth3/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "All.", + "IP": "192.168.147.153", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename6", + "node_id": "nodeid6", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "93:e3:92:61:6c:69", + "node_services": [ + { + "service_address": "192.168.147.153:9000", + "service_name": "servicename17", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid7", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + }, + { + "service_address": "192.168.147.153:9003", + "service_name": "servicename7", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid7", + "service_port": "9003", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_kind": "servicekind7" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername12", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-104/eth3/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "All.", + "IP": "192.168.147.153", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename7", + "node_id": "nodeid7", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "4d:4b:91:be:73:17", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername13", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-100/eth6/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.99.27.147" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Indicate.", + "IP": "10.99.27.147", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename16", + "node_id": "nodeid16", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "ab:46:91:24:6d:ca", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename17", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid11", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername15", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-104/eth3/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fear.", + "IP": "192.168.147.153", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename11", + "node_id": "nodeid11", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "ab:46:91:24:6d:ca", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename0", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid6", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername15", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-104/eth3/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fear.", + "IP": "192.168.147.153", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename6", + "node_id": "nodeid6", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "ab:46:91:24:6d:ca", + "node_services": [ + { + "service_address": "192.168.147.153:9000", + "service_name": "servicename17", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid7", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + }, + { + "service_address": "192.168.147.153:9003", + "service_name": "servicename7", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid7", + "service_port": "9003", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_kind": "servicekind7" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername15", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-104/eth3/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fear.", + "IP": "192.168.147.153", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename7", + "node_id": "nodeid7", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf104", + "CEP-Mac": "26:4c:74:9f:b8:4e", + "node_services": [ + { + "service_address": ":9002", + "service_name": "servicename12", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 3 + }, + "node_id": "nodeid8", + "service_port": "9002", + "service_namespace": "namespace12", + "service_id": "serviceid12", + "service_kind": "servicekind12" + }, + { + "service_address": ":9004", + "service_name": "servicename6", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid8", + "service_port": "9004", + "service_namespace": "namespace6", + "service_id": "serviceid6", + "service_kind": "servicekind6" + }, + { + "service_address": "172.16.17.236:9000", + "service_name": "servicename9", + "service_ip": "172.16.17.236", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid8", + "service_port": "9000", + "service_namespace": "namespace9", + "service_id": "serviceid9", + "service_kind": "servicekind9" + }, + { + "service_address": ":9001", + "service_name": "servicename18", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 1 + }, + "node_id": "nodeid8", + "service_port": "9001", + "service_namespace": "namespace18", + "service_id": "serviceid18", + "service_kind": "servicekind18" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername17", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-104/eth0/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "172.16.17.236" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Design.", + "IP": "172.16.17.236", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename8", + "node_id": "nodeid8", + "controllerName": "vcenter104" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "21:38:f0:14:c4:23", + "node_services": [ + { + "service_address": ":9001", + "service_name": "servicename4", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid17", + "service_port": "9001", + "service_namespace": "namespace4", + "service_id": "serviceid4", + "service_kind": "servicekind4" + }, + { + "service_address": "10.201.143.18:9003", + "service_name": "servicename7", + "service_ip": "10.201.143.18", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid17", + "service_port": "9003", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_kind": "servicekind7" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername16", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-106/eth5/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "10.201.143.18" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Decade.", + "IP": "10.201.143.18", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename17", + "node_id": "nodeid17", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "21:38:f0:14:c4:23", + "node_services": [ + { + "service_address": "10.201.143.18:9002", + "service_name": "servicename11", + "service_ip": "10.201.143.18", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid3", + "service_port": "9002", + "service_namespace": "namespace11", + "service_id": "serviceid11", + "service_kind": "servicekind11" + }, + { + "service_address": "10.201.143.18:9004", + "service_name": "servicename15", + "service_ip": "10.201.143.18", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid3", + "service_port": "9004", + "service_namespace": "namespace15", + "service_id": "serviceid15", + "service_kind": "servicekind15" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername16", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-106/eth5/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "10.201.143.18" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Decade.", + "IP": "10.201.143.18", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename3", + "node_id": "nodeid3", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "f6:5d:9c:a0:16:4d", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename1", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 3 + }, + "node_id": "nodeid1", + "service_port": "9000", + "service_namespace": "namespace1", + "service_id": "serviceid1", + "service_kind": "servicekind1" + }, + { + "service_address": "10.64.49.230:9001", + "service_name": "servicename3", + "service_ip": "10.64.49.230", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid1", + "service_port": "9001", + "service_namespace": "namespace3", + "service_id": "serviceid3", + "service_kind": "servicekind3" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername19", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-105/eth1/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "10.64.49.230" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fire.", + "IP": "10.64.49.230", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename1", + "node_id": "nodeid1", + "controllerName": "vcenter102" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_ep/aci_consul_mappings.json b/ConsulExtension/Service/tests/merge/data/service_to_ep/aci_consul_mappings.json new file mode 100644 index 0000000..b05ff0e --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_ep/aci_consul_mappings.json @@ -0,0 +1,13 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_ep/aci_data.json b/ConsulExtension/Service/tests/merge/data/service_to_ep/aci_data.json new file mode 100644 index 0000000..526f890 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_ep/aci_data.json @@ -0,0 +1,37 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "She.", + "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "VMM-Domain": "ESX0-leaf106", + "CEP-Mac": "a6:62:cc:f7:4c:87", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-103/eth4/6" + ], + "epg_health": "8", + "VRF": "tn0/", + "controllerName": "vcenter106" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_ep/consul_data.json b/ConsulExtension/Service/tests/merge/data/service_to_ep/consul_data.json new file mode 100644 index 0000000..b8162ae --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_ep/consul_data.json @@ -0,0 +1,31 @@ +[ + { + "node_ips": [ + "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b" + ], + "node_check": { + "warning": 1 + }, + "node_id": "nodeid0", + "node_services": [ + { + "service_checks": { + "warning": 1 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_name": "servicename0", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000", + "service_ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "service_kind": "servicekind0", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_ep/final_list.json b/ConsulExtension/Service/tests/merge/data/service_to_ep/final_list.json new file mode 100644 index 0000000..66f1ef8 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_ep/final_list.json @@ -0,0 +1,66 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf106", + "CEP-Mac": "a6:62:cc:f7:4c:87", + "node_services": [ + { + "service_address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000", + "service_name": "servicename0", + "service_ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 1 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-103/eth4/6" + ], + "epg_health": "8", + "VRF": "tn0/", + "fraction": 0, + "node_ips": [ + "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": {}, + "learningSource": "vmm", + "VM-Name": "She.", + "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename0", + "node_id": "nodeid0", + "controllerName": "vcenter106" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_none/aci_consul_mappings.json b/ConsulExtension/Service/tests/merge/data/service_to_none/aci_consul_mappings.json new file mode 100644 index 0000000..30a64b0 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_none/aci_consul_mappings.json @@ -0,0 +1 @@ +[{"dn": "uni/tn-tn0/ap-ap0/epg-epg0", "bd": "uni/tn-tn0/ap-ap0/epg-epg0", "ip": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee", "enabled": true, "ap": "ap0", "recommended": true, "vrf": "tn0/", "epg": "epg0", "tenant": "tn0"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_none/aci_data.json b/ConsulExtension/Service/tests/merge/data/service_to_none/aci_data.json new file mode 100644 index 0000000..3a00c0f --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_none/aci_data.json @@ -0,0 +1,37 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "learningSource": "vmm", + "VM-Name": "Too.", + "IP": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "e3:47:da:1c:b7:50", + "EPG": "epg0", + "AppProfile": "ap0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Provider": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-4/Node-104/eth1/6" + ], + "epg_health": "79", + "VRF": "tn0/", + "controllerName": "vcenter102" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_none/consul_data.json b/ConsulExtension/Service/tests/merge/data/service_to_none/consul_data.json new file mode 100644 index 0000000..1e588de --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_none/consul_data.json @@ -0,0 +1,31 @@ +[ + { + "node_ips": [ + "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee" + ], + "node_check": { + "passing": 1 + }, + "node_id": "nodeid0", + "node_services": [ + { + "service_checks": { + "warning": 1 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_name": "servicename0", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_address": ":9000", + "service_ip": "", + "service_kind": "servicekind0", + "service_tags": [ + "cache", + "global" + ] + } + ], + "node_name": "nodename0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_to_none/final_list.json b/ConsulExtension/Service/tests/merge/data/service_to_none/final_list.json new file mode 100644 index 0000000..28d236c --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_to_none/final_list.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "VMM-Domain": "ESX0-leaf102", "CEP-Mac": "e3:47:da:1c:b7:50", "node_services": [{"service_address": ":9000", "service_name": "servicename0", "service_ip": "", "service_tags": ["cache", "global"], "service_checks": {"warning": 1}, "node_id": "nodeid0", "service_port": "9000", "service_namespace": "namespace0", "service_id": "serviceid0", "service_kind": "servicekind0"}], "EPG": "epg0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Interfaces": ["Pod-4/Node-104/eth1/6"], "epg_health": "79", "VRF": "tn0/", "fraction": 0, "node_ips": ["951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee"], "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "Non_IPs": {}, "learningSource": "vmm", "VM-Name": "Too.", "IP": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee", "node_check": {"passing": 1}, "AppProfile": "ap0", "node_name": "nodename0", "node_id": "nodeid0", "controllerName": "vcenter102"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_without_ip/aci_consul_mappings.json b/ConsulExtension/Service/tests/merge/data/service_without_ip/aci_consul_mappings.json new file mode 100644 index 0000000..2bbda2f --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_without_ip/aci_consul_mappings.json @@ -0,0 +1 @@ +[{"dn": "uni/tn-tn0/ap-ap0/epg-epg0", "bd": "uni/tn-tn0/ap-ap0/epg-epg0", "ip": "b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e", "enabled": true, "ap": "ap0", "recommended": true, "vrf": "tn0/", "epg": "epg0", "tenant": "tn0"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_without_ip/aci_data.json b/ConsulExtension/Service/tests/merge/data/service_without_ip/aci_data.json new file mode 100644 index 0000000..07d1772 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_without_ip/aci_data.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "learningSource": "vmm", "VM-Name": "Name.", "IP": "b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e", "VMM-Domain": "ESX0-leaf103", "CEP-Mac": "93:0f:2a:19:ea:85", "EPG": "epg0", "AppProfile": "ap0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Provider": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Consumer Interface": ["dummy"]}, "Interfaces": ["Pod-3/Node-106/eth2/6"], "epg_health": "24", "VRF": "tn0/", "controllerName": "vcenter103"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_without_ip/consul_data.json b/ConsulExtension/Service/tests/merge/data/service_without_ip/consul_data.json new file mode 100644 index 0000000..a6de83d --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_without_ip/consul_data.json @@ -0,0 +1 @@ +[{"node_ips": ["b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e"], "node_check": {"passing": 1}, "node_id": "nodeid0", "node_services": [], "node_name": "nodename0"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/data/service_without_ip/final_list.json b/ConsulExtension/Service/tests/merge/data/service_without_ip/final_list.json new file mode 100644 index 0000000..2f54ae0 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/data/service_without_ip/final_list.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "VMM-Domain": "ESX0-leaf103", "CEP-Mac": "93:0f:2a:19:ea:85", "node_services": [], "EPG": "epg0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Interfaces": ["Pod-3/Node-106/eth2/6"], "epg_health": "24", "VRF": "tn0/", "fraction": 0, "node_ips": ["b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e"], "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "Non_IPs": {}, "learningSource": "vmm", "VM-Name": "Name.", "IP": "b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e", "node_check": {"passing": 1}, "AppProfile": "ap0", "node_name": "nodename0", "node_id": "nodeid0", "controllerName": "vcenter103"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/merge/test_merge.py b/ConsulExtension/Service/tests/merge/test_merge.py new file mode 100644 index 0000000..df3fcd3 --- /dev/null +++ b/ConsulExtension/Service/tests/merge/test_merge.py @@ -0,0 +1,61 @@ +import json +import pytest +from Service import merge + + +def get_data(case, file_name): + with open('./tests/merge/data/{}/{}'.format(case, file_name), 'r') as fp: + data = json.load(fp) + return data + + +''' +Case1: Dangeling node +Case2: All the data having ipv6 addresses +Case3: Service with different ip as that of Node which mappes to Some EP +Case4: Service with different ip as that of Node which DOES NOT map to any EP +Case5: Service with no ip +Case6: All above combinations +''' +cases = [ + "dangling", + "ipv6", + "service_to_ep", + "service_to_none", + "service_without_ip", + "random_combination" +] + + +def gen_keys_ls(data): + ls = [] + for each in data: + ls.append("{}{}".format( + each.get("dn", ""), + each.get("IP", "") + )) + return ls + + +def get_final_output(original_response, generated_response): + for each in generated_response: + if each not in original_response: + return False + return True + + +@pytest.mark.parametrize("case", cases) +def test_merge_aci_consul(case): + tenant = 'tn0' + aci_data = get_data(case, 'aci_data.json') + consul_data = get_data(case, 'consul_data.json') + aci_consul_mappings = get_data(case, 'aci_consul_mappings.json') + original_response = get_data(case, 'final_list.json') + generated_response = merge.merge_aci_consul(tenant, + aci_data, + consul_data, + aci_consul_mappings + ) + original_response = gen_keys_ls(original_response) + generated_response = gen_keys_ls(generated_response) + assert get_final_output(original_response, generated_response) diff --git a/ConsulExtension/Service/tests/plugin_server/__init__.py b/ConsulExtension/Service/tests/plugin_server/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_input.json b/ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_input.json new file mode 100644 index 0000000..9988fee --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_input.json @@ -0,0 +1,12 @@ +[["10.0.9.251", "10123", "http", "", "1", "dc1", + "2020, 7, 9, 18, 20, 18, 702888", + "2020, 7, 10, 11, 57, 21, 478654", + "2020, 7, 10, 11, 57, 21, 478683"], +["10.0.9.251", "10124", "http", "", "0", "dc1", + "2020, 7, 9, 18, 20, 18, 702888", + "2020, 7, 10, 11, 57, 21, 478654", + "2020, 7, 10, 11, 57, 21, 478683"], +["10.0.9.251", "10125", "http", "", "1", "dc1", + "2020, 7, 9, 18, 20, 18, 702888", + "2020, 7, 10, 11, 57, 21, 478654", + "2020, 7, 10, 11, 57, 21, 478683"]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_output.json b/ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_output.json new file mode 100644 index 0000000..98349de --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/agent_status/1_initial_output.json @@ -0,0 +1 @@ +{"up": 2, "down": 1} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_input.json b/ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_input.json new file mode 100644 index 0000000..6e67d72 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_input.json @@ -0,0 +1,12 @@ +[["10.0.9.251", "10123", "http", "", "1", "dc2", + "2020, 7, 9, 18, 20, 18, 702888", + "2020, 7, 10, 11, 57, 21, 478654", + "2020, 7, 10, 11, 57, 21, 478683"], +["10.0.9.251", "10124", "http", "", "0", "dc1", + "2020, 7, 9, 18, 20, 18, 702888", + "2020, 7, 10, 11, 57, 21, 478654", + "2020, 7, 10, 11, 57, 21, 478683"], +["10.0.9.251", "10125", "http", "", "1", "dc1", + "2020, 7, 9, 18, 20, 18, 702888", + "2020, 7, 10, 11, 57, 21, 478654", + "2020, 7, 10, 11, 57, 21, 478683"]] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_output.json b/ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_output.json new file mode 100644 index 0000000..54e136a --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/agent_status/2_different_dc_output.json @@ -0,0 +1 @@ +{"up": 1, "down": 1} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_input.json b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_output.json b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_output.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_empty_output.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_input.json b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_input.json new file mode 100644 index 0000000..4ced7d9 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_input.json @@ -0,0 +1,70 @@ +[ + { + "service_address": ":1066", + "service_name": "servicename10", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 3 + }, + "node_id": "nodeid16", + "service_port": "1066", + "service_namespace": "namespace10", + "service_id": "serviceid10", + "service_kind": "servicekind10" + }, + { + "service_address": ":1067", + "service_name": "servicename3", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 2 + }, + "node_id": "nodeid16", + "service_port": "1067", + "service_namespace": "namespace3", + "service_id": "serviceid3", + "service_kind": "servicekind3" + }, + { + "service_address": ":1065", + "service_name": "servicename16", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 5 + }, + "node_id": "nodeid16", + "service_port": "1065", + "service_namespace": "namespace16", + "service_id": "serviceid16", + "service_kind": "servicekind16" + }, + { + "service_address": ":1068", + "service_name": "servicename23", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid16", + "service_port": "1068", + "service_namespace": "namespace23", + "service_id": "serviceid23", + "service_kind": "servicekind23" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_output.json b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_output.json new file mode 100644 index 0000000..e58ed24 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/change_key/1_initial_output.json @@ -0,0 +1,58 @@ +[ + { + "service": "servicename10", + "serviceKind": "servicekind10", + "serviceTags": [ + "cache", + "global" + ], + "serviceNamespace": "namespace10", + "serviceChecks": { + "passing": 3 + }, + "port": "1066", + "serviceInstance": "serviceid10" + }, + { + "service": "servicename3", + "serviceKind": "servicekind3", + "serviceTags": [ + "cache", + "global" + ], + "serviceNamespace": "namespace3", + "serviceChecks": { + "passing": 2 + }, + "port": "1067", + "serviceInstance": "serviceid3" + }, + { + "service": "servicename16", + "serviceKind": "servicekind16", + "serviceTags": [ + "cache", + "global" + ], + "serviceNamespace": "namespace16", + "serviceChecks": { + "warning": 5 + }, + "port": "1065", + "serviceInstance": "serviceid16" + }, + { + "service": "servicename23", + "serviceKind": "servicekind23", + "serviceTags": [ + "cache", + "global" + ], + "serviceNamespace": "namespace23", + "serviceChecks": { + "failing": 2 + }, + "port": "1068", + "serviceInstance": "serviceid23" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/dangling.db b/ConsulExtension/Service/tests/plugin_server/data/dangling.db new file mode 100644 index 0000000000000000000000000000000000000000..672c904bc935f2518f4c68c8f02f15f98a5b1a07 GIT binary patch literal 114688 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ÕhonDvj?rs$;pH3>A3t4m!fKIYc)-6-G7(#H|zw$N26~r-R$t%`2^+;p8mOm z-(c?B!NrjTW)RY;mpwBG-*ArGL2f94*@JI7!Ie!<_=a=U4)#*4N5w3{)+FOMo=yDC zXAvIWNHS_n3uIH@>HCDg;nZ+8&*P1z1*S+pE=vC=kRRM2009U<00Izz00bZa0SG_< z0uVTB0`b0dlFSUC^Z$kOXRUB34+J0p0SG_<0uX=z1Rwwb2tWV=K>>RHAD{n&B6th| z2tWV=5P$##AOHafKmY;|IC}!E>;D}I($U!~8%hKL2tWV=5P$##AOHafKmY;|I8_2q z#Sv+ILY9Uvjc0Eb1R+N+D`cDOj$WK8$Nps4|Adok{r5MyXR(I~Qiz|n{vW%Vn0*#| zR1+VLkTf;Fn9Y%Y>dKOupR2|6Z0P!b3oE&Nc5xw3uK(Bi{{No@=})Ih1Umx(2tWV= z5P$##AOHafKmY;|fWX@c4E0OnNq>j|-~WF*Ol%DS2tWV=5P$##AOHafKmY;|cpn7t g{r~qNO4vsTKmY;|fB*y_009U<00Izzz}pG@KOUmT8UO$Q literal 0 HcmV?d00001 diff --git a/ConsulExtension/Service/tests/plugin_server/data/dangling.json b/ConsulExtension/Service/tests/plugin_server/data/dangling.json new file mode 100644 index 0000000..3b66ea6 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/dangling.json @@ -0,0 +1,13 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "10.224.39.129", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/uni/tn-tn0/ap-ap0/epg-epg0", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_output.json new file mode 100644 index 0000000..25b58c3 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/empty_output.json @@ -0,0 +1 @@ +{"status_code": "300", "message": "Error while fetching Audit log details.", "payload": []} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_input.json new file mode 100644 index 0000000..13f5c18 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_input.json @@ -0,0 +1 @@ +{"auditLogRecords": [{"aaaModLR": {"attributes": {"affected": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA/ip-[1.1.1.1]", "descr": "For Tenant DummyTn, application EPG DummyEpg, ACI has detected some fault. Context: 0000.", "created": "1970-1-1T00:00:00.000-01:00", "user": "dummy-user", "ind": "dummy-action", "id": "ID000"}}}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_output.json new file mode 100644 index 0000000..bff054c --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_audit_logs/get_audit_logs_output.json @@ -0,0 +1 @@ +{"status_code": "200", "message": "OK", "payload": [{"affected": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA/ip-[1.1.1.1]", "descr": "For Tenant DummyTn, application EPG DummyEpg, ACI has detected some fault. Context: 0000.", "created": "1970-1-1T00:00:00.000-01:00", "user": "dummy-user", "action": "dummy-action", "id": "ID000"}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_input.json new file mode 100644 index 0000000..eeea239 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_input.json @@ -0,0 +1 @@ +[{"fvCEp": {"attributes": {"mcastAddr": "not-applicable", "mac": "00:00:00:00:00:AA", "lcC": "dummy-lcc", "encap": "dummy-encap"}, "children": []}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_ip.json b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_ip.json new file mode 100644 index 0000000..2b991e4 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_ip.json @@ -0,0 +1 @@ +"1.1.1.1" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_output.json new file mode 100644 index 0000000..cb42339 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvcep_output.json @@ -0,0 +1 @@ +{"status_code": "200", "message": "OK", "payload": [{"ep_name": "dummy-vm-name", "learning_source": "dummy-lcc", "mac": "00:00:00:00:00:AA", "iface_name": ["Pod-0/Node-111/eth0/0"], "encap": "dummy-encap", "hosting_server_name": "1.1.1.1", "ip": "1.1.1.1", "mcast_addr": "---", "ctrlr_name": "hyper000"}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_input.json new file mode 100644 index 0000000..aa449db --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_input.json @@ -0,0 +1 @@ +[{"fvCEp": {"attributes": {"mcastAddr": "not-applicable", "ip": "2.2.2.2", "mac": "00:00:00:00:00:AA", "lcC": "dummy-lcc", "encap": "dummy-encap"}, "children": [{"fvIp": {"attributes": {"addr": "2.2.2.2"}}}]}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_ip.json b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_ip.json new file mode 100644 index 0000000..3cc762b --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_ip.json @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_output.json new file mode 100644 index 0000000..fefb6fc --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/fvip_output.json @@ -0,0 +1 @@ +{"status_code": "200", "message": "OK", "payload": [{"ep_name": "dummy-vm-name", "learning_source": "dummy-lcc", "mac": "00:00:00:00:00:AA", "iface_name": ["Pod-0/Node-111/eth0/0"], "encap": "dummy-encap", "hosting_server_name": "1.1.1.1", "ip": "2.2.2.2", "mcast_addr": "---", "ctrlr_name": "hyper000"}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/get_ep_info.json b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/get_ep_info.json new file mode 100644 index 0000000..f9cca11 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_children_ep_info/get_ep_info.json @@ -0,0 +1,7 @@ +{ + "controller": "hyper000", + "hosting_servername": "1.1.1.1", + "interfaces": ["Pod-0/Node-111/eth0/0"], + "vm_name": "dummy-vm-name", + "vmm_domain": "DUMMY0-leaf000" +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_input.json new file mode 100644 index 0000000..c192918 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_input.json @@ -0,0 +1 @@ +[{"syntheticAccessPolicyInfo": {"attributes": {"pathEp": "topology/pod-1/paths-111/pathep-[dummy-path]", "domain": "uni/vmmp-DummyHost/dom-DummyDom", "accBndlGrp": "uni/dummy/dummy/accportgrp-Dummy-Group", "vLanPool": "uni/dummy/dummy/from-[dummy-lan1]-to-[dummy-lan2]", "accPortP": "uni/dummy/accportprof-Dummy-Profile", "attEntityP": "uni/dummy/attentp-Dummy-AttEntryP", "nodeP": "uni/dummy/nprof-Dummy-Switch"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_output.json new file mode 100644 index 0000000..9b69556 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_configured_access_policies/get_configured_access_policies_output.json @@ -0,0 +1 @@ +{"status_code": "200", "message": "Ok", "payload": [{"node": "111", "switch_prof": "Dummy-Switch", "domain": "DummyHost/DummyDom", "pc_vpc": "Dummy-Group", "aep": "Dummy-AttEntryP", "path_ep": "dummy-path", "iface_prof": "Dummy-Profile", "vlan_pool": "[dummy-lan1]-to-[dummy-lan2]"}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_epg_alias.json b/ConsulExtension/Service/tests/plugin_server/data/get_epg_alias.json new file mode 100644 index 0000000..3a5fdf2 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_epg_alias.json @@ -0,0 +1,10 @@ +[ + { + "dn": "dn", + "expected": "epg_alias" + }, + { + "dn": "dn2", + "expected": "" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_events/empty_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_events/empty_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_events/empty_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_events/empty_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_events/empty_output.json new file mode 100644 index 0000000..3194607 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_events/empty_output.json @@ -0,0 +1 @@ +{"status_code": "300", "message": "Error while fetching Event details.", "payload": []} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_input.json new file mode 100644 index 0000000..28fe0b6 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_input.json @@ -0,0 +1 @@ +{"eventRecords": [{"eventRecord": {"attributes": {"code": "F000", "affected": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA/ip-[1.1.1.1]", "severity": "cleared", "descr": "For Tenant DummyTn, application EPG DummyEpg, ACI has detected some fault. Context: 0000.", "created": "1970-1-1T00:00:00.000-01:00", "cause": "dummy-error"}}}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_output.json new file mode 100644 index 0000000..85bbbb7 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_events/get_events_output.json @@ -0,0 +1 @@ +{"status_code": "200", "message": "OK", "payload": [{"code": "F000", "affected": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA/ip-[1.1.1.1]", "severity": "cleared", "descr": "For Tenant DummyTn, application EPG DummyEpg, ACI has detected some fault. Context: 0000.", "created": "1970-1-1T00:00:00.000-01:00", "cause": "dummy-error"}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_output.json new file mode 100644 index 0000000..e8ac6c7 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_faults/empty_output.json @@ -0,0 +1 @@ +{"status_code": "300", "message": "Error while fetching Fault details.", "payload": []} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_input.json new file mode 100644 index 0000000..b87ff83 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_input.json @@ -0,0 +1 @@ +{"faultRecords": [{"faultRecord": {"attributes": {"code": "F000", "affected": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA/ip-[1.1.1.1]", "severity": "cleared", "descr": "For Tenant DummyTn, application EPG DummyEpg, ACI has detected some fault. Context: 0000.", "created": "1970-1-1T00:00:00.000-01:00", "cause": "dummy-error"}}}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_output.json new file mode 100644 index 0000000..85bbbb7 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_faults/get_faults_output.json @@ -0,0 +1 @@ +{"status_code": "200", "message": "OK", "payload": [{"code": "F000", "affected": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg/cep-00:00:00:00:00:AA/ip-[1.1.1.1]", "severity": "cleared", "descr": "For Tenant DummyTn, application EPG DummyEpg, ACI has detected some fault. Context: 0000.", "created": "1970-1-1T00:00:00.000-01:00", "cause": "dummy-error"}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_input.json new file mode 100644 index 0000000..1a00119 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_input.json @@ -0,0 +1 @@ +[{"vzRFltE": {"attributes": {"etherT": "unspecified"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_output.json new file mode 100644 index 0000000..8c92986 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/1_output.json @@ -0,0 +1 @@ +["*"] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_input.json new file mode 100644 index 0000000..d1ed7c3 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_input.json @@ -0,0 +1 @@ +[{"vzRFltE": {"attributes": {"dToPort": "unspecified", "prot": "unspecified", "sFromPort": "unspecified", "sToPort": "unspecified", "etherT": "dummy", "dFromPort": "unspecified"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_output.json new file mode 100644 index 0000000..fc69939 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/2_output.json @@ -0,0 +1 @@ +["dummy:*:* to *"] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_input.json new file mode 100644 index 0000000..6e36f11 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_input.json @@ -0,0 +1 @@ +[{"vzRFltE": {"attributes": {"dToPort": "unspecified", "prot": "dummy", "sFromPort": "unspecified", "sToPort": "unspecified", "etherT": "dummy", "dFromPort": "unspecified"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_output.json new file mode 100644 index 0000000..68a9965 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/3_output.json @@ -0,0 +1 @@ +["dummy:dummy:* to *"] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_input.json new file mode 100644 index 0000000..803f38d --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_input.json @@ -0,0 +1 @@ +[{"vzRFltE": {"attributes": {"dToPort": "unspecified", "prot": "dummy", "sFromPort": "dummy", "sToPort": "unspecified", "etherT": "dummy", "dFromPort": "unspecified"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_output.json new file mode 100644 index 0000000..68a9965 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/4_output.json @@ -0,0 +1 @@ +["dummy:dummy:* to *"] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_input.json new file mode 100644 index 0000000..afabbd7 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_input.json @@ -0,0 +1 @@ +[{"vzRFltE": {"attributes": {"dToPort": "unspecified", "prot": "dummy", "sFromPort": "dummy", "sToPort": "dummy", "etherT": "dummy", "dFromPort": "unspecified"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_output.json new file mode 100644 index 0000000..d9e17a5 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/5_output.json @@ -0,0 +1 @@ +["dummy:dummy:dummy-dummy to *"] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_input.json new file mode 100644 index 0000000..d072d04 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_input.json @@ -0,0 +1 @@ +[{"vzRFltE": {"attributes": {"dToPort": "unspecified", "prot": "dummy", "sFromPort": "unspecified", "sToPort": "unspecified", "etherT": "dummy", "dFromPort": "dummy"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_output.json new file mode 100644 index 0000000..68a9965 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/6_output.json @@ -0,0 +1 @@ +["dummy:dummy:* to *"] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_input.json new file mode 100644 index 0000000..b96bf61 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_input.json @@ -0,0 +1 @@ +[{"vzRFltE": {"attributes": {"dToPort": "dummy", "prot": "dummy", "sFromPort": "unspecified", "sToPort": "unspecified", "etherT": "dummy", "dFromPort": "dummy"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_output.json new file mode 100644 index 0000000..fd70385 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_filter_list/7_output.json @@ -0,0 +1 @@ +["dummy:dummy:* to dummy-dummy"] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/empty_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/empty_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/empty_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/ingress_egress_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/ingress_egress_input.json new file mode 100644 index 0000000..bd42163 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_ingress_egress/ingress_egress_input.json @@ -0,0 +1 @@ +[{"actrlRuleHitAg15min": {"attributes": {"ingrPktsCum": "11", "egrPktsCum": "22"}}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_input.json b/ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_input.json new file mode 100644 index 0000000..a9e667c --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_input.json @@ -0,0 +1 @@ +[{"vzFromEPg": {"children": [{"vzToEPg": {"attributes": {"epgDefDn": "uni/tn-DummyTn/brc-DummyBrc/dummy/cons-dummy", "epgDn": "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg"}, "children": [{"vzRsRFltAtt": {"attributes": {"tDn": "uni/tn-common/fp-default"}, "children": [{"vzCreatedBy": {"attributes": {"ownerDn": "uni/tn-DummyTn/brc-DummyBrc/subj-DummySubj/rssubjFiltAtt-DummyFilt"}}}]}}]}}]}}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_output.json b/ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_output.json new file mode 100644 index 0000000..74b7bee --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_output.json @@ -0,0 +1 @@ +{"status_code": "200", "message": "", "payload": [{"alias": "DummyAlias", "filter_list": ["flt1", "flt1"], "type": "Consumer", "contract_type": "", "ingr_pkts": "1", "contract_subj": "DummyTn/DummyBrc/DummySubj", "egr_pkts": "1", "to_epg": "DummyTn/DummyAp/DummyEpg"}]} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_input.json b/ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_input.json new file mode 100644 index 0000000..25a6e39 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_input.json @@ -0,0 +1,35 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg2", + "bd": "uni/tn-tn0/ap-ap1/epg-epg2", + "ip": "10.64.230.177", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/vrf0", + "epg": "epg2", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "10.49.30.11", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/vrf1", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "bd": "uni/tn-tn0/ap-ap1/epg-epg0", + "ip": "192.168.17.87", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/vrf0", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_output.json b/ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_output.json new file mode 100644 index 0000000..685775e --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/mapping/1_mapping_initial_output.json @@ -0,0 +1,39 @@ +{ + "status_code": "200", + "message": "OK", + "payload": [ + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg2", + "bd": "uni/tn-tn0/ap-ap1/epg-epg2", + "ip": "10.64.230.177", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/vrf0", + "epg": "epg2", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "10.49.30.11", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/vrf1", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "bd": "uni/tn-tn0/ap-ap1/epg-epg0", + "ip": "192.168.17.87", + "enabled": true, + "ap": "ap1", + "recommended": true, + "vrf": "tn0/vrf0", + "epg": "epg0", + "tenant": "tn0" + } + ] +} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/mapping/2_mapping_exception_output.json b/ConsulExtension/Service/tests/plugin_server/data/mapping/2_mapping_exception_output.json new file mode 100644 index 0000000..d31000e --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/mapping/2_mapping_exception_output.json @@ -0,0 +1 @@ +{"status_code": "300", "message": "Could not load mapping", "payload": {}} \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_input.json b/ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_input.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_input.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_output.json b/ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_output.json new file mode 100644 index 0000000..0464456 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/mapping/3_mapping_empty_output.json @@ -0,0 +1,5 @@ +{ + "status_code": "200", + "message": "OK", + "payload": [] +} diff --git a/ConsulExtension/Service/tests/plugin_server/data/node_to_ep.db b/ConsulExtension/Service/tests/plugin_server/data/node_to_ep.db new file mode 100644 index 0000000000000000000000000000000000000000..672c904bc935f2518f4c68c8f02f15f98a5b1a07 GIT binary patch literal 114688 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ÕhonDvj?rs$;pH3>A3t4m!fKIYc)-6-G7(#H|zw$N26~r-R$t%`2^+;p8mOm z-(c?B!NrjTW)RY;mpwBG-*ArGL2f94*@JI7!Ie!<_=a=U4)#*4N5w3{)+FOMo=yDC zXAvIWNHS_n3uIH@>HCDg;nZ+8&*P1z1*S+pE=vC=kRRM2009U<00Izz00bZa0SG_< z0uVTB0`b0dlFSUC^Z$kOXRUB34+J0p0SG_<0uX=z1Rwwb2tWV=K>>RHAD{n&B6th| z2tWV=5P$##AOHafKmY;|IC}!E>;D}I($U!~8%hKL2tWV=5P$##AOHafKmY;|I8_2q z#Sv+ILY9Uvjc0Eb1R+N+D`cDOj$WK8$Nps4|Adok{r5MyXR(I~Qiz|n{vW%Vn0*#| zR1+VLkTf;Fn9Y%Y>dKOupR2|6Z0P!b3oE&Nc5xw3uK(Bi{{No@=})Ih1Umx(2tWV= z5P$##AOHafKmY;|fWX@c4E0OnNq>j|-~WF*Ol%DS2tWV=5P$##AOHafKmY;|cpn7t g{r~qNO4vsTKmY;|fB*y_009U<00Izzz}pG@KOUmT8UO$Q literal 0 HcmV?d00001 diff --git a/ConsulExtension/Service/tests/plugin_server/data/node_to_ep.json b/ConsulExtension/Service/tests/plugin_server/data/node_to_ep.json new file mode 100644 index 0000000..3b66ea6 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/node_to_ep.json @@ -0,0 +1,13 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "10.224.39.129", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/uni/tn-tn0/ap-ap0/epg-epg0", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/read_creds.json b/ConsulExtension/Service/tests/plugin_server/data/read_creds.json new file mode 100644 index 0000000..2dfe64b --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/read_creds.json @@ -0,0 +1,27 @@ +[ + "empty_agents", + [ + "0.0.0.0", + "1234", + "http", + "", + "True", + "datacenter" + ], + [ + "0.0.0.0", + "1234", + "http", + "", + "True", + "-" + ], + [ + "0.0.0.0", + "1234", + "http", + "", + "False", + "datacenter" + ] +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/saved_mapping.json b/ConsulExtension/Service/tests/plugin_server/data/saved_mapping.json new file mode 100644 index 0000000..2b325a8 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/saved_mapping.json @@ -0,0 +1,47 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap2/epg-epg2", + "bd": "uni/tn-tn0/ap-ap2/epg-epg2", + "ip": "172.23.231.56", + "enabled": true, + "ap": "ap2", + "recommended": true, + "vrf": "tn0/", + "epg": "epg2", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap1/epg-epg3", + "bd": "uni/tn-tn0/ap-ap1/epg-epg3", + "ip": "172.23.231.56", + "enabled": false, + "ap": "ap1", + "recommended": false, + "vrf": "tn0/", + "epg": "epg3", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap2/epg-epg0", + "bd": "uni/tn-tn0/ap-ap2/epg-epg0", + "ip": "172.23.231.56", + "enabled": true, + "ap": "ap2", + "recommended": false, + "vrf": "tn0/", + "epg": "epg0", + "tenant": "tn0" + }, + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg3", + "bd": "uni/tn-tn0/ap-ap0/epg-epg3", + "ip": "10.199.123.148", + "enabled": false, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/", + "epg": "epg3", + "tenant": "tn0" + }, + "fail" +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_both_to_diff_ep.db b/ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_both_to_diff_ep.db new file mode 100644 index 0000000000000000000000000000000000000000..7f7fcff06e241447e2282e6325eecce27735c357 GIT binary patch literal 114688 zcmeI*Pi)&*eg|+;vL#Eg%{W>QlX{KN8Mw9^OD5$wwlxSE+0iCJ96R+mK?YcZph;RL zB8ikl857JFJGPT_fu7pSUVH4J?Qv1;ae=)p&|;1)x`*DThhou1F)8-a_nt(Fl+0NN zNgOBnDvBjO{t@5j_xLEi_e6dE7i*SlO1pNgthv%Wcb8Oh7TsXWq92Z5AeyB$gyiClgxHthlP>NRRTHt9SC7()z}hwEl2yZB|Mq9J}ToKci;5 zwr-canRH>-eqvVq33XR<8+Ct*p}Cq)UeB!gQ}vpuxu&7Ib?Fw_!>zmb3v_!8hb-Qk zT+-^Us_&Wlliqm`Ht*igZ+;=&D|{hMdpVnxXf|e&Gc!U=ydj49F%eZ^59bf%!MK=8 z@y~8EMbjyg`%plTBv3!2o#lX>YgV*M+m2@EO5wrnEBS-BOM*6oU0({!S+vbM28 zSJ|)a`d1*YsP36s$=&m(YL25iHG9`8nf_$DuvW6Pfd5;PHY!ASawsM)r^0mU?vUbH z96sDj#>KHQ{`nM>EtB21D#g~rxqxshkt&Cj&k+3HVit%E2@N?i3~6O!W37;1r_x%x z{L`r&qf631*%g%DK))qq%bAso3i;nYhGyu#uHGrE-jk-iJl$QFrsY{lnIRELpNon4 zv9O4=bXBGGWbkMq!6Ne_-zxK3!yr|R!yb}>$g~n^WXhWE*Xaa`?p!ZUCt`H|ep#(( z8_~ZTM}wCI0(`^EUDYC z8IkT(FDBjT@2U2q{@gPb^-?Kpr(y}z^}RLFDW8W=zsS-f zDey*!ou21nF>!S~>}23cvU4<(jvrm@i;I(!{Bv>)lGA0YnE5Ld_Pjq35&u#&Dqi6X zRwKt0cyGb(QtYJ%&nsT4|NSY=wwHcP-R{kDwPNSY;w3&IZ=wAa5#5WrLry~e#LkJ= zpL+W7P0k$rBpMelU*?aR?@lQvi$(iMUmz&$WEzoU>{(Jbd~-RcV|9kIU*qHA=%_#Y zbZ;X)nLZ}Jfy&`^GR{6-badWaF$f&G%_tb;&D>NZCVn;=cKovC6#6&X{5+W&7$Q%2 z;cqx{#|;7yfB*y_009U<00Izz00bZafzuKw^NF#`E2&#~j-wycEkmXcwB1GiID=sMMkfE1+>(-=r?aziR!+;;)AO>VC^=cq z$=5Q=^UJa@V^|n;|2i;KmY;|fB*y_009U<00Izzz=tG|jE=Dp9;9)BwkD84 z|F}T_0uX=z1Rwwb2tWV=5P$##An*YT;Pd|n99(1#0uX=z1Rwwb2tWV=5P$##AkY%P z=YJFh2tWV=5P$##AOHafKmY;|fWU_@K)?Tw@&6xwoRLEaKmY;|fB*y_009U<00I#B zxCPMv|8d73xrYD*AOHafKmY;|fB*y_0D+G~0H6OqjyNNi5P$##AOHafKmY;|fB*y_ z@No;^^Z&;kf8-tl5P$##AOHafKmY;|fB*zO4uK&d%0-4PZrBovA4iUnO9(&!0uX=z z1Rwwb2tWV=5O}Ks2O>W-l}{y7`O)!Ip35t8CYxQzC`-$k>|�&AFAdTao89C#^a1 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 literal 0 HcmV?d00001 diff --git a/ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_node_to_ep.json b/ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_node_to_ep.json new file mode 100644 index 0000000..2b0fc7e --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_node_to_ep.json @@ -0,0 +1,13 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "10.25.1.98", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/vrf2", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_service_to_ep.db b/ConsulExtension/Service/tests/plugin_server/data/service_node_with_diff_ip_service_to_ep.db new file mode 100644 index 0000000000000000000000000000000000000000..a93b59ab5a62e17d9b1433914714c9fd4eb35dad GIT binary patch literal 114688 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 v^KYOx@UxC5v+6*d7czvZG0YICkoB0uQhO!H~2} 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 literal 0 HcmV?d00001 diff --git a/ConsulExtension/Service/tests/plugin_server/data/service_without_ip.json b/ConsulExtension/Service/tests/plugin_server/data/service_without_ip.json new file mode 100644 index 0000000..203849d --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/data/service_without_ip.json @@ -0,0 +1,13 @@ +[ + { + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "bd": "uni/tn-tn0/ap-ap0/epg-epg0", + "ip": "192.168.228.126", + "enabled": true, + "ap": "ap0", + "recommended": true, + "vrf": "tn0/vrf2", + "epg": "epg0", + "tenant": "tn0" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/plugin_server/test_plugin_server.py b/ConsulExtension/Service/tests/plugin_server/test_plugin_server.py new file mode 100644 index 0000000..597c5e3 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/test_plugin_server.py @@ -0,0 +1,529 @@ +import json +import os +import pytest +import sys +from mock import Mock + +sys.modules['cobra'] = 'cobra' +sys.modules['cobra.model'] = 'cobra.model' +sys.modules['cobra.model.pol'] = Mock(name='Uni') +sys.modules['cobra.model.aaa'] = Mock(name='UserEp') + +from Service import plugin_server +from Service import alchemy_core +from Service import consul_utils +from Service.apic_utils import AciUtils +from Service.tests.plugin_server.utils import (generate_dummy_new_mapping_data, + verify_mapping, + generate_dummy_exception_new_mapping_data, + generate_multiple_dummy_db_output, + generate_dummy_db_output, + verify_change_key, + get_absolue_path, + parse_json_file, + verify_agent_status, + dummy_db_select_exception, + get_data_json, + get_data_str) + + +def get_data(file_name): + with open('./tests/plugin_server/data/{}'.format(file_name), 'r') as fp: + data = json.load(fp) + return data + + +def mapping_key_maker(data, obj_type, datacenter): + dc = dict() + if obj_type == 'dc': + for each in data: + st = "" + st += each.get("ip") + st += each.get("dn") + st += datacenter + st += "1" if each.get("enabled") else "0" + st += each.get("ap") + st += each.get("bd") + st += each.get("vrf") + st += each.get("tenant") + dc[st] = True + else: + for each in data: + st = "" + st += each[0] + st += each[1] + st += each[2] + st += "1" if each[3] else "0" + st += each[4] + st += each[5] + st += each[6] + st += each[7] + dc[st] = True + return dc + + +def check_saved_mapping(db_saved_data, data, datacenter): + data = mapping_key_maker(data, 'dc', datacenter) + db_saved_data = mapping_key_maker(db_saved_data, 'db', datacenter) + for each in db_saved_data: + if each not in data: + return False + return True + + +def read_creds_checker(response, db_data): + response = response.get("payload")[0] + db_data = db_data[0] + if response.get("ip") != db_data[0]: + return False + if response.get("port") != db_data[1]: + return False + if response.get("protocol") != db_data[2]: + return False + if response.get("token") != db_data[3]: + return False + if response.get("status") != bool(db_data[4]): + return False + if response.get("datacenter") != db_data[5]: + return False + return True + + +def check_connection(self): + return True, "message" + + +def datacenter(self): + return "-" + + +consul_utils.Consul.check_connection = check_connection +consul_utils.Consul.datacenter = datacenter +''' +Case 1: Dangeling node +Case 2: Node to EP mapping +Case 3: Service and Node has same ip but not mapped with any EP +Case 4: Service and Node has same ip and mapped with any EP +Case 5: Service and Node has different ip but Service mapped with any EP +Case 6: Service and Node has different ip and Service, Node not mapped with any EP +Case 7: Service and Node has different ip and Service and Node mapped with different EPs +Case 8: Service and Node has different ip and Node mapped with any EP +Case 9: Service without any ip address +''' +get_new_mapping_cases = [ + "dangling", + "node_to_ep", + "service_node_with_same_ip_to_none", + "service_node_with_same_ip_to_ep", + "service_node_with_diff_ip_service_to_ep", + "service_node_with_diff_ip_both_to_none", + "service_node_with_diff_ip_both_to_diff_ep", + "service_node_with_diff_ip_node_to_ep", + "service_without_ip" +] + +mapping_data = get_data('saved_mapping.json') +read_creds_cases = get_data('read_creds.json') +epg_alias_data = get_data('get_epg_alias.json') + + +@pytest.mark.parametrize("case", get_new_mapping_cases) +def test_get_new_mapping(case): + tenant = 'tn0' + datacenter = 'dc1' + + try: + os.system( + 'cp ./tests/plugin_server/data/{}.db ./ConsulDatabase.db'.format(case) + ) + except Exception: + assert False + + new_mapping = plugin_server.get_new_mapping(tenant, datacenter) + original_mapping = get_data('{}.json'.format(case)) + os.remove('./ConsulDatabase.db') + assert new_mapping == original_mapping + + +@pytest.mark.parametrize("mapped_data", mapping_data) +def test_save_mapping(mapped_data): + db_obj = alchemy_core.Database() + db_obj.create_tables() + tenant = 'tn0' + datacenter = 'dc1' + passed_response = { + "payload": "Saved Mappings", + "status_code": "200", + "message": "OK" + } + failed_response = { + "payload": {}, + "status_code": "300", + "message": "Could not save mappings to the database." + } + if mapped_data != "fail": + mapped_data = [mapped_data] + response = json.loads(plugin_server.save_mapping( + tenant, + datacenter, + json.dumps(mapped_data) + )) + assert response == passed_response + connection = db_obj.engine.connect() + db_saved_data = db_obj.select_from_table( + connection, + db_obj.MAPPING_TABLE_NAME + ) + connection.close() + assert check_saved_mapping(db_saved_data, mapped_data, datacenter) + else: + response = json.loads(plugin_server.save_mapping( + tenant, + datacenter, + {} + )) + assert response == failed_response + + os.remove('./ConsulDatabase.db') + + +@pytest.mark.parametrize("case", read_creds_cases) +def test_read_creds(case): + db_obj = alchemy_core.Database() + db_obj.create_tables() + empty_agent_response = { + 'payload': [], + 'status_code': '301', + 'message': 'Agents not found' + } + if case == "empty_agents": + response = json.loads(plugin_server.read_creds()) + assert response == empty_agent_response + else: + data = case + connection = db_obj.engine.connect() + db_obj.insert_and_update( + connection, + db_obj.LOGIN_TABLE_NAME, + data, + { + 'agent_ip': data[0], + 'port': data[1] + } + ) + connection.close() + response = json.loads(plugin_server.read_creds()) + connection = db_obj.engine.connect() + db_data = db_obj.select_from_table(connection, db_obj.LOGIN_TABLE_NAME) + connection.close() + assert read_creds_checker(response, db_data) + os.remove('./ConsulDatabase.db') + + +@pytest.mark.parametrize("case", epg_alias_data) +def test_get_epg_alias(case): + arg = case.get("dn") + expected = case.get("expected") + db_obj = alchemy_core.Database() + db_obj.create_tables() + connection = db_obj.engine.connect() + db_obj.insert_and_update( + connection, + db_obj.EPG_TABLE_NAME, + [ + "dn", + "tenant", + "EPG", + "BD", + "contracts", + "vrf", + "epg_health", + "app_profile", + "epg_alias" + ], + { + "dn": arg + } + ) + connection.close() + response = plugin_server.get_epg_alias(arg) + assert response == expected + os.remove('./ConsulDatabase.db') + + +@pytest.mark.parametrize("data, expected", [ + ("/plugin_server/data/get_faults/get_faults_input.json", + "/plugin_server/data/get_faults/get_faults_output.json"), + ("/plugin_server/data/get_faults/empty_input.json", + "/plugin_server/data/get_faults/empty_output.json") +]) +def test_get_faults(data, expected): + + # Mock apic_util login + + def dummy_login(self): + return "dummy-token" + + def dummy_get_ap_epg_faults(self, dn): + return get_data_json(data) + + AciUtils.login = dummy_login + AciUtils.get_ap_epg_faults = dummy_get_ap_epg_faults + + response = plugin_server.get_faults("uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg") + + assert response == get_data_str(expected) + + +@pytest.mark.parametrize("data, expected", [ + ("/plugin_server/data/get_events/get_events_input.json", + "/plugin_server/data/get_events/get_events_output.json"), + ("/plugin_server/data/get_events/empty_input.json", + "/plugin_server/data/get_events/empty_output.json") +]) +def test_get_events(data, expected): + + def dummy_get_ap_epg_events(self, dn): + return get_data_json(data) + + AciUtils.get_ap_epg_events = dummy_get_ap_epg_events + + response = plugin_server.get_events("uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg") + + assert response == get_data_str(expected) + + +@pytest.mark.parametrize("data, expected", [ + ("/plugin_server/data/get_audit_logs/get_audit_logs_input.json", + "/plugin_server/data/get_audit_logs/get_audit_logs_output.json"), + ("/plugin_server/data/get_audit_logs/empty_input.json", + "/plugin_server/data/get_audit_logs/empty_output.json") +]) +def test_get_audit_logs(data, expected): + + def dummy_get_ap_epg_audit_logs(self, dn): + return get_data_json(data) + + AciUtils.get_ap_epg_audit_logs = dummy_get_ap_epg_audit_logs + + response = plugin_server.get_audit_logs("uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg") + + assert response == get_data_str(expected) + + +@pytest.mark.parametrize("data, expected", [ + ("uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", "DummyTn/DummyAp/DummyEpg"), + ("uni//ap-DummyAp/epg-DummyEpg", "/DummyAp/DummyEpg"), + ("uni/tn-DummyTn//epg-DummyEpg", "DummyTn//DummyEpg"), + ("uni/a-a/a-a/a-a", "/a/a"), + ("dummy-string", "//"), +]) +def test_get_to_epg(data, expected): + + response = plugin_server.get_to_epg(data) + + assert response == expected + + +@pytest.mark.parametrize("data, expected", [ + ("/plugin_server/data/get_ingress_egress/ingress_egress_input.json", + ("11", "22")), + ("/plugin_server/data/get_ingress_egress/empty_input.json", + ("0", "0")) +]) +def test_get_ingress_egress(data, expected): + + def dummy_get_mo_related_item(self, mo_dn, item_query_string, item_type): + return get_data_json(data) + + def dummy_login(self): + return "dummy-token" + + AciUtils.login = dummy_login + AciUtils.get_mo_related_item = dummy_get_mo_related_item + + obj = AciUtils() + response = plugin_server.get_ingress_egress("uni/tn-DummyTn/ap-DummyAp/epg-DummyToEpg", "uni/tn-DummyTn/ap-DummyAp/epg-DummyFromEpg", "subj", "flt", obj) + + assert response == expected + + +@pytest.mark.parametrize("data, expected", [ + ("/plugin_server/data/get_filter_list/1_input.json", + "/plugin_server/data/get_filter_list/1_output.json"), + ("/plugin_server/data/get_filter_list/2_input.json", + "/plugin_server/data/get_filter_list/2_output.json"), + ("/plugin_server/data/get_filter_list/3_input.json", + "/plugin_server/data/get_filter_list/3_output.json"), + ("/plugin_server/data/get_filter_list/4_input.json", + "/plugin_server/data/get_filter_list/4_output.json"), + ("/plugin_server/data/get_filter_list/5_input.json", + "/plugin_server/data/get_filter_list/5_output.json"), + ("/plugin_server/data/get_filter_list/6_input.json", + "/plugin_server/data/get_filter_list/6_output.json"), + ("/plugin_server/data/get_filter_list/7_input.json", + "/plugin_server/data/get_filter_list/7_output.json"), +]) +def test_get_filter_list(data, expected): + + def dummy_get_mo_related_item(self, mo_dn, item_query_string, item_type): + return get_data_json(data) + + def dummy_login(self): + return "dummy-token" + + AciUtils.login = dummy_login + AciUtils.get_mo_related_item = dummy_get_mo_related_item + + obj = AciUtils() + response = plugin_server.get_filter_list("uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", obj) + + assert response == get_data_json(expected) + + +@pytest.mark.parametrize("data, dn, mo_type, mac_list, ip, expected", [ + ("/plugin_server/data/get_children_ep_info/fvcep_input.json", + "", "ep", "00:00:00:00:00:AA", + "/plugin_server/data/get_children_ep_info/fvcep_ip.json", + "/plugin_server/data/get_children_ep_info/fvcep_output.json"), + ("/plugin_server/data/get_children_ep_info/fvip_input.json", + "uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg", "epg", "", + "/plugin_server/data/get_children_ep_info/fvip_ip.json", + "/plugin_server/data/get_children_ep_info/fvip_output.json") +]) +def test_get_children_ep_info(data, dn, mo_type, mac_list, ip, expected): + + def dummy_get_mo_related_item(self, mo_dn, item_query_string, item_type): + return get_data_json(data) + + def dummy_login(self): + return "dummy-token" + + def dummy_get_ep_info(self, ep_attr): + return get_data_json("/plugin_server/data/get_children_ep_info/get_ep_info.json") + + AciUtils.login = dummy_login + AciUtils.get_ep_info = dummy_get_ep_info + AciUtils.get_mo_related_item = dummy_get_mo_related_item + + response = plugin_server.get_children_ep_info(dn, mo_type, mac_list, get_data_json(ip)) + + assert json.loads(response) == get_data_json(expected) + + +@pytest.mark.parametrize("data, expected", [ + ("/plugin_server/data/get_configured_access_policies/get_configured_access_policies_input.json", + "/plugin_server/data/get_configured_access_policies/get_configured_access_policies_output.json") +]) +def test_get_configured_access_policies(data, expected): + + def dummy_get_mo_related_item(self, mo_dn, item_query_string, item_type): + return get_data_json(data) + + def dummy_login(self): + return "dummy-token" + + AciUtils.login = dummy_login + AciUtils.get_mo_related_item = dummy_get_mo_related_item + + response = plugin_server.get_configured_access_policies("DummyTn", "DummyAp", "DummyEpg") + + assert json.loads(response) == get_data_json(expected) + + +@pytest.mark.parametrize("data, expected", [ + ("/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_input.json", + "/plugin_server/data/get_to_epg_traffic/get_to_epg_traffic_output.json") +]) +def test_get_to_epg_traffic(data, expected): + + def dummy_get_all_mo_instances(self, mo_dn, item_query_string): + return get_data_json(data) + + def dummy_login(self): + return "dummy-token" + + def dummy_get_filter_list(flt_attr_tdn, aci_util_obj): + return ["flt1", "flt1"] + + def dummy_get_ingress_egress(from_epg_dn, to_epg_dn, subj_dn, flt_name, aci_util_obj): + return ("1", "1") + + def dummy_get_epg_alias(dn): + return "DummyAlias" + + def dummy_get_to_epg(dn): + return "DummyTn/DummyAp/DummyEpg" + + AciUtils.login = dummy_login + AciUtils.get_to_epg = dummy_get_to_epg + AciUtils.get_all_mo_instances = dummy_get_all_mo_instances + plugin_server.get_filter_list = dummy_get_filter_list + plugin_server.get_ingress_egress = dummy_get_ingress_egress + plugin_server.get_epg_alias = dummy_get_epg_alias + + response = plugin_server.get_to_epg_traffic("uni/tn-DummyTn/ap-DummyAp/epg-DummyEpg") + + assert json.loads(response) == get_data_json(expected) + + +@pytest.mark.parametrize("test_input, expected", + [('/plugin_server/data/mapping/1_mapping_initial_input.json', + {'output': '/plugin_server/data/mapping/1_mapping_initial_output.json', + 'method': verify_mapping}), ('/plugin_server/data/mapping/3_mapping_empty_input.json', + {'output': '/plugin_server/data/mapping/3_mapping_empty_output.json', + 'method': verify_mapping})]) +def test_mapping(test_input, expected): + plugin_server.get_new_mapping = generate_dummy_new_mapping_data(test_input) + actual_output = plugin_server.mapping('', '') + verifier = expected['method'] + assert verifier(actual_output, expected['output']) + + +@pytest.mark.parametrize("test_input, expected", + [('/plugin_server/data/mapping/3_mapping_empty_input.json', + {'output': '/plugin_server/data/mapping/2_mapping_exception_output.json', + 'method': verify_mapping})]) +def test_mapping_exception(test_input, expected): + plugin_server.get_new_mapping = generate_dummy_exception_new_mapping_data() + actual_output = plugin_server.mapping('', '') + verifier = expected['method'] + assert verifier(actual_output, expected['output']) + + +@pytest.mark.parametrize('input, expected', + [(100, ('200', 'Polling Interval Set!')), + (3, ('200', 'Polling Interval Set!'))]) +def test_set_polling_interval(input, expected): + assert plugin_server.set_polling_interval(input), expected + + +@pytest.mark.parametrize('input, expected', + [('/plugin_server/data/change_key/1_initial_input.json', '/plugin_server/data/change_key/1_initial_output.json'), + ('/plugin_server/data/change_key/1_empty_input.json', '/plugin_server/data/change_key/1_empty_output.json'), + (None, [])]) +def test_change_key(input, expected): + services = None + if input: + input_file = get_absolue_path(input) + services = parse_json_file(input_file) + actual_output = plugin_server.change_key(services) + assert verify_change_key(actual_output, expected) + else: + actual_output = plugin_server.change_key(services) + assert actual_output == [] + + +@pytest.mark.parametrize('input, expected', + [('/plugin_server/data/agent_status/1_initial_input.json', '/plugin_server/data/agent_status/1_initial_output.json'), + ('/plugin_server/data/agent_status/2_different_dc_input.json', '/plugin_server/data/agent_status/2_different_dc_output.json'), + (None, [])]) +def test_get_agent_status(input, expected): + if input: + alchemy_core.Database.select_from_table = generate_dummy_db_output(None, input) + actual_output = plugin_server.get_agent_status('dc1') + assert verify_agent_status(actual_output, expected) + else: + alchemy_core.Database.select_from_table = dummy_db_select_exception() + with pytest.raises(Exception): + assert plugin_server.get_agent_status('dc1') diff --git a/ConsulExtension/Service/tests/plugin_server/utils.py b/ConsulExtension/Service/tests/plugin_server/utils.py new file mode 100644 index 0000000..f0cd788 --- /dev/null +++ b/ConsulExtension/Service/tests/plugin_server/utils.py @@ -0,0 +1,112 @@ +from Service.tests.utils import get_absolue_path +from Service.tests.utils import parse_json_file +import json + + +def generate_dummy_new_mapping_data(input_file): + def dummy_get_new_mapping(tenant, datacenter): + file_path = get_absolue_path(input_file) + x = parse_json_file(file_path) + print('=== {}'.format(x)) + return x + return dummy_get_new_mapping + + +def generate_dummy_db_output(formator, expected_file): + def dummy_select_query(self, connection, table_name, primary_key={}): + file_path = get_absolue_path(expected_file) + x = parse_json_file(file_path) + print('=== {}'.format(x)) + if formator: + format(x) + else: + return x + return dummy_select_query + + +def generate_multiple_dummy_db_output(formator, expected_files): + db_outputs = [] + for file in expected_files: + file_path = get_absolue_path(file) + x = parse_json_file(file_path) + # print('=== {}'.format(x)) + if formator: + db_outputs.append(formator(x)) + else: + db_outputs.append(x) + cnt = 0 + print('=== {}'.format(db_outputs)) + while cnt < len(db_outputs): + yield db_outputs[cnt] + cnt = cnt + 1 + + +def dummy_db_select_exception(): + def dummy_select_query(self, connection, table_name, primary_key={}): + raise Exception() + return dummy_select_query + + +def generate_dummy_exception_new_mapping_data(): + def dummy_get_new_mapping(tenant, datacenter): + raise Exception + return dummy_get_new_mapping + + +def compare_dicts(actual, expected): + shared_items = {k: expected[k] for k in expected if k in actual and expected[k] == actual[k]} + return len(shared_items.keys()) == len(expected.keys()) == len(actual.keys()) + + +def compare_obj_list(actual_output, expected_output): + if actual_output == expected_output: + return True + else: + flag = False + for act in actual_output: + for exp in expected_output: + for k, v in exp.items(): + if act[k] == v: + flag = True + else: + flag = False + break + if not flag: + break + if not flag: + break + return flag + + +def verify_mapping(actual_output, expected_file): + file = get_absolue_path(expected_file) + expected_json = parse_json_file(file) + actual_output = ''.join(actual_output) + actual_output = json.loads(actual_output) + print('==== {}'.format(actual_output)) + print('==== {}'.format(expected_json)) + if actual_output == expected_json: + return True + else: + return False + + +def verify_change_key(actual_output, expected_file): + file = get_absolue_path(expected_file) + expected_output = parse_json_file(file) + return compare_obj_list(actual_output, expected_output) + + +def verify_agent_status(actual_output, expected_file): + file = get_absolue_path(expected_file) + expected_output = parse_json_file(file) + print('======== {} {} '.format(actual_output, expected_output)) + return compare_dicts(actual_output, expected_output) + + +def get_data_json(file_name): + return parse_json_file(get_absolue_path(file_name)) + + +def get_data_str(file_name): + return json.dumps(parse_json_file(get_absolue_path(file_name))) diff --git a/ConsulExtension/Service/tests/recommendation/__init__.py b/ConsulExtension/Service/tests/recommendation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ConsulExtension/Service/tests/recommendation/data/ConsulDatabase.db b/ConsulExtension/Service/tests/recommendation/data/ConsulDatabase.db new file mode 100644 index 0000000000000000000000000000000000000000..05eb2395c0218873f2da9eb26cfa7891a8734ad7 GIT binary patch literal 103424 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 literal 0 HcmV?d00001 diff --git a/ConsulExtension/Service/tests/recommendation/data/recommendation_config.cfg b/ConsulExtension/Service/tests/recommendation/data/recommendation_config.cfg new file mode 100644 index 0000000..5054ed5 --- /dev/null +++ b/ConsulExtension/Service/tests/recommendation/data/recommendation_config.cfg @@ -0,0 +1,2 @@ +[IP] +RECOMMENDATION_TEST_IP = 192.168.63.241 \ No newline at end of file diff --git a/ConsulExtension/Service/tests/recommendation/test_recommendation.py b/ConsulExtension/Service/tests/recommendation/test_recommendation.py new file mode 100644 index 0000000..f861713 --- /dev/null +++ b/ConsulExtension/Service/tests/recommendation/test_recommendation.py @@ -0,0 +1,208 @@ +from Service.recommend_utils import (determine_recommendation, + recommended_eps) +from Service.plugin_server import get_apic_data + +import pytest +import sys +from mock import Mock + +sys.modules['cobra'] = 'cobra' +sys.modules['cobra.model'] = 'cobra.model' +sys.modules['cobra.model.pol'] = Mock(name='Uni') +sys.modules['cobra.model.aaa'] = Mock(name='UserEp') + + +import os +import configparser + + +from Service import custom_logger +logger = custom_logger.CustomLogger.get_logger("./app.log") + +DOMAIN_LIST = ['uni/tn-tn0/ap-ap0/epg-epg1', + 'uni/tn-tn0/ap-ap0/epg-epg2', + 'uni/tn-tn0/ap-ap1/epg-epg1'] + +IP_LIST = [] +STATIC_IP_KEY = 'RECOMMENDATION_TEST_IP' + + +class FileCopyException(Exception): + pass + + +def get_conf_value(section, key_name): + """Function to return value from configuration + File + + Args: + key_name (str): Name of key + """ + + dir_path = os.path.dirname(os.path.abspath(__file__)) + print('Dir path : {}'.format(dir_path)) + file_path = r''.join([dir_path, + '/data/recommendation_config.cfg']) + print('################################### file_path : {}'.format(file_path)) + config = configparser.ConfigParser() + + config.read(file_path) + return config.get(section, key_name) + + +@pytest.fixture(scope="module", autouse=True) +def pre_test_setup(request): + # factory will only be invoked once per session - + try: + os_cmd = os.system( + 'cp ./tests/recommendation/data/ConsulDatabase.db ./ConsulDatabase.db') + if os_cmd != 0: + raise FileCopyException('Unable to execute copy command') + print('Test DB successfully copied') + except FileCopyException as e: + print('Exception {}'.format(e)) + + IP_LIST.append(get_conf_value('IP', STATIC_IP_KEY)) + + def delete_db(): + os.remove('./ConsulDatabase.db') + request.addfinalizer(delete_db) + + +@pytest.fixture(scope='class') +def cef_ip_and_fvip_data(): + extract_ap_epgs = {'ap2': {'epg3': 2, 'epg0': 1, 'epg1': 2, 'epg4': 2}, + 'ap0': {'epg2': 2, 'epg0': 1, 'epg1': 2, 'epg4': 1}, + 'ap1': {'epg2': 2, 'epg1': 1, 'epg4': 2}} + + common_eps = [] + common_eps.append({'dn': DOMAIN_LIST[0], + 'IP': IP_LIST[0], 'cep_ip': True}) + common_eps.append({'dn': DOMAIN_LIST[1], + 'IP': IP_LIST[0], 'cep_ip': False}) + common_eps.append({'dn': DOMAIN_LIST[2], + 'IP': IP_LIST[0], 'cep_ip': True}) + apic_data = get_apic_data('tn0') + return extract_ap_epgs, common_eps, apic_data + + +@pytest.fixture(scope='class') +def vrf_data(): + extract_ap_epgs = {'ap2': {'epg3': 2, 'epg0': 1, 'epg1': 2, 'epg4': 2}, + 'ap0': {'epg2': 2, 'epg0': 1, 'epg1': 2, 'epg4': 1}, + 'ap1': {'epg2': 2, 'epg1': 1, 'epg4': 2}} + common_eps = [] + common_eps.append({'dn': DOMAIN_LIST[0], + 'IP': IP_LIST[0], 'cep_ip': False}) + common_eps.append({'dn': DOMAIN_LIST[1], + 'IP': IP_LIST[0], 'cep_ip': False}) + common_eps.append({'dn': DOMAIN_LIST[2], + 'IP': IP_LIST[0], 'cep_ip': False}) + apic_data = get_apic_data('tn0') + return extract_ap_epgs, common_eps, apic_data + + +@pytest.fixture(scope='class') +def ap_data(): + extract_ap_epgs = {'ap2': {'epg3': 2, 'epg0': 1, 'epg1': 2, 'epg4': 2}, + 'ap0': {'epg2': 2, 'epg0': 1, 'epg1': 2, 'epg4': 1}, + 'ap1': {'epg2': 2, 'epg1': 5, 'epg4': 2, }} + common_eps = [] + common_eps.append({'dn': DOMAIN_LIST[0], + 'IP': IP_LIST[0], 'cep_ip': False}) + common_eps.append({'dn': DOMAIN_LIST[1], + 'IP': IP_LIST[0], 'cep_ip': False}) + common_eps.append({'dn': DOMAIN_LIST[2], + 'IP': IP_LIST[0], 'cep_ip': False}) + apic_data = get_apic_data('tn0') + return extract_ap_epgs, common_eps, apic_data + + +@pytest.fixture(scope='class') +def ap_same_count_data(scope='class'): + extract_ap_epgs = {'ap2': {'epg3': 2, 'epg0': 1, 'epg1': 2, 'epg4': 2}, + 'ap0': {'epg2': 2, 'epg0': 1, 'epg1': 2, 'epg4': 1}, + 'ap1': {'epg2': 2, 'epg0': 1, 'epg1': 2, 'epg4': 1}} + common_eps = [] + common_eps.append({'dn': DOMAIN_LIST[0], + 'IP': IP_LIST[0], 'cep_ip': False}) + common_eps.append({'dn': DOMAIN_LIST[1], + 'IP': IP_LIST[0], 'cep_ip': False}) + common_eps.append({'dn': DOMAIN_LIST[2], + 'IP': IP_LIST[0], 'cep_ip': False}) + apic_data = get_apic_data('tn0') + return extract_ap_epgs, common_eps, apic_data + + +def test_recommended_eps(): + source_ip_list = [] + parsed_eps = [] + apic_data = [] + actual_eps = recommended_eps(source_ip_list, + parsed_eps, apic_data) + assert actual_eps == [] + + +def test_determine_recommendation_cef_fvip(cef_ip_and_fvip_data): + source_ip_list, parsed_eps, apic_data = cef_ip_and_fvip_data + expected_eps = [] + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[0], 'No', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[2], 'No', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[1], 'Yes', 'IP']) + actual_eps = determine_recommendation(source_ip_list, + parsed_eps, apic_data) + + assert len(actual_eps) == len(expected_eps) + assert all(item in actual_eps for item in expected_eps) + + +def test_determine_recommendation_vrf(vrf_data): + source_ip_list, parsed_eps, apic_data = vrf_data + expected_eps = [] + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[0], 'No', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[2], 'No', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[1], 'Yes', 'IP']) + actual_eps = determine_recommendation(source_ip_list, + parsed_eps, apic_data) + assert len(actual_eps) == len(expected_eps) + assert all(item in actual_eps for item in expected_eps) + + +def test_determine_recommendation_ap(ap_data): + source_ip_list, parsed_eps, apic_data = ap_data + expected_eps = [] + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[0], 'No', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[2], 'No', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[1], 'Yes', 'IP']) + actual_eps = determine_recommendation(source_ip_list, + parsed_eps, apic_data) + + print('expected {}'.format(expected_eps)) + print('expected {}'.format(actual_eps)) + + assert len(actual_eps) == len(expected_eps) + assert all(item in actual_eps for item in expected_eps) + + +def test_determine_recommendation_same_ap_count(ap_same_count_data): + source_ip_list, parsed_eps, apic_data = ap_same_count_data + expected_eps = [] + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[0], 'No', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[2], 'Yes', 'IP']) + expected_eps.append([IP_LIST[0], + DOMAIN_LIST[1], 'Yes', 'IP']) + actual_eps = determine_recommendation(source_ip_list, + parsed_eps, apic_data) + assert len(actual_eps) == len(expected_eps) + assert all(item in actual_eps for item in expected_eps) diff --git a/ConsulExtension/Service/tests/tree_parser/__init__.py b/ConsulExtension/Service/tests/tree_parser/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ConsulExtension/Service/tests/tree_parser/data/input/dangling.json b/ConsulExtension/Service/tests/tree_parser/data/input/dangling.json new file mode 100644 index 0000000..9205f9e --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/input/dangling.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "VMM-Domain": "ESX0-leaf105", "CEP-Mac": "44:6c:3d:e9:f7:c8", "node_services": [], "EPG": "epg0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Interfaces": ["Pod-6/Node-104/eth1/6"], "epg_health": "72", "VRF": "tn0/", "fraction": 0, "node_ips": ["df60:49fd:71b0:d65a:f674:56c8:1151:8a27"], "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "Non_IPs": {}, "learningSource": "vmm", "VM-Name": "Indeed.", "IP": "df60:49fd:71b0:d65a:f674:56c8:1151:8a27", "node_check": {"passing": 1}, "AppProfile": "ap0", "node_name": "nodename0", "node_id": "nodeid0", "controllerName": "vcenter105"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/input/ipv6.json b/ConsulExtension/Service/tests/tree_parser/data/input/ipv6.json new file mode 100644 index 0000000..66f1ef8 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/input/ipv6.json @@ -0,0 +1,66 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf106", + "CEP-Mac": "a6:62:cc:f7:4c:87", + "node_services": [ + { + "service_address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000", + "service_name": "servicename0", + "service_ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 1 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-103/eth4/6" + ], + "epg_health": "8", + "VRF": "tn0/", + "fraction": 0, + "node_ips": [ + "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": {}, + "learningSource": "vmm", + "VM-Name": "She.", + "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename0", + "node_id": "nodeid0", + "controllerName": "vcenter106" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/input/random_combination.json b/ConsulExtension/Service/tests/tree_parser/data/input/random_combination.json new file mode 100644 index 0000000..28ffc33 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/input/random_combination.json @@ -0,0 +1,1462 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "3f:31:2b:20:38:ea", + "node_services": [ + { + "service_address": "172.31.192.243:9001", + "service_name": "servicename5", + "service_ip": "172.31.192.243", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 5 + }, + "node_id": "nodeid10", + "service_port": "9001", + "service_namespace": "namespace5", + "service_id": "serviceid5", + "service_kind": "servicekind5" + }, + { + "service_address": "172.31.192.243:9000", + "service_name": "servicename13", + "service_ip": "172.31.192.243", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid10", + "service_port": "9000", + "service_namespace": "namespace13", + "service_id": "serviceid13", + "service_kind": "servicekind13" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername1", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "172.31.192.243" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Fish.", + "IP": "172.31.192.243", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename10", + "node_id": "nodeid10", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "3f:31:2b:20:38:ea", + "node_services": [ + { + "service_address": ":9003", + "service_name": "servicename4", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid12", + "service_port": "9003", + "service_namespace": "namespace4", + "service_id": "serviceid4", + "service_kind": "servicekind4" + }, + { + "service_address": ":9000", + "service_name": "servicename0", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid12", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername1", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "172.31.192.243" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Fish.", + "IP": "172.31.192.243", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename12", + "node_id": "nodeid12", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "fc:a4:66:80:1e:33", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-102/eth2/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.137.44.72" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "They.", + "IP": "10.137.44.72", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename15", + "node_id": "nodeid15", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "fc:a4:66:80:1e:33", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-102/eth2/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.137.44.72" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "They.", + "IP": "10.137.44.72", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename4", + "node_id": "nodeid4", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf103", + "CEP-Mac": "fc:a4:66:80:1e:33", + "node_services": [ + { + "service_address": "10.137.44.72:9001", + "service_name": "servicename19", + "service_ip": "10.137.44.72", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid0", + "service_port": "9001", + "service_namespace": "namespace19", + "service_id": "serviceid19", + "service_kind": "servicekind19" + }, + { + "service_address": "10.137.44.72:9000", + "service_name": "servicename9", + "service_ip": "10.137.44.72", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_namespace": "namespace9", + "service_id": "serviceid9", + "service_kind": "servicekind9" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername3", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-102/eth2/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.137.44.72" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "They.", + "IP": "10.137.44.72", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename0", + "node_id": "nodeid0", + "controllerName": "vcenter103" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "05:8d:7b:13:84:c0", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername2", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.6.228.3" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "As.", + "IP": "10.6.228.3", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename13", + "node_id": "nodeid13", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "05:8d:7b:13:84:c0", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername2", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-105/eth0/6" + ], + "epg_health": "26", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.6.228.3" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "As.", + "IP": "10.6.228.3", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename14", + "node_id": "nodeid14", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "40:a5:25:1e:fb:55", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename6", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid5", + "service_port": "9000", + "service_namespace": "namespace6", + "service_id": "serviceid6", + "service_kind": "servicekind6" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername10", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-102/eth1/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.25.28.100" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Crime.", + "IP": "10.25.28.100", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename5", + "node_id": "nodeid5", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "df:77:e9:ff:01:c7", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername11", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-105/eth0/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.71.181" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Back.", + "IP": "192.168.71.181", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename9", + "node_id": "nodeid9", + "controllerName": "vcenter102" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "93:e3:92:61:6c:69", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename17", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid11", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername12", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-104/eth3/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "All.", + "IP": "192.168.147.153", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename11", + "node_id": "nodeid11", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "93:e3:92:61:6c:69", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename0", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid6", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername12", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-104/eth3/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "All.", + "IP": "192.168.147.153", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename6", + "node_id": "nodeid6", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "93:e3:92:61:6c:69", + "node_services": [ + { + "service_address": "192.168.147.153:9000", + "service_name": "servicename17", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid7", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + }, + { + "service_address": "192.168.147.153:9003", + "service_name": "servicename7", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid7", + "service_port": "9003", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_kind": "servicekind7" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername12", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-6/Node-104/eth3/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "All.", + "IP": "192.168.147.153", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename7", + "node_id": "nodeid7", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg0", + "VMM-Domain": "ESX0-leaf105", + "CEP-Mac": "4d:4b:91:be:73:17", + "node_services": [], + "EPG": "epg0", + "hostingServerName": "hypername13", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-2/Node-100/eth6/6" + ], + "epg_health": "18", + "VRF": "tn0/", + "fraction": 3, + "node_ips": [ + "10.99.27.147" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg0", + "Non_IPs": { + "ce:68:06:b3:4f:f1": "192.168.112.168", + "f0:cb:31:be:ad:18": "172.20.79.65", + "61:6d:1f:45:91:27": "192.168.147.153" + }, + "learningSource": "vmm", + "VM-Name": "Indicate.", + "IP": "10.99.27.147", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename16", + "node_id": "nodeid16", + "controllerName": "vcenter105" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "ab:46:91:24:6d:ca", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename17", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid11", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername15", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-104/eth3/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fear.", + "IP": "192.168.147.153", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename11", + "node_id": "nodeid11", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "ab:46:91:24:6d:ca", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename0", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid6", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername15", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-104/eth3/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fear.", + "IP": "192.168.147.153", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename6", + "node_id": "nodeid6", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "ab:46:91:24:6d:ca", + "node_services": [ + { + "service_address": "192.168.147.153:9000", + "service_name": "servicename17", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 4 + }, + "node_id": "nodeid7", + "service_port": "9000", + "service_namespace": "namespace17", + "service_id": "serviceid17", + "service_kind": "servicekind17" + }, + { + "service_address": "192.168.147.153:9003", + "service_name": "servicename7", + "service_ip": "192.168.147.153", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid7", + "service_port": "9003", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_kind": "servicekind7" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername15", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-5/Node-104/eth3/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "192.168.147.153" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fear.", + "IP": "192.168.147.153", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename7", + "node_id": "nodeid7", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf104", + "CEP-Mac": "26:4c:74:9f:b8:4e", + "node_services": [ + { + "service_address": ":9002", + "service_name": "servicename12", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 3 + }, + "node_id": "nodeid8", + "service_port": "9002", + "service_namespace": "namespace12", + "service_id": "serviceid12", + "service_kind": "servicekind12" + }, + { + "service_address": ":9004", + "service_name": "servicename6", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid8", + "service_port": "9004", + "service_namespace": "namespace6", + "service_id": "serviceid6", + "service_kind": "servicekind6" + }, + { + "service_address": "172.16.17.236:9000", + "service_name": "servicename9", + "service_ip": "172.16.17.236", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid8", + "service_port": "9000", + "service_namespace": "namespace9", + "service_id": "serviceid9", + "service_kind": "servicekind9" + }, + { + "service_address": ":9001", + "service_name": "servicename18", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 1 + }, + "node_id": "nodeid8", + "service_port": "9001", + "service_namespace": "namespace18", + "service_id": "serviceid18", + "service_kind": "servicekind18" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername17", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-104/eth0/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "172.16.17.236" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Design.", + "IP": "172.16.17.236", + "node_check": { + "failing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename8", + "node_id": "nodeid8", + "controllerName": "vcenter104" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "21:38:f0:14:c4:23", + "node_services": [ + { + "service_address": ":9001", + "service_name": "servicename4", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid17", + "service_port": "9001", + "service_namespace": "namespace4", + "service_id": "serviceid4", + "service_kind": "servicekind4" + }, + { + "service_address": "10.201.143.18:9003", + "service_name": "servicename7", + "service_ip": "10.201.143.18", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "failing": 2 + }, + "node_id": "nodeid17", + "service_port": "9003", + "service_namespace": "namespace7", + "service_id": "serviceid7", + "service_kind": "servicekind7" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername16", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-106/eth5/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "10.201.143.18" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Decade.", + "IP": "10.201.143.18", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename17", + "node_id": "nodeid17", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf101", + "CEP-Mac": "21:38:f0:14:c4:23", + "node_services": [ + { + "service_address": "10.201.143.18:9002", + "service_name": "servicename11", + "service_ip": "10.201.143.18", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 2 + }, + "node_id": "nodeid3", + "service_port": "9002", + "service_namespace": "namespace11", + "service_id": "serviceid11", + "service_kind": "servicekind11" + }, + { + "service_address": "10.201.143.18:9004", + "service_name": "servicename15", + "service_ip": "10.201.143.18", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 4 + }, + "node_id": "nodeid3", + "service_port": "9004", + "service_namespace": "namespace15", + "service_id": "serviceid15", + "service_kind": "servicekind15" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername16", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-1/Node-106/eth5/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "10.201.143.18" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Decade.", + "IP": "10.201.143.18", + "node_check": { + "passing": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename3", + "node_id": "nodeid3", + "controllerName": "vcenter101" + }, + { + "BD": "uni/tn-tn0/ap-ap1/epg-epg1", + "VMM-Domain": "ESX0-leaf102", + "CEP-Mac": "f6:5d:9c:a0:16:4d", + "node_services": [ + { + "service_address": ":9000", + "service_name": "servicename1", + "service_ip": "", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "passing": 3 + }, + "node_id": "nodeid1", + "service_port": "9000", + "service_namespace": "namespace1", + "service_id": "serviceid1", + "service_kind": "servicekind1" + }, + { + "service_address": "10.64.49.230:9001", + "service_name": "servicename3", + "service_ip": "10.64.49.230", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 3 + }, + "node_id": "nodeid1", + "service_port": "9001", + "service_namespace": "namespace3", + "service_id": "serviceid3", + "service_kind": "servicekind3" + } + ], + "EPG": "epg1", + "hostingServerName": "hypername19", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-3/Node-105/eth1/6" + ], + "epg_health": "74", + "VRF": "tn0/", + "fraction": 6, + "node_ips": [ + "10.64.49.230" + ], + "dn": "uni/tn-tn0/ap-ap1/epg-epg1", + "Non_IPs": { + "94:b2:eb:9b:29:30": "192.168.131.112", + "b4:70:91:68:a5:85": "10.137.44.72", + "44:ae:46:8b:20:0d": "172.26.63.162", + "79:ba:1c:e6:5d:c1": "172.20.79.65", + "67:fc:d4:2d:c7:0d": "10.64.49.230", + "6e:1f:03:70:d6:a1": "10.71.130.231" + }, + "learningSource": "vmm", + "VM-Name": "Fire.", + "IP": "10.64.49.230", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap1", + "node_name": "nodename1", + "node_id": "nodeid1", + "controllerName": "vcenter102" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/input/service_to_ep.json b/ConsulExtension/Service/tests/tree_parser/data/input/service_to_ep.json new file mode 100644 index 0000000..66f1ef8 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/input/service_to_ep.json @@ -0,0 +1,66 @@ +[ + { + "BD": "uni/tn-tn0/ap-ap0/epg-epg0", + "VMM-Domain": "ESX0-leaf106", + "CEP-Mac": "a6:62:cc:f7:4c:87", + "node_services": [ + { + "service_address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000", + "service_name": "servicename0", + "service_ip": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "service_tags": [ + "cache", + "global" + ], + "service_checks": { + "warning": 1 + }, + "node_id": "nodeid0", + "service_port": "9000", + "service_namespace": "namespace0", + "service_id": "serviceid0", + "service_kind": "servicekind0" + } + ], + "EPG": "epg0", + "hostingServerName": "hypername0", + "Contracts": { + "IntraEpg": [ + "dummy" + ], + "Consumer Interface": [ + "dummy" + ], + "Consumer": [ + "dummy" + ], + "Taboo": [ + "dummy" + ], + "Provider": [ + "dummy" + ] + }, + "Interfaces": [ + "Pod-0/Node-103/eth4/6" + ], + "epg_health": "8", + "VRF": "tn0/", + "fraction": 0, + "node_ips": [ + "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b" + ], + "dn": "uni/tn-tn0/ap-ap0/epg-epg0", + "Non_IPs": {}, + "learningSource": "vmm", + "VM-Name": "She.", + "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", + "node_check": { + "warning": 1 + }, + "AppProfile": "ap0", + "node_name": "nodename0", + "node_id": "nodeid0", + "controllerName": "vcenter106" + } +] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/input/service_to_none.json b/ConsulExtension/Service/tests/tree_parser/data/input/service_to_none.json new file mode 100644 index 0000000..28d236c --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/input/service_to_none.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "VMM-Domain": "ESX0-leaf102", "CEP-Mac": "e3:47:da:1c:b7:50", "node_services": [{"service_address": ":9000", "service_name": "servicename0", "service_ip": "", "service_tags": ["cache", "global"], "service_checks": {"warning": 1}, "node_id": "nodeid0", "service_port": "9000", "service_namespace": "namespace0", "service_id": "serviceid0", "service_kind": "servicekind0"}], "EPG": "epg0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Interfaces": ["Pod-4/Node-104/eth1/6"], "epg_health": "79", "VRF": "tn0/", "fraction": 0, "node_ips": ["951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee"], "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "Non_IPs": {}, "learningSource": "vmm", "VM-Name": "Too.", "IP": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee", "node_check": {"passing": 1}, "AppProfile": "ap0", "node_name": "nodename0", "node_id": "nodeid0", "controllerName": "vcenter102"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/input/service_without_ip.json b/ConsulExtension/Service/tests/tree_parser/data/input/service_without_ip.json new file mode 100644 index 0000000..2f54ae0 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/input/service_without_ip.json @@ -0,0 +1 @@ +[{"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "VMM-Domain": "ESX0-leaf103", "CEP-Mac": "93:0f:2a:19:ea:85", "node_services": [], "EPG": "epg0", "hostingServerName": "hypername0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Interfaces": ["Pod-3/Node-106/eth2/6"], "epg_health": "24", "VRF": "tn0/", "fraction": 0, "node_ips": ["b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e"], "dn": "uni/tn-tn0/ap-ap0/epg-epg0", "Non_IPs": {}, "learningSource": "vmm", "VM-Name": "Name.", "IP": "b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e", "node_check": {"passing": 1}, "AppProfile": "ap0", "node_name": "nodename0", "node_id": "nodeid0", "controllerName": "vcenter103"}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/output/dangling.json b/ConsulExtension/Service/tests/tree_parser/data/output/dangling.json new file mode 100644 index 0000000..3425d77 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/output/dangling.json @@ -0,0 +1 @@ +[{"name": "AppProf", "sub_label": "ap0", "checks": {"passing": 1}, "attributes": {}, "type": "#581552", "children": [{"name": "EPG", "sub_label": "epg0", "children": [{"name": "EP", "sub_label": "Indeed.", "label": "nodename0", "children": [], "attributes": {"Node": "nodename0", "Node Checks": {"passing": 1}, "Reporting Node IP": "df60:49fd:71b0:d65a:f674:56c8:1151:8a27", "IP": "df60:49fd:71b0:d65a:f674:56c8:1151:8a27", "Interfaces": ["Pod-6/Node-104/eth1/6"], "Mac": "44:6c:3d:e9:f7:c8", "VMM-Domain": "ESX0-leaf105", "Services_List": []}, "type": "#2DBBAD", "checks": {"passing": 1}}], "fraction": 0, "attributes": {"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename0", "Reporting Node IP": "df60:49fd:71b0:d65a:f674:56c8:1151:8a27", "Node Checks": {"passing": 1}}], "VRF": "tn0/", "Services_List": []}, "label": "", "type": "#085A87", "checks": {"passing": 1}}]}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/output/ipv6.json b/ConsulExtension/Service/tests/tree_parser/data/output/ipv6.json new file mode 100644 index 0000000..750bcb8 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/output/ipv6.json @@ -0,0 +1 @@ +[{"name": "AppProf", "sub_label": "ap0", "checks": {"warning": 2}, "attributes": {}, "type": "#581552", "children": [{"name": "EPG", "sub_label": "epg0", "children": [{"name": "EP", "sub_label": "She.", "label": "nodename0", "children": [{"attributes": {"Service Kind": "servicekind0", "Service": "servicename0", "Service Checks": {"warning": 1}, "Namespace": "namespace0", "Service Tags": ["cache", "global"], "Service Instance": "serviceid0", "Address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000"}, "label": "serviceid0", "type": "#C5D054", "name": "Service", "checks": {"warning": 1}}], "attributes": {"Node": "nodename0", "Node Checks": {"warning": 1}, "Reporting Node IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", "Interfaces": ["Pod-0/Node-103/eth4/6"], "Mac": "a6:62:cc:f7:4c:87", "VMM-Domain": "ESX0-leaf106", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 1}, "Address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000"}]}, "type": "#2DBBAD", "checks": {"warning": 2}}], "fraction": 0, "attributes": {"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename0", "Reporting Node IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", "Node Checks": {"warning": 1}}], "VRF": "tn0/", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 1}, "Address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000"}]}, "label": "serviceid0, ...", "type": "#085A87", "checks": {"warning": 2}}]}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/output/random_combination.json b/ConsulExtension/Service/tests/tree_parser/data/output/random_combination.json new file mode 100644 index 0000000..c46be8f --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/output/random_combination.json @@ -0,0 +1 @@ +[{"name": "AppProf", "sub_label": "ap0", "checks": {"passing": 6, "failing": 5, "warning": 10}, "attributes": {}, "type": "#581552", "children": [{"name": "EPG", "sub_label": "epg0", "children": [{"name": "EP", "sub_label": "They.", "label": "nodename15", "children": [], "attributes": {"Node": "nodename15", "Node Checks": {"failing": 1}, "Reporting Node IP": "10.137.44.72", "IP": "10.137.44.72", "Interfaces": ["Pod-3/Node-102/eth2/6"], "Mac": "fc:a4:66:80:1e:33", "VMM-Domain": "ESX0-leaf103", "Services_List": []}, "type": "#2DBBAD", "checks": {"failing": 1}}, {"name": "EP", "sub_label": "They.", "label": "nodename4", "children": [], "attributes": {"Node": "nodename4", "Node Checks": {"warning": 1}, "Reporting Node IP": "10.137.44.72", "IP": "10.137.44.72", "Interfaces": ["Pod-3/Node-102/eth2/6"], "Mac": "fc:a4:66:80:1e:33", "VMM-Domain": "ESX0-leaf103", "Services_List": []}, "type": "#2DBBAD", "checks": {"warning": 1}}, {"name": "EP", "sub_label": "They.", "label": "nodename0", "children": [{"attributes": {"Service Kind": "servicekind19", "Service": "servicename19", "Service Checks": {"warning": 4}, "Namespace": "namespace19", "Service Tags": ["cache", "global"], "Service Instance": "serviceid19", "Address": "10.137.44.72:9001"}, "label": "serviceid19", "type": "#C5D054", "name": "Service", "checks": {"warning": 4}}, {"attributes": {"Service Kind": "servicekind9", "Service": "servicename9", "Service Checks": {"warning": 2}, "Namespace": "namespace9", "Service Tags": ["cache", "global"], "Service Instance": "serviceid9", "Address": "10.137.44.72:9000"}, "label": "serviceid9", "type": "#C5D054", "name": "Service", "checks": {"warning": 2}}], "attributes": {"Node": "nodename0", "Node Checks": {"failing": 1}, "Reporting Node IP": "10.137.44.72", "IP": "10.137.44.72", "Interfaces": ["Pod-3/Node-102/eth2/6"], "Mac": "fc:a4:66:80:1e:33", "VMM-Domain": "ESX0-leaf103", "Services_List": [{"Service": "serviceid19", "Service Checks": {"warning": 4}, "Address": "10.137.44.72:9001"}, {"Service": "serviceid9", "Service Checks": {"warning": 2}, "Address": "10.137.44.72:9000"}]}, "type": "#2DBBAD", "checks": {"failing": 1, "warning": 6}}, {"name": "EP", "sub_label": "As.", "label": "nodename13", "children": [], "attributes": {"Node": "nodename13", "Node Checks": {"passing": 1}, "Reporting Node IP": "10.6.228.3", "IP": "10.6.228.3", "Interfaces": ["Pod-2/Node-105/eth0/6"], "Mac": "05:8d:7b:13:84:c0", "VMM-Domain": "ESX0-leaf101", "Services_List": []}, "type": "#2DBBAD", "checks": {"passing": 1}}, {"name": "EP", "sub_label": "As.", "label": "nodename14", "children": [], "attributes": {"Node": "nodename14", "Node Checks": {"warning": 1}, "Reporting Node IP": "10.6.228.3", "IP": "10.6.228.3", "Interfaces": ["Pod-2/Node-105/eth0/6"], "Mac": "05:8d:7b:13:84:c0", "VMM-Domain": "ESX0-leaf101", "Services_List": []}, "type": "#2DBBAD", "checks": {"warning": 1}}, {"name": "EP", "sub_label": "Fish.", "label": "nodename10", "children": [{"attributes": {"Service Kind": "servicekind5", "Service": "servicename5", "Service Checks": {"passing": 5}, "Namespace": "namespace5", "Service Tags": ["cache", "global"], "Service Instance": "serviceid5", "Address": "172.31.192.243:9001"}, "label": "serviceid5", "type": "#C5D054", "name": "Service", "checks": {"passing": 5}}, {"attributes": {"Service Kind": "servicekind13", "Service": "servicename13", "Service Checks": {"failing": 4}, "Namespace": "namespace13", "Service Tags": ["cache", "global"], "Service Instance": "serviceid13", "Address": "172.31.192.243:9000"}, "label": "serviceid13", "type": "#C5D054", "name": "Service", "checks": {"failing": 4}}], "attributes": {"Node": "nodename10", "Node Checks": {"warning": 1}, "Reporting Node IP": "172.31.192.243", "IP": "172.31.192.243", "Interfaces": ["Pod-2/Node-105/eth0/6"], "Mac": "3f:31:2b:20:38:ea", "VMM-Domain": "ESX0-leaf102", "Services_List": [{"Service": "serviceid5", "Service Checks": {"passing": 5}, "Address": "172.31.192.243:9001"}, {"Service": "serviceid13", "Service Checks": {"failing": 4}, "Address": "172.31.192.243:9000"}]}, "type": "#2DBBAD", "checks": {"passing": 5, "warning": 1, "failing": 4}}, {"name": "EP", "sub_label": "Fish.", "label": "nodename12", "children": [{"attributes": {"Service Kind": "servicekind4", "Service": "servicename4", "Service Checks": {"warning": 3}, "Namespace": "namespace4", "Service Tags": ["cache", "global"], "Service Instance": "serviceid4", "Address": "172.31.192.243:9003"}, "label": "serviceid4", "type": "#C5D054", "name": "Service", "checks": {"warning": 3}}, {"attributes": {"Service Kind": "servicekind0", "Service": "servicename0", "Service Checks": {"warning": 4}, "Namespace": "namespace0", "Service Tags": ["cache", "global"], "Service Instance": "serviceid0", "Address": "172.31.192.243:9000"}, "label": "serviceid0", "type": "#C5D054", "name": "Service", "checks": {"warning": 4}}], "attributes": {"Node": "nodename12", "Node Checks": {"failing": 1}, "Reporting Node IP": "172.31.192.243", "IP": "172.31.192.243", "Interfaces": ["Pod-2/Node-105/eth0/6"], "Mac": "3f:31:2b:20:38:ea", "VMM-Domain": "ESX0-leaf102", "Services_List": [{"Service": "serviceid4", "Service Checks": {"warning": 3}, "Address": "172.31.192.243:9003"}, {"Service": "serviceid0", "Service Checks": {"warning": 4}, "Address": "172.31.192.243:9000"}]}, "type": "#2DBBAD", "checks": {"failing": 1, "warning": 7}}, {"fractions": 3, "name": "EP", "level": "grey", "sub_label": "", "label": "", "attributes": {"ce:68:06:b3:4f:f1": "192.168.112.168", "f0:cb:31:be:ad:18": "172.20.79.65", "61:6d:1f:45:91:27": "192.168.147.153"}, "type": "grey"}], "fraction": 3, "attributes": {"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename15", "Reporting Node IP": "10.137.44.72", "Node Checks": {"failing": 1}}, {"Node": "nodename4", "Reporting Node IP": "10.137.44.72", "Node Checks": {"warning": 1}}, {"Node": "nodename0", "Reporting Node IP": "10.137.44.72", "Node Checks": {"failing": 1}}, {"Node": "nodename13", "Reporting Node IP": "10.6.228.3", "Node Checks": {"passing": 1}}, {"Node": "nodename14", "Reporting Node IP": "10.6.228.3", "Node Checks": {"warning": 1}}, {"Node": "nodename10", "Reporting Node IP": "172.31.192.243", "Node Checks": {"warning": 1}}, {"Node": "nodename12", "Reporting Node IP": "172.31.192.243", "Node Checks": {"failing": 1}}], "VRF": "tn0/", "Services_List": [{"Service": "serviceid19", "Service Checks": {"warning": 4}, "Address": "10.137.44.72:9001"}, {"Service": "serviceid9", "Service Checks": {"warning": 2}, "Address": "10.137.44.72:9000"}, {"Service": "serviceid5", "Service Checks": {"passing": 5}, "Address": "172.31.192.243:9001"}, {"Service": "serviceid13", "Service Checks": {"failing": 4}, "Address": "172.31.192.243:9000"}, {"Service": "serviceid4", "Service Checks": {"warning": 3}, "Address": "172.31.192.243:9003"}, {"Service": "serviceid0", "Service Checks": {"warning": 4}, "Address": "172.31.192.243:9000"}]}, "label": "serviceid19, ...", "type": "#085A87", "checks": {"passing": 6, "failing": 5, "warning": 10}}]}, {"name": "AppProf", "sub_label": "ap1", "checks": {"passing": 7, "failing": 12, "warning": 21}, "attributes": {}, "type": "#581552", "children": [{"name": "EPG", "sub_label": "epg0", "children": [{"name": "EP", "sub_label": "Indicate.", "label": "nodename16", "children": [], "attributes": {"Node": "nodename16", "Node Checks": {"passing": 1}, "Reporting Node IP": "10.99.27.147", "IP": "10.99.27.147", "Interfaces": ["Pod-2/Node-100/eth6/6"], "Mac": "4d:4b:91:be:73:17", "VMM-Domain": "ESX0-leaf105", "Services_List": []}, "type": "#2DBBAD", "checks": {"passing": 1}}, {"name": "EP", "sub_label": "Back.", "label": "nodename9", "children": [], "attributes": {"Node": "nodename9", "Node Checks": {"passing": 1}, "Reporting Node IP": "192.168.71.181", "IP": "192.168.71.181", "Interfaces": ["Pod-5/Node-105/eth0/6"], "Mac": "df:77:e9:ff:01:c7", "VMM-Domain": "ESX0-leaf102", "Services_List": []}, "type": "#2DBBAD", "checks": {"passing": 1}}, {"name": "EP", "sub_label": "All.", "label": "nodename11", "children": [{"attributes": {"Service Kind": "servicekind17", "Service": "servicename17", "Service Checks": {"failing": 4}, "Namespace": "namespace17", "Service Tags": ["cache", "global"], "Service Instance": "serviceid17", "Address": "192.168.147.153:9000"}, "label": "serviceid17", "type": "#C5D054", "name": "Service", "checks": {"failing": 4}}], "attributes": {"Node": "nodename11", "Node Checks": {"warning": 1}, "Reporting Node IP": "192.168.147.153", "IP": "192.168.147.153", "Interfaces": ["Pod-6/Node-104/eth3/6"], "Mac": "93:e3:92:61:6c:69", "VMM-Domain": "ESX0-leaf105", "Services_List": [{"Service": "serviceid17", "Service Checks": {"failing": 4}, "Address": "192.168.147.153:9000"}]}, "type": "#2DBBAD", "checks": {"warning": 1, "failing": 4}}, {"name": "EP", "sub_label": "All.", "label": "nodename6", "children": [{"attributes": {"Service Kind": "servicekind0", "Service": "servicename0", "Service Checks": {"warning": 4}, "Namespace": "namespace0", "Service Tags": ["cache", "global"], "Service Instance": "serviceid0", "Address": "192.168.147.153:9000"}, "label": "serviceid0", "type": "#C5D054", "name": "Service", "checks": {"warning": 4}}], "attributes": {"Node": "nodename6", "Node Checks": {"failing": 1}, "Reporting Node IP": "192.168.147.153", "IP": "192.168.147.153", "Interfaces": ["Pod-6/Node-104/eth3/6"], "Mac": "93:e3:92:61:6c:69", "VMM-Domain": "ESX0-leaf105", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 4}, "Address": "192.168.147.153:9000"}]}, "type": "#2DBBAD", "checks": {"failing": 1, "warning": 4}}, {"name": "EP", "sub_label": "All.", "label": "nodename7", "children": [{"attributes": {"Service Kind": "servicekind17", "Service": "servicename17", "Service Checks": {"failing": 4}, "Namespace": "namespace17", "Service Tags": ["cache", "global"], "Service Instance": "serviceid17", "Address": "192.168.147.153:9000"}, "label": "serviceid17", "type": "#C5D054", "name": "Service", "checks": {"failing": 4}}, {"attributes": {"Service Kind": "servicekind7", "Service": "servicename7", "Service Checks": {"failing": 2}, "Namespace": "namespace7", "Service Tags": ["cache", "global"], "Service Instance": "serviceid7", "Address": "192.168.147.153:9003"}, "label": "serviceid7", "type": "#C5D054", "name": "Service", "checks": {"failing": 2}}], "attributes": {"Node": "nodename7", "Node Checks": {"passing": 1}, "Reporting Node IP": "192.168.147.153", "IP": "192.168.147.153", "Interfaces": ["Pod-6/Node-104/eth3/6"], "Mac": "93:e3:92:61:6c:69", "VMM-Domain": "ESX0-leaf105", "Services_List": [{"Service": "serviceid17", "Service Checks": {"failing": 4}, "Address": "192.168.147.153:9000"}, {"Service": "serviceid7", "Service Checks": {"failing": 2}, "Address": "192.168.147.153:9003"}]}, "type": "#2DBBAD", "checks": {"passing": 1, "failing": 6}}, {"name": "EP", "sub_label": "Crime.", "label": "nodename5", "children": [{"attributes": {"Service Kind": "servicekind6", "Service": "servicename6", "Service Checks": {"warning": 2}, "Namespace": "namespace6", "Service Tags": ["cache", "global"], "Service Instance": "serviceid6", "Address": "10.25.28.100:9000"}, "label": "serviceid6", "type": "#C5D054", "name": "Service", "checks": {"warning": 2}}], "attributes": {"Node": "nodename5", "Node Checks": {"warning": 1}, "Reporting Node IP": "10.25.28.100", "IP": "10.25.28.100", "Interfaces": ["Pod-1/Node-102/eth1/6"], "Mac": "40:a5:25:1e:fb:55", "VMM-Domain": "ESX0-leaf102", "Services_List": [{"Service": "serviceid6", "Service Checks": {"warning": 2}, "Address": "10.25.28.100:9000"}]}, "type": "#2DBBAD", "checks": {"warning": 3}}, {"fractions": 3, "name": "EP", "level": "grey", "sub_label": "", "label": "", "attributes": {"ce:68:06:b3:4f:f1": "192.168.112.168", "f0:cb:31:be:ad:18": "172.20.79.65", "61:6d:1f:45:91:27": "192.168.147.153"}, "type": "grey"}], "fraction": 3, "attributes": {"BD": "uni/tn-tn0/ap-ap1/epg-epg0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename16", "Reporting Node IP": "10.99.27.147", "Node Checks": {"passing": 1}}, {"Node": "nodename9", "Reporting Node IP": "192.168.71.181", "Node Checks": {"passing": 1}}, {"Node": "nodename11", "Reporting Node IP": "192.168.147.153", "Node Checks": {"warning": 1}}, {"Node": "nodename6", "Reporting Node IP": "192.168.147.153", "Node Checks": {"failing": 1}}, {"Node": "nodename7", "Reporting Node IP": "192.168.147.153", "Node Checks": {"passing": 1}}, {"Node": "nodename5", "Reporting Node IP": "10.25.28.100", "Node Checks": {"warning": 1}}], "VRF": "tn0/", "Services_List": [{"Service": "serviceid17", "Service Checks": {"failing": 4}, "Address": "192.168.147.153:9000"}, {"Service": "serviceid0", "Service Checks": {"warning": 4}, "Address": "192.168.147.153:9000"}, {"Service": "serviceid7", "Service Checks": {"failing": 2}, "Address": "192.168.147.153:9003"}, {"Service": "serviceid6", "Service Checks": {"warning": 2}, "Address": "10.25.28.100:9000"}]}, "label": "serviceid17, ...", "type": "#085A87", "checks": {"passing": 2, "failing": 6, "warning": 4}}, {"name": "EPG", "sub_label": "epg1", "children": [{"name": "EP", "sub_label": "Fire.", "label": "nodename1", "children": [{"attributes": {"Service Kind": "servicekind1", "Service": "servicename1", "Service Checks": {"passing": 3}, "Namespace": "namespace1", "Service Tags": ["cache", "global"], "Service Instance": "serviceid1", "Address": "10.64.49.230:9000"}, "label": "serviceid1", "type": "#C5D054", "name": "Service", "checks": {"passing": 3}}, {"attributes": {"Service Kind": "servicekind3", "Service": "servicename3", "Service Checks": {"warning": 3}, "Namespace": "namespace3", "Service Tags": ["cache", "global"], "Service Instance": "serviceid3", "Address": "10.64.49.230:9001"}, "label": "serviceid3", "type": "#C5D054", "name": "Service", "checks": {"warning": 3}}], "attributes": {"Node": "nodename1", "Node Checks": {"warning": 1}, "Reporting Node IP": "10.64.49.230", "IP": "10.64.49.230", "Interfaces": ["Pod-3/Node-105/eth1/6"], "Mac": "f6:5d:9c:a0:16:4d", "VMM-Domain": "ESX0-leaf102", "Services_List": [{"Service": "serviceid1", "Service Checks": {"passing": 3}, "Address": "10.64.49.230:9000"}, {"Service": "serviceid3", "Service Checks": {"warning": 3}, "Address": "10.64.49.230:9001"}]}, "type": "#2DBBAD", "checks": {"passing": 3, "warning": 4}}, {"name": "EP", "sub_label": "Design.", "label": "nodename8", "children": [{"attributes": {"Service Kind": "servicekind12", "Service": "servicename12", "Service Checks": {"failing": 3}, "Namespace": "namespace12", "Service Tags": ["cache", "global"], "Service Instance": "serviceid12", "Address": "172.16.17.236:9002"}, "label": "serviceid12", "type": "#C5D054", "name": "Service", "checks": {"failing": 3}}, {"attributes": {"Service Kind": "servicekind6", "Service": "servicename6", "Service Checks": {"warning": 2}, "Namespace": "namespace6", "Service Tags": ["cache", "global"], "Service Instance": "serviceid6", "Address": "172.16.17.236:9004"}, "label": "serviceid6", "type": "#C5D054", "name": "Service", "checks": {"warning": 2}}, {"attributes": {"Service Kind": "servicekind9", "Service": "servicename9", "Service Checks": {"warning": 2}, "Namespace": "namespace9", "Service Tags": ["cache", "global"], "Service Instance": "serviceid9", "Address": "172.16.17.236:9000"}, "label": "serviceid9", "type": "#C5D054", "name": "Service", "checks": {"warning": 2}}, {"attributes": {"Service Kind": "servicekind18", "Service": "servicename18", "Service Checks": {"passing": 1}, "Namespace": "namespace18", "Service Tags": ["cache", "global"], "Service Instance": "serviceid18", "Address": "172.16.17.236:9001"}, "label": "serviceid18", "type": "#C5D054", "name": "Service", "checks": {"passing": 1}}], "attributes": {"Node": "nodename8", "Node Checks": {"failing": 1}, "Reporting Node IP": "172.16.17.236", "IP": "172.16.17.236", "Interfaces": ["Pod-1/Node-104/eth0/6"], "Mac": "26:4c:74:9f:b8:4e", "VMM-Domain": "ESX0-leaf104", "Services_List": [{"Service": "serviceid12", "Service Checks": {"failing": 3}, "Address": "172.16.17.236:9002"}, {"Service": "serviceid6", "Service Checks": {"warning": 2}, "Address": "172.16.17.236:9004"}, {"Service": "serviceid9", "Service Checks": {"warning": 2}, "Address": "172.16.17.236:9000"}, {"Service": "serviceid18", "Service Checks": {"passing": 1}, "Address": "172.16.17.236:9001"}]}, "type": "#2DBBAD", "checks": {"passing": 1, "failing": 4, "warning": 4}}, {"name": "EP", "sub_label": "Fear.", "label": "nodename11", "children": [{"attributes": {"Service Kind": "servicekind17", "Service": "servicename17", "Service Checks": {"failing": 4}, "Namespace": "namespace17", "Service Tags": ["cache", "global"], "Service Instance": "serviceid17", "Address": "192.168.147.153:9000"}, "label": "serviceid17", "type": "#C5D054", "name": "Service", "checks": {"failing": 4}}], "attributes": {"Node": "nodename11", "Node Checks": {"warning": 1}, "Reporting Node IP": "192.168.147.153", "IP": "192.168.147.153", "Interfaces": ["Pod-5/Node-104/eth3/6"], "Mac": "ab:46:91:24:6d:ca", "VMM-Domain": "ESX0-leaf101", "Services_List": [{"Service": "serviceid17", "Service Checks": {"failing": 4}, "Address": "192.168.147.153:9000"}]}, "type": "#2DBBAD", "checks": {"warning": 1, "failing": 4}}, {"name": "EP", "sub_label": "Fear.", "label": "nodename6", "children": [{"attributes": {"Service Kind": "servicekind0", "Service": "servicename0", "Service Checks": {"warning": 4}, "Namespace": "namespace0", "Service Tags": ["cache", "global"], "Service Instance": "serviceid0", "Address": "192.168.147.153:9000"}, "label": "serviceid0", "type": "#C5D054", "name": "Service", "checks": {"warning": 4}}], "attributes": {"Node": "nodename6", "Node Checks": {"failing": 1}, "Reporting Node IP": "192.168.147.153", "IP": "192.168.147.153", "Interfaces": ["Pod-5/Node-104/eth3/6"], "Mac": "ab:46:91:24:6d:ca", "VMM-Domain": "ESX0-leaf101", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 4}, "Address": "192.168.147.153:9000"}]}, "type": "#2DBBAD", "checks": {"failing": 1, "warning": 4}}, {"name": "EP", "sub_label": "Fear.", "label": "nodename7", "children": [{"attributes": {"Service Kind": "servicekind17", "Service": "servicename17", "Service Checks": {"failing": 4}, "Namespace": "namespace17", "Service Tags": ["cache", "global"], "Service Instance": "serviceid17", "Address": "192.168.147.153:9000"}, "label": "serviceid17", "type": "#C5D054", "name": "Service", "checks": {"failing": 4}}, {"attributes": {"Service Kind": "servicekind7", "Service": "servicename7", "Service Checks": {"failing": 2}, "Namespace": "namespace7", "Service Tags": ["cache", "global"], "Service Instance": "serviceid7", "Address": "192.168.147.153:9003"}, "label": "serviceid7", "type": "#C5D054", "name": "Service", "checks": {"failing": 2}}], "attributes": {"Node": "nodename7", "Node Checks": {"passing": 1}, "Reporting Node IP": "192.168.147.153", "IP": "192.168.147.153", "Interfaces": ["Pod-5/Node-104/eth3/6"], "Mac": "ab:46:91:24:6d:ca", "VMM-Domain": "ESX0-leaf101", "Services_List": [{"Service": "serviceid17", "Service Checks": {"failing": 4}, "Address": "192.168.147.153:9000"}, {"Service": "serviceid7", "Service Checks": {"failing": 2}, "Address": "192.168.147.153:9003"}]}, "type": "#2DBBAD", "checks": {"passing": 1, "failing": 6}}, {"name": "EP", "sub_label": "Decade.", "label": "nodename17", "children": [{"attributes": {"Service Kind": "servicekind4", "Service": "servicename4", "Service Checks": {"warning": 3}, "Namespace": "namespace4", "Service Tags": ["cache", "global"], "Service Instance": "serviceid4", "Address": "10.201.143.18:9001"}, "label": "serviceid4", "type": "#C5D054", "name": "Service", "checks": {"warning": 3}}, {"attributes": {"Service Kind": "servicekind7", "Service": "servicename7", "Service Checks": {"failing": 2}, "Namespace": "namespace7", "Service Tags": ["cache", "global"], "Service Instance": "serviceid7", "Address": "10.201.143.18:9003"}, "label": "serviceid7", "type": "#C5D054", "name": "Service", "checks": {"failing": 2}}], "attributes": {"Node": "nodename17", "Node Checks": {"passing": 1}, "Reporting Node IP": "10.201.143.18", "IP": "10.201.143.18", "Interfaces": ["Pod-1/Node-106/eth5/6"], "Mac": "21:38:f0:14:c4:23", "VMM-Domain": "ESX0-leaf101", "Services_List": [{"Service": "serviceid4", "Service Checks": {"warning": 3}, "Address": "10.201.143.18:9001"}, {"Service": "serviceid7", "Service Checks": {"failing": 2}, "Address": "10.201.143.18:9003"}]}, "type": "#2DBBAD", "checks": {"passing": 1, "warning": 3, "failing": 2}}, {"name": "EP", "sub_label": "Decade.", "label": "nodename3", "children": [{"attributes": {"Service Kind": "servicekind11", "Service": "servicename11", "Service Checks": {"warning": 2}, "Namespace": "namespace11", "Service Tags": ["cache", "global"], "Service Instance": "serviceid11", "Address": "10.201.143.18:9002"}, "label": "serviceid11", "type": "#C5D054", "name": "Service", "checks": {"warning": 2}}, {"attributes": {"Service Kind": "servicekind15", "Service": "servicename15", "Service Checks": {"warning": 4}, "Namespace": "namespace15", "Service Tags": ["cache", "global"], "Service Instance": "serviceid15", "Address": "10.201.143.18:9004"}, "label": "serviceid15", "type": "#C5D054", "name": "Service", "checks": {"warning": 4}}], "attributes": {"Node": "nodename3", "Node Checks": {"passing": 1}, "Reporting Node IP": "10.201.143.18", "IP": "10.201.143.18", "Interfaces": ["Pod-1/Node-106/eth5/6"], "Mac": "21:38:f0:14:c4:23", "VMM-Domain": "ESX0-leaf101", "Services_List": [{"Service": "serviceid11", "Service Checks": {"warning": 2}, "Address": "10.201.143.18:9002"}, {"Service": "serviceid15", "Service Checks": {"warning": 4}, "Address": "10.201.143.18:9004"}]}, "type": "#2DBBAD", "checks": {"passing": 1, "warning": 6}}, {"fractions": 6, "name": "EP", "level": "grey", "sub_label": "", "label": "", "attributes": {"94:b2:eb:9b:29:30": "192.168.131.112", "b4:70:91:68:a5:85": "10.137.44.72", "44:ae:46:8b:20:0d": "172.26.63.162", "79:ba:1c:e6:5d:c1": "172.20.79.65", "67:fc:d4:2d:c7:0d": "10.64.49.230", "6e:1f:03:70:d6:a1": "10.71.130.231"}, "type": "grey"}], "fraction": 6, "attributes": {"BD": "uni/tn-tn0/ap-ap1/epg-epg1", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename1", "Reporting Node IP": "10.64.49.230", "Node Checks": {"warning": 1}}, {"Node": "nodename8", "Reporting Node IP": "172.16.17.236", "Node Checks": {"failing": 1}}, {"Node": "nodename11", "Reporting Node IP": "192.168.147.153", "Node Checks": {"warning": 1}}, {"Node": "nodename6", "Reporting Node IP": "192.168.147.153", "Node Checks": {"failing": 1}}, {"Node": "nodename7", "Reporting Node IP": "192.168.147.153", "Node Checks": {"passing": 1}}, {"Node": "nodename17", "Reporting Node IP": "10.201.143.18", "Node Checks": {"passing": 1}}, {"Node": "nodename3", "Reporting Node IP": "10.201.143.18", "Node Checks": {"passing": 1}}], "VRF": "tn0/", "Services_List": [{"Service": "serviceid1", "Service Checks": {"passing": 3}, "Address": "10.64.49.230:9000"}, {"Service": "serviceid3", "Service Checks": {"warning": 3}, "Address": "10.64.49.230:9001"}, {"Service": "serviceid12", "Service Checks": {"failing": 3}, "Address": "172.16.17.236:9002"}, {"Service": "serviceid6", "Service Checks": {"warning": 2}, "Address": "172.16.17.236:9004"}, {"Service": "serviceid9", "Service Checks": {"warning": 2}, "Address": "172.16.17.236:9000"}, {"Service": "serviceid18", "Service Checks": {"passing": 1}, "Address": "172.16.17.236:9001"}, {"Service": "serviceid17", "Service Checks": {"failing": 4}, "Address": "192.168.147.153:9000"}, {"Service": "serviceid0", "Service Checks": {"warning": 4}, "Address": "192.168.147.153:9000"}, {"Service": "serviceid7", "Service Checks": {"failing": 2}, "Address": "192.168.147.153:9003"}, {"Service": "serviceid4", "Service Checks": {"warning": 3}, "Address": "10.201.143.18:9001"}, {"Service": "serviceid7", "Service Checks": {"failing": 2}, "Address": "10.201.143.18:9003"}, {"Service": "serviceid11", "Service Checks": {"warning": 2}, "Address": "10.201.143.18:9002"}, {"Service": "serviceid15", "Service Checks": {"warning": 4}, "Address": "10.201.143.18:9004"}]}, "label": "serviceid1, ...", "type": "#085A87", "checks": {"passing": 5, "warning": 18, "failing": 12}}]}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/output/service_to_ep.json b/ConsulExtension/Service/tests/tree_parser/data/output/service_to_ep.json new file mode 100644 index 0000000..750bcb8 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/output/service_to_ep.json @@ -0,0 +1 @@ +[{"name": "AppProf", "sub_label": "ap0", "checks": {"warning": 2}, "attributes": {}, "type": "#581552", "children": [{"name": "EPG", "sub_label": "epg0", "children": [{"name": "EP", "sub_label": "She.", "label": "nodename0", "children": [{"attributes": {"Service Kind": "servicekind0", "Service": "servicename0", "Service Checks": {"warning": 1}, "Namespace": "namespace0", "Service Tags": ["cache", "global"], "Service Instance": "serviceid0", "Address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000"}, "label": "serviceid0", "type": "#C5D054", "name": "Service", "checks": {"warning": 1}}], "attributes": {"Node": "nodename0", "Node Checks": {"warning": 1}, "Reporting Node IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", "IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", "Interfaces": ["Pod-0/Node-103/eth4/6"], "Mac": "a6:62:cc:f7:4c:87", "VMM-Domain": "ESX0-leaf106", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 1}, "Address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000"}]}, "type": "#2DBBAD", "checks": {"warning": 2}}], "fraction": 0, "attributes": {"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename0", "Reporting Node IP": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b", "Node Checks": {"warning": 1}}], "VRF": "tn0/", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 1}, "Address": "6c40:b7d1:3209:8f20:f0fa:8ae1:1c72:979b:9000"}]}, "label": "serviceid0, ...", "type": "#085A87", "checks": {"warning": 2}}]}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/output/service_to_none.json b/ConsulExtension/Service/tests/tree_parser/data/output/service_to_none.json new file mode 100644 index 0000000..b179a13 --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/output/service_to_none.json @@ -0,0 +1 @@ +[{"name": "AppProf", "sub_label": "ap0", "checks": {"passing": 1, "warning": 1}, "attributes": {}, "type": "#581552", "children": [{"name": "EPG", "sub_label": "epg0", "children": [{"name": "EP", "sub_label": "Too.", "label": "nodename0", "children": [{"attributes": {"Service Kind": "servicekind0", "Service": "servicename0", "Service Checks": {"warning": 1}, "Namespace": "namespace0", "Service Tags": ["cache", "global"], "Service Instance": "serviceid0", "Address": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee:9000"}, "label": "serviceid0", "type": "#C5D054", "name": "Service", "checks": {"warning": 1}}], "attributes": {"Node": "nodename0", "Node Checks": {"passing": 1}, "Reporting Node IP": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee", "IP": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee", "Interfaces": ["Pod-4/Node-104/eth1/6"], "Mac": "e3:47:da:1c:b7:50", "VMM-Domain": "ESX0-leaf102", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 1}, "Address": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee:9000"}]}, "type": "#2DBBAD", "checks": {"passing": 1, "warning": 1}}], "fraction": 0, "attributes": {"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename0", "Reporting Node IP": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee", "Node Checks": {"passing": 1}}], "VRF": "tn0/", "Services_List": [{"Service": "serviceid0", "Service Checks": {"warning": 1}, "Address": "951d:56e4:69ae:46b1:3510:f9e0:cd26:49ee:9000"}]}, "label": "serviceid0, ...", "type": "#085A87", "checks": {"passing": 1, "warning": 1}}]}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/data/output/service_without_ip.json b/ConsulExtension/Service/tests/tree_parser/data/output/service_without_ip.json new file mode 100644 index 0000000..98fc3fc --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/data/output/service_without_ip.json @@ -0,0 +1 @@ +[{"name": "AppProf", "sub_label": "ap0", "checks": {"passing": 1}, "attributes": {}, "type": "#581552", "children": [{"name": "EPG", "sub_label": "epg0", "children": [{"name": "EP", "sub_label": "Name.", "label": "nodename0", "children": [], "attributes": {"Node": "nodename0", "Node Checks": {"passing": 1}, "Reporting Node IP": "b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e", "IP": "b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e", "Interfaces": ["Pod-3/Node-106/eth2/6"], "Mac": "93:0f:2a:19:ea:85", "VMM-Domain": "ESX0-leaf103", "Services_List": []}, "type": "#2DBBAD", "checks": {"passing": 1}}], "fraction": 0, "attributes": {"BD": "uni/tn-tn0/ap-ap0/epg-epg0", "Contracts": {"IntraEpg": ["dummy"], "Consumer Interface": ["dummy"], "Consumer": ["dummy"], "Taboo": ["dummy"], "Provider": ["dummy"]}, "Nodes": [{"Node": "nodename0", "Reporting Node IP": "b9ad:3af9:46fe:59c8:44b8:f7cc:edea:d45e", "Node Checks": {"passing": 1}}], "VRF": "tn0/", "Services_List": []}, "label": "", "type": "#085A87", "checks": {"passing": 1}}]}] \ No newline at end of file diff --git a/ConsulExtension/Service/tests/tree_parser/test_tree_parser.py b/ConsulExtension/Service/tests/tree_parser/test_tree_parser.py new file mode 100644 index 0000000..22cca2b --- /dev/null +++ b/ConsulExtension/Service/tests/tree_parser/test_tree_parser.py @@ -0,0 +1,110 @@ +import pytest +import json +from Service import tree_parser + + +''' +Case1: Dangeling node +Case2: All the data having ipv6 addresses +Case3: Service with different ip as that of Node which mappes to Some EP +Case4: Service with different ip as that of Node which DOES NOT map to any EP +Case5: Service with no ip +Case6: All above combinations +''' +cases = [ + "dangling", + "ipv6", + "service_to_ep", + "service_to_none", + "service_without_ip", + "random_combination" +] + + +def get_data(in_out, case): + with open('./tests/tree_parser/data/{}/{}.json'.format(in_out, case), 'r') as f: + return json.load(f) + + +checks = [ + [ + { + "passing": 1, + "warning": 2, + "failing": 2 + }, + { + "passing": 5, + "warning": 9, + "failing": 4 + } + ], + [ + { + "passing": 1, + "warning": 2, + }, + { + "passing": 4, + "warning": 3, + } + ], + [ + { + "warning": 3, + }, + { + "warning": 2, + } + ], + [ + { + "warning": 7, + }, + { + "passing": 2, + } + ], + [ + { + }, + { + } + ], + [ + { + "passing": 0, + "warning": 0, + "failing": 0 + }, + { + } + ] +] + + +@pytest.mark.parametrize("case", cases) +def test_consul_tree_dict(case): + input_data = get_data('input', case) + original_output = get_data('output', case) + response = tree_parser.consul_tree_dict(input_data) + + for each in original_output: + assert each in response + + +@pytest.mark.parametrize("check", checks) +def test_add_checks(check): + base_checks, new_checks = check + passing = base_checks.get('passing', 0) \ + + new_checks.get('passing', 0) + warning = base_checks.get('warning', 0) \ + + new_checks.get('warning', 0) + failing = base_checks.get('failing', 0) \ + + new_checks.get('failing', 0) + + response = tree_parser.add_checks(base_checks, new_checks) + + assert response.get('passing', 0) == passing + assert response.get('warning', 0) == warning + assert response.get('failing', 0) == failing diff --git a/ConsulExtension/Service/tests/utils.py b/ConsulExtension/Service/tests/utils.py new file mode 100644 index 0000000..9c95ae6 --- /dev/null +++ b/ConsulExtension/Service/tests/utils.py @@ -0,0 +1,24 @@ +"""Utilities for test cases""" + +import json +import os + + +class DummyClass: + """Dummy class for any dummy object""" + pass + + +def get_absolue_path(input_file): + dir_path = os.path.dirname(os.path.abspath(__file__)) + print('Dir path : {}'.format(dir_path)) + file_path = r''.join([dir_path, + input_file]) + print('Absolute file path {} '.format(file_path)) + return file_path + + +def parse_json_file(file_path): + with open(file_path) as f: + data = json.load(f) + return data diff --git a/ConsulExtension/Service/threading_util.py b/ConsulExtension/Service/threading_util.py index 2d7be99..6e8b859 100644 --- a/ConsulExtension/Service/threading_util.py +++ b/ConsulExtension/Service/threading_util.py @@ -2,10 +2,11 @@ import threading + class ThreadSafeDict(dict): """A thread safe dict - Method for seeing that there is no race condition + Method for seeing that there is no race condition and using lock when accessing the thread_registry """ @@ -18,4 +19,4 @@ def __enter__(self): return self def __exit__(self, type, value, traceback): - self._lock.release() \ No newline at end of file + self._lock.release() diff --git a/ConsulExtension/Service/tree_parser.py b/ConsulExtension/Service/tree_parser.py index 6fe0441..6a9e025 100644 --- a/ConsulExtension/Service/tree_parser.py +++ b/ConsulExtension/Service/tree_parser.py @@ -1,32 +1,31 @@ """Module for parsing tree data for consul - This module will gets the mapped data and return a + This module will gets the mapped data and return a hierarchical Tree data for the D3 component in UI. Multiple Tree will be returned in case of multiple AP in that mapped data. - Along with every node(AP,EP,EPG,Service) information + Along with every node(AP,EP,EPG,Service) information to be show in the side pane is also displayed is also sent in attributes. """ + def consul_tree_dict(data): """Create tree specific dict - + input: The merged CEps data output: list of dict of trees """ - # Final list of ap(application profile) ap_list = [] - # distinct APs - ap_set= set([node['AppProfile'] for node in data]) + ap_set = set([node['AppProfile'] for node in data]) - # Iterating for each AP and creating a tree view for + # Iterating for each AP and creating a tree view for # each AP, with all node's info to be shown in the tree # and its Side Pane(when clicked on the node). for ap in ap_set: @@ -37,7 +36,7 @@ def consul_tree_dict(data): # List for maintaining unique ep ips, # and service addresses ap_node_ip_list = [] - ap_service_addr_list=[] + ap_service_addr_list = [] # Top level node in Tree ap_dict = { @@ -79,7 +78,7 @@ def consul_tree_dict(data): # List for maintaining unique ep ips, # and service addresses epg_node_ip_list = [] - epg_service_addr_list=[] + epg_service_addr_list = [] # distinct ips in current EPg epg_ip_set = set([ep['IP'] for ep in epg_eps]) @@ -100,11 +99,11 @@ def consul_tree_dict(data): 'label': ep_node['node_name'], 'sub_label': ep_node['VM-Name'], 'attributes': { - 'Node' : ep_node['node_name'], - 'Node Checks' : ep_node['node_check'], + 'Node': ep_node['node_name'], + 'Node Checks': ep_node['node_check'], 'Reporting Node IP': ep_node['node_ips'][0], 'Mac': ep_node['CEP-Mac'], - 'Services_List' : [], + 'Services_List': [], 'IP': ep_node['IP'], 'Interfaces': ep_node['Interfaces'], 'VMM-Domain': ep_node['VMM-Domain'] @@ -127,7 +126,7 @@ def consul_tree_dict(data): if service['service_ip']: service_address = str(service['service_ip']) + ':' + str(service['service_port']) else: - service_address = str(ep_node['node_ips'][0]) + ':' + str(service['service_port']) # for now 0th is taken, will change + service_address = str(ep_node['node_ips'][0]) + ':' + str(service['service_port']) # 4rd layer nodes in Tree (Service) service_dict = { @@ -135,12 +134,12 @@ def consul_tree_dict(data): 'type': '#C5D054', 'label': service_label, 'attributes': { - 'Service' : service['service_name'], - 'Service Instance' : service['service_id'], - 'Address' : service_address, - 'Service Kind' : service['service_kind'], - 'Service Tags' : service['service_tags'], - 'Service Checks' : service['service_checks'], + 'Service': service['service_name'], + 'Service Instance': service['service_id'], + 'Address': service_address, + 'Service Kind': service['service_kind'], + 'Service Tags': service['service_tags'], + 'Service Checks': service['service_checks'], 'Namespace': service['service_namespace'] }, 'checks': service['service_checks'] @@ -149,16 +148,15 @@ def consul_tree_dict(data): # Add Service to EP ep_dict['children'].append(service_dict) - # Now adding the service info in EP and EPG attributes - # for the Side Pane info, + # for the Side Pane info, # And adding services label to EPG # Service for side pane service_side_pane = { - 'Service' : service['service_id'], - 'Address' : service_address, - 'Service Checks' : service['service_checks'] + 'Service': service['service_id'], + 'Address': service_address, + 'Service Checks': service['service_checks'] } # Adding services to EP attributes @@ -183,13 +181,12 @@ def consul_tree_dict(data): epg_dict['checks'] = add_checks(epg_dict['checks'], service_dict['checks']) epg_service_addr_list.append(service_address) - # Add label to EPG if not there, a EPG can have more then one services in - # the EPs, But as it is difficult to show all of those in the tree view + # Add label to EPG if not there, a EPG can have more then one services in + # the EPs, But as it is difficult to show all of those in the tree view # UI only 1 is shown with ellipsis if not epg_dict['label']: epg_dict['label'] = service['service_id'] + ', ...' - # Add service checks to EPG checks, only if # the check for that service has not been # added before. @@ -197,11 +194,10 @@ def consul_tree_dict(data): ap_dict['checks'] = add_checks(ap_dict['checks'], service_dict['checks']) ap_service_addr_list.append(service_address) - # Add EP to EPG epg_dict['children'].append(ep_dict) - # Now adding the Node info in the EPG Side Pane + # Now adding the Node info in the EPG Side Pane # if it does not exist # Node for side pane @@ -232,12 +228,12 @@ def consul_tree_dict(data): # 3rd layer nodes in Tree (EP) # Iterating for each Non service end point in EPG if epg_eps[0]['Non_IPs']: - non_ep_dict={} + non_ep_dict = {} non_ep_dict['name'] = 'EP' non_ep_dict['type'] = 'grey' - non_ep_dict['label'] = '' # No label is shown in the ui for a non-service ep + non_ep_dict['label'] = '' # No label is shown in the ui for a non-service ep non_ep_dict['level'] = 'grey' - non_ep_dict['sub_label'] = '' # No sub_label is shown in the ui for a non-service ep + non_ep_dict['sub_label'] = '' # No sub_label is shown in the ui for a non-service ep non_ep_dict['attributes'] = epg_eps[0]['Non_IPs'] non_ep_dict['fractions'] = epg_eps[0]['fraction'] epg_dict['children'].append(non_ep_dict) @@ -252,7 +248,7 @@ def consul_tree_dict(data): def add_checks(base_checks, new_checks): """Adding up checks for every node""" - + final_check = {} for status, check_value in base_checks.iteritems(): diff --git a/ConsulExtension/Service/urls.py b/ConsulExtension/Service/urls.py index 12d9b32..6c9ebe4 100644 --- a/ConsulExtension/Service/urls.py +++ b/ConsulExtension/Service/urls.py @@ -1,6 +1,6 @@ """All the API for the app are stored here""" -#Aci Utils +# Aci Utils LOGIN_URL_SUFFIX = '/api/requestAppToken.json' LOGIN_URL = '{0}{1}' + LOGIN_URL_SUFFIX @@ -19,7 +19,7 @@ FETCH_BD_URL = '{0}{1}/api/node/mo/{2}.json?query-target=children&target-subtree-class=fvRsBd' FETCH_VRF_URL = '{0}{1}/api/node/mo/{2}.json?query-target=children&target-subtree-class=fvRsCtx' -FETCH_CONTRACT_URL = '{0}{1}/api/node/mo/{2}.json?query-target=children&target-subtree-class=fvRsCons,fvRsProv,fvRsConsIf,fvRsProtBy,fvRsConsIf' +FETCH_CONTRACT_URL = '{0}{1}/api/node/mo/{2}.json?query-target=children&target-subtree-class=fvRsCons,fvRsProv,fvRsConsIf,fvRsProtBy,fvRsIntraEpg' CHECK_UNICAST_URL = '{0}{1}/api/node/class/fvBD.json?query-target-filter=eq(fvBD.name,"{2}")' FETCH_EP_MAC_URL = '{0}{1}/api/node/class/fvCEp.json?query-target-filter=eq(fvCEp.mac,"{2}")' @@ -37,4 +37,4 @@ NODE_SERVICES = '{}/v1/catalog/node-services/{}' NODE_CHECK = '{}/v1/health/node/{}' SERVICE_CHECK = '{}/v1/health/checks/{}' -SERVICE_INFO = '{}/v1/catalog/service/{}' \ No newline at end of file +SERVICE_INFO = '{}/v1/catalog/service/{}' diff --git a/ConsulExtension/UIAssets/app-start.html b/ConsulExtension/UIAssets/app-start.html index 0bd769c..ba4c2a0 100644 --- a/ConsulExtension/UIAssets/app-start.html +++ b/ConsulExtension/UIAssets/app-start.html @@ -1,4 +1,4 @@ - + Loading diff --git a/ConsulExtension/UIAssets/app.html b/ConsulExtension/UIAssets/app.html index 22b88fb..09db28f 100644 --- a/ConsulExtension/UIAssets/app.html +++ b/ConsulExtension/UIAssets/app.html @@ -1,4 +1,4 @@ - + Consul diff --git a/ConsulExtension/UIAssets/app/Agent/index.js b/ConsulExtension/UIAssets/app/Agent/index.js index fe5fbe2..41ebd2a 100644 --- a/ConsulExtension/UIAssets/app/Agent/index.js +++ b/ConsulExtension/UIAssets/app/Agent/index.js @@ -89,8 +89,11 @@ export default class Agent extends React.Component { console.log("ERRROR :===>> ", error, info) } - refreshField() { - this.setState({ ...defaultFieldState }) + refreshField(){ + this.setState({ ...defaultFieldState, errormsg: { + Address: null, + Port: null + } }) } setDetails(details, isReloaded = false) { @@ -226,7 +229,8 @@ export default class Agent extends React.Component { // thiss.setState({ details: credsData.payload }) } else if (parseInt(credsData.status_code) === 300) { try { - thiss.notify(credsData.message) + thiss.setDetails(credsData.payload, isReloaded); + thiss.notify(credsData.message); } catch (e) { console.log("message error", e) } @@ -621,7 +625,7 @@ export default class Agent extends React.Component { }}>
-
+
{ agentFields.map(function (elem) { @@ -634,6 +638,7 @@ export default class Agent extends React.Component { className={!saveAllow && "disabled"} size="btn--small" type="btn--primary" + onClick={this.submitAgent} >Save
@@ -658,7 +663,7 @@ export default class Agent extends React.Component { className={`half-margin-left ${readAgentLoading && 'disabled'}`} size="btn--small" type="btn--primary-ghost" - onClick={() => { this.setState({ isNewAgentAdded: true }, () => this.handleModal(true)) }}> {"Add " + AGENTS} + onClick={() => { this.setState({ isNewAgentAdded: true }, () => {this.handleModal(true)}) }}> {"Add " + AGENTS} this.readDatacenter(), INTERVAL_API_CALL); + } + + + componentWillUnmount() { + console.log("Component will unmount; intervalcall") + clearInterval(this.intervalCall); // this clears the interval calls + this.xhrCred.abort(); // cancel all apis + } + + shouldComponentUpdate(nextProps, nextState){ + console.log("In should component Update") + console.log(_.isEqual(this.state.details, nextState.details)) + if(_.isEqual(this.state, nextState)){ + return false + } + return true } readDatacenter() { @@ -201,7 +220,7 @@ export default class App extends React.Component { } catch (err) { console.log("setsidebar err ", err); } - console.log("Setted sidebar ", sidebarItems); + this.setState({ details, sidebarItems }) } @@ -240,7 +259,7 @@ export default class App extends React.Component { return; } let payload = POST_TENANT_QUERY(this.tenantName) - let xhrPostTenant = new XMLHttpRequest(); + let xhrPostTenant = this.xhrCred; try { xhrPostTenant.open("POST", QUERY_URL, true); xhrPostTenant.setRequestHeader("Content-type", "application/json"); @@ -249,11 +268,9 @@ export default class App extends React.Component { xhrPostTenant.setRequestHeader("DevCookie", window.APIC_DEV_COOKIE); xhrPostTenant.setRequestHeader("APIC-challenge", window.APIC_URL_TOKEN); xhrPostTenant.onreadystatechange = function () { - console.log("xhrPostTenant state ", xhrPostTenant.readyState); if (xhrPostTenant.readyState == 4 && xhrPostTenant.status == 200) { let responsejson = JSON.parse(xhrPostTenant.responseText); - console.log("Response of dc: ", responsejson); let datacenterData = JSON.parse(responsejson.data.PostTenant.tenant); @@ -276,7 +293,7 @@ export default class App extends React.Component { readDcCall() { let thiss = this; - let xhrReadDc = new XMLHttpRequest(); + let xhrReadDc = this.xhrCred; try { xhrReadDc.open("POST", QUERY_URL, true); xhrReadDc.setRequestHeader("Content-type", "application/json"); @@ -285,12 +302,10 @@ export default class App extends React.Component { xhrReadDc.setRequestHeader("DevCookie", window.APIC_DEV_COOKIE); xhrReadDc.setRequestHeader("APIC-challenge", window.APIC_URL_TOKEN); xhrReadDc.onreadystatechange = function () { - console.log("chr== state ", xhrReadDc.readyState); if (xhrReadDc.readyState == 4 && xhrReadDc.status == 200) { let checkData = JSON.parse(xhrReadDc.responseText); - console.log("Response of dc: ", checkData); - // let datacenterData = JSON.parse(checkData.data.ReadCreds.creds); + let datacenterData = JSON.parse(checkData.data.GetDatacenters.datacenters); if (parseInt(datacenterData.status_code) === 200) { @@ -318,7 +333,6 @@ export default class App extends React.Component { } render() { - console.log("Appb Render state ", this.state); return (
@@ -326,7 +340,7 @@ export default class App extends React.Component { {/* {this.state.agentPopup && } */} {this.state.mappingPopup && } {this.state.agentPopup && } - + {this.state.agentPopup || this.state.mappingPopup?null: }
); diff --git a/ConsulExtension/UIAssets/app/Components/SummaryPane.js b/ConsulExtension/UIAssets/app/Components/SummaryPane.js index 8a3311c..820b85a 100644 --- a/ConsulExtension/UIAssets/app/Components/SummaryPane.js +++ b/ConsulExtension/UIAssets/app/Components/SummaryPane.js @@ -1,7 +1,10 @@ import React from "react"; import { Icon } from "blueprint-react"; +import { showShortName } from "../Utility/utils"; import "./SummaryPane.css"; +const HEADER_LENGTH = 25; + class SummaryPane extends React.Component { constructor(props) { super(props); @@ -15,8 +18,8 @@ class SummaryPane extends React.Component {
-
{this.props.subTitle}
-
{this.props.title}
+
{showShortName(this.props.subTitle, HEADER_LENGTH)}
+
{showShortName(this.props.title, HEADER_LENGTH)}
diff --git a/ConsulExtension/UIAssets/app/Container.js b/ConsulExtension/UIAssets/app/Container.js index 3a7bd03..5e98b5c 100644 --- a/ConsulExtension/UIAssets/app/Container.js +++ b/ConsulExtension/UIAssets/app/Container.js @@ -1,10 +1,11 @@ import React from 'react'; import { Route, Switch, Redirect } from 'react-router-dom'; -import { Sidebar, Dropdown, ButtonGroup, Icon, Screen, Button } from 'blueprint-react'; +import { Sidebar, ButtonGroup, Icon, Screen, Button, Dropdown, Carousel } from 'blueprint-react'; import Iframe from 'react-iframe'; import { PROFILE_NAME, getParamObject } from "../constants.js"; import Modal from './commonComponent/Modal.js'; import Dashboard from './Dashboard/Dashboard.js'; +import Details from './Details/App.js'; import 'react-toastify/dist/ReactToastify.css'; // import qsimg from './Asset/qs-details.png'; @@ -27,10 +28,15 @@ export default class Container extends React.Component { pathname = pathname.split("/"); pathname.pop(); this.pathname = pathname.join("/"); - this.closeHelpPopUp = this.closeHelpPopUp.bind(this) - this.openHelpPopUp = this.openHelpPopUp.bind(this) - console.log("container constructor"); - // + this.closeHelpPopUp = this.closeHelpPopUp.bind(this); + this.openHelpPopUp = this.openHelpPopUp.bind(this); + this.getDataCenters = this.getDataCenters.bind(this); + } + + getDataCenters(DataCentersObj){ + let DataCenters = [] + DataCentersObj.map((item)=>(DataCenters.push(item.datacenter))) + return DataCenters } closeHelpPopUp() { @@ -62,18 +68,21 @@ export default class Container extends React.Component { } size="btn--small" - items={this.props.items}> + items={this.props.items} + type="dropdown--type-button">
-
+
{/* help */} - {this.state.images.map(item=>help)} - + {/* {this.state.images.map(item=>help)} */} + + {this.state.images.map(item=>help)} +
@@ -105,7 +114,7 @@ export default class Container extends React.Component { }} /> + return }} /> @@ -133,8 +142,6 @@ class OperationalViewComponent extends React.Component { this.paramsObject = getParamObject(window.location); // query string as object - console.log("extracted paramsObject ", this.paramsObject); - this.handleIsListView = this.handleIsListView.bind(this); this.state = { isListView: true, // True signifies detailview and False for Treeview @@ -148,20 +155,15 @@ class OperationalViewComponent extends React.Component { isListView: (selectedView.value === "detail") }) } - componentWillMount() { - console.log("Mounting Operations view") - } - componentWillUnmount() { - console.log("Unmounting Operations view") - } render() { let { isListView, treeViewLocation, detailViewLocation } = this.state; let toLocation = isListView ? detailViewLocation : treeViewLocation; let dcName = this.paramsObject[PROFILE_NAME]; + let tenantName = this.paramsObject["tn"]; + let isDeleted = !this.props.availableDataCenter.includes(dcName); - console.log("Operations view Render", this.state); return (
@@ -177,7 +179,10 @@ class OperationalViewComponent extends React.Component { onChange={this.handleIsListView} />
- } + {this.state.isListView ?
: +
+ +
}
) } @@ -187,7 +192,6 @@ class OperationalViewComponent extends React.Component { function FrameComponent(props) { return