diff -Nru archipel-agent-vmparking-0.5.0/archipelagentvmparking/vmparking.py archipel-agent-vmparking-0.6.0/archipelagentvmparking/vmparking.py
--- archipel-agent-vmparking-0.5.0/archipelagentvmparking/vmparking.py 2012-11-02 13:54:29.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/archipelagentvmparking/vmparking.py 2013-03-21 00:58:52.000000000 +0000
@@ -21,23 +21,30 @@
import datetime
import os
+import random
import shutil
+import sqlite3
+import string
import xmpp
from archipel.archipelHypervisor import TNArchipelHypervisor
from archipel.archipelVirtualMachine import TNArchipelVirtualMachine
from archipelcore.archipelPlugin import TNArchipelPlugin
-from archipelcore.pubsub import TNPubSubNode
from archipelcore.utils import build_error_iq, build_error_message
-ARCHIPEL_ERROR_CODE_VMPARK_LIST = -11001
-ARCHIPEL_ERROR_CODE_VMPARK_PARK = -11002
-ARCHIPEL_ERROR_CODE_VMPARK_UNPARK = -11003
-ARCHIPEL_ERROR_CODE_VMPARK_DELETE = -11004
-ARCHIPEL_ERROR_CODE_VMPARK_UPDATEXML = -11004
+ARCHIPEL_ERROR_CODE_VMPARK_LIST = -11001
+ARCHIPEL_ERROR_CODE_VMPARK_PARK = -11002
+ARCHIPEL_ERROR_CODE_VMPARK_UNPARK = -11003
+ARCHIPEL_ERROR_CODE_VMPARK_DELETE = -11004
+ARCHIPEL_ERROR_CODE_VMPARK_UPDATEXML = -11004
+ARCHIPEL_ERROR_CODE_VMPARK_CREATE_PARKED = -11005
ARCHIPEL_NS_HYPERVISOR_VMPARKING = "archipel:hypervisor:vmparking"
-ARCHIPEL_NS_VM_VMPARKING = "archipel:vm:vmparking"
+ARCHIPEL_NS_VM_VMPARKING = "archipel:vm:vmparking"
+
+ARCHIPEL_PARKING_STATUS_NOT_PARKED = 0
+ARCHIPEL_PARKING_STATUS_PARKED = 1
+ARCHIPEL_PARKING_STATUS_STATE_CHANGING = 2
class TNVMParking (TNArchipelPlugin):
@@ -52,8 +59,6 @@
@param entry_point_group: the group name of plugin entry_point
"""
TNArchipelPlugin.__init__(self, configuration=configuration, entity=entity, entry_point_group=entry_point_group)
- self.pubsub_vmparking = None;
- self.inhibit_next_general_push = None
# creates permissions
self.entity.permission_center.create_permission("vmparking_park", "Authorizes user to park a virtual machines", False)
@@ -63,6 +68,7 @@
self.entity.permission_center.create_permission("vmparking_unpark", "Authorizes user to unpark a virtual machines", False)
self.entity.permission_center.create_permission("vmparking_delete", "Authorizes user to delete parked virtual machines", False)
self.entity.permission_center.create_permission("vmparking_updatexml", "Authorizes user to delete parked virtual machines", False)
+ self.entity.permission_center.create_permission("vmparking_create_parked", "Authorizes user to create a new VM in parking", False)
# vocabulary
if isinstance(self.entity, TNArchipelHypervisor):
@@ -94,10 +100,39 @@
self.entity.add_message_registrar_items(registrar_items)
- # register to the node vmrequest
+ # register to the node parking and create database if needed
if isinstance(self.entity, TNArchipelHypervisor):
- self.entity.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=self.manage_vmparking_node)
+ self.manage_database()
+
+ if self.entity.__class__.__name__ == "TNArchipelVirtualMachine":
+ self.entity.register_hook("HOOK_VM_DEFINE", method=self.hook_vm_define)
+ self.entity.register_hook("HOOK_VM_UNDEFINE", method=self.hook_vm_undefine)
+ ### Hooks
+ def hook_vm_define(self, origin=None, user_info=None, arguments=None):
+ """
+ Called when a VM definition occurs.
+ This will insert the XML desc in the parking
+ """
+ hypervisor_parking_plugin = self.entity.hypervisor.get_plugin("vmparking")
+ xmldesc = self.entity.xmldesc(mask_description=False)
+
+ if not hypervisor_parking_plugin.is_vm_registered(self.entity.uuid):
+ vms_info = [{"uuid": self.entity.uuid, "domain": str(xmldesc), "parker": "nobody", "status": ARCHIPEL_PARKING_STATUS_NOT_PARKED, "creation_date": datetime.datetime.now()}]
+ hypervisor_parking_plugin.register_vms_into_db(vms_info)
+ else:
+ hypervisor_parking_plugin.update_vm_domain_in_db(self.entity.uuid, xmldesc)
+
+ def hook_vm_undefine(self, origin=None, user_info=None, arguments=None):
+ """
+ Called when a VM definition occurs.
+ This will insert the XML desc in the parking
+ """
+ hypervisor_parking_plugin = self.entity.hypervisor.get_plugin("vmparking")
+
+ if hypervisor_parking_plugin.is_vm_registered(self.entity.uuid):
+ if not hypervisor_parking_plugin.is_vm_parked(self.entity.uuid):
+ hypervisor_parking_plugin.unregister_vms_from_db([{"uuid": self.entity.uuid}])
### Plugin interface
@@ -121,76 +156,50 @@
self.entity.xmppclient.UnregisterHandler('iq', self.process_iq_for_vm, ns=ARCHIPEL_NS_VM_VMPARKING)
- @staticmethod
- def plugin_info():
+ ### Database Management
+
+ def manage_database(self):
"""
- Return informations about the plugin.
- @rtype: dict
- @return: dictionary contaning plugin informations
+ Create and / or recover the parking database
"""
- plugin_friendly_name = "Virtual Machine Parking"
- plugin_identifier = "vmparking"
- plugin_configuration_section = None
- plugin_configuration_tokens = []
- return { "common-name" : plugin_friendly_name,
- "identifier" : plugin_identifier,
- "configuration-section" : plugin_configuration_section,
- "configuration-tokens" : plugin_configuration_tokens }
-
-
+ self.database = sqlite3.connect(self.configuration.get("VMPARKING", "database"), check_same_thread=False)
+ self.database.row_factory = sqlite3.Row
+ self.database.execute("create table if not exists parking (uuid text unique, parker string, creation_date date, domain string, status int)")
+ self.database.commit()
- ### Pubsub management
-
- def manage_vmparking_node(self, origin, user_info, arguments):
+ def register_vms_into_db(self, vm_informations):
"""
- Register to pubsub event node /archipel/platform/requests/in
- and /archipel/platform/requests/out
- @type origin: L{TNArchipelEnity}
- @param origin: the origin of the hook
- @type user_info: object
- @param user_info: random user information
- @type arguments: object
- @param arguments: runtime argument
+ Add a VM in the parking
+ @type vm_informations: list
+ @param vm_informations: list of dict containing {"uuid": x, "parker": y, "creation_date": z, "status": s}
"""
- nodeVMParkingName = "/archipel/vmparking"
- self.entity.log.info("VMPARKING: getting the pubsub node %s" % nodeVMParkingName)
- self.pubsub_vmparking = TNPubSubNode(self.entity.xmppclient, self.entity.pubsubserver, nodeVMParkingName)
- self.pubsub_vmparking.recover(wait=True)
- self.entity.log.info("VMPARKING: node %s recovered." % nodeVMParkingName)
- self.pubsub_vmparking.subscribe(self.entity.jid, self._handle_request_event, wait=True)
- self.entity.log.info("VMPARKING: entity %s is now subscribed to events from node %s" % (self.entity.jid, nodeVMParkingName))
+ self.database.executemany("insert into parking values(:uuid, :parker, :creation_date, :domain, :status)", vm_informations)
+ self.database.commit()
- def _handle_request_event(self, event):
+ def unregister_vms_from_db(self, vms_uuid):
"""
- Triggered when a platform wide virtual machine request is received.
- @type event: xmpp.Node
- @param event: the push event
+ Add a VM in the parking
+ @type vm_informations: list
+ @param vm_informations: list of dict containing {"uuid": x}
"""
- self.entity.log.debug("VMPARKING: received pubsub event")
- if not self.inhibit_next_general_push:
- self.entity.push_change("vmparking", "external-update")
- self.inhibit_next_general_push = False
-
-
+ self.database.executemany("delete from parking where uuid=:uuid", vms_uuid)
+ self.database.commit()
- ### Utilities
-
- def get_ticket_from_uuid(self, uuid):
+ def is_vm_registered(self, uuid):
"""
- parse the parked vm to find the ticket of the given uuid
+ Check if vm with given UUID is already in DB
@type uuid: String
@param uuid: the UUID of the vm
- @rtype: String
- @return: pubsub item id
+ @rtype: Boolean
+ @return: True is vm is already in park
"""
- items = self.pubsub_vmparking.get_items()
- for item in items:
- domain = item.getTag("virtualmachine").getTag("domain")
- if domain.getTag("uuid").getData() == uuid:
- return item.getAttr("id")
- return None
+ rows = self.database.execute("select uuid from parking where uuid=?", (uuid,))
+ n = rows.fetchone()
+ if n and n[0] > 1:
+ return True
+ return False
- def is_vm_already_parked(self, uuid):
+ def is_vm_parked(self, uuid):
"""
Check if vm with given UUID is already parked
@type uuid: String
@@ -198,10 +207,75 @@
@rtype: Boolean
@return: True is vm is already in park
"""
- if self.get_ticket_from_uuid(uuid):
+ rows = self.database.execute("select uuid from parking where uuid=? and status=?", (uuid, ARCHIPEL_PARKING_STATUS_PARKED))
+ n = rows.fetchone()
+ if n and n[0] > 1:
return True
return False
+ def get_vm_by_uuid_from_db(self, uuid):
+ """
+ Get a VM from the parking
+ @type uuid: String
+ @param uuid: The UUID of the VM
+ @rtype: dict
+ @return: dict like {"uuid": x, "parker": y, "date": z, "status": s, "domain": d}
+ """
+ rows = self.database.execute("select * from parking where uuid=?", (uuid,))
+ if not rows:
+ return None
+ row = rows.fetchone()
+ return {"uuid": row[0], "parker": row[1], "date": row[2], "status": row[4], "domain": xmpp.simplexml.NodeBuilder(data=row[3]).getDom()}
+
+ def get_all_vms_from_db(self):
+ """
+ Return all vms in parkings
+ @rtype: list
+ @return: list containing dict like {"uuid": x, "parker": y, "date": z, "status": s, "domain": d}
+ """
+ rows = self.database.execute("select * from parking where status=?", (ARCHIPEL_PARKING_STATUS_PARKED,))
+ ret = []
+ for row in rows:
+ ret.append({"uuid": row[0], "parker": row[1], "date": row[2], "status": row[4], "domain": xmpp.simplexml.NodeBuilder(data=row[3]).getDom()})
+ return ret
+
+ def update_vm_domain_in_db(self, uuid, new_domain):
+ """
+ Update the domain of a parked virtual machine
+ @type uuid: string
+ @param uuid: the UUID of the parked VM to update
+ """
+ self.database.execute("update parking set domain=? where uuid=?", (str(new_domain).replace('xmlns=\"archipel:hypervisor:vmparking\"', ''), uuid))
+ self.database.commit()
+
+ def set_vms_status(self, vm_informations):
+ """
+ Set the status of the parking
+ @type vm_informations: list
+ @param vm_informations: list of dict containing {"uuid": x, "parker": y, "status": z}
+ """
+ self.database.executemany("update parking set status=:status, parker=:parker where uuid=:uuid", vm_informations)
+ self.database.commit()
+
+
+ ### Plugin information
+
+ @staticmethod
+ def plugin_info():
+ """
+ Return informations about the plugin.
+ @rtype: dict
+ @return: dictionary contaning plugin informations
+ """
+ plugin_friendly_name = "Virtual Machine Parking"
+ plugin_identifier = "vmparking"
+ plugin_configuration_section = "VMPARKING"
+ plugin_configuration_tokens = ["database"]
+ return {"common-name": plugin_friendly_name,
+ "identifier": plugin_identifier,
+ "configuration-section": plugin_configuration_section,
+ "configuration-tokens": plugin_configuration_tokens}
+
### Processing function
@@ -217,146 +291,125 @@
@rtype: Array
@return: listinformations about virtual machines.
"""
- nodes = self.pubsub_vmparking.get_items()
+ vms = self.get_all_vms_from_db()
ret = []
- for node in nodes:
- domain = xmpp.Node(node=node.getTag("virtualmachine").getTag("domain"))
- ret.append({"info":
- {"itemid": node.getAttr("id"),
- "parker": node.getTag("virtualmachine").getAttr("parker"),
- "date": node.getTag("virtualmachine").getAttr("date")},
- "domain": domain})
+ for vm in vms:
+ ret.append({"info": {"uuid": vm["uuid"], "parker": vm["parker"], "date": vm["date"]}, "domain": vm["domain"]})
+
def sorting(a, b):
return cmp(a["domain"].getTag("name").getData(), b["domain"].getTag("name").getData())
+
ret.sort(sorting)
return ret
- def park(self, uuid, parker_jid, force=False):
+ def park(self, vm_informations):
"""
Park a virtual machine
- @type uuid: String
- @param uuid: the UUID of the virtual machine to park
- @type force: Boolean
- @param force: if True, the machine will be destroyed if running
- """
- if self.is_vm_already_parked(uuid):
- raise Exception("VM with UUID %s is already parked" % uuid)
-
- vm = self.entity.get_vm_by_uuid(uuid)
- if not vm:
- raise Exception("No virtual machine with UUID %s" % uuid)
- if not vm.domain:
- raise Exception("VM with UUID %s cannot be parked because it is not defined" % uuid)
- if not vm.info()["state"] == 5:
- if not force:
- raise Exception("VM with UUID %s cannot be parked because it is running" % uuid)
- else:
+ @type vm_informations: list
+ @param vm_informations: list of dict like {"uuid": x, "status": y, "parker": z)}
+ """
+ vm_informations_cleaned = []
+ for vm_info in vm_informations:
+ if self.is_vm_parked(vm_info["uuid"]):
+ self.entity.log.error("VMPARKING: VM with UUID %s is already parked" % vm_info["uuid"])
+ continue
+
+ vm = self.entity.get_vm_by_uuid(vm_info["uuid"])
+ if not vm:
+ self.entity.log.error("VMPARKING: No virtual machine with UUID %s" % vm_info["uuid"])
+ continue
+ if not vm.domain:
+ self.entity.log.error("VMPARKING: VM with UUID %s cannot be parked because it is not defined" % vm_info["uuid"])
+ continue
+ vm_informations_cleaned.append(vm_info)
+
+ # Now, perform operations
+ for vm_info in vm_informations_cleaned:
+ vm = self.entity.get_vm_by_uuid(vm_info["uuid"])
+ if not vm.info()["state"] == 5:
vm.destroy()
+ domain = vm.xmldesc(mask_description=False)
+ vm_jid = xmpp.JID(domain.getTag("description").getData().split("::::")[0])
+ self.set_vms_status([vm_info])
+ self.entity.soft_free(vm_jid)
+ self.entity.push_change("vmparking", "parked")
- domain = vm.xmldesc(mask_description=False)
- vm_jid = xmpp.JID(domain.getTag("description").getData().split("::::")[0])
-
- def publish_success(resp):
- if resp.getType() == "result":
- self.entity.soft_free(vm_jid)
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "parked")
- self.entity.log.info("VMPARKING: successfully parked %s" % str(vm_jid))
- else:
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "cannot-park", content_node=resp)
- self.entity.log.error("VMPARKING: cannot park: %s" % str(resp))
-
- vmparkednode = xmpp.Node(tag="virtualmachine", attrs={ "parker": parker_jid.getStripped(),
- "date": datetime.datetime.now(),
- "origin": self.entity.jid.getStripped().lower()})
- vmparkednode.addChild(node=domain)
- self.pubsub_vmparking.add_item(vmparkednode, callback=publish_success)
- self.entity.log.info("VMPARKING: virtual machine %s as been parked" % uuid)
-
- def unpark(self, identifier, start=False):
+ def unpark(self, vm_informations):
"""
Unpark virtual machine
- @type identifier: String
- @param identifier: the UUID of a VM or the pubsub ID (parking ticket)
- @type start: Boolean
- @param start: if True, the virtual machine will start after unparking
- """
- ticket = self.get_ticket_from_uuid(identifier)
- if not ticket:
- ticket = identifier
- vm_item = self.pubsub_vmparking.get_item(ticket)
- if not vm_item:
- raise Exception("There is no virtual machine parked with ticket %s" % ticket)
-
- def retract_success(resp, user_info):
- if resp.getType() == "result":
- domain = vm_item.getTag("virtualmachine").getTag("domain")
- ret = str(domain).replace('xmlns=\"archipel:hypervisor:vmparking\"', '')
- domain = xmpp.simplexml.NodeBuilder(data=ret).getDom()
- vmjid = domain.getTag("description").getData().split("::::")[0]
- vmpass = domain.getTag("description").getData().split("::::")[1]
- vmname = domain.getTag("name").getData()
- vm_thread = self.entity.soft_alloc(xmpp.JID(vmjid), vmname, vmpass, start=False)
- vm = vm_thread.get_instance()
- vm.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=vm.define_hook, user_info=domain, oneshot=True)
- if start:
- vm.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=vm.control_create_hook, oneshot=True)
- vm_thread.start()
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "unparked")
- self.entity.log.info("VMPARKING: successfully unparked %s" % str(vmjid))
+ @type vm_informations: list
+ @param vm_informations: list of dict like {"uuid": x, "status": y, "start": True|False, "parker": z}
+ """
+ vm_informations_cleaned = []
+ # First, check if everything is correct and cleanup bad items
+ for vm_info in vm_informations:
+ if self.is_vm_parked(vm_info["uuid"]):
+ vm_informations_cleaned.append(vm_info)
else:
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "cannot-unpark", content_node=resp)
- self.entity.log.error("VMPARKING: cannot unpark: %s" % str(resp))
- self.pubsub_vmparking.remove_item(ticket, callback=retract_success)
+ self.entity.log.error("VMPARKING: There is no virtual machine parked with uuid %s" % vm_info["uuid"])
+
+ # Now, perform operations
+ for vm_info in vm_informations_cleaned:
+ vm_item = self.get_vm_by_uuid_from_db(vm_info["uuid"])
+ domain = vm_item["domain"]
+ ret = str(domain).replace('xmlns=\"archipel:hypervisor:vmparking\"', '')
+ domain = xmpp.simplexml.NodeBuilder(data=ret).getDom()
+ vmjid = domain.getTag("description").getData().split("::::")[0]
+ vmpass = domain.getTag("description").getData().split("::::")[1]
+ vmname = domain.getTag("name").getData()
+ vm_thread = self.entity.soft_alloc(xmpp.JID(vmjid), vmname, vmpass, start=False, organizationInfo=self.entity.vcard_infos)
+ vm = vm_thread.get_instance()
+ vm.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=vm.define_hook, user_info=domain, oneshot=True)
+ if vm_info["start"]:
+ vm.register_hook("HOOK_ARCHIPELENTITY_XMPP_AUTHENTICATED", method=vm.control_create_hook, oneshot=True)
+ vm_thread.start()
+ self.set_vms_status([vm_info])
+
+ self.entity.push_change("vmparking", "unparked")
+ self.entity.log.info("VMPARKING: successfully unparked %s" % str(vmjid))
- def delete(self, identifier):
+ def delete(self, vm_uuids):
"""
Delete a parked virtual machine
- @type identifier: String
- @param identifier: the UUID of a parked VM or the pubsub ID (parking ticket)
+ @type vm_uuids: list
+ @param uuid: list of dic like {"uuid": x}
"""
- ticket = self.get_ticket_from_uuid(identifier)
- if not ticket:
- ticket = identifier
- vm_item = self.pubsub_vmparking.get_item(ticket)
- if not vm_item:
- raise Exception("There is no virtual machine parked with ticket %s" % ticket)
-
- def retract_success(resp, user_info):
- if resp.getType() == "result":
- vmjid = xmpp.JID(vm_item.getTag("virtualmachine").getTag("domain").getTag("description").getData().split("::::")[0])
- vmfolder = "%s/%s" % (self.configuration.get("VIRTUALMACHINE", "vm_base_path"), vmjid.getNode())
- if os.path.exists(vmfolder):
- shutil.rmtree(vmfolder)
- self.entity.get_plugin("xmppserver").users_unregister([vmjid])
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "deleted")
- self.entity.log.info("VMPARKING: successfully deleted %s from parking" % str(vmjid))
- else:
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "cannot-delete", content_node=resp)
- self.entity.log.error("VMPARKING: cannot delete: %s" % str(resp))
- self.pubsub_vmparking.remove_item(ticket, callback=retract_success)
+ vm_jids = []
+ # first, check there is no problems
+ for vm_uuid in vm_uuids:
+ if not self.is_vm_parked(vm_uuid["uuid"]):
+ raise Exception("There is no virtual machine parked with uuid %s" % vm_uuid["uuid"])
+ vm_item = self.get_vm_by_uuid_from_db(vm_uuid["uuid"])
+ vm_jids.append(xmpp.JID(vm_item["domain"].getTag("description").getData().split("::::")[0]))
+
+ # Update DB and Push
+ self.unregister_vms_from_db(vm_uuids)
+ self.entity.push_change("vmparking", "deleted")
+
+ # Then perfom cleanup operations
+ for vm_jid in vm_jids:
+ vmfolder = "%s/%s" % (self.configuration.get("VIRTUALMACHINE", "vm_base_path"), vm_jid.getNode())
+ if os.path.exists(vmfolder):
+ shutil.rmtree(vmfolder)
+
+ # And remove the XMPP account
+ self.entity.get_plugin("xmppserver").users_unregister(vm_jids)
+ self.entity.log.info("VMPARKING: successfully deleted %s from parking" % str(vm_jids))
- def updatexml(self, identifier, domain):
+ def updatexml(self, uuid, domain):
"""
Update the domain XML of a parked VM
- @type identifier: String
- @param identifier: the pubsub ID (parking ticket) or the VM UUID
+ @type uuid: String
+ @param uuid: the VM UUID
@type domain: xmpp.Node
@param domain: the new XML description
"""
- ticket = self.get_ticket_from_uuid(identifier)
- if not ticket:
- ticket = identifier
- vm_item = self.pubsub_vmparking.get_item(ticket)
- if not vm_item:
- raise Exception("There is no virtual machine parked with ticket %s" % ticket)
+ if not self.is_vm_parked(uuid):
+ raise Exception("There is no virtual machine parked with uuid %s" % uuid)
+
+ vm_item = self.get_vm_by_uuid_from_db(uuid)
- old_domain = vm_item.getTag("virtualmachine").getTag("domain")
+ old_domain = vm_item["domain"]
previous_uuid = old_domain.getTag("uuid").getData()
previous_name = old_domain.getTag("name").getData()
new_uuid = domain.getTag("uuid").getData()
@@ -374,21 +427,33 @@
if domain.getTag('description'):
domain.delChild("description")
domain.addChild(node=old_domain.getTag("description"))
- vm_item.getTag("virtualmachine").delChild("domain")
- vm_item.getTag("virtualmachine").addChild(node=domain)
+ self.update_vm_domain_in_db(uuid, domain)
+ self.entity.push_change("vmparking", "updated")
- def publish_success(resp):
- if resp.getType() == "result":
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "updated")
- self.pubsub_vmparking.remove_item(ticket)
- self.entity.log.info("VMPARKING: virtual machine %s as been updated" % new_uuid)
- else:
- self.inhibit_next_general_push = True
- self.entity.push_change("vmparking", "cannot-update", content_node=resp)
- self.entity.log.error("VMPARKING: unable to update item for virtual machine %s: %s" % (new_uuid, resp))
- self.pubsub_vmparking.add_item(vm_item.getTag("virtualmachine"), callback=publish_success)
+ def create_parked(self, vm_informations):
+ """
+ Creates a VM directly into the parking.
+ @type vm_informations: list
+ @param vm_informations: list containing VM to park [{"uuid": x, domain: y, parker: x, creation_date: d, status: s}]
+ """
+ for vm_info in vm_informations:
+ if self.is_vm_parked(vm_info["uuid"]):
+ raise Exception("VM with UUID %s is already parked" % vm_info["uuid"])
+
+ vm = self.entity.get_vm_by_uuid(vm_info["uuid"])
+ if vm:
+ raise Exception("There is already a VM with UUID %s" % vm_info["uuid"])
+
+ if vm_info["domain"].getTag("description"):
+ raise Exception("You cannot park a VM XML with a tag. Please remove it")
+
+ password = ''.join([random.choice(string.letters + string.digits) for i in range(32)])
+ vm_info["domain"].addChild("description").setData("%s@%s::::%s" % (vm_info["uuid"], self.entity.jid.getDomain(), password))
+ vm_info["domain"] = str(vm_info["domain"]).replace('xmlns=\"archipel:hypervisor:vmparking\"', '')
+
+ self.register_vms_into_db(vm_informations)
+ self.entity.push_change("vmparking", "parked")
### XMPP Management for hypervisors
@@ -399,6 +464,7 @@
It understands IQ of type:
- list
- park
+ - create_parked
- unpark
- destroy
- updatexml
@@ -420,6 +486,8 @@
reply = self.iq_delete(iq)
if action == "updatexml":
reply = self.iq_updatexml(iq)
+ if action == "create_parked":
+ reply = self.iq_create_parked(iq)
if reply:
conn.send(reply)
raise xmpp.protocol.NodeProcessed
@@ -480,15 +548,17 @@
"""
try:
items = iq.getTag("query").getTag("archipel").getTags("item")
+ vms_info = []
for item in items:
vm_uuid = item.getAttr("uuid")
if not vm_uuid:
self.entity.log.error("VMPARKING: Unable to park vm: missing 'uuid' element.")
raise Exception("You must must set the UUID of the vms you want to park")
- force_destroy = False
- if item.getAttr("force") and item.getAttr("force").lower() in ("yes", "y", "true", "1"):
- force_destroy = True
- self.park(vm_uuid, iq.getFrom(), force=force_destroy)
+
+ vms_info.append({"uuid": vm_uuid, "status": ARCHIPEL_PARKING_STATUS_PARKED, "parker": str(iq.getFrom())})
+
+ self.park(vms_info)
+
reply = iq.buildReply("result")
except Exception as ex:
reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_VMPARK_PARK)
@@ -507,8 +577,12 @@
if len(tokens) < 2:
return "I'm sorry, you use a wrong format. You can type 'help' to get help."
uuids = tokens[1].split(",")
+ vms_info = []
for vmuuid in uuids:
- self.park(vmuuid, msg.getFrom())
+ vms_info.append({"uuid": vmuuid, "status": ARCHIPEL_PARKING_STATUS_PARKED, "parker": str(msg.getFrom())})
+
+ self.park(vms_info)
+
if len(uuids) == 1:
return "Virtual machine is parking."
else:
@@ -527,12 +601,16 @@
try:
reply = iq.buildReply("result")
items = iq.getTag("query").getTag("archipel").getTags("item")
+ vms_info = []
for item in items:
identifier = item.getAttr("identifier")
autostart = False
if item.getAttr("start") and item.getAttr("start").lower() in ("yes", "y", "true", "1"):
autostart = True
- self.unpark(identifier, start=autostart)
+ vms_info.append({"uuid": identifier, "status": ARCHIPEL_PARKING_STATUS_NOT_PARKED, "start": autostart, "parker": str(iq.getFrom())})
+
+ self.unpark(vms_info)
+
except Exception as ex:
reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_VMPARK_UNPARK)
return reply
@@ -550,8 +628,12 @@
if len(tokens) < 2:
return "I'm sorry, you use a wrong format. You can type 'help' to get help."
itemids = tokens[1].split(",")
+ vms_info = []
for itemid in itemids:
- self.unpark(itemid)
+ vms_info.append({"uuid": itemid, "start": False, "status": ARCHIPEL_PARKING_STATUS_NOT_PARKED, "parker": str(msg.getFrom())})
+
+ self.unpark(vms_info)
+
if len(itemids) == 1:
return "Virtual machine is unparking."
else:
@@ -570,9 +652,13 @@
try:
reply = iq.buildReply("result")
items = iq.getTag("query").getTag("archipel").getTags("item")
+ vm_uuids = []
+
for item in items:
- identifier = item.getAttr("identifier")
- self.delete(identifier)
+ vm_uuids.append({"uuid": item.getAttr("identifier")})
+
+ self.delete(vm_uuids)
+
except Exception as ex:
reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_VMPARK_DELETE)
return reply
@@ -594,6 +680,32 @@
reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_VMPARK_UPDATEXML)
return reply
+ def iq_create_parked(self, iq):
+ """
+ Create a VM in directly into the parking
+ @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:
+ items = iq.getTag("query").getTag("archipel").getTags("item")
+ vms_info = []
+ for item in items:
+ vm_uuid = item.getAttr("uuid")
+ if not vm_uuid:
+ self.entity.log.error("VMPARKING: Unable to park vm: missing 'uuid' element.")
+ raise Exception("You must must set the UUID of the vms you want to park")
+ vm_domain = item.getTag("domain")
+ vms_info.append({"uuid": vm_uuid, "domain": vm_domain, "parker": str(iq.getFrom()), "creation_date": datetime.datetime.now(), "status": ARCHIPEL_PARKING_STATUS_PARKED})
+
+ self.create_parked(vms_info)
+
+ reply = iq.buildReply("result")
+ except Exception as ex:
+ reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_VMPARK_CREATE_PARKED)
+ return reply
+
## XMPP Management for hypervisors
@@ -626,7 +738,8 @@
"""
try:
reply = iq.buildReply("result")
- self.entity.hypervisor.get_plugin("vmparking").park(self.entity.uuid, iq.getFrom())
+ vms_info = [{"uuid": self.entity.uuid, "status": ARCHIPEL_PARKING_STATUS_PARKED, "parker": str(iq.getFrom())}]
+ self.entity.hypervisor.get_plugin("vmparking").park(vms_info)
except Exception as ex:
reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_VMPARK_PARK)
return reply
@@ -643,7 +756,8 @@
tokens = msg.getBody().split()
if not len(tokens) == 1:
return "I'm sorry, you use a wrong format. You can type 'help' to get help."
- self.entity.hypervisor.get_plugin("vmparking").park(self.entity.uuid, msg.getFrom())
+ vms_info = [{"uuid": self.entity.uuid, "status": ARCHIPEL_PARKING_STATUS_PARKED, "parker": str(msg.getFrom())}]
+ self.entity.hypervisor.get_plugin("vmparking").park(vms_info)
return "I'm parking."
except Exception as ex:
return build_error_message(self, ex, msg)
diff -Nru archipel-agent-vmparking-0.5.0/debian/changelog archipel-agent-vmparking-0.6.0/debian/changelog
--- archipel-agent-vmparking-0.5.0/debian/changelog 2012-11-02 20:38:59.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/debian/changelog 2013-05-05 08:56:32.000000000 +0000
@@ -1,3 +1,11 @@
+archipel-agent-vmparking (0.6.0-1) unstable; urgency=low
+
+ * New upstream beta release.
+ * New maintainer (closes: #704318).
+ * Add watch file.
+
+ -- Laszlo Boszormenyi (GCS) Tue, 30 Apr 2013 07:49:15 +0000
+
archipel-agent-vmparking (0.5.0-1) unstable; urgency=low
* Initial release.
diff -Nru archipel-agent-vmparking-0.5.0/debian/clean archipel-agent-vmparking-0.6.0/debian/clean
--- archipel-agent-vmparking-0.5.0/debian/clean 1970-01-01 00:00:00.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/debian/clean 2013-05-05 09:04:28.000000000 +0000
@@ -0,0 +1 @@
+archipel_agent_vmparking.egg-info/*
diff -Nru archipel-agent-vmparking-0.5.0/debian/control archipel-agent-vmparking-0.6.0/debian/control
--- archipel-agent-vmparking-0.5.0/debian/control 2012-11-02 20:38:44.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/debian/control 2013-04-30 07:50:08.000000000 +0000
@@ -1,7 +1,7 @@
Source: archipel-agent-vmparking
Section: python
Priority: optional
-Maintainer: Daniel Baumann
+Maintainer: Laszlo Boszormenyi (GCS)
Build-Depends: debhelper (>= 9), python, python-setuptools
Standards-Version: 3.9.4
Homepage: http://archipelproject.org/
diff -Nru archipel-agent-vmparking-0.5.0/debian/copyright archipel-agent-vmparking-0.6.0/debian/copyright
--- archipel-agent-vmparking-0.5.0/debian/copyright 2012-11-02 20:38:46.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/debian/copyright 2013-05-05 08:57:37.000000000 +0000
@@ -9,7 +9,8 @@
License: AGPL-3+
Files: debian/*
-Copyright: 2012 Daniel Baumann
+Copyright: 2013 Laszlo Boszormenyi (GCS) ,
+ 2012 Daniel Baumann
License: AGPL-3+
License: AGPL-3+
diff -Nru archipel-agent-vmparking-0.5.0/debian/watch archipel-agent-vmparking-0.6.0/debian/watch
--- archipel-agent-vmparking-0.5.0/debian/watch 1970-01-01 00:00:00.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/debian/watch 2013-05-05 08:56:24.000000000 +0000
@@ -0,0 +1,3 @@
+version=3
+opts="uversionmangle=s/(\d[\.\d]*)/0.$1.0/" \
+https://github.com/ArchipelProject/Archipel/tags .*/@beta(\d[\.\d]*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz))
diff -Nru archipel-agent-vmparking-0.5.0/install/bin/archipel-vmparkingnode archipel-agent-vmparking-0.6.0/install/bin/archipel-vmparkingnode
--- archipel-agent-vmparking-0.5.0/install/bin/archipel-vmparkingnode 2012-11-02 13:54:29.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/install/bin/archipel-vmparkingnode 1970-01-01 00:00:00.000000000 +0000
@@ -1,213 +0,0 @@
-#!/usr/bin/python -W ignore::DeprecationWarning
-#
-# archipel-vmrequestnode
-#
-# Copyright (C) 2010 Antoine Mercadal
-# 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 .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)
\ No newline at end of file
diff -Nru archipel-agent-vmparking-0.5.0/setup.py archipel-agent-vmparking-0.6.0/setup.py
--- archipel-agent-vmparking-0.5.0/setup.py 2012-11-02 13:54:29.000000000 +0000
+++ archipel-agent-vmparking-0.6.0/setup.py 2013-03-21 00:58:52.000000000 +0000
@@ -17,7 +17,7 @@
from setuptools import setup, find_packages
-VERSION = '0.5.0'
+VERSION = '0.6.0'
AUTHOR = 'Antoine Mercadal'
MAIL = 'antoine.mercadal@archipelproject.org'
@@ -74,10 +74,7 @@
include_package_data=True,
zip_safe=False,
install_requires=[
- "archipel-core>=0.5.0beta"
+ "archipel-core>=0.6.0beta"
],
- entry_points=ENTRY_POINTS,
- scripts = [
- 'install/bin/archipel-vmparkingnode',
- ]
- )
\ No newline at end of file
+ entry_points=ENTRY_POINTS
+ )