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

feature #1772:Resize VM capacity (cpu, memory and vcpu) offline

This commit is contained in:
Ruben S. Montero 2013-02-23 19:49:06 +01:00
parent 00b664dc8d
commit dcfa0a1773
17 changed files with 523 additions and 22 deletions

View File

@ -317,6 +317,19 @@ public:
}
};
/**
* Updates the capacity used in a host when a VM is resized
* counters
* @param cpu increment of cpu requested by the VM
* @param mem increment of memory requested by the VM
* @param disk not used
* @return 0 on success
*/
void update_capacity(int cpu, int mem, int disk)
{
host_share.update(cpu,mem,disk);
};
/**
* Tests whether a new VM can be hosted by the host or not
* @param cpu needed by the VM (percentage)

View File

@ -54,6 +54,19 @@ public:
running_vms++;
}
/**
* Updates the capacity of VM in this share
* @param cpu increment
* @param mem increment
* @param disk increment
*/
void update(int cpu, int mem, int disk)
{
cpu_usage += cpu;
mem_usage += mem;
disk_usage += disk;
}
/**
* Delete a VM from this share
* @param cpu requested by the VM

View File

@ -427,6 +427,16 @@ public:
obj_template->add(name, value);
}
/**
* Adds a float attribute
* @param att_name Name for the attribute
* @param att_val integer
*/
void add_template_attribute(const string& name, float value)
{
obj_template->add(name, value);
}
/**
* Factory method for templates, it should be implemented
* by classes that uses templates

View File

@ -51,13 +51,26 @@ public:
*/
virtual bool check(Template* tmpl, Quotas& default_quotas, string& error) = 0;
/**
* Check if a resource update in usage counters will exceed the
* quota limits. If not the usage counters are updated for that resource
* @param tmpl with increments in MEMORY and CPU
* @param default_quotas Quotas that contain the default limits
* @param error string
* @return true if the operation can be performed
*/
virtual bool update(Template * tmpl, Quotas& default_quotas, string& error)
{
error = "Update operation for quotas not supported.";
return false;
};
/**
* Decrement usage counters when deallocating image
* @param tmpl template for the resource
*/
virtual void del(Template* tmpl) = 0;
/**
* Returns the name that identifies the quota in a template
*/

View File

@ -57,6 +57,16 @@ public:
*/
bool check(Template* tmpl, Quotas& default_quotas, string& error);
/**
* Check if the resource update (change in MEMORY or CPU) will exceed the
* quota limits. If not the usage counters are updated
* @param tmpl with increments in MEMORY and CPU
* @param default_quotas Quotas that contain the default limits
* @param error string
* @return true if the operation can be performed
*/
bool update(Template * tmpl, Quotas& default_quotas, string& error);
/**
* Decrement usage counters when deallocating image
* @param tmpl template for the resource

View File

@ -141,13 +141,27 @@ public:
* @param tmpl template for the VirtualMachine
* @param default_quotas Quotas that contain the default limits
* @param error_str string describing the error
* @return true if VM can be allocated, false otherwise
* @return true if resource can be allocated, false otherwise
*/
bool quota_check(QuotaType type,
Template *tmpl,
Quotas& default_quotas,
string& error_str);
/**
* Update usage of an existing quota (e.g. size of an image), it updates
* the usage counters if quotas are not exceeded.
* @param type the quota to work with
* @param tmpl template for the VirtualMachine
* @param default_quotas Quotas that contain the default limits
* @param error_str string describing the error
* @return true if resource can be updated, false otherwise
*/
bool quota_update(QuotaType type,
Template *tmpl,
Quotas& default_quotas,
string& error_str);
/**
* Delete usage from the given quota counters.
* @param type the quota to work with

View File

@ -217,6 +217,21 @@ public:
RequestAttributes& att);
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class VirtualMachineResize : public RequestManagerVirtualMachine
{
public:
VirtualMachineResize():
RequestManagerVirtualMachine("VirtualMachineResize",
"Changes the capacity of the virtual machine",
"A:sidiib"){};
~VirtualMachineResize(){};
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -156,10 +156,10 @@ public:
oss << value;
return replace(name, oss.str());
return replace(name, oss.str());
}
/*
/*
* Adds a new single attribute to the template. It will replace an existing
* one if replace_mode was set to true
* @param name of the attribute
@ -184,6 +184,20 @@ public:
set(new SingleAttribute(name, oss.str()));
}
/**
* Adds a new single attribute to the template.
* @param name of the attribute
* @param value of the attribute
*/
void add(const string& name, float value)
{
ostringstream oss;
oss << value;
set(new SingleAttribute(name, oss.str()));
}
/**
* Removes an attribute from the template. The attributes are returned. The
* attributes MUST be freed by the calling funtion
@ -196,10 +210,10 @@ public:
vector<Attribute *>& values);
/**
* Removes an attribute from the template, but it DOES NOT free the
* Removes an attribute from the template, but it DOES NOT free the
* attribute.
* @param att Attribute to remove. It will be deleted
* @return pointer to the removed attribute or 0 if non attribute was
* @return pointer to the removed attribute or 0 if non attribute was
* removed
*/
virtual Attribute * remove(Attribute * att);

View File

@ -747,7 +747,7 @@ public:
};
// ------------------------------------------------------------------------
// Timers
// Timers &
// ------------------------------------------------------------------------
/**
* Gets time from last information polling.
@ -766,6 +766,14 @@ public:
*/
void get_requirements (int& cpu, int& memory, int& disk);
/**
* Resize the VM capacity
* @param cpu
* @param memory
* @param vcpu
*/
void resize (float cpu, int memory, int vcpu);
// ------------------------------------------------------------------------
// Network Leases & Disk Images
// ------------------------------------------------------------------------

View File

@ -103,6 +103,7 @@ EOT
}
]
#NOTE: Other options defined using this array, add new options at the end
TEMPLATE_OPTIONS=[
{
:name => 'cpu',
@ -212,6 +213,8 @@ EOT
TEMPLATE_OPTIONS_VM=[TEMPLATE_NAME_VM]+TEMPLATE_OPTIONS+[DRY]
CAPACITY_OPTIONS_VM=[TEMPLATE_OPTIONS[0],TEMPLATE_OPTIONS[1],TEMPLATE_OPTIONS[3]]
OPTIONS = XML, NUMERIC, KILOBYTES
class OneHelper

View File

@ -662,4 +662,23 @@ cmd=CommandParser::CmdParser.new(ARGV) do
:options=>CLIHelper::OPTIONS+OpenNebulaHelper::OPTIONS do
helper.list_pool(options, true, args[0])
end
resize_desc = <<-EOT.unindent
Resizes the capacity of a Virtual Machine (offline, the VM cannot be
RUNNING)
EOT
command :resize, resize_desc, :vmid, :options =>
OpenNebulaHelper::CAPACITY_OPTIONS_VM + [ENFORCE]do
cpu = options[:cpu] || 0
memory = options[:memory] || 0
vcpu = options[:vcpu] || 0
enforce = options[:enforce] || true
helper.perform_action(args[0], options, "Resizing VM") do |vm|
vm.resize(cpu, memory, vcpu, enforce)
end
end
end

View File

@ -37,7 +37,8 @@ module OpenNebula
:attach => "vm.attach",
:detach => "vm.detach",
:rename => "vm.rename",
:update => "vm.update"
:update => "vm.update",
:resize => "vm.resize"
}
VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED
@ -336,6 +337,17 @@ module OpenNebula
return rc
end
# Resize the VM
# @param cpu [Float] the new CPU value
# @param memory [Integer] the new MEMORY value
# @param vcpu [Integer] the new VCPU value
# @param enforce [true|false] If it is set to true, the host capacity
# will be checked
def resize(cpu, memory, vcpu, enforce)
return @client.call(VM_METHODS[:resize], @pe_id, cpu, memory,
vcpu, enforce)
end
# Changes the owner/group
# uid:: _Integer_ the new owner id. Set to -1 to leave the current one
# gid:: _Integer_ the new group id. Set to -1 to leave the current one

View File

@ -254,6 +254,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vm_monitoring(new VirtualMachineMonitoring());
xmlrpc_c::methodPtr vm_attach(new VirtualMachineAttach());
xmlrpc_c::methodPtr vm_detach(new VirtualMachineDetach());
xmlrpc_c::methodPtr vm_resize(new VirtualMachineResize());
xmlrpc_c::methodPtr vm_pool_acct(new VirtualMachinePoolAccounting());
xmlrpc_c::methodPtr vm_pool_monitoring(new VirtualMachinePoolMonitoring());
@ -396,6 +397,7 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.vm.attach", vm_attach);
RequestManagerRegistry.addMethod("one.vm.detach", vm_detach);
RequestManagerRegistry.addMethod("one.vm.rename", vm_rename);
RequestManagerRegistry.addMethod("one.vm.resize", vm_resize);
RequestManagerRegistry.addMethod("one.vm.update", vm_update);
RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info);

View File

@ -17,6 +17,7 @@
#include "RequestManagerVirtualMachine.h"
#include "PoolObjectAuth.h"
#include "Nebula.h"
#include "Quotas.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -1056,3 +1057,295 @@ void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int id = xmlrpc_c::value_int(paramList.getInt(1));
float ncpu = xmlrpc_c::value_int(paramList.getDouble(2));
int nmemory = xmlrpc_c::value_int(paramList.getInt(3));
int nvcpu = xmlrpc_c::value_int(paramList.getInt(4));
bool enforce = xmlrpc_c::value_boolean(paramList.getBoolean(5));
float ocpu, dcpu;
int omemory, dmemory;
Nebula& nd = Nebula::instance();
UserPool* upool = nd.get_upool();
GroupPool* gpool = nd.get_gpool();
Quotas dquotas = nd.get_default_user_quota();
HostPool * hpool = nd.get_hpool();
Host * host;
Template deltas;
string error_str;
bool rc;
int hid = -1;
PoolObjectAuth vm_perms;
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
VirtualMachine * vm;
vm = vmpool->get(id, true);
if (vm == 0)
{
failure_response(NO_EXISTS,
get_error(object_name(PoolObjectSQL::VM),id),
att);
return;
}
vm->get_permissions(vm_perms);
vm->get_template_attribute("MEMORY", omemory);
vm->get_template_attribute("CPU", ocpu);
dcpu = ncpu - ocpu;
dmemory = nmemory - omemory;
deltas.add("MEMORY", dmemory);
deltas.add("CPU", dcpu);
switch (vm->get_state())
{
case VirtualMachine::POWEROFF: //Only check host capacity in POWEROFF
if (vm->hasHistory() == true)
{
hid = vm->get_hid();
}
case VirtualMachine::INIT:
case VirtualMachine::PENDING:
case VirtualMachine::HOLD:
case VirtualMachine::FAILED:
break;
case VirtualMachine::STOPPED:
case VirtualMachine::DONE:
case VirtualMachine::SUSPENDED:
case VirtualMachine::ACTIVE:
failure_response(ACTION,
request_error("Wrong state to perform action",""),
att);
vm->unlock();
return;
}
vm->unlock();
/* ---------------------------------------------------------------------- */
/* Authorize the operation */
/* ---------------------------------------------------------------------- */
if ( att.uid != UserPool::ONEADMIN_ID )
{
AuthRequest ar(att.uid, att.gid);
ar.add_auth(AuthRequest::MANAGE, vm_perms);
if (enforce == false) //Admin rights to overcommit
{
ar.add_auth(AuthRequest::ADMIN, vm_perms);
}
if (UserPool::authorize(ar) == -1)
{
failure_response(AUTHORIZATION,
authorization_error(ar.message, att),
att);
vm->unlock();
return;
}
}
/* ---------------------------------------------------------------------- */
/* Check quotas */
/* ---------------------------------------------------------------------- */
if (att.uid != UserPool::ONEADMIN_ID)
{
User * user = upool->get(att.uid, true);
if ( user == 0 )
{
failure_response(NO_EXISTS,
get_error(object_name(PoolObjectSQL::USER),att.uid),
att);
return;
}
rc = user->quota.quota_update(Quotas::VM, &deltas, dquotas, error_str);
if (rc == false)
{
ostringstream oss;
oss << object_name(PoolObjectSQL::USER) << " [" << att.uid << "] "
<< error_str;
failure_response(AUTHORIZATION,
request_error(oss.str(), ""),
att);
user->unlock();
return;
}
user->unlock();
}
if (att.gid != GroupPool::ONEADMIN_ID)
{
Group * group = gpool->get(att.gid, true);
if ( group == 0 )
{
failure_response(NO_EXISTS,
get_error(object_name(PoolObjectSQL::GROUP),att.gid),
att);
return;
}
rc = group->quota.quota_update(Quotas::VM, &deltas, dquotas, error_str);
if (rc == false)
{
ostringstream oss;
RequestAttributes att_tmp(att.uid, -1, att);
oss << object_name(PoolObjectSQL::GROUP) << " [" << att.gid << "] "
<< error_str;
failure_response(AUTHORIZATION,
request_error(oss.str(), ""),
att);
group->unlock();
quota_rollback(&deltas, Quotas::VM, att_tmp);
return;
}
group->unlock();
}
/* ---------------------------------------------------------------------- */
/* Check & update host capacity */
/* ---------------------------------------------------------------------- */
if (hid != -1)
{
host = hpool->get(hid, true);
if (host == 0)
{
failure_response(NO_EXISTS,
get_error(object_name(PoolObjectSQL::HOST),hid),
att);
quota_rollback(&deltas, Quotas::VM, att);
return ;
}
if ( enforce && host->test_capacity(dcpu, dmemory, 0) == false )
{
ostringstream oss;
oss << object_name(PoolObjectSQL::HOST)
<< " " << hid << " does not have enough capacity.";
failure_response(ACTION, request_error(oss.str(),""), att);
host->unlock();
quota_rollback(&deltas, Quotas::VM, att);
return;
}
host->update_capacity(dcpu, dmemory, 0);
hpool->update(host);
host->unlock();
}
/* ---------------------------------------------------------------------- */
/* Resize the VM */
/* ---------------------------------------------------------------------- */
vm = vmpool->get(id, true);
if (vm == 0)
{
failure_response(NO_EXISTS,
get_error(object_name(PoolObjectSQL::VM),id),
att);
quota_rollback(&deltas, Quotas::VM, att);
if (hid != -1)
{
host = hpool->get(hid, true);
if (host != 0)
{
host->update_capacity(-dcpu, -dmemory, 0);
hpool->update(host);
host->unlock();
}
}
return;
}
//Check again state as the VM may transit to active (e.g. scheduled)
switch (vm->get_state())
{
case VirtualMachine::INIT:
case VirtualMachine::PENDING:
case VirtualMachine::HOLD:
case VirtualMachine::FAILED:
case VirtualMachine::POWEROFF:
vm->resize(ncpu, nmemory, nvcpu);
vmpool->update(vm);
break;
case VirtualMachine::STOPPED:
case VirtualMachine::DONE:
case VirtualMachine::SUSPENDED:
case VirtualMachine::ACTIVE:
failure_response(ACTION,
request_error("Wrong state to perform action",""),
att);
vm->unlock();
quota_rollback(&deltas, Quotas::VM, att);
if (hid != -1)
{
host = hpool->get(hid, true);
if (host != 0)
{
host->update_capacity(ocpu - ncpu, omemory - nmemory, 0);
hpool->update(host);
host->unlock();
}
}
return;
}
vm->unlock();
success_response(id, att);
}

View File

@ -117,3 +117,25 @@ int QuotaVirtualMachine::get_default_quota(
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool QuotaVirtualMachine::update(Template * tmpl,
Quotas& default_quotas,
string& error)
{
map<string, float> vm_request;
int delta_memory;
float delta_cpu;
if ( tmpl->get("MEMORY", delta_memory) == true )
{
vm_request.insert(make_pair("MEMORY", delta_memory));
}
if ( tmpl->get("CPU", delta_cpu) == true )
{
vm_request.insert(make_pair("CPU", delta_cpu));
}
return check_quota("", vm_request, default_quotas, error);
}

View File

@ -29,7 +29,7 @@ int Quotas::set(Template *tmpl, string& error)
{
return -1;
}
vquotas.clear();
}
@ -39,7 +39,7 @@ int Quotas::set(Template *tmpl, string& error)
{
return -1;
}
vquotas.clear();
}
@ -49,7 +49,7 @@ int Quotas::set(Template *tmpl, string& error)
{
return -1;
}
vquotas.clear();
}
@ -59,7 +59,7 @@ int Quotas::set(Template *tmpl, string& error)
{
return -1;
}
vquotas.clear();
}
@ -219,6 +219,31 @@ bool Quotas::quota_check(QuotaType type,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool Quotas::quota_update(QuotaType type,
Template *tmpl,
Quotas &default_quotas,
string &error_str)
{
switch (type)
{
// This is an internal check, should never get in here.
case DATASTORE:
case NETWORK:
case IMAGE:
case VIRTUALMACHINE:
error_str = "Cannot update quota. Not implemented";
return false;
case VM:
return vm_quota.update(tmpl, default_quotas, error_str);
}
return false;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void Quotas::quota_del(QuotaType type, int uid, int gid, Template * tmpl)
{
Nebula& nd = Nebula::instance();
@ -239,7 +264,7 @@ void Quotas::quota_del(QuotaType type, int uid, int gid, Template * tmpl)
upool->update(user);
user->unlock();
}
}
}
if ( gid != GroupPool::ONEADMIN_ID )
@ -253,6 +278,6 @@ void Quotas::quota_del(QuotaType type, int uid, int gid, Template * tmpl)
gpool->update(group);
group->unlock();
}
}
}
}

View File

@ -1258,14 +1258,11 @@ void VirtualMachine::cp_previous_history()
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk)
{
string scpu;
istringstream iss;
float fcpu;
get_template_attribute("MEMORY",memory);
get_template_attribute("CPU",scpu);
if ((memory == 0) || (scpu==""))
if ((get_template_attribute("MEMORY",memory) == false) ||
(get_template_attribute("CPU",fcpu) == false))
{
cpu = 0;
memory = 0;
@ -1274,9 +1271,6 @@ void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk)
return;
}
iss.str(scpu);
iss >> fcpu;
cpu = (int) (fcpu * 100);//now in 100%
memory = memory * 1024; //now in Kilobytes
disk = 0;
@ -1287,6 +1281,27 @@ void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachine::resize(float cpu, int memory, int vcpu)
{
ostringstream oss;
oss << cpu;
replace_template_attribute("CPU", oss.str());
oss.str("");
oss << memory;
replace_template_attribute("MEMORY", oss.str());
oss.str("");
oss << vcpu;
replace_template_attribute("VCPU", oss.str());
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static void assign_disk_targets(queue<pair <string, VectorAttribute *> >& _queue,
set<string>& used_targets)
{