Exemplo n.º 1
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'),
            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)
Exemplo n.º 2
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,
                            type='str',
                            choices=['present', 'absent'],
                            default='present'),
                 allow_list=dict(required=False, type='list', elements='str'),
                 policy=dict(required=False, type='str'),
                 service=dict(required=False,
                              type='str',
                              choices=[
                                  'dns', 'http', 'https', 'ndmp', 'ndmps',
                                  'ntp', 'portmap', 'rsh', 'snmp', 'ssh',
                                  'telnet'
                              ]),
                 vserver=dict(required=False, type="str"),
                 enable=dict(required=False,
                             type="str",
                             choices=['enable', 'disable']),
                 logging=dict(required=False,
                              type="str",
                              choices=['enable', 'disable']),
                 node=dict(required=False, type="str")))

        self.module = AnsibleModule(
            argument_spec=self.argument_spec,
            required_together=(['policy', 'service',
                                'vserver'], ['enable', 'node']),
            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)

        if HAS_IPADDRESS_LIB is False:
            self.module.fail_json(
                msg="the python ipaddress lib is required for this module")
        return

    def validate_ip_addresses(self):
        '''
            Validate if the given IP address is a network address (i.e. it's host bits are set to 0)
            ONTAP doesn't validate if the host bits are set,
            and hence doesn't add a new address unless the IP is from a different network.
            So this validation allows the module to be idempotent.
            :return: None
        '''
        for ip in self.parameters['allow_list']:
            # create an IPv4 object for current IP address
            if sys.version_info[0] >= 3:
                ip_addr = str(ip)
            else:
                ip_addr = unicode(ip)  # pylint: disable=undefined-variable
            # get network address from netmask, throw exception if address is not a network address
            try:
                ipaddress.ip_network(ip_addr)
            except ValueError as exc:
                self.module.fail_json(
                    msg=
                    'Error: Invalid IP address value for allow_list parameter.'
                    'Please specify a network address without host bits set: %s'
                    % (to_native(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")
        attributes = {
            'query': {
                'net-firewall-policy-info': self.firewall_policy_attributes()
            }
        }
        net_firewall_policy_obj.translate_struct(attributes)

        try:
            result = self.server.invoke_successfully(net_firewall_policy_obj,
                                                     True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg="Error getting firewall policy %s:%s" %
                (self.parameters['policy'], to_native(error)),
                exception=traceback.format_exc())

        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')
            policy_info = attributes_list.get_child_by_name(
                'net-firewall-policy-info')
            ips = self.na_helper.get_value_for_list(
                from_zapi=True,
                zapi_parent=policy_info.get_child_by_name('allow-list'))
            return {'service': policy_info['service'], 'allow_list': ips}
        return None

    def create_firewall_policy(self):
        """
        Create a firewall policy for given vserver
        :return: None
        """
        net_firewall_policy_obj = netapp_utils.zapi.NaElement(
            "net-firewall-policy-create")
        net_firewall_policy_obj.translate_struct(
            self.firewall_policy_attributes())
        if self.parameters.get('allow_list'):
            self.validate_ip_addresses()
            net_firewall_policy_obj.add_child_elem(
                self.na_helper.get_value_for_list(
                    from_zapi=False,
                    zapi_parent='allow-list',
                    zapi_child='ip-and-mask',
                    data=self.parameters['allow_list']))
        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 from a vserver
        :return: None
        """
        net_firewall_policy_obj = netapp_utils.zapi.NaElement(
            "net-firewall-policy-destroy")
        net_firewall_policy_obj.translate_struct(
            self.firewall_policy_attributes())
        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 modify_firewall_policy(self, modify):
        """
        Modify a firewall Policy on a vserver
        :return: none
        """
        self.validate_ip_addresses()
        net_firewall_policy_obj = netapp_utils.zapi.NaElement(
            "net-firewall-policy-modify")
        net_firewall_policy_obj.translate_struct(
            self.firewall_policy_attributes())
        net_firewall_policy_obj.add_child_elem(
            self.na_helper.get_value_for_list(from_zapi=False,
                                              zapi_parent='allow-list',
                                              zapi_child='ip-and-mask',
                                              data=modify['allow_list']))
        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 firewall_policy_attributes(self):
        return {
            'policy': self.parameters['policy'],
            'service': self.parameters['service'],
            'vserver': self.parameters['vserver'],
        }

    def get_firewall_config_for_node(self):
        """
        Get firewall configuration on the node
        :return: dict() with firewall config details
        """
        if self.parameters.get('logging'):
            if self.parameters.get('node') is None:
                self.module.fail_json(
                    msg=
                    'Error: Missing parameter \'node\' to modify firewall logging'
                )
        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())
        if result.get_child_by_name('attributes'):
            firewall_info = result['attributes'].get_child_by_name(
                'net-firewall-config-info')
            return {
                'enable':
                self.change_status_to_bool(
                    firewall_info.get_child_content('is-enabled'),
                    to_zapi=False),
                'logging':
                self.change_status_to_bool(
                    firewall_info.get_child_content('is-logging'),
                    to_zapi=False)
            }
        return None

    def modify_firewall_config(self, modify):
        """
        Modify the configuration of a firewall on node
        :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'])
        if modify.get('enable'):
            net_firewall_config_obj.add_new_child(
                'is-enabled',
                self.change_status_to_bool(self.parameters['enable']))
        if modify.get('logging'):
            net_firewall_config_obj.add_new_child(
                'is-logging',
                self.change_status_to_bool(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 change_status_to_bool(self, input, to_zapi=True):
        if to_zapi:
            return 'true' if input == 'enable' else 'false'
        else:
            return 'enable' if input == 'true' else 'disable'

    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_firewall_policy", cserver)

    def apply(self):
        self.autosupport_log()
        cd_action, modify, modify_config = None, None, None
        if self.parameters.get('policy'):
            current = self.get_firewall_policy()
            cd_action = self.na_helper.get_cd_action(current, self.parameters)
            if cd_action is None and self.parameters['state'] == 'present':
                modify = self.na_helper.get_modified_attributes(
                    current, self.parameters)
        if self.parameters.get('node'):
            current_config = self.get_firewall_config_for_node()
            # firewall config for a node is always present, we cannot create or delete a firewall on a node
            modify_config = self.na_helper.get_modified_attributes(
                current_config, self.parameters)

        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if cd_action == 'create':
                    self.create_firewall_policy()
                elif cd_action == 'delete':
                    self.destroy_firewall_policy()
                else:
                    if modify:
                        self.modify_firewall_policy(modify)
                    if modify_config:
                        self.modify_firewall_config(modify_config)
        self.module.exit_json(changed=self.na_helper.changed)
Exemplo n.º 3
0
class NetAppONTAPJob(object):
    '''Class with job schedule cron methods'''
    def __init__(self):

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

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

        self.restApi = OntapRestAPI(self.module)
        if self.restApi.is_rest():
            self.use_rest = True
        else:
            if HAS_NETAPP_LIB is False:
                self.module.fail_json(
                    msg="the python NetApp-Lib module is required")
            else:
                self.server = netapp_utils.setup_na_ontap_zapi(
                    module=self.module)

    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 set_playbook_api_key_map(self):
        self.na_helper.api_list_keys = {
            'job_minutes': 'minutes',
            'job_months': 'months',
            'job_hours': 'hours',
            'job_days_of_month': 'days',
            'job_days_of_week': 'weekdays'
        }

    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
        """
        if self.use_rest:
            params = {'name': self.parameters['name']}
            api = '/cluster/schedules'
            message, error = self.restApi.get(api, params)
            if error is not None:
                self.module.fail_json(
                    msg="Error on fetching job schedule: %s" % error)
            if message['num_records'] > 0:
                self.uuid = message['records'][0]['uuid']
                job_details = dict()
                job_details['name'] = message['records'][0]['name']
                for key, value in self.na_helper.api_list_keys.items():
                    if value in message['records'][0]['cron']:
                        job_details[key] = message['records'][0]['cron'][value]
                # convert list of int to list of string
                for key, value in job_details.items():
                    if isinstance(value, list):
                        for i in range(len(value)):
                            value[i] = str(value[i])
                return job_details

        else:
            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: modify 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')

        if self.use_rest:
            cron = dict()
            for key, value in self.na_helper.api_list_keys.items():
                # -1 means all in zapi, while empty means all in api.
                if self.parameters.get(key):
                    if len(self.parameters[key]) == 1 and int(
                            self.parameters[key][0]) == -1:
                        pass
                    else:
                        cron[value] = self.parameters[key]

            params = {'name': self.parameters['name'], 'cron': cron}
            api = '/cluster/schedules'
            message, error = self.restApi.post(api, params)
            if error is not None:
                self.module.fail_json(
                    msg="Error on creating job schedule: %s" % error)

        else:
            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
        """
        if self.use_rest:
            api = '/cluster/schedules/' + self.uuid
            message, error = self.restApi.delete(api, {})
            if error is not None:
                self.module.fail_json(
                    msg="Error on deleting job schedule: %s" % error)
        else:
            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, current):
        """
        modify a job schedule
        """
        if self.use_rest:
            cron = dict()
            for key, value in self.na_helper.api_list_keys.items():
                # -1 means all in zapi, while empty means all in api.
                if params.get(key):
                    if len(self.parameters[key]) == 1 and int(
                            self.parameters[key][0]) == -1:
                        pass
                    else:
                        cron[value] = self.parameters[key]
                # Usually only include modify attributes, but omitting an attribute means all in api.
                # Need to add the current attributes in params.
                elif current.get(key):
                    cron[value] = current[key]
            params = {'cron': cron}
            api = '/cluster/schedules/' + self.uuid
            message, error = self.restApi.patch(api, params)
            if error is not None:
                self.module.fail_json(
                    msg="Error on modifying job schedule: %s" % error)
        else:
            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
        """
        if not self.use_rest:
            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, current)
        self.module.exit_json(changed=self.na_helper.changed)
Exemplo n.º 4
0
class NetAppontapExportRule(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,
                           type='str',
                           choices=['present', 'absent'],
                           default='present'),
                name=dict(required=True, type='str', aliases=['policy_name']),
                protocol=dict(required=False,
                              type='list',
                              elements='str',
                              default=None,
                              choices=[
                                  'any', 'nfs', 'nfs3', 'nfs4', 'cifs',
                                  'flexcache'
                              ]),
                client_match=dict(required=False, type='list', elements='str'),
                ro_rule=dict(required=False,
                             type='list',
                             elements='str',
                             default=None,
                             choices=[
                                 'any', 'none', 'never', 'krb5', 'krb5i',
                                 'krb5p', 'ntlm', 'sys'
                             ]),
                rw_rule=dict(required=False,
                             type='list',
                             elements='str',
                             default=None,
                             choices=[
                                 'any', 'none', 'never', 'krb5', 'krb5i',
                                 'krb5p', 'ntlm', 'sys'
                             ]),
                super_user_security=dict(required=False,
                                         type='list',
                                         elements='str',
                                         default=None,
                                         choices=[
                                             'any', 'none', 'never', 'krb5',
                                             'krb5i', 'krb5p', 'ntlm', 'sys'
                                         ]),
                allow_suid=dict(required=False, type='bool'),
                rule_index=dict(required=False, type='int'),
                anonymous_user_id=dict(required=False, type='int'),
                vserver=dict(required=True, type='str'),
            ))

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

        self.na_helper = NetAppModule()
        self.parameters = self.na_helper.set_parameters(self.module.params)
        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, vserver=self.parameters['vserver'])

    def set_playbook_zapi_key_map(self):
        self.na_helper.zapi_string_keys = {
            'client_match': 'client-match',
            'name': 'policy-name'
        }
        self.na_helper.zapi_list_keys = {
            'protocol': ('protocol', 'access-protocol'),
            'ro_rule': ('ro-rule', 'security-flavor'),
            'rw_rule': ('rw-rule', 'security-flavor'),
            'super_user_security': ('super-user-security', 'security-flavor'),
        }
        self.na_helper.zapi_bool_keys = {
            'allow_suid': 'is-allow-set-uid-enabled'
        }
        self.na_helper.zapi_int_keys = {
            'rule_index': 'rule-index',
            'anonymous_user_id': 'anonymous-user-id'
        }

    def set_query_parameters(self):
        """
        Return dictionary of query parameters and
        :return:
        """
        query = {
            'policy-name': self.parameters['name'],
            'vserver': self.parameters['vserver']
        }

        if self.parameters.get('rule_index'):
            query['rule-index'] = self.parameters['rule_index']
        elif self.parameters.get('client_match'):
            query['client-match'] = self.parameters['client_match']
        else:
            self.module.fail_json(
                msg=
                "Need to specify at least one of the rule_index and client_match option."
            )

        attributes = {'query': {'export-rule-info': query}}
        return attributes

    def get_export_policy_rule(self):
        """
        Return details about the export policy rule
        :param:
            name : Name of the export_policy
        :return: Details about the export_policy. None if not found.
        :rtype: dict
        """
        current, result = None, None
        rule_iter = netapp_utils.zapi.NaElement('export-rule-get-iter')
        rule_iter.translate_struct(self.set_query_parameters())
        try:
            result = self.server.invoke_successfully(rule_iter, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error getting export policy rule %s: %s' %
                (self.parameters['name'], to_native(error)),
                exception=traceback.format_exc())
        if result is not None and \
                result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
            current = dict()
            rule_info = result.get_child_by_name(
                'attributes-list').get_child_by_name('export-rule-info')
            for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
                current[item_key] = rule_info.get_child_content(zapi_key)
            for item_key, zapi_key in self.na_helper.zapi_bool_keys.items():
                current[item_key] = self.na_helper.get_value_for_bool(
                    from_zapi=True, value=rule_info[zapi_key])
            for item_key, zapi_key in self.na_helper.zapi_int_keys.items():
                current[item_key] = self.na_helper.get_value_for_int(
                    from_zapi=True, value=rule_info[zapi_key])
            for item_key, zapi_key in self.na_helper.zapi_list_keys.items():
                parent, dummy = zapi_key
                current[item_key] = self.na_helper.get_value_for_list(
                    from_zapi=True,
                    zapi_parent=rule_info.get_child_by_name(parent))
            current['num_records'] = int(
                result.get_child_content('num-records'))
            if not self.parameters.get('rule_index'):
                self.parameters['rule_index'] = current['rule_index']
        return current

    def get_export_policy(self):
        """
        Return details about the export-policy
        :param:
            name : Name of the export-policy

        :return: Details about the export-policy. None if not found.
        :rtype: dict
        """
        export_policy_iter = netapp_utils.zapi.NaElement(
            'export-policy-get-iter')
        attributes = {
            'query': {
                'export-policy-info': {
                    'policy-name': self.parameters['name'],
                    'vserver': self.parameters['vserver']
                }
            }
        }

        export_policy_iter.translate_struct(attributes)
        try:
            result = self.server.invoke_successfully(export_policy_iter, True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error getting export policy %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

        if result.get_child_by_name('num-records') and int(
                result.get_child_content('num-records')) == 1:
            return result

        return None

    def add_parameters_for_create_or_modify(self, na_element_object, values):
        """
            Add children node for create or modify NaElement object
            :param na_element_object: modify or create NaElement object
            :param values: dictionary of cron values to be added
            :return: None
        """
        for key in values:
            if key in self.na_helper.zapi_string_keys:
                zapi_key = self.na_helper.zapi_string_keys.get(key)
                na_element_object[zapi_key] = values[key]
            elif key in self.na_helper.zapi_list_keys:
                parent_key, child_key = self.na_helper.zapi_list_keys.get(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[key]))
            elif key in self.na_helper.zapi_int_keys:
                zapi_key = self.na_helper.zapi_int_keys.get(key)
                na_element_object[zapi_key] = self.na_helper.get_value_for_int(
                    from_zapi=False, value=values[key])
            elif key in self.na_helper.zapi_bool_keys:
                zapi_key = self.na_helper.zapi_bool_keys.get(key)
                na_element_object[
                    zapi_key] = self.na_helper.get_value_for_bool(
                        from_zapi=False, value=values[key])

    def create_export_policy_rule(self):
        """
        create rule for the export policy.
        """
        for key in ['client_match', 'ro_rule', 'rw_rule']:
            if self.parameters.get(key) is None:
                self.module.fail_json(
                    msg=
                    'Error: Missing required param for creating export policy rule %s'
                    % key)
        export_rule_create = netapp_utils.zapi.NaElement('export-rule-create')
        self.add_parameters_for_create_or_modify(export_rule_create,
                                                 self.parameters)
        try:
            self.server.invoke_successfully(export_rule_create,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error creating export policy rule %s: %s' %
                (self.parameters['name'], to_native(error)),
                exception=traceback.format_exc())

    def create_export_policy(self):
        """
        Creates an export policy
        """
        export_policy_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'export-policy-create', **{'policy-name': self.parameters['name']})
        try:
            self.server.invoke_successfully(export_policy_create,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error creating export-policy %s: %s' %
                                  (self.parameters['name'], to_native(error)),
                                  exception=traceback.format_exc())

    def delete_export_policy_rule(self, rule_index):
        """
        delete rule for the export policy.
        """
        export_rule_delete = netapp_utils.zapi.NaElement.create_node_with_children(
            'export-rule-destroy', **{
                'policy-name': self.parameters['name'],
                'rule-index': str(rule_index)
            })

        try:
            self.server.invoke_successfully(export_rule_delete,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error deleting export policy rule %s: %s' %
                (self.parameters['name'], to_native(error)),
                exception=traceback.format_exc())

    def modify_export_policy_rule(self, params):
        '''
        Modify an existing export policy rule
        :param params: dict() of attributes with desired values
        :return: None
        '''
        export_rule_modify = netapp_utils.zapi.NaElement.create_node_with_children(
            'export-rule-modify', **{
                'policy-name': self.parameters['name'],
                'rule-index': str(self.parameters['rule_index'])
            })
        self.add_parameters_for_create_or_modify(export_rule_modify, params)
        try:
            self.server.invoke_successfully(export_rule_modify,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(
                msg='Error modifying allow_suid %s: %s' %
                (self.parameters['allow_suid'], to_native(error)),
                exception=traceback.format_exc())

    def autosupport_log(self):
        netapp_utils.ems_log_event("na_ontap_export_policy_rules", self.server)

    def apply(self):
        ''' Apply required action from the play'''
        self.autosupport_log()
        # convert client_match list to comma-separated string
        if self.parameters.get('client_match') is not None:
            self.parameters['client_match'] = ','.join(
                self.parameters['client_match'])
            self.parameters['client_match'] = self.parameters[
                'client_match'].replace(' ', '')

        current, modify = self.get_export_policy_rule(), None
        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:
                # create export policy (if policy doesn't exist) only when changed=True
                if action == 'create':
                    if not self.get_export_policy():
                        self.create_export_policy()
                    self.create_export_policy_rule()
                elif action == 'delete':
                    if current['num_records'] > 1:
                        self.module.fail_json(
                            msg='Multiple export policy rules exist.'
                            'Please specify a rule_index to delete')
                    self.delete_export_policy_rule(current['rule_index'])
                elif modify:
                    self.modify_export_policy_rule(modify)
        self.module.exit_json(changed=self.na_helper.changed)
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: modify 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)