#!/usr/bin/env python
from mistansible.helpers import authenticate
from ansible.module_utils.basic import *

DOCUMENTATION = '''
---
module: mist_clouds
short_description: Manage clouds in the mist.io service
description:
  - Manage multi-cloud clouds through mist.io service.
  - You can add/remove multiple clouds from multiple providers through mist.io service.
  - Before you can provision, monitor etc machines through mist.io, you have to first add a cloud to the mist.io service.
  - Mist.io supports
  - EC2,
  - Rackspace,
  - Openstack,
  - Linode,
  - Google Compute Engine,
  - SoftLayer,
  - Digital Ocean,
  - Nephoscale,
  - Bare metal servers,
  - Docker containers,
  - HP Cloud,
  - Azure,
  - VmWare - Vcloud,
  - KVM(libvirt),
  - I(mist_email) and I(mist_password) can be skipped if I(~/.mist) config file is present.
  - See documentation for config file U(http://mistclient.readthedocs.org/en/latest/cmd/cmd.html)
options:
  mist_email:
    description:
      - Email to login to the mist.io service
    required: false
  mist_password:
    description:
      - Password to login to the mist.io service
    required: false
  mist_uri:
    default: https://mist.io
    description:
      - Url of the mist.io service. By default https://mist.io. But if you have a custom installation of mist.io you can provide the url here
    required: false
  state:
    description:
      - If provided it will instruct the module to trigger cloud actions, otherwise it will only list information
    choices: ["present", "absent"]
    required: false
  title:
    description:
      - The title you want the cloud to have
    required: false
  provider:
    description:
      - Provider id for the cloud you want to add to mist.io. You can see all the providers ids using the M(mist_providers) module.
    required: false
author: "Mist.io Inc"
version_added: "1.7.1"

'''

EXAMPLES = '''
- name: Add EC2 cloud
  mist_clouds:
    title: MyEC2
    provider: ec2
    api_key: kjhf98y9lkj0909kj90edffwwf432fd
    api_secret: LKHLKjlkdlkho8976dhjkjhd987987
    region: ec2_ap_northeast
    state: present

- name: Add Rackspace cloud
  mist_clouds:
    title: MyRackspace
    provider: rackspace
    region: dfw
    username: rack_username
    api_key: sadlkjnjkhbi0HBCG
    state: present

- name: Add Nephoscale cloud
  mist_clouds:
    title: MyNepho
    provider: nephoscale
    username: nepho_user
    password: nepho_pass
    state: present

- name: Add SoftLayer cloud
  mist_clouds:
    title: MySoftLayer
    provider: softlayer
    username: SL09890
    api_key: kjhdskjhad987987098sdlkhjlajslkj
    state: present

- name: Add Digital Ocena cloud
  mist_clouds:
    title: MyDigi
    provider: digitalocean
    token: oiulksdjkjhd0987098lkahkjdhkj....
    state: present

- name: Add Google Compute Engine cloud
  mist_clouds:
    title: GCE
    provider: gce
    email: my.gce.email@gce
    project_id: electron-25
    private_key: /path/to/locally/stored/private_key
    state: present

- name: Add Azure cloud
  mist_clouds:
    title: AZURE
    provider: azure
    subscription_id: lkjafh-08jhkl-09kljlj...
    certificate: /path/to/locally/saved/certificate
    state: present

- name: Add Linode cloud
  mist_clouds:
    title: MyLinode
    provider: linode
    api_key: dlkjdljkd0989yKGFgjgc86798ohkl
    state: present

- name: Add Bare Metal (or any server with ssh access)
  mist_clouds:
    title: MyOtherServer
    provider: bare_metal
    machine_ip: 190.20.10.45
    machine_user: myuser
    machine_key: name_of_key_added_to_mist.io
    machine_port: 22
    state: present

- name: Add vCloud cloud
  mist_clouds:
    title: MyVCLOUD
    provider: vcloud
    username: vuser
    password: vpass
    organization: Mist.io
    host: compute.idcloudonline.com
    state: present

- name: Add Indonesian vCloud cloud
  mist_clouds:
    title: IndoVCLOUD
    provider: indonesian_vcloud
    username: vuser
    password: vpass
    organization: Mist.io
    state: present

- name: Add KVM(libvirt) cloud
  mist_clouds:
    title: MyKVM
    provider: libvirt
    machine_hostname: 190.198.23.0
    machine_user: root
    machine_key: name_of_key_added_to_mist.io
    state: present

- name: Add HP Cloud cloud
  mist_clouds:
    title: MyHP
    provider: hpcloud
    region: region-a.geo-1
    username: hpuser
    password: hppass
    tenant_name: my_tenant
    state: present

- name: Add Openstack cloud
  mist_clouds:
    title: MyOPENSTACK
    provider: openstack
    username: user
    password: pass
    tenant_name: admin
    auth_url: http://190.132.20.22:5000
    region: my_region_if_exists
    state: present

- name: Add Docker cloud
  mist_clouds:
    title: MyDOCKER
    provider: docker
    docker_host: 190.189.1.2
    docker_port: 4243
    auth_user: user if I have Basic HTTP AUTH setup
    auth_password: pass if I have Basic HTTP AUTH setup
    key_file: path to key file if I have TLS setup
    cert_file: path to cert file if I have TLS setup

- name: List information about DigitalOcean cloud
  mist_clouds:
    mist_email: your@email.com
    mist_password: yourpassword
    cloud: DigitalOcean
  register: cloud
'''


def determine_action(state):
    if not state:
        return "list"
    else:
        return "addremove"


def list_clouds(module, client):
    clouds = client.clouds()
    title = module.params.get('title')

    if not title:
        result = [cloud.title for cloud in clouds]
        module.exit_json(changed=False, clouds=result)
    else:
        clouds = client.clouds(search=title)
        if clouds:
            module.exit_json(changed=False, info=clouds[0].info)
        else:
            module.exit_json(changed=False, info="Not Found")


def cloud_action(module, client):
    provider = module.params.get('provider')
    title = module.params.get('title')
    desired_state = module.params.get('state')

    cloud_state, chosen_cloud = check_state(client, provider, title)

    if cloud_state == 'present' and desired_state == 'present':
        module.exit_json(changed=False, info=chosen_cloud.info)
    elif cloud_state == 'present' and desired_state == 'absent':
        chosen_cloud.delete()
        module.exit_json(changed=True)
    elif cloud_state == 'absent' and desired_state == 'absent':
        module.exit_json(changed=False)
    elif cloud_state == 'absent' and desired_state == 'present':
        chosen_cloud = add_cloud(module, client)
        module.exit_json(changed=True, info=chosen_cloud.info)
    module.exit_json(changed=False, info="paparia")


def check_state(client, provider, title):
    cloud_state = 'absent'
    chosen_cloud = None

    clouds = [cloud.title for cloud in client.clouds()]
    if title in clouds:
        cloud_state = 'present'
        chosen_cloud = client.clouds(search=title)[0]

    return cloud_state, chosen_cloud


def remove_cloud(provider, client):
    for key in client.clouds:
        cloud = client.clouds[key]
        if cloud.info['provider'] == provider:
            cloud.delete()
            return


def add_cloud(module, client):
    title = module.params.get('title')
    provider = module.params.get('provider')

    if provider == "ec2":
        api_key = module.params.get('api_key')
        api_secret = module.params.get('api_secret')
        region = module.params.get('region')
        client.add_cloud(title, provider, api_key=api_key,
                           api_secret=api_secret, region=region)
    elif provider == "rackspace":
        username = module.params.get('username')
        api_key = module.params.get('api_key')
        region = module.params.get('region')
        client.add_cloud(title, provider, username=username,
                           api_key=api_key, region=region)
    elif provider == "nephoscale":
        username = module.params.get('username')
        password = module.params.get('password')
        client.add_cloud(title, provider, username=username,
                           password=password)
    elif provider == "softlayer":
        username = module.params.get('username')
        api_key = module.params.get('api_key')
        client.add_cloud(title, provider, username=username,
                           api_key=api_key)
    elif provider == "digitalocean":
        token = module.params.get('token')
        client.add_cloud(title, provider, token=token)
    elif provider == "gce":
        email = module.params.get('email')
        private_key_path = module.params.get('private_key')
        with open(private_key_path, 'r') as f:
            private_key = f.read()
        project_id = module.params.get('project_id')
        client.add_cloud(title, provider, email=email,
                           private_key=private_key, project_id=project_id)
    elif provider == "azure":
        subscription_id = module.params.get('subscription_id')
        certificate_path = module.params.get('certificate')
        with open(certificate_path, 'r') as f:
            certificate = f.read()
        client.add_cloud(title, provider, subscription_id=subscription_id,
                           certificate=certificate)
    elif provider == "linode":
        api_key = module.params.get('api_key')
        client.add_cloud(title, provider, api_key=api_key)
    elif provider == "bare_metal":
        machine_ip = module.params.get('machine_ip')
        machine_key = module.params.get('machine_key')
        machine_user = module.params.get('machine_user')
        machine_port = module.params.get('machine_port')
        client.add_cloud(title, provider, machine_ip=machine_ip,
                           machine_key=machine_key, machine_user=machine_user,
                           machine_port=int(machine_port))
    elif provider in ['vcloud', 'indonesian_vcloud']:
        username = module.params.get('username')
        password = module.params.get('password')
        organization = module.params.get('organization')
        host = module.params.get('host')
        client.add_cloud(title, provider, username=username,
                           password=password, organization=organization, host=host)
    elif provider == "libvirt":
        machine_hostname = module.params.get('machine_hostname')
        machine_user = module.params.get('machine_user')
        machine_key = module.params.get('machine_key')
        client.add_cloud(title, provider, machine_hostname=machine_hostname,
                           machine_user=machine_user, machine_key=machine_key)
    elif provider == "hpcloud":
        username = module.params.get('username')
        password = module.params.get('password')
        tenant_name = module.params.get('tenant_name')
        region = module.params.get('region')
        client.add_cloud(title, provider, username=username,
                           password=password, tenant_name=tenant_name, region=region)
    elif provider == "openstack":
        username = module.params.get('username')
        password = module.params.get('password')
        auth_url = module.params.get('auth_url')
        tenant_name = module.params.get('tenant_name')
        region = module.params.get('region')
        compute_endpoint = module.params.get('compute_endpoint')
        client.add_cloud(title, provider, username=username, password=password,
                           auth_url=auth_url, tenant_name=tenant_name, region=region,
                           compute_endpoint=compute_endpoint)
    elif provider == "docker":
        docker_port = module.params.get('docker_port')
        docker_host = module.params.get('docker_host')
        auth_user = module.params.get('auth_user')
        auth_password = module.params.get('auth_password')
        key_file_path = module.params.get('key_file')
        if key_file_path:
            with open(key_file_path, 'r') as f:
                key_file = f.read()
        else:
            key_file = None
        cert_file_path = module.params.get('cert_file')
        if cert_file_path:
            with open(cert_file_path, 'r') as f:
                cert_file = f.read()
        else:
            cert_file = None
        client.add_cloud(title, provider, docker_host=docker_host, docker_port=docker_port,
                           auth_user=auth_user, auth_password=auth_password, key_file=key_file,
                           cert_file=cert_file)

    client.update_clouds()
    cloud = client.clouds(search=title)[0]
    return cloud


def main():
    module = AnsibleModule(
        argument_spec=dict(
            state=dict(required=False, choices=['present', 'absent']),
            provider=dict(required=False, type='str'),
            title=dict(required=False, type='str'),
            mist_uri=dict(default='https://mist.io', type='str'),
            mist_email=dict(required=False, type='str'),
            mist_password=dict(required=False, type='str'),
            api_key=dict(required=False, type='str'),
            api_secret=dict(required=False, type='str'),
            region=dict(required=False, type='str'),
            username=dict(required=False, type='str'),
            password=dict(required=False, type='str'),
            token=dict(required=False, type='str'),
            email=dict(required=False, type='str'),
            private_key=dict(required=False, type='str'),
            project_id=dict(required=False, type='str'),
            certificate=dict(required=False, type='str'),
            subscription_id=dict(required=False, type='str'),
            machine_ip=dict(required=False, type='str'),
            machine_key=dict(required=False, type='str'),
            machine_user=dict(required=False, type='str', default='root'),
            machine_port=dict(required=False, type='str', default='22'),
            machine_hostname=dict(required=False, type='str'),
            host=dict(required=False, type='str'),
            organization=dict(required=False, type='str'),
            tenant_name=dict(required=False, type='str'),
            docker_port=dict(required=False, type='str', default='4243'),
            docker_host=dict(required=False, type='str'),
            auth_user=dict(required=False, type='str'),
            auth_password=dict(required=False, type='str'),
            key_file=dict(required=False, type='str'),
            cert_file=dict(required=False, type='str'),
        )
    )

    client = authenticate(module)

    #Determine which action to run (e.g. list clouds, add cloud etc)
    state = module.params.get('state')
    action = determine_action(state)

    if action == "list":
        list_clouds(module, client)
    else:
        cloud_action(module, client)

main()
