diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
commit | 975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch) | |
tree | 89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/netapp_eseries/santricity/roles | |
parent | Initial commit. (diff) | |
download | ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip |
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/netapp_eseries/santricity/roles')
42 files changed, 3795 insertions, 0 deletions
diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/.travis.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/.travis.yml new file mode 100644 index 000000000..36bbf6208 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/.travis.yml @@ -0,0 +1,29 @@ +--- +language: python +python: "2.7" + +# Use the new container infrastructure +sudo: false + +# Install ansible +addons: + apt: + packages: + - python-pip + +install: + # Install ansible + - pip install ansible + + # Check ansible version + - ansible --version + + # Create ansible.cfg with correct roles_path + - printf '[defaults]\nroles_path=../' >ansible.cfg + +script: + # Basic role syntax check + - ansible-playbook tests/test.yml -i tests/inventory --syntax-check + +notifications: + webhooks: https://galaxy.ansible.com/api/v1/notifications/
\ No newline at end of file diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/README.md b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/README.md new file mode 100644 index 000000000..b5ae41037 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/README.md @@ -0,0 +1,149 @@ +nar_santricity_common +===================== + Discover NetApp E-Series storage systems and configures SANtricity Web Services Proxy. + + The following variables will be added to the runtime host inventory. + current_eseries_api_url: # Web Services REST API URL + current_eseries_api_username: # Web Services REST API username + current_eseries_api_password: # Web Services REST API password + current_eseries_ssid: # Arbitrary string for the proxy to represent the storage system. + current_eseries_validate_certs: # Indicates whether SSL certificates should be verified. + current_eseries_api_is_proxy: # Indicates whether Web Services REST API is running on a proxy. + + +Requirements +------------ + - NetApp E-Series E2800 platform or newer or NetApp E-Series SANtricity Web Services Proxy configured for older E-Series storage systems. + +Tested Ansible Versions +----------------------- + - Ansible 5.x (ansible-core 2.12) + +Example Playbook +---------------- + - hosts: eseries_storage_systems + gather_facts: false + collection: + - netapp_eseries.santricity + tasks: + - name: Configure SANtricity Web Services and discover storage systems + import_role: + name: nar_santricity_common + + +Example Inventory Host file using discovery with proxy +------------------------------------------------------ + eseries_proxy_api_url: https://192.168.1.100:8443/devmgr/v2/ + eseries_proxy_api_password: admin_password + eseries_subnet: 192.168.1.0/24 # This should only be defined at the group level once when utilizing Web Services Proxy and should be broad enough to include all systems being added to proxy instance. + eseries_system_serial: 012345678901 + eseries_system_password: admin_password + eseries_validate_certs: false + (...) + + +Example Inventory Host file using discovery without proxy +--------------------------------------------------------- +**Note that while eseries_management_interfaces or eseries_system_api_url are optional, including at least one of them will prevent the discovery mechanism from being used when the system can be reached from their information. + eseries_subnet: 192.168.1.0/24 + eseries_system_serial: 012345678901 + eseries_system_password: admin_password + eseries_validate_certs: false + (...) + + +Example Inventory Host file without using discovery (Embedded Web Services) +--------------------------------------------------------------------------- + eseries_system_api_url: https://192.168.1.200:8443/devmgr/v2/ + eseries_system_password: admin_password + eseries_validate_certs: false + (...) + + +Example Inventory Host file without using discovery (Proxy Web Services - system must have already been added to the proxy) +------------------------------------------------------------------------ + eseries_proxy_ssid: storage_ssid + eseries_proxy_api_url: https://192.168.2.200:8443/devmgr/v2/ + eseries_proxy_api_password: admin_password + (...) + + +Notes +----- +Use SANtricity Web Services Proxy to avoid the need to discover the storage systems each time nar_santricity_common is executed. The first time nar_santricity_common is executed will add the storage systems the proxy so that they can be recalled without the need to search the subnet each subsequent execution. +The na_santricity_proxy_systems module is used to add storage systems to the proxy but required a complete list of desired systems since it will ensure that only the systems provided will remain on the proxy. As a result any system that is not included will be removed from the proxy. + +Role Variables +-------------- + eseries_subnet: # Network subnet to search for the storage system specified in CIDR form. Example: 192.168.1.0/24 + # Note: eseries_subnet should only be defined once at the group level when utilizing the Web Services Proxy. + eseries_template_api_url: # Template for the web services api url. Default: https://0.0.0.0:8443/devmgr/v2/ + eseries_prefer_embedded: false # Overrides the default behavior of using Web Services Proxy when eseries_proxy_api_url is defined. This will only effect storage systems that have Embedded Web Services. + eseries_validate_certs: true # Indicates Whether SSL certificates should be verified. Used for both embedded and proxy. Choices: true, false + + # Storage system specific variables + eseries_proxy_ssid: # Arbitrary string for the proxy to represent the storage system. eseries_system_serial will be used when not defined. + eseries_system_serial: # Storage system serial number. (This is located on a label at the top-left towards the front on the device) + eseries_system_addresses: # Storage system management IP addresses. Only required when eseries_system_serial or eseries_system_api_url are not defined. When not specified, addresses will be populated with eseries_management_interfaces controller addresses. + eseries_system_api_url: # Url for the storage system's for embedded web services rest api. Example: https://192.168.10.100/devmgr/v2 + eseries_system_username: admin # Username for the storage system's for embedded web services rest api + eseries_system_password: # Password for the storage system's for embedded web services rest api and when the admin password has not been set eseries_system_password will be used to set it. + eseries_system_tags: # Meta tags to associate with storage system when added to the proxy. + + # Storage system management interface information + Note: eseries_management_interfaces will be used when eseries_system_serial, eseries_system_api_url, or eseries_system_addresses are not defined. + eseries_management_interfaces: # Subset of the eseries_management_interface variable found in the nar_santricity_management role + controller_a: + - address: # Controller A port 1's IP address + - address: # Controller A port 2's IP address + controller_b: + - address: # Controller B port 1's IP address + - address: # Controller B port 2's IP address + + # Web Services Proxy specific variable + Note: eseries_proxy_* variables are required to discover storage systems prior to SANtricity OS version 11.60.2. + eseries_proxy_api_url: # Url for the storage system's for proxy web services rest api. Example: https://192.168.10.100/devmgr/v2 + eseries_proxy_api_username: # Username for the storage system's for proxy web services rest api (Default: admin). + eseries_proxy_api_password: # Password for the storage system's for proxy web services rest api and when the admin password has + # not been set eseries_proxy_api_password will be used to set it. + eseries_proxy_api_old_password: # Previous proxy admin password. This is used to change the current admin password by setting this + # variable to the current proxy password and eseries_proxy_api_password to the new password. + eseries_proxy_monitor_password: # Proxy password for the monitor username + eseries_proxy_security_password: # Proxy password for the security username + eseries_proxy_storage_password: # Proxy password for the monitor username + eseries_proxy_support_password: # Proxy password for the support username + eseries_proxy_accept_certifications: # Force automatic acceptance of all storage system's certificate + eseries_proxy_default_system_tags: # Default meta tags to associate with all storage systems + eseries_proxy_default_password: # Default password to associate with all storage systems. This is overridden by eseries_system_password. + eseries_proxy_client_certificate_common_certificates: # List of common proxy client certificate file paths. These files will be appended to each client certificate list. + eseries_proxy_client_certificate_certificates: # List of proxy client certificate file paths + eseries_proxy_server_certificate_common_certificates: # List of common proxy server certificates. These files will be appended to each controller's server certificate list. + eseries_proxy_server_certificate_common_passphrase: # Common passphrase for decrypting PEM (PKCS8) private key. + eseries_proxy_server_certificate_certificates: # List of proxy server certificates. Leave blank to use self-signed certificate. + eseries_proxy_server_certificate_passphrase: # Passphrase for decrypting PEM (PKCS8) private key. + + # LDAP configuration defaults + eseries_proxy_ldap_state: # Whether LDAP should be configured for the proxy` + eseries_proxy_ldap_identifier: # The user attributes that should be considered for the group to role mapping + eseries_proxy_ldap_user_attribute: # Attribute used to the provided username during authentication. + eseries_proxy_ldap_bind_username: # User account that will be used for querying the LDAP server. + eseries_proxy_ldap_bind_password: # Password for the bind user account + eseries_proxy_ldap_server: # LDAP server URL. + eseries_proxy_ldap_search_base: # Search base used for find user's group membership + eseries_proxy_ldap_role_mappings: # Dictionary of user groups, each containing the list of access roles. + # Role choices: storage.admin - allows users full read/writes access to storage objects and operations. + # storage.monitor - allows users read-only access to storage objects and operations. + # storage.admin - allows users access to hardware, diagnostic information, major event logs, + # and other critical support-related functionality, but not the sorage configuration. + # security.admin - allows users access to authentication/authorization configuration, as + # well as the audit log configuration, adn certification management. + + +License +------- + BSD-3-Clause + + +Author Information +------------------ + Nathan Swartz (@ndswartz) diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/defaults/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/defaults/main.yml new file mode 100644 index 000000000..4c0233b24 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/defaults/main.yml @@ -0,0 +1,45 @@ +--- +#eseries_subnet: # Network subnet to search for the storage system specified in CIDR form. Example: 192.168.1.0/24 +eseries_subnet_default_prefix: 22 # Default subnet prefix to use when no other prefix is supplied. Default: 22 +eseries_template_api_url: https://0.0.0.0:8443/devmgr/v2/ # Template for the web services api url. Default: https://0.0.0.0:8443/devmgr/v2/ +#eseries_validate_certs: # Whether SSL certificates should be verified. Used for both embedded and proxy. Choices: true, false +eseries_prefer_embedded: false # Overrides the default behavior of using Web Services Proxy when eseries_proxy_api_url is defined. This will only + # effect storage systems that have Embedded Web Services. + +# Storage system specific variables +# --------------------------------- +#eseries_proxy_ssid: # Arbitrary string for the proxy to represent the storage system. eseries_system_serial will be used when not defined. +#eseries_system_serial: # Storage system serial number (This is located on a label at the top-left towards the front on the device) +#eseries_system_addresses: # Storage system management IP addresses. Only required when eseries_system_serial or eseries_system_api_url are not + # defined. When not specified, addresses will be populated with eseries_management_interfaces controller addresses +#eseries_system_api_url: # Url for the storage system's for embedded web services rest api. Example: https://192.168.10.100/devmgr/v2 +eseries_system_username: admin # Username for the storage system's for embedded web services rest api +#eseries_system_password: # Password for the storage system's for embedded web services rest api and when the admin password has not been set + # eseries_system_password will be used to set it. +#eseries_system_tags: # Meta tags to associate with storage system when added to the proxy. + +# Storage system management interface information +# ----------------------------------------------- +# Note: eseries_management_interfaces will be used when eseries_system_serial, eseries_system_api_url, or eseries_system_addresses are not defined. +#eseries_management_interfaces: # Subset of the eseries_management_interface variable found in the nar_santricity_management role +# controller_a: +# - address: # Controller A port 1's IP address +# - address: # Controller A port 2's IP address +# controller_b: +# - address: # Controller B port 1's IP address +# - address: # Controller B port 2's IP address + +# Web Services Proxy specific variable +# ------------------------------------ +# Note: eseries_proxy_* variables are required to discover storage systems prior to SANtricity OS version 11.60.2. +#eseries_proxy_api_url: # Url for the storage system's for proxy web services rest api. Example: https://192.168.10.100/devmgr/v2 +eseries_proxy_api_username: admin # Username for the storage system's for proxy web services rest api. +#eseries_proxy_api_password: # Password for the storage system's for proxy web services rest api and when the admin password has not been set + # eseries_proxy_api_password will be used to set it. +#eseries_proxy_monitor_password: # Proxy password for the monitor username +#eseries_proxy_security_password: # Proxy password for the security username +#eseries_proxy_storage_password: # Proxy password for the monitor username +#eseries_proxy_support_password: # Proxy password for the support username +#eseries_proxy_accept_certifications: # Force automatic acceptance of all storage system's certificate +#eseries_proxy_default_system_tags: # Default meta tags to associate with all storage systems +#eseries_proxy_default_password: # Default password to associate with all storage systems. This is overridden by eseries_system_password. diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/meta/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/meta/main.yml new file mode 100644 index 000000000..62da5894a --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/meta/main.yml @@ -0,0 +1,13 @@ +galaxy_info: + author: Nathan Swartz (@ndswartz) + description: Discover NetApp E-Series storage systems and configures SANtricity Web Services Proxy. + company: NetApp, Inc + license: BSD-3-Clause + platforms: [] + min_ansible_version: 2.13 + galaxy_tags: + - netapp + - eseries + - storage + +dependencies: []
\ No newline at end of file diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/build_info.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/build_info.yml new file mode 100644 index 000000000..a78af62ff --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/build_info.yml @@ -0,0 +1,38 @@ +- name: Collect storage system facts + uri: + url: |- + {%- if eseries_prefer_embedded == True -%} + {{- eseries_system_api_url | default(eseries_proxy_api_url) | regex_replace('v2/?$', 'utils/about') -}} + {%- else -%} + {{- eseries_proxy_api_url | default(eseries_system_api_url) | regex_replace('v2/?$', 'utils/about') -}} + {%- endif -%} + headers: + Content-Type: "application/json" + Accept: "application/json" + validate_certs: false + connection: local + register: about + failed_when: false + when: eseries_proxy_api_url is defined or eseries_system_api_url is defined + tags: always + +- name: Determine whether SANtricity Web Services REST API is proxy and information + set_fact: + current_eseries_api_is_proxy: "{{ about['json']['runningAsProxy'] | default(False) }}" + tags: always + +- name: Collect Web Services information from either proxy or embedded with a preference for embedded. + include_tasks: collect_facts/prefer_embedded.yml + when: (current_eseries_api_is_proxy == True and eseries_prefer_embedded == True) or current_eseries_api_is_proxy == False + tags: always + +- name: Collect Web Services information from proxy. + include_tasks: collect_facts/prefer_proxy.yml + when: current_eseries_api_is_proxy == True and current_eseries_api_url is not defined + tags: always + +- name: Check whether current_eseries_api_url is defined + fail: + msg: "Could not determine or discover storage system contact information!" + when: current_eseries_api_url is not defined or current_eseries_ssid is not defined + tags: always diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/discovery.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/discovery.yml new file mode 100644 index 000000000..3a5e0da49 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/discovery.yml @@ -0,0 +1,64 @@ +- name: Check whether eseries_system_serial is defined. + ansible.builtin.fail: + msg: "Unable to search for storage system! The variable eseries_system_serial must be defined (See SANtricity README, section Storage System Credentials)." + when: eseries_system_serial is not defined + +- name: Determine associated management interface subnet information. + ansible.builtin.set_fact: + eseries_subnets: |- + {%- set subnets = [] %} + {%- if eseries_subnet is defined -%} + {%- if subnets.append(eseries_subnet) -%}{%- endif -%} + {%- endif -%} + {%- set interfaces = eseries_management_interfaces["controller_a"] | default([]) + eseries_management_interfaces["controller_b"] | default([]) -%} + {%- for interface in interfaces if interface["address"] is defined -%} + {%- if subnets.append(interface["address"] ~ "/" ~ interface["subnet_mask"] | default(eseries_management_interfaces["subnet_mask"] | default(eseries_management_subnet_mask | default(eseries_subnet_default_prefix)))) -%}{%- endif -%} + {%- endfor -%} + {{- subnets | ansible.utils.ipaddr('network/prefix') | unique -}} + +- name: Ensure there is at least one subnet to search for storage systems. + ansible.builtin.fail: + msg: "There is not enough management information to search for the storage system(s)! (See SANtricity README, section Storage System Credentials)" + when: eseries_subnets | length == 0 + +- name: Discover storage systems from all subnet ranges + netapp_eseries.santricity.na_santricity_discover: + proxy_url: "{{ item['value']['proxy_url'] }}" + proxy_username: "{{ item['value']['proxy_username'] }}" + proxy_password: "{{ item['value']['proxy_password'] }}" + proxy_validate_certs: "{{ item['value']['proxy_validate_certs'] }}" + subnet_mask: "{{ item['key'] }}" + prefer_embedded: "{{ item['value']['prefer_embedded'] }}" + run_once: true + connection: local + register: discovered_systems + loop: "{{ subnets | dict2items }}" + tags: always + vars: + subnets: |- + {#- Build a dictionary subnet searches and any proxies should they be available #} + {%- set systems = {} %} + {%- for array in ansible_play_hosts_all %} + {%- for eseries_subnet in hostvars[array]["eseries_subnets"] | default([]) -%} + + {%- if "eseries_proxy_api_url" in (hostvars[array].keys() | list) -%} + {%- if systems.update({eseries_subnet: { + "proxy_url": hostvars[array]["eseries_proxy_api_url"] | default(omit), + "proxy_username": hostvars[array]["eseries_proxy_api_username"] | default("admin"), + "proxy_password": hostvars[array]["eseries_proxy_api_password"] | default(omit), + "prefer_embedded": hostvars[array]["eseries_prefer_embedded"] | default(omit), + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit)}}) %} + {%- endif %} + {%- else -%} + {%- if systems.update({eseries_subnet: { + "proxy_url": hostvars[array]["eseries_proxy_api_url"] | default(omit), + "proxy_username": hostvars[array]["eseries_proxy_api_username"] | default(omit), + "proxy_password": hostvars[array]["eseries_proxy_api_password"] | default(omit), + "prefer_embedded": hostvars[array]["eseries_prefer_embedded"] | default(omit), + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit)}}) %} + {%- endif %} + {%- endif -%} + + {%- endfor %} + {%- endfor %} + {{ systems }} diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/prefer_embedded.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/prefer_embedded.yml new file mode 100644 index 000000000..e9fb16bc7 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/prefer_embedded.yml @@ -0,0 +1,150 @@ +# Test whether eseries_system_api_url is a valid storage system web services api. +- name: Validate the storage system embedded Web Services REST API supplied in eseries_system_api_url. + block: + - name: Determine management url based on eseries_system_api_url. + set_fact: + eseries_api_url_list: "{{ [eseries_system_api_url] }}" + + - name: Check for valid storage system Web Services API url. + include_tasks: collect_facts/validate_system_api_url.yml + when: (current_eseries_api_url is not defined or current_eseries_ssid is not defined) and eseries_system_api_url is defined + tags: always + + +# Test when a valid storage system web services api can be extrapolated from eseries_management_interfaces +- name: Validate the storage system embedded Web Services REST API derived from eseries_management_interfaces. + block: + - name: Determine management interface IP addresses + set_fact: + eseries_api_url_list: |- + {%- set addresses = [] -%} + {%- set url_info = eseries_template_api_url | urlsplit %} + {%- for address in [eseries_management_interfaces["controller_a"][0]["address"] | default(""), + eseries_management_interfaces["controller_a"][1]["address"] | default(""), + eseries_management_interfaces["controller_b"][0]["address"] | default(""), + eseries_management_interfaces["controller_b"][1]["address"] | default("")] -%} + {%- if address != "" and addresses.append([url_info["scheme"], "://", address, ":", url_info["port"], url_info["path"]] | join("")) %}{%- endif -%} + {%- endfor %} + {{ addresses }} + + - name: Check for valid storage system Web Services API url. + include_tasks: collect_facts/validate_system_api_url.yml + when: (current_eseries_api_url is not defined or current_eseries_ssid is not defined) and eseries_management_interfaces is defined + tags: always + + +# If proxy is available get information from there and avoid the discovery process. +- name: Attempt to retrieve the storage system from Web Services Proxy. + block: + - name: Determine existing storage systems in Web Services Proxy. + uri: + url: "{{ eseries_proxy_api_url | regex_replace('v2/?$', 'v2/storage-systems') }}" + headers: + Content-Type: "application/json" + Accept: "application/json" + url_username: "{{ eseries_proxy_api_username | default('admin') }}" + url_password: "{{ eseries_proxy_api_password }}" + validate_certs: false + connection: local + register: proxy_systems + - name: Determine associated management interface IP addresses. + set_fact: + eseries_system_addresses: |- + {%- set addresses = [] %} + {%- set url_info = eseries_template_api_url | urlsplit %} + {%- for address in [eseries_management_interfaces["controller_a"][0]["address"] | default(""), + eseries_management_interfaces["controller_a"][1]["address"] | default(""), + eseries_management_interfaces["controller_b"][0]["address"] | default(""), + eseries_management_interfaces["controller_b"][1]["address"] | default("")] %} + {%- if address != "" and addresses.append(address) -%}{%- endif %} + {%- endfor %} + {{ addresses }} + when: eseries_management_interfaces is defined + + - name: Determine storage system SSID based on storage system serial number or associated IP addresses. + set_fact: + eseries_api_url_list: |- + {#- Determine any system that either has the expected serial number or a management ip address -#} + {%- set ssids = [] -%} + {%- set addresses = [] -%} + + {#- Search discovered storage systems -#} + {%- set url_info = eseries_template_api_url | urlsplit %} + {%- for system in proxy_systems["json"] -%} + + {#- Check for serial number match -#} + {%- if eseries_system_serial is defined and system["chassisSerialNumber"] == eseries_system_serial -%} + {%- if ssids.append(system["id"]) -%}{%- endif -%} + {%- for address in system["managementPaths"] -%} + {%- if addresses.append([url_info["scheme"], "://", address, ":", url_info["port"], url_info["path"]] | join("")) %}{%- endif -%} + {%- endfor -%} + + {%- elif eseries_proxy_ssid is defined and eseries_proxy_ssid == system["id"] -%} + {%- if ssids.append(system["id"]) -%}{%- endif -%} + {%- for address in system["managementPaths"] -%} + {%- if addresses.append([url_info["scheme"], "://", address, ":", url_info["port"], url_info["path"]] | join("")) %}{%- endif -%} + {%- endfor -%} + + {%- elif eseries_system_addresses is defined and eseries_system_addresses | length > 0 -%} + {%- for address in eseries_system_addresses -%} + {%- if address in system["managementPaths"] -%} + {%- if ssids.append(system["id"]) -%}{%- endif -%} + {%- for address in system["managementPaths"] -%} + {%- if addresses.append([url_info["scheme"], "://", address, ":", url_info["port"], url_info["path"]] | join("")) %}{%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endfor -%} + + {%- if ssids | unique | length == 1 -%} + {{- addresses -}} + {%- else -%}[]{%- endif -%} + + - name: Check for valid storage system Web Services API url. + include_tasks: collect_facts/validate_system_api_url.yml + when: current_eseries_api_is_proxy == True and (current_eseries_api_url is not defined or current_eseries_ssid is not defined) + tags: always + +# Try discovering eseries_system_api_url if known eseries_system_api_url is not valid +- name: Attempt to discover storage system. + block: + - name: Search subnet for storage system. + include_tasks: collect_facts/discovery.yml + when: discovered_systems is not defined + + - name: Determine storage system Web Services information + set_fact: + current_eseries_api_info: |- + {%- set info = {} -%} + {%- if eseries_system_serial is defined -%} + {%- set serial = eseries_system_serial | string -%} + {%- for result in discovered_systems["results"] if result["systems_found"][serial] is defined -%} + {%- if info.update(result["systems_found"][serial]) %}{%- endif -%} + {%- endfor %} + {%- endif -%} + {{ info }} + + - name: Check whether storage system was discovered. + fail: + msg: "Storage system failed to be discovered! Serial [{{ eseries_system_serial }}]." + when: current_eseries_api_info == {} + + - name: Set storage systems Web Services URL information + set_fact: + current_eseries_api_is_proxy: "{{ current_eseries_api_info['proxy_required'] }}" + current_eseries_api_url: "{{ current_eseries_api_info['api_urls'][0] }}" + current_eseries_ssid: |- + {%- if current_eseries_api_info["proxy_required"] == False -%} + 1 + {%- elif current_eseries_api_info["proxy_required"] == True and current_eseries_api_info['proxy_ssid'] != "" -%} + {{- current_eseries_api_info['proxy_ssid'] -}} + {%- else -%} + {{- eseries_system_serial -}} + {%- endif -%} + current_eseries_api_username: "{% if current_eseries_api_info['proxy_required'] %}{{ eseries_proxy_api_username | default('admin') }}{% else %}{{ eseries_system_username | default('admin') }}{% endif %}" + current_eseries_api_password: "{% if current_eseries_api_info['proxy_required'] %}{{ eseries_proxy_api_password }}{% else %}{{ eseries_system_password }}{% endif %}" + current_eseries_validate_certs: "{{ eseries_validate_certs | default(omit) }}" + no_log: true + when: current_eseries_api_url is not defined or current_eseries_ssid is not defined + tags: always diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/prefer_proxy.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/prefer_proxy.yml new file mode 100644 index 000000000..593a5c57c --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/prefer_proxy.yml @@ -0,0 +1,107 @@ +- name: Determine existing storage systems in Web Services Proxy. + uri: + url: "{{ eseries_proxy_api_url | regex_replace('v2/?$', 'v2/storage-systems') }}" + headers: + Content-Type: "application/json" + Accept: "application/json" + url_username: "{{ eseries_proxy_api_username | default('admin') }}" + url_password: "{{ eseries_proxy_api_password }}" + validate_certs: false + connection: local + register: proxy_systems + tags: always + +- name: Determine associated management interface IP addresses. + set_fact: + eseries_system_addresses: |- + {%- set addresses = [] %} + {%- set url_info = eseries_template_api_url | urlsplit %} + {%- for address in [eseries_management_interfaces["controller_a"][0]["address"] | default(""), + eseries_management_interfaces["controller_a"][1]["address"] | default(""), + eseries_management_interfaces["controller_b"][0]["address"] | default(""), + eseries_management_interfaces["controller_b"][1]["address"] | default("")] %} + {%- if address != "" and addresses.append(address) -%}{%- endif %} + {%- endfor %} + {{ addresses }} + when: eseries_management_interfaces is defined + tags: always + +- name: Determine storage system SSID based on storage system serial number or associated IP addresses. + set_fact: + eseries_ssid_list: |- + {#- Determine any system that either has the expected serial number or a management ip address -#} + {%- set ssids = [] -%} + + {#- Search discovered storage systems -#} + {%- for system in proxy_systems["json"] -%} + + {#- Check for serial number match -#} + {%- if eseries_system_serial is defined and system["chassisSerialNumber"] == eseries_system_serial -%} + {%- if ssids.append(system["id"]) -%}{%- endif -%} + + {%- elif eseries_proxy_ssid is defined and eseries_proxy_ssid == system["id"] -%} + {%- if ssids.append(system["id"]) -%}{%- endif -%} + + {%- elif eseries_system_addresses is defined and eseries_system_addresses | length > 0 -%} + {%- for address in eseries_system_addresses -%} + {%- if address in system["managementPaths"] -%} + {%- if ssids.append(system["id"]) -%}{%- endif -%} + {%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endfor -%} + {{- ssids | unique -}} + tags: always + +- name: Use the Web Services Proxy REST API + set_fact: + current_eseries_api_url: "{{ eseries_proxy_api_url }}" + current_eseries_ssid: "{{ eseries_ssid_list[0] }}" + current_eseries_api_username: "{{ eseries_proxy_api_username | default('admin') }}" + current_eseries_api_password: "{{ eseries_proxy_api_password }}" + current_eseries_validate_certs: "{{ eseries_validate_certs | default(omit) }}" + no_log: true + when: eseries_ssid_list | length == 1 and (eseries_proxy_ssid is not defined or eseries_proxy_ssid == eseries_ssid_list[0]) + tags: always + +- name: Search subnet for storage system. + block: + - name: Search subnet for storage system. + include_tasks: collect_facts/discovery.yml + when: discovered_systems is not defined + + - name: Determine storage system Web Services information + set_fact: + current_eseries_api_info: |- + {%- set info = {} -%} + {%- if eseries_system_serial is defined -%} + {%- set serial = eseries_system_serial | string -%} + {%- for result in discovered_systems["results"] if result["systems_found"][serial] is defined -%} + {%- if info.update(result["systems_found"][serial]) %}{%- endif -%} + {%- endfor %} + {%- endif -%} + {{ info }} + + - name: Check whether storage system was discovered. + fail: + msg: "Storage system failed to be discovered! Serial [{{ eseries_system_serial }}]." + when: current_eseries_api_info == {} + + - name: Set storage systems Web Services URL information + set_fact: + current_eseries_api_is_proxy: "{{ current_eseries_api_info['proxy_required'] }}" + current_eseries_api_url: "{{ current_eseries_api_info['api_urls'][0] }}" + current_eseries_ssid: |- + {%- if eseries_proxy_ssid is defined -%} + {{- eseries_proxy_ssid -}} + {%- elif current_eseries_api_info["proxy_ssid"] != "" -%} + {{- current_eseries_api_info["proxy_ssid"] -}} + {%- else -%} + {{- eseries_system_serial -}} + {%- endif -%} + current_eseries_api_username: "{{ eseries_proxy_api_username | default('admin') }}" + current_eseries_api_password: "{{ eseries_proxy_api_password }}" + current_eseries_validate_certs: "{{ eseries_validate_certs | default(omit) }}" + no_log: true + when: current_eseries_api_url is not defined or current_eseries_ssid is not defined + tags: always diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/validate_system_api_url.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/validate_system_api_url.yml new file mode 100644 index 000000000..709239d8e --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/collect_facts/validate_system_api_url.yml @@ -0,0 +1,34 @@ +- name: Validate storage system urls. + block: + - name: Collect storage system facts. + uri: + url: "{{ item | regex_replace('v2/?$', 'utils/about') }}" + headers: + Content-Type: "application/json" + Accept: "application/json" + validate_certs: false + ignore_errors: true + connection: local + register: about_results + loop: "{{ lookup('list', eseries_api_url_list) }}" + + - name: Determine the first successful Web Services REST API url. + set_fact: + current_eseries_api_url: |- + {%- set valid_urls = [] %} + {%- for result in about_results["results"] if result["failed"] == false -%} + {%- if valid_urls.append(result['item']) %}{%- endif %} + {%- endfor %} + {{ valid_urls[0] | default("") }} + + - name: Set Web Services REST API credentials. + set_fact: + current_eseries_api_is_proxy: False + current_eseries_ssid: "{{ current_eseries_ssid | default('1') }}" + current_eseries_api_username: "{{ eseries_system_username | default('admin') }}" + current_eseries_api_password: "{{ eseries_system_password }}" + current_eseries_validate_certs: "{{ eseries_validate_certs | default(omit) }}" + when: current_eseries_api_url != "" + no_log: true + when: eseries_api_url_list is defined and eseries_api_url_list | length > 0 + tags: always diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/main.yml new file mode 100644 index 000000000..ba568b99f --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/main.yml @@ -0,0 +1,14 @@ +- name: Configure SANtricity Web Services Proxy's passwords, certificates, and LDAP. + import_tasks: proxy_security.yml + run_once: true + +- name: Build information for Web Services + import_tasks: build_info.yml + tags: + - always + +- name: Configure SANtricity WebServices Proxy + import_tasks: proxy.yml + run_once: true + tags: + - always diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/proxy.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/proxy.yml new file mode 100644 index 000000000..965801d2f --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/proxy.yml @@ -0,0 +1,49 @@ +- name: Add storage systems to SANtricity Web Services Proxy + na_santricity_proxy_systems: + api_url: "{{ item['key'] }}" + api_username: "{{ item['value']['proxy_username'] }}" + api_password: "{{ item['value']['proxy_password'] }}" + validate_certs: "{{ item['value']['proxy_validate_certs'] | default(omit) }}" + accept_certificate: "{{ item['value']['proxy_accept_certifications'] | default(omit) }}" + subnet_mask: "{{ item['value']['proxy_subnet'] }}" + password: "{{ item['value']['proxy_default_password'] | default(omit) }}" + tags: "{{ item['value']['proxy_default_system_tags'] | default(omit) }}" + systems: "{{ item['value']['proxy_systems'] }}" + connection: local + loop: "{{ lookup('dict', proxy_systems_info, wantlist=True) }}" + no_log: true + vars: + proxy_systems_info: |- + {#- Build a dictionary of all inventoried proxies keyed by their api url #} + {%- set systems = {} %} + {%- for array in ansible_play_hosts_all %} + {%- if hostvars[array]["current_eseries_api_is_proxy"] %} + {%- set array_info = {} %} + {%- if "eseries_system_serial" in hostvars[array] or "eseries_system_addresses" in hostvars[array] %} + {%- if array_info.update({ + "ssid": hostvars[array]["current_eseries_ssid"] | default(omit), + "password": hostvars[array]["eseries_system_password"] | default(omit), + "serial": hostvars[array]["eseries_system_serial"] | default(omit), + "addresses": hostvars[array]["eseries_system_addresses"] | default(omit), + "tags": hostvars[array]["eseries_system_tags"] | default(omit)}) %} + {%- endif %} + {%- endif %} + {%- if "eseries_proxy_api_url" in hostvars[array] and "eseries_proxy_api_password" in hostvars[array] %} + {%- if hostvars[array]["eseries_proxy_api_url"] in systems %} + {%- if systems[hostvars[array]["eseries_proxy_api_url"]]["proxy_systems"].append(array_info) %}{%- endif %} + {%- else %} + {%- if systems.update({hostvars[array]["eseries_proxy_api_url"]: { + "proxy_username": hostvars[array]["eseries_proxy_api_username"] | default("admin"), + "proxy_password": hostvars[array]["eseries_proxy_api_password"] | default(omit), + "proxy_subnet": hostvars[array]["eseries_subnet"] | default(omit), + "proxy_systems": [array_info], + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit), + "proxy_accept_certifications": hostvars[array]["eseries_proxy_accept_certifications"] | default(omit), + "proxy_default_system_tags": hostvars[array]["eseries_proxy_default_system_tags"] | default(omit), + "proxy_default_password": hostvars[array]["eseries_proxy_default_password"] | default(omit)}}) %} + {%- endif %} + {%- endif %} + {%- endif %} + {%- endif %} + {%- endfor %} + {{ systems }} diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/proxy_security.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/proxy_security.yml new file mode 100644 index 000000000..6cfb60246 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_common/tasks/proxy_security.yml @@ -0,0 +1,241 @@ +- name: Ensure proxy admin password has been set + na_santricity_auth: + ssid: proxy + api_url: "{{ item['key'] }}" + api_username: "{{ item['value']['proxy_username'] }}" + api_password: "{{ item['value']['current_proxy_password'] }}" + validate_certs: "{{ item['value']['proxy_validate_certs'] }}" + user: admin + password: "{{ item['value']['proxy_password'] }}" + minimum_password_length: "{{ item['value']['proxy_minimum_password_length'] }}" + connection: local + loop: "{{ lookup('dict', proxy_admin, wantlist=True) }}" + no_log: true + vars: + proxy_admin: |- + {#- Build a dictionary of all inventoried proxies keyed by their api url #} + {%- set systems = {} %} + {%- for array in ansible_play_hosts_all %} + {%- if "eseries_proxy_api_url" in hostvars[array] and "eseries_proxy_api_password" in hostvars[array] %} + {%- if systems.update({hostvars[array]["eseries_proxy_api_url"]: { + "proxy_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_password": hostvars[array]["eseries_proxy_api_password"], + "current_proxy_password": hostvars[array]["eseries_proxy_api_old_password"] | default(hostvars[array]["eseries_proxy_api_password"]), + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit), + "proxy_minimum_password_length": hostvars[array]["eseries_proxy_minimum_password_length"] | default(omit)}}) %} + {%- endif %} + {%- endif %} + {%- endfor %} + {{ systems }} + tags: + - always + +- name: Ensure proxy non-admin passwords have been set + na_santricity_auth: + ssid: proxy + api_url: "{{ item['value']['proxy_url'] }}" + api_username: "{{ item['value']['proxy_url_username'] }}" + api_password: "{{ item['value']['proxy_url_password'] }}" + validate_certs: "{{ item['value']['proxy_validate_certs'] }}" + user: "{{ item['value']['proxy_username'] }}" + password: "{{ item['value']['proxy_password'] }}" + connection: local + loop: "{{ lookup('dict', proxy_non_admin, wantlist=True) }}" + no_log: true + vars: + proxy_non_admin: |- + {#- Build a dictionary of all inventoried proxies keyed by their api url containing non-admin usernames/passwords #} + {%- set systems = {} %} + {%- for array in ansible_play_hosts_all %} + {%- if "eseries_proxy_api_url" in hostvars[array] and "eseries_proxy_api_password" in hostvars[array] and + (("eseries_proxy_monitor_password" in hostvars[array] and hostvars[array]["eseries_proxy_monitor_password"]) or + ("eseries_proxy_security_password" in hostvars[array] and hostvars[array]["eseries_proxy_security_password"]) or + ("eseries_proxy_storage_password" in hostvars[array] and hostvars[array]["eseries_proxy_storage_password"]) or + ("eseries_proxy_support_password" in hostvars[array] and hostvars[array]["eseries_proxy_support_password"])) %} + {%- if "eseries_proxy_monitor_password" in hostvars[array] and hostvars[array]["eseries_proxy_monitor_password"] and + systems.update({[hostvars[array]["eseries_proxy_api_url"], 'monitor'] | join("-"): { + "proxy_url": hostvars[array]["eseries_proxy_api_url"], + "proxy_url_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_url_password": hostvars[array]["eseries_proxy_api_password"], + "proxy_username": 'monitor', + "proxy_password": hostvars[array]["eseries_proxy_monitor_password"], + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit)}}) %} + {%- endif %} + {%- if "eseries_proxy_security_password" in hostvars[array] and hostvars[array]["eseries_proxy_security_password"] and + systems.update({[hostvars[array]["eseries_proxy_api_url"], 'security'] | join("-"): { + "proxy_url": hostvars[array]["eseries_proxy_api_url"], + "proxy_url_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_url_password": hostvars[array]["eseries_proxy_api_password"], + "proxy_username": 'security', + "proxy_password": hostvars[array]["eseries_proxy_security_password"], + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit)}}) %} + {%- endif %} + {%- if "eseries_proxy_storage_password" in hostvars[array] and hostvars[array]["eseries_proxy_storage_password"] and + systems.update({[hostvars[array]["eseries_proxy_api_url"], 'storage'] | join("-"): { + "proxy_url": hostvars[array]["eseries_proxy_api_url"], + "proxy_url_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_url_password": hostvars[array]["eseries_proxy_api_password"], + "proxy_username": 'storage', + "proxy_password": hostvars[array]["eseries_proxy_storage_password"], + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit)}}) %} + {%- endif %} + {%- if "eseries_proxy_support_password" in hostvars[array] and hostvars[array]["eseries_proxy_support_password"] and + systems.update({[hostvars[array]["eseries_proxy_api_url"], 'support'] | join("-"): { + "proxy_url": hostvars[array]["eseries_proxy_api_url"], + "proxy_url_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_url_password": hostvars[array]["eseries_proxy_api_password"], + "proxy_username": 'support', + "proxy_password": hostvars[array]["eseries_proxy_support_password"], + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit)}}) %} + {%- endif %} + {%- endif %} + {%- endfor %} + {{ systems }} + +- name: Ensure proxy client certificates are installed + na_santricity_client_certificate: + ssid: proxy + api_url: "{{ item['key'] }}" + api_username: "{{ item['value']['proxy_username'] }}" + api_password: "{{ item['value']['proxy_password'] }}" + validate_certs: "{{ item['value']['proxy_validate_certs'] }}" + certificates: "{{ item['value']['certificates'] }}" + connection: local + loop: "{{ lookup('dict', proxy_client_certificates, wantlist=True) }}" + when: item['value']['certificates'] | length > 0 + no_log: true + vars: + proxy_client_certificates: |- + {#- Build a dictionary of all inventoried proxies keyed by their api url #} + {%- set systems = {} %} + {%- for array in ansible_play_hosts_all %} + {%- if "eseries_proxy_api_url" in hostvars[array] and "eseries_proxy_api_password" in hostvars[array] %} + {%- set certs = [] -%} + + {#- Add common proxy client certificates -#} + {%- if "eseries_proxy_client_certificate_common_certificates" in (hostvars[array].keys() | list) -%} + {%- if hostvars[array]["eseries_proxy_client_certificate_common_certificates"] is string -%} + {%- if certs.append(hostvars[array]["eseries_proxy_client_certificate_common_certificates"]) -%}{%- endif -%} + {%- elif hostvars[array]["eseries_proxy_client_certificate_common_certificates"] is iterable -%} + {%- if certs.extend(hostvars[array]["eseries_proxy_client_certificate_common_certificates"]) -%}{%- endif -%} + {%- endif -%} + {%- endif -%} + + {#- Add proxy specific client certificates -#} + {%- if "eseries_proxy_client_certificate_certificates" in (hostvars[array].keys() | list) -%} + {%- if hostvars[array]["eseries_proxy_client_certificate_certificates"] is string -%} + {%- if hostvars[array]["eseries_proxy_client_certificate_certificates"] not in certs -%} + {%- if certs.append(hostvars[array]["eseries_proxy_client_certificate_certificates"]) -%}{%- endif -%} + {%- endif -%} + {%- elif hostvars[array]["eseries_proxy_client_certificate_certificates"] is iterable -%} + {%- for client_cert in hostvars[array]["eseries_proxy_client_certificate_certificates"] if client_cert not in certs -%} + {%- if certs.append(client_cert) -%}{%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endif -%} + + {%- if systems.update({hostvars[array]["eseries_proxy_api_url"]: { + "proxy_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_password": hostvars[array]["eseries_proxy_api_password"], + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit), + "certificates": certs}}) %} + {%- endif %} + {%- endif %} + {%- endfor %} + {{ systems }} + +- name: Ensure proxy server certificates are installed + na_santricity_server_certificate: + ssid: proxy + api_url: "{{ item['key'] }}" + api_username: "{{ item['value']['proxy_username'] }}" + api_password: "{{ item['value']['proxy_password'] }}" + validate_certs: "{{ item['value']['proxy_validate_certs'] }}" + certificates: "{{ item['value']['certificates'] }}" + passphrase: "{{ item['value']['passphrase'] }}" + connection: local + loop: "{{ lookup('dict', proxy_server_certificates, wantlist=True) }}" + when: item['value']['certificates'] | length > 0 + no_log: true + vars: + proxy_server_certificates: |- + {#- Build a dictionary of all inventoried proxies keyed by their api url #} + {%- set systems = {} %} + {%- for array in ansible_play_hosts_all %} + {%- if "eseries_proxy_api_url" in hostvars[array] and "eseries_proxy_api_password" in hostvars[array] %} + {%- set certs = [] -%} + + {#- Add common proxy server certificates -#} + {%- if "eseries_proxy_server_certificate_common_certificates" in (hostvars[array].keys() | list) -%} + {%- if hostvars[array]["eseries_proxy_server_certificate_common_certificates"] is string -%} + {%- if certs.append(hostvars[array]["eseries_proxy_server_certificate_common_certificates"]) -%}{%- endif -%} + {%- elif hostvars[array]["eseries_proxy_server_certificate_common_certificates"] is iterable -%} + {%- if certs.extend(hostvars[array]["eseries_proxy_server_certificate_common_certificates"]) -%}{%- endif -%} + {%- endif -%} + {%- endif -%} + + {#- Add proxy specific server certificates -#} + {%- if "eseries_proxy_server_certificate_certificates" in (hostvars[array].keys() | list) -%} + {%- if hostvars[array]["eseries_proxy_server_certificate_certificates"] is string -%} + {%- if hostvars[array]["eseries_proxy_server_certificate_certificates"] not in certs -%} + {%- if certs.append(hostvars[array]["eseries_proxy_server_certificate_certificates"]) -%}{%- endif -%} + {%- endif -%} + {%- elif hostvars[array]["eseries_proxy_server_certificate_certificates"] is iterable -%} + {%- for client_cert in hostvars[array]["eseries_proxy_server_certificate_certificates"] if client_cert not in certs -%} + {%- if certs.append(client_cert) -%}{%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endif -%} + + {%- if systems.update({hostvars[array]["eseries_proxy_api_url"]: { + "proxy_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_password": hostvars[array]["eseries_proxy_api_password"], + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit), + "certificates": certs, + "passphrase": hostvars[array]["eseries_proxy_server_certificate_passphrase"] | default(hostvars[array]["eseries_proxy_server_certificate_common_passphrase"] | default(omit))}}) %} + {%- endif %} + {%- endif %} + {%- endfor %} + {{ systems }} + +- name: Ensure proxy LDAP have been configured + na_santricity_ldap: + ssid: proxy + api_url: "{{ item['key'] }}" + api_username: "{{ item['value']['proxy_username'] }}" + api_password: "{{ item['value']['current_password'] | default(item['value']['proxy_password']) }}" + validate_certs: "{{ item['value']['proxy_validate_certs'] }}" + state: "{{ item['value']['ldap_state'] }}" + identifier: "{{ item['value']['ldap_identifier'] | default(omit) }}" + server_url: "{{ item['value']['ldap_server'] | default(omit) }}" + bind_user: "{{ item['value']['ldap_bind_username'] | default(omit) }}" + bind_password: "{{ item['value']['ldap_bind_password'] | default(omit) }}" + search_base: "{{ item['value']['ldap_search_base'] | default(omit) }}" + user_attribute: "{{ item['value']['ldap_user_attribute'] | default(omit) }}" + role_mappings: "{{ item['value']['ldap_role_mappings'] | default(omit) }}" + ignore_errors: true + connection: local + loop: "{{ lookup('dict', proxy_admin, wantlist=True) }}" + vars: + proxy_admin: |- + {#- Build a dictionary of all inventoried proxies keyed by their api url #} + {%- set systems = {} %} + {%- for array in ansible_play_hosts_all %} + {%- if "eseries_proxy_api_url" in hostvars[array] and "eseries_proxy_api_password" in hostvars[array] and "eseries_proxy_ldap_state" in hostvars[array] %} + {%- if systems.update({hostvars[array]["eseries_proxy_api_url"]: { + "proxy_username": hostvars[array]["eseries_proxy_api_username"] | default('admin'), + "proxy_password": hostvars[array]["eseries_proxy_api_password"], + "current_proxy_password": hostvars[array]["eseries_proxy_current_api_password"] | default(omit), + "proxy_validate_certs": hostvars[array]["eseries_validate_certs"] | default(omit), + "ldap_state": hostvars[array]["eseries_proxy_ldap_state"], + "ldap_identifier": hostvars[array]["eseries_proxy_ldap_identifier"] | default(omit), + "ldap_server": hostvars[array]["eseries_proxy_ldap_server"] | default(omit), + "ldap_bind_username": hostvars[array]["eseries_proxy_ldap_bind_username"] | default(omit), + "ldap_bind_password": hostvars[array]["eseries_proxy_ldap_bind_password"] | default(omit), + "ldap_search_base": hostvars[array]["eseries_proxy_ldap_search_base"] | default(omit), + "ldap_user_attribute": hostvars[array]["eseries_proxy_ldap_user_attribute"] | default(omit), + "ldap_role_mappings": hostvars[array]["eseries_proxy_ldap_role_mappings"] | default(omit)}}) %} + {%- endif %} + {%- endif %} + {%- endfor %} + {{ systems }} diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/README.md b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/README.md new file mode 100644 index 000000000..011b98565 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/README.md @@ -0,0 +1,443 @@ +nar_santricity_host +========= + Configures storage pools, volumes, hosts, host groups, and port interfaces for NetApp E-Series storage arrays + using iSCSI, FC, SAS, IB, NVMe protocols. + +Requirements +------------ + - NetApp E-Series E2800 platform or newer or NetApp E-Series SANtricity Web Services Proxy configured for older E-Series Storage arrays. + +Tested Ansible Versions +----------------------- + - Ansible 5.x (ansible-core 2.12) + +Example Playbook +---------------- + - hosts: eseries_storage_systems + gather_facts: false + collection: + - netapp_eseries.santricity + tasks: + - name: Ensure NetApp E-Series storage system is properly configured + import_role: + name: nar_santricity_host + +Example Storage System Inventory File (Discover storage system with proxy) +------------------------------------- + eseries_system_serial: "012345678901" # Be sure to quote if the serial is all numbers and begins with zero. + eseries_system_password: admin_password + eseries_proxy_api_url: https://192.168.1.100:8443/devmgr/v2/ + eseries_proxy_api_password: admin_password + eseries_subnet: 192.168.1.0/24 + eseries_prefer_embedded: true + eseries_validate_certs: false + + eseries_initiator_protocol: iscsi + + # Controller port definitions + eseries_controller_iscsi_port_config_method: static + eseries_controller_iscsi_port_subnet_mask: 255.255.255.0 + eseries_controller_iscsi_port: + controller_a: + - address: 192.168.2.100 + - address: 192.168.2.110 + controller_b: + - address: 192.168.3.100 + - address: 192.168.3.110 + + # Storage pool and volume configuration + eseries_storage_pool_configuration: + - name: pool[1-2] + raid_level: raid6 + criteria_drive_count: 10 + volumes: + - name: "[pool]_volume[A-C]" + host: server_group + size: 4096 + +Example Storage System Inventory File (Without storage system discovery) +------------------------------------- + eseries_system_api_url: https://192.168.1.200:8443/devmgr/v2/ + eseries_system_password: admin_password + eseries_validate_certs: false + + (...) # Same as the previous example + +Yet Another Example System Inventory File +----------------------------------------- + eseries_system_api_url: https://192.168.1.200:8443/devmgr/v2/ + eseries_system_password: admin_password + eseries_validate_certs: false + + eseries_initiator_protocol: nvme_ib + eseries_controller_nvme_ib_port: + controller_a: + - 192.168.1.100 + - 192.168.1.110 + controller_b: + - 192.168.2.100 + - 192.168.2.110 + + eseries_storage_pool_configuration: + - name: vg[1-2] + raid_level: raid6 + criteria_drive_count: 12 + criteria_volume_count: 4 + criteria_reserve_free_capacity_pct: 7 + common_volume_host: server_group + +Role Variables +-------------- +**Note that when values are specified below, they indicate the default value.** + + # Web Services Embedded information + eseries_subnet: # Network subnet to search for the storage system specified in CIDR form. Example: 192.168.1.0/24 + eseries_system_serial: # Storage system serial number. Be sure to quote if the serial is all numbers and begins with zero. (This is located + # on a label at the top-left towards the front on the device) + eseries_system_addresses: # Storage system management IP addresses. Only required when eseries_system_serial or eseries_system_api_url are not + # defined. When not specified, addresses will be populated with eseries_management_interfaces controller addresses. + eseries_system_api_url: # Url for the storage system's for embedded web services rest api. Example: https://192.168.10.100/devmgr/v2 + eseries_system_username: admin # Username for the storage system's for embedded web services rest api + eseries_system_password: # Password for the storage system's for embedded web services rest api and when the admin password has not been set + # eseries_system_password will be used to set it. + eseries_proxy_ssid: # Arbitrary string for the proxy to represent the storage system. eseries_system_serial will be used when not defined. + eseries_template_api_url: # Template for the web services api url. Default: https://0.0.0.0:8443/devmgr/v2/ + eseries_prefer_embedded: false # Overrides the default behavior of using Web Services Proxy when eseries_proxy_api_url is defined. This will only effect storage systems that have Embedded Web Services. + eseries_validate_certs: true # Indicates Whether SSL certificates should be verified. Used for both embedded and proxy. Choices: true, false + + # Web Services Proxy information + Note: eseries_proxy_* variables are required to discover storage systems prior to SANtricity OS version 11.60.2. + eseries_proxy_api_url: # Url for the storage system's for proxy web services rest api. Example: https://192.168.10.100/devmgr/v2 + eseries_proxy_api_username: # Username for the storage system's for proxy web services rest api. + eseries_proxy_api_password: # Password for the storage system's for proxy web services rest api and when the admin password has not been set + # eseries_proxy_api_password will be used to set it. + + # Controller iSCSI Interface Port Default Policy Specifications + eseries_controller_iscsi_port_state: enabled # Generally specifies whether a controller port definition should be applied Choices: enabled, disabled + eseries_controller_iscsi_port_config_method: dhcp # General port configuration method definition for both controllers. Choices: static, dhcp + eseries_controller_iscsi_port_gateway: # General port IPv4 gateway for both controllers. + eseries_controller_iscsi_port_subnet_mask: # General port IPv4 subnet mask for both controllers. + eseries_controller_iscsi_port_mtu: 9000 # General port maximum transfer units (MTU) for both controllers. Any value greater than 1500 (bytes). + eseries_controller_iscsi_port_speed: # General port speed for both controllers. + eseries_controller_iscsi_port: + controller_a: # Ordered list of controller A channel definition. + - state: # Whether the port should be enabled. Choices: enabled, disabled + config_method: # Port configuration method Choices: static, dhcp + address: # Port IPv4 address + gateway: # Port IPv4 gateway + subnet_mask: # Port IPv4 subnet_mask + mtu: # Port IPv4 mtu + speed: # Port speed + controller_b: # Ordered list of controller B channel definition. + - (...) # Same as controller A but for controller B + + # Controller InfiniBand iSER Interface Channel + eseries_controller_ib_iser_port: + controller_a: # Ordered list of controller A channel address definition. + - # Port IPv4 address for channel 1 + - (...) # So on and so forth + controller_b: # Ordered list of controller B channel address definition. + + # Controller NVMe over InfiniBand Interface Channel + eseries_controller_nvme_ib_port: + controller_a: # Ordered list of controller A channel address definition. + - # Port IPv4 address for channel 1 + - (...) # So on and so forth + controller_b: # Ordered list of controller B channel address definition. + + # Controller NVMe RoCE Interface Port Default Policy Specifications + eseries_controller_nvme_roce_port_state: enabled # Generally specifies whether a controller port definition should be applied Choices: enabled, disabled + eseries_controller_nvme_roce_port_config_method: dhcp # General port configuration method definition for both controllers. Choices: static, dhcp + eseries_controller_nvme_roce_port_gateway: # General port IPv4 gateway for both controllers. + eseries_controller_nvme_roce_port_subnet_mask: # General port IPv4 subnet mask for both controllers. + eseries_controller_nvme_roce_port_mtu: 4200 # General port maximum transfer units (MTU). Any value greater than 1500 (bytes). + eseries_controller_nvme_roce_port_speed: auto # General interface speed. Value must be a supported speed or auto for automatically negotiating the speed with the port. + eseries_controller_nvme_roce_port: + controller_a: # Ordered list of controller A channel definition. + - state: # Whether the port should be enabled. + config_method: # Port configuration method Choices: static, dhcp + address: # Port IPv4 address + subnet_mask: # Port IPv4 subnet_mask + gateway: # Port IPv4 gateway + mtu: # Port IPv4 mtu + speed: # Port IPv4 speed + controller_b: # Ordered list of controller B channel definition. + - (...) # Same as controller A but for controller B + + # Target discovery specifications + Note: add the following to ansible-playbook command to update the chap secret: --extra-vars "eseries_target_chap_secret_update=True + eseries_target_name: # iSCSI target name that will be seen by the initiator + eseries_target_ping: True # Enables ICMP ping response from the configured iSCSI ports (boolean) + eseries_target_unnamed_discovery: True # Whether the iSCSI target iqn should be returned when an initiator performs a discovery session. + eseries_target_chap_secret: # iSCSI chap secret. When left blank, the chap secret will be removed from the storage system. + eseries_target_chap_secret_update: False # DO NOT REMOVE! Since na_santricity_iscsi_target cannot compare the chap secret with the current and chooses to always + # return changed=True, this flag is used to force the module to update the chap secret. It is preferable to + # leave this value False and to add the --extra-vars "eseries_target_chap_secret_update=True". + + # Storage Pool Default Policy Specifications + eseries_storage_pool_state: present # Default storage pool state. Choices: present, absent + eseries_storage_pool_raid_level: raidDiskPool # Default volume raid level. Choices: raid0, raid1, raid5, raid6, raidDiskPool + eseries_storage_pool_secure_pool: false # Default for storage pool drive security. This flag will enable the security at rest feature. There + # must be sufficient FDE or FIPS security capable drives. Choices: true, false + eseries_storage_pool_criteria_drive_count: # Default storage pool drive count. + eseries_storage_pool_reserve_drive_count: # Default reserve drive count for drive reconstruction for storage pools using dynamic disk pool and + # the raid level must be set for raidDiskPool. + eseries_storage_pool_criteria_min_usable_capacity: # Default minimum required capacity for storage pools. + eseries_storage_pool_criteria_drive_type: # Default drive type for storage pools. Choices: hdd, ssd + eseries_storage_pool_criteria_drive_interface_type: # Default interface type to use when selecting drives for the storage pool. + # Choices: scsi, fibre, sata, pata, fibre520b, sas, sas4k, nvme4k + eseries_storage_pool_criteria_size_unit: gb # Default unit size for all storage pool related sizing. + # Choices: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb + eseries_storage_pool_criteria_drive_min_size: # Default minimum drive size for storage pools. + eseries_storage_pool_criteria_drive_max_size: # Default maximum drive size for storage pools. + eseries_storage_pool_criteria_drive_require_da: # Default for whether storage pools are required to have data assurance (DA) compatible drives. + # Choices: true, false + eseries_storage_pool_criteria_drive_require_fde: # Default for whether storage pools are required to have drive security compatible drives. + # Choices: true, false + eseries_storage_pool_remove_volumes: # Default policy for deleting volumes prior to removing storage pools. + eseries_storage_pool_erase_secured_drives: # Default policy for erasing the content drives during create and delete storage pool operations. + # Choices: true, false + eseries_storage_pool_ddp_critical_threshold_pct: # Default policy for dynamic disk pool alert critical threshold. + eseries_storage_pool_ddp_warning_threshold_pct: # Default policy for dynamic disk pool alert warning threshold. + + # Volume Default Policy Specifications + eseries_volume_state: present # Default volume state. Choices: present, absent + eseries_volume_size_unit: gb # Default unit size for all volume sizing options. + # Choices: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb, pct + eseries_volume_size: # Default volume size or the presented size for thinly provisioned volumes. + eseries_volume_data_assurance_enabled: # Default for whether data assurance(DA) is required to be enabled. + eseries_volume_segment_size_kb: # Default segment size measured in kib. + eseries_volume_read_cache_enable: # Default for read caching which will cache all read requests. + eseries_volume_read_ahead_enable: # Default for read ahead caching; this is good for sequential workloads to cache subsequent blocks. + eseries_volume_write_cache_enable: # Default for write caching which will cache all writes. + eseries_volume_write_cache_mirror_enable: # Default for write cache mirroring which mirrors writes to both controller's cache. + eseries_volume_cache_without_batteries: # Default for allowing caching when batteries are not present. + eseries_volume_thin_provision: # Default for whether volumes should be thinly provisioned. + eseries_volume_thin_volume_repo_size: # Default for actually allocated space for thinly provisioned volumes. + eseries_volume_thin_volume_max_repo_size: # Default for the maximum allocated space allowed for thinly provisioned volumes. + eseries_volume_thin_volume_expansion_policy: # Default thin volume expansion policy. Choices: automatic, manual + eseries_volume_thin_volume_growth_alert_threshold: # Default thin volume growth alert threshold; this is the threshold for when the thin volume expansion + # policy will be enacted. Allowable values are between and including 10% and 99% + eseries_volume_ssd_cache_enabled: # Default for ssd cache which will enable the volume to use an existing SSD cache on the storage array. + eseries_volume_host: # Default host for all volumes; the value can be any host from the Ansible inventory. Any initiator may be + # used whether connected or not since the storage array does not require connectivity in order to create + # host objects. + eseries_volume_workload_name: # Default workload tag name + eseries_volume_workload_metadata: # Default workload metadata + eseries_volume_volume_metadata: # Default volume_metadata + eseries_volume_owning_controller # Default preferred owning controller + eseries_volume_allow_expansion: false # Default for whether volume expansions are permitted + eseries_volume_wait_for_initialization: false # Default for whether volume creation with wait for initialization to complete + + # Storage Pool-Volume Mapping Default Policy Specifications + eseries_lun_mapping_state: present # Generally specifies whether a LUN mapping should be present. This is useful when adding a default host for all + # volumes. Choices: present, absent + eseries_lun_mapping_host: # Default host for all volumes not specifically give a host either in common_volume_configuration or in + # eseries_storage_pool_configuration. + + # Storage Pool-Volume Default Policy Specifications + Name schemes: Storage pool and volume names can be used to specify a naming scheme to produce a list of storage pools and volumes. The scheme are defined by + brackets and can be used to specify a range of lowercase letters, uppercase letters, range of single digit numbers, any top-level inventory + variables, and the current defined storage pool (volume only). + eseries_storage_pool_configuration: + - name: # Name or name scheme (see above) for the storage pool. + state: # Specifies whether the storage pool should exist (present, absent). When removing an existing storage array all of the + # volumes must be defined with state=absent. + raid_level # Volume group raid level. Choices: raid0, raid1, raid5, raid6, raidDiskPool (Default: raidDiskPool) + secure_pool: # Default for storage pool drive security. This flag will enable the security at rest feature. There must be sufficient FDE + # or FIPS security capable drives. Choices: true, false + criteria_drive_count: # Default storage pool drive count. + criteria_volume_count: # Number of equally sized volumes to create. All available storage pool space will be used. The option will be ignored + # if volumes is defined. + criteria_reserve_free_capacity_pct # Percent of reserve free space capacity to leave when creating the criteria_volume_count volumes. + common_volume_host # Host or host group for the criteria_volume_count volumes should be mapped. + reserve_drive_count: # Default reserve drive count for drive reconstruction for storage pools using dynamic disk pool and the raid level must be + # set for raidDiskPool. + criteria_size_unit: # Unit size for all storage pool related sizing. Choices: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb, pct + criteria_min_usable_capacity: # Minimum required capacity for storage pools. + criteria_drive_type: # Drive type for storage pools. Choices: hdd, ssd + criteria_drive_interface_type # Interface type to use when selecting drives for the storage pool. Choices: scsi, fibre, sata, pata, fibre520b, sas, sas4k, nvme4k + criteria_drive_min_size: # Minimum drive size for storage pools. + criteria_drive_max_size: # Maximum drive size for storage pools. + criteria_drive_require_da: # Whether storage pools are required to have data assurance (DA) compatible drives. Choices: true, false + criteria_drive_require_fde: # Whether storage pools are required to have drive security compatible drives. Choices: true, false + remove_volumes: # Policy for deleting volumes prior to removing storage pools. + erase_secured_drives: # Policy for erasing the content drives during create and delete storage pool operations. Choices: true, false + common_volume_configuration: # Any option that can be specified at the volume level can be generalized here at the storage pool level. This is useful when + # all volumes share common configuration definitions. + volumes: # List of volumes associated the storage pool. + - state: # Specifies whether the volume should exist (present, absent) + name: # (required) Name or name scheme (see above) for the volume(s) to be created in the storage pool(s) + host: # host or host group for the volume should be mapped to. + host_type: # Only required when using something other than Linux kernel 3.10 or later with DM-MP (Linux DM-MP), + # non-clustered Windows (Windows), or the storage system default host type is incorrect. Common definitions below: + # - AIX MPIO: The Advanced Interactive Executive (AIX) OS and the native MPIO driver + # - AVT 4M: Silicon Graphics, Inc. (SGI) proprietary multipath driver; refer to the SGI installation documentation for more information + # - HP-UX: The HP-UX OS with native multipath driver + # - Linux ATTO: The Linux OS and the ATTO Technology, Inc. driver (must use ATTO FC HBAs) + # - Linux DM-MP: The Linux OS and the native DM-MP driver + # - Linux Pathmanager: The Linux OS and the SGI proprietary multipath driver; refer to the SGI installation documentation for more information + # - Mac: The Mac OS and the ATTO Technology, Inc. driver + # - ONTAP: FlexArray + # - Solaris 11 or later: The Solaris 11 or later OS and the native MPxIO driver + # - Solaris 10 or earlier: The Solaris 10 or earlier OS and the native MPxIO driver + # - SVC: IBM SAN Volume Controller + # - VMware: ESXi OS + # - Windows: Windows Server OS and Windows MPIO with a DSM driver + # - Windows Clustered: Clustered Windows Server OS and Windows MPIO with a DSM driver + # - Windows ATTO: Windows OS and the ATTO Technology, Inc. driver + size: # Size of the volume or presented size of the thinly provisioned volume. + size_unit: # Unit size for the size, thin_volume_repo_size, and thin_volume_max_repo_size + # Choices: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb, pct + segment_size_kb: # Indicates the amount of data stored on a drive before moving on to the next drive in the volume group. Does not apply to pool volumes. + thin_provision: # Whether volumes should be thinly provisioned. + thin_volume_repo_size: # Actually allocated space for thinly provisioned volumes. + thin_volume_max_repo_size: # Maximum allocated space allowed for thinly provisioned volumes. + thin_volume_expansion_policy: # Thin volume expansion policy. Choices: automatic, manual + thin_volume_growth_alert_threshold: # Thin volume growth alert threshold; this is the threshold for when the thin volume expansion + # policy will be enacted. Allowable values are between and including 10% and 99% + ssd_cache_enabled: # Enables ssd cache which will enable the volume to use an existing SSD cache on the storage array. + data_assurance_enabled: # Enables whether data assurance(DA) is required to be enabled. + read_cache_enable: # Enables read caching which will cache all read requests. + read_ahead_enable: # Enables read ahead caching; this is good for sequential workloads to cache subsequent blocks. + write_cache_enable: # Enables write caching which will cache all writes. + write_cache_mirror_enable: # Enables write cache mirroring which mirrors writes to both controller's cache. + workload_name: # Name of the volume's workload. This can be defined using the metadata option or, if already defined, specify one already + # created on the storage array. + workload_metadata: # Dictionary containing arbitrary entries normally used for defining the volume(s) workload. + volume_metadata # Dictionary containing arbitrary entries used to define information about the volume itself. + # Note: format_type, format_options[0-9]?, mount_directory, mount_options[0-9]? are used by netapp_eseries.host.mount role to format and mount volumes. + allow_expansion: # Whether volume expansions are permitted + wait_for_initialization: # Whether volume creation with wait for initialization to complete + + # Snapshot Consistency Group Default Policy Specifications + eseries_snapshot_remove_unspecified: # Whether to remove any snapshot group or view that is not specified (Default: false). + eseries_snapshot_groups_maximum_snapshots: # Default maximum point-in-time snapshot images (Default: 32). + eseries_snapshot_groups_reserve_capacity_pct: # Default reserve capacity percentage (Default: 40) + eseries_snapshot_groups_preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. + eseries_snapshot_groups_reserve_capacity_full_policy: # Default full reserve capacity policy (Default: purge). Choices: [purge, reject] + eseries_snapshot_groups_alert_threshold_pct: # Default reserve capacity percentage full to alert administrators (Default 75). + eseries_snapshot_groups: + - name: # Name of snapshot consistency group. + maximum_snapshots: # Maximum allowed snapshot point-in-time images for consistency group (Default: 32). + reserve_capacity_pct: # Reserve capacity measured as a percentage of the base volume (Default: 40). Reserve capacity can be expanded + # and trimmed; however, the trim operation requires there be no base volume snapshots images in the group. + reserve_capacity_full_policy: # Policy to implement when reserve capacity is full (Default: purge). Choices [purge, reject] + alert_threshold_pct: # Reserve capacity full alert threshold for storage system administrators (Default: 75). + rollback_priority: # Storage system priority for base volume rollback (Default: medium). Choices [lowest, low, medium, high, highest] + volumes: # Information for each volume in the consistency group. + - volume: # Base volume name + reserve_capacity_pct: # Reserve capacity measured as a percentage of the base volume (Default: 40). Reserve capacity can be expanded + # and trimmed; however, the trim operation requires there be no base volume snapshots images in the group. + preferred_reserve_storage_pool: # Preferred reserve capacity storage pool or volume group. This will default to the base volume's + # storage pool or volume group. The reserve capacity volume cannot be changed once created. + - (...) + + # Snapshot Consistency Group View Default Policy Specifications + eseries_snapshot_views_host: # Default host or host group to map all snapshot volumes. + eseries_snapshot_views_reserve_capacity_pct: # Default reserve capacity percentage (Default: 40) + eseries_snapshot_views_preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. + eseries_snapshot_views_alert_threshold_pct: # Default reserve capacity percentage full to alert administrators (Default 75). + eseries_snapshot_views_writable: # Default for whether to make snapshot volumes writable. + eseries_snapshot_views_validate: # Default for whether to validate snapshot volumes after creation. + eseries_snapshot_views: + - volume: # Consistency group's snapshot view's name. + group_name: # Snapshot consistency group's name. + pit_name: # Point-in-time snapshot images group name. (Only available when specified using Ansible na_santricity_module (via direct or role) + pit_timestamp: # Point-in-time snapshot images group timestamp. Snapshot image timestamp in the YYYY-MM-DD HH:MM:SS (AM|PM) (hours, minutes, seconds, and day-period are optional) + host: # Host or host group to map snapshot volumes. + writable: # Whether snapshot volume of base volume images should be writable. + validate: # Whether snapshot volume should be validated which includes both a media scan and parity validation. + reserve_capacity_pct: # Percentage of base volume capacity to reserve for snapshot copy-on-writes (COW). Only used when snapshot volume is writable. + preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. + alert_threshold: # Reserve capacity percentage full to alert administrators + volumes: # (Optional) Select subset of volumes within the snapshot consistency group. + - name: # Name of volume within consistency group. + host: # Host or host group to map snapshot volumes. + lun: # Logical unit number (LUN) mapping for the host or host group. + writable: # Whether snapshot volume of base volume images should be writable. + validate: # Whether snapshot volume should be validated which includes both a media scan and parity validation. + reserve_capacity_pct: # Percentage of base volume capacity to reserve for snapshot copy-on-writes (COW). Only used when snapshot volume is writable. + preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. + + # Snapshot Consistency Group Rollback Default Policy Specifications + eseries_snapshot_rollback_priority: medium # Default point-in-time rollback priority (Default: medium). Choices [lowest, low, medium, high, highest] + eseries_snapshot_rollback_backup: true # Default whether snapshot should be taken prior to rolling back base volumes (Default: true). + eseries_snapshot_rollbacks: + - group_name: # Snapshot consistency group's name. + pit_name: # Point-in-time snapshot images group name (Only available when specified using Ansible na_santricity_module (via direct or role) + pit_timestamp: # Point-in-time snapshot images group timestamp. Snapshot image timestamp in the YYYY-MM-DD HH:MM:SS (AM|PM) (hours, minutes, seconds, and day-period are optional) + rollback_priority: # Storage system priority for base volume rollback (Default: medium). Choices [lowest, low, medium, high, highest] + rollback_backup: # Whether to create point-in-time snapshot images of the consistency group prior to rollback. + volumes: + + # Initiator-Target Protocol Variable Defaults + Note that the following commands need to produce a unique list of IQNs or WWNs of the interfaces used, line separated. Overwrite as necessary. + eseries_initiator_protocol: fc # This variable defines which protocol the storage array will use. Choices: fc, iscsi, sas, ib_iser, ib_srp, nvme_ib, nvme_fc, nvme_roce + eseries_initiator_command: + fc: + linux: "cat /sys/class/fc_host/host*/port_name | sort | uniq" + windows: "(Get-InitiatorPort | Where-Object -P ConnectionType -EQ 'Fibre Channel' | Select-Object -Property PortAddress | + Format-Table -AutoSize -HideTableHeaders | Out-String).trim()" + iscsi: + linux: "grep -o iqn.* /etc/iscsi/initiatorname.iscsi" + windows: "(get-initiatorPort | select-object -property nodeaddress | sort-object | get-unique | ft -autoSize | out-string -stream | + select-string iqn | out-string).trim()" + sas: + # NetApp IMT for SAS attached E-Series SAN hosts recommends adding all possible SAS addresses with the base address + # starting at 0, and the last address ending in 3 for single port HBAs, or 7 for dual port HBAs. Since determining + # single vs . dual port HBAs adds complexity, we always add all 8 possible permutations of the SAS address. + linux: "cat /sys/class/sas_host/host*/device/scsi_host/*/host_sas_address | sort | uniq" + windows: "(Get-InitiatorPort | Where-Object -P ConnectionType -EQ 'SAS' | Select-Object -Property PortAddress | Format-Table -AutoSize -HideTableHeaders | Out-String).trim()" + ib_iser: + linux: "grep -o iqn.* /etc/iscsi/initiatorname.iscsi" + windows: "" # add windows command for determining host iqn address(es) + ib_srp: + linux: "for fp in /sys/class/infiniband/*/ports/*/gids/*; do out=`cat $fp | tr -d :`; port=`expr substr $out 17 32`; if [ $port != 0000000000000000 ]; then echo 0x$port; fi; done | sort | uniq" + windows: "" # add windows command for determining host guid + nvme_ib: + linux: "grep -o nqn.* /etc/nvme/hostnqn" + windows: "" # add windows command for determining host nqn address(es) + nvme_fc: + linux: "grep -o nqn.* /etc/nvme/hostnqn" + windows: "" # add windows command for determining host nqn address(es) + nvme_roce: + linux: "grep -o nqn.* /etc/nvme/hostnqn" + windows: "" # add windows command for determining host nqn address(es) + + # Manual host definitions, Linux and Windows systems can be automatically populated based on host mappings found in eseries_storage_pool_configuration + eseries_host_force_port: true # Default for whether ports are to be allowed to be re-assigned (boolean) + eseries_host_remove_unused_hostgroup: true # Forces any unused groups to be removed + eseries_host_object: + - name: # Host label as referenced by the storage array. + state: # Specifies whether host definition should be exist. Choices: present, absent + ports: # List of port definitions + - type: # Port protocol definition (iscsi, fc, sas, ib, nvme). Note that you should use 'iscsi' prior to Santricity version 11.60 for IB iSER. + label: # Arbitrary port label + port: # Port initiator (iqn, wwn, etc) + group: # Host's host group + host_type: # Only required when using something other than Linux kernel 3.10 or later with DM-MP (Linux DM-MP), + # non-clustered Windows (Windows), or the storage system default host type is incorrect. Common definitions below: + # - AIX MPIO: The Advanced Interactive Executive (AIX) OS and the native MPIO driver + # - AVT 4M: Silicon Graphics, Inc. (SGI) proprietary multipath driver; refer to the SGI installation documentation for more information + # - HP-UX: The HP-UX OS with native multipath driver + # - Linux ATTO: The Linux OS and the ATTO Technology, Inc. driver (must use ATTO FC HBAs) + # - Linux DM-MP: The Linux OS and the native DM-MP driver + # - Linux Pathmanager: The Linux OS and the SGI proprietary multipath driver; refer to the SGI installation documentation for more information + # - Mac: The Mac OS and the ATTO Technology, Inc. driver + # - ONTAP: FlexArray + # - Solaris 11 or later: The Solaris 11 or later OS and the native MPxIO driver + # - Solaris 10 or earlier: The Solaris 10 or earlier OS and the native MPxIO driver + # - SVC: IBM SAN Volume Controller + # - VMware: ESXi OS + # - Windows: Windows Server OS and Windows MPIO with a DSM driver + # - Windows Clustered: Clustered Windows Server OS and Windows MPIO with a DSM driver + # - Windows ATTO: Windows OS and the ATTO Technology, Inc. driver + +License +------- + BSD-3-Clause + +Author Information +------------------ + Nathan Swartz (@ndswartz) diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/defaults/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/defaults/main.yml new file mode 100644 index 000000000..da9db4c7d --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/defaults/main.yml @@ -0,0 +1,367 @@ +# Web Services Embedded information +#eseries_subnet: # Network subnet to search for the storage system specified in CIDR form. Example: 192.168.1.0/24 +#eseries_system_serial: # Storage system serial number. Be sure to quote if the serial is all numbers and begins with zero. (This is located + # on a label at the top-left towards the front on the device) +#eseries_system_addresses: # Storage system management IP addresses. Only required when eseries_system_serial or eseries_system_api_url are not + # defined. When not specified, addresses will be populated with eseries_management_interfaces controller addresses. +#eseries_system_api_url: # Url for the storage system's for embedded web services rest api. Example: https://192.168.10.100/devmgr/v2 +#eseries_system_username: # Username for the storage system's for embedded web services rest api +#eseries_system_password: # Password for the storage system's for embedded web services rest api and when the admin password has not been set + # eseries_system_password will be used to set it. +#eseries_proxy_ssid: # Arbitrary string for the proxy to represent the storage system. eseries_system_serial will be used when not defined. +#eseries_template_api_url: # Template for the web services api url. Default: https://0.0.0.0:8443/devmgr/v2/ +#eseries_validate_certs: # Indicates Whether SSL certificates should be verified. Used for both embedded and proxy. Choices: true, false + +# Web Services Proxy information +# Note: eseries_proxy_* variables are required to discover storage systems prior to SANtricity OS version 11.60.2. +#eseries_proxy_api_url: # Url for the storage system's for proxy web services rest api. Example: https://192.168.10.100/devmgr/v2 +#eseries_proxy_api_username: # Username for the storage system's for proxy web services rest api. +#eseries_proxy_api_password: # Password for the storage system's for proxy web services rest api and when the admin password has not been set + # eseries_proxy_api_password will be used to set it. + + +# Storage Pool Default Policy Specifications +# ------------------------------------------ +eseries_storage_pool_state: present # Default storage pool state. Choices: present, absent +eseries_storage_pool_raid_level: raidDiskPool # Default volume raid level. Choices: raid0, raid1, raid5, raid6, raidDiskPool +eseries_storage_pool_secure_pool: false # Default for storage pool drive security. This flag will enable the security at rest feature. There + # must be sufficient FDE or FIPS security capable drives. Type: boolean +#eseries_storage_pool_criteria_drive_count: # Default storage pool drive count. +#eseries_storage_pool_reserve_drive_count: # Default reserve drive count for drive reconstruction for storage pools using dynamic disk pool and + # the raid level must be set for raidDiskPool. +#eseries_storage_pool_criteria_min_usable_capacity: # Default minimum required capacity for storage pools. +#eseries_storage_pool_criteria_drive_type: # Default drive type for storage pools. Choices: hdd, ssd +eseries_storage_pool_criteria_size_unit: gb # Default unit size for all storage pool related sizing. + # Choices: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb +#eseries_storage_pool_criteria_drive_min_size: # Default minimum drive size for storage pools. +#eseries_storage_pool_criteria_drive_require_da: # Default for whether storage pools are required to have data assurance (DA) compatible drives. + # Type: boolean +#eseries_storage_pool_criteria_drive_require_fde: # Default for whether storage pools are required to have drive security compatible drives. + # Type: boolean +#eseries_storage_pool_usable_drives: # Ordered list of <tray_number>:<drive_slot> strings for drive candidates. This is useful to control + # drive selections. +eseries_storage_pool_remove_volumes: True # Default policy for deleting volumes prior to removing storage pools. +#eseries_storage_pool_erase_secured_drives: # Default policy for erasing the content drives during create and delete storage pool operations. + # Type: boolean +#eseries_storage_pool_ddp_critical_threshold_pct: # Default policy for dynamic disk pool alert critical threshold. +#eseries_storage_pool_ddp_warning_threshold_pct: # Default policy for dynamic disk pool alert warning threshold. + +# Volume Default Policy Specifications +# ------------------------------------ +eseries_volume_state: present # Default volume state. Choices: present, absent +eseries_volume_size_unit: gb # Default unit size for all volume sizing options. +#eseries_volume_size: # Default volume size or the presented size for thinly provisioned volumes. +#eseries_volume_data_assurance_enabled: # Default for whether data assurance(DA) is required to be enabled. +#eseries_volume_segment_size_kb: # Default segment size measured in kib. +#eseries_volume_read_cache_enable: # Default for read caching which will cache all read requests. +#eseries_volume_read_ahead_enable: # Default for read ahead caching; this is good for sequential workloads to cache subsequent blocks. +#eseries_volume_write_cache_enable: # Default for write caching which will cache all writes. +#eseries_volume_cache_without_batteries: # Default for allowing caching when batteries are not present. +#eseries_volume_thin_provision: # Default for whether volumes should be thinly provisioned. +#eseries_volume_thin_volume_repo_size: # Default for actually allocated space for thinly provisioned volumes. +#eseries_volume_thin_volume_max_repo_size: # Default for the maximum allocated space allowed for thinly provisioned volumes. +#eseries_volume_thin_volume_expansion_policy: # Default thin volume expansion policy. Choices: automatic, manual +#eseries_volume_thin_volume_growth_alert_threshold: # Default thin volume growth alert threshold; this is the threshold for when the thin volume expansion + # policy will be enacted. Allowable values are between and including 10% and 99% +#eseries_volume_ssd_cache_enabled: # Default for ssd cache which will enable the volume to use an existing SSD cache on the storage array. +#eseries_volume_host: # Default host for all volumes; the value can be any host from the Ansible inventory. Any initiator may be + # used whether connected or not since the storage array does not require connectivity in order to create + # host objects. +#eseries_volume_workload_name: # Default workload tag name +#eseries_volume_metadata: # Default metadata +#eseries_volume_owning_controller # Default preferred owning controller +eseries_volume_wait_for_initialization: false # Default for whether volume creation with wait for initialization to complete + + +# Storage Pool-Volume Mapping Default Policy Specifications +# --------------------------------------------------------- +eseries_lun_mapping_state: present # Generally specifies whether a LUN mapping should be present. This is useful when adding a default host for all + # volumes. Choices: present, absent +#eseries_lun_mapping_host: # Default host for all volumes not specifically give a host either in common_volume_configuration or in + # eseries_storage_pool_configuration. + + +# Controller iSCSI Interface Port Default Policy Specifications +# ------------------------------------------------------- +eseries_controller_iscsi_port_state: enabled # Generally specifies whether a controller port definition should be applied Choices: enabled, disabled +eseries_controller_iscsi_port_config_method: dhcp # General port configuration method definition for both controllers. Choices: static, dhcp +#eseries_controller_iscsi_port_gateway: # General port IPv4 gateway for both controllers. +#eseries_controller_iscsi_port_subnet_mask: # General port IPv4 subnet mask for both controllers. +eseries_controller_iscsi_port_mtu: 9000 # General port maximum transfer units (MTU) for both controllers. Any value greater than 1500 (bytes). +#eseries_controller_iscsi_port: +# controller_a: # Controller A port definition. +# state: # General definitions for all ports on controller A. Any option specified in the ports definition can be + # specified here to generalize for all controller A ports. Choices: enabled, disabled +# config_method: # Port configuration method Choices: static, dhcp +# address: # Port IPv4 address +# gateway: # Port IPv4 gateway +# subnet_mask: # Port IPv4 subnet_mask +# mtu: # Port IPv4 mtu +# ports: # List containing ports definitions +# - state: # Whether the port should be enabled. Choices: enabled, disabled +# config_method: # Port configuration method Choices: static, dhcp +# address: # Port IPv4 address +# gateway: # Port IPv4 gateway +# subnet_mask: # Port IPv4 subnet_mask +# controller_b: # Controller B port definition. +# (...) # Same as controller A but for controller B + + + +# Controller InfiniBand iSER Interface Channel +# -------------------------------------------- +#eseries_controller_ib_iser_port: +# controller_a: # Ordered list of controller A channel address definition. +# - # Port IPv4 address for channel 1 +# - (...) # So on and so forth +# controller_b: # Ordered list of controller B channel address definition. + +# Controller NVMe over InfiniBand Interface Channel +# ------------------------------------------------- +#eseries_controller_nvme_ib_port: +# controller_a: # Ordered list of controller A channel address definition. +# - # Port IPv4 address for channel 1 +# - (...) # So on and so forth +# controller_b: # Ordered list of controller B channel address definition. + +# Controller NVMe RoCE Interface Port Default Policy Specifications +# ------------------------------------------------------- +eseries_controller_nvme_roce_port_state: enabled # Generally specifies whether a controller port definition should be applied Choices: enabled, disabled +eseries_controller_nvme_roce_port_config_method: dhcp # General port configuration method definition for both controllers. Choices: static, dhcp +#eseries_controller_nvme_roce_port_gateway: # General port IPv4 gateway for both controllers. +#eseries_controller_nvme_roce_port_subnet_mask: # General port IPv4 subnet mask for both controllers. +eseries_controller_nvme_roce_port_mtu: 4200 # General port maximum transfer units (MTU). Any value greater than 1500 (bytes). +eseries_controller_nvme_roce_port_speed: auto # General interface speed. Value must be a supported speed or auto for automatically negotiating the speed with the port. +#eseries_controller_nvme_roce_port: +# controller_a: # Controller A port definition. +# state: # General definitions for all ports on controller A. Any option specified in the ports definition can be + # specified here to generalize for all controller A ports. +# config_method: # Port configuration method Choices: static, dhcp +# address: # Port IPv4 address +# gateway: # Port IPv4 gateway +# subnet_mask: # Port IPv4 subnet_mask +# mtu: # Port IPv4 mtu +# speed: # Port IPv4 speed +# ports: # List containing ports definitions +# - channel: # Channel of the port to modify. This will be a numerical value that represents the port; typically read + # left to right on the HIC. +# state: # Whether the port should be enabled. +# config_method: # Port configuration method Choices: static, dhcp +# address: # Port IPv4 address +# gateway: # Port IPv4 gateway +# subnet_mask: # Port IPv4 subnet_mask +# controller_b: # Controller B port definition. +# state: # General definitions for all ports on controller B. Any option specified in the ports definition can be + # specified here to generalize for all controller A ports. +# config_method: # Port configuration method Choices: static, dhcp +# address: # Port IPv4 address +# gateway: # Port IPv4 gateway +# subnet_mask: # Port IPv4 subnet_mask +# mtu: # Port IPv4 mtu +# speed: # Port IPv4 speed +# ports: # List containing ports definitions +# - channel: # Channel of the port to modify. This will be a numerical value that represents the port; typically read + # left to right on the HIC. +# state: # Whether the port should be enabled. +# config_method: # Port configuration method Choices: static, dhcp +# address: # Port IPv4 address +# gateway: # Port IPv4 gateway +# subnet_mask: # Port IPv4 subnet_mask + + +# Target Discovery Default Policy Specifications +# ---------------------------------------------- +#eseries_target_name: # iSCSI target name +eseries_target_ping: True # Enables ICMP ping response from the configured iSCSI ports (boolean) +eseries_target_unnamed_discovery: True # Whether the iSCSI target iqn should be returned when an initiator performs a discovery session. +eseries_target_chap_secret: # iSCSI chap secret. When left blank, the chap secret will be removed from the storage system. +eseries_target_chap_secret_update: False # DO NOT REMOVE! Since netapp_e_iscsi_target cannot compare the chap secret with the current and chooses to always + # return changed=True, this flag is used to force the module to update the chap secret. It is preferable to + # leave this value False and to add the --extra-vars "eseries_target_chap_secret_update=True". + +# Host Default Policy Specifications +# ---------------------------------- +eseries_host_force_port: True # Default for whether ports are to be allowed to be re-assigned (boolean) +eseries_host_remove_unused_hostgroup: True # Forces any unused groups to be removed +#eseries_host_object: +# - name: # Host label as referenced by the storage array. +# state: +# host_type: # Windows (non-clustering) 1, Windows (clustering) 6, Vmware 10, Linux (using kernal 3.10 and later) 28 +# group: # Host's host group +# ports: # List of port definitions +# - type: # Port protocol definition (iscsi, fc, sas, ib, nvme) +# label: # Arbitrary port label +# port: # Port initiator (iqn, wwn, etc) + + +# Storage Pool-Volume Default Policy Specifications +# ------------------------------------------------- +# Name schemes: Storage pool and volume names can be used to specify a naming scheme to produce a list of storage pools and volumes. The scheme are defined by +# brackets and can be used to specify a range of lowercase letters, uppercase letters, range of single digit numbers, any top-level inventory +# variables, and the current defined storage pool (volume only). + +#eseries_storage_pool_configuration: +# - name: # Name or name scheme (see above) for the storage pool. +# state: # Specifies whether the storage pool should exist (present, absent). When removing an existing storage array all of the + # volumes must be defined with state=absent. +# raid_level # Volume group raid level. Choices: raid0, raid1, raid5, raid6, raidDiskPool (Default: raidDiskPool) +# secure_pool: no # Default for storage pool drive security. This flag will enable the security at rest feature. There must be sufficient FDE + # or FIPS security capable drives. Type: boolean +# criteria_drive_count: # Default storage pool drive count. +# reserve_drive_count: # Default reserve drive count for drive reconstruction for storage pools using dynamic disk pool and the raid level must be + # set for raidDiskPool. +# criteria_min_usable_capacity: # Default minimum required capacity for storage pools. +# criteria_drive_type: # Default drive type for storage pools. Choices: hdd, ssd +# criteria_size_unit: gb # Default unit size for all storage pool related sizing. Choices: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb +# criteria_drive_min_size: # Default minimum drive size for storage pools. +# criteria_drive_require_da: # Default for whether storage pools are required to have data assurance (DA) compatible drives. Type: boolean +# criteria_drive_require_fde: # Default for whether storage pools are required to have drive security compatible drives. Type: boolean +# usable_drives: # Ordered list of <tray_number>:<drive_slot> strings for drive candidates. This is useful to control + # drive selections. +# remove_volumes: # Default policy for deleting volumes prior to removing storage pools. +# erase_secured_drives: # Default policy for erasing the content drives during create and delete storage pool operations. Type: boolean +# common_volume_configuration: # Any option that can be specified at the volume level can be generalized here at the storage pool level. This is useful when + # all volumes share common configuration definitions. +# volumes: # List of volumes associated the storage pool. +# - state: # Specifies whether the volume should exist (present, absent) +# name: # (required) Name or name scheme (see above) for the volume(s) to be created in the storage pool(s) +# host: # host or host group for the volume should be mapped to. +# host_type: # Only required when using something other than Linux kernel 3.10 or later with DM-MP (Linux DM-MP), + # non-clustered Windows (Windows), or the storage system default host type is incorrect. Common definitions below: + # - AIX MPIO: The Advanced Interactive Executive (AIX) OS and the native MPIO driver + # - AVT 4M: Silicon Graphics, Inc. (SGI) proprietary multipath driver; refer to the SGI installation documentation for more information + # - HP-UX: The HP-UX OS with native multipath driver + # - Linux ATTO: The Linux OS and the ATTO Technology, Inc. driver (must use ATTO FC HBAs) + # - Linux DM-MP: The Linux OS and the native DM-MP driver + # - Linux Pathmanager: The Linux OS and the SGI proprietary multipath driver; refer to the SGI installation documentation for more information + # - Mac: The Mac OS and the ATTO Technology, Inc. driver + # - ONTAP: FlexArray + # - Solaris 11 or later: The Solaris 11 or later OS and the native MPxIO driver + # - Solaris 10 or earlier: The Solaris 10 or earlier OS and the native MPxIO driver + # - SVC: IBM SAN Volume Controller + # - VMware: ESXi OS + # - Windows: Windows Server OS and Windows MPIO with a DSM driver + # - Windows Clustered: Clustered Windows Server OS and Windows MPIO with a DSM driver + # - Windows ATTO: Windows OS and the ATTO Technology, Inc. driver +# size: # Size of the volume or presented size of the thinly provisioned volume. +# size_unit: # Unit size for the size, thin_volume_repo_size, and thin_volume_max_repo_size + # Choices: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb +# segment_size_kb: # Indicates the amount of data stored on a drive before moving on to the next drive in the volume group. Does not apply to pool volumes. +# thin_provision: # Whether volumes should be thinly provisioned. +# thin_volume_repo_size: # Actually allocated space for thinly provisioned volumes. +# thin_volume_max_repo_size: # Maximum allocated space allowed for thinly provisioned volumes. +# thin_volume_expansion_policy: # Thin volume expansion policy. Choices: automatic, manual +# thin_volume_growth_alert_threshold: # Thin volume growth alert threshold; this is the threshold for when the thin volume expansion + # policy will be enacted. Allowable values are between and including 10% and 99% +# ssd_cache_enabled: # Enables ssd cache which will enable the volume to use an existing SSD cache on the storage array. +# data_assurance_enabled: # Enables whether data assurance(DA) is required to be enabled. +# read_cache_enable: # Enables read caching which will cache all read requests. +# read_ahead_enable: # Enables read ahead caching; this is good for sequential workloads to cache subsequent blocks. +# write_cache_enable: # Enables write caching which will cache all writes. +# workload_name: # Name of the volume's workload. This can be defined using the metadata option or, if already defined, specify one already + # created on the storage array. +# metadata: # Dictionary containing arbitrary entries normally used for defining the volume(s) workload. +# wait_for_initialization: # Whether volume creation with wait for initialization to complete + +# Snapshot Consistency Group Default Policy Specifications +# -------------------------------------------------------- +eseries_snapshot_remove_unspecified: false # Whether to remove any snapshot group or view that is not specified (Default: false). +#eseries_snapshot_groups_maximum_snapshots: # Default maximum point-in-time snapshot images (Default: 32). +#eseries_snapshot_groups_reserve_capacity_pct: # Default reserve capacity percentage (Default: 40) +#eseries_snapshot_groups_preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. +#eseries_snapshot_groups_reserve_capacity_full_policy: # Default full reserve capacity policy (Default: purge). Choices: [purge, reject] +#eseries_snapshot_groups_alert_threshold_pct: # Default reserve capacity percentage full to alert administrators (Default 75). +#eseries_snapshot_groups: +# - name: # Name of snapshot consistency group. +# maximum_snapshots: # Maximum allowed snapshot point-in-time images for consistency group (Default: 32). +# reserve_capacity_pct: # Reserve capacity measured as a percentage of the base volume (Default: 40). Reserve capacity can be expanded +# # and trimmed; however, the trim operation requires there be no base volume snapshots images in the group. +# reserve_capacity_full_policy: # Policy to implement when reserve capacity is full (Default: purge). Choices [purge, reject] +# alert_threshold_pct: # Reserve capacity full alert threshold for storage system administrators (Default: 75). +# rollback_priority: # Storage system priority for base volume rollback (Default: medium). Choices [lowest, low, medium, high, highest] +# volumes: # Information for each volume in the consistency group. +# - volume: # Base volume name +# reserve_capacity_pct: # Reserve capacity measured as a percentage of the base volume (Default: 40). Reserve capacity can be expanded + # and trimmed; however, the trim operation requires there be no base volume snapshots images in the group. +# preferred_reserve_storage_pool: # Preferred reserve capacity storage pool or volume group. This will default to the base volume's + # storage pool or volume group. The reserve capacity volume cannot be changed once created. +# - (...) + +#eseries_snapshot_views_host: # Default host or host group to map all snapshot volumes. +#eseries_snapshot_views_reserve_capacity_pct: # Default reserve capacity percentage (Default: 40) +#eseries_snapshot_views_preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. +#eseries_snapshot_views_alert_threshold_pct: # Default reserve capacity percentage full to alert administrators (Default 75). +#eseries_snapshot_views_writable: # Default for whether to make snapshot volumes writable. +#eseries_snapshot_views_validate: # Default for whether to validate snapshot volumes after creation. +#eseries_snapshot_views: +# - volume: # Consistency group's snapshot view's name. +# group_name: # Snapshot consistency group's name. +# pit_name: # Point-in-time snapshot images group name. (Only available when specified using Ansible na_santricity_module (via direct or role) +# pit_timestamp: # Point-in-time snapshot images group timestamp. Snapshot image timestamp in the YYYY-MM-DD HH:MM:SS (AM|PM) (hours, minutes, seconds, and day-period are optional) +# host: # Host or host group to map snapshot volumes. +# writable: # Whether snapshot volume of base volume images should be writable. +# validate: # Whether snapshot volume should be validated which includes both a media scan and parity validation. +# reserve_capacity_pct: # Percentage of base volume capacity to reserve for snapshot copy-on-writes (COW). Only used when snapshot volume is writable. +# preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. +# alert_threshold: # Reserve capacity percentage full to alert administrators +# volumes: # (Optional) Select subset of volumes within the snapshot consistency group. +# - name: # Name of volume within consistency group. +# host: # Host or host group to map snapshot volumes. +# writable: # Whether snapshot volume of base volume images should be writable. +# validate: # Whether snapshot volume should be validated which includes both a media scan and parity validation. +# reserve_capacity_pct: # Percentage of base volume capacity to reserve for snapshot copy-on-writes (COW). Only used when snapshot volume is writable. +# preferred_reserve_storage_pool: # Preferred storage pool or volume group for the reserve capacity volume. + +#eseries_snapshot_rollback_priority: medium # Default point-in-time rollback priority (Default: medium). Choices [lowest, low, medium, high, highest] +#eseries_snapshot_rollback_backup: true # Default whether snapshot should be taken prior to rolling back base volumes (Default: true). +#eseries_snapshot_rollbacks: +# - group_name: # Snapshot consistency group's name. +# pit_name: # Point-in-time snapshot images group name (Only available when specified using Ansible na_santricity_module (via direct or role) +# pit_timestamp: # Point-in-time snapshot images group timestamp. Snapshot image timestamp in the YYYY-MM-DD HH:MM:SS (AM|PM) (hours, minutes, seconds, and day-period are optional) +# rollback_priority: # Storage system priority for base volume rollback (Default: medium). Choices [lowest, low, medium, high, highest] +# rollback_backup: # Whether to create point-in-time snapshot images of the consistency group prior to rollback. +# volumes: # (Optional) Select subset of volume names within the snapshot consistency group to rollback. + +# Initiator-Target Protocol Variable Defaults +# ------------------------------------------- +# Note that the following commands produce a unique list of IQNs or WWNs of the interfaces used, line separated. +eseries_initiator_protocol: # This variable defines which protocol the storage array will use. Choices: iscsi, fc, sas, ib_iser, ib_srp, nvme_ib, nvme_fc, nvme_roce +eseries_initiator_command: + fc: + linux: "cat /sys/class/fc_host/host*/port_name | sort | uniq" + windows: "(Get-InitiatorPort | Where-Object -P ConnectionType -EQ 'Fibre Channel' | Select-Object -Property PortAddress | + Format-Table -AutoSize -HideTableHeaders | Out-String).trim()" + iscsi: + linux: "grep -o iqn.* /etc/iscsi/initiatorname.iscsi" + windows: "(get-initiatorPort | select-object -property nodeaddress | sort-object | get-unique | ft -autoSize | out-string -stream | + select-string iqn | out-string).trim()" + sas: + # NetApp IMT for SAS attached E-Series SAN hosts recommends adding all possible SAS addresses with the base address + # starting at 0, and the last address ending in 3 for single port HBAs, or 7 for dual port HBAs. Since determining + # single vs . dual port HBAs adds complexity, we always add all 8 possible permutations of the SAS address. + linux: "cat /sys/class/sas_host/host*/device/scsi_host/*/host_sas_address | sort | uniq" + windows: "(Get-InitiatorPort | Where-Object -P ConnectionType -EQ 'SAS' | Select-Object -Property PortAddress | Format-Table -AutoSize -HideTableHeaders | Out-String).trim()" + ib_iser: + linux: "grep -o iqn.* /etc/iscsi/initiatorname.iscsi" + windows: "" # add windows command for determining host iqn address(es) + ib_srp: + linux: "for fp in /sys/class/infiniband/*/ports/*/gids/*; do out=`cat $fp | tr -d :`; port=`expr substr $out 17 32`; if [ $port != 0000000000000000 ]; then echo 0x$port; fi; done | sort | uniq" + windows: "" # add windows command for determining host guid + nvme_ib: + linux: "grep -o nqn.* /etc/nvme/hostnqn" + windows: "" # add windows command for determining host nqn address(es) + nvme_fc: + linux: "grep -o nqn.* /etc/nvme/hostnqn" + windows: "" # add windows command for determining host nqn address(es) + nvme_roce: + linux: "grep -o nqn.* /etc/nvme/hostnqn" + windows: "" # add windows command for determining host nqn address(es) + +eseries_iscsi_iqn_prefix: "iqn.2005-03.org.open-iscsi:" # Last 12 characters from host machine-id (uuid) will be appended to the prefix if the host does not have a required iqn. +eseries_nvme_nqn_prefix: "nqn.2014-08.org.nvmexpress:uuid:" # Host machine-id (uuid) will be appended to the prefix if the host does not have a required nqn. +eseries_protocols_using_eseries_iscsi_iqn: ["iscsi", "ib_iser"] +eseries_protocols_using_eseries_nvme_nqn: ["nvme_ib", "nvme_fc", "nvme_roce"] +eseries_iscsi_iqn_path: "/etc/iscsi/" #initiatorname.iscsi" +eseries_nvme_nqn_path: "/etc/nvme/" #hostnqn" + +eseries_remove_all_configuration: False # WARNING!!! This flag will force any storage pool, volume, host, hostgroup and mapping to be absent. Choices: True, False
\ No newline at end of file diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/meta/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/meta/main.yml new file mode 100644 index 000000000..05169af14 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/meta/main.yml @@ -0,0 +1,19 @@ +galaxy_info: + author: Nathan Swartz (@ndswartz) + description: Manages NetApp E-Series storage system's interfaces, storage pools, volumes, hosts, hostgroups, and volume mappings. + company: NetApp, Inc + license: BSD-3 Clause + platforms: + min_ansible_version: 2.13 + galaxy_tags: + - netapp + - eseries + - storage + - iscsi + - sas + - fc + - infiniband + - ib + - nvme + +dependencies: [] diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/initiator.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/initiator.yml new file mode 100644 index 000000000..4d40051d5 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/initiator.yml @@ -0,0 +1,114 @@ +--- +# netapp_eseries_iscsi/tasks/initiator.yml + +- name: Collect facts on the storage array + na_santricity_facts: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + connection: local + register: storage_array_facts + when: eseries_host_object is defined + +- name: Organize current and expected hostgroups + set_fact: + current_storage_array_hostgroups: |- + {%- set current_hostgroup={} %} + {%- for group in storage_array_facts["storage_array_facts"]["netapp_host_groups"] %} + {%- if current_hostgroup.update( {group["name"]: []} ) %}{%- endif %} + {%- for host in storage_array_facts["storage_array_facts"]["netapp_hosts"] %} + {%- if group["id"] == host["group_id"] and current_hostgroup[group["name"]].append(host["name"]) %}{%- endif %} + {%- endfor %} + {%- endfor %} + {{ current_hostgroup }} + hostgroups: |- + {%- set hostgroups=[] %} + {%- for host in eseries_host_object %} + {%- if "group" in (host.keys()|list) and host["group"] not in hostgroups and + ("state" not in (host.keys()|list) or host["state"] == "present") and hostgroups.append(host["group"]) %} + {%- endif %} + {%- endfor %} + {{ hostgroups }} + when: eseries_host_object is defined + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} inventory-defined hostgroup definitions" + na_santricity_hostgroup: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ eseries_remove_all_configuration_state | default('present') }}" + name: "{{ item }}" + hosts: "{{ current_storage_array_hostgroups[item] | default(omit) }}" + connection: local + loop: "{{ lookup('list', hostgroups) }}" + when: eseries_host_object is defined and (hostgroups | length > 0) + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} inventory-defined host definitions" + na_santricity_host: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ eseries_remove_all_configuration_state | default(item['state'] | default(omit)) }}" + name: "{{ item['name'] }}" + ports: "{{ item['ports'] | default(omit) }}" + force_port: "{{ item['force_port'] | default(eseries_host_force_port | default(omit)) }}" + group: "{{ item['group'] | default(eseries_host_group | default(omit)) }}" + host_type: "{{ item['host_type_index'] | default(item['host_type'] | default(eseries_host_type_index | default(omit))) }}" + connection: local + loop: "{{ lookup('list', eseries_host_object) }}" + when: eseries_host_object is defined + +- name: Collect facts on the storage array + na_santricity_facts: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + connection: local + register: storage_array_facts + when: eseries_host_object is defined + +- name: Update the current storage array hostgroups + set_fact: + current_storage_array_hostgroups: |- + {%- set current_hostgroup={} %} + {%- for group in storage_array_facts["storage_array_facts"]["netapp_host_groups"] %} + {%- if current_hostgroup.update( {group["name"]: []} ) %}{%- endif %} + {%- for host in storage_array_facts["storage_array_facts"]["netapp_hosts"] %} + {%- if group["id"] == host["group_id"] and current_hostgroup[group["name"]].append(host["name"]) %}{%- endif %} + {%- endfor %} + {%- endfor %} + {{ current_hostgroup }} + when: eseries_host_object is defined + +- name: Create list of unused hostgroups + set_fact: + unused_hostgroups: |- + {%- set unused_hostgroup = [] %} + {%- for current_host_name in (current_storage_array_hostgroups.keys()|list) %} + {%- if (current_storage_array_hostgroups[current_host_name]|length==0) and unused_hostgroup.append(current_host_name) %}{%- endif %} + {%- endfor %} + {{ unused_hostgroup }} + when: eseries_host_object is defined + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} inventory-defined hostgroup definitions" + na_santricity_hostgroup: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: absent + name: "{{ item }}" + hosts: "{{ current_storage_array_hostgroups[item] | default(omit) }}" + connection: local + loop: "{{ lookup('list', unused_hostgroups) }}" + when: "eseries_host_object is defined and (unused_hostgroups|length>0) and eseries_host_remove_unused_hostgroup is + defined and eseries_host_remove_unused_hostgroup" diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface.yml new file mode 100644 index 000000000..673084908 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface.yml @@ -0,0 +1,27 @@ +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controllers iSCSI interface ports" + import_tasks: interface/iscsi.yml + delegate_to: localhost + when: eseries_initiator_protocol == "iscsi" + tags: + - iscsi + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controllers InfiniBand iSER interface ports" + import_tasks: interface/ib_iser.yml + delegate_to: localhost + when: eseries_initiator_protocol == "ib_iser" + tags: + - ib_iser + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controllers NVMe interface ports over InfiniBand" + import_tasks: interface/nvme_ib.yml + delegate_to: localhost + when: eseries_initiator_protocol == "nvme_ib" + tags: + - nvme_ib + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controllers NVMe interface ports on RoCE" + import_tasks: interface/nvme_roce.yml + delegate_to: localhost + when: eseries_initiator_protocol == "nvme_roce" + tags: + - nvme_roce diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/ib_iser.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/ib_iser.yml new file mode 100644 index 000000000..01d253647 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/ib_iser.yml @@ -0,0 +1,29 @@ +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller A inventory-defined controller port definitions for InfiniBand iSER" + na_santricity_ib_iser_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: A + channel: "{{ channel + 1 }}" + address: "{{ item }}" + loop: "{{ lookup('list', eseries_controller_ib_iser_port['controller_a']) }}" + loop_control: + index_var: channel + when: eseries_controller_ib_iser_port is defined and eseries_controller_ib_iser_port['controller_a'] is defined + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller B inventory-defined controller port definitions for InfiniBand iSER" + na_santricity_ib_iser_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: B + channel: "{{ channel + 1 }}" + address: "{{ item }}" + loop: "{{ lookup('list', eseries_controller_ib_iser_port['controller_b']) }}" + loop_control: + index_var: channel + when: eseries_controller_ib_iser_port is defined and eseries_controller_ib_iser_port['controller_b'] is defined diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/iscsi.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/iscsi.yml new file mode 100644 index 000000000..7bc047ec5 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/iscsi.yml @@ -0,0 +1,56 @@ +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller A inventory-defined controller port definitions for iSCSI" + na_santricity_iscsi_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ item['state'] | default(eseries_controller_iscsi_port_state | default(omit)) }}" + port: "{{ port + 1 }}" + controller: A + config_method: "{{ item['config_method'] | default(eseries_controller_iscsi_port_config_method | default(omit)) }}" + address: "{{ item['address'] | default(omit) }}" + gateway: "{{ item['gateway'] | default(eseries_controller_iscsi_port_gateway | default(omit)) }}" + subnet_mask: "{{ item['subnet_mask'] | default(eseries_controller_iscsi_port_subnet_mask | default(omit)) }}" + mtu: "{{ item['mtu'] | default(eseries_controller_iscsi_port_mtu | default(omit)) }}" + speed: "{{ item['speed'] | default(eseries_controller_iscsi_port_speed | default(omit)) }}" + loop: "{{ lookup('list', eseries_controller_iscsi_port['controller_a']) }}" + loop_control: + index_var: port + when: eseries_controller_iscsi_port is defined and eseries_controller_iscsi_port['controller_a'] is defined + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller B inventory-defined controller port definitions for iSCSI" + na_santricity_iscsi_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ item['state'] | default(eseries_controller_iscsi_port_state | default(omit)) }}" + port: "{{ port + 1 }}" + controller: B + config_method: "{{ item['config_method'] | default(eseries_controller_iscsi_port_config_method | default(omit)) }}" + address: "{{ item['address'] | default(omit) }}" + gateway: "{{ item['gateway'] | default(eseries_controller_iscsi_port_gateway | default(omit)) }}" + subnet_mask: "{{ item['subnet_mask'] | default(eseries_controller_iscsi_port_subnet_mask | default(omit)) }}" + mtu: "{{ item['mtu'] | default(eseries_controller_iscsi_port_mtu | default(omit)) }}" + speed: "{{ item['speed'] | default(eseries_controller_iscsi_port_speed | default(omit)) }}" + loop: "{{ lookup('list', eseries_controller_iscsi_port['controller_b']) }}" + loop_control: + index_var: port + when: eseries_controller_iscsi_port is defined and eseries_controller_iscsi_port['controller_b'] is defined + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} iSCSI discovery parameters" + na_santricity_iscsi_target: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + name: "{{ eseries_iscsi_target_name | default(omit) }}" + chap_secret: "{%- if eseries_iscsi_target_chap_secret_update %}{{ eseries_iscsi_target_chap_secret }}{%- endif %}" + ping: "{{ eseries_iscsi_target_ping | default(omit) }}" + unnamed_discovery: "{{ eseries_iscsi_target_unnamed_discovery | default(omit) }}" + when: ((eseries_iscsi_target_chap_secret is defined and eseries_iscsi_target_chap_secret_update) or + eseries_iscsi_target_name is defined or eseries_iscsi_target_ping is defined or + eseries_iscsi_target_unnamed_discovery is defined) diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/nvme_ib.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/nvme_ib.yml new file mode 100644 index 000000000..d39e3b504 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/nvme_ib.yml @@ -0,0 +1,29 @@ +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller A inventory-defined controller port definitions for NVMe interface ports over InfiniBand" + na_santricity_nvme_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: A + channel: "{{ channel + 1 }}" + address: "{{ item }}" + loop: "{{ lookup('list', eseries_controller_nvme_ib_port['controller_a']) }}" + loop_control: + index_var: channel + when: eseries_controller_nvme_ib_port is defined and eseries_controller_nvme_ib_port['controller_a'] is defined + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller B inventory-defined controller port definitions for NVMe interface ports over InfiniBand" + na_santricity_nvme_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: B + channel: "{{ channel + 1 }}" + address: "{{ item }}" + loop: "{{ lookup('list', eseries_controller_nvme_ib_port['controller_b']) }}" + loop_control: + index_var: channel + when: eseries_controller_nvme_ib_port is defined and eseries_controller_nvme_ib_port['controller_b'] is defined diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/nvme_roce.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/nvme_roce.yml new file mode 100644 index 000000000..fae92f8a6 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/interface/nvme_roce.yml @@ -0,0 +1,41 @@ +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller A inventory-defined controller port definitions for NVMe interface ports on RoCE" + na_santricity_nvme_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ item['state'] | default(eseries_controller_nvme_roce_port_state | default(omit)) }}" + controller: A + channel: "{{ channel + 1 }}" + config_method: "{{ item['config_method'] | default(eseries_controller_nvme_roce_port_config_method | default(omit)) }}" + address: "{{ item['address'] | default(omit) }}" + gateway: "{{ item['gateway'] | default(eseries_controller_nvme_roce_port_gateway | default(omit)) }}" + subnet_mask: "{{ item['subnet_mask'] | default(eseries_controller_nvme_roce_port_subnet_mask | default(omit)) }}" + mtu: "{{ item['mtu'] | default(eseries_controller_nvme_roce_port_mtu | default(omit)) }}" + speed: "{{ item['speed'] | default(eseries_controller_nvme_roce_port_speed | default(omit)) }}" + loop: "{{ lookup('list', eseries_controller_nvme_roce_port['controller_a']) }}" + loop_control: + index_var: channel + when: eseries_controller_nvme_roce_port is defined and eseries_controller_nvme_roce_port['controller_a'] is defined + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} controller B inventory-defined controller port definitions for NVMe interface ports on RoCE" + na_santricity_nvme_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ item['state'] | default(eseries_controller_nvme_roce_port_state | default(omit)) }}" + controller: B + channel: "{{ channel + 1 }}" + config_method: "{{ item['config_method'] | default(eseries_controller_nvme_roce_port_config_method | default(omit)) }}" + address: "{{ item['address'] | default(omit) }}" + gateway: "{{ item['gateway'] | default(eseries_controller_nvme_roce_port_gateway | default(omit)) }}" + subnet_mask: "{{ item['subnet_mask'] | default(eseries_controller_nvme_roce_port_subnet_mask | default(omit)) }}" + mtu: "{{ item['mtu'] | default(eseries_controller_nvme_roce_port_mtu | default(omit)) }}" + speed: "{{ item['speed'] | default(eseries_controller_nvme_roce_port_speed | default(omit)) }}" + loop: "{{ lookup('list', eseries_controller_nvme_roce_port['controller_b']) }}" + loop_control: + index_var: channel + when: eseries_controller_nvme_roce_port is defined and eseries_controller_nvme_roce_port['controller_b'] is defined diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/lun_mapping.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/lun_mapping.yml new file mode 100644 index 000000000..395a5d399 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/lun_mapping.yml @@ -0,0 +1,178 @@ +- name: Collect facts on the storage array + na_santricity_facts: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + connection: local + register: storage_array_facts + +- name: Collect volume host and host group list + set_fact: + hosts: "{{ lookup('netapp_eseries.santricity.santricity_host', hostvars[inventory_hostname], + volumes=lookup('netapp_eseries.santricity.santricity_volume', hostvars[inventory_hostname])) }}" + +- name: Retrieve required details and map luns + block: + - name: Collect host/host group networking information + setup: + gather_subset: min + register: hosts_info + delegate_to: "{{ item }}" + delegate_facts: True + loop: "{{ lookup('list', (hosts['expected_hosts'].keys() | list)) }}" + + - name: Collect Ansible defined host and host group interface information + set_fact: + host_interface_ansible: |- + {%- set host_interfaces = [] -%} + {%- for host in (hosts['expected_hosts'].keys() | list) -%} + {%- if "eseries_iscsi_iqn" in (hostvars[host].keys() | list) -%} + {%- if host_interfaces.append({"item": host, "stdout_lines": [hostvars[host]["eseries_iscsi_iqn"]]}) -%}{%- endif -%} + {%- elif "eseries_nvme_nqn" in (hostvars[host].keys() | list) -%} + {%- if host_interfaces.append({"item": host, "stdout_lines": [hostvars[host]["eseries_nvme_nqn"]]}) -%}{%- endif -%} + {%- endif -%} + {%- endfor -%} + {{ host_interfaces }} + + - name: Collect host and host group interface information for Linux + shell: "{{ eseries_initiator_command[eseries_initiator_protocol]['linux'] }}" + register: host_interface_linux + delegate_to: "{{ item }}" + become: True + changed_when: False + failed_when: "host_interface_linux.rc != 0 and not (eseries_initiator_protocol in eseries_protocols_using_eseries_iscsi_iqn or + eseries_initiator_protocol in eseries_protocols_using_eseries_nvme_nqn)" + when: '((hostvars[item]["ansible_facts"]["system"] | lower) == "linux" and + ("eseries_iscsi_iqn" not in (hostvars[item].keys() | list) or eseries_initiator_protocol not in eseries_protocols_using_eseries_iscsi_iqn) and + ("eseries_nvme_nqn" not in (hostvars[item].keys() | list) or eseries_initiator_protocol not in eseries_protocols_using_eseries_nvme_nqn))' + loop: "{{ lookup('list', (hosts['expected_hosts'].keys() | list)) }}" + + - name: Collect host and host group interface information for Windows + win_shell: "{{ eseries_initiator_command[eseries_initiator_protocol]['windows'] }}" + register: host_interface_windows + delegate_to: "{{ item }}" + changed_when: False + failed_when: "host_interface_windows.rc != 0" + when: '((hostvars[item]["ansible_facts"]["os_family"] | lower == "windows") and + ("eseries_iscsi_iqn" not in (hostvars[item].keys() | list) or eseries_initiator_protocol not in eseries_protocols_using_eseries_iscsi_iqn) and + ("eseries_nvme_nqn" not in (hostvars[item].keys() | list) or eseries_initiator_protocol not in eseries_protocols_using_eseries_nvme_nqn))' + loop: "{{ lookup('list', (hosts['expected_hosts'].keys() | list)) }}" + + - name: Aggregate host/host group interface information + set_fact: + host_interface: |- + {%- set host_interfaces = [] -%} + {%- for host in (hosts['expected_hosts'].keys() | list) -%} + {%- set found_interfaces = host_interface_ansible + host_interface_linux['results'] + host_interface_windows['results'] -%} + {%- for interface in found_interfaces if interface["item"] == host and "skip_reason" not in (interface.keys() | list) and interface["stdout_lines"] -%} + {%- if host_interfaces.append(interface) -%}{%- endif -%} + {%- else -%} + {%- if eseries_initiator_protocol in eseries_protocols_using_eseries_iscsi_iqn -%} + {%- if host_interfaces.append({"item": host, "stdout_lines": [eseries_iscsi_iqn_prefix ~ hostvars[host]["ansible_machine_id"][-12:]], "generate": True}) -%}{%- endif -%} + {%- elif eseries_initiator_protocol in eseries_protocols_using_eseries_nvme_nqn -%} + {%- if host_interfaces.append({"item": host, "stdout_lines": [eseries_nvme_nqn_prefix ~ hostvars[host]["ansible_machine_id"]], "generate": True}) -%}{%- endif -%} {%- endif -%} + {%- endfor -%} + {%- endfor -%} + {{- host_interfaces -}} + + - name: Generate missing host IQN (Linux only). + block: + - name: Ensure path for initiatorname.iscsi exists. + file: + state: directory + path: "{{ eseries_iscsi_iqn_path }}" + delegate_to: "{{ item['item'] }}" + become: true + loop: "{{ host_interface }}" + when: "(hostvars[item['item']]['ansible_facts']['system'] | lower) == 'linux' and (item['generate'] | default(False)) == True" + - name: Generate initiatorname.iscsi file. + ansible.builtin.template: + src: initiatorname_iscsi.j2 + dest: "{{ eseries_iscsi_iqn_path }}initiatorname.iscsi" + delegate_to: "{{ item['item'] }}" + become: true + loop: "{{ host_interface }}" + when: "(hostvars[item['item']]['ansible_facts']['system'] | lower) == 'linux' and (item['generate'] | default(False)) == True" + when: eseries_initiator_protocol in eseries_protocols_using_eseries_iscsi_iqn + + - name: Generate missing host NQN (Linux only). + block: + - name: Ensure NVMe NQN directory exists on host. + file: + state: directory + path: "{{ eseries_nvme_nqn_path }}" + delegate_to: "{{ item['item'] }}" + become: true + loop: "{{ host_interface }}" + when: "(hostvars[item['item']]['ansible_facts']['system'] | lower) == 'linux' and (item['generate'] | default(False)) == True" + - name: Generate NVMe NQN for host if one was not discovered. + ansible.builtin.template: + src: hostnqn.j2 + dest: "{{ eseries_nvme_nqn_path }}hostnqn" + delegate_to: "{{ item['item'] }}" + become: true + loop: "{{ host_interface }}" + when: "(hostvars[item['item']]['ansible_facts']['system'] | lower) == 'linux' and (item['generate'] | default(False)) == True" + when: eseries_initiator_protocol in eseries_protocols_using_eseries_nvme_nqn + + - name: Organize host/host group interface information and update hosts variable + set_fact: + hosts: "{{ lookup('netapp_eseries.santricity.santricity_host_detail', + hosts, hosts_info=hosts_info['results'], host_interface_ports=host_interface, protocol=eseries_initiator_protocol) }}" + + - name: "{{'Create' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Delete' }} all hosts objects on the storage array" + na_santricity_host: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ eseries_remove_all_configuration_state | default(hosts['expected_hosts'][item]['state'] | default(omit)) }}" + name: "{{ hosts['expected_hosts'][item]['sanitized_hostname'] }}" + ports: "{{ hosts['expected_hosts'][item]['ports'] }}" + force_port: "{{ eseries_host_force_port | default(omit) }}" + host_type: "{{ hosts['expected_hosts'][item]['host_type'] | default(omit) }}" + connection: local + loop: "{{ lookup('list', (hosts['expected_hosts'].keys()|list)) }}" + + - name: "{{'Create' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Delete' }} all required host groups on the storage array" + na_santricity_hostgroup: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ eseries_remove_all_configuration_state | default('present') }}" + name: "{{ item }}" + hosts: "{{ hosts['host_groups'][item] | default(omit) }}" + connection: local + loop: "{{ lookup('list', (hosts['host_groups'].keys()|list)) }}" + + - name: Update facts on the storage array + na_santricity_facts: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + connection: local + register: storage_array_facts + when: eseries_remove_all_configuration_state is not defined or eseries_remove_all_configuration_state == False + + - name: "{{'Map' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unmap' }} volume to host or host group." + na_santricity_lun_mapping: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ 'present' if item['target'] is defined else 'absent' }}" + volume: "{{ item['volume'] }}" + target: "{{ item['target'] | default(eseries_lun_mapping_host) | default(omit) }}" + lun: "{{ item['lun'] | default(omit) }}" + connection: local + loop: "{{ lookup('netapp_eseries.santricity.santricity_lun_mapping', storage_array_facts, + volumes=lookup('netapp_eseries.santricity.santricity_volume', hostvars[inventory_hostname]), wantlist=True) }}" + when: hosts != [] diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/main.yml new file mode 100644 index 000000000..d19ff8427 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/main.yml @@ -0,0 +1,52 @@ +- name: Set current storage system credentials + include_role: + name: netapp_eseries.santricity.nar_santricity_common + tasks_from: build_info.yml + when: current_eseries_api_url is not defined + tags: + - always + +- name: Override all inventory configuration states. + set_fact: + eseries_remove_all_configuration_state: absent + when: eseries_remove_all_configuration is defined and eseries_remove_all_configuration == True + tags: + - always + +- name: Unconfigure snapshot consistency groups + import_tasks: snapshot.yml + when: eseries_remove_all_configuration == True | default(False) + +- name: Configure NetApp E-Series storage system disk pool configuration + import_tasks: storage_pool_present.yml + tags: + - storage_pools + +- name: Configure NetApp E-Series storage system volume configuration + import_tasks: volume.yml + tags: + - volumes + +- name: Configure NetApp E-Series storage system disk pool configuration + import_tasks: storage_pool_absent.yml + tags: + - storage_pools + +- name: Configure storage system's hosts/hostgroups initiators + import_tasks: initiator.yml + tags: + - initiators + +- name: Map storage system's volumes to host objects + import_tasks: lun_mapping.yml + tags: + - lun_mappings + +- name: Configure controllers interfaces + import_tasks: interface.yml + tags: + - interface + +- name: Configure snapshot consistency groups + import_tasks: snapshot.yml + when: eseries_remove_all_configuration == False | default(True) diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot.yml new file mode 100644 index 000000000..c99c2861b --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot.yml @@ -0,0 +1,19 @@ +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} all snapshot consistency groups." + import_tasks: snapshot/group.yml + when: eseries_snapshot_groups | default(False) or eseries_snapshot_remove_unspecified == True + tags: + - snapshot_group + +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} all snapshot consistency group views." + import_tasks: snapshot/view.yml + when: eseries_snapshot_views | default(False) or eseries_snapshot_remove_unspecified == True + tags: + - snapshot_view + +- name: Rollback base volumes to point-in-time snapshot images. + import_tasks: snapshot/rollback.yml + when: 'eseries_remove_all_configuration == False | default(True) and + (eseries_snapshot_rollbacks | default(False) or + eseries_snapshot_remove_unspecified == True)' + tags: + - snapshot_rollback diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/group.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/group.yml new file mode 100644 index 000000000..473226f1d --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/group.yml @@ -0,0 +1,75 @@ +- name: Determine if any snapshot consistency groups are no longer needed. + block: + - name: Retrieve all snapshot consistency groups + uri: + url: "{{ current_eseries_api_url }}storage-systems/{{ current_eseries_ssid }}/consistency-groups" + method: GET + url_password: "{{ current_eseries_api_password }}" + url_username: "{{ current_eseries_api_username }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + connection: local + register: existing_consistency_groups + + - name: Ensure all unspecified snapshot consistency groups are removed. + na_santricity_snapshot: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: absent + type: group + group_name: "{{ item }}" + connection: local + loop: "{{ unspecified_groups }}" + vars: + unspecified_groups: |- + {%- set unspecified_groups = [] -%} + {%- for existing_group in existing_consistency_groups["json"] -%} + {%- for group in eseries_snapshot_groups | default([]) if existing_group["name"] == group["name"] -%} + {%- else -%} + {%- if unspecified_groups.append(existing_group["name"]) -%}{%- endif -%} + {%- endfor -%} + {%- endfor -%} + {{- unspecified_groups -}} + when: (eseries_remove_all_configuration | default(False)) == False and eseries_snapshot_remove_unspecified == True + +- name: "Ensure all snapshot consistency groups {{'exist' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'are removed' }}." + na_santricity_snapshot: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ eseries_remove_all_configuration_state | default('present') }}" + type: group + group_name: "{{ item['name'] }}" + maximum_snapshots: "{{ item['maximum_snapshots'] }}" + alert_threshold_pct: "{{ item['alert_threshold_pct'] }}" + reserve_capacity_full_policy: "{{ item['reserve_capacity_full_policy'] }}" + preferred_reserve_storage_pool: "{{ item['preferred_reserve_storage_pool'] }}" + rollback_priority: "{{ item['rollback_priority'] }}" + volumes: "{{ item['volumes'] }}" + connection: local + loop: "{{ consistency_groups }}" + vars: + consistency_groups: |- + {%- set consistency_groups = [] -%} + {%- for group in eseries_snapshot_groups | default([]) -%} + {%- set info = {"name": group["name"], + "maximum_snapshots": group["maximum_snapshots"] | default(eseries_snapshot_groups_maximum_snapshots | default(omit)), + "reserve_capacity_pct": group["reserve_capacity_pct"] | default(eseries_snapshot_groups_reserve_capacity_pct | default(omit)), + "preferred_reserve_storage_pool": group["preferred_reserve_storage_pool"] | default(eseries_snapshot_groups_preferred_reserve_storage_pool | default(omit)), + "reserve_capacity_full_policy": group["reserve_capacity_full_policy"] | default(eseries_snapshot_groups_reserve_capacity_full_policy | default(omit)), + "alert_threshold_pct": group["alert_threshold_pct"] | default(eseries_snapshot_groups_alert_threshold_pct | default(omit)), + "rollback_priority": group["rollback_priority"] | default(eseries_snapshot_rollback_priority | default(omit)), + "volumes": []} -%} + {%- for volume in group["volumes"] -%} + {%- set volume_info = {"volume": volume["volume"]} -%} + {%- if volume["reserve_capacity_pct"] | default(False) and volume_info.update({"reserve_capacity_pct": volume["reserve_capacity_pct"]}) -%}{%- endif -%} + {%- if volume["reserve_capacity_pct"] | default(False) and volume_info.update({"preferred_reserve_storage_pool": volume["preferred_reserve_storage_pool"]}) -%}{%- endif -%} + {%- if info["volumes"].append(volume_info) -%}{%- endif -%} + {%- endfor -%} + {%- if consistency_groups.append(info) -%}{%- endif -%} + {%- endfor -%} + {{- consistency_groups -}} diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/rollback.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/rollback.yml new file mode 100644 index 000000000..45fae418e --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/rollback.yml @@ -0,0 +1,41 @@ +- name: Roll volumes back to expected point-in-time. + na_santricity_snapshot: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: rollback + group_name: "{{ item['group_name'] }}" + pit_name: "{{ item['pit_name'] | default(omit) }}" + pit_timestamp: "{{ item['pit_timestamp'] | default(omit) }}" + rollback_priority: "{{ item['rollback_priority'] | default(omit) }}" + rollback_backup: "{{ item['rollback_backup'] | default(omit) }}" + volumes: "{{ item['volumes'] | default(omit) }}" + connection: local + loop: "{{ consistency_group_rollbacks }}" + vars: + consistency_group_rollbacks: |- + {%- set consistency_group_rollbacks = [] -%} + {%- for rollback in eseries_snapshot_rollbacks | default([]) -%} + {%- set rollback_info = {"group_name": rollback["group_name"]} -%} + {%- if "pit_name" in (rollback.keys() | list) and rollback_info.update({"pit_name": rollback["pit_name"]}) -%}{%- endif -%} + {%- if "pit_timestamp" in (rollback.keys() | list) and rollback_info.update({"pit_timestamp": rollback["pit_timestamp"]}) -%}{%- endif -%} + + {%- if "rollback_priority" in (rollback.keys() | list) or eseries_snapshot_rollback_priority is defined -%} + {%- if rollback_info.update({"rollback_priority": rollback["rollback_priority"] | default(eseries_snapshot_rollback_priority)}) -%}{%- endif -%} + {%- endif -%} + {%- if "rollback_backup" in (rollback.keys() | list) or eseries_snapshot_rollback_backup is defined -%} + {%- if rollback_info.update({"rollback_backup": rollback["rollback_backup"] | default(eseries_snapshot_rollback_backup)}) -%}{%- endif -%} + {%- endif -%} + + {%- if "volumes" in (rollback.keys() | list) -%} + {%- if rollback_info.update({"volumes": []}) -%}{%- endif -%} + {%- for volume in rollback["volumes"] -%} + {%- if rollback_info["volumes"].append({"volume": volume}) -%}{%- endif -%} + {%- endfor -%} + {%- endif -%} + + {%- if consistency_group_rollbacks.append(rollback_info) -%}{%- endif -%} + {%- endfor -%} + {{- consistency_group_rollbacks -}} diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/view.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/view.yml new file mode 100644 index 000000000..f8de06c6c --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/snapshot/view.yml @@ -0,0 +1,116 @@ +- name: Determine if any snapshot consistency group views are not specified. + block: + - name: Retrieve all snapshot consistency groups + uri: + url: "{{ current_eseries_api_url }}storage-systems/{{ current_eseries_ssid }}/consistency-groups" + method: GET + url_password: "{{ current_eseries_api_password }}" + url_username: "{{ current_eseries_api_username }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + connection: local + register: existing_consistency_groups + + - name: Retrieve all snapshot consistency group views + uri: + url: "{{ current_eseries_api_url }}storage-systems/{{ current_eseries_ssid }}/consistency-groups/views" + method: GET + url_password: "{{ current_eseries_api_password }}" + url_username: "{{ current_eseries_api_username }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + connection: local + register: existing_consistency_group_views + + - name: Ensure all unspecified snapshot consistency group views are removed. + na_santricity_snapshot: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: absent + type: view + group_name: "{{ item['group_name'] }}" + view_name: "{{ item['view_name'] }}" + connection: local + loop: "{{ unspecified_groups }}" + vars: + unspecified_groups: |- + {%- set unspecified_group_views = [] -%} + {%- for existing_view in existing_consistency_group_views["json"] -%} + {%- for view in eseries_snapshot_views | default([]) if existing_view["name"] == view["name"] -%} + {#- DO NOTHING -#} + {%- else -%} + {%- for group in existing_consistency_groups["json"] if group["id"] == existing_view["groupRef"] -%} + {%- if unspecified_group_views.append({"group_name": group["name"], "view_name": existing_view["name"]}) -%}{%- endif -%} + {%- endfor -%} + {%- endfor -%} + {%- endfor -%} + {{- unspecified_group_views -}} + when: (eseries_remove_all_configuration | default(False)) == False and eseries_snapshot_remove_unspecified == True + +- name: "Ensure all snapshot consistency views {{'exist' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'are removed' }}." + na_santricity_snapshot: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ eseries_remove_all_configuration_state | default('present') }}" + type: view + view_name: "{{ item['name'] }}" + group_name: "{{ item['group_name'] }}" + pit_name: "{{ item['pit_name'] | default(omit) }}" + pit_timestamp: "{{ item['pit_timestamp'] | default(omit) }}" + volumes: "{{ item['volumes'] | default(omit) }}" + reserve_capacity_pct: "{{ item['reserve_capacity_pct'] | default(omit) }}" + preferred_reserve_storage_pool: "{{ item['preferred_reserve_storage_pool'] | default(omit) }}" + alert_threshold_pct: "{{ item['alert_threshold_pct'] | default(omit) }}" + view_host: "{{ item['host'] | default(omit) }}" + view_writable: "{{ item['writable'] | default(omit) }}" + view_validate: "{{ item['validate'] | default(omit) }}" + connection: local + loop: "{{ consistency_group_views }}" + vars: + consistency_group_views: |- + {%- set consistency_group_views = [] -%} + {%- for view in eseries_snapshot_views | default([]) -%} + {%- set view_info = {"name": view["name"], "group_name": view["group_name"]} -%} + {%- if "pit_name" in (view.keys() | list) and view_info.update({"pit_name": view["pit_name"]}) -%}{%- endif -%} + {%- if "pit_timestamp" in (view.keys() | list) and view_info.update({"pit_timestamp": view["pit_timestamp"]}) -%}{%- endif -%} + + {%- if "host" in (view.keys() | list) or eseries_snapshot_views_host is defined -%} + {%- if view_info.update({"host": view["host"] | default(eseries_snapshot_views_host)}) -%}{%- endif -%}{%- endif -%} + {%- if "reserve_capacity_pct" in (view.keys() | list) or eseries_snapshot_views_reserve_capacity_pct is defined -%} + {%- if view_info.update({"reserve_capacity_pct": view["reserve_capacity_pct"] | default(eseries_snapshot_views_reserve_capacity_pct)}) -%}{%- endif -%}{%- endif -%} + {%- if "preferred_reserve_storage_pool" in (view.keys() | list) or eseries_snapshot_views_preferred_reserve_storage_pool is defined -%} + {%- if view_info.update({"preferred_reserve_storage_pool": view["preferred_reserve_storage_pool"] | default(eseries_snapshot_views_preferred_reserve_storage_pool)}) -%}{%- endif -%}{%- endif -%} + {%- if "alert_threshold_pct" in (view.keys() | list) or eseries_snapshot_views_alert_threshold_pct is defined -%} + {%- if view_info.update({"alert_threshold_pct": view["alert_threshold_pct"] | default(eseries_snapshot_views_alert_threshold_pct)}) -%}{%- endif -%}{%- endif -%} + {%- if "writable" in (view.keys() | list) or eseries_snapshot_views_writable is defined -%} + {%- if view_info.update({"writable": view["writable"] | default(eseries_snapshot_views_writable)}) -%}{%- endif -%}{%- endif -%} + {%- if "validate" in (view.keys() | list) or eseries_snapshot_views_validate is defined -%} + {%- if view_info.update({"validate": view["validate"] | default(eseries_snapshot_views_validate)}) -%}{%- endif -%}{%- endif -%} + {%- if "alert_threshold_pct" in (view.keys() | list) or eseries_snapshot_views_alert_threshold_pct is defined -%} + {%- if view_info.update({"alert_threshold_pct": view["alert_threshold_pct"] | default(eseries_snapshot_views_alert_threshold_pct)}) -%}{%- endif -%}{%- endif -%} + + {%- if "volumes" in (view.keys() | list) -%} + {%- if view_info.update({"volumes": [] }) -%}{%- endif -%} + {%- for volume in view["volumes"] -%} + {%- set volume_info = {"volume": volume["volume"], + "reserve_capacity_pct": volume["reserve_capacity_pct"] | default(view_info["reserve_capacity_pct"] | default(False)), + "snapshot_volume_writable": volume["writable"] | default(view_info["writable"] | default(True)), + "snapshot_volume_validate": volume["validate"] | default(view_info["validate"] | default(False))} -%} + + {%- if "host" in (volume.keys() | list) or "host" in (view_info.keys() | list) -%} + {%- if volume_info.update({"snapshot_volume_host": volume["host"] | default(view_info["host"])}) -%}{%- endif -%}{%- endif -%} + {%- if "lun" in (volume.keys() | list) -%} + {%- if volume_info.update({"snapshot_volume_lun": volume["lun"]}) -%}{%- endif -%}{%- endif -%} + {%- if "preferred_reserve_storage_pool" in (volume.keys() | list) or "preferred_reserve_storage_pool" in (view_info.keys() | list) -%} + {%- if volume_info.update({"preferred_reserve_storage_pool": volume["preferred_reserve_storage_pool"] | default(view_info["preferred_reserve_storage_pool"])}) -%}{%- endif -%}{%- endif -%} + + {%- if view_info["volumes"].append(volume_info) -%}{%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- if consistency_group_views.append(view_info) -%}{%- endif -%} + {%- endfor -%} + {{- consistency_group_views -}}
\ No newline at end of file diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/storage_pool_absent.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/storage_pool_absent.yml new file mode 100644 index 000000000..49e2c2d35 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/storage_pool_absent.yml @@ -0,0 +1,27 @@ +- name: Unconfigure NetApp E-Series storage system disk pool configuration + na_santricity_storagepool: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ item['state'] }}" + name: "{{ item['name'] }}" + raid_level: "{{ item['raid_level'] | default(eseries_storage_pool_raid_level | default(omit)) }}" + secure_pool: "{{ item['secure_pool'] | default(eseries_storage_pool_secure_pool | default(omit)) }}" + criteria_drive_count: "{{ item['criteria_drive_count'] | default(eseries_storage_pool_criteria_drive_count | default(omit)) }}" + reserve_drive_count: "{{ item['reserve_drive_count'] | default(eseries_storage_pool_reserve_drive_count | default(omit)) }}" + criteria_min_usable_capacity: "{{ item['criteria_min_usable_capacity'] | default(eseries_storage_pool_criteria_min_usable_capacity | default(omit)) }}" + criteria_drive_type: "{{ item['criteria_drive_type'] | default(eseries_storage_pool_criteria_drive_type | default(omit)) }}" + criteria_size_unit: "{{ item['criteria_size_unit'] | default(eseries_storage_pool_criteria_size_unit | default(omit)) }}" + criteria_drive_min_size: "{{ item['criteria_drive_min_size'] | default(eseries_storage_pool_criteria_drive_min_size | default(omit)) }}" + criteria_drive_max_size: "{{ item['criteria_drive_max_size'] | default(eseries_storage_pool_criteria_drive_max_size | default(omit)) }}" + criteria_drive_require_da: "{{ item['criteria_drive_require_da'] | default(eseries_storage_pool_criteria_drive_require_da | default(omit)) }}" + criteria_drive_require_fde: "{{ item['criteria_drive_require_fde'] | default(eseries_storage_pool_criteria_drive_require_fde | default(omit)) }}" + usable_drives: "{{ item['usable_drives'] | default(eseries_storage_pool_usable_drives | default(omit)) }}" + remove_volumes: "{{ item['remove_volumes'] | default(eseries_storage_pool_remove_volumes | default(omit)) }}" + erase_secured_drives: "{{ item['erase_secured_drives'] | default(eseries_storage_pool_erase_secured_drives | default(omit)) }}" + ddp_critical_threshold_pct: "{{ item['ddp_critical_threshold_pct'] | default(eseries_storage_pool_ddp_critical_threshold_pct | default(omit)) }}" + ddp_warning_threshold_pct: "{{ item['ddp_warning_threshold_pct'] | default(eseries_storage_pool_ddp_warning_threshold_pct | default(omit)) }}" + connection: local + loop: "{{ query('netapp_eseries.santricity.santricity_storage_pool', hostvars[inventory_hostname], state='absent') }}" diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/storage_pool_present.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/storage_pool_present.yml new file mode 100644 index 000000000..d90430ab4 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/storage_pool_present.yml @@ -0,0 +1,28 @@ +- name: Configure NetApp E-Series storage system disk pool configuration + na_santricity_storagepool: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ item['state'] }}" + name: "{{ item['name'] }}" + raid_level: "{{ item['raid_level'] | default(eseries_storage_pool_raid_level | default(omit)) }}" + secure_pool: "{{ item['secure_pool'] | default(eseries_storage_pool_secure_pool | default(omit)) }}" + criteria_drive_count: "{{ item['criteria_drive_count'] | default(eseries_storage_pool_criteria_drive_count | default(omit)) }}" + reserve_drive_count: "{{ item['reserve_drive_count'] | default(eseries_storage_pool_reserve_drive_count | default(omit)) }}" + criteria_min_usable_capacity: "{{ item['criteria_min_usable_capacity'] | default(eseries_storage_pool_criteria_min_usable_capacity | default(omit)) }}" + criteria_drive_type: "{{ item['criteria_drive_type'] | default(eseries_storage_pool_criteria_drive_type | default(omit)) }}" + criteria_drive_interface_type: "{{ item['criteria_drive_interface_type'] | default(eseries_storage_pool_criteria_drive_interface_type | default(omit)) }}" + criteria_size_unit: "{{ item['criteria_size_unit'] | default(eseries_storage_pool_criteria_size_unit | default(omit)) }}" + criteria_drive_min_size: "{{ item['criteria_drive_min_size'] | default(eseries_storage_pool_criteria_drive_min_size | default(omit)) }}" + criteria_drive_max_size: "{{ item['criteria_drive_max_size'] | default(eseries_storage_pool_criteria_drive_max_size | default(omit)) }}" + criteria_drive_require_da: "{{ item['criteria_drive_require_da'] | default(eseries_storage_pool_criteria_drive_require_da | default(omit)) }}" + criteria_drive_require_fde: "{{ item['criteria_drive_require_fde'] | default(eseries_storage_pool_criteria_drive_require_fde | default(omit)) }}" + usable_drives: "{{ item['usable_drives'] | default(eseries_storage_pool_usable_drives | default(omit)) }}" + remove_volumes: "{{ item['remove_volumes'] | default(eseries_storage_pool_remove_volumes | default(omit)) }}" + erase_secured_drives: "{{ item['erase_secured_drives'] | default(eseries_storage_pool_erase_secured_drives | default(omit)) }}" + ddp_critical_threshold_pct: "{{ item['ddp_critical_threshold_pct'] | default(eseries_storage_pool_ddp_critical_threshold_pct | default(omit)) }}" + ddp_warning_threshold_pct: "{{ item['ddp_warning_threshold_pct'] | default(eseries_storage_pool_ddp_warning_threshold_pct | default(omit)) }}" + connection: local + loop: "{{ query('netapp_eseries.santricity.santricity_storage_pool', hostvars[inventory_hostname], state='present') }}" diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/volume.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/volume.yml new file mode 100644 index 000000000..86a32ac29 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/tasks/volume.yml @@ -0,0 +1,34 @@ +- name: "{{'Configure' if (eseries_remove_all_configuration_state | default('present')) == 'present' else 'Unconfigure' }} Netapp E-Series storage system disk pool volume configuration" + na_santricity_volume: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ item['state'] }}" + name: "{{ item['name'] }}" + storage_pool_name: "{{ item['storage_pool_name'] }}" + size: "{{ item['size'] | default(eseries_volume_size | default(omit)) }}" + size_unit: "{{ item['size_unit'] | default(eseries_volume_size_unit | default(omit)) }}" + segment_size_kb: "{{ item['segment_size_kb'] | default(eseries_volume_segment_size_kb | default(omit)) }}" + owning_controller: "{{ item['owning_controller'] | default(eseries_volume_owning_controller | default(omit)) }}" + thin_provision: "{{ item['thin_provision'] | default(eseries_volume_thin_provision | default(omit)) }}" + thin_volume_repo_size: "{{ item['thin_volume_repo_size'] | default(eseries_volume_thin_volume_repo_size | default(omit)) }}" + thin_volume_max_repo_size: "{{ item['thin_volume_max_repo_size'] | default(eseries_volume_thin_volume_max_repo_size | default(omit)) }}" + thin_volume_expansion_policy: "{{ item['thin_volume_expansion_policy'] | default(eseries_volume_thin_volume_expansion_policy | default(omit)) }}" + thin_volume_growth_alert_threshold: "{{ item['thin_volume_growth_alert_threshold'] | default(eseries_volume_thin_volume_growth_alert_threshold | default(omit)) }}" + ssd_cache_enabled: "{{ item['ssd_cache_enabled'] | default(eseries_volume_ssd_cache_enabled | default(omit)) }}" + data_assurance_enabled: "{{ item['data_assurance_enabled'] | default(eseries_volume_data_assurance_enabled | default(omit)) }}" + read_cache_enable: "{{ item['read_cache_enable'] | default(eseries_volume_read_cache_enable | default(omit)) }}" + read_ahead_enable: "{{ item['read_ahead_enable'] | default(eseries_volume_read_ahead_enable | default(omit)) }}" + write_cache_enable: "{{ item['write_cache_enable'] | default(eseries_volume_write_cache_enable | default(omit)) }}" + write_cache_mirror_enable: "{{ item['write_cache_mirror_enable'] | default(eseries_volume_write_cache_mirror_enable | default(omit)) }}" + cache_without_batteries: "{{ item['cache_without_batteries'] | default(eseries_volume_cache_without_batteries | default(omit)) }}" + allow_expansion: "{{ item['allow_expansion'] | default(eseries_volume_allow_expansion | default(omit)) }}" + wait_for_initialization: "{{ item['wait_for_initialization'] | default(eseries_volume_wait_for_initialization | default(omit)) }}" + workload_name: "{{ item['workload_name'] | default(eseries_volume_workload_name | default(omit)) }}" + workload_metadata: "{{ item['workload_metadata'] | default(item['metadata'] | default(eseries_volume_workload_metadata | default(eseries_volume_metadata | default(omit)))) }}" + volume_metadata: "{{ item['volume_metadata'] | default(eseries_volume_volume_metadata | default(omit)) }}" + connection: local + when: eseries_storage_pool_configuration is defined + loop: "{{ query('netapp_eseries.santricity.santricity_volume', hostvars[inventory_hostname]) }}" diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/templates/hostnqn.j2 b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/templates/hostnqn.j2 new file mode 100644 index 000000000..90478d074 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/templates/hostnqn.j2 @@ -0,0 +1 @@ +{{ item["stdout_lines"][0] }} diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/templates/initiatorname_iscsi.j2 b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/templates/initiatorname_iscsi.j2 new file mode 100644 index 000000000..f6c3740eb --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_host/templates/initiatorname_iscsi.j2 @@ -0,0 +1,11 @@ +## +## /etc/iscsi/iscsi.initiatorname +## +## Default iSCSI Initiatorname. +## +## DO NOT EDIT OR REMOVE THIS FILE! +## If you remove this file, the iSCSI daemon will not start. +## If you change the InitiatorName, existing access control lists +## may reject this initiator. The InitiatorName must be unique +## for each iSCSI initiator. Do NOT duplicate iSCSI InitiatorNames. +InitiatorName={{ item["stdout_lines"][0] }} diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/.travis.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/.travis.yml new file mode 100644 index 000000000..36bbf6208 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/.travis.yml @@ -0,0 +1,29 @@ +--- +language: python +python: "2.7" + +# Use the new container infrastructure +sudo: false + +# Install ansible +addons: + apt: + packages: + - python-pip + +install: + # Install ansible + - pip install ansible + + # Check ansible version + - ansible --version + + # Create ansible.cfg with correct roles_path + - printf '[defaults]\nroles_path=../' >ansible.cfg + +script: + # Basic role syntax check + - ansible-playbook tests/test.yml -i tests/inventory --syntax-check + +notifications: + webhooks: https://galaxy.ansible.com/api/v1/notifications/
\ No newline at end of file diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/README.md b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/README.md new file mode 100644 index 000000000..d5b454c96 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/README.md @@ -0,0 +1,301 @@ +nar_santricity_management +========= + Manages NetApp E-Series storage system's name, passwords, management interfaces, alerts, syslog, auditlog, asup, ldap, certificates, drive firmware and controller firmware. + +Requirements +------------ + - NetApp E-Series E2800 platform or newer or NetApp E-Series SANtricity Web Services Proxy configured for older E-Series storage systems. + +Tested Ansible Versions +----------------------- + - Ansible 5.x (ansible-core 2.12) + +Example Playbook +---------------- + - hosts: eseries_storage_systems + gather_facts: false + collection: + - netapp_eseries.santricity + tasks: + - name: Ensure NetApp E-Series storage system is properly configured + import_role: + name: nar_santricity_management + +Example Storage System Inventory File (Discover storage system with proxy) +------------------------------------- + eseries_system_serial: "012345678901" # Be sure to quote if the serial is all numbers and begins with zero. + eseries_system_password: admin_password + eseries_proxy_api_url: https://192.168.1.100:8443/devmgr/v2/ + eseries_proxy_api_password: admin_password + eseries_subnet: 192.168.1.0/24 + eseries_prefer_embedded: false # Overrides the default behavior of using Web Services Proxy when eseries_proxy_api_url is defined. This will only effect storage systems that have Embedded Web Services. + eseries_validate_certs: false + + eseries_system_name: my_eseries_array + eseries_system_cache_block_size: 128 + eseries_system_cache_flush_threshold: 90 + eseries_system_autoload_balance: enabled + eseries_system_host_connectivity_reporting: enabled + eseries_system_default_host_type: Linux DM-MP + + eseries_management_interfaces: + config_method: static + subnet_mask: 255.255.255.0 + gateway: 192.168.1.1 + dns_config_method: static + dns_address: 192.168.1.253 + dns_address_backup: 192.168.1.254 + ssh: true + ntp_config_method: static + ntp_address: 192.168.1.200 + ntp_address_backup: 192.168.1.201 + controller_a: + - address: 192.168.1.100 + - address: 192.168.1.101 + controller_b: + - address: 192.168.1.102 + - address: 192.168.1.103 + + eseries_ldap_state: present + eseries_ldap_bind_username: + eseries_ldap_bind_password: + eseries_ldap_server: + eseries_ldap_search_base: + eseries_ldap_role_mappings: + ".*": + - storage.admin + - storage.monitor + - support.admin + - security.admin + + eseries_client_certificate_certificates: + - /path/to/client_certificate.crt + eseries_server_certificate: + controller_a: + public_certificate: "/path/to/controller_a_server_certificate_bundle.pem" + controller_b: + public_certificate: "/path/to/controller_b_server_certificate_bundle.pem" + + eseries_firmware_firmware: "/path/to/firmware.dlp" + eseries_firmware_nvsram: "/path/to/nvsram.dlp" + eseries_drive_firmware_firmware_list: + - "/path/to/drive_firmware.dlp" + + eseries_asup_state: enabled + eseries_asup_active: true + eseries_asup_days: [sunday, saturday] + eseries_asup_start: 17 + eseries_asup_end: 24 + eseries_asup_validate: false + eseries_asup_method: email + eseries_asup_email: + server: smtp.example.com + sender: noreply@example.com + + eseries_syslog_state: present + eseries_syslog_address: 192.168.1.150 + eseries_syslog_protocol: udp + eseries_syslog_port: 514 + eseries_alert_syslog_servers: + - "address": 192.168.1.150 + "port": 514 + +Example Storage System Inventory File (Without storage system discovery) +------------------------------------- + eseries_system_api_url: https://192.168.1.200:8443/devmgr/v2/ + eseries_system_password: admin_password + eseries_validate_certs: false + + (...) # Same as the previous example + +Role Variables +-------------- +**Note that when values are specified below, they indicate the default value.** + + # Web Services Embedded information + eseries_subnet: # Network subnet to search for the storage system specified in CIDR form. Example: 192.168.1.0/24 + eseries_system_serial: # Storage system serial number. Be sure to quote if the serial is all numbers and begins with zero. (This is located on a label at the top-left towards the front on the device) + eseries_system_addresses: # Storage system management IP addresses. Only required when eseries_system_serial or eseries_system_api_url are not defined. When not specified, addresses will be populated with eseries_management_interfaces controller addresses. + eseries_system_api_url: # Url for the storage system's for embedded web services rest api. Example: https://192.168.10.100/devmgr/v2 + eseries_system_username: admin # Username for the storage system's for embedded web services rest api + eseries_system_password: # Password for the storage system's for embedded web services rest api and when the admin password has not been set eseries_system_password will be used to set it. + eseries_system_old_password: # Previous admin password. This is used to change the current admin password by setting this variable to the current + # password and eseries_system_password to the new password. + eseries_proxy_ssid: # Arbitrary string for the proxy to represent the storage system. eseries_system_serial will be used when not defined. + eseries_template_api_url: # Template for the web services api url. Default: https://0.0.0.0:8443/devmgr/v2/ + eseries_prefer_embedded: false # Overrides the default behavior of using Web Services Proxy when eseries_proxy_api_url is defined. This will only effect storage systems that have Embedded Web Services. + eseries_validate_certs: true # Indicates Whether SSL certificates should be verified. Used for both embedded and proxy. Choices: true, false + + # Web Services Proxy information + Note: eseries_proxy_* variables are required to discover storage systems prior to SANtricity OS version 11.60.2. + eseries_proxy_api_url: # Url for the storage system's for proxy web services rest api. Example: https://192.168.10.100/devmgr/v2 + eseries_proxy_api_username: # Username for the storage system's for proxy web services rest api. + eseries_proxy_api_password: # Password for the storage system's for proxy web services rest api and when the admin password has not been set + # eseries_proxy_api_password will be used to set it. + + # Global storage system information + eseries_system_name: # Name of the storage system. + eseries_system_cache_block_size: # Cache block size + eseries_system_cache_flush_threshold: # Unwritten data will be flushed when exceeds this threshold + eseries_system_autoload_balance: # Whether automatic load balancing should be enabled. Choices: enabled, disabled + eseries_system_host_connectivity_reporting: # Whether host connectivity reporting should be enabled. Choices: enabled, disabled + eseries_system_login_banner_message: # Message that appears prior to the login. + eseries_system_controller_shelf_id: # Controller shelf identifier. + eseries_system_default_host_type: # Only required when using something other than Linux kernel 3.10 or later with DM-MP (Linux DM-MP), + # non-clustered Windows (Windows), or the storage system default host type is incorrect. Common definitions below: + # - AIX MPIO: The Advanced Interactive Executive (AIX) OS and the native MPIO driver + # - AVT 4M: Silicon Graphics, Inc. (SGI) proprietary multipath driver; refer to the SGI installation documentation for more information + # - HP-UX: The HP-UX OS with native multipath driver + # - Linux ATTO: The Linux OS and the ATTO Technology, Inc. driver (must use ATTO FC HBAs) + # - Linux DM-MP: The Linux OS and the native DM-MP driver + # - Linux Pathmanager: The Linux OS and the SGI proprietary multipath driver; refer to the SGI installation documentation for more information + # - Mac: The Mac OS and the ATTO Technology, Inc. driver + # - ONTAP: FlexArray + # - Solaris 11 or later: The Solaris 11 or later OS and the native MPxIO driver + # - Solaris 10 or earlier: The Solaris 10 or earlier OS and the native MPxIO driver + # - SVC: IBM SAN Volume Controller + # - VMware: ESXi OS + # - Windows: Windows Server OS and Windows MPIO with a DSM driver + # - Windows Clustered: Clustered Windows Server OS and Windows MPIO with a DSM driver + # - Windows ATTO: Windows OS and the ATTO Technology, Inc. driver + + # Role-based username passwords + eseries_system_monitor_password: # Storage system monitor username password + eseries_system_security_password: # Storage system security username password + eseries_system_storage_password: # Storage system storage username password + eseries_system_support_password: # Storage system support username password + + # SSL/TLS certificate configurations + eseries_client_certificate_common_certificates: # List of common client certificate file paths. These files will be appended to each client certificate list. + eseries_client_certificate_certificates: # List of client certificate file paths + eseries_server_certificate_common_certificates: # List of common server certificates. These files will be appended to each controller's server certificate list. + eseries_server_certificate_common_passphrase: # Common passphrase for decrypting PEM (PKCS8) private key. + eseries_server_certificate: + controller_a: + certificates: # List of server certificates for the storage systems controller A. Leave blank to use self-signed certificate. + passphrase: # Passphrase for decrypting PEM (PKCS8) private key. + controller_b: + certificates: # List of server certificates for the storage systems controller B. Leave blank to use self-signed certificate. + passphrase: # Passphrase for decrypting PEM (PKCS8) private key. + + # Storage management interface defaults + Note: eseries_management_* variables have the lowest priority and will be overwritten by those found in eseries_management_interfaces; use these to defined host group defaults. + eseries_management_config_method: # Default config method for all management interfaces. Choices: static, dhcp + eseries_management_subnet_mask: # Default subnet mask for all management interfaces + eseries_management_gateway: # Default gateway for all management interfaces + eseries_management_dns_config_method: # Default DNS config method for all management interfaces + eseries_management_dns_address: # Default primary DNS address for all management interfaces + eseries_management_dns_address_backup: # Default backup DNS address for all management interfaces + eseries_management_ntp_config_method: # Default NTP config method for all management interfaces + eseries_management_ntp_address: # Default primary NTP address for all management interfaces + eseries_management_ntp_address_backup: # Default backup NTP address for all management interfaces + eseries_management_ssh: # Default SSH access for all management interfaces. Choices: true, false + eseries_management_interfaces: + config_method: # Config method for all management interfaces. Choices: static, dhcp + subnet_mask: # Subnet mask for all management interfaces + gateway_mask: # Gateway for all management interfaces + dns_config_method: # DNS config method for all management interfaces + dns_address: # Primary DNS address for all management interfaces + dns_address_backup: # Backup DNS address for all management interfaces + ntp_config_method: # NTP config method for all management interfaces + ntp_address: # Primary NTP address for all management interfaces + ntp_address_backup: # Backup NTP address for all management interfaces + ssh: # SSH access for all management interfaces. Choices: true, false + controller_a: # List of controller A ports + - address: # IPv4 address for controller A + config_method: # Config method for controller A. Choices: static, dhcp + subnet_mask: # Subnet mask for controller A + gateway: # Gateway for controller A + dns_config_method: # DNS config method for controller A + dns_address: # Primary DNS address for controller A + dns_address_backup: # Backup DNS address for controller A + ntp_config_method: # NTP config method for controller A + ntp_address: # Primary NTP address for controller A + ntp_address_backup: # Backup NTP address for controller A + ssh: # SSH access for controller A. Choices: true, false + controller_b: # List of controller B ports + - (...) # Same as for controller A but for controller B. + + # Alerts configuration defaults + eseries_alerts_state: # Whether to enable storage system alerts. Choices: enabled, disabled + eseries_alerts_contact: # This allows owner to specify free-form contact information such as email or phone number. + eseries_alerts_recipients: # List containing e-mails that should be sent notifications when alerts are issued. + eseries_alerts_sender: # Sender email. This does not necessarily need to be a valid e-mail. + eseries_alerts_server: # Fully qualified domain name, IPv4 address, or IPv6 address of the mail server. + eseries_alerts_test: false # When changes are made to the storage system alert configuration a test e-mail will be sent. Choices: true, false + eseries_alert_syslog_servers: # List of dictionaries where each dictionary contains a syslog server entry. [{"address": <syslog_address>, "port": 514}] + eseries_alert_syslog_test: false # When changes are made to the alerts syslog servers configuration a test message will be sent to them. Choices: true, false + + # LDAP configuration defaults + eseries_ldap_state: # Whether LDAP should be configured + eseries_ldap_identifier: # The user attributes that should be considered for the group to role mapping + eseries_ldap_user_attribute: # Attribute used to the provided username during authentication. + eseries_ldap_bind_username: # User account that will be used for querying the LDAP server. + eseries_ldap_bind_password: # Password for the bind user account + eseries_ldap_server: # LDAP server URL. + eseries_ldap_search_base: # Search base used for find user's group membership + eseries_ldap_role_mappings: # Dictionary of user groups, each containing the list of access roles. + # Role choices: storage.admin - allows users full read/writes access to storage objects and operations. + # storage.monitor - allows users read-only access to storage objects and operations. + # storage.admin - allows users access to hardware, diagnostic information, major event logs, + # and other critical support-related functionality, but not the sorage configuration. + # security.admin - allows users access to authentication/authorization configuration, as + # well as the audit log configuration, adn certification management. + + # Drive firmware defaults + eseries_drive_firmware_firmware_list: # Local path list for drive firmware. + eseries_drive_firmware_wait_for_completion: # Forces drive firmware upgrades to wait for all associated tasks to complete. Choices: true, false + eseries_drive_firmware_ignore_inaccessible_drives: # Forces drive firmware upgrades to ignore any inaccessible drives. Choices: true, false + eseries_drive_firmware_upgrade_drives_online: # Forces drive firmware upgrades to be performed while I/Os are accepted. Choices: true, false + + # Controller firmware defaults + eseries_firmware_nvsram: # Local path for NVSRAM file. + eseries_firmware_firmware: # Local path for controller firmware file. + eseries_firmware_wait_for_completion: # Forces controller firmware upgrade to wait until upgrade has completed before continuing. Choices: true, false + eseries_firmware_clear_mel_events: # Forces firmware upgrade to be attempted regardless of the health check results. Choices: true, false + + # Auto-Support configuration defaults + eseries_asup_state: # Whether auto support (ASUP) should be enabled. Choices: enabled, disabled + eseries_asup_active: # Enables active monitoring which allows NetApp support personnel to request support data to resolve issues. Choices: true, false + eseries_asup_days: # List of days of the week. Choices: monday, tuesday, wednesday, thursday, friday, saturday, sunday + eseries_asup_start: # Hour of the day(s) to start ASUP bundle transmissions. Start time must be less than end time. Choices: 0-23 + eseries_asup_end: # Hour of the day(s) to end ASUP bundle transmissions. Start time must be less than end time. Choices: 1-24 + eseries_asup_method: # ASUP delivery method. Choices https, http, email (default: https) + eseries_asup_routing_type: # ASUP delivery routing type for https or http. Choices: direct, proxy, script (default: direct) + eseries_asup_proxy: # ASUP proxy delivery method information. + host: # ASUP proxy host IP address or FQDN. When eseries_asup_routing_type==proxy this must be specified. + port: # ASUP proxy host port. When eseries_asup_routing_type==proxy this must be specified. + username: # ASUP proxy username. + password: # ASUP proxy password. + script: # ASUP proxy host script. + eseries_asup_email: # ASUP email delivery configuration information + server: # ASUP email server + sender: # ASUP email sender + test_recipient: # ASUP configuration mail test recipient + eseries_maintenance_duration: # Duration in hours (1-72) the ASUP maintenance mode will be active + eseries_maintenance_emails: # List of email addresses for maintenance notifications + eseries_asup_validate: # Verify ASUP configuration prior to applying changes + + # Audit-log configuration defaults + eseries_auditlog_enforce_policy: # Whether to make audit-log policy changes. Choices: true, false + eseries_auditlog_force: # Forces audit-log to delete log messages when fullness threshold has been exceeded. Applicable when eseries_auditlog_full_policy=preventSystemAccess. Choices: true, false + eseries_auditlog_full_policy: # Policy for what to do when record limit has been reached. Choices: overWrite, preventSystemAccess + eseries_auditlog_log_level: # Filters logs based on the specified level. Choices: all, writeOnly + eseries_auditlog_max_records: # Maximum number of audit-log messages retained. Choices: 100-50000. + eseries_auditlog_threshold: # Memory full percentage threshold that audit-log will start issuing warning messages. Choices: 60-90 + + # Syslog configuration defaults + eseries_syslog_state: # Whether syslog servers should be added or removed from storage system. Choices: present, absent + eseries_syslog_address: # Syslog server IPv4 address or fully qualified hostname. + eseries_syslog_test: # Whether a test messages should be sent to syslog server when added to the storage system. Choices: true, false + eseries_syslog_protocol: # Protocol to be used when transmitting log messages to syslog server. Choices: udp, tc, tls + eseries_syslog_port: # Port to be used when transmitting log messages to syslog server. + eseries_syslog_components: # List of components log to syslog server. Choices: auditLog, (others may become available) + +License +------- + BSD-3-Clause + +Author Information +------------------ + Nathan Swartz (@ndswartz) diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/defaults/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/defaults/main.yml new file mode 100644 index 000000000..9e99c7d2f --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/defaults/main.yml @@ -0,0 +1,197 @@ +# Storage system specific credentials +# ----------------------------------- +eseries_system_username: admin # Storage system username. Default: admin +#eseries_system_password: # Storage system admin password. +#eseries_validate_certs: # Whether the SSL certificates should be verified. (boolean) +#eseries_system_subnet: # IPv4 search range for discovering E-Series storage. Must be in CIDR form. +#eseries_system_serial: # Storage system chassis serial number. This is used to automatically discover the system. +#eseries_system_addresses: # (list) Controller address(es) for the storage system. Only applicable for proxy web services. +#eseries_system_tags: # Meta tags to associate to the storage system. Only applicable for proxy web services. +#eseries_system_password: # Required when adding storage systems to SANtricity Web Services Proxy. +#eseries_system_minimum_password_length: # Minimum required password length + +# SANtricity Web Services Proxy specific variables +# ------------------------------------------------ +#eseries_proxy_ssid: # Storage array identifier. This value will be 1 when interacting with the embedded web services, +#eseries_proxy_api_url: # Url for the web services proxy rest api. Example: https://192.168.10.100:8443/devmgr/v2 +#eseries_proxy_api_username: # Username for the web services proxy rest api. +#eseries_proxy_api_password: # Password for the web services proxy rest api. +#eseries_proxy_current_api_password: # This is for changing the password for the proxy. +#eseries_proxy_api_validate_certs: # Whether the SSL certificates should be verified. (boolean) +#eseries_proxy_minimum_password_length: # Minimum required proxy password length + +#eseries_proxy_discovery_subnet: # IPv4 search range for discovering E-Series storage. Must be in CIDR form. +#eseries_proxy_accept_certifications: # Force automatic acceptance of all storage system's certificate +#eseries_proxy_default_system_tags: # Default meta tags to associate with all storage systems +#eseries_proxy_default_password: # Default password to associate with all storage systems +#eseries_proxy_systems: # List of storage system information which defines which systems should be added to proxy web services. + # Automatically populated from storage system's inventory when not defined. + # See na_santricity_proxy_systems for more details. + +# Storage proxy non-admin passwords +# --------------------------------- +#eseries_proxy_monitor_password: # Proxy monitor username password +#eseries_proxy_security_password: # Proxy security username password +#eseries_proxy_storage_password: # Proxy storage username password +#eseries_proxy_support_password: # Proxy support username password + +# Storage system non-admin passwords +# ---------------------------------- +#eseries_system_monitor_password: # Storage system monitor username password +#eseries_system_security_password: # Storage system security username password +#eseries_system_storage_password: # Storage system storage username password +#eseries_system_support_password: # Storage system support username password + +# Storage system defaults +# ----------------------------- +#eseries_system_name: # Name of the storage system. +#eseries_system_cache_block_size: # Cache block size +#eseries_system_cache_flush_threshold: # Unwritten data will be flushed when exceeds this threshold +#eseries_system_autoload_balance: # Whether automatic load balancing should be enabled. Choices: enabled, disabled +#eseries_system_host_connectivity_reporting: # Whether host connectivity reporting should be enabled. Choices: enabled, disabled +#eseries_system_login_banner_message: # Message that appears prior to the login. +#eseries_system_default_host_type: # Only required when using something other than Linux kernel 3.10 or later with DM-MP (Linux DM-MP), + # non-clustered Windows (Windows), or the storage system default host type is incorrect. Common definitions below: + # - AIX MPIO: The Advanced Interactive Executive (AIX) OS and the native MPIO driver + # - AVT 4M: Silicon Graphics, Inc. (SGI) proprietary multipath driver; refer to the SGI installation documentation for more information + # - HP-UX: The HP-UX OS with native multipath driver + # - Linux ATTO: The Linux OS and the ATTO Technology, Inc. driver (must use ATTO FC HBAs) + # - Linux DM-MP: The Linux OS and the native DM-MP driver + # - Linux Pathmanager: The Linux OS and the SGI proprietary multipath driver; refer to the SGI installation documentation for more information + # - Mac: The Mac OS and the ATTO Technology, Inc. driver + # - ONTAP: FlexArray + # - Solaris 11 or later: The Solaris 11 or later OS and the native MPxIO driver + # - Solaris 10 or earlier: The Solaris 10 or earlier OS and the native MPxIO driver + # - SVC: IBM SAN Volume Controller + # - VMware: ESXi OS + # - Windows: Windows Server OS and Windows MPIO with a DSM driver + # - Windows Clustered: Clustered Windows Server OS and Windows MPIO with a DSM driver + # - Windows ATTO: Windows OS and the ATTO Technology, Inc. driver + +# Storage system SSL certificates +# ------------------------------- +eseries_client_certificate_remove_unspecified_user_certificates: True # Whether existing user certificates should be automatically removed. +#eseries_client_certificate_certificates: # Dictionary containing the SSL certificate file paths. The key will be used as the alias. +#eseries_client_certificate_absent_certificates: # List of aliases to remove from the storage array's trust store. + +# Storage management interface defaults +# ------------------------------------- +#eseries_management_config_method: +#eseries_management_subnet_mask: +#eseries_management_gateway: +#eseries_management_dns_config_method: +#eseries_management_dns_address: +#eseries_management_dns_address_backup: +#eseries_management_ntp_config_method: +#eseries_management_ntp_address: +#eseries_management_ntp_address_backup: +#eseries_management_ssh: +#eseries_management_interfaces: +# config_method: +# subnet_mask: +# gateway_mask: +# dns_config_method: +# dns_address: +# dns_address_backup: +# ntp_config_method: +# ntp_address: +# ntp_address_backup: +# ssh +# controller_a: +# config_method: +# address: +# subnet_mask: +# gateway: +# dns_config_method: +# dns_address: +# dns_address_backup: +# ntp_config_method: +# ntp_address: +# ntp_address_backup: +# ssh: +# - (...) +# controller_b: +# - (...) +# - (...) + +# Alerts configuration defaults +# ----------------------------- +#eseries_alerts_state: # Whether to enable storage system alerts. Choices: enabled, disabled +#eseries_alerts_contact: # This allows owner to specify free-form contact information such as email or phone number. +#eseries_alerts_recipients: # List containing e-mails that should be sent notifications when alerts are issued. +#eseries_alerts_sender: # Sender email. This does not necessarily need to be a valid e-mail. +#eseries_alerts_server: # Fully qualified domain name, IPv4 address, or IPv6 address of the mail server. +#eseries_alert_syslog_servers: # List of dictionaries where each dictionary contains a syslog server entry. [{"address": <syslog_address>, "port": 514}] +eseries_alerts_test: false # When changes are made to the storage system alert configuration a test e-mail will be sent. Choices: true, false +eseries_alert_syslog_test: false # When changes are made to the alerts syslog servers configuration a test message will be sent to them. Choices: true, false + +# LDAP configuration defaults +# --------------------------- +#eseries_ldap_state: # Whether LDAP should be configured +#eseries_ldap_identifier: memberOf # The user attributes that should be considered for the group to role mapping +#eseries_ldap_user_attribute: sAMAccountName # Attribute used to the provided username during authentication. +#eseries_ldap_bind_username: # User account that will be used for querying the LDAP server. +#eseries_ldap_bind_password: # Password for the bind user account +#eseries_ldap_server: # LDAP server URL. +#eseries_ldap_search_base: # Search base used for find user's group membership +#eseries_ldap_role_mappings: # Dictionary of user groups, each containing the list of access roles. + # Role choices: storage.admin - allows users full read/writes access to storage objects and operations. + # storage.monitor - allows users read-only access to storage objects and operations. + # storage.admin - allows users access to hardware, diagnostic information, major event logs, and + # other critical support-related functionality, but not the sorage configuration. + # security.admin - allows users access to authentication/authorization configuration, as well as + # the audit log configuration, adn certification management. + +# Drive firmware defaults +# ----------------------- +#eseries_drive_firmware_firmware_list: # Local path list for drive firmware. +eseries_drive_firmware_wait_for_completion: true # Forces drive firmware upgrades to wait for all associated tasks to complete. Choices: true, false +eseries_drive_firmware_ignore_inaccessible_drives: false # Forces drive firmware upgrades to ignore any inaccessible drives. Choices: true, false +eseries_drive_firmware_upgrade_drives_online: true # Forces drive firmware upgrades to be performed while I/Os are accepted. Choices: true, false + +# Controller firmware defaults +# ---------------------------- +#eseries_firmware_nvsram: # Local path for NVSRAM file. +#eseries_firmware_firmware: # Local path for controller firmware file. +eseries_firmware_wait_for_completion: true # Forces controller firmware upgrade to wait until upgrade has completed before continuing. Choices: true, false +eseries_firmware_ignore_mel_events: false # Forces firmware upgrade to be attempted regardless of the health check results. Choices: true, false + +# ASUP configuration defaults +# --------------------------- +#eseries_asup_state: # Whether auto support (ASUP) should be enabled. Choices: enabled, disabled +eseries_asup_active: true # Enables active monitoring which allows NetApp support personnel to request support data to resolve issues. Choices: true, false +#eseries_asup_days: # List of days of the week. Choices: monday, tuesday, wednesday, thursday, friday, saturday, sunday +eseries_asup_start: 0 # Hour of the day(s) to start ASUP bundle transmissions. Start time must be less than end time. Choices: 0-23 +eseries_asup_end: 24 # Hour of the day(s) to end ASUP bundle transmissions. Start time must be less than end time. Choices: 1-24 +#eseries_asup_method: # ASUP delivery method. Choices https, http, email (default: https) +#eseries_asup_routing_type: # ASUP delivery routing type for https or http. Choices: direct, proxy, script (default: direct) +#eseries_asup_proxy: # ASUP proxy delivery method information. +# host: # ASUP proxy host IP address or FQDN. When eseries_asup_routing_type==proxy this must be specified. +# port: # ASUP proxy host port. When eseries_asup_routing_type==proxy this must be specified. +# script: # ASUP proxy host script. +#eseries_asup_email: # ASUP email delivery configuration information +# server: # ASUP email server +# sender: # ASUP email sender +# test_recipient: # ASUP configuration mail test recipient +#eseries_maintenance_duration: # Duration in hours (1-72) the ASUP maintenance mode will be active +#eseries_maintenance_emails: # List of email addresses for maintenance notifications +#eseries_asup_validate: # Verify ASUP configuration prior to applying changes. + +# Audit-log configuration defaults +# -------------------------------- +eseries_auditlog_enforce_policy: false # Whether to make audit-log policy changes. Choices: true, false +eseries_auditlog_force: false # Forces audit-log to delete log messages when fullness threshold has been exceeded. + # Applicable when eseries_auditlog_full_policy=preventSystemAccess. Choices: true, false +eseries_auditlog_full_policy: overWrite # Policy for what to do when record limit has been reached. Choices: overWrite, preventSystemAccess +eseries_auditlog_log_level: writeOnly # Filters logs based on the specified level. Choices: all, writeOnly +eseries_auditlog_max_records: 50000 # Maximum number of audit-log messages retained. Choices: 100-50000. +eseries_auditlog_threshold: 90 # Memory full percentage threshold that audit-log will start issuing warning messages. Choices: 60-90 + +# Syslog configuration defaults +# ----------------------------- +#eseries_syslog_state: # Whether syslog servers should be added or removed from storage system. Choices: present, absent +#eseries_syslog_address: # Syslog server IPv4 address or fully qualified hostname. +eseries_syslog_test: false # Whether a test messages should be sent to syslog server when added to the storage system. Choices: true, false +eseries_syslog_protocol: udp # Protocol to be used when transmitting log messages to syslog server. Choices: udp, tc, tls +eseries_syslog_port: 514 # Port to be used when transmitting log messages to syslog server. +eseries_syslog_components: ["auditLog"] # List of components log to syslog server. Choices: auditLog, (others may be available) diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/meta/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/meta/main.yml new file mode 100644 index 000000000..a519eeceb --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/meta/main.yml @@ -0,0 +1,13 @@ +galaxy_info: + author: Nathan Swartz (@ndswartz) + description: Manages NetApp E-Series storage system's firmware, management interfaces, security, system, and logging configuration. + company: NetApp, Inc + license: BSD-3 Clause + platforms: [] + min_ansible_version: 2.13 + galaxy_tags: + - netapp + - eseries + - storage + +dependencies: []
\ No newline at end of file diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/firmware.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/firmware.yml new file mode 100644 index 000000000..d53d2568c --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/firmware.yml @@ -0,0 +1,83 @@ +- name: Upload required drive, nvsram, and firmware files to Web Services Proxy. + block: + - name: Collect expected firmware file lists + ansible.builtin.set_fact: + eseries_proxy_drive_firmware: |- + {%- set drive_firmware = [] %} + {%- for host in ansible_play_hosts_all %} + {%- if hostvars[host]["current_eseries_api_is_proxy"] and "eseries_drive_firmware_firmware_list" in hostvars[host] %} + {%- if drive_firmware.extend(hostvars[host]["eseries_drive_firmware_firmware_list"]) %}{%- endif %} + {%- endif %} + {%- endfor %} + {{ drive_firmware | list }} + eseries_proxy_nvsram: |- + {%- set nvsram = [] %} + {%- for host in ansible_play_hosts_all %} + {%- if hostvars[host]["current_eseries_api_is_proxy"] and "eseries_firmware_nvsram" in hostvars[host] %} + {%- if nvsram.append(hostvars[host]["eseries_firmware_nvsram"]) %}{%- endif %} + {%- endif %} + {%- endfor %} + {{ nvsram | list }} + eseries_proxy_firmware: |- + {%- set firmware = [] %} + {%- for host in ansible_play_hosts_all %} + {%- if hostvars[host]["current_eseries_api_is_proxy"] and "eseries_firmware_firmware" in hostvars[host] %} + {%- if firmware.append(hostvars[host]["eseries_firmware_firmware"]) %}{%- endif %} + {%- endif %} + {%- endfor %} + {{ firmware | list }} + + - name: Ensure SANtricity Web Services Proxy has the expected drive firmware + netapp_eseries.santricity.na_santricity_proxy_drive_firmware_upload: + api_url: "{{ eseries_proxy_api_url }}" + api_username: "{{ eseries_proxy_api_username }}" + api_password: "{{ eseries_proxy_api_password }}" + validate_certs: "{{ eseries_validate_certs | default(omit) }}" + firmware: "{{ eseries_proxy_drive_firmware | default(omit) }}" + connection: local + when: eseries_proxy_drive_firmware != [] + + - name: Ensure SANtricity Web Services Proxy has the expected controller firmware and NVSRAM + netapp_eseries.santricity.na_santricity_proxy_firmware_upload: + api_url: "{{ eseries_proxy_api_url }}" + api_username: "{{ eseries_proxy_api_username }}" + api_password: "{{ eseries_proxy_api_password }}" + validate_certs: "{{ eseries_validate_certs | default(omit) }}" + firmware: "{{ eseries_proxy_firmware | default(omit) + eseries_proxy_nvsram | default(omit) }}" + connection: local + when: eseries_proxy_nvsram != [] or eseries_proxy_firmware != [] + run_once: true + +- name: Ensure drive firmware is properly configured + netapp_eseries.santricity.na_santricity_drive_firmware: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + firmware: "{{ eseries_drive_firmware_firmware_list }}" + wait_for_completion: "{{ eseries_drive_firmware_wait_for_completion | default(true) }}" + ignore_inaccessible_drives: "{{ eseries_drive_firmware_ignore_inaccessible_drives | default(omit) }}" + upgrade_drives_online: "{{ eseries_drive_firmware_upgrade_drives_online | default(omit) }}" + connection: local + when: eseries_drive_firmware_firmware_list is defined + tags: + - firmware + - drive_firmware + +- name: Ensure controller firmware is properly configured + netapp_eseries.santricity.na_santricity_firmware: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + nvsram: "{{ eseries_firmware_nvsram | default('') }}" + firmware: "{{ eseries_firmware_firmware | default('') }}" + wait_for_completion: "{{ eseries_firmware_wait_for_completion | default(true) }}" + clear_mel_events: "{{ eseries_firmware_ignore_mel_events | default(omit) }}" + connection: local + when: eseries_firmware_nvsram is defined or eseries_firmware_firmware is defined + tags: + - firmware + - controller_firmware diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/interface.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/interface.yml new file mode 100644 index 000000000..2e8f535fe --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/interface.yml @@ -0,0 +1,171 @@ +- name: Determine individual management interface information. + ansible.builtin.set_fact: + do_not_remove: 0 # Placeholder to prevent task from failing when no interfaces are defined. + interface_a1: "{{ eseries_management_interfaces['controller_a'][0] | default(omit) }}" + interface_a2: "{{ eseries_management_interfaces['controller_a'][1] | default(omit) }}" + interface_b1: "{{ eseries_management_interfaces['controller_b'][0] | default(omit) }}" + interface_b2: "{{ eseries_management_interfaces['controller_b'][1] | default(omit) }}" + +# This task is only executed when no controller A interfaces are defined so global interface options can still be set. +- name: Ensure controller A DNS, NTP and SSH configuration is set. + netapp_eseries.santricity.na_santricity_mgmt_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: A + dns_config_method: "{{ eseries_management_interfaces['dns_config_method'] | + default(eseries_management_dns_config_method | default(omit)) }}" + dns_address: "{{ eseries_management_interfaces['dns_address'] | + default(eseries_management_dns_address | default(omit)) }}" + dns_address_backup: "{{ eseries_management_interfaces['dns_address_backup'] | + default(eseries_management_dns_address_backup | default(omit)) }}" + ntp_config_method: "{{ eseries_management_interfaces['ntp_config_method'] | + default(eseries_management_ntp_config_method | default(omit)) }}" + ntp_address: "{{ eseries_management_interfaces['ntp_address'] | + default(eseries_management_ntp_address | default(omit)) }}" + ntp_address_backup: "{{ eseries_management_interfaces['ntp_address_backup'] | + default(eseries_management_ntp_address_backup | default(omit)) }}" + ssh: "{{ eseries_management_interfaces['ssh'] | default(eseries_management_ssh | default(omit)) }}" + when: interface_a1 is not defined and interface_a2 is not defined + +# This task is only executed when no controller B interfaces are defined so global interface options can still be set. +- name: Ensure controller B DNS, NTP and SSH configuration is set. + netapp_eseries.santricity.na_santricity_mgmt_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: B + dns_config_method: "{{ eseries_management_interfaces['dns_config_method'] | + default(eseries_management_dns_config_method | default(omit)) }}" + dns_address: "{{ eseries_management_interfaces['dns_address'] | + default(eseries_management_dns_address | default(omit)) }}" + dns_address_backup: "{{ eseries_management_interfaces['dns_address_backup'] | + default(eseries_management_dns_address_backup | default(omit)) }}" + ntp_config_method: "{{ eseries_management_interfaces['ntp_config_method'] | + default(eseries_management_ntp_config_method | default(omit)) }}" + ntp_address: "{{ eseries_management_interfaces['ntp_address'] | + default(eseries_management_ntp_address | default(omit)) }}" + ntp_address_backup: "{{ eseries_management_interfaces['ntp_address_backup'] | + default(eseries_management_ntp_address_backup | default(omit)) }}" + ssh: "{{ eseries_management_interfaces['ssh'] | default(eseries_management_ssh | default(omit)) }}" + when: interface_b1 is not defined and interface_b2 is not defined + +- name: Ensure the management interface (controller A, port 1) has been configured. + block: + - name: Ensure the management interface (controller A, port 1) has been configured. + netapp_eseries.santricity.na_santricity_mgmt_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: A + port: 1 + address: "{{ interface_a1['address'] | default(omit) }}" + config_method: "{{ interface_a1['config_method'] | default(eseries_management_interfaces['config_method'] | default(eseries_management_config_method | default(omit))) }}" + subnet_mask: "{{ interface_a1['subnet_mask'] | default(eseries_management_interfaces['subnet_mask'] | default(eseries_management_subnet_mask | default(omit))) }}" + gateway: "{{ interface_a1['gateway'] | default(eseries_management_interfaces['gateway'] | default(eseries_management_gateway | default(omit))) }}" + dns_config_method: "{{ interface_a1['dns_config_method'] | default(eseries_management_interfaces['dns_config_method'] | default(eseries_management_dns_config_method | default(omit))) }}" + dns_address: "{{ interface_a1['dns_address'] | default(eseries_management_interfaces['dns_address'] | default(eseries_management_dns_address | default(omit))) }}" + dns_address_backup: "{{ interface_a1['dns_address_backup'] | default(eseries_management_interfaces['dns_address_backup'] | default(eseries_management_dns_address_backup | default(omit))) }}" + ntp_config_method: "{{ interface_a1['ntp_config_method'] | default(eseries_management_interfaces['ntp_config_method'] | default(eseries_management_ntp_config_method | default(omit))) }}" + ntp_address: "{{ interface_a1['ntp_address'] | default(eseries_management_interfaces['ntp_address'] | default(eseries_management_ntp_address | default(omit))) }}" + ntp_address_backup: "{{ interface_a1['ntp_address_backup'] | default(eseries_management_interfaces['ntp_address_backup'] | default(eseries_management_ntp_address_backup | default(omit))) }}" + ssh: "{{ interface_a1['ssh'] | default(eseries_management_interfaces['ssh'] | default(eseries_management_ssh | default(omit))) }}" + connection: local + register: current_management_urls_a1 + - name: Update Web Services URL + ansible.builtin.set_fact: + current_eseries_api_url: "{{ current_management_urls_a1['available_embedded_api_urls'][0] | default(current_eseries_api_url) }}" + when: interface_a1 is defined and interface_a1 + +- name: Ensure the management interface (controller A, port 2) has been configured. + block: + - name: Ensure the management interface (controller A, port 2) has been configured. + netapp_eseries.santricity.na_santricity_mgmt_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: A + port: 2 + address: "{{ interface_a2['address'] | default(omit) }}" + config_method: "{{ interface_a2['config_method'] | default(eseries_management_interfaces['config_method'] | default(eseries_management_config_method | default(omit))) }}" + subnet_mask: "{{ interface_a2['subnet_mask'] | default(eseries_management_interfaces['subnet_mask'] | default(eseries_management_subnet_mask | default(omit))) }}" + gateway: "{{ interface_a2['gateway'] | default(eseries_management_interfaces['gateway'] | default(eseries_management_gateway | default(omit))) }}" + dns_config_method: "{{ interface_a2['dns_config_method'] | default(eseries_management_interfaces['dns_config_method'] | default(eseries_management_dns_config_method | default(omit))) }}" + dns_address: "{{ interface_a2['dns_address'] | default(eseries_management_interfaces['dns_address'] | default(eseries_management_dns_address | default(omit))) }}" + dns_address_backup: "{{ interface_a2['dns_address_backup'] | default(eseries_management_interfaces['dns_address_backup'] | default(eseries_management_dns_address_backup | default(omit))) }}" + ntp_config_method: "{{ interface_a2['ntp_config_method'] | default(eseries_management_interfaces['ntp_config_method'] | default(eseries_management_ntp_config_method | default(omit))) }}" + ntp_address: "{{ interface_a2['ntp_address'] | default(eseries_management_interfaces['ntp_address'] | default(eseries_management_ntp_address | default(omit))) }}" + ntp_address_backup: "{{ interface_a2['ntp_address_backup'] | default(eseries_management_interfaces['ntp_address_backup'] | default(eseries_management_ntp_address_backup | default(omit))) }}" + ssh: "{{ interface_a2['ssh'] | default(eseries_management_interfaces['ssh'] | default(eseries_management_ssh | default(omit))) }}" + connection: local + register: current_management_urls_a2 + - name: Try backup Web Services REST API url. + ansible.builtin.set_fact: + current_eseries_api_url: "{{ current_management_urls_a2['available_embedded_api_urls'][0] | default(current_eseries_api_url) }}" + when: interface_a2 is defined and interface_a2 + +- name: Ensure the management interface (controller B, port 1) has been configured. + block: + - name: Ensure the management interface (controller B, port 1) has been configured. + netapp_eseries.santricity.na_santricity_mgmt_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: B + port: 1 + address: "{{ interface_b1['address'] | default(omit) }}" + config_method: "{{ interface_b1['config_method'] | default(eseries_management_interfaces['config_method'] | default(eseries_management_config_method | default(omit))) }}" + subnet_mask: "{{ interface_b1['subnet_mask'] | default(eseries_management_interfaces['subnet_mask'] | default(eseries_management_subnet_mask | default(omit))) }}" + gateway: "{{ interface_b1['gateway'] | default(eseries_management_interfaces['gateway'] | default(eseries_management_gateway | default(omit))) }}" + dns_config_method: "{{ interface_b1['dns_config_method'] | default(eseries_management_interfaces['dns_config_method'] | default(eseries_management_dns_config_method | default(omit))) }}" + dns_address: "{{ interface_b1['dns_address'] | default(eseries_management_interfaces['dns_address'] | default(eseries_management_dns_address | default(omit))) }}" + dns_address_backup: "{{ interface_b1['dns_address_backup'] | default(eseries_management_interfaces['dns_address_backup'] | default(eseries_management_dns_address_backup | default(omit))) }}" + ntp_config_method: "{{ interface_b1['ntp_config_method'] | default(eseries_management_interfaces['ntp_config_method'] | default(eseries_management_ntp_config_method | default(omit))) }}" + ntp_address: "{{ interface_b1['ntp_address'] | default(eseries_management_interfaces['ntp_address'] | default(eseries_management_ntp_address | default(omit))) }}" + ntp_address_backup: "{{ interface_b1['ntp_address_backup'] | default(eseries_management_interfaces['ntp_address_backup'] | default(eseries_management_ntp_address_backup | default(omit))) }}" + ssh: "{{ interface_b1['ssh'] | default(eseries_management_interfaces['ssh'] | default(eseries_management_ssh | default(omit))) }}" + connection: local + register: current_management_urls_b1 + - name: Try backup Web Services REST API url. + ansible.builtin.set_fact: + current_eseries_api_url: "{{ current_management_urls_b1['available_embedded_api_urls'][0] | default(current_eseries_api_url) }}" + when: interface_b1 is defined and interface_b1 + +- name: Ensure the management interface (controller B, port 2) has been configured. + block: + - name: Ensure the management interface (controller B, port 2) has been configured. + netapp_eseries.santricity.na_santricity_mgmt_interface: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: B + port: 2 + address: "{{ interface_b2['address'] | default(omit) }}" + config_method: "{{ interface_b2['config_method'] | default(eseries_management_interfaces['config_method'] | default(eseries_management_config_method | default(omit))) }}" + subnet_mask: "{{ interface_b2['subnet_mask'] | default(eseries_management_interfaces['subnet_mask'] | default(eseries_management_subnet_mask | default(omit))) }}" + gateway: "{{ interface_b2['gateway'] | default(eseries_management_interfaces['gateway'] | default(eseries_management_gateway | default(omit))) }}" + dns_config_method: "{{ interface_b2['dns_config_method'] | default(eseries_management_interfaces['dns_config_method'] | default(eseries_management_dns_config_method | default(omit))) }}" + dns_address: "{{ interface_b2['dns_address'] | default(eseries_management_interfaces['dns_address'] | default(eseries_management_dns_address | default(omit))) }}" + dns_address_backup: "{{ interface_b2['dns_address_backup'] | default(eseries_management_interfaces['dns_address_backup'] | default(eseries_management_dns_address_backup | default(omit))) }}" + ntp_config_method: "{{ interface_b2['ntp_config_method'] | default(eseries_management_interfaces['ntp_config_method'] | default(eseries_management_ntp_config_method | default(omit))) }}" + ntp_address: "{{ interface_b2['ntp_address'] | default(eseries_management_interfaces['ntp_address'] | default(eseries_management_ntp_address | default(omit))) }}" + ntp_address_backup: "{{ interface_b2['ntp_address_backup'] | default(eseries_management_interfaces['ntp_address_backup'] | default(eseries_management_ntp_address_backup | default(omit))) }}" + ssh: "{{ interface_b2['ssh'] | default(eseries_management_interfaces['ssh'] | default(eseries_management_ssh | default(omit))) }}" + connection: local + register: current_management_urls_b2 + - name: Try backup Web Services REST API url. + ansible.builtin.set_fact: + current_eseries_api_url: "{{ current_management_urls_b2['available_embedded_api_urls'][0] | default(current_eseries_api_url) }}" + when: interface_b2 is defined and interface_b2 diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/logging.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/logging.yml new file mode 100644 index 000000000..852f22793 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/logging.yml @@ -0,0 +1,95 @@ +- name: Ensure ASUP configuration + netapp_eseries.santricity.na_santricity_asup: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ eseries_validate_certs | default(omit) }}" + state: "{{ eseries_asup_state }}" + active: "{{ eseries_asup_active | default(omit) }}" + days: "{{ eseries_asup_days | default(omit) }}" + start: "{{ eseries_asup_start | default(omit) }}" + end: "{{ eseries_asup_end | default(omit) }}" + method: "{{ eseries_asup_method | default(omit) }}" + routing_type: "{{ eseries_asup_routing_type | default(omit) }}" + proxy: "{{ eseries_asup_proxy | default(omit) }}" + email: "{{ eseries_asup_email | default(omit) }}" + maintenance_duration: "{{ eseries_maintenance_duration | default(omit) }}" + maintenance_emails: "{{ eseries_maintenance_emails | default(omit) }}" + validate: "{{ eseries_asup_validate | default(omit) }}" + connection: local + when: eseries_asup_state is defined + tags: + - logging + - asup + +- name: Ensure alerts have been configured + netapp_eseries.santricity.na_santricity_alerts: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ eseries_validate_certs | default(omit) }}" + state: "{{ eseries_alerts_state }}" + contact: "{{ eseries_alerts_contact | default(omit) }}" + recipients: "{{ eseries_alerts_recipients | default(omit) }}" + sender: "{{ eseries_alerts_sender| default(omit) }}" + server: "{{ eseries_alerts_server | default(omit) }}" + test: "{{ eseries_alerts_test | default(omit) }}" + connection: local + when: eseries_alerts_state is defined + tags: + - logging + - alerts + +- name: Ensure auditLog configuration + netapp_eseries.santricity.na_santricity_auditlog: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ eseries_validate_certs | default(omit) }}" + force: "{{ eseries_auditlog_force | default(omit) }}" + full_policy: "{{ eseries_auditlog_full_policy | default(omit) }}" + log_level: "{{ eseries_auditlog_log_level | default(omit) }}" + max_records: "{{ eseries_auditlog_max_records | default(omit) }}" + threshold: "{{ eseries_auditlog_threshold | default(omit) }}" + connection: local + when: eseries_auditlog_enforce_policy + tags: + - logging + - auditlog + +- name: Ensure components are configured to be sent to the approriate syslog servers + netapp_eseries.santricity.na_santricity_syslog: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ eseries_validate_certs | default(omit) }}" + state: "{{ eseries_syslog_state }}" + address: "{{ eseries_syslog_address }}" + test: "{{ eseries_syslog_test | default(omit) }}" + protocol: "{{ eseries_syslog_protocol | default(omit) }}" + port: "{{ eseries_syslog_port | default(omit) }}" + components: "{{ eseries_syslog_components | default(omit) }}" + connection: local + when: eseries_syslog_state is defined and eseries_syslog_address is defined + tags: + - logging + - syslog + +- name: Ensure alerts are configured to be sent to the approriate syslog servers + netapp_eseries.santricity.na_santricity_alerts_syslog: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ eseries_validate_certs | default(omit) }}" + servers: "{{ eseries_alert_syslog_servers | default(omit) }}" + test: "{{ eseries_alert_syslog_test | default(omit) }}" + connection: local + when: eseries_syslog_state is defined and eseries_syslog_address is defined + tags: + - logging + - syslog diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/main.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/main.yml new file mode 100644 index 000000000..f2b2bbe6e --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/main.yml @@ -0,0 +1,27 @@ +- name: Set current storage system credentials + ansible.builtin.include_role: + name: netapp_eseries.santricity.nar_santricity_common + tasks_from: build_info.yml + when: current_eseries_api_url is not defined + tags: + - always + +- name: Ensure security settings are configured + ansible.builtin.import_tasks: security.yml + +- name: Ensure management interfaces are configured + ansible.builtin.import_tasks: interface.yml + tags: + - interface + - ntp + - dns + - ssh + +- name: Ensure all global system settings are configured + ansible.builtin.import_tasks: system.yml + +- name: Ensure event logging has been configured + ansible.builtin.import_tasks: logging.yml + +- name: Ensure drive and controller firmware are correct + ansible.builtin.import_tasks: firmware.yml diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/security.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/security.yml new file mode 100644 index 000000000..d176b1922 --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/security.yml @@ -0,0 +1,213 @@ +- name: Ensure admin password is set and is correct + netapp_eseries.santricity.na_santricity_auth: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: |- + {%- if current_eseries_api_is_proxy == True -%} + {{- current_eseries_api_password -}} + {%- else -%} + {{- eseries_system_old_password | default(current_eseries_api_password) -}} + {%- endif -%} + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + current_admin_password: |- + {%- if current_eseries_api_is_proxy == True -%} + {{- eseries_system_old_password | default(eseries_system_password) -}} + {%- else -%} + {{- omit -}} + {%- endif -%} + user: admin + password: "{{ eseries_system_password }}" + connection: local + register: admin_password + when: eseries_system_password is defined + tags: + - always + +- name: Update current_eseries_api_password if storage system password changed. + block: + - name: Update current_eseries_api_password. + ansible.builtin.set_fact: + current_eseries_api_password: |- + {%- if current_eseries_api_is_proxy == True -%} + {{- current_eseries_api_password -}} + {%- else -%} + {{- eseries_system_password -}} + {%- endif -%} + no_log: true + - name: Wait for password to update + ansible.builtin.pause: + seconds: 5 + when: admin_password['changed'] == True + +- name: Ensure non-admin passwords have been set + netapp_eseries.santricity.na_santricity_auth: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + current_admin_password: |- + {%- if current_eseries_api_is_proxy == True -%} + {{- eseries_system_password -}} + {%- else -%} + {{- omit -}} + {%- endif -%} + user: "{{ item['key'] }}" + password: "{{ item['value'] }}" + connection: local + loop: "{{ lookup('dict', non_admin_user_authentication, wantlist=True) }}" + vars: + non_admin_user_authentication: |- + {%- set non_admin_list = {} %} + {%- if eseries_system_monitor_password is defined and eseries_system_monitor_password and non_admin_list.update({"monitor": eseries_system_monitor_password})%}{%- endif %} + {%- if eseries_system_security_password is defined and eseries_system_security_password and non_admin_list.update({"security": eseries_system_security_password})%}{%- endif %} + {%- if eseries_system_storage_password is defined and eseries_system_storage_password and non_admin_list.update({"storage": eseries_system_storage_password})%}{%- endif %} + {%- if eseries_system_support_password is defined and eseries_system_support_password and non_admin_list.update({"support": eseries_system_support_password})%}{%- endif %} + {{ non_admin_list }} + +- name: Ensure client certificates are installed + netapp_eseries.santricity.na_santricity_client_certificate: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + certificates: "{{ certificates }}" + remove_unspecified_user_certificates: "{{ eseries_client_certificate_remove_unspecified_user_certificates | default(omit) }}" + connection: local + when: eseries_client_certificate_certificates is defined or eseries_client_certificate_common_certificates is defined + tags: + - security + - certificates + vars: + certificates: |- + {%- set certs = [] -%} + + {#- Add common client certificates -#} + {%- if eseries_client_certificate_common_certificates is defined -%} + {%- if eseries_client_certificate_common_certificates is string -%} + {%- if certs.append(eseries_client_certificate_common_certificates) -%}{%- endif -%} + {%- elif eseries_client_certificate_common_certificates is iterable -%} + {%- if certs.extend(eseries_client_certificate_common_certificates) -%}{%- endif -%} + {%- endif -%} + {%- endif -%} + + {#- Add controller A client certificates -#} + {%- if eseries_client_certificate_certificates is defined -%} + {%- if eseries_client_certificate_certificates is string -%} + {%- if eseries_client_certificate_certificates not in certs -%} + {%- if certs.append(eseries_client_certificate_certificates) -%}{%- endif -%} + {%- endif -%} + {%- elif eseries_client_certificate_certificates is iterable -%} + {%- for client_cert in eseries_client_certificate_certificates if client_cert not in certs -%} + {%- if certs.append(client_cert) -%}{%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endif -%} + {{- certs -}} + +- name: Ensure controller A server certificates are installed + netapp_eseries.santricity.na_santricity_server_certificate: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: "A" + certificates: "{{ certificates }}" + passphrase: "{{ eseries_server_certificate['controller_a']['passphrase'] | default(eseries_server_certificate_common_passphrase | default(omit)) }}" + connection: local + when: eseries_server_certificate_common_certificates is defined or eseries_server_certificate['controller_a'] is defined or eseries_server_certificate['controller_a']['certificates'] is defined + tags: + - security + - certificates + vars: + certificates: |- + {%- set certs = [] -%} + + {#- Add common server certificates -#} + {%- if eseries_server_certificate_common_certificates is defined -%} + {%- if eseries_server_certificate_common_certificates is string -%} + {%- if certs.append(eseries_server_certificate_common_certificates) -%}{%- endif -%} + {%- elif eseries_server_certificate_common_certificates is iterable -%} + {%- if certs.extend(eseries_server_certificate_common_certificates) -%}{%- endif -%} + {%- endif -%} + {%- endif -%} + + {#- Add controller A certificates -#} + {%- if eseries_server_certificate is defined and eseries_server_certificate["controller_a"] is defined or eseries_server_certificate["controller_b"]["certificates"] is defined -%} + {%- if eseries_server_certificate["controller_a"]["certificates"] is string -%} + {%- if eseries_server_certificate["controller_a"]["certificates"] not in certs -%} + {%- if certs.append(eseries_server_certificate["controller_a"]["certificates"]) -%}{%- endif -%} + {%- endif -%} + {%- elif eseries_server_certificate["controller_a"]["certificates"] is iterable -%} + {%- for server_cert in eseries_server_certificate["controller_a"]["certificates"] if server_cert not in certs -%} + {%- if certs.append(server_cert) -%}{%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endif -%} + {{- certs -}} + +- name: Ensure controller B server certificates are installed + netapp_eseries.santricity.na_santricity_server_certificate: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + controller: "B" + certificates: "{{ certificates }}" + passphrase: "{{ eseries_server_certificate['controller_b']['passphrase'] | default(eseries_server_certificate_common_passphrase | default(omit)) }}" + connection: local + when: eseries_server_certificate_common_certificates is defined or eseries_server_certificate['controller_b'] is defined or eseries_server_certificate['controller_b']['certificates'] is defined + tags: + - security + - certificates + vars: + certificates: |- + {%- set certs = [] -%} + + {#- Add common server certificates -#} + {%- if eseries_server_certificate_common_certificates is defined -%} + {%- if eseries_server_certificate_common_certificates is string -%} + {%- if certs.append(eseries_server_certificate_common_certificates) -%}{%- endif -%} + {%- elif eseries_server_certificate_common_certificates is iterable -%} + {%- if certs.extend(eseries_server_certificate_common_certificates) -%}{%- endif -%} + {%- endif -%} + {%- endif -%} + + {#- Add controller B certificates -#} + {%- if eseries_server_certificate is defined and eseries_server_certificate["controller_b"] is defined or eseries_server_certificate["controller_b"]["certificates"] is defined -%} + {%- if eseries_server_certificate["controller_b"]["certificates"] is string -%} + {%- if eseries_server_certificate["controller_b"] not in certs -%} + {%- if certs.append(eseries_server_certificate["controller_b"]["certificates"]) -%}{%- endif -%} + {%- endif -%} + {%- elif eseries_server_certificate["controller_b"]["certificates"] is iterable -%} + {%- for server_cert in eseries_server_certificate["controller_b"]["certificates"] if server_cert not in certs -%} + {%- if certs.append(server_cert) -%}{%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endif -%} + {{- certs -}} + +- name: Ensure LDAP has been configured + netapp_eseries.santricity.na_santricity_ldap: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + state: "{{ eseries_ldap_state }}" + identifier: "{{ eseries_ldap_identifier | default(omit) }}" + server_url: "{{ eseries_ldap_server | default(omit) }}" + bind_user: "{{ eseries_ldap_bind_username | default(omit) }}" + bind_password: "{{ eseries_ldap_bind_password | default(omit) }}" + search_base: "{{ eseries_ldap_search_base | default(omit) }}" + user_attribute: "{{ eseries_ldap_user_attribute | default(omit) }}" + role_mappings: "{{ eseries_ldap_role_mappings | default(omit) }}" + connection: local + when: eseries_ldap_state is defined + tags: + - security + - ldap diff --git a/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/system.yml b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/system.yml new file mode 100644 index 000000000..8bcf87cda --- /dev/null +++ b/ansible_collections/netapp_eseries/santricity/roles/nar_santricity_management/tasks/system.yml @@ -0,0 +1,26 @@ +- name: Ensure storage array has the correct array globals + netapp_eseries.santricity.na_santricity_global: + ssid: "{{ current_eseries_ssid }}" + api_url: "{{ current_eseries_api_url }}" + api_username: "{{ current_eseries_api_username }}" + api_password: "{{ current_eseries_api_password }}" + validate_certs: "{{ current_eseries_validate_certs | default(omit) }}" + name: "{{ eseries_system_name | default(omit) }}" + cache_block_size: "{{ eseries_system_cache_block_size | default(omit) }}" + cache_flush_threshold: "{{ eseries_system_cache_flush_threshold | default(omit) }}" + automatic_load_balancing: "{{ eseries_system_autoload_balance | default(omit) }}" + host_connectivity_reporting: "{{ eseries_system_host_connectivity_reporting | default(omit) }}" + default_host_type: "{{ eseries_system_default_host_type | default(omit) }}" + login_banner_message: "{{ eseries_system_login_banner_message | default(omit) }}" + controller_shelf_id: "{{ eseries_system_controller_shelf_id | default(omit) }}" + connection: local + when: "eseries_system_name is defined or + eseries_system_cache_block_size is defined or + eseries_system_cache_flush_threshold is defined or + eseries_system_autoload_balance is defined or + eseries_system_host_connectivity_reporting is defined or + eseries_system_default_host_type is defined or + eseries_system_login_banner_message is defined or + eseries_system_controller_shelf_id is defined" + tags: + - system |