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

DOCUMENTATION = '''
---
module: mist_backends
short_description: Manage backends in the mist.io service
description:
  - Manage multi-cloud backends through mist.io service.
  - You can add/remove multiple backends from multiple providers through mist.io service.
  - Before you can provision, monitor etc machines through mist.io, you have to first add a backend 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 backend actions, otherwise it will only list information
    choices: ["present", "absent"]
    required: false
  title:
    description:
      - The title you want the backend to have
    required: false
  provider:
    description:
      - Provider id for the backend 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 backend
  mist_backends:
    title: MyEC2
    provider: ec2
    api_key: kjhf98y9lkj0909kj90edffwwf432fd
    api_secret: LKHLKjlkdlkho8976dhjkjhd987987
    region: ec2_ap_northeast
    state: present

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

- name: Add Nephoscale backend
  mist_backends:
    title: MyNepho
    provider: nephoscale
    username: nepho_user
    password: nepho_pass
    state: present

- name: Add SoftLayer backend
  mist_backends:
    title: MySoftLayer
    provider: softlayer
    username: SL09890
    api_key: kjhdskjhad987987098sdlkhjlajslkj
    state: present

- name: Add Digital Ocena backend
  mist_backends:
    title: MyDigi
    provider: digitalocean
    token: oiulksdjkjhd0987098lkahkjdhkj....
    state: present

- name: Add Google Compute Engine backend
  mist_backends:
    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 backend
  mist_backends:
    title: AZURE
    provider: azure
    subscription_id: lkjafh-08jhkl-09kljlj...
    certificate: /path/to/locally/saved/certificate
    state: present

- name: Add Linode backend
  mist_backends:
    title: MyLinode
    provider: linode
    api_key: dlkjdljkd0989yKGFgjgc86798ohkl
    state: present

- name: Add Bare Metal (or any server with ssh access)
  mist_backends:
    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 backend
  mist_backends:
    title: MyVCLOUD
    provider: vcloud
    username: vuser
    password: vpass
    organization: Mist.io
    host: compute.idcloudonline.com
    state: present

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

- name: Add KVM(libvirt) backend
  mist_backends:
    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 backend
  mist_backends:
    title: MyHP
    provider: hpcloud
    region: region-a.geo-1
    username: hpuser
    password: hppass
    tenant_name: my_tenant
    state: present

- name: Add Openstack backend
  mist_backends:
    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 backend
  mist_backends:
    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 backend
  mist_backends:
    mist_email: your@email.com
    mist_password: yourpassword
    backend: DigitalOcean
  register: backend
'''


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


def list_backends(module, client):
    backends = client.backends()
    title = module.params.get('title')

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


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

    backend_state, chosen_backend = check_state(client, provider, title)

    if backend_state == 'present' and desired_state == 'present':
        module.exit_json(changed=False, info=chosen_backend.info)
    elif backend_state == 'present' and desired_state == 'absent':
        chosen_backend.delete()
        module.exit_json(changed=True)
    elif backend_state == 'absent' and desired_state == 'absent':
        module.exit_json(changed=False)
    elif backend_state == 'absent' and desired_state == 'present':
        chosen_backend = add_backend(module, client)
        module.exit_json(changed=True, info=chosen_backend.info)
    module.exit_json(changed=False, info="paparia")


def check_state(client, provider, title):
    backend_state = 'absent'
    chosen_backend = None

    backends = [backend.title for backend in client.backends()]
    if title in backends:
        backend_state = 'present'
        chosen_backend = client.backends(search=title)[0]

    return backend_state, chosen_backend


def remove_backend(provider, client):
    for key in client.backends:
        backend = client.backends[key]
        if backend.info['provider'] == provider:
            backend.delete()
            return


def add_backend(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_backend(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_backend(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_backend(title, provider, username=username,
                           password=password)
    elif provider == "softlayer":
        username = module.params.get('username')
        api_key = module.params.get('api_key')
        client.add_backend(title, provider, username=username,
                           api_key=api_key)
    elif provider == "digitalocean":
        token = module.params.get('token')
        client.add_backend(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_backend(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_backend(title, provider, subscription_id=subscription_id,
                           certificate=certificate)
    elif provider == "linode":
        api_key = module.params.get('api_key')
        client.add_backend(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_backend(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_backend(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_backend(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_backend(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_backend(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_backend(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_backends()
    backend = client.backends(search=title)[0]
    return backend


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 backends, add backend etc)
    state = module.params.get('state')
    action = determine_action(state)

    if action == "list":
        list_backends(module, client)
    else:
        backend_action(module, client)

main()
