#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2018, Simon Dodsley (simon@purestorage.com)
# 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 = r'''
---
module: purefa_facts
version_added: '2.6'
short_description: Collect facts from Pure Storage FlashArray
description:
  - Collect facts information from a Pure Storage Flasharray running the
    Purity//FA operating system. By default, the module will collect basic
    fact information including hosts, host groups, protection
    groups and volume counts. Additional fact information can be collected
    based on the configured set of arguements.
author:
  - Simon Dodsley (@sdodsley)
options:
  gather_subset:
    description:
      - When supplied, this argument will define the facts to be collected.
        Possible values for this include all, minimum, config, performance,
        capacity, network, subnet, interfaces, hgroups, pgroups, hosts,
        volumes and snapshots.
    required: false
    default: minimum
extends_documentation_fragment:
  - purestorage.fa
'''

EXAMPLES = r'''
- name: collect default set of facts
  purefa_facts:
    fa_url: 10.10.10.2
    api_token: e31060a7-21fc-e277-6240-25983c6c4592

- name: collect configuration and capacity facts
  purefa_facts:
    gather_subset:
      - config
      - capacity
    fa_url: 10.10.10.2
    api_token: e31060a7-21fc-e277-6240-25983c6c4592

- name: collect all facts
  purefa_facts:
    gather_subset:
      - all
    fa_url: 10.10.10.2
    api_token: e31060a7-21fc-e277-6240-25983c6c4592
'''

RETURN = r'''
ansible_facts:
  description: Returns the facts collected from the FlashArray
  returned: always
  type: complex
  contains:
        "capacity": {}
        "config": {
            "directory_service": {
                "array_admin_group": null,
                "base_dn": null,
                "bind_password": null,
                "bind_user": null,
                "check_peer": false,
                "enabled": false,
                "group_base": null,
                "readonly_group": null,
                "storage_admin_group": null,
                "uri": []
            },
            "dns": {
                "domain": "domain.com",
                "nameservers": [
                    "8.8.8.8",
                    "8.8.4.4"
                ]
            },
            "ntp": [
                "0.ntp.pool.org",
                "1.ntp.pool.org",
                "2.ntp.pool.org",
                "3.ntp.pool.org"
            ],
            "smtp": [
                {
                    "enabled": true,
                    "name": "alerts@acme.com"
                },
                {
                    "enabled": true,
                    "name": "user@acme.com"
                }
            ],
            "snmp": [
                {
                    "auth_passphrase": null,
                    "auth_protocol": null,
                    "community": null,
                    "host": "localhost",
                    "name": "localhost",
                    "privacy_passphrase": null,
                    "privacy_protocol": null,
                    "user": null,
                    "version": "v2c"
                }
            ],
            "ssl_certs": {
                "country": null,
                "email": null,
                "issued_by": "",
                "issued_to": "",
                "key_size": 2048,
                "locality": null,
                "organization": "Acme Storage, Inc.",
                "organizational_unit": "Acme Storage, Inc.",
                "state": null,
                "status": "self-signed",
                "valid_from": "2017-08-11T23:09:06Z",
                "valid_to": "2027-08-09T23:09:06Z"
            },
            "syslog": []
        }
        "default": {
            "array_name": "flasharray1",
            "connected_arrays": 1,
            "hostgroups": 0,
            "hosts": 10,
            "pods": 3,
            "protection_groups": 1,
            "purity_version": "5.0.4",
            "snapshots": 1,
            "volume_groups": 2
        }
        "hgroups": {}
        "hosts": {
            "host1": {
                "hgroup": null,
                "iqn": [
                    "iqn.1994-05.com.redhat:2f6f5715a533"
                ],
                "wwn": []
            },
            "host2": {
                "hgroup": null,
                "iqn": [
                    "iqn.1994-05.com.redhat:d17fb13fe0b"
                ],
                "wwn": []
            },
            "host3": {
                "hgroup": null,
                "iqn": [
                    "iqn.1994-05.com.redhat:97b1351bfb2"
                ],
                "wwn": []
            },
            "host4": {
                "hgroup": null,
                "iqn": [
                    "iqn.1994-05.com.redhat:dd84e9a7b2cb"
                ],
                "wwn": [
                    "10000000C96C48D1",
                    "10000000C96C48D2"
                ]
            }
        }
        "interfaces": {
            "CT0.ETH4": "iqn.2010-06.com.purestorage:flasharray.2111b767484e4682",
            "CT0.ETH5": "iqn.2010-06.com.purestorage:flasharray.2111b767484e4682",
            "CT1.ETH4": "iqn.2010-06.com.purestorage:flasharray.2111b767484e4682",
            "CT1.ETH5": "iqn.2010-06.com.purestorage:flasharray.2111b767484e4682"
        }
        "network": {
            "ct0.eth0": {
                "address": "10.10.10.10",
                "gateway": "10.10.10.1",
                "hwaddr": "ec:f4:bb:c8:8a:04",
                "mtu": 1500,
                "netmask": "255.255.255.0",
                "services": [
                    "management"
                ],
                "speed": 1000000000
            },
            "ct0.eth2": {
                "address": "10.10.10.11",
                "gateway": null,
                "hwaddr": "ec:f4:bb:c8:8a:00",
                "mtu": 1500,
                "netmask": "255.255.255.0",
                "services": [
                    "replication"
                ],
                "speed": 10000000000
            },
            "ct0.eth3": {
                "address": "10.10.10.12",
                "gateway": null,
                "hwaddr": "ec:f4:bb:c8:8a:02",
                "mtu": 1500,
                "netmask": "255.255.255.0",
                "services": [
                    "replication"
                ],
                "speed": 10000000000
            },
            "ct0.eth4": {
                "address": "10.10.10.13",
                "gateway": null,
                "hwaddr": "90:e2:ba:83:79:0c",
                "mtu": 1500,
                "netmask": "255.255.255.0",
                "services": [
                    "iscsi"
                ],
                "speed": 10000000000
            },
            "ct0.eth5": {
                "address": "10.10.10.14",
                "gateway": null,
                "hwaddr": "90:e2:ba:83:79:0d",
                "mtu": 1500,
                "netmask": "255.255.255.0",
                "services": [
                    "iscsi"
                ],
                "speed": 10000000000
            },
            "vir0": {
                "address": "10.10.10.20",
                "gateway": "10.10.10.1",
                "hwaddr": "fe:ba:e9:e7:6b:0f",
                "mtu": 1500,
                "netmask": "255.255.255.0",
                "services": [
                    "management"
                ],
                "speed": 1000000000
            }
        }
        "performance": {
            "input_per_sec": 8191,
            "output_per_sec": 0,
            "queue_depth": 1,
            "reads_per_sec": 0,
            "san_usec_per_write_op": 15,
            "usec_per_read_op": 0,
            "usec_per_write_op": 642,
            "writes_per_sec": 2
        }
        "pgroups": {
            "consisgroup-07b6b983-986e-46f5-bdc3-deaa3dbb299e-cinder": {
                "hgroups": null,
                "hosts": null,
                "source": "host1",
                "targets": null,
                "volumes": [
                    "volume-1"
                ]
            }
        }
        "snapshots": {
            "consisgroup.cgsnapshot": {
                "created": "2018-03-28T09:34:02Z",
                "size": 13958643712,
                "source": "volume-1"
            }
        }
        "subnet": {}
        "volumes": {
            "ansible_data": {
                "bandwidth": null,
                "hosts": [
                    [
                        "host1",
                        1
                    ]
                ],
                "serial": "43BE47C12334399B000114A6",
                "size": 1099511627776,
                "source": null
            }
        }
'''


from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_system, purefa_argument_spec


AC_REQUIRED_API_VERSION = '1.14'
CAP_REQUIRED_API_VERSION = '1.6'
SAN_REQUIRED_API_VERSION = '1.10'


def generate_default_dict(array):
    default_facts = {}
    defaults = array.get()
    api_version = array._list_available_rest_versions()
    if AC_REQUIRED_API_VERSION in api_version:
        default_facts['volume_groups'] = len(array.list_vgroups())
        default_facts['connected_arrays'] = len(array.list_array_connections())
        default_facts['pods'] = len(array.list_pods())
    hosts = array.list_hosts()
    snaps = array.list_volumes(snap=True, pending=True)
    pgroups = array.list_pgroups(pending=True)
    hgroups = array.list_hgroups()
    default_facts['array_name'] = defaults['array_name']
    default_facts['purity_version'] = defaults['version']
    default_facts['hosts'] = len(hosts)
    default_facts['snapshots'] = len(snaps)
    default_facts['protection_groups'] = len(pgroups)
    default_facts['hostgroups'] = len(hgroups)
    return default_facts


def generate_perf_dict(array):
    perf_facts = {}
    perf_info = array.get(action='monitor')[0]
    #  IOPS
    perf_facts['writes_per_sec'] = perf_info['writes_per_sec']
    perf_facts['reads_per_sec'] = perf_info['reads_per_sec']

    #  Bandwidth
    perf_facts['input_per_sec'] = perf_info['input_per_sec']
    perf_facts['output_per_sec'] = perf_info['output_per_sec']

    #  Latency
    api_version = array._list_available_rest_versions()
    if SAN_REQUIRED_API_VERSION in api_version:
        perf_facts['san_usec_per_read_op'] = perf_info['san_usec_per_read_op']
        perf_facts['san_usec_per_write_op'] = perf_info['san_usec_per_write_op']
    perf_facts['usec_per_read_op'] = perf_info['usec_per_read_op']
    perf_facts['usec_per_write_op'] = perf_info['usec_per_write_op']
    perf_facts['queue_depth'] = perf_info['queue_depth']
    return perf_facts


def generate_config_dict(array):
    config_facts = {}
    # DNS
    config_facts['dns'] = array.get_dns()
    # SMTP
    config_facts['smtp'] = array.list_alert_recipients()
    # SMNP
    config_facts['snmp'] = array.list_snmp_managers()
    # DS
    config_facts['directory_service'] = array.get_directory_service()
    config_facts['directory_service'].update(array.get_directory_service(groups=True))
    # NTP
    config_facts['ntp'] = array.get(ntpserver=True)['ntpserver']
    # SYSLOG
    config_facts['syslog'] = array.get(syslogserver=True)['syslogserver']
    # SSL
    config_facts['ssl_certs'] = array.get_certificate()
    return config_facts


def generate_subnet_dict(array):
    sub_facts = {}
    subnets = array.list_subnets()
    for sub in range(0, len(subnets)):
        sub_name = subnets[sub]['name']
        if subnets[sub]['enabled']:
            sub_facts[sub_name] = {
                'gateway': subnets[sub]['gateway'],
                'mtu': subnets[sub]['mtu'],
                'vlan': subnets[sub]['vlan'],
                'prefix': subnets[sub]['prefix'],
                'interfaces': subnets[sub]['interfaces'],
                'services': subnets[sub]['services'],
            }
    return sub_facts


def generate_network_dict(array):
    net_facts = {}
    ports = array.list_network_interfaces()
    for port in range(0, len(ports)):
        int_name = ports[port]['name']
        if ports[port]['enabled']:
            net_facts[int_name] = {
                'hwaddr': ports[port]['hwaddr'],
                'mtu': ports[port]['mtu'],
                'speed': ports[port]['speed'],
                'address': ports[port]['address'],
                'services': ports[port]['services'],
                'gateway': ports[port]['gateway'],
                'netmask': ports[port]['netmask'],
            }
            if ports[port]['subnet']:
                subnets = array.get_subnet(ports[port]['subnet'])
                if subnets['enabled']:
                    net_facts[int_name]['subnet'] = {
                        'name': subnets['name'],
                        'prefix': subnets['prefix'],
                        'vlan': subnets['vlan'],
                    }
    return net_facts


def generate_capacity_dict(array):
    capacity_facts = {}
    api_version = array._list_available_rest_versions()
    if CAP_REQUIRED_API_VERSION in api_version:
        volumes = array.list_volumes(pending=True)
        capacity_facts['provisioned_space'] = sum(item['size'] for item in volumes)
        capacity = array.get(space=True)
        total_capacity = capacity[0]['capacity']
        used_space = capacity[0]["total"]
        capacity_facts['free_space'] = total_capacity - used_space
        capacity_facts['total_capacity'] = total_capacity
        capacity_facts['data_reduction'] = capacity[0]['data_reduction']
        capacity_facts['system_space'] = capacity[0]['system']
        capacity_facts['volume_space'] = capacity[0]['volumes']
        capacity_facts['shared_space'] = capacity[0]['shared_space']
        capacity_facts['snapshot_space'] = capacity[0]['snapshots']
        capacity_facts['thin_provisioning'] = capacity[0]['thin_provisioning']
        capacity_facts['total_reduction'] = capacity[0]['total_reduction']

    return capacity_facts


def generate_snap_dict(array):
    snap_facts = {}
    snaps = array.list_volumes(snap=True)
    for snap in range(0, len(snaps)):
        snapshot = snaps[snap]['name']
        snap_facts[snapshot] = {
            'size': snaps[snap]['size'],
            'source': snaps[snap]['source'],
            'created': snaps[snap]['created'],
        }
    return snap_facts


def generate_vol_dict(array):
    volume_facts = {}
    vols = array.list_volumes()
    for vol in range(0, len(vols)):
        volume = vols[vol]['name']
        volume_facts[volume] = {
            'source': vols[vol]['source'],
            'size': vols[vol]['size'],
            'serial': vols[vol]['serial'],
            'hosts': [],
            'bandwidth': ""
        }
    api_version = array._list_available_rest_versions()
    if AC_REQUIRED_API_VERSION in api_version:
        qvols = array.list_volumes(qos=True)
        for qvol in range(0, len(qvols)):
            volume = qvols[qvol]['name']
            qos = qvols[qvol]['bandwidth_limit']
            volume_facts[volume]['bandwidth'] = qos
        vvols = array.list_volumes(protocol_endpoint=True)
        for vvol in range(0, len(vvols)):
            volume = vvols[vvol]['name']
            volume_facts[volume] = {
                'source': vols[vol]['source'],
                'serial': vols[vol]['serial'],
                'hosts': []
            }
    cvols = array.list_volumes(connect=True)
    for cvol in range(0, len(cvols)):
        volume = cvols[cvol]['name']
        voldict = [cvols[cvol]['host'], cvols[cvol]['lun']]
        volume_facts[volume]['hosts'].append(voldict)
    return volume_facts


def generate_host_dict(array):
    host_facts = {}
    hosts = array.list_hosts()
    for host in range(0, len(hosts)):
        hostname = hosts[host]['name']
        host_facts[hostname] = {
            'hgroup': hosts[host]['hgroup'],
            'iqn': hosts[host]['iqn'],
            'wwn': hosts[host]['wwn'],
        }
    return host_facts


def generate_pgroups_dict(array):
    pgroups_facts = {}
    pgroups = array.list_pgroups()
    for pgroup in range(0, len(pgroups)):
        protgroup = pgroups[pgroup]['name']
        pgroups_facts[protgroup] = {
            'hgroups': pgroups[pgroup]['hgroups'],
            'hosts': pgroups[pgroup]['hosts'],
            'source': pgroups[pgroup]['source'],
            'targets': pgroups[pgroup]['targets'],
            'volumes': pgroups[pgroup]['volumes'],
        }
    return pgroups_facts


def generate_hgroups_dict(array):
    hgroups_facts = {}
    hgroups = array.list_hgroups()
    for hgroup in range(0, len(hgroups)):
        hostgroup = hgroups[hgroup]['name']
        hgroups_facts[hostgroup] = {
            'hosts': hgroups[hgroup]['hosts'],
            'pgs': [],
            'vols': [],
        }
    pghgroups = array.list_hgroups(protect=True)
    for pghg in range(0, len(pghgroups)):
        pgname = pghgroups[pghg]['name']
        hgroups_facts[pgname]['pgs'].append(pghgroups[pghg]['protection_group'])
    volhgroups = array.list_hgroups(connect=True)
    for pgvol in range(0, len(volhgroups)):
        pgname = volhgroups[pgvol]['name']
        volpgdict = [volhgroups[pgvol]['vol'], volhgroups[pgvol]['lun']]
        hgroups_facts[pgname]['vols'].append(volpgdict)
    return hgroups_facts


def generate_interfaces_dict(array):
    int_facts = {}
    ports = array.list_ports()
    for port in range(0, len(ports)):
        int_name = ports[port]['name']
        if ports[port]['wwn']:
            int_facts[int_name] = ports[port]['wwn']
        if ports[port]['iqn']:
            int_facts[int_name] = ports[port]['iqn']
    return int_facts


def main():
    argument_spec = purefa_argument_spec()
    argument_spec.update(dict(
        gather_subset=dict(default='minimum', type='list',)
    ))

    module = AnsibleModule(argument_spec, supports_check_mode=False)

    array = get_system(module)

    subset = [test.lower() for test in module.params['gather_subset']]
    valid_subsets = ('all', 'minimum', 'config', 'performance', 'capacity',
                     'network', 'subnet', 'interfaces', 'hgroups', 'pgroups',
                     'hosts', 'volumes', 'snapshots')
    subset_test = (test in valid_subsets for test in subset)
    if not all(subset_test):
        module.fail_json(msg="value must gather_subset must be one or more of: %s, got: %s"
                         % (",".join(valid_subsets), ",".join(subset)))

    facts = {}

    if 'minimum' in subset or 'all' in subset:
        facts['default'] = generate_default_dict(array)
    if 'performance' in subset or 'all' in subset:
        facts['performance'] = generate_perf_dict(array)
    if 'config' in subset or 'all' in subset:
        facts['config'] = generate_config_dict(array)
    if 'capacity' in subset or 'all' in subset:
        facts['capacity'] = generate_capacity_dict(array)
    if 'network' in subset or 'all' in subset:
        facts['network'] = generate_network_dict(array)
    if 'subnet' in subset or 'all' in subset:
        facts['subnet'] = generate_subnet_dict(array)
    if 'interfaces' in subset or 'all' in subset:
        facts['interfaces'] = generate_interfaces_dict(array)
    if 'hosts' in subset or 'all' in subset:
        facts['hosts'] = generate_host_dict(array)
    if 'volumes' in subset or 'all' in subset:
        facts['volumes'] = generate_vol_dict(array)
    if 'snapshots' in subset or 'all' in subset:
        facts['snapshots'] = generate_snap_dict(array)
    if 'hgroups' in subset or 'all' in subset:
        facts['hgroups'] = generate_hgroups_dict(array)
    if 'pgroups' in subset or 'all' in subset:
        facts['pgroups'] = generate_pgroups_dict(array)

    module.exit_json(ansible_facts={'ansible_purefa_facts': facts})


if __name__ == '__main__':
    main()
