class AzureRMNetAppSnapshot(AzureRMNetAppModuleBase): """ crate or delete snapshots """ def __init__(self): self.module_arg_spec = dict(resource_group=dict(type='str', required=True), name=dict(type='str', required=True), volume_name=dict(type='str', required=True), pool_name=dict(type='str', required=True), account_name=dict(type='str', required=True), location=dict(type='str', required=False), state=dict(choices=['present', 'absent'], default='present', type='str')) self.module = AnsibleModule(argument_spec=self.module_arg_spec, required_if=[ ('state', 'present', ['location']), ], supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) self.fail_when_import_errors(IMPORT_ERRORS, HAS_AZURE_MGMT_NETAPP) super(AzureRMNetAppSnapshot, self).__init__(derived_arg_spec=self.module_arg_spec, supports_check_mode=True) def get_azure_netapp_snapshot(self): """ Returns snapshot object for an existing snapshot Return None if snapshot does not exist """ try: snapshot_get = self.netapp_client.snapshots.get( self.parameters['resource_group'], self.parameters['account_name'], self.parameters['pool_name'], self.parameters['volume_name'], self.parameters['name']) except (CloudError, ResourceNotFoundError): # snapshot does not exist return None return snapshot_get def create_azure_netapp_snapshot(self): """ Create a snapshot for the given Azure NetApp Account :return: None """ kw_args = dict(resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['pool_name'], volume_name=self.parameters['volume_name'], snapshot_name=self.parameters['name']) if self.new_style: kw_args['body'] = Snapshot(location=self.parameters['location']) else: kw_args['location'] = self.parameters['location'] try: self.get_method('snapshots', 'create')(**kw_args) except (CloudError, AzureError) as error: self.module.fail_json( msg='Error creating snapshot %s for Azure NetApp account %s: %s' % (self.parameters['name'], self.parameters['account_name'], to_native(error)), exception=traceback.format_exc()) def delete_azure_netapp_snapshot(self): """ Delete a snapshot for the given Azure NetApp Account :return: None """ try: self.get_method('snapshots', 'delete')( resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['pool_name'], volume_name=self.parameters['volume_name'], snapshot_name=self.parameters['name']) except (CloudError, AzureError) as error: self.module.fail_json( msg='Error deleting snapshot %s for Azure NetApp account %s: %s' % (self.parameters['name'], self.parameters['account_name'], to_native(error)), exception=traceback.format_exc()) def exec_module(self, **kwargs): current = self.get_azure_netapp_snapshot() cd_action = self.na_helper.get_cd_action(current, self.parameters) if self.na_helper.changed: if self.module.check_mode: pass else: if cd_action == 'create': self.create_azure_netapp_snapshot() elif cd_action == 'delete': self.delete_azure_netapp_snapshot() self.module.exit_json(changed=self.na_helper.changed)
class AzureRMNetAppCapacityPool(AzureRMNetAppModuleBase): def __init__(self): self.module_arg_spec = dict( resource_group=dict(type='str', required=True), name=dict(type='str', required=True), account_name=dict(type='str', required=True), location=dict(type='str', required=False), state=dict(choices=['present', 'absent'], default='present', type='str'), size=dict(type='int', required=False, default=1), service_level=dict(type='str', required=False, choices=['Standard', 'Premium', 'Ultra']), ) self.module = AnsibleModule( argument_spec=self.module_arg_spec, required_if=[ ('state', 'present', ['location', 'service_level']), ], supports_check_mode=True ) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) if HAS_AZURE_MGMT_NETAPP is False: self.module.fail_json(msg="the python Azure-mgmt-NetApp module is required") super(AzureRMNetAppCapacityPool, self).__init__(derived_arg_spec=self.module_arg_spec, supports_check_mode=True) def get_azure_netapp_capacity_pool(self): """ Returns capacity pool object for an existing pool Return None if capacity pool does not exist """ try: capacity_pool_get = self.netapp_client.pools.get(self.parameters['resource_group'], self.parameters['account_name'], self.parameters['name']) except CloudError: # capacity pool does not exist return None return capacity_pool_get def create_azure_netapp_capacity_pool(self): """ Create a capacity pool for the given Azure NetApp Account :return: None """ capacity_pool_body = CapacityPool( location=self.parameters['location'], size=self.parameters['size'] * SIZE_POOL, service_level=self.parameters['service_level'] ) try: self.netapp_client.pools.create_or_update(body=capacity_pool_body, resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['name']) except CloudError as error: self.module.fail_json(msg='Error creating capacity pool %s for Azure NetApp account %s: %s' % (self.parameters['name'], self.parameters['account_name'], to_native(error)), exception=traceback.format_exc()) def modify_azure_netapp_capacity_pool(self, modify): """ Modify a capacity pool for the given Azure NetApp Account :return: None """ capacity_pool_body = CapacityPool( location=self.parameters['location'], service_level=self.parameters['service_level'], size=self.parameters['size'] * SIZE_POOL ) try: self.netapp_client.pools.update(body=capacity_pool_body, resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['name']) except CloudError as error: self.module.fail_json(msg='Error modifying capacity pool %s for Azure NetApp account %s: %s' % (self.parameters['name'], self.parameters['account_name'], to_native(error)), exception=traceback.format_exc()) def delete_azure_netapp_capacity_pool(self): """ Delete a capacity pool for the given Azure NetApp Account :return: None """ try: self.netapp_client.pools.delete(resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['name']) except CloudError as error: self.module.fail_json(msg='Error deleting capacity pool %s for Azure NetApp account %s: %s' % (self.parameters['name'], self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def exec_module(self, **kwargs): modify = {} current = self.get_azure_netapp_capacity_pool() cd_action = self.na_helper.get_cd_action(current, self.parameters) if cd_action is None and self.parameters['state'] == 'present': current = vars(current) # to match with the unit of size input current['size'] = int(current['size'] / SIZE_POOL) # get_azure_netapp_capacity_pool() returns pool name with account name appended in front of it like 'account/pool' current['name'] = self.parameters['name'] modify = self.na_helper.get_modified_attributes(current, self.parameters) if self.na_helper.changed: if self.module.check_mode: pass else: if cd_action == 'create': self.create_azure_netapp_capacity_pool() elif cd_action == 'delete': self.delete_azure_netapp_capacity_pool() elif modify: self.modify_azure_netapp_capacity_pool(modify) self.module.exit_json(changed=self.na_helper.changed)
class AzureRMNetAppVolume(AzureRMNetAppModuleBase): ''' create or delete a volume ''' def __init__(self): self.module_arg_spec = dict( resource_group=dict(type='str', required=True), name=dict(type='str', required=True), file_path=dict(type='str', required=False), pool_name=dict(type='str', required=True), account_name=dict(type='str', required=True), location=dict(type='str', required=False), state=dict(choices=['present', 'absent'], default='present', type='str'), subnet_name=dict(type='str', required=False, aliases=['subnet_id']), virtual_network=dict(type='str', required=False), size=dict(type='int', required=False), vnet_resource_group_for_subnet=dict(type='str', required=False), service_level=dict(type='str', required=False, choices=['Premium', 'Standard', 'Ultra']), protocol_types=dict(type='list', elements='str')) self.module = AnsibleModule(argument_spec=self.module_arg_spec, required_if=[ ('state', 'present', [ 'location', 'file_path', 'subnet_name', 'virtual_network' ]), ], supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) if HAS_AZURE_MGMT_NETAPP is False: self.module.fail_json( msg="the python Azure-mgmt-NetApp module is required") super(AzureRMNetAppVolume, self).__init__(derived_arg_spec=self.module_arg_spec, supports_check_mode=True) def get_azure_netapp_volume(self): """ Returns volume object for an existing volume Return None if volume does not exist """ try: volume_get = self.netapp_client.volumes.get( self.parameters['resource_group'], self.parameters['account_name'], self.parameters['pool_name'], self.parameters['name']) except CloudError: # volume does not exist return None return volume_get def get_export_policy_rules(self): # ExportPolicyRule(rule_index: int=None, unix_read_only: bool=None, unix_read_write: bool=None, # kerberos5_read_only: bool=False, kerberos5_read_write: bool=False, kerberos5i_read_only: bool=False, # kerberos5i_read_write: bool=False, kerberos5p_read_only: bool=False, kerberos5p_read_write: bool=False, # cifs: bool=None, nfsv3: bool=None, nfsv41: bool=None, allowed_clients: str=None, has_root_access: bool=True ptypes = self.parameters.get('protocol_types') if ptypes is None: return None ptypes = [x.lower() for x in ptypes] if 'nfsv4.1' in ptypes: ptypes.append('nfsv41') else: return None # only create a policy when NFSv4 is used (for now) options = dict(rule_index=1, allowed_clients='0.0.0.0/0', unix_read_write=True) for protocol in ('cifs', 'nfsv3', 'nfsv41'): options[protocol] = protocol in ptypes if options: return VolumePropertiesExportPolicy( rules=[ExportPolicyRule(**options)]) return None def create_azure_netapp_volume(self): """ Create a volume for the given Azure NetApp Account :return: None """ options = dict() for attr in ('protocol_types', 'service_level', 'size'): value = self.parameters.get(attr) if value is not None: if attr == 'size': attr = 'usage_threshold' value *= ONE_GIB options[attr] = value rules = self.get_export_policy_rules() if rules is not None: options['export_policy'] = rules subnet_id = '/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s'\ % (self.netapp_client.config.subscription_id, self.parameters['resource_group'] if self.parameters.get('vnet_resource_group_for_subnet') is None else self.parameters['vnet_resource_group_for_subnet'], self.parameters['virtual_network'], self.parameters['subnet_name']) volume_body = Volume(location=self.parameters['location'], creation_token=self.parameters['file_path'], subnet_id=subnet_id, **options) try: result = self.netapp_client.volumes.create_or_update( body=volume_body, resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['pool_name'], volume_name=self.parameters['name']) # waiting till the status turns Succeeded while result.done() is not True: result.result(10) except (CloudError, ValidationError) as error: self.module.fail_json( msg= 'Error creating volume %s for Azure NetApp account %s and subnet ID %s: %s' % (self.parameters['name'], self.parameters['account_name'], subnet_id, to_native(error)), exception=traceback.format_exc()) def delete_azure_netapp_volume(self): """ Delete a volume for the given Azure NetApp Account :return: None """ try: result = self.netapp_client.volumes.delete( resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['pool_name'], volume_name=self.parameters['name']) # waiting till the status turns Succeeded while result.done() is not True: result.result(10) except CloudError as error: self.module.fail_json( msg='Error deleting volume %s for Azure NetApp account %s: %s' % (self.parameters['name'], self.parameters['account_name'], to_native(error)), exception=traceback.format_exc()) def exec_module(self, **kwargs): current = self.get_azure_netapp_volume() cd_action = self.na_helper.get_cd_action(current, self.parameters) if self.na_helper.changed: if self.module.check_mode: pass else: if cd_action == 'create': self.create_azure_netapp_volume() elif cd_action == 'delete': self.delete_azure_netapp_volume() return_info = '' if self.parameters['state'] == 'present': return_info = self.get_azure_netapp_volume() if return_info is None: self.module.fail_json( msg= 'Error: volume %s was created successfully, but cannot be found.' % self.parameters['name']) if return_info.mount_targets is None: self.module.fail_json( msg= 'Error: volume %s was created successfully, but mount target(s) cannot be found - volume details: %s.' % (self.parameters['name'], str(return_info))) return_info = '%s:/%s' % (return_info.mount_targets[0].ip_address, return_info.creation_token) self.module.exit_json(changed=self.na_helper.changed, msg=str(return_info))
class AzureRMNetAppAccount(AzureRMNetAppModuleBase): def __init__(self): self.module_arg_spec = dict( resource_group=dict(type='str', required=True), name=dict(type='str', required=True), location=dict(type='str'), state=dict(choices=['present', 'absent'], default='present', type='str'), ) self.module = AnsibleModule(argument_spec=self.module_arg_spec, supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) if HAS_AZURE_MGMT_NETAPP is False: self.module.fail_json( msg="the python Azure-mgmt-NetApp module is required") super(AzureRMNetAppAccount, self).__init__(derived_arg_spec=self.module_arg_spec, supports_check_mode=True) def get_azure_netapp_account(self): """ Returns NetApp Account object for an existing account Return None if account does not exist """ try: account_get = self.netapp_client.accounts.get( self.parameters['resource_group'], self.parameters['name']) except CloudError: # account does not exist return None return account_get def create_azure_netapp_account(self): """ Create an Azure NetApp Account :return: None """ account_body = NetAppAccount(location=self.parameters['location']) try: self.netapp_client.accounts.create_or_update( body=account_body, resource_group_name=self.parameters['resource_group'], account_name=self.parameters['name']) except CloudError as error: self.module.fail_json( msg='Error creating Azure NetApp account %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def delete_azure_netapp_account(self): """ Delete an Azure NetApp Account :return: None """ try: self.netapp_client.accounts.delete( resource_group_name=self.parameters['resource_group'], account_name=self.parameters['name']) except CloudError as error: self.module.fail_json( msg='Error deleting Azure NetApp account %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def exec_module(self, **kwargs): current = self.get_azure_netapp_account() cd_action = self.na_helper.get_cd_action(current, self.parameters) if self.na_helper.changed: if self.module.check_mode: pass else: if cd_action == 'create': self.create_azure_netapp_account() elif cd_action == 'delete': self.delete_azure_netapp_account() self.module.exit_json(changed=self.na_helper.changed)
class AzureRMNetAppVolume(AzureRMNetAppModuleBase): def __init__(self): self.module_arg_spec = dict( resource_group=dict(type='str', required=True), name=dict(type='str', required=True), file_path=dict(type='str', required=False), pool_name=dict(type='str', required=True), account_name=dict(type='str', required=True), location=dict(type='str', required=False), state=dict(choices=['present', 'absent'], default='present', type='str'), subnet_id=dict(type='str', required=False), virtual_network=dict(type='str', required=False), size=dict(type='int', required=False), vnet_resource_group_for_subnet=dict(type='str', required=False), service_level=dict(type='str', required=False, choices=['Premium', 'Standard', 'Ultra'])) self.module = AnsibleModule(argument_spec=self.module_arg_spec, required_if=[ ('state', 'present', [ 'location', 'file_path', 'subnet_id', 'virtual_network' ]), ], supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) if HAS_AZURE_MGMT_NETAPP is False: self.module.fail_json( msg="the python Azure-mgmt-NetApp module is required") super(AzureRMNetAppVolume, self).__init__(derived_arg_spec=self.module_arg_spec, supports_check_mode=True) def get_azure_netapp_volume(self): """ Returns volume object for an existing volume Return None if volume does not exist """ try: volume_get = self.netapp_client.volumes.get( self.parameters['resource_group'], self.parameters['account_name'], self.parameters['pool_name'], self.parameters['name']) except CloudError: # volume does not exist return None return volume_get def create_azure_netapp_volume(self): """ Create a volume for the given Azure NetApp Account :return: None """ volume_body = Volume( location=self.parameters['location'], creation_token=self.parameters['file_path'], service_level=self.parameters['service_level'] if self.parameters.get('service_level') is not None else 'Premium', usage_threshold=(self.parameters['size'] if self.parameters.get( 'size') is not None else 100) * ONE_GIB, subnet_id= '/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s' % (self.netapp_client.config.subscription_id, self.parameters['resource_group'] if self.parameters.get('vnet_resource_group_for_subnet') is None else self.parameters['vnet_resource_group_for_subnet'], self.parameters['virtual_network'], self.parameters['subnet_id'])) try: result = self.netapp_client.volumes.create_or_update( body=volume_body, resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['pool_name'], volume_name=self.parameters['name']) # waiting till the status turns Succeeded while result.done() is not True: result.result(10) except CloudError as error: self.module.fail_json( msg= 'Error creating volume %s for Azure NetApp account %s and subnet ID %s: %s' % (self.parameters['name'], self.parameters['account_name'], self.parameters['subnet_id'], to_native(error)), exception=traceback.format_exc()) def delete_azure_netapp_volume(self): """ Delete a volume for the given Azure NetApp Account :return: None """ try: result = self.netapp_client.volumes.delete( resource_group_name=self.parameters['resource_group'], account_name=self.parameters['account_name'], pool_name=self.parameters['pool_name'], volume_name=self.parameters['name']) # waiting till the status turns Succeeded while result.done() is not True: result.result(10) except CloudError as error: self.module.fail_json( msg='Error deleting volume %s for Azure NetApp account %s: %s' % (self.parameters['name'], self.parameters['account_name'], to_native(error)), exception=traceback.format_exc()) def exec_module(self, **kwargs): current = self.get_azure_netapp_volume() cd_action = self.na_helper.get_cd_action(current, self.parameters) if self.na_helper.changed: if self.module.check_mode: pass else: if cd_action == 'create': self.create_azure_netapp_volume() elif cd_action == 'delete': self.delete_azure_netapp_volume() return_info = '' if self.parameters['state'] == 'present': return_info = self.get_azure_netapp_volume() return_info = ('%s:/%s' % (return_info.mount_targets[0].ip_address, return_info.creation_token) ) if return_info is not None else '' self.module.exit_json(changed=self.na_helper.changed, msg=str(return_info))
class AzureRMNetAppAccount(AzureRMNetAppModuleBase): ''' create, modify, delete account, including joining AD domain ''' def __init__(self): self.module_arg_spec = dict( resource_group=dict(type='str', required=True), name=dict(type='str', required=True), location=dict(type='str', required=False), state=dict(choices=['present', 'absent'], default='present', type='str'), tags=dict(type='dict', required=False), active_directories=dict(type='list', elements='dict', options=dict( active_directory_id=dict(type='str'), dns=dict(type='list', elements='str'), domain=dict(type='str'), site=dict(type='str'), smb_server_name=dict(type='str'), organizational_unit=dict(type='str'), username=dict(type='str'), password=dict(type='str', no_log=True), aes_encryption=dict(type='bool'), ldap_signing=dict(type='bool'), )), debug=dict(type='bool', default=False)) self.module = AnsibleModule(argument_spec=self.module_arg_spec, required_if=[ ('state', 'present', ['location']), ], supports_check_mode=True) self.na_helper = NetAppModule() self.parameters = self.na_helper.set_parameters(self.module.params) self.debug = list() self.warnings = list() if HAS_AZURE_MGMT_NETAPP is False: self.module.fail_json( msg="the python Azure-mgmt-NetApp module is required") super(AzureRMNetAppAccount, self).__init__(derived_arg_spec=self.module_arg_spec, supports_check_mode=True) def get_azure_netapp_account(self): """ Returns NetApp Account object for an existing account Return None if account does not exist """ try: account_get = self.netapp_client.accounts.get( self.parameters['resource_group'], self.parameters['name']) except CloudError: # account does not exist return None account = vars(account_get) ads = None if account.get('active_directories') is not None: ads = list() for each_ad in account.get('active_directories'): ad_dict = vars(each_ad) dns = ad_dict.get('dns') if dns is not None: ad_dict['dns'] = sorted(dns.split(',')) ads.append(ad_dict) account['active_directories'] = ads return account def create_account_request_body(self, modify=None): """ Create an Azure NetApp Account Request Body :return: None """ options = dict() location = None for attr in ('location', 'tags', 'active_directories'): value = self.parameters.get(attr) if attr == 'location' and modify is None: location = value continue if value is not None: if modify is None or attr in modify: if attr == 'active_directories': ads = list() for ad_dict in value: if ad_dict.get('dns') is not None: # API expects a string of comma separated elements ad_dict['dns'] = ','.join(ad_dict['dns']) ads.append( ActiveDirectory( **self.na_helper.filter_out_none_entries( ad_dict))) value = ads options[attr] = value if modify is None: if location is None: self.module.fail_json( msg="Error: 'location' is a required parameter") return NetAppAccount(location=location, **options) return NetAppAccountPatch(**options) def create_azure_netapp_account(self): """ Create an Azure NetApp Account :return: None """ account_body = self.create_account_request_body() try: self.netapp_client.accounts.create_or_update( body=account_body, resource_group_name=self.parameters['resource_group'], account_name=self.parameters['name']) except CloudError as error: self.module.fail_json( msg='Error creating Azure NetApp account %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def update_azure_netapp_account(self, modify): """ Create an Azure NetApp Account :return: None """ account_body = self.create_account_request_body(modify) try: self.netapp_client.accounts.update( body=account_body, resource_group_name=self.parameters['resource_group'], account_name=self.parameters['name']) except CloudError as error: self.module.fail_json( msg='Error creating Azure NetApp account %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def delete_azure_netapp_account(self): """ Delete an Azure NetApp Account :return: None """ try: self.netapp_client.accounts.delete( resource_group_name=self.parameters['resource_group'], account_name=self.parameters['name']) except CloudError as error: self.module.fail_json( msg='Error deleting Azure NetApp account %s: %s' % (self.parameters['name'], to_native(error)), exception=traceback.format_exc()) def get_changes_in_ads(self, current, desired): c_ads = current.get('active_directories') d_ads = desired.get('active_directories') if not c_ads: return desired.get('active_directories'), None if not d_ads: return None, current.get('active_directories') if len(c_ads) > 1 or len(d_ads) > 1: msg = 'Error checking for AD, currently only one AD is supported.' if len(c_ads) > 1: msg += ' Current: %s.' % str(c_ads) if len(d_ads) > 1: msg += ' Desired: %s.' % str(d_ads) self.module.fail_json( msg='Error checking for AD, currently only one AD is supported' ) changed = False d_ad = d_ads[0] c_ad = c_ads[0] for key, value in c_ad.items(): if key == 'password': if d_ad.get(key) is None: continue self.warnings.append( "module is not idempotent if 'password:'******'current: %s' % str(current)) if current is not None and cd_action is None: ads_to_add, ads_to_delete = self.get_changes_in_ads( current, self.parameters) self.parameters.pop('active_directories', None) if ads_to_add: self.parameters['active_directories'] = ads_to_add if ads_to_delete: self.module.fail_json( msg="Error: API does not support unjoining an AD", debug=self.debug) modify = self.na_helper.get_modified_attributes( current, self.parameters) if self.na_helper.changed: if self.module.check_mode: pass else: if cd_action == 'create': self.create_azure_netapp_account() elif cd_action == 'delete': self.delete_azure_netapp_account() elif modify: self.update_azure_netapp_account(modify) results = dict(changed=self.na_helper.changed, modify=modify) if self.warnings: results['warnings'] = self.warnings if self.parameters['debug']: results['debug'] = self.debug self.module.exit_json(**results)