1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-22 13:33:52 +03:00

Feature #3214: Add action to cancel deferred disk snapshots

(cherry picked from commit 2ea26af01e1156594c70bfadf7f05ed67c4a190f)
This commit is contained in:
Carlos Martín 2015-04-20 13:03:16 +02:00 committed by Ruben S. Montero
parent b030daa78b
commit 099ab8573e
17 changed files with 369 additions and 69 deletions

View File

@ -163,12 +163,13 @@ public:
string& error);
/**
* Deletes an image from the repository and the DB
* Deletes an image from the repository and the DB. The Datastore image list
* is also updated
* @param iid id of image
* @param error_str Error reason, if any
* @return 0 on success
*/
int delete_image(int iid, const string& ds_data, string& error_str);
int delete_image(int iid, string& error_str);
/**
* Gets the size of an image by calling the STAT action of the associated

View File

@ -187,6 +187,23 @@ public:
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class VirtualMachineSaveDiskCancel : public RequestManagerVirtualMachine
{
public:
VirtualMachineSaveDiskCancel():
RequestManagerVirtualMachine("VirtualMachineSaveDiskCancel",
"Cancels a disk snapshot set by VirtualMachineSaveDisk",
"A:sii"){};
~VirtualMachineSaveDiskCancel(){};
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class VirtualMachineMonitoring : public RequestManagerVirtualMachine
{
public:

View File

@ -1218,6 +1218,20 @@ public:
const string& source,
int img_id);
/**
* Clears the SAVE_AS attribute for the "disk_id"th disk.
* @param disk_id Index of the disk to save
* @return 0 on success, -1 if the disk does not exist
*/
int clear_save_disk(int disk_id);
/**
* Returns the image ID to be saved-as.
* @param disk_id Index of the disk to save
* @return The image ID, or -1 if the disk is not going to be saved-as
*/
int get_save_disk_image(int disk_id);
/**
* Set the SAVE_AS attribute for the "disk_id"th disk.
* @param disk_id Index of the disk to save

View File

@ -177,6 +177,11 @@ digraph OpenNebula {
suspended -> hotplug_saveas_suspended [label="disk-snapshot"]
hotplug_saveas_suspended -> suspended [style="dashed", color="blue"];
# disk-snapshot-cancel
running -> running [label="disk-snapshot-cancel"]
poweroff -> poweroff [label="disk-snapshot-cancel"]
suspended -> suspended [label="disk-snapshot-cancel"]
# failures and misc.
epilog_stop -> epilog_stop_failure [label=" ", style="dotted", color="red"];
epilog_stop_failure -> epilog_stop [label="recover"];

View File

@ -330,6 +330,19 @@ cmd=CommandParser::CmdParser.new(ARGV) do
end
end
disk_snapshot_cancel_desc = <<-EOT.unindent
Cancels a deferred disk snapshot that has been set by disk-snapshot.
The target image is also deleted.
States: ANY
EOT
command :"disk-snapshot-cancel", disk_snapshot_cancel_desc, :vmid, :diskid do
helper.perform_action(args[0],options,"disk snapshot canceled") do |vm|
vm.disk_snapshot_cancel(args[1].to_i)
end
end
shutdown_desc = <<-EOT.unindent
Shuts down the given VM. The VM life cycle will end.

View File

@ -390,13 +390,15 @@ int ImageManager::enable_image(int iid, bool to_enable, string& error_str)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ImageManager::delete_image(int iid, const string& ds_data, string& error_str)
int ImageManager::delete_image(int iid, string& error_str)
{
Image * img;
Image * img;
Datastore * ds;
string source;
string img_tmpl;
string * drv_msg;
string ds_data;
long long size;
int ds_id;
@ -411,6 +413,31 @@ int ImageManager::delete_image(int iid, const string& ds_data, string& error_str
if ( img == 0 )
{
error_str = "Image does not exist";
return -1;
}
ds_id = img->get_ds_id();
img->unlock();
ds = dspool->get(ds_id, true);
if ( ds == 0 )
{
error_str = "Datastore no longer exists cannot remove image";
return -1;
}
ds->to_xml(ds_data);
ds->unlock();
img = ipool->get(iid,true);
if ( img == 0 )
{
error_str = "Image does not exist";
return -1;
}
@ -518,6 +545,16 @@ int ImageManager::delete_image(int iid, const string& ds_data, string& error_str
release_cloning_image(cloning_id, iid);
}
ds = dspool->get(ds_id, true);
if ( ds != 0 )
{
ds->del_image(iid);
dspool->update(ds);
ds->unlock();
}
return 0;
}

View File

@ -24,26 +24,27 @@ module OpenNebula
#######################################################################
VM_METHODS = {
:info => "vm.info",
:allocate => "vm.allocate",
:action => "vm.action",
:migrate => "vm.migrate",
:deploy => "vm.deploy",
:savedisk => "vm.savedisk",
:chown => "vm.chown",
:chmod => "vm.chmod",
:monitoring => "vm.monitoring",
:attach => "vm.attach",
:detach => "vm.detach",
:rename => "vm.rename",
:update => "vm.update",
:resize => "vm.resize",
:info => "vm.info",
:allocate => "vm.allocate",
:action => "vm.action",
:migrate => "vm.migrate",
:deploy => "vm.deploy",
:savedisk => "vm.savedisk",
:savediskcancel => "vm.savediskcancel",
:chown => "vm.chown",
:chmod => "vm.chmod",
:monitoring => "vm.monitoring",
:attach => "vm.attach",
:detach => "vm.detach",
:rename => "vm.rename",
:update => "vm.update",
:resize => "vm.resize",
:snapshotcreate => "vm.snapshotcreate",
:snapshotrevert => "vm.snapshotrevert",
:snapshotdelete => "vm.snapshotdelete",
:attachnic => "vm.attachnic",
:detachnic => "vm.detachnic",
:recover => "vm.recover"
:attachnic => "vm.attachnic",
:detachnic => "vm.detachnic",
:recover => "vm.recover"
}
VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED
@ -481,6 +482,14 @@ module OpenNebula
return disk_snapshot(disk_id, image_name, image_type, hot)
end
# Cancels a deferred snapshot that has been set by disk_snapshot.
# The target image is also deleted.
def disk_snapshot_cancel(disk_id)
return call(VM_METHODS[:savediskcancel],
@pe_id,
disk_id)
end
# Resize the VM
#
# @param capacity_template [String] Template containing the new capacity

View File

@ -293,6 +293,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vm_migrate(new VirtualMachineMigrate());
xmlrpc_c::methodPtr vm_action(new VirtualMachineAction());
xmlrpc_c::methodPtr vm_savedisk(new VirtualMachineSaveDisk());
xmlrpc_c::methodPtr vm_savedisk_cancel(new VirtualMachineSaveDiskCancel());
xmlrpc_c::methodPtr vm_monitoring(new VirtualMachineMonitoring());
xmlrpc_c::methodPtr vm_attach(new VirtualMachineAttach());
xmlrpc_c::methodPtr vm_detach(new VirtualMachineDetach());
@ -438,6 +439,7 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.vm.action", vm_action);
RequestManagerRegistry.addMethod("one.vm.migrate", vm_migrate);
RequestManagerRegistry.addMethod("one.vm.savedisk", vm_savedisk);
RequestManagerRegistry.addMethod("one.vm.savediskcancel", vm_savedisk_cancel);
RequestManagerRegistry.addMethod("one.vm.allocate", vm_allocate);
RequestManagerRegistry.addMethod("one.vm.info", vm_info);
RequestManagerRegistry.addMethod("one.vm.chown", vm_chown);

View File

@ -180,49 +180,11 @@ int HostDelete::drop(int oid, PoolObjectSQL * object, string& error_msg)
int ImageDelete::drop(int oid, PoolObjectSQL * object, string& error_msg)
{
Nebula& nd = Nebula::instance();
ImageManager * imagem = nd.get_imagem();
DatastorePool * dspool = nd.get_dspool();
Datastore * ds;
Image * img;
object->unlock();
int ds_id, rc;
string ds_data;
img = static_cast<Image *>(object);
ds_id = img->get_ds_id();
img->unlock();
ds = dspool->get(ds_id, true);
if ( ds == 0 )
{
error_msg = "Datastore no longer exists cannot remove image";
return -1;
}
ds->to_xml(ds_data);
ds->unlock();
rc = imagem->delete_image(oid, ds_data, error_msg);
if ( rc == 0 )
{
ds = dspool->get(ds_id, true);
if ( ds != 0 )
{
ds->del_image(oid);
dspool->update(ds);
ds->unlock();
}
}
return rc;
return imagem->delete_image(oid, error_msg);
}
/* ------------------------------------------------------------------------- */

View File

@ -1494,6 +1494,157 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineSaveDiskCancel::request_execute(
xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
Nebula& nd = Nebula::instance();
AclManager * aclm = nd.get_aclm();
ImageManager * imagem = nd.get_imagem();
ImagePool * ipool = nd.get_ipool();
Image * img;
int img_id;
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
VirtualMachine * vm;
string error_str;
int id = xmlrpc_c::value_int(paramList.getInt(1));
int disk_id = xmlrpc_c::value_int(paramList.getInt(2));
// -------------------------------------------------------------------------
// Authorize the VM operation
// -------------------------------------------------------------------------
if (att.uid != UserPool::ONEADMIN_ID)
{
PoolObjectAuth vm_perms;
PoolObjectAuth img_perms;
if ((vm = get_vm(id, att)) == 0)
{
return;
}
vm->get_permissions(vm_perms);
img_id = vm->get_save_disk_image(disk_id);
vm->unlock();
AuthRequest ar(att.uid, att.group_ids);
ar.add_auth(auth_op, vm_perms); // MANAGE VM
img = ipool->get(img_id, true);
if ( img != 0 )
{
img->get_permissions(img_perms);
img->unlock();
ar.add_auth(AuthRequest::MANAGE, img_perms); // MANAGE IMAGE
}
if (UserPool::authorize(ar) == -1)
{
failure_response(AUTHORIZATION,
authorization_error(ar.message, att),
att);
return;
}
}
// -------------------------------------------------------------------------
// Check the VM state
// -------------------------------------------------------------------------
if ((vm = get_vm(id, att)) == 0)
{
return;
}
if ((vm->get_state() != VirtualMachine::ACTIVE ||
(vm->get_lcm_state() != VirtualMachine::RUNNING &&
vm->get_lcm_state() != VirtualMachine::UNKNOWN) ) &&
vm->get_state() != VirtualMachine::POWEROFF &&
vm->get_state() != VirtualMachine::SUSPENDED)
{
failure_response(ACTION,
request_error("Wrong state to perform action",""),
att);
vm->unlock();
return;
}
// -------------------------------------------------------------------------
// Cancel the disk snapshot
// -------------------------------------------------------------------------
img_id = vm->get_save_disk_image(disk_id);
if ( img_id == -1 )
{
ostringstream oss;
oss << "Disk with ID [" << disk_id << "] is not going to be saved";
failure_response(ACTION,
request_error(oss.str(), ""),
att);
vm->unlock();
return;
}
vm->clear_save_disk(disk_id);
vmpool->update(vm);
vm->unlock();
// -------------------------------------------------------------------------
// Delete the target Image
// -------------------------------------------------------------------------
img = ipool->get(img_id, true);
if ( img != 0 )
{
img->unlock();
int rc = imagem->delete_image(img_id, error_str);
if (rc != 0)
{
ostringstream oss;
oss << "The snapshot was canceled, but "
<< object_name(PoolObjectSQL::IMAGE) << " [" << img_id
<< "] could not be deleted: " << error_str;
failure_response(INTERNAL,
request_error(oss.str(), ""),
att);
return;
}
aclm->del_resource_rules(img_id, PoolObjectSQL::IMAGE);
}
// TODO: Delete the cloned template
success_response(id, att);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineMonitoring::request_execute(
xmlrpc_c::paramList const& paramList,
RequestAttributes& att)

View File

@ -192,6 +192,7 @@ tabs:
VM.attachdisk: true
VM.detachdisk: true
VM.saveas: true
VM.disk_snapshot_cancel: true
VM.attachnic: true
VM.detachnic: true
VM.snapshot_create: true

View File

@ -192,6 +192,7 @@ tabs:
VM.attachdisk: true
VM.detachdisk: true
VM.saveas: false
VM.disk_snapshot_cancel: false
VM.attachnic: true
VM.detachnic: true
VM.snapshot_create: true

View File

@ -193,6 +193,7 @@ tabs:
VM.attachdisk: true
VM.detachdisk: true
VM.saveas: true
VM.disk_snapshot_cancel: true
VM.attachnic: true
VM.detachnic: true
VM.snapshot_create: true

View File

@ -56,6 +56,7 @@ module OpenNebulaJSON
when "restart" then self.restart
when "reset" then self.reset
when "saveas" then self.save_as(action_hash['params'])
when "disk_snapshot_cancel" then self.disk_snapshot_cancel(action_hash['params'])
when "snapshot_create" then self.snapshot_create(action_hash['params'])
when "snapshot_revert" then self.snapshot_revert(action_hash['params'])
when "snapshot_delete" then self.snapshot_delete(action_hash['params'])
@ -110,6 +111,10 @@ module OpenNebulaJSON
disk_snapshot(params['disk_id'].to_i, params['image_name'], params['type'], params['hot'], clone)
end
def disk_snapshot_cancel(params=Hash.new)
super(params['disk_id'].to_i)
end
def snapshot_create(params=Hash.new)
super(params['snapshot_name'])
end

View File

@ -1067,6 +1067,11 @@ var OpenNebula = {
OpenNebula.Action.simple_action(params,OpenNebula.VM.resource,
"saveas",action_obj);
},
"disk_snapshot_cancel": function(params){
var action_obj = {"disk_id": params.data.extra_param};
OpenNebula.Action.simple_action(params,OpenNebula.VM.resource,
"disk_snapshot_cancel",action_obj);
},
"snapshot_create": function(params){
var action_obj = params.data.extra_param;
OpenNebula.Action.simple_action(params,OpenNebula.VM.resource,

View File

@ -63,7 +63,7 @@ var state_actions = {
["VM.delete", "VM.delete_recreate", "VM.resume", "VM.deploy"],
5: //OpenNebula.VM.state.SUSPENDED:
["VM.delete", "VM.resume"],
["VM.delete", "VM.resume", "VM.saveas", "VM.disk_snapshot_cancel"],
6: //OpenNebula.VM.state.DONE:
[],
@ -72,7 +72,7 @@ var state_actions = {
["VM.delete", "VM.delete_recreate", "VM.resize"],
8: //OpenNebula.VM.state.POWEROFF:
["VM.delete", "VM.resume", "VM.resize", "VM.attachdisk", "VM.detachdisk", "VM.attachnic", "VM.detachnic", "VM.migrate"],
["VM.delete", "VM.resume", "VM.resize", "VM.attachdisk", "VM.detachdisk", "VM.attachnic", "VM.detachnic", "VM.saveas", "VM.disk_snapshot_cancel", "VM.migrate"],
9: //OpenNebula.VM.state.UNDEPLOYED:
["VM.delete", "VM.delete_recreate", "VM.resume", "VM.resize", "VM.deploy"],
@ -86,7 +86,7 @@ var lcm_state_actions = {
2: //OpenNebula.VM.lcm_state.BOOT:
["VM.boot"],
3: //OpenNebula.VM.lcm_state.RUNNING:
["VM.shutdown", "VM.shutdown_hard", "VM.stop", "VM.suspend", "VM.reboot", "VM.reboot_hard", "VM.resched", "VM.unresched", "VM.poweroff", "VM.poweroff_hard", "VM.undeploy", "VM.undeploy_hard", "VM.migrate", "VM.migrate_live", "VM.attachdisk", "VM.detachdisk", "VM.attachnic", "VM.detachnic"],
["VM.shutdown", "VM.shutdown_hard", "VM.stop", "VM.suspend", "VM.reboot", "VM.reboot_hard", "VM.resched", "VM.unresched", "VM.poweroff", "VM.poweroff_hard", "VM.undeploy", "VM.undeploy_hard", "VM.migrate", "VM.migrate_live", "VM.attachdisk", "VM.detachdisk", "VM.attachnic", "VM.detachnic", "VM.saveas", "VM.disk_snapshot_cancel"],
4: //OpenNebula.VM.lcm_state.MIGRATE:
[],
5: //OpenNebula.VM.lcm_state.SAVE_STOP:
@ -112,7 +112,7 @@ var lcm_state_actions = {
15: //OpenNebula.VM.lcm_state.CLEANUP_RESUBMIT:
[],
16: //OpenNebula.VM.lcm_state.UNKNOWN:
["VM.shutdown", "VM.shutdown_hard", "VM.boot", "VM.resched", "VM.unresched", "VM.poweroff", "VM.poweroff_hard", "VM.undeploy", "VM.undeploy_hard", "VM.migrate", "VM.migrate_live"],
["VM.shutdown", "VM.shutdown_hard", "VM.boot", "VM.resched", "VM.unresched", "VM.poweroff", "VM.poweroff_hard", "VM.undeploy", "VM.undeploy_hard", "VM.migrate", "VM.migrate_live", "VM.disk_snapshot_cancel"],
17: //OpenNebula.VM.lcm_state.HOTPLUG:
[],
18: //OpenNebula.VM.lcm_state.SHUTDOWN_POWEROFF:
@ -555,6 +555,17 @@ var vm_actions = {
notify: true
},
"VM.disk_snapshot_cancel" : {
type: "single",
call: OpenNebula.VM.disk_snapshot_cancel,
callback: function(request) {
Sunstone.runAction("VM.show", request.request.data[0]);
OpenNebula.Helper.clear_cache("IMAGE");
},
error:onError,
notify: true
},
"VM.snapshot_create" : {
type: "single",
call: OpenNebula.VM.snapshot_create,
@ -2030,10 +2041,18 @@ function printDisks(vm_info){
actions = '';
if (Config.isTabActionEnabled("vms-tab", "VM.saveas")) {
// Check if its volatie
if (disk.IMAGE_ID) {
if ((vm_info.STATE == "3" && vm_info.LCM_STATE == "3") || vm_info.STATE == "5" || vm_info.STATE == "8") {
if (disk.SAVE == "YES") {
if (Config.isTabActionEnabled("vms-tab", "VM.disk_snapshot_cancel")) {
if ( enabledStateAction("VM.disk_snapshot_cancel", vm_info.STATE, vm_info.LCM_STATE)) {
actions += '<a href="VM.disk_snapshot_cancel" class="disk_snapshot_cancel" >\
<i class="fa fa-times"/></span>'+tr("Cancel Snapshot")+'</a> &emsp;'
}
}
} else {
if (Config.isTabActionEnabled("vms-tab", "VM.saveas")) {
// Check if it's volatile
if ( disk.IMAGE_ID &&
enabledStateAction("VM.saveas", vm_info.STATE, vm_info.LCM_STATE)) {
actions += '<a href="VM.saveas" class="saveas" ><i class="fa fa-save"/>'+tr("Snapshot")+'</a> &emsp;'
}
}
@ -2225,6 +2244,18 @@ function hotpluggingOps(){
});
}
if (Config.isTabActionEnabled("vms-tab", "VM.disk_snapshot_cancel")) {
$('a.disk_snapshot_cancel').live('click', function(){
var b = $(this);
var vm_id = b.parents('form').attr('vmid');
var disk_id = b.parents('tr').attr('disk_id');
Sunstone.runAction('VM.disk_snapshot_cancel', vm_id, disk_id);
return false;
});
}
if (Config.isTabActionEnabled("vms-tab", "VM.attachdisk")) {
setupAttachDiskDialog();

View File

@ -3353,6 +3353,51 @@ int VirtualMachine::save_disk(int disk_id,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::clear_save_disk(int disk_id)
{
VectorAttribute * disk;
disk = get_disk(disk_id);
if ( disk != 0 )
{
disk->remove("SAVE_AS_SOURCE");
disk->remove("SAVE_AS");
disk->replace("SAVE", "NO");
return 0;
}
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::get_save_disk_image(int disk_id)
{
VectorAttribute * disk;
bool save;
int img_id = -1;
disk = get_disk(disk_id);
if ( disk != 0 )
{
disk->vector_value("SAVE", save);
if (save)
{
disk->vector_value("SAVE_AS", img_id);
}
}
return img_id;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::save_disk_hot(int disk_id,
const string& source,
int img_id)