ad91793428
* 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.
276 lines
9.3 KiB
YAML
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 }}"
|