#!/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 free_ip
from onepdns import PDNS, filter_records, ip2int
import axconfig

import requests

# Variables
ACTION = 'FREE'
#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 spxops_del(host):
    h_auth = axconfig.load_config(keypath='spxops:api_headers')
    params = {
        "Comment": "Deleted by OpenNebula"
    }
    r = requests.delete('http://coreapi.slc.efscloud.net/api/core/{}'.format(host), json=params, headers=h_auth)


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

    ip = str(ip_address(args['ADDRESS']['IP']))
    size = int(args['ADDRESS']['SIZE'])
    log_me('ip=%s, size=%s' % (ip, size))
    spxops_compatible = ip2int(ip) & ip2int('255.0.240.0') == ip2int('10.0.64.0')
#    pdns.free_ip(ip, recurse=True) # free_ip(first_net_ip, server=pdns_server)
    if spxops_compatible:
#            pass
        records = pdns.search(ip)
        records = filter_records(records, "type", ["PTR"])
        for r in records:
            h = r['content'].split('.')[0]
            if h.startswith('rb-'):
                log_me('Deleteing %s host through SpxOps' % h)
                spxops_del(h)
    elif 'EXT_MAP' in args['AR']:
        pdns.free_ip(ip, recurse=True)
        first_net_ip = ip_address(args['AR']['IP'])
        diff = int(ip_address(ip)) - int(first_net_ip)
        first_ext_ip = ip_address(args['AR']['EXT_MAP'])
        ext_ip = first_ext_ip + diff
        log_me('ext_ip=%s' % str(ext_ip))
        axextcfg = axconfig.merge_with_subpath(axcfg, 'map:ext')
        pdns_ext = PDNS(**axextcfg)
        pdns_ext.free_ip(str(ext_ip), recurse=True)
    else:
        pdns.free_ip(ip, recurse=True)
    return

main()

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

exit(0)

