From c1c3d0479dcd03a9330527d8dc643a0005177a2c Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 15 Dec 2016 21:12:33 +0100 Subject: [PATCH] F #4393: More work on resize --- include/DispatchManager.h | 16 +++ include/RequestManagerVirtualMachine.h | 22 +++ include/Template.h | 8 ++ include/VirtualMachineDisk.h | 26 ++++ src/dm/DispatchManagerActions.cc | 124 +++++++++++++++++ src/lcm/LifeCycleStates.cc | 2 +- src/rm/RequestManagerVirtualMachine.cc | 185 +++++++++++++++++++++++++ src/vm/VirtualMachineDisk.cc | 162 ++++++++++++++++++---- 8 files changed, 516 insertions(+), 29 deletions(-) diff --git a/include/DispatchManager.h b/include/DispatchManager.h index 5c79353865..b205824f77 100644 --- a/include/DispatchManager.h +++ b/include/DispatchManager.h @@ -347,6 +347,7 @@ public: int id, int nic_id, string& error_str); + /** * Starts the snapshot create action * @@ -441,6 +442,21 @@ public: int snap_id, string& error_str); + /** + * Starts the disk resize create action + * + * @param vid VirtualMachine identification + * @param did DISK identification + * @param size new size for the disk + * @param error_str Error reason, if any + * + * @return 0 on success, -1 otherwise + */ + int disk_resize( + int vid, + int did, + long long new_size, + string& error_str); private: /** diff --git a/include/RequestManagerVirtualMachine.h b/include/RequestManagerVirtualMachine.h index a414e3c031..22520a5bd2 100644 --- a/include/RequestManagerVirtualMachine.h +++ b/include/RequestManagerVirtualMachine.h @@ -483,4 +483,26 @@ public: RequestAttributes& att); }; +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VirtualMachineDiskResize : public RequestManagerVirtualMachine +{ +public: + VirtualMachineDiskResize(): + RequestManagerVirtualMachine("VirtualMachineDiskResize", + "Resizes a disk from a virtual machine", + "A:siis"){ + Nebula& nd = Nebula::instance(); + ipool = nd.get_ipool(); + }; + + ~VirtualMachineDiskResize(){}; + + void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att); +private: + ImagePool* ipool; +}; + #endif diff --git a/include/Template.h b/include/Template.h index 8ad0d9051e..70157ef32f 100644 --- a/include/Template.h +++ b/include/Template.h @@ -412,6 +412,14 @@ public: */ virtual bool has_restricted(); + /** + * @return true if template is empty + */ + bool empty() + { + return attributes.empty(); + } + protected: /** * The template attributes diff --git a/include/VirtualMachineDisk.h b/include/VirtualMachineDisk.h index b16c252138..51d04c95a1 100644 --- a/include/VirtualMachineDisk.h +++ b/include/VirtualMachineDisk.h @@ -232,6 +232,32 @@ public: */ void delete_snapshot(int snap_id, Template **ds_quota, Template **vm_quota); + /* ---------------------------------------------------------------------- */ + /* Disk space usage functions */ + /* ---------------------------------------------------------------------- */ + + /** + * @return the space required by this disk in the system datastore + */ + long long system_ds_size(); + + /** + * Calculate the quotas for a resize operation on the disk + * @param new_size of disk + * @param dsdeltas increment in datastore usage + * @param vmdelta increment in system datastore usage + */ + void resize_quotas(long long new_size, Template& dsdelta, Template& vmdelta); + + /** + * Compute the storage needed by the disk in the system and/or image + * datastore + * @param ds_id of the datastore + * @param img_sz size in image datastore needed + * @param sys_sz size in system datastore needed + */ + void datastore_sizes(int& ds_id, long long& img_sz, long long& sys_sz); + private: Snapshots * snapshots; diff --git a/src/dm/DispatchManagerActions.cc b/src/dm/DispatchManagerActions.cc index d77618cdb7..a123ee4e52 100644 --- a/src/dm/DispatchManagerActions.cc +++ b/src/dm/DispatchManagerActions.cc @@ -2045,3 +2045,127 @@ int DispatchManager::disk_snapshot_delete( return 0; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int DispatchManager::disk_resize( + int vid, + int did, + long long new_size, + string& error_str) +{ + ostringstream oss; + time_t the_time; + + VirtualMachine * vm = vmpool->get(vid, true); + + if ( vm == 0 ) + { + oss << "Could not resize disk for VM " << vid << ", VM does not exist" ; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + return -1; + } + + VirtualMachine::VmState state = vm->get_state(); + VirtualMachine::LcmState lstate = vm->get_lcm_state(); + + if ((state !=VirtualMachine::POWEROFF || lstate !=VirtualMachine::LCM_INIT)&& + (state !=VirtualMachine::STOPPED || lstate !=VirtualMachine::LCM_INIT)&& + (state !=VirtualMachine::UNDEPLOYED || lstate !=VirtualMachine::LCM_INIT)&& + (state !=VirtualMachine::ACTIVE || lstate !=VirtualMachine::RUNNING)) + { + oss << "Could not resize disk for VM " << vid << ", wrong state " + << vm->state_str() << "."; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + vm->unlock(); + + return -1; + } + + // Set the VM info in the history before the disk is resized + vm->set_vm_info(); + + int rc = vm->set_up_resize_disk(did, new_size, error_str); + + if (rc == -1) + { + vm->unlock(); + return -1; + } +/* + switch(state) + { + case VirtualMachine::POWEROFF: + vm->set_state(VirtualMachine::ACTIVE); + vm->set_state(VirtualMachine::DISK_RESIZE_POWEROFF); + break; + + case VirtualMachine::STOPPED: + vm->set_state(VirtualMachine::ACTIVE); + vm->set_state(VirtualMachine::DISK_RESIZE_STOPPED); + break; + + case VirtualMachine::UNDEPLOYED: + vm->set_state(VirtualMachine::ACTIVE); + vm->set_state(VirtualMachine::DISK_RESIZE_UNDEPLOYED); + break; + + case VirtualMachine::ACTIVE: + vm->set_state(VirtualMachine::ACTIVE); + vm->set_state(VirtualMachine::DISK_RESIZE); + break; + + default: break; + } + + vmpool->update(vm); + + vm->unlock(); + + switch(state) + { + case VirtualMachine::POWEROFF: + case VirtualMachine::SUSPENDED: + tm->trigger(TransferManager::SNAPSHOT_CREATE,vid); + break; + + case VirtualMachine::ACTIVE: + the_time = time(0); + + // Close current history record + + vm->set_running_etime(the_time); + + vm->set_etime(the_time); + + vm->set_action(History::DISK_SNAPSHOT_CREATE_ACTION); + vm->set_reason(History::USER); + + vmpool->update_history(vm); + + // Open a new history record + + vm->cp_history(); + + vm->set_stime(the_time); + + vm->set_running_stime(the_time); + + vmpool->update_history(vm); + + vmm->trigger(VirtualMachineManager::DISK_SNAPSHOT_CREATE, vid); + break; + + default: break; + } +*/ + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 0faf7eaa9b..a1f82ddcec 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -1994,7 +1994,7 @@ void LifeCycleManager::disk_snapshot_success(int vid) } // Update image if it is persistent and ln mode does not clone it - if ( img_id != -1 && is_persistent && has_snaps && target != "SYSTEM" ) + if ( img_id != -1 && is_persistent && has_snaps && target == "NONE" ) { imagem->set_image_snapshots(img_id, snaps); } diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index ebb9313635..3959e05104 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -2888,3 +2888,188 @@ void VirtualMachineUpdateConf::request_execute( vm->unlock(); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineDiskResize::request_execute( + xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + Nebula& nd = Nebula::instance(); + DispatchManager * dm = nd.get_dm(); + + VirtualMachine * vm; + + Template ds_deltas; + Template vm_deltas; + + PoolObjectAuth vm_perms; + + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int did = xmlrpc_c::value_int(paramList.getInt(2)); + string size_s = xmlrpc_c::value_string(paramList.getString(3)); + + long long size , current_size; + + // ------------------------------------------------------------------------ + // Check request consistency (VM & disk exists, size, and no snapshots) + // ------------------------------------------------------------------------ + istringstream iss(size_s); + + iss >> size; + + if (iss.fail() || !iss.eof()) + { + att.resp_msg = "Disk SIZE is not a valid integer"; + failure_response(ACTION, att); + + return; + } + + if ((vm = get_vm(id, att)) == 0) + { + return; + } + + VirtualMachineDisk * disk =vm->get_disk(did); + + if (disk == 0) + { + att.resp_msg = "VM disk does not exist"; + failure_response(ACTION, att); + + vm->unlock(); + + return; + } + + disk->vector_value("SIZE", current_size); + + if ( size <= current_size ) + { + att.resp_msg = "New disk size has to be greater than current one"; + failure_response(ACTION, att); + + vm->unlock(); + + return; + } + + if ( disk->has_snapshots() ) + { + att.resp_msg = "Cannot resize a disk with snapshots"; + failure_response(ACTION, att); + + vm->unlock(); + + return; + } + + /* ------------- Get information about the disk and image --------------- */ + bool is_persistent = disk->is_persistent(); + + disk->resize_quotas(size, ds_deltas, vm_deltas); + + int img_id = -1; + disk->vector_value("IMAGE_ID", img_id); + + vm->get_permissions(vm_perms); + + vm->unlock(); + + /* ---------------------------------------------------------------------- */ + /* Authorize the request for VM and IMAGE for persistent disks */ + /* ---------------------------------------------------------------------- */ + RequestAttributes ds_att_quota; + RequestAttributes vm_att_quota; + + if ( is_persistent ) + { + PoolObjectAuth img_perms; + + if ( img_id != -1 ) + { + Image* img = ipool->get(img_id, true); + + if (img == 0) + { + att.resp_obj = PoolObjectSQL::IMAGE; + att.resp_id = img_id; + failure_response(NO_EXISTS, att); + + return; + } + + img->get_permissions(img_perms); + + img->unlock(); + } + + if (vm_authorization(id, 0, 0, att, 0, 0, &img_perms, auth_op) == false) + { + return; + } + + ds_att_quota = RequestAttributes(img_perms.uid, img_perms.gid, att); + } + else + { + if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false ) + { + return; + } + + ds_att_quota = RequestAttributes(vm_perms.uid, vm_perms.gid, att); + } + + /* ---------------------------------------------------------------------- */ + /* Check quotas for the new size in image/system datastoress */ + /* ---------------------------------------------------------------------- */ + + if ( !ds_deltas.empty() ) + { + if (!quota_authorization(&ds_deltas, Quotas::DATASTORE, ds_att_quota)) + { + return; + } + } + + if ( !vm_deltas.empty() ) + { + if (!quota_resize_authorization(id, &vm_deltas, vm_att_quota)) + { + if (!ds_deltas.empty()) + { + quota_rollback(&ds_deltas, Quotas::DATASTORE, ds_att_quota); + } + + return; + } + } + + // ------------------------------------------------------------------------ + // Do the snapshot + // ------------------------------------------------------------------------ + int rc = dm->disk_resize(id, did, size, att.resp_msg); + + if ( rc != 0 ) + { + if ( !ds_deltas.empty() ) + { + quota_rollback(&ds_deltas, Quotas::DATASTORE, ds_att_quota); + } + + if ( !vm_deltas.empty() ) + { + quota_rollback(&vm_deltas, Quotas::VM, vm_att_quota); + } + + failure_response(ACTION, att); + } + else + { + success_response(did, att); + } + + return; +} diff --git a/src/vm/VirtualMachineDisk.cc b/src/vm/VirtualMachineDisk.cc index 945dd2204e..f8d08b9e63 100644 --- a/src/vm/VirtualMachineDisk.cc +++ b/src/vm/VirtualMachineDisk.cc @@ -316,6 +316,112 @@ void VirtualMachineDisk::delete_snapshot(int snap_id, Template **ds_quotas, } } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +long long VirtualMachineDisk::system_ds_size() +{ + long long disk_sz, snapshot_sz = 0; + + if ( vector_value("SIZE", disk_sz) != 0 ) + { + return 0; + } + + //Volatile disks don't have snapshots + if (vector_value("DISK_SNAPSHOT_TOTAL_SIZE", snapshot_sz) == 0) + { + disk_sz += snapshot_sz; + } + + if ( is_volatile() || get_tm_target() == "SYSTEM" ) + { + return disk_sz; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineDisk::resize_quotas(long long new_size, Template& ds_deltas, + Template& vm_deltas) +{ + long long current_size, delta_size; + + if ( vector_value("SIZE", current_size) != 0 ) + { + return; + } + + delta_size = new_size - current_size; + + bool is_system = get_tm_target() == "SYSTEM"; + string ds_id = vector_value("DATASTORE_ID"); + + if ( !is_volatile() && ( is_persistent() || !is_system ) ) + { + ds_deltas.add("DATASTORE", ds_id); + ds_deltas.add("SIZE", delta_size); + ds_deltas.add("IMAGES", 0); + } + + if ( is_volatile() || is_system ) + { + VectorAttribute * delta_disk = new VectorAttribute("DISK"); + delta_disk->replace("TYPE", "FS"); + delta_disk->replace("SIZE", delta_size); + + vm_deltas.add("VMS", 0); + vm_deltas.set(delta_disk); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineDisk::datastore_sizes(int& ds_id, long long& image_sz, + long long& system_sz) +{ + long long tmp_size, snapshot_size; + + image_sz = 0; + system_sz = 0; + ds_id = -1; + + if ( vector_value("SIZE", tmp_size) != 0 ) + { + return; + } + + if ( vector_value("DISK_SNAPSHOT_TOTAL_SIZE", snapshot_size) == 0 ) + { + tmp_size += snapshot_size; + } + + if ( is_volatile() ) + { + system_sz = tmp_size; + return; + } + else + { + string target = get_tm_target(); + + if ( target == "SYSTEM" ) + { + system_sz = tmp_size; + } + else if ( target == "SELF" ) + { + vector_value("DATASTORE_ID", ds_id); + + image_sz = tmp_size; + }// else if ( target == "NONE" ) + } +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -341,26 +447,7 @@ long long VirtualMachineDisks::system_ds_size() for ( disk_iterator disk = begin() ; disk != end() ; ++disk ) { - long long tmp_size; - - if ( (*disk)->vector_value("SIZE", tmp_size) != 0 ) - { - continue; - } - - if ( (*disk)->is_volatile() ) - { - size += tmp_size; - } - else if ( (*disk)->get_tm_target() == "SYSTEM" ) - { - size += tmp_size; - - if ((*disk)->vector_value("DISK_SNAPSHOT_TOTAL_SIZE",tmp_size) == 0) - { - size += tmp_size; - } - } + size += (*disk)->system_ds_size(); } return size; @@ -373,6 +460,33 @@ long long VirtualMachineDisks::system_ds_size(Template * ds_tmpl) return disks.system_ds_size(); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* +void VirtualMachineDisks::image_ds_size(bool resize_snapshot, long long system, + std::map& ds_size) const +{ + int ds_id; + long long system_sz, image_sz; + + for ( disk_iterator disk = begin() ; disk != end() ; ++disk ) + { + (*disk)->ds_size(resize_snapshot, ds_id, image_sz, system_sz); + + system += system_sz; + + if ( ds_id != -1 && image_sz > 0 ) + { + if (ds_size.count(ds_id) == 0) + { + ds_size[ds_id] = 0; + } + + ds_size[ds_id] += image_sz; + } + } +} +*/ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -418,14 +532,6 @@ bool VirtualMachineDisks::volatile_info(int ds_id) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VirtualMachineDisks::image_ds_size(std::map& ds_size) const -{ - -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - void VirtualMachineDisks::get_image_ids(set& ids, int uid) { int id;