From 725337ea5eaf4ca2dd7539db5e300edfc94ddde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Czern=C3=BD?= Date: Tue, 12 Dec 2023 16:19:20 +0100 Subject: [PATCH] B #6355: Fix VM quotas (#2861) * Remove useless default values from VM quotas, adapt chown and chgrp to it * Fix VM transition from poweroff, stopped, suspended, undeployed to done when quotas are tmp exceeded * Fix VM transition from poweroff to undeployed * Fix VM transition from suspended to stopped (cherry picked from commit 1e25904148a1900d5355963ee3c10dc2a037c883) --- include/Quota.h | 11 ++- include/QuotaVirtualMachine.h | 6 ++ include/Quotas.h | 22 ++++- src/lcm/LifeCycleActions.cc | 54 +++++++++-- src/lcm/LifeCycleStates.cc | 1 - src/rm/RequestManagerChown.cc | 2 + src/rm/RequestManagerVirtualMachine.cc | 7 -- src/um/Quota.cc | 34 +++++++ src/um/QuotaVirtualMachine.cc | 123 ++++++++++++++++--------- src/um/Quotas.cc | 31 ++++++- src/vm/VirtualMachine.cc | 8 +- src/vm/VirtualMachineDisk.cc | 2 - src/vm/VirtualMachinePool.cc | 1 - src/vm/VirtualMachineSystemSnapshot.cc | 1 - 14 files changed, 228 insertions(+), 75 deletions(-) diff --git a/include/Quota.h b/include/Quota.h index 8e3f5634f1..9198be7cd0 100644 --- a/include/Quota.h +++ b/include/Quota.h @@ -39,10 +39,11 @@ public: virtual bool check(Template* tmpl, Quotas& default_quotas, std::string& error) = 0; /** - * Decrement usage counters when deallocating image + * Decrement usage counters * @param tmpl template for the resource */ virtual void del(Template* tmpl) = 0; + /** * Set the quotas. If the quota previously exists its limit is updated. * @param quota_str the quota template in ASCII or XML formats @@ -251,6 +252,14 @@ protected: Quotas& default_quotas, std::string& error); + /** + * Add usage for a given quota without checking the limits + * @param qid id that identifies the quota, to be used by get_quota + * @param usage_req usage for each metric + */ + void add_quota(const std::string& qid, + std::map& usage_req); + /** * Reduce usage from a given quota based on the current consumption * @param qid id that identifies the quota, to be used by get_quota diff --git a/include/QuotaVirtualMachine.h b/include/QuotaVirtualMachine.h index e6ed14c307..3ac9c588da 100644 --- a/include/QuotaVirtualMachine.h +++ b/include/QuotaVirtualMachine.h @@ -75,6 +75,12 @@ public: */ bool update(Template * tmpl, Quotas& default_quotas, std::string& error) override; + /** + * Add usage counters. Use carefully this method does not care about exceeding the quota + * @param tmpl Template with the quota usage + */ + void add(Template* tmpl); + /** * Decrement usage counters when deallocating image * @param tmpl template for the resource diff --git a/include/Quotas.h b/include/Quotas.h index f9c382a287..0139bdc642 100644 --- a/include/Quotas.h +++ b/include/Quotas.h @@ -50,7 +50,7 @@ public: /** * Delete usage from quota counters. - * @param tmpl template for the image, with usage + * @param tmpl Template with the quota usage */ void ds_del(Template * tmpl) { @@ -70,6 +70,15 @@ public: return datastore_quota.get_quota(id, va); } + /** + * Add VM quota usage, without checking limits + * @param tmpl Template with the quota usage + */ + void vm_add(Template * tmpl) + { + vm_quota.add(tmpl); + } + /** * Gets a VM quota identified by its ID. * @@ -157,6 +166,15 @@ public: */ int from_xml(ObjectXML * object_xml); + /** + * Add VM quota usage, without checking the limits + * @param uid of the user + * @param gid of the group + * @param tmpl template with quota usage + * @note Use carefully as this method may exceed quota limits + */ + static void vm_add(int uid, int gid, Template * tmpl); + /** * Delete VM related usage (network, image and compute) from quota counters. * for the given user and group @@ -244,7 +262,7 @@ public: * @param type the quota to work with * @param uid of the user * @param gid of the group - * @param tmpl template for the image, with usage + * @param tmpl template with quota usage */ static void quota_del(QuotaType type, int uid, int gid, Template * tmpl); diff --git a/src/lcm/LifeCycleActions.cc b/src/lcm/LifeCycleActions.cc index f33e87ff01..48f2c9c41b 100644 --- a/src/lcm/LifeCycleActions.cc +++ b/src/lcm/LifeCycleActions.cc @@ -192,6 +192,20 @@ void LifeCycleManager::trigger_stop(int vid, const RequestAttributes& ra) //---------------------------------------------------- // Bypass SAVE_STOP //---------------------------------------------------- + VirtualMachineTemplate quota_tmpl; + + std::string memory, cpu; + + int quota_uid = vm->get_uid(); + int quota_gid = vm->get_gid(); + + vm->get_template_attribute("MEMORY", memory); + vm->get_template_attribute("CPU", cpu); + + quota_tmpl.add("RUNNING_MEMORY", memory); + quota_tmpl.add("RUNNING_CPU", cpu); + quota_tmpl.add("RUNNING_VMS", 1); + vm->set_state(VirtualMachine::ACTIVE); vm->set_state(VirtualMachine::EPILOG_STOP); @@ -206,6 +220,10 @@ void LifeCycleManager::trigger_stop(int vid, const RequestAttributes& ra) //---------------------------------------------------- tm->trigger_epilog_stop(vm.get()); + + // Add running quota, it will be removed in DM::stop_success + vm.reset(); + Quotas::vm_add(quota_uid, quota_gid, "a_tmpl); } else { @@ -428,7 +446,6 @@ void LifeCycleManager::trigger_shutdown(int vid, bool hard, trigger([this, hard, vid, uid, gid, req_id] { auto vm = vmpool->get(vid); VirtualMachineTemplate quota_tmpl; - string error; if ( vm == nullptr ) { @@ -451,10 +468,6 @@ void LifeCycleManager::trigger_shutdown(int vid, bool hard, quota_tmpl.add("RUNNING_MEMORY", memory); quota_tmpl.add("RUNNING_CPU", cpu); quota_tmpl.add("RUNNING_VMS", 1); - - quota_tmpl.add("MEMORY", 0); - quota_tmpl.add("CPU", 0); - quota_tmpl.add("VMS", 0); } auto lcm_state = vm->get_lcm_state(); @@ -505,8 +518,6 @@ void LifeCycleManager::trigger_shutdown(int vid, bool hard, vm->set_state(VirtualMachine::ACTIVE); vm->set_state(VirtualMachine::EPILOG); - Quotas::vm_check(uid, gid, "a_tmpl, error); - vm->set_action(VMActions::TERMINATE_ACTION, uid, gid, req_id); vm->set_epilog_stime(time(0)); @@ -518,6 +529,10 @@ void LifeCycleManager::trigger_shutdown(int vid, bool hard, //---------------------------------------------------- tm->trigger_epilog(false, vm.get()); + + // Add running quota, it will be removed in DM::done + vm.reset(); + Quotas::vm_add(uid, gid, "a_tmpl); } else if (vm->get_state() == VirtualMachine::STOPPED || vm->get_state() == VirtualMachine::UNDEPLOYED) @@ -525,8 +540,6 @@ void LifeCycleManager::trigger_shutdown(int vid, bool hard, vm->set_state(VirtualMachine::ACTIVE); vm->set_state(VirtualMachine::EPILOG); - Quotas::vm_check(uid, gid, "a_tmpl, error); - vm->set_action(VMActions::TERMINATE_ACTION, uid, gid, req_id); vm->set_epilog_stime(time(0)); @@ -538,6 +551,10 @@ void LifeCycleManager::trigger_shutdown(int vid, bool hard, //---------------------------------------------------- tm->trigger_epilog(true, vm.get()); + + // Add running quota, it will be removed in DM::done + vm.reset(); + Quotas::vm_add(uid, gid, "a_tmpl); } else { @@ -612,6 +629,20 @@ void LifeCycleManager::trigger_undeploy(int vid, bool hard, // Bypass SHUTDOWN_UNDEPLOY //---------------------------------------------------- + VirtualMachineTemplate quota_tmpl; + + std::string memory, cpu; + + int quota_uid = vm->get_uid(); + int quota_gid = vm->get_gid(); + + vm->get_template_attribute("MEMORY", memory); + vm->get_template_attribute("CPU", cpu); + + quota_tmpl.add("RUNNING_MEMORY", memory); + quota_tmpl.add("RUNNING_CPU", cpu); + quota_tmpl.add("RUNNING_VMS", 1); + vm->set_state(VirtualMachine::ACTIVE); vm->set_state(VirtualMachine::EPILOG_UNDEPLOY); @@ -626,6 +657,11 @@ void LifeCycleManager::trigger_undeploy(int vid, bool hard, //---------------------------------------------------- tm->trigger_epilog_stop(vm.get()); + + vm.reset(); + + // Add running quota, it will be removed in DM:undeploy_success + Quotas::vm_add(quota_uid, quota_gid, "a_tmpl); } else { diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 814080ee87..0cdf750154 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -1601,7 +1601,6 @@ void LifeCycleManager::trigger_snapshot_delete_success(int vid) Template quota_tmpl; quota_tmpl.set(snap); - quota_tmpl.replace("VMS", 0); Quotas::quota_del(Quotas::VM, vm_uid, vm_gid, "a_tmpl); } diff --git a/src/rm/RequestManagerChown.cc b/src/rm/RequestManagerChown.cc index 309f825c29..cafb5eead1 100644 --- a/src/rm/RequestManagerChown.cc +++ b/src/rm/RequestManagerChown.cc @@ -79,6 +79,8 @@ unique_ptr RequestManagerChown::get_and_quota( tmpl->add("RUNNING_VMS", 1); } + tmpl->add("VMS", 1); + VirtualMachineDisks::image_ds_quotas(tmpl.get(), ds_quotas); quota_map.insert(make_pair(Quotas::VIRTUALMACHINE, move(tmpl))); diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index 5b18c0c5a2..fc739e61c0 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -525,10 +525,6 @@ Request::ErrorCode VirtualMachineAction::request_execute(RequestAttributes& att, quota_tmpl.add("RUNNING_CPU", cpu); quota_tmpl.add("RUNNING_VMS", 1); - quota_tmpl.add("VMS", 0); - quota_tmpl.add("MEMORY", 0); - quota_tmpl.add("CPU", 0); - att_aux.uid = vm->get_uid(); att_aux.gid = vm->get_gid(); @@ -2170,7 +2166,6 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, deltas.add("MEMORY", dmemory); deltas.add("CPU", dcpu); - deltas.add("VMS", 0); if (update_running_quota) { @@ -2347,8 +2342,6 @@ Request::ErrorCode VirtualMachineSnapshotCreate::request_execute(RequestAttribut Template quota_tmpl; quota_tmpl.set(snap); - quota_tmpl.add("MEMORY", 0); - quota_tmpl.add("CPU", 0); quota_tmpl.add("VMS", 0); RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att); diff --git a/src/um/Quota.cc b/src/um/Quota.cc index 1c4ed5093d..f0aabfc2a5 100644 --- a/src/um/Quota.cc +++ b/src/um/Quota.cc @@ -274,6 +274,40 @@ bool Quota::check_quota(const string& qid, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void Quota::add_quota(const string& qid, map& usage_req) +{ + VectorAttribute * q; + + if ( get_quota(qid, &q) == -1) + { + return; + } + + if ( q == 0 ) + { + return; + } + + for (int i=0; i < num_metrics; i++) + { + string metrics_used = metrics[i]; + + metrics_used += "_USED"; + + auto it = usage_req.find(metrics[i]); + + if (it == usage_req.end()) + { + continue; + } + + add_to_quota(q, metrics_used, it->second); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void Quota::del_quota(const string& qid, map& usage_req) { VectorAttribute * q; diff --git a/src/um/QuotaVirtualMachine.cc b/src/um/QuotaVirtualMachine.cc index 9c6d88ce32..ac25340773 100644 --- a/src/um/QuotaVirtualMachine.cc +++ b/src/um/QuotaVirtualMachine.cc @@ -53,58 +53,53 @@ bool QuotaVirtualMachine::check(Template * tmpl, float cpu, running_cpu; long long size; - if ( tmpl->get("MEMORY", memory) == false || memory < 0 ) + if ( tmpl->get("MEMORY", memory) ) { - error = "MEMORY attribute must be a positive integer value"; - return false; + if ( memory < 0 ) + { + error = "MEMORY attribute must be a positive integer value"; + return false; + } + + vm_request.insert(make_pair("MEMORY", memory)); } - if ( tmpl->get("CPU", cpu) == false || cpu < 0 ) + if ( tmpl->get("CPU", cpu) ) { - error = "CPU attribute must be a positive float or integer value"; - return false; + if ( cpu < 0 ) + { + error = "CPU attribute must be a positive float or integer value"; + return false; + } + + vm_request.insert(make_pair("CPU", cpu)); } size = VirtualMachineDisks::system_ds_size(tmpl, true); size += VirtualMachine::get_snapshots_system_size(tmpl); - if ( tmpl->get("VMS", vms) == false ) + vm_request.insert(make_pair("SYSTEM_DISK_SIZE", size)); + + if ( tmpl->get("VMS", vms) ) { - vms = 1; + vm_request.insert(make_pair("VMS", vms)); } if ( tmpl->get("RUNNING_MEMORY", running_memory) ) { vm_request.insert(make_pair("RUNNING_MEMORY", running_memory)); } - else - { - vm_request.insert(make_pair("RUNNING_MEMORY", 0)); - } if ( tmpl->get("RUNNING_CPU", running_cpu) ) { vm_request.insert(make_pair("RUNNING_CPU", running_cpu)); } - else - { - vm_request.insert(make_pair("RUNNING_CPU", 0)); - } if ( tmpl->get("RUNNING_VMS", running_vms) ) { vm_request.insert(make_pair("RUNNING_VMS", running_vms)); } - else - { - vm_request.insert(make_pair("RUNNING_VMS", 0)); - } - - vm_request.insert(make_pair("VMS", vms)); - vm_request.insert(make_pair("MEMORY", memory)); - vm_request.insert(make_pair("CPU", cpu)); - vm_request.insert(make_pair("SYSTEM_DISK_SIZE", size)); return check_quota("", vm_request, default_quotas, error); } @@ -112,6 +107,54 @@ bool QuotaVirtualMachine::check(Template * tmpl, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void QuotaVirtualMachine::add(Template * tmpl) +{ + map vm_request; + + float value; + + if ( tmpl->get("MEMORY", value) ) + { + vm_request.insert(make_pair("MEMORY", value)); + } + + if ( tmpl->get("CPU", value) ) + { + vm_request.insert(make_pair("CPU", value)); + } + + if ( tmpl->get("VMS", value) ) + { + vm_request.insert(make_pair("VMS", value)); + } + + if ( tmpl->get("RUNNING_MEMORY", value) ) + { + vm_request.insert(make_pair("RUNNING_MEMORY", value)); + } + + if ( tmpl->get("RUNNING_CPU", value) ) + { + vm_request.insert(make_pair("RUNNING_CPU", value)); + } + + if ( tmpl->get("RUNNING_VMS", value) ) + { + vm_request.insert(make_pair("RUNNING_VMS", value)); + } + + long long size = VirtualMachineDisks::system_ds_size(tmpl, true); + + size += VirtualMachine::get_snapshots_system_size(tmpl); + + vm_request.insert(make_pair("SYSTEM_DISK_SIZE", size)); + + add_quota("", vm_request); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void QuotaVirtualMachine::del(Template * tmpl) { map vm_request; @@ -120,46 +163,40 @@ void QuotaVirtualMachine::del(Template * tmpl) float cpu, running_cpu; long long size; - if ( tmpl->get("MEMORY", memory) == false ) + if ( tmpl->get("MEMORY", memory) ) { - memory = 0; + vm_request.insert(make_pair("MEMORY", memory)); } - if ( tmpl->get("CPU", cpu) == false ) + if ( tmpl->get("CPU", cpu) ) { - cpu = 0; + vm_request.insert(make_pair("CPU", cpu)); } - if ( tmpl->get("VMS", vms) == false ) + if ( tmpl->get("VMS", vms) ) { - vms = 1; + vm_request.insert(make_pair("VMS", vms)); } - if ( tmpl->get("RUNNING_MEMORY", running_memory) == false ) + if ( tmpl->get("RUNNING_MEMORY", running_memory) ) { - running_memory = 0; + vm_request.insert(make_pair("RUNNING_MEMORY", running_memory)); } - if ( tmpl->get("RUNNING_CPU", running_cpu) == false ) + if ( tmpl->get("RUNNING_CPU", running_cpu) ) { - running_cpu = 0; + vm_request.insert(make_pair("RUNNING_CPU", running_cpu)); } - if ( tmpl->get("RUNNING_VMS", running_vms) == false ) + if ( tmpl->get("RUNNING_VMS", running_vms) ) { - running_vms = 0; + vm_request.insert(make_pair("RUNNING_VMS", running_vms)); } size = VirtualMachineDisks::system_ds_size(tmpl, true); size += VirtualMachine::get_snapshots_system_size(tmpl); - vm_request.insert(make_pair("VMS", vms)); - vm_request.insert(make_pair("MEMORY", memory)); - vm_request.insert(make_pair("CPU", cpu)); - vm_request.insert(make_pair("RUNNING_VMS", running_vms)); - vm_request.insert(make_pair("RUNNING_MEMORY", running_memory)); - vm_request.insert(make_pair("RUNNING_CPU", running_cpu)); vm_request.insert(make_pair("SYSTEM_DISK_SIZE", size)); del_quota("", vm_request); diff --git a/src/um/Quotas.cc b/src/um/Quotas.cc index 3037406e60..76c6cc7c00 100644 --- a/src/um/Quotas.cc +++ b/src/um/Quotas.cc @@ -141,6 +141,36 @@ int Quotas::from_xml(ObjectXML * object_xml) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void Quotas::vm_add(int uid, int gid, Template * tmpl) +{ + Nebula& nd = Nebula::instance(); + UserPool * upool = nd.get_upool(); + GroupPool * gpool = nd.get_gpool(); + + if ( uid != UserPool::ONEADMIN_ID ) + { + if ( auto user = upool->get(uid) ) + { + user->quota.vm_add(tmpl); + + upool->update_quotas(user.get()); + } + } + + if ( gid != GroupPool::ONEADMIN_ID ) + { + if ( auto group = gpool->get(gid) ) + { + group->quota.vm_add(tmpl); + + gpool->update_quotas(group.get()); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void Quotas::quota_del(QuotaType type, Template *tmpl) { switch (type) @@ -195,7 +225,6 @@ bool Quotas::quota_check(QuotaType type, case VM: return vm_quota.check(tmpl, default_quotas, error_str); - case VIRTUALMACHINE: if ( network_quota.check(tmpl, default_quotas, error_str) == false ) { diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 7831dcbe1a..acf375b146 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -3980,13 +3980,7 @@ void VirtualMachine::get_quota_template(VirtualMachineTemplate& quota_tmpl, quota_tmpl.add("RUNNING_CPU", cpu); quota_tmpl.add("RUNNING_VMS", 1); - if (only_running) - { - quota_tmpl.add("MEMORY", 0); - quota_tmpl.add("CPU", 0); - quota_tmpl.add("VMS", 0); - } - else + if (!only_running) { quota_tmpl.add("MEMORY", memory); quota_tmpl.add("CPU", cpu); diff --git a/src/vm/VirtualMachineDisk.cc b/src/vm/VirtualMachineDisk.cc index 7380d180d5..5d68e62345 100644 --- a/src/vm/VirtualMachineDisk.cc +++ b/src/vm/VirtualMachineDisk.cc @@ -364,7 +364,6 @@ void VirtualMachineDisk::delete_snapshot(int snap_id, Template **ds_quotas, delta_disk->replace("TYPE", "FS"); delta_disk->replace("SIZE", ssize); - (*vm_quotas)->add("VMS", 0); (*vm_quotas)->set(delta_disk); } } @@ -1507,7 +1506,6 @@ void VirtualMachineDisks::delete_non_persistent_snapshots(Template &vm_quotas, delta_disk->replace("TYPE", "FS"); delta_disk->replace("SIZE", system_disk); - vm_quotas.add("VMS", 0); vm_quotas.set(delta_disk); } } diff --git a/src/vm/VirtualMachinePool.cc b/src/vm/VirtualMachinePool.cc index e3ecea23c5..121135ea33 100644 --- a/src/vm/VirtualMachinePool.cc +++ b/src/vm/VirtualMachinePool.cc @@ -1037,7 +1037,6 @@ void VirtualMachinePool::delete_attach_disk(std::unique_ptr vm) Template tmpl; tmpl.set(disk->vector_attribute()); - tmpl.add("VMS", 0); if (disk->is_volatile()) { diff --git a/src/vm/VirtualMachineSystemSnapshot.cc b/src/vm/VirtualMachineSystemSnapshot.cc index a1d72e3778..b42812e45e 100644 --- a/src/vm/VirtualMachineSystemSnapshot.cc +++ b/src/vm/VirtualMachineSystemSnapshot.cc @@ -264,7 +264,6 @@ void VirtualMachine::delete_snapshots(Template& snapshots) obj_template->remove("SNAPSHOT", attrs); snapshots.set(attrs); - snapshots.add("VMS", 0); } /* -------------------------------------------------------------------------- */