--- # Test code for the netapp_e_host module # (c) 2018, NetApp, Inc # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - name: NetApp Test Host module fail: msg: 'Please define netapp_e_api_username, netapp_e_api_password, netapp_e_api_host, and netapp_e_ssid.' when: netapp_e_api_username is undefined or netapp_e_api_password is undefined or netapp_e_api_host is undefined or netapp_e_ssid is undefined vars: gather_facts: yes credentials: &creds api_url: "https://{{ netapp_e_api_host }}/devmgr/v2" api_username: "{{ netapp_e_api_username }}" api_password: "{{ netapp_e_api_password }}" ssid: "{{ netapp_e_ssid }}" validate_certs: no hosts: &hosts 1: host_type: 27 update_host_type: 28 ports: - type: 'iscsi' label: 'I_1' port: 'iqn.1996-04.de.suse:01:56f86f9bd1fe' - type: 'iscsi' label: 'I_2' port: 'iqn.1996-04.de.suse:01:56f86f9bd1ff' ports2: - type: 'iscsi' label: 'I_1' port: 'iqn.1996-04.de.suse:01:56f86f9bd1fe' - type: 'iscsi' label: 'I_2' port: 'iqn.1996-04.de.suse:01:56f86f9bd1ff' - type: 'fc' label: 'FC_3' port: '10:00:8C:7C:FF:1A:B9:01' 2: host_type: 27 update_host_type: 28 ports: - type: 'fc' label: 'FC_1' port: '10:00:8C:7C:FF:1A:B9:01' - type: 'fc' label: 'FC_2' port: '10:00:8C:7C:FF:1A:B9:00' ports2: - type: 'fc' label: 'FC_6' port: '10:00:8C:7C:FF:1A:B9:01' - type: 'fc' label: 'FC_4' port: '10:00:8C:7C:FF:1A:B9:00' # ******************************************** # *** Ensure jmespath package is installed *** # ******************************************** # NOTE: jmespath must be installed for the json_query filter - name: Ensure that jmespath is installed pip: name: jmespath state: present register: jmespath - fail: msg: "Restart playbook, the jmespath package was installed and is need for the playbook's execution." when: jmespath.changed # ***************************************** # *** Set credential and host variables *** # ***************************************** - name: Set hosts variable set_fact: hosts: *hosts - name: set credentials set_fact: credentials: *creds - name: Show some debug information debug: msg: "Using user={{ credentials.api_username }} on server={{ credentials.api_url }}." # *** Remove any existing hosts to set initial state and verify state *** - name: Remove any existing hosts netapp_e_host: <<: *creds state: absent name: "{{ item.key }}" with_dict: *hosts # Retrieve array host definitions - name: HTTP request for all host definitions from array uri: url: "{{ credentials.api_url }}/storage-systems/{{ credentials.ssid }}/hosts" user: "{{ credentials.api_username }}" password: "{{ credentials.api_password }}" body_format: json validate_certs: no register: result # Verify that host 1 and 2 host objects do not exist - name: Collect host side port labels set_fact: host_labels: "{{ result | json_query('json[*].label') }}" - name: Assert hosts were removed assert: that: "'{{ item.key }}' not in host_labels" msg: "Host, {{ item.key }}, failed to be removed from the hosts!" loop: "{{ lookup('dict', hosts) }}" # ***************************************************************** # *** Create host definitions and validate host object creation *** # ***************************************************************** - name: Define hosts netapp_e_host: <<: *creds state: present host_type: "{{ item.value.host_type }}" ports: "{{ item.value.ports }}" name: "{{ item.key }}" with_dict: *hosts # Retrieve array host definitions - name: https request to validate host definitions were created uri: url: "{{ credentials.api_url }}/storage-systems/{{ credentials.ssid }}/hosts" user: "{{ credentials.api_username }}" password: "{{ credentials.api_password }}" body_format: json validate_certs: no register: result # Verify hosts were indeed created - name: Collect host label list set_fact: hosts_labels: "{{ result | json_query('json[*].label') }}" - name: Validate hosts were in fact created assert: that: "'{{ item.key }}' in hosts_labels" msg: "host, {{ item.key }}, not define on array!" loop: "{{ lookup('dict', hosts) }}" # *** Update with no state changes results in no changes *** - name: Redefine hosts, expecting no changes netapp_e_host: <<: *creds state: present host_type: "{{ item.value.host_type }}" ports: "{{ item.value.ports }}" name: "{{ item.key }}" with_dict: *hosts register: result # Verify that no changes occurred - name: Ensure no change occurred assert: msg: "A change was not detected!" that: "not result.changed" # *********************************************************************************** # *** Redefine hosts using ports2 host definitions and validate the updated state *** # *********************************************************************************** - name: Redefine hosts, expecting changes netapp_e_host: <<: *creds state: present host_type: "{{ item.value.host_type }}" ports: "{{ item.value.ports2 }}" name: "{{ item.key }}" force_port: yes with_dict: *hosts register: result # Request from the array all host definitions - name: HTTP request for port information uri: url: "{{ credentials.api_url }}/storage-systems/{{ credentials.ssid }}/hosts" user: "{{ credentials.api_username }}" password: "{{ credentials.api_password }}" body_format: json validate_certs: no register: result # Compile a list of array host port information for verifying changes - name: Compile array host port information list set_fact: tmp: [] # Append each loop to the previous extraction. Each loop consists of host definitions and the filters will perform # the following: grab host side port lists; combine to each list a dictionary containing the host name(label); # lastly, convert the zip_longest object into a list - set_fact: tmp: "{{ tmp }} + {{ [item | json_query('hostSidePorts[*]')] | zip_longest([], fillvalue={'host_name': item.label}) | list }}" loop: "{{ result.json }}" # Make new list, port_info, by combining each list entry's dictionaries into a single dictionary - name: Create port information list set_fact: port_info: [] - set_fact: port_info: "{{ port_info }} + [{{ item[0] |combine(item[1]) }}]" loop: "{{ tmp }}" # Compile list of expected host port information for verifying changes - name: Create expected port information list set_fact: tmp: [] # Append each loop to the previous extraction. Each loop consists of host definitions and the filters will perform # the following: grab host side port lists; combine to each list a dictionary containing the host name(label); # lastly, convert the zip_longest object into a list - set_fact: tmp: "{{ tmp }} + {{ [item | json_query('value.ports2[*]')]| zip_longest([], fillvalue={'host_name': item.key|string}) | list }}" loop: "{{ lookup('dict', hosts) }}" # Make new list, expected_port_info, by combining each list entry's dictionaries into a single dictionary - name: Create expected port information list set_fact: expected_port_info: [] - set_fact: expected_port_info: "{{ expected_port_info }} + [{{ item[0] |combine(item[1]) }}]" loop: "{{ tmp }}" # Verify that each host object has the expected protocol type and address/port - name: Assert hosts information was updated with new port information assert: that: "{{ item[0].host_name != item[1].host_name or item[0].label != item[1].label or (item[0].type == item[1].type and (item[0].address|regex_replace(':','')) == (item[1].port|regex_replace(':',''))) }}" msg: "port failed to be updated!" loop: "{{ query('nested', port_info, expected_port_info) }}" # **************************************************** # *** Remove any existing hosts and verify changes *** # **************************************************** - name: Remove any existing hosts netapp_e_host: <<: *creds state: absent name: "{{ item.key }}" with_dict: *hosts # Request all host object definitions - name: HTTP request for all host definitions from array uri: url: "{{ credentials.api_url }}/storage-systems/{{ credentials.ssid }}/hosts" user: "{{ credentials.api_username }}" password: "{{ credentials.api_password }}" body_format: json validate_certs: no register: results # Collect port label information - name: Collect host side port labels set_fact: host_side_port_labels: "{{ results | json_query('json[*].hostSidePorts[*].label') }}" - name: Collect removed port labels set_fact: removed_host_side_port_labels: "{{ hosts | json_query('*.ports[*].label') }}" # Verify host 1 and 2 objects were removed - name: Assert hosts were removed assert: that: item not in host_side_port_labels msg: "Host {{ item }} failed to be removed from the hosts!" loop: "{{ removed_host_side_port_labels }}"