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

DOCUMENTATION = '''


---
module: oracle_ovm_module
short_description: Manage Virtual Storage for VM:s in Oracle Virtual Manager 3.3
description:
    - Best way to use this module in task playbooks is to delegate_to: 127.0.0.1
version_added: "0.0.1"
options:
    ovmHostname:
        description:
            - Hostname/Ipadress to OVM host
        required: true
    ovmPort
        description:
            - Port that OVM listen on
        required: true    
    user
        description:
            - Username for logon to the OVM Web Gui
        required: true
    password
        description:
            - Hostname/Ipadress to OVM host
        required: true
    state
        description:
            - The intended state of the Oracle Cloud Instance
                - present = Create New Cloud Service
                - absent = Delete Existen Cloud Service
                - start = Start Existen Cloud Service VM
                - stop  = Stop Existen Cloud Service VM
                - restart = Restart Existen Cloud Service VM
                - scale = Scale Up or Down Cloud Service VM
        required: true
        choices=["present","absent","start", "stop", "restart","scale"]
    repositoryName
        description:
            - Virtdisk storage repository
        required: false    
    virtualDiskName
        description:
            - Name for virtualdisk
        required: False    
    virtualDiskSize
        description:
            - Size of the disk in bytes. If this is a sparse image, this number does not reflect the actual size of the
            image on disk, but rather the maximum size of the file. For a non-sparse image this is the same as the size
            of the file on disk.
        required: False    
    virtualSparse
        description:
            - parse Allocation or Non-sparse Allocation. Sparse Allocation creates a sparse disk, so the size of the
            disk is initially small and increases as it is used. Sparse allocation is faster than using Non-Sparse
            Allocation when creating a virtual machine. Non-Sparse Allocation creates the entire disk when the
            virtual machine is created, and so is slower than creating a sparse disk
        required: False    
    vmName
        description:
            - Name for the Vm
        required: true    
    vmDiskMappingSlott
        description:
            - Fix Disk slott in the vm
        required: true    
        
'''

EXAMPLES = '''

# Create Virtual Disk
oracle_ovm_storage: ovmHostname: 192.168.1.100 ovmPort: 7002 user: admin password: Welcome1 state: present virtualDiskName: KallEDisk repositoryName: ssd_1000 virtualDiskSize: 2 virtualSparse: False

# Remove Virtual Disk from a repository
oracle_ovm_storage: ovmHostname: 192.168.1.100 ovmPort: 7002 user: admin password: Welcome1 state: absent vmName: db1 virtualDiskName: db1_u01 repositoryName: ssd_1000

# Add mapping between VM and Virtualdisk 
oracle_ovm_storage: ovmHostname: 192.168.1.100 ovmPort: 7002 user: admin password: Welcome1 state: mappDisk vmName: db1 description: "dddddd" virtualDiskName: db1_u01 vmDiskMappingSlott: 6

# Remove mapping between vm and disk
oracle_ovm_storage: ovmHostname: 192.168.1.100 ovmPort: 7002 user: admin password: Welcome1 state: removeMappDisk vmName: db1 virtualDiskName: db1_u01 repositoryName: ssd_1000

'''
try:
    import requests

    requests.packages.urllib3.disable_warnings()
    import time
    import json
except ImportError:
    requests_exists = False
else:
    requests_exists = True
"""Return jobStatus of job send to Oracle Cloud
"""


def get_vm_info_by_id(module, vm_id, rest_session):

    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Vm/{vmId}'.format(vmId=vm_id,
                                                                             hostName=module.params["ovmHostname"],
                                                                             portNr=module.params["ovmPort"])
    vm_info = rest_session.get(url)
    vm_info_json = json.loads(vm_info.text)
    return vm_info_json


def get_vm_info_by_name(module, rest_session):

    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Vm/id'.format(hostName=module.params["ovmHostname"],
                                                                         portNr=module.params["ovmPort"])
    vm_results = rest_session.get(url)

    for obj in vm_results.json():
        if 'name' in obj.keys():
            if obj['name'] == module.params['vmName']:
                return obj


def wait_for_job(job_uri, rest_session, module):
    while True:
        time.sleep(1)
        r = rest_session.get(job_uri)
        job = r.json()
        if job['summaryDone']:
            print '{name}: {runState}'.format(name=job['name'], runState=job['jobRunState'])
            if job['jobRunState'].upper() == 'FAILURE':
                raise Exception('Job failed: {error}'.format(error=job['error']))
            elif job['jobRunState'].upper() == 'SUCCESS':
                if 'resultId' in job:
                    return job['resultId']
                break
            else:
                break


def get_job_info(rest_session, job_id, module):
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Job/{jobId}'.format(jobId=job_id,
                                                                               hostName=module.params["ovmHostname"],
                                                                               portNr=module.params["ovmPort"])

    result_job_info = rest_session.get(url)
    return json.loads(result_job_info.text)


def get_id_from_name(rest_session, module, resource, obj_name):
    base_uri = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest'.format(hostName=module.params["ovmHostname"],
                                                                        portNr=module.params["ovmPort"])
    uri = base_uri + '/' + resource + '/id'
    r = rest_session.get(uri)
    for obj in r.json():
        if 'name' in obj.keys():
            if obj['name'] == obj_name:
                return obj
    raise Exception('Failed to find id for {name}'.format(name=obj_name))


def get_virtual_disk_by_id_info(rest_session, module, virtual_disk_id):
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/VirtualDisk/{virtual_disk_id}'.format(
        virtual_disk_id=virtual_disk_id
        , hostName=module.params["ovmHostname"],
        portNr=module.params["ovmPort"])

    virtual_disk_result = rest_session.get(url)
    virtual_disk_json = json.loads(virtual_disk_result.text)

    return virtual_disk_json


def get_vm_disk_mapping_from_vm(module, rest_session):
    vm_info = get_vm_info_by_id(module, get_vm_info_by_name(module, rest_session)['value'], rest_session)
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Vm/{vmId}/VmDiskMapping'.format(
        hostName=module.params["ovmHostname"], portNr=module.params["ovmPort"], vmId=vm_info['id']['value'])
    vm_disk_mapping_result = rest_session.get(url)

    for obj in vm_disk_mapping_result.json():
        if 'virtualDiskId' in obj.keys():
            if obj['virtualDiskId']['name'] == module.params['virtualDiskName']:
                return obj


def virtual_disk_exists(module, rest_session):
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/VirtualDisk/id'.format(hostName=module.params["ovmHostname"],
                                                                                  portNr=module.params["ovmPort"])
    vm_results = rest_session.get(url)

    for obj in vm_results.json():
        if 'name' in obj.keys():
            if obj['name'] == module.params['virtualDiskName']:
                return True

    return False


def virtual_disk_in_repository_exists(module, rest_session):
    repository_id = get_id_from_name(rest_session, module, 'Repository', module.params["repositoryName"])
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Repository/{repositoryId}/VirtualDisk'.format(
        hostName=module.params["ovmHostname"], portNr=module.params["ovmPort"], repositoryId=repository_id['value'])
    vm_results = rest_session.get(url)

    for obj in vm_results.json():
        if 'id' in obj.keys():
            if obj['id']['name'] == module.params['virtualDiskName']:
                return True

    return False


def virtual_disk_have_mappings(module, rest_session):
    virtual_disk_info = get_virtual_disk_by_id_info(rest_session, module, get_id_from_name(rest_session, module, 'VirtualDisk',
                                                                                           module.params["virtualDiskName"])[
        'value'])
    virtual_disk_mappings = virtual_disk_info['vmDiskMappingIds']

    if len(virtual_disk_mappings) >= 1:
        return True
    else:
        return False


def vm_disk_mapping_exists(module, rest_session):
    vm_info = get_vm_info_by_id(module, get_vm_info_by_name(module, rest_session)['value'], rest_session)
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Vm/{vmId}/VmDiskMapping'.format(
        hostName=module.params["ovmHostname"], portNr=module.params["ovmPort"], vmId=vm_info['id']['value'])
    vm_results = rest_session.get(url)

    for obj in vm_results.json():
        if 'virtualDiskId' in obj.keys():
            if obj['virtualDiskId']['name'] == module.params['virtualDiskName']:
                return True

    return False


def repository_exists(module, rest_session):
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Repository/id'.format(hostName=module.params["ovmHostname"],
                                                                                 portNr=module.params["ovmPort"])
    vm_results = rest_session.get(url)

    for obj in vm_results.json():
        if 'name' in obj.keys():
            if obj['name'] == module.params['repositoryName']:
                return True

    return False


def create_virtual_disk(module, rest_session):
    if not virtual_disk_exists(module, rest_session):
        repository_id = get_id_from_name(rest_session, module, 'Repository', module.params['repositoryName'])
        url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Repository/{repositoryId}/VirtualDisk'.format(
            hostName=module.params["ovmHostname"], portNr=module.params["ovmPort"], repositoryId=repository_id['value'])

        data = {"diskType": "VIRTUAL_DISK",
                "name": module.params['virtualDiskName'],
                "size": module.params['virtualDiskSize'] * 1024 * 1024 * 1024,
                }
        create_virtual_disk_result = rest_session.post(url, data=json.dumps(data),
                                                       params={"sparse": module.params['virtualSparse']})
        create_virtual_disk_json = json.loads(create_virtual_disk_result.text)

        job_id = create_virtual_disk_json['id']['value']
        waitModifyJob = wait_for_job(create_virtual_disk_json['id']['uri'], rest_session, module)

        job_info = get_job_info(rest_session, job_id, module)

        return job_info['resultId']['value']
    else:
        module.exit_json(msg='vmDisk Exists', changed=False)


def create_vm_disk_mapping(module, rest_session):
    if not vm_disk_mapping_exists(module, rest_session):
        virtual_disk_info = get_virtual_disk_by_id_info(rest_session,
                                                        module,
                                                        get_id_from_name(rest_session,
                                                                         module,
                                                                         'VirtualDisk',
                                                                         module.params["virtualDiskName"])['value'])
        vm_info = get_vm_info_by_id(module, get_vm_info_by_name(module, rest_session)['value'], rest_session)

        url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Vm/{vmId}/VmDiskMapping'.format(
            hostName=module.params["ovmHostname"], portNr=module.params["ovmPort"], vmId=vm_info['id']['value'])

        data = {"id": {"type": "com.oracle.ovm.mgr.ws.model.VmDiskMapping"},
                "virtualDiskId": {
                    "type": "com.oracle.ovm.mgr.ws.model.VirtualDisk",
                    "value": virtual_disk_info['id']['value']
                },
                "diskTarget": module.params["vmDiskMappingSlott"],
                "name": module.params["virtualDiskName"],
                "description": module.params["description"],
                }
        create_vmd_disk_mapping_result = rest_session.post(url, data=json.dumps(data))
        create_vmd_disk_mapping_json = json.loads(create_vmd_disk_mapping_result.text)
        wait_modify_job = wait_for_job(create_vmd_disk_mapping_json['id']['uri'], rest_session, module)
    else:
        module.exit_json(msg='mapping Exists', changed=False)


def del_vm_disk_mapping(rest_session, module, vm_disk_mapping_id):
    vm_info = get_vm_info_by_id(module, get_vm_info_by_name(module, rest_session)['value'], rest_session)
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Vm/{VmId}/VmDiskMapping/{VmDiskMappingId}'.format(
        VmId=vm_info['id']['value'], VmDiskMappingId=vm_disk_mapping_id, hostName=module.params["ovmHostname"],
        portNr=module.params["ovmPort"])

    del_vm_disk_mapping_result = rest_session.delete(url)
    del_vm_disk_mapping_json = json.loads(del_vm_disk_mapping_result.text)

    waitModifyJob = wait_for_job(del_vm_disk_mapping_json['id']['uri'], rest_session, module)


def del_virtual_disk_mapping_from_vm(rest_session, module):
    vmInfo = get_vm_info_by_id(module, get_vm_info_by_name(module, rest_session)['value'], rest_session)
    virtuelDiskMappInfo = get_vm_disk_mapping_from_vm(module, rest_session)

    if virtual_disk_exists(module, rest_session):
        if vm_disk_mapping_exists(module, rest_session):
            del_vm_disk_mapping(rest_session, module, virtuelDiskMappInfo['id']['value'])
            module.exit_json(msg='virtualdiskmapping removed', changed=True)
        else:
            module.exit_json(msg='VirtualDisk MApping on Vm not Exists', changed=False)
    else:
        module.exit_json(msg='VirtualDisk not Exists', changed=False)


def del_virtual_disk(rest_session, module):
    virtualDiskInfo = get_virtual_disk_by_id_info(rest_session, module, get_id_from_name(rest_session, module, 'VirtualDisk',
                                                                                         module.params["virtualDiskName"])[
        'value'])
    url = 'https://{hostName}:{portNr}/ovm/core/wsapi/rest/Repository/{repositoryId}/VirtualDisk/{virtualDiskId}'.format(
        repositoryId=virtualDiskInfo['repositoryId']['value'], virtualDiskId=virtualDiskInfo['id']['value'],
        hostName=module.params["ovmHostname"], portNr=module.params["ovmPort"])
    del_virtual_disk_result = rest_session.delete(url)
    del_virtual_disk_json = json.loads(del_virtual_disk_result.text)

    waitModifyJob = wait_for_job(del_virtual_disk_json['id']['uri'], rest_session, module)


def del_virtual_disk_in_repository(rest_session, module):
    if virtual_disk_in_repository_exists(module, rest_session):
        if not virtual_disk_have_mappings(module, rest_session):
            del_virtual_disk(rest_session, module)
            module.exit_json(msg='VirtualDisk in Repo removed', changed=True)
        else:
            module.exit_json(msg='VirtualDisk in Repo Still Have Mapping', changed=False)
    else:
        module.exit_json(msg='VirtualDisk in Repo not exists', changed=False)


def main():
    msg = ['']
    module = AnsibleModule(
        argument_spec=dict(
            ovmHostname=dict(required=True),
            ovmPort			= dict(required=True),user= dict(required=True),
            password                =dict(required=True),
            state                   =dict(choices=["present", "absent", "mappDisk", "removeMappDisk"]),
            repositoryName          =dict(required=False),
            description             =dict(required=False),
            virtualDiskName         =dict(required=False),
            virtualDiskSize         =dict(required=False),virtualSparse		    =dict(required=False),
            vmName		=dict(required=False),
            vmDiskMappingSlott      =dict(required=False),
        ),
        supports_check_mode=False
    )

    rest_session = requests.Session()
    rest_session.auth = (module.params["user"], module.params["password"])
    rest_session.headers.update({'Accept': 'application/json', 'Content-Type': 'application/json'})
    rest_session. verify= False
    if module.params["state"] == "mappDisk":
        create_vm_disk_mapping(module, rest_session)
        module.exit_json(msg='vmDisk Created', changed=True)
    if module.params["state"] == "present":
        create_virtual_disk(module, rest_session)
        module.exit_json(msg='vmDisk Created', changed=True)
    elif module.params["state"] == "removeMappDisk":
        del_virtual_disk_mapping_from_vm(rest_session, module)
    elif module.params["state"] == "absent":
        del_virtual_disk_in_repository(rest_session, module)
    else:
        module.fail_json(msg="Wrong state")

from ansible.module_utils.basic import *
if __name__ == '__main__':
    main()