class AzureRMNetAppCapacityPool(AzureRMModuleBase):

    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),
        )
        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)

        # authentication - using CLI
        if HAS_AZURE_MGMT_NETAPP is False:
            self.module.fail_json(msg="the python Azure-mgmt-NetApp module is required")
        if HAS_AZURE_COMMON is False:
            self.module.fail_json(msg="the python azure-common module is required")
        self.client = get_client_from_cli_profile(AzureNetAppFilesManagementClient)
        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.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
        )
        try:
            self.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 delete_azure_netapp_capacity_pool(self):
        """
            Delete a capacity pool for the given Azure NetApp Account
            :return: None
        """
        try:
            self.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):
        current = self.get_azure_netapp_capacity_pool()
        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_capacity_pool()
                elif cd_action == 'delete':
                    self.delete_azure_netapp_capacity_pool()

        self.module.exit_json(changed=self.na_helper.changed)
コード例 #2
0
class AwsCvsNetappSnapshot(object):
    """
    Contains methods to parse arguments,
    derive details of AWS_CVS objects
    and send requests to AWS CVS via
    the restApi
    """
    def __init__(self):
        """
        Parse arguments, setup state variables,
        check parameters and ensure request module is installed
        """
        self.argument_spec = netapp_utils.aws_cvs_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=True, choices=['present', 'absent']),
                 region=dict(required=True, type='str'),
                 name=dict(required=True, type='str'),
                 from_name=dict(required=False, type='str'),
                 fileSystemId=dict(required=False, type='str')))

        self.module = AnsibleModule(argument_spec=self.argument_spec,
                                    required_if=[
                                        ('state', 'present',
                                         ['name', 'fileSystemId']),
                                    ],
                                    supports_check_mode=True)

        self.na_helper = NetAppModule()

        # set up state variables
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # Calling generic AWSCVS restApi class
        self.restApi = AwsCvsRestAPI(self.module)

        # Checking for the parameters passed and create new parameters list
        self.data = {}
        for key in self.parameters.keys():
            self.data[key] = self.parameters[key]

    def getSnapshotId(self, name):
        # Check if  snapshot exists
        # Return snapshot Id  If Snapshot is found, None otherwise
        list_snapshots, error = self.restApi.get('Snapshots')

        if error:
            self.module.fail_json(msg=error)

        for snapshot in list_snapshots:
            if snapshot['name'] == name:
                return snapshot['snapshotId']
        return None

    def getfilesystemId(self):
        # Check given FileSystem is exists
        # Return fileSystemId is found, None otherwise
        list_filesystem, error = self.restApi.get('FileSystems')

        if error:
            self.module.fail_json(msg=error)
        for FileSystem in list_filesystem:
            if FileSystem['fileSystemId'] == self.parameters['fileSystemId']:
                return FileSystem['fileSystemId']
            elif FileSystem['creationToken'] == self.parameters[
                    'fileSystemId']:
                return FileSystem['fileSystemId']
        return None

    def create_snapshot(self):
        # Create Snapshot
        api = 'Snapshots'
        response, error = self.restApi.post(api, self.data)
        if error:
            self.module.fail_json(msg=error)

    def rename_snapshot(self, snapshotId):
        # Rename Snapshot
        api = 'Snapshots/' + snapshotId
        response, error = self.restApi.put(api, self.data)
        if error:
            self.module.fail_json(msg=error)

    def delete_snapshot(self, snapshotId):
        # Delete Snapshot
        api = 'Snapshots/' + snapshotId
        data = None
        response, error = self.restApi.delete(api, self.data)
        if error:
            self.module.fail_json(msg=error)

    def apply(self):
        """
        Perform pre-checks, call functions and exit
        """
        self.snapshotId = self.getSnapshotId(self.data['name'])

        if self.snapshotId is None and 'fileSystemId' in self.data:
            self.fileSystemId = self.getfilesystemId()
            self.data['fileSystemId'] = self.fileSystemId
            if self.fileSystemId is None:
                self.module.fail_json(
                    msg='Error: Specified filesystem id %s does not exist ' %
                    self.data['fileSystemId'])

        cd_action = self.na_helper.get_cd_action(self.snapshotId, self.data)
        result_message = ""
        if self.na_helper.changed:
            if self.module.check_mode:
                # Skip changes
                result_message = "Check mode, skipping changes"
            else:
                if cd_action == "delete":
                    self.delete_snapshot(self.snapshotId)
                    result_message = "Snapshot Deleted"

                elif cd_action == "create":
                    if 'from_name' in self.data:
                        # If cd_action is create and from_name is given
                        snapshotId = self.getSnapshotId(self.data['from_name'])
                        if snapshotId is not None:
                            # If resource pointed by from_name exists, rename the snapshot to name
                            self.rename_snapshot(snapshotId)
                            result_message = "Snapshot Updated"
                        else:
                            # If resource pointed by from_name does not exists, error out
                            self.module.fail_json(
                                msg="Resource does not exist : %s" %
                                self.data['from_name'])
                    else:
                        self.create_snapshot()
                        # If from_name is not defined, Create from scratch.
                        result_message = "Snapshot Created"

        self.module.exit_json(changed=self.na_helper.changed,
                              msg=result_message)
コード例 #3
0
class NetAppONTAPFirewallPolicy(object):
    def __init__(self):
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            choices=['present', 'absent'],
                            default='present'),
                 allow_list=dict(required=False, type="list"),
                 policy=dict(required=True, type='str'),
                 service=dict(required=True,
                              type='str',
                              choices=[
                                  'dns', 'http', 'https', 'ndmp', 'ndmps',
                                  'ntp', 'rsh', 'snmp', 'ssh', 'telnet'
                              ]),
                 vserver=dict(required=True, type="str"),
                 enable=dict(required=False,
                             type="str",
                             choices=['enable', 'disable'],
                             default='enable'),
                 logging=dict(required=False,
                              type="str",
                              choices=["enable", 'disable'],
                              default='disable'),
                 node=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)

        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)
        return

    def create_firewall_policy(self):
        """
        Create a firewall policy
        :return: Nothing
        """
        net_firewall_policy_obj = netapp_utils.zapi.NaElement(
            "net-firewall-policy-create")
        net_firewall_policy_obj = self.create_modify_policy(
            net_firewall_policy_obj)
        try:
            self.server.invoke_successfully(net_firewall_policy_obj,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error creating Firewall Policy: %s" %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def destroy_firewall_policy(self):
        """
        Destroy a Firewall Policy
        :return: None
        """
        net_firewall_policy_obj = netapp_utils.zapi.NaElement(
            "net-firewall-policy-destroy")
        net_firewall_policy_obj.add_new_child('policy',
                                              self.parameters['policy'])
        net_firewall_policy_obj.add_new_child('service',
                                              self.parameters['service'])
        net_firewall_policy_obj.add_new_child('vserver',
                                              self.parameters['vserver'])
        try:
            self.server.invoke_successfully(net_firewall_policy_obj,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error destroying Firewall Policy: %s" %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def get_firewall_policy(self):
        """
        Get a firewall policy
        :return: returns a firewall policy object, or returns False if there are none
        """
        net_firewall_policy_obj = netapp_utils.zapi.NaElement(
            "net-firewall-policy-get-iter")
        net_firewall_policy_info = netapp_utils.zapi.NaElement(
            "net-firewall-policy-info")
        query = netapp_utils.zapi.NaElement('query')
        net_firewall_policy_info.add_new_child('policy',
                                               self.parameters['policy'])
        query.add_child_elem(net_firewall_policy_info)
        net_firewall_policy_obj.add_child_elem(query)
        result = self.server.invoke_successfully(net_firewall_policy_obj, True)
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) == 1:
            return result
        return False

    def modify_firewall_policy(self):
        """
        Modify a firewall Policy
        :return: none
        """
        net_firewall_policy_obj = netapp_utils.zapi.NaElement(
            "net-firewall-policy-modify")
        net_firewall_policy_obj = self.create_modify_policy(
            net_firewall_policy_obj)
        try:
            self.server.invoke_successfully(net_firewall_policy_obj,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error modifying Firewall Policy: %s" %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def create_modify_policy(self, net_firewall_policy_obj):
        """
        Set up the parameters for creating or modifying a policy
        :param net_firewall_policy_obj: The Firewall policy to modify
        :return:
        """
        net_firewall_policy_obj.add_new_child('policy',
                                              self.parameters['policy'])
        net_firewall_policy_obj.add_new_child('service',
                                              self.parameters['service'])
        net_firewall_policy_obj.add_new_child('vserver',
                                              self.parameters['vserver'])
        allow_ip_list = netapp_utils.zapi.NaElement("allow-list")
        for each in self.parameters['allow_list']:
            net_firewall_policy_ip = netapp_utils.zapi.NaElement("ip-and-mask")
            net_firewall_policy_ip.set_content(each)
            allow_ip_list.add_child_elem(net_firewall_policy_ip)
        net_firewall_policy_obj.add_child_elem(allow_ip_list)
        return net_firewall_policy_obj

    def get_firewall_config(self):
        """
        Get a firewall configuration
        :return: the firewall configuration
        """
        net_firewall_config_obj = netapp_utils.zapi.NaElement(
            "net-firewall-config-get")
        net_firewall_config_obj.add_new_child('node-name',
                                              self.parameters['node'])
        try:
            result = self.server.invoke_successfully(net_firewall_config_obj,
                                                     True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg="Error getting Firewall Configuration: %s" %
                (to_native(error)),
                exception=traceback.format_exc())
        return result

    def check_policy(self, policy):
        """
        Check to see if a policy has been changed or not
        :param policy: policy to check
        :return: True if the policy has changed, False if there are no changes
        """
        changed = False
        attributes_list = policy.get_child_by_name('attributes-list')
        policy_info = attributes_list.get_child_by_name(
            'net-firewall-policy-info')
        allow_list = policy_info.get_child_by_name('allow-list')
        for each in allow_list.get_children():
            if each.get_content() not in self.parameters['allow_list']:
                changed = True
        if self.parameters['service'] != policy_info.get_child_by_name(
                'service').get_content():
            changed = True
        if self.parameters['policy'] != policy_info.get_child_by_name(
                'policy').get_content():
            changed = True
        return changed

    def modify_firewall_config(self):
        """
        Modify the configuration of a firewall
        :return: none
        """
        net_firewall_config_obj = netapp_utils.zapi.NaElement(
            "net-firewall-config-modify")
        net_firewall_config_obj.add_new_child('node-name',
                                              self.parameters['node'])
        net_firewall_config_obj.add_new_child('is-enabled',
                                              self.parameters['enable'])
        net_firewall_config_obj.add_new_child('is-logging',
                                              self.parameters['logging'])
        try:
            self.server.invoke_successfully(net_firewall_config_obj,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error modifying Firewall Config: %s" %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def check_config(self, config):
        """
        check to see if a firewall configuration has changed or not
        :param config: The configuration to check
        :return: true if it has changed, false if it has not
        """
        changed = False
        attributes_list = config.get_child_by_name('attributes')
        firewall_info = attributes_list.get_child_by_name(
            'net-firewall-config-info')
        enable = firewall_info.get_child_by_name('is-enabled')
        logging = firewall_info.get_child_by_name('is-logging')
        if self.parameters['enable'] == 'enable':
            is_enable = "true"
        else:
            is_enable = "false"
        if enable != is_enable:
            changed = True
        if self.parameters['logging'] == 'logging':
            is_logging = "true"
        else:
            is_logging = "false"
        if logging != is_logging:
            changed = True
        return changed

    def apply(self):
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event("na_ontap_firewall_policy", cserver)
        changed = False
        if self.parameters['state'] == 'present':
            policy = self.get_firewall_policy()
            if not policy:
                self.create_firewall_policy()
                if not self.check_config(self.get_firewall_config()):
                    self.modify_firewall_config()
                changed = True
            else:
                if self.check_policy(policy):
                    self.modify_firewall_policy()
                    changed = True
                if not self.check_config(self.get_firewall_config()):
                    self.modify_firewall_config()
                    changed = True
        else:
            if self.get_firewall_policy():
                self.destroy_firewall_policy()
                if not self.check_config(self.get_firewall_config()):
                    self.modify_firewall_config()
                changed = True
            else:
                if not self.check_config(self.get_firewall_config()):
                    self.modify_firewall_config()
                    changed = True
        self.module.exit_json(changed=changed)
コード例 #4
0
class NetAppONTAPMotd(object):
    def __init__(self):
        argument_spec = netapp_utils.na_ontap_host_argument_spec()
        argument_spec.update(
            dict(state=dict(required=False,
                            default='present',
                            choices=['present', 'absent']),
                 vserver=dict(required=True, type='str'),
                 message=dict(default='', type='str'),
                 show_cluster_motd=dict(default=True, type='bool')))

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

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        if HAS_NETAPP_LIB is False:
            self.module.fail_json(
                msg="the python NetApp-Lib module is required")

        self.server = netapp_utils.setup_na_ontap_zapi(
            module=self.module, vserver=self.parameters['vserver'])

    def motd_get_iter(self):
        """
        Compose NaElement object to query current motd
        :return: NaElement object for vserver-motd-get-iter
        """
        motd_get_iter = netapp_utils.zapi.NaElement('vserver-motd-get-iter')
        query = netapp_utils.zapi.NaElement('query')
        motd_info = netapp_utils.zapi.NaElement('vserver-motd-info')
        motd_info.add_new_child('is-cluster-message-enabled',
                                str(self.parameters['show_cluster_motd']))
        motd_info.add_new_child('vserver', self.parameters['vserver'])
        query.add_child_elem(motd_info)
        motd_get_iter.add_child_elem(query)
        return motd_get_iter

    def motd_get(self):
        """
        Get current motd
        :return: Dictionary of current motd details if query successful, else None
        """
        motd_get_iter = self.motd_get_iter()
        motd_result = dict()
        try:
            result = self.server.invoke_successfully(motd_get_iter,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching motd info: %s' %
                                  to_native(error),
                                  exception=traceback.format_exc())
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) > 0:
            motd_info = result.get_child_by_name(
                'attributes-list').get_child_by_name('vserver-motd-info')
            motd_result['message'] = motd_info.get_child_content('message')
            motd_result['message'] = str(motd_result['message']).rstrip()
            motd_result[
                'show_cluster_motd'] = True if motd_info.get_child_content(
                    'is-cluster-message-enabled') == 'true' else False
            motd_result['vserver'] = motd_info.get_child_content('vserver')
            return motd_result
        return None

    def modify_motd(self):
        motd_create = netapp_utils.zapi.NaElement('vserver-motd-modify-iter')
        motd_create.add_new_child('message', self.parameters['message'])
        motd_create.add_new_child(
            'is-cluster-message-enabled', 'true'
            if self.parameters['show_cluster_motd'] is True else 'false')
        query = netapp_utils.zapi.NaElement('query')
        motd_info = netapp_utils.zapi.NaElement('vserver-motd-info')
        motd_info.add_new_child('vserver', self.parameters['vserver'])
        query.add_child_elem(motd_info)
        motd_create.add_child_elem(query)
        try:
            self.server.invoke_successfully(motd_create,
                                            enable_tunneling=False)
        except netapp_utils.zapi.NaApiError as err:
            self.module.fail_json(msg="Error creating motd: %s" %
                                  (to_native(err)),
                                  exception=traceback.format_exc())
        return motd_create

    def apply(self):
        """
        Applies action from playbook
        """
        netapp_utils.ems_log_event("na_ontap_motd", self.server)
        current = self.motd_get()
        if self.parameters['state'] == 'present' and self.parameters[
                'message'] == "":
            self.module.fail_json(msg="message parameter cannot be empty")
        if self.parameters['state'] == 'absent':
            # Just make sure it is empty
            self.parameters['message'] = ''
            if current['message'] == 'None':
                current = None
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        if cd_action is None and self.parameters['state'] == 'present':
            self.na_helper.get_modified_attributes(current, self.parameters)

        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                self.modify_motd()
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #5
0
class NetAppONTAPNVMe(object):
    """
    Class with NVMe service methods
    """

    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            state=dict(type='str', default='present', choices=['absent', 'present']),
            vserver=dict(type='str', required=True),
            status_admin=dict(type='bool'),
        )

        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)

        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_nvme(self):
        """
        Get current nvme details
        :return: dict if nvme exists, None otherwise
        """
        nvme_get = netapp_utils.zapi.NaElement('nvme-get-iter')
        query = {
            'query': {
                'nvme-target-service-info': {
                    'vserver': self.parameters['vserver']
                }
            }
        }
        nvme_get.translate_struct(query)
        try:
            result = self.server.invoke_successfully(nvme_get, enable_tunneling=False)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching nvme info: %s' % to_native(error))
        if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
            attributes_list = result.get_child_by_name('attributes-list')
            nvme_info = attributes_list.get_child_by_name('nvme-target-service-info')
            return_value = {'status_admin': nvme_info.get_child_content('is-available')}
            return return_value
        return None

    def create_nvme(self):
        """
        Create NVMe service
        """
        nvme_create = netapp_utils.zapi.NaElement('nvme-create')
        if self.parameters.get('status_admin') is not None:
            options = {'is-available': self.parameters['status_admin']}
            nvme_create.translate_struct(options)
        try:
            self.server.invoke_successfully(nvme_create, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating nvme for vserver %s: %s'
                                  % (self.parameters['vserver'], to_native(error)))

    def delete_nvme(self):
        """
        Delete NVMe service
        """
        nvme_delete = netapp_utils.zapi.NaElement('nvme-delete')
        try:
            self.server.invoke_successfully(nvme_delete, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting nvme for vserver %s: %s'
                                  % (self.parameters['vserver'], to_native(error)))

    def modify_nvme(self, status=None):
        """
        Modify NVMe service
        """
        if status is None:
            status = self.parameters['status_admin']
        options = {'is-available': status}
        nvme_modify = netapp_utils.zapi.NaElement('nvme-modify')
        nvme_modify.translate_struct(options)
        try:
            self.server.invoke_successfully(nvme_modify, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error modifying nvme for vserver %s: %s'
                                  % (self.parameters['vserver'], to_native(error)))

    def apply(self):
        """
        Apply action to NVMe service
        """
        netapp_utils.ems_log_event("na_ontap_nvme", self.server)
        current = self.get_nvme()
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        if self.parameters.get('status_admin') is not None:
            self.parameters['status_admin'] = self.na_helper.get_value_for_bool(False, self.parameters['status_admin'])
            if cd_action is None and self.parameters['state'] == 'present':
                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_nvme()
                elif cd_action == 'delete':
                    # NVMe status_admin needs to be down before deleting it
                    self.modify_nvme('false')
                    self.delete_nvme()
                elif modify:
                    self.modify_nvme()

        self.module.exit_json(changed=self.na_helper.changed)
コード例 #6
0
ファイル: na_ontap_quotas.py プロジェクト: tklebanoff/ansible
class NetAppONTAPQuotas(object):
    '''Class with quotas methods'''
    def __init__(self):

        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'),
                 volume=dict(required=True, type='str'),
                 quota_target=dict(required=True, type='str'),
                 qtree=dict(required=False, type='str', default=""),
                 type=dict(required=True,
                           type='str',
                           choices=['user', 'group', 'tree']),
                 policy=dict(required=False, type='str'),
                 set_quota_status=dict(required=False, type='bool'),
                 file_limit=dict(required=False, type='str', default='-'),
                 disk_limit=dict(required=False, type='str', default='-'),
                 threshold=dict(required=False, type='str', default='-')))

        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)

        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_quota_status(self):
        """
        Return details about the quota status
        :param:
            name : volume name
        :return: status of the quota. None if not found.
        :rtype: dict
        """
        quota_status_get = netapp_utils.zapi.NaElement('quota-status')
        quota_status_get.translate_struct(
            {'volume': self.parameters['volume']})
        try:
            result = self.server.invoke_successfully(quota_status_get,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching quotas status info: %s' %
                                  to_native(error),
                                  exception=traceback.format_exc())
        if result:
            return result['status']
        return None

    def get_quotas(self):
        """
        Get quota details
        :return: name of volume if quota exists, None otherwise
        """
        quota_get = netapp_utils.zapi.NaElement('quota-list-entries-iter')
        query = {
            'query': {
                'quota-entry': {
                    'volume': self.parameters['volume'],
                    'quota-target': self.parameters['quota_target'],
                    'quota-type': self.parameters['type']
                }
            }
        }
        quota_get.translate_struct(query)
        if self.parameters.get('policy'):
            quota_get['query']['quota-entry'].add_new_child(
                'policy', self.parameters['policy'])
        try:
            result = self.server.invoke_successfully(quota_get,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching quotas info: %s' %
                                  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_values = {
                'volume':
                result['attributes-list']['quota-entry']['volume'],
                'file_limit':
                result['attributes-list']['quota-entry']['file-limit'],
                'disk_limit':
                result['attributes-list']['quota-entry']['disk-limit'],
                'threshold':
                result['attributes-list']['quota-entry']['threshold']
            }
            return return_values
        return None

    def quota_entry_set(self):
        """
        Adds a quota entry
        """
        options = {
            'volume': self.parameters['volume'],
            'quota-target': self.parameters['quota_target'],
            'quota-type': self.parameters['type'],
            'qtree': self.parameters['qtree'],
            'file-limit': self.parameters['file_limit'],
            'disk-limit': self.parameters['disk_limit'],
            'threshold': self.parameters['threshold']
        }
        if self.parameters.get('policy'):
            options['policy'] = self.parameters['policy']
        set_entry = netapp_utils.zapi.NaElement.create_node_with_children(
            'quota-set-entry', **options)
        try:
            self.server.invoke_successfully(set_entry, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error adding/modifying quota entry %s: %s' %
                (self.parameters['volume'], to_native(error)),
                exception=traceback.format_exc())

    def quota_entry_delete(self):
        """
        Deletes a quota entry
        """
        options = {
            'volume': self.parameters['volume'],
            'quota-target': self.parameters['quota_target'],
            'quota-type': self.parameters['type'],
            'qtree': self.parameters['qtree']
        }
        set_entry = netapp_utils.zapi.NaElement.create_node_with_children(
            'quota-delete-entry', **options)
        if self.parameters.get('policy'):
            set_entry.add_new_child('policy', self.parameters['policy'])
        try:
            self.server.invoke_successfully(set_entry, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error deleting quota entry %s: %s' %
                (self.parameters['volume'], to_native(error)),
                exception=traceback.format_exc())

    def quota_entry_modify(self, modify_attrs):
        """
        Modifies a quota entry
        """
        options = {
            'volume': self.parameters['volume'],
            'quota-target': self.parameters['quota_target'],
            'quota-type': self.parameters['type'],
            'qtree': self.parameters['qtree']
        }
        options.update(modify_attrs)
        if self.parameters.get('policy'):
            options['policy'] = str(self.parameters['policy'])
        modify_entry = netapp_utils.zapi.NaElement.create_node_with_children(
            'quota-modify-entry', **options)
        try:
            self.server.invoke_successfully(modify_entry,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error modifying quota entry %s: %s' %
                (self.parameters['volume'], to_native(error)),
                exception=traceback.format_exc())

    def on_or_off_quota(self, status):
        """
        on or off quota
        """
        quota = netapp_utils.zapi.NaElement.create_node_with_children(
            status, **{'volume': self.parameters['volume']})
        try:
            self.server.invoke_successfully(quota, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error setting %s for %s: %s' %
                (status, self.parameters['volume'], to_native(error)),
                exception=traceback.format_exc())

    def apply(self):
        """
        Apply action to quotas
        """
        netapp_utils.ems_log_event("na_ontap_quotas", self.server)
        modify_quota_status = None
        modify_quota = None
        current = self.get_quotas()
        if 'set_quota_status' in self.parameters:
            quota_status = self.get_quota_status()
            if quota_status is not None:
                quota_status_action = self.na_helper.get_modified_attributes(
                    {
                        'set_quota_status':
                        True if quota_status == 'on' else False
                    }, self.parameters)
                if quota_status_action:
                    modify_quota_status = 'quota-on' if quota_status_action[
                        'set_quota_status'] else 'quota-off'
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        if cd_action is None:
            modify_quota = 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.quota_entry_set()
                elif cd_action == 'delete':
                    self.quota_entry_delete()
                elif modify_quota is not None:
                    for key in list(modify_quota):
                        modify_quota[key.replace("_",
                                                 "-")] = modify_quota.pop(key)
                    self.quota_entry_modify(modify_quota)
                if modify_quota_status is not None:
                    self.on_or_off_quota(modify_quota_status)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #7
0
class NetAppOntapPorts(object):
    def __init__(self):
        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=False, type='str'),
                names=dict(required=True, type='list'),
                resource_name=dict(required=True, type='str'),
                resource_type=dict(required=True,
                                   type='str',
                                   choices=['broadcast_domain', 'portset']),
                ipspace=dict(required=False, type='str'),
                portset_type=dict(required=False,
                                  type='str',
                                  choices=['fcp', 'iscsi', 'mixed']),
            ))

        self.module = AnsibleModule(argument_spec=self.argument_spec,
                                    required_if=[
                                        ('resource_type', 'portset',
                                         ['vserver']),
                                    ],
                                    supports_check_mode=True)

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        if HAS_NETAPP_LIB is False:
            self.module.fail_json(
                msg="the python NetApp-Lib module is required")
        else:
            if self.parameters['resource_type'] == 'broadcast_domain':
                self.server = netapp_utils.setup_na_ontap_zapi(
                    module=self.module)
            elif self.parameters['resource_type'] == 'portset':
                self.server = netapp_utils.setup_na_ontap_zapi(
                    module=self.module, vserver=self.parameters['vserver'])

    def add_broadcast_domain_ports(self, ports):
        """
        Add broadcast domain ports
        :param: ports to be added.
        """
        domain_obj = netapp_utils.zapi.NaElement(
            'net-port-broadcast-domain-add-ports')
        domain_obj.add_new_child("broadcast-domain",
                                 self.parameters['resource_name'])
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        ports_obj = netapp_utils.zapi.NaElement('ports')
        domain_obj.add_child_elem(ports_obj)
        for port in ports:
            ports_obj.add_new_child('net-qualified-port-name', port)
        try:
            self.server.invoke_successfully(domain_obj, True)
            return True
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error adding port for broadcast domain %s: %s' %
                (self.parameters['resource_name'], to_native(error)),
                exception=traceback.format_exc())

    def remove_broadcast_domain_ports(self, ports):
        """
        Deletes broadcast domain ports
        :param: ports to be removed.
        """
        domain_obj = netapp_utils.zapi.NaElement(
            'net-port-broadcast-domain-remove-ports')
        domain_obj.add_new_child("broadcast-domain",
                                 self.parameters['resource_name'])
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        ports_obj = netapp_utils.zapi.NaElement('ports')
        domain_obj.add_child_elem(ports_obj)
        for port in ports:
            ports_obj.add_new_child('net-qualified-port-name', port)
        try:
            self.server.invoke_successfully(domain_obj, True)
            return True
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error removing port for broadcast domain %s: %s' %
                (self.parameters['resource_name'], to_native(error)),
                exception=traceback.format_exc())

    def get_broadcast_domain_ports(self):
        """
        Return details about the broadcast domain ports.
        :return: Details about the broadcast domain ports. [] if not found.
        :rtype: list
        """
        domain_get_iter = netapp_utils.zapi.NaElement(
            'net-port-broadcast-domain-get-iter')
        broadcast_domain_info = netapp_utils.zapi.NaElement(
            'net-port-broadcast-domain-info')
        broadcast_domain_info.add_new_child('broadcast-domain',
                                            self.parameters['resource_name'])
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(broadcast_domain_info)
        domain_get_iter.add_child_elem(query)
        result = self.server.invoke_successfully(domain_get_iter, True)
        ports = []
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) == 1:
            domain_info = result.get_child_by_name(
                'attributes-list').get_child_by_name(
                    'net-port-broadcast-domain-info')
            domain_ports = domain_info.get_child_by_name('ports')
            if domain_ports is not None:
                ports = [
                    port.get_child_content('port')
                    for port in domain_ports.get_children()
                ]
        return ports

    def remove_portset_ports(self, port):
        """
        Removes all existing ports from portset
        :return: None
        """
        options = {
            'portset-name': self.parameters['resource_name'],
            'portset-port-name': port.strip()
        }

        portset_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'portset-remove', **options)

        try:
            self.server.invoke_successfully(portset_modify,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error removing port in portset %s: %s' %
                (self.parameters['resource_name'], to_native(error)),
                exception=traceback.format_exc())

    def add_portset_ports(self, port):
        """
        Add the list of ports to portset
        :return: None
        """
        options = {
            'portset-name': self.parameters['resource_name'],
            'portset-port-name': port.strip()
        }

        portset_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'portset-add', **options)

        try:
            self.server.invoke_successfully(portset_modify,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error adding port in portset %s: %s' %
                (self.parameters['resource_name'], to_native(error)),
                exception=traceback.format_exc())

    def portset_get_iter(self):
        """
        Compose NaElement object to query current portset using vserver, portset-name and portset-type parameters
        :return: NaElement object for portset-get-iter with query
        """
        portset_get = netapp_utils.zapi.NaElement('portset-get-iter')
        query = netapp_utils.zapi.NaElement('query')
        portset_info = netapp_utils.zapi.NaElement('portset-info')
        portset_info.add_new_child('vserver', self.parameters['vserver'])
        portset_info.add_new_child('portset-name',
                                   self.parameters['resource_name'])
        if self.parameters.get('portset_type'):
            portset_info.add_new_child('portset-type',
                                       self.parameters['portset_type'])
        query.add_child_elem(portset_info)
        portset_get.add_child_elem(query)
        return portset_get

    def portset_get(self):
        """
        Get current portset info
        :return: List of current ports if query successful, else return []
        """
        portset_get_iter = self.portset_get_iter()
        result, ports = None, []
        try:
            result = self.server.invoke_successfully(portset_get_iter,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error fetching portset %s: %s' %
                (self.parameters['resource_name'], to_native(error)),
                exception=traceback.format_exc())
        # return portset details
        if result.get_child_by_name('num-records') and int(
                result.get_child_content('num-records')) > 0:
            portset_get_info = result.get_child_by_name(
                'attributes-list').get_child_by_name('portset-info')
            if int(portset_get_info.get_child_content(
                    'portset-port-total')) > 0:
                port_info = portset_get_info.get_child_by_name(
                    'portset-port-info')
                ports = [
                    port.get_content() for port in port_info.get_children()
                ]
        return ports

    def modify_broadcast_domain_ports(self):
        """
        compare current and desire ports. Call add or remove ports methods if needed.
        :return: None.
        """
        current_ports = self.get_broadcast_domain_ports()
        cd_ports = self.parameters['names']
        if self.parameters['state'] == 'present':
            ports_to_add = [
                port for port in cd_ports if port not in current_ports
            ]
            if len(ports_to_add) > 0:
                self.add_broadcast_domain_ports(ports_to_add)
                self.na_helper.changed = True

        if self.parameters['state'] == 'absent':
            ports_to_remove = [
                port for port in cd_ports if port in current_ports
            ]
            if len(ports_to_remove) > 0:
                self.remove_broadcast_domain_ports(ports_to_remove)
                self.na_helper.changed = True

    def modify_portset_ports(self):
        current_ports = self.portset_get()
        cd_ports = self.parameters['names']
        if self.parameters['state'] == 'present':
            ports_to_add = [
                port for port in cd_ports if port not in current_ports
            ]
            if len(ports_to_add) > 0:
                for port in ports_to_add:
                    self.add_portset_ports(port)
                self.na_helper.changed = True

        if self.parameters['state'] == 'absent':
            ports_to_remove = [
                port for port in cd_ports if port in current_ports
            ]
            if len(ports_to_remove) > 0:
                for port in ports_to_remove:
                    self.remove_portset_ports(port)
                self.na_helper.changed = True

    def apply(self):
        self.asup_log_for_cserver("na_ontap_ports")
        if self.parameters['resource_type'] == 'broadcast_domain':
            self.modify_broadcast_domain_ports()
        elif self.parameters['resource_type'] == 'portset':
            self.modify_portset_ports()
        self.module.exit_json(changed=self.na_helper.changed)

    def asup_log_for_cserver(self, event_name):
        """
        Fetch admin vserver for the given cluster
        Create and Autosupport log event with the given module name
        :param event_name: Name of the event log
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event(event_name, cserver)
コード例 #8
0
class NetAppONTAPClusterPeer(object):
    """
    Class with cluster peer methods
    """
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            type='str',
                            choices=['present', 'absent'],
                            default='present'),
                 source_intercluster_lif=dict(required=False, type='str'),
                 dest_intercluster_lif=dict(required=False, type='str'),
                 passphrase=dict(required=False, type='str', no_log=True),
                 dest_hostname=dict(required=True, type='str'),
                 dest_username=dict(required=False, type='str'),
                 dest_password=dict(required=False, type='str', no_log=True),
                 source_cluster_name=dict(required=False, type='str'),
                 dest_cluster_name=dict(required=False, type='str')))

        self.module = AnsibleModule(argument_spec=self.argument_spec,
                                    required_together=[[
                                        'source_intercluster_lif',
                                        'dest_intercluster_lif', 'passphrase'
                                    ]],
                                    required_if=[('state', 'absent', [
                                        'source_cluster_name',
                                        'dest_cluster_name'
                                    ])],
                                    supports_check_mode=True)

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        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)
            # set destination server connection
            self.module.params['hostname'] = self.parameters['dest_hostname']
            if self.parameters.get('dest_username'):
                self.module.params['username'] = self.parameters[
                    'dest_username']
            if self.parameters.get('dest_password'):
                self.module.params['password'] = self.parameters[
                    'dest_password']
            self.dest_server = netapp_utils.setup_na_ontap_zapi(
                module=self.module)

    def cluster_peer_get_iter(self, cluster):
        """
        Compose NaElement object to query current source cluster using peer-cluster-name and peer-addresses parameters
        :param cluster: type of cluster (source or destination)
        :return: NaElement object for cluster-get-iter with query
        """
        cluster_peer_get = netapp_utils.zapi.NaElement('cluster-peer-get-iter')
        query = netapp_utils.zapi.NaElement('query')
        cluster_peer_info = netapp_utils.zapi.NaElement('cluster-peer-info')
        if cluster == 'source':
            peer_lif, peer_cluster = 'dest_intercluster_lif', 'dest_cluster_name'
        else:
            peer_lif, peer_cluster = 'source_intercluster_lif', 'source_cluster_name'
        peer_addresses = netapp_utils.zapi.NaElement('peer-addresses')
        if self.parameters.get(peer_lif):
            peer_addresses.add_new_child('remote-inet-address',
                                         self.parameters[peer_lif])
            cluster_peer_info.add_child_elem(peer_addresses)
        if self.parameters.get(peer_cluster):
            cluster_peer_info.add_new_child('cluster-name',
                                            self.parameters[peer_cluster])
        query.add_child_elem(cluster_peer_info)
        cluster_peer_get.add_child_elem(query)
        return cluster_peer_get

    def cluster_peer_get(self, cluster):
        """
        Get current cluster peer info
        :param cluster: type of cluster (source or destination)
        :return: Dictionary of current cluster peer details if query successful, else return None
        """
        cluster_peer_get_iter = self.cluster_peer_get_iter(cluster)
        cluster_info = dict()
        if cluster == 'source':
            server = self.server
        else:
            server = self.dest_server
        try:
            result = server.invoke_successfully(cluster_peer_get_iter,
                                                enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error fetching cluster peer %s: %s' %
                (self.parameters['dest_cluster_name'], to_native(error)),
                exception=traceback.format_exc())
        # return cluster peer details
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) >= 1:
            cluster_peer_info = result.get_child_by_name(
                'attributes-list').get_child_by_name('cluster-peer-info')
            cluster_info['cluster_name'] = cluster_peer_info.get_child_content(
                'cluster-name')
            peers = cluster_peer_info.get_child_by_name('peer-addresses')
            cluster_info['peer-addresses'] = [
                peer.get_content() for peer in peers.get_children()
            ]
            return cluster_info
        return None

    def cluster_peer_delete(self, cluster):
        """
        Delete a cluster peer on source or destination
        For source cluster, peer cluster-name = destination cluster name and vice-versa
        :param cluster: type of cluster (source or destination)
        :return:
        """
        if cluster == 'source':
            server, peer_cluster_name = self.server, self.parameters[
                'dest_cluster_name']
        else:
            server, peer_cluster_name = self.dest_server, self.parameters[
                'source_cluster_name']
        cluster_peer_delete = netapp_utils.zapi.NaElement.create_node_with_children(
            'cluster-peer-delete', **{'cluster-name': peer_cluster_name})
        try:
            server.invoke_successfully(cluster_peer_delete,
                                       enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting cluster peer %s: %s' %
                                  (peer_cluster_name, to_native(error)),
                                  exception=traceback.format_exc())

    def cluster_peer_create(self, cluster):
        """
        Create a cluster peer on source or destination
        For source cluster, peer address = destination inter-cluster LIF and vice-versa
        :param cluster: type of cluster (source or destination)
        :return: None
        """
        cluster_peer_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'cluster-peer-create',
            **{'passphrase': self.parameters['passphrase']})
        peer_addresses = netapp_utils.zapi.NaElement('peer-addresses')
        if cluster == 'source':
            server, peer_address = self.server, self.parameters[
                'dest_intercluster_lif']
        else:
            server, peer_address = self.dest_server, self.parameters[
                'source_intercluster_lif']
        peer_addresses.add_new_child('remote-inet-address', peer_address)
        cluster_peer_create.add_child_elem(peer_addresses)
        try:
            server.invoke_successfully(cluster_peer_create,
                                       enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating cluster peer %s: %s' %
                                  (peer_address, to_native(error)),
                                  exception=traceback.format_exc())

    def apply(self):
        """
        Apply action to cluster peer
        :return: None
        """
        source = self.cluster_peer_get('source')
        destination = self.cluster_peer_get('destination')
        source_action = self.na_helper.get_cd_action(source, self.parameters)
        destination_action = self.na_helper.get_cd_action(
            destination, self.parameters)
        self.na_helper.changed = False
        # create only if expected cluster peer relation is not present on both source and destination clusters
        if source_action == 'create' and destination_action == 'create':
            self.cluster_peer_create('source')
            self.cluster_peer_create('destination')
            self.na_helper.changed = True
        # delete peer relation in cluster where relation is present
        else:
            if source_action == 'delete':
                self.cluster_peer_delete('source')
                self.na_helper.changed = True
            if destination_action == 'delete':
                self.cluster_peer_delete('destination')
                self.na_helper.changed = True

        self.module.exit_json(changed=self.na_helper.changed)
コード例 #9
0
ファイル: na_ontap_qtree.py プロジェクト: zzhang01/ansible
class NetAppOntapQTree(object):
    '''Class with qtree operations'''
    def __init__(self):
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(
                state=dict(required=False,
                           choices=['present', 'absent'],
                           default='present'),
                name=dict(required=True, type='str'),
                from_name=dict(required=False, type='str'),
                flexvol_name=dict(type='str'),
                vserver=dict(required=True, type='str'),
                export_policy=dict(required=False, type='str'),
                security_style=dict(required=False,
                                    choices=['unix', 'ntfs', 'mixed']),
                oplocks=dict(required=False, choices=['enabled', 'disabled']),
                unix_permissions=dict(required=False, type='str'),
            ))

        self.module = AnsibleModule(argument_spec=self.argument_spec,
                                    required_if=[('state', 'present',
                                                  ['flexvol_name'])],
                                    supports_check_mode=True)
        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        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_qtree(self, name=None):
        """
        Checks if the qtree exists.
        :param:
            name : qtree name
        :return:
            Details about the qtree
            False if qtree is not found
        :rtype: bool
        """
        if name is None:
            name = self.parameters['name']

        qtree_list_iter = netapp_utils.zapi.NaElement('qtree-list-iter')
        query_details = netapp_utils.zapi.NaElement.create_node_with_children(
            'qtree-info', **{
                'vserver': self.parameters['vserver'],
                'volume': self.parameters['flexvol_name'],
                'qtree': name
            })
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(query_details)
        qtree_list_iter.add_child_elem(query)
        result = self.server.invoke_successfully(qtree_list_iter,
                                                 enable_tunneling=True)
        return_q = False
        if (result.get_child_by_name('num-records')
                and int(result.get_child_content('num-records')) >= 1):
            return_q = {
                'export_policy':
                result['attributes-list']['qtree-info']['export-policy'],
                'unix_permissions':
                result['attributes-list']['qtree-info']['mode'],
                'oplocks':
                result['attributes-list']['qtree-info']['oplocks'],
                'security_style':
                result['attributes-list']['qtree-info']['security-style']
            }

        return return_q

    def create_qtree(self):
        """
        Create a qtree
        """
        options = {
            'qtree': self.parameters['name'],
            'volume': self.parameters['flexvol_name']
        }
        if self.parameters.get('export_policy'):
            options['export-policy'] = self.parameters['export_policy']
        if self.parameters.get('security_style'):
            options['security-style'] = self.parameters['security_style']
        if self.parameters.get('oplocks'):
            options['oplocks'] = self.parameters['oplocks']
        if self.parameters.get('unix_permissions'):
            options['mode'] = self.parameters['unix_permissions']
        qtree_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'qtree-create', **options)
        try:
            self.server.invoke_successfully(qtree_create,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error provisioning qtree %s: %s" %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_qtree(self):
        """
        Delete a qtree
        """
        path = '/vol/%s/%s' % (self.parameters['flexvol_name'],
                               self.parameters['name'])
        qtree_delete = netapp_utils.zapi.NaElement.create_node_with_children(
            'qtree-delete', **{'qtree': path})

        try:
            self.server.invoke_successfully(qtree_delete,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error deleting qtree %s: %s" %
                                  (path, to_native(error)),
                                  exception=traceback.format_exc())

    def rename_qtree(self):
        """
        Rename a qtree
        """
        path = '/vol/%s/%s' % (self.parameters['flexvol_name'],
                               self.parameters['from_name'])
        new_path = '/vol/%s/%s' % (self.parameters['flexvol_name'],
                                   self.parameters['name'])
        qtree_rename = netapp_utils.zapi.NaElement.create_node_with_children(
            'qtree-rename', **{
                'qtree': path,
                'new-qtree-name': new_path
            })

        try:
            self.server.invoke_successfully(qtree_rename,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg="Error renaming qtree %s: %s" %
                (self.parameters['from_name'], to_native(error)),
                exception=traceback.format_exc())

    def modify_qtree(self):
        """
        Modify a qtree
        """
        options = {
            'qtree': self.parameters['name'],
            'volume': self.parameters['flexvol_name']
        }
        if self.parameters.get('export_policy'):
            options['export-policy'] = self.parameters['export_policy']
        if self.parameters.get('security_style'):
            options['security-style'] = self.parameters['security_style']
        if self.parameters.get('oplocks'):
            options['oplocks'] = self.parameters['oplocks']
        if self.parameters.get('unix_permissions'):
            options['mode'] = self.parameters['unix_permissions']
        qtree_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'qtree-modify', **options)
        try:
            self.server.invoke_successfully(qtree_modify,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error modifying qtree %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def apply(self):
        '''Call create/delete/modify/rename operations'''
        # changed = False
        # rename_qtree = False
        # modified_qtree = None
        changed, rename_qtree, modified_qtree = False, False, None
        netapp_utils.ems_log_event("na_ontap_qtree", self.server)
        qtree_detail = self.get_qtree()
        if qtree_detail:
            # delete or modify qtree
            if self.parameters['state'] == 'absent':  # delete
                changed = True
            else:
                modified_qtree = self.na_helper.get_modified_attributes(
                    qtree_detail, self.parameters)
                if modified_qtree is not None:
                    changed = True
        elif self.parameters['state'] == 'present':
            # create or rename qtree
            if self.parameters.get('from_name'):
                if self.get_qtree(self.parameters['from_name']) is None:
                    self.module.fail_json(
                        msg="Error renaming qtree %s: does not exists" %
                        self.parameters['from_name'])
                else:
                    changed = True
                    rename_qtree = True
            else:
                changed = True
        if changed:
            if self.module.check_mode:
                pass
            else:
                if self.parameters['state'] == 'present':
                    if rename_qtree:
                        self.rename_qtree()
                    elif modified_qtree:
                        self.modify_qtree()
                    else:
                        self.create_qtree()
                elif self.parameters['state'] == 'absent':
                    self.delete_qtree()

        self.module.exit_json(changed=changed)
コード例 #10
0
class NetAppOntapAdaptiveQosPolicyGroup(object):
    """
    Create, delete, modify and rename a policy group.
    """
    def __init__(self):
        """
        Initialize the Ontap qos policy group class.
        """
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            type='str',
                            choices=['present', 'absent'],
                            default='present'),
                 name=dict(required=True, type='str'),
                 from_name=dict(required=False, type='str'),
                 vserver=dict(required=True, type='str'),
                 absolute_min_iops=dict(required=False, type='str'),
                 expected_iops=dict(required=False, type='str'),
                 peak_iops=dict(required=False, type='str'),
                 peak_iops_allocation=dict(
                     choices=['allocated_space', 'used_space'],
                     default='used_space'),
                 force=dict(required=False, type='bool', default=False)))

        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)

        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)

    def get_policy_group(self, policy_group_name=None):
        """
        Return details of a policy group.
        :param policy_group_name: policy group name
        :return: policy group details.
        :rtype: dict.
        """
        if policy_group_name is None:
            policy_group_name = self.parameters['name']
        policy_group_get_iter = netapp_utils.zapi.NaElement(
            'qos-adaptive-policy-group-get-iter')
        policy_group_info = netapp_utils.zapi.NaElement(
            'qos-adaptive-policy-group-info')
        policy_group_info.add_new_child('policy-group', policy_group_name)
        policy_group_info.add_new_child('vserver', self.parameters['vserver'])
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(policy_group_info)
        policy_group_get_iter.add_child_elem(query)
        result = self.server.invoke_successfully(policy_group_get_iter, True)
        policy_group_detail = None

        if result.get_child_by_name('num-records') and int(
                result.get_child_content('num-records')) == 1:
            policy_info = result.get_child_by_name(
                'attributes-list').get_child_by_name(
                    'qos-adaptive-policy-group-info')

            policy_group_detail = {
                'name':
                policy_info.get_child_content('policy-group'),
                'vserver':
                policy_info.get_child_content('vserver'),
                'absolute_min_iops':
                policy_info.get_child_content('absolute-min-iops'),
                'expected_iops':
                policy_info.get_child_content('expected-iops'),
                'peak_iops':
                policy_info.get_child_content('peak-iops'),
                'peak_iops_allocation':
                policy_info.get_child_content('peak-iops-allocation')
            }
        return policy_group_detail

    def create_policy_group(self):
        """
        create a policy group name.
        """
        policy_group = netapp_utils.zapi.NaElement(
            'qos-adaptive-policy-group-create')
        policy_group.add_new_child('policy-group', self.parameters['name'])
        policy_group.add_new_child('vserver', self.parameters['vserver'])
        if self.parameters.get('absolute_min_iops'):
            policy_group.add_new_child('absolute-min-iops',
                                       self.parameters['absolute_min_iops'])
        if self.parameters.get('expected_iops'):
            policy_group.add_new_child('expected-iops',
                                       self.parameters['expected_iops'])
        if self.parameters.get('peak_iops'):
            policy_group.add_new_child('peak-iops',
                                       self.parameters['peak_iops'])
        if self.parameters.get('peak_iops_allocation'):
            policy_group.add_new_child('peak-iops-allocation',
                                       self.parameters['peak_iops_allocation'])
        try:
            self.server.invoke_successfully(policy_group, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error creating adaptive qos policy group %s: %s' %
                (self.parameters['name'], to_native(error)),
                exception=traceback.format_exc())

    def delete_policy_group(self, policy_group=None):
        """
        delete an existing policy group.
        :param policy_group: policy group name.
        """
        if policy_group is None:
            policy_group = self.parameters['name']
        policy_group_obj = netapp_utils.zapi.NaElement(
            'qos-adaptive-policy-group-delete')
        policy_group_obj.add_new_child('policy-group', policy_group)
        if self.parameters.get('force'):
            policy_group_obj.add_new_child('force',
                                           str(self.parameters['force']))
        try:
            self.server.invoke_successfully(policy_group_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error deleting adaptive qos policy group %s: %s' %
                (policy_group, to_native(error)),
                exception=traceback.format_exc())

    def modify_policy_group(self):
        """
        Modify policy group.
        """
        policy_group_obj = netapp_utils.zapi.NaElement(
            'qos-adaptive-policy-group-modify')
        policy_group_obj.add_new_child('policy-group', self.parameters['name'])
        if self.parameters.get('absolute_min_iops'):
            policy_group_obj.add_new_child(
                'absolute-min-iops', self.parameters['absolute_min_iops'])
        if self.parameters.get('expected_iops'):
            policy_group_obj.add_new_child('expected-iops',
                                           self.parameters['expected_iops'])
        if self.parameters.get('peak_iops'):
            policy_group_obj.add_new_child('peak-iops',
                                           self.parameters['peak_iops'])
        if self.parameters.get('peak_iops_allocation'):
            policy_group_obj.add_new_child(
                'peak-iops-allocation',
                self.parameters['peak_iops_allocation'])
        try:
            self.server.invoke_successfully(policy_group_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error modifying adaptive qos policy group %s: %s' %
                (self.parameters['name'], to_native(error)),
                exception=traceback.format_exc())

    def rename_policy_group(self):
        """
        Rename policy group name.
        """
        rename_obj = netapp_utils.zapi.NaElement(
            'qos-adaptive-policy-group-rename')
        rename_obj.add_new_child('new-name', self.parameters['name'])
        rename_obj.add_new_child('policy-group-name',
                                 self.parameters['from_name'])
        try:
            self.server.invoke_successfully(rename_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error renaming adaptive qos policy group %s: %s' %
                (self.parameters['from_name'], to_native(error)),
                exception=traceback.format_exc())

    def modify_helper(self, modify):
        """
        helper method to modify policy group.
        :param modify: modified attributes.
        """
        for attribute in modify.keys():
            if attribute in [
                    'absolute_min_iops', 'expected_iops', 'peak_iops',
                    'peak_iops_allocation'
            ]:
                self.modify_policy_group()

    def apply(self):
        """
        Run module based on playbook
        """
        self.autosupport_log("na_ontap_qos_policy_group")
        current = self.get_policy_group()
        rename, cd_action = None, None
        if self.parameters.get('from_name'):
            rename = self.na_helper.is_rename_action(
                self.get_policy_group(self.parameters['from_name']), current)
        else:
            cd_action = self.na_helper.get_cd_action(current, self.parameters)
        modify = self.na_helper.get_modified_attributes(
            current, self.parameters)
        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if rename:
                    self.rename_policy_group()
                if cd_action == 'create':
                    self.create_policy_group()
                elif cd_action == 'delete':
                    self.delete_policy_group()
                elif modify:
                    self.modify_helper(modify)
        self.module.exit_json(changed=self.na_helper.changed)

    def autosupport_log(self, event_name):
        """
        Create a log event against the provided vserver
        """
        server = netapp_utils.setup_na_ontap_zapi(
            module=self.module, vserver=self.parameters['vserver'])
        netapp_utils.ems_log_event(event_name, server)
コード例 #11
0
class NetAppONTAPCifsSecurity(object):
    '''
    modify vserver cifs security
    '''
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(dict(
            vserver=dict(required=True, type='str'),
            kerberos_clock_skew=dict(required=False, type='int'),
            kerberos_ticket_age=dict(required=False, type='int'),
            kerberos_renew_age=dict(required=False, type='int'),
            kerberos_kdc_timeout=dict(required=False, type='int'),
            is_signing_required=dict(required=False, type='bool'),
            is_password_complexity_required=dict(required=False, type='bool'),
            is_aes_encryption_enabled=dict(required=False, type='bool'),
            is_smb_encryption_required=dict(required=False, type='bool'),
            lm_compatibility_level=dict(required=False, choices=['lm_ntlm_ntlmv2_krb', 'ntlm_ntlmv2_krb', 'ntlmv2_krb', 'krb']),
            referral_enabled_for_ad_ldap=dict(required=False, type='bool'),
            session_security_for_ad_ldap=dict(required=False, choices=['none', 'sign', 'seal']),
            smb1_enabled_for_dc_connections=dict(required=False, choices=['false', 'true', 'system_default']),
            smb2_enabled_for_dc_connections=dict(required=False, choices=['false', 'true', 'system_default']),
            use_start_tls_for_ad_ldap=dict(required=False, type='bool')
        ))

        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)

        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 cifs_security_get_iter(self):
        """
        get current vserver cifs security.
        :return: a dict of vserver cifs security
        """
        cifs_security_get = netapp_utils.zapi.NaElement('cifs-security-get-iter')
        query = netapp_utils.zapi.NaElement('query')
        cifs_security = netapp_utils.zapi.NaElement('cifs-security')
        cifs_security.add_new_child('vserver', self.parameters['vserver'])
        query.add_child_elem(cifs_security)
        cifs_security_get.add_child_elem(query)
        cifs_security_details = dict()
        try:
            result = self.server.invoke_successfully(cifs_security_get, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching cifs security from %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')) > 0:
            cifs_security_info = result.get_child_by_name('attributes-list').get_child_by_name('cifs-security')
            cifs_security_details['kerberos_clock_skew'] = cifs_security_info.get_child_content('kerberos-clock-skew')
            cifs_security_details['kerberos_ticket_age'] = cifs_security_info.get_child_content('kerberos-ticket-age')
            cifs_security_details['kerberos_renew_age'] = cifs_security_info.get_child_content('kerberos-renew-age')
            cifs_security_details['kerberos_kdc_timeout'] = cifs_security_info.get_child_content('kerberos-kdc-timeout')
            cifs_security_details['is_signing_required'] = bool(cifs_security_info.get_child_content('is-signing-required'))
            cifs_security_details['is_password_complexity_required'] = bool(cifs_security_info.get_child_content('is-password-complexity-required'))
            cifs_security_details['is_aes_encryption_enabled'] = bool(cifs_security_info.get_child_content('is-aes-encryption-enabled'))
            cifs_security_details['is_smb_encryption_required'] = bool(cifs_security_info.get_child_content('is-smb-encryption-required'))
            cifs_security_details['lm_compatibility_level'] = cifs_security_info.get_child_content('lm-compatibility-level')
            cifs_security_details['referral_enabled_for_ad_ldap'] = bool(cifs_security_info.get_child_content('referral-enabled-for-ad-ldap'))
            cifs_security_details['session_security_for_ad_ldap'] = cifs_security_info.get_child_content('session-security-for-ad-ldap')
            cifs_security_details['smb1_enabled_for_dc_connections'] = cifs_security_info.get_child_content('smb1-enabled-for-dc-connections')
            cifs_security_details['smb2_enabled_for_dc_connections'] = cifs_security_info.get_child_content('smb2-enabled-for-dc-connections')
            cifs_security_details['use_start_tls_for_ad_ldap'] = bool(cifs_security_info.get_child_content('use-start-tls-for-ad-ldap'))
            return cifs_security_details
        return None

    def cifs_security_modify(self, modify):
        """
        :param modify: A list of attributes to modify
        :return: None
        """
        cifs_security_modify = netapp_utils.zapi.NaElement('cifs-security-modify')
        for attribute in modify:
            cifs_security_modify.add_new_child(self.attribute_to_name(attribute), str(self.parameters[attribute]))
        try:
            self.server.invoke_successfully(cifs_security_modify, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as e:
            self.module.fail_json(msg='Error modifying cifs security on %s: %s'
                                  % (self.parameters['vserver'], to_native(e)),
                                  exception=traceback.format_exc())

    @staticmethod
    def attribute_to_name(attribute):
        return str.replace(attribute, '_', '-')

    def apply(self):
        """Call modify operations."""
        self.asup_log_for_cserver("na_ontap_vserver_cifs_security")
        current = self.cifs_security_get_iter()
        modify = self.na_helper.get_modified_attributes(current, self.parameters)
        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if modify:
                    self.cifs_security_modify(modify)
        self.module.exit_json(changed=self.na_helper.changed)

    def asup_log_for_cserver(self, event_name):
        """
        Fetch admin vserver for the given cluster
        Create and Autosupport log event with the given module name
        :param event_name: Name of the event log
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
        netapp_utils.ems_log_event(event_name, cserver)
コード例 #12
0
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            type='str',
                            choices=['present', 'absent'],
                            default='present'),
                 source_vserver=dict(required=False, type='str'),
                 destination_vserver=dict(required=False, type='str'),
                 source_volume=dict(required=False, type='str'),
                 destination_volume=dict(required=False, type='str'),
                 source_path=dict(required=False, type='str'),
                 destination_path=dict(required=False, type='str'),
                 schedule=dict(required=False, type='str'),
                 policy=dict(required=False, type='str'),
                 relationship_type=dict(required=False,
                                        type='str',
                                        choices=[
                                            'data_protection', 'load_sharing',
                                            'vault', 'restore',
                                            'transition_data_protection',
                                            'extended_data_protection'
                                        ]),
                 source_hostname=dict(required=False, type='str'),
                 connection_type=dict(required=False,
                                      type='str',
                                      choices=[
                                          'ontap_ontap', 'elementsw_ontap',
                                          'ontap_elementsw'
                                      ],
                                      default='ontap_ontap'),
                 source_username=dict(required=False, type='str'),
                 source_password=dict(required=False, type='str', no_log=True),
                 max_transfer_rate=dict(required=False, type='int'),
                 identity_preserve=dict(required=False, type='bool')))

        self.module = AnsibleModule(
            argument_spec=self.argument_spec,
            required_together=(['source_volume', 'destination_volume'],
                               ['source_vserver', 'destination_vserver']),
            supports_check_mode=True)

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # setup later if required
        self.source_server = None
        # only for ElementSW -> ONTAP snapmirroring, validate if ElementSW SDK is available
        if self.parameters.get('connection_type') in [
                'elementsw_ontap', 'ontap_elementsw'
        ]:
            if HAS_SF_SDK is False:
                self.module.fail_json(
                    msg="Unable to import the SolidFire Python SDK")
        if HAS_NETAPP_LIB is False:
            self.module.fail_json(
                msg="the python NetApp-Lib module is required")
        if self.parameters.get('connection_type') != 'ontap_elementsw':
            self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
        else:
            if self.parameters.get('source_username'):
                self.module.params['username'] = self.parameters[
                    'source_username']
            if self.parameters.get('source_password'):
                self.module.params['password'] = self.parameters[
                    'source_password']
            self.module.params['hostname'] = self.parameters['source_hostname']
            self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
コード例 #13
0
class NetAppONTAPSnapmirror(object):
    """
    Class with Snapmirror methods
    """
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            type='str',
                            choices=['present', 'absent'],
                            default='present'),
                 source_vserver=dict(required=False, type='str'),
                 destination_vserver=dict(required=False, type='str'),
                 source_volume=dict(required=False, type='str'),
                 destination_volume=dict(required=False, type='str'),
                 source_path=dict(required=False, type='str'),
                 destination_path=dict(required=False, type='str'),
                 schedule=dict(required=False, type='str'),
                 policy=dict(required=False, type='str'),
                 relationship_type=dict(required=False,
                                        type='str',
                                        choices=[
                                            'data_protection', 'load_sharing',
                                            'vault', 'restore',
                                            'transition_data_protection',
                                            'extended_data_protection'
                                        ]),
                 source_hostname=dict(required=False, type='str'),
                 connection_type=dict(required=False,
                                      type='str',
                                      choices=[
                                          'ontap_ontap', 'elementsw_ontap',
                                          'ontap_elementsw'
                                      ],
                                      default='ontap_ontap'),
                 source_username=dict(required=False, type='str'),
                 source_password=dict(required=False, type='str', no_log=True),
                 max_transfer_rate=dict(required=False, type='int'),
                 identity_preserve=dict(required=False, type='bool')))

        self.module = AnsibleModule(
            argument_spec=self.argument_spec,
            required_together=(['source_volume', 'destination_volume'],
                               ['source_vserver', 'destination_vserver']),
            supports_check_mode=True)

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # setup later if required
        self.source_server = None
        # only for ElementSW -> ONTAP snapmirroring, validate if ElementSW SDK is available
        if self.parameters.get('connection_type') in [
                'elementsw_ontap', 'ontap_elementsw'
        ]:
            if HAS_SF_SDK is False:
                self.module.fail_json(
                    msg="Unable to import the SolidFire Python SDK")
        if HAS_NETAPP_LIB is False:
            self.module.fail_json(
                msg="the python NetApp-Lib module is required")
        if self.parameters.get('connection_type') != 'ontap_elementsw':
            self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
        else:
            if self.parameters.get('source_username'):
                self.module.params['username'] = self.parameters[
                    'source_username']
            if self.parameters.get('source_password'):
                self.module.params['password'] = self.parameters[
                    'source_password']
            self.module.params['hostname'] = self.parameters['source_hostname']
            self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)

    def set_element_connection(self, kind):
        if kind == 'source':
            self.module.params['hostname'] = self.parameters['source_hostname']
            self.module.params['username'] = self.parameters['source_username']
            self.module.params['password'] = self.parameters['source_password']
        elif kind == 'destination':
            self.module.params['hostname'] = self.parameters['hostname']
            self.module.params['username'] = self.parameters['username']
            self.module.params['password'] = self.parameters['password']
        elem = netapp_utils.create_sf_connection(module=self.module)
        elementsw_helper = NaElementSWModule(elem)
        return elementsw_helper, elem

    def snapmirror_get_iter(self, destination=None):
        """
        Compose NaElement object to query current SnapMirror relations using destination-path
        SnapMirror relation for a destination path is unique
        :return: NaElement object for SnapMirror-get-iter
        """
        snapmirror_get_iter = netapp_utils.zapi.NaElement(
            'snapmirror-get-iter')
        query = netapp_utils.zapi.NaElement('query')
        snapmirror_info = netapp_utils.zapi.NaElement('snapmirror-info')
        if destination is None:
            destination = self.parameters['destination_path']
        snapmirror_info.add_new_child('destination-location', destination)
        query.add_child_elem(snapmirror_info)
        snapmirror_get_iter.add_child_elem(query)
        return snapmirror_get_iter

    def snapmirror_get(self, destination=None):
        """
        Get current SnapMirror relations
        :return: Dictionary of current SnapMirror details if query successful, else None
        """
        snapmirror_get_iter = self.snapmirror_get_iter(destination)
        snap_info = dict()
        try:
            result = self.server.invoke_successfully(snapmirror_get_iter,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching snapmirror info: %s' %
                                  to_native(error),
                                  exception=traceback.format_exc())
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) > 0:
            snapmirror_info = result.get_child_by_name(
                'attributes-list').get_child_by_name('snapmirror-info')
            snap_info['mirror_state'] = snapmirror_info.get_child_content(
                'mirror-state')
            snap_info['status'] = snapmirror_info.get_child_content(
                'relationship-status')
            snap_info['schedule'] = snapmirror_info.get_child_content(
                'schedule')
            snap_info['policy'] = snapmirror_info.get_child_content('policy')
            snap_info['relationship'] = snapmirror_info.get_child_content(
                'relationship-type')
            if snapmirror_info.get_child_by_name('max-transfer-rate'):
                snap_info['max_transfer_rate'] = int(
                    snapmirror_info.get_child_content('max-transfer-rate'))
            if snap_info['schedule'] is None:
                snap_info['schedule'] = ""
            return snap_info
        return None

    def check_if_remote_volume_exists(self):
        """
        Validate existence of source volume
        :return: True if volume exists, False otherwise
        """
        self.set_source_cluster_connection()
        # do a get volume to check if volume exists or not
        volume_info = netapp_utils.zapi.NaElement('volume-get-iter')
        volume_attributes = netapp_utils.zapi.NaElement('volume-attributes')
        volume_id_attributes = netapp_utils.zapi.NaElement(
            'volume-id-attributes')
        volume_id_attributes.add_new_child('name',
                                           self.parameters['source_volume'])
        # if source_volume is present, then source_vserver is also guaranteed to be present
        volume_id_attributes.add_new_child('vserver-name',
                                           self.parameters['source_vserver'])
        volume_attributes.add_child_elem(volume_id_attributes)
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(volume_attributes)
        volume_info.add_child_elem(query)
        try:
            result = self.source_server.invoke_successfully(volume_info, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error fetching source volume details %s : %s' %
                (self.parameters['source_volume'], to_native(error)),
                exception=traceback.format_exc())
        if result.get_child_by_name('num-records') and int(
                result.get_child_content('num-records')) > 0:
            return True
        return False

    def snapmirror_create(self):
        """
        Create a SnapMirror relationship
        """
        if self.parameters.get('source_hostname') and self.parameters.get(
                'source_volume'):
            if not self.check_if_remote_volume_exists():
                self.module.fail_json(
                    msg=
                    'Source volume does not exist. Please specify a volume that exists'
                )
        options = {
            'source-location': self.parameters['source_path'],
            'destination-location': self.parameters['destination_path']
        }
        snapmirror_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-create', **options)
        if self.parameters.get('relationship_type'):
            snapmirror_create.add_new_child(
                'relationship-type', self.parameters['relationship_type'])
        if self.parameters.get('schedule'):
            snapmirror_create.add_new_child('schedule',
                                            self.parameters['schedule'])
        if self.parameters.get('policy'):
            snapmirror_create.add_new_child('policy',
                                            self.parameters['policy'])
        if self.parameters.get('max_transfer_rate'):
            snapmirror_create.add_new_child(
                'max-transfer-rate', str(self.parameters['max_transfer_rate']))
        if self.parameters.get('identity_preserve'):
            snapmirror_create.add_new_child(
                'identity-preserve', str(self.parameters['identity_preserve']))
        try:
            self.server.invoke_successfully(snapmirror_create,
                                            enable_tunneling=True)
            self.snapmirror_initialize()
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating SnapMirror %s' %
                                  to_native(error),
                                  exception=traceback.format_exc())

    def set_source_cluster_connection(self):
        """
        Setup ontap ZAPI server connection for source hostname
        :return: None
        """
        if self.parameters.get('source_username'):
            self.module.params['username'] = self.parameters['source_username']
        if self.parameters.get('source_password'):
            self.module.params['password'] = self.parameters['source_password']
        self.module.params['hostname'] = self.parameters['source_hostname']
        self.source_server = netapp_utils.setup_na_ontap_zapi(
            module=self.module)

    def delete_snapmirror(self, is_hci, relationship_type):
        """
        Delete a SnapMirror relationship
        #1. Quiesce the SnapMirror relationship at destination
        #2. Break the SnapMirror relationship at the destination
        #3. Release the SnapMirror at source
        #4. Delete SnapMirror at destination
        """
        if not is_hci:
            if not self.parameters.get('source_hostname'):
                self.module.fail_json(
                    msg='Missing parameters for delete: Please specify the '
                    'source cluster hostname to release the SnapMirror relation'
                )
        # Quiesce at destination
        self.snapmirror_quiesce()
        # Break at destination
        if relationship_type not in ['load_sharing', 'vault']:
            self.snapmirror_break()
        # if source is ONTAP, release the destination at source cluster
        if not is_hci:
            self.set_source_cluster_connection()
            if self.get_destination():
                # Release at source
                self.snapmirror_release()
        # Delete at destination
        self.snapmirror_delete()

    def snapmirror_quiesce(self):
        """
        Quiesce SnapMirror relationship - disable all future transfers to this destination
        """
        options = {'destination-location': self.parameters['destination_path']}

        snapmirror_quiesce = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-quiesce', **options)
        try:
            self.server.invoke_successfully(snapmirror_quiesce,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error Quiescing SnapMirror : %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def snapmirror_delete(self):
        """
        Delete SnapMirror relationship at destination cluster
        """
        options = {'destination-location': self.parameters['destination_path']}

        snapmirror_delete = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-destroy', **options)
        try:
            self.server.invoke_successfully(snapmirror_delete,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting SnapMirror : %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def snapmirror_break(self, destination=None):
        """
        Break SnapMirror relationship at destination cluster
        """
        if destination is None:
            destination = self.parameters['destination_path']
        options = {'destination-location': destination}
        snapmirror_break = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-break', **options)
        try:
            self.server.invoke_successfully(snapmirror_break,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error breaking SnapMirror relationship : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_release(self):
        """
        Release SnapMirror relationship from source cluster
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_release = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-release', **options)
        try:
            self.source_server.invoke_successfully(snapmirror_release,
                                                   enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error releasing SnapMirror relationship : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_abort(self):
        """
        Abort a SnapMirror relationship in progress
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_abort = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-abort', **options)
        try:
            self.server.invoke_successfully(snapmirror_abort,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error aborting SnapMirror relationship : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_initialize(self):
        """
        Initialize SnapMirror based on relationship type
        """
        current = self.snapmirror_get()
        if current['mirror_state'] != 'snapmirrored':
            initialize_zapi = 'snapmirror-initialize'
            if self.parameters.get('relationship_type') and self.parameters[
                    'relationship_type'] == 'load_sharing':
                initialize_zapi = 'snapmirror-initialize-ls-set'
                options = {'source-location': self.parameters['source_path']}
            else:
                options = {
                    'destination-location': self.parameters['destination_path']
                }
            snapmirror_init = netapp_utils.zapi.NaElement.create_node_with_children(
                initialize_zapi, **options)
            try:
                self.server.invoke_successfully(snapmirror_init,
                                                enable_tunneling=True)
            except netapp_utils.zapi.NaApiError as error:
                self.module.fail_json(
                    msg='Error initializing SnapMirror : %s' %
                    (to_native(error)),
                    exception=traceback.format_exc())

    def snapmirror_modify(self, modify):
        """
        Modify SnapMirror schedule or policy
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-modify', **options)
        if modify.get('schedule') is not None:
            snapmirror_modify.add_new_child('schedule', modify.get('schedule'))
        if modify.get('policy'):
            snapmirror_modify.add_new_child('policy', modify.get('policy'))
        if modify.get('max_transfer_rate'):
            snapmirror_modify.add_new_child(
                'max-transfer-rate', str(modify.get('max_transfer_rate')))
        try:
            self.server.invoke_successfully(snapmirror_modify,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error modifying SnapMirror schedule or policy : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_update(self):
        """
        Update data in destination endpoint
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_update = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-update', **options)
        try:
            result = self.server.invoke_successfully(snapmirror_update,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error updating SnapMirror : %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def check_parameters(self):
        """
        Validate parameters and fail if one or more required params are missing
        Update source and destination path from vserver and volume parameters
        """
        if self.parameters['state'] == 'present'\
                and (self.parameters.get('source_path') or self.parameters.get('destination_path')):
            if not self.parameters.get(
                    'destination_path') or not self.parameters.get(
                        'source_path'):
                self.module.fail_json(
                    msg='Missing parameters: Source path or Destination path')
        elif self.parameters.get('source_volume'):
            if not self.parameters.get(
                    'source_vserver') or not self.parameters.get(
                        'destination_vserver'):
                self.module.fail_json(
                    msg=
                    'Missing parameters: source vserver or destination vserver or both'
                )
            self.parameters['source_path'] = self.parameters[
                'source_vserver'] + ":" + self.parameters['source_volume']
            self.parameters['destination_path'] = self.parameters['destination_vserver'] + ":" +\
                self.parameters['destination_volume']
        elif self.parameters.get('source_vserver'):
            self.parameters[
                'source_path'] = self.parameters['source_vserver'] + ":"
            self.parameters['destination_path'] = self.parameters[
                'destination_vserver'] + ":"

    def get_destination(self):
        result = None
        release_get = netapp_utils.zapi.NaElement(
            'snapmirror-get-destination-iter')
        query = netapp_utils.zapi.NaElement('query')
        snapmirror_dest_info = netapp_utils.zapi.NaElement(
            'snapmirror-destination-info')
        snapmirror_dest_info.add_new_child('destination-location',
                                           self.parameters['destination_path'])
        query.add_child_elem(snapmirror_dest_info)
        release_get.add_child_elem(query)
        try:
            result = self.source_server.invoke_successfully(
                release_get, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error fetching snapmirror destinations info: %s' %
                to_native(error),
                exception=traceback.format_exc())
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) > 0:
            return True
        return None

    @staticmethod
    def element_source_path_format_matches(value):
        return re.match(
            pattern=r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\/lun\/[0-9]+",
            string=value)

    def check_elementsw_parameters(self, kind='source'):
        """
        Validate all ElementSW cluster parameters required for managing the SnapMirror relationship
        Validate if both source and destination paths are present
        Validate if source_path follows the required format
        Validate SVIP
        Validate if ElementSW volume exists
        :return: None
        """
        path = None
        if kind == 'destination':
            path = self.parameters.get('destination_path')
        elif kind == 'source':
            path = self.parameters.get('source_path')
        if path is None:
            self.module.fail_json(
                msg="Error: Missing required parameter %s_path for "
                "connection_type %s" %
                (kind, self.parameters['connection_type']))
        else:
            if NetAppONTAPSnapmirror.element_source_path_format_matches(
                    path) is None:
                self.module.fail_json(
                    msg="Error: invalid %s_path %s. "
                    "If the path is a ElementSW cluster, the value should be of the format"
                    " <Element_SVIP>:/lun/<Element_VOLUME_ID>" % (kind, path))
        # validate source_path
        elementsw_helper, elem = self.set_element_connection(kind)
        self.validate_elementsw_svip(path, elem)
        self.check_if_elementsw_volume_exists(path, elementsw_helper)

    def validate_elementsw_svip(self, path, elem):
        """
        Validate ElementSW cluster SVIP
        :return: None
        """
        result = None
        try:
            result = elem.get_cluster_info()
        except solidfire.common.ApiServerError as err:
            self.module.fail_json(msg="Error fetching SVIP",
                                  exception=to_native(err))
        if result and result.cluster_info.svip:
            cluster_svip = result.cluster_info.svip
            svip = path.split(':')[0]  # split IP address from source_path
            if svip != cluster_svip:
                self.module.fail_json(msg="Error: Invalid SVIP")

    def check_if_elementsw_volume_exists(self, path, elementsw_helper):
        """
        Check if remote ElementSW volume exists
        :return: None
        """
        volume_id, vol_id = None, path.split('/')[-1]
        try:
            volume_id = elementsw_helper.volume_id_exists(int(vol_id))
        except solidfire.common.ApiServerError as err:
            self.module.fail_json(msg="Error fetching Volume details",
                                  exception=to_native(err))

        if volume_id is None:
            self.module.fail_json(
                msg=
                "Error: Source volume does not exist in the ElementSW cluster")

    def asup_log_for_cserver(self, event_name):
        """
        Fetch admin vserver for the given cluster
        Create and Autosupport log event with the given module name
        :param event_name: Name of the event log
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event(event_name, cserver)

    def apply(self):
        """
        Apply action to SnapMirror
        """
        self.asup_log_for_cserver("na_ontap_snapmirror")
        # source is ElementSW
        if self.parameters['state'] == 'present' and self.parameters.get(
                'connection_type') == 'elementsw_ontap':
            self.check_elementsw_parameters()
        elif self.parameters.get('connection_type') == 'ontap_elementsw':
            self.check_elementsw_parameters('destination')
        else:
            self.check_parameters()
        if self.parameters['state'] == 'present' and self.parameters.get(
                'connection_type') == 'ontap_elementsw':
            current_elementsw_ontap = self.snapmirror_get(
                self.parameters['source_path'])
            if current_elementsw_ontap is None:
                self.module.fail_json(
                    msg=
                    'Error: creating an ONTAP to ElementSW snapmirror relationship requires an '
                    'established SnapMirror relation from ElementSW to ONTAP cluster'
                )
        current = self.snapmirror_get()
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        modify = self.na_helper.get_modified_attributes(
            current, self.parameters)
        element_snapmirror = False
        if cd_action == 'create':
            self.snapmirror_create()
        elif cd_action == 'delete':
            if current['status'] == 'transferring':
                self.snapmirror_abort()
            else:
                if self.parameters.get('connection_type') == 'elementsw_ontap':
                    element_snapmirror = True
                self.delete_snapmirror(element_snapmirror,
                                       current['relationship'])
        else:
            if modify:
                self.snapmirror_modify(modify)
            # check for initialize
            if current and current['mirror_state'] != 'snapmirrored':
                self.snapmirror_initialize()
                # set changed explicitly for initialize
                self.na_helper.changed = True
            # Update when create is called again, or modify is being called
            if self.parameters['state'] == 'present':
                self.snapmirror_update()
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #14
0
class NetAppOntapSnapshotPolicy(object):
    """
    Creates and deletes a Snapshot Policy
    """

    def __init__(self):
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(dict(
            state=dict(required=False, choices=[
                       'present', 'absent'], default='present'),
            name=dict(required=True, type="str"),
            enabled=dict(required=False, type="bool"),
            # count is a list of integers
            count=dict(required=False, type="list", elements="int"),
            comment=dict(required=False, type="str"),
            schedule=dict(required=False, type="list", elements="str"),
            snapmirror_label=dict(required=False, type="list", elements="str"),
            vserver=dict(required=False, type="str")
        ))
        self.module = AnsibleModule(
            argument_spec=self.argument_spec,
            required_if=[
                ('state', 'present', ['enabled', 'count', 'schedule']),
            ],
            supports_check_mode=True
        )

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        if HAS_NETAPP_LIB is False:
            self.module.fail_json(
                msg="the python NetApp-Lib module is required")
        else:
            if 'vserver' in self.parameters:
                self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
            else:
                self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
        return

    def get_snapshot_policy(self):
        """
        Checks to see if a snapshot policy exists or not
        :return: Return policy details if a snapshot policy exists, None if it doesn't
        """
        snapshot_obj = netapp_utils.zapi.NaElement("snapshot-policy-get-iter")
        # compose query
        query = netapp_utils.zapi.NaElement("query")
        snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-policy-info")
        snapshot_info_obj.add_new_child("policy", self.parameters['name'])
        if 'vserver' in self.parameters:
            snapshot_info_obj.add_new_child("vserver-name", self.parameters['vserver'])
        query.add_child_elem(snapshot_info_obj)
        snapshot_obj.add_child_elem(query)
        try:
            result = self.server.invoke_successfully(snapshot_obj, True)
            if result.get_child_by_name('num-records') and \
                    int(result.get_child_content('num-records')) == 1:
                snapshot_policy = result.get_child_by_name('attributes-list').get_child_by_name('snapshot-policy-info')
                current = {}
                current['name'] = snapshot_policy.get_child_content('policy')
                current['vserver'] = snapshot_policy.get_child_content('vserver-name')
                current['enabled'] = False if snapshot_policy.get_child_content('enabled').lower() == 'false' else True
                current['comment'] = snapshot_policy.get_child_content('comment') or ''
                current['schedule'], current['count'], current['snapmirror_label'] = [], [], []
                if snapshot_policy.get_child_by_name('snapshot-policy-schedules'):
                    for schedule in snapshot_policy['snapshot-policy-schedules'].get_children():
                        current['schedule'].append(schedule.get_child_content('schedule'))
                        current['count'].append(int(schedule.get_child_content('count')))
                        snapmirror_label = schedule.get_child_content('snapmirror-label')
                        if snapmirror_label is None or snapmirror_label == '-':
                            snapmirror_label = ''
                        current['snapmirror_label'].append(snapmirror_label)
                return current
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg=to_native(error), exception=traceback.format_exc())
        return None

    def validate_parameters(self):
        """
        Validate if each schedule has a count associated
        :return: None
        """
        if 'count' not in self.parameters or 'schedule' not in self.parameters or \
                len(self.parameters['count']) > 5 or len(self.parameters['schedule']) > 5 or \
                len(self.parameters['count']) < 1 or len(self.parameters['schedule']) < 1 or \
                len(self.parameters['count']) != len(self.parameters['schedule']):
            self.module.fail_json(msg="Error: A Snapshot policy must have at least 1 "
                                      "schedule and can have up to a maximum of 5 schedules, with a count "
                                      "representing the maximum number of Snapshot copies for each schedule")

        if 'snapmirror_label' in self.parameters:
            if len(self.parameters['snapmirror_label']) != len(self.parameters['schedule']):
                self.module.fail_json(msg="Error: Each Snapshot Policy schedule must have an "
                                          "accompanying SnapMirror Label")

    def modify_snapshot_policy(self, current):
        """
        Modifies an existing snapshot policy
        """
        # Set up required variables to modify snapshot policy
        options = {'policy': self.parameters['name']}
        modify = False

        # Set up optional variables to modify snapshot policy
        if 'enabled' in self.parameters and self.parameters['enabled'] != current['enabled']:
            options['enabled'] = str(self.parameters['enabled'])
            modify = True
        if 'comment' in self.parameters and self.parameters['comment'] != current['comment']:
            options['comment'] = self.parameters['comment']
            modify = True

        if modify:
            snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children('snapshot-policy-modify', **options)
            try:
                self.server.invoke_successfully(snapshot_obj, True)
            except netapp_utils.zapi.NaApiError as error:
                self.module.fail_json(msg='Error modifying snapshot policy %s: %s' %
                                      (self.parameters['name'], to_native(error)),
                                      exception=traceback.format_exc())

    def modify_snapshot_policy_schedules(self, current):
        """
        Modify existing schedules in snapshot policy
        :return: None
        """
        self.validate_parameters()

        delete_schedules, modify_schedules, add_schedules = [], [], []

        if 'snapmirror_label' in self.parameters:
            snapmirror_labels = self.parameters['snapmirror_label']
        else:
            # User hasn't supplied any snapmirror labels.
            snapmirror_labels = [None] * len(self.parameters['schedule'])

        # Identify schedules for deletion
        for schedule in current['schedule']:
            schedule = schedule.strip()
            if schedule not in [item.strip() for item in self.parameters['schedule']]:
                options = {'policy': current['name'],
                           'schedule': schedule}
                delete_schedules.append(options)

        # Identify schedules to be modified or added
        for schedule, count, snapmirror_label in zip(self.parameters['schedule'], self.parameters['count'], snapmirror_labels):
            schedule = schedule.strip()
            if snapmirror_label is not None:
                snapmirror_label = snapmirror_label.strip()

            options = {'policy': current['name'],
                       'schedule': schedule}

            if schedule in current['schedule']:
                # Schedule exists. Only modify if it has changed.
                modify = False
                schedule_index = current['schedule'].index(schedule)

                if count != current['count'][schedule_index]:
                    options['new-count'] = str(count)
                    modify = True

                if snapmirror_label is not None:
                    if snapmirror_label != current['snapmirror_label'][schedule_index]:
                        options['new-snapmirror-label'] = snapmirror_label
                        modify = True

                if modify:
                    modify_schedules.append(options)
            else:
                # New schedule
                options['count'] = str(count)
                if snapmirror_label is not None and snapmirror_label != '':
                    options['snapmirror-label'] = snapmirror_label
                add_schedules.append(options)

        # Delete N-1 schedules no longer required. Must leave 1 schedule in policy
        # at any one time. Delete last one afterwards.
        while len(delete_schedules) > 1:
            options = delete_schedules.pop()
            self.modify_snapshot_policy_schedule(options, 'snapshot-policy-remove-schedule')

        # Modify schedules.
        while len(modify_schedules) > 0:
            options = modify_schedules.pop()
            self.modify_snapshot_policy_schedule(options, 'snapshot-policy-modify-schedule')

        # Add N-1 new schedules. Add last one after last schedule has been deleted.
        while len(add_schedules) > 1:
            options = add_schedules.pop()
            self.modify_snapshot_policy_schedule(options, 'snapshot-policy-add-schedule')

        # Delete last schedule no longer required.
        while len(delete_schedules) > 0:
            options = delete_schedules.pop()
            self.modify_snapshot_policy_schedule(options, 'snapshot-policy-remove-schedule')

        # Add last new schedule.
        while len(add_schedules) > 0:
            options = add_schedules.pop()
            self.modify_snapshot_policy_schedule(options, 'snapshot-policy-add-schedule')

    def modify_snapshot_policy_schedule(self, options, zapi):
        """
        Add, modify or remove a schedule to/from a snapshot policy
        """
        snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children(zapi, **options)
        try:
            self.server.invoke_successfully(snapshot_obj, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error modifying snapshot policy schedule %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def create_snapshot_policy(self):
        """
        Creates a new snapshot policy
        """
        # set up required variables to create a snapshot policy
        self.validate_parameters()
        options = {'policy': self.parameters['name'],
                   'enabled': str(self.parameters['enabled']),
                   }

        if 'snapmirror_label' in self.parameters:
            snapmirror_labels = self.parameters['snapmirror_label']
        else:
            # User hasn't supplied any snapmirror labels.
            snapmirror_labels = [None] * len(self.parameters['schedule'])

        # zapi attribute for first schedule is schedule1, second is schedule2 and so on
        positions = [str(i) for i in range(1, len(self.parameters['schedule']) + 1)]
        for schedule, count, snapmirror_label, position in zip(self.parameters['schedule'], self.parameters['count'], snapmirror_labels, positions):
            schedule = schedule.strip()
            options['count' + position] = str(count)
            options['schedule' + position] = schedule
            if snapmirror_label is not None:
                snapmirror_label = snapmirror_label.strip()
                if snapmirror_label != '':
                    options['snapmirror-label' + position] = snapmirror_label
        snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children('snapshot-policy-create', **options)

        # Set up optional variables to create a snapshot policy
        if self.parameters.get('comment'):
            snapshot_obj.add_new_child("comment", self.parameters['comment'])
        try:
            self.server.invoke_successfully(snapshot_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating snapshot policy %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_snapshot_policy(self):
        """
        Deletes an existing snapshot policy
        """
        snapshot_obj = netapp_utils.zapi.NaElement("snapshot-policy-delete")

        # Set up required variables to delete a snapshot policy
        snapshot_obj.add_new_child("policy", self.parameters['name'])
        try:
            self.server.invoke_successfully(snapshot_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting snapshot policy %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def asup_log_for_cserver(self, event_name):
        """
        Fetch admin vserver for the given cluster
        Create and Autosupport log event with the given module name
        :param event_name: Name of the event log
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
        netapp_utils.ems_log_event(event_name, cserver)

    def apply(self):
        """
        Check to see which play we should run
        """
        self.asup_log_for_cserver("na_ontap_snapshot_policy")
        current = self.get_snapshot_policy()
        modify = None
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        if cd_action is None and self.parameters['state'] == 'present':
            # Don't sort schedule/count/snapmirror_label lists as it can
            # mess up the intended parameter order.
            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_snapshot_policy()
                elif cd_action == 'delete':
                    self.delete_snapshot_policy()
                if modify:
                    self.modify_snapshot_policy(current)
                    self.modify_snapshot_policy_schedules(current)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #15
0
class NetAppONTAPJob(object):
    '''Class with job schedule cron methods'''

    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(dict(
            state=dict(required=False, choices=[
                       'present', 'absent'], default='present'),
            name=dict(required=True, type='str'),
            job_minutes=dict(required=False, type='int'),
            job_month=dict(required=False, type='int'),
            job_hour=dict(required=False, type='int'),
            job_day_of_month=dict(required=False, type='int'),
            job_day_of_week=dict(required=False, type='int')
        ))

        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)

        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)

    def get_job_schedule(self):
        """
        Return details about the job
        :param:
            name : Job name
        :return: Details about the Job. None if not found.
        :rtype: dict
        """
        job_get_iter = netapp_utils.zapi.NaElement('job-schedule-cron-get-iter')
        job_get_iter.translate_struct({
            'query': {
                'job-schedule-cron-info': {
                    'job-schedule-name': self.parameters['name']
                }
            }
        })
        result = self.server.invoke_successfully(job_get_iter, True)
        job_details = None
        # check if job exists
        if result.get_child_by_name('num-records') and int(result['num-records']) >= 1:
            job_exists_info = result['attributes-list']['job-schedule-cron-info']
            job_details = {
                'name': job_exists_info.get_child_content('job-schedule-name'),
                'job_minutes': int(job_exists_info['job-schedule-cron-minute']['cron-minute']),
                # set default values to other job attributes (by default, cron runs on all months if months is empty)
                'job_hour': 0,
                'job_month': -1,
                'job_day_of_month': 0,
                'job_day_of_week': 0
            }
            if job_exists_info.get_child_by_name('job-schedule-cron-hour'):
                job_details['job_hour'] = int(job_exists_info['job-schedule-cron-hour']['cron-hour'])
            if job_exists_info.get_child_by_name('job-schedule-cron-month'):
                job_details['job_month'] = int(job_exists_info['job-schedule-cron-month']['cron-month'])
            if job_exists_info.get_child_by_name('job-schedule-cron-day'):
                job_details['job_day_of_month'] = int(job_exists_info['job-schedule-cron-day']['cron-day-of-month'])
            if job_exists_info.get_child_by_name('job-schedule-cron-day-of-week'):
                job_details['job_day_of_week'] = int(job_exists_info['job-schedule-cron-day-of-week']
                                                     ['cron-day-of-week'])
        return job_details

    def add_job_details(self, na_element_object, values):
        """
        Add children node for create or modify NaElement object
        :param na_element_object: modif or create NaElement object
        :param values: dictionary of cron values to be added
        :return: None
        """
        if values.get('job_minutes'):
            na_element_object.add_node_with_children(
                'job-schedule-cron-minute', **{'cron-minute': str(values['job_minutes'])})
        if values.get('job_hour'):
            na_element_object.add_node_with_children(
                'job-schedule-cron-hour', **{'cron-hour': str(values['job_hour'])})
        if values.get('job_month'):
            na_element_object.add_node_with_children(
                'job-schedule-cron-month', **{'cron-month': str(values['job_month'])})
        if values.get('job_day_of_month'):
            na_element_object.add_node_with_children(
                'job-schedule-cron-day', **{'cron-day-of-month': str(values['job_day_of_month'])})
        if values.get('job_day_of_week'):
            na_element_object.add_node_with_children(
                'job-schedule-cron-day-of-week', **{'cron-day-of-week': str(values['job_day_of_week'])})

    def create_job_schedule(self):
        """
        Creates a job schedule
        """
        # job_minutes is mandatory for create
        if self.parameters.get('job_minutes') is None:
            self.module.fail_json(msg='Error: missing required parameter job_minutes for create')

        job_schedule_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'job-schedule-cron-create', **{'job-schedule-name': self.parameters['name']})
        self.add_job_details(job_schedule_create, self.parameters)
        try:
            self.server.invoke_successfully(job_schedule_create,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating job schedule %s: %s'
                                  % (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_job_schedule(self):
        """
        Delete a job schedule
        """
        job_schedule_delete = netapp_utils.zapi.NaElement.create_node_with_children(
            'job-schedule-cron-destroy', **{'job-schedule-name': self.parameters['name']})
        try:
            self.server.invoke_successfully(job_schedule_delete,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting job schedule %s: %s'
                                  % (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def modify_job_schedule(self, params):
        """
        modify a job schedule
        """
        job_schedule_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'job-schedule-cron-modify', **{'job-schedule-name': self.parameters['name']})
        self.add_job_details(job_schedule_modify, params)
        try:
            self.server.invoke_successfully(job_schedule_modify, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error modifying job schedule %s: %s'
                                  % (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def autosupport_log(self):
        """
        Autosupport log for job_schedule
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_ontap_zapi(module=self.module, vserver=results)
        netapp_utils.ems_log_event("na_ontap_job_schedule", cserver)

    def apply(self):
        """
        Apply action to job-schedule
        """
        self.autosupport_log()
        current = self.get_job_schedule()
        action = self.na_helper.get_cd_action(current, self.parameters)
        modify = self.na_helper.get_modified_attributes(current, self.parameters)
        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if action == 'create':
                    self.create_job_schedule()
                elif action == 'delete':
                    self.delete_job_schedule()
                elif modify:
                    self.modify_job_schedule(modify)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #16
0
class ElementSWVolumePair(object):
    ''' class to handle volume pairing operations '''
    def __init__(self):
        """
            Setup Ansible parameters and SolidFire connection
        """
        self.argument_spec = netapp_utils.ontap_sf_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            choices=['present', 'absent'],
                            default='present'),
                 src_volume=dict(required=True, type='str'),
                 src_account=dict(required=True, type='str'),
                 dest_volume=dict(required=True, type='str'),
                 dest_account=dict(required=True, type='str'),
                 mode=dict(required=False,
                           type='str',
                           choices=['async', 'sync', 'snapshotsonly'],
                           default='async'),
                 dest_mvip=dict(required=True, type='str'),
                 dest_username=dict(required=False, type='str'),
                 dest_password=dict(required=False, type='str', no_log=True)))

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

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

        self.elementsw_helper = NaElementSWModule(self.elem)
        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # get element_sw_connection for destination cluster
        # overwrite existing source host, user and password with destination credentials
        self.module.params['hostname'] = self.parameters['dest_mvip']
        # username and password is same as source,
        # if dest_username and dest_password aren't specified
        if self.parameters.get('dest_username'):
            self.module.params['username'] = self.parameters['dest_username']
        if self.parameters.get('dest_password'):
            self.module.params['password'] = self.parameters['dest_password']
        self.dest_elem = netapp_utils.create_sf_connection(module=self.module)
        self.dest_elementsw_helper = NaElementSWModule(self.dest_elem)

    def check_if_already_paired(self, vol_id):
        """
            Check for idempotency
            A volume can have only one pair
            Return paired-volume-id if volume is paired already
            None if volume is not paired
        """
        paired_volumes = self.elem.list_volumes(volume_ids=[vol_id],
                                                is_paired=True)
        for vol in paired_volumes.volumes:
            for pair in vol.volume_pairs:
                if pair is not None:
                    return pair.remote_volume_id
        return None

    def pair_volumes(self):
        """
            Start volume pairing on source, and complete on target volume
        """
        try:
            pair_key = self.elem.start_volume_pairing(
                volume_id=self.parameters['src_vol_id'],
                mode=self.parameters['mode'])
            self.dest_elem.complete_volume_pairing(
                volume_pairing_key=pair_key.volume_pairing_key,
                volume_id=self.parameters['dest_vol_id'])
        except solidfire.common.ApiServerError as err:
            self.module.fail_json(msg="Error pairing volume id %s" %
                                  (self.parameters['src_vol_id']),
                                  exception=to_native(err))

    def pairing_exists(self, src_id, dest_id):
        src_paired = self.check_if_already_paired(
            self.parameters['src_vol_id'])
        dest_paired = self.check_if_already_paired(
            self.parameters['dest_vol_id'])
        if src_paired is not None or dest_paired is not None:
            return True
        return None

    def unpair_volumes(self):
        """
            Delete volume pair
        """
        try:
            self.elem.remove_volume_pair(
                volume_id=self.parameters['src_vol_id'])
            self.dest_elem.remove_volume_pair(
                volume_id=self.parameters['dest_vol_id'])
        except solidfire.common.ApiServerError as err:
            self.module.fail_json(msg="Error unpairing volume ids %s and %s" %
                                  (self.parameters['src_vol_id'],
                                   self.parameters['dest_vol_id']),
                                  exception=to_native(err))

    def get_account_id(self, account, type):
        """
            Get source and destination account IDs
        """
        try:
            if type == 'src':
                self.parameters[
                    'src_account_id'] = self.elementsw_helper.account_exists(
                        account)
            elif type == 'dest':
                self.parameters[
                    'dest_account_id'] = self.dest_elementsw_helper.account_exists(
                        account)
        except solidfire.common.ApiServerError as err:
            self.module.fail_json(
                msg="Error: either account %s or %s does not exist" %
                (self.parameters['src_account'],
                 self.parameters['dest_account']),
                exception=to_native(err))

    def get_volume_id(self, volume, type):
        """
            Get source and destination volume IDs
        """
        if type == 'src':
            self.parameters[
                'src_vol_id'] = self.elementsw_helper.volume_exists(
                    volume, self.parameters['src_account_id'])
            if self.parameters['src_vol_id'] is None:
                self.module.fail_json(
                    msg="Error: source volume %s does not exist" %
                    (self.parameters['src_volume']))
        elif type == 'dest':
            self.parameters[
                'dest_vol_id'] = self.dest_elementsw_helper.volume_exists(
                    volume, self.parameters['dest_account_id'])
            if self.parameters['dest_vol_id'] is None:
                self.module.fail_json(
                    msg="Error: destination volume %s does not exist" %
                    (self.parameters['dest_volume']))

    def get_ids(self):
        """
            Get IDs for volumes and accounts
        """
        self.get_account_id(self.parameters['src_account'], 'src')
        self.get_account_id(self.parameters['dest_account'], 'dest')
        self.get_volume_id(self.parameters['src_volume'], 'src')
        self.get_volume_id(self.parameters['dest_volume'], 'dest')

    def apply(self):
        """
            Call create / delete volume pair methods
        """
        self.get_ids()
        paired = self.pairing_exists(self.parameters['src_vol_id'],
                                     self.parameters['dest_vol_id'])
        # calling helper to determine action
        cd_action = self.na_helper.get_cd_action(paired, self.parameters)
        if cd_action == "create":
            self.pair_volumes()
        elif cd_action == "delete":
            self.unpair_volumes()
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #17
0
class NetAppOntapFCP(object):
    """
    Enable and Disable FCP
    """

    def __init__(self):
        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'),
            status=dict(required=False, choices=['up', 'down'], default='up')
        ))

        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)

        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_fcp(self):
        """
        Create's and Starts an FCP
        :return: none
        """
        try:
            self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-create'), True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating FCP: %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def start_fcp(self):
        """
        Starts an existing FCP
        :return: none
        """
        try:
            self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-start'), True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error starting FCP %s' %
                                      (to_native(error)),
                                  exception=traceback.format_exc())

    def stop_fcp(self):
        """
        Steps an Existing FCP
        :return: none
        """
        try:
            self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-stop'), True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error Stoping FCP %s' %
                                      (to_native(error)),
                                  exception=traceback.format_exc())

    def destroy_fcp(self):
        """
        Destroys an already stopped FCP
        :return:
        """
        try:
            self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-destroy'), True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error destroying FCP %s' %
                                      (to_native(error)),
                                  exception=traceback.format_exc())

    def get_fcp(self):
        fcp_obj = netapp_utils.zapi.NaElement('fcp-service-get-iter')
        fcp_info = netapp_utils.zapi.NaElement('fcp-service-info')
        fcp_info.add_new_child('vserver', self.parameters['vserver'])
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(fcp_info)
        fcp_obj.add_child_elem(query)
        result = self.server.invoke_successfully(fcp_obj, True)
        # There can only be 1 FCP per vserver. If true, one is set up, else one isn't set up
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) >= 1:
            return True
        else:
            return False

    def current_status(self):
        try:
            status = self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-status'), True)
            return status.get_child_content('is-available') == 'true'
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error destroying FCP: %s' %
                                      (to_native(error)),
                                  exception=traceback.format_exc())

    def apply(self):
        exists = self.get_fcp()
        changed = False
        if self.parameters['state'] == 'present':
            if exists:
                if self.parameters['status'] == 'up':
                    if not self.current_status():
                        self.start_fcp()
                        changed = True
                else:
                    if self.current_status():
                        self.stop_fcp()
                        changed = True
            else:
                self.create_fcp()
                if self.parameters['status'] == 'up':
                    self.start_fcp()
                changed = True
        else:
            if exists:
                if self.current_status():
                    self.stop_fcp()
                self.destroy_fcp()
                changed = True
        self.module.exit_json(changed=changed)
コード例 #18
0
class NetAppOntapNode(object):
    """
    Rename node
    """

    def __init__(self):
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(dict(
            name=dict(required=True, type='str'),
            from_name=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)

        if HAS_NETAPP_LIB is False:
            self.module.fail_json(msg="the python NetApp-Lib module is required")
        else:
            self.cluster = netapp_utils.setup_na_ontap_zapi(module=self.module)
        return

    def rename_node(self):
        """
        Rename an existing node
        :return: none
        """
        node_obj = netapp_utils.zapi.NaElement('system-node-rename')
        node_obj.add_new_child('node', self.parameters['from_name'])
        node_obj.add_new_child('new-name', self.parameters['name'])
        try:
            self.cluster.invoke_successfully(node_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating node: %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def get_node(self, name):
        node_obj = netapp_utils.zapi.NaElement('system-node-get')
        node_obj.add_new_child('node', name)
        try:
            self.cluster.invoke_successfully(node_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            if to_native(error.code) == "13115":
                # 13115 (EINVALIDINPUTERROR) if the node does not exist
                return None
            else:
                self.module.fail_json(msg=to_native(
                    error), exception=traceback.format_exc())
        return True

    def apply(self):
        # logging ems event
        results = netapp_utils.get_cserver(self.cluster)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
        netapp_utils.ems_log_event("na_ontap_node", cserver)

        exists = self.get_node(self.parameters['name'])
        from_exists = self.get_node(self.parameters['from_name'])
        changed = False
        if exists:
            pass
        else:
            if from_exists:
                self.rename_node()
                changed = True
            else:
                self.module.fail_json(msg='Error renaming node, from_name %s does not exist' % self.parameters['from_name'])

        self.module.exit_json(changed=changed)
コード例 #19
0
class NetAppONTAPasup(object):
    """Class with autosupport methods"""
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            choices=['present', 'absent'],
                            default='present'),
                 node_name=dict(required=True, type='str'),
                 transport=dict(required=False,
                                type='str',
                                choices=['smtp', 'http', 'https']),
                 noteto=dict(required=False, type='list'),
                 post_url=dict(reuired=False, type='str'),
                 support=dict(required=False, type='bool'),
                 mail_hosts=dict(required=False, type='list')))

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

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # present or absent requires modifying state to enabled or disabled
        self.parameters['service_state'] = 'started' if self.parameters[
            'state'] == 'present' else 'stopped'

        if HAS_NETAPP_LIB is False:
            self.module.fail_json(
                msg="the python NetApp-Lib module is required")
        else:
            self.server = netapp_utils.setup_ontap_zapi(module=self.module)

    def get_autosupport_config(self):
        """
        Invoke zapi - get current autosupport status
        @return: 'true' or 'false' / FAILURE with an error_message
        """
        asup_details = netapp_utils.zapi.NaElement('autosupport-config-get')
        asup_details.add_new_child('node-name', self.parameters['node_name'])
        asup_info = dict()
        try:
            result = self.server.invoke_successfully(asup_details,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='%s' % to_native(error),
                                  exception=traceback.format_exc())
        # zapi invoke successful
        asup_attr_info = result.get_child_by_name(
            'attributes').get_child_by_name('autosupport-config-info')
        current_state = asup_attr_info.get_child_content('is-enabled')
        if current_state == 'true':
            asup_info['service_state'] = 'started'
        elif current_state == 'false':
            asup_info['service_state'] = 'stopped'
        current_support = asup_attr_info.get_child_content(
            'is-support-enabled')
        if current_support == 'true':
            asup_info['support'] = True
        elif current_support == 'false':
            asup_info['support'] = False
        asup_info['transport'] = asup_attr_info.get_child_content('transport')
        asup_info['post_url'] = asup_attr_info.get_child_content('post-url')
        mail_hosts = asup_attr_info.get_child_by_name('mail-hosts')
        # mail hosts has one valid entry always
        if mail_hosts is not None:
            # get list of mail hosts
            asup_info['mail_hosts'] = [
                mail.get_content() for mail in mail_hosts.get_children()
            ]
        email_list = asup_attr_info.get_child_by_name('noteto')
        # if email_list is empty, noteto is also empty
        asup_info['noteto'] = [] if email_list is None else [
            email.get_content() for email in email_list.get_children()
        ]
        return asup_info

    def modify_autosupport_config(self, modify):
        """
        Invoke zapi - modify autosupport config
        @return: NaElement object / FAILURE with an error_message
        """
        asup_details = netapp_utils.zapi.NaElement('autosupport-config-modify')
        asup_details.add_new_child('node-name', self.parameters['node_name'])
        if modify.get('service_state'):
            if modify.get('service_state') == 'started':
                asup_details.add_new_child('is-enabled', 'true')
            elif modify.get('service_state') == 'stopped':
                asup_details.add_new_child('is-enabled', 'false')
        if modify.get('support') is not None:
            if modify.get('support') is True:
                asup_details.add_new_child('is-support-enabled', 'true')
            elif modify.get('support') is False:
                asup_details.add_new_child('is-support-enabled', 'false')
        if modify.get('transport'):
            asup_details.add_new_child('transport', modify['transport'])
        if modify.get('post_url'):
            asup_details.add_new_child('post-url', modify['post_url'])
        if modify.get('noteto'):
            asup_email = netapp_utils.zapi.NaElement('noteto')
            asup_details.add_child_elem(asup_email)
            for email in modify.get('noteto'):
                asup_email.add_new_child('mail-address', email)
        if modify.get('mail_hosts'):
            asup_mail_hosts = netapp_utils.zapi.NaElement('mail-hosts')
            asup_details.add_child_elem(asup_mail_hosts)
            for mail in modify.get('mail_hosts'):
                asup_mail_hosts.add_new_child('string', mail)
        try:
            result = self.server.invoke_successfully(asup_details,
                                                     enable_tunneling=True)
            return result
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='%s' % to_native(error),
                                  exception=traceback.format_exc())

    def apply(self):
        """
        Apply action to autosupport
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event("na_ontap_autosupport", cserver)

        current = self.get_autosupport_config()
        modify = self.na_helper.get_modified_attributes(
            current, self.parameters)
        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if modify:
                    self.modify_autosupport_config(modify)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #20
0
class NetAppONTAPJob(object):
    '''Class with job schedule cron methods'''

    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(dict(
            state=dict(required=False, choices=[
                       'present', 'absent'], default='present'),
            name=dict(required=True, type='str'),
            job_minutes=dict(required=False, type='list'),
            job_months=dict(required=False, type='list'),
            job_hours=dict(required=False, type='list'),
            job_days_of_month=dict(required=False, type='list'),
            job_days_of_week=dict(required=False, type='list')
        ))

        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)
        self.set_playbook_zapi_key_map()

        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)

    def set_playbook_zapi_key_map(self):
        self.na_helper.zapi_string_keys = {
            'name': 'job-schedule-name',
        }
        self.na_helper.zapi_list_keys = {
            'job_minutes': ('job-schedule-cron-minute', 'cron-minute'),
            'job_months': ('job-schedule-cron-month', 'cron-month'),
            'job_hours': ('job-schedule-cron-hour', 'cron-hour'),
            'job_days_of_month': ('job-schedule-cron-day', 'cron-day-of-month'),
            'job_days_of_week': ('job-schedule-cron-day-of-week', 'cron-day-of-week')
        }

    def get_job_schedule(self):
        """
        Return details about the job
        :param:
            name : Job name
        :return: Details about the Job. None if not found.
        :rtype: dict
        """
        job_get_iter = netapp_utils.zapi.NaElement('job-schedule-cron-get-iter')
        job_get_iter.translate_struct({
            'query': {
                'job-schedule-cron-info': {
                    'job-schedule-name': self.parameters['name']
                }
            }
        })
        result = self.server.invoke_successfully(job_get_iter, True)
        job_details = None
        # check if job exists
        if result.get_child_by_name('num-records') and int(result['num-records']) >= 1:
            job_info = result['attributes-list']['job-schedule-cron-info']
            job_details = dict()
            for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
                job_details[item_key] = job_info[zapi_key]
            for item_key, zapi_key in self.na_helper.zapi_list_keys.items():
                parent, dummy = zapi_key
                job_details[item_key] = self.na_helper.get_value_for_list(from_zapi=True,
                                                                          zapi_parent=job_info.get_child_by_name(parent)
                                                                          )
                # if any of the job_hours, job_minutes, job_months, job_days are empty:
                # it means the value is -1 for ZAPI
                if not job_details[item_key]:
                    job_details[item_key] = ['-1']
        return job_details

    def add_job_details(self, na_element_object, values):
        """
        Add children node for create or modify NaElement object
        :param na_element_object: modif or create NaElement object
        :param values: dictionary of cron values to be added
        :return: None
        """
        for item_key in values:
            if item_key in self.na_helper.zapi_string_keys:
                zapi_key = self.na_helper.zapi_string_keys.get(item_key)
                na_element_object[zapi_key] = values[item_key]
            elif item_key in self.na_helper.zapi_list_keys:
                parent_key, child_key = self.na_helper.zapi_list_keys.get(item_key)
                na_element_object.add_child_elem(self.na_helper.get_value_for_list(from_zapi=False,
                                                                                   zapi_parent=parent_key,
                                                                                   zapi_child=child_key,
                                                                                   data=values.get(item_key)))

    def create_job_schedule(self):
        """
        Creates a job schedule
        """
        # job_minutes is mandatory for create
        if self.parameters.get('job_minutes') is None:
            self.module.fail_json(msg='Error: missing required parameter job_minutes for create')

        job_schedule_create = netapp_utils.zapi.NaElement('job-schedule-cron-create')
        self.add_job_details(job_schedule_create, self.parameters)
        try:
            self.server.invoke_successfully(job_schedule_create,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating job schedule %s: %s'
                                  % (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_job_schedule(self):
        """
        Delete a job schedule
        """
        job_schedule_delete = netapp_utils.zapi.NaElement('job-schedule-cron-destroy')
        self.add_job_details(job_schedule_delete, self.parameters)
        try:
            self.server.invoke_successfully(job_schedule_delete,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting job schedule %s: %s'
                                  % (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def modify_job_schedule(self, params):
        """
        modify a job schedule
        """
        job_schedule_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'job-schedule-cron-modify', **{'job-schedule-name': self.parameters['name']})
        self.add_job_details(job_schedule_modify, params)
        try:
            self.server.invoke_successfully(job_schedule_modify, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error modifying job schedule %s: %s'
                                  % (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def autosupport_log(self):
        """
        Autosupport log for job_schedule
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
        netapp_utils.ems_log_event("na_ontap_job_schedule", cserver)

    def apply(self):
        """
        Apply action to job-schedule
        """
        self.autosupport_log()
        current = self.get_job_schedule()
        action = self.na_helper.get_cd_action(current, self.parameters)
        if action is None and self.parameters['state'] == 'present':
            modify = self.na_helper.get_modified_attributes(current, self.parameters)

        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if action == 'create':
                    self.create_job_schedule()
                elif action == 'delete':
                    self.delete_job_schedule()
                elif modify:
                    self.modify_job_schedule(modify)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #21
0
class NetAppONTAPSnapmirror(object):
    """
    Class with Snapmirror methods
    """
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            type='str',
                            choices=['present', 'absent'],
                            default='present'),
                 source_vserver=dict(required=False, type='str'),
                 destination_vserver=dict(required=False, type='str'),
                 source_volume=dict(required=False, type='str'),
                 destination_volume=dict(required=False, type='str'),
                 source_path=dict(required=False, type='str'),
                 destination_path=dict(required=False, type='str'),
                 schedule=dict(required=False, type='str'),
                 relationship_type=dict(required=False,
                                        type='str',
                                        choices=[
                                            'data_protection', 'load_sharing',
                                            'vault', 'restore',
                                            'transition_data_protection',
                                            'extended_data_protection'
                                        ]),
                 source_hostname=dict(required=False, type='str'),
                 source_username=dict(required=False, type='str'),
                 source_password=dict(required=False, type='str',
                                      no_log=True)))

        self.module = AnsibleModule(
            argument_spec=self.argument_spec,
            required_together=(['source_volume', 'destination_volume'],
                               ['source_vserver', 'destination_vserver']),
            supports_check_mode=True)

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # setup later if required
        self.source_server = None
        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)

    def snapmirror_get_iter(self):
        """
        Compose NaElement object to query current SnapMirror relations using destination-path
        SnapMirror relation for a destination path is unique
        :return: NaElement object for SnapMirror-get-iter
        """
        snapmirror_get_iter = netapp_utils.zapi.NaElement(
            'snapmirror-get-iter')
        query = netapp_utils.zapi.NaElement('query')
        snapmirror_info = netapp_utils.zapi.NaElement('snapmirror-info')
        snapmirror_info.add_new_child('destination-location',
                                      self.parameters['destination_path'])
        query.add_child_elem(snapmirror_info)
        snapmirror_get_iter.add_child_elem(query)
        return snapmirror_get_iter

    def snapmirror_get(self):
        """
        Get current SnapMirror relations
        :return: Dictionary of current SnapMirror details if query successful, else None
        """
        snapmirror_get_iter = self.snapmirror_get_iter()
        snap_info = dict()
        try:
            result = self.server.invoke_successfully(snapmirror_get_iter,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching snapmirror info: %s' %
                                  to_native(error),
                                  exception=traceback.format_exc())
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) > 0:
            snapmirror_info = result.get_child_by_name(
                'attributes-list').get_child_by_name('snapmirror-info')
            snap_info['mirror_state'] = snapmirror_info.get_child_content(
                'mirror-state')
            snap_info['status'] = snapmirror_info.get_child_content(
                'relationship-status')
            snap_info['schedule'] = snapmirror_info.get_child_content(
                'schedule')
            if snap_info['schedule'] is None:
                snap_info['schedule'] = ""
            return snap_info
        return None

    def snapmirror_create(self):
        """
        Create a SnapMirror relationship
        """
        options = {
            'source-location': self.parameters['source_path'],
            'destination-location': self.parameters['destination_path']
        }
        snapmirror_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-create', **options)
        if self.parameters.get('relationship_type'):
            snapmirror_create.add_new_child(
                'relationship-type', self.parameters['relationship_type'])
        if self.parameters.get('schedule'):
            snapmirror_create.add_new_child('schedule',
                                            self.parameters['schedule'])
        try:
            self.server.invoke_successfully(snapmirror_create,
                                            enable_tunneling=True)
            self.snapmirror_initialize()
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating SnapMirror %s' %
                                  to_native(error),
                                  exception=traceback.format_exc())

    def delete_snapmirror(self):
        """
        Delete a SnapMirror relationship
        #1. Quiesce the SnapMirror relationship at destination
        #2. Break the SnapMirror relationship at the source
        #3. Release the SnapMirror at source
        #4. Delete SnapMirror at destination
        """
        if not self.parameters.get('source_hostname'):
            self.module.fail_json(
                msg='Missing parameters for delete: Please specify the '
                'source cluster hostname to release the SnapMirror relation')
        if self.parameters.get('source_username'):
            self.module.params['username'] = self.parameters['source_username']
        if self.parameters.get('source_password'):
            self.module.params['password'] = self.parameters['source_password']
        self.module.params['hostname'] = self.parameters['source_hostname']
        self.source_server = netapp_utils.setup_ontap_zapi(module=self.module)
        self.snapmirror_quiesce()
        if self.parameters.get('relationship_type') and \
                self.parameters.get('relationship_type') not in ['load_sharing', 'vault']:
            self.snapmirror_break()
        if self.get_destination():
            self.snapmirror_release()
        self.snapmirror_delete()

    def snapmirror_quiesce(self):
        """
        Quiesce SnapMirror relationship - disable all future transfers to this destination
        """
        options = {'destination-location': self.parameters['destination_path']}

        snapmirror_quiesce = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-quiesce', **options)
        try:
            self.server.invoke_successfully(snapmirror_quiesce,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error Quiescing SnapMirror : %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def snapmirror_delete(self):
        """
        Delete SnapMirror relationship at destination cluster
        """
        options = {'destination-location': self.parameters['destination_path']}

        snapmirror_delete = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-destroy', **options)
        try:
            self.server.invoke_successfully(snapmirror_delete,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting SnapMirror : %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def snapmirror_break(self):
        """
        Break SnapMirror relationship at destination cluster
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_break = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-break', **options)
        try:
            self.server.invoke_successfully(snapmirror_break,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error breaking SnapMirror relationship : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_release(self):
        """
        Release SnapMirror relationship from source cluster
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_release = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-release', **options)
        try:
            self.source_server.invoke_successfully(snapmirror_release,
                                                   enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error releasing SnapMirror relationship : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_abort(self):
        """
        Abort a SnapMirror relationship in progress
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_abort = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-abort', **options)
        try:
            self.server.invoke_successfully(snapmirror_abort,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error aborting SnapMirror relationship : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_initialize(self):
        """
        Initialize SnapMirror based on relationship type
        """
        current = self.snapmirror_get()
        if current['mirror_state'] != 'snapmirrored':
            initialize_zapi = 'snapmirror-initialize'
            if self.parameters.get('relationship_type') and self.parameters[
                    'relationship_type'] == 'load_sharing':
                initialize_zapi = 'snapmirror-initialize-ls-set'
                options = {'source-location': self.parameters['source_path']}
            else:
                options = {
                    'destination-location': self.parameters['destination_path']
                }
            snapmirror_init = netapp_utils.zapi.NaElement.create_node_with_children(
                initialize_zapi, **options)
            try:
                self.server.invoke_successfully(snapmirror_init,
                                                enable_tunneling=True)
            except netapp_utils.zapi.NaApiError as error:
                self.module.fail_json(
                    msg='Error initializing SnapMirror : %s' %
                    (to_native(error)),
                    exception=traceback.format_exc())

    def snapmirror_modify(self, modify):
        """
        Modify SnapMirror schedule
        """
        options = {
            'destination-location': self.parameters['destination_path'],
            'schedule': modify.get('schedule')
        }
        snapmirror_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-modify', **options)
        try:
            self.server.invoke_successfully(snapmirror_modify,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error modifying SnapMirror schedule : %s' %
                (to_native(error)),
                exception=traceback.format_exc())

    def snapmirror_update(self):
        """
        Update data in destination endpoint
        """
        options = {'destination-location': self.parameters['destination_path']}
        snapmirror_update = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapmirror-update', **options)
        try:
            result = self.server.invoke_successfully(snapmirror_update,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error updating SnapMirror : %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def check_parameters(self):
        """
        Validate parameters and fail if one or more required params are missing
        Update source and destination path from vserver and volume parameters
        """
        if self.parameters['state'] == 'present'\
                and (self.parameters.get('source_path') or self.parameters.get('destination_path')):
            if not self.parameters.get(
                    'destination_path') or not self.parameters.get(
                        'source_path'):
                self.module.fail_json(
                    msg='Missing parameters: Source path or Destination path')
        elif self.parameters.get('source_volume'):
            if not self.parameters.get(
                    'source_vserver') or not self.parameters.get(
                        'destination_vserver'):
                self.module.fail_json(
                    msg=
                    'Missing parameters: source vserver or destination vserver or both'
                )
            self.parameters['source_path'] = self.parameters[
                'source_vserver'] + ":" + self.parameters['source_volume']
            self.parameters['destination_path'] = self.parameters['destination_vserver'] + ":" +\
                self.parameters['destination_volume']
        elif self.parameters.get('source_vserver'):
            self.parameters[
                'source_path'] = self.parameters['source_vserver'] + ":"
            self.parameters['destination_path'] = self.parameters[
                'destination_vserver'] + ":"

    def get_destination(self):
        release_get = netapp_utils.zapi.NaElement(
            'snapmirror-get-destination-iter')
        query = netapp_utils.zapi.NaElement('query')
        snapmirror_dest_info = netapp_utils.zapi.NaElement(
            'snapmirror-destination-info')
        snapmirror_dest_info.add_new_child('destination-location',
                                           self.parameters['destination_path'])
        query.add_child_elem(snapmirror_dest_info)
        release_get.add_child_elem(query)
        try:
            result = self.source_server.invoke_successfully(
                release_get, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error fetching snapmirror destinations info: %s' %
                to_native(error),
                exception=traceback.format_exc())
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) > 0:
            return True
        return None

    def apply(self):
        """
        Apply action to SnapMirror
        """
        self.check_parameters()
        current = self.snapmirror_get()
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        modify = self.na_helper.get_modified_attributes(
            current, self.parameters)

        if cd_action == 'create':
            self.snapmirror_create()
        elif cd_action == 'delete':
            if current['status'] == 'transferring':
                self.snapmirror_abort()
            else:
                self.delete_snapmirror()
        else:
            if modify:
                self.snapmirror_modify(modify)
            # check for initialize
            if current and current['mirror_state'] != 'snapmirrored':
                self.snapmirror_initialize()
                # set changed explicitly for initialize
                self.na_helper.changed = True
            # Update when create is called again, or modify is being called
            if self.parameters['state'] == 'present':
                self.snapmirror_update()
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #22
0
class NetAppOntapKerberosRealm(object):
    '''
    Kerberos Realm definition class
    '''

    def __init__(self):
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(dict(
            admin_server_ip=dict(required=False, default=None, type='str'),
            admin_server_port=dict(required=False, default=None, type='str'),
            clock_skew=dict(required=False, default=None, type='str'),
            comment=dict(required=False, default=None, type='str'),
            kdc_ip=dict(required_if=[["state", "present"]], default=None, type='str'),
            kdc_port=dict(required=False, default=None, type='str'),
            kdc_vendor=dict(required_if=[["state", "present"]], default=None, type='str', choices=['Microsoft', 'Other']),
            pw_server_ip=dict(required=False, default=None, type='str'),
            pw_server_port=dict(required=False, default=None, type='str'),
            realm=dict(required=True, type='str'),
            state=dict(required=False, choices=['present', 'absent'], default='present'),
            vserver=dict(required=True, type='str')
        ))

        self.module = AnsibleModule(
            argument_spec=self.argument_spec,
            supports_check_mode=True,
            required_if=[('state', 'present', ['kdc_vendor', 'kdc_ip'])],
        )
        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        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'])

        self.simple_attributes = [
            'admin_server_ip',
            'admin_server_port',
            'clock_skew',
            'kdc_ip',
            'kdc_port',
            'kdc_vendor',
        ]

    def get_krbrealm(self, realm_name=None, vserver_name=None):
        '''
        Checks if Kerberos Realm config exists.

        :return:
            kerberos realm object if found
            None if not found
        :rtype: object/None
        '''
        # Make query
        krbrealm_info = netapp_utils.zapi.NaElement('kerberos-realm-get-iter')

        if realm_name is None:
            realm_name = self.parameters['realm']

        if vserver_name is None:
            vserver_name = self.parameters['vserver']

        query_details = netapp_utils.zapi.NaElement.create_node_with_children('kerberos-realm', **{'realm': realm_name, 'vserver-name': vserver_name})

        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(query_details)
        krbrealm_info.add_child_elem(query)

        result = self.server.invoke_successfully(krbrealm_info, enable_tunneling=True)

        # Get Kerberos Realm details
        krbrealm_details = None
        if (result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1):
            attributes_list = result.get_child_by_name('attributes-list')
            config_info = attributes_list.get_child_by_name('kerberos-realm')

            krbrealm_details = {
                'admin_server_ip': config_info.get_child_content('admin-server-ip'),
                'admin_server_port': config_info.get_child_content('admin-server-port'),
                'clock_skew': config_info.get_child_content('clock-skew'),
                'kdc_ip': config_info.get_child_content('kdc-ip'),
                'kdc_port': config_info.get_child_content('kdc-port'),
                'kdc_vendor': config_info.get_child_content('kdc-vendor'),
                'pw_server_ip': config_info.get_child_content('password-server-ip'),
                'pw_server_port': config_info.get_child_content('password-server-port'),
                'realm': config_info.get_child_content('realm'),
                'vserver': config_info.get_child_content('vserver'),
            }

        return krbrealm_details

    def create_krbrealm(self):
        '''supported
        Create Kerberos Realm configuration
        '''
        options = {
            'realm': self.parameters['realm']
        }

        # Other options/attributes
        for attribute in self.simple_attributes:
            if self.parameters.get(attribute) is not None:
                options[str(attribute).replace('_', '-')] = self.parameters[attribute]

        if self.parameters.get('pw_server_ip') is not None:
            options['password-server-ip'] = self.parameters['pw_server_ip']
        if self.parameters.get('pw_server_port') is not None:
            options['password-server-port'] = self.parameters['pw_server_port']

        # Initialize NaElement
        krbrealm_create = netapp_utils.zapi.NaElement.create_node_with_children('kerberos-realm-create', **options)

        # Try to create Kerberos Realm configuration
        try:
            self.server.invoke_successfully(krbrealm_create, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as errcatch:
            self.module.fail_json(msg='Error creating Kerberos Realm configuration %s: %s' % (self.parameters['realm'], to_native(errcatch)),
                                  exception=traceback.format_exc())

    def delete_krbrealm(self):
        '''
        Delete Kerberos Realm configuration
        '''
        krbrealm_delete = netapp_utils.zapi.NaElement.create_node_with_children('kerberos-realm-delete', **{'realm': self.parameters['realm']})

        try:
            self.server.invoke_successfully(krbrealm_delete, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as errcatch:
            self.module.fail_json(msg='Error deleting Kerberos Realm configuration %s: %s' % (
                self.parameters['realm'], to_native(errcatch)), exception=traceback.format_exc())

    def modify_krbrealm(self, modify):
        '''
        Modify Kerberos Realm
        :param modify: list of modify attributes
        '''
        krbrealm_modify = netapp_utils.zapi.NaElement('kerberos-realm-modify')
        krbrealm_modify.add_new_child('realm', self.parameters['realm'])

        for attribute in modify:
            if attribute in self.simple_attributes:
                krbrealm_modify.add_new_child(str(attribute).replace('_', '-'), self.parameters[attribute])
            if attribute == 'pw_server_ip':
                krbrealm_modify.add_new_child('password-server-ip', self.parameters['pw_server_ip'])
            if attribute == 'pw_server_port':
                krbrealm_modify.add_new_child('password-server-port', self.parameters['pw_server_port'])

        # Try to modify Kerberos Realm
        try:
            self.server.invoke_successfully(krbrealm_modify, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as errcatch:
            self.module.fail_json(msg='Error modifying Kerberos Realm %s: %s' % (self.parameters['realm'], to_native(errcatch)),
                                  exception=traceback.format_exc())

    def apply(self):
        '''Call create/modify/delete operations.'''
        current = self.get_krbrealm()
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        modify = self.na_helper.get_modified_attributes(current, self.parameters)
        #  create an ems log event for users with auto support turned on
        netapp_utils.ems_log_event("na_ontap_kerberos_realm", self.server)

        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if cd_action == 'create':
                    self.create_krbrealm()
                elif cd_action == 'delete':
                    self.delete_krbrealm()
                elif modify:
                    self.modify_krbrealm(modify)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #23
0
ファイル: na_ontap_autosupport.py プロジェクト: ydd171/public
class NetAppONTAPasup(object):
    """Class with autosupport methods"""
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(
                state=dict(required=False,
                           choices=['present', 'absent'],
                           default='present'),
                node_name=dict(required=True, type='str'),
                transport=dict(required=False,
                               type='str',
                               choices=['smtp', 'http', 'https']),
                noteto=dict(required=False, type='list'),
                post_url=dict(reuired=False, type='str'),
                support=dict(required=False, type='bool'),
                mail_hosts=dict(required=False, type='list'),
                from_address=dict(required=False, type='str'),
                partner_addresses=dict(required=False, type='list'),
                to_addresses=dict(required=False, type='list'),
                proxy_url=dict(required=False, type='str'),
                hostname_in_subject=dict(required=False, type='bool'),
            ))

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

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # present or absent requires modifying state to enabled or disabled
        self.parameters['service_state'] = 'started' if self.parameters[
            'state'] == 'present' else 'stopped'
        self.set_playbook_zapi_key_map()

        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)

    def set_playbook_zapi_key_map(self):
        self.na_helper.zapi_string_keys = {
            'node_name': 'node-name',
            'transport': 'transport',
            'post_url': 'post-url',
            'from_address': 'from',
            'proxy_url': 'proxy-url'
        }
        self.na_helper.zapi_list_keys = {
            'noteto': ('noteto', 'mail-address'),
            'mail_hosts': ('mail-hosts', 'string'),
            'partner_addresses': ('partner-address', 'mail-address'),
            'to_addresses': ('to', 'mail-address'),
        }
        self.na_helper.zapi_bool_keys = {
            'support': 'is-support-enabled',
            'hostname_in_subject': 'is-node-in-subject'
        }

    def get_autosupport_config(self):
        """
        Invoke zapi - get current autosupport details
        :return: dict()
        """
        asup_details = netapp_utils.zapi.NaElement('autosupport-config-get')
        asup_details.add_new_child('node-name', self.parameters['node_name'])
        asup_info = dict()
        try:
            result = self.server.invoke_successfully(asup_details,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='%s' % to_native(error),
                                  exception=traceback.format_exc())
        # zapi invoke successful
        asup_attr_info = result.get_child_by_name(
            'attributes').get_child_by_name('autosupport-config-info')
        asup_info['service_state'] = 'started' if asup_attr_info[
            'is-enabled'] == 'true' else 'stopped'
        for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
            asup_info[item_key] = asup_attr_info[zapi_key]
        for item_key, zapi_key in self.na_helper.zapi_bool_keys.items():
            asup_info[item_key] = self.na_helper.get_value_for_bool(
                from_zapi=True, value=asup_attr_info[zapi_key])
        for item_key, zapi_key in self.na_helper.zapi_list_keys.items():
            parent, dummy = zapi_key
            asup_info[item_key] = self.na_helper.get_value_for_list(
                from_zapi=True,
                zapi_parent=asup_attr_info.get_child_by_name(parent))
        return asup_info

    def modify_autosupport_config(self, modify):
        """
        Invoke zapi - modify autosupport config
        @return: NaElement object / FAILURE with an error_message
        """
        asup_details = {'node-name': self.parameters['node_name']}
        if modify.get('service_state'):
            asup_details['is-enabled'] = 'true' if modify.get(
                'service_state') == 'started' else 'false'
        asup_config = netapp_utils.zapi.NaElement('autosupport-config-modify')
        for item_key in modify:
            if item_key in self.na_helper.zapi_string_keys:
                zapi_key = self.na_helper.zapi_string_keys.get(item_key)
                asup_details[zapi_key] = modify[item_key]
            elif item_key in self.na_helper.zapi_bool_keys:
                zapi_key = self.na_helper.zapi_bool_keys.get(item_key)
                asup_details[zapi_key] = self.na_helper.get_value_for_bool(
                    from_zapi=False, value=modify[item_key])
            elif item_key in self.na_helper.zapi_list_keys:
                parent_key, child_key = self.na_helper.zapi_list_keys.get(
                    item_key)
                asup_config.add_child_elem(
                    self.na_helper.get_value_for_list(
                        from_zapi=False,
                        zapi_parent=parent_key,
                        zapi_child=child_key,
                        data=modify.get(item_key)))
        asup_config.translate_struct(asup_details)
        try:
            return self.server.invoke_successfully(asup_config,
                                                   enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='%s' % to_native(error),
                                  exception=traceback.format_exc())

    def autosupport_log(self):
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event("na_ontap_autosupport", cserver)

    def apply(self):
        """
        Apply action to autosupport
        """
        current = self.get_autosupport_config()
        modify = self.na_helper.get_modified_attributes(
            current, self.parameters)
        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                self.modify_autosupport_config(modify)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #24
0
class NetAppOntapClusterHA(object):
    """
    object initialize and class methods
    """
    def __init__(self):

        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            choices=['present', 'absent'],
                            default='present'), ))
        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)

        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)

    def modify_cluster_ha(self, configure):
        """
        Enable or disable HA on cluster
        :return: None
        """
        cluster_ha_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'cluster-ha-modify', **{'ha-configured': configure})
        try:
            self.server.invoke_successfully(cluster_ha_modify,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error modifying cluster HA to %s: %s' %
                                  (configure, to_native(error)),
                                  exception=traceback.format_exc())

    def get_cluster_ha_enabled(self):
        """
        Get current cluster HA details
        :return: dict if enabled, None if disabled
        """
        cluster_ha_get = netapp_utils.zapi.NaElement('cluster-ha-get')
        try:
            result = self.server.invoke_successfully(cluster_ha_get,
                                                     enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error fetching cluster HA details',
                                  exception=traceback.format_exc())
        cluster_ha_info = result.get_child_by_name(
            'attributes').get_child_by_name('cluster-ha-info')
        if cluster_ha_info.get_child_content('ha-configured') == 'true':
            return {'ha-configured': True}
        return None

    def apply(self):
        """
        Apply action to cluster HA
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event("na_ontap_cluster_ha", cserver)
        current = self.get_cluster_ha_enabled()
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        if cd_action == 'create':
            self.modify_cluster_ha("true")
        elif cd_action == 'delete':
            self.modify_cluster_ha("false")

        self.module.exit_json(changed=self.na_helper.changed)
コード例 #25
0
class ElementSWClusterPair(object):
    """ class to handle cluster pairing operations """

    def __init__(self):
        """
            Setup Ansible parameters and ElementSW connection
        """
        self.argument_spec = netapp_utils.ontap_sf_host_argument_spec()
        self.argument_spec.update(dict(
            state=dict(required=False, choices=['present', 'absent'],
                       default='present'),
            dest_mvip=dict(required=True, type='str'),
            dest_username=dict(required=False, type='str'),
            dest_password=dict(required=False, type='str', no_log=True)
        ))

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

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

        self.elementsw_helper = NaElementSWModule(self.elem)
        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        # get element_sw_connection for destination cluster
        # overwrite existing source host, user and password with destination credentials
        self.module.params['hostname'] = self.parameters['dest_mvip']
        # username and password is same as source,
        # if dest_username and dest_password aren't specified
        if self.parameters.get('dest_username'):
            self.module.params['username'] = self.parameters['dest_username']
        if self.parameters.get('dest_password'):
            self.module.params['password'] = self.parameters['dest_password']
        self.dest_elem = netapp_utils.create_sf_connection(module=self.module)
        self.dest_elementsw_helper = NaElementSWModule(self.dest_elem)

    def check_if_already_paired(self):
        """
            Check for idempotency
        """
        # src cluster and dest cluster exist
        paired_clusters = self.elem.list_cluster_pairs()
        for pair in paired_clusters.cluster_pairs:
            if pair.mvip == self.parameters['dest_mvip']:
                return pair.cluster_pair_id
        return None

    def pair_clusters(self):
        """
            Start cluster pairing on source, and complete on target cluster
        """
        try:
            pair_key = self.elem.start_cluster_pairing()
            self.dest_elem.complete_cluster_pairing(
                cluster_pairing_key=pair_key.cluster_pairing_key)
        except solidfire.common.ApiServerError as err:
            self.module.fail_json(msg="Error pairing cluster %s and %s"
                                  % (self.parameters['hostname'],
                                     self.parameters['dest_mvip']),
                                  exception=to_native(err))

    def unpair_clusters(self, pair_id):
        """
            Delete cluster pair
        """
        try:
            self.elem.remove_cluster_pair(cluster_pair_id=pair_id)
            self.dest_elem.remove_cluster_pair(cluster_pair_id=pair_id)
        except solidfire.common.ApiServerError as err:
            self.module.fail_json(msg="Error unpairing cluster %s and %s"
                                  % (self.parameters['hostname'],
                                     self.parameters['dest_mvip']),
                                  exception=to_native(err))

    def apply(self):
        """
            Call create / delete cluster pair methods
        """
        pair_id = self.check_if_already_paired()
        # calling helper to determine action
        cd_action = self.na_helper.get_cd_action(pair_id, self.parameters)
        if cd_action == "create":
            self.pair_clusters()
        elif cd_action == "delete":
            self.unpair_clusters(pair_id)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #26
0
class NetAppOntapBroadcastDomain(object):
    """
        Create, Modifies and Destroys a Broadcast domain
    """
    def __init__(self):
        """
            Initialize the ONTAP Broadcast Domain 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'),
            name=dict(required=True, type='str', aliases=["broadcast_domain"]),
            ipspace=dict(required=False, type='str'),
            mtu=dict(required=False, type='str'),
            ports=dict(required=False, type='list'),
            from_name=dict(required=False, 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)

        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)
        return

    def get_broadcast_domain(self, broadcast_domain=None):
        """
        Return details about the broadcast domain
        :param broadcast_domain: specific broadcast domain to get.
        :return: Details about the broadcast domain. None if not found.
        :rtype: dict
        """
        if broadcast_domain is None:
            broadcast_domain = self.parameters['name']
        domain_get_iter = netapp_utils.zapi.NaElement('net-port-broadcast-domain-get-iter')
        broadcast_domain_info = netapp_utils.zapi.NaElement('net-port-broadcast-domain-info')
        broadcast_domain_info.add_new_child('broadcast-domain', broadcast_domain)
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(broadcast_domain_info)
        domain_get_iter.add_child_elem(query)
        result = self.server.invoke_successfully(domain_get_iter, True)
        domain_exists = None
        # check if broadcast_domain exists
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) == 1:
            domain_info = result.get_child_by_name('attributes-list').\
                get_child_by_name('net-port-broadcast-domain-info')
            domain_name = domain_info.get_child_content('broadcast-domain')
            domain_mtu = domain_info.get_child_content('mtu')
            domain_ipspace = domain_info.get_child_content('ipspace')
            domain_ports = domain_info.get_child_by_name('ports')
            if domain_ports is not None:
                ports = [port.get_child_content('port') for port in domain_ports.get_children()]
            else:
                ports = []
            domain_exists = {
                'domain-name': domain_name,
                'mtu': domain_mtu,
                'ipspace': domain_ipspace,
                'ports': ports
            }
        return domain_exists

    def create_broadcast_domain(self):
        """
        Creates a new broadcast domain
        """
        domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-create')
        domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        if self.parameters.get('mtu'):
            domain_obj.add_new_child("mtu", self.parameters['mtu'])
        if self.parameters.get('ports'):
            ports_obj = netapp_utils.zapi.NaElement('ports')
            domain_obj.add_child_elem(ports_obj)
            for port in self.parameters['ports']:
                ports_obj.add_new_child('net-qualified-port-name', port)
        try:
            self.server.invoke_successfully(domain_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating broadcast domain %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_broadcast_domain(self, broadcast_domain=None):
        """
        Deletes a broadcast domain
        """
        if broadcast_domain is None:
            broadcast_domain = self.parameters['name']
        domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-destroy')
        domain_obj.add_new_child("broadcast-domain", broadcast_domain)
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        try:
            self.server.invoke_successfully(domain_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting broadcast domain %s: %s' %
                                  (broadcast_domain, to_native(error)),
                                  exception=traceback.format_exc())

    def modify_broadcast_domain(self):
        """
        Modifies ipspace and mtu options of a broadcast domain
        """
        domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-modify')
        domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
        if self.parameters.get('mtu'):
            domain_obj.add_new_child("mtu", self.parameters['mtu'])
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        try:
            self.server.invoke_successfully(domain_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error modifying broadcast domain %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def split_broadcast_domain(self):
        """
        split broadcast domain
        """
        domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-split')
        domain_obj.add_new_child("broadcast-domain", self.parameters['from_name'])
        domain_obj.add_new_child("new-broadcast-domain", self.parameters['name'])
        if self.parameters.get('ports'):
            ports_obj = netapp_utils.zapi.NaElement('ports')
            domain_obj.add_child_elem(ports_obj)
            for port in self.parameters['ports']:
                ports_obj.add_new_child('net-qualified-port-name', port)
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        try:
            self.server.invoke_successfully(domain_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error splitting broadcast domain %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())
        if len(self.get_broadcast_domain_ports(self.parameters['from_name'])) == 0:
            self.delete_broadcast_domain(self.parameters['from_name'])

    def modify_redirect(self, modify):
        """
        :param modify: modify attributes.
        """
        for attribute in modify.keys():
            if attribute == 'mtu':
                self.modify_broadcast_domain()
            if attribute == 'ports':
                self.modify_broadcast_domain_ports()

    def get_modify_attributes(self, current, split):
        """
        :param current: current state.
        :param split: True or False of split action.
        :return: list of modified attributes.
        """
        modify = None
        if self.parameters['state'] == 'present':
            # split already handled ipspace and ports.
            if self.parameters.get('from_name'):
                current = self.get_broadcast_domain(self.parameters['from_name'])
                if split:
                    modify = self.na_helper.get_modified_attributes(current, self.parameters)
                    if modify.get('ipspace'):
                        del modify['ipspace']
                    if modify.get('ports'):
                        del modify['ports']
        # ipspace can not be modified.
            else:
                modify = self.na_helper.get_modified_attributes(current, self.parameters)
                if modify.get('ipspace'):
                    self.module.fail_json(msg='A domain ipspace can not be modified after the domain has been created.',
                                          exception=traceback.format_exc())
        return modify

    def modify_broadcast_domain_ports(self):
        """
        compare current and desire ports. Call add or remove ports methods if needed.
        :return: None.
        """
        current_ports = self.get_broadcast_domain_ports()
        expect_ports = self.parameters['ports']
        # if want to remove all ports, simply delete the broadcast domain.
        if len(expect_ports) == 0:
            self.delete_broadcast_domain()
            return
        ports_to_remove = list(set(current_ports) - set(expect_ports))
        ports_to_add = list(set(expect_ports) - set(current_ports))

        if len(ports_to_add) > 0:
            self.add_broadcast_domain_ports(ports_to_add)

        if len(ports_to_remove) > 0:
            self.delete_broadcast_domain_ports(ports_to_remove)

    def add_broadcast_domain_ports(self, ports):
        """
        Creates new broadcast domain ports
        """
        domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-add-ports')
        domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        if ports:
            ports_obj = netapp_utils.zapi.NaElement('ports')
            domain_obj.add_child_elem(ports_obj)
            for port in ports:
                ports_obj.add_new_child('net-qualified-port-name', port)
        try:
            self.server.invoke_successfully(domain_obj, True)
            return True
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating port for broadcast domain %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_broadcast_domain_ports(self, ports):
        """
        Deletes broadcast domain ports
        :param: ports to be deleted.
        """
        domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-remove-ports')
        domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
        if self.parameters.get('ipspace'):
            domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
        if ports:
            ports_obj = netapp_utils.zapi.NaElement('ports')
            domain_obj.add_child_elem(ports_obj)
            for port in ports:
                ports_obj.add_new_child('net-qualified-port-name', port)
        try:
            self.server.invoke_successfully(domain_obj, True)
            return True
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting port for broadcast domain %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def get_broadcast_domain_ports(self, broadcast_domain=None):
        """
        Return details about the broadcast domain ports.
        :return: Details about the broadcast domain ports. None if not found.
        :rtype: list
        """
        if broadcast_domain is None:
            broadcast_domain = self.parameters['name']
        domain_get_iter = netapp_utils.zapi.NaElement('net-port-broadcast-domain-get-iter')
        broadcast_domain_info = netapp_utils.zapi.NaElement('net-port-broadcast-domain-info')
        broadcast_domain_info.add_new_child('broadcast-domain', broadcast_domain)
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(broadcast_domain_info)
        domain_get_iter.add_child_elem(query)
        result = self.server.invoke_successfully(domain_get_iter, True)
        ports = []
        if result.get_child_by_name('num-records') and \
                int(result.get_child_content('num-records')) == 1:
            domain_info = result.get_child_by_name('attributes-list').get_child_by_name('net-port-broadcast-domain-info')
            domain_ports = domain_info.get_child_by_name('ports')
            if domain_ports is not None:
                ports = [port.get_child_content('port') for port in domain_ports.get_children()]
        return ports

    def apply(self):
        """
        Run Module based on play book
        """
        self.asup_log_for_cserver("na_ontap_broadcast_domain")
        current = self.get_broadcast_domain()
        cd_action, split = None, None
        cd_action = self.na_helper.get_cd_action(current, self.parameters)
        if cd_action == 'create':
            # either create new domain or split domain.
            if self.parameters.get('from_name'):
                split = self.na_helper.is_rename_action(self.get_broadcast_domain(self.parameters['from_name']), current)
                if split is None:
                    self.module.fail_json(msg='A domain can not be split if it does not exist.',
                                          exception=traceback.format_exc())
                if split:
                    cd_action = None
        modify = self.get_modify_attributes(current, split)
        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if split:
                    self.split_broadcast_domain()
                if cd_action == 'create':
                    self.create_broadcast_domain()
                elif cd_action == 'delete':
                    self.delete_broadcast_domain()
                elif modify:
                    self.modify_redirect(modify)
        self.module.exit_json(changed=self.na_helper.changed)

    def asup_log_for_cserver(self, event_name):
        """
        Fetch admin vserver for the given cluster
        Create and Autosupport log event with the given module name
        :param event_name: Name of the event log
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
        netapp_utils.ems_log_event(event_name, cserver)
コード例 #27
0
class NetAppOntapSnapshotPolicy(object):
    """
    Creates and deletes a Snapshot Policy
    """
    def __init__(self):
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(state=dict(required=False,
                            choices=['present', 'absent'],
                            default='present'),
                 name=dict(required=True, type="str"),
                 enabled=dict(required=False, type="bool"),
                 count=dict(required=False, type="int"),
                 comment=dict(required=False, type="str"),
                 schedule=dict(required=False, type="str")))
        self.module = AnsibleModule(argument_spec=self.argument_spec,
                                    required_if=[
                                        ('state', 'present',
                                         ['enabled', 'count', 'schedule']),
                                    ],
                                    supports_check_mode=True)

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        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)
        return

    def get_snapshot_policy(self):
        """
        Checks to see if a snapshot policy exists or not
        :return: Return policy details if a snapshot policy exists, None if it doesn't
        """
        snapshot_obj = netapp_utils.zapi.NaElement("snapshot-policy-get-iter")
        # compose query
        query = netapp_utils.zapi.NaElement("query")
        snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-policy-info")
        snapshot_info_obj.add_new_child("policy", self.parameters['name'])
        query.add_child_elem(snapshot_info_obj)
        snapshot_obj.add_child_elem(query)
        try:
            result = self.server.invoke_successfully(snapshot_obj, True)
            if result.get_child_by_name('num-records') and \
                    int(result.get_child_content('num-records')) == 1:
                return result
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg=to_native(error),
                                  exception=traceback.format_exc())
        return None

    def create_snapshot_policy(self):
        """
        Creates a new snapshot policy
        """
        # set up required variables to create a snapshot policy
        options = {
            'policy': self.parameters['name'],
            'enabled': str(self.parameters['enabled']),
            'count1': str(self.parameters['count']),
            'schedule1': self.parameters['schedule']
        }
        snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children(
            'snapshot-policy-create', **options)

        # Set up optional variables to create a snapshot policy
        if self.parameters.get('comment'):
            snapshot_obj.add_new_child("comment", self.parameters['comment'])
        try:
            self.server.invoke_successfully(snapshot_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating snapshot policy %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_snapshot_policy(self):
        """
        Deletes an existing snapshot policy
        """
        snapshot_obj = netapp_utils.zapi.NaElement("snapshot-policy-delete")

        # Set up required variables to delete a snapshot policy
        snapshot_obj.add_new_child("policy", self.parameters['name'])
        try:
            self.server.invoke_successfully(snapshot_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting snapshot policy %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def asup_log_for_cserver(self, event_name):
        """
        Fetch admin vserver for the given cluster
        Create and Autosupport log event with the given module name
        :param event_name: Name of the event log
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event(event_name, cserver)

    def apply(self):
        """
        Check to see which play we should run
        """
        self.asup_log_for_cserver("na_ontap_snapshot_policy")
        current = self.get_snapshot_policy()
        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_snapshot_policy()
                elif cd_action == 'delete':
                    self.delete_snapshot_policy()
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #28
0
ファイル: na_ontap_dns.py プロジェクト: Matthias-Beck/ansible
class NetAppOntapDns(object):
    """
    Enable and Disable dns
    """
    def __init__(self):
        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')))

        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)

        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
        """
        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)
        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):
        """
        Destroys an already created dns
        :return:
        """
        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):
        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()
        ]
        return attrs

    def modify_dns(self, dns_attrs):
        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:
            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
        netapp_utils.ems_log_event("na_ontap_dns", self.vserver)

        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()
                changed = True
        self.module.exit_json(changed=changed)
コード例 #29
0
class NetAppOntapAggregate(object):
    ''' object initialize and class methods '''
    def __init__(self):
        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
        self.argument_spec.update(
            dict(
                state=dict(required=False,
                           choices=['present', 'absent'],
                           default='present'),
                service_state=dict(required=False,
                                   choices=['online', 'offline']),
                name=dict(required=True, type='str'),
                from_name=dict(required=False, type='str'),
                disk_count=dict(required=False, type='int', default=None),
                disk_type=dict(required=False,
                               choices=[
                                   'ATA', 'BSAS', 'FCAL', 'FSAS', 'LUN',
                                   'MSATA', 'SAS', 'SSD', 'VMDISK'
                               ]),
                raid_type=dict(required=False, type='str'),
                disk_size=dict(required=False, type='int'),
                nodes=dict(required=False, type='list'),
                raid_size=dict(required=False, type='int'),
                unmount_volumes=dict(required=False, type='bool'),
            ))

        self.module = AnsibleModule(argument_spec=self.argument_spec,
                                    required_if=[('service_state', 'offline',
                                                  ['unmount_volumes'])],
                                    supports_check_mode=True)

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)

        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)

    def aggr_get_iter(self, name):
        """
        Return aggr-get-iter query results
        :param name: Name of the aggregate
        :return: NaElement if aggregate found, None otherwise
        """

        aggr_get_iter = netapp_utils.zapi.NaElement('aggr-get-iter')
        query_details = netapp_utils.zapi.NaElement.create_node_with_children(
            'aggr-attributes', **{'aggregate-name': name})
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(query_details)
        aggr_get_iter.add_child_elem(query)
        try:
            result = self.server.invoke_successfully(aggr_get_iter,
                                                     enable_tunneling=False)
        except netapp_utils.zapi.NaApiError as error:
            # Error 13040 denotes an aggregate not being found.
            if to_native(error.code) == "13040":
                return None
            else:
                self.module.fail_json(msg=to_native(error),
                                      exception=traceback.format_exc())
        return result

    def get_aggr(self, name=None):
        """
        Fetch details if aggregate exists.
        :param name: Name of the aggregate to be fetched
        :return:
            Dictionary of current details if aggregate found
            None if aggregate is not found
        """
        if name is None:
            name = self.parameters['name']
        aggr_get = self.aggr_get_iter(name)
        if (aggr_get and aggr_get.get_child_by_name('num-records')
                and int(aggr_get.get_child_content('num-records')) >= 1):
            current_aggr = dict()
            attr = aggr_get.get_child_by_name(
                'attributes-list').get_child_by_name('aggr-attributes')
            current_aggr['service_state'] = attr.get_child_by_name(
                'aggr-raid-attributes').get_child_content('state')
            return current_aggr
        return None

    def aggregate_online(self):
        """
        Set state of an offline aggregate to online
        :return: None
        """
        online_aggr = netapp_utils.zapi.NaElement.create_node_with_children(
            'aggr-online', **{
                'aggregate': self.parameters['name'],
                'force-online': 'true'
            })
        try:
            self.server.invoke_successfully(online_aggr, enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error changing the state of aggregate %s to %s: %s' %
                (self.parameters['name'], self.parameters['service_state'],
                 to_native(error)),
                exception=traceback.format_exc())

    def aggregate_offline(self):
        """
        Set state of an online aggregate to offline
        :return: None
        """
        offline_aggr = netapp_utils.zapi.NaElement.create_node_with_children(
            'aggr-offline', **{
                'aggregate': self.parameters['name'],
                'force-offline': 'false',
                'unmount-volumes': str(self.parameters['unmount_volumes'])
            })
        try:
            self.server.invoke_successfully(offline_aggr,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error changing the state of aggregate %s to %s: %s' %
                (self.parameters['name'], self.parameters['service_state'],
                 to_native(error)),
                exception=traceback.format_exc())

    def create_aggr(self):
        """
        Create aggregate
        :return: None
        """
        if not self.parameters.get('disk_count'):
            self.module.fail_json(msg='Error provisioning aggregate %s: \
                                             disk_count is required' %
                                  self.parameters['name'])
        options = {
            'aggregate': self.parameters['name'],
            'disk-count': str(self.parameters['disk_count'])
        }
        if self.parameters.get('disk_type'):
            options['disk-type'] = self.parameters['disk_type']
        if self.parameters.get('raid_size'):
            options['raid-size'] = str(self.parameters['raid_size'])
        if self.parameters.get('raid_type'):
            options['raid-type'] = self.parameters['raid_type']
        if self.parameters.get('disk_size'):
            options['disk-size'] = str(self.parameters['disk_size'])
        aggr_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'aggr-create', **options)
        if self.parameters.get('nodes'):
            nodes_obj = netapp_utils.zapi.NaElement('nodes')
            aggr_create.add_child_elem(nodes_obj)
            for node in self.parameters['nodes']:
                nodes_obj.add_new_child('node-name', node)

        try:
            self.server.invoke_successfully(aggr_create,
                                            enable_tunneling=False)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error provisioning aggregate %s: %s" %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_aggr(self):
        """
        Delete aggregate.
        :return: None
        """
        aggr_destroy = netapp_utils.zapi.NaElement.create_node_with_children(
            'aggr-destroy', **{'aggregate': self.parameters['name']})

        try:
            self.server.invoke_successfully(aggr_destroy,
                                            enable_tunneling=False)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg="Error removing aggregate %s: %s" %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def rename_aggregate(self):
        """
        Rename aggregate.
        """
        aggr_rename = netapp_utils.zapi.NaElement.create_node_with_children(
            'aggr-rename', **{
                'aggregate': self.parameters['from_name'],
                'new-aggregate-name': self.parameters['name']
            })

        try:
            self.server.invoke_successfully(aggr_rename,
                                            enable_tunneling=False)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg="Error renaming aggregate %s: %s" %
                (self.parameters['from_name'], to_native(error)),
                exception=traceback.format_exc())

    def modify_aggr(self, modify):
        """
        Modify state of the aggregate
        :param modify: dictionary of parameters to be modified
        :return: None
        """
        if modify['service_state'] == 'offline':
            self.aggregate_offline()
        elif modify['service_state'] == 'online':
            self.aggregate_online()

    def asup_log_for_cserver(self, event_name):
        """
        Fetch admin vserver for the given cluster
        Create and Autosupport log event with the given module name
        :param event_name: Name of the event log
        :return: None
        """
        results = netapp_utils.get_cserver(self.server)
        cserver = netapp_utils.setup_na_ontap_zapi(module=self.module,
                                                   vserver=results)
        netapp_utils.ems_log_event(event_name, cserver)

    def apply(self):
        """
        Apply action to the aggregate
        :return: None
        """
        self.asup_log_for_cserver("na_ontap_aggregate")

        current = self.get_aggr()
        # rename and create are mutually exclusive
        rename, cd_action = None, None
        if self.parameters.get('from_name'):
            rename = self.na_helper.is_rename_action(
                self.get_aggr(self.parameters['from_name']), current)
            if rename is None:
                self.module.fail_json(
                    msg="Error renaming: aggregate %s does not exist" %
                    self.parameters['from_name'])
        else:
            cd_action = self.na_helper.get_cd_action(current, self.parameters)
        modify = self.na_helper.get_modified_attributes(
            current, self.parameters)

        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if rename:
                    self.rename_aggregate()
                elif cd_action == 'create':
                    self.create_aggr()
                elif cd_action == 'delete':
                    self.delete_aggr()
                elif modify:
                    self.modify_aggr(modify)
        self.module.exit_json(changed=self.na_helper.changed)
コード例 #30
0
class NetAppOntapNetRoutes(object):
    """
    Create, Modifies and Destroys a Net Route
    """
    def __init__(self):
        """
        Initialize the Ontap Net Route 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'),
                destination=dict(required=True, type='str'),
                gateway=dict(required=True, type='str'),
                metric=dict(required=False, type='str'),
                new_destination=dict(required=False, type='str', default=None),
                new_gateway=dict(required=False, type='str', default=None),
                new_metric=dict(required=False, type='str', default=None),
            ))

        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)

        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_net_route(self, current_metric=None):
        """
        Creates a new Route
        """
        route_obj = netapp_utils.zapi.NaElement('net-routes-create')
        route_obj.add_new_child("destination", self.parameters['destination'])
        route_obj.add_new_child("gateway", self.parameters['gateway'])
        if current_metric is None and self.parameters.get(
                'metric') is not None:
            metric = self.parameters['metric']
        else:
            metric = current_metric
        route_obj.add_new_child("metric", metric)
        try:
            self.server.invoke_successfully(route_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating net route: %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def delete_net_route(self):
        """
        Deletes a given Route
        """
        route_obj = netapp_utils.zapi.NaElement('net-routes-destroy')
        route_obj.add_new_child("destination", self.parameters['destination'])
        route_obj.add_new_child("gateway", self.parameters['gateway'])
        try:
            self.server.invoke_successfully(route_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting net route: %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def modify_net_route(self, current, desired):
        """
        Modify a net route
        """
        # return if there is nothing to change
        for key, val in desired.items():
            if val == current[key]:
                self.na_helper.changed = False
                return
        # delete and re-create with new params
        self.delete_net_route()
        route_obj = netapp_utils.zapi.NaElement('net-routes-create')
        for attribute in ['metric', 'destination', 'gateway']:
            if desired.get(attribute) is not None:
                value = desired[attribute]
            else:
                value = current[attribute]
            route_obj.add_new_child(attribute, value)
        try:
            result = self.server.invoke_successfully(route_obj, True)
        except netapp_utils.zapi.NaApiError as error:
            # restore the old route, create the route with the existing metric
            self.create_net_route(current['metric'])
            # return if desired route already exists
            if to_native(error.code) == '13001':
                return
            # Invalid value specified for any of the attributes
            self.module.fail_json(msg='Error modifying net route: %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())

    def get_net_route(self, params=None):
        """
        Checks to see if a route exist or not
        :return: NaElement object if a route exists, None otherwise
        """
        if params is not None:
            # we need at least on of the new_destination or new_gateway to fetch desired route
            if params.get('destination') is None and params.get(
                    'gateway') is None:
                return None
        current = dict()
        route_obj = netapp_utils.zapi.NaElement('net-routes-get')
        for attr in ['destination', 'gateway']:
            if params and params.get(attr) is not None:
                value = params[attr]
            else:
                value = self.parameters[attr]
            route_obj.add_new_child(attr, value)
        try:
            result = self.server.invoke_successfully(route_obj, True)
            route_info = result.get_child_by_name(
                'attributes').get_child_by_name('net-vs-routes-info')
            current['destination'] = route_info.get_child_content(
                'destination')
            current['gateway'] = route_info.get_child_content('gateway')
            current['metric'] = route_info.get_child_content('metric')
        except netapp_utils.zapi.NaApiError as error:
            # Error 13040 denotes a route doesn't exist.
            if to_native(error.code) == "15661":
                return None
            self.module.fail_json(msg='Error fetching net route: %s' %
                                  (to_native(error)),
                                  exception=traceback.format_exc())
        return current

    def is_modify_action(self, current, desired):
        """
        Get desired action to be applied for net routes
        Destination and gateway are unique params for a route and cannot be duplicated
        So if a route with desired destination or gateway exists already, we don't try to modify
        :param current: current details
        :param desired: desired details
        :return: create / delete / modify / None
        """
        if current is None and desired is None:
            # this is invalid
            # cannot modify a non existent resource
            return None
        if current is None and desired is not None:
            # idempotency or duplication
            # we need not create
            return False
        if current is not None and desired is not None:
            # we can't modify an ambiguous route (idempotency/duplication)
            return False
        return True

    def get_params_to_be_modified(self, current):
        """
        Get parameters and values that need to be modified
        :param current: current details
        :return: dict(), None
        """
        if current is None:
            return None
        desired = dict()
        if self.parameters.get('new_destination') is not None and \
                self.parameters['new_destination'] != current['destination']:
            desired['destination'] = self.parameters['new_destination']
        if self.parameters.get('new_gateway') is not None and \
                self.parameters['new_gateway'] != current['gateway']:
            desired['gateway'] = self.parameters['new_gateway']
        if self.parameters.get('new_metric') is not None and \
                self.parameters['new_metric'] != current['metric']:
            desired['metric'] = self.parameters['new_metric']
        return desired

    def apply(self):
        """
        Run Module based on play book
        """
        # changed = False
        netapp_utils.ems_log_event("na_ontap_net_routes", self.server)
        # route_exists = False
        current = self.get_net_route()
        modify, cd_action = None, None
        modify_params = {
            'destination': self.parameters.get('new_destination'),
            'gateway': self.parameters.get('new_gateway'),
            'metric': self.parameters.get('new_metric')
        }
        # if any new_* param is present in playbook, check for modify action
        if any(modify_params.values()):
            # get parameters that are eligible for modify
            d = self.get_net_route(modify_params)
            modify = self.na_helper.is_rename_action(current, d)
            if modify is None:
                self.module.fail_json(
                    msg="Error modifying: route %s does not exist" %
                    self.parameters['destination'])
        else:
            cd_action = self.na_helper.get_cd_action(current, self.parameters)

        if cd_action == 'create':
            self.create_net_route()
        elif cd_action == 'delete':
            self.delete_net_route()
        elif modify:
            self.modify_net_route(current, modify_params)

        self.module.exit_json(changed=self.na_helper.changed)