ansible/test/integration/targets/netapp_eseries_host/tasks/run.yml
Michael Price ad91793428 Resolve issues in NetApp E-Series Host module (#39748)
* Resolve issues in NetApp E-Series Host module

The E-Series host module had some bugs relating to the update/creation
of host definitions when iSCSI initiators when included in the
configuration. This patch resolves this and other minor issues with
correctly detecting updates.

There were also several minor issues found that were causing issues with
truly idepotent updates/changes to the host definition.

This patch also provides some unit tests and integration tests to help
catch future issues in these areas.

fixes #28272

* Improve NetApp E-Series Host module testing

The NetApp E-Series Host module integration test lacked feature test
verification to verify the changes made to the storage array.

The NetApp E-Series rest api was used to verify host create, update, and
remove changes made to the NetApp E-Series storage arrays.
2018-08-24 15:44:59 +01:00

276 lines
9.3 KiB
YAML

---
# 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 }}"