From a4ae8536d9393f1ab11a5ff440ddf361ed0dbc73 Mon Sep 17 00:00:00 2001 From: Felipe Garcia Bulsoni Date: Wed, 30 Aug 2017 11:46:05 -0300 Subject: [PATCH] NetworkSetFactsModule for HPE OneView (#28730) * Add NetworkSetFactsModule for retrieving HPE OneView Network Sets - Allow querying for Network Set resources in HPE OneView - Adds unit tests to new module - Updates oneview_module_loader copyright header to short GPL3 version * Adding possibility to pass in credentials as parameters * Removed required false and changed format of filter_by_name declaration * Updated examples in docs to reflect new way to pass in credentials - All examples of the oneview_network_set_facts updated to use credential parameters - All required=False from oneview base module removed - Shared docs updated to bring attention to API version being used --- lib/ansible/module_utils/oneview.py | 22 ++- .../oneview/oneview_network_set_facts.py | 152 ++++++++++++++++++ .../utils/module_docs_fragments/oneview.py | 15 +- .../oneview/oneview_module_loader.py | 19 +-- .../oneview/test_oneview_network_set_facts.py | 113 +++++++++++++ 5 files changed, 290 insertions(+), 31 deletions(-) create mode 100644 lib/ansible/modules/remote_management/oneview/oneview_network_set_facts.py create mode 100644 test/units/modules/remote_management/oneview/test_oneview_network_set_facts.py diff --git a/lib/ansible/module_utils/oneview.py b/lib/ansible/module_utils/oneview.py index 3c220e4700b..7a7a4c9276f 100644 --- a/lib/ansible/module_utils/oneview.py +++ b/lib/ansible/module_utils/oneview.py @@ -202,15 +202,15 @@ class OneViewModuleBase(object): HPE_ONEVIEW_SDK_REQUIRED = 'HPE OneView Python SDK is required for this module.' ONEVIEW_COMMON_ARGS = dict( - config=dict(required=False, type='str') + config=dict(type='path'), + hostname=dict(type='str'), + username=dict(type='str'), + password=dict(type='str'), + api_version=dict(type='int'), + image_streamer_hostname=dict(type='str') ) - ONEVIEW_VALIDATE_ETAG_ARGS = dict( - validate_etag=dict( - required=False, - type='bool', - default=True) - ) + ONEVIEW_VALIDATE_ETAG_ARGS = dict(validate_etag=dict(type='bool', default=True)) resource_client = None @@ -257,7 +257,13 @@ class OneViewModuleBase(object): self.module.fail_json(msg=self.HPE_ONEVIEW_SDK_REQUIRED) def _create_oneview_client(self): - if not self.module.params['config']: + if self.module.params.get('hostname'): + config = dict(ip=self.module.params['hostname'], + credentials=dict(userName=self.module.params['username'], password=self.module.params['password']), + api_version=self.module.params['api_version'], + image_streamer_ip=self.module.params['image_streamer_hostname']) + self.oneview_client = OneViewClient(config) + elif not self.module.params['config']: self.oneview_client = OneViewClient.from_environment_variables() else: self.oneview_client = OneViewClient.from_json_file(self.module.params['config']) diff --git a/lib/ansible/modules/remote_management/oneview/oneview_network_set_facts.py b/lib/ansible/modules/remote_management/oneview/oneview_network_set_facts.py new file mode 100644 index 00000000000..0b3d5793214 --- /dev/null +++ b/lib/ansible/modules/remote_management/oneview/oneview_network_set_facts.py @@ -0,0 +1,152 @@ +#!/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_network_set_facts +short_description: Retrieve facts about the OneView Network Sets +description: + - Retrieve facts about the Network Sets from OneView. +version_added: "2.4" +requirements: + - hpOneView >= 2.0.1 +author: + - Felipe Bulsoni (@fgbulsoni) + - Thiago Miotto (@tmiotto) + - Adriane Cardozo (@adriane-cardozo) +options: + name: + description: + - Network Set name. + + options: + description: + - "List with options to gather facts about Network Set. + Option allowed: C(withoutEthernet). + The option C(withoutEthernet) retrieves the list of network_sets excluding Ethernet networks." + +extends_documentation_fragment: + - oneview + - oneview.factsparams +''' + +EXAMPLES = ''' +- name: Gather facts about all Network Sets + oneview_network_set_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + no_log: true + delegate_to: localhost + +- debug: var=network_sets + +- name: Gather paginated, filtered, and sorted facts about Network Sets + oneview_network_set_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + params: + start: 0 + count: 3 + sort: 'name:descending' + filter: name='netset001' + no_log: true + delegate_to: localhost + +- debug: var=network_sets + +- name: Gather facts about all Network Sets, excluding Ethernet networks + oneview_network_set_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + options: + - withoutEthernet + no_log: true + delegate_to: localhost + +- debug: var=network_sets + + +- name: Gather facts about a Network Set by name + oneview_network_set_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + name: Name of the Network Set + no_log: true + delegate_to: localhost + +- debug: var=network_sets + + +- name: Gather facts about a Network Set by name, excluding Ethernet networks + oneview_network_set_facts: + hostname: 172.16.101.48 + username: administrator + password: my_password + api_version: 500 + name: Name of the Network Set + options: + - withoutEthernet + no_log: true + delegate_to: localhost + +- debug: var=network_sets +''' + +RETURN = ''' +network_sets: + description: Has all the OneView facts about the Network Sets. + returned: Always, but can be empty. + type: dict +''' + +from ansible.module_utils.oneview import OneViewModuleBase + + +class NetworkSetFactsModule(OneViewModuleBase): + argument_spec = dict( + name=dict(type='str'), + options=dict(type='list'), + params=dict(type='dict'), + ) + + def __init__(self): + super(NetworkSetFactsModule, self).__init__(additional_arg_spec=self.argument_spec) + + def execute_module(self): + + name = self.module.params.get('name') + + if 'withoutEthernet' in self.options: + filter_by_name = ("\"'name'='%s'\"" % name) if name else '' + network_sets = self.oneview_client.network_sets.get_all_without_ethernet(filter=filter_by_name) + elif name: + network_sets = self.oneview_client.network_sets.get_by('name', name) + else: + network_sets = self.oneview_client.network_sets.get_all(**self.facts_params) + + return dict(changed=False, + ansible_facts=dict(network_sets=network_sets)) + + +def main(): + NetworkSetFactsModule().run() + + +if __name__ == '__main__': + main() diff --git a/lib/ansible/utils/module_docs_fragments/oneview.py b/lib/ansible/utils/module_docs_fragments/oneview.py index f54319cb96d..88429522b24 100644 --- a/lib/ansible/utils/module_docs_fragments/oneview.py +++ b/lib/ansible/utils/module_docs_fragments/oneview.py @@ -27,10 +27,9 @@ options: The configuration file is optional and when used should be present in the host running the ansible commands. If the file path is not provided, the configuration will be loaded from environment variables. For links to example configuration files or how to use the environment variables verify the notes section. - required: false requirements: - - "python >= 2.7.9" + - python >= 2.7.9 notes: - "A sample configuration file for the config parameter can be found at: @@ -39,6 +38,9 @@ notes: U(https://github.com/HewlettPackard/oneview-ansible#environment-variables)" - "Additional Playbooks for the HPE OneView Ansible modules can be found at: U(https://github.com/HewlettPackard/oneview-ansible/tree/master/examples)" + - "The OneView API version used will directly affect returned and expected fields in resources. + Information on setting the desired API version and can be found at: + U(https://github.com/HewlettPackard/oneview-ansible#setting-your-oneview-version)" ''' VALIDATEETAG = ''' @@ -57,9 +59,8 @@ options: description: - List of params to delimit, filter and sort the list of resources. - "params allowed: - C(start): The first item to return, using 0-based indexing. - C(count): The number of resources to return. - C(filter): A general filter/query string to narrow the list of items returned. - C(sort): The sort order of the returned data set." - required: false + - C(start): The first item to return, using 0-based indexing. + - C(count): The number of resources to return. + - C(filter): A general filter/query string to narrow the list of items returned. + - C(sort): The sort order of the returned data set." ''' diff --git a/test/units/modules/remote_management/oneview/oneview_module_loader.py b/test/units/modules/remote_management/oneview/oneview_module_loader.py index c448b69c1d1..f1ddc3bef99 100644 --- a/test/units/modules/remote_management/oneview/oneview_module_loader.py +++ b/test/units/modules/remote_management/oneview/oneview_module_loader.py @@ -1,19 +1,5 @@ -# -*- coding: utf-8 -*- -# -# Copyright (2016-2017) Hewlett Packard Enterprise Development LP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 sys from ansible.compat.tests.mock import patch, Mock @@ -34,3 +20,4 @@ from ansible.modules.remote_management.oneview.oneview_fc_network import FcNetwo from ansible.modules.remote_management.oneview.oneview_fc_network_facts import FcNetworkFactsModule from ansible.modules.remote_management.oneview.oneview_fcoe_network import FcoeNetworkModule from ansible.modules.remote_management.oneview.oneview_network_set import NetworkSetModule +from ansible.modules.remote_management.oneview.oneview_network_set_facts import NetworkSetFactsModule diff --git a/test/units/modules/remote_management/oneview/test_oneview_network_set_facts.py b/test/units/modules/remote_management/oneview/test_oneview_network_set_facts.py new file mode 100644 index 00000000000..6fe66df45d6 --- /dev/null +++ b/test/units/modules/remote_management/oneview/test_oneview_network_set_facts.py @@ -0,0 +1,113 @@ +# 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 NetworkSetFactsModule +from hpe_test_utils import FactsParamsTestCase + +ERROR_MSG = 'Fake message error' + +PARAMS_GET_ALL = dict( + config='config.json', + name=None +) + +PARAMS_GET_ALL_WITHOUT_ETHERNET = dict( + config='config.json', + name=None, + options=['withoutEthernet'] +) + +PARAMS_GET_BY_NAME = dict( + config='config.json', + name='Network Set 1' +) + +PARAMS_GET_BY_NAME_WITHOUT_ETHERNET = dict( + config='config.json', + name='Network Set 1', + options=['withoutEthernet'] +) + + +class NetworkSetFactsSpec(unittest.TestCase, + FactsParamsTestCase): + def setUp(self): + self.configure_mocks(self, NetworkSetFactsModule) + self.network_sets = self.mock_ov_client.network_sets + FactsParamsTestCase.configure_client_mock(self, self.network_sets) + + def test_should_get_all_network_sets(self): + network_sets = [{ + "name": "Network Set 1", + "networkUris": ['/rest/ethernet-networks/aaa-bbb-ccc'] + }, { + "name": "Network Set 2", + "networkUris": ['/rest/ethernet-networks/ddd-eee-fff', '/rest/ethernet-networks/ggg-hhh-fff'] + }] + + self.network_sets.get_all.return_value = network_sets + self.mock_ansible_module.params = PARAMS_GET_ALL + + NetworkSetFactsModule().run() + + self.network_sets.get_all.assert_called_once_with() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(network_sets=network_sets)) + + def test_should_get_all_network_sets_without_ethernet(self): + network_sets = [{ + "name": "Network Set 1", + "networkUris": [] + }, { + "name": "Network Set 2", + "networkUris": [] + }] + + self.network_sets.get_all.return_value = network_sets + self.mock_ansible_module.params = PARAMS_GET_ALL + + NetworkSetFactsModule().run() + + self.network_sets.get_all.assert_called_once_with() + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(network_sets=network_sets)) + + def test_should_get_network_set_by_name(self): + network_sets = [{ + "name": "Network Set 1", + "networkUris": ['/rest/ethernet-networks/aaa-bbb-ccc'] + }] + + self.network_sets.get_by.return_value = network_sets + self.mock_ansible_module.params = PARAMS_GET_BY_NAME + + NetworkSetFactsModule().run() + + self.network_sets.get_by.assert_called_once_with('name', 'Network Set 1') + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(network_sets=network_sets)) + + def test_should_get_network_set_by_name_without_ethernet(self): + network_sets = [{ + "name": "Network Set 1", + "networkUris": [] + }] + + self.network_sets.get_all_without_ethernet.return_value = network_sets + self.mock_ansible_module.params = PARAMS_GET_BY_NAME_WITHOUT_ETHERNET + + NetworkSetFactsModule().run() + + expected_filter = "\"'name'='Network Set 1'\"" + self.network_sets.get_all_without_ethernet.assert_called_once_with(filter=expected_filter) + + self.mock_ansible_module.exit_json.assert_called_once_with( + changed=False, + ansible_facts=dict(network_sets=network_sets))