From 7d74c126a98a958ceb35a383cbd4b2fd747b3663 Mon Sep 17 00:00:00 2001 From: Felipe Garcia Bulsoni Date: Mon, 2 Oct 2017 17:32:36 -0300 Subject: [PATCH] EnclosureFactsModule for HPE OneView (#28852) * Added support to retrieving Enclosures in HPE OneView - Added unit tests * Updated version_added to 2.5 * Changing return type of enclosure_script to string * Fixing copyright header according to review * Replaced config for credentials in parameters for documentation --- .../oneview/oneview_enclosure_facts.py | 205 ++++++++++++++++++ .../oneview/test_oneview_enclosure_facts.py | 134 ++++++++++++ 2 files changed, 339 insertions(+) create mode 100644 lib/ansible/modules/remote_management/oneview/oneview_enclosure_facts.py create mode 100644 test/units/modules/remote_management/oneview/test_oneview_enclosure_facts.py diff --git a/lib/ansible/modules/remote_management/oneview/oneview_enclosure_facts.py b/lib/ansible/modules/remote_management/oneview/oneview_enclosure_facts.py new file mode 100644 index 00000000000..d7f195ddc0e --- /dev/null +++ b/lib/ansible/modules/remote_management/oneview/oneview_enclosure_facts.py @@ -0,0 +1,205 @@ +#!/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_enclosure_facts +short_description: Retrieve facts about one or more Enclosures +description: + - Retrieve facts about one or more of the Enclosures from OneView. +version_added: "2.5" +requirements: + - hpOneView >= 2.0.1 +author: + - Felipe Bulsoni (@fgbulsoni) + - Thiago Miotto (@tmiotto) + - Adriane Cardozo (@adriane-cardozo) +options: + name: + description: + - Enclosure name. + options: + description: + - "List with options to gather additional facts about an Enclosure and related resources. + Options allowed: C(script), C(environmentalConfiguration), and C(utilization). For the option C(utilization), + you can provide specific parameters." + +extends_documentation_fragment: + - oneview + - oneview.factsparams +''' + +EXAMPLES = ''' +- name: Gather facts about all Enclosures + oneview_enclosure_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + no_log: true + delegate_to: localhost +- debug: var=enclosures + +- name: Gather paginated, filtered and sorted facts about Enclosures + oneview_enclosure_facts: + params: + start: 0 + count: 3 + sort: name:descending + filter: status=OK + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + no_log: true + delegate_to: localhost +- debug: var=enclosures + +- name: Gather facts about an Enclosure by name + oneview_enclosure_facts: + name: Enclosure-Name + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + no_log: true + delegate_to: localhost +- debug: var=enclosures + +- name: Gather facts about an Enclosure by name with options + oneview_enclosure_facts: + name: Test-Enclosure + options: + - script # optional + - environmentalConfiguration # optional + - utilization # optional + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + no_log: true + delegate_to: localhost +- debug: var=enclosures +- debug: var=enclosure_script +- debug: var=enclosure_environmental_configuration +- debug: var=enclosure_utilization + +- name: "Gather facts about an Enclosure with temperature data at a resolution of one sample per day, between two + specified dates" + oneview_enclosure_facts: + name: Test-Enclosure + options: + - utilization: # optional + fields: AmbientTemperature + filter: + - startDate=2016-07-01T14:29:42.000Z + - endDate=2017-07-01T03:29:42.000Z + view: day + refresh: false + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + no_log: true + delegate_to: localhost +- debug: var=enclosures +- debug: var=enclosure_utilization +''' + +RETURN = ''' +enclosures: + description: Has all the OneView facts about the Enclosures. + returned: Always, but can be null. + type: dict + +enclosure_script: + description: Has all the OneView facts about the script of an Enclosure. + returned: When requested, but can be null. + type: string + +enclosure_environmental_configuration: + description: Has all the OneView facts about the environmental configuration of an Enclosure. + returned: When requested, but can be null. + type: dict + +enclosure_utilization: + description: Has all the OneView facts about the utilization of an Enclosure. + returned: When requested, but can be null. + type: dict +''' + +from ansible.module_utils.oneview import OneViewModuleBase + + +class EnclosureFactsModule(OneViewModuleBase): + argument_spec = dict(name=dict(type='str'), options=dict(type='list'), params=dict(type='dict')) + + def __init__(self): + super(EnclosureFactsModule, self).__init__(additional_arg_spec=self.argument_spec) + + def execute_module(self): + + ansible_facts = {} + + if self.module.params['name']: + enclosures = self._get_by_name(self.module.params['name']) + + if self.options and enclosures: + ansible_facts = self._gather_optional_facts(self.options, enclosures[0]) + else: + enclosures = self.oneview_client.enclosures.get_all(**self.facts_params) + + ansible_facts['enclosures'] = enclosures + + return dict(changed=False, + ansible_facts=ansible_facts) + + def _gather_optional_facts(self, options, enclosure): + + enclosure_client = self.oneview_client.enclosures + ansible_facts = {} + + if options.get('script'): + ansible_facts['enclosure_script'] = enclosure_client.get_script(enclosure['uri']) + if options.get('environmentalConfiguration'): + env_config = enclosure_client.get_environmental_configuration(enclosure['uri']) + ansible_facts['enclosure_environmental_configuration'] = env_config + if options.get('utilization'): + ansible_facts['enclosure_utilization'] = self._get_utilization(enclosure, options['utilization']) + + return ansible_facts + + def _get_utilization(self, enclosure, params): + fields = view = refresh = filter = '' + + if isinstance(params, dict): + fields = params.get('fields') + view = params.get('view') + refresh = params.get('refresh') + filter = params.get('filter') + + return self.oneview_client.enclosures.get_utilization(enclosure['uri'], + fields=fields, + filter=filter, + refresh=refresh, + view=view) + + def _get_by_name(self, name): + return self.oneview_client.enclosures.get_by('name', name) + + +def main(): + EnclosureFactsModule().run() + + +if __name__ == '__main__': + main() diff --git a/test/units/modules/remote_management/oneview/test_oneview_enclosure_facts.py b/test/units/modules/remote_management/oneview/test_oneview_enclosure_facts.py new file mode 100644 index 00000000000..5d4a480d900 --- /dev/null +++ b/test/units/modules/remote_management/oneview/test_oneview_enclosure_facts.py @@ -0,0 +1,134 @@ +# 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 ansible.compat.tests import unittest +from oneview_module_loader import OneViewModuleBase +from ansible.modules.remote_management.oneview.oneview_enclosure_facts import EnclosureFactsModule +from hpe_test_utils import FactsParamsTestCase + + +ERROR_MSG = 'Fake message error' + +PARAMS_GET_ALL = dict( + config='config.json', + name=None +) + +PARAMS_GET_BY_NAME = dict( + config='config.json', + name="Test-Enclosure", + options=[] +) + +PARAMS_GET_BY_NAME_WITH_OPTIONS = dict( + config='config.json', + name="Test-Enclosure", + options=['utilization', 'environmentalConfiguration', 'script'] +) + +PARAMS_GET_UTILIZATION_WITH_PARAMS = dict( + config='config.json', + name="Test-Enclosure", + options=[dict(utilization=dict(fields='AveragePower', + filter=['startDate=2016-06-30T03:29:42.000Z', + 'endDate=2016-07-01T03:29:42.000Z'], + view='day', + refresh=True))] +) + +PRESENT_ENCLOSURES = [{ + "name": "Test-Enclosure", + "uri": "/rest/enclosures/c6bf9af9-48e7-4236-b08a-77684dc258a5" +}] + +ENCLOSURE_SCRIPT = '# script content' + +ENCLOSURE_UTILIZATION = { + "isFresh": "True" +} + +ENCLOSURE_ENVIRONMENTAL_CONFIG = { + "calibratedMaxPower": "2500" +} + + +class EnclosureFactsSpec(unittest.TestCase, + FactsParamsTestCase): + def setUp(self): + self.configure_mocks(self, EnclosureFactsModule) + self.enclosures = self.mock_ov_client.enclosures + FactsParamsTestCase.configure_client_mock(self, self.enclosures) + + def test_should_get_all_enclosures(self): + self.enclosures.get_all.return_value = PRESENT_ENCLOSURES + self.mock_ansible_module.params = PARAMS_GET_ALL + + EnclosureFactsModule().run() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(enclosures=(PRESENT_ENCLOSURES)) + ) + + def test_should_get_enclosure_by_name(self): + self.enclosures.get_by.return_value = PRESENT_ENCLOSURES + self.mock_ansible_module.params = PARAMS_GET_BY_NAME + + EnclosureFactsModule().run() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(enclosures=(PRESENT_ENCLOSURES)) + + ) + + def test_should_get_enclosure_by_name_with_options(self): + self.enclosures.get_by.return_value = PRESENT_ENCLOSURES + self.enclosures.get_script.return_value = ENCLOSURE_SCRIPT + self.enclosures.get_utilization.return_value = ENCLOSURE_UTILIZATION + self.enclosures.get_environmental_configuration.return_value = ENCLOSURE_ENVIRONMENTAL_CONFIG + + self.mock_ansible_module.params = PARAMS_GET_BY_NAME_WITH_OPTIONS + + EnclosureFactsModule().run() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(enclosures=PRESENT_ENCLOSURES, + enclosure_script=ENCLOSURE_SCRIPT, + enclosure_environmental_configuration=ENCLOSURE_ENVIRONMENTAL_CONFIG, + enclosure_utilization=ENCLOSURE_UTILIZATION) + + ) + + def test_should_get_all_utilization_data(self): + self.enclosures.get_by.return_value = PRESENT_ENCLOSURES + self.enclosures.get_script.return_value = ENCLOSURE_SCRIPT + self.enclosures.get_utilization.return_value = ENCLOSURE_UTILIZATION + self.enclosures.get_environmental_configuration.return_value = ENCLOSURE_ENVIRONMENTAL_CONFIG + + self.mock_ansible_module.params = PARAMS_GET_BY_NAME_WITH_OPTIONS + + EnclosureFactsModule().run() + + self.enclosures.get_utilization.assert_called_once_with(PRESENT_ENCLOSURES[0]['uri'], fields='', filter='', + view='', refresh='') + + def test_should_get_utilization_with_parameters(self): + self.enclosures.get_by.return_value = PRESENT_ENCLOSURES + self.enclosures.get_script.return_value = ENCLOSURE_SCRIPT + self.enclosures.get_utilization.return_value = ENCLOSURE_UTILIZATION + self.enclosures.get_environmental_configuration.return_value = ENCLOSURE_ENVIRONMENTAL_CONFIG + + self.mock_ansible_module.params = PARAMS_GET_UTILIZATION_WITH_PARAMS + + EnclosureFactsModule().run() + + date_filter = ["startDate=2016-06-30T03:29:42.000Z", "endDate=2016-07-01T03:29:42.000Z"] + + self.enclosures.get_utilization.assert_called_once_with( + PRESENT_ENCLOSURES[0]['uri'], fields='AveragePower', filter=date_filter, view='day', refresh=True) + + +if __name__ == '__main__': + unittest.main()