From 08399c57328760129f5a1e1381ca724f6c7bc588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= Date: Tue, 19 Feb 2013 15:21:33 +0100 Subject: [PATCH] Feature #1224: New method one.vm.snapshotcreate --- include/DispatchManager.h | 14 +++ include/LifeCycleManager.h | 6 + include/RequestManagerVirtualMachine.h | 17 +++ include/VirtualMachine.h | 32 ++++++ include/VirtualMachineManager.h | 9 +- include/VirtualMachineManagerDriver.h | 13 +++ src/dm/DispatchManagerActions.cc | 58 ++++++++++ src/lcm/LifeCycleManager.cc | 16 +++ src/lcm/LifeCycleStates.cc | 60 ++++++++++ src/rm/RequestManager.cc | 2 + src/rm/RequestManagerVirtualMachine.cc | 42 +++++++ src/vm/VirtualMachine.cc | 147 +++++++++++++++++++++++++ src/vmm/VirtualMachineManager.cc | 85 ++++++++++++++ src/vmm/VirtualMachineManagerDriver.cc | 29 ++++- 14 files changed, 528 insertions(+), 2 deletions(-) diff --git a/include/DispatchManager.h b/include/DispatchManager.h index dfa9bff0a6..3f1ae9e5d2 100644 --- a/include/DispatchManager.h +++ b/include/DispatchManager.h @@ -276,6 +276,20 @@ public: int disk_id, string& error_str); + /** + * Starts the snapshot create action + * + * @param vid VirtualMachine identification + * @param name Name for the new snapshot + * @param error_str Error reason, if any + * + * @return 0 on success, -1 otherwise + */ + int snapshot_create( + int vid, + string& name, + string& error_str); + private: /** * Thread id for the Dispatch Manager diff --git a/include/LifeCycleManager.h b/include/LifeCycleManager.h index 34d7eece7c..d5908214ee 100644 --- a/include/LifeCycleManager.h +++ b/include/LifeCycleManager.h @@ -64,6 +64,8 @@ public: DETACH_FAILURE, /**< Sent by the VMM when a detach action fails */ CLEANUP_SUCCESS, /**< Sent by the VMM when a cleanup action succeeds */ CLEANUP_FAILURE, /**< Sent by the VMM when a cleanup action fails */ + SNAPSHOT_CREATE_SUCCESS, /**< Sent by the VMM on snap. create success */ + SNAPSHOT_CREATE_FAILURE, /**< Sent by the VMM on snap. create failure */ DEPLOY, /**< Sent by the DM to deploy a VM on a host */ SUSPEND, /**< Sent by the DM to suspend an running VM */ RESTORE, /**< Sent by the DM to restore a suspended VM */ @@ -189,6 +191,10 @@ private: void cleanup_callback_action(int vid); + void snapshot_create_success(int vid); + + void snapshot_create_failure(int vid); + void deploy_action(int vid); void suspend_action(int vid); diff --git a/include/RequestManagerVirtualMachine.h b/include/RequestManagerVirtualMachine.h index 0393c22b99..52279a79ea 100644 --- a/include/RequestManagerVirtualMachine.h +++ b/include/RequestManagerVirtualMachine.h @@ -217,6 +217,23 @@ public: RequestAttributes& att); }; +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualMachineSnapshotCreate: public RequestManagerVirtualMachine +{ +public: + VirtualMachineSnapshotCreate(): + RequestManagerVirtualMachine("VirtualMachineSnapshotCreate", + "Creates a new virtual machine snapshot", + "A:sis"){}; + + ~VirtualMachineSnapshotCreate(){}; + + void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att); +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index ec52350bed..50e840d7b0 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -924,6 +924,38 @@ public: */ int detach_failure(); + + // ------------------------------------------------------------------------ + // Snapshot related functions + // ------------------------------------------------------------------------ + + int new_snapshot(string& name); + + /** + * Returns the snapshot with an active operation + * + * @return the snapshot with an active operation, or 0 + */ + VectorAttribute* get_active_snapshot(); + + /** + * Replaces HYPERVISOR_ID for the active SNAPSHOT + * + * @param hypervisor_id Id returned by the hypervisor for the newly + * created snapshot + */ + void update_snapshot_id(string& hypervisor_id); + + /** + * Cleans the ACTIVE = YES attribute from the snapshots + */ + void clear_active_snapshot(); + + /** + * Deletes the SNAPSHOT that was in the process of being created + */ + void delete_active_snapshot(); + private: // ------------------------------------------------------------------------- diff --git a/include/VirtualMachineManager.h b/include/VirtualMachineManager.h index 0191a366ba..7f58147bc6 100644 --- a/include/VirtualMachineManager.h +++ b/include/VirtualMachineManager.h @@ -61,7 +61,8 @@ public: DRIVER_CANCEL, FINALIZE, ATTACH, - DETACH + DETACH, + SNAPSHOT_CREATE }; /** @@ -324,6 +325,12 @@ private: void attach_action( int vid); + /** + * Creates a new system snapshot + * @param vid the id of the VM. + */ + void snapshot_create_action(int vid); + /** * Detaches a disk from a VM. The VM must have a disk with the * attribute ATTACH = YES diff --git a/include/VirtualMachineManagerDriver.h b/include/VirtualMachineManagerDriver.h index 6ffe23c07f..992169b564 100644 --- a/include/VirtualMachineManagerDriver.h +++ b/include/VirtualMachineManagerDriver.h @@ -284,6 +284,19 @@ private: write_drv("DETACHDISK", oid, drv_msg); } + /** + * Sends a snapshot create request to the MAD: + * "SNAPSHOTCREATE ID XML_DRV_MSG" + * @param oid the virtual machine id. + * @param drv_msg xml data for the mad operation + */ + void snapshot_create ( + const int oid, + const string& drv_msg) const + { + write_drv("SNAPSHOTCREATE", oid, drv_msg); + } + void write_drv(const char * aname, const int oid, const string& msg) const { ostringstream os; diff --git a/src/dm/DispatchManagerActions.cc b/src/dm/DispatchManagerActions.cc index eb3ad8e235..269a33e1cf 100644 --- a/src/dm/DispatchManagerActions.cc +++ b/src/dm/DispatchManagerActions.cc @@ -1075,3 +1075,61 @@ int DispatchManager::detach( return 0; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int DispatchManager::snapshot_create( + int vid, + string& name, + string& error_str) +{ + ostringstream oss; + + Nebula& nd = Nebula::instance(); + VirtualMachineManager* vmm = nd.get_vmm(); + + VirtualMachine * vm = vmpool->get(vid, true); + + if ( vm == 0 ) + { + oss << "Could not create a new snapshot for VM " << vid + << ", VM does not exist" ; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + return -1; + } + + if ( vm->get_state() != VirtualMachine::ACTIVE || + vm->get_lcm_state() != VirtualMachine::RUNNING ) + { + oss << "Could not create a new snapshot for VM " << vid + << ", wrong state."; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + vm->unlock(); + return -1; + } + + vm->set_state(VirtualMachine::HOTPLUG); + + vm->set_resched(false); + + vm->new_snapshot(name); + + vmpool->update(vm); + + vm->unlock(); + + vmm->trigger(VirtualMachineManager::SNAPSHOT_CREATE,vid); + + return 0; +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/lcm/LifeCycleManager.cc b/src/lcm/LifeCycleManager.cc index 326da9c36f..2f2f109a54 100644 --- a/src/lcm/LifeCycleManager.cc +++ b/src/lcm/LifeCycleManager.cc @@ -153,6 +153,14 @@ void LifeCycleManager::trigger(Actions action, int _vid) aname = "CLEANUP_FAILURE"; break; + case SNAPSHOT_CREATE_SUCCESS: + aname = "SNAPSHOT_CREATE_SUCCESS"; + break; + + case SNAPSHOT_CREATE_FAILURE: + aname = "SNAPSHOT_CREATE_FAILURE"; + break; + case DEPLOY: aname = "DEPLOY"; break; @@ -314,6 +322,14 @@ void LifeCycleManager::do_action(const string &action, void * arg) { cleanup_callback_action(vid); } + else if (action == "SNAPSHOT_CREATE_SUCCESS") + { + snapshot_create_success(vid); + } + else if (action == "SNAPSHOT_CREATE_FAILURE") + { + snapshot_create_failure(vid); + } else if (action == "DEPLOY") { deploy_action(vid); diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 8c17bcd206..dff7e64505 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -1197,3 +1197,63 @@ void LifeCycleManager::detach_failure_action(int vid) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +void LifeCycleManager::snapshot_create_success(int vid) +{ + VirtualMachine * vm; + + vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + if ( vm->get_lcm_state() == VirtualMachine::HOTPLUG ) + { + vm->clear_active_snapshot(); + + vm->set_state(VirtualMachine::RUNNING); + + vmpool->update(vm); + } + else + { + vm->log("LCM",Log::ERROR,"snapshot_create_success, VM in a wrong state"); + } + + vm->unlock(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void LifeCycleManager::snapshot_create_failure(int vid) +{ + VirtualMachine * vm; + + vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + if ( vm->get_lcm_state() == VirtualMachine::HOTPLUG ) + { + vm->delete_active_snapshot(); + + vm->set_state(VirtualMachine::RUNNING); + + vmpool->update(vm); + } + else + { + vm->log("LCM",Log::ERROR,"snapshot_create_failure, VM in a wrong state"); + } + + vm->unlock(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index d698e67197..924db5f618 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -254,6 +254,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr vm_monitoring(new VirtualMachineMonitoring()); xmlrpc_c::methodPtr vm_attach(new VirtualMachineAttach()); xmlrpc_c::methodPtr vm_detach(new VirtualMachineDetach()); + xmlrpc_c::methodPtr vm_snap_create(new VirtualMachineSnapshotCreate()); xmlrpc_c::methodPtr vm_pool_acct(new VirtualMachinePoolAccounting()); xmlrpc_c::methodPtr vm_pool_monitoring(new VirtualMachinePoolMonitoring()); @@ -397,6 +398,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vm.detach", vm_detach); RequestManagerRegistry.addMethod("one.vm.rename", vm_rename); RequestManagerRegistry.addMethod("one.vm.update", vm_update); + RequestManagerRegistry.addMethod("one.vm.snapshotcreate", vm_snap_create); RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info); RequestManagerRegistry.addMethod("one.vmpool.accounting", vm_pool_acct); diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index b8baaff07f..7a6820caaa 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -1054,5 +1054,47 @@ void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList, return; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineSnapshotCreate::request_execute( + xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + Nebula& nd = Nebula::instance(); + DispatchManager * dm = nd.get_dm(); + + int rc; + string error_str; + + int id = xmlrpc_c::value_int(paramList.getInt(1)); + string str = xmlrpc_c::value_string(paramList.getString(2)); + + // ------------------------------------------------------------------------- + // Authorize the operation + // ------------------------------------------------------------------------- + + if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false ) + { + return; + } + + rc = dm->snapshot_create(id, str, error_str); + + if ( rc != 0 ) + { + failure_response(ACTION, + request_error(error_str, ""), + att); + } + else + { + success_response(id, att); + } + + return; +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index c60f67d023..b85ec1680f 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -1803,6 +1803,153 @@ void VirtualMachine::release_disk_images() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int VirtualMachine::new_snapshot(string& name) +{ + int num_snaps; + int id; + int max_id = -1; + + vector snaps; + VectorAttribute * snap; + + num_snaps = obj_template->get("SNAPSHOT", snaps); + + for(int i=0; i(snaps[i]); + + if ( snap == 0 ) + { + continue; + } + + snap->vector_value("SNAPSHOT_ID", id); + + if (id > max_id) + { + max_id = id; + } + } + + snap = new VectorAttribute("SNAPSHOT"); + snap->replace("SNAPSHOT_ID", max_id+1); + snap->replace("NAME", name); + snap->replace("TIME", (int)time(0)); + snap->replace("HYPERVISOR_ID", ""); + + snap->replace("ACTIVE", "YES"); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +VectorAttribute* VirtualMachine::get_active_snapshot() +{ + int num_snaps; + vector snaps; + VectorAttribute * snap; + + num_snaps = obj_template->get("SNAPSHOT", snaps); + + for(int i=0; i(snaps[i]); + + if ( snap == 0 ) + { + continue; + } + + if ( snap->vector_value("ACTIVE") == "YES" ) + { + return snap; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachine::update_snapshot_id(string& hypervisor_id) +{ + VectorAttribute* snap; + + snap = get_active_snapshot(); + + if (snap == 0) + { + return; + } + + snap->replace("HYPERVISOR_ID", hypervisor_id); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachine::clear_active_snapshot() +{ + int num_snaps; + vector snaps; + VectorAttribute * snap; + + num_snaps = obj_template->get("SNAPSHOT", snaps); + + for(int i=0; i(snaps[i]); + + if ( snap == 0 ) + { + continue; + } + + if ( snap->vector_value("ACTIVE") == "YES" ) + { + snap->remove("ACTIVE"); + return; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachine::delete_active_snapshot() +{ + vector snaps; + VectorAttribute * snap; + + int num_snaps = obj_template->get("SNAPSHOT", snaps); + + for(int i=0; i(snaps[i]); + + if ( snap == 0 ) + { + continue; + } + + if ( snap->vector_value("ACTIVE") == "YES" ) + { + if (obj_template->remove(snap) != 0) + { + delete snap; + } + + return; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + int VirtualMachine::get_network_leases(string& estr) { int num_nics, rc; diff --git a/src/vmm/VirtualMachineManager.cc b/src/vmm/VirtualMachineManager.cc index 383d3bfe0d..6630dc9fa1 100644 --- a/src/vmm/VirtualMachineManager.cc +++ b/src/vmm/VirtualMachineManager.cc @@ -183,6 +183,10 @@ void VirtualMachineManager::trigger(Actions action, int _vid) aname = "DETACH"; break; + case SNAPSHOT_CREATE: + aname = "SNAPSHOT_CREATE"; + break; + default: delete vid; return; @@ -279,6 +283,10 @@ void VirtualMachineManager::do_action(const string &action, void * arg) { detach_action(vid); } + else if (action == "SNAPSHOT_CREATE") + { + snapshot_create_action(vid); + } else if (action == ACTION_TIMER) { timer_action(); @@ -1761,6 +1769,83 @@ error_common: return; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineManager::snapshot_create_action(int vid) +{ + VirtualMachine * vm; + const VirtualMachineManagerDriver * vmd; + + ostringstream os; + + string vm_tmpl; + string* drv_msg; + + // Get the VM from the pool + vm = vmpool->get(vid,true); + + if (vm == 0) + { + return; + } + + if (!vm->hasHistory()) + { + goto error_history; + } + + // Get the driver for this VM + vmd = get(vm->get_vmm_mad()); + + if ( vmd == 0 ) + { + goto error_driver; + } + + drv_msg = format_message( + vm->get_hostname(), + vm->get_vnm_mad(), + "", + "", + vm->get_deploy_id(), + "", + "", + "", + "", + "", + vm->to_xml(vm_tmpl)); + + vmd->snapshot_create(vid, *drv_msg); + + delete drv_msg; + + vm->unlock(); + + return; + +error_history: + os.str(""); + os << "snapshot_create_action, VM has no history"; + goto error_common; + +error_driver: + os.str(""); + os << "snapshot_create_action, error getting driver " << vm->get_vmm_mad(); + goto error_common; + +error_common: + Nebula &ne = Nebula::instance(); + LifeCycleManager * lcm = ne.get_lcm(); + + lcm->trigger(LifeCycleManager::SNAPSHOT_CREATE_FAILURE, vid); + + vm->log("VMM", Log::ERROR, os); + vm->unlock(); + return; + +} + /* ************************************************************************** */ /* MAD Loading */ /* ************************************************************************** */ diff --git a/src/vmm/VirtualMachineManagerDriver.cc b/src/vmm/VirtualMachineManagerDriver.cc index dcb92986a1..6b5bd87461 100644 --- a/src/vmm/VirtualMachineManagerDriver.cc +++ b/src/vmm/VirtualMachineManagerDriver.cc @@ -338,7 +338,7 @@ void VirtualMachineManagerDriver::protocol( LifeCycleManager *lcm = ne.get_lcm(); if ( result == "SUCCESS" ) - { + { vm->log("VMM", Log::INFO, "VM Disk successfully attached."); lcm->trigger(LifeCycleManager::ATTACH_SUCCESS, id); @@ -370,6 +370,33 @@ void VirtualMachineManagerDriver::protocol( lcm->trigger(LifeCycleManager::DETACH_FAILURE, id); } } + else if ( action == "SNAPSHOTCREATE" ) + { + Nebula &ne = Nebula::instance(); + LifeCycleManager *lcm = ne.get_lcm(); + + if ( result == "SUCCESS" ) + { + string hypervisor_id; + + is >> hypervisor_id; + + vm->update_snapshot_id(hypervisor_id); + + vmpool->update(vm); + + vm->log("VMM", Log::INFO, "VM Snapshot successfully created."); + + lcm->trigger(LifeCycleManager::SNAPSHOT_CREATE_SUCCESS, id); + } + else + { + log_error(vm, os, is, "Error creating new VM Snapshot"); + vmpool->update(vm); + + lcm->trigger(LifeCycleManager::SNAPSHOT_CREATE_FAILURE, id); + } + } else if ( action == "CLEANUP" ) { Nebula &ne = Nebula::instance();