1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-04-02 10:50:07 +03:00

feature #3782: Snapshots in RUNNING state

This commit is contained in:
Ruben S. Montero 2015-07-01 13:37:58 +02:00
parent 26da64416c
commit 10442f8182
12 changed files with 439 additions and 72 deletions

View File

@ -146,7 +146,7 @@ public:
ostream& xfr);
/**
* This function generates the the epilog_delete sequence for current,
* This function generates the epilog_delete sequence for current,
* front-end and previous hosts.
* @param vm pointer to VM, locked
* @param xfr stream to write the commands
@ -159,6 +159,17 @@ public:
ostream& xfr,
bool local,
bool previous);
/**
* This function generates the TM command for the given snapshot action
* @param vm pointer to VM, locked
* @param snap_action: "SNAP_CREATE, SNAP_DELETE, SNAP_REVERT"
* @param xfr stream to write the commands
*
* @return 0 on success
*/
int snapshot_transfer_command(VirtualMachine * vm,
const char * snap_action,
ostream& xfr);
private:
/**
* Thread id for the Transfer Manager

View File

@ -67,7 +67,9 @@ public:
DETACH_NIC,
SNAPSHOT_CREATE,
SNAPSHOT_REVERT,
SNAPSHOT_DELETE
SNAPSHOT_DELETE,
DISK_SNAPSHOT_CREATE,
DISK_SNAPSHOT_REVERT
};
/**
@ -385,6 +387,20 @@ private:
*/
void snapshot_delete_action(int vid);
/**
* Creates a new disk system snapshot.
*
* @param vid the id of the VM.
*/
void disk_snapshot_create_action(int vid);
/**
* Reverts to a disk snapshot.
*
* @param vid the id of the VM.
*/
void disk_snapshot_revert_action(int vid);
/**
* This function cancels the current driver operation
*/

View File

@ -360,6 +360,32 @@ private:
write_drv("SNAPSHOTDELETE", oid, drv_msg);
}
/**
* Sends a disk snapshot create request to the MAD:
* "DISKSNAPSHOTCREATE ID XML_DRV_MSG"
* @param oid the virtual machine id.
* @param drv_msg xml data for the mad operation
*/
void disk_snapshot_create (
const int oid,
const string& drv_msg) const
{
write_drv("DISKSNAPSHOTCREATE", oid, drv_msg);
}
/**
* Sends a disk snapshot revert request to the MAD:
* "DISKSNAPSHOTREVERT ID XML_DRV_MSG"
* @param oid the virtual machine id.
* @param drv_msg xml data for the mad operation
*/
void disk_snapshot_revert (
const int oid,
const string& drv_msg) const
{
write_drv("DISKSNAPSHOTREVERT", oid, drv_msg);
}
/**
*
*/

View File

@ -1672,10 +1672,10 @@ int DispatchManager::disk_snapshot_create(
vm->set_state(VirtualMachine::DISK_SNAPSHOT_SUSPENDED);
break;
//case VirtualMachine::ACTIVE:
// vm->set_state(VirtualMachine::ACTIVE);
// vm->set_state(VirtualMachine::DISK_SNAPSHOT);
// break;
case VirtualMachine::ACTIVE:
vm->set_state(VirtualMachine::ACTIVE);
vm->set_state(VirtualMachine::DISK_SNAPSHOT);
break;
default: break;
}
@ -1691,9 +1691,9 @@ int DispatchManager::disk_snapshot_create(
tm->trigger(TransferManager::SNAPSHOT_CREATE,vid);
break;
//case VirtualMachine::ACTIVE:
// vmm->trigger(VirtualMachineManager::DISK_SNAPSHOT_CREATE, vid);
// break;
case VirtualMachine::ACTIVE:
vmm->trigger(VirtualMachineManager::DISK_SNAPSHOT_CREATE, vid);
break;
default: break;
}
@ -1776,10 +1776,10 @@ int DispatchManager::disk_snapshot_revert(
vm->set_state(VirtualMachine::DISK_SNAPSHOT_REVERT_SUSPENDED);
break;
//case VirtualMachine::ACTIVE:
// vm->set_state(VirtualMachine::ACTIVE);
// vm->set_state(VirtualMachine::DISK_SNAPSHOT_REVERT);
// break;
case VirtualMachine::ACTIVE:
vm->set_state(VirtualMachine::ACTIVE);
vm->set_state(VirtualMachine::DISK_SNAPSHOT_REVERT);
break;
default: break;
}
@ -1795,9 +1795,9 @@ int DispatchManager::disk_snapshot_revert(
tm->trigger(TransferManager::SNAPSHOT_REVERT, vid);
break;
//case VirtualMachine::ACTIVE:
// vmm->trigger(VirtualMachineManager::DISK_SNAPSHOT_REVERT, vid);
// break;
case VirtualMachine::ACTIVE:
vmm->trigger(VirtualMachineManager::DISK_SNAPSHOT_REVERT, vid);
break;
default: break;
}

View File

@ -1751,6 +1751,9 @@ void LifeCycleManager::disk_snapshot_success(int vid)
switch (state)
{
case VirtualMachine::DISK_SNAPSHOT:
case VirtualMachine::DISK_SNAPSHOT_REVERT:
vm->set_state(VirtualMachine::RUNNING);
case VirtualMachine::DISK_SNAPSHOT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_SUSPENDED:
case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF:
@ -1843,12 +1846,15 @@ void LifeCycleManager::disk_snapshot_failure(int vid)
switch (state)
{
case VirtualMachine::DISK_SNAPSHOT:
vm->set_state(VirtualMachine::RUNNING);
case VirtualMachine::DISK_SNAPSHOT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_SUSPENDED:
vm->log("LCM", Log::ERROR, "Could not take disk snapshot.");
vm->delete_disk_snapshot(idisk_id, isnap_id, qt, &quotas);
break;
case VirtualMachine::DISK_SNAPSHOT_REVERT:
case VirtualMachine::DISK_SNAPSHOT_DELETE:
vm->set_state(VirtualMachine::RUNNING);
case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF:

View File

@ -47,7 +47,9 @@ class VirtualMachineDriver < OpenNebulaDriver
:snapshot_delete => "SNAPSHOTDELETE",
:cleanup => "CLEANUP",
:attach_nic => "ATTACHNIC",
:detach_nic => "DETACHNIC"
:detach_nic => "DETACHNIC",
:disk_snapshot_create => "DISKSNAPSHOTCREATE",
:disk_snapshot_revert => "DISKSNAPSHOTREVERT"
}
POLL_ATTRIBUTE = {
@ -87,26 +89,25 @@ class VirtualMachineDriver < OpenNebulaDriver
@hosts = Array.new
register_action(ACTION[:deploy].to_sym, method("deploy"))
register_action(ACTION[:shutdown].to_sym, method("shutdown"))
register_action(ACTION[:reboot].to_sym, method("reboot"))
register_action(ACTION[:reset].to_sym, method("reset"))
register_action(ACTION[:cancel].to_sym, method("cancel"))
register_action(ACTION[:save].to_sym, method("save"))
register_action(ACTION[:restore].to_sym, method("restore"))
register_action(ACTION[:migrate].to_sym, method("migrate"))
register_action(ACTION[:poll].to_sym, method("poll"))
register_action(ACTION[:attach_disk].to_sym, method("attach_disk"))
register_action(ACTION[:detach_disk].to_sym, method("detach_disk"))
register_action(ACTION[:snapshot_create].to_sym,
method("snapshot_create"))
register_action(ACTION[:snapshot_revert].to_sym,
method("snapshot_revert"))
register_action(ACTION[:snapshot_delete].to_sym,
method("snapshot_delete"))
register_action(ACTION[:cleanup].to_sym, method("cleanup"))
register_action(ACTION[:attach_nic].to_sym, method("attach_nic"))
register_action(ACTION[:detach_nic].to_sym, method("detach_nic"))
register_action(ACTION[:deploy].to_sym, method("deploy"))
register_action(ACTION[:shutdown].to_sym, method("shutdown"))
register_action(ACTION[:reboot].to_sym, method("reboot"))
register_action(ACTION[:reset].to_sym, method("reset"))
register_action(ACTION[:cancel].to_sym, method("cancel"))
register_action(ACTION[:save].to_sym, method("save"))
register_action(ACTION[:restore].to_sym, method("restore"))
register_action(ACTION[:migrate].to_sym, method("migrate"))
register_action(ACTION[:poll].to_sym, method("poll"))
register_action(ACTION[:attach_disk].to_sym, method("attach_disk"))
register_action(ACTION[:detach_disk].to_sym, method("detach_disk"))
register_action(ACTION[:snapshot_create].to_sym, method("snapshot_create"))
register_action(ACTION[:snapshot_revert].to_sym, method("snapshot_revert"))
register_action(ACTION[:snapshot_delete].to_sym, method("snapshot_delete"))
register_action(ACTION[:cleanup].to_sym, method("cleanup"))
register_action(ACTION[:attach_nic].to_sym, method("attach_nic"))
register_action(ACTION[:detach_nic].to_sym, method("detach_nic"))
register_action(ACTION[:disk_snapshot_create].to_sym, method("disk_snapshot_create"))
register_action(ACTION[:disk_snapshot_revert].to_sym, method("disk_snapshot_revert"))
end
# Decodes the encoded XML driver message received from the core
@ -211,6 +212,16 @@ class VirtualMachineDriver < OpenNebulaDriver
send_message(ACTION[:snapshot_delete],RESULT[:failure],id,error)
end
def disk_snapshot_create(id, drv_message)
error = "Action not implemented by driver #{self.class}"
send_message(ACTION[:disk_snapshot_create],RESULT[:failure],id,error)
end
def disk_snapshot_revert(id, drv_message)
error = "Action not implemented by driver #{self.class}"
send_message(ACTION[:disk_snapshot_revert],RESULT[:failure],id,error)
end
def cleanup(id, drv_message)
error = "Action not implemented by driver #{self.class}"
send_message(ACTION[:cleanup],RESULT[:failure],id,error)

View File

@ -2165,28 +2165,58 @@ void TransferManager::migrate_transfer_command(
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void TransferManager::do_snapshot_action(int vid, const char * snap_action)
int TransferManager::snapshot_transfer_command(
VirtualMachine * vm, const char * snap_action, ostream& xfr)
{
string tm_mad;
string ds_id;
string disk_id;
string parent_id;
string snap_id;
if (vm->get_snapshot_disk(ds_id, tm_mad, disk_id, snap_id) == -1)
{
vm->log("TM", Log::ERROR, "Could not get disk information to"
"take snapshot");
return -1;
}
//SNAP_CREATE tm_mad host:remote_system_dir/disk.0 snapid vmid dsid
xfr << snap_action << " "
<< tm_mad << " "
<< vm->get_hostname() << ":"
<< vm->get_remote_system_dir() << "/disk." << disk_id << " "
<< snap_id << " "
<< vm->get_oid() << " "
<< ds_id
<< endl;
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void TransferManager::do_snapshot_action(int vid, const char * snap_action)
{
ostringstream os;
ofstream xfr;
string xfr_name;
VirtualMachine * vm;
int rc;
const TransferManagerDriver * tm_md;
Nebula& nd = Nebula::instance();
// ------------------------------------------------------------------------
// Setup & Transfer script
// ------------------------------------------------------------------------
tm_md = get();
if (tm_md == 0)
{
goto error_driver;
}
vm = vmpool->get(vid,true);
if (vm == 0)
@ -2201,20 +2231,6 @@ void TransferManager::do_snapshot_action(int vid, const char * snap_action)
goto error_common;
}
if (vm->get_snapshot_disk(ds_id, tm_mad, disk_id, snap_id) == -1)
{
vm->log("TM", Log::ERROR, "Could not get disk information to"
"take snapshot");
goto error_common;
}
tm_md = get();
if (tm_md == 0)
{
goto error_driver;
}
xfr_name = vm->get_transfer_file() + ".disk_snapshot";
xfr.open(xfr_name.c_str(),ios::out | ios::trunc);
@ -2223,18 +2239,15 @@ void TransferManager::do_snapshot_action(int vid, const char * snap_action)
goto error_file;
}
//SNAP_CREATE tm_mad host:remote_system_dir/disk.0 snapid vmid dsid
xfr << snap_action << " "
<< tm_mad << " "
<< vm->get_hostname() << ":"
<< vm->get_remote_system_dir() << "/disk." << disk_id << " "
<< snap_id << " "
<< vm->get_oid() << " "
<< ds_id
<< endl;
rc = snapshot_transfer_command(vm, snap_action, xfr);
xfr.close();
if ( rc == -1 )
{
goto error_common;
}
tm_md->transfer(vid, xfr_name);
vm->unlock();
@ -2242,17 +2255,17 @@ void TransferManager::do_snapshot_action(int vid, const char * snap_action)
return;
error_driver:
os << "saveas_hot_transfer, error getting TM driver.";
os << "disk_snapshot, error getting TM driver.";
goto error_common;
error_file:
os << "disk_snapshot_create, could not open file: " << xfr_name;
os << "disk_snapshot, could not open file: " << xfr_name;
goto error_common;
error_common:
vm->log("TM", Log::ERROR, os);
(nd.get_lcm())->trigger(LifeCycleManager::DISK_SNAPSHOT_FAILURE, vid);
(nd.get_lcm())->trigger(LifeCycleManager::DISK_SNAPSHOT_FAILURE, vid);
vm->unlock();
return;

View File

@ -197,6 +197,14 @@ void VirtualMachineManager::trigger(Actions action, int _vid)
aname = "SNAPSHOT_DELETE";
break;
case DISK_SNAPSHOT_CREATE:
aname = "DISK_SNAPSHOT_CREATE";
break;
case DISK_SNAPSHOT_REVERT:
aname = "DISK_SNAPSHOT_REVERT";
break;
default:
delete vid;
return;
@ -312,6 +320,14 @@ void VirtualMachineManager::do_action(const string &action, void * arg)
{
snapshot_delete_action(vid);
}
else if (action == "DISK_SNAPSHOT_CREATE")
{
disk_snapshot_create_action(vid);
}
else if (action == "DISK_SNAPSHOT_REVERT")
{
disk_snapshot_revert_action(vid);
}
else if (action == ACTION_TIMER)
{
timer_action();
@ -1650,8 +1666,6 @@ void VirtualMachineManager::attach_action(
goto error_disk;
}
vm_tm_mad = vm->get_tm_mad();
opennebula_hostname = nd.get_nebula_hostname();
rc = tm->prolog_transfer_command(
@ -2090,6 +2104,134 @@ error_common:
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineManager::disk_snapshot_create_action(int vid)
{
VirtualMachine * vm;
const VirtualMachineManagerDriver * vmd;
ostringstream os;
string vm_tmpl;
string* drv_msg;
string vm_tm_mad;
string snap_cmd, snap_cmd_rollback;
string disk_path;
string ds_id, tm_mad, disk_id, snap_id;
int rc;
Nebula& nd = Nebula::instance();
TransferManager * tm = nd.get_tm();
vm = vmpool->get(vid,true);
if (vm == 0)
{
return;
}
if (!vm->hasHistory())
{
goto error_history;
}
vmd = get(vm->get_vmm_mad());
if ( vmd == 0 )
{
goto error_driver;
}
if ( vm->get_snapshot_disk(ds_id, tm_mad, disk_id, snap_id) != 0 )
{
goto error_disk;
}
rc = tm->snapshot_transfer_command( vm, "SNAP_CREATE", os);
snap_cmd = os.str();
os.str("");
rc += tm->snapshot_transfer_command( vm, "SNAP_DELETE", os);
snap_cmd_rollback = os.str();
os.str("");
if ( snap_cmd.empty() || snap_cmd_rollback.empty() || rc != 0 )
{
goto error_no_tm_command;
}
os << vm->get_remote_system_dir() << "/disk." << disk_id;
disk_path = os.str();
// Invoke driver method
drv_msg = format_message(
vm->get_hostname(),
vm->get_vnm_mad(),
"",
"",
vm->get_deploy_id(),
"",
"",
vm->get_checkpoint_file(),
snap_cmd,
snap_cmd_rollback,
disk_path,
vm->to_xml(vm_tmpl));
vmd->disk_snapshot_create(vid, *drv_msg);
delete drv_msg;
vm->unlock();
return;
error_disk:
os << "disk_snapshot_create, could not find disk to take snapshot";
goto error_common;
error_history:
os << "disk_snapshot_create, VM has no history";
goto error_common;
error_driver:
os << "disk_snapshot_create, error getting driver " << vm->get_vmm_mad();
goto error_common;
error_no_tm_command:
os << "Cannot set disk for snapshot.";
goto error_common;
error_common:
Nebula &ne = Nebula::instance();
LifeCycleManager * lcm = ne.get_lcm();
lcm->trigger(LifeCycleManager::DISK_SNAPSHOT_FAILURE, vid);
vm->log("VMM", Log::ERROR, os);
vm->unlock();
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineManager::disk_snapshot_revert_action(int vid)
{
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineManager::attach_nic_action(
int vid)
{

View File

@ -520,6 +520,44 @@ void VirtualMachineManagerDriver::protocol(const string& message) const
lcm->trigger(LifeCycleManager::SNAPSHOT_DELETE_FAILURE, id);
}
}
else if ( action == "DISKSNAPSHOTCREATE" )
{
Nebula &ne = Nebula::instance();
LifeCycleManager *lcm = ne.get_lcm();
if ( result == "SUCCESS" )
{
vm->log("VMM", Log::INFO, "VM disk snapshot successfully created.");
lcm->trigger(LifeCycleManager::DISK_SNAPSHOT_SUCCESS, id);
}
else
{
log_error(vm, os, is, "Error creating new disk snapshot");
vmpool->update(vm);
lcm->trigger(LifeCycleManager::DISK_SNAPSHOT_FAILURE, id);
}
}
else if ( action == "DISKSNAPSHOTREVERT" )
{
Nebula &ne = Nebula::instance();
LifeCycleManager *lcm = ne.get_lcm();
if ( result == "SUCCESS" )
{
vm->log("VMM", Log::INFO, "VM disk state reverted.");
lcm->trigger(LifeCycleManager::DISK_SNAPSHOT_SUCCESS, id);
}
else
{
log_error(vm, os, is, "Error reverting disk snapshot");
vmpool->update(vm);
lcm->trigger(LifeCycleManager::DISK_SNAPSHOT_FAILURE, id);
}
}
else if ( action == "CLEANUP" )
{
Nebula &ne = Nebula::instance();

View File

@ -158,6 +158,18 @@ class DummyDriver < VirtualMachineDriver
send_message(ACTION[:snapshot_delete], result, id)
end
def disk_snapshot_create(id, drv_message)
result = retrieve_result("disk_snapshot_create")
send_message(ACTION[:disk_snapshot_create], result, id, "dummy-snap")
end
def disk_snapshot_revert(id, drv_message)
result = retrieve_result("disk_snapshot_revert")
send_message(ACTION[:disk_snapshot_revert], result, id)
end
def cleanup(id, drv_message)
result = retrieve_result("cleanup")

View File

@ -587,8 +587,6 @@ class ExecDriver < VirtualMachineDriver
target_index = target.downcase[-1..-1].unpack('c').first - 97
action = VmmAction.new(self, id, :attach_disk, drv_message)
# Bug #1355, argument character limitation in ESX
@ -890,6 +888,91 @@ class ExecDriver < VirtualMachineDriver
action.run(steps)
end
#
# DISKSNAPSHOTCREATE action, takes a snapshot of a disk
#
def disk_snapshot_create(id, drv_message)
action = ACTION[:disk_snapshot_create]
xml_data = decode(drv_message)
tm_command = ensure_xpath(xml_data, id, action, 'TM_COMMAND') || return
tm_rollback= xml_data.elements['TM_COMMAND_ROLLBACK'].text.strip
target_xpath = "VM/TEMPLATE/DISK[DISK_SNAPSHOT_ACTIVE='YES']/TARGET"
target = ensure_xpath(xml_data, id, action, target_xpath) || return
target_index = target.downcase[-1..-1].unpack('c').first - 97
disk = xml_data.elements[target_xpath]
attach = REXML::Element.new('ATTACH')
attach.add_text('YES')
disk.add(attach)
drv_message = Base64.encode64(xml_data.to_s)
action = VmmAction.new(self, id, :disk_snapshot_create, drv_message)
steps = [
# First detach the disk from the VM
#{
# :driver => :vmm,
# :action => :detach_disk,
# :parameters => [
# :deploy_id,
# :disk_target_path,
# target,
# target_index
# ]
#},
# Save the Virtual Machine state
{
:driver => :vmm,
:action => :save,
:parameters => [:deploy_id, :checkpoint_file, :host]
},
# Do the snapshot
{
:driver => :tm,
:action => :tm_snap_create,
:parameters => tm_command.split
},
# Restore the Virtual Machine from checkpoint
{
:driver => :vmm,
:action => :restore,
:parameters => [:checkpoint_file, :host, :deploy_id],
:fail_actions => [
{
:driver => :tm,
:action => :tm_snap_delete,
:parameters => tm_rollback.split
}
]
},
# Attach the disk again
#{
# :driver => :vmm,
# :action => :attach_disk,
# :parameters => [
# :deploy_id,
# :disk_target_path,
# target,
# target_index,
# drv_message
# ],
# :fail_actions => [
# {
# :driver => :tm,
# :action => :tm_snap_delete,
# :parameters => tm_rollback.split
# }
# ]
#}
]
action.run(steps)
end
private
def ensure_xpath(xml_data, id, action, xpath)

View File

@ -28,3 +28,12 @@ DETACH_PARAMS="--domain $DOMAIN --target $TARGET"
exec_and_log "virsh --connect $LIBVIRT_URI detach-disk $DETACH_PARAMS" \
"Could not detach $TARGET from $DOMAIN"
virsh --connect $LIBVIRT_URI dumpxml $DOMAIN | grep $TARGET > /dev/null 2>&1
if [ $? -eq 0 ] ; then
error_message "Could not detach $TARGET from $DOMAIN"
exit -1
fi
exit 0