diff options
Diffstat (limited to 'src/pybind/mgr/ansible/tests')
-rw-r--r-- | src/pybind/mgr/ansible/tests/__init__.py | 0 | ||||
-rw-r--r-- | src/pybind/mgr/ansible/tests/pb_execution_events.data | 183 | ||||
-rw-r--r-- | src/pybind/mgr/ansible/tests/test_client_playbooks.py | 287 | ||||
-rw-r--r-- | src/pybind/mgr/ansible/tests/test_output_wizards.py | 207 |
4 files changed, 677 insertions, 0 deletions
diff --git a/src/pybind/mgr/ansible/tests/__init__.py b/src/pybind/mgr/ansible/tests/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/pybind/mgr/ansible/tests/__init__.py diff --git a/src/pybind/mgr/ansible/tests/pb_execution_events.data b/src/pybind/mgr/ansible/tests/pb_execution_events.data new file mode 100644 index 00000000..248134a3 --- /dev/null +++ b/src/pybind/mgr/ansible/tests/pb_execution_events.data @@ -0,0 +1,183 @@ +{ + "status": "OK", + "msg": "", + "data": { + "events": { + "2-6edf768f-2923-44e1-b884-f0227b811cfc": { + "event": "playbook_on_start" + }, + "3-2016b900-e38f-7dcd-a2e7-000000000008": { + "event": "playbook_on_play_start" + }, + "4-2016b900-e38f-7dcd-a2e7-000000000012": { + "event": "playbook_on_task_start", + "task": "Gathering Facts" + }, + "5-19ae1e5e-aa2d-479e-845a-ef0253cc1f99": { + "event": "runner_on_ok", + "host": "192.168.121.245", + "task": "Gathering Facts" + }, + "6-aad3acc4-06a3-4c97-82ff-31e9e484b1f5": { + "event": "runner_on_ok", + "host": "192.168.121.61", + "task": "Gathering Facts" + }, + "7-55298017-3e7d-4734-b316-bbe13ce1da5e": { + "event": "runner_on_ok", + "host": "192.168.121.254", + "task": "Gathering Facts" + }, + "8-2016b900-e38f-7dcd-a2e7-00000000000a": { + "event": "playbook_on_task_start", + "task": "setup" + }, + "9-2085ccb6-e337-4b9f-bc38-1d8bbf9b973f": { + "event": "runner_on_ok", + "host": "192.168.121.254", + "task": "setup" + }, + "10-e14cdbbc-4883-436c-a41c-a8194ec69075": { + "event": "runner_on_ok", + "host": "192.168.121.245", + "task": "setup" + }, + "11-6d815a26-df53-4240-b8b6-2484e88e4f48": { + "event": "runner_on_ok", + "host": "192.168.121.61", + "task": "setup" + }, + "12-2016b900-e38f-7dcd-a2e7-00000000000b": { + "event": "playbook_on_task_start", + "task": "Get a list of block devices (excludes loop and child devices)" + }, + "13-799b0119-ccab-4eca-b30b-a37b0bafa02c": { + "event": "runner_on_ok", + "host": "192.168.121.245", + "task": "Get a list of block devices (excludes loop and child devices)" + }, + "14-6beb6958-4bfd-4a9c-bd2c-d20d00248605": { + "event": "runner_on_ok", + "host": "192.168.121.61", + "task": "Get a list of block devices (excludes loop and child devices)" + }, + "15-3ca99cc8-98ea-4967-8f2d-115426d00b6a": { + "event": "runner_on_ok", + "host": "192.168.121.254", + "task": "Get a list of block devices (excludes loop and child devices)" + }, + "16-2016b900-e38f-7dcd-a2e7-00000000000c": { + "event": "playbook_on_task_start", + "task": "check if disk {{ item }} is free" + }, + "17-8c88141a-08d1-411f-a855-9f7702a49c4e": { + "event": "runner_item_on_failed", + "host": "192.168.121.245", + "task": "check if disk vda is free" + }, + "18-4457db98-6f18-4f63-bfaa-584db5eea05b": { + "event": "runner_on_failed", + "host": "192.168.121.245", + "task": "check if disk {{ item }} is free" + }, + "19-ac3c72cd-1fbb-495a-be69-53fa6029f356": { + "event": "runner_item_on_failed", + "host": "192.168.121.61", + "task": "check if disk vda is free" + }, + "20-d161cb70-ba2e-4571-b029-c6428a566fef": { + "event": "runner_on_failed", + "host": "192.168.121.61", + "task": "check if disk {{ item }} is free" + }, + "21-65f1ce5c-2d86-4cc3-8e10-cff6bf6cbd82": { + "event": "runner_item_on_failed", + "host": "192.168.121.254", + "task": "check if disk sda is free" + }, + "22-7f86dcd4-4ef7-4f5a-9db3-c3780b67cc4b": { + "event": "runner_item_on_failed", + "host": "192.168.121.254", + "task": "check if disk sdb is free" + }, + "23-837bf4f6-a912-46a8-b94b-55aa66a935c4": { + "event": "runner_item_on_ok", + "host": "192.168.121.254", + "task": "check if disk sdc is free" + }, + "24-adf6238d-723f-4783-9226-8475419d466e": { + "event": "runner_item_on_failed", + "host": "192.168.121.254", + "task": "check if disk vda is free" + }, + "25-554661d8-bc34-4885-a589-4960d6b8a487": { + "event": "runner_on_failed", + "host": "192.168.121.254", + "task": "check if disk {{ item }} is free" + }, + "26-2016b900-e38f-7dcd-a2e7-00000000000d": { + "event": "playbook_on_task_start", + "task": "Update hosts freedisk list" + }, + "27-52df484c-30a0-4e3b-9057-02ca345c5790": { + "event": "runner_item_on_skipped", + "host": "192.168.121.254", + "task": "Update hosts freedisk list" + }, + "28-083616ad-3c1f-4fb8-a06c-5d64e670e362": { + "event": "runner_item_on_skipped", + "host": "192.168.121.254", + "task": "Update hosts freedisk list" + }, + "29-bffc68d3-5448-491f-8780-07858285f5cd": { + "event": "runner_item_on_skipped", + "host": "192.168.121.245", + "task": "Update hosts freedisk list" + }, + "30-cca2dfd9-16e9-4fcb-8bf7-c4da7dab5668": { + "event": "runner_on_skipped", + "host": "192.168.121.245", + "task": "Update hosts freedisk list" + }, + "31-158a98ac-7e8d-4ebb-8c53-4467351a2d3a": { + "event": "runner_item_on_ok", + "host": "192.168.121.254", + "task": "Update hosts freedisk list" + }, + "32-06a7e809-8d82-41df-b01d-45d94e519cb7": { + "event": "runner_item_on_skipped", + "host": "192.168.121.254", + "task": "Update hosts freedisk list" + }, + "33-d5cdbb58-728a-4be5-abf1-4a051146e727": { + "event": "runner_item_on_skipped", + "host": "192.168.121.61", + "task": "Update hosts freedisk list" + }, + "34-9b3c570b-22d8-4539-8c94-d0c1cbed8633": { + "event": "runner_on_ok", + "host": "192.168.121.254", + "task": "Update hosts freedisk list" + }, + "35-93336830-03cd-43ff-be87-a7e063ca7547": { + "event": "runner_on_skipped", + "host": "192.168.121.61", + "task": "Update hosts freedisk list" + }, + "36-2016b900-e38f-7dcd-a2e7-00000000000e": { + "event": "playbook_on_task_start", + "task": "RESULTS" + }, + "37-100564f1-9fed-48c2-bd62-4ae8636dfcdb": { + "event": "runner_on_ok", + "host": "192.168.121.254", + "task": "RESULTS" + }, + "38-20a64160-30a1-481f-a3ee-36e491bc7869": { + "event": "playbook_on_stats" + } + }, + "total_events": 37 + } +} + diff --git a/src/pybind/mgr/ansible/tests/test_client_playbooks.py b/src/pybind/mgr/ansible/tests/test_client_playbooks.py new file mode 100644 index 00000000..98dfd3dd --- /dev/null +++ b/src/pybind/mgr/ansible/tests/test_client_playbooks.py @@ -0,0 +1,287 @@ +import logging +import unittest +import mock +import json + +import requests_mock + +from requests.exceptions import ConnectionError + +from ..ansible_runner_svc import Client, PlayBookExecution, ExecutionStatusCode, \ + LOGIN_URL, API_URL, PLAYBOOK_EXEC_URL, \ + PLAYBOOK_EVENTS, AnsibleRunnerServiceError + + +SERVER_URL = "ars:5001" +USER = "admin" +PASSWORD = "admin" +CERTIFICATE = "" + +# Playbook attributes +PB_NAME = "test_playbook" +PB_UUID = "1733c3ac" + +# Playbook execution data file +PB_EVENTS_FILE = "./tests/pb_execution_events.data" + +# create console handler and set level to info +logger = logging.getLogger() +handler = logging.StreamHandler() +handler.setLevel(logging.INFO) +formatter = logging.Formatter("%(levelname)s - %(message)s") +handler.setFormatter(formatter) +logger.addHandler(handler) + + +def mock_login(mock_server): + + the_login_url = "https://%s/%s" % (SERVER_URL,LOGIN_URL) + + mock_server.register_uri("GET", + the_login_url, + json={"status": "OK", + "msg": "Token returned", + "data": {"token": "dummy_token"}}, + status_code=200) + + the_api_url = "https://%s/%s" % (SERVER_URL,API_URL) + mock_server.register_uri("GET", + the_api_url, + text="<!DOCTYPE html>api</html>", + status_code=200) + +def mock_get_pb(mock_server, playbook_name, return_code): + + mock_login(mock_server) + + ars_client = Client(SERVER_URL, USER, PASSWORD, + CERTIFICATE, logger) + + the_pb_url = "https://%s/%s/%s" % (SERVER_URL, PLAYBOOK_EXEC_URL, playbook_name) + + if return_code == 404: + mock_server.register_uri("POST", + the_pb_url, + json={ "status": "NOTFOUND", + "msg": "playbook file not found", + "data": {}}, + status_code=return_code) + elif return_code == 202: + mock_server.register_uri("POST", + the_pb_url, + json={ "status": "STARTED", + "msg": "starting", + "data": { "play_uuid": "1733c3ac" }}, + status_code=return_code) + + return PlayBookExecution(ars_client, playbook_name, logger, + result_pattern = "RESULTS") + +class ARSclientTest(unittest.TestCase): + + def test_server_not_reachable(self): + + with self.assertRaises(AnsibleRunnerServiceError): + ars_client = Client(SERVER_URL, USER, PASSWORD, + CERTIFICATE, logger) + + def test_server_wrong_USER(self): + + with requests_mock.Mocker() as mock_server: + the_login_url = "https://%s/%s" % (SERVER_URL,LOGIN_URL) + mock_server.get(the_login_url, + json={"status": "NOAUTH", + "msg": "Access denied invalid login: unknown USER", + "data": {}}, + status_code=401) + + + ars_client = Client(SERVER_URL, USER, PASSWORD, + CERTIFICATE, logger) + + self.assertFalse(ars_client.is_operative(), + "Operative attribute expected to be False") + + def test_server_connection_ok(self): + + with requests_mock.Mocker() as mock_server: + + mock_login(mock_server) + + ars_client = Client(SERVER_URL, USER, PASSWORD, + CERTIFICATE, logger) + + self.assertTrue(ars_client.is_operative(), + "Operative attribute expected to be True") + + def test_server_http_delete(self): + + with requests_mock.Mocker() as mock_server: + + mock_login(mock_server) + + ars_client = Client(SERVER_URL, USER, PASSWORD, + CERTIFICATE, logger) + + url = "https://%s/test" % (SERVER_URL) + mock_server.register_uri("DELETE", + url, + json={ "status": "OK", + "msg": "", + "data": {}}, + status_code=201) + + response = ars_client.http_delete("test") + self.assertTrue(response.status_code == 201) + +class PlayBookExecutionTests(unittest.TestCase): + + + def test_playbook_execution_ok(self): + """Check playbook id is set when the playbook is launched + """ + with requests_mock.Mocker() as mock_server: + + test_pb = mock_get_pb(mock_server, PB_NAME, 202) + + test_pb.launch() + + self.assertEqual(test_pb.play_uuid, PB_UUID, + "Found Unexpected playbook uuid") + + + + def test_playbook_execution_error(self): + """Check playbook id is not set when the playbook is not present + """ + + with requests_mock.Mocker() as mock_server: + + test_pb = mock_get_pb(mock_server, "unknown_playbook", 404) + + with self.assertRaises(AnsibleRunnerServiceError): + test_pb.launch() + + #self.assertEqual(test_pb.play_uuid, "", + # "Playbook uuid not empty") + + def test_playbook_not_launched(self): + """Check right status code when Playbook execution has not been launched + """ + + with requests_mock.Mocker() as mock_server: + + test_pb = mock_get_pb(mock_server, PB_NAME, 202) + + # Check playbook not launched + self.assertEqual(test_pb.get_status(), + ExecutionStatusCode.NOT_LAUNCHED, + "Wrong status code for playbook not launched") + + def test_playbook_launched(self): + """Check right status code when Playbook execution has been launched + """ + + with requests_mock.Mocker() as mock_server: + + test_pb = mock_get_pb(mock_server, PB_NAME, 202) + + test_pb.launch() + + the_status_url = "https://%s/%s/%s" % (SERVER_URL, + PLAYBOOK_EXEC_URL, + PB_UUID) + mock_server.register_uri("GET", + the_status_url, + json={"status": "OK", + "msg": "running", + "data": {"task": "Step 2", + "last_task_num": 6} + }, + status_code=200) + + self.assertEqual(test_pb.get_status(), + ExecutionStatusCode.ON_GOING, + "Wrong status code for a running playbook") + + self.assertEqual(test_pb.play_uuid, PB_UUID, + "Unexpected playbook uuid") + + def test_playbook_finish_ok(self): + """Check right status code when Playbook execution is succesful + """ + with requests_mock.Mocker() as mock_server: + + test_pb = mock_get_pb(mock_server, PB_NAME, 202) + + test_pb.launch() + + the_status_url = "https://%s/%s/%s" % (SERVER_URL, + PLAYBOOK_EXEC_URL, + PB_UUID) + mock_server.register_uri("GET", + the_status_url, + json={"status": "OK", + "msg": "successful", + "data": {} + }, + status_code=200) + + self.assertEqual(test_pb.get_status(), + ExecutionStatusCode.SUCCESS, + "Wrong status code for a playbook executed succesfully") + + def test_playbook_finish_error(self): + """Check right status code when Playbook execution has failed + """ + with requests_mock.Mocker() as mock_server: + + test_pb = mock_get_pb(mock_server, PB_NAME, 202) + + test_pb.launch() + + the_status_url = "https://%s/%s/%s" % (SERVER_URL, + PLAYBOOK_EXEC_URL, + PB_UUID) + mock_server.register_uri("GET", + the_status_url, + json={"status": "OK", + "msg": "failed", + "data": {} + }, + status_code=200) + + self.assertEqual(test_pb.get_status(), + ExecutionStatusCode.ERROR, + "Wrong status code for a playbook with error") + + def test_playbook_get_result(self): + """ Find the right result event in a set of different events + """ + with requests_mock.Mocker() as mock_server: + + test_pb = mock_get_pb(mock_server, PB_NAME, 202) + + test_pb.launch() + + the_events_url = "https://%s/%s" % (SERVER_URL, + PLAYBOOK_EVENTS % PB_UUID) + + # Get the events stored in a file + pb_events = {} + with open(PB_EVENTS_FILE) as events_file: + pb_events = json.loads(events_file.read()) + + mock_server.register_uri("GET", + the_events_url, + json=pb_events, + status_code=200) + + result = test_pb.get_result("runner_on_ok") + + self.assertEqual(len(result.keys()), 1, + "Unique result event not found") + + self.assertIn("37-100564f1-9fed-48c2-bd62-4ae8636dfcdb", + result.keys(), + "Predefined result event not found") diff --git a/src/pybind/mgr/ansible/tests/test_output_wizards.py b/src/pybind/mgr/ansible/tests/test_output_wizards.py new file mode 100644 index 00000000..2a3a9017 --- /dev/null +++ b/src/pybind/mgr/ansible/tests/test_output_wizards.py @@ -0,0 +1,207 @@ +""" Test output wizards +""" +import unittest +import mock + +from ..ansible_runner_svc import EVENT_DATA_URL +from ..output_wizards import ProcessHostsList, ProcessPlaybookResult, \ + ProcessInventory + +class OutputWizardProcessHostsList(unittest.TestCase): + """Test ProcessHostsList Output Wizard + """ + RESULT_OK = """ + { + "status": "OK", + "msg": "", + "data": { + "hosts": [ + "host_a", + "host_b", + "host_c" + ] + } + } + """ + ar_client = mock.Mock() + logger = mock.Mock() + test_wizard = ProcessHostsList(ar_client, logger) + + def test_process(self): + """Test a normal call""" + + nodes_list = self.test_wizard.process("", self.RESULT_OK) + self.assertEqual([node.name for node in nodes_list], + ["host_a", "host_b", "host_c"]) + + def test_errors(self): + """Test different kind of errors processing result""" + + # Malformed json + host_list = self.test_wizard.process("", """{"msg": """"") + self.assertEqual(host_list, []) + + # key error + host_list = self.test_wizard.process("", """{"msg": ""}""") + self.assertEqual(host_list, []) + + # Hosts not in iterable + host_list = self.test_wizard.process("", """{"data":{"hosts": 123} }""") + self.assertEqual(host_list, []) + +class OutputWizardProcessPlaybookResult(unittest.TestCase): + """Test ProcessPlaybookResult Output Wizard + """ + # Input to process + INVENTORY_EVENTS = {1:"first event", 2:"second event"} + EVENT_INFORMATION = "event information\n" + + # Mocked response + mocked_response = mock.Mock() + mocked_response.text = EVENT_INFORMATION + + # The Ansible Runner Service client + ar_client = mock.Mock() + ar_client.http_get = mock.MagicMock(return_value=mocked_response) + + logger = mock.Mock() + + test_wizard = ProcessPlaybookResult(ar_client, logger) + + def test_process(self): + """Test a normal call + """ + + operation_id = 24 + result = self.test_wizard.process(operation_id, self.INVENTORY_EVENTS) + + # Check http request are correct and compose expected result + expected_result = "" + for key, dummy_data in self.INVENTORY_EVENTS.items(): + http_request = EVENT_DATA_URL % (operation_id, key) + self.ar_client.http_get.assert_any_call(http_request) + expected_result += self.EVENT_INFORMATION + + #Check result + self.assertEqual(result, expected_result) + +class OutputWizardProcessInventory(unittest.TestCase): + """Test ProcessInventory Output Wizard + """ + # Input to process + INVENTORY_EVENTS = {'event_uuid_1': {'host': '192.168.121.144', + 'task': 'list storage inventory', + 'event': 'runner_on_ok'}} + EVENT_DATA = r""" + { + "status": "OK", + "msg": "", + "data": { + "uuid": "5e96d509-174d-4f5f-bd94-e278c3a5b85b", + "counter": 11, + "stdout": "changed: [192.168.121.144]", + "start_line": 17, + "end_line": 18, + "runner_ident": "6e98b2ba-3ce1-11e9-be81-2016b900e38f", + "created": "2019-03-02T11:50:56.582112", + "pid": 482, + "event_data": { + "play_pattern": "osds", + "play": "query each host for storage device inventory", + "task": "list storage inventory", + "task_args": "_ansible_version=2.6.5, _ansible_selinux_special_fs=['fuse', 'nfs', 'vboxsf', 'ramfs', '9p'], _ansible_no_log=False, _ansible_module_name=ceph_volume, _ansible_debug=False, _ansible_verbosity=0, _ansible_keep_remote_files=False, _ansible_syslog_facility=LOG_USER, _ansible_socket=None, action=inventory, _ansible_diff=False, _ansible_remote_tmp=~/.ansible/tmp, _ansible_shell_executable=/bin/sh, _ansible_check_mode=False, _ansible_tmpdir=None", + "remote_addr": "192.168.121.144", + "res": { + "_ansible_parsed": true, + "stderr_lines": [], + "changed": true, + "end": "2019-03-02 11:50:56.554937", + "_ansible_no_log": false, + "stdout": "[{\"available\": true, \"rejected_reasons\": [], \"sys_api\": {\"scheduler_mode\": \"noop\", \"rotational\": \"1\", \"vendor\": \"ATA\", \"human_readable_size\": \"50.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {}, \"rev\": \"2.5+\", \"sas_address\": \"\", \"locked\": 0, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/sdc\", \"support_discard\": \"\", \"model\": \"QEMU HARDDISK\", \"ro\": \"0\", \"nr_requests\": \"128\", \"size\": 53687091200.0}, \"lvs\": [], \"path\": \"/dev/sdc\"}, {\"available\": false, \"rejected_reasons\": [\"locked\"], \"sys_api\": {\"scheduler_mode\": \"noop\", \"rotational\": \"1\", \"vendor\": \"ATA\", \"human_readable_size\": \"50.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {}, \"rev\": \"2.5+\", \"sas_address\": \"\", \"locked\": 1, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/sda\", \"support_discard\": \"\", \"model\": \"QEMU HARDDISK\", \"ro\": \"0\", \"nr_requests\": \"128\", \"size\": 53687091200.0}, \"lvs\": [{\"cluster_name\": \"ceph\", \"name\": \"osd-data-dcf8a88c-5546-42d2-afa4-b36f7fb23b66\", \"osd_id\": \"3\", \"cluster_fsid\": \"30d61f3e-7ee4-4bdc-8fe7-2ad5bb3f5317\", \"type\": \"block\", \"block_uuid\": \"fVqujC-9dgh-cN9W-1XD4-zVx1-1UdA-fUS3ha\", \"osd_fsid\": \"8b7cbeba-5e86-44ff-a5f3-2e7df77753fe\"}], \"path\": \"/dev/sda\"}, {\"available\": false, \"rejected_reasons\": [\"locked\"], \"sys_api\": {\"scheduler_mode\": \"noop\", \"rotational\": \"1\", \"vendor\": \"ATA\", \"human_readable_size\": \"50.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {}, \"rev\": \"2.5+\", \"sas_address\": \"\", \"locked\": 1, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/sdb\", \"support_discard\": \"\", \"model\": \"QEMU HARDDISK\", \"ro\": \"0\", \"nr_requests\": \"128\", \"size\": 53687091200.0}, \"lvs\": [{\"cluster_name\": \"ceph\", \"name\": \"osd-data-8c92e986-bd97-4b3d-ba77-2cb88e15d80f\", \"osd_id\": \"1\", \"cluster_fsid\": \"30d61f3e-7ee4-4bdc-8fe7-2ad5bb3f5317\", \"type\": \"block\", \"block_uuid\": \"mgzO7O-vUfu-H3mf-4R3K-2f97-ZMRH-SngBFP\", \"osd_fsid\": \"6d067688-3e1b-45f9-ad03-8abd19e9f117\"}], \"path\": \"/dev/sdb\"}, {\"available\": false, \"rejected_reasons\": [\"locked\"], \"sys_api\": {\"scheduler_mode\": \"mq-deadline\", \"rotational\": \"1\", \"vendor\": \"0x1af4\", \"human_readable_size\": \"41.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {\"vda1\": {\"start\": \"2048\", \"holders\": [], \"sectorsize\": 512, \"sectors\": \"2048\", \"size\": \"1024.00 KB\"}, \"vda3\": {\"start\": \"2101248\", \"holders\": [\"dm-0\", \"dm-1\"], \"sectorsize\": 512, \"sectors\": \"81784832\", \"size\": \"39.00 GB\"}, \"vda2\": {\"start\": \"4096\", \"holders\": [], \"sectorsize\": 512, \"sectors\": \"2097152\", \"size\": \"1024.00 MB\"}}, \"rev\": \"\", \"sas_address\": \"\", \"locked\": 1, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/vda\", \"support_discard\": \"\", \"model\": \"\", \"ro\": \"0\", \"nr_requests\": \"256\", \"size\": 44023414784.0}, \"lvs\": [{\"comment\": \"not used by ceph\", \"name\": \"LogVol00\"}, {\"comment\": \"not used by ceph\", \"name\": \"LogVol01\"}], \"path\": \"/dev/vda\"}]", + "cmd": [ + "ceph-volume", + "inventory", + "--format=json" + ], + "rc": 0, + "start": "2019-03-02 11:50:55.150121", + "stderr": "", + "delta": "0:00:01.404816", + "invocation": { + "module_args": { + "wal_vg": null, + "wal": null, + "dmcrypt": false, + "block_db_size": "-1", + "journal": null, + "objectstore": "bluestore", + "db": null, + "batch_devices": [], + "db_vg": null, + "journal_vg": null, + "cluster": "ceph", + "osds_per_device": 1, + "containerized": "False", + "crush_device_class": null, + "report": false, + "data_vg": null, + "data": null, + "action": "inventory", + "journal_size": "5120" + } + }, + "stdout_lines": [ + "[{\"available\": true, \"rejected_reasons\": [], \"sys_api\": {\"scheduler_mode\": \"noop\", \"rotational\": \"1\", \"vendor\": \"ATA\", \"human_readable_size\": \"50.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {}, \"rev\": \"2.5+\", \"sas_address\": \"\", \"locked\": 0, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/sdc\", \"support_discard\": \"\", \"model\": \"QEMU HARDDISK\", \"ro\": \"0\", \"nr_requests\": \"128\", \"size\": 53687091200.0}, \"lvs\": [], \"path\": \"/dev/sdc\"}, {\"available\": false, \"rejected_reasons\": [\"locked\"], \"sys_api\": {\"scheduler_mode\": \"noop\", \"rotational\": \"1\", \"vendor\": \"ATA\", \"human_readable_size\": \"50.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {}, \"rev\": \"2.5+\", \"sas_address\": \"\", \"locked\": 1, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/sda\", \"support_discard\": \"\", \"model\": \"QEMU HARDDISK\", \"ro\": \"0\", \"nr_requests\": \"128\", \"size\": 53687091200.0}, \"lvs\": [{\"cluster_name\": \"ceph\", \"name\": \"osd-data-dcf8a88c-5546-42d2-afa4-b36f7fb23b66\", \"osd_id\": \"3\", \"cluster_fsid\": \"30d61f3e-7ee4-4bdc-8fe7-2ad5bb3f5317\", \"type\": \"block\", \"block_uuid\": \"fVqujC-9dgh-cN9W-1XD4-zVx1-1UdA-fUS3ha\", \"osd_fsid\": \"8b7cbeba-5e86-44ff-a5f3-2e7df77753fe\"}], \"path\": \"/dev/sda\"}, {\"available\": false, \"rejected_reasons\": [\"locked\"], \"sys_api\": {\"scheduler_mode\": \"noop\", \"rotational\": \"1\", \"vendor\": \"ATA\", \"human_readable_size\": \"50.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {}, \"rev\": \"2.5+\", \"sas_address\": \"\", \"locked\": 1, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/sdb\", \"support_discard\": \"\", \"model\": \"QEMU HARDDISK\", \"ro\": \"0\", \"nr_requests\": \"128\", \"size\": 53687091200.0}, \"lvs\": [{\"cluster_name\": \"ceph\", \"name\": \"osd-data-8c92e986-bd97-4b3d-ba77-2cb88e15d80f\", \"osd_id\": \"1\", \"cluster_fsid\": \"30d61f3e-7ee4-4bdc-8fe7-2ad5bb3f5317\", \"type\": \"block\", \"block_uuid\": \"mgzO7O-vUfu-H3mf-4R3K-2f97-ZMRH-SngBFP\", \"osd_fsid\": \"6d067688-3e1b-45f9-ad03-8abd19e9f117\"}], \"path\": \"/dev/sdb\"}, {\"available\": false, \"rejected_reasons\": [\"locked\"], \"sys_api\": {\"scheduler_mode\": \"mq-deadline\", \"rotational\": \"1\", \"vendor\": \"0x1af4\", \"human_readable_size\": \"41.00 GB\", \"sectors\": 0, \"sas_device_handle\": \"\", \"partitions\": {\"vda1\": {\"start\": \"2048\", \"holders\": [], \"sectorsize\": 512, \"sectors\": \"2048\", \"size\": \"1024.00 KB\"}, \"vda3\": {\"start\": \"2101248\", \"holders\": [\"dm-0\", \"dm-1\"], \"sectorsize\": 512, \"sectors\": \"81784832\", \"size\": \"39.00 GB\"}, \"vda2\": {\"start\": \"4096\", \"holders\": [], \"sectorsize\": 512, \"sectors\": \"2097152\", \"size\": \"1024.00 MB\"}}, \"rev\": \"\", \"sas_address\": \"\", \"locked\": 1, \"sectorsize\": \"512\", \"removable\": \"0\", \"path\": \"/dev/vda\", \"support_discard\": \"\", \"model\": \"\", \"ro\": \"0\", \"nr_requests\": \"256\", \"size\": 44023414784.0}, \"lvs\": [{\"comment\": \"not used by ceph\", \"name\": \"LogVol00\"}, {\"comment\": \"not used by ceph\", \"name\": \"LogVol01\"}], \"path\": \"/dev/vda\"}]" + ] + }, + "pid": 482, + "play_uuid": "2016b900-e38f-0e09-19be-00000000000c", + "task_uuid": "2016b900-e38f-0e09-19be-000000000012", + "event_loop": null, + "playbook_uuid": "e80e66f2-4a78-4a96-aaf6-fbe473f11312", + "playbook": "storage-inventory.yml", + "task_action": "ceph_volume", + "host": "192.168.121.144", + "task_path": "/usr/share/ansible-runner-service/project/storage-inventory.yml:29" + }, + "event": "runner_on_ok" + } + } + """ + + # Mocked response + mocked_response = mock.Mock() + mocked_response.text = EVENT_DATA + + # The Ansible Runner Service client + ar_client = mock.Mock() + ar_client.http_get = mock.MagicMock(return_value=mocked_response) + + logger = mock.Mock() + + test_wizard = ProcessInventory(ar_client, logger) + + def test_process(self): + """Test a normal call + """ + operation_id = 12 + nodes_list = self.test_wizard.process(operation_id, self.INVENTORY_EVENTS) + + for key, dummy_data in self.INVENTORY_EVENTS.items(): + http_request = EVENT_DATA_URL % (operation_id, key) + self.ar_client.http_get.assert_any_call(http_request) + + + # Only one host + self.assertTrue(len(nodes_list), 1) + + # Host retrieved OK + self.assertEqual(nodes_list[0].name, "192.168.121.144") + + # Devices + self.assertTrue(len(nodes_list[0].devices), 4) + + expected_device_ids = ["/dev/sdc", "/dev/sda", "/dev/sdb", "/dev/vda"] + device_ids = [dev.id for dev in nodes_list[0].devices] + + self.assertEqual(expected_device_ids, device_ids) |