Пример #1
0
    def __init__(self, jid, password, configuration, name, database_file="./database.sqlite3"):
        """
        This is the constructor of the class.
        @type jid: string
        @param jid: the jid of the hypervisor
        @type password: string
        @param password: the password associated to the JID
        @type name: string
        @param name: the name of the hypervisor
        @type database_file: string
        @param database_file: the sqlite3 file to store existing VM for persistance
        """
        TNArchipelEntity.__init__(self, jid, password, configuration, name)
        archipelLibvirtEntity.TNArchipelLibvirtEntity.__init__(self, configuration)

        self.virtualmachines            = {}
        self.database_file              = database_file
        self.xmppserveraddr             = self.jid.getDomain()
        self.entity_type                = "hypervisor"
        self.default_avatar             = self.configuration.get("HYPERVISOR", "hypervisor_default_avatar")
        self.libvirt_event_callback_id  = None

        # libvirt connection
        self.connect_libvirt()

        self.vcard_infos                = {}
        if (self.configuration.has_section("VCARD")):
            for key in ("orgname", "userid", "locality", "url"):
                if self.configuration.has_option("VCARD", key):
                    self.vcard_infos[key.upper()] = self.configuration.get("VCARD", key)
        self.vcard_infos["TITLE"] = "Hypervisor (%s)" % self.current_hypervisor()

        # permissions
        permission_db_file              = self.configuration.get("HYPERVISOR", "hypervisor_permissions_database_path")
        permission_admin_names          = self.configuration.get("GLOBAL", "archipel_root_admins").split()
        self.permission_center          = TNArchipelPermissionCenter(permission_db_file, permission_admin_names)
        self.init_permissions()

        names_file = open(self.configuration.get("HYPERVISOR", "name_generation_file"), 'r')
        self.generated_names = names_file.readlines()
        names_file.close()
        self.number_of_names = len(self.generated_names) - 1

        self.log.info("Server address defined as %s" % self.xmppserveraddr)

        # hooks
        self.create_hook("HOOK_HYPERVISOR_ALLOC")
        self.create_hook("HOOK_HYPERVISOR_FREE")
        self.create_hook("HOOK_HYPERVISOR_MIGRATEDVM_LEAVE")
        self.create_hook("HOOK_HYPERVISOR_MIGRATEDVM_ARRIVE")
        self.create_hook("HOOK_HYPERVISOR_CLONE")

        # vocabulary
        self.init_vocabulary()

        # module inits
        self.initialize_modules('archipel.plugin.core')
        self.initialize_modules('archipel.plugin.hypervisor')

        if self.is_hypervisor((archipelLibvirtEntity.ARCHIPEL_HYPERVISOR_TYPE_QEMU, archipelLibvirtEntity.ARCHIPEL_HYPERVISOR_TYPE_XEN)):
            try:
                self.libvirt_event_callback_id = self.libvirt_connection.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, self.hypervisor_on_domain_event, None)
            except libvirt.libvirtError:
                self.log.error("We are sorry. But your hypervisor doesn't support libvirt virConnectDomainEventRegisterAny. And this really bad. I'm sooo sorry.")
        else:
            self.log.warning("Your hypervisor doesn't support libvirt eventing. Using fake event loop.")
        self.capabilities = self.get_capabilities()

        # persistance
        self.manage_persistance()

        # action on auth
        self.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=self.manage_vcard_hook)
        self.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=self.update_presence)
Пример #2
0
class TNArchipelHypervisor (TNArchipelEntity, archipelLibvirtEntity.TNArchipelLibvirtEntity, TNHookableEntity, TNAvatarControllableEntity, TNTaggableEntity):
    """
    This class represents a Hypervisor XMPP Capable. This is a XMPP client
    that allows to alloc threaded instance of XMPP Virtual Machine, destroy already
    active XMPP VM, and remember which have been created.
    """

    def __init__(self, jid, password, configuration, name, database_file="./database.sqlite3"):
        """
        This is the constructor of the class.
        @type jid: string
        @param jid: the jid of the hypervisor
        @type password: string
        @param password: the password associated to the JID
        @type name: string
        @param name: the name of the hypervisor
        @type database_file: string
        @param database_file: the sqlite3 file to store existing VM for persistance
        """
        TNArchipelEntity.__init__(self, jid, password, configuration, name)
        archipelLibvirtEntity.TNArchipelLibvirtEntity.__init__(self, configuration)

        self.virtualmachines            = {}
        self.database_file              = database_file
        self.xmppserveraddr             = self.jid.getDomain()
        self.entity_type                = "hypervisor"
        self.default_avatar             = self.configuration.get("HYPERVISOR", "hypervisor_default_avatar")
        self.libvirt_event_callback_id  = None

        # libvirt connection
        self.connect_libvirt()

        self.vcard_infos                = {}
        if (self.configuration.has_section("VCARD")):
            for key in ("orgname", "userid", "locality", "url"):
                if self.configuration.has_option("VCARD", key):
                    self.vcard_infos[key.upper()] = self.configuration.get("VCARD", key)
        self.vcard_infos["TITLE"] = "Hypervisor (%s)" % self.current_hypervisor()

        # permissions
        permission_db_file              = self.configuration.get("HYPERVISOR", "hypervisor_permissions_database_path")
        permission_admin_names          = self.configuration.get("GLOBAL", "archipel_root_admins").split()
        self.permission_center          = TNArchipelPermissionCenter(permission_db_file, permission_admin_names)
        self.init_permissions()

        names_file = open(self.configuration.get("HYPERVISOR", "name_generation_file"), 'r')
        self.generated_names = names_file.readlines()
        names_file.close()
        self.number_of_names = len(self.generated_names) - 1

        self.log.info("Server address defined as %s" % self.xmppserveraddr)

        # hooks
        self.create_hook("HOOK_HYPERVISOR_ALLOC")
        self.create_hook("HOOK_HYPERVISOR_FREE")
        self.create_hook("HOOK_HYPERVISOR_MIGRATEDVM_LEAVE")
        self.create_hook("HOOK_HYPERVISOR_MIGRATEDVM_ARRIVE")
        self.create_hook("HOOK_HYPERVISOR_CLONE")

        # vocabulary
        self.init_vocabulary()

        # module inits
        self.initialize_modules('archipel.plugin.core')
        self.initialize_modules('archipel.plugin.hypervisor')

        if self.is_hypervisor((archipelLibvirtEntity.ARCHIPEL_HYPERVISOR_TYPE_QEMU, archipelLibvirtEntity.ARCHIPEL_HYPERVISOR_TYPE_XEN)):
            try:
                self.libvirt_event_callback_id = self.libvirt_connection.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, self.hypervisor_on_domain_event, None)
            except libvirt.libvirtError:
                self.log.error("We are sorry. But your hypervisor doesn't support libvirt virConnectDomainEventRegisterAny. And this really bad. I'm sooo sorry.")
        else:
            self.log.warning("Your hypervisor doesn't support libvirt eventing. Using fake event loop.")
        self.capabilities = self.get_capabilities()

        # persistance
        self.manage_persistance()

        # action on auth
        self.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=self.manage_vcard_hook)
        self.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=self.update_presence)

    def update_presence(self, origin=None, user_info=None, parameters=None):
        """
        Set the presence of the hypervisor.
        @type origin: L{TNArchipelEntity}
        @param origin: the origin of the hook
        @type user_info: object
        @param user_info: random user info
        @type parameters: object
        @param parameters: runtime arguments
        """
        count   = len(self.virtualmachines)
        status  = ARCHIPEL_XMPP_SHOW_ONLINE + " (" + str(count) + ")"
        self.change_presence(self.xmppstatusshow, status)

    def register_handlers(self):
        """
        This method overrides the defaut register_handler of the super class.
        """
        TNArchipelEntity.register_handlers(self)
        self.xmppclient.RegisterHandler('iq', self.process_iq, ns=ARCHIPEL_NS_HYPERVISOR_CONTROL)

    def unregister_handlers(self):
        """
        Unregister the handlers.
        """
        TNArchipelEntity.unregister_handlers(self)
        self.xmppclient.UnregisterHandler('iq', self.process_iq, ns=ARCHIPEL_NS_HYPERVISOR_CONTROL)


    def init_vocabulary(self):
        """
        Initialize the base vocabulary.
        """
        TNArchipelEntity.init_vocabulary(self)
        registrar_items = [
                            {   "commands" : ["capabilities"],
                                "parameters": [],
                                "method": self.message_capabilities,
                                "permissions": ["capabilities"],
                                "description": "Get my libvirt capabilities" },
                            {   "commands" : ["libvirt uri"],
                                "parameters": [],
                                "method": self.message_libvirt_uri,
                                "permissions": ["uri"],
                                "description": "Get my libvirt URI" },
                            {   "commands" : ["ip"],
                                "parameters": [],
                                "method": self.message_ip,
                                "permissions": ["ip"],
                                "description": "Get my IP address" },
                            {   "commands" : ["roster", "vms", "virtual machines", "domains"],
                                "parameters": [],
                                "method": self.message_roster,
                                "permissions": ["rostervm"],
                                "description": "Get the content of my roster" },
                            {   "commands" : ["alloc"],
                                "parameters": [{"name": "name", "description": "The name of the vm. If not given, it will be generated"}],
                                "method": self.message_alloc,
                                "permissions": ["alloc"],
                                "description": "Allocate a new virtual machine" },
                            {   "commands" : ["free"],
                                "parameters": [{"name": "identifier", "description": "The name or the UUID of the vm to free"}],
                                "method": self.message_free,
                                "permissions": ["free"],
                                "description": "Free a virtual machine" },
                            {   "commands" : ["clone"],
                                "parameters": [{"name": "identifier", "description": "The name or the UUID of the vm to clone"}],
                                "method": self.message_clone,
                                "permissions": ["clone"],
                                "description": "Clone a virtual machine" }
                            ]

        self.add_message_registrar_items(registrar_items)

    def init_permissions(self):
        """
        Initialize the permissions.
        """
        TNArchipelEntity.init_permissions(self)
        self.permission_center.create_permission("alloc", "Authorizes users to allocate new virtual machines", False)
        self.permission_center.create_permission("free", "Authorizes users to free allocated virtual machines", False)
        self.permission_center.create_permission("rostervm", "Authorizes users to access the hypervisor's roster", False)
        self.permission_center.create_permission("clone", "Authorizes users to clone virtual machines", False)
        self.permission_center.create_permission("ip", "Authorizes users to get hypervisor's IP address", False)
        self.permission_center.create_permission("uri", "Authorizes users to get the hypervisor's libvirt URI", False)
        self.permission_center.create_permission("capabilities", "Authorizes users to access the hypervisor capabilities", False)

    def manage_persistance(self):
        """
        If the database_file parameter contains a valid populated sqlite3 database,
        this method will recreate all the old L{TNArchipelVirtualMachine}. If not, it will create a
        blank database file.
        """
        self.log.info("opening database file %s" % self.database_file)
        self.database = sqlite3.connect(self.database_file, check_same_thread=False)
        self.log.info("Populating database if not exists.")
        self.database.execute("create table if not exists virtualmachines (jid text, password text, creation_date date, comment text, name text)")
        c = self.database.cursor()
        c.execute("select * from virtualmachines")
        for vm in c:
            string_jid, password, date, comment, name = vm
            jid = xmpp.JID(string_jid)
            jid.setResource(self.jid.getNode().lower())
            vm_thread = self.create_threaded_vm(jid, password, name)
            self.virtualmachines[vm_thread.jid.getNode()] = vm_thread.get_instance()
            vm_thread.start()

    def create_threaded_vm(self, jid, password, name):
        """
        This method creates a threaded L{TNArchipelVirtualMachine}, starts it and returns the Thread instance.
        @type jid: string
        @param jid: the JID of the L{TNArchipelVirtualMachine}
        @type password: string
        @param password: the password associated to the JID
        @rtype: L{TNThreadedVirtualMachine}
        @return: a L{TNThreadedVirtualMachine} instance of the virtual machine
        """
        return TNThreadedVirtualMachine(jid, password, self, self.configuration, name)

    def generate_name(self):
        """
        Get a random name from the names file.
        @rtype: string
        @return: a generated name
        """
        search = True
        currentName = None
        while search:
            currentName = self.generated_names[random.randint(0, self.number_of_names)].replace("\n", "")
            if not self.get_vm_by_name(currentName):
                self.log.info("Generated name %s available. Using it." % currentName)
                search = False
        return currentName

    def get_vm_by_name(self, name):
        """
        Return the vm object by name.
        @type name : string
        @param name: the name of the vm
        @rtype: L{TNArchipelVirtualMachine}
        @return: the virtual machine or None
        """
        for uuid, vm in self.virtualmachines.iteritems():
            if vm.name.upper() == name.upper():
                return vm
        return None

    def get_vm_by_uuid(self, uuid):
        """
        Return the vm object by uuid.
        @type uuid : string
        @param uuid: the uuid of the vm
        @rtype: L{TNArchipelVirtualMachine}
        @return: the virtual machine or None
        """
        if not uuid.lower() in self.virtualmachines:
            return None
        return self.virtualmachines[uuid.lower()]

    def get_vm_by_identifier(self, identifier):
        """
        Return the vm object by identifier. Identifier can be the UUID of the name.
        @type identifier : string
        @param identifier: the identifier of the vm
        @rtype: L{TNArchipelVirtualMachine}
        @return: the virtual machine or None
        """
        vm = self.get_vm_by_name(identifier)
        if not vm:
            vm = self.get_vm_by_uuid(identifier)
        return vm


    ### LIBVIRT events Processing

    def hypervisor_on_domain_event(self, conn, dom, event, detail, opaque):
        """
        Trigger when a domain trigger vbent. We care only about RESUMED and SHUTDOWNED from MIGRATED.
        """
        if event == libvirt.VIR_DOMAIN_EVENT_STOPPED and detail == libvirt.VIR_DOMAIN_EVENT_STOPPED_MIGRATED:
            try:
                strdesc = dom.XMLDesc(0)
                desc    = xmpp.simplexml.NodeBuilder(data=strdesc).getDom()
                vmjid   = desc.getTag(name="description").getCDATA().split("::::")[0]
                self.log.info("MIGRATION: Virtual machine %s stopped because of live migration. Freeing softly." % vmjid)
                self.free_for_migration(xmpp.JID(vmjid))
                self.perform_hooks("HOOK_HYPERVISOR_MIGRATEDVM_LEAVE", vmjid)
            except Exception as ex:
                self.log.error("MIGRATION: Can't free softly this virtual machine: %s" % str(ex))

        elif event == libvirt.VIR_DOMAIN_EVENT_RESUMED and detail == libvirt.VIR_DOMAIN_EVENT_RESUMED_MIGRATED:
            try:
                strdesc = dom.XMLDesc(0)
                desc    = xmpp.simplexml.NodeBuilder(data=strdesc).getDom()
                vmjid   = desc.getTag(name="description").getCDATA().split("::::")[0]
                vmpass  = desc.getTag(name="description").getCDATA().split("::::")[1]
                vmname  = desc.getTag(name="name").getCDATA()
                self.log.info("MIGRATION: Virtual machine %s resumed from live migration. Allocating softly." % vmjid)
                self.alloc_for_migration(xmpp.JID(vmjid), vmname, vmpass)
                self.perform_hooks("HOOK_HYPERVISOR_MIGRATEDVM_ARRIVE", vmjid)
            except Exception as ex:
                self.log.warning("MIGRATION: Can't alloc softly this virtual machine. Maybe it is not an archipel VM: %s" % str(ex))


    ### XMPP Processing

    def process_iq(self, conn, iq):
        """
        This method is invoked when a ARCHIPEL_NS_HYPERVISOR_CONTROL IQ is received.
        It understands IQ of type:
            - alloc
            - free
        @type conn: xmpp.Dispatcher
        @param conn: ths instance of the current connection that send the stanza
        @type iq: xmpp.Protocol.Iq
        @param iq: the received IQ
        """
        reply = None
        action = self.check_acp(conn, iq)

        # temp fix to authorize migration
        # We should find a way to authorize
        # hypervisors to ask uri with another way
        if not action in ('uri'):
            self.check_perm(conn, iq, action, -1)

        if action == "alloc":
            reply = self.iq_alloc(iq)
        elif action == "free":
            reply = self.iq_free(iq)
        elif action == "rostervm":
            reply = self.iq_roster(iq)
        elif action == "clone":
            reply = self.iq_clone(iq)
        elif action == "ip":
            reply = self.iq_ip(iq)
        elif action == "uri":
            reply = self.iq_libvirt_uri(iq)
        elif action == "capabilities":
            reply = self.iq_capabilities(iq)

        if reply:
            conn.send(reply)
            raise xmpp.protocol.NodeProcessed


    ###  Hypervisor controls

    def alloc(self, requester=None, requested_name=None, start=True):
        """
        Alloc a new XMPP entity.
        @type requester: xmpp.JID
        @param requester: the JID of the migrated VM to alloc
        @type requested_name: string
        @param requested_name: the requested name for the VM if None, will be generated
        @type start: Boolean
        @param start: if True, start the vm immediatly
        @rtype: L{TNArchipelVirtualMachine} or L{TNThreadedVirtualMachine}
        @return: L{TNArchipelVirtualMachine} if start==True or L{TNThreadedVirtualMachine} if start==False
        """
        vmuuid = str(moduuid.uuid1())
        vm_password = ''.join([random.choice(string.letters + string.digits) for i in range(self.configuration.getint("VIRTUALMACHINE", "xmpp_password_size"))])
        vm_jid = xmpp.JID(node=vmuuid.lower(), domain=self.xmppserveraddr.lower(), resource=self.jid.getNode().lower())
        disallow_spaces_in_name = (self.configuration.has_option("VIRTUALMACHINE", "allow_blank_space_in_vm_name") and not self.configuration.getboolean("VIRTUALMACHINE", "allow_blank_space_in_vm_name"))

        if not requested_name:
            name = self.generate_name()
        else:
            if disallow_spaces_in_name:
                requested_name = requested_name.replace(" ", "-")
            if not self.get_vm_by_name(requested_name):
                name = requested_name
            else:
                raise Exception("This hypervisor already has virtual machine named %s. Please, choose another one." % requested_name)

        if disallow_spaces_in_name:
            name = name.replace(" ", "-")

        self.log.info("Starting xmpp threaded virtual machine.")
        vm_thread = self.create_threaded_vm(vm_jid, vm_password, name)
        vm = vm_thread.get_instance()

        if requester:
            self.log.info("Adding the requesting controller %s to the VM's roster." % (str(requester)))
            vm.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=vm.add_jid_hook, user_info=xmpp.JID(requester), oneshot=True)
            vm.permission_center.grant_permission_to_user("all", requester.getStripped())

        self.log.info("Registering the new VM in hypervisor's database.")
        self.database.execute("insert into virtualmachines values(?,?,?,?,?)", (str(vm_jid.getStripped()), vm_password, datetime.datetime.now(), '', name))
        self.database.commit()
        self.virtualmachines[vmuuid] = vm

        self.update_presence()
        self.log.info("XMPP Virtual Machine instance sucessfully initialized.")
        self.perform_hooks("HOOK_HYPERVISOR_ALLOC", vm)
        self.push_change("hypervisor", "alloc")
        if start:
            vm_thread.start()
            return vm
        else:
            return vm_thread

    def alloc_for_migration(self, jid, name, password):
        """
        Perform light allocation (no registration, no subscription).
        @type jid: xmpp.JID
        @param jid: the JID of the migrated VM to alloc
        @type name: string
        @param name: the name of the migrated VM to alloc
        @type password: string
        @param password: the password of the migrated VM to alloc
        """
        uuid = jid.getNode()

        jid.setResource(self.jid.getNode().lower())
        self.log.info("Starting xmpp threaded virtual machine with incoming jid : %s" % jid)
        vm_thread = self.create_threaded_vm(jid, password, name)
        vm = vm_thread.get_instance()
        vm_thread.start()
        self.log.info("Registering the new VM in hypervisor's database.")
        self.database.execute("insert into virtualmachines values(?,?,?,?,?)", (str(jid.getStripped()), password, datetime.datetime.now(), '', name))
        self.database.commit()
        self.virtualmachines[uuid] = vm

        self.update_presence()
        self.log.info("Migrated XMPP VM is ready.")
        return vm

    def free(self, jid):
        """
        Remove the XMPP container of VM with given jid.
        @type jid: xmpp.JID
        @param jid: the JID of the VM to free
        """
        uuid    = jid.getNode()
        vm      = self.virtualmachines[uuid]

        if vm.is_migrating:
            raise Exception("Virtual machine is migrating. Can't free.")
        if vm.domain and (vm.domain.info()[0] == 1 or vm.domain.info()[0] == 2 or vm.domain.info()[0] == 3):
            vm.domain.destroy()
        if vm.domain:
            vm.domain.undefine()

        self.log.info("Launch %s's terminate method." % jid)
        vm.terminate()

        self.log.info("Unregistering the VM from hypervisor's database.")
        self.database.execute("delete from virtualmachines where jid=?", (jid.getStripped(),))
        self.database.commit()

        del self.virtualmachines[uuid]

        self.log.info("Starting the vm removing procedure.")
        vm.inband_unregistration()
        self.perform_hooks("HOOK_HYPERVISOR_FREE", vm)
        self.log.info("XMPP Virtual Machine %s sucessfully destroyed." % jid)
        self.push_change("hypervisor", "free")
        self.update_presence()

    def free_for_migration(self, jid):
        """
        Perform light free (no removing of account, no unsubscription).
        @type jid: xmpp.JID
        @param jid: the JID of the migrated VM to free
        """
        uuid    = jid.getNode()
        vm      = self.virtualmachines[uuid]

        vm.undefine_and_disconnect()

        self.log.info("Unregistering the VM from hypervisor's database.")
        self.database.execute("delete from virtualmachines where jid='%s'" % jid.getStripped())
        self.database.commit()
        del self.virtualmachines[uuid]
        self.update_presence()

    def clone(self, uuid, requester, wanted_name=None):
        """
        Clone a existing virtual machine.
        @type uuid: string
        @param uuid: the uuid of the VM to clone
        @type requester: xmpp.JID
        @param requester: JID of the requester
        """
        xmppvm = self.get_vm_by_uuid(uuid)
        xmldesc = xmppvm.definition

        if not xmldesc:
            raise Exception('The mother vm has to be defined to be cloned.')

        dominfo = xmppvm.domain.info()
        if not (dominfo[0] == libvirt.VIR_DOMAIN_SHUTOFF or dominfo[0] == libvirt.VIR_DOMAIN_SHUTDOWN):
            raise Exception('The mother vm has to be stopped to be cloned.')

        if not wanted_name:
            name = "%s (clone of %s)" % (self.generate_name(), xmppvm.name)
        else:
            name = wanted_name

        newvm_thread = self.alloc(requester, requested_name=name, start=False)
        newvm = newvm_thread.get_instance()
        newvm.register_hook("HOOK_VM_INITIALIZE",
                            method=newvm.clone,
                            user_info={"definition": xmldesc, "path": xmppvm.folder, "parentuuid": uuid, "parentname": self.name},
                            oneshot=True)
        newvm_thread.start()
        self.perform_hooks("HOOK_HYPERVISOR_CLONE", newvm)
        self.push_change("hypervisor", "clone")

    def get_capabilities(self):
        """
        Return hypervisor's capabilities.
        """
        capp = xmpp.simplexml.NodeBuilder(data=self.libvirt_connection.getCapabilities()).getDom()
        return capp

    def migration_libvirt_uri(self):
        """
        Return the libvirt URI
        """
        if self.configuration.has_option("GLOBAL", "migration_uri"):
            return self.configuration.get("GLOBAL", "migration_uri")
        else:
            return self.local_libvirt_uri.replace("///", "//%s/" % self.ipaddr)


    ###  Hypervisor IQs

    def iq_alloc(self, iq):
        """
        This method creates a threaded L{TNArchipelVirtualMachine} with UUID given
        as payload in IQ and register the hypervisor and the iq sender in
        the VM's roster.
        @type iq: xmpp.Protocol.Iq
        @param iq: the sender request IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready-to-send IQ containing the results
        """
        try:
            try:
                requested_name = iq.getTag("query").getTag("archipel").getAttr("name")
            except:
                requested_name = None
            vm = self.alloc(iq.getFrom(), requested_name=requested_name)
            reply = iq.buildReply("result")
            payload = xmpp.Node("virtualmachine", attrs={"jid": str(vm.jid.getStripped())})
            reply.setQueryPayload([payload])
            self.shout("virtualmachine", "A new Archipel Virtual Machine has been created by %s with uuid %s" % (iq.getFrom(), vm.uuid))
        except libvirt.libvirtError as ex:
            reply = build_error_iq(self, ex, iq, ex.get_error_code(), ns=ARCHIPEL_NS_LIBVIRT_GENERIC_ERROR)
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_ALLOC)
        return reply

    def message_alloc(self, msg):
        """
        Handle the allocation request message.
        @type msg: xmpp.Protocol.Message
        @param msg: the received message
        @rtype: xmpp.Protocol.Message
        @return: a ready to send Message containing the result of the action
        """
        try:
            tokens = msg.getBody().split(None, 1)
            name = None
            if len(tokens) == 2:
                name = tokens[1]
            else:
                name = None
            vm = self.alloc(msg.getFrom(), name)
            return "Archipel VM with name %s has been allocated using JID %s" % (vm.name, vm.jid)
        except Exception as ex:
            return build_error_message(self, ex, msg)

    def iq_alloc_for_migration(self, iq):
        """
        Perform light allocation for handler migrating vm.
        @type iq: xmpp.Protocol.Iq
        @param iq: the sender request IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready-to-send IQ containing the results
        """
        try:
            reply = iq.buildReply("result")
            vmjid = xmpp.JID(iq.getTag("query").getTag("archipel").getAttr("jid"))
            name = iq.getTag("query").getTag("archipel").getAttr("name")
            password = iq.getTag("query").getTag("archipel").getAttr("password")

            self.alloc_for_migration(vmjid, name, password)

            self.push_change("hypervisor", "migrate")
            self.shout("virtualmachine", "The virtual machine %s has been migrated from hypervisor %s" % (vmjid, iq.getFrom()))
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_ALLOC_MIGRATION)
        return reply

    def iq_free(self, iq):
        """
        This method destroy a threaded L{TNArchipelVirtualMachine} with UUID given
        as payload in IQ and remove it from the hypervisor roster.
        @type iq: xmpp.Protocol.Iq
        @param iq: the sender request IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready-to-send IQ containing the results
        """
        reply = iq.buildReply("result")
        try:
            vm_jid      = xmpp.JID(jid=iq.getTag("query").getTag("archipel").getAttr("jid"))
            domain_uuid = vm_jid.getNode()
            self.free(vm_jid)
            reply.setQueryPayload([xmpp.Node(tag="virtualmachine", attrs={"jid": vm_jid})])
            self.shout("virtualmachine", "The Archipel Virtual Machine %s has been destroyed by %s" % (domain_uuid, iq.getFrom()))
        except libvirt.libvirtError as ex:
            reply = build_error_iq(self, ex, iq, ex.get_error_code(), ns=ARCHIPEL_NS_LIBVIRT_GENERIC_ERROR)
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_FREE)
        return reply

    def message_free(self, msg):
        """
        Handle the free request message.
        @type msg: xmpp.Protocol.Message
        @param msg: the received message
        @rtype: xmpp.Protocol.Message
        @return: a ready to send Message containing the result of the action
        """
        try:
            tokens = msg.getBody().split(None, 1)
            if not len(tokens) == 2: return "I'm sorry, you use a wrong format. You can type 'help' to get help"
            identifier = tokens[1]
            vm = self.get_vm_by_identifier(identifier)
            if not vm: return "It seems that vm with identifer %s doesn't exists." % identifier
            self.free(vm.jid)
            return "Archipel VM with JID %s has been freed." % (vm.jid)
        except Exception as ex:
            return build_error_message(self, ex, msg)

    def iq_free_for_migration(self, iq):
        """
        Perform light free for virtual machine migration.
        """
        try:
            reply = iq.buildReply("result")
            vmjid = xmpp.JID(iq.getTag("query").getTag("archipel").getAttr("jid"))
            self.free_for_migration(vmjid)
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_FREE_MIGRATION)
        return reply

    def iq_clone(self, iq):
        """
        Alloc a virtual as a clone of another.
        @type iq: xmpp.Protocol.Iq
        @param iq: the received IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready to send IQ containing the result of the action
        """
        try:
            wanted_name = None
            reply = iq.buildReply("result")
            vmjid = xmpp.JID(jid=iq.getTag("query").getTag("archipel").getAttr("jid"))
            vmuuid = vmjid.getNode()
            if iq.getTag("query").getTag("archipel").getAttr("name"):
                wanted_name = iq.getTag("query").getTag("archipel").getAttr("name")
            self.clone(vmuuid, iq.getFrom(), wanted_name)
            self.shout("virtualmachine", "The Archipel Virtual Machine %s has been cloned by %s" % (vmuuid, iq.getFrom()))
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_CLONE)
        return reply

    def message_clone(self, msg):
        """
        Handle the clone request message.
        @type msg: xmpp.Protocol.Message
        @param msg: the received message
        @rtype: xmpp.Protocol.Message
        @return: a ready to send Message containing the result of the action
        """
        try:
            tokens = msg.getBody().split(None, 1)
            if not len(tokens) == 2: return "I'm sorry, you use a wrong format. You can type 'help' to get help"
            identifier = tokens[1]
            vm = self.get_vm_by_identifier(identifier)
            if not vm: return "It seems that vm with identifer %s doesn't exists." % identifier
            self.clone(vm.uuid, msg.getFrom())
            return "Cloning of virtual machine %s has started." % (vm.jid)
        except Exception as ex:
            return build_error_message(self, ex, msg)

    def iq_roster(self, iq):
        """
        Send the hypervisor roster content.
        @type iq: xmpp.Protocol.Iq
        @param iq: the sender request IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready-to-send IQ containing the results
        """
        try:
            reply = iq.buildReply("result")
            nodes = []
            for uuid, vm in self.virtualmachines.iteritems():
                n = xmpp.Node("item")
                n.addData(vm.jid.getStripped())
                nodes.append(n)
            reply.setQueryPayload(nodes)
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_ROSTER)
        return reply

    def message_roster(self, msg):
        """
        Process the roster message request.
        @type msg: xmpp.Protocol.Message
        @param msg: the received message
        @rtype: xmpp.Protocol.Message
        @return: a ready to send Message containing the result of the action
        """
        try:
            ret = "Here is the content of my roster:\n"
            for uuid, vm in self.virtualmachines.iteritems():
                ret += " - %s (%s)\n" % (vm.name, vm.jid)
            return ret
        except Exception as ex:
            return build_error_message(self, ex, msg)

    def iq_ip(self, iq):
        """
        Send the hypervisor IP address.
        @type iq: xmpp.Protocol.Iq
        @param iq: the sender request IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready-to-send IQ containing the results
        """
        try:
            reply = iq.buildReply("result")
            reply.getTag("query").addChild(name="ip", payload=self.ipaddr)
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_IP)
        return reply

    def message_ip(self, msg):
        """
        Process the IP message request.
        @type msg: xmpp.Protocol.Message
        @param msg: the received message
        @rtype: xmpp.Protocol.Message
        @return: a ready to send Message containing the result of the action
        """
        try:
            return "Sure, my IP is %s" % self.ipaddr
        except Exception as ex:
            return build_error_message(self, ex, msg)

    def iq_libvirt_uri(self, iq):
        """
        Send the hypervisor IP address.
        @type iq: xmpp.Protocol.Iq
        @param iq: the sender request IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready-to-send IQ containing the results
        """
        try:
            network_libvirt_uri = self.migration_libvirt_uri()
            reply = iq.buildReply("result")
            reply.getTag("query").addChild(name="uri", payload=network_libvirt_uri)
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_LIBVIRT_URI)
        return reply

    def message_libvirt_uri(self, msg):
        """
        Process the libvirt URI message request.
        @type msg: xmpp.Protocol.Message
        @param msg: the received message
        @rtype: xmpp.Protocol.Message
        @return: a ready to send Message containing the result of the action
        """
        try:
            return "Sure, my libvirt URI is %s" % self.migration_libvirt_uri()
        except Exception as ex:
            return build_error_message(self, ex, msg)

    def iq_capabilities(self, iq):
        """
        Send the hypervisor capabilities.
        @type iq: xmpp.Protocol.Iq
        @param iq: the sender request IQ
        @rtype: xmpp.Protocol.Iq
        @return: a ready-to-send IQ containing the results
        """
        try:
            reply = iq.buildReply("result")
            reply.setQueryPayload(self.capabilities)
        except Exception as ex:
            reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_HYPERVISOR_CAPABILITIES)
        return reply

    def message_capabilities(self, msg):
        """
        Process the capabilities message request.
        @type msg: xmpp.Protocol.Message
        @param msg: the received message
        @rtype: xmpp.Protocol.Message
        @return: a ready to send Message containing the result of the action
        """
        try:
            return str(self.capabilities)
        except Exception as ex:
            return build_error_message(self, ex, msg)