Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding ElementSW Snapshot Module #43972

Merged
merged 2 commits into from
Aug 28, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
377 changes: 377 additions & 0 deletions lib/ansible/modules/storage/netapp/na_elementsw_snapshot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,377 @@
#!/usr/bin/python
# (c) 2018, NetApp, Inc
# GNU General Public License v3.0+ (see COPYING or
# https://www.gnu.org/licenses/gpl-3.0.txt)

'''
Element OS Software Snapshot Manager
'''
from __future__ import absolute_import, division, print_function
__metaclass__ = type


ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}


DOCUMENTATION = '''

module: na_elementsw_snapshot

short_description: NetApp Element Software Manage Snapshots
extends_documentation_fragment:
- netapp.solidfire
version_added: '2.7'
author: NetApp Ansible Team (ng-ansibleteam@netapp.com)
description:
- Create, Modify or Delete Snapshot on Element OS Cluster.

options:
name:
description:
- Name of new snapshot create.
- If unspecified, date and time when the snapshot was taken is used.

state:
description:
- Whether the specified snapshot should exist or not.
choices: ['present', 'absent']
default: 'present'

src_volume_id:
description:
- ID or Name of active volume.
required: true

account_id:
description:
- Account ID or Name of Parent/Source Volume.
required: true

retention:
description:
- Retention period for the snapshot.
- Format is 'HH:mm:ss'.

src_snapshot_id:
description:
- ID or Name of an existing snapshot.
- Required when C(state=present), to modify snapshot properties.
- Required when C(state=present), to create snapshot from another snapshot in the volume.
- Required when C(state=absent), to delete snapshot.

enable_remote_replication:
description:
- Flag, whether to replicate the snapshot created to a remote replication cluster.
- To enable specify 'true' value.
type: bool

snap_mirror_label:
description:
- Label used by SnapMirror software to specify snapshot retention policy on SnapMirror endpoint.

expiration_time:
description:
- The date and time (format ISO 8601 date string) at which this snapshot will expire.

password:
description:
- Element OS access account password
aliases:
- pass

username:
description:
- Element OS access account user-name
aliases:
- user

'''

EXAMPLES = """
- name: Create snapshot
tags:
- elementsw_create_snapshot
na_elementsw_snapshot:
hostname: "{{ elementsw_hostname }}"
username: "{{ elementsw_username }}"
password: "{{ elementsw_password }}"
state: present
src_volume_id: 118
account_id: sagarsh
name: newsnapshot-1

- name: Modify Snapshot
tags:
- elementsw_modify_snapshot
na_elementsw_snapshot:
hostname: "{{ elementsw_hostname }}"
username: "{{ elementsw_username }}"
password: "{{ elementsw_password }}"
state: present
src_volume_id: sagarshansivolume
src_snapshot_id: test1
account_id: sagarsh
expiration_time: '2018-06-16T12:24:56Z'
enable_remote_replication: false

- name: Delete Snapshot
tags:
- elementsw_delete_snapshot
na_elementsw_snapshot:
hostname: "{{ elementsw_hostname }}"
username: "{{ elementsw_username }}"
password: "{{ elementsw_password }}"
state: absent
src_snapshot_id: deltest1
account_id: sagarsh
src_volume_id: sagarshansivolume
"""


RETURN = """

msg:
description: Success message
returned: success
type: string

"""
import traceback

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
from ansible.module_utils.netapp_elementsw_module import NaElementSWModule


HAS_SF_SDK = netapp_utils.has_sf_sdk()


class ElementOSSnapshot(object):
"""
Element OS Snapshot Manager
"""

def __init__(self):
self.argument_spec = netapp_utils.ontap_sf_host_argument_spec()
self.argument_spec.update(dict(
state=dict(required=False, choices=['present', 'absent'], default='present'),
account_id=dict(required=True, type='str'),
name=dict(required=False, type='str'),
src_volume_id=dict(required=True, type='str'),
retention=dict(required=False, type='str'),
src_snapshot_id=dict(required=False, type='str'),
enable_remote_replication=dict(required=False, type='bool'),
expiration_time=dict(required=False, type='str'),
snap_mirror_label=dict(required=False, type='str')
))

self.module = AnsibleModule(
argument_spec=self.argument_spec,
supports_check_mode=True
)

input_params = self.module.params

self.state = input_params['state']
self.name = input_params['name']
self.account_id = input_params['account_id']
self.src_volume_id = input_params['src_volume_id']
self.src_snapshot_id = input_params['src_snapshot_id']
self.retention = input_params['retention']
self.properties_provided = False

self.expiration_time = input_params['expiration_time']
if input_params['expiration_time'] is not None:
self.properties_provided = True

self.enable_remote_replication = input_params['enable_remote_replication']
if input_params['enable_remote_replication'] is not None:
self.properties_provided = True

self.snap_mirror_label = input_params['snap_mirror_label']
if input_params['snap_mirror_label'] is not None:
self.properties_provided = True

if self.state == 'absent' and self.src_snapshot_id is None:
self.module.fail_json(
msg="Please provide required parameter : snapshot_id")

if HAS_SF_SDK is False:
self.module.fail_json(
msg="Unable to import the SolidFire Python SDK")
else:
self.sfe = netapp_utils.create_sf_connection(module=self.module)

self.elementsw_helper = NaElementSWModule(self.sfe)

# add telemetry attributes
self.attributes = self.elementsw_helper.set_element_attributes(source='na_elementsw_snapshot')

def get_account_id(self):
"""
Return account id if found
"""
try:
# Update and return self.account_id
self.account_id = self.elementsw_helper.account_exists(self.account_id)
return self.account_id
except Exception as err:
self.module.fail_json(msg="Error: account_id %s does not exist" % self.account_id, exception=to_native(err))

def get_src_volume_id(self):
"""
Return volume id if found
"""
src_vol_id = self.elementsw_helper.volume_exists(self.src_volume_id, self.account_id)
if src_vol_id is not None:
# Update and return self.volume_id
self.src_volume_id = src_vol_id
# Return src_volume_id
return self.src_volume_id
return None

def get_snapshot(self, name=None):
"""
Return snapshot details if found
"""
src_snapshot = None
if name is not None:
src_snapshot = self.elementsw_helper.get_snapshot(name, self.src_volume_id)
elif self.src_snapshot_id is not None:
src_snapshot = self.elementsw_helper.get_snapshot(self.src_snapshot_id, self.src_volume_id)
if src_snapshot is not None:
# Update self.src_snapshot_id
self.src_snapshot_id = src_snapshot.snapshot_id
# Return src_snapshot
return src_snapshot

def create_snapshot(self):
"""
Create Snapshot
"""
try:
self.sfe.create_snapshot(volume_id=self.src_volume_id,
snapshot_id=self.src_snapshot_id,
name=self.name,
enable_remote_replication=self.enable_remote_replication,
retention=self.retention,
snap_mirror_label=self.snap_mirror_label,
attributes=self.attributes)
except Exception as exception_object:
self.module.fail_json(
msg='Error creating snapshot %s' % (
to_native(exception_object)),
exception=traceback.format_exc())

def modify_snapshot(self):
"""
Modify Snapshot Properties
"""
try:
self.sfe.modify_snapshot(snapshot_id=self.src_snapshot_id,
expiration_time=self.expiration_time,
enable_remote_replication=self.enable_remote_replication,
snap_mirror_label=self.snap_mirror_label)
except Exception as exception_object:
self.module.fail_json(
msg='Error modify snapshot %s' % (
to_native(exception_object)),
exception=traceback.format_exc())

def delete_snapshot(self):
"""
Delete Snapshot
"""
try:
self.sfe.delete_snapshot(snapshot_id=self.src_snapshot_id)
except Exception as exception_object:
self.module.fail_json(
msg='Error delete snapshot %s' % (
to_native(exception_object)),
exception=traceback.format_exc())

def apply(self):
"""
Check, process and initiate snapshot operation
"""
changed = False
snapshot_delete = False
snapshot_create = False
snapshot_modify = False
result_message = None
self.get_account_id()

# Dont proceed if source volume is not found
if self.get_src_volume_id() is None:
self.module.fail_json(msg="Volume id not found %s" % self.src_volume_id)

# Get snapshot details using source volume
snapshot_detail = self.get_snapshot()

if snapshot_detail:
if self.properties_provided:
if self.expiration_time != snapshot_detail.expiration_time:
changed = True
else: # To preserve value in case parameter expiration_time is not defined/provided.
self.expiration_time = snapshot_detail.expiration_time

if self.enable_remote_replication != snapshot_detail.enable_remote_replication:
changed = True
else: # To preserve value in case parameter enable_remote_Replication is not defined/provided.
self.enable_remote_replication = snapshot_detail.enable_remote_replication

if self.snap_mirror_label != snapshot_detail.snap_mirror_label:
changed = True
else: # To preserve value in case parameter snap_mirror_label is not defined/provided.
self.snap_mirror_label = snapshot_detail.snap_mirror_label

if self.account_id is None or self.src_volume_id is None or self.module.check_mode:
changed = False
result_message = "Check mode, skipping changes"
elif self.state == 'absent' and snapshot_detail is not None:
self.delete_snapshot()
changed = True
elif self.state == 'present' and snapshot_detail is not None:
if changed:
self.modify_snapshot() # Modify Snapshot properties
elif not self.properties_provided:
if self.name is not None:
snapshot = self.get_snapshot(self.name)
# If snapshot with name already exists return without performing any action
if snapshot is None:
self.create_snapshot() # Create Snapshot using parent src_snapshot_id
changed = True
else:
self.create_snapshot()
changed = True
elif self.state == 'present':
if self.name is not None:
snapshot = self.get_snapshot(self.name)
# If snapshot with name already exists return without performing any action
if snapshot is None:
self.create_snapshot() # Create Snapshot using parent src_snapshot_id
changed = True
else:
self.create_snapshot()
changed = True
else:
changed = False
result_message = "No changes requested, skipping changes"

self.module.exit_json(changed=changed, msg=result_message)


def main():
"""
Main function
"""

na_elementsw_snapshot = ElementOSSnapshot()
na_elementsw_snapshot.apply()


if __name__ == '__main__':
main()