1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-03 01:17:41 +03:00

Feature #1224: New method one.vm.snapshotcreate

This commit is contained in:
Carlos Martín 2013-02-19 15:21:33 +01:00
parent ae5561c27e
commit 08399c5732
14 changed files with 528 additions and 2 deletions

View File

@ -276,6 +276,20 @@ public:
int disk_id, int disk_id,
string& error_str); 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: private:
/** /**
* Thread id for the Dispatch Manager * Thread id for the Dispatch Manager

View File

@ -64,6 +64,8 @@ public:
DETACH_FAILURE, /**< Sent by the VMM when a detach action fails */ DETACH_FAILURE, /**< Sent by the VMM when a detach action fails */
CLEANUP_SUCCESS, /**< Sent by the VMM when a cleanup action succeeds */ CLEANUP_SUCCESS, /**< Sent by the VMM when a cleanup action succeeds */
CLEANUP_FAILURE, /**< Sent by the VMM when a cleanup action fails */ 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 */ DEPLOY, /**< Sent by the DM to deploy a VM on a host */
SUSPEND, /**< Sent by the DM to suspend an running VM */ SUSPEND, /**< Sent by the DM to suspend an running VM */
RESTORE, /**< Sent by the DM to restore a suspended VM */ RESTORE, /**< Sent by the DM to restore a suspended VM */
@ -189,6 +191,10 @@ private:
void cleanup_callback_action(int vid); void cleanup_callback_action(int vid);
void snapshot_create_success(int vid);
void snapshot_create_failure(int vid);
void deploy_action(int vid); void deploy_action(int vid);
void suspend_action(int vid); void suspend_action(int vid);

View File

@ -217,6 +217,23 @@ public:
RequestAttributes& att); 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);
};
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */

View File

@ -924,6 +924,38 @@ public:
*/ */
int detach_failure(); 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: private:
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------

View File

@ -61,7 +61,8 @@ public:
DRIVER_CANCEL, DRIVER_CANCEL,
FINALIZE, FINALIZE,
ATTACH, ATTACH,
DETACH DETACH,
SNAPSHOT_CREATE
}; };
/** /**
@ -324,6 +325,12 @@ private:
void attach_action( void attach_action(
int vid); 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 * Detaches a disk from a VM. The VM must have a disk with the
* attribute ATTACH = YES * attribute ATTACH = YES

View File

@ -284,6 +284,19 @@ private:
write_drv("DETACHDISK", oid, drv_msg); 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 void write_drv(const char * aname, const int oid, const string& msg) const
{ {
ostringstream os; ostringstream os;

View File

@ -1075,3 +1075,61 @@ int DispatchManager::detach(
return 0; 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;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -153,6 +153,14 @@ void LifeCycleManager::trigger(Actions action, int _vid)
aname = "CLEANUP_FAILURE"; aname = "CLEANUP_FAILURE";
break; break;
case SNAPSHOT_CREATE_SUCCESS:
aname = "SNAPSHOT_CREATE_SUCCESS";
break;
case SNAPSHOT_CREATE_FAILURE:
aname = "SNAPSHOT_CREATE_FAILURE";
break;
case DEPLOY: case DEPLOY:
aname = "DEPLOY"; aname = "DEPLOY";
break; break;
@ -314,6 +322,14 @@ void LifeCycleManager::do_action(const string &action, void * arg)
{ {
cleanup_callback_action(vid); 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") else if (action == "DEPLOY")
{ {
deploy_action(vid); deploy_action(vid);

View File

@ -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();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -254,6 +254,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vm_monitoring(new VirtualMachineMonitoring()); xmlrpc_c::methodPtr vm_monitoring(new VirtualMachineMonitoring());
xmlrpc_c::methodPtr vm_attach(new VirtualMachineAttach()); xmlrpc_c::methodPtr vm_attach(new VirtualMachineAttach());
xmlrpc_c::methodPtr vm_detach(new VirtualMachineDetach()); 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_acct(new VirtualMachinePoolAccounting());
xmlrpc_c::methodPtr vm_pool_monitoring(new VirtualMachinePoolMonitoring()); 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.detach", vm_detach);
RequestManagerRegistry.addMethod("one.vm.rename", vm_rename); RequestManagerRegistry.addMethod("one.vm.rename", vm_rename);
RequestManagerRegistry.addMethod("one.vm.update", vm_update); 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.info", vm_pool_info);
RequestManagerRegistry.addMethod("one.vmpool.accounting", vm_pool_acct); RequestManagerRegistry.addMethod("one.vmpool.accounting", vm_pool_acct);

View File

@ -1054,5 +1054,47 @@ void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList,
return; 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;
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */

View File

@ -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<Attribute *> snaps;
VectorAttribute * snap;
num_snaps = obj_template->get("SNAPSHOT", snaps);
for(int i=0; i<num_snaps; i++)
{
snap = dynamic_cast<VectorAttribute * >(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<Attribute *> snaps;
VectorAttribute * snap;
num_snaps = obj_template->get("SNAPSHOT", snaps);
for(int i=0; i<num_snaps; i++)
{
snap = dynamic_cast<VectorAttribute * >(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<Attribute *> snaps;
VectorAttribute * snap;
num_snaps = obj_template->get("SNAPSHOT", snaps);
for(int i=0; i<num_snaps; i++)
{
snap = dynamic_cast<VectorAttribute * >(snaps[i]);
if ( snap == 0 )
{
continue;
}
if ( snap->vector_value("ACTIVE") == "YES" )
{
snap->remove("ACTIVE");
return;
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachine::delete_active_snapshot()
{
vector<Attribute *> snaps;
VectorAttribute * snap;
int num_snaps = obj_template->get("SNAPSHOT", snaps);
for(int i=0; i<num_snaps; i++)
{
snap = dynamic_cast<VectorAttribute * >(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 VirtualMachine::get_network_leases(string& estr)
{ {
int num_nics, rc; int num_nics, rc;

View File

@ -183,6 +183,10 @@ void VirtualMachineManager::trigger(Actions action, int _vid)
aname = "DETACH"; aname = "DETACH";
break; break;
case SNAPSHOT_CREATE:
aname = "SNAPSHOT_CREATE";
break;
default: default:
delete vid; delete vid;
return; return;
@ -279,6 +283,10 @@ void VirtualMachineManager::do_action(const string &action, void * arg)
{ {
detach_action(vid); detach_action(vid);
} }
else if (action == "SNAPSHOT_CREATE")
{
snapshot_create_action(vid);
}
else if (action == ACTION_TIMER) else if (action == ACTION_TIMER)
{ {
timer_action(); timer_action();
@ -1761,6 +1769,83 @@ error_common:
return; 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 */ /* MAD Loading */
/* ************************************************************************** */ /* ************************************************************************** */

View File

@ -338,7 +338,7 @@ void VirtualMachineManagerDriver::protocol(
LifeCycleManager *lcm = ne.get_lcm(); LifeCycleManager *lcm = ne.get_lcm();
if ( result == "SUCCESS" ) if ( result == "SUCCESS" )
{ {
vm->log("VMM", Log::INFO, "VM Disk successfully attached."); vm->log("VMM", Log::INFO, "VM Disk successfully attached.");
lcm->trigger(LifeCycleManager::ATTACH_SUCCESS, id); lcm->trigger(LifeCycleManager::ATTACH_SUCCESS, id);
@ -370,6 +370,33 @@ void VirtualMachineManagerDriver::protocol(
lcm->trigger(LifeCycleManager::DETACH_FAILURE, id); 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" ) else if ( action == "CLEANUP" )
{ {
Nebula &ne = Nebula::instance(); Nebula &ne = Nebula::instance();