summaryrefslogtreecommitdiffstats
path: root/app/test/fetch
diff options
context:
space:
mode:
authorKoren Lev <korenlev@gmail.com>2017-07-27 15:04:07 +0000
committerGerrit Code Review <gerrit@opnfv.org>2017-07-27 15:04:07 +0000
commit162c03ef301396072c1934e7e7e0c40a841b4fe2 (patch)
tree7a2a2781949252436450ff5832962785061a774a /app/test/fetch
parentb88c78e3cf2bef22aa2f1c4d0bf305e303bc15f0 (diff)
parent7e83d0876ddb84a45e130eeba28bc40ef53c074b (diff)
Merge "Calipso initial release for OPNFV"
Diffstat (limited to 'app/test/fetch')
-rw-r--r--app/test/fetch/__init__.py9
-rw-r--r--app/test/fetch/api_fetch/__init__.py9
-rw-r--r--app/test/fetch/api_fetch/test_api_access.py142
-rw-r--r--app/test/fetch/api_fetch/test_api_fetch_availability_zone.py72
-rw-r--r--app/test/fetch/api_fetch/test_api_fetch_host_instances.py83
-rw-r--r--app/test/fetch/api_fetch/test_api_fetch_networks.py65
-rw-r--r--app/test/fetch/api_fetch/test_api_fetch_ports.py89
-rw-r--r--app/test/fetch/api_fetch/test_api_fetch_project_hosts.py137
-rw-r--r--app/test/fetch/api_fetch/test_api_fetch_projects.py120
-rw-r--r--app/test/fetch/api_fetch/test_api_fetch_regions.py41
-rw-r--r--app/test/fetch/api_fetch/test_data/__init__.py9
-rw-r--r--app/test/fetch/api_fetch/test_data/api_access.py55
-rw-r--r--app/test/fetch/api_fetch/test_data/api_fetch_availability_zones.py71
-rw-r--r--app/test/fetch/api_fetch/test_data/api_fetch_host_instances.py85
-rw-r--r--app/test/fetch/api_fetch/test_data/api_fetch_host_project_hosts.py225
-rw-r--r--app/test/fetch/api_fetch/test_data/api_fetch_networks.py72
-rw-r--r--app/test/fetch/api_fetch/test_data/api_fetch_ports.py72
-rw-r--r--app/test/fetch/api_fetch/test_data/api_fetch_projects.py88
-rw-r--r--app/test/fetch/api_fetch/test_data/api_fetch_regions.py50
-rw-r--r--app/test/fetch/api_fetch/test_data/configurations.py52
-rw-r--r--app/test/fetch/api_fetch/test_data/regions.py110
-rw-r--r--app/test/fetch/api_fetch/test_data/token.py23
-rw-r--r--app/test/fetch/cli_fetch/__init__.py9
-rw-r--r--app/test/fetch/cli_fetch/test_cli_access.py159
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_host_pnics.py135
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_host_pnics_vpp.py34
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_host_vservices.py132
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics.py111
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_ovs.py36
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_vpp.py23
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_vconnectors.py66
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_ovs.py38
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_vpp.py50
-rw-r--r--app/test/fetch/cli_fetch/test_cli_fetch_vservice_vnics.py124
-rw-r--r--app/test/fetch/cli_fetch/test_data/__init__.py9
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_access.py58
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics.py147
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics_vpp.py204
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_host_verservices.py276
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_instance_vnics.py288
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors.py103
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_ovs.py234
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_vpp.py137
-rw-r--r--app/test/fetch/cli_fetch/test_data/cli_fetch_vservice_vnics.py616
-rw-r--r--app/test/fetch/config/__init__.py9
-rw-r--r--app/test/fetch/config/test_config.py17
-rw-r--r--app/test/fetch/db_fetch/__init__.py9
-rw-r--r--app/test/fetch/db_fetch/mock_cursor.py25
-rw-r--r--app/test/fetch/db_fetch/test_data/__init__.py9
-rw-r--r--app/test/fetch/db_fetch/test_data/db_access.py40
-rw-r--r--app/test/fetch/db_fetch/test_data/db_fetch_aggregate_hosts.py34
-rw-r--r--app/test/fetch/db_fetch/test_data/db_fetch_aggregates.py17
-rw-r--r--app/test/fetch/db_fetch/test_data/db_fetch_host_network_agents.py65
-rw-r--r--app/test/fetch/db_fetch/test_data/db_fetch_instances.py91
-rw-r--r--app/test/fetch/db_fetch/test_data/db_fetch_oteps.py131
-rw-r--r--app/test/fetch/db_fetch/test_data/db_fetch_vedges_ovs.py168
-rw-r--r--app/test/fetch/db_fetch/test_data/db_fetch_vedges_vpp.py89
-rw-r--r--app/test/fetch/db_fetch/test_db_access.py108
-rw-r--r--app/test/fetch/db_fetch/test_db_fetch_aggregate_hosts.py60
-rw-r--r--app/test/fetch/db_fetch/test_db_fetch_aggregates.py26
-rw-r--r--app/test/fetch/db_fetch/test_db_fetch_instances.py37
-rw-r--r--app/test/fetch/db_fetch/test_db_fetch_oteps.py92
-rw-r--r--app/test/fetch/db_fetch/test_db_fetch_vedges_ovs.py109
-rw-r--r--app/test/fetch/db_fetch/test_db_fetch_vedges_vpp.py82
-rw-r--r--app/test/fetch/db_fetch/test_fetch_host_network_agents.py66
-rw-r--r--app/test/fetch/test_fetch.py46
66 files changed, 5998 insertions, 0 deletions
diff --git a/app/test/fetch/__init__.py b/app/test/fetch/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/api_fetch/__init__.py b/app/test/fetch/api_fetch/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/api_fetch/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/api_fetch/test_api_access.py b/app/test/fetch/api_fetch/test_api_access.py
new file mode 100644
index 0000000..e4767b7
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_access.py
@@ -0,0 +1,142 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from unittest.mock import patch, MagicMock
+from discover.fetchers.api.api_access import ApiAccess
+from test.fetch.api_fetch.test_data.api_access import *
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.regions import REGIONS
+
+
+class TestApiAccess(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.api_access = ApiAccess()
+ self.set_regions_for_fetcher(self.api_access)
+
+ def test_parse_time_without_dot_in_time(self):
+ time = self.api_access.parse_time(TIME_WITHOUT_DOT)
+ self.assertNotEqual(time, None, "Can't parse the time without dot")
+
+ def test_parse_time_with_dot_in_time(self):
+ time = self.api_access.parse_time(TIME_WITH_DOT)
+ self.assertNotEqual(time, None, "Can't parse the time with dot")
+
+ def test_parse_illegal_time(self):
+ time = self.api_access.parse_time(ILLEGAL_TIME)
+ self.assertEqual(time, None, "Can't get None when the time format is wrong")
+
+ def test_get_existing_token(self):
+ self.api_access.tokens = VALID_TOKENS
+ token = self.api_access.get_existing_token(PROJECT)
+ self.assertNotEqual(token, VALID_TOKENS[PROJECT], "Can't get existing token")
+
+ def test_get_nonexistent_token(self):
+ self.api_access.tokens = EMPTY_TOKENS
+ token = self.api_access.get_existing_token(TEST_PROJECT)
+ self.assertEqual(token, None, "Can't get None when the token doesn't " +
+ "exist in tokens")
+
+ @patch("httplib2.Http.request")
+ def test_v2_auth(self, mock_request):
+ self.api_access.get_existing_token = MagicMock(return_value=None)
+ # mock authentication info from OpenStack Api
+ mock_request.return_value = (RESPONSE, CORRECT_AUTH_CONTENT)
+ token_details = self.api_access.v2_auth(TEST_PROJECT, TEST_HEADER, TEST_BODY)
+ self.assertNotEqual(token_details, None, "Can't get the token details")
+
+ @patch("httplib2.Http.request")
+ def test_v2_auth_with_error_content(self, mock_request):
+ self.api_access.get_existing_token = MagicMock(return_value=None)
+ # authentication content from OpenStack Api will be incorrect
+ mock_request.return_value = (RESPONSE, ERROR_AUTH_CONTENT)
+ token_details = self.api_access.v2_auth(TEST_PROJECT, TEST_HEADER, TEST_BODY)
+ self.assertIs(token_details, None, "Can't get None when the content is wrong")
+
+ @patch("httplib2.Http.request")
+ def test_v2_auth_with_error_token(self, mock_request):
+ # authentication info from OpenStack Api will not contain token info
+ mock_request.return_value = (RESPONSE, ERROR_TOKEN_CONTENT)
+ token_details = self.api_access.v2_auth(TEST_PROJECT, TEST_HEADER, TEST_BODY)
+ self.assertIs(token_details, None, "Can't get None when the content " +
+ "doesn't contain any token info")
+
+ @patch("httplib2.Http.request")
+ def test_v2_auth_with_error_expiry_time(self, mock_request):
+ mock_request.return_value = (RESPONSE, CORRECT_AUTH_CONTENT)
+
+ # store original parse_time method
+ original_method = self.api_access.parse_time
+ # the time will not be parsed
+ self.api_access.parse_time = MagicMock(return_value=None)
+
+ token_details = self.api_access.v2_auth(TEST_PROJECT, TEST_HEADER, TEST_BODY)
+ # reset original parse_time method
+ self.api_access.parse_time = original_method
+
+ self.assertIs(token_details, None, "Can't get None when the time in token " +
+ "can't be parsed")
+
+ @patch("httplib2.Http.request")
+ def test_v2_auth_pwd(self, mock_request):
+ # mock the authentication info from OpenStack Api
+ mock_request.return_value = (RESPONSE, CORRECT_AUTH_CONTENT)
+ token = self.api_access.v2_auth_pwd(PROJECT)
+ self.assertNotEqual(token, None, "Can't get token")
+
+ @patch("httplib2.Http.request")
+ def test_get_url(self, mock_request):
+ mock_request.return_value = (RESPONSE, GET_CONTENT)
+ result = self.api_access.get_url(TEST_URL, TEST_HEADER)
+ # check whether it returns content message when the response is correct
+ self.assertNotIn("status", result, "Can't get content when the " +
+ "response is correct")
+
+ @patch("httplib2.Http.request")
+ def test_get_url_with_error_response(self, mock_request):
+ # the response will be wrong
+ mock_request.return_value = (ERROR_RESPONSE, None)
+ result = self.api_access.get_url(TEST_URL, TEST_HEADER)
+ self.assertNotEqual(result, None, "Can't get response message " +
+ "when the response status is not 200")
+
+ def test_get_region_url(self):
+ region_url = self.api_access.get_region_url(REGION_NAME, SERVICE_NAME)
+
+ self.assertNotEqual(region_url, None, "Can't get region url")
+
+ def test_get_region_url_with_wrong_region_name(self):
+ # error region name doesn't exist in the regions info
+ region_url = self.api_access.get_region_url(ERROR_REGION_NAME, "")
+ self.assertIs(region_url, None, "Can't get None with the region " +
+ "name is wrong")
+
+ def test_get_region_url_without_service_endpoint(self):
+ # error service doesn't exist in region service endpoints
+ region_url = self.api_access.get_region_url(REGION_NAME, ERROR_SERVICE_NAME)
+ self.assertIs(region_url, None, "Can't get None with wrong service name")
+
+ def test_region_url_nover(self):
+ # mock return value of get_region_url, which has something starting from v2
+ self.api_access.get_region_url = MagicMock(return_value=REGION_URL)
+ region_url = self.api_access.get_region_url_nover(REGION_NAME, SERVICE_NAME)
+ # get_region_nover will remove everything from v2
+ self.assertNotIn("v2", region_url, "Can't get region url without v2 info")
+
+ def test_get_service_region_endpoints(self):
+ region = REGIONS[REGION_NAME]
+ result = self.api_access.get_service_region_endpoints(region, SERVICE_NAME)
+ self.assertNotEqual(result, None, "Can't get service endpoint")
+
+ def test_get_service_region_endpoints_with_nonexistent_service(self):
+ region = REGIONS[REGION_NAME]
+ result = self.api_access.get_service_region_endpoints(region, ERROR_SERVICE_NAME)
+ self.assertIs(result, None, "Can't get None when the service name " +
+ "doesn't exist in region's services")
diff --git a/app/test/fetch/api_fetch/test_api_fetch_availability_zone.py b/app/test/fetch/api_fetch/test_api_fetch_availability_zone.py
new file mode 100644
index 0000000..f32be36
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_fetch_availability_zone.py
@@ -0,0 +1,72 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.api.api_fetch_availability_zones import ApiFetchAvailabilityZones
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.api_fetch_availability_zones import *
+from unittest.mock import MagicMock
+from test.fetch.api_fetch.test_data.token import TOKEN
+
+
+class TestApiFetchAvailabilityZones(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ ApiFetchAvailabilityZones.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.fetcher = ApiFetchAvailabilityZones()
+ self.set_regions_for_fetcher(self.fetcher)
+
+ def test_get_for_region(self):
+ # mock the endpoint url
+ self.fetcher.get_region_url_nover = MagicMock(return_value=ENDPOINT)
+ # mock the response from OpenStack Api
+ self.fetcher.get_url = MagicMock(return_value=AVAILABILITY_ZONE_RESPONSE)
+
+ result = self.fetcher.get_for_region(PROJECT, REGION_NAME, TOKEN)
+ self.assertNotEqual(result, [], "Can't get availability zone info")
+
+ def test_get_for_region_with_wrong_response(self):
+ # mock the endpoint url
+ self.fetcher.get_region_url_nover = MagicMock(return_value=ENDPOINT)
+ # mock the wrong response from OpenStack Api
+ self.fetcher.get_url = MagicMock(return_value=WRONG_RESPONSE)
+
+ result = self.fetcher.get_for_region(PROJECT, REGION_NAME, TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the response is wrong")
+
+ def test_get_for_region_without_avz_response(self):
+ # mock the endpoint url
+ self.fetcher.get_region_url_nover = MagicMock(return_value=ENDPOINT)
+ # mock the response from OpenStack Api
+ # the response doesn't contain availability zone info
+ self.fetcher.get_url = MagicMock(return_value=RESPONSE_WITHOUT_AVAILABILITY_ZONE)
+
+ result = self.fetcher.get_for_region(PROJECT, REGION_NAME, TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the response doesn't " +
+ "contain availability zone")
+
+ def test_get(self):
+ # store original get_for_region method
+ original_method = self.fetcher.get_for_region
+ # mock the result from get_for_region method
+ self.fetcher.get_for_region = MagicMock(return_value=GET_REGION_RESULT)
+
+ result = self.fetcher.get(PROJECT)
+
+ # reset get_for_region method
+ self.fetcher.get_for_region = original_method
+
+ self.assertNotEqual(result, [], "Can't get availability zone info")
+
+ def test_get_without_token(self):
+ # mock the empty token
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=None)
+ result = self.fetcher.get(PROJECT)
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the token is invalid")
diff --git a/app/test/fetch/api_fetch/test_api_fetch_host_instances.py b/app/test/fetch/api_fetch/test_api_fetch_host_instances.py
new file mode 100644
index 0000000..c1c7b6e
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_fetch_host_instances.py
@@ -0,0 +1,83 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.api.api_fetch_host_instances import ApiFetchHostInstances
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.api_fetch_host_instances import *
+from test.fetch.api_fetch.test_data.token import TOKEN
+from unittest.mock import MagicMock
+
+
+class TestApiFetchHostInstances(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ ApiFetchHostInstances.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.fetcher = ApiFetchHostInstances()
+ self.set_regions_for_fetcher(self.fetcher)
+
+ def test_get_projects(self):
+ # mock the projects got from the database
+ self.fetcher.inv.get = MagicMock(return_value=PROJECT_LIST)
+
+ self.fetcher.get_projects()
+ self.assertNotEqual(self.fetcher.projects, None, "Can't get projects info")
+
+ def test_get_instances_from_api(self):
+ self.fetcher.inv.get = MagicMock(return_value=PROJECT_LIST)
+ # mock the response from the OpenStack Api
+ self.fetcher.get_url = MagicMock(return_value=GET_SERVERS_RESPONSE)
+
+ result = self.fetcher.get_instances_from_api(HOST_NAME)
+ self.assertEqual(result, GET_INSTANCES_FROM_API, "Can't get correct " +
+ "instances info")
+
+ def test_get_instances_from_api_with_wrong_auth(self):
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=None)
+
+ result = self.fetcher.get_instances_from_api(HOST_NAME)
+ self.assertEqual(result, [], "Can't get [] when the token is invalid")
+
+ def test_get_instances_from_api_without_hypervisors_in_res(self):
+ # mock the response without hypervisors info from OpenStack Api
+ self.fetcher.get_url = MagicMock(return_value=RESPONSE_WITHOUT_HYPERVISORS)
+
+ result = self.fetcher.get_instances_from_api(HOST_NAME)
+ self.assertEqual(result, [], "Can't get [] when the response doesn't " +
+ "contain hypervisors info")
+
+ def test_get_instances_from_api_without_servers_in_res(self):
+ # mock the response without servers info from OpenStack Api
+ self.fetcher.get_url = MagicMock(return_value=RESPONSE_WITHOUT_SERVERS)
+
+ result = self.fetcher.get_instances_from_api(HOST_NAME)
+ self.assertEqual(result, [], "Can't get [] when the response doesn't " +
+ "contain servers info")
+
+ def test_get(self):
+ self.fetcher.inv.get = MagicMock(return_value=PROJECT_LIST)
+ self.fetcher.inv.get_by_id = MagicMock(return_value=HOST)
+
+ original_method = self.fetcher.get_instances_from_api
+ self.fetcher.get_instances_from_api = MagicMock(return_value=
+ GET_INSTANCES_FROM_API)
+
+ self.fetcher.db_fetcher.get_instance_data = MagicMock()
+ result = self.fetcher.get(INSTANCE_FOLDER_ID)
+ self.assertNotEqual(result, [], "Can't get instances info")
+
+ self.fetcher.get_instances_from_api = original_method
+
+ def test_get_with_non_compute_node(self):
+ self.fetcher.inv.get = MagicMock(return_value=PROJECT_LIST)
+ self.fetcher.inv.get_by_id = MagicMock(return_value=NON_COMPUTE_HOST)
+
+ result = self.fetcher.get(INSTANCE_FOLDER_ID)
+ self.assertEqual(result, [], "Can't get [] when the host is " +
+ "not compute node")
diff --git a/app/test/fetch/api_fetch/test_api_fetch_networks.py b/app/test/fetch/api_fetch/test_api_fetch_networks.py
new file mode 100644
index 0000000..1dc74ce
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_fetch_networks.py
@@ -0,0 +1,65 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from unittest.mock import MagicMock
+from discover.fetchers.api.api_fetch_networks import ApiFetchNetworks
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.api_fetch_networks import *
+from test.fetch.api_fetch.test_data.token import TOKEN
+
+
+class TestApiFetchNetworks(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ ApiFetchNetworks.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.fetcher = ApiFetchNetworks()
+ self.set_regions_for_fetcher(self.fetcher)
+
+ def test_get_networks(self):
+ self.fetcher.get_region_url_nover = MagicMock(return_value=ENDPOINT)
+ self.fetcher.get_url = MagicMock(side_effect=[NETWORKS_RESPONSE,
+ SUBNETS_RESPONSE])
+ self.fetcher.inv.get_by_id = MagicMock(return_value=PROJECT)
+ result = self.fetcher.get_networks(REGION_NAME, TOKEN)
+ self.assertEqual(result, NETWORKS_RESULT, "Can't get networks info")
+
+ def test_get_networks_with_wrong_networks_response(self):
+ self.fetcher.get_region_url_nover = MagicMock(return_value=ENDPOINT)
+ self.fetcher.get_url = MagicMock(return_value=WRONG_NETWORK_RESPONSE)
+
+ result = self.fetcher.get_networks(REGION_NAME, TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the networks " +
+ "response is wrong")
+
+ def test_get_networks_with_wrong_subnet_response(self):
+ self.fetcher.get_region_url_nover = MagicMock(return_value=ENDPOINT)
+ self.fetcher.get_url = MagicMock(side_effect=[NETWORKS_RESPONSE,
+ WRONG_SUBNETS_RESPONSE])
+ self.fetcher.inv.get_by_id = MagicMock(return_value=PROJECT)
+
+ result = self.fetcher.get_networks(REGION_NAME, TOKEN)
+
+ self.assertNotEqual(result, [], "Can't get networks info when the " +
+ "subnet response is wrong")
+
+ def test_get(self):
+ original_method = self.fetcher.get_networks
+ self.fetcher.get_networks = MagicMock(return_value=NETWORKS_RESULT)
+ result = self.fetcher.get(REGION_NAME)
+
+ self.fetcher.get_networks = original_method
+ self.assertEqual(result, NETWORKS_RESULT, "Can't get region networks info")
+
+ def test_get_with_wrong_token(self):
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=None)
+ result = self.fetcher.get(REGION_NAME)
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the " +
+ "token is invalid")
diff --git a/app/test/fetch/api_fetch/test_api_fetch_ports.py b/app/test/fetch/api_fetch/test_api_fetch_ports.py
new file mode 100644
index 0000000..ad79757
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_fetch_ports.py
@@ -0,0 +1,89 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.api.api_fetch_ports import ApiFetchPorts
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.api_fetch_ports import *
+from test.fetch.api_fetch.test_data.token import TOKEN
+from unittest.mock import MagicMock
+
+
+class TestApiFetchPorts(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ ApiFetchPorts.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.fetcher = ApiFetchPorts()
+ self.set_regions_for_fetcher(self.fetcher)
+
+ def check_get_ports_for_region_result_is_correct(self, network,
+ tenant,
+ port_response,
+ expected_result,
+ error_msg):
+ self.fetcher.get_region_url = MagicMock(return_value=ENDPOINT)
+ self.fetcher.get_url = MagicMock(return_value=port_response)
+ self.fetcher.inv.get_by_id = MagicMock(side_effect=[network, tenant])
+
+ result = self.fetcher.get_ports_for_region(REGION_NAME, TOKEN)
+ self.assertEqual(result, expected_result, error_msg)
+
+ def test_get_ports_for_region(self):
+ test_cases = [
+ {
+ "network": NETWORK,
+ "tenant": None,
+ "port_response": PORTS_RESPONSE,
+ "expected_result": PORTS_RESULT_WITH_NET,
+ "error_msg": "Can't get correct ports info "
+ "when network of the port exists"
+ },
+ {
+ "network": None,
+ "tenant": None,
+ "port_response": PORTS_RESPONSE,
+ "expected_result": PORTS_RESULT_WITHOUT_NET,
+ "error_msg": "Can't get correct ports info "
+ "when network of the port doesn't exists"
+ },
+ {
+ "network": NETWORK,
+ "tenant": TENANT,
+ "port_response": PORTS_RESPONSE,
+ "expected_result": PORTS_RESULT_WITH_PROJECT,
+ "error_msg": "Can't get correct ports info "
+ "when project of the port exists"
+ },
+ {
+ "network": None,
+ "tenant": None,
+ "port_response": ERROR_PORTS_RESPONSE,
+ "expected_result": [],
+ "error_msg": "Can't get [] when ports response is wrong"
+ },
+ ]
+ for test_case in test_cases:
+ self.check_get_ports_for_region_result_is_correct(test_case["network"],
+ test_case["tenant"],
+ test_case["port_response"],
+ test_case["expected_result"],
+ test_case["error_msg"])
+
+ def test_get(self):
+ original_method = self.fetcher.get_ports_for_region
+ self.fetcher.get_ports_for_region = MagicMock(return_value=PORTS_RESULT_WITH_NET)
+ result = self.fetcher.get(REGION_NAME)
+ self.fetcher.get_ports_for_region = original_method
+ self.assertEqual(result, PORTS_RESULT_WITH_NET, "Can't get correct ports info")
+
+ def test_get_with_wrong_token(self):
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=None)
+ result = self.fetcher.get(REGION_NAME)
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the token is invalid")
diff --git a/app/test/fetch/api_fetch/test_api_fetch_project_hosts.py b/app/test/fetch/api_fetch/test_api_fetch_project_hosts.py
new file mode 100644
index 0000000..7cedf67
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_fetch_project_hosts.py
@@ -0,0 +1,137 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from unittest.mock import MagicMock
+from discover.fetchers.api.api_fetch_project_hosts import ApiFetchProjectHosts
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.api_fetch_host_project_hosts import *
+from test.fetch.api_fetch.test_data.token import TOKEN
+from test.fetch.api_fetch.test_data.regions import REGIONS
+
+
+class TestApiFetchProjectHosts(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ ApiFetchProjectHosts.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.fetcher = ApiFetchProjectHosts()
+ self.set_regions_for_fetcher(self.fetcher)
+ self.region = REGIONS[REGION_NAME]
+
+ def test_add_host_type_with_nonexistent_type(self):
+ # clear host type
+ HOST_DOC["host_type"] = []
+ self.fetcher.add_host_type(HOST_DOC, NONEXISTENT_TYPE, HOST_ZONE)
+ self.assertIn(NONEXISTENT_TYPE, HOST_DOC["host_type"], "Can't put nonexistent " +
+ "type in host_type")
+
+ def test_add_host_type_with_existent_host_type(self):
+ # add nonexistent host type to host type
+ HOST_DOC["host_type"] = [NONEXISTENT_TYPE]
+ # try to add existing host type
+ self.fetcher.add_host_type(HOST_DOC, NONEXISTENT_TYPE, HOST_ZONE)
+ self.assertEqual(len(HOST_DOC['host_type']), 1, "Add duplicate host type")
+
+ def test_add_compute_host_type(self):
+ HOST_DOC['host_type'] = []
+ # clear zone
+ HOST_DOC['zone'] = None
+ # add compute host type
+ self.fetcher.add_host_type(HOST_DOC, COMPUTE_TYPE, HOST_ZONE)
+ # for compute host type, zone information will be added
+ self.assertEqual(HOST_DOC['zone'], HOST_ZONE, "Can't update zone " +
+ "name for compute node")
+ self.assertEqual(HOST_DOC['parent_id'], HOST_ZONE, "Can't update parent_id " +
+ "for compute node")
+
+ def test_fetch_compute_node_ip_address(self):
+ # mock ip address information fetched from DB
+ self.fetcher.get_objects_list_for_id = MagicMock(return_value=IP_ADDRESS_RESPONSE)
+
+ self.fetcher.fetch_compute_node_ip_address(HOST_TO_BE_FETCHED_IP,
+ HOST_TO_BE_FETCHED_IP["host"])
+ self.assertIn("ip_address", HOST_TO_BE_FETCHED_IP, "Can't update ip address " +
+ "for the compute host")
+
+ def test_fetch_network_node_details(self):
+ # mock NETWORKS_DETAILS_RESPONSE fetched from DB
+ self.fetcher.get_objects_list = MagicMock(return_value=NETWORKS_DETAILS_RESPONSE)
+
+ self.fetcher.fetch_network_node_details(HOSTS_TO_BE_FETCHED_NETWORK_DETAILS)
+ # get the network node document from HOSTS
+ NETWORK_NODE_DOC = [doc for doc in HOSTS_TO_BE_FETCHED_NETWORK_DETAILS
+ if doc['host'] == HOST_NAME][0]
+ # check if the network node document has been updated
+ self.assertIn("Network", NETWORK_NODE_DOC['host_type'], "Can't put Network in " +
+ "the network node host_type")
+ self.assertIn("config", NETWORK_NODE_DOC, "Can't put config in the network node")
+
+ def test_get_host_details(self):
+ # test node have nova-conductor attribute, controller type will be added
+ result = self.fetcher.get_host_details(AVAILABILITY_ZONE, HOST_NAME)
+ self.assertIn("Controller", result['host_type'], "Can't put controller type " +
+ "in the compute node host_type")
+
+ def test_get_hosts_from_az(self):
+ result = self.fetcher.get_hosts_from_az(AVAILABILITY_ZONE)
+ self.assertNotEqual(result, [], "Can't get hosts information from "
+ "availability zone")
+
+ def test_get_for_region(self):
+ # mock region url for nova node
+ self.fetcher.get_region_url = MagicMock(return_value=REGION_URL)
+ # mock the response from OpenStack Api
+ side_effect = [AVAILABILITY_ZONE_RESPONSE, HYPERVISORS_RESPONSE]
+ self.fetcher.get_url = MagicMock(side_effect=side_effect)
+
+ result = self.fetcher.get_for_region(self.region, TOKEN)
+ self.assertNotEqual(result, [], "Can't get hosts information for region")
+
+ def test_get_for_region_without_token(self):
+ self.fetcher.get_region_url = MagicMock(return_value=REGION_URL)
+ result = self.fetcher.get_for_region(self.region, None)
+ self.assertEqual(result, [], "Can't get [] when the token is invalid")
+
+ def test_get_for_region_with_error_availability_response(self):
+ self.fetcher.get_region_url = MagicMock(return_value=REGION_URL)
+ # mock error availability zone response from OpenStack Api
+ side_effect = [AVAILABILITY_ERROR_RESPONSE, None]
+ self.fetcher.get_url = MagicMock(side_effect=side_effect)
+
+ result = self.fetcher.get_for_region(self.region, TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the response is wrong")
+
+ def test_get_for_region_with_error_hypervisors_response(self):
+ self.fetcher.get_region_url = MagicMock(return_value=REGION_URL)
+ # mock error hypervisors response from OpenStack Api
+ side_effect = [AVAILABILITY_ZONE_RESPONSE, HYPERVISORS_ERROR_RESPONSE]
+ self.fetcher.get_url = MagicMock(side_effect=side_effect)
+
+ result = self.fetcher.get_for_region(self.region, TOKEN)
+ self.assertNotEqual(result, [], "Can't get hosts information when " +
+ "the hypervisors response is wrong")
+
+ def test_get(self):
+ original_method = self.fetcher.get_for_region
+ self.fetcher.get_for_region = MagicMock(return_value=GET_FOR_REGION_INFO)
+
+ result = self.fetcher.get(PROJECT_NAME)
+
+ self.fetcher.get_for_region = original_method
+
+ self.assertNotEqual(result, [], "Can't get hosts info for the project")
+
+ def test_get_with_wrong_project_name(self):
+ result = self.fetcher.get(TEST_PROJECT_NAME)
+ self.assertEqual(result, [], "Can't get [] when the project name is not admin")
+
+ def test_get_with_wrong_token(self):
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=[])
+ result = self.fetcher.get(PROJECT_NAME)
+ self.assertEqual(result, [], "Can't get [] when the token is invalid")
diff --git a/app/test/fetch/api_fetch/test_api_fetch_projects.py b/app/test/fetch/api_fetch/test_api_fetch_projects.py
new file mode 100644
index 0000000..1db4237
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_fetch_projects.py
@@ -0,0 +1,120 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from unittest.mock import MagicMock
+from discover.fetchers.api.api_fetch_projects import ApiFetchProjects
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.api_fetch_projects import *
+from test.fetch.api_fetch.test_data.regions import REGIONS
+from test.fetch.api_fetch.test_data.token import TOKEN
+
+
+class TestApiFetchProjects(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ ApiFetchProjects.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.fetcher = ApiFetchProjects()
+ self.set_regions_for_fetcher(self.fetcher)
+ self.region = REGIONS[REGION_NAME]
+ self.fetcher.get_region_url_nover = MagicMock(return_value=REGION_URL_NOVER)
+
+ def test_get_for_region(self):
+ # mock request endpoint
+ self.fetcher.get_region_url_nover = MagicMock(return_value=REGION_URL_NOVER)
+ self.fetcher.get_url = MagicMock(return_value=REGION_RESPONSE)
+
+ result = self.fetcher.get_for_region(self.region, TOKEN)
+ self.assertEqual(result, REGION_RESULT, "Can't get correct projects info")
+
+ # TODO does this test case make sense?
+ def test_get_for_region_with_error_region_response(self):
+ self.fetcher.get_region_url_nover = MagicMock(return_value=REGION_URL_NOVER)
+ self.fetcher.get_url = MagicMock(return_value=REGION_ERROR_RESPONSE)
+
+ result = self.fetcher.get_for_region(self.region, TOKEN)
+ self.assertEqual(result, [], "Can't get [] when the " +
+ "region response is wrong")
+
+ def test_get_projects_for_api_user(self):
+ # mock the responses from OpenStack Api
+ self.fetcher.get_url = MagicMock(return_value=PROJECTS_CORRECT_RESPONSE)
+
+ result = self.fetcher.get_projects_for_api_user(self.region, TOKEN)
+ self.assertEqual(result, PROJECT_RESULT, "Can't get correct " +
+ "projects info for api user")
+
+ def test_get_projects_for_api_user_without_projects_response(self):
+ # the projects info from OpenStack Api will be None
+ self.fetcher.get_url = MagicMock(return_value=
+ PROJECTS_RESPONSE_WITHOUT_PROJECTS)
+
+ result = self.fetcher.get_projects_for_api_user(self.region, TOKEN)
+ self.assertIs(result, None, "Can't get None when the project " +
+ "response doesn't contain projects info")
+
+ def check_get_result(self, projects_for_api_user,
+ region_result,
+ token,
+ expected_result, error_msg):
+ self.fetcher.get_projects_for_api_user = MagicMock(return_value=
+ projects_for_api_user)
+ original_method = self.fetcher.get_for_region
+ # mock
+ self.fetcher.get_for_region = MagicMock(return_value=region_result)
+ self.fetcher.v2_auth_pwd = MagicMock(return_value=token)
+
+ result = self.fetcher.get(PROJECT_ID)
+
+ self.fetcher.get_for_region = original_method
+ self.assertEqual(result, expected_result, error_msg)
+
+ def test_get(self):
+ # test get method with different test cases
+ test_cases = [
+ {
+ "projects": PROJECT_RESULT,
+ "regions": REGION_RESULT,
+ "token": TOKEN,
+ "expected_result": REGION_RESULT,
+ "err_msg": "Can't get correct project result"
+ },
+ {
+ "projects": PROJECT_RESULT,
+ "regions": REGION_RESULT_WITH_NON_USER_PROJECT,
+ "token": TOKEN,
+ "expected_result": REGION_RESULT,
+ "err_msg": "Can't get correct project result" +
+ "when the region result contains project " +
+ "that doesn't belong to the user"
+ },
+ {
+ "projects": PROJECT_RESULT,
+ "regions": REGION_RESULT,
+ "token": None,
+ "expected_result": [],
+ "err_msg": "Can't get [] when the token is invalid"
+ },
+ {
+ "projects": None,
+ "regions": REGION_RESULT,
+ "token": TOKEN,
+ "expected_result": REGION_RESULT,
+ "err_msg": "Can't get the region " +
+ "result if the projects " +
+ "for the user doesn't exist"
+ }
+ ]
+
+ for test_case in test_cases:
+ self.check_get_result(test_case["projects"],
+ test_case["regions"],
+ test_case["token"],
+ test_case["expected_result"],
+ test_case["err_msg"])
diff --git a/app/test/fetch/api_fetch/test_api_fetch_regions.py b/app/test/fetch/api_fetch/test_api_fetch_regions.py
new file mode 100644
index 0000000..1ff7999
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_api_fetch_regions.py
@@ -0,0 +1,41 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.api.api_access import ApiAccess
+from discover.fetchers.api.api_fetch_regions import ApiFetchRegions
+from test.fetch.test_fetch import TestFetch
+from test.fetch.api_fetch.test_data.api_fetch_regions import *
+from test.fetch.api_fetch.test_data.token import TOKEN
+from unittest.mock import MagicMock
+
+
+class TestApiFetchRegions(TestFetch):
+
+ def setUp(self):
+ ApiFetchRegions.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.configure_environment()
+
+ def test_get(self):
+ fetcher = ApiFetchRegions()
+ fetcher.set_env(ENV)
+
+ ApiAccess.auth_response = AUTH_RESPONSE
+ ret = fetcher.get("test_id")
+ self.assertEqual(ret, REGIONS_RESULT,
+ "Can't get correct regions information")
+
+ def test_get_without_token(self):
+ fetcher = ApiFetchRegions()
+ fetcher.v2_auth_pwd = MagicMock(return_value=[])
+ fetcher.set_env(ENV)
+
+ ret = fetcher.get("test_id")
+
+ ApiFetchRegions.v2_auth_pwd = MagicMock(return_value=TOKEN)
+ self.assertEqual(ret, [], "Can't get [] when the token is invalid")
diff --git a/app/test/fetch/api_fetch/test_data/__init__.py b/app/test/fetch/api_fetch/test_data/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/api_fetch/test_data/api_access.py b/app/test/fetch/api_fetch/test_data/api_access.py
new file mode 100644
index 0000000..2181c48
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_access.py
@@ -0,0 +1,55 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from datetime import datetime, timedelta
+
+
+TIME_WITH_DOT = "2016-10-19T23:21:09.418406Z"
+TIME_WITHOUT_DOT = "2016-10-19T23:21:09Z"
+ILLEGAL_TIME = "23243423"
+TEST_PROJECT = "test"
+PROJECT = "admin"
+TEST_URL = "test_url"
+TEST_HEADER = "test_headers"
+TEST_BODY = "test_body"
+
+RESPONSE = {
+ 'server': 'Apache',
+ 'vary': 'X-Auth-Token',
+ 'content-type': 'application/json',
+ 'date': 'Wed, 19 Oct 2016 23:15:36 GMT',
+ 'content-length': '4876',
+ 'x-openstack-request-id': 'req-01cda259-7f60-4440-99a0-508fed90f815',
+ 'connection': 'close',
+ 'status': '200'
+}
+ERROR_RESPONSE = {
+ 'connection': 'close',
+ 'status': '400'
+}
+GET_CONTENT = b'{"text":"test"}'
+CORRECT_AUTH_CONTENT = b'{"access": {"token": {"issued_at": "2016-10-21T23:49:50.000000Z", "expires": "2016-10-22T00:49:50.445603Z", "id": "gAAAAABYCqme1l0qCm6mi3jON4ElweTkhZjGXZ_bYuxLHZGGXgO3T_JLnxKJ7KbK4xA8KjQ-DQe2trDncKQA0M-yeX167wT0xO_rjqqcCA19JV-EeXFfx7QOukkt8eC4pfK1r8Dc_kvBc-bwAemjZ1IvPGu5Nd2f0ktGWre0Qqzbg9QGtCEJUe8", "tenant": {"is_domain": false, "description": "admin tenant", "enabled": true, "id": "8c1751e0ce714736a63fee3c776164da", "parent_id": null, "name": "admin"}, "audit_ids": ["8BvzDPpyRBmeJho-FzKuGA"]}, "serviceCatalog": [{"endpoints": [{"adminURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da", "region": "RegionOne", "internalURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da", "id": "274cbbd9fd6d4311b78e78dd3a1df51f", "publicURL": "http://172.16.0.3:8774/v2/8c1751e0ce714736a63fee3c776164da"}], "endpoints_links": [], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL": "http://192.168.0.2:9696", "region": "RegionOne", "internalURL": "http://192.168.0.2:9696", "id": "8dc28584da224c4b9671171ead3c982a", "publicURL": "http://172.16.0.3:9696"}], "endpoints_links": [], "type": "network", "name": "neutron"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8776/v2/8c1751e0ce714736a63fee3c776164da", "region": "RegionOne", "internalURL": "http://192.168.0.2:8776/v2/8c1751e0ce714736a63fee3c776164da", "id": "2c30937688e944889db4a64fab6816e6", "publicURL": "http://172.16.0.3:8776/v2/8c1751e0ce714736a63fee3c776164da"}], "endpoints_links": [], "type": "volumev2", "name": "cinderv2"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8774/v3", "region": "RegionOne", "internalURL": "http://192.168.0.2:8774/v3", "id": "1df917160dfb4ce5b469764fde22b3ab", "publicURL": "http://172.16.0.3:8774/v3"}], "endpoints_links": [], "type": "computev3", "name": "novav3"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8080", "region": "RegionOne", "internalURL": "http://192.168.0.2:8080", "id": "4f655c8f2bef46a0a7ba4a20bba53666", "publicURL": "http://172.16.0.3:8080"}], "endpoints_links": [], "type": "s3", "name": "swift_s3"}, {"endpoints": [{"adminURL": "http://192.168.0.2:9292", "region": "RegionOne", "internalURL": "http://192.168.0.2:9292", "id": "475c6c77a94e4e63a5a0f0e767f697a8", "publicURL": "http://172.16.0.3:9292"}], "endpoints_links": [], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8777", "region": "RegionOne", "internalURL": "http://192.168.0.2:8777", "id": "617177a3dcb64560a5a79ab0a91a7225", "publicURL": "http://172.16.0.3:8777"}], "endpoints_links": [], "type": "metering", "name": "ceilometer"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8000/v1", "region": "RegionOne", "internalURL": "http://192.168.0.2:8000/v1", "id": "0f04ec6ed49f4940822161bf677bdfb2", "publicURL": "http://172.16.0.3:8000/v1"}], "endpoints_links": [], "type": "cloudformation", "name": "heat-cfn"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8776/v1/8c1751e0ce714736a63fee3c776164da", "region": "RegionOne", "internalURL": "http://192.168.0.2:8776/v1/8c1751e0ce714736a63fee3c776164da", "id": "05643f2cf9094265b432376571851841", "publicURL": "http://172.16.0.3:8776/v1/8c1751e0ce714736a63fee3c776164da"}], "endpoints_links": [], "type": "volume", "name": "cinder"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8773/services/Admin", "region": "RegionOne", "internalURL": "http://192.168.0.2:8773/services/Cloud", "id": "390dddc753cc4d378b489129d06c4b7d", "publicURL": "http://172.16.0.3:8773/services/Cloud"}], "endpoints_links": [], "type": "ec2", "name": "nova_ec2"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8004/v1/8c1751e0ce714736a63fee3c776164da", "region": "RegionOne", "internalURL": "http://192.168.0.2:8004/v1/8c1751e0ce714736a63fee3c776164da", "id": "9e60268a5aaf422d9e42f0caab0a19b4", "publicURL": "http://172.16.0.3:8004/v1/8c1751e0ce714736a63fee3c776164da"}], "endpoints_links": [], "type": "orchestration", "name": "heat"}, {"endpoints": [{"adminURL": "http://192.168.0.2:8080/v1/AUTH_8c1751e0ce714736a63fee3c776164da", "region": "RegionOne", "internalURL": "http://192.168.0.2:8080/v1/AUTH_8c1751e0ce714736a63fee3c776164da", "id": "12e78e06595f48339baebdb5d4309c70", "publicURL": "http://172.16.0.3:8080/v1/AUTH_8c1751e0ce714736a63fee3c776164da"}], "endpoints_links": [], "type": "object-store", "name": "swift"}, {"endpoints": [{"adminURL": "http://192.168.0.2:35357/v2.0", "region": "RegionOne", "internalURL": "http://192.168.0.2:5000/v2.0", "id": "404cceb349614eb39857742970408301", "publicURL": "http://172.16.0.3:5000/v2.0"}], "endpoints_links": [], "type": "identity", "name": "keystone"}], "user": {"username": "admin", "roles_links": [], "name": "admin", "roles": [{"id": "888bdf92213a477ba9f10554bc382e57", "name": "admin"}], "enabled": true, "email": "admin@localhost", "id": "13baa553aae44adca6615e711fd2f6d9"}, "metadata": {"is_admin": 0, "roles": []}}}'
+ERROR_AUTH_CONTENT = b'{"access": {}}'
+ERROR_TOKEN_CONTENT = b'{"error":{"code":"code","title":"title","message":"message",", URL":"URL"},"access": {}}'
+
+VALID_TOKENS = {
+ PROJECT: {
+ # make sure the expired time of the token is later than now
+ "expires": (datetime.now() + timedelta(1)).strftime("%Y-%m-%dT%H:%M:%SZ")
+ }
+}
+
+EMPTY_TOKENS = {}
+
+REGION_NAME = "RegionOne"
+ERROR_REGION_NAME = "ERROR"
+SERVICE_NAME = "nova"
+ERROR_SERVICE_NAME = "ERROR"
+
+REGION_URL = "http://10.56.20.239:8774/v2/329e0576da594c62a911d0dccb1238a7"
diff --git a/app/test/fetch/api_fetch/test_data/api_fetch_availability_zones.py b/app/test/fetch/api_fetch/test_data/api_fetch_availability_zones.py
new file mode 100644
index 0000000..f6e717c
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_fetch_availability_zones.py
@@ -0,0 +1,71 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+AVAILABILITY_ZONE_RESPONSE = {
+ "availabilityZoneInfo": [
+ {
+ "hosts": {
+ "node-6.cisco.com": {
+ }
+ },
+ "zoneName": "internal",
+ "zoneState": {
+ "available": True
+ }
+ },
+ {
+ "hosts": {
+ "node-5.cisco.com": {
+ }
+ },
+ "zoneName": "osdna-zone",
+ "zoneState": {
+ "available": True
+ }
+ }
+ ]
+}
+GET_REGION_RESULT = [
+ {
+ "available": True,
+ "hosts": {
+ "node-6.cisco.com": {
+ }
+ },
+ "id": "internal",
+ "master_parent_id": "RegionOne",
+ "master_parent_type": "region",
+ "name": "internal",
+ "parent_id": "RegionOne-availability_zones",
+ "parent_text": "Availability Zones",
+ "parent_type": "availability_zones_folder"
+ },
+ {
+ "available": True,
+ "hosts": {
+ "node-5.cisco.com": {
+ }
+ },
+ "id": "osdna-zone",
+ "master_parent_id": "RegionOne",
+ "master_parent_type": "region",
+ "name": "osdna-zone",
+ "parent_id": "RegionOne-availability_zones",
+ "parent_text": "Availability Zones",
+ "parent_type": "availability_zones_folder"
+ }
+]
+RESPONSE_WITHOUT_AVAILABILITY_ZONE = {"text": "test"}
+WRONG_RESPONSE = {"status": 400}
+EMPTY_AVAILABILITY_ZONE_RESPONSE = {
+ "availabilityZoneInfo": []
+}
+ENDPOINT = "http://10.56.20.239:8774"
+PROJECT = "admin"
+REGION_NAME = "RegionOne"
diff --git a/app/test/fetch/api_fetch/test_data/api_fetch_host_instances.py b/app/test/fetch/api_fetch/test_data/api_fetch_host_instances.py
new file mode 100644
index 0000000..d6f8ea6
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_fetch_host_instances.py
@@ -0,0 +1,85 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+PROJECT_LIST = [
+ {
+ 'name': 'OSDNA-project',
+ },
+ {
+ 'name': 'admin',
+ }
+]
+
+HOST = {
+ 'host_type': ['Compute'],
+}
+
+NON_COMPUTE_HOST = {
+ 'host_type': [],
+}
+
+HOST_NAME = "node-5.cisco.com"
+
+GET_INSTANCES_FROM_API = [
+ {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ "local_name": "instance-00000002",
+ "uuid": "6f29c867-9150-4533-8e19-70d749b172fa"
+ },
+ {
+ "host": "node-5.cisco.com",
+ "id": "79e20dbf-a46d-46ee-870b-e0c9f7b357d9",
+ "local_name": "instance-0000001c",
+ "uuid": "79e20dbf-a46d-46ee-870b-e0c9f7b357d9"
+ },
+ {
+ "host": "node-5.cisco.com",
+ "id": "bf0cb914-b316-486c-a4ce-f22deb453c52",
+ "local_name": "instance-00000026",
+ "uuid": "bf0cb914-b316-486c-a4ce-f22deb453c52"
+ }
+]
+
+GET_SERVERS_RESPONSE = {
+ "hypervisors": [
+ {
+ "hypervisor_hostname": "node-5.cisco.com",
+ "id": 1,
+ "servers": [
+ {
+ "name": "instance-00000002",
+ "uuid": "6f29c867-9150-4533-8e19-70d749b172fa"
+ },
+ {
+ "name": "instance-0000001c",
+ "uuid": "79e20dbf-a46d-46ee-870b-e0c9f7b357d9"
+ },
+ {
+ "name": "instance-00000026",
+ "uuid": "bf0cb914-b316-486c-a4ce-f22deb453c52"
+ }
+ ]
+ }
+ ]
+}
+
+RESPONSE_WITHOUT_HYPERVISORS = {
+ "text": "test"
+}
+
+RESPONSE_WITHOUT_SERVERS = {
+ "hypervisors": [
+ {
+
+ }
+ ]
+}
+
+INSTANCE_FOLDER_ID = "node-5.cisco.com-instances"
diff --git a/app/test/fetch/api_fetch/test_data/api_fetch_host_project_hosts.py b/app/test/fetch/api_fetch/test_data/api_fetch_host_project_hosts.py
new file mode 100644
index 0000000..3ef1ac7
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_fetch_host_project_hosts.py
@@ -0,0 +1,225 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+HOST_DOC = {
+ "host": "node-6.cisco.com",
+ "host_type": [],
+ "id": "node-6.cisco.com",
+ "name": "node-6.cisco.com",
+ "parent_id": "internal",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ },
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ }
+ },
+ "zone": "internal"
+}
+
+NONEXISTENT_TYPE = "nova"
+COMPUTE_TYPE = "Compute"
+ZONE = "internal"
+HOST_ZONE = "Test"
+
+REGION_NAME = "RegionOne"
+TEST_PROJECT_NAME = "Test"
+PROJECT_NAME = "admin"
+
+AVAILABILITY_ZONE_RESPONSE = {
+ "availabilityZoneInfo": [
+ {
+ "hosts": {
+ "node-6.cisco.com": {
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ },
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ }
+ }
+ },
+ "zoneName": "internal",
+ "zoneState": {
+ "available": True
+ }
+ },
+ {
+ "hosts": {
+ "node-5.cisco.com": {
+ "nova-compute": {
+ "active": True,
+ "available": True,
+ }
+ }
+ },
+ "zoneName": "osdna-zone",
+ "zoneState": {
+ "available": True
+ }
+ }
+ ]
+}
+
+AVAILABILITY_ERROR_RESPONSE = {'status': 400}
+
+HYPERVISORS_RESPONSE = {
+ "hypervisors": []
+}
+
+HYPERVISORS_ERROR_RESPONSE = {'status': 400}
+
+HOST_TO_BE_FETCHED_IP = {
+ "host": "node-5.cisco.com",
+ "id": "node-5.cisco.com"
+}
+
+IP_ADDRESS_RESPONSE = [
+ {
+ "ip_address": "192.168.0.4"
+ }
+]
+
+HOSTS_TO_BE_FETCHED_NETWORK_DETAILS = [
+ {
+ "host": "node-6.cisco.com",
+ "host_type": [
+ "Controller"
+ ],
+ "id": "node-6.cisco.com",
+ "name": "node-6.cisco.com",
+ },
+ {
+ "host": "node-5.cisco.com",
+ "host_type": [
+ "Compute"
+ ],
+ "id": "node-5.cisco.com",
+ "name": "node-5.cisco.com",
+ }
+]
+
+NETWORKS_DETAILS_RESPONSE = [
+ {
+ "configurations": "{}",
+ "host": "node-6.cisco.com"
+ },
+ {
+ "configurations": "{}",
+ "host": "node-6.cisco.com",
+ },
+ {
+ "configurations": "{}",
+ "host": "node-6.cisco.com",
+ }
+]
+
+REGION_URL = "http://192.168.0.2:8776/v2/329e0576da594c62a911d0dccb1238a7"
+AVAILABILITY_ZONE = {
+ "hosts": {
+ "node-6.cisco.com": {
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ },
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ }
+ }
+ },
+ "zoneName": "internal"
+}
+
+HOST_NAME = "node-6.cisco.com"
+
+GET_FOR_REGION_INFO = [
+ {
+ "config": {
+ },
+ "host": "node-6.cisco.com",
+ "host_type": [
+ "Controller",
+ "Network"
+ ],
+ "id": "node-6.cisco.com",
+ "name": "node-6.cisco.com",
+ "parent_id": "internal",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ },
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ }
+ },
+ "zone": "internal"
+ },
+ {
+ "host": "node-5.cisco.com",
+ "host_type": [
+ "Compute"
+ ],
+ "id": "node-5.cisco.com",
+ "ip_address": "192.168.0.4",
+ "name": "node-5.cisco.com",
+ "os_id": "1",
+ "parent_id": "osdna-zone",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-compute": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:22:42.000000"
+ }
+ },
+ "zone": "osdna-zone"
+ }
+]
diff --git a/app/test/fetch/api_fetch/test_data/api_fetch_networks.py b/app/test/fetch/api_fetch/test_data/api_fetch_networks.py
new file mode 100644
index 0000000..5079a92
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_fetch_networks.py
@@ -0,0 +1,72 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+NETWORKS_RESPONSE = {
+ "networks": [
+ {
+ "id": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "subnets": [
+ "cae3c81d-9a27-48c4-b8f6-32867ca03134"
+ ],
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40"
+ }
+ ]
+}
+
+NETWORKS_RESULT = [
+ {
+ "id": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "subnets": {
+ "test23": {
+ "cidr": "172.16.12.0/24",
+ "id": "cae3c81d-9a27-48c4-b8f6-32867ca03134",
+ "name": "test23",
+ "network_id": "0abe6331-0d74-4bbd-ad89-a5719c3793e4",
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40"
+ }
+ },
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "master_parent_type": "project",
+ "master_parent_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "parent_type": "networks_folder",
+ "parent_id": "75c0eb79ff4a42b0ae4973c8375ddf40-networks",
+ "parent_text": "Networks",
+ "project": "Calipso-project",
+ "cidrs": ["172.16.12.0/24"],
+ "subnet_ids": ["cae3c81d-9a27-48c4-b8f6-32867ca03134"],
+ "network": "8673c48a-f137-4497-b25d-08b7b218fd17"
+ }
+]
+
+WRONG_NETWORK_RESPONSE = {
+}
+
+SUBNETS_RESPONSE = {
+ "subnets": [
+ {
+ "cidr": "172.16.12.0/24",
+ "id": "cae3c81d-9a27-48c4-b8f6-32867ca03134",
+ "name": "test23",
+ "network_id": "0abe6331-0d74-4bbd-ad89-a5719c3793e4",
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40"
+ }
+ ]
+}
+
+ENDPOINT = "http://10.56.20.239:9696"
+WRONG_SUBNETS_RESPONSE = {}
+
+PROJECT = {
+ "description": "",
+ "enabled": True,
+ "id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "name": "Calipso-project"
+ }
+
+REGION_NAME = "RegionOne"
diff --git a/app/test/fetch/api_fetch/test_data/api_fetch_ports.py b/app/test/fetch/api_fetch/test_data/api_fetch_ports.py
new file mode 100644
index 0000000..fc0552c
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_fetch_ports.py
@@ -0,0 +1,72 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+PORTS_RESPONSE = {
+ "ports": [
+ {
+ "id": "16620a58-c48c-4195-b9c1-779a8ba2e6f8",
+ "mac_address": "fa:16:3e:d7:c5:16",
+ "name": "",
+ "network_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40"
+ }
+ ]
+}
+
+PORTS_RESULT_WITH_NET = [
+ {
+ "id": "16620a58-c48c-4195-b9c1-779a8ba2e6f8",
+ "mac_address": "fa:16:3e:d7:c5:16",
+ "name": "fa:16:3e:d7:c5:16",
+ "network_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "master_parent_type": "network",
+ "master_parent_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "parent_type": "ports_folder",
+ "parent_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe-ports",
+ "parent_text": "Ports",
+ }
+]
+
+PORTS_RESULT_WITHOUT_NET = [
+ {
+ "id": "16620a58-c48c-4195-b9c1-779a8ba2e6f8",
+ "mac_address": "fa:16:3e:d7:c5:16",
+ "name": "16620a58-c48c-4195-b9c1-779a8ba2e6f8",
+ "network_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "master_parent_type": "network",
+ "master_parent_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "parent_type": "ports_folder",
+ "parent_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe-ports",
+ "parent_text": "Ports",
+ }
+]
+
+PORTS_RESULT_WITH_PROJECT = [
+ {
+ "id": "16620a58-c48c-4195-b9c1-779a8ba2e6f8",
+ "mac_address": "fa:16:3e:d7:c5:16",
+ "name": "fa:16:3e:d7:c5:16",
+ "network_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "master_parent_type": "network",
+ "master_parent_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "parent_type": "ports_folder",
+ "parent_id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe-ports",
+ "parent_text": "Ports",
+ "project": "Calipso-project"
+ }
+]
+
+ERROR_PORTS_RESPONSE = {}
+NETWORK = {"id": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe"}
+TENANT = {"id": "75c0eb79ff4a42b0ae4973c8375ddf40", "name": "Calipso-project"}
+ENDPOINT = "http://10.56.20.239:9696"
+REGION_NAME = "RegionOne"
diff --git a/app/test/fetch/api_fetch/test_data/api_fetch_projects.py b/app/test/fetch/api_fetch/test_data/api_fetch_projects.py
new file mode 100644
index 0000000..4b2c678
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_fetch_projects.py
@@ -0,0 +1,88 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+PROJECTS_CORRECT_RESPONSE = {
+ "projects": [
+ {
+ "name": "Calipso-project"
+ },
+ {
+ "name": "admin",
+ }
+ ]
+}
+
+PROJECT_RESULT = [
+ "Calipso-project",
+ "admin"
+]
+
+PROJECTS_RESPONSE_WITHOUT_PROJECTS = ""
+
+REGION_PROJECTS = [
+ {
+ "description": "",
+ "enabled": True,
+ "id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "name": "OSDNA-project"
+ },
+ {
+ "description": "admin tenant",
+ "enabled": True,
+ "id": "8c1751e0ce714736a63fee3c776164da",
+ "name": "admin"
+ }
+]
+
+USERS_PROJECTS = [
+ "OSDNA-project",
+ "admin"
+]
+
+REGION_URL_NOVER = "http://10.56.20.239:35357"
+
+REGION_RESPONSE = {
+ "tenants": [
+ {
+ "name": "Calipso-project"
+ },
+ {
+ "name": "admin"
+ },
+ {
+ "name": "services"
+ }
+ ]
+}
+
+REGION_RESULT = [
+ {
+ "name": "Calipso-project"
+ },
+ {
+ "name": "admin"
+ }
+]
+
+REGION_RESULT_WITH_NON_USER_PROJECT = [
+ {
+ "name": "Calipso-project"
+ },
+ {
+ "name": "admin"
+ },
+ {
+ "name": "non-user project"
+ }
+]
+
+REGION_ERROR_RESPONSE = []
+
+REGION_NAME = "RegionOne"
+PROJECT_ID = "admin"
diff --git a/app/test/fetch/api_fetch/test_data/api_fetch_regions.py b/app/test/fetch/api_fetch/test_data/api_fetch_regions.py
new file mode 100644
index 0000000..bd7be78
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/api_fetch_regions.py
@@ -0,0 +1,50 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+REGION = "RegionOne"
+ENV = "Mirantis-Liberty"
+
+AUTH_RESPONSE = {
+ "access": {
+ "serviceCatalog": [
+ {
+ "endpoints": [
+ {
+ "adminURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "id": "274cbbd9fd6d4311b78e78dd3a1df51f",
+ "internalURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "publicURL": "http://172.16.0.3:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "region": "RegionOne"
+ }
+ ],
+ "endpoints_links": [],
+ "name": "nova",
+ "type": "compute"
+ }
+ ]
+ }
+}
+
+REGIONS_RESULT = [
+ {
+ "id": "RegionOne",
+ "endpoints": {
+ "nova": {
+ "adminURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "id": "274cbbd9fd6d4311b78e78dd3a1df51f",
+ "internalURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "publicURL": "http://172.16.0.3:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "service_type": "compute"
+ }
+ },
+ "name": "RegionOne",
+ "parent_type": "regions_folder",
+ "parent_id": ENV + "-regions",
+ }
+]
diff --git a/app/test/fetch/api_fetch/test_data/configurations.py b/app/test/fetch/api_fetch/test_data/configurations.py
new file mode 100644
index 0000000..ba15346
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/configurations.py
@@ -0,0 +1,52 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+CONFIGURATIONS = {
+ "configuration": [
+ {
+ "mock": "True",
+ "host": "10.56.20.239",
+ "name": "mysql",
+ "password": "102QreDdiD5sKcvNf9qbHrmr",
+ "port": 3307.0,
+ "user": "root",
+ "schema": "nova"
+ },
+ {
+ "name": "OpenStack",
+ "host": "10.56.20.239",
+ "admin_token": "38MUh19YWcgQQUlk2VEFQ7Ec",
+ "port": "5000",
+ "user": "admin",
+ "pwd": "admin"
+ },
+ {
+ "host": "10.56.20.239",
+ "key": "/Users/xiaocdon/.ssh/id_rsa",
+ "name": "CLI",
+ "pwd": "",
+ "user": "root"
+ },
+ {
+ "name": "AMQP",
+ "host": "10.56.20.239",
+ "port": "5673",
+ "user": "nova",
+ "password": "NF2nSv3SisooxPkCTr8fbfOa"
+ }
+ ],
+ "distribution": "Mirantis-8.0",
+ "last_scanned:": "5/8/16",
+ "name": "Mirantis-Liberty-Xiaocong",
+ "network_plugins": [
+ "OVS"
+ ],
+ "operational": "yes",
+ "type": "environment"
+} \ No newline at end of file
diff --git a/app/test/fetch/api_fetch/test_data/regions.py b/app/test/fetch/api_fetch/test_data/regions.py
new file mode 100644
index 0000000..9945386
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/regions.py
@@ -0,0 +1,110 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+REGIONS = {
+ "RegionOne": {
+ "endpoints": {
+ "ceilometer": {
+ "adminURL": "http://192.168.0.2:8777",
+ "id": "617177a3dcb64560a5a79ab0a91a7225",
+ "internalURL": "http://192.168.0.2:8777",
+ "publicURL": "http://172.16.0.3:8777",
+ "service_type": "metering"
+ },
+ "cinder": {
+ "adminURL": "http://192.168.0.2:8776/v1/8c1751e0ce714736a63fee3c776164da",
+ "id": "05643f2cf9094265b432376571851841",
+ "internalURL": "http://192.168.0.2:8776/v1/8c1751e0ce714736a63fee3c776164da",
+ "publicURL": "http://172.16.0.3:8776/v1/8c1751e0ce714736a63fee3c776164da",
+ "service_type": "volume"
+ },
+ "cinderv2": {
+ "adminURL": "http://192.168.0.2:8776/v2/8c1751e0ce714736a63fee3c776164da",
+ "id": "2c30937688e944889db4a64fab6816e6",
+ "internalURL": "http://192.168.0.2:8776/v2/8c1751e0ce714736a63fee3c776164da",
+ "publicURL": "http://172.16.0.3:8776/v2/8c1751e0ce714736a63fee3c776164da",
+ "service_type": "volumev2"
+ },
+ "glance": {
+ "adminURL": "http://192.168.0.2:9292",
+ "id": "475c6c77a94e4e63a5a0f0e767f697a8",
+ "internalURL": "http://192.168.0.2:9292",
+ "publicURL": "http://172.16.0.3:9292",
+ "service_type": "image"
+ },
+ "heat": {
+ "adminURL": "http://192.168.0.2:8004/v1/8c1751e0ce714736a63fee3c776164da",
+ "id": "9e60268a5aaf422d9e42f0caab0a19b4",
+ "internalURL": "http://192.168.0.2:8004/v1/8c1751e0ce714736a63fee3c776164da",
+ "publicURL": "http://172.16.0.3:8004/v1/8c1751e0ce714736a63fee3c776164da",
+ "service_type": "orchestration"
+ },
+ "heat-cfn": {
+ "adminURL": "http://192.168.0.2:8000/v1",
+ "id": "0f04ec6ed49f4940822161bf677bdfb2",
+ "internalURL": "http://192.168.0.2:8000/v1",
+ "publicURL": "http://172.16.0.3:8000/v1",
+ "service_type": "cloudformation"
+ },
+ "keystone": {
+ "adminURL": "http://192.168.0.2:35357/v2.0",
+ "id": "404cceb349614eb39857742970408301",
+ "internalURL": "http://192.168.0.2:5000/v2.0",
+ "publicURL": "http://172.16.0.3:5000/v2.0",
+ "service_type": "identity"
+ },
+ "neutron": {
+ "adminURL": "http://192.168.0.2:9696",
+ "id": "8dc28584da224c4b9671171ead3c982a",
+ "internalURL": "http://192.168.0.2:9696",
+ "publicURL": "http://172.16.0.3:9696",
+ "service_type": "network"
+ },
+ "nova": {
+ "adminURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "id": "274cbbd9fd6d4311b78e78dd3a1df51f",
+ "internalURL": "http://192.168.0.2:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "publicURL": "http://172.16.0.3:8774/v2/8c1751e0ce714736a63fee3c776164da",
+ "service_type": "compute"
+ },
+ "nova_ec2": {
+ "adminURL": "http://192.168.0.2:8773/services/Admin",
+ "id": "390dddc753cc4d378b489129d06c4b7d",
+ "internalURL": "http://192.168.0.2:8773/services/Cloud",
+ "publicURL": "http://172.16.0.3:8773/services/Cloud",
+ "service_type": "ec2"
+ },
+ "novav3": {
+ "adminURL": "http://192.168.0.2:8774/v3",
+ "id": "1df917160dfb4ce5b469764fde22b3ab",
+ "internalURL": "http://192.168.0.2:8774/v3",
+ "publicURL": "http://172.16.0.3:8774/v3",
+ "service_type": "computev3"
+ },
+ "swift": {
+ "adminURL": "http://192.168.0.2:8080/v1/AUTH_8c1751e0ce714736a63fee3c776164da",
+ "id": "12e78e06595f48339baebdb5d4309c70",
+ "internalURL": "http://192.168.0.2:8080/v1/AUTH_8c1751e0ce714736a63fee3c776164da",
+ "publicURL": "http://172.16.0.3:8080/v1/AUTH_8c1751e0ce714736a63fee3c776164da",
+ "service_type": "object-store"
+ },
+ "swift_s3": {
+ "adminURL": "http://192.168.0.2:8080",
+ "id": "4f655c8f2bef46a0a7ba4a20bba53666",
+ "internalURL": "http://192.168.0.2:8080",
+ "publicURL": "http://172.16.0.3:8080",
+ "service_type": "s3"
+ }
+ },
+ "id": "RegionOne",
+ "name": "RegionOne",
+ "parent_id": "Mirantis-Liberty-Xiaocong-regions",
+ "parent_type": "regions_folder"
+ }
+} \ No newline at end of file
diff --git a/app/test/fetch/api_fetch/test_data/token.py b/app/test/fetch/api_fetch/test_data/token.py
new file mode 100644
index 0000000..2abbdd8
--- /dev/null
+++ b/app/test/fetch/api_fetch/test_data/token.py
@@ -0,0 +1,23 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+TOKEN = {'tenant': {
+ 'description': 'admin tenant',
+ 'name': 'admin',
+ 'is_domain': False,
+ 'id': '8c1751e0ce714736a63fee3c776164da',
+ 'enabled': True,
+ 'parent_id': None
+ },
+ 'issued_at': '2016-10-19T23:06:29.000000Z',
+ 'expires': '2016-10-20T00:06:28.615780Z',
+ 'id': 'gAAAAABYB_x10x_6AlA2Y5RJZ6HCcCDSXe0f8vfisKnOM_XCDZvwl2qiwzCQIOYX9mCmRyGojZ2JEjIb0vHL0f0hxqSq84g5jbZpN0h0Un_RkTZXSKf0K1uigbr3q__ilhctLvwWNem6XQSGrav1fQrec_DjdvUxSwuoBSSo82kKQ7SvPSdVwrA',
+ 'token_expiry_time': 1476921988,
+ 'audit_ids': ['2Ps0lRlHRIG80FWamMkwWg']
+} \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/__init__.py b/app/test/fetch/cli_fetch/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/cli_fetch/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/cli_fetch/test_cli_access.py b/app/test/fetch/cli_fetch/test_cli_access.py
new file mode 100644
index 0000000..f393538
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_access.py
@@ -0,0 +1,159 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+import time
+
+from discover.fetchers.cli.cli_access import CliAccess
+from test.fetch.cli_fetch.test_data.cli_access import *
+from test.fetch.test_fetch import TestFetch
+from unittest.mock import MagicMock, patch
+from utils.ssh_conn import SshConn
+
+
+class TestCliAccess(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.cli_access = CliAccess()
+
+ @patch("utils.ssh_conn.SshConn.exec")
+ def check_run_result(self, is_gateway_host,
+ enable_cache,
+ cached_command_result, exec_result,
+ expected_result, err_msg,
+ ssh_con_exec):
+ # mock cached commands
+ if not is_gateway_host:
+ self.cli_access.cached_commands = {
+ NON_GATEWAY_CACHED_COMMAND: cached_command_result
+ }
+ else:
+ self.cli_access.cached_commands = {
+ GATEWAY_CACHED_COMMAND: cached_command_result
+ }
+ original_is_gateway_host = SshConn.is_gateway_host
+ SshConn.is_gateway_host = MagicMock(return_value=is_gateway_host)
+ ssh_con_exec.return_value = exec_result
+ result = self.cli_access.run(COMMAND, COMPUTE_HOST_ID,
+ on_gateway=False, enable_cache=enable_cache)
+ self.assertEqual(result, expected_result, err_msg)
+
+ # reset the cached commands after testing
+ self.cli_access.cached_commands = {}
+ # reset method
+ SshConn.is_gateway_host = original_is_gateway_host
+
+ def test_run(self):
+ curr_time = time.time()
+ test_cases = [
+ {
+ "is_gateway_host": True,
+ "enable_cache": False,
+ "cached_command_result": None,
+ "exec_result": RUN_RESULT,
+ "expected_result": RUN_RESULT,
+ "err_msg": "Can't get the " +
+ "result of the command"
+ },
+ {
+ "is_gateway_host": True,
+ "enable_cache": True,
+ "cached_command_result": {
+ "timestamp": curr_time,
+ "result": CACHED_COMMAND_RESULT
+ },
+ "exec_result": None,
+ "expected_result": CACHED_COMMAND_RESULT,
+ "err_msg": "Can't get the cached " +
+ "result of the command " +
+ "when the host is a gateway host"
+ },
+ {
+ "is_gateway_host": False,
+ "enable_cache": True,
+ "cached_command_result": {
+ "timestamp": curr_time,
+ "result": CACHED_COMMAND_RESULT
+ },
+ "exec_result": None,
+ "expected_result": CACHED_COMMAND_RESULT,
+ "err_msg": "Can't get the cached " +
+ "result of the command " +
+ "when the host is not a gateway host"
+ },
+ {
+ "is_gateway_host": True,
+ "enable_cache": True,
+ "cached_command_result": {
+ "timestamp": curr_time - self.cli_access.cache_lifetime,
+ "result": CACHED_COMMAND_RESULT
+ },
+ "exec_result": RUN_RESULT,
+ "expected_result": RUN_RESULT,
+ "err_msg": "Can't get the result " +
+ "of the command when the cached result expired " +
+ "and the host is a gateway host"
+ },
+ {
+ "is_gateway_host": False,
+ "enable_cache": True,
+ "cached_command_result": {
+ "timestamp": curr_time - self.cli_access.cache_lifetime,
+ "result": CACHED_COMMAND_RESULT
+ },
+ "exec_result": RUN_RESULT,
+ "expected_result": RUN_RESULT,
+ "err_msg": "Can't get the result " +
+ "of the command when the cached result expired " +
+ "and the host is a not gateway host"
+ }
+ ]
+
+ for test_case in test_cases:
+ self.check_run_result(test_case["is_gateway_host"],
+ test_case["enable_cache"],
+ test_case["cached_command_result"],
+ test_case["exec_result"],
+ test_case["expected_result"],
+ test_case["err_msg"])
+
+ def test_run_fetch_lines(self):
+ original_run = self.cli_access.run
+ self.cli_access.run = MagicMock(return_value=RUN_RESULT)
+
+ result = self.cli_access.run_fetch_lines(COMMAND, COMPUTE_HOST_ID)
+
+ self.assertEqual(result, FETCH_LINES_RESULT,
+ "Can't get correct result of the command line")
+ self.cli_access.run = original_run
+
+ def test_run_fetch_lines_with_empty_command_result(self):
+ original_run = self.cli_access.run
+ self.cli_access.run = MagicMock(return_value="")
+
+ result = self.cli_access.run_fetch_lines(COMMAND, COMPUTE_HOST_ID)
+ self.assertEqual(result, [], "Can't get [] when the command " +
+ "result is empty")
+ self.cli_access.run = original_run
+
+ def test_merge_ws_spillover_lines(self):
+ fixed_lines = self.cli_access.merge_ws_spillover_lines(LINES_FOR_FIX)
+ self.assertEqual(fixed_lines, FIXED_LINES, "Can't merge the " +
+ "ws-separated spillover lines")
+
+ def test_parse_line_with_ws(self):
+ parse_line = self.cli_access.parse_line_with_ws(LINE_FOR_PARSE, HEADERS)
+ self.assertEqual(parse_line, PARSED_LINE, "Can't parse the line with ws")
+
+ def test_parse_cmd_result_with_whitespace(self):
+ result = self.cli_access.parse_cmd_result_with_whitespace(FIXED_LINES,
+ HEADERS,
+ remove_first=False)
+ self.assertEqual(result, PARSED_CMD_RESULT,
+ "Can't parse the cmd result with whitespace")
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_host_pnics.py b/app/test/fetch/cli_fetch/test_cli_fetch_host_pnics.py
new file mode 100644
index 0000000..f5f327e
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_host_pnics.py
@@ -0,0 +1,135 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_host_pnics import CliFetchHostPnics
+from test.fetch.cli_fetch.test_data.cli_fetch_host_pnics import *
+from test.fetch.test_fetch import TestFetch
+from unittest.mock import MagicMock
+from unittest.mock import call
+
+
+class TestCliFetchHostPnics(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchHostPnics()
+ self.fetcher.set_env(self.env)
+
+ def check_get_result(self, host,
+ interface_lines, interface_names,
+ interface_details, expected_result,
+ err_msg):
+ original_get_by_id = self.fetcher.inv.get_by_id
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_find_interface_details = self.fetcher.find_interface_details
+
+ self.fetcher.inv.get_by_id = MagicMock(return_value=host)
+ self.fetcher.run_fetch_lines = MagicMock(return_value=interface_lines)
+ self.fetcher.find_interface_details = MagicMock(side_effect=
+ interface_details)
+ result = self.fetcher.get(PNICS_FOLDER_ID)
+ self.assertEqual(result, expected_result, err_msg)
+
+ if interface_names:
+ interface_calls = [call(HOST_ID, interface_name) for
+ interface_name in interface_names]
+ self.fetcher.find_interface_details.assert_has_calls(interface_calls,
+ any_order=True)
+ # reset the methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.find_interface_details = original_find_interface_details
+
+ def test_get(self):
+ test_cases = [
+ {
+ "host": NETWORK_NODE,
+ "interface_lines": INTERFACE_LINES,
+ "interface_names": INTERFACE_NAMES,
+ "interface_details": [INTERFACE, None],
+ "expected_results": INTERFACES_GET_RESULTS,
+ "err_msg": "Can't get interfaces"
+ },
+ {
+ "host": [],
+ "interface_lines": None,
+ "interface_names": None,
+ "interface_details": None,
+ "expected_results": [],
+ "err_msg": "Can't get [] when the host " +
+ "doesn't exist in the database"
+ },
+ {
+ "host": WRONG_NODE,
+ "interface_lines": None,
+ "interface_names": None,
+ "interface_details": None,
+ "expected_results": [],
+ "err_msg": "Can't get [] when the host doesn't " +
+ "have required host type"
+ },
+ {
+ "host": NETWORK_NODE,
+ "interface_lines": [],
+ "interface_names": None,
+ "interface_details":None,
+ "expected_results": [],
+ "err_msg": "Can't get [] when " +
+ "the interface lines is []"
+ }
+ ]
+ for test_case in test_cases:
+ self.check_get_result(test_case["host"],
+ test_case["interface_lines"],
+ test_case["interface_names"],
+ test_case["interface_details"],
+ test_case["expected_results"],
+ test_case["err_msg"])
+
+ def test_find_interface_details(self):
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_handle_line = self.fetcher.handle_line
+ original_set_interface_data = self.fetcher.set_interface_data
+
+ self.fetcher.run_fetch_lines = MagicMock(return_value=IFCONFIG_CM_RESULT)
+ self.fetcher.handle_line = MagicMock()
+ self.fetcher.set_interface_data = MagicMock()
+
+ result = self.fetcher.find_interface_details(HOST_ID, INTERFACE_NAME)
+
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.handle_line = original_handle_line
+ self.fetcher.set_interface_data = original_set_interface_data
+
+ self.assertEqual(result, INTERFACE_DETAILS, "Can't get interface details")
+
+ def test_handle_mac_address_line(self):
+ self.fetcher.handle_line(RAW_INTERFACE, MAC_ADDRESS_LINE)
+ self.assertEqual(RAW_INTERFACE["mac_address"], MAC_ADDRESS,
+ "Can't get the correct mac address")
+
+ # Test failed, defect, result: addr: expected result: fe80::f816:3eff:fea1:eb73/64
+ def test_handle_ipv6_address_line(self):
+ self.fetcher.handle_line(RAW_INTERFACE, IPV6_ADDRESS_LINE)
+ self.assertEqual(RAW_INTERFACE['IPv6 Address'], IPV6_ADDRESS,
+ "Can' get the correct ipv6 address")
+
+ def test_handle_ipv4_address_line(self):
+ self.fetcher.handle_line(RAW_INTERFACE, IPV4_ADDRESS_LINE)
+ self.assertEqual(RAW_INTERFACE['IP Address'], IPV4_ADDRESS,
+ "Can't get the correct ipv4 address")
+
+ def test_set_interface_data(self):
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ self.fetcher.run_fetch_lines = MagicMock(return_value=ETHTOOL_RESULT)
+ self.fetcher.set_interface_data(INTERFACE_FOR_SET)
+ self.assertEqual(INTERFACE_FOR_SET, INTERFACE_AFTER_SET, "Can't get the attributes of the "
+ "interface from the CMD result")
+
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_host_pnics_vpp.py b/app/test/fetch/cli_fetch/test_cli_fetch_host_pnics_vpp.py
new file mode 100644
index 0000000..805e36d
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_host_pnics_vpp.py
@@ -0,0 +1,34 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_host_pnics_vpp import CliFetchHostPnicsVpp
+from test.fetch.test_fetch import TestFetch
+from unittest.mock import MagicMock
+from test.fetch.cli_fetch.test_data.cli_fetch_host_pnics_vpp import *
+
+
+class TestCliFetchHostPnicsVpp(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchHostPnicsVpp()
+ self.fetcher.set_env(self.env)
+
+ def test_get(self):
+ # store original method
+ original_find_items = self.fetcher.inv.find_items
+
+ # mock the method
+ self.fetcher.inv.find_items = MagicMock(return_value=VEDGES)
+
+ result = self.fetcher.get(ID)
+ # reset the method
+ self.fetcher.inv.find_items = original_find_items
+
+ self.assertNotEqual(result, [], "Can't get the pnics info") \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_host_vservices.py b/app/test/fetch/cli_fetch/test_cli_fetch_host_vservices.py
new file mode 100644
index 0000000..c33faca
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_host_vservices.py
@@ -0,0 +1,132 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_host_vservices import CliFetchHostVservices
+from test.fetch.test_fetch import TestFetch
+from test.fetch.cli_fetch.test_data.cli_fetch_host_verservices import *
+from unittest.mock import MagicMock
+
+
+class TestCliFetchHostVservices(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchHostVservices()
+ self.fetcher.set_env(self.env)
+
+ def test_get(self):
+ # store original get_single method
+ original_get_single = self.fetcher.inv.get_single
+ # mock the host data
+ self.fetcher.inv.get_single = MagicMock(return_value=NETWORK_HOST)
+ # store original run_fetch_lines method
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ # mock command line results
+ self.fetcher.run_fetch_lines = MagicMock(return_value=NAMESPACES)
+
+ # only test the logic on get method, mock the set_details method
+ original_set_details = self.fetcher.set_details
+ self.fetcher.set_details = MagicMock()
+
+ result = self.fetcher.get(NETWORK_HOST['id'])
+ # reset methods
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.set_details = original_set_details
+ self.fetcher.inv.get_single = original_get_single
+
+ self.assertNotEqual(result, [], "Can't get verservices")
+
+ def test_get_with_wrong_host_type(self):
+ # store original get_single method
+ original_get_single = self.fetcher.inv.get_single
+ # mock the host data
+ self.fetcher.inv.get_single = MagicMock(return_value=COMPUTE_HOST)
+ result = self.fetcher.get(COMPUTE_HOST['id'])
+
+ self.fetcher.inv.get_single = original_get_single
+
+ self.assertEqual(result, [], "Can't get empty array when the host_type doesn't contain Network")
+
+ def test_set_details(self):
+ # store orginal methods
+ original_get_router_name = self.fetcher.get_router_name
+ original_get_network_name = self.fetcher.get_network_name
+ original_get_type = self.fetcher.agents_list.get_type
+
+ # mock methods
+ self.fetcher.get_network_name = MagicMock(return_value=ROUTER[0]['name'])
+ self.fetcher.get_router_name = MagicMock(return_value=ROUTER[0]['name'])
+ self.fetcher.agents_list.get_type = MagicMock(return_value=AGENT)
+
+ self.fetcher.set_details(NETWORK_HOST['id'], LOCAL_SERVICES_IDS[0])
+
+ # reset methods
+ self.fetcher.get_network_name = original_get_network_name
+ self.fetcher.get_router_name = original_get_router_name
+ self.fetcher.agents_list.get_type = original_get_type
+
+ self.assertIn("name", LOCAL_SERVICES_IDS[0], "Can't add name")
+ self.assertIn("parent_id", LOCAL_SERVICES_IDS[0], "Can't add parent id")
+
+ def test_get_network_name(self):
+ # store original method
+ original_get_objects_list_for_id = self.fetcher.get_objects_list_for_id
+ # mock the result
+ self.fetcher.get_objects_list_for_id = MagicMock(return_value=ROUTER)
+
+ name = self.fetcher.get_network_name(ID_CLEAN)
+
+ self.fetcher.get_objects_list_for_id = original_get_objects_list_for_id
+ self.assertEqual(name, ROUTER[0]['name'], "Can't get network name")
+
+ def test_get_network_without_router(self):
+ # store original method
+ original_get_objects_list_for_id = self.fetcher.get_objects_list_for_id
+ # mock the result
+ self.fetcher.get_objects_list_for_id = MagicMock(return_value=[])
+
+ name = self.fetcher.get_network_name(ID_CLEAN)
+
+ self.fetcher.get_objects_list_for_id = original_get_objects_list_for_id
+ self.assertEqual(name, ID_CLEAN, "Can't use the id as the name when network info from database is empty")
+
+ def test_get_router_name(self):
+ # store original method
+ original_get_objects_list_for_id = self.fetcher.get_objects_list_for_id
+ # mock the result
+ self.fetcher.get_objects_list_for_id = MagicMock(return_value=ROUTER)
+
+ name = self.fetcher.get_router_name(LOCAL_SERVICES_IDS[0], ID_CLEAN)
+
+ self.fetcher.get_objects_list_for_id = original_get_objects_list_for_id
+
+ self.assertIn("name", LOCAL_SERVICES_IDS[0], "Can't get network name")
+ self.assertEqual(name, ROUTER[0]['name'], "Can't get router name")
+
+ def test_set_agent_type(self):
+ # store original get_type method
+ original_get_type = self.fetcher.agents_list.get_type
+ self.fetcher.agents_list.get_type = MagicMock(return_value=AGENT)
+
+ self.fetcher.set_agent_type(VSERVICE)
+ # reset method
+ self.fetcher.set_agent_type = original_get_type
+ self.assertIn("parent_id", VSERVICE, "Can't add parent id to vservice document")
+
+ def test_set_agent_type_without_agent(self):
+ # store original get_type method
+ original_get_type = self.fetcher.agents_list.get_type
+ self.fetcher.agents_list.get_type = MagicMock(return_value={})
+
+ self.fetcher.set_agent_type(VSERVICE)
+ # reset method
+ self.fetcher.set_agent_type = original_get_type
+ self.assertIn("parent_id", VSERVICE, "Can't add parent id to vservice document")
+ self.assertEqual(VSERVICE['parent_type'], "vservice_miscellenaous_folder",
+ "Can't add document to miscellenaous folder when it doesn't have agent") \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics.py b/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics.py
new file mode 100644
index 0000000..5a57b9c
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics.py
@@ -0,0 +1,111 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_instance_vnics import CliFetchInstanceVnics
+from test.fetch.test_fetch import TestFetch
+from test.fetch.cli_fetch.test_data.cli_fetch_instance_vnics import *
+from unittest.mock import MagicMock
+
+
+class TestCliFetchInstanceVnics(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchInstanceVnics()
+ self.fetcher.set_env(self.env)
+
+ def test_get(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_get_vnics_from_dumpxml = self.fetcher.get_vnics_from_dumpxml
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(side_effect=[INSATNCE, COMPUTE_HOST])
+ self.fetcher.run_fetch_lines = MagicMock(return_value=INSTANCES_LIST)
+ self.fetcher.get_vnics_from_dumpxml = MagicMock(return_value=VNICS_FROM_DUMP_XML)
+
+ result = self.fetcher.get(VNICS_FOLDER['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.get_vnics_from_dumpxml = original_get_vnics_from_dumpxml
+
+ self.assertNotEqual(result, [], "Can't get vnics with VNICS folder id")
+
+ def test_get_without_instance(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(return_value=[])
+
+ result = self.fetcher.get(VNICS_FOLDER['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+
+ self.assertEqual(result, [], "Can't get empty array when the instance can't be found")
+
+ def test_get_without_host(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(side_effect=[[], NETWORK_HOST])
+
+ result = self.fetcher.get(VNICS_FOLDER['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+
+ self.assertEqual(result, [], "Can't get empty array when the host doesn't contain network host type")
+
+ def test_get_vnics_from_dumpxml(self):
+ # store original functions
+ original_run = self.fetcher.run
+ original_set_vnic_properties = self.fetcher.set_vnic_properties
+
+ # mock the functions
+ self.fetcher.run = MagicMock(return_value=DUMPXML)
+ self.fetcher.set_vnic_properties = MagicMock()
+
+ vnics = self.fetcher.get_vnics_from_dumpxml(ID, INSATNCE)
+ # reset functions
+ self.fetcher.run = original_run
+ self.fetcher.set_vnic_properties = original_set_vnic_properties
+
+ self.assertNotEqual(vnics, [], "Can't get vnics")
+
+ def test_get_vnics_from_dumpxml_with_empty_command_result(self):
+ # store original functions
+ original_run = self.fetcher.run
+
+ # mock the functions
+ self.fetcher.run = MagicMock(return_value=" ")
+
+ vnics = self.fetcher.get_vnics_from_dumpxml(ID, INSATNCE)
+ # reset functions
+ self.fetcher.run = original_run
+
+ self.assertEqual(vnics, [], "Can't get empty array when the dumpxml is empty")
+
+ def test_get_vnics_from_dumpxml_with_wrong_instance(self):
+ # store original functions
+ original_run = self.fetcher.run
+
+ # mock the functions
+ self.fetcher.run = MagicMock(return_value=WRONG_DUMPXML)
+
+ vnics = self.fetcher.get_vnics_from_dumpxml(ID, INSATNCE)
+ # reset functions
+ self.fetcher.run = original_run
+
+ self.assertEqual(vnics, [], "Can't get empty array when the instance is wrong") \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_ovs.py b/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_ovs.py
new file mode 100644
index 0000000..24a1b5d
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_ovs.py
@@ -0,0 +1,36 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.cli_fetch_instance_vnics_ovs import CliFetchInstanceVnicsOvs
+from test.fetch.test_fetch import TestFetch
+from test.fetch.cli_fetch.test_data.cli_fetch_instance_vnics import *
+from unittest.mock import MagicMock
+
+
+class TestCliFetchInstanceVnicsOvs(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchInstanceVnicsOvs()
+ self.fetcher.set_env(self.env)
+
+ def test_set_vnic_properties(self):
+ # store original method
+ original_set = self.fetcher.inv.set
+ self.fetcher.inv.set = MagicMock()
+
+ self.fetcher.set_vnic_properties(VNIC, INSATNCE)
+ # reset method
+ self.fetcher.inv.set = original_set
+
+ self.assertIn("source_bridge", VNIC, "Can't set source_bridge for ovs vnic")
+
+ def test_get_vnic_name(self):
+ name = self.fetcher.get_vnic_name(VNIC, INSATNCE)
+ self.assertNotEqual(name, None, "Can't get vnic name") \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_vpp.py b/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_vpp.py
new file mode 100644
index 0000000..46c25fb
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_instance_vnics_vpp.py
@@ -0,0 +1,23 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.cli_fetch_instance_vnics_vpp import CliFetchInstanceVnicsVpp
+from test.fetch.cli_fetch.test_data.cli_fetch_instance_vnics import *
+from test.fetch.test_fetch import TestFetch
+
+
+class TestCliFetchInstanceVnicsVpp(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchInstanceVnicsVpp()
+
+ def test_get_name(self):
+ name = self.fetcher.get_vnic_name(VNIC, INSATNCE)
+ self.assertNotEqual(name, None, "Can't get vnic name") \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors.py b/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors.py
new file mode 100644
index 0000000..23e0a99
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors.py
@@ -0,0 +1,66 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_vconnectors import CliFetchVconnectors
+from test.fetch.test_fetch import TestFetch
+from test.fetch.cli_fetch.test_data.cli_fetch_vconnectors import *
+from unittest.mock import MagicMock
+
+
+class TestCliFetchVconnectors(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchVconnectors()
+ self.fetcher.set_env(self.env)
+
+ def test_get(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+ original_get_vconnectors = self.fetcher.get_vconnectors
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(return_value=HOST)
+ self.fetcher.get_vconnectors = MagicMock(return_value=VCONNECTORS)
+
+ result = self.fetcher.get(VCONNECTORS_FOLDER['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+ self.fetcher.get_vconnectors = original_get_vconnectors
+
+ self.assertEqual(result, VCONNECTORS, "Can't get the vconnectors")
+
+ def test_get_without_host(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(return_value=[])
+
+ result = self.fetcher.get(VCONNECTORS_FOLDER['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+
+ self.assertEqual(result, [], "Can't get empty array when the host doesn't exist")
+
+ def test_get_with_wrong_host(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(return_value=WRONG_HOST)
+
+ result = self.fetcher.get(VCONNECTORS_FOLDER['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+
+ self.assertEqual(result, [], "Can't get empty array when the host doesn't contain host type") \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_ovs.py b/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_ovs.py
new file mode 100644
index 0000000..cc882a1
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_ovs.py
@@ -0,0 +1,38 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_vconnectors_ovs import CliFetchVconnectorsOvs
+from test.fetch.test_fetch import TestFetch
+from test.fetch.cli_fetch.test_data.cli_fetch_vconnectors_ovs import *
+from unittest.mock import MagicMock
+
+
+class TestCliFetchVconnectorsOvs(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchVconnectorsOvs()
+ self.fetcher.set_env(self.env)
+
+ def test_get_vconnectors(self):
+ # store the original methods
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_find_items = self.fetcher.inv.find_items
+
+ # mock the methods
+ self.fetcher.run_fetch_lines = MagicMock(return_value=BRIDGE_RESULT)
+ self.fetcher.inv.find_items = MagicMock(return_value=[])
+
+ result = self.fetcher.get_vconnectors(NETWORK_NODE)
+
+ # reset methods
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.inv.find_items = original_find_items
+
+ self.assertNotEqual(result, [], "Can't get vconnectors with the host id")
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_vpp.py b/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_vpp.py
new file mode 100644
index 0000000..f729c2c
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_vconnectors_vpp.py
@@ -0,0 +1,50 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_vconnectors_vpp import CliFetchVconnectorsVpp
+from test.fetch.test_fetch import TestFetch
+from unittest.mock import MagicMock
+from test.fetch.cli_fetch.test_data.cli_fetch_vconnectors_vpp import *
+
+
+class TestCliFetchVconnectorsVpp(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchVconnectorsVpp()
+ self.fetcher.set_env(self.env)
+
+ def test_get_vconnectors(self):
+ # store original method
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_get_interface_details = self.fetcher.get_interface_details
+
+ # mock methods
+ self.fetcher.run_fetch_lines = MagicMock(return_value=MODE_RESULT)
+ self.fetcher.get_interface_details = MagicMock(return_value=None)
+
+ result = self.fetcher.get_vconnectors(HOST)
+
+ # reset methods
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.get_interface_details = original_get_interface_details
+
+ self.assertNotEqual(result, {}, "Can't get vconnectors info")
+
+ def test_set_interface_details(self):
+ # store original methods
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+
+ # mock method
+ self.fetcher.run_fetch_lines = MagicMock(return_value=INTERFACE_LINES)
+
+ result = self.fetcher.get_interface_details(HOST, INTERFACE_NAME)
+ # restore method
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.assertNotEqual(result, None, "Can't get the interface details") \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_cli_fetch_vservice_vnics.py b/app/test/fetch/cli_fetch/test_cli_fetch_vservice_vnics.py
new file mode 100644
index 0000000..b77f41e
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_cli_fetch_vservice_vnics.py
@@ -0,0 +1,124 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.cli.cli_fetch_vservice_vnics import CliFetchVserviceVnics
+from test.fetch.test_fetch import TestFetch
+from test.fetch.cli_fetch.test_data.cli_fetch_vservice_vnics import *
+from unittest.mock import MagicMock
+
+
+class TestCliFetchVserviceVnics(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = CliFetchVserviceVnics()
+ self.fetcher.set_env(self.env)
+
+ def test_get(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_handle_service = self.fetcher.handle_service
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(return_value=NETWORK_NODE)
+ self.fetcher.run_fetch_lines = MagicMock(return_value=NAME_SPACES)
+ self.fetcher.handle_service = MagicMock(return_value=SERVICES)
+
+ result = self.fetcher.get(NETWORK_NODE['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.handle_service = original_handle_service
+
+ self.assertNotEqual(result, [], "Can't get vnics")
+
+ def test_get_with_error_host(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(return_value=ERROR_NODE)
+
+ result = self.fetcher.get(NETWORK_NODE['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+
+ self.assertEqual(result, [], "Can't get empty array when the host doesn't contain host_type")
+
+ def test_get_with_compute_host(self):
+ # store original methods
+ original_get_by_id = self.fetcher.inv.get_by_id
+
+ # mock methods
+ self.fetcher.inv.get_by_id = MagicMock(return_value=COMPUTE_NODE)
+
+ result = self.fetcher.get(NETWORK_NODE['id'])
+
+ # reset methods
+ self.fetcher.inv.get_by_id = original_get_by_id
+
+ self.assertEqual(result, [], "Can't get empty array when the host type doesn't contain network")
+
+ def test_handle_service(self):
+ # store original method
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_set_interface_data = self.fetcher.set_interface_data
+ # mock the method
+ self.fetcher.run_fetch_lines = MagicMock(return_value=IFCONFIG_RESULT)
+ self.fetcher.set_interface_data = MagicMock()
+ result = self.fetcher.handle_service(NETWORK_NODE['id'], SERVICE_ID)
+ # reset method
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.set_interface_data = original_set_interface_data
+
+ self.assertNotEqual(result, [], "Can't get interfaces data")
+
+ def test_set_interface_data(self):
+ # store original methods
+ original_get_by_field = self.fetcher.inv.get_by_field
+ original_get_by_id = self.fetcher.inv.get_by_id
+ original_set = self.fetcher.inv.set
+
+ # mock the methods
+ self.fetcher.inv.get_by_field = MagicMock(return_value=NETWORK)
+ self.fetcher.inv.get_by_id = MagicMock(return_value=VSERVICE)
+ self.fetcher.inv.set = MagicMock()
+
+ self.fetcher.set_interface_data(VNIC)
+
+ # reset methods
+ self.fetcher.inv.get_by_field = original_get_by_field
+ self.fetcher.inv.get_by_id = original_get_by_id
+ self.fetcher.inv.set = original_set
+
+ self.assertIn("data", VNIC, "Can't set data")
+ self.assertIn("cidr", VNIC, "Can't set cidr")
+ self.assertIn("network", VNIC, "Can't set network")
+
+ def test_handle_mac_address_line(self):
+ self.fetcher.handle_line(RAW_VNIC, MAC_ADDRESS_LINE)
+ self.assertEqual(RAW_VNIC['mac_address'], MAC_ADDRESS, "Can't get the correct mac address from the line")
+
+ def test_handle_ipv4_address_line(self):
+ self.fetcher.handle_line(RAW_VNIC, IPV4_ADDRESS_LINE)
+ self.assertEqual(RAW_VNIC['IP Address'], IPV4_ADDRESS, "Can't get the correct ipv4 address from the line")
+
+ def test_handle_ipv6_address_line(self):
+ self.fetcher.handle_line(RAW_VNIC, IPV6_ADDRESS_LINE)
+ self.assertEqual(RAW_VNIC['IPv6 Address'], IPV6_ADDRESS, "Can't get the correct ipv6 address from the line")
+
+ def test_get_net_size(self):
+ size = self.fetcher.get_net_size(NET_MASK_ARRAY)
+ self.assertEqual(size, SIZE, "Can't get the size of network by netmask")
+
+ def test_get_cidr_for_vnic(self):
+ cidr = self.fetcher.get_cidr_for_vnic(VNIC)
+ self.assertEqual(cidr, CIDR, "the cidr info is wrong")
diff --git a/app/test/fetch/cli_fetch/test_data/__init__.py b/app/test/fetch/cli_fetch/test_data/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/cli_fetch/test_data/cli_access.py b/app/test/fetch/cli_fetch/test_data/cli_access.py
new file mode 100644
index 0000000..b151dc6
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_access.py
@@ -0,0 +1,58 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+COMPUTE_HOST_ID = "node-5.cisco.com"
+COMMAND = "virsh list"
+NON_GATEWAY_CACHED_COMMAND = COMPUTE_HOST_ID + "," + "ssh -o StrictHostKeyChecking=no " + \
+ COMPUTE_HOST_ID + " sudo " + COMMAND
+GATEWAY_CACHED_COMMAND = COMPUTE_HOST_ID + "," + "sudo " + COMMAND
+CACHED_COMMAND_RESULT = " Id Name State\n---\n 2 instance-00000003 running"
+RUN_RESULT = " Id Name State\n---\n 2 instance-00000002 running"
+FETCH_LINES_RESULT = [
+ " Id Name State",
+ "---",
+ " 2 instance-00000002 running"
+]
+
+LINES_FOR_FIX = [
+ "br-ex\t\t8000.005056acc9a2\tno\t\teno33554952",
+ "\t\t\t\t\t\t\tp_ff798dba-0",
+ "\t\t\t\t\t\t\tv_public",
+ "\t\t\t\t\t\t\tv_vrouter_pub",
+ "br-fw-admin\t\t8000.005056ace897\tno\t\teno16777728"
+]
+
+FIXED_LINES = [
+ "br-ex\t\t8000.005056acc9a2\tno\t\teno33554952,p_ff798dba-0,v_public,v_vrouter_pub",
+ "br-fw-admin\t\t8000.005056ace897\tno\t\teno16777728"
+]
+
+PARSED_CMD_RESULT = [
+ {
+ "bridge_id": "8000.005056acc9a2",
+ "bridge_name": "br-ex",
+ "interfaces": "eno33554952,p_ff798dba-0,v_public,v_vrouter_pub",
+ "stp_enabled": "no"
+ },
+ {
+ "bridge_id": "8000.005056ace897",
+ "bridge_name": "br-fw-admin",
+ "interfaces": "eno16777728",
+ "stp_enabled": "no"
+ }
+]
+
+LINE_FOR_PARSE = "br-ex\t\t8000.005056acc9a2\tno\t\teno33554952,p_ff798dba-0,v_public,v_vrouter_pub"
+PARSED_LINE = {
+ "bridge_id": "8000.005056acc9a2",
+ "bridge_name": "br-ex",
+ "interfaces": "eno33554952,p_ff798dba-0,v_public,v_vrouter_pub",
+ "stp_enabled": "no"
+}
+HEADERS = ["bridge_name", "bridge_id", "stp_enabled", "interfaces"]
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics.py
new file mode 100644
index 0000000..316c68a
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics.py
@@ -0,0 +1,147 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+PNICS_FOLDER_ID = "node-6.cisco.com-pnics"
+HOST_ID = "node-6.cisco.com"
+
+NETWORK_NODE = {
+ "host_type": [
+ "Controller",
+ "Network"
+ ],
+ "id": "node-6.cisco.com"
+}
+
+WRONG_NODE = {
+ "host_type": [
+ "Controller"
+ ]
+}
+
+INTERFACE_LINES = [
+ "lrwxrwxrwx 1 root 0 Jul 5 17:17 eno16777728 -> ../../devices/0000:02:00.0/net/eno16777728",
+ "lrwxrwxrwx 1 root 0 Jul 5 17:17 eno33554952 -> ../../devices/0000:02:01.0/net/eno33554952"
+]
+
+INTERFACE_NAMES = ["eno16777728", "eno33554952"]
+
+INTERFACE_NAME = INTERFACE_NAMES[0]
+IFCONFIG_CM_RESULT = [
+ "eno16777728 Link encap:Ethernet HWaddr 00:50:56:ac:e8:97 ",
+ " UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1",
+ " RX packets:409056348 errors:0 dropped:0 overruns:0 frame:0",
+ " TX packets:293898173 errors:0 dropped:0 overruns:0 carrier:0",
+ " collisions:0 txqueuelen:1000 ",
+ " RX bytes:103719003730 (103.7 GB) TX bytes:165090993470 (165.0 GB)",
+ ""
+]
+
+INTERFACE_DETAILS = {
+ "host": "node-6.cisco.com",
+ "id": "eno16777728-unknown_mac",
+ "lines": [],
+ "local_name": "eno16777728",
+ "name": "eno16777728",
+ "state": "UP"
+}
+
+MAC_ADDRESS_LINE = "eno16777728 Link encap:Ethernet HWaddr 00:50:56:ac:e8:97 "
+MAC_ADDRESS = "00:50:56:ac:e8:97"
+RAW_INTERFACE = {
+ "host": "node-6.cisco.com",
+ "lines": [],
+ "local_name": "eno16777728",
+ "name": "eno16777728"
+}
+
+INTERFACE_AFTER_LINE_HANDLE = {
+ "host": "node-6.cisco.com",
+ "lines": [MAC_ADDRESS_LINE.strip()],
+ "local_name": "eno16777728",
+ "name": "eno16777728",
+ "id": "eno16777728-" + MAC_ADDRESS,
+ "mac_address": MAC_ADDRESS
+}
+
+INTERFACE_FOR_SET = {
+ "host": "node-6.cisco.com",
+ "lines": [
+ "Link encap:Ethernet HWaddr 00:50:56:ac:e8:97",
+ "UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1"
+ ],
+ "local_name": "eno16777728",
+ "mac_address": "00:50:56:ac:e8:97"
+}
+
+INTERFACE_AFTER_SET = {
+ "host": "node-6.cisco.com",
+ "data": "Link encap:Ethernet HWaddr 00:50:56:ac:e8:97" +
+ "\nUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1",
+ "local_name": "eno16777728",
+ "mac_address": "00:50:56:ac:e8:97",
+ "Supported ports": "[ TP ]",
+ "Supported link modes": ["10baseT/Half 10baseT/Full",
+ "100baseT/Half 100baseT/Full",
+ "1000baseT/Full"],
+ "Supported pause frame use": "No"
+}
+
+INTERFACE = {
+ "Advertised auto-negotiation": "Yes",
+ "Advertised link modes": [
+ "10baseT/Half 10baseT/Full",
+ "100baseT/Half 100baseT/Full",
+ "1000baseT/Full"
+ ],
+ "Advertised pause frame use": "No",
+ "Auto-negotiation": "on",
+ "Current message level": [
+ "0x00000007 (7)",
+ "drv probe link"
+ ],
+ "Duplex": "Full",
+ "Link detected": "yes",
+ "MDI-X": "off (auto)",
+ "PHYAD": "0",
+ "Port": "Twisted Pair",
+ "Speed": "1000Mb/s",
+ "Supported link modes": [
+ "10baseT/Half 10baseT/Full",
+ "100baseT/Half 100baseT/Full",
+ "1000baseT/Full"
+ ],
+ "Supported pause frame use": "No",
+ "Supported ports": "[ TP ]",
+ "Supports Wake-on": "d",
+ "Supports auto-negotiation": "Yes",
+ "Transceiver": "internal",
+ "Wake-on": "d",
+ "data": "Link encap:Ethernet HWaddr 00:50:56:ac:e8:97\nUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1\nRX packets:408989052 errors:0 dropped:0 overruns:0 frame:0\nTX packets:293849880 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:1000\nRX bytes:103702814216 (103.7 GB) TX bytes:165063440009 (165.0 GB)\n",
+ "host": "node-6.cisco.com",
+ "id": "eno16777728-00:50:56:ac:e8:97",
+ "local_name": "eno16777728",
+ "mac_address": "00:50:56:ac:e8:97",
+ "name": "eno16777728"
+}
+
+INTERFACES_GET_RESULTS = [INTERFACE]
+
+IPV6_ADDRESS_LINE = " inet6 addr: fe80::f816:3eff:fea1:eb73/64 Scope:Link"
+IPV6_ADDRESS = "fe80::f816:3eff:fea1:eb73/64"
+IPV4_ADDRESS_LINE = " inet addr:172.16.13.2 Bcast:172.16.13.255 Mask:255.255.255.0"
+IPV4_ADDRESS = "172.16.13.2"
+
+ETHTOOL_RESULT = [
+ "Settings for eno16777728:",
+ "\tSupported ports: [ TP ]",
+ "\tSupported link modes: 10baseT/Half 10baseT/Full ",
+ "\t 100baseT/Half 100baseT/Full ",
+ "\t 1000baseT/Full ",
+ "\tSupported pause frame use: No",
+]
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics_vpp.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics_vpp.py
new file mode 100644
index 0000000..99bd4cd
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_host_pnics_vpp.py
@@ -0,0 +1,204 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+ID = "node-4.cisco.com-VPP-folders"
+VEDGES = [
+ {
+ "agent_type": "Open vSwitch agent",
+ "binary": "neutron-openvswitch-agent",
+ "configurations" : {
+ "tunneling_ip": "192.168.2.3",
+ "arp_responder_enabled" : True,
+ "extensions" : [
+
+ ],
+ "l2_population" : True,
+ "enable_distributed_routing" : False,
+ "bridge_mappings" : {
+ "physnet1": "br-floating"
+ },
+ "log_agent_heartbeats" : False,
+ "tunnel_types" : [
+ "vxlan"
+ ],
+ "in_distributed_mode" : False
+ },
+ "description" : None,
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-6.cisco.com",
+ "id": "1764430c-c09e-4717-86fa-c04350b1fcbb",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/internal/node-6.cisco.com/node-6.cisco.com-vedges/1764430c-c09e-4717-86fa-c04350b1fcbb",
+ "name": "node-6.cisco.com-OVS",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/internal/node-6.cisco.com/vEdges/node-6.cisco.com-OVS",
+ "object_name": "node-6.cisco.com-OVS",
+ "parent_id": "node-6.cisco.com-vedges",
+ "parent_type": "vedges_folder",
+ "ports" : {
+ "TenGigabitEthernet-g-63489f34-af" : {
+ "id": "8",
+ "name": "qg-63489f34-af",
+ "internal" : True,
+ "tag": "2",
+ "host": "node-4.cisco.com",
+ "state": "up"
+ },
+ "qr-3ff411a2-54" : {
+ "id": "7",
+ "name": "qr-3ff411a2-54",
+ "internal" : True,
+ "tag": "5"
+ },
+ "tap31c19fbe-5d" : {
+ "id": "19",
+ "name": "tap31c19fbe-5d",
+ "internal" : True,
+ "tag": "117"
+ },
+ "br-int" : {
+ "id": "3",
+ "name": "br-int",
+ "internal" : True
+ },
+ "qr-18f029db-77" : {
+ "id": "17",
+ "name": "qr-18f029db-77",
+ "internal" : True,
+ "tag": "105"
+ },
+ "br-tun" : {
+ "id": "13",
+ "name": "br-tun",
+ "internal" : True
+ },
+ "tap82d4992f-4d" : {
+ "id": "9",
+ "name": "tap82d4992f-4d",
+ "internal" : True,
+ "tag": "5"
+ },
+ "tap16620a58-c4" : {
+ "id": "16",
+ "name": "tap16620a58-c4",
+ "internal" : True,
+ "tag": "6"
+ },
+ "p_ff798dba-0" : {
+ "id": "15",
+ "name": "p_ff798dba-0",
+ "internal" : True
+ },
+ "tapee8e5dbb-03" : {
+ "id": "6",
+ "name": "tapee8e5dbb-03",
+ "internal" : True,
+ "tag": "1"
+ },
+ "tap702e9683-0c" : {
+ "id": "20",
+ "name": "tap702e9683-0c",
+ "internal" : True,
+ "tag": "118"
+ },
+ "tapaf69959f-ef" : {
+ "id": "18",
+ "name": "tapaf69959f-ef",
+ "internal" : True,
+ "tag": "105"
+ },
+ "tap5f22f397-d8" : {
+ "id": "11",
+ "name": "tap5f22f397-d8",
+ "internal" : True,
+ "tag": "3"
+ },
+ "qr-bb9b8340-72" : {
+ "id": "1",
+ "name": "qr-bb9b8340-72",
+ "internal" : True,
+ "tag": "3"
+ },
+ "qr-8733cc5d-b3" : {
+ "id": "2",
+ "name": "qr-8733cc5d-b3",
+ "internal" : True,
+ "tag": "4"
+ },
+ "ovs-system" : {
+ "id": "0",
+ "name": "ovs-system",
+ "internal" : True
+ },
+ "br-floating" : {
+ "id": "14",
+ "name": "br-floating",
+ "internal" : True
+ },
+ "qg-57e65d34-3d" : {
+ "id": "10",
+ "name": "qg-57e65d34-3d",
+ "internal" : True,
+ "tag": "2"
+ },
+ "qr-f7b44150-99" : {
+ "id": "4",
+ "name": "qr-f7b44150-99",
+ "internal" : True,
+ "tag": "1"
+ },
+ "tapbf16c3ab-56" : {
+ "id": "5",
+ "name": "tapbf16c3ab-56",
+ "internal" : True,
+ "tag": "4"
+ }
+ },
+ "show_in_tree" : True,
+ "topic": "N/A",
+ "tunnel_ports" : {
+ "br-tun" : {
+ "name": "br-tun",
+ "interface": "br-tun",
+ "type": "internal"
+ },
+ "vxlan-c0a80201" : {
+ "name": "vxlan-c0a80201",
+ "options" : {
+ "local_ip": "192.168.2.3",
+ "out_key": "flow",
+ "in_key": "flow",
+ "df_default": "True",
+ "remote_ip": "192.168.2.1"
+ },
+ "interface": "vxlan-c0a80201",
+ "type": "vxlan"
+ },
+ "vxlan-c0a80202" : {
+ "name": "vxlan-c0a80202",
+ "options" : {
+ "local_ip": "192.168.2.3",
+ "out_key": "flow",
+ "in_key": "flow",
+ "df_default": "True",
+ "remote_ip": "192.168.2.2"
+ },
+ "interface": "vxlan-c0a80202",
+ "type": "vxlan"
+ },
+ "patch-int" : {
+ "name": "patch-int",
+ "options" : {
+ "peer": "patch-tun"
+ },
+ "interface": "patch-int",
+ "type": "patch"
+ }
+ },
+ "type": "vedge"
+}
+ ] \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_host_verservices.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_host_verservices.py
new file mode 100644
index 0000000..94ee38c
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_host_verservices.py
@@ -0,0 +1,276 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+NETWORK_HOST = {
+ "config": {
+ "interfaces": 4,
+ "log_agent_heartbeats": False,
+ "gateway_external_network_id": "",
+ "router_id": "",
+ "interface_driver": "neutron.agent.linux.interface.OVSInterfaceDriver",
+ "ex_gw_ports": 2,
+ "routers": 2,
+ "handle_internal_only_routers": True,
+ "floating_ips": 1,
+ "external_network_bridge": "",
+ "use_namespaces": True,
+ "agent_mode": "legacy"
+ },
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-6.cisco.com",
+ "host_type": [
+ "Controller",
+ "Network"
+ ],
+ "id": "node-6.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/internal/node-6.cisco.com",
+ "name": "node-6.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/internal/node-6.cisco.com",
+ "object_name": "node-6.cisco.com",
+ "parent_id": "internal",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:10.000000"
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:54.000000"
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:45.000000"
+ },
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:56.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type" : "host",
+ "zone" : "internal"
+}
+
+COMPUTE_HOST = {
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-5.cisco.com",
+ "host_type": [
+ "Compute"
+ ],
+ "id": "node-5.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/osdna-zone/node-5.cisco.com",
+ "ip_address": "192.168.0.4",
+ "name": "node-5.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/osdna-zone/node-5.cisco.com",
+ "object_name": "node-5.cisco.com",
+ "os_id": "1",
+ "parent_id": "osdna-zone",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-compute": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:42.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type": "host",
+ "zone": "osdna-zone"
+}
+
+NAMESPACES = [
+ 'qdhcp-413de095-01ed-49dc-aa50-4479f43d390e',
+ 'qdhcp-2e3b85f4-756c-49d9-b34c-f3db13212dbc',
+ 'qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe',
+ 'qdhcp-eb276a62-15a9-4616-a192-11466fdd147f',
+ 'qdhcp-7e59b726-d6f4-451a-a574-c67a920ff627',
+ 'qdhcp-a55ff1e8-3821-4e5f-bcfd-07df93720a4f',
+ 'qdhcp-6504fcf7-41d7-40bb-aeb1-6a7658c105fc',
+ 'qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9',
+ 'qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6',
+ 'haproxy',
+ 'vrouter'
+]
+
+LOCAL_SERVICES_IDS = [
+ {
+ "local_service_id": "qdhcp-413de095-01ed-49dc-aa50-4479f43d390e"
+ },
+ {
+ "local_service_id": "qdhcp-2e3b85f4-756c-49d9-b34c-f3db13212dbc"
+ },
+ {
+ "local_service_id": "qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe"
+ },
+ {
+ "local_service_id": "qdhcp-eb276a62-15a9-4616-a192-11466fdd147f"
+ },
+ {
+ "local_service_id": "qdhcp-7e59b726-d6f4-451a-a574-c67a920ff627"
+ },
+ {
+ "local_service_id": "qdhcp-a55ff1e8-3821-4e5f-bcfd-07df93720a4f"
+ },
+ {
+ "local_service_id": "qdhcp-6504fcf7-41d7-40bb-aeb1-6a7658c105fc"
+ },
+ {
+ "local_service_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9"
+ },
+ {
+ "local_service_id": "qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6"
+ }
+]
+
+VSERVICE = {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "local_service_id": "qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "name": "dhcp-osdna-met4",
+ "service_type": "dhcp"
+ }
+
+AGENT = {
+ "description": "DHCP agent",
+ "folder_text": "DHCP servers",
+ "type": "dhcp"
+}
+
+ROUTER = [
+ {"name": "123456"}
+]
+
+ID_CLEAN = "413de095-01ed-49dc-aa50-4479f43d390e"
+# functional test
+INPUT = "node-6.cisco.com"
+OUTPUT = [
+ {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-413de095-01ed-49dc-aa50-4479f43d390e",
+ "local_service_id": "qdhcp-413de095-01ed-49dc-aa50-4479f43d390e",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "dhcp-aiya",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp"
+ },
+ {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-2e3b85f4-756c-49d9-b34c-f3db13212dbc",
+ "local_service_id": "qdhcp-2e3b85f4-756c-49d9-b34c-f3db13212dbc",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "dhcp-123456",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp"
+ },
+ {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "local_service_id": "qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "dhcp-osdna-met4",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp"
+ },
+ {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-eb276a62-15a9-4616-a192-11466fdd147f",
+ "local_service_id": "qdhcp-eb276a62-15a9-4616-a192-11466fdd147f",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "dhcp-osdna-net3",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp"
+ },
+ {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-7e59b726-d6f4-451a-a574-c67a920ff627",
+ "local_service_id": "qdhcp-7e59b726-d6f4-451a-a574-c67a920ff627",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "dhcp-osdna-net1",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp"
+ },
+ {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-a55ff1e8-3821-4e5f-bcfd-07df93720a4f",
+ "local_service_id": "qdhcp-a55ff1e8-3821-4e5f-bcfd-07df93720a4f",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "dhcp-osdna-net2",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp"
+ },
+ {
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-6504fcf7-41d7-40bb-aeb1-6a7658c105fc",
+ "local_service_id": "qdhcp-6504fcf7-41d7-40bb-aeb1-6a7658c105fc",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "dhcp-admin_internal_net",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp"
+ },
+ {
+ "admin_state_up": 1,
+ "enable_snat": 1,
+ "gw_port_id": "63489f34-af99-44f4-81de-9a2eb1c1941f",
+ "host": "node-6.cisco.com",
+ "id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9",
+ "local_service_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "router-osdna-router",
+ "parent_id": "node-6.cisco.com-vservices-routers",
+ "parent_text": "Gateways",
+ "parent_type": "vservice_routers_folder",
+ "service_type": "router",
+ "status": "ACTIVE",
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40"
+ },
+ {
+ "admin_state_up": 1,
+ "enable_snat": 1,
+ "gw_port_id": "57e65d34-3d87-4751-8e95-fc78847a3070",
+ "host": "node-6.cisco.com",
+ "id": "qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6",
+ "local_service_id": "qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6",
+ "master_parent_id": "node-6.cisco.com-vservices",
+ "master_parent_type": "vservices_folder",
+ "name": "router-router04",
+ "parent_id": "node-6.cisco.com-vservices-routers",
+ "parent_text": "Gateways",
+ "parent_type": "vservice_routers_folder",
+ "service_type": "router",
+ "status": "ACTIVE",
+ "tenant_id": "8c1751e0ce714736a63fee3c776164da"
+ }
+] \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_instance_vnics.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_instance_vnics.py
new file mode 100644
index 0000000..a43b5c2
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_instance_vnics.py
@@ -0,0 +1,288 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+VNICS_FOLDER = {
+ "create_object": True,
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "id": "bf0cb914-b316-486c-a4ce-f22deb453c52-vnics",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/osdna-zone/node-5.cisco.com/node-5.cisco.com-instances/bf0cb914-b316-486c-a4ce-f22deb453c52/bf0cb914-b316-486c-a4ce-f22deb453c52-vnics",
+ "name": "vNICs",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/osdna-zone/node-5.cisco.com/Instances/test/vNICs",
+ "object_name": "vNICs",
+ "parent_id": "bf0cb914-b316-486c-a4ce-f22deb453c52",
+ "parent_type": "instance",
+ "show_in_tree": True,
+ "text": "vNICs",
+ "type": "vnics_folder"
+}
+
+INSATNCE = {
+ "_id": "5806817e4a0a8a3fbe3bee8b",
+ "children_url": "/osdna_dev/discover.py?type=tree&id=bf0cb914-b316-486c-a4ce-f22deb453c52",
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-5.cisco.com",
+ "id": "bf0cb914-b316-486c-a4ce-f22deb453c52",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/osdna-zone/node-5.cisco.com/node-5.cisco.com-instances/bf0cb914-b316-486c-a4ce-f22deb453c52",
+ "ip_address": "192.168.0.4",
+ "local_name": "instance-00000026",
+ "mac_address": "fa:16:3e:e8:7f:04",
+ "name": "test",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/osdna-zone/node-5.cisco.com/Instances/test",
+ "network": [
+ "2e3b85f4-756c-49d9-b34c-f3db13212dbc"
+ ],
+ "network_info": [
+ {
+ "devname": "tap1f72bd15-8a",
+ "id": "1f72bd15-8ab2-43cb-94d7-e823dd845255",
+ "profile": {
+
+ },
+ "vnic_type": "normal",
+ "type": "ovs",
+ "address": "fa:16:3e:e8:7f:04",
+ "qbg_params": None,
+ "network": {
+ "bridge": "br-int",
+ "label": "123456",
+ "subnets": [
+ {
+ "cidr": "172.16.13.0/24",
+ "version": 4,
+ "gateway": {
+ "version": 4,
+ "meta": {
+
+ },
+ "address": "172.16.13.1",
+ "type": "gateway"
+ },
+ "routes": [
+
+ ],
+ "dns": [
+
+ ],
+ "ips": [
+ {
+ "meta": {
+
+ },
+ "version": 4,
+ "type": "fixed",
+ "address": "172.16.13.4",
+ "floating_ips": [
+
+ ]
+ }
+ ],
+ "meta": {
+ "dhcp_server": "172.16.13.2"
+ }
+ }
+ ],
+ "meta": {
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "injected": False
+ },
+ "id": "2e3b85f4-756c-49d9-b34c-f3db13212dbc"
+ },
+ "active": True,
+ "meta": {
+
+ },
+ "details": {
+ "port_filter": True,
+ "ovs_hybrid_plug": True
+ },
+ "preserve_on_delete": False,
+ "qbh_params": None,
+ "ovs_interfaceid": "1f72bd15-8ab2-43cb-94d7-e823dd845255"
+ }
+ ],
+ "object_name": "test",
+ "parent_id": "node-5.cisco.com-instances",
+ "parent_type": "instances_folder",
+ "project_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "projects": [
+ "OSDNA-project"
+ ],
+ "show_in_tree": True,
+ "type": "instance",
+ "uuid": "bf0cb914-b316-486c-a4ce-f22deb453c52"
+}
+
+
+COMPUTE_HOST = {
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-5.cisco.com",
+ "host_type": [
+ "Compute"
+ ],
+ "id": "node-5.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/osdna-zone/node-5.cisco.com",
+ "ip_address": "192.168.0.4",
+ "name": "node-5.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/osdna-zone/node-5.cisco.com",
+ "object_name": "node-5.cisco.com",
+ "os_id": "1",
+ "parent_id": "osdna-zone",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-compute": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:42.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type": "host",
+ "zone": "osdna-zone"
+}
+
+NETWORK_HOST = {
+ "config": {
+ "interfaces": 4,
+ "log_agent_heartbeats": False,
+ "gateway_external_network_id": "",
+ "router_id": "",
+ "interface_driver": "neutron.agent.linux.interface.OVSInterfaceDriver",
+ "ex_gw_ports": 2,
+ "routers": 2,
+ "handle_internal_only_routers": True,
+ "floating_ips": 1,
+ "external_network_bridge": "",
+ "use_namespaces": True,
+ "agent_mode": "legacy"
+ },
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-6.cisco.com",
+ "host_type": [
+ "Controller",
+ "Network"
+ ],
+ "id": "node-6.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/internal/node-6.cisco.com",
+ "name": "node-6.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/internal/node-6.cisco.com",
+ "object_name": "node-6.cisco.com",
+ "parent_id": "internal",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:10.000000"
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:54.000000"
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:45.000000"
+ },
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:56.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type": "host",
+ "zone": "internal"
+}
+
+DUMPXML = "<domain type='qemu' id='38'>\n <name>instance-00000026</name>\n <uuid>bf0cb914-b316-486c-a4ce-f22deb453c52</uuid>\n <metadata>\n <nova:instance xmlns:nova=\"http://openstack.org/xmlns/libvirt/nova/1.0\">\n <nova:package version=\"12.0.0\"/>\n <nova:name>test</nova:name>\n <nova:creationTime>2016-10-17 22:37:43</nova:creationTime>\n <nova:flavor name=\"m1.micro\">\n <nova:memory>64</nova:memory>\n <nova:disk>0</nova:disk>\n <nova:swap>0</nova:swap>\n <nova:ephemeral>0</nova:ephemeral>\n <nova:vcpus>1</nova:vcpus>\n </nova:flavor>\n <nova:owner>\n <nova:user uuid=\"13baa553aae44adca6615e711fd2f6d9\">admin</nova:user>\n <nova:project uuid=\"75c0eb79ff4a42b0ae4973c8375ddf40\">OSDNA-project</nova:project>\n </nova:owner>\n <nova:root type=\"image\" uuid=\"c6f490c4-3656-43c6-8d03-b4e66bd249f9\"/>\n </nova:instance>\n </metadata>\n <memory unit='KiB'>65536</memory>\n <currentMemory unit='KiB'>65536</currentMemory>\n <vcpu placement='static'>1</vcpu>\n <cputune>\n <shares>1024</shares>\n </cputune>\n <sysinfo type='smbios'>\n <system>\n <entry name='manufacturer'>OpenStack Foundation</entry>\n <entry name='product'>OpenStack Nova</entry>\n <entry name='version'>12.0.0</entry>\n <entry name='serial'>9cf57bfd-7477-4671-b2d3-3dfeebfefb1d</entry>\n <entry name='uuid'>bf0cb914-b316-486c-a4ce-f22deb453c52</entry>\n <entry name='family'>Virtual Machine</entry>\n </system>\n </sysinfo>\n <os>\n <type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type>\n <boot dev='hd'/>\n <smbios mode='sysinfo'/>\n </os>\n <features>\n <acpi/>\n <apic/>\n </features>\n <cpu>\n <topology sockets='1' cores='1' threads='1'/>\n </cpu>\n <clock offset='utc'/>\n <on_poweroff>destroy</on_poweroff>\n <on_reboot>restart</on_reboot>\n <on_crash>destroy</on_crash>\n <devices>\n <emulator>/usr/bin/qemu-system-x86_64</emulator>\n <disk type='file' device='disk'>\n <driver name='qemu' type='qcow2' cache='directsync'/>\n <source file='/var/lib/nova/instances/bf0cb914-b316-486c-a4ce-f22deb453c52/disk'/>\n <backingStore type='file' index='1'>\n <format type='raw'/>\n <source file='/var/lib/nova/instances/_base/44881e4441fbd821d0d6240f90742fc97e52f83e'/>\n <backingStore/>\n </backingStore>\n <target dev='vda' bus='virtio'/>\n <alias name='virtio-disk0'/>\n <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>\n </disk>\n <controller type='usb' index='0'>\n <alias name='usb0'/>\n <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>\n </controller>\n <controller type='pci' index='0' model='pci-root'>\n <alias name='pci.0'/>\n </controller>\n <interface type='bridge'>\n <mac address='fa:16:3e:e8:7f:04'/>\n <source bridge='qbr1f72bd15-8a'/>\n <target dev='tap1f72bd15-8a'/>\n <model type='virtio'/>\n <driver name='qemu'/>\n <alias name='net0'/>\n <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>\n </interface>\n <serial type='file'>\n <source path='/var/lib/nova/instances/bf0cb914-b316-486c-a4ce-f22deb453c52/console.log'/>\n <target port='0'/>\n <alias name='serial0'/>\n </serial>\n <serial type='pty'>\n <source path='/dev/pts/8'/>\n <target port='1'/>\n <alias name='serial1'/>\n </serial>\n <console type='file'>\n <source path='/var/lib/nova/instances/bf0cb914-b316-486c-a4ce-f22deb453c52/console.log'/>\n <target type='serial' port='0'/>\n <alias name='serial0'/>\n </console>\n <input type='tablet' bus='usb'>\n <alias name='input0'/>\n </input>\n <input type='mouse' bus='ps2'/>\n <input type='keyboard' bus='ps2'/>\n <graphics type='vnc' port='5902' autoport='yes' listen='0.0.0.0' keymap='en-us'>\n <listen type='address' address='0.0.0.0'/>\n </graphics>\n <video>\n <model type='cirrus' vram='9216' heads='1'/>\n <alias name='video0'/>\n <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>\n </video>\n <memballoon model='virtio'>\n <alias name='balloon0'/>\n <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>\n <stats period='10'/>\n </memballoon>\n </devices>\n <seclabel type='dynamic' model='apparmor' relabel='yes'>\n <label>libvirt-bf0cb914-b316-486c-a4ce-f22deb453c52</label>\n <imagelabel>libvirt-bf0cb914-b316-486c-a4ce-f22deb453c52</imagelabel>\n </seclabel>\n</domain>\n\n"
+WRONG_DUMPXML = "<domain type='qemu' id='38'><uuid>wrong_instance</uuid></domain>"
+INSTANCES_LIST = [
+ ' Id Name State',
+ '----------------------------------------------------',
+ ' 2 instance-00000002 running',
+ ' 27 instance-0000001c running',
+ ' 38 instance-00000026 running',
+ ' 39 instance-00000028 running',
+ ''
+]
+
+VNIC = {
+ "@type": "bridge",
+ "address": {
+ "@bus": "0x00",
+ "@domain": "0x0000",
+ "@function": "0x0",
+ "@slot": "0x03",
+ "@type": "pci"
+ },
+ "alias": {
+ "@name": "net0"
+ },
+ "driver": {
+ "@name": "qemu"
+ },
+ "mac": {
+ "@address": "fa:16:3e:e8:7f:04"
+ },
+ "model": {
+ "@type": "virtio"
+ },
+ "source": {
+ "@bridge": "qbr1f72bd15-8a"
+ },
+ "target": {
+ "@dev": "tap1f72bd15-8a"
+ }
+}
+
+ID = "38"
+
+VNICS_FROM_DUMP_XML = [
+ {
+ "@type": "bridge",
+ "address": {
+ "@bus": "0x00",
+ "@domain": "0x0000",
+ "@function": "0x0",
+ "@slot": "0x03",
+ "@type": "pci"
+ },
+ "alias": {
+ "@name": "net0"
+ },
+ "driver": {
+ "@name": "qemu"
+ },
+ "host": "node-5.cisco.com",
+ "id": "tap1f72bd15-8a",
+ "instance_db_id": "5806817e4a0a8a3fbe3bee8b",
+ "instance_id": "bf0cb914-b316-486c-a4ce-f22deb453c52",
+ "mac": {
+ "@address": "fa:16:3e:e8:7f:04"
+ },
+ "mac_address": "fa:16:3e:e8:7f:04",
+ "model": {
+ "@type": "virtio"
+ },
+ "name": "tap1f72bd15-8a",
+ "source": {
+ "@bridge": "qbr1f72bd15-8a"
+ },
+ "source_bridge": "qbr1f72bd15-8a",
+ "target": {
+ "@dev": "tap1f72bd15-8a"
+ },
+ "vnic_type": "instance_vnic"
+ }
+]
+
+
+# functional test
+INPUT = "bf0cb914-b316-486c-a4ce-f22deb453c52-vnics" \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors.py
new file mode 100644
index 0000000..f51e510
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors.py
@@ -0,0 +1,103 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+HOST = {
+ "config" : {
+ "metadata_proxy_socket" : "/opt/stack/data/neutron/metadata_proxy",
+ "nova_metadata_ip" : "192.168.20.14",
+ "log_agent_heartbeats" : False
+ },
+ "environment" : "Devstack-VPP-2",
+ "host" : "ubuntu0",
+ "host_type" : [
+ "Controller",
+ "Compute",
+ "Network"
+ ],
+ "id" : "ubuntu0",
+ "id_path" : "/Devstack-VPP-2/Devstack-VPP-2-regions/RegionOne/RegionOne-availability_zones/nova/ubuntu0",
+ "ip_address" : "192.168.20.14",
+ "name" : "ubuntu0",
+ "name_path" : "/Devstack-VPP-2/Regions/RegionOne/Availability Zones/nova/ubuntu0",
+ "object_name" : "ubuntu0",
+ "os_id" : "1",
+ "parent_id" : "nova",
+ "parent_type" : "availability_zone",
+ "services" : {
+ "nova-conductor" : {
+ "available" : True,
+ "active" : True,
+ "updated_at" : "2016-08-30T09:18:58.000000"
+ },
+ "nova-scheduler" : {
+ "available" : True,
+ "active" : True,
+ "updated_at" : "2016-08-30T09:18:54.000000"
+ },
+ "nova-consoleauth" : {
+ "available" : True,
+ "active" : True,
+ "updated_at" : "2016-08-30T09:18:54.000000"
+ }
+ },
+ "show_in_tree" : True,
+ "type" : "host",
+ "zone" : "nova"
+}
+
+WRONG_HOST = {
+ "show_in_tree" : True,
+ "type" : "host",
+ "zone" : "nova"
+}
+
+VCONNECTORS_FOLDER = {
+ "create_object" : True,
+ "environment" : "Mirantis-Liberty-Xiaocong",
+ "id" : "node-6.cisco.com-vconnectors",
+ "id_path" : "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/internal/node-6.cisco.com/node-6.cisco.com-vconnectors",
+ "name" : "vConnectors",
+ "name_path" : "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/internal/node-6.cisco.com/vConnectors",
+ "object_name" : "vConnectors",
+ "parent_id" : "node-6.cisco.com",
+ "parent_type" : "host",
+ "show_in_tree" : True,
+ "text" : "vConnectors",
+ "type" : "vconnectors_folder"
+}
+
+VCONNECTORS = [
+ {
+ "bd_id": "5678",
+ "host": "ubuntu0",
+ "id": "ubuntu0-vconnector-5678",
+ "interfaces": {
+ "name": {
+ "hardware": "VirtualEthernet0/0/8",
+ "id": "15",
+ "mac_address": "fa:16:3e:d1:98:73",
+ "name": "VirtualEthernet0/0/8",
+ "state": "up"
+ }
+ },
+ "interfaces_names": [
+ "TenGigabitEthernetc/0/0",
+ "VirtualEthernet0/0/0",
+ "VirtualEthernet0/0/1",
+ "VirtualEthernet0/0/2",
+ "VirtualEthernet0/0/3",
+ "VirtualEthernet0/0/4",
+ "VirtualEthernet0/0/5",
+ "VirtualEthernet0/0/6",
+ "VirtualEthernet0/0/7",
+ "VirtualEthernet0/0/8"
+ ],
+ "name": "bridge-domain-5678"
+ }
+] \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_ovs.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_ovs.py
new file mode 100644
index 0000000..9161457
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_ovs.py
@@ -0,0 +1,234 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+NETWORK_NODE = {
+ "config": {
+ "interfaces": 4,
+ "log_agent_heartbeats": False,
+ "gateway_external_network_id": "",
+ "router_id": "",
+ "interface_driver": "neutron.agent.linux.interface.OVSInterfaceDriver",
+ "ex_gw_ports": 2,
+ "routers": 2,
+ "handle_internal_only_routers": True,
+ "floating_ips": 1,
+ "external_network_bridge": "",
+ "use_namespaces": True,
+ "agent_mode": "legacy"
+ },
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-6.cisco.com",
+ "host_type": [
+ "Controller",
+ "Network"
+ ],
+ "id": "node-6.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/internal/node-6.cisco.com",
+ "name": "node-6.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/internal/node-6.cisco.com",
+ "object_name": "node-6.cisco.com",
+ "parent_id": "internal",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:10.000000"
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:54.000000"
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:45.000000"
+ },
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:56.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type": "host",
+ "zone": "internal"
+}
+
+BRIDGE_RESULT = [
+ "bridge name\tbridge id\t\tSTP enabled\tinterfaces",
+ "br-ex\t\t8000.005056acc9a2\tno\t\teno33554952",
+ "\t\t\t\t\t\t\tp_ff798dba-0",
+ "\t\t\t\t\t\t\tv_public",
+ "\t\t\t\t\t\t\tv_vrouter_pub",
+ "br-fw-admin\t\t8000.005056ace897\tno\t\teno16777728",
+ "br-mesh\t\t8000.005056acc9a2\tno\t\teno33554952.103",
+ "br-mgmt\t\t8000.005056ace897\tno\t\teno16777728.101",
+ "\t\t\t\t\t\t\tmgmt-conntrd",
+ "\t\t\t\t\t\t\tv_management",
+ "\t\t\t\t\t\t\tv_vrouter",
+ "br-storage\t\t8000.005056ace897\tno\t\teno16777728.102"
+]
+
+FIXED_LINES = [
+ "br-ex\t\t8000.005056acc9a2\tno\t\teno33554952,p_ff798dba-0,v_public,v_vrouter_pub",
+ "br-fw-admin\t\t8000.005056ace897\tno\t\teno16777728",
+ "br-mesh\t\t8000.005056acc9a2\tno\t\teno33554952.103",
+ "br-mgmt\t\t8000.005056ace897\tno\t\teno16777728.101,mgmt-conntrd,v_management,v_vrouter",
+ "br-storage\t\t8000.005056ace897\tno\t\teno16777728.102"
+]
+
+PARSE_CM_RESULTS = [
+ {
+ "bridge_id": "8000.005056acc9a2",
+ "bridge_name": "br-ex",
+ "interfaces": "eno33554952,p_ff798dba-0,v_public,v_vrouter_pub",
+ "stp_enabled": "no"
+ },
+ {
+ "bridge_id": "8000.005056ace897",
+ "bridge_name": "br-fw-admin",
+ "interfaces": "eno16777728",
+ "stp_enabled": "no"
+ },
+ {
+ "bridge_id": "8000.005056acc9a2",
+ "bridge_name": "br-mesh",
+ "interfaces": "eno33554952.103",
+ "stp_enabled": "no"
+ },
+ {
+ "bridge_id": "8000.005056ace897",
+ "bridge_name": "br-mgmt",
+ "interfaces": "eno16777728.101,mgmt-conntrd,v_management,v_vrouter",
+ "stp_enabled": "no"
+ },
+ {
+ "bridge_id": "8000.005056ace897",
+ "bridge_name": "br-storage",
+ "interfaces": "eno16777728.102",
+ "stp_enabled": "no"
+ }
+]
+
+# functional test
+INPUT = "node-6.cisco.com"
+OUPUT = [
+ {
+ "connector_type": "bridge",
+ "host": "node-6.cisco.com",
+ "id": "8000.005056acc9a2",
+ "interfaces": {
+ "eno33554952": {
+ "mac_address": "",
+ "name": "eno33554952"
+ },
+ "p_ff798dba-0": {
+ "mac_address": "",
+ "name": "p_ff798dba-0"
+ },
+ "v_public": {
+ "mac_address": "",
+ "name": "v_public"
+ },
+ "v_vrouter_pub": {
+ "mac_address": "",
+ "name": "v_vrouter_pub"
+ }
+ },
+ "interfaces_names": [
+ "p_ff798dba-0",
+ "v_public",
+ "v_vrouter_pub",
+ "eno33554952"
+ ],
+ "name": "br-ex",
+ "stp_enabled": "no"
+ },
+ {
+ "connector_type": "bridge",
+ "host": "node-6.cisco.com",
+ "id": "8000.005056ace897",
+ "interfaces": {
+ "eno16777728": {
+ "mac_address": "",
+ "name": "eno16777728"
+ }
+ },
+ "interfaces_names": [
+ "eno16777728"
+ ],
+ "name": "br-fw-admin",
+ "stp_enabled": "no"
+ },
+ {
+ "connector_type": "bridge",
+ "host": "node-6.cisco.com",
+ "id": "8000.005056acc9a2",
+ "interfaces": {
+ "eno33554952.103": {
+ "mac_address": "",
+ "name": "eno33554952.103"
+ }
+ },
+ "interfaces_names": [
+ "eno33554952.103"
+ ],
+ "name": "br-mesh",
+ "stp_enabled": "no"
+ },
+ {
+ "connector_type": "bridge",
+ "host": "node-6.cisco.com",
+ "id": "8000.005056ace897",
+ "interfaces": {
+ "eno16777728.101": {
+ "mac_address": "",
+ "name": "eno16777728.101"
+ },
+ "mgmt-conntrd": {
+ "mac_address": "",
+ "name": "mgmt-conntrd"
+ },
+ "v_management": {
+ "mac_address": "",
+ "name": "v_management"
+ },
+ "v_vrouter": {
+ "mac_address": "",
+ "name": "v_vrouter"
+ }
+ },
+ "interfaces_names": [
+ "v_management",
+ "mgmt-conntrd",
+ "v_vrouter",
+ "eno16777728.101"
+ ],
+ "name": "br-mgmt",
+ "stp_enabled": "no"
+ },
+ {
+ "connector_type": "bridge",
+ "host": "node-6.cisco.com",
+ "id": "8000.005056ace897",
+ "interfaces": {
+ "eno16777728.102": {
+ "mac_address": "",
+ "name": "eno16777728.102"
+ }
+ },
+ "interfaces_names": [
+ "eno16777728.102"
+ ],
+ "name": "br-storage",
+ "stp_enabled": "no"
+ }
+] \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_vpp.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_vpp.py
new file mode 100644
index 0000000..2c78b6a
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_vconnectors_vpp.py
@@ -0,0 +1,137 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+HOST = {
+ "config" : {
+ "metadata_proxy_socket" : "/opt/stack/data/neutron/metadata_proxy",
+ "nova_metadata_ip" : "192.168.20.14",
+ "log_agent_heartbeats" : False
+ },
+ "environment" : "Devstack-VPP-2",
+ "host" : "ubuntu0",
+ "host_type" : [
+ "Controller",
+ "Compute",
+ "Network"
+ ],
+ "id" : "ubuntu0",
+ "id_path" : "/Devstack-VPP-2/Devstack-VPP-2-regions/RegionOne/RegionOne-availability_zones/nova/ubuntu0",
+ "ip_address" : "192.168.20.14",
+ "name" : "ubuntu0",
+ "name_path" : "/Devstack-VPP-2/Regions/RegionOne/Availability Zones/nova/ubuntu0",
+ "object_name" : "ubuntu0",
+ "os_id" : "1",
+ "parent_id" : "nova",
+ "parent_type" : "availability_zone",
+ "services" : {
+ "nova-conductor" : {
+ "available" : True,
+ "active" : True,
+ "updated_at" : "2016-08-30T09:18:58.000000"
+ },
+ "nova-scheduler" : {
+ "available" : True,
+ "active" : True,
+ "updated_at" : "2016-08-30T09:18:54.000000"
+ },
+ "nova-consoleauth" : {
+ "available" : True,
+ "active" : True,
+ "updated_at" : "2016-08-30T09:18:54.000000"
+ }
+ },
+ "show_in_tree" : True,
+ "type" : "host",
+ "zone" : "nova"
+}
+
+MODE_RESULT = [
+ "l3 local0 ",
+ "l3 pg/stream-0 ",
+ "l3 pg/stream-1 ",
+ "l3 pg/stream-2 ",
+ "l3 pg/stream-3 ",
+ "l2 bridge TenGigabitEthernetc/0/0 bd_id 5678 shg 0",
+ "l3 TenGigabitEthernetd/0/0 ",
+ "l2 bridge VirtualEthernet0/0/0 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/1 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/2 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/3 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/4 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/5 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/6 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/7 bd_id 5678 shg 0",
+ "l2 bridge VirtualEthernet0/0/8 bd_id 5678 shg 0"
+]
+
+INTERFACE_LINES = [
+ " Name Idx Link Hardware",
+ "TenGigabitEthernetc/0/0 5 up TenGigabitEthernetc/0/0",
+ " Ethernet address 00:25:b5:99:00:5c",
+ " Cisco VIC",
+ " carrier up full duplex speed 40000 mtu 1500 promisc",
+ " rx queues 1, rx desc 5120, tx queues 1, tx desc 2048",
+ " cpu socket 0",
+ "",
+ " tx frames ok 81404",
+ " tx bytes ok 6711404",
+ " rx frames ok 502521",
+ " rx bytes ok 668002732",
+ " rx missed 64495",
+ " extended stats:",
+ " rx good packets 502521",
+ " tx good packets 81404",
+ " rx good bytes 668002732",
+ " tx good bytes 6711404"
+]
+
+INTERFACE_NAME = "TenGigabitEthernetc/0/0"
+
+GET_INTERFACE_DETAIL = {
+ "hardware": "TenGigabitEthernetc/0/0",
+ "id": "5",
+ "mac_address": "00:25:b5:99:00:5c",
+ "name": "TenGigabitEthernetc/0/0",
+ "state": "up"
+}
+
+# functional test
+# environment: Devstack-VPP-2
+# inventory name: vpp
+
+INPUT = "ubuntu0"
+OUPUT = [
+ {
+ "bd_id": "5678",
+ "host": "ubuntu0",
+ "id": "ubuntu0-vconnector-5678",
+ "interfaces": {
+ "name": {
+ "hardware": "VirtualEthernet0/0/8",
+ "id": "15",
+ "mac_address": "fa:16:3e:d1:98:73",
+ "name": "VirtualEthernet0/0/8",
+ "state": "up"
+ }
+ },
+ "interfaces_names": [
+ "TenGigabitEthernetc/0/0",
+ "VirtualEthernet0/0/0",
+ "VirtualEthernet0/0/1",
+ "VirtualEthernet0/0/2",
+ "VirtualEthernet0/0/3",
+ "VirtualEthernet0/0/4",
+ "VirtualEthernet0/0/5",
+ "VirtualEthernet0/0/6",
+ "VirtualEthernet0/0/7",
+ "VirtualEthernet0/0/8"
+ ],
+ "name": "bridge-domain-5678"
+ }
+] \ No newline at end of file
diff --git a/app/test/fetch/cli_fetch/test_data/cli_fetch_vservice_vnics.py b/app/test/fetch/cli_fetch/test_data/cli_fetch_vservice_vnics.py
new file mode 100644
index 0000000..0b60af5
--- /dev/null
+++ b/app/test/fetch/cli_fetch/test_data/cli_fetch_vservice_vnics.py
@@ -0,0 +1,616 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+NETWORK_NODE = {
+ "config": {
+ "interfaces": 4,
+ "log_agent_heartbeats": False,
+ "gateway_external_network_id": "",
+ "router_id": "",
+ "interface_driver": "neutron.agent.linux.interface.OVSInterfaceDriver",
+ "ex_gw_ports": 2,
+ "routers": 2,
+ "handle_internal_only_routers": True,
+ "floating_ips": 1,
+ "external_network_bridge": "",
+ "use_namespaces": True,
+ "agent_mode": "legacy"
+ },
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-6.cisco.com",
+ "host_type": [
+ "Controller",
+ "Network"
+ ],
+ "id": "node-6.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/internal/node-6.cisco.com",
+ "name": "node-6.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/internal/node-6.cisco.com",
+ "object_name": "node-6.cisco.com",
+ "parent_id": "internal",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-scheduler": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:10.000000"
+ },
+ "nova-consoleauth": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:54.000000"
+ },
+ "nova-conductor": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:45.000000"
+ },
+ "nova-cert": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:56.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type": "host",
+ "zone": "internal"
+}
+
+COMPUTE_NODE = {
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-5.cisco.com",
+ "host_type": [
+ "Compute"
+ ],
+ "id": "node-5.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/osdna-zone/node-5.cisco.com",
+ "ip_address": "192.168.0.4",
+ "name": "node-5.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/osdna-zone/node-5.cisco.com",
+ "object_name": "node-5.cisco.com",
+ "os_id": "1",
+ "parent_id": "osdna-zone",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-compute": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:42.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type": "host",
+ "zone": "osdna-zone"
+}
+
+ERROR_NODE = {
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-5.cisco.com",
+ "id": "node-5.cisco.com",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/osdna-zone/node-5.cisco.com",
+ "ip_address": "192.168.0.4",
+ "name": "node-5.cisco.com",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/osdna-zone/node-5.cisco.com",
+ "object_name": "node-5.cisco.com",
+ "os_id": "1",
+ "parent_id": "osdna-zone",
+ "parent_type": "availability_zone",
+ "services": {
+ "nova-compute": {
+ "active": True,
+ "available": True,
+ "updated_at": "2016-10-21T18:01:42.000000"
+ }
+ },
+ "show_in_tree": True,
+ "type": "host",
+ "zone": "osdna-zone"
+}
+
+NAME_SPACES = [
+ 'qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17',
+ 'qdhcp-0abe6331-0d74-4bbd-ad89-a5719c3793e4',
+ 'qdhcp-413de095-01ed-49dc-aa50-4479f43d390e',
+ 'qdhcp-2e3b85f4-756c-49d9-b34c-f3db13212dbc',
+ 'qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe',
+ 'qdhcp-eb276a62-15a9-4616-a192-11466fdd147f',
+ 'qdhcp-7e59b726-d6f4-451a-a574-c67a920ff627',
+ 'qdhcp-a55ff1e8-3821-4e5f-bcfd-07df93720a4f',
+ 'qdhcp-6504fcf7-41d7-40bb-aeb1-6a7658c105fc',
+ 'qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9',
+ 'qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6',
+ 'haproxy',
+ 'vrouter'
+]
+
+SERVICE_ID = 'qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17'
+
+SERVICES = [
+ {
+ "IP Address": "172.16.13.2",
+ "IPv6 Address": "fe80::f816:3eff:fea1:eb73/64",
+ "cidr": "172.16.13.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:a1:eb:73\ninet addr:172.16.13.2 Bcast:172.16.13.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fea1:eb73/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:28 errors:0 dropped:35 overruns:0 frame:0\nTX packets:8 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:4485 (4.4 KB) TX bytes:648 (648.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "tapa68b2627-a1",
+ "mac_address": "fa:16:3e:a1:eb:73",
+ "master_parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "master_parent_type": "vservice",
+ "name": "tapa68b2627-a1",
+ "netmask": "255.255.255.0",
+ "network": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ }
+]
+
+NET_MASK_ARRAY = ["255", "255", "255", "0"]
+SIZE = '24'
+
+VNIC = {
+ "IP Address": "172.16.13.2",
+ "IPv6 Address": "fe80::f816:3eff:fea1:eb73/64",
+ "host": "node-6.cisco.com",
+ "id": "tapa68b2627-a1",
+ "lines": [
+ "Link encap:Ethernet HWaddr fa:16:3e:a1:eb:73",
+ "inet addr:172.16.13.2 Bcast:172.16.13.255 Mask:255.255.255.0",
+ "inet6 addr: fe80::f816:3eff:fea1:eb73/64 Scope:Link",
+ "UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1",
+ "RX packets:28 errors:0 dropped:35 overruns:0 frame:0",
+ "TX packets:8 errors:0 dropped:0 overruns:0 carrier:0",
+ "collisions:0 txqueuelen:0",
+ "RX bytes:4485 (4.4 KB) TX bytes:648 (648.0 B)",
+ ""
+ ],
+ "mac_address": "fa:16:3e:a1:eb:73",
+ "master_parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "master_parent_type": "vservice",
+ "name": "tapa68b2627-a1",
+ "netmask": "255.255.255.0",
+ "parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+}
+
+RAW_VNIC = {
+ "host": "node-6.cisco.com",
+ "id": "tapa68b2627-a1",
+ "lines": [],
+ "master_parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "master_parent_type": "vservice",
+ "name": "tapa68b2627-a1",
+ "parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+}
+
+NETWORK = [{
+ "admin_state_up": True,
+ "cidrs": [
+ "172.16.13.0/24"
+ ],
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "id": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-projects/75c0eb79ff4a42b0ae4973c8375ddf40/75c0eb79ff4a42b0ae4973c8375ddf40-networks/8673c48a-f137-4497-b25d-08b7b218fd17",
+ "mtu": 1400,
+ "name": "25",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Projects/OSDNA-project/Networks/25",
+ "network": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "object_name": "25",
+ "parent_id": "75c0eb79ff4a42b0ae4973c8375ddf40-networks",
+ "parent_text": "Networks",
+ "parent_type": "networks_folder",
+ "port_security_enabled": True,
+ "project": "OSDNA-project",
+ "provider:network_type": "vxlan",
+ "provider:physical_network": None,
+ "provider:segmentation_id": 52,
+ "router:external": False,
+ "shared": False,
+ "show_in_tree": True,
+ "status": "ACTIVE",
+ "subnets": {
+ "123e": {
+ "ip_version": 4,
+ "enable_dhcp": True,
+ "gateway_ip": "172.16.13.1",
+ "id": "fcfa62ec-5ae7-46ce-9259-5f30de7af858",
+ "ipv6_ra_mode": None,
+ "name": "123e",
+ "dns_nameservers": [
+
+ ],
+ "cidr" : "172.16.13.0/24",
+ "subnetpool_id": None,
+ "ipv6_address_mode": None,
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "network_id": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "host_routes": [
+
+ ],
+ "allocation_pools": [
+ {
+ "start": "172.16.13.2",
+ "end": "172.16.13.254"
+ }
+ ]
+ }
+ },
+ "tenant_id": "75c0eb79ff4a42b0ae4973c8375ddf40",
+ "type": "network"
+}]
+
+VSERVICE = {
+ "children_url": "/osdna_dev/discover.py?type=tree&id=qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "environment": "Mirantis-Liberty-Xiaocong",
+ "host": "node-6.cisco.com",
+ "id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "id_path": "/Mirantis-Liberty-Xiaocong/Mirantis-Liberty-Xiaocong-regions/RegionOne/RegionOne-availability_zones/internal/node-6.cisco.com/node-6.cisco.com-vservices/node-6.cisco.com-vservices-dhcps/qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "local_service_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "name": "dhcp-25",
+ "name_path": "/Mirantis-Liberty-Xiaocong/Regions/RegionOne/Availability Zones/internal/node-6.cisco.com/Vservices/DHCP servers/dhcp-25",
+ "network": [
+ "8673c48a-f137-4497-b25d-08b7b218fd17"
+ ],
+ "object_name": "dhcp-25",
+ "parent_id": "node-6.cisco.com-vservices-dhcps",
+ "parent_text": "DHCP servers",
+ "parent_type": "vservice_dhcps_folder",
+ "service_type": "dhcp",
+ "show_in_tree": True,
+ "type": "vservice"
+}
+
+
+CIDR = "172.16.13.0/24"
+
+IFCONFIG_RESULT = [
+ "lo Link encap:Local Loopback ",
+ " inet addr:127.0.0.1 Mask:255.0.0.0",
+ " inet6 addr: ::1/128 Scope:Host",
+ " UP LOOPBACK RUNNING MTU:65536 Metric:1",
+ " RX packets:0 errors:0 dropped:0 overruns:0 frame:0",
+ " TX packets:0 errors:0 dropped:0 overruns:0 carrier:0",
+ " collisions:0 txqueuelen:0 ",
+ " RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)",
+ "",
+ "tapa68b2627-a1 Link encap:Ethernet HWaddr fa:16:3e:a1:eb:73 ",
+ " inet addr:172.16.13.2 Bcast:172.16.13.255 Mask:255.255.255.0",
+ " inet6 addr: fe80::f816:3eff:fea1:eb73/64 Scope:Link",
+ " UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1",
+ " RX packets:28 errors:0 dropped:35 overruns:0 frame:0",
+ " TX packets:8 errors:0 dropped:0 overruns:0 carrier:0",
+ " collisions:0 txqueuelen:0 ",
+ " RX bytes:4485 (4.4 KB) TX bytes:648 (648.0 B)",
+ ""
+]
+
+MAC_ADDRESS_LINE = "tapa68b2627-a1 Link encap:Ethernet HWaddr 00:50:56:ac:e8:97 "
+MAC_ADDRESS = "00:50:56:ac:e8:97"
+IPV6_ADDRESS_LINE = " inet6 addr: fe80::f816:3eff:fea1:eb73/64 Scope:Link"
+IPV6_ADDRESS = "fe80::f816:3eff:fea1:eb73/64"
+IPV4_ADDRESS_LINE = " inet addr:172.16.13.2 Bcast:172.16.13.255 Mask:255.255.255.0"
+IPV4_ADDRESS = "172.16.13.2"
+
+# functional test
+INPUT = "node-6.cisco.com"
+OUTPUT = [
+ {
+ "IP Address": "172.16.13.2",
+ "IPv6 Address": "fe80::f816:3eff:fea1:eb73/64",
+ "cidr": "172.16.13.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:a1:eb:73\ninet addr:172.16.13.2 Bcast:172.16.13.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fea1:eb73/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:28 errors:0 dropped:35 overruns:0 frame:0\nTX packets:8 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:4485 (4.4 KB) TX bytes:648 (648.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "tapa68b2627-a1",
+ "mac_address": "fa:16:3e:a1:eb:73",
+ "master_parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17",
+ "master_parent_type": "vservice",
+ "name": "tapa68b2627-a1",
+ "netmask": "255.255.255.0",
+ "network": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "parent_id": "qdhcp-8673c48a-f137-4497-b25d-08b7b218fd17-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.12.2",
+ "IPv6 Address": "fe80::f816:3eff:fec1:7f19/64",
+ "cidr": "172.16.12.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:c1:7f:19\ninet addr:172.16.12.2 Bcast:172.16.12.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fec1:7f19/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:6 errors:0 dropped:8 overruns:0 frame:0\nTX packets:8 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:360 (360.0 B) TX bytes:648 (648.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "tape67d81de-48",
+ "mac_address": "fa:16:3e:c1:7f:19",
+ "master_parent_id": "qdhcp-0abe6331-0d74-4bbd-ad89-a5719c3793e4",
+ "master_parent_type": "vservice",
+ "name": "tape67d81de-48",
+ "netmask": "255.255.255.0",
+ "network": "0abe6331-0d74-4bbd-ad89-a5719c3793e4",
+ "parent_id": "qdhcp-0abe6331-0d74-4bbd-ad89-a5719c3793e4-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.10.2",
+ "IPv6 Address": "fe80::f816:3eff:fe23:1b94/64",
+ "cidr": "172.16.10.0/25",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:23:1b:94\ninet addr:172.16.10.2 Bcast:172.16.10.127 Mask:255.255.255.128\ninet6 addr: fe80::f816:3eff:fe23:1b94/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:51 errors:0 dropped:12 overruns:0 frame:0\nTX packets:8 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:9161 (9.1 KB) TX bytes:648 (648.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "tapa1bf631f-de",
+ "mac_address": "fa:16:3e:23:1b:94",
+ "master_parent_id": "qdhcp-413de095-01ed-49dc-aa50-4479f43d390e",
+ "master_parent_type": "vservice",
+ "name": "tapa1bf631f-de",
+ "netmask": "255.255.255.128",
+ "network": "413de095-01ed-49dc-aa50-4479f43d390e",
+ "parent_id": "qdhcp-413de095-01ed-49dc-aa50-4479f43d390e-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.13.2",
+ "IPv6 Address": "fe80::f816:3eff:fec3:c871/64",
+ "cidr": "172.16.13.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:c3:c8:71\ninet addr:172.16.13.2 Bcast:172.16.13.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fec3:c871/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:4614 errors:0 dropped:4 overruns:0 frame:0\nTX packets:4459 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:823296 (823.2 KB) TX bytes:929712 (929.7 KB)\n",
+ "host": "node-6.cisco.com",
+ "id": "tapaf69959f-ef",
+ "mac_address": "fa:16:3e:c3:c8:71",
+ "master_parent_id": "qdhcp-2e3b85f4-756c-49d9-b34c-f3db13212dbc",
+ "master_parent_type": "vservice",
+ "name": "tapaf69959f-ef",
+ "netmask": "255.255.255.0",
+ "network": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "parent_id": "qdhcp-2e3b85f4-756c-49d9-b34c-f3db13212dbc-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.4.2",
+ "IPv6 Address": "fe80::f816:3eff:fed7:c516/64",
+ "cidr": "172.16.4.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:d7:c5:16\ninet addr:172.16.4.2 Bcast:172.16.4.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fed7:c516/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:56928 errors:0 dropped:15 overruns:0 frame:0\nTX packets:56675 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:10526014 (10.5 MB) TX bytes:12041070 (12.0 MB)\n",
+ "host": "node-6.cisco.com",
+ "id": "tap16620a58-c4",
+ "mac_address": "fa:16:3e:d7:c5:16",
+ "master_parent_id": "qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "master_parent_type": "vservice",
+ "name": "tap16620a58-c4",
+ "netmask": "255.255.255.0",
+ "network": "b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe",
+ "parent_id": "qdhcp-b6fd5175-4b22-4256-9b1a-9fc4b9dce1fe-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.2.2",
+ "IPv6 Address": "fe80::f816:3eff:feeb:39c2/64",
+ "cidr": "172.16.2.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:eb:39:c2\ninet addr:172.16.2.2 Bcast:172.16.2.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:feeb:39c2/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:93317 errors:0 dropped:57 overruns:0 frame:0\nTX packets:93264 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:17406098 (17.4 MB) TX bytes:19958079 (19.9 MB)\n",
+ "host": "node-6.cisco.com",
+ "id": "tap82d4992f-4d",
+ "mac_address": "fa:16:3e:eb:39:c2",
+ "master_parent_id": "qdhcp-eb276a62-15a9-4616-a192-11466fdd147f",
+ "master_parent_type": "vservice",
+ "name": "tap82d4992f-4d",
+ "netmask": "255.255.255.0",
+ "network": "eb276a62-15a9-4616-a192-11466fdd147f",
+ "parent_id": "qdhcp-eb276a62-15a9-4616-a192-11466fdd147f-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.3.2",
+ "IPv6 Address": "fe80::f816:3eff:fe1c:9936/64",
+ "cidr": "172.16.3.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:1c:99:36\ninet addr:172.16.3.2 Bcast:172.16.3.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fe1c:9936/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:170894 errors:0 dropped:41 overruns:0 frame:0\nTX packets:170588 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:31784458 (31.7 MB) TX bytes:36444046 (36.4 MB)\n",
+ "host": "node-6.cisco.com",
+ "id": "tap5f22f397-d8",
+ "mac_address": "fa:16:3e:1c:99:36",
+ "master_parent_id": "qdhcp-7e59b726-d6f4-451a-a574-c67a920ff627",
+ "master_parent_type": "vservice",
+ "name": "tap5f22f397-d8",
+ "netmask": "255.255.255.0",
+ "network": "7e59b726-d6f4-451a-a574-c67a920ff627",
+ "parent_id": "qdhcp-7e59b726-d6f4-451a-a574-c67a920ff627-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.1.2",
+ "IPv6 Address": "fe80::f816:3eff:fe59:5fff/64",
+ "cidr": "172.16.1.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:59:5f:ff\ninet addr:172.16.1.2 Bcast:172.16.1.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fe59:5fff/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:93468 errors:0 dropped:38 overruns:0 frame:0\nTX packets:93452 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:17416578 (17.4 MB) TX bytes:19972565 (19.9 MB)\n",
+ "host": "node-6.cisco.com",
+ "id": "tapbf16c3ab-56",
+ "mac_address": "fa:16:3e:59:5f:ff",
+ "master_parent_id": "qdhcp-a55ff1e8-3821-4e5f-bcfd-07df93720a4f",
+ "master_parent_type": "vservice",
+ "name": "tapbf16c3ab-56",
+ "netmask": "255.255.255.0",
+ "network": "a55ff1e8-3821-4e5f-bcfd-07df93720a4f",
+ "parent_id": "qdhcp-a55ff1e8-3821-4e5f-bcfd-07df93720a4f-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "192.168.111.2",
+ "IPv6 Address": "fe80::f816:3eff:fe74:5/64",
+ "cidr": "192.168.111.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:74:00:05\ninet addr:192.168.111.2 Bcast:192.168.111.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fe74:5/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:45 errors:0 dropped:28 overruns:0 frame:0\nTX packets:8 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:3734 (3.7 KB) TX bytes:648 (648.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "tapee8e5dbb-03",
+ "mac_address": "fa:16:3e:74:00:05",
+ "master_parent_id": "qdhcp-6504fcf7-41d7-40bb-aeb1-6a7658c105fc",
+ "master_parent_type": "vservice",
+ "name": "tapee8e5dbb-03",
+ "netmask": "255.255.255.0",
+ "network": "6504fcf7-41d7-40bb-aeb1-6a7658c105fc",
+ "parent_id": "qdhcp-6504fcf7-41d7-40bb-aeb1-6a7658c105fc-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.0.131",
+ "IPv6 Address": "2001:420:4482:24c1:f816:3eff:fe23:3ad7/64",
+ "cidr": "172.16.0.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:23:3a:d7\ninet addr:172.16.0.131 Bcast:172.16.0.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fe23:3ad7/64 Scope:Link\ninet6 addr: 2001:420:4482:24c1:f816:3eff:fe23:3ad7/64 Scope:Global\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:48172796 errors:0 dropped:1144801 overruns:0 frame:0\nTX packets:63 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:4220491940 (4.2 GB) TX bytes:3162 (3.1 KB)\n",
+ "host": "node-6.cisco.com",
+ "id": "qg-63489f34-af",
+ "mac_address": "fa:16:3e:23:3a:d7",
+ "master_parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9",
+ "master_parent_type": "vservice",
+ "name": "qg-63489f34-af",
+ "netmask": "255.255.255.0",
+ "network": "c64adb76-ad9d-4605-9f5e-bd6dbe325cfb",
+ "parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.13.5",
+ "IPv6 Address": "fe80::f816:3eff:fe1f:e174/64",
+ "cidr": "172.16.13.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:1f:e1:74\ninet addr:172.16.13.5 Bcast:172.16.13.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fe1f:e174/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:25 errors:0 dropped:1 overruns:0 frame:0\nTX packets:10 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:2460 (2.4 KB) TX bytes:864 (864.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "qr-18f029db-77",
+ "mac_address": "fa:16:3e:1f:e1:74",
+ "master_parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9",
+ "master_parent_type": "vservice",
+ "name": "qr-18f029db-77",
+ "netmask": "255.255.255.0",
+ "network": "8673c48a-f137-4497-b25d-08b7b218fd17",
+ "parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.2.1",
+ "IPv6 Address": "fe80::f816:3eff:fe2c:fb9b/64",
+ "cidr": "172.16.2.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:2c:fb:9b\ninet addr:172.16.2.1 Bcast:172.16.2.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fe2c:fb9b/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:49 errors:0 dropped:3 overruns:0 frame:0\nTX packets:10 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:5825 (5.8 KB) TX bytes:864 (864.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "qr-3ff411a2-54",
+ "mac_address": "fa:16:3e:2c:fb:9b",
+ "master_parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9",
+ "master_parent_type": "vservice",
+ "name": "qr-3ff411a2-54",
+ "netmask": "255.255.255.0",
+ "network": "eb276a62-15a9-4616-a192-11466fdd147f",
+ "parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.1.1",
+ "IPv6 Address": "fe80::f816:3eff:feee:9a46/64",
+ "cidr": "172.16.1.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:ee:9a:46\ninet addr:172.16.1.1 Bcast:172.16.1.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:feee:9a46/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:85 errors:0 dropped:14 overruns:0 frame:0\nTX packets:10 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:7402 (7.4 KB) TX bytes:864 (864.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "qr-8733cc5d-b3",
+ "mac_address": "fa:16:3e:ee:9a:46",
+ "master_parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9",
+ "master_parent_type": "vservice",
+ "name": "qr-8733cc5d-b3",
+ "netmask": "255.255.255.0",
+ "network": "a55ff1e8-3821-4e5f-bcfd-07df93720a4f",
+ "parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.3.1",
+ "IPv6 Address": "fe80::f816:3eff:feba:5a3c/64",
+ "cidr": "172.16.3.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:ba:5a:3c\ninet addr:172.16.3.1 Bcast:172.16.3.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:feba:5a3c/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:3018 errors:0 dropped:15 overruns:0 frame:0\nTX packets:1766 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:295458 (295.4 KB) TX bytes:182470 (182.4 KB)\n",
+ "host": "node-6.cisco.com",
+ "id": "qr-bb9b8340-72",
+ "mac_address": "fa:16:3e:ba:5a:3c",
+ "master_parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9",
+ "master_parent_type": "vservice",
+ "name": "qr-bb9b8340-72",
+ "netmask": "255.255.255.0",
+ "network": "7e59b726-d6f4-451a-a574-c67a920ff627",
+ "parent_id": "qrouter-9ec3d703-0725-47e3-8f48-02b16236caf9-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "172.16.0.130",
+ "IPv6 Address": "fe80::f816:3eff:fecb:8d7b/64",
+ "cidr": "172.16.0.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:cb:8d:7b\ninet addr:172.16.0.130 Bcast:172.16.0.255 Mask:255.255.255.0\ninet6 addr: 2001:420:4482:24c1:f816:3eff:fecb:8d7b/64 Scope:Global\ninet6 addr: fe80::f816:3eff:fecb:8d7b/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:48172955 errors:0 dropped:1144729 overruns:0 frame:0\nTX packets:59 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:4220505032 (4.2 GB) TX bytes:2958 (2.9 KB)\n",
+ "host": "node-6.cisco.com",
+ "id": "qg-57e65d34-3d",
+ "mac_address": "fa:16:3e:cb:8d:7b",
+ "master_parent_id": "qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6",
+ "master_parent_type": "vservice",
+ "name": "qg-57e65d34-3d",
+ "netmask": "255.255.255.0",
+ "network": "c64adb76-ad9d-4605-9f5e-bd6dbe325cfb",
+ "parent_id": "qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ },
+ {
+ "IP Address": "192.168.111.1",
+ "IPv6 Address": "fe80::f816:3eff:fe0a:3cc/64",
+ "cidr": "192.168.111.0/24",
+ "data": "Link encap:Ethernet HWaddr fa:16:3e:0a:03:cc\ninet addr:192.168.111.1 Bcast:192.168.111.255 Mask:255.255.255.0\ninet6 addr: fe80::f816:3eff:fe0a:3cc/64 Scope:Link\nUP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1\nRX packets:79 errors:0 dropped:0 overruns:0 frame:0\nTX packets:10 errors:0 dropped:0 overruns:0 carrier:0\ncollisions:0 txqueuelen:0\nRX bytes:6475 (6.4 KB) TX bytes:864 (864.0 B)\n",
+ "host": "node-6.cisco.com",
+ "id": "qr-f7b44150-99",
+ "mac_address": "fa:16:3e:0a:03:cc",
+ "master_parent_id": "qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6",
+ "master_parent_type": "vservice",
+ "name": "qr-f7b44150-99",
+ "netmask": "255.255.255.0",
+ "network": "6504fcf7-41d7-40bb-aeb1-6a7658c105fc",
+ "parent_id": "qrouter-49ac7716-06da-49ed-b388-f8ba60e8a0e6-vnics",
+ "parent_text": "vNICs",
+ "parent_type": "vnics_folder",
+ "type": "vnic",
+ "vnic_type": "vservice_vnic"
+ }
+] \ No newline at end of file
diff --git a/app/test/fetch/config/__init__.py b/app/test/fetch/config/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/config/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/config/test_config.py b/app/test/fetch/config/test_config.py
new file mode 100644
index 0000000..176fd48
--- /dev/null
+++ b/app/test/fetch/config/test_config.py
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+# local config info for test.
+
+
+MONGODB_CONFIG = 'your-mongo-config-path-here'
+
+ENV_CONFIG = 'your-env-name-here'
+
+COLLECTION_CONFIG = 'your-inventory-collection-name-here'
diff --git a/app/test/fetch/db_fetch/__init__.py b/app/test/fetch/db_fetch/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/db_fetch/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/db_fetch/mock_cursor.py b/app/test/fetch/db_fetch/mock_cursor.py
new file mode 100644
index 0000000..71efd3b
--- /dev/null
+++ b/app/test/fetch/db_fetch/mock_cursor.py
@@ -0,0 +1,25 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+class MockCursor:
+
+ def __init__(self, result):
+ self.result = result
+ self.current = 0
+
+ def __next__(self):
+ if self.current < len(self.result):
+ next = self.result[self.current]
+ self.current += 1
+ return next
+ else:
+ raise StopIteration
+
+ def __iter__(self):
+ return self
diff --git a/app/test/fetch/db_fetch/test_data/__init__.py b/app/test/fetch/db_fetch/test_data/__init__.py
new file mode 100644
index 0000000..b0637e9
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/__init__.py
@@ -0,0 +1,9 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
diff --git a/app/test/fetch/db_fetch/test_data/db_access.py b/app/test/fetch/db_fetch/test_data/db_access.py
new file mode 100644
index 0000000..a4ad548
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_access.py
@@ -0,0 +1,40 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+DB_CONFIG = {
+ "host": "10.56.20.239",
+ "name": "mysql",
+ "password": "102QreDdiD5sKcvNf9qbHrmr",
+ "port": 3307.0,
+ "user": "root",
+ "schema": "nova"
+ }
+
+QUERY_WITHOUT_ID = """
+ SELECT id, name
+ FROM nova.aggregates
+ WHERE deleted = 0
+ """
+
+QUERY_WITH_ID = """
+ SELECT CONCAT('aggregate-', a.name, '-', host) AS id, host AS name
+ FROM nova.aggregate_hosts ah
+ JOIN nova.aggregates a ON a.id = ah.aggregate_id
+ WHERE ah.deleted = 0 AND aggregate_id = %s
+ """
+
+ID = "2"
+OBJECT_TYPE = "host aggregate"
+
+OBJECTS_LIST = [
+ {
+ "id": 1,
+ "name": "osdna-agg"
+ }
+]
diff --git a/app/test/fetch/db_fetch/test_data/db_fetch_aggregate_hosts.py b/app/test/fetch/db_fetch/test_data/db_fetch_aggregate_hosts.py
new file mode 100644
index 0000000..2f1313a
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_fetch_aggregate_hosts.py
@@ -0,0 +1,34 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from bson.objectid import ObjectId
+
+
+AGGREGATE = {
+ "id": "1",
+}
+
+HOSTS = [
+ {
+ "id": "aggregate-osdna-agg-node-5.cisco.com",
+ "name": "node-5.cisco.com"
+ }
+]
+
+HOST_IN_INVENTORY = {
+ "_id": "595ac4b6d7c037efdb8918a7"
+}
+
+HOSTS_RESULT = [
+ {
+ "id": "aggregate-osdna-agg-node-5.cisco.com",
+ "name": "node-5.cisco.com",
+ "ref_id": ObjectId(HOST_IN_INVENTORY["_id"])
+ }
+]
diff --git a/app/test/fetch/db_fetch/test_data/db_fetch_aggregates.py b/app/test/fetch/db_fetch/test_data/db_fetch_aggregates.py
new file mode 100644
index 0000000..65182fa
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_fetch_aggregates.py
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+REGION_ID = "RegionOne"
+
+OBJECTS_LIST = [
+ {
+ "id": 1,
+ "name": "calipso-agg"
+ }
+]
diff --git a/app/test/fetch/db_fetch/test_data/db_fetch_host_network_agents.py b/app/test/fetch/db_fetch/test_data/db_fetch_host_network_agents.py
new file mode 100644
index 0000000..6188ddf
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_fetch_host_network_agents.py
@@ -0,0 +1,65 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+CONFIG_WITH_MECHANISM_DRIVERS = {
+ 'mechanism_drivers': [
+ "OVS"
+ ]
+}
+
+CONFIG_WITHOUT_MECHANISM_DRIVERS = {
+ 'mechanism_drivers': [
+
+ ]
+}
+
+NETWORK_AGENT_FOLDER_ID = 'node-6.cisco.com-network_agents'
+
+NETWORK_AGENT = [
+ {
+ 'configurations': '{}',
+ 'id': '1764430c-c09e-4717-86fa-c04350b1fcbb',
+ 'binary': 'neutron-openvswitch-agent',
+ },
+ {
+ 'configurations': '{}',
+ 'id': '2c2ddfee-91f9-47da-bd65-aceecd998b7c',
+ 'binary': 'neutron-dhcp-agent',
+ }
+]
+
+NETWORK_AGENT_WITH_MECHANISM_DRIVERS_IN_CONFIG_RESULTS = [
+ {
+ 'configurations': {},
+ 'id': 'OVS-1764430c-c09e-4717-86fa-c04350b1fcbb',
+ 'binary': 'neutron-openvswitch-agent',
+ 'name': 'neutron-openvswitch-agent'
+ },
+ {
+ 'configurations': {},
+ 'id': 'OVS-2c2ddfee-91f9-47da-bd65-aceecd998b7c',
+ 'binary': 'neutron-dhcp-agent',
+ 'name': 'neutron-dhcp-agent'
+ }
+]
+
+NETWORK_AGENT_WITHOUT_MECHANISM_DRIVERS_IN_CONFIG_RESULTS = [
+ {
+ 'configurations': {},
+ 'id': 'network_agent-1764430c-c09e-4717-86fa-c04350b1fcbb',
+ 'binary': 'neutron-openvswitch-agent',
+ 'name': 'neutron-openvswitch-agent'
+ },
+ {
+ 'configurations': {},
+ 'id': 'network_agent-2c2ddfee-91f9-47da-bd65-aceecd998b7c',
+ 'binary': 'neutron-dhcp-agent',
+ 'name': 'neutron-dhcp-agent'
+ }
+]
diff --git a/app/test/fetch/db_fetch/test_data/db_fetch_instances.py b/app/test/fetch/db_fetch/test_data/db_fetch_instances.py
new file mode 100644
index 0000000..5ba6a74
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_fetch_instances.py
@@ -0,0 +1,91 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+INSTANCES_FROM_API = [
+ {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ }
+]
+
+INSTANCES_FROM_DB = [
+ {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ "network_info": "[{\"network\": {\"id\": \"7e59b726-d6f4-451a-a574-c67a920ff627\"}}]",
+ "project": "Calipso-project",
+ },
+ {
+ "host": "node-5.cisco.com",
+ "id": "bf0cb914-b316-486c-a4ce-f22deb453c52",
+ "network_info": "[{\"network\": {\"id\": \"7e59b726-d6f4-451a-a574-c67a920ff627\"}}]",
+ "project": "Calipso-project",
+ }
+]
+
+UPDATED_INSTANCES_DATA = [
+ {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ "network": ["7e59b726-d6f4-451a-a574-c67a920ff627"],
+ "type": "instance",
+ "parent_type": "instances_folder",
+ "parent_id": "node-5.cisco.com-instances",
+ "in_project-Calipso-project": "1",
+ "network_info": [
+ {
+ "network": {
+ "id": "7e59b726-d6f4-451a-a574-c67a920ff627"
+ }
+ }
+ ]
+ }
+]
+
+INSTANCE_WITH_NETWORK = {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ "network_info": "[{\"network\": {\"id\": \"7e59b726-d6f4-451a-a574-c67a920ff627\"}}]",
+ "project": "Calipso-project",
+}
+
+INSTANCE_WITH_NETWORK_RESULT = {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ "network": ["7e59b726-d6f4-451a-a574-c67a920ff627"],
+ "type": "instance",
+ "parent_type": "instances_folder",
+ "parent_id": "node-5.cisco.com-instances",
+ "in_project-Calipso-project": "1",
+ "network_info": [
+ {
+ "network": {
+ "id": "7e59b726-d6f4-451a-a574-c67a920ff627"
+ }
+ }
+ ]
+}
+
+INSTANCE_WITHOUT_NETWORK = {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ "network_info": "[]",
+ "project": "Calipso-project",
+}
+
+INSTANCE_WITHOUT_NETWORK_RESULT = {
+ "host": "node-5.cisco.com",
+ "id": "6f29c867-9150-4533-8e19-70d749b172fa",
+ "network": [],
+ "type": "instance",
+ "parent_type": "instances_folder",
+ "parent_id": "node-5.cisco.com-instances",
+ "in_project-Calipso-project": "1",
+ "network_info": []
+}
diff --git a/app/test/fetch/db_fetch/test_data/db_fetch_oteps.py b/app/test/fetch/db_fetch/test_data/db_fetch_oteps.py
new file mode 100644
index 0000000..a5bc63d
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_fetch_oteps.py
@@ -0,0 +1,131 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+VEDGE_ID = "3858e121-d861-4348-9d64-a55fcd5bf60a"
+VEDGE = {
+ "configurations": {
+ "tunnel_types": [
+ "vxlan"
+ ],
+ "tunneling_ip": "192.168.2.1"
+ },
+ "host": "node-5.cisco.com",
+ "id": "3858e121-d861-4348-9d64-a55fcd5bf60a",
+ "tunnel_ports": {
+ "vxlan-c0a80203": {
+ },
+ "br-tun": {
+ }
+ },
+ "type": "vedge"
+}
+VEDGE_WITHOUT_CONFIGS ={
+
+}
+VEDGE_WITHOUT_TUNNEL_TYPES = {
+ "configuration": {
+ "tunnel_types": ""
+ }
+}
+NON_ICEHOUSE_CONFIGS = {
+ "distribution": "Mirantis-8.0"
+}
+ICEHOUSE_CONFIGS = {
+ "distribution": "Canonical-icehouse"
+}
+HOST = {
+ "host": "node-5.cisco.com",
+ "id": "node-5.cisco.com",
+ "ip_address": "192.168.0.4",
+ "name": "node-5.cisco.com"
+}
+OTEPS_WITHOUT_CONFIGURATIONS_IN_VEDGE_RESULTS = []
+OTEPS_WITHOUT_TUNNEL_TYPES_IN_VEDGE_RESULTS = []
+OTEPS_FOR_NON_ICEHOUSE_DISTRIBUTION_RESULTS = [
+ {
+ "host": "node-5.cisco.com",
+ "ip_address": "192.168.2.1",
+ "udp_port": 4789,
+ "id": "node-5.cisco.com-otep",
+ "name": "node-5.cisco.com-otep",
+ "overlay_type": "vxlan",
+ "ports": {
+ "vxlan-c0a80203": {
+ },
+ "br-tun": {
+ }
+ }
+ }
+]
+OTEPS_FOR_ICEHOUSE_DISTRIBUTION_RESULTS = [
+ {
+ "host": "node-5.cisco.com",
+ "ip_address": "192.168.0.4",
+ "id": "node-5.cisco.com-otep",
+ "name": "node-5.cisco.com-otep",
+ "overlay_type": "vxlan",
+ "ports": {
+ "vxlan-c0a80203": {
+ },
+ "br-tun": {
+ }
+ },
+ "udp_port": "67"
+ }
+]
+
+OTEPS = [
+ {
+ "host": "node-5.cisco.com",
+ "ip_address": "192.168.2.1",
+ "udp_port": 4789
+ }
+]
+
+OTEP_FOR_GETTING_VECONNECTOR = {
+ "host": "node-5.cisco.com",
+ "ip_address": "192.168.2.1",
+ "udp_port": 4789,
+ "id": "node-5.cisco.com-otep",
+ "name": "node-5.cisco.com-otep",
+ "overlay_type": "vxlan",
+ "ports": {
+ "vxlan-c0a80203": {
+ },
+ "br-tun": {
+ }
+ }
+}
+HOST_ID = "node-5.cisco.com"
+IFCONFIG_LINES = [
+ "br-mesh Link encap:Ethernet HWaddr 00:50:56:ac:28:9d ",
+ " inet addr:192.168.2.1 Bcast:192.168.2.255 Mask:255.255.255.0",
+ " inet6 addr: fe80::d4e1:8fff:fe33:ed6a/64 Scope:Link",
+ " UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1",
+ " RX packets:2273307 errors:0 dropped:0 overruns:0 frame:0",
+ " TX packets:2255930 errors:0 dropped:0 overruns:0 carrier:0",
+ " collisions:0 txqueuelen:0 ",
+ " RX bytes:578536155 (578.5 MB) TX bytes:598541522 (598.5 MB)",
+ ""
+]
+OTEP_WITH_CONNECTOR = {
+ "host": "node-5.cisco.com",
+ "ip_address": "192.168.2.1",
+ "udp_port": 4789,
+ "id": "node-5.cisco.com-otep",
+ "name": "node-5.cisco.com-otep",
+ "overlay_type": "vxlan",
+ "ports": {
+ "vxlan-c0a80203": {
+ },
+ "br-tun": {
+ }
+ },
+ "vconnector": "br-mesh"
+}
diff --git a/app/test/fetch/db_fetch/test_data/db_fetch_vedges_ovs.py b/app/test/fetch/db_fetch/test_data/db_fetch_vedges_ovs.py
new file mode 100644
index 0000000..818704c
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_fetch_vedges_ovs.py
@@ -0,0 +1,168 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+VEDGES_FOLDER_ID = "node-6.cisco.com-vedges"
+
+OBJECTS_FROM_DB = [
+ {
+ "host": "node-6.cisco.com",
+ "agent_type": "Open vSwitch agent",
+ "configurations": '{"tunneling_ip": "192.168.2.3"}',
+ }
+]
+
+HOST = {
+ "host": "node-6.cisco.com",
+ "host_type": [
+ "Controller",
+ "Network"
+ ],
+ "id": "node-6.cisco.com",
+ "name": "node-6.cisco.com"
+}
+
+HOST_WITHOUT_REQUIRED_HOST_TYPES = {
+ "id": "node-6.cisco.com",
+ "host_type": []
+}
+
+PORTS = {
+ "ovs-system": {
+ "name": "ovs-system",
+ "id": "0",
+ "internal": True
+ },
+ "qr-bb9b8340-72": {
+ "name": "qr-bb9b8340-72",
+ "id": "1",
+ "internal": True,
+ "tag": "3"
+ },
+ "qr-8733cc5d-b3": {
+ "name": "qr-8733cc5d-b3",
+ "id": "2",
+ "internal": True,
+ "tag": "4"
+ }
+}
+
+TUNNEL_PORTS = {
+ "patch-int": {
+ "interface": "patch-int",
+ "name": "patch-int",
+ "options": {
+ "peer": "patch-tun"
+ },
+ "type": "patch"
+ }
+}
+
+GET_RESULTS = [
+ {
+ 'name': 'node-6.cisco.com-OVS',
+ 'host': 'node-6.cisco.com',
+ 'agent_type': 'Open vSwitch agent',
+ 'configurations': {"tunneling_ip": "192.168.2.3"},
+ 'ports': PORTS,
+ 'tunnel_ports': TUNNEL_PORTS
+ }
+]
+
+
+VSCTL_LINES = [
+ "3b12f08e-4e13-4976-8da5-23314b268805",
+ " Bridge br-int",
+ " fail_mode: secure",
+ " Port \"qr-bb9b8340-72\"",
+ " tag: 3",
+ " Interface \"qr-bb9b8340-72\"",
+ " type: internal",
+ " Port \"qr-8733cc5d-b3\"",
+ " tag: 4",
+ " Interface \"qr-8733cc5d-b3\"",
+ " type: internal",
+ " Bridge br-tun",
+ " fail_mode: secure",
+ " Port patch-int",
+ " Interface patch-int",
+ " type: patch",
+ " options: {peer=patch-tun}",
+]
+
+DPCTL_LINES = [
+ "system@ovs-system:",
+ "\tlookups: hit:14039304 missed:35687906 lost:0",
+ "\tflows: 4",
+ "\tmasks: hit:95173613 total:2 hit/pkt:1.91",
+ "\tport 0: ovs-system (internal)",
+ "\tport 1: qr-bb9b8340-72 (internal)",
+ "\tport 2: qr-8733cc5d-b3 (internal)"
+]
+
+DPCTL_RESULTS = {
+ "ovs-system": {
+ "name": "ovs-system",
+ "id": "0",
+ "internal": True
+ },
+ "qr-bb9b8340-72": {
+ "name": "qr-bb9b8340-72",
+ "id": "1",
+ "internal": True
+ },
+ "qr-8733cc5d-b3": {
+ "name": "qr-8733cc5d-b3",
+ "id": "2",
+ "internal": True
+ }
+}
+
+FETCH__PORT_TAGS_INPUT = {
+ "ovs-system": {
+ "name": "ovs-system",
+ "id": "0",
+ "internal": True
+ },
+ "qr-bb9b8340-72": {
+ "name": "qr-bb9b8340-72",
+ "id": "1",
+ "internal": True
+ },
+ "qr-8733cc5d-b3": {
+ "name": "qr-8733cc5d-b3",
+ "id": "2",
+ "internal": True
+ }
+}
+
+FETCH_PORT_TAGS_RESULT = {
+ "ovs-system": {
+ "name": "ovs-system",
+ "id": "0",
+ "internal": True
+ },
+ "qr-bb9b8340-72": {
+ "name": "qr-bb9b8340-72",
+ "id": "1",
+ "internal": True,
+ "tag": "3"
+ },
+ "qr-8733cc5d-b3": {
+ "name": "qr-8733cc5d-b3",
+ "id": "2",
+ "internal": True,
+ "tag": "4"
+ }
+}
+
+DOC_TO_GET_OVERLAY = {
+ "host": "node-6.cisco.com",
+ "agent_type": "Open vSwitch agent",
+ "configurations": {"tunneling_ip": "192.168.2.3"},
+}
diff --git a/app/test/fetch/db_fetch/test_data/db_fetch_vedges_vpp.py b/app/test/fetch/db_fetch/test_data/db_fetch_vedges_vpp.py
new file mode 100644
index 0000000..24265ae
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_data/db_fetch_vedges_vpp.py
@@ -0,0 +1,89 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+VEDGE_FOLDER_ID = "ubuntu0-vedges"
+
+HOST = {
+ "host_type": [
+ "Controller",
+ "Compute",
+ "Network"
+ ],
+ "id": "ubuntu0",
+}
+
+HOST_WITHOUT_REQUIRED_HOST_TYPE = {
+ "host_type": [
+
+ ]
+}
+
+VERSION = [
+ "vpp v16.09-rc0~157-g203c632 built by localadmin on ubuntu0 at Sun Jun 26 16:35:15 PDT 2016\n"
+]
+
+INTERFACES = [
+ " Name Idx State Counter Count ",
+ "TenGigabitEthernetc/0/0 5 up rx packets 502022",
+ " rx bytes 663436206",
+ " tx packets 81404",
+ " tx bytes 6366378",
+ " drops 1414",
+ " punts 1",
+ " rx-miss 64525",
+ "VirtualEthernet0/0/0 7 up tx packets 31496",
+ " tx bytes 2743185",
+ "local0 0 down ",
+ "pg/stream-0 1 down ",
+]
+
+PORTS = {
+ "TenGigabitEthernetc/0/0": {
+ "id": "5",
+ "name": "TenGigabitEthernetc/0/0",
+ "state": "up"
+ },
+ "VirtualEthernet0/0/0": {
+ "id": "7",
+ "name": "VirtualEthernet0/0/0",
+ "state": "up"
+ },
+ "local0": {
+ "id": "0",
+ "name": "local0",
+ "state": "down"
+ },
+ "pg/stream-0": {
+ "id": "1",
+ "name": "pg/stream-0",
+ "state": "down"
+ }
+}
+
+
+VEDGE_RESULTS = [
+ {
+ "host": "ubuntu0",
+ "id": "ubuntu0-VPP",
+ "name": "VPP-ubuntu0",
+ "agent_type": "VPP",
+ "binary": "vpp v16.09-rc0~157-g203c632",
+ "ports": PORTS
+ }
+]
+
+VEDGE_RESULTS_WITHOUT_BINARY = [
+ {
+ "host": "ubuntu0",
+ "id": "ubuntu0-VPP",
+ "name": "VPP-ubuntu0",
+ "agent_type": "VPP",
+ "ports": PORTS
+ }
+]
diff --git a/app/test/fetch/db_fetch/test_db_access.py b/app/test/fetch/db_fetch/test_db_access.py
new file mode 100644
index 0000000..4ef3e74
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_db_access.py
@@ -0,0 +1,108 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.db.db_access import DbAccess
+from test.fetch.test_fetch import TestFetch
+from test.fetch.db_fetch.test_data.db_access import *
+from unittest.mock import MagicMock, patch
+from test.fetch.db_fetch.mock_cursor import MockCursor
+
+
+class TestDbAccess(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbAccess()
+
+ @patch("mysql.connector.connect")
+ def test_db_connect(self, db_connect):
+ DbAccess.conn = None
+ db_conn = MagicMock()
+ db_conn.ping = MagicMock()
+ db_connect.return_value = db_conn
+
+ self.fetcher.db_connect(DB_CONFIG['host'], DB_CONFIG['port'],
+ DB_CONFIG['user'], DB_CONFIG['password'],
+ DB_CONFIG['schema'])
+
+ self.assertEqual(True, db_connect.called, "connect method has't been called")
+ db_conn.ping.assert_called_once_with(True)
+
+ def test_connect_to_db(self):
+ DbAccess.conn = None
+ self.fetcher.db_connect = MagicMock()
+ self.fetcher.connect_to_db()
+
+ self.assertEqual(True, self.fetcher.db_connect.called)
+
+ def test_connect_to_db_with_force(self):
+ DbAccess.conn = MagicMock()
+ self.fetcher.db_connect = MagicMock()
+ self.fetcher.connect_to_db(force=True)
+
+ self.assertEqual(True, self.fetcher.db_connect.called)
+
+ def test_connect_to_db_without_force(self):
+ DbAccess.conn = MagicMock()
+ self.fetcher.db_connect = MagicMock()
+ self.fetcher.connect_to_db()
+
+ self.assertEqual(False, self.fetcher.db_connect.called)
+
+ def test_get_objects_list_for_id_with_id(self):
+ # mock the db cursor
+ mock_cursor = MockCursor(OBJECTS_LIST)
+ mock_cursor.execute = MagicMock()
+
+ self.fetcher.connect_to_db = MagicMock()
+ DbAccess.conn.cursor = MagicMock(return_value=mock_cursor)
+
+ result = self.fetcher.get_objects_list_for_id(QUERY_WITH_ID, OBJECT_TYPE, ID)
+
+ mock_cursor.execute.assert_called_once_with(QUERY_WITH_ID, [ID])
+ self.assertEqual(result, OBJECTS_LIST, "Can't get objects list")
+
+ def test_get_objects_list_for_id_without_id(self):
+ mock_cursor = MockCursor(OBJECTS_LIST)
+
+ self.fetcher.connect_to_db = MagicMock()
+ DbAccess.conn.cursor = MagicMock(return_value=mock_cursor)
+ mock_cursor.execute = MagicMock()
+
+ result = self.fetcher.get_objects_list_for_id(QUERY_WITHOUT_ID, OBJECT_TYPE, None)
+
+ mock_cursor.execute.assert_called_once_with(QUERY_WITHOUT_ID)
+ self.assertEqual(result, OBJECTS_LIST, "Can't get objects list")
+
+ def test_get_objects_list_for_id_with_id_with_exception(self):
+ mock_cursor = MockCursor(OBJECTS_LIST)
+ self.fetcher.connect_to_db = MagicMock()
+ # mock exception
+ DbAccess.conn.cursor = MagicMock(return_value=mock_cursor)
+ mock_cursor.execute = MagicMock(side_effect=[AttributeError, ""])
+
+ result = self.fetcher.get_objects_list_for_id(QUERY_WITH_ID, OBJECT_TYPE, ID)
+
+ self.assertEqual(mock_cursor.execute.call_count, 2, "Can't invoke execute method " +
+ "twice when error occurs")
+ self.assertEqual(result, OBJECTS_LIST, "Can't get objects list")
+
+ def test_get_objects_list_for_id_without_id_with_exception(self):
+ mock_cursor = MockCursor(OBJECTS_LIST)
+ self.fetcher.connect_to_db = MagicMock()
+ DbAccess.conn.cursor = MagicMock(return_value=mock_cursor)
+ mock_cursor.execute = MagicMock(side_effect=[AttributeError, ""])
+
+ result = self.fetcher.get_objects_list_for_id(QUERY_WITHOUT_ID,
+ OBJECT_TYPE,
+ None)
+
+ self.assertEqual(mock_cursor.execute.call_count, 2, "Can't invoke execute method " +
+ "twice when error occurs")
+ self.assertEqual(result, OBJECTS_LIST, "Can't get objects list")
diff --git a/app/test/fetch/db_fetch/test_db_fetch_aggregate_hosts.py b/app/test/fetch/db_fetch/test_db_fetch_aggregate_hosts.py
new file mode 100644
index 0000000..2066577
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_db_fetch_aggregate_hosts.py
@@ -0,0 +1,60 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.db.db_fetch_aggregate_hosts import DbFetchAggregateHosts
+from test.fetch.test_fetch import TestFetch
+from test.fetch.db_fetch.test_data.db_fetch_aggregate_hosts import *
+from unittest.mock import MagicMock
+
+
+class TestDbFetchAggregateHosts(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbFetchAggregateHosts()
+
+ def check_get_results_is_correct(self,
+ objects_list,
+ host_in_inventory,
+ expected_result,
+ err_msg):
+ self.fetcher.get_objects_list_for_id = MagicMock(return_value=objects_list)
+ self.inv.get_by_id = MagicMock(return_value=host_in_inventory)
+ result = self.fetcher.get(AGGREGATE["id"])
+
+ self.assertEqual(result, expected_result, err_msg)
+
+ def test_get(self):
+ test_cases = [
+ {
+ "objects_list": HOSTS,
+ "host_in_inventory": HOST_IN_INVENTORY,
+ "expected_result": HOSTS_RESULT,
+ "err_msg": "Can't get correct hosts info"
+ },
+ {
+ "objects_list": [],
+ "host_in_inventory": None,
+ "expected_result": [],
+ "err_msg": "Can't get [] when the "
+ "returned objects list is empty"
+ },
+ {
+ "objects_list": HOSTS,
+ "host_in_inventory": [],
+ "expected_result": HOSTS,
+ "err_msg": "Can't get correct hosts info "
+ "when the host doesn't exist in the inventory"
+ }
+ ]
+ for test_case in test_cases:
+ self.check_get_results_is_correct(test_case["objects_list"],
+ test_case["host_in_inventory"],
+ test_case["expected_result"],
+ test_case["err_msg"])
diff --git a/app/test/fetch/db_fetch/test_db_fetch_aggregates.py b/app/test/fetch/db_fetch/test_db_fetch_aggregates.py
new file mode 100644
index 0000000..12693b7
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_db_fetch_aggregates.py
@@ -0,0 +1,26 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.db.db_fetch_aggregates import DbFetchAggregates
+from test.fetch.test_fetch import TestFetch
+from test.fetch.db_fetch.test_data.db_fetch_aggregates import *
+from unittest.mock import MagicMock
+
+
+class TestDbFetchAggregates(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbFetchAggregates()
+
+ def test_get(self):
+ self.fetcher.get_objects_list = MagicMock(return_value=OBJECTS_LIST)
+ result = self.fetcher.get(REGION_ID)
+ self.assertEqual(result, OBJECTS_LIST, "Can't get correct " +
+ "aggregates info")
diff --git a/app/test/fetch/db_fetch/test_db_fetch_instances.py b/app/test/fetch/db_fetch/test_db_fetch_instances.py
new file mode 100644
index 0000000..a1207a1
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_db_fetch_instances.py
@@ -0,0 +1,37 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.db.db_fetch_instances import DbFetchInstances
+from test.fetch.test_fetch import TestFetch
+from unittest.mock import MagicMock
+from test.fetch.db_fetch.test_data.db_fetch_instances import *
+
+
+class TestDbFetchInstances(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbFetchInstances()
+
+ def test_get(self):
+ self.fetcher.get_objects_list = MagicMock(return_value=
+ INSTANCES_FROM_DB)
+ self.fetcher.get_instance_data(INSTANCES_FROM_API)
+
+ self.assertEqual(INSTANCES_FROM_API, UPDATED_INSTANCES_DATA)
+
+ def test_build_instance_details_with_network(self):
+ self.fetcher.build_instance_details(INSTANCE_WITH_NETWORK)
+ self.assertEqual(INSTANCE_WITH_NETWORK,
+ INSTANCE_WITH_NETWORK_RESULT)
+
+ def test_build_instance_details_without_network(self):
+ self.fetcher.build_instance_details(INSTANCE_WITHOUT_NETWORK)
+ self.assertEqual(INSTANCE_WITHOUT_NETWORK,
+ INSTANCE_WITHOUT_NETWORK_RESULT)
diff --git a/app/test/fetch/db_fetch/test_db_fetch_oteps.py b/app/test/fetch/db_fetch/test_db_fetch_oteps.py
new file mode 100644
index 0000000..905f55a
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_db_fetch_oteps.py
@@ -0,0 +1,92 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+import copy
+
+from discover.fetchers.db.db_fetch_oteps import DbFetchOteps
+from test.fetch.test_fetch import TestFetch
+from test.fetch.db_fetch.test_data.db_fetch_oteps import *
+from unittest.mock import MagicMock
+
+
+class TestDbFetchOteps(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbFetchOteps()
+ self.fetcher.set_env(self.env)
+
+ def check_get_oteps_results(self, vedge,
+ config,
+ host,
+ oteps_from_db,
+ expected_results,
+ err_msg):
+ original_get_vconnector = self.fetcher.get_vconnector
+ self.fetcher.get_vconnector = MagicMock()
+ self.fetcher.inv.get_by_id = MagicMock(side_effect=[vedge, host])
+ self.fetcher.config.get_env_config = MagicMock(return_value=config)
+ self.fetcher.get_objects_list_for_id = MagicMock(return_value=oteps_from_db)
+ results = self.fetcher.get(VEDGE_ID)
+ self.assertEqual(results, expected_results, err_msg)
+ self.fetcher.get_vconnector = original_get_vconnector
+
+ def test_get(self):
+ test_cases = [
+ {
+ "vedge": VEDGE_WITHOUT_CONFIGS,
+ "config": NON_ICEHOUSE_CONFIGS,
+ "host": None,
+ "oteps_from_db": None,
+ "expected_results": [],
+ "err_msg": "Can't get [] when the vedge " +
+ "doesn't contains configurations"
+ },
+ {
+ "vedge": VEDGE_WITHOUT_TUNNEL_TYPES,
+ "config": NON_ICEHOUSE_CONFIGS,
+ "host": None,
+ "oteps_from_db": None,
+ "expected_results": [],
+ "err_msg": "Can't get [] when the vedge configurations " +
+ "doesn't contain tunnel_types"
+ },
+ {
+ "vedge": VEDGE,
+ "config": ICEHOUSE_CONFIGS,
+ "host": HOST,
+ "oteps_from_db": None,
+ "expected_results": OTEPS_FOR_ICEHOUSE_DISTRIBUTION_RESULTS,
+ "err_msg": "Can't get correct oteps result " +
+ "when the distribution is icehouse"
+ },
+ {
+ "vedge": VEDGE,
+ "config": NON_ICEHOUSE_CONFIGS,
+ "host": None,
+ "oteps_from_db": OTEPS,
+ "expected_results": OTEPS_FOR_NON_ICEHOUSE_DISTRIBUTION_RESULTS,
+ "err_msg": "Can't get correct oteps result " +
+ "when the distribution is not icehouse"
+ }
+ ]
+ for test_case in test_cases:
+ self.check_get_oteps_results(test_case["vedge"],
+ test_case["config"],
+ test_case["host"],
+ test_case["oteps_from_db"],
+ test_case["expected_results"],
+ test_case["err_msg"])
+
+ def test_get_vconnectors(self):
+ self.fetcher.run_fetch_lines = MagicMock(return_value=IFCONFIG_LINES)
+ self.fetcher.get_vconnector(OTEP_FOR_GETTING_VECONNECTOR,
+ HOST_ID, VEDGE)
+ self.assertEqual(OTEP_FOR_GETTING_VECONNECTOR, OTEP_WITH_CONNECTOR,
+ "Can't get vconnector from the config lines for otep")
diff --git a/app/test/fetch/db_fetch/test_db_fetch_vedges_ovs.py b/app/test/fetch/db_fetch/test_db_fetch_vedges_ovs.py
new file mode 100644
index 0000000..b08aebd
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_db_fetch_vedges_ovs.py
@@ -0,0 +1,109 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.db.db_fetch_vedges_ovs import DbFetchVedgesOvs
+from test.fetch.test_fetch import TestFetch
+from test.fetch.db_fetch.test_data.db_fetch_vedges_ovs import *
+from unittest.mock import MagicMock
+
+
+class TestDbFetchVedgesOvs(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbFetchVedgesOvs()
+ self.fetcher.set_env(self.env)
+
+ def check_get_result(self,
+ objects_from_db, host,
+ vsctl_lines, ports, tunnel_ports,
+ expected_result, err_msg):
+ # store original methods
+ original_get_objects_list_by_id = self.fetcher.get_objects_list_for_id
+ original_get_by_id = self.fetcher.inv.get_by_id
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_fetch_ports = self.fetcher.fetch_ports
+ original_get_overlay_tunnels = self.fetcher.get_overlay_tunnels
+
+ self.fetcher.get_objects_list_for_id = MagicMock(return_value=objects_from_db)
+ self.fetcher.inv.get_by_id = MagicMock(return_value=host)
+ self.fetcher.run_fetch_lines = MagicMock(return_value=vsctl_lines)
+ self.fetcher.fetch_ports = MagicMock(return_value=ports)
+ self.fetcher.get_overlay_tunnels = MagicMock(return_value=tunnel_ports)
+
+ results = self.fetcher.get(VEDGES_FOLDER_ID)
+ self.assertEqual(results, expected_result, err_msg)
+
+ # restore methods
+ self.fetcher.get_objects_list_for_id = original_get_objects_list_by_id
+ self.fetcher.inv.get_by_id = original_get_by_id
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.fetch_ports = original_fetch_ports
+ self.fetcher.get_overlay_tunnels = original_get_overlay_tunnels
+
+ def test_get(self):
+ test_cases = [
+ {
+ "objects_from_db": OBJECTS_FROM_DB,
+ "host": HOST,
+ "vsctl_lines": "",
+ "ports": PORTS,
+ "tunnel_ports": TUNNEL_PORTS,
+ "expected_result": GET_RESULTS,
+ "err_msg": "Can't get correct vedges"
+ },
+ {
+ "objects_from_db": OBJECTS_FROM_DB,
+ "host": [],
+ "vsctl_lines": "",
+ "ports": {},
+ "tunnel_ports": [],
+ "expected_result": [],
+ "err_msg": "Can't get [] when the host " +
+ "doesn't exist"
+ },
+ {
+ "objects_from_db": OBJECTS_FROM_DB,
+ "host": HOST_WITHOUT_REQUIRED_HOST_TYPES,
+ "vsctl_lines": "",
+ "ports": {},
+ "tunnel_ports": [],
+ "expected_result": [],
+ "err_msg": "Can't get [] when the host " +
+ "doesn't have required host types"
+ }
+ ]
+ for test_case in test_cases:
+ self.check_get_result(test_case["objects_from_db"],
+ test_case["host"],
+ test_case["vsctl_lines"],
+ test_case["ports"],
+ test_case["tunnel_ports"],
+ test_case["expected_result"],
+ test_case["err_msg"])
+
+ def test_fetch_ports_from_dpctl(self):
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ self.fetcher.run_fetch_lines = MagicMock(return_value=DPCTL_LINES)
+
+ results = self.fetcher.fetch_ports_from_dpctl(HOST['id'])
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.assertEqual(results, DPCTL_RESULTS,
+ "Can' t get correct ports info from dpctl lines")
+
+ def test_fetch_port_tags_from_vsctl(self):
+ ports = self.fetcher.fetch_port_tags_from_vsctl(VSCTL_LINES,
+ FETCH__PORT_TAGS_INPUT)
+ self.assertEqual(ports, FETCH_PORT_TAGS_RESULT,
+ "Can't fetch tag from vsctl")
+
+ def test_get_overlay_tunnels(self):
+ results = self.fetcher.get_overlay_tunnels(DOC_TO_GET_OVERLAY,
+ VSCTL_LINES)
+ self.assertEqual(results, TUNNEL_PORTS)
diff --git a/app/test/fetch/db_fetch/test_db_fetch_vedges_vpp.py b/app/test/fetch/db_fetch/test_db_fetch_vedges_vpp.py
new file mode 100644
index 0000000..9e6f497
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_db_fetch_vedges_vpp.py
@@ -0,0 +1,82 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+from discover.fetchers.db.db_fetch_vedges_vpp import DbFetchVedgesVpp
+from test.fetch.test_fetch import TestFetch
+from test.fetch.db_fetch.test_data.db_fetch_vedges_vpp import *
+from unittest.mock import MagicMock
+
+
+class TestDbFetchVedgesVpp(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbFetchVedgesVpp()
+ self.fetcher.set_env(self.env)
+
+ def check_get_results(self, version,
+ interfaces, host,
+ expected_results, err_msg):
+ original_run_fetch_lines = self.fetcher.run_fetch_lines
+ original_get_by_id = self.fetcher.inv.get_by_id
+
+ self.fetcher.run_fetch_lines = MagicMock(side_effect=[version, interfaces])
+ self.fetcher.inv.get_by_id = MagicMock(return_value=host)
+
+ vedges = self.fetcher.get(VEDGE_FOLDER_ID)
+ self.assertEqual(vedges, expected_results, err_msg)
+
+ self.fetcher.run_fetch_lines = original_run_fetch_lines
+ self.fetcher.inv.get_by_id = original_get_by_id
+
+ def test_get(self):
+ test_cases = [
+ {
+ "version": VERSION,
+ "interfaces": INTERFACES,
+ "host": HOST,
+ "expected_results": VEDGE_RESULTS,
+ "err_msg": "Can' get correct vedges"
+ },
+ {
+ "version": [],
+ "interfaces": INTERFACES,
+ "host": HOST,
+ "expected_results": VEDGE_RESULTS_WITHOUT_BINARY,
+ "err_msg": "Can' get correct vedges when " +
+ "it can't get version info host"
+ },
+ {
+ "version": VERSION,
+ "interfaces": INTERFACES,
+ "host": [],
+ "expected_results": [],
+ "err_msg": "Can't get [] when the host of the " +
+ "vedge doesn't exist in db"
+ },
+ {
+ "version": VERSION,
+ "interfaces": INTERFACES,
+ "host": HOST_WITHOUT_REQUIRED_HOST_TYPE,
+ "expected_results": [],
+ "err_msg": "Can't get [] when the host of the " +
+ "vedge doesn't contains required host types"
+ }
+ ]
+
+ for test_case in test_cases:
+ self.check_get_results(test_case["version"],
+ test_case["interfaces"],
+ test_case["host"],
+ test_case["expected_results"],
+ test_case["err_msg"])
+
+ def test_fetch_ports(self):
+ ports = self.fetcher.fetch_ports(INTERFACES)
+ self.assertEqual(ports, PORTS, "Can't get the correct ports info") \ No newline at end of file
diff --git a/app/test/fetch/db_fetch/test_fetch_host_network_agents.py b/app/test/fetch/db_fetch/test_fetch_host_network_agents.py
new file mode 100644
index 0000000..fd68a56
--- /dev/null
+++ b/app/test/fetch/db_fetch/test_fetch_host_network_agents.py
@@ -0,0 +1,66 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+import copy
+
+from discover.fetchers.db.db_fetch_host_network_agents import DbFetchHostNetworkAgents
+from test.fetch.test_fetch import TestFetch
+from test.fetch.db_fetch.test_data.db_fetch_host_network_agents import *
+from unittest.mock import MagicMock
+
+
+class TestFetchHostNetworkAgents(TestFetch):
+
+ def setUp(self):
+ self.configure_environment()
+ self.fetcher = DbFetchHostNetworkAgents()
+
+ def check_get_result(self,
+ config,
+ network_agent_res,
+ expected_result,
+ err_msg):
+ self.fetcher.env_config = config
+ self.fetcher.get_objects_list_for_id =\
+ MagicMock(return_value=network_agent_res)
+ result = self.fetcher.get(NETWORK_AGENT_FOLDER_ID)
+ self.assertEqual(result, expected_result, err_msg)
+
+ def test_get(self):
+ test_cases = [
+ {
+ 'config': CONFIG_WITH_MECHANISM_DRIVERS,
+ 'network_agent_res': copy.deepcopy(NETWORK_AGENT),
+ 'expected_result':
+ NETWORK_AGENT_WITH_MECHANISM_DRIVERS_IN_CONFIG_RESULTS,
+ 'err_msg': "Can't get correct result when the " +
+ "mechanism drivers exists in the config"
+ },
+ {
+ 'config': CONFIG_WITHOUT_MECHANISM_DRIVERS,
+ 'network_agent_res': copy.deepcopy(NETWORK_AGENT),
+ 'expected_result':
+ NETWORK_AGENT_WITHOUT_MECHANISM_DRIVERS_IN_CONFIG_RESULTS,
+ 'err_msg': "Can't get correct result when the " +
+ "mechanism drivers doesn't exist in the config"
+ },
+ {
+ 'config': CONFIG_WITH_MECHANISM_DRIVERS,
+ 'network_agent_res': [],
+ 'expected_result': [],
+ 'err_msg': "Can't get [] when the network agent result " +
+ "is empty"
+ }
+ ]
+
+ for test_case in test_cases:
+ self.check_get_result(test_case['config'],
+ test_case['network_agent_res'],
+ test_case['expected_result'],
+ test_case['err_msg'])
diff --git a/app/test/fetch/test_fetch.py b/app/test/fetch/test_fetch.py
new file mode 100644
index 0000000..b9fd3f1
--- /dev/null
+++ b/app/test/fetch/test_fetch.py
@@ -0,0 +1,46 @@
+###############################################################################
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) #
+# and others #
+# #
+# All rights reserved. This program and the accompanying materials #
+# are made available under the terms of the Apache License, Version 2.0 #
+# which accompanies this distribution, and is available at #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+###############################################################################
+import unittest
+
+from discover.configuration import Configuration
+from discover.fetchers.db.db_access import DbAccess
+from test.fetch.config.test_config import MONGODB_CONFIG, ENV_CONFIG, COLLECTION_CONFIG
+from test.fetch.api_fetch.test_data.regions import REGIONS
+from test.fetch.api_fetch.test_data.configurations import CONFIGURATIONS
+from unittest.mock import MagicMock
+from utils.inventory_mgr import InventoryMgr
+from utils.mongo_access import MongoAccess
+from utils.ssh_connection import SshConnection
+from utils.ssh_conn import SshConn
+
+
+class TestFetch(unittest.TestCase):
+
+ def configure_environment(self):
+ self.env = ENV_CONFIG
+ self.inventory_collection = COLLECTION_CONFIG
+ # mock the Mongo Access
+ MongoAccess.mongo_connect = MagicMock()
+ MongoAccess.db = MagicMock()
+
+ self.conf = Configuration()
+ self.conf.use_env = MagicMock()
+ self.conf.environment = CONFIGURATIONS
+ self.conf.configuration = CONFIGURATIONS["configuration"]
+
+ self.inv = InventoryMgr()
+ self.inv.set_collections(self.inventory_collection)
+ DbAccess.conn = MagicMock()
+ SshConnection.connect = MagicMock()
+ SshConnection.check_definitions = MagicMock()
+ SshConn.check_definitions = MagicMock()
+
+ def set_regions_for_fetcher(self, fetcher):
+ fetcher.regions = REGIONS