summaryrefslogtreecommitdiffstats
path: root/ansible_collections/dellemc/unity/plugins/modules/snapshot.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/dellemc/unity/plugins/modules/snapshot.py
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/dellemc/unity/plugins/modules/snapshot.py')
-rw-r--r--ansible_collections/dellemc/unity/plugins/modules/snapshot.py751
1 files changed, 751 insertions, 0 deletions
diff --git a/ansible_collections/dellemc/unity/plugins/modules/snapshot.py b/ansible_collections/dellemc/unity/plugins/modules/snapshot.py
new file mode 100644
index 000000000..c8aba1846
--- /dev/null
+++ b/ansible_collections/dellemc/unity/plugins/modules/snapshot.py
@@ -0,0 +1,751 @@
+#!/usr/bin/python
+# Copyright: (c) 2020, Dell Technologies
+
+# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+""" Ansible module for managing Snapshots on Unity"""
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+---
+module: snapshot
+short_description: Manage snapshots on the Unity storage system
+description:
+- Managing snapshots on the Unity storage system includes create snapshot,
+ delete snapshot, update snapshot, get snapshot, map host and unmap host.
+version_added: '1.1.0'
+
+extends_documentation_fragment:
+ - dellemc.unity.unity
+
+author:
+- P Srinivas Rao (@srinivas-rao5) <ansible.team@dell.com>
+options:
+ snapshot_name:
+ description:
+ - The name of the snapshot.
+ - Mandatory parameter for creating a snapshot.
+ - For all other operations either I(snapshot_name) or I(snapshot_id) is
+ required.
+ type: str
+ vol_name:
+ description:
+ - The name of the volume for which snapshot is created.
+ - For creation of a snapshot either I(vol_name) or I(cg_name) is required.
+ - Not required for other operations.
+ type: str
+ cg_name:
+ description:
+ - The name of the Consistency Group for which snapshot is created.
+ - For creation of a snapshot either I(vol_name) or I(cg_name) is required.
+ - Not required for other operations.
+ type: str
+ snapshot_id:
+ description:
+ - The id of the snapshot.
+ - For all operations other than creation either I(snapshot_name) or
+ I(snapshot_id) is required.
+ type: str
+ auto_delete:
+ description:
+ - This option specifies whether the snapshot is auto deleted or not.
+ - If set to C(true), snapshot will expire based on the pool auto deletion
+ policy.
+ - If set to (false), snapshot will not be auto deleted
+ based on the pool auto deletion policy.
+ - Option I(auto_delete) can not be set to C(true), if I(expiry_time) is specified.
+ - If during creation neither I(auto_delete) nor I(expiry_time) is mentioned
+ then snapshot will be created keeping I(auto_delete) as C(true).
+ - Once the I(expiry_time) is set then snapshot cannot be assigned
+ to the auto delete policy.
+ type: bool
+ expiry_time:
+ description:
+ - This option is for specifying the date and time after which the
+ snapshot will expire.
+ - The time is to be mentioned in UTC timezone.
+ - The format is "MM/DD/YYYY HH:MM". Year must be in 4 digits.
+ type: str
+ description:
+ description:
+ - The additional information about the snapshot can be provided using
+ this option.
+ type: str
+ new_snapshot_name:
+ description:
+ - New name for the snapshot.
+ type: str
+ state:
+ description:
+ - The I(state) option is used to mention the existence of
+ the snapshot.
+ type: str
+ required: true
+ choices: [ 'absent', 'present' ]
+ host_name:
+ description:
+ - The name of the host.
+ - Either I(host_name) or I(host_id) is required to map or unmap a snapshot from
+ a host.
+ - Snapshot can be attached to multiple hosts.
+ type: str
+ host_id:
+ description:
+ - The id of the host.
+ - Either I(host_name) or I(host_id) is required to map or unmap a snapshot from
+ a host.
+ - Snapshot can be attached to multiple hosts.
+ type: str
+ host_state:
+ description:
+ - The I(host_state) option is used to mention the existence of the host
+ for snapshot.
+ - It is required when a snapshot is mapped or unmapped from host.
+ type: str
+ choices: ['mapped', 'unmapped']
+
+notes:
+ - The I(check_mode) is not supported.
+'''
+
+EXAMPLES = r'''
+ - name: Create a Snapshot for a CG
+ dellemc.unity.snapshot:
+ unispherehost: "{{unispherehost}}"
+ username: "{{username}}"
+ password: "{{password}}"
+ validate_certs: "{{validate_certs}}"
+ port: "{{port}}"
+ cg_name: "{{cg_name}}"
+ snapshot_name: "{{cg_snapshot_name}}"
+ description: "{{description}}"
+ auto_delete: False
+ state: "present"
+
+ - name: Create a Snapshot for a volume with Host attached
+ dellemc.unity.snapshot:
+ unispherehost: "{{unispherehost}}"
+ username: "{{username}}"
+ password: "{{password}}"
+ validate_certs: "{{validate_certs}}"
+ port: "{{port}}"
+ vol_name: "{{vol_name}}"
+ snapshot_name: "{{vol_snapshot_name}}"
+ description: "{{description}}"
+ expiry_time: "04/15/2025 16:30"
+ host_name: "{{host_name}}"
+ host_state: "mapped"
+ state: "present"
+
+ - name: Unmap a host for a Snapshot
+ dellemc.unity.snapshot:
+ unispherehost: "{{unispherehost}}"
+ username: "{{username}}"
+ password: "{{password}}"
+ validate_certs: "{{validate_certs}}"
+ port: "{{port}}"
+ snapshot_name: "{{vol_snapshot_name}}"
+ host_name: "{{host_name}}"
+ host_state: "unmapped"
+ state: "present"
+
+ - name: Map snapshot to a host
+ dellemc.unity.snapshot:
+ unispherehost: "{{unispherehost}}"
+ username: "{{username}}"
+ password: "{{password}}"
+ validate_certs: "{{validate_certs}}"
+ port: "{{port}}"
+ snapshot_name: "{{vol_snapshot_name}}"
+ host_name: "{{host_name}}"
+ host_state: "mapped"
+ state: "present"
+
+ - name: Update attributes of a Snapshot for a volume
+ dellemc.unity.snapshot:
+ unispherehost: "{{unispherehost}}"
+ username: "{{username}}"
+ password: "{{password}}"
+ validate_certs: "{{validate_certs}}"
+ snapshot_name: "{{vol_snapshot_name}}"
+ new_snapshot_name: "{{new_snapshot_name}}"
+ description: "{{new_description}}"
+ host_name: "{{host_name}}"
+ host_state: "unmapped"
+ state: "present"
+
+ - name: Delete Snapshot of CG
+ dellemc.unity.snapshot:
+ unispherehost: "{{unispherehost}}"
+ username: "{{username}}"
+ password: "{{password}}"
+ validate_certs: "{{validate_certs}}"
+ snapshot_name: "{{cg_snapshot_name}}"
+ state: "absent"
+'''
+
+RETURN = r'''
+changed:
+ description: Whether or not the resource has changed.
+ returned: always
+ type: bool
+ sample: True
+
+snapshot_details:
+ description: Details of the snapshot.
+ returned: When snapshot exists
+ type: dict
+ contains:
+ is_auto_delete:
+ description: Additional information mentioned for snapshot.
+ type: str
+ expiration_time:
+ description: Date and time after which the snapshot
+ will expire.
+ type: str
+ hosts_list:
+ description: Contains the name and id of the associated
+ hosts.
+ type: dict
+ id:
+ description: Unique identifier of the snapshot instance.
+ type: str
+ name:
+ description: The name of the snapshot.
+ type: str
+ storage_resource_name:
+ description: Name of the storage resource for which the
+ snapshot exists.
+ type: str
+ storage_resource_id:
+ description: Id of the storage resource for which the snapshot
+ exists.
+ type: str
+ sample: {
+ "access_type": null,
+ "attached_wwn": null,
+ "creation_time": "2022-10-21 08:20:25.803000+00:00",
+ "creator_schedule": null,
+ "creator_type": "SnapCreatorTypeEnum.USER_CUSTOM",
+ "creator_user": {
+ "id": "user_admin"
+ },
+ "description": "Test snap creation",
+ "existed": true,
+ "expiration_time": null,
+ "hash": 8756689457056,
+ "hosts_list": [],
+ "id": "85899355291",
+ "io_limit_policy": null,
+ "is_auto_delete": true,
+ "is_modifiable": false,
+ "is_modified": false,
+ "is_read_only": true,
+ "is_system_snap": false,
+ "last_writable_time": null,
+ "lun": null,
+ "name": "ansible_snap_cg_1_1",
+ "parent_snap": null,
+ "size": null,
+ "snap_group": null,
+ "state": "SnapStateEnum.READY",
+ "storage_resource_id": "res_95",
+ "storage_resource_name": "CG_ansible_test_2_new"
+ }
+'''
+
+import logging
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
+ import utils
+from datetime import datetime
+
+LOG = utils.get_logger('snapshot')
+
+application_type = "Ansible/1.6.0"
+
+
+class Snapshot(object):
+ """Class with Snapshot operations"""
+
+ def __init__(self):
+ """ Define all parameters required by this module"""
+
+ self.module_params = utils.get_unity_management_host_parameters()
+ self.module_params.update(get_snapshot_parameters())
+
+ mutually_exclusive = [['snapshot_name', 'snapshot_id'],
+ ['vol_name', 'cg_name'],
+ ['host_name', 'host_id']]
+
+ required_one_of = [['snapshot_name', 'snapshot_id']]
+ # initialize the ansible module
+ self.module = AnsibleModule(argument_spec=self.module_params,
+ supports_check_mode=False,
+ mutually_exclusive=mutually_exclusive,
+ required_one_of=required_one_of)
+ utils.ensure_required_libs(self.module)
+
+ # result is a dictionary that contains changed status and
+ # snapshot details
+ self.result = {"changed": False,
+ 'snapshot_details': {}}
+
+ self.unity_conn = utils.get_unity_unisphere_connection(
+ self.module.params, application_type)
+ self.snap_obj = utils.snap.UnitySnap(self.unity_conn)
+ LOG.info('Connection established with the Unity Array')
+
+ def validate_expiry_time(self, expiry_time):
+ """Validates the specified expiry_time"""
+ try:
+ datetime.strptime(expiry_time, '%m/%d/%Y %H:%M')
+ except ValueError:
+ error_msg = "expiry_time not in MM/DD/YYYY HH:MM format"
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def to_update(self, snapshot, new_name=None, description=None,
+ auto_del=None, expiry_time=None, host=None,
+ host_state=None):
+ """Determines whether to update the snapshot or not"""
+ # If the snapshot has is_auto_delete True,
+ # Check if auto_delete in the input is either None or True
+ if expiry_time and snapshot.is_auto_delete and \
+ (auto_del is None or auto_del):
+ self.module.fail_json(msg="expiry_time can be assigned "
+ "when auto delete is False")
+ if auto_del and snapshot.expiration_time:
+ error_msg = "expiry_time for snapshot is set." \
+ " Once it is set then snapshot cannot" \
+ " be assigned to auto_delete policy"
+ self.module.fail_json(msg=error_msg)
+ if new_name and new_name != snapshot.name:
+ return True
+ if description and description != snapshot.description:
+ return True
+ if auto_del and auto_del != snapshot.is_auto_delete:
+ return True
+ if to_update_expiry_time(snapshot, expiry_time):
+ return True
+ if host and to_update_host_list(snapshot, host, host_state):
+ return True
+ return False
+
+ def update_snapshot(self, snapshot, new_name=None,
+ description=None, auto_del=None, expiry_time=None,
+ host_access_list=None):
+ try:
+ duration = None
+ if expiry_time:
+ duration = convert_timestamp_to_sec(
+ expiry_time, self.unity_conn.system_time)
+ if duration and duration <= 0:
+ self.module.fail_json(msg="expiry_time should be after"
+ " the current system time")
+ snapshot.modify(name=new_name, retentionDuration=duration,
+ isAutoDelete=auto_del, description=description,
+ hostAccess=host_access_list)
+ snapshot.update()
+ except Exception as e:
+ error_msg = "Failed to modify snapshot" \
+ " [name: %s , id: %s] with error %s"\
+ % (snapshot.name, snapshot.id, str(e))
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def create_snapshot(self, snap_name, storage_id, description=None,
+ auto_del=None, expiry_time=None):
+ try:
+ duration = None
+ if expiry_time:
+ duration = convert_timestamp_to_sec(
+ expiry_time, self.unity_conn.system_time)
+ if duration <= 0:
+ self.module.fail_json(msg="expiry_time should be after"
+ " the current system time")
+ snapshot = self.snap_obj.create(
+ cli=self.unity_conn._cli, storage_resource=storage_id,
+ name=snap_name, description=description,
+ is_auto_delete=auto_del, retention_duration=duration)
+ return snapshot
+ except Exception as e:
+ error_msg = "Failed to create snapshot" \
+ " %s with error %s" % (snap_name, str(e))
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def delete_snapshot(self, snapshot):
+ try:
+ if not bool(get_hosts_dict(snapshot)):
+ snapshot.detach_from(None)
+ snapshot.delete()
+ else:
+ snapshot.delete()
+ return None
+
+ except Exception as e:
+ error_msg = "Failed to delete snapshot" \
+ " [name: %s, id: %s] with error %s" \
+ % (snapshot.name, snapshot.id, str(e))
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def get_snapshot_obj(self, name=None, id=None):
+ snapshot = id if id else name
+ msg = "Failed to get details of snapshot %s with error %s "
+ try:
+ return self.unity_conn.get_snap(name=name, _id=id)
+
+ except utils.HttpError as e:
+ if e.http_status == 401:
+ cred_err = "Incorrect username or password , {0}".format(
+ e.message)
+ self.module.fail_json(msg=cred_err)
+ else:
+ err_msg = msg % (snapshot, str(e))
+ LOG.error(err_msg)
+ self.module.fail_json(msg=err_msg)
+
+ except utils.UnityResourceNotFoundError as e:
+ err_msg = msg % (snapshot, str(e))
+ LOG.error(err_msg)
+ return None
+
+ except Exception as e:
+ err_msg = msg % (snapshot, str(e))
+ LOG.error(err_msg)
+ self.module.fail_json(msg=err_msg)
+
+ def get_volume_obj(self, name):
+ try:
+ return self.unity_conn.get_lun(name=name)
+ except Exception as e:
+ error_msg = "Failed to get volume %s with error %s"\
+ % (name, str(e))
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def get_cg_obj(self, name):
+ try:
+ return self.unity_conn.get_cg(name=name)
+ except Exception as e:
+ error_msg = "Failed to get cg %s with error %s" % (name, str(e))
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def get_host_obj(self, name=None, id=None):
+ """ Get the Host object"""
+ try:
+ return self.unity_conn.get_host(name=name, _id=id)
+ except Exception as e:
+ host = id if id else name
+ error_msg = "Failed to get host %s with error %s"\
+ % (host, str(e))
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def attach_to_snap(self, snapshot, host):
+ """ Attach snapshot to a host """
+ try:
+ if not get_hosts_dict(snapshot):
+ snapshot.detach_from(None)
+ snapshot.attach_to(host)
+ snapshot.update()
+ except Exception as e:
+ error_msg = "Failed to attach snapshot [name: %s, id: %s]" \
+ " to host [%s, %s] with error %s"\
+ % (snapshot.name, snapshot.id,
+ host.name, host.id, str(e))
+ LOG.error(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ def perform_module_operation(self):
+ """
+ Perform different actions on snapshot module based on parameters
+ chosen in playbook
+ """
+ snapshot_name = self.module.params['snapshot_name']
+ snapshot_id = self.module.params['snapshot_id']
+ vol_name = self.module.params['vol_name']
+ cg_name = self.module.params['cg_name']
+ auto_delete = self.module.params['auto_delete']
+ expiry_time = self.module.params['expiry_time']
+ description = self.module.params['description']
+ new_snapshot_name = self.module.params['new_snapshot_name']
+ host_name = self.module.params['host_name']
+ host_id = self.module.params['host_id']
+ host_state = self.module.params['host_state']
+ state = self.module.params['state']
+ host = None
+ storage_resource = None
+ changed = False
+
+ LOG.info("Getting Snapshot details")
+ snapshot = self.get_snapshot_obj(name=snapshot_name, id=snapshot_id)
+
+ if snapshot and not snapshot.existed:
+ snapshot = None
+ msg = "snapshot details: %s" % str(snapshot)
+ LOG.info(msg)
+
+ # Get Volume Object
+ if vol_name is not None:
+ if vol_name == "" or vol_name.isspace():
+ self.module.fail_json(msg="Invalid vol_name given, Please"
+ " provide a valid vol_name")
+ storage_resource = self.get_volume_obj(name=vol_name)
+
+ # Get Consistency Group Object
+ if cg_name is not None:
+ if cg_name == "" or cg_name.isspace():
+ self.module.fail_json(msg="Invalid cg_name given, Please"
+ " provide a valid cg_name")
+ storage_resource = self.get_cg_obj(name=cg_name)
+
+ # Get host object for volume snapshots
+ if host_id or host_name:
+ if cg_name:
+ self.module.fail_json(msg="Mapping CG snapshot to host"
+ " is not supported.")
+ host = self.get_host_obj(name=host_name, id=host_id)
+
+ # Check whether host_name or host_id is given in input
+ # along with host_state
+ if (host and not host_state) or (not host and host_state):
+ self.module.fail_json(
+ msg="Either host_name or host_id along with host_state "
+ "is required to map or unmap a snapshot from a host")
+
+ # Check for error, if user tries to create a snapshot with the
+ # same name for other storage resource.
+ if snapshot and storage_resource and\
+ (snapshot.storage_resource.id != storage_resource.id):
+ self.module.fail_json(
+ msg="Snapshot %s is of %s storage resource. Cannot create new"
+ " snapshot with same name for %s storage resource"
+ % (snapshot.name, snapshot.storage_resource.name,
+ storage_resource.name))
+
+ # check for valid expiry_time
+ if expiry_time is not None and \
+ (expiry_time == "" or expiry_time.isspace()):
+ self.module.fail_json(msg="Please provide valid expiry_time,"
+ " empty expiry_time given")
+ # Check if in input auto_delete is True and expiry_time is not None
+ if expiry_time and auto_delete:
+ error_msg = "Cannot set expiry_time if auto_delete given as True"
+ LOG.info(error_msg)
+ self.module.fail_json(msg=error_msg)
+
+ # Check whether to modify the snapshot or not
+ update_flag = False
+ if snapshot:
+ update_flag = self.to_update(snapshot,
+ new_name=new_snapshot_name,
+ description=description,
+ auto_del=auto_delete,
+ expiry_time=expiry_time,
+ host=host, host_state=host_state)
+ msg = "update_flag for snapshot %s" % str(update_flag)
+ LOG.info(msg)
+
+ # Create a Snapshot
+ if not snapshot and state == "present":
+ LOG.info("Creating a snapshot")
+ if snapshot_id:
+ self.module.fail_json(msg="Creation of Snapshot is allowed"
+ " using snapshot_name only, "
+ "snapshot_id given")
+ if snapshot_name == "" or snapshot_name.isspace():
+ self.module.fail_json(msg="snapshot_name is required for"
+ " creation of a snapshot,"
+ " empty snapshot_name given")
+ if not storage_resource:
+ self.module.fail_json(msg="vol_name or cg_name required to"
+ " create a snapshot")
+
+ if new_snapshot_name:
+ self.module.fail_json(
+ msg="new_snapshot_name can not be assigned"
+ " during creation of a snapshot")
+
+ snapshot = self.create_snapshot(snapshot_name,
+ storage_resource.id,
+ description, auto_delete,
+ expiry_time)
+ if host and host_state == "mapped":
+ self.attach_to_snap(snapshot, host)
+ changed = True
+
+ # Update the Snapshot
+ if snapshot and state == "present" and update_flag:
+
+ LOG.info("Updating the Snapshot details")
+
+ if host_state == 'mapped':
+ self.attach_to_snap(snapshot, host)
+ self.update_snapshot(
+ snapshot, new_name=new_snapshot_name,
+ description=description, auto_del=auto_delete,
+ expiry_time=expiry_time)
+
+ elif host_state == 'unmapped':
+ host_access_list = create_host_access_list(snapshot,
+ host,
+ host_state)
+ self.update_snapshot(
+ snapshot, new_name=new_snapshot_name,
+ description=description, auto_del=auto_delete,
+ expiry_time=expiry_time,
+ host_access_list=host_access_list)
+
+ else:
+ self.update_snapshot(
+ snapshot, new_name=new_snapshot_name,
+ description=description, auto_del=auto_delete,
+ expiry_time=expiry_time)
+ changed = True
+
+ # Delete the Snapshot
+ if state == "absent" and snapshot:
+ snapshot = self.delete_snapshot(snapshot)
+ changed = True
+
+ # Add snapshot details to the result.
+ if snapshot:
+ snapshot.update()
+ self.result["snapshot_details"] = \
+ create_snapshot_details_dict(snapshot)
+ else:
+ self.result["snapshot_details"] = {}
+
+ self.result["changed"] = changed
+ self.module.exit_json(**self.result)
+
+
+def create_snapshot_details_dict(snapshot):
+ """ Add name and id of storage resource and hosts to snapshot details """
+ snapshot_dict = snapshot._get_properties()
+ del snapshot_dict['storage_resource']
+ del snapshot_dict['host_access']
+ snapshot_dict['hosts_list'] = get_hosts_list(
+ get_hosts_dict(snapshot))
+ snapshot_dict['storage_resource_name'] = \
+ snapshot.storage_resource.name
+ snapshot_dict['storage_resource_id'] = \
+ snapshot.storage_resource.id
+ return snapshot_dict
+
+
+def get_hosts_list(hosts_dict):
+ """ Get the host name and host id of all the associated hosts """
+ hosts_list = []
+ if not hosts_dict:
+ return hosts_list
+
+ for host in list(hosts_dict.keys()):
+ hosts_list.append(
+ {
+ "host_name": host.name,
+ "host_id": host.id
+ }
+ )
+ return hosts_list
+
+
+def create_host_access_list(snapshot, host, host_state):
+ """ This method creates a List of dictionaries which will be used
+ to modify the list of hosts mapped to a snapshot """
+ host_access_list = []
+ hosts_dict = get_hosts_dict(snapshot)
+ # If snapshot is not attached to any host.
+ if not hosts_dict:
+ return None
+ if to_update_host_list(snapshot, host, host_state):
+ if host_state == "mapped":
+ return None
+ for snap_host in list(hosts_dict.keys()):
+ if snap_host != host:
+ access_dict = {'host': snap_host,
+ 'allowedAccess': hosts_dict[snap_host]}
+ host_access_list.append(access_dict)
+ return host_access_list
+
+
+def get_hosts_dict(snapshot):
+ """ This method creates a dictionary, with host as key and
+ allowed access as value """
+ hosts_dict = {}
+ LOG.info("Inside get_hosts_dict")
+ if not snapshot.host_access:
+ return hosts_dict
+ for host_access_obj in snapshot.host_access:
+ hosts_dict[host_access_obj.host] = \
+ host_access_obj.allowed_access
+ return hosts_dict
+
+
+def to_update_host_list(snapshot, host, host_state):
+ """ Determines whether to update hosts list or not"""
+ hosts_dict = get_hosts_dict(snapshot)
+ if (not hosts_dict or host not in list(hosts_dict.keys()))\
+ and host_state == "mapped":
+ return True
+ if (hosts_dict and host in list(hosts_dict.keys())) \
+ and host_state == "unmapped":
+ return True
+ return False
+
+
+def to_update_expiry_time(snapshot, expiry_time=None):
+ """ Check whether to update expiry_time or not"""
+ if not expiry_time:
+ return False
+ if snapshot.expiration_time is None:
+ return True
+ if convert_timestamp_to_sec(expiry_time, snapshot.expiration_time) != 0:
+ return True
+ return False
+
+
+def convert_timestamp_to_sec(expiry_time, snap_time):
+ """Converts the time difference to seconds"""
+ snap_time_str = snap_time.strftime('%m/%d/%Y %H:%M')
+ snap_timestamp = datetime.strptime(snap_time_str, '%m/%d/%Y %H:%M')
+ expiry_timestamp = datetime.strptime(expiry_time, "%m/%d/%Y %H:%M")
+ return int((expiry_timestamp - snap_timestamp).total_seconds())
+
+
+def get_snapshot_parameters():
+ """This method provide parameter required for the ansible snapshot
+ module on Unity"""
+ return dict(
+ snapshot_name=dict(required=False, type='str'),
+ snapshot_id=dict(required=False, type='str'),
+ vol_name=dict(required=False, type='str'),
+ cg_name=dict(required=False, type='str'),
+ auto_delete=dict(required=False, type='bool'),
+ expiry_time=dict(required=False, type='str'),
+ description=dict(required=False, type='str'),
+ new_snapshot_name=dict(required=False, type='str'),
+ host_name=dict(required=False, type='str'),
+ host_id=dict(required=False, type='str'),
+ host_state=dict(required=False, type='str',
+ choices=['mapped', 'unmapped']),
+ state=dict(required=True, type='str', choices=['present', 'absent'])
+ )
+
+
+def main():
+ """ Create Unity Snapshot object and perform actions on it
+ based on user input from playbook"""
+ obj = Snapshot()
+ obj.perform_module_operation()
+
+
+if __name__ == '__main__':
+ main()