From 211427894719b959b02e86275b6fb5b1d4df154a Mon Sep 17 00:00:00 2001 From: Alex Monteiro Date: Tue, 28 Nov 2017 10:49:51 -0300 Subject: [PATCH] DatacenterFactsModule for HPE OneView (#32701) * Added support to Datacenter resources in HPE OneView * Adjusting comments in oneview_datacenter_facts * Adding no_log on the documentation * Using Pytest to Oneview DatacenterFactsModule tests --- lib/ansible/module_utils/oneview.py | 2 +- .../oneview/oneview_datacenter_facts.py | 138 ++++++++++++++++++ .../remote_management/oneview/conftest.py | 23 +++ .../oneview/hpe_test_utils.py | 77 ++++++++++ .../oneview/test_oneview_datacenter_facts.py | 76 ++++++++++ 5 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 lib/ansible/modules/remote_management/oneview/oneview_datacenter_facts.py create mode 100644 test/units/modules/remote_management/oneview/conftest.py create mode 100644 test/units/modules/remote_management/oneview/test_oneview_datacenter_facts.py diff --git a/lib/ansible/module_utils/oneview.py b/lib/ansible/module_utils/oneview.py index 3940d00a765..c7b80aed5b2 100644 --- a/lib/ansible/module_utils/oneview.py +++ b/lib/ansible/module_utils/oneview.py @@ -207,7 +207,7 @@ class OneViewModuleBase(object): config=dict(type='path'), hostname=dict(type='str'), username=dict(type='str'), - password=dict(type='str'), + password=dict(type='str', no_log=True), api_version=dict(type='int'), image_streamer_hostname=dict(type='str') ) diff --git a/lib/ansible/modules/remote_management/oneview/oneview_datacenter_facts.py b/lib/ansible/modules/remote_management/oneview/oneview_datacenter_facts.py new file mode 100644 index 00000000000..7f642d631b2 --- /dev/null +++ b/lib/ansible/modules/remote_management/oneview/oneview_datacenter_facts.py @@ -0,0 +1,138 @@ +#!/usr/bin/python +# Copyright (c) 2016-2017 Hewlett Packard Enterprise Development LP +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = ''' +--- +module: oneview_datacenter_facts +short_description: Retrieve facts about the OneView Data Centers +description: + - Retrieve facts about the OneView Data Centers. +version_added: "2.5" +requirements: + - "hpOneView >= 2.0.1" +author: + - Alex Monteiro (@aalexmonteiro) + - Madhav Bharadwaj (@madhav-bharadwaj) + - Priyanka Sood (@soodpr) + - Ricardo Galeno (@ricardogpsf) +options: + name: + description: + - Data Center name. + options: + description: + - "Retrieve additional facts. Options available: 'visualContent'." + +extends_documentation_fragment: + - oneview + - oneview.factsparams +''' + +EXAMPLES = ''' +- name: Gather facts about all Data Centers + oneview_datacenter_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + delegate_to: localhost +- debug: var=datacenters + +- name: Gather paginated, filtered and sorted facts about Data Centers + oneview_datacenter_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + params: + start: 0 + count: 3 + sort: 'name:descending' + filter: 'state=Unmanaged' +- debug: var=datacenters + +- name: Gather facts about a Data Center by name + oneview_datacenter_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + name: "My Data Center" + delegate_to: localhost +- debug: var=datacenters + +- name: Gather facts about the Data Center Visual Content + oneview_datacenter_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + name: "My Data Center" + options: + - visualContent + delegate_to: localhost +- debug: var=datacenters +- debug: var=datacenter_visual_content +''' + +RETURN = ''' +datacenters: + description: Has all the OneView facts about the Data Centers. + returned: Always, but can be null. + type: dict + +datacenter_visual_content: + description: Has facts about the Data Center Visual Content. + returned: When requested, but can be null. + type: dict +''' + +from ansible.module_utils.oneview import OneViewModuleBase + + +class DatacenterFactsModule(OneViewModuleBase): + argument_spec = dict( + name=dict(type='str'), + options=dict(type='list'), + params=dict(type='dict') + ) + + def __init__(self): + super(DatacenterFactsModule, self).__init__(additional_arg_spec=self.argument_spec) + + def execute_module(self): + + client = self.oneview_client.datacenters + ansible_facts = {} + + if self.module.params.get('name'): + datacenters = client.get_by('name', self.module.params['name']) + + if self.options and 'visualContent' in self.options: + if datacenters: + ansible_facts['datacenter_visual_content'] = client.get_visual_content(datacenters[0]['uri']) + else: + ansible_facts['datacenter_visual_content'] = None + + ansible_facts['datacenters'] = datacenters + else: + ansible_facts['datacenters'] = client.get_all(**self.facts_params) + + return dict(changed=False, + ansible_facts=ansible_facts) + + +def main(): + DatacenterFactsModule().run() + + +if __name__ == '__main__': + main() diff --git a/test/units/modules/remote_management/oneview/conftest.py b/test/units/modules/remote_management/oneview/conftest.py new file mode 100644 index 00000000000..715d9cdc49a --- /dev/null +++ b/test/units/modules/remote_management/oneview/conftest.py @@ -0,0 +1,23 @@ +# Copyright (c) 2016-2017 Hewlett Packard Enterprise Development LP +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +import pytest + +from mock import Mock, patch +from oneview_module_loader import ONEVIEW_MODULE_UTILS_PATH +from hpOneView.oneview_client import OneViewClient + + +@pytest.fixture +def mock_ov_client(): + patcher_json_file = patch.object(OneViewClient, 'from_json_file') + client = patcher_json_file.start() + return client.return_value + + +@pytest.fixture +def mock_ansible_module(): + patcher_ansible = patch(ONEVIEW_MODULE_UTILS_PATH + '.AnsibleModule') + patcher_ansible = patcher_ansible.start() + ansible_module = Mock() + patcher_ansible.return_value = ansible_module + return ansible_module diff --git a/test/units/modules/remote_management/oneview/hpe_test_utils.py b/test/units/modules/remote_management/oneview/hpe_test_utils.py index 620c1ea6560..42f2cdf89d7 100644 --- a/test/units/modules/remote_management/oneview/hpe_test_utils.py +++ b/test/units/modules/remote_management/oneview/hpe_test_utils.py @@ -15,12 +15,89 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import pytest +import re import yaml + from mock import Mock, patch from oneview_module_loader import ONEVIEW_MODULE_UTILS_PATH from hpOneView.oneview_client import OneViewClient +class OneViewBaseTest(object): + @pytest.fixture(autouse=True) + def setUp(self, mock_ansible_module, mock_ov_client, request): + marker = request.node.get_marker('resource') + self.resource = getattr(mock_ov_client, "%s" % (marker.args)) + self.mock_ov_client = mock_ov_client + self.mock_ansible_module = mock_ansible_module + + @pytest.fixture + def testing_module(self): + resource_name = type(self).__name__.replace('Test', '') + resource_module_path_name = resource_name.replace('Module', '') + resource_module_path_name = re.findall('[A-Z][^A-Z]*', resource_module_path_name) + resource_module_path_name = 'oneview_' + str.join('_', resource_module_path_name).lower() + + ansible = __import__('ansible') + oneview_module = ansible.modules.remote_management.oneview + resource_module = getattr(oneview_module, resource_module_path_name) + self.testing_class = getattr(resource_module, resource_name) + testing_module = self.testing_class.__module__.split('.')[-1] + testing_module = getattr(oneview_module, testing_module) + try: + # Load scenarios from module examples (Also checks if it is a valid yaml) + EXAMPLES = yaml.load(testing_module.EXAMPLES, yaml.SafeLoader) + + except yaml.scanner.ScannerError: + message = "Something went wrong while parsing yaml from {}.EXAMPLES".format(self.testing_class.__module__) + raise Exception(message) + return testing_module + + def test_main_function_should_call_run_method(self, testing_module, mock_ansible_module): + mock_ansible_module.params = {'config': 'config.json'} + + main_func = getattr(testing_module, 'main') + + with patch.object(self.testing_class, "run") as mock_run: + main_func() + mock_run.assert_called_once() + + +class FactsParamsTest(OneViewBaseTest): + def test_should_get_all_using_filters(self, testing_module): + self.resource.get_all.return_value = [] + + params_get_all_with_filters = dict( + config='config.json', + name=None, + params={ + 'start': 1, + 'count': 3, + 'sort': 'name:descending', + 'filter': 'purpose=General', + 'query': 'imported eq true' + }) + self.mock_ansible_module.params = params_get_all_with_filters + + self.testing_class().run() + + self.resource.get_all.assert_called_once_with(start=1, count=3, sort='name:descending', filter='purpose=General', query='imported eq true') + + def test_should_get_all_without_params(self, testing_module): + self.resource.get_all.return_value = [] + + params_get_all_with_filters = dict( + config='config.json', + name=None + ) + self.mock_ansible_module.params = params_get_all_with_filters + + self.testing_class().run() + + self.resource.get_all.assert_called_once_with() + + class OneViewBaseTestCase(object): mock_ov_client_from_json_file = None testing_class = None diff --git a/test/units/modules/remote_management/oneview/test_oneview_datacenter_facts.py b/test/units/modules/remote_management/oneview/test_oneview_datacenter_facts.py new file mode 100644 index 00000000000..937a75b4072 --- /dev/null +++ b/test/units/modules/remote_management/oneview/test_oneview_datacenter_facts.py @@ -0,0 +1,76 @@ +# Copyright (c) 2016-2017 Hewlett Packard Enterprise Development LP +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +import pytest + +from oneview_module_loader import OneViewModuleBase +from ansible.modules.remote_management.oneview.oneview_datacenter_facts import DatacenterFactsModule +from hpe_test_utils import FactsParamsTest + +PARAMS_GET_CONNECTED = dict( + config='config.json', + name="MyDatacenter", + options=['visualContent'] +) + + +@pytest.mark.resource('datacenters') +class TestDatacenterFactsModule(FactsParamsTest): + @pytest.fixture(autouse=True) + def setUp(self, mock_ansible_module, mock_ov_client): + self.resource = mock_ov_client.datacenters + self.mock_ansible_module = mock_ansible_module + self.mock_ov_client = mock_ov_client + + def test_should_get_all_datacenters(self): + self.resource.get_all.return_value = {"name": "Data Center Name"} + + self.mock_ansible_module.params = dict(config='config.json',) + + DatacenterFactsModule().run() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(datacenters=({"name": "Data Center Name"})) + ) + + def test_should_get_datacenter_by_name(self): + self.resource.get_by.return_value = [{"name": "Data Center Name"}] + + self.mock_ansible_module.params = dict(config='config.json', name="MyDatacenter") + + DatacenterFactsModule().run() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(datacenters=([{"name": "Data Center Name"}])) + ) + + def test_should_get_datacenter_visual_content(self): + self.resource.get_by.return_value = [{"name": "Data Center Name", "uri": "/rest/datacenter/id"}] + + self.resource.get_visual_content.return_value = { + "name": "Visual Content"} + + self.mock_ansible_module.params = PARAMS_GET_CONNECTED + + DatacenterFactsModule().run() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts={'datacenter_visual_content': {'name': 'Visual Content'}, + 'datacenters': [{'name': 'Data Center Name', 'uri': '/rest/datacenter/id'}]} + ) + + def test_should_get_none_datacenter_visual_content(self): + self.resource.get_by.return_value = [] + + self.mock_ansible_module.params = PARAMS_GET_CONNECTED + + DatacenterFactsModule().run() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts={'datacenter_visual_content': None, + 'datacenters': []} + )