From d61df0a9baf1f731d48a4950cd51e79f34573b0f Mon Sep 17 00:00:00 2001 From: Nathan Swartz Date: Fri, 9 Aug 2019 07:25:38 -0500 Subject: [PATCH] Lun mapping upstream dev (#57096) * Fix hosts with same lun number conflict in netapp_e_lun_mapping. This patch fixes an issue of when multiple hosts are created and then subsequently volume(s) are mapped to them using the same specified number. * Fix netapp_e_host module bug when lun=0 * Add thin-volumes to the netapp_e_lun_mapping update_mapping_info method. --- .../storage/netapp/netapp_e_lun_mapping.py | 10 +- .../netapp_eseries_lun_mapping/aliases | 10 + .../netapp_eseries_lun_mapping/tasks/main.yml | 1 + .../netapp_eseries_lun_mapping/tasks/run.yml | 326 ++++++++++++++++++ 4 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 test/integration/targets/netapp_eseries_lun_mapping/aliases create mode 100644 test/integration/targets/netapp_eseries_lun_mapping/tasks/main.yml create mode 100644 test/integration/targets/netapp_eseries_lun_mapping/tasks/run.yml diff --git a/lib/ansible/modules/storage/netapp/netapp_e_lun_mapping.py b/lib/ansible/modules/storage/netapp/netapp_e_lun_mapping.py index 576718a4420..643a79710a5 100644 --- a/lib/ansible/modules/storage/netapp/netapp_e_lun_mapping.py +++ b/lib/ansible/modules/storage/netapp/netapp_e_lun_mapping.py @@ -174,6 +174,11 @@ class LunMapping(object): volume_name.update({volume["name"]: volume["volumeRef"]}) if volume["listOfMappings"]: lun_name.update({volume["name"]: volume["listOfMappings"][0]["lun"]}) + for volume in response["highLevelVolBundle"]["thinVolume"]: + volume_reference.update({volume["volumeRef"]: volume["name"]}) + volume_name.update({volume["name"]: volume["volumeRef"]}) + if volume["listOfMappings"]: + lun_name.update({volume["name"]: volume["listOfMappings"][0]["lun"]}) # Build current mapping object self.mapping_info = dict(lun_mapping=[dict(volume_reference=mapping["volumeRef"], @@ -202,9 +207,10 @@ class LunMapping(object): # Verify that when a lun is specified that it does not match an existing lun value unless it is associated with # the specified volume (ie for an update) if self.lun and any((self.lun == lun_mapping["lun"] and + self.target == self.mapping_info["target_by_reference"][lun_mapping["map_reference"]] and self.volume != self.mapping_info["volume_by_reference"][lun_mapping["volume_reference"]] ) for lun_mapping in self.mapping_info["lun_mapping"]): - self.module.fail_json(msg="Option lun value is already in use! Id [%s]." % self.ssid) + self.module.fail_json(msg="Option lun value is already in use for target! Array Id [%s]." % self.ssid) # Verify that when target_type is specified then it matches the target's actually type if self.target and self.target_type and self.target in self.mapping_info["target_type_by_name"].keys() and \ @@ -246,7 +252,7 @@ class LunMapping(object): target = None if not self.target else self.mapping_info["target_by_name"][self.target] if target: body.update(dict(targetId=target)) - if self.lun: + if self.lun is not None: body.update(dict(lun=self.lun)) if lun_reference: diff --git a/test/integration/targets/netapp_eseries_lun_mapping/aliases b/test/integration/targets/netapp_eseries_lun_mapping/aliases new file mode 100644 index 00000000000..ef22d27e9ca --- /dev/null +++ b/test/integration/targets/netapp_eseries_lun_mapping/aliases @@ -0,0 +1,10 @@ +# This test is not enabled by default, but can be utilized by defining required variables in integration_config.yml +# Example integration_config.yml: +# --- +#netapp_e_api_host: 192.168.1.100 +#netapp_e_api_username: admin +#netapp_e_api_password: myPass +#netapp_e_ssid: 1 + +unsupported +netapp/eseries diff --git a/test/integration/targets/netapp_eseries_lun_mapping/tasks/main.yml b/test/integration/targets/netapp_eseries_lun_mapping/tasks/main.yml new file mode 100644 index 00000000000..996354c8860 --- /dev/null +++ b/test/integration/targets/netapp_eseries_lun_mapping/tasks/main.yml @@ -0,0 +1 @@ +- include_tasks: run.yml diff --git a/test/integration/targets/netapp_eseries_lun_mapping/tasks/run.yml b/test/integration/targets/netapp_eseries_lun_mapping/tasks/run.yml new file mode 100644 index 00000000000..a702e3caa03 --- /dev/null +++ b/test/integration/targets/netapp_eseries_lun_mapping/tasks/run.yml @@ -0,0 +1,326 @@ +# Test code for the netapp_e_iscsi_interface 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 ASUP 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: + 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 + +- name: set credentials + set_fact: + credentials: *creds +# **************************************************** +# *** Setup test hosts, storage pools, and volumes *** +# **************************************************** +- name: Create host for host mapping + netapp_e_host: + <<: *creds + state: present + name: test_host_mapping_host + host_type: 27 +- netapp_e_host: + <<: *creds + state: present + name: test_host1 + host_type: 27 +- netapp_e_host: + <<: *creds + state: present + name: test_host2 + host_type: 27 +- name: Create storage pool for host mapping + netapp_e_storagepool: + <<: *creds + state: present + name: test_host_mapping_storage_pool + raid_level: raid0 + criteria_min_usable_capacity: 1 +- name: Create volume for host mapping + netapp_e_volume: + <<: *creds + state: present + name: test_host_mapping_volume + storage_pool_name: test_host_mapping_storage_pool + size: 1 +- name: Create volume for host mapping + netapp_e_volume: + <<: *creds + state: present + name: test_host_mapping_volume2 + storage_pool_name: test_host_mapping_storage_pool + size: 1 + +# ********************************************** +# *** Create new lun between host and volume *** +# ********************************************** +- name: Create netapp_e_lun_mapping + netapp_e_lun_mapping: + <<: *creds + state: present + target: test_host_mapping_host + volume: test_host_mapping_volume + register: result + +- name: Verify lun mapping + uri: + url: "{{ credentials.api_url }}/storage-systems/{{ netapp_e_ssid }}/graph/xpath-filter?query=//volume[name='test_host_mapping_volume']" + user: "{{ credentials.api_username }}" + password: "{{ credentials.api_password }}" + body_format: json + validate_certs: no + register: current + +- assert: + that: "{{ item['mapped'] }}" + msg: "Lun failed to be created." + loop: "{{ lookup('list', current.json)}}" + +# QUICK VERIFICATION OF MISMATCHING TARGET/TARGET_TYPE - GOOD +#- name: Create netapp_e_lun_mapping +# netapp_e_lun_mapping: +# <<: *creds +# state: present +# target: test_host_mapping_host +# volume: test_host_mapping_volume +# lun: 100 +# target_type: group +# register: result +# +#- pause: seconds=30 +# ************************************************************** +# *** Repeat previous lun creation play and verify unchanged *** +# ************************************************************** +- name: Repeat lun creation + netapp_e_lun_mapping: + <<: *creds + state: present + target: test_host_mapping_host + volume: test_host_mapping_volume + register: result + +- name: Verify lun mapping + uri: + url: "{{ credentials.api_url }}/storage-systems/{{ netapp_e_ssid }}/graph/xpath-filter?query=//volume[name='test_host_mapping_volume']" + user: "{{ credentials.api_username }}" + password: "{{ credentials.api_password }}" + body_format: json + validate_certs: no + register: current + +- assert: + that: "{{ item['mapped'] and result.changed==False }}" + msg: "Lun failed to be unchanged." + loop: "{{ lookup('list', current.json)}}" + +# **************************************************************** +# *** Move existing lun to default target and verify unchanged *** +# **************************************************************** +- name: Move lun to default target + netapp_e_lun_mapping: + <<: *creds + state: present + volume: test_host_mapping_volume + register: result + +- name: Verify lun mapping + uri: + url: "{{ credentials.api_url }}/storage-systems/{{ netapp_e_ssid }}/graph/xpath-filter?query=//volume[name='test_host_mapping_volume']" + user: "{{ credentials.api_username }}" + password: "{{ credentials.api_password }}" + body_format: json + validate_certs: no + register: current + +- assert: + that: "{{ item['mapped'] }}" + msg: "Lun failed to be created." + loop: "{{ lookup('list', current.json)}}" + +# ***************************************************************** +# *** Move existing lun to specific target and verify unchanged *** +# ***************************************************************** +- name: Move lun to default target + netapp_e_lun_mapping: + <<: *creds + state: present + target: test_host_mapping_host + volume: test_host_mapping_volume + register: result + +- name: Verify lun mapping + uri: + url: "{{ credentials.api_url }}/storage-systems/{{ netapp_e_ssid }}/graph/xpath-filter?query=//volume[name='test_host_mapping_volume']" + user: "{{ credentials.api_username }}" + password: "{{ credentials.api_password }}" + body_format: json + validate_certs: no + register: current + +- assert: + that: "{{ item['mapped'] }}" + msg: "Lun failed to be created." + loop: "{{ lookup('list', current.json)}}" + +# ******************************************* +# *** Modify a volume mapping's lun value *** +# ******************************************* +- name: Change volume mapping's lun value + netapp_e_lun_mapping: + <<: *creds + state: present + target: test_host_mapping_host + volume: test_host_mapping_volume + lun: 100 + register: result + +- pause: seconds=15 + +- name: Verify lun mapping + uri: + url: "{{ credentials.api_url }}/storage-systems/{{ netapp_e_ssid }}/graph/xpath-filter?query=//volume[name='test_host_mapping_volume']" + user: "{{ credentials.api_username }}" + password: "{{ credentials.api_password }}" + body_format: json + validate_certs: no + register: current + +- assert: + that: "{{ result.changed }}" + msg: "Lun failed to be unchanged." + loop: "{{ lookup('list', current.json)}}" + +- name: Verify mapping fails when lun already in use on existing host object + netapp_e_lun_mapping: + <<: *creds + state: present + target: test_host_mapping_host + volume: test_host_mapping_volume2 + lun: 100 + register: result + ignore_errors: True + +- pause: seconds=15 + +- assert: + that: "{{ not result.changed }}" + msg: "Lun succeeded when it should have failed." + loop: "{{ lookup('list', current.json)}}" + +- name: Verify mapping succeeds when the same lun is used on multiple host objects. + netapp_e_lun_mapping: + <<: *creds + state: present + target: test_host1 + volume: test_host_mapping_volume2 + lun: 100 + register: result + +- pause: seconds=15 + +- assert: + that: "{{ result.changed }}" + msg: "Lun failed to be unchanged." + loop: "{{ lookup('list', current.json)}}" + +# ************************************************************************************************* +# *** Verify that exact mapping details but different lun results in an unchanged configuration *** +# ************************************************************************************************* +- name: Verify that exact mapping details but different lun results in an unchanged configuration + netapp_e_lun_mapping: + <<: *creds + state: absent + target: test_host_mapping_host + volume: test_host_mapping_volume + lun: 99 + register: result + +- name: Verify lun mapping + uri: + url: "{{ credentials.api_url }}/storage-systems/{{ netapp_e_ssid }}/graph/xpath-filter?query=//volume[name='test_host_mapping_volume']" + user: "{{ credentials.api_username }}" + password: "{{ credentials.api_password }}" + body_format: json + validate_certs: no + register: current + +- assert: + that: "{{ item['mapped'] and not result.changed }}" + msg: "Lun failed to be unchanged." + loop: "{{ lookup('list', current.json)}}" + +# ******************************** +# *** Delete newly created lun *** +# ******************************** +- name: Delete lun creation + netapp_e_lun_mapping: + <<: *creds + state: absent + target: test_host_mapping_host + volume: test_host_mapping_volume + register: result + +- name: Verify lun mapping + uri: + url: "{{ credentials.api_url }}/storage-systems/{{ netapp_e_ssid }}/graph/xpath-filter?query=//volume[name='test_host_mapping_volume']" + user: "{{ credentials.api_username }}" + password: "{{ credentials.api_password }}" + body_format: json + validate_certs: no + register: current + +- assert: + that: "{{ not item['mapped'] }}" + msg: "Lun failed to be created." + loop: "{{ lookup('list', current.json)}}" + +# ******************************************************** +# *** Tear down test hosts, storage pools, and volumes *** +# ******************************************************** +- name: Delete volume for host mapping + netapp_e_volume: + <<: *creds + state: absent + name: test_host_mapping_volume + storage_pool_name: test_host_mapping_storage_pool + size: 1 +- name: Delete volume for host mapping + netapp_e_volume: + <<: *creds + state: absent + name: test_host_mapping_volume2 + storage_pool_name: test_host_mapping_storage_pool + size: 1 +- name: Delete storage pool for host mapping + netapp_e_storagepool: + <<: *creds + state: absent + name: test_host_mapping_storage_pool + raid_level: raid0 + criteria_min_usable_capacity: 1 +- name: Delete host for host mapping + netapp_e_host: + <<: *creds + state: absent + name: test_host_mapping_host + host_type_index: 27 +- name: Delete host for host mapping + netapp_e_host: + <<: *creds + state: absent + name: test_host2 + host_type_index: 27 +- name: Delete host for host mapping + netapp_e_host: + <<: *creds + state: absent + name: test_host1 + host_type_index: 27 \ No newline at end of file