diff --git a/ansible_collection/hpe/nimble/plugins/module_utils/hpe_nimble.py b/ansible_collection/hpe/nimble/plugins/module_utils/hpe_nimble.py index f140f2b..64fa35f 100644 --- a/ansible_collection/hpe/nimble/plugins/module_utils/hpe_nimble.py +++ b/ansible_collection/hpe/nimble/plugins/module_utils/hpe_nimble.py @@ -128,8 +128,7 @@ def remove_unchanged_or_null_args(server_resp, **kwargs): if len(value) == 0: # don't add empty list for update continue - else: - changed_attrs_dict[key] = value + changed_attrs_dict[key] = value elif server_value != value: # This is a special key used to force any operation for object. # So, that is never updated as a server attribute. @@ -306,3 +305,26 @@ def get_initiator_group_id(client_obj, ig_name): if resp is None: raise Exception(f"Invalid value for initiator group {ig_name}") return resp.attrs.get("id") + + +def is_array_version_above_or_equal(array_obj_client, arr_version_to_check): + if arr_version_to_check is None: + return False + resp = array_obj_client.get() + if resp is None: + return False + array_version = resp.attrs.get("version") + if array_version is None: + return False + + temp = array_version.split('-') + array_version = temp[0] + arr_version = array_version.split('.') + version_to_check = arr_version_to_check.split('.') + if arr_version[0] > version_to_check[0]: + return True + elif arr_version[0] >= version_to_check[0] and arr_version[1] >= version_to_check[1]: + return True + elif arr_version[0] >= version_to_check[0] and arr_version[1] >= version_to_check[1] and arr_version[2] >= version_to_check[2]: + return True + return False diff --git a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_fc.py b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_fc.py index 66334b2..8d76a71 100644 --- a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_fc.py +++ b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_fc.py @@ -133,18 +133,18 @@ def update_fc_interface( online): if utils.is_null_or_empty(array_name_or_serial): - return (False, False, "Fibre channel interface update failed as no array name is provided.", {}) + return (False, False, "Fibre channel interface update failed as no array name is provided.", {}, {}) if utils.is_null_or_empty(fc_name): - return (False, False, "Fibre channel interface update failed as no interface name is provided.", {}) + return (False, False, "Fibre channel interface update failed as no interface name is provided.", {}, {}) if utils.is_null_or_empty(controller): - return (False, False, "Fibre channel interface update failed as no controller name is provided.", {}) + return (False, False, "Fibre channel interface update failed as no controller name is provided.", {}, {}) if utils.is_null_or_empty(online): - return (False, False, "Fibre channel interface update failed as online flag is not provided.", {}) + return (False, False, "Fibre channel interface update failed as online flag is not provided.", {}, {}) try: # get the details of the fc fc_resp = client_obj.fibre_channel_interfaces.list(detail=True, array_name_or_serial=array_name_or_serial) if fc_resp is None: - return (False, False, f"No fibre channel is present for array '{array_name_or_serial}'.", {}) + return (False, False, f"No fibre channel is present for array '{array_name_or_serial}'.", {}, {}) else: fc_result = None for fc_interface_obj in fc_resp: @@ -155,11 +155,15 @@ def update_fc_interface( changed_attrs_dict, params = utils.remove_unchanged_or_null_args(fc_result, online=online) if changed_attrs_dict.__len__() > 0: fc_result = client_obj.fibre_channel_interfaces.update(id=fc_result.attrs.get("id"), online=online) - return (True, True, f"Updated fibre channel interface '{fc_result.attrs.get('name')}'.", {}) + if hasattr(fc_result, 'attrs'): + fc_result = fc_result.attrs + return (True, True, "Updated fibre channel interface.", {}, fc_result) else: - return (True, False, f"Fibre channel interface '{fc_result.attrs.get('name')}' already in given state.", {}) + if hasattr(fc_result, 'attrs'): + fc_result = fc_result.attrs + return (True, False, "Fibre channel interface already in given state.", {}, fc_result) except Exception as ex: - return (False, False, f"Fibre channel update failed |'{ex}'", {}) + return (False, False, f"Fibre channel update failed |'{ex}'", {}, {}) def regenerate_wwn( @@ -169,20 +173,22 @@ def regenerate_wwn( precheck): if utils.is_null_or_empty(array_name_or_serial): - return (False, False, "Fibre channel config update failed as no array name is provided.", {}) + return (False, False, "Fibre channel config update failed as no array name is provided.", {}, {}) try: # get the details of the fc config fc_config_resp = client_obj.fibre_channel_configs.get(id=None, group_leader_array=array_name_or_serial) if fc_config_resp is None: - return (False, False, f"No fibre channel config is present for array '{array_name_or_serial}'.", {}) + return (False, False, f"No fibre channel config is present for array '{array_name_or_serial}'.", {}, {}) else: changed_attrs_dict = {} fc_config_resp = client_obj.fibre_channel_configs.regenerate(fc_config_resp.attrs.get("id"), precheck, wwnn_base_str) + if hasattr(fc_config_resp, 'attrs'): + fc_config_resp = fc_config_resp.attrs changed_attrs_dict['wwnn_base_str'] = wwnn_base_str return (True, True, f"Updated fibre channel config for group leader array '{array_name_or_serial}'." - "Modified the following fields :", changed_attrs_dict) + f"Modified the following fields '{changed_attrs_dict}'.", changed_attrs_dict, fc_config_resp) except Exception as ex: - return (False, False, f"Fibre channel config update failed |'{ex}'", {}) + return (False, False, f"Fibre channel config update failed |'{ex}'", {}, {}) def upgrade_hardware( @@ -190,17 +196,19 @@ def upgrade_hardware( array_name_or_serial): if utils.is_null_or_empty(array_name_or_serial): - return (False, False, "Hardware update failed as no array name is provided.", {}) + return (False, False, "Hardware update failed as no array name is provided.", {}, {}) try: # get the details of the fc config fc_config_resp = client_obj.fibre_channel_configs.get(id=None, group_leader_array=array_name_or_serial) if fc_config_resp is None: - return (False, False, f"No fibre channel config is present for array '{array_name_or_serial}'.", {}) + return (False, False, f"No fibre channel config is present for array '{array_name_or_serial}'.", {}, {}) else: fc_config_resp = client_obj.fibre_channel_configs.hw_upgrade(fc_config_resp.attrs.get("id")) - return (True, True, f"Hardware update for group leader array '{array_name_or_serial}' done successfully", {}) + if hasattr(fc_config_resp, 'attrs'): + fc_config_resp = fc_config_resp.attrs + return (True, True, f"Hardware update for group leader array '{array_name_or_serial}' done successfully", {}, fc_config_resp) except Exception as ex: - return (False, False, f"Hardware update failed |'{ex}'", {}) + return (False, False, f"Hardware update failed |'{ex}'", {}, {}) def main(): @@ -278,6 +286,7 @@ def main(): # defaults return_status = changed = False msg = "No task to run." + resp = None try: client_obj = client.NimOSClient( hostname, @@ -288,19 +297,19 @@ def main(): # States if state == "present": if regenerate is True: - return_status, changed, msg, changed_attrs_dict = regenerate_wwn( + return_status, changed, msg, changed_attrs_dict, resp = regenerate_wwn( client_obj, array_name_or_serial, wwnn_base_str, precheck) elif hw_upgrade is True: - return_status, changed, msg, changed_attrs_dict = upgrade_hardware( + return_status, changed, msg, changed_attrs_dict, resp = upgrade_hardware( client_obj, array_name_or_serial) else: - return_status, changed, msg, changed_attrs_dict = update_fc_interface( + return_status, changed, msg, changed_attrs_dict, resp = update_fc_interface( client_obj, array_name_or_serial, fc_name, @@ -311,10 +320,10 @@ def main(): msg = str(ex) if return_status: - if not utils.is_null_or_empty(changed_attrs_dict) and changed_attrs_dict.__len__() > 0: - module.exit_json(return_status=return_status, changed=changed, message=msg, modified_attrs=changed_attrs_dict) - else: + if utils.is_null_or_empty(resp): module.exit_json(return_status=return_status, changed=changed, msg=msg) + else: + module.exit_json(return_status=return_status, changed=changed, msg=msg, attrs=resp) else: module.fail_json(return_status=return_status, changed=changed, msg=msg) diff --git a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_info.py b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_info.py index 017eb52..a548d13 100644 --- a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_info.py +++ b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_info.py @@ -714,7 +714,7 @@ def generate_dict(name, resp): def fetch_config_subset(info_subset): if info_subset is None: - return {} + return ({}, True) toreturn = {'config': {}} result = {} temp_dict = {} @@ -737,15 +737,12 @@ def fetch_config_subset(info_subset): syslogd_server, vvol_enabled, alarms_enabled, - auto_switchover_enabled, - failover_mode, member_list, encryption_config, name, fc_enabled, - iscsi_enabled, - leader_array_name, - default_iscsi_target_scope + iscsi_enabled + """ try: for key, cl_obj in info_subset.items(): @@ -766,7 +763,7 @@ def fetch_config_subset(info_subset): result['pools'] = generate_dict('pools', temp_dict['pools'])['pools'] result['network_configs'] = generate_dict('network_configs', temp_dict['network_configs'])['network_configs'] toreturn['config'] = result - return (toreturn) + return (toreturn, True) except Exception: raise @@ -774,7 +771,7 @@ def fetch_config_subset(info_subset): def fetch_minimum_subset(info_subset): if info_subset is None: - return {} + return ({}, True) minimum_subset = [ "arrays", "disks", @@ -802,8 +799,12 @@ def fetch_minimum_subset(info_subset): if key == 'arrays': resp = cl_obj.list(detail=True, fields="extended_model,full_name,all_flash") elif key == 'groups': - resp = cl_obj.list(detail=True, - fields="encryption_config,name,fc_enabled,iscsi_enabled,leader_array_name,default_iscsi_target_scope,num_snaps") + # certain fields were only added in NimOS 5.1 and above + if utils.is_array_version_above_or_equal(info_subset['arrays'], "5.1"): + resp = cl_obj.list(detail=True, + fields="encryption_config,name,fc_enabled,iscsi_enabled,leader_array_name,default_iscsi_target_scope,num_snaps") + else: + resp = cl_obj.list(detail=True, fields="name") else: resp = cl_obj.list(detail=False) temp_dict[key] = resp @@ -824,11 +825,11 @@ def fetch_minimum_subset(info_subset): result['arrays'] = generate_dict('arrays', temp_dict['arrays'])['arrays'] result['groups'] = generate_dict('groups', temp_dict['groups'])['groups'] toreturn['default'] = result - return (toreturn) + return (toreturn, True) except Exception as ex: result['failed'] = str(ex) toreturn['default'] = result - return (toreturn) + return (toreturn, False) # snapshots actually needs a vol_name/vol_id as mandatory params. Hence ,in case of 'all' subset # where user cannot provide a query option. we need to fetch the snapshots by iterating @@ -866,15 +867,22 @@ def fetch_subset(valid_subset_list, info_subset): result = {} try: if subset['name'] == "minimum": - result = fetch_minimum_subset(info_subset) + result, flag = fetch_minimum_subset(info_subset) + if flag is False: + raise Exception(result) elif subset['name'] == "config": - result = fetch_config_subset(info_subset) + result, flag = fetch_config_subset(info_subset) + if flag is False: + raise Exception(result) elif subset['name'] == "all": result = fetch_snapshots_for_all_subset(subset, info_subset['all']) for key, value in result.items(): result_dict[key] = value continue else: + # if subset is user_policies then make sure nimos aversion is fiji and above + if subset['name'] == 'user_policies' and utils.is_array_version_above_or_equal(info_subset['arrays'], "5.1.0") is False: + continue cl_obj_set = info_subset[subset['name']] query = subset['query'] if query is not None: diff --git a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot.py b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot.py index 5e53ff9..fe8a33f 100644 --- a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot.py +++ b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot.py @@ -62,7 +62,6 @@ force: required: False type: bool - default: False description: - Forcibly delete the specified snapshot even if it is the last replicated collection. Doing so could lead to full re-seeding at the next replication. metadata: @@ -279,7 +278,6 @@ def main(): "force": { "required": False, "type": "bool", - "default": False, "no_log": False } } diff --git a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot_collection.py b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot_collection.py index 95bd840..bd19ddf 100644 --- a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot_collection.py +++ b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_snapshot_collection.py @@ -64,7 +64,6 @@ force: required: False type: bool - default: False description: - Forcibly delete the specified snapshot collection even if it is the last replicated snapshot. Doing so could lead to full re-seeding at the next replication. @@ -327,7 +326,6 @@ def main(): "force": { "required": False, "type": "bool", - "default": False, "no_log": False } } diff --git a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_volume_collection.py b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_volume_collection.py index 18b60be..6fcbb38 100644 --- a/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_volume_collection.py +++ b/ansible_collection/hpe/nimble/plugins/modules/hpe_nimble_volume_collection.py @@ -658,13 +658,17 @@ def main(): replication_partner_id=utils.get_replication_partner_id(client_obj, replication_partner)) elif state == 'present' and handover is True: + replication_partner_id = utils.get_replication_partner_id(client_obj, replication_partner) + if utils.is_null_or_empty(replication_partner_id) is True: + module.fail_json(msg="Handover for volume collection failed. Please provide a valid replication partner.") + return_status, changed, msg, changed_attrs_dict = handover_volcoll( client_obj, volcoll_name, - invoke_on_upstream_partner, - no_reverse, - override_upstream_down, - replication_partner_id=utils.get_replication_partner_id(client_obj, replication_partner)) + invoke_on_upstream_partner=invoke_on_upstream_partner, + no_reverse=no_reverse, + override_upstream_down=override_upstream_down, + replication_partner_id=replication_partner_id) elif state == 'present' and abort_handover is True: return_status, changed, msg, changed_attrs_dict = abort_handover_volcoll(client_obj, volcoll_name)