#!/usr/bin/env python
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright notice,
#      this list of conditions and the following disclaimer in the documentation
#      and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os

try:
    from novaclient.v1_1 import client as nova_client
    from novaclient import exceptions
    import time
except ImportError:
    print("failed=True msg='novaclient is required for this module'")

DOCUMENTATION = '''
---
module: nova_facts
short_description: Return facts from Nova
description:
   - Returns instance state and metadata from Openstack Nova.
options:
   login_username:
     description:
        - login username to authenticate to keystone
     required: true
     default: admin
   login_password:
     description:
        - Password of login user
     required: true
     default: 'yes'
   login_tenant_name:
     description:
        - The tenant name of the login user
     required: true
     default: 'yes'
   auth_url:
     description:
        - The keystone url for authentication
     required: false
     default: 'http://127.0.0.1:35357/v2.0/'
   region_name:
     description:
        - Name of the region
     required: false
     default: None
   name:
     description:
        - Name of the instance for which facts will be retrieved.
     default: None
   instance_id:
     description:
        - Instance ID of the instance for which facts will be retrieved.
     default: None
requirements: ["novaclient"]
'''

EXAMPLES = '''
# Rebuilds an existing VM with a new image
- nova_facts:
       login_username: admin
       login_password: admin
       login_tenant_name: admin
       name: vm1
       image_id: 4f905f38-e52a-43d2-b6ec-754a13ffb529
'''


# The following openstack_ is a copy paste from an upcoming
# core module "lib/ansible/module_utils/openstack.py" Once that's landed,
# these should be replaced with a line at the bottom of the file:
# from ansible.module_utils.openstack import *
def openstack_argument_spec():
    # Consume standard OpenStack environment variables.
    # This is mainly only useful for ad-hoc command line operation as
    # in playbooks one would assume variables would be used appropriately
    OS_AUTH_URL = os.environ.get('OS_AUTH_URL', 'http://127.0.0.1:35357/v2.0/')
    OS_PASSWORD = os.environ.get('OS_PASSWORD', None)
    OS_REGION_NAME = os.environ.get('OS_REGION_NAME', None)
    OS_USERNAME = os.environ.get('OS_USERNAME', 'admin')
    OS_TENANT_NAME = os.environ.get('OS_TENANT_NAME', OS_USERNAME)

    spec = dict(
        login_username=dict(default=OS_USERNAME),
        auth_url=dict(default=OS_AUTH_URL),
        region_name=dict(default=OS_REGION_NAME),
        availability_zone=dict(default=None),
    )
    if OS_PASSWORD:
        spec['login_password'] = dict(default=OS_PASSWORD)
    else:
        spec['login_password'] = dict(required=True)
    if OS_TENANT_NAME:
        spec['login_tenant_name'] = dict(default=OS_TENANT_NAME)
    else:
        spec['login_tenant_name'] = dict(required=True)
    return spec


def _nova_facts(module, nova):
    server = None
    try:
        if module.params.get('instance_id') is None:
            servers = nova.servers.list(True, {'name': module.params['name']})
            if servers:
                # the {'name': module.params['name']} will also return servers
                # with names that partially match the server name, so we have to
                # strictly filter here
                servers = [
                    x for x in servers if x.name == module.params['name']
                ]
                if servers:
                    server = servers[0]
        else:
            server = nova.servers.get(module.params['instance_id'])
    except Exception, e:
        module.fail_json(
            msg="Error in getting the server list: %s" % e.message
        )
    if not server:
        module.exit_json(changed=False, result="not present")

    try:
        server = nova.servers.get(server.id)
    except Exception, e:
        module.fail_json(msg="not present")

    facts = {'ansible_facts': {}}
    facts['ansible_facts']['instance_status'] = server.status
    facts['ansible_facts']['instance_metadata'] = server.metadata

    module.exit_json(**facts)


def main():
    argument_spec = openstack_argument_spec()
    argument_spec.update(dict(
        name=dict(),
        instance_id=dict(),
    ))
    module = AnsibleModule(argument_spec=argument_spec)

    nova = nova_client.Client(module.params['login_username'],
                              module.params['login_password'],
                              module.params['login_tenant_name'],
                              module.params['auth_url'],
                              region_name=module.params['region_name'],
                              service_type='compute')
    try:
        nova.authenticate()
    except exceptions.Unauthorized, e:
        module.fail_json(
            msg="Invalid OpenStack Nova credentials.: %s" % e.message
        )
    except exceptions.AuthorizationFailure, e:
        module.fail_json(msg="Unable to authorize user: %s" % e.message)

    _nova_facts(module, nova)
# this is magic, see lib/ansible/module_common.py
from ansible.module_utils.basic import *
main()
