mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-10-23 20:44:00 -07:00
Initial commits for integration of HPE OneView resources with Ansible (#26026)
* Initial commit for integration of HPE OneView resources with Ansible Core. Adding FC Network and FC Network Fact modules and unit tests, and OneView base class for all OV resources.
This commit is contained in:
parent
8bb10bb225
commit
b060d0ccba
8 changed files with 964 additions and 0 deletions
0
test/units/modules/remote_management/__init__.py
Normal file
0
test/units/modules/remote_management/__init__.py
Normal file
137
test/units/modules/remote_management/hpe/hpe_test_utils.py
Normal file
137
test/units/modules/remote_management/hpe/hpe_test_utils.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# -*- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml
|
||||
from mock import Mock, patch
|
||||
from oneview_module_loader import ONEVIEW_MODULE_UTILS_PATH
|
||||
from hpOneView.oneview_client import OneViewClient
|
||||
|
||||
|
||||
class OneViewBaseTestCase(object):
|
||||
mock_ov_client_from_json_file = None
|
||||
testing_class = None
|
||||
mock_ansible_module = None
|
||||
mock_ov_client = None
|
||||
testing_module = None
|
||||
EXAMPLES = None
|
||||
|
||||
def configure_mocks(self, test_case, testing_class):
|
||||
"""
|
||||
Preload mocked OneViewClient instance and AnsibleModule
|
||||
Args:
|
||||
test_case (object): class instance (self) that are inheriting from OneViewBaseTestCase
|
||||
testing_class (object): class being tested
|
||||
"""
|
||||
self.testing_class = testing_class
|
||||
|
||||
# Define OneView Client Mock (FILE)
|
||||
patcher_json_file = patch.object(OneViewClient, 'from_json_file')
|
||||
test_case.addCleanup(patcher_json_file.stop)
|
||||
self.mock_ov_client_from_json_file = patcher_json_file.start()
|
||||
|
||||
# Define OneView Client Mock
|
||||
self.mock_ov_client = self.mock_ov_client_from_json_file.return_value
|
||||
|
||||
# Define Ansible Module Mock
|
||||
patcher_ansible = patch(ONEVIEW_MODULE_UTILS_PATH + '.AnsibleModule')
|
||||
test_case.addCleanup(patcher_ansible.stop)
|
||||
mock_ansible_module = patcher_ansible.start()
|
||||
self.mock_ansible_module = Mock()
|
||||
mock_ansible_module.return_value = self.mock_ansible_module
|
||||
|
||||
self.__set_module_examples()
|
||||
|
||||
def test_main_function_should_call_run_method(self):
|
||||
self.mock_ansible_module.params = {'config': 'config.json'}
|
||||
|
||||
main_func = getattr(self.testing_module, 'main')
|
||||
|
||||
with patch.object(self.testing_class, "run") as mock_run:
|
||||
main_func()
|
||||
mock_run.assert_called_once()
|
||||
|
||||
def __set_module_examples(self):
|
||||
# Load scenarios from module examples (Also checks if it is a valid yaml)
|
||||
ansible = __import__('ansible')
|
||||
testing_module = self.testing_class.__module__.split('.')[-1]
|
||||
self.testing_module = getattr(ansible.modules.remote_management.hpe, testing_module)
|
||||
|
||||
try:
|
||||
# Load scenarios from module examples (Also checks if it is a valid yaml)
|
||||
self.EXAMPLES = yaml.load(self.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)
|
||||
|
||||
|
||||
class FactsParamsTestCase(OneViewBaseTestCase):
|
||||
"""
|
||||
FactsParamsTestCase has common test for classes that support pass additional
|
||||
parameters when retrieving all resources.
|
||||
"""
|
||||
|
||||
def configure_client_mock(self, resorce_client):
|
||||
"""
|
||||
Args:
|
||||
resorce_client: Resource client that is being called
|
||||
"""
|
||||
self.resource_client = resorce_client
|
||||
|
||||
def __validations(self):
|
||||
if not self.testing_class:
|
||||
raise Exception("Mocks are not configured, you must call 'configure_mocks' before running this test.")
|
||||
|
||||
if not self.resource_client:
|
||||
raise Exception(
|
||||
"Mock for the client not configured, you must call 'configure_client_mock' before running this test.")
|
||||
|
||||
def test_should_get_all_using_filters(self):
|
||||
self.__validations()
|
||||
self.resource_client.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_client.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):
|
||||
self.__validations()
|
||||
self.resource_client.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_client.get_all.assert_called_once_with()
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# -*- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
from ansible.compat.tests.mock import patch, Mock
|
||||
sys.modules['hpOneView'] = Mock()
|
||||
sys.modules['hpOneView.oneview_client'] = Mock()
|
||||
sys.modules['hpOneView.exceptions'] = Mock()
|
||||
sys.modules['future'] = Mock()
|
||||
sys.modules['__future__'] = Mock()
|
||||
|
||||
ONEVIEW_MODULE_UTILS_PATH = 'ansible.module_utils.oneview'
|
||||
from ansible.module_utils.oneview import (HPOneViewException,
|
||||
HPOneViewTaskError,
|
||||
OneViewModuleBase)
|
||||
|
||||
from ansible.modules.remote_management.hpe.oneview_fc_network import FcNetworkModule
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
# -*- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ansible.compat.tests import unittest
|
||||
from oneview_module_loader import FcNetworkModule
|
||||
from hpe_test_utils import OneViewBaseTestCase
|
||||
|
||||
FAKE_MSG_ERROR = 'Fake message error'
|
||||
|
||||
DEFAULT_FC_NETWORK_TEMPLATE = dict(
|
||||
name='New FC Network 2',
|
||||
autoLoginRedistribution=True,
|
||||
fabricType='FabricAttach'
|
||||
)
|
||||
|
||||
PARAMS_FOR_PRESENT = dict(
|
||||
config='config.json',
|
||||
state='present',
|
||||
data=dict(name=DEFAULT_FC_NETWORK_TEMPLATE['name'])
|
||||
)
|
||||
|
||||
PARAMS_WITH_CHANGES = dict(
|
||||
config='config.json',
|
||||
state='present',
|
||||
data=dict(name=DEFAULT_FC_NETWORK_TEMPLATE['name'],
|
||||
newName="New Name",
|
||||
fabricType='DirectAttach')
|
||||
)
|
||||
|
||||
PARAMS_FOR_ABSENT = dict(
|
||||
config='config.json',
|
||||
state='absent',
|
||||
data=dict(name=DEFAULT_FC_NETWORK_TEMPLATE['name'])
|
||||
)
|
||||
|
||||
|
||||
class FcNetworkModuleSpec(unittest.TestCase,
|
||||
OneViewBaseTestCase):
|
||||
"""
|
||||
OneViewBaseTestCase provides the mocks used in this test case
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.configure_mocks(self, FcNetworkModule)
|
||||
self.resource = self.mock_ov_client.fc_networks
|
||||
|
||||
def test_should_create_new_fc_network(self):
|
||||
self.resource.get_by.return_value = []
|
||||
self.resource.create.return_value = DEFAULT_FC_NETWORK_TEMPLATE
|
||||
|
||||
self.mock_ansible_module.params = PARAMS_FOR_PRESENT
|
||||
|
||||
FcNetworkModule().run()
|
||||
|
||||
self.mock_ansible_module.exit_json.assert_called_once_with(
|
||||
changed=True,
|
||||
msg=FcNetworkModule.MSG_CREATED,
|
||||
ansible_facts=dict(fc_network=DEFAULT_FC_NETWORK_TEMPLATE)
|
||||
)
|
||||
|
||||
def test_should_not_update_when_data_is_equals(self):
|
||||
self.resource.get_by.return_value = [DEFAULT_FC_NETWORK_TEMPLATE]
|
||||
|
||||
self.mock_ansible_module.params = PARAMS_FOR_PRESENT
|
||||
|
||||
FcNetworkModule().run()
|
||||
|
||||
self.mock_ansible_module.exit_json.assert_called_once_with(
|
||||
changed=False,
|
||||
msg=FcNetworkModule.MSG_ALREADY_PRESENT,
|
||||
ansible_facts=dict(fc_network=DEFAULT_FC_NETWORK_TEMPLATE)
|
||||
)
|
||||
|
||||
def test_update_when_data_has_modified_attributes(self):
|
||||
data_merged = DEFAULT_FC_NETWORK_TEMPLATE.copy()
|
||||
|
||||
data_merged['fabricType'] = 'DirectAttach'
|
||||
|
||||
self.resource.get_by.return_value = [DEFAULT_FC_NETWORK_TEMPLATE]
|
||||
self.resource.update.return_value = data_merged
|
||||
|
||||
self.mock_ansible_module.params = PARAMS_WITH_CHANGES
|
||||
|
||||
FcNetworkModule().run()
|
||||
|
||||
self.mock_ansible_module.exit_json.assert_called_once_with(
|
||||
changed=True,
|
||||
msg=FcNetworkModule.MSG_UPDATED,
|
||||
ansible_facts=dict(fc_network=data_merged)
|
||||
)
|
||||
|
||||
def test_should_remove_fc_network(self):
|
||||
self.resource.get_by.return_value = [DEFAULT_FC_NETWORK_TEMPLATE]
|
||||
|
||||
self.mock_ansible_module.params = PARAMS_FOR_ABSENT
|
||||
|
||||
FcNetworkModule().run()
|
||||
|
||||
self.mock_ansible_module.exit_json.assert_called_once_with(
|
||||
changed=True,
|
||||
msg=FcNetworkModule.MSG_DELETED
|
||||
)
|
||||
|
||||
def test_should_do_nothing_when_fc_network_not_exist(self):
|
||||
self.resource.get_by.return_value = []
|
||||
|
||||
self.mock_ansible_module.params = PARAMS_FOR_ABSENT
|
||||
|
||||
FcNetworkModule().run()
|
||||
|
||||
self.mock_ansible_module.exit_json.assert_called_once_with(
|
||||
changed=False,
|
||||
msg=FcNetworkModule.MSG_ALREADY_ABSENT
|
||||
)
|
||||
|
||||
def test_update_scopes_when_different(self):
|
||||
params_to_scope = PARAMS_FOR_PRESENT.copy()
|
||||
params_to_scope['data']['scopeUris'] = ['test']
|
||||
self.mock_ansible_module.params = params_to_scope
|
||||
|
||||
resource_data = DEFAULT_FC_NETWORK_TEMPLATE.copy()
|
||||
resource_data['scopeUris'] = ['fake']
|
||||
resource_data['uri'] = 'rest/fc/fake'
|
||||
self.resource.get_by.return_value = [resource_data]
|
||||
|
||||
patch_return = resource_data.copy()
|
||||
patch_return['scopeUris'] = ['test']
|
||||
self.resource.patch.return_value = patch_return
|
||||
|
||||
FcNetworkModule().run()
|
||||
|
||||
self.resource.patch.assert_called_once_with('rest/fc/fake',
|
||||
operation='replace',
|
||||
path='/scopeUris',
|
||||
value=['test'])
|
||||
|
||||
self.mock_ansible_module.exit_json.assert_called_once_with(
|
||||
changed=True,
|
||||
ansible_facts=dict(fc_network=patch_return),
|
||||
msg=FcNetworkModule.MSG_UPDATED
|
||||
)
|
||||
|
||||
def test_should_do_nothing_when_scopes_are_the_same(self):
|
||||
params_to_scope = PARAMS_FOR_PRESENT.copy()
|
||||
params_to_scope['data']['scopeUris'] = ['test']
|
||||
self.mock_ansible_module.params = params_to_scope
|
||||
|
||||
resource_data = DEFAULT_FC_NETWORK_TEMPLATE.copy()
|
||||
resource_data['scopeUris'] = ['test']
|
||||
self.resource.get_by.return_value = [resource_data]
|
||||
|
||||
FcNetworkModule().run()
|
||||
|
||||
self.resource.patch.not_been_called()
|
||||
|
||||
self.mock_ansible_module.exit_json.assert_called_once_with(
|
||||
changed=False,
|
||||
ansible_facts=dict(fc_network=resource_data),
|
||||
msg=FcNetworkModule.MSG_ALREADY_PRESENT
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue