#!/usr/bin/python
''' this is igroup module

 (c) 2018, NetApp, Inc
 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
'''

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    'metadata_version': '1.1',
    'status': ['preview'],
    'supported_by': 'community'
}

DOCUMENTATION = '''

module: na_ontap_igroup
short_description: ONTAP iSCSI igroup configuration
extends_documentation_fragment:
    - netapp.na_ontap
version_added: '2.6'
author: NetApp Ansible Team (ng-ansibleteam@netapp.com)

description:
    - create, destroy or rename Igroups and add or remove initiator in igroups.

options:
  state:
    description:
    - Whether the specified Igroup should exist or not.
    choices: ['present', 'absent']
    default: present

  name:
    description:
    - The name of the igroup to manage.
    required: true

  initiator_group_type:
    description:
    - Type of the initiator group.
    - Required when C(state=present).
    choices: ['fcp', 'iscsi', 'mixed']

  from_name:
    description:
    - Name of igroup to rename to name.
    version_added: '2.7'

  ostype:
    description:
    - OS type of the initiators within the group.

  initiator:
    description:
    - WWPN, WWPN Alias, or iSCSI name of Initiator to add or remove.

  bind_portset:
    description:
    - Name of a current portset to bind to the newly created igroup.

  force_remove_initiator:
    description:
    -  Forcibly remove the initiator even if there are existing LUNs mapped to this initiator group.
    type: bool

  vserver:
    description:
    - The name of the vserver to use.
    required: true

'''

EXAMPLES = '''
    - name: Create Igroup
      na_ontap_igroup:
        state: present
        name: ansibleIgroup3
        initiator_group_type: iscsi
        ostype: linux
        initiator: iqn.1994-05.com.redhat:scspa0395855001.rtp.openenglab.netapp.com
        vserver: ansibleVServer
        hostname: "{{ netapp_hostname }}"
        username: "{{ netapp_username }}"
        password: "{{ netapp_password }}"

    - name: rename Igroup
      na_ontap_igroup:
        state: present
        from_name: ansibleIgroup3
        name: testexamplenewname
        initiator_group_type: iscsi
        ostype: linux
        initiator: iqn.1994-05.com.redhat:scspa0395855001.rtp.openenglab.netapp.com
        vserver: ansibleVServer
        hostname: "{{ netapp_hostname }}"
        username: "{{ netapp_username }}"
        password: "{{ netapp_password }}"

    - name: remove Igroup
      na_ontap_igroup:
        state: absent
        name: ansibleIgroup3
        initiator_group_type: iscsi
        ostype: linux
        initiator: iqn.1994-05.com.redhat:scspa0395855001.rtp.openenglab.netapp.com
        vserver: ansibleVServer
        hostname: "{{ netapp_hostname }}"
        username: "{{ netapp_username }}"
        password: "{{ netapp_password }}"

'''

RETURN = '''
'''

import traceback

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils

HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()


class NetAppOntapIgroup(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'),
            name=dict(required=True, type='str'),
            from_name=dict(required=False, type='str', default=None),
            ostype=dict(required=False, type='str'),
            initiator_group_type=dict(required=False, type='str',
                                      choices=['fcp', 'iscsi', 'mixed']),
            initiator=dict(required=False, type='str'),
            vserver=dict(required=True, type='str'),
            force_remove_initiator=dict(required=False, type='bool', default=False),
            bind_portset=dict(required=False, type='str')
        ))

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

        params = self.module.params

        # set up state variables
        self.state = params['state']
        self.name = params['name']
        self.ostype = params['ostype']
        self.initiator_group_type = params['initiator_group_type']
        self.initiator = params['initiator']
        self.vserver = params['vserver']
        self.from_name = params['from_name']
        self.force_remove_initiator = params['force_remove_initiator']
        self.bind_portset = params['bind_portset']

        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.vserver)

    def get_igroup(self, name):
        """
        Return details about the igroup
        :param:
            name : Name of the igroup

        :return: Details about the igroup. None if not found.
        :rtype: dict
        """
        igroup_info = netapp_utils.zapi.NaElement('igroup-get-iter')
        igroup_attributes = netapp_utils.zapi.NaElement('initiator-group-info')
        igroup_attributes.add_new_child('initiator-group-name', name)
        query = netapp_utils.zapi.NaElement('query')
        query.add_child_elem(igroup_attributes)
        igroup_info.add_child_elem(query)
        result = self.server.invoke_successfully(igroup_info, True)
        return_value = None

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

            igroup_attributes = result.get_child_by_name(
                'attributes-list').get_child_by_name(
                    'igroup-attributes')
            return_value = {
                'name': name,
            }

        return return_value

    def add_initiator(self):
        """
        Add the initiator.
        """
        options = {'initiator-group-name': self.name}

        if self.initiator is not None:
            options['initiator'] = self.initiator

        igroup_add = netapp_utils.zapi.NaElement.create_node_with_children(
            'igroup-add', **options)

        try:
            self.server.invoke_successfully(igroup_add,
                                            enable_tunneling=True)
            return True
        except netapp_utils.zapi.NaApiError as error:
            if to_native(error.code) == "9008":
                # Error 9008 denotes Initiator group already contains initiator
                return False
            else:
                self.module.fail_json(msg='Error adding igroup initiator %s: %s' % (self.name, to_native(error)),
                                      exception=traceback.format_exc())

    def remove_initiator(self):
        """
        Remove the initiator.
        """
        options = {'initiator': self.initiator}

        options['initiator-group-name'] = self.name

        igroup_remove = netapp_utils.zapi.NaElement.create_node_with_children(
            'igroup-remove', **options)

        try:
            self.server.invoke_successfully(igroup_remove,
                                            enable_tunneling=True)
            return True
        except netapp_utils.zapi.NaApiError as error:
            if to_native(error.code) == "9007":
                # Error 9007 denotes Initiator group does not contain initiator
                return False
            else:
                self.module.fail_json(msg='Error removing igroup initiator %s: %s' % (self.name, to_native(error)),
                                      exception=traceback.format_exc())

    def create_igroup(self):
        """
        Create the igroup.
        """
        options = {'initiator-group-name': self.name}
        if self.ostype is not None:
            options['os-type'] = self.ostype
        if self.initiator_group_type is not None:
            options['initiator-group-type'] = self.initiator_group_type
        if self.bind_portset is not None:
            options['bind-portset'] = self.bind_portset

        igroup_create = netapp_utils.zapi.NaElement.create_node_with_children(
            'igroup-create', **options)

        try:
            self.server.invoke_successfully(igroup_create,
                                            enable_tunneling=True)
            self.add_initiator()
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error provisioning igroup %s: %s' % (self.name, to_native(error)),
                                  exception=traceback.format_exc())

    def delete_igroup(self):
        """
        Delete the igroup.
        """
        igroup_delete = netapp_utils.zapi.NaElement.create_node_with_children(
            'igroup-destroy', **{'initiator-group-name': self.name, 'force': 'true' if self.force_remove_initiator else 'false'})

        try:
            self.server.invoke_successfully(igroup_delete,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error deleting igroup %s: %s' % (self.name, to_native(error)),
                                  exception=traceback.format_exc())

    def rename_igroup(self):
        """
        Rename the igroup.
        """
        igroup_rename = netapp_utils.zapi.NaElement.create_node_with_children(
            'igroup-rename', **{'initiator-group-name': self.from_name, 'initiator-group-new-name': str(
                self.name)})
        try:
            self.server.invoke_successfully(igroup_rename,
                                            enable_tunneling=True)
        except netapp_utils.zapi.NaApiError as error:
            self.module.fail_json(msg='Error renaming igroup %s: %s' % (self.name, to_native(error)),
                                  exception=traceback.format_exc())

    def apply(self):
        changed = False
        igroup_exists = False
        rename_igroup = False
        initiator_changed = False
        netapp_utils.ems_log_event("na_ontap_igroup", self.server)
        igroup_details = self.get_igroup(self.name)

        if igroup_details is not None:
            igroup_exists = True
            if self.state == 'absent':
                changed = True
            elif self.state == 'present':
                if self.initiator:
                    changed = True
        else:
            if self.state == 'present':
                # create by default, or rename if from_name exists
                changed = True
                if self.from_name:
                    igroup_details = self.get_igroup(self.from_name)
                    if igroup_details is not None:
                        rename_igroup = True
                        igroup_exists = True
                    else:
                        self.module.fail_json(msg='Error renaming igroup %s does not exist' % (self.from_name))

        if changed:
            changed = False
            if self.module.check_mode:
                pass
            else:
                if self.state == 'present':
                    if not igroup_exists:
                        self.create_igroup()
                        changed = True
                    else:
                        if self.initiator:
                            changed = self.add_initiator()
                        if rename_igroup:
                            self.rename_igroup()
                            changed = True

                elif self.state == 'absent':
                    if self.initiator:
                        self.remove_initiator()
                    self.delete_igroup()
                    changed = True

        self.module.exit_json(changed=changed)


def main():
    obj = NetAppOntapIgroup()
    obj.apply()


if __name__ == '__main__':
    main()
