Repository URL to install this package:
|
Version:
6.0.0 ▾
|
#!/usr/bin/python
# (c) 2021-2022, NetApp, Inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = """
module: na_ontap_volume_efficiency
short_description: NetApp ONTAP enables, disables or modifies volume efficiency
extends_documentation_fragment:
- netapp.ontap.netapp.na_ontap
version_added: '21.2.0'
author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
description:
- Enable, modify or disable volume efficiency
options:
state:
description:
- Whether the specified volume efficiency should be enabled or not.
choices: ['present', 'absent']
default: present
type: str
vserver:
description:
- Specifies the vserver for the volume.
required: true
type: str
path:
description:
- Specifies the path for the volume.
required: true
type: str
schedule:
description:
- Specifies the storage efficiency schedule.
type: str
policy:
description:
- Specifies the storage efficiency policy to use.
- By default, the following names are available 'auto', 'default', 'inline-only', '-'.
type: str
enable_compression:
description:
- Specifies if compression is to be enabled.
type: bool
enable_inline_compression:
description:
- Specifies if in-line compression is to be enabled.
type: bool
enable_inline_dedupe:
description:
- Specifies if in-line deduplication is to be enabled, only supported on AFF systems or hybrid aggregates.
type: bool
enable_data_compaction:
description:
- Specifies if compaction is to be enabled.
type: bool
enable_cross_volume_inline_dedupe:
description:
- Specifies if in-line cross volume inline deduplication is to be enabled, this can only be enabled when inline deduplication is enabled.
type: bool
enable_cross_volume_background_dedupe:
description:
- Specifies if cross volume background deduplication is to be enabled, this can only be enabled when inline deduplication is enabled.
type: bool
volume_efficiency:
description:
- Start or Stop a volume efficiency operation on a given volume path.
choices: ['start', 'stop']
version_added: '21.4.0'
type: str
start_ve_scan_all:
description:
- Specifies the scanner to scan the entire volume without applying share block optimization.
version_added: '21.4.0'
type: bool
start_ve_build_metadata:
description:
- Specifies the scanner to scan the entire and generate fingerprint database without attempting the sharing.
version_added: '21.4.0'
type: bool
start_ve_delete_checkpoint:
description:
- Specifies the scanner to delete existing checkpoint and start the operation from the begining.
version_added: '21.4.0'
type: bool
start_ve_queue_operation:
description:
- Specifies the operation to queue if an exisitng operation is already running on the volume and in the fingerprint verification phase.
version_added: '21.4.0'
type: bool
start_ve_scan_old_data:
description:
- Specifies the operation to scan the file system to process all the existing data.
version_added: '21.4.0'
type: bool
start_ve_qos_policy:
description:
- Specifies the QoS policy for the operation.
choices: ['background', 'best-effort']
default: best-effort
version_added: '21.4.0'
type: str
stop_ve_all_operations:
description:
- Specifies that all running and queued operations to be stopped.
version_added: '21.4.0'
type: bool
storage_efficiency_mode:
description:
- Storage efficiency mode used by volume. This parameter is only supported on AFF platforms.
- Requires ONTAP 9.10.1 or later.
choices: ['default', 'efficient']
type: str
version_added: '21.14.0'
notes:
- supports ZAPI and REST. REST requires ONTAP 9.6 or later.
- supports check mode.
"""
EXAMPLES = """
- name: Enable Volume efficiency
na_ontap_volume_efficiency:
state: present
vserver: "TESTSVM"
path: "/vol/test_sis"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
- name: Disable Volume efficiency test
na_ontap_volume_efficiency:
state: absent
vserver: "TESTSVM"
path: "/vol/test_sis"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
- name: Modify storage efficiency schedule
na_ontap_volume_efficiency:
state: present
vserver: "TESTSVM"
path: "/vol/test_sis"
schedule: "mon-sun@0,1,23"
enable_compression: "True"
enable_inline_compression: "True"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
- name: Start volume efficiency
na_ontap_volume_efficiency:
state: present
vserver: "TESTSVM"
volume_efficiency: "start"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
- name: Stop volume efficiency
na_ontap_volume_efficiency:
state: present
vserver: "TESTSVM"
volume_efficiency: "stop"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
"""
RETURN = """
"""
import copy
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible_collections.netapp.ontap.plugins.module_utils.netapp as netapp_utils
from ansible_collections.netapp.ontap.plugins.module_utils.netapp_module import NetAppModule
from ansible_collections.netapp.ontap.plugins.module_utils.netapp import OntapRestAPI
import ansible_collections.netapp.ontap.plugins.module_utils.rest_response_helpers as rrh
HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
class NetAppOntapVolumeEfficiency(object):
"""
Creates, Modifies and Disables a Volume Efficiency
"""
def __init__(self):
"""
Initialize the ONTAP Volume Efficiency class
"""
self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
self.argument_spec.update(dict(
state=dict(required=False, choices=['present', 'absent'], default='present'),
vserver=dict(required=True, type='str'),
path=dict(required=True, type='str'),
schedule=dict(required=False, type='str'),
policy=dict(required=False, type='str'),
enable_inline_compression=dict(required=False, type='bool'),
enable_compression=dict(required=False, type='bool'),
enable_inline_dedupe=dict(required=False, type='bool'),
enable_data_compaction=dict(required=False, type='bool'),
enable_cross_volume_inline_dedupe=dict(required=False, type='bool'),
enable_cross_volume_background_dedupe=dict(required=False, type='bool'),
storage_efficiency_mode=dict(required=False, choices=['default', 'efficient'], type='str'),
volume_efficiency=dict(required=False, choices=['start', 'stop'], type='str'),
start_ve_scan_all=dict(required=False, type='bool'),
start_ve_build_metadata=dict(required=False, type='bool'),
start_ve_delete_checkpoint=dict(required=False, type='bool'),
start_ve_queue_operation=dict(required=False, type='bool'),
start_ve_scan_old_data=dict(required=False, type='bool'),
start_ve_qos_policy=dict(required=False, choices=['background', 'best-effort'], type='str', default='best-effort'),
stop_ve_all_operations=dict(required=False, type='bool')
))
self.module = AnsibleModule(
argument_spec=self.argument_spec,
supports_check_mode=True,
required_if=[('start_ve_scan_all', True, ['start_ve_scan_old_data'])],
mutually_exclusive=[('policy', 'schedule')]
)
# set up variables
self.na_helper = NetAppModule()
self.parameters = self.na_helper.set_parameters(self.module.params)
if self.parameters['state'] == 'present':
self.parameters['enabled'] = 'enabled'
else:
self.parameters['enabled'] = 'disabled'
if 'volume_efficiency' in self.parameters:
if self.parameters['volume_efficiency'] == 'start':
self.parameters['status'] = 'running'
else:
self.parameters['status'] = 'idle'
self.rest_api = OntapRestAPI(self.module)
self.use_rest = self.rest_api.is_rest()
if not self.use_rest:
if HAS_NETAPP_LIB is False:
self.module.fail_json(msg="the python NetApp-Lib module is required")
else:
self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
if self.parameters.get('storage_efficiency_mode') is not None:
self.rest_api.fail_if_not_rest_minimum_version('option storage_efficiency_mode', 9, 10, 1)
def get_volume_efficiency(self):
"""
get the storage efficiency for a given path
:return: dict of sis if exist, None if not
"""
return_value = None
if self.use_rest:
api = 'private/cli/volume/efficiency'
query = {
'fields': 'path,volume,state,op_status,schedule,compression,inline_compression,inline_dedupe,policy,data_compaction,'
'cross_volume_inline_dedupe,cross_volume_background_dedupe',
'path': self.parameters['path'],
'vserver': self.parameters['vserver']
}
if self.parameters.get('storage_efficiency_mode') is not None:
query['fields'] += ',storage_efficiency_mode'
message, error = self.rest_api.get(api, query)
record, error = rrh.check_for_0_or_1_records(api, message, error)
if error:
self.module.fail_json(msg=error)
if record is None:
return None
return_value = {
'path': record['path'],
'enabled': record['state'],
'status': record['op_status'],
'schedule': record['schedule'],
'enable_inline_compression': record['inline_compression'],
'enable_compression': record['compression'],
'enable_inline_dedupe': record['inline_dedupe'],
'enable_data_compaction': record['data_compaction'],
'enable_cross_volume_inline_dedupe': record['cross_volume_inline_dedupe'],
'enable_cross_volume_background_dedupe': record['cross_volume_background_dedupe']
}
return_value['policy'] = record.get('policy', '-')
if self.parameters.get('storage_efficiency_mode') is not None:
# force a value to force a change - and an error if the system is not AFF
return_value['storage_efficiency_mode'] = record.get('storage_efficiency_mode', '-')
return return_value
else:
sis_get_iter = netapp_utils.zapi.NaElement('sis-get-iter')
sis_status_info = netapp_utils.zapi.NaElement('sis-status-info')
sis_status_info.add_new_child('path', self.parameters['path'])
query = netapp_utils.zapi.NaElement('query')
query.add_child_elem(sis_status_info)
sis_get_iter.add_child_elem(query)
result = self.server.invoke_successfully(sis_get_iter, True)
try:
if result.get_child_by_name('attributes-list'):
sis_status_attributes = result['attributes-list']['sis-status-info']
return_value = {
'path': sis_status_attributes['path'],
'enabled': sis_status_attributes['state'],
'status': sis_status_attributes['status'],
'schedule': sis_status_attributes['schedule'],
'enable_inline_compression': self.na_helper.get_value_for_bool(
True, sis_status_attributes.get_child_content('is-inline-compression-enabled')
),
'enable_compression': self.na_helper.get_value_for_bool(True, sis_status_attributes.get_child_content('is-compression-enabled')),
'enable_inline_dedupe': self.na_helper.get_value_for_bool(True, sis_status_attributes.get_child_content('is-inline-dedupe-enabled')),
'enable_data_compaction': self.na_helper.get_value_for_bool(
True, sis_status_attributes.get_child_content('is-data-compaction-enabled')
),
'enable_cross_volume_inline_dedupe': self.na_helper.get_value_for_bool(
True, sis_status_attributes.get_child_content('is-cross-volume-inline-dedupe-enabled')
),
'enable_cross_volume_background_dedupe': self.na_helper.get_value_for_bool(
True, sis_status_attributes.get_child_content('is-cross-volume-background-dedupe-enabled')
)
}
if sis_status_attributes.get_child_by_name('policy'):
return_value['policy'] = sis_status_attributes['policy']
else:
return_value['policy'] = '-'
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error getting volume efficiency for path %s on vserver %s: %s' % (
self.parameters['path'], self.parameters['vserver'], to_native(error)), exception=traceback.format_exc()
)
return return_value
def enable_volume_efficiency(self):
"""
Enables Volume efficiency for a given volume by path
"""
if self.use_rest:
api = 'private/cli/volume/efficiency/on'
body = dict()
query = {
'path': self.parameters['path'],
'vserver': self.parameters['vserver']
}
message, error = self.rest_api.patch(api, body, query)
if error:
self.module.fail_json(msg=error)
elif message['num_records'] == 0:
error = 'Error enabling storage efficiency for path %s on vserver %s as the path provided does not exist.' % (self.parameters['path'],
self.parameters['vserver'])
self.module.fail_json(msg=error)
else:
sis_enable = netapp_utils.zapi.NaElement("sis-enable")
sis_enable.add_new_child("path", self.parameters['path'])
try:
self.server.invoke_successfully(sis_enable, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error enabling storage efficiency for path %s on vserver %s: %s' % (self.parameters['path'],
self.parameters['vserver'], to_native(error)), exception=traceback.format_exc())
def disable_volume_efficiency(self):
"""
Disables Volume efficiency for a given volume by path
"""
if self.use_rest:
api = 'private/cli/volume/efficiency/off'
body = dict()
query = {
'path': self.parameters['path'],
'vserver': self.parameters['vserver']
}
dummy, error = self.rest_api.patch(api, body, query)
if error:
self.module.fail_json(msg=error)
else:
sis_disable = netapp_utils.zapi.NaElement("sis-disable")
sis_disable.add_new_child("path", self.parameters['path'])
try:
self.server.invoke_successfully(sis_disable, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error disabling storage efficiency for path %s: %s' % (self.parameters['path'], to_native(error)),
exception=traceback.format_exc())
def modify_volume_efficiency(self):
"""
Modifies volume efficiency settings for a given volume by path
"""
if self.use_rest:
api = 'private/cli/volume/efficiency'
body = dict()
query = {
'path': self.parameters['path'],
'vserver': self.parameters['vserver']
}
if 'schedule' in self.parameters:
body['schedule'] = self.parameters['schedule']
if 'policy' in self.parameters:
body['policy'] = self.parameters['policy']
if 'enable_compression' in self.parameters:
body['compression'] = self.parameters['enable_compression']
if 'enable_inline_compression' in self.parameters:
body['inline_compression'] = self.parameters['enable_inline_compression']
if 'enable_inline_dedupe' in self.parameters:
body['inline_dedupe'] = self.parameters['enable_inline_dedupe']
if 'enable_data_compaction' in self.parameters:
body['data_compaction'] = self.parameters['enable_data_compaction']
if 'enable_cross_volume_inline_dedupe' in self.parameters:
body['cross_volume_inline_dedupe'] = self.parameters['enable_cross_volume_inline_dedupe']
if 'enable_cross_volume_background_dedupe' in self.parameters:
body['cross_volume_background_dedupe'] = self.parameters['enable_cross_volume_background_dedupe']
if 'storage_efficiency_mode' in self.parameters:
body['storage_efficiency_mode'] = self.parameters['storage_efficiency_mode']
dummy, error = self.rest_api.patch(api, body, query)
if error:
self.module.fail_json(msg='Error in volume/efficiency patch: %s' % error)
else:
sis_config_obj = netapp_utils.zapi.NaElement("sis-set-config")
sis_config_obj.add_new_child('path', self.parameters['path'])
if 'schedule' in self.parameters:
sis_config_obj.add_new_child('schedule', self.parameters['schedule'])
if 'policy' in self.parameters:
sis_config_obj.add_new_child('policy-name', self.parameters['policy'])
if 'enable_compression' in self.parameters:
sis_config_obj.add_new_child('enable-compression', self.na_helper.get_value_for_bool(False, self.parameters['enable_compression']))
if 'enable_inline_compression' in self.parameters:
sis_config_obj.add_new_child('enable-inline-compression', self.na_helper.get_value_for_bool(
False, self.parameters['enable_inline_compression'])
)
if 'enable_inline_dedupe' in self.parameters:
sis_config_obj.add_new_child('enable-inline-dedupe', self.na_helper.get_value_for_bool(
False, self.parameters['enable_inline_dedupe'])
)
if 'enable_data_compaction' in self.parameters:
sis_config_obj.add_new_child('enable-data-compaction', self.na_helper.get_value_for_bool(
False, self.parameters['enable_data_compaction'])
)
if 'enable_cross_volume_inline_dedupe' in self.parameters:
sis_config_obj.add_new_child('enable-cross-volume-inline-dedupe', self.na_helper.get_value_for_bool(
False, self.parameters['enable_cross_volume_inline_dedupe'])
)
if 'enable_cross_volume_background_dedupe' in self.parameters:
sis_config_obj.add_new_child('enable-cross-volume-background-dedupe', self.na_helper.get_value_for_bool(
False, self.parameters['enable_cross_volume_background_dedupe'])
)
try:
self.server.invoke_successfully(sis_config_obj, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error modifying storage efficiency for path %s: %s' % (self.parameters['path'], to_native(error)),
exception=traceback.format_exc())
def start_volume_efficiency(self):
"""
Starts volume efficiency for a given flex volume by path
"""
if self.use_rest:
api = 'private/cli/volume/efficiency/start'
body = dict()
query = {
'path': self.parameters['path'],
'vserver': self.parameters['vserver']
}
if 'start_ve_scan_all' in self.parameters:
body['scan_all'] = self.parameters['start_ve_scan_all']
if 'start_ve_build_metadata' in self.parameters:
body['build_metadata'] = self.parameters['start_ve_build_metadata']
if 'start_ve_delete_checkpoint' in self.parameters:
body['delete_checkpoint'] = self.parameters['start_ve_delete_checkpoint']
if 'start_ve_queue_operation' in self.parameters:
body['queue'] = self.parameters['start_ve_queue_operation']
if 'start_ve_scan_old_data' in self.parameters:
body['scan_old_data'] = self.parameters['start_ve_scan_old_data']
if 'start_ve_qos_policy' in self.parameters:
body['qos-policy'] = self.parameters['start_ve_qos_policy']
dummy, error = self.rest_api.patch(api, body, query)
if error:
self.module.fail_json(msg='Error in efficiency/start: %s' % error)
else:
sis_start = netapp_utils.zapi.NaElement('sis-start')
sis_start.add_new_child('path', self.parameters['path'])
if 'start_ve_scan_all' in self.parameters:
sis_start.add_new_child('scan-all', self.na_helper.get_value_for_bool(
False, self.parameters['start_ve_scan_all'])
)
if 'start_ve_build_metadata' in self.parameters:
sis_start.add_new_child('build-metadata', self.na_helper.get_value_for_bool(
False, self.parameters['start_ve_build_metadata'])
)
if 'start_ve_delete_checkpoint' in self.parameters:
sis_start.add_new_child('delete-checkpoint', self.na_helper.get_value_for_bool(
False, self.parameters['start_ve_delete_checkpoint'])
)
if 'start_ve_queue_operation' in self.parameters:
sis_start.add_new_child('queue-operation', self.na_helper.get_value_for_bool(
False, self.parameters['start_ve_queue_operation'])
)
if 'start_ve_scan_old_data' in self.parameters:
sis_start.add_new_child('scan', self.na_helper.get_value_for_bool(
False, self.parameters['start_ve_scan_old_data'])
)
if 'start_ve_qos_policy' in self.parameters:
sis_start.add_new_child('qos-policy', self.parameters['start_ve_qos_policy'])
try:
self.server.invoke_successfully(sis_start, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error starting storage efficiency for path %s on vserver %s: %s' % (self.parameters['path'],
self.parameters['vserver'], to_native(error)), exception=traceback.format_exc())
def stop_volume_efficiency(self):
"""
Stops volume efficiency for a given flex volume by path
"""
if self.use_rest:
api = 'private/cli/volume/efficiency/stop'
body = dict()
query = {
'path': self.parameters['path'],
'vserver': self.parameters['vserver']
}
if 'stop_ve_all_operations' in self.parameters:
body['all'] = self.parameters['stop_ve_all_operations'] # look and check parameter
dummy, error = self.rest_api.patch(api, body, query)
if error:
self.module.fail_json(msg='Error in efficiency/stop: %s' % error)
else:
sis_stop = netapp_utils.zapi.NaElement('sis-stop')
sis_stop.add_new_child('path', self.parameters['path'])
if 'stop_ve_all_operations' in self.parameters:
sis_stop.add_new_child('all-operations', self.na_helper.get_value_for_bool(
False, self.parameters['stop_ve_all_operations'])
)
try:
self.server.invoke_successfully(sis_stop, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error stopping storage efficiency for path %s on vserver %s: %s' % (self.parameters['path'],
self.parameters['vserver'], to_native(error)), exception=traceback.format_exc())
def apply(self):
if not self.use_rest:
netapp_utils.ems_log_event("na_ontap_volume_efficiency", self.server)
current = self.get_volume_efficiency()
ve_status = None
# If the volume efficiency does not exist for a given path to create this current is set to disabled
# this is for ONTAP systems that do not enable efficiency by default.
if current is None:
current = {'enabled': 'disabled'}
modify = self.na_helper.get_modified_attributes(current, self.parameters)
to_modify = copy.deepcopy(modify)
if self.na_helper.changed and not self.module.check_mode:
if 'enabled' in modify:
if modify['enabled'] == 'enabled':
self.enable_volume_efficiency()
# Checking to see if there are any additional parameters that need to be set after enabling volume efficiency required for Non-AFF systems
current = self.get_volume_efficiency()
modify = self.na_helper.get_modified_attributes(current, self.parameters)
to_modify['modify_after_enable'] = copy.deepcopy(modify)
elif modify['enabled'] == 'disabled':
self.disable_volume_efficiency()
# key may not exist anymore, if modify is refreshed at line 620
modify.pop('enabled', None)
if 'status' in modify:
ve_status = modify['status']
del modify['status']
# Removed the enabled and volume efficiency status,
# if there is anything remaining in the modify dict we need to modify.
if modify:
self.modify_volume_efficiency()
if ve_status == 'running':
self.start_volume_efficiency()
elif ve_status == 'idle':
self.stop_volume_efficiency()
self.module.exit_json(changed=self.na_helper.changed, modify=to_modify)
def main():
"""
Enables, modifies or disables NetApp Ontap volume efficiency
"""
obj = NetAppOntapVolumeEfficiency()
obj.apply()
if __name__ == '__main__':
main()