#!/usr/bin/env python3
#-*- coding: utf-8 -*-
""" OpenNebula GET ADDRESS """

# Standard library imports
from base64 import b64decode
from datetime import datetime
from random import randint
from subprocess import check_output
from sys import argv, stdin

# Third party library imports
from ipaddress import ip_address
from xmltodict import parse

#import zmq

#from onepdns import find_free, allocate_ip
import axconfig
from onepdns import PDNS

# Variables
ACTION = 'GET'
#DRV_ACTION = argv[1]
REQ_ID = randint(1, 1000)
LOG_FILE = open('/var/log/one/ipam_efs.log', 'a')
VERBOSE = True

###############################################################################
# This script is used to get a free IP address (or set of IPs). The IP will be
# used by OpenNebula VMs and should not be allocated to any other host in the
# network.
#
# Input Arguments:
#  $1 - Base64 encoded XML with the AR description and the address request
#  $2 - Request ID
#
# XML format
#  <IPAM_DRIVER_ACTION_DATA>
#  <AR>
#    <TYPE>IP4</TYPE>
#    <IP> First IP in the network in '.' notation
#    <MAC> First MAC in the network in ':' notation
#    <SIZE>Number of IPs in the network
#    <NETWORK_ADDRESS> Base network address
#    <NETWORK_MASK> Network mask
#    <GATEWAY> Default gateway for the network
#    <DNS> DNS servers, a space separated list of servers
#    <GUEST_MTU> Sets the MTU for the NICs in this network
#    <SEARCH_DOMAIN> for DNS client
# <ADDRESS>
#   <IP>
#   <SIZE> Number of IPs to allocate
#   <MAC> MAC is optional
#
# This scrit MUST output the leased IP range, if the "size" IPs cannot be
# assgined the sript must return -1, otherwise it must exit 0. The answer to
# OpenNebula needs to include the ADDRESS spec:
#
#  ADDRESS = [ IP = "10.0.0.2", SIZE=34 ]
#
################################################################################

def get_args(DRV_ACTION):
    """ Decode args """
    xml_args = b64decode(DRV_ACTION)
    return parse(xml_args)['IPAM_DRIVER_ACTION_DATA']

def log_me(string, force=False):
    """ Format log """
    if VERBOSE or force:
        LOG_FILE.write('%s [%s]: [%s] %s\n' % (
            datetime.now().strftime("%F %T"),
            REQ_ID,
            ACTION,
            string))

def onevm_match_record(name_record):
    """ Verify if record is already in OpenNebula """
    log_me('onevm_match_record : %s' % name_record)

    search = check_output([
        '/usr/bin/onevm',
        'list',
        '-l', 'IP',
        '--csv'
        ])
    return name_record in search.split('\n')

def main():
    """ Main class """
    DRV_ACTION = ''
    for l in stdin:
        DRV_ACTION += l
    args = get_args(DRV_ACTION)
    log_me('DRV_ACTION : %s' % DRV_ACTION)
    log_me('get_args : %s' % args)
    axcfg = axconfig.load_config(keypath='pdns')
    pdns = PDNS(**axcfg)
#    pdns = PDNS('10.2.10.13')

    first_net_ip = ip_address(args['AR']['IP'])
    size = int(args['AR']['SIZE'])
    log_me('first_net_ip=%s, size=%s' % (first_net_ip, size))

    ip_candidate = pdns.find_free_ip_fast(str(first_net_ip), size) # find_free(str(first_net_ip), size, server=pdns_server)
    if ip_candidate:
        if pdns.allocate_ip(ip_candidate):  #allocate_ip(ip_candidate, server=pdns_server):
            log_me('[FINAL] ip_candidate=%s' % ip_candidate)
            log_me('ADDRESS = [ IP = "%s", SIZE=1 ]' % ip_candidate, force=True)
            return 'ADDRESS = [ IP = "%s", SIZE=1 ]' % ip_candidate

        log_me('[ERROR] Failed to allocate %s' % ip_candidate, force=True)

    log_me('[ERROR] No IP candidate in the range', force=True)
    return 'ADDRESS = [ IP = "", SIZE=0 ]'

print(main())

log_me('Done.')
LOG_FILE.close()

exit(0)

