From 9283772e545e6046814d7f0f099677fb32b4a471 Mon Sep 17 00:00:00 2001 From: Sumit Kumar Date: Wed, 25 Jan 2017 04:51:57 -0500 Subject: [PATCH] Add doc_fragment and module util for NetApp platforms (#19607) * Add doc_fragment and module util for NetApp platforms * Make requested changes * Fix links and change formatting. * Fix description sections. --- .../dev_guide/developing_module_utilities.rst | 2 +- lib/ansible/module_utils/netapp.py | 90 ++++ lib/ansible/modules/storage/netapp/README.md | 454 ------------------ .../utils/module_docs_fragments/netapp.py | 80 +++ 4 files changed, 171 insertions(+), 455 deletions(-) create mode 100644 lib/ansible/module_utils/netapp.py delete mode 100644 lib/ansible/modules/storage/netapp/README.md create mode 100644 lib/ansible/utils/module_docs_fragments/netapp.py diff --git a/docs/docsite/rst/dev_guide/developing_module_utilities.rst b/docs/docsite/rst/dev_guide/developing_module_utilities.rst index 40e78afa8a..84add50cff 100644 --- a/docs/docsite/rst/dev_guide/developing_module_utilities.rst +++ b/docs/docsite/rst/dev_guide/developing_module_utilities.rst @@ -27,6 +27,7 @@ The following is a list of module_utils files and a general description. The mod - junos.py - Definitions and helper functions for modules that manage Junos networking devices - known_hosts.py - utilities for working with known_hosts file - mysql.py - Allows modules to connect to a MySQL instance +- netapp.py - Functions and utilities for modules that work with the NetApp storage platforms. - netcfg.py - Configuration utility functions for use by networking modules - netcmd.py - Defines commands and comparison operators for use in networking modules - network.py - Functions for running commands on networking devices @@ -45,4 +46,3 @@ The following is a list of module_utils files and a general description. The mod - vca.py - Contains utilities for modules that work with VMware vCloud Air - vmware.py - Contains utilities for modules that work with VMware vSphere VMs - vyos.py - Definitions and functions for working with VyOS networking - diff --git a/lib/ansible/module_utils/netapp.py b/lib/ansible/module_utils/netapp.py new file mode 100644 index 0000000000..20b8e23443 --- /dev/null +++ b/lib/ansible/module_utils/netapp.py @@ -0,0 +1,90 @@ +# +# (c) 2016, Sumit Kumar +# +# This file is part of Ansible +# +# Ansible 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. +# +# Ansible 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 Ansible. If not, see . + +HAS_NETAPP_LIB = False +try: + from netapp_lib.api.zapi import zapi + from netapp_lib.api.zapi import errors as zapi_errors + HAS_NETAPP_LIB = True +except: + HAS_NETAPP_LIB = False + + +HAS_SF_SDK = False +try: + from solidfire.factory import ElementFactory + from solidfire.custom.models import TimeIntervalFrequency + from solidfire.models import Schedule, ScheduleInfo + + HAS_SF_SDK = True +except: + HAS_SF_SDK = False + + +def has_netapp_lib(): + return HAS_NETAPP_LIB + + +def has_sf_sdk(): + return HAS_SF_SDK + + +def ontap_sf_host_argument_spec(): + + return dict( + hostname=dict(required=True, type='str'), + username=dict(required=True, type='str', aliases=['user']), + password=dict(required=True, type='str', aliases=['pass'], no_log=True), + ) + + +def create_sf_connection(module, port=None): + hostname = module.params['hostname'] + username = module.params['username'] + password = module.params['password'] + + if HAS_SF_SDK and hostname and username and password: + try: + return_val = ElementFactory.create(hostname, username, password, port=port) + return return_val + except: + raise Exception("Unable to create SF connection") + else: + module.fail_json(msg="the python SolidFire SDK module is required") + + +def setup_ontap_zapi(module, vserver=None): + hostname = module.params['hostname'] + username = module.params['username'] + password = module.params['password'] + + if HAS_NETAPP_LIB: + # set up zapi + server = zapi.NaServer(hostname) + server.set_username(username) + server.set_password(password) + if vserver: + server.set_vserver(vserver) + # Todo : Replace hard-coded values with configurable parameters. + server.set_api_version(major=1, minor=21) + server.set_port(80) + server.set_server_type('FILER') + server.set_transport_type('HTTP') + return server + else: + module.fail_json(msg="the python NetApp-Lib module is required") diff --git a/lib/ansible/modules/storage/netapp/README.md b/lib/ansible/modules/storage/netapp/README.md deleted file mode 100644 index 8d5ab2fd4c..0000000000 --- a/lib/ansible/modules/storage/netapp/README.md +++ /dev/null @@ -1,454 +0,0 @@ -#NetApp Storage Modules -This directory contains modules that support the storage platforms in the NetApp portfolio. - -##SANtricity Modules -The modules prefixed with *netapp\_e* are built to support the SANtricity storage platform. They require the SANtricity -WebServices Proxy. The WebServices Proxy is free software available at the [NetApp Software Download site](http://mysupport.netapp.com/NOW/download/software/eseries_webservices/1.40.X000.0009/). -Starting with the E2800 platform (11.30 OS), the modules will work directly with the storage array. Starting with this -platform, REST API requests are handled directly on the box. This array can still be managed by proxy for large scale deployments. -The modules provide idempotent provisioning for volume groups, disk pools, standard volumes, thin volumes, LUN mapping, -hosts, host groups (clusters), volume snapshots, consistency groups, and asynchronous mirroring. -### Prerequisites -| Software | Version | -| -------- |:-------:| -| SANtricity Web Services Proxy*|1.4 or 2.0| -| Ansible | 2.2** | -\* Not required for *E2800 with 11.30 OS*
-\*\*The modules where developed with this version. Ansible forward and backward compatibility applies. - -###Questions and Contribution -Please feel free to submit pull requests with improvements. Issues for these modules should be routed to @hulquest but -we also try to keep an eye on the list for issues specific to these modules. General questions can be made to our [development team](mailto:ng-hsg-engcustomer-esolutions-support@netapp.com) - -### Examples -These examples are not comprehensive but are intended to help you get started when integrating storage provisioning into -your playbooks. -```yml -- name: NetApp Test All Modules - hosts: proxy20 - gather_facts: yes - connection: local - vars: - storage_systems: - ansible1: - address1: "10.251.230.41" - address2: "10.251.230.42" - ansible2: - address1: "10.251.230.43" - address2: "10.251.230.44" - ansible3: - address1: "10.251.230.45" - address2: "10.251.230.46" - ansible4: - address1: "10.251.230.47" - address2: "10.251.230.48" - storage_pools: - Disk_Pool_1: - raid_level: raidDiskPool - criteria_drive_count: 11 - Disk_Pool_2: - raid_level: raidDiskPool - criteria_drive_count: 11 - Disk_Pool_3: - raid_level: raid0 - criteria_drive_count: 2 - volumes: - vol_1: - storage_pool_name: Disk_Pool_1 - size: 10 - thin_provision: false - thin_volume_repo_size: 7 - vol_2: - storage_pool_name: Disk_Pool_2 - size: 10 - thin_provision: false - thin_volume_repo_size: 7 - vol_3: - storage_pool_name: Disk_Pool_3 - size: 10 - thin_provision: false - thin_volume_repo_size: 7 - thin_vol_1: - storage_pool_name: Disk_Pool_1 - size: 10 - thin_provision: true - thin_volume_repo_size: 7 - hosts: - ANSIBLE-1: - host_type: 1 - index: 1 - ports: - - type: 'fc' - label: 'fpPort1' - port: '2100000E1E191B01' - - netapp_api_host: 10.251.230.29 - netapp_api_url: http://{{ netapp_api_host }}/devmgr/v2 - netapp_api_username: rw - netapp_api_password: rw - ssid: ansible1 - auth: no - lun_mapping: no - netapp_api_validate_certs: False - snapshot: no - gather_facts: no - amg_create: no - remove_volume: no - make_volume: no - check_thins: no - remove_storage_pool: yes - check_storage_pool: yes - remove_storage_system: no - check_storage_system: yes - change_role: no - flash_cache: False - configure_hostgroup: no - configure_async_mirror: False - configure_snapshot: no - copy_volume: False - volume_copy_source_volume_id: - volume_destination_source_volume_id: - snapshot_volume_storage_pool_name: Disk_Pool_3 - snapshot_volume_image_id: 3400000060080E5000299B640063074057BC5C5E - snapshot_volume: no - snapshot_volume_name: vol_1_snap_vol - host_type_index: 1 - host_name: ANSIBLE-1 - set_host: no - remove_host: no - amg_member_target_array: - amg_member_primary_pool: - amg_member_secondary_pool: - amg_member_primary_volume: - amg_member_secondary_volume: - set_amg_member: False - amg_array_name: foo - amg_name: amg_made_by_ansible - amg_secondaryArrayId: ansible2 - amg_sync_name: foo - amg_sync: no - - tasks: - - - name: Get array facts - netapp_e_facts: - ssid: "{{ item.key }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - with_dict: "{{ storage_systems }}" - when: gather_facts - - - name: Presence of storage system - netapp_e_storage_system: - ssid: "{{ item.key }}" - state: present - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - controller_addresses: - - "{{ item.value.address1 }}" - - "{{ item.value.address2 }}" - with_dict: "{{ storage_systems }}" - when: check_storage_system - - - name: Create Snapshot - netapp_e_snapshot_images: - ssid: "{{ ssid }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - snapshot_group: "ansible_snapshot_group" - state: 'create' - when: snapshot - - - name: Auth Module Example - netapp_e_auth: - ssid: "{{ ssid }}" - current_password: 'Infinit2' - new_password: 'Infinit1' - set_admin: yes - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - when: auth - - - name: No disk groups - netapp_e_storagepool: - ssid: "{{ ssid }}" - name: "{{ item }}" - state: absent - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - remove_volumes: yes - with_items: - - Disk_Pool_1 - - Disk_Pool_2 - - Disk_Pool_3 - when: remove_storage_pool - - - name: Make disk groups - netapp_e_storagepool: - ssid: "{{ ssid }}" - name: "{{ item.key }}" - state: present - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - raid_level: "{{ item.value.raid_level }}" - criteria_drive_count: "{{ item.value.criteria_drive_count }}" - with_dict: " {{ storage_pools }}" - when: check_storage_pool - - - name: No thin volume - netapp_e_volume: - ssid: "{{ ssid }}" - name: NewThinVolumeByAnsible - state: absent - thin_provision: yes - log_path: /tmp/volume.log - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - when: check_thins - - - name: Make a thin volume - netapp_e_volume: - ssid: "{{ ssid }}" - name: NewThinVolumeByAnsible - state: present - thin_provision: yes - thin_volume_repo_size: 7 - size: 10 - log_path: /tmp/volume.log - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - storage_pool_name: Disk_Pool_1 - when: check_thins - - - name: Remove standard/thick volumes - netapp_e_volume: - ssid: "{{ ssid }}" - name: "{{ item.key }}" - state: absent - log_path: /tmp/volume.log - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - with_dict: "{{ volumes }}" - when: remove_volume - - - name: Make a volume - netapp_e_volume: - ssid: "{{ ssid }}" - name: "{{ item.key }}" - state: present - storage_pool_name: "{{ item.value.storage_pool_name }}" - size: "{{ item.value.size }}" - thin_provision: "{{ item.value.thin_provision }}" - thin_volume_repo_size: "{{ item.value.thin_volume_repo_size }}" - log_path: /tmp/volume.log - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - with_dict: "{{ volumes }}" - when: make_volume - - - name: No storage system - netapp_e_storage_system: - ssid: "{{ item.key }}" - state: absent - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - with_dict: "{{ storage_systems }}" - when: remove_storage_system - - - name: Update the role of a storage array - netapp_e_amg_role: - name: "{{ amg_name }}" - role: primary - force: true - noSync: true - ssid: "{{ ssid }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - when: change_role - - - name: Flash Cache - netapp_e_flashcache: - ssid: "{{ ssid }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - name: SSDCacheBuiltByAnsible - when: flash_cache - - - name: Configure Hostgroup - netapp_e_hostgroup: - ssid: "{{ ssid }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - state: absent - name: "ansible-host-group" - when: configure_hostgroup - - - name: Configure Snapshot group - netapp_e_snapshot_group: - ssid: "{{ ssid }}" - state: present - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - validate_certs: "{{ netapp_api_validate_certs }}" - base_volume_name: vol_3 - name: ansible_snapshot_group - repo_pct: 20 - warning_threshold: 85 - delete_limit: 30 - full_policy: purgepit - storage_pool_name: Disk_Pool_3 - rollback_priority: medium - when: configure_snapshot - - - name: Copy volume - netapp_e_volume_copy: - ssid: "{{ ssid }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - status: present - source_volume_id: "{{ volume_copy_source_volume_id }}" - destination_volume_id: "{{ volume_destination_source_volume_id }}" - when: copy_volume - - - name: Snapshot volume - netapp_e_snapshot_volume: - ssid: "{{ ssid }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - state: present - storage_pool_name: "{{ snapshot_volume_storage_pool_name }}" - snapshot_image_id: "{{ snapshot_volume_image_id }}" - name: "{{ snapshot_volume_name }}" - when: snapshot_volume - - - name: Remove hosts - netapp_e_host: - ssid: "{{ ssid }}" - state: absent - name: "{{ item.key }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - host_type_index: "{{ host_type_index }}" - with_dict: "{{hosts}}" - when: remove_host - - - name: Ensure/add hosts - netapp_e_host: - ssid: "{{ ssid }}" - state: present - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - name: "{{ item.key }}" - host_type_index: "{{ item.value.index }}" - ports: - - type: 'fc' - label: 'fpPort1' - port: '2100000E1E191B01' - with_dict: "{{hosts}}" - when: set_host - - - name: Unmap a volume - netapp_e_lun_mapping: - state: absent - ssid: "{{ ssid }}" - lun: 2 - target: "{{ host_name }}" - volume_name: "thin_vol_1" - target_type: host - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - when: lun_mapping - - - name: Map a volume - netapp_e_lun_mapping: - state: present - ssid: "{{ ssid }}" - lun: 16 - target: "{{ host_name }}" - volume_name: "thin_vol_1" - target_type: host - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - when: lun_mapping - - - name: Update LUN Id - netapp_e_lun_mapping: - state: present - ssid: "{{ ssid }}" - lun: 2 - target: "{{ host_name }}" - volume_name: "thin_vol_1" - target_type: host - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - when: lun_mapping - - - name: AMG removal - netapp_e_amg: - state: absent - ssid: "{{ ssid }}" - secondaryArrayId: "{{amg_secondaryArrayId}}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - new_name: "{{amg_array_name}}" - name: "{{amg_name}}" - when: amg_create - - - name: AMG create - netapp_e_amg: - state: present - ssid: "{{ ssid }}" - secondaryArrayId: "{{amg_secondaryArrayId}}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - new_name: "{{amg_array_name}}" - name: "{{amg_name}}" - when: amg_create - - - name: start AMG async - netapp_e_amg_sync: - name: "{{ amg_name }}" - state: running - ssid: "{{ ssid }}" - api_url: "{{ netapp_api_url }}" - api_username: "{{ netapp_api_username }}" - api_password: "{{ netapp_api_password }}" - when: amg_sync -``` diff --git a/lib/ansible/utils/module_docs_fragments/netapp.py b/lib/ansible/utils/module_docs_fragments/netapp.py new file mode 100644 index 0000000000..9459302c37 --- /dev/null +++ b/lib/ansible/utils/module_docs_fragments/netapp.py @@ -0,0 +1,80 @@ +# +# (c) 2016, Sumit Kumar +# +# This file is part of Ansible +# +# Ansible 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. +# +# Ansible 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 Ansible. If not, see . + + +class ModuleDocFragment(object): + + DOCUMENTATION = """ +options: + - See respective platform section for more details +requirements: + - See respective platform section for more details +notes: + - Ansible modules are available for the following NetApp Storage Platforms: E-Series, ONTAP, SolidFire +""" + + # Documentation fragment for ONTAP + ONTAP = """ +options: + hostname: + required: true + description: + - The hostname or IP address of the ONTAP instance. + username: + required: true + description: + - Username: This can be a Cluster-scoped or SVM-scoped account, depending on whether a Cluster-level or SVM-level API is required. For more information, please read the documentation U(https://goo.gl/BRu78Z). + + password: + required: true + description: + - Password for the specified user. + +requirements: + - A physical or virtual clustered Data ONTAP system. The modules were developed with Clustered Data ONTAP 8.3 + - Ansible 2.2 + - netapp-lib (2015.9.25). Install using 'pip install netapp-lib' + +notes: + - The modules prefixed with C(netapp\_cdot) are built to support the ONTAP storage platform. + +""" + +# Documentation fragment for SolidFire + SOLIDFIRE = """ +options: + hostname: + required: true + description: + - The hostname or IP address of the SolidFire cluster. + username: + required: true + description: + - Username: Please ensure that the user has the adequate permissions. For more information, please read the official documentation U(https://goo.gl/ddJa4Q). + password: + required: true + description: + - Password for the specified user. + +requirements: + - solidfire-sdk-python (1.1.0.92) + +notes: + - The modules prefixed with C(sf\_) are built to support the SolidFire storage platform. + +"""