def __init__(self): self.use_rest = False # Volume_autosize returns KB and not B like Volume so values are shifted down 1 self._size_unit_map = dict( k=1, m=1024, g=1024**2, t=1024**3, ) self.argument_spec = netapp_utils.na_ontap_host_argument_spec() self.argument_spec.update( dict(volume=dict(required=True, type="str"), mode=dict(required=False, choices=['grow', 'grow_shrink', 'off']), vserver=dict(required=True, type='str'), grow_threshold_percent=dict(required=False, type='int'), increment_size=dict(required=False, type='str'), maximum_size=dict(required=False, type='str'), minimum_size=dict(required=False, type='str'), reset=dict(required=False, type='bool'), shrink_threshold_percent=dict(required=False, type='int'))) self.module = AnsibleModule( argument_spec=self.argument_spec, supports_check_mode=True, mutually_exclusive=[['reset', 'maximum_size'], ['reset', 'increment_size'], ['reset', 'minimum_size'], ['reset', 'grow_threshold_percent'], ['reset', 'shrink_threshold_percent'], ['reset', 'mode']]) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) # API should be used for ONTAP 9.6 or higher, ZAPI for lower version self.restApi = OntapRestAPI(self.module) if self.restApi.is_rest(): self.use_rest = True # increment size and reset are not supported with rest api if self.parameters.get('increment_size'): self.module.fail_json( msg= "Rest API does not support increment size, please switch to ZAPI" ) if self.parameters.get('reset'): self.module.fail_json( msg="Rest API does not support reset, please switch to ZAPI" ) else: 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'])
def __init__(self): self.use_rest = False 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'), domains=dict(required=False, type='list'), nameservers=dict(required=False, type='list'), skip_validation=dict(required=False, type='bool'))) self.module = AnsibleModule(argument_spec=self.argument_spec, required_if=[('state', 'present', ['domains', 'nameservers'])], supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) # REST API should be used for ONTAP 9.6 or higher, ZAPI for lower version self.restApi = OntapRestAPI(self.module) # some attributes are not supported in earlier REST implementation unsupported_rest_properties = ['skip_validation'] used_unsupported_rest_properties = [ x for x in unsupported_rest_properties if x in self.parameters ] self.use_rest, error = self.restApi.is_rest( used_unsupported_rest_properties) if error is not None: self.module.fail_json(msg=error) 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']) return
def __init__(self): self.use_rest = False self.argument_spec = netapp_utils.na_ontap_host_argument_spec() self.argument_spec.update( dict( enable=dict(type='bool', default=True), vserver=dict(required=True, type='str'), )) self.module = AnsibleModule(argument_spec=self.argument_spec, supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) # API should be used for ONTAP 9.6 or higher, Zapi for lower version self.restApi = OntapRestAPI(self.module) if self.restApi.is_rest(): self.use_rest = True else: 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'])
class NetAppOntapDns(object): """ Enable and Disable dns """ def __init__(self): self.use_rest = False 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'), domains=dict(required=False, type='list'), nameservers=dict(required=False, type='list'), skip_validation=dict(required=False, type='bool'))) self.module = AnsibleModule(argument_spec=self.argument_spec, required_if=[('state', 'present', ['domains', 'nameservers'])], supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) # REST API should be used for ONTAP 9.6 or higher, ZAPI for lower version self.restApi = OntapRestAPI(self.module) # some attributes are not supported in earlier REST implementation unsupported_rest_properties = ['skip_validation'] used_unsupported_rest_properties = [ x for x in unsupported_rest_properties if x in self.parameters ] self.use_rest, error = self.restApi.is_rest( used_unsupported_rest_properties) if error is not None: self.module.fail_json(msg=error) 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']) return def create_dns(self): """ Create DNS server :return: none """ if self.use_rest: api = 'name-services/dns' params = {} params['domains'] = self.parameters['domains'] params['servers'] = self.parameters['nameservers'] params['svm'] = {'name': self.parameters['vserver']} message, error = self.restApi.post(api, params) if error: self.module.fail_json(msg=error) else: dns = netapp_utils.zapi.NaElement('net-dns-create') nameservers = netapp_utils.zapi.NaElement('name-servers') domains = netapp_utils.zapi.NaElement('domains') for each in self.parameters['nameservers']: ip_address = netapp_utils.zapi.NaElement('ip-address') ip_address.set_content(each) nameservers.add_child_elem(ip_address) dns.add_child_elem(nameservers) for each in self.parameters['domains']: domain = netapp_utils.zapi.NaElement('string') domain.set_content(each) domains.add_child_elem(domain) dns.add_child_elem(domains) if self.parameters.get('skip_validation'): validation = netapp_utils.zapi.NaElement( 'skip-config-validation') validation.set_content(str(self.parameters['skip_validation'])) dns.add_child_elem(validation) try: self.server.invoke_successfully(dns, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error creating dns: %s' % (to_native(error)), exception=traceback.format_exc()) def destroy_dns(self, dns_attrs): """ Destroys an already created dns :return: """ if self.use_rest: uuid = dns_attrs['records'][0]['svm']['uuid'] api = 'name-services/dns/' + uuid data = None message, error = self.restApi.delete(api, data) if error: self.module.fail_json(msg=error) else: try: self.server.invoke_successfully( netapp_utils.zapi.NaElement('net-dns-destroy'), True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error destroying dns %s' % (to_native(error)), exception=traceback.format_exc()) def get_dns(self): if self.use_rest: api = "name-services/dns" params = { 'fields': 'domains,servers,svm', "svm.name": self.parameters['vserver'] } message, error = self.restApi.get(api, params) if error: self.module.fail_json(msg=error) if len(message.keys()) == 0: message = None elif 'records' in message and len(message['records']) == 0: message = None elif 'records' not in message or len(message['records']) != 1: error = "Unexpected response from %s: %s" % (api, repr(message)) self.module.fail_json(msg=error) return message else: dns_obj = netapp_utils.zapi.NaElement('net-dns-get') try: result = self.server.invoke_successfully(dns_obj, True) except netapp_utils.zapi.NaApiError as error: if to_native(error.code) == "15661": # 15661 is object not found return None else: self.module.fail_json(msg=to_native(error), exception=traceback.format_exc()) # read data for modify attrs = dict() attributes = result.get_child_by_name('attributes') dns_info = attributes.get_child_by_name('net-dns-info') nameservers = dns_info.get_child_by_name('name-servers') attrs['nameservers'] = [ each.get_content() for each in nameservers.get_children() ] domains = dns_info.get_child_by_name('domains') attrs['domains'] = [ each.get_content() for each in domains.get_children() ] attrs['skip_validation'] = dns_info.get_child_by_name( 'skip-config-validation') return attrs def modify_dns(self, dns_attrs): if self.use_rest: changed = False params = {} if dns_attrs['records'][0]['servers'] != self.parameters[ 'nameservers']: changed = True params['servers'] = self.parameters['nameservers'] if dns_attrs['records'][0]['domains'] != self.parameters['domains']: changed = True params['domains'] = self.parameters['domains'] if changed: uuid = dns_attrs['records'][0]['svm']['uuid'] api = "name-services/dns/" + uuid message, error = self.restApi.patch(api, params) if error: self.module.fail_json(msg=error) else: changed = False dns = netapp_utils.zapi.NaElement('net-dns-modify') if dns_attrs['nameservers'] != self.parameters['nameservers']: changed = True nameservers = netapp_utils.zapi.NaElement('name-servers') for each in self.parameters['nameservers']: ip_address = netapp_utils.zapi.NaElement('ip-address') ip_address.set_content(each) nameservers.add_child_elem(ip_address) dns.add_child_elem(nameservers) if dns_attrs['domains'] != self.parameters['domains']: changed = True domains = netapp_utils.zapi.NaElement('domains') for each in self.parameters['domains']: domain = netapp_utils.zapi.NaElement('string') domain.set_content(each) domains.add_child_elem(domain) dns.add_child_elem(domains) if changed: if self.parameters.get('skip_validation'): validation = netapp_utils.zapi.NaElement( 'skip-config-validation') validation.set_content( str(self.parameters['skip_validation'])) dns.add_child_elem(validation) try: self.server.invoke_successfully(dns, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error modifying dns %s' % (to_native(error)), exception=traceback.format_exc()) return changed def apply(self): # asup logging if not self.use_rest: netapp_utils.ems_log_event("na_ontap_dns", self.server) dns_attrs = self.get_dns() changed = False if self.parameters['state'] == 'present': if dns_attrs is not None: changed = self.modify_dns(dns_attrs) else: self.create_dns() changed = True else: if dns_attrs is not None: self.destroy_dns(dns_attrs) changed = True self.module.exit_json(changed=changed)
class NetAppOntapVolumeAutosize(object): def __init__(self): self.use_rest = False # Volume_autosize returns KB and not B like Volume so values are shifted down 1 self._size_unit_map = dict( k=1, m=1024, g=1024 ** 2, t=1024 ** 3, ) self.argument_spec = netapp_utils.na_ontap_host_argument_spec() self.argument_spec.update(dict( volume=dict(required=True, type="str"), mode=dict(required=False, choices=['grow', 'grow_shrink', 'off']), vserver=dict(required=True, type='str'), grow_threshold_percent=dict(required=False, type='int'), increment_size=dict(required=False, type='str'), maximum_size=dict(required=False, type='str'), minimum_size=dict(required=False, type='str'), reset=dict(required=False, type='bool'), shrink_threshold_percent=dict(required=False, type='int') )) self.module = AnsibleModule( argument_spec=self.argument_spec, supports_check_mode=True, mutually_exclusive=[ ['reset', 'maximum_size'], ['reset', 'increment_size'], ['reset', 'minimum_size'], ['reset', 'grow_threshold_percent'], ['reset', 'shrink_threshold_percent'], ['reset', 'mode'] ] ) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) # API should be used for ONTAP 9.6 or higher, ZAPI for lower version self.restApi = OntapRestAPI(self.module) if self.restApi.is_rest(): self.use_rest = True # increment size and reset are not supported with rest api if self.parameters.get('increment_size'): self.module.fail_json(msg="Rest API does not support increment size, please switch to ZAPI") if self.parameters.get('reset'): self.module.fail_json(msg="Rest API does not support reset, please switch to ZAPI") else: 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']) def get_volume_autosize(self, uuid=None): """ Get volume_autosize information from the ONTAP system :return: """ if self.use_rest: params = {'fields': 'autosize'} api = 'storage/volumes/' + uuid message, error = self.restApi.get(api, params) if error is not None: self.module.fail_json(msg="%s" % error) return self._create_get_volume_return(message['autosize']) else: volume_autosize_info = netapp_utils.zapi.NaElement('volume-autosize-get') volume_autosize_info.add_new_child('volume', self.parameters['volume']) try: result = self.server.invoke_successfully(volume_autosize_info, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error fetching volume autosize infor for %s : %s' % (self.parameters['volume'], to_native(error)), exception=traceback.format_exc()) return self._create_get_volume_return(result) def _create_get_volume_return(self, results): """ Create a return value from volume-autosize-get info file :param results: :return: """ return_value = {} if self.use_rest: if 'mode' in results: return_value['mode'] = results['mode'] if 'grow_threshold' in results: return_value['grow_threshold_percent'] = results['grow_threshold'] if 'maximum' in results: return_value['maximum_size'] = results['maximum'] if 'minimum' in results: return_value['minimum_size'] = results['minimum'] if 'shrink_threshold' in results: return_value['shrink_threshold_percent'] = results['shrink_threshold'] else: if results.get_child_by_name('mode'): return_value['mode'] = results.get_child_content('mode') if results.get_child_by_name('grow-threshold-percent'): return_value['grow_threshold_percent'] = int(results.get_child_content('grow-threshold-percent')) if results.get_child_by_name('increment-size'): return_value['increment_size'] = results.get_child_content('increment-size') if results.get_child_by_name('maximum-size'): return_value['maximum_size'] = results.get_child_content('maximum-size') if results.get_child_by_name('minimum-size'): return_value['minimum_size'] = results.get_child_content('minimum-size') if results.get_child_by_name('shrink-threshold-percent'): return_value['shrink_threshold_percent'] = int(results.get_child_content('shrink-threshold-percent')) if return_value == {}: return_value = None return return_value def modify_volume_autosize(self, uuid=None): """ Modify a Volumes autosize :return: """ if self.use_rest: params = {} data = {} autosize = {} if self.parameters.get('mode'): autosize['mode'] = self.parameters['mode'] if self.parameters.get('grow_threshold_percent'): autosize['grow_threshold'] = self.parameters['grow_threshold_percent'] if self.parameters.get('maximum_size'): autosize['maximum'] = self.parameters['maximum_size'] if self.parameters.get('minimum_size'): autosize['minimum'] = self.parameters['minimum_size'] if self.parameters.get('shrink_threshold_percent'): autosize['shrink_threshold'] = self.parameters['shrink_threshold_percent'] data['autosize'] = autosize api = "storage/volumes/" + uuid message, error = self.restApi.patch(api, data, params) if error is not None: self.module.fail_json(msg="%s" % error) else: volume_autosize_info = netapp_utils.zapi.NaElement('volume-autosize-set') volume_autosize_info.add_new_child('volume', self.parameters['volume']) if self.parameters.get('mode'): volume_autosize_info.add_new_child('mode', self.parameters['mode']) if self.parameters.get('grow_threshold_percent'): volume_autosize_info.add_new_child('grow-threshold-percent', str(self.parameters['grow_threshold_percent'])) if self.parameters.get('increment_size'): volume_autosize_info.add_new_child('increment-size', self.parameters['increment_size']) if self.parameters.get('reset') is not None: volume_autosize_info.add_new_child('reset', str(self.parameters['reset'])) if self.parameters.get('maximum_size'): volume_autosize_info.add_new_child('maximum-size', self.parameters['maximum_size']) if self.parameters.get('minimum_size'): volume_autosize_info.add_new_child('minimum-size', self.parameters['minimum_size']) if self.parameters.get('shrink_threshold_percent'): volume_autosize_info.add_new_child('shrink-threshold-percent', str(self.parameters['shrink_threshold_percent'])) try: self.server.invoke_successfully(volume_autosize_info, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg="Error modify volume autosize for %s: %s" % (self.parameters["volume"], to_native(error)), exception=traceback.format_exc()) def modify_to_kb(self, converted_parameters): """ Save a converted parameter :param converted_parameters: Dic of all parameters :return: """ for attr in ['maximum_size', 'minimum_size', 'increment_size']: if converted_parameters.get(attr): if self.use_rest: converted_parameters[attr] = self.convert_to_byte(attr, converted_parameters) else: converted_parameters[attr] = str(self.convert_to_kb(attr, converted_parameters)) return converted_parameters def convert_to_kb(self, variable, converted_parameters): """ Convert a number 10m in to its correct KB size :param variable: the Parameter we are going to covert :param converted_parameters: Dic of all parameters :return: """ if converted_parameters.get(variable)[-1] not in ['k', 'm', 'g', 't']: self.module.fail_json(msg="%s must end with a k, m, g or t" % variable) return self._size_unit_map[converted_parameters.get(variable)[-1]] * int(converted_parameters.get(variable)[:-1]) def convert_to_byte(self, variable, converted_parameters): if converted_parameters.get(variable)[-1] not in ['k', 'm', 'g', 't']: self.module.fail_json(msg="%s must end with a k, m, g or t" % variable) return (self._size_unit_map[converted_parameters.get(variable)[-1]] * int(converted_parameters.get(variable)[:-1])) * 1024 def get_volume_uuid(self): """ Get a volume's UUID :return: uuid of the volume """ params = {'fields': '*', 'name': self.parameters['volume'], 'svm.name': self.parameters['vserver']} api = "storage/volumes" message, error = self.restApi.get(api, params) if error is not None: self.module.fail_json(msg="%s" % error) return message['records'][0]['uuid'] def apply(self): # TODO Logging for rest uuid = None if not self.use_rest: netapp_utils.ems_log_event("na_ontap_volume_autosize", self.server) if self.use_rest: # we only have the volume name, we need to the uuid for the volume uuid = self.get_volume_uuid() current = self.get_volume_autosize(uuid=uuid) converted_parameters = copy.deepcopy(self.parameters) converted_parameters = self.modify_to_kb(converted_parameters) self.na_helper.get_modified_attributes(current, converted_parameters) if self.na_helper.changed: if self.module.check_mode: pass else: self.modify_volume_autosize(uuid=uuid) if self.parameters.get('reset') is True: self.modify_volume_autosize(uuid=uuid) self.na_helper.changed = True self.module.exit_json(changed=self.na_helper.changed)
class NetAppOntapVscan(object): def __init__(self): self.use_rest = False self.argument_spec = netapp_utils.na_ontap_host_argument_spec() self.argument_spec.update( dict( enable=dict(type='bool', default=True), vserver=dict(required=True, type='str'), )) self.module = AnsibleModule(argument_spec=self.argument_spec, supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) # API should be used for ONTAP 9.6 or higher, Zapi for lower version self.restApi = OntapRestAPI(self.module) if self.restApi.is_rest(): self.use_rest = True else: 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']) def get_vscan(self): if self.use_rest: params = { 'fields': 'svm,enabled', "svm.name": self.parameters['vserver'] } api = "protocols/vscan" message, error = self.restApi.get(api, params) if error: self.module.fail_json(msg=error) return message['records'][0] else: vscan_status_iter = netapp_utils.zapi.NaElement( 'vscan-status-get-iter') vscan_status_info = netapp_utils.zapi.NaElement( 'vscan-status-info') vscan_status_info.add_new_child('vserver', self.parameters['vserver']) query = netapp_utils.zapi.NaElement('query') query.add_child_elem(vscan_status_info) vscan_status_iter.add_child_elem(query) try: result = self.server.invoke_successfully( vscan_status_iter, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json( msg='Error getting Vscan info for Vserver %s: %s' % (self.parameters['vserver'], to_native(error)), exception=traceback.format_exc()) if result.get_child_by_name('num-records') and int( result.get_child_content('num-records')) >= 1: return result.get_child_by_name( 'attributes-list').get_child_by_name('vscan-status-info') def enable_vscan(self, uuid=None): if self.use_rest: params = {"svm.name": self.parameters['vserver']} data = {"enabled": self.parameters['enable']} api = "protocols/vscan/" + uuid message, error = self.restApi.patch(api, data, params) if error is not None: self.module.fail_json(msg=error) # self.module.fail_json(msg=repr(self.restApi.errors), log=repr(self.restApi.debug_logs)) else: vscan_status_obj = netapp_utils.zapi.NaElement( "vscan-status-modify") vscan_status_obj.add_new_child('is-vscan-enabled', str(self.parameters['enable'])) try: self.server.invoke_successfully(vscan_status_obj, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg="Error Enable/Disabling Vscan: %s" % to_native(error), exception=traceback.format_exc()) def asup_log(self): if self.use_rest: # TODO: logging for Rest return else: # Either we are using ZAPI, or REST failed when it should not try: netapp_utils.ems_log_event("na_ontap_vscan", self.server) except Exception: # TODO: we may fail to connect to REST or ZAPI, the line below shows REST issues only # self.module.fail_json(msg=repr(self.restApi.errors), log=repr(self.restApi.debug_logs)) pass def apply(self): changed = False self.asup_log() current = self.get_vscan() if self.use_rest: if current['enabled'] != self.parameters['enable']: if not self.module.check_mode: self.enable_vscan(current['svm']['uuid']) changed = True else: if current.get_child_content('is-vscan-enabled') != str( self.parameters['enable']).lower(): if not self.module.check_mode: self.enable_vscan() changed = True self.module.exit_json(changed=changed)