#!/usr/bin/python -W ignore::DeprecationWarning
#
# archipel-vmrequestnode
#
# Copyright (C) 2010 Antoine Mercadal <antoine.mercadal@inframonde.eu>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.archipel-vmrequestnode


import os
import sys
from optparse import OptionParser
import xmpp
import archipelcore.pubsub
from archipelcore.scriptutils import *


NODENAME_VMPARKING = "/archipel/vmparking"

def create(xmppclient, pubsubserver):
    """
    Create the pubsub node
    """
    config = {
            archipelcore.pubsub.XMPP_PUBSUB_VAR_ACCESS_MODEL: archipelcore.pubsub.XMPP_PUBSUB_VAR_ACCESS_MODEL_AUTHORIZE,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_PUBLISH_MODEL: archipelcore.pubsub.XMPP_PUBSUB_VAR_ACCESS_MODEL_AUTHORIZE,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_DELIVER_NOTIFICATION: 1,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_MAX_ITEMS: 1000,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_PERSIST_ITEMS: 1,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_NOTIFY_RECTRACT: 1,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_DELIVER_PAYLOADS: 1,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_SEND_LAST_PUBLISHED_ITEM: archipelcore.pubsub.XMPP_PUBSUB_VAR_SEND_LAST_PUBLISHED_ITEM_NEVER,
            archipelcore.pubsub.XMPP_PUBSUB_VAR_ITEM_REPLY: archipelcore.pubsub.XMPP_PUBSUB_VAR_ITEM_REPLY_PUBLISHER
    }
    create_pubsub(xmppclient, pubsubserver, NODENAME_VMPARKING, config)
    configure_pubsub(xmppclient, pubsubserver, NODENAME_VMPARKING, archipelcore.pubsub.XMPP_PUBSUB_VAR_MAX_ITEMS, 1000)


def delete(xmppclient, pubsubserver):
    """
    Delete the pubsub node
    """
    delete_pubsub(xmppclient, pubsubserver, NODENAME_VMPARKING)


def list_affiliations(xmppclient, pubsubserver):
    """
    List the affiliatons
    """
    pubSubNode = get_pubsub(xmppclient, pubsubserver, NODENAME_VMPARKING)
    if pubSubNode.fetch_affiliations(wait=True):
        if len(pubSubNode.affiliations) == 0: print "Parking authorized accounts"
        for jid, aff in pubSubNode.affiliations.items():
            print " - %s (%s)" % (jid, aff)
    else:
        error("Unable to add set affiliation to node %s" % NODENAME_VMPARKING)


def set_affiliation(xmppclient, account, affiliation, pubsubserver):
    """
    Set the affiliation of an account
    @type jid: xmpp.JID
    @param jid: what
    """
    check_valid_jid(account, bare=True)
    pubSubNode = get_pubsub(xmppclient, pubsubserver, NODENAME_VMPARKING)
    if pubSubNode.set_affiliation(account, affiliation, wait=True):
        success("JID %s affiliation is now %s" % (account, affiliation))
    else:
        error("Unable to set affiliation %s to account %s" % (affiliation, account))

def content(xmppclient, pubsubserver, show_domain=False):
    """
    List the content of the parking
    """
    pubSubNode = get_pubsub(xmppclient, pubsubserver, NODENAME_VMPARKING)
    for item in  pubSubNode.get_items():
        print "ID       : %s" % item.getAttr("id")
        print "Name     : %s" % item.getTag("virtualmachine").getTag("domain").getTag("name").getData()
        print "Parker   : %s" % item.getTag("virtualmachine").getAttr("parker")
        print "Date     : %s" % item.getTag("virtualmachine").getAttr("date")
        if show_domain:
            print "XML  : "
            print "%s" % str(item.getTag("virtualmachine").getTag("domain")).replace('xmlns="http://www.gajim.org/xmlns/undeclared" ', "")
        print ""

def delete_item(xmppclient, pubsubserver, pid):
    """
    delete a parked VM
    """
    if retract_item(xmppclient, pubsubserver, NODENAME_VMPARKING, pid, wait=True):
        success("VM Parking with ID %s has been removed" % pid)
    else:
        error("Unable to remove VM with parking ticket %s" % pid)


def park(xmppclient, pubsubserver, name, uuid, xml_string):
    """
    Directly park a virtual machine
    """
    import random
    import string
    import datetime
    xml = xmpp.simplexml.NodeBuilder(data=xml_string).getDom()
    if xml.getTag("uuid"):
        xml.delChild("uuid")
    xml.addChild("uuid").setData(uuid)
    if xml.getTag("name"):
        xml.delChild("name")
    xml.addChild("name").setData(name)
    if xml.getTag("description"):
        xml.delChild("description")
    password = ''.join([random.choice(string.letters + string.digits) for i in range(32)])
    xml.addChild("description").setData("%s@%s::::%s" % (uuid, xmppclient.Server, password))
    vmparkednode = xmpp.Node(tag="virtualmachine", attrs={"parker": "from@script", "date": datetime.datetime.now(), "origin": "from@script"})
    vmparkednode.addChild(node=xml)
    publish_item(xmppclient, pubsubserver, NODENAME_VMPARKING, vmparkednode, wait=True)


if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("-j", "--jid",
                        dest="jid",
                        help="set the JID to use",
                        metavar="user@domain")
    parser.add_option("-p", "--password",
                        dest="password",
                        help="set the password associated to the JID",
                        metavar="123456")
    parser.add_option("-P", "--pubsubserver",
                        dest="pubsubserver",
                        help="set the pubsubserver to use. if not given it will be pubsub.[jid.getDomain()]",
                        metavar="pubsub.domain",
                        default=None)
    parser.add_option("-c", "--create",
                        action="store_true",
                        dest="create",
                        help="create the node (default action)")
    parser.add_option("-d", "--delete",
                        action="store_true",
                        dest="delete",
                        help="delete the node")
    parser.add_option("-a", "--authorize",
                        dest="auth",
                        help="authorize an hypervisor to handle the parking",
                        metavar="user@domain")
    parser.add_option("-u", "--unauthorize",
                        dest="unauth",
                        help="unauthorize an hypervisor to handle the parking",
                        metavar="user@domain")
    parser.add_option("--park",
                        action="store_true",
                        help="directly park a XML description")
    parser.add_option("--uuid",
                        dest="park_uuid",
                        help="UUID of a the VM to park",
                        metavar="uuid")
    parser.add_option("--xml",
                        dest="park_xml_string",
                        help="the libvirt description",
                        metavar="libvirt desc")
    parser.add_option("--name",
                        dest="park_name",
                        help="the name of the virtual machine",
                        metavar="a name")
    parser.add_option("-l", "--list",
                        action="store_true",
                        dest="list",
                        help="List authorized accounts")
    parser.add_option("-L", "--List",
                        action="store_true",
                        dest="listContent",
                        help="List parked information")
    parser.add_option("-r", "--remove",
                        dest="delete_item",
                        help="Delete a parked VM")
    parser.add_option("-v", "--verbose",
                        action="store_true",
                        dest="verbose",
                        help="verbose mode")

    options, args = parser.parse_args()

    xmppclient = initialize(options)

    if options.list:
        list_affiliations(xmppclient, options.pubsubserver)
    elif options.auth:
        set_affiliation(xmppclient, xmpp.JID(options.auth), archipelcore.pubsub.XMPP_PUBSUB_AFFILIATION_OWNER, options.pubsubserver)
    elif options.unauth:
        set_affiliation(xmppclient, xmpp.JID(options.unauth), archipelcore.pubsub.XMPP_PUBSUB_AFFILIATION_NONE, options.pubsubserver)
    elif options.create:
        create(xmppclient, options.pubsubserver)
    elif options.delete:
        delete(xmppclient, options.pubsubserver)
    elif options.listContent:
        content(xmppclient, options.pubsubserver, options.verbose)
    elif options.delete_item:
        delete_item(xmppclient, options.pubsubserver, options.delete_item)
    elif options.park:
        if not options.park_uuid or not options.park_xml_string or not options.park_name:
            error("You must set the UUID and the XML string if you want to park directly a virtual machine")
        park(xmppclient, options.pubsubserver, options.park_name, options.park_uuid, options.park_xml_string)