Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commits for integration of HPE OneView resources with Ansible #26026

Merged
merged 19 commits into from Aug 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5fd572d
Initial commit for integration of HPE OneView resources with Ansible …
fgbulsoni Jun 22, 2017
7969abe
Adding mocks for oneview module imports and removing shebangs from fi…
fgbulsoni Jun 26, 2017
8af214c
Changing OrderedDict imports and calls syntax for unit tests to pass
fgbulsoni Jun 28, 2017
b11506b
Changing import of unittest to use ansible.compat.tests
fgbulsoni Jul 3, 2017
b474022
Changing status on ansible metadata from stableinterface to preview
fgbulsoni Jul 3, 2017
ce27f80
Removed FcNetworkFacts module so the PR features only one module
fgbulsoni Jul 7, 2017
513c098
Removed hpOneView requirement from unit tests and fixed importlib iss…
fgbulsoni Jul 13, 2017
4da165f
Skipping future import in case it is not available
fgbulsoni Jul 13, 2017
a39a5bc
Moving module from cloud to remote_management and changing author to …
fgbulsoni Jul 14, 2017
e783df0
Changed dual underscore convention for single underscore in all priva…
fgbulsoni Jul 28, 2017
171986a
Adding documentation mentioning to check notes section when trying to…
fgbulsoni Aug 1, 2017
40c6376
Adding __metadata__ and changing __future__ import to try to fix code…
fgbulsoni Aug 1, 2017
4872896
Moved ResourceComparator methods to OneViewModuleBase and changed log…
fgbulsoni Aug 1, 2017
a6cdde8
Moved python requirement from module to doc fragments, removed deepco…
fgbulsoni Aug 2, 2017
a5e98bd
Removed future required message since future is no longer used
fgbulsoni Aug 2, 2017
80a76c9
fixed imports order, removed logging import, changed style of add abc…
fgbulsoni Aug 2, 2017
c8d3fdc
Fixed docstrings and docstrings identation, removed a couple of copy …
fgbulsoni Aug 2, 2017
e36e64b
Changed condition of not <reference> to is None according to review.
fgbulsoni Aug 2, 2017
09142f4
Moving toplevel functions out of OneViewBaseClass and changing the li…
fgbulsoni Aug 2, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
433 changes: 433 additions & 0 deletions lib/ansible/module_utils/oneview.py

Large diffs are not rendered by default.

Empty file.
124 changes: 124 additions & 0 deletions lib/ansible/modules/remote_management/hpe/oneview_fc_network.py
@@ -0,0 +1,124 @@
#!/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.0',
'status': ['preview'],
'supported_by': 'community'}

DOCUMENTATION = '''
---
module: oneview_fc_network
short_description: Manage OneView Fibre Channel Network resources.
description:
- Provides an interface to manage Fibre Channel Network resources. Can create, update, and delete.
version_added: "2.4"
requirements:
- "hpOneView >= 4.0.0"
author: "Felipe Bulsoni (@fgbulsoni)"
options:
state:
description:
- Indicates the desired state for the Fibre Channel Network resource.
C(present) will ensure data properties are compliant with OneView.
C(absent) will remove the resource from OneView, if it exists.
choices: ['present', 'absent']
data:
description:
- List with the Fibre Channel Network properties.
required: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jimi-c are we okay with modules that just have a free-form data parameter?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jimi-c said on slack that this is fine.

We have added a new feature in 2.4 that allows specifying the structure of objects inside of a list if you want to do that. It could also be done as an update to the module. (I'm not entirely sure how to use it yet, knowledge of usage is still percolating out).


extends_documentation_fragment:
- oneview
- oneview.validateetag
'''

EXAMPLES = '''
- name: Ensure that the Fibre Channel Network is present using the default configuration
oneview_fc_network:
config: "{{ config_file_path }}"
state: present
data:
name: 'New FC Network'

- name: Ensure that the Fibre Channel Network is present with fabricType 'DirectAttach'
oneview_fc_network:
config: "{{ config_file_path }}"
state: present
data:
name: 'New FC Network'
fabricType: 'DirectAttach'

- name: Ensure that the Fibre Channel Network is present and is inserted in the desired scopes
oneview_fc_network:
config: "{{ config_file_path }}"
state: present
data:
name: 'New FC Network'
scopeUris:
- '/rest/scopes/00SC123456'
- '/rest/scopes/01SC123456'

- name: Ensure that the Fibre Channel Network is absent
oneview_fc_network:
config: "{{ config_file_path }}"
state: absent
data:
name: 'New FC Network'
'''

RETURN = '''
fc_network:
description: Has the facts about the managed OneView FC Network.
returned: On state 'present'. Can be null.
type: dict
'''

from ansible.module_utils.oneview import OneViewModuleBase


class FcNetworkModule(OneViewModuleBase):
MSG_CREATED = 'FC Network created successfully.'
MSG_UPDATED = 'FC Network updated successfully.'
MSG_DELETED = 'FC Network deleted successfully.'
MSG_ALREADY_PRESENT = 'FC Network is already present.'
MSG_ALREADY_ABSENT = 'FC Network is already absent.'
RESOURCE_FACT_NAME = 'fc_network'

def __init__(self):

additional_arg_spec = dict(data=dict(required=True, type='dict'),
state=dict(
required=True,
choices=['present', 'absent']))

super(FcNetworkModule, self).__init__(additional_arg_spec=additional_arg_spec,
validate_etag_support=True)

self.resource_client = self.oneview_client.fc_networks

def execute_module(self):
resource = self.get_by_name(self.data['name'])

if self.state == 'present':
return self._present(resource)
else:
return self.resource_absent(resource)

def _present(self, resource):
scope_uris = self.data.pop('scopeUris', None)
result = self.resource_present(resource, self.RESOURCE_FACT_NAME)
if scope_uris is not None:
result = self.resource_scopes_set(result, 'fc_network', scope_uris)
return result


def main():
FcNetworkModule().run()


if __name__ == '__main__':
main()
65 changes: 65 additions & 0 deletions lib/ansible/utils/module_docs_fragments/oneview.py
@@ -0,0 +1,65 @@
# -*- 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/>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to, you can change this license header to the short, one line version as shown here: https://github.com/ansible/ansible/blob/devel/docs/docsite/rst/dev_guide/developing_modules_documenting.rst#copyright

I've been trying to move modules to that since modules are copied over the network to the remote machine and so making them smaller can speed that up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so, in that link I see this short licence:

#!/usr/bin/python
# Copyright (c) 2017 [New Contributor(s)]
# Copyright (c) 2015 [Original Contributor(s)]
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

I'm assuming the oneview_fc_network.py will then have:

#!/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) 

Correct? Also, since that licence is GNU and module_utils must be BSD, is there a similar model for BSD?



class ModuleDocFragment(object):

# OneView doc fragment
DOCUMENTATION = '''
options:
config:
description:
- Path to a .json configuration file containing the OneView client configuration.
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"

notes:
- "A sample configuration file for the config parameter can be found at:
U(https://github.com/HewlettPackard/oneview-ansible/blob/master/examples/oneview_config-rename.json)"
- "Check how to use environment variables for configuration at:
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)"
'''

VALIDATEETAG = '''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this and the FACTSPARAMS variables do anything? I was unaware that the documentation generator would make use of anything besides DOCUMENTATION.

Copy link
Contributor Author

@fgbulsoni fgbulsoni Aug 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, it is apparently able to use it when extending documentation.

I see this inside the FCNetworkModule:

extends_documentation_fragment:
    - oneview
    - oneview.validateetag

And looking at the oneview_fc_network_module.rst file inside docs:

(...)
        truefalse
        When the ETag Validation is enabled, the request will be conditionally processed only if the current ETag for the resource matches the ETag provided in the data.        
(...)

And we also have facts modules which call the FACTSPARAMS for extending documentation, so these should be useful.

options:
validate_etag:
description:
- When the ETag Validation is enabled, the request will be conditionally processed only if the current ETag
for the resource matches the ETag provided in the data.
default: true
choices: ['true', 'false']
'''

FACTSPARAMS = '''
options:
params:
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
'''
Empty file.
137 changes: 137 additions & 0 deletions test/units/modules/remote_management/hpe/hpe_test_utils.py
@@ -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()
31 changes: 31 additions & 0 deletions test/units/modules/remote_management/hpe/oneview_module_loader.py
@@ -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