diff --git a/lib/ansible/modules/storage/netapp/na_elementsw_access_group.py b/lib/ansible/modules/storage/netapp/na_elementsw_access_group.py index 21982f0b23f..e5d12f6e443 100644 --- a/lib/ansible/modules/storage/netapp/na_elementsw_access_group.py +++ b/lib/ansible/modules/storage/netapp/na_elementsw_access_group.py @@ -37,24 +37,35 @@ options: required: true choices: ['present', 'absent'] - src_access_group_id: + from_name: description: - - ID or Name of the access group to modify or delete. - - Required for delete and modify operations. + - ID or Name of the access group to rename. + - Required to create a new access group called 'name' by renaming 'from_name'. + version_added: '2.8' - new_name: + name: description: - - New name for the access group for create and modify operation. - - Required for create operation. + - Name for the access group for create, modify and delete operations. + required: True + aliases: + - src_access_group_id initiators: description: - List of initiators to include in the access group. If unspecified, the access group will start out without configured initiators. - required: false volumes: description: - List of volumes to initially include in the volume access group. If unspecified, the access group will start without any volumes. + - It accepts either volume_name or volume_id + + account_id: + description: + - Account ID for the owner of this volume. + - It accepts either account_name or account_id + - if account_id is digit, it will consider as account_id + - If account_id is string, it will consider as account_name + version_added: '2.8' virtual_network_id: description: @@ -76,8 +87,9 @@ EXAMPLES = """ username: "{{ elementsw_username }}" password: "{{ elementsw_password }}" state: present - new_name: AnsibleAccessGroup + name: AnsibleAccessGroup volumes: [7,8] + account_id: 1 - name: Modify Access Group na_elementsw_access_group: @@ -85,17 +97,26 @@ EXAMPLES = """ username: "{{ elementsw_username }}" password: "{{ elementsw_password }}" state: present - src_access_group_id: AnsibleAccessGroup - new_name: AnsibleAccessGroup-Renamed + name: AnsibleAccessGroup-Renamed + account_id: 1 attributes: {"volumes": [1,2,3], "virtual_network_id": 12345} + - name: Rename Access Group + na_elementsw_access_group: + hostname: "{{ elementsw_hostname }}" + username: "{{ elementsw_username }}" + password: "{{ elementsw_password }}" + state: present + from_name: AnsibleAccessGroup + name: AnsibleAccessGroup-Renamed + - name: Delete Access Group na_elementsw_access_group: hostname: "{{ elementsw_hostname }}" username: "{{ elementsw_username }}" password: "{{ elementsw_password }}" state: absent - src_access_group_id: 1 + name: 1 """ @@ -127,10 +148,11 @@ class ElementSWAccessGroup(object): self.argument_spec = netapp_utils.ontap_sf_host_argument_spec() self.argument_spec.update(dict( state=dict(required=True, choices=['present', 'absent']), - src_access_group_id=dict(required=False, type='str'), - new_name=dict(required=False, type='str'), + from_name=dict(required=False, type='str'), + name=dict(required=True, aliases=["src_access_group_id"], type='str'), initiators=dict(required=False, type='list'), volumes=dict(required=False, type='list'), + account_id=dict(required=False, type='str'), virtual_network_id=dict(required=False, type='list'), virtual_network_tags=dict(required=False, type='list'), attributes=dict(required=False, type='dict'), @@ -138,6 +160,9 @@ class ElementSWAccessGroup(object): self.module = AnsibleModule( argument_spec=self.argument_spec, + required_if=[ + ('state', 'present', ['account_id']) + ], supports_check_mode=True ) @@ -145,20 +170,15 @@ class ElementSWAccessGroup(object): # Set up state variables self.state = input_params['state'] - self.src_access_group_id = input_params['src_access_group_id'] - self.new_name = input_params['new_name'] + self.from_name = input_params['from_name'] + self.access_group_name = input_params['name'] self.initiators = input_params['initiators'] self.volumes = input_params['volumes'] + self.account_id = input_params['account_id'] self.virtual_network_id = input_params['virtual_network_id'] self.virtual_network_tags = input_params['virtual_network_tags'] self.attributes = input_params['attributes'] - if self.state == "absent" and self.src_access_group_id is None: - self.module.fail_json(msg="For delete operation, src_access_group_id parameter is required") - - if self.state == 'present' and self.new_name is None and self.src_access_group_id is None: - self.module.fail_json(msg="new_name parameter or src_access_group is required parameter") - if HAS_SF_SDK is False: self.module.fail_json(msg="Unable to import the SolidFire Python SDK") else: @@ -172,40 +192,53 @@ class ElementSWAccessGroup(object): else: self.attributes = self.elementsw_helper.set_element_attributes(source='na_elementsw_access_group') - def get_access_group(self): + def get_access_group(self, name): """ Get Access Group - :description: Get Access Group object for a given src_access_group_id + :description: Get Access Group object for a given name :return: object (Group object) :rtype: object (Group object) """ access_groups_list = self.sfe.list_volume_access_groups() - self.new_name_exists = False group_obj = None for group in access_groups_list.volume_access_groups: - # Check and get access_group object for a given src_access_group_id - if self.src_access_group_id is not None and group_obj is None: - if str(group.volume_access_group_id) == self.src_access_group_id: - group_obj = group - elif group.name == self.src_access_group_id: - self.src_access_group_id = group.volume_access_group_id - group_obj = group - # Check if new_name exists on the list - if group_obj is not None and self.new_name is None: - return group_obj - elif group.name == self.new_name: - self.new_name_exists = True - return group_obj + # Check and get access_group object for a given name + if str(group.volume_access_group_id) == name: + group_obj = group + elif group.name == name: + group_obj = group + return group_obj + def get_account_id(self): + # Validate account id + # Return account_id if found, None otherwise + try: + account_id = self.elementsw_helper.account_exists(self.account_id) + return account_id + except Exception: + return None + + def get_volume_id(self): + # Validate volume_ids + # Return volume ids if found, fail if not found + volume_ids = [] + for volume in self.volumes: + volume_id = self.elementsw_helper.volume_exists(volume, self.account_id) + if volume_id: + volume_ids.append(volume_id) + else: + self.module.fail_json(msg='Specified volume %s does not exist' % volume) + return volume_ids + def create_access_group(self): """ Create the Access Group """ try: - self.sfe.create_volume_access_group(name=self.new_name, + self.sfe.create_volume_access_group(name=self.access_group_name, initiators=self.initiators, volumes=self.volumes, virtual_network_id=self.virtual_network_id, @@ -213,76 +246,112 @@ class ElementSWAccessGroup(object): attributes=self.attributes) except Exception as e: self.module.fail_json(msg="Error creating volume access group %s: %s" % - (self.name, to_native(e)), exception=traceback.format_exc()) + (self.access_group_name, to_native(e)), exception=traceback.format_exc()) def delete_access_group(self): """ Delete the Access Group """ try: - self.sfe.delete_volume_access_group(volume_access_group_id=self.src_access_group_id) + self.sfe.delete_volume_access_group(volume_access_group_id=self.group_id) except Exception as e: self.module.fail_json(msg="Error deleting volume access group %s: %s" % - (self.src_access_group_id, to_native(e)), + (self.access_group_name, to_native(e)), exception=traceback.format_exc()) def update_access_group(self): """ - Update the Access Group + Update the Access Group if the access_group already exists """ try: - self.sfe.modify_volume_access_group(volume_access_group_id=self.src_access_group_id, + self.sfe.modify_volume_access_group(volume_access_group_id=self.group_id, virtual_network_id=self.virtual_network_id, virtual_network_tags=self.virtual_network_tags, - name=self.new_name, initiators=self.initiators, volumes=self.volumes, attributes=self.attributes) except Exception as e: self.module.fail_json(msg="Error updating volume access group %s: %s" % - (self.src_access_group_id, to_native(e)), exception=traceback.format_exc()) + (self.access_group_name, to_native(e)), exception=traceback.format_exc()) + + def rename_access_group(self): + """ + Rename the Access Group to the new name + """ + try: + self.sfe.modify_volume_access_group(volume_access_group_id=self.from_group_id, + virtual_network_id=self.virtual_network_id, + virtual_network_tags=self.virtual_network_tags, + name=self.access_group_name, + initiators=self.initiators, + volumes=self.volumes, + attributes=self.attributes) + except Exception as e: + self.module.fail_json(msg="Error updating volume access group %s: %s" % + (self.from_name, to_native(e)), exception=traceback.format_exc()) def apply(self): """ Process the access group operation on the Element Software Cluster """ changed = False - group_exists = False update_group = False - group_detail = self.get_access_group() - if self.module.check_mode is False and group_detail is not None: - group_exists = True + if self.account_id is not None: + self.account_id_valid = self.get_account_id() + + if self.state == 'present' and self.volumes is not None: + if self.account_id_valid: + self.volumes = self.get_volume_id() + else: + self.module.fail_json(msg='Error: Specified account id %s does not exist ' % self.account_id) + + group_detail = self.get_access_group(self.access_group_name) + + if group_detail is not None: + # If access group found + self.group_id = group_detail.volume_access_group_id if self.state == "absent": self.delete_access_group() changed = True else: - # Check if we need to update the group - if self.new_name is not None and self.new_name_exists is False: - update_group = True - changed = True - - elif self.volumes is not None and group_detail.volumes != self.volumes: - update_group = True - changed = True + # If state - present, check for any parameter of exising group needs modification. + if self.volumes is not None and len(self.volumes) > 0: + # Compare the volume list + for volumeID in group_detail.volumes: + if volumeID not in self.volumes: + update_group = True + changed = True elif self.initiators is not None and group_detail.initiators != self.initiators: update_group = True changed = True - elif self.virtual_network_id is not None or self.virtual_network_tags is not None or \ - self.attributes is not None: + elif self.virtual_network_id is not None or self.virtual_network_tags is not None: update_group = True changed = True if update_group: self.update_access_group() - elif self.module.check_mode is False and self.new_name_exists is False and self.new_name is not None and self.state == 'present': - self.create_access_group() - changed = True + else: + # access_group does not exist + if self.state == "present" and self.from_name is not None: + group_detail = self.get_access_group(self.from_name) + if group_detail is not None: + # If resource pointed by from_name exists, rename the access_group to name + self.from_group_id = group_detail.volume_access_group_id + self.rename_access_group() + changed = True + else: + # If resource pointed by from_name does not exists, error out + self.module.fail_json(msg="Resource does not exist : %s" % self.from_name) + elif self.state == "present": + # If from_name is not defined, Create from scratch. + self.create_access_group() + changed = True self.module.exit_json(changed=changed)