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

F #1660: Hotplug VCPU and mem for KVM (#392)

Co-authored-by: Ruben S. Montero <rsmontero@opennebula.org>
This commit is contained in:
Pavel Czerný 2020-11-17 11:24:52 +01:00 committed by GitHub
parent c4c6cc9998
commit 7ba1bbe633
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 597 additions and 21 deletions

View File

@ -142,6 +142,9 @@ public:
void trigger_update_conf_success(int vid);
void trigger_update_conf_failure(int vid);
void trigger_resize_success(int vid);
void trigger_resize_failure(int vid);
// -------------------------------------------------------------------------
// External Actions, triggered by user requests
// -------------------------------------------------------------------------

View File

@ -170,6 +170,7 @@ enum class VMManagerMessages : unsigned short int
UPDATESG,
DRIVER_CANCEL,
LOG,
RESIZE,
ENUM_MAX
};

View File

@ -135,7 +135,8 @@ public:
DISK_RESIZE = 62,
DISK_RESIZE_POWEROFF = 63,
DISK_RESIZE_UNDEPLOYED = 64,
HOTPLUG_NIC_POWEROFF = 65
HOTPLUG_NIC_POWEROFF = 65,
HOTPLUG_RESIZE = 66
};
/**
@ -1018,7 +1019,20 @@ public:
* @param memory
* @param vcpu
*/
int resize(float cpu, long int memory, unsigned int vcpu, std::string& error);
int resize(float cpu, long int memory, unsigned int vcpu, std::string& error);
/**
* Store old values of resize parameters, to be able to revert in case of failure
* @param cpu - old cpu value
* @param memory - old memory value
* @param vcpu - old vcpu value
*/
void store_resize(float cpu, long int memory, unsigned int vcpu);
/**
* Clear resize parameters
*/
void reset_resize();
/**
* Parse TOPOLOGY and NUMA_NODE

View File

@ -111,6 +111,21 @@ public:
return vmd->is_cold_nic_attach();
}
/**
* Get live_resize capability from driver
*/
bool is_live_resize(const std::string& name)
{
const VirtualMachineManagerDriver * vmd = get(name);
if ( vmd == nullptr )
{
return false;
}
return vmd->is_live_resize();
}
/**
* Returns a pointer to a Virtual Machine Manager driver. The driver is
* searched by its name.
@ -269,6 +284,11 @@ private:
*/
void _driver_cancel(std::unique_ptr<vm_msg_t> msg);
/**
*
*/
void _resize(std::unique_ptr<vm_msg_t> msg);
/**
*
*/
@ -495,6 +515,13 @@ public:
* @param vid the id of the VM.
*/
void trigger_update_conf(int vid);
/**
* Update VM context
*
* @param vid the id of the VM.
*/
void trigger_resize(int vid);
};
#endif /*VIRTUAL_MACHINE_MANAGER_H*/

View File

@ -99,6 +99,14 @@ public:
return cold_nic_attach;
}
/**
* @return true if hotplug vcpu and memory supported
*/
bool is_live_resize() const
{
return live_resize;
}
protected:
/**
* Gets a configuration attr from driver configuration file (single
@ -263,6 +271,11 @@ private:
*/
bool cold_nic_attach;
/**
* Set to true if hypervisor supports hotplug vcpu and memory
*/
bool live_resize;
/**
* Sends a deploy request to the MAD: "DEPLOY ID XML_DRV_MSG"
* @param oid the virtual machine id.

View File

@ -1116,6 +1116,7 @@ VMM_EXEC_KVM_SCRIPTS="src/vmm_mad/remotes/kvm/cancel \
src/vmm_mad/remotes/kvm/shutdown \
src/vmm_mad/remotes/kvm/reconfigure \
src/vmm_mad/remotes/kvm/prereconfigure \
src/vmm_mad/remotes/kvm/resize \
src/vmm_mad/remotes/kvm/resize_disk"
#-------------------------------------------------------------------------------

View File

@ -162,6 +162,7 @@ VM_MAD = [
DEFAULT = \"vmm_exec/vmm_exec_kvm.conf\",
TYPE = \"kvm\",
KEEP_SNAPSHOTS = \"no\",
LIVE_RESIZE = \"no\",
IMPORTED_VMS_ACTIONS = \"terminate, terminate-hard, hold, release, suspend,
resume, delete, reboot, reboot-hard, resched, unresched, disk-attach,
disk-detach, nic-attach, nic-detach, snapshot-create, snapshot-delete\"

View File

@ -345,6 +345,14 @@
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="LIVE_RESIZE" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[yY][eE][sS]" />
<xs:pattern value="[nN][oO]" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>

View File

@ -389,6 +389,8 @@ IM_MAD = [
# keep_snapshots: do not remove snapshots on power on/off cycles and live
# migrations if the hypervisor supports that.
#
# live_resize: [yes|no] Hypervisor supports hotplug VCPU and memory
#
# imported_vms_actions : comma-separated list of actions supported
# for imported vms. The available actions are:
# migrate
@ -443,6 +445,7 @@ VM_MAD = [
DEFAULT = "vmm_exec/vmm_exec_kvm.conf",
TYPE = "kvm",
KEEP_SNAPSHOTS = "yes",
LIVE_RESIZE = "yes",
IMPORTED_VMS_ACTIONS = "terminate, terminate-hard, hold, release, suspend,
resume, delete, reboot, reboot-hard, resched, unresched, disk-attach,
disk-detach, nic-attach, nic-detach, snapshot-create, snapshot-delete"

View File

@ -221,6 +221,7 @@ module OneGate
DISK_RESIZE_POWEROFF
DISK_RESIZE_UNDEPLOYED
HOTPLUG_NIC_POWEROFF
HOTPLUG_RESIZE
}
SHORT_VM_STATES={
@ -302,7 +303,8 @@ module OneGate
"DISK_RESIZE" => "drsz",
"DISK_RESIZE_POWEROFF" => "drsz",
"DISK_RESIZE_UNDEPLOYED" => "drsz",
"HOTPLUG_NIC_POWEROFF" => "hotp"
"HOTPLUG_NIC_POWEROFF" => "hotp",
"HOTPLUG_RESIZE" => "hotp"
}
def self.state_to_str(id, lcm_id)

View File

@ -596,7 +596,8 @@ func (d *Driver) GetState() (state.State, error) {
"HOTPLUG_NIC",
"HOTPLUG_SAVEAS",
"DISK_SNAPSHOT",
"DISK_SNAPSHOT_DELETE":
"DISK_SNAPSHOT_DELETE",
"HOTPLUG_RESIZE":
return state.Running, nil

View File

@ -1102,6 +1102,15 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose,
tm->trigger_epilog_delete(vm);
break;
case VirtualMachine::HOTPLUG_RESIZE:
vm->reset_resize();
vm->set_running_etime(the_time);
vmm->trigger_driver_cancel(vid);
vmm->trigger_cleanup(vid, false);
break;
case VirtualMachine::DISK_SNAPSHOT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF:
@ -1446,6 +1455,17 @@ void LifeCycleManager::recover(VirtualMachine * vm, bool success,
}
break;
case VirtualMachine::HOTPLUG_RESIZE:
if (success)
{
trigger_resize_success(vim);
}
else
{
trigger_resize_failure(vim);
}
break;
case VirtualMachine::DISK_SNAPSHOT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF:
@ -1681,6 +1701,7 @@ void LifeCycleManager::retry(VirtualMachine * vm)
case VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED:
case VirtualMachine::HOTPLUG_PROLOG_POWEROFF:
case VirtualMachine::HOTPLUG_EPILOG_POWEROFF:
case VirtualMachine::HOTPLUG_RESIZE:
case VirtualMachine::DISK_SNAPSHOT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF:
case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF:
@ -1817,6 +1838,7 @@ void LifeCycleManager::trigger_updatesg(int sgid)
case VirtualMachine::HOTPLUG:
case VirtualMachine::HOTPLUG_SNAPSHOT:
case VirtualMachine::HOTPLUG_SAVEAS:
case VirtualMachine::HOTPLUG_RESIZE:
case VirtualMachine::DISK_SNAPSHOT:
case VirtualMachine::DISK_SNAPSHOT_DELETE:
case VirtualMachine::DISK_RESIZE:

View File

@ -2387,3 +2387,118 @@ void LifeCycleManager::trigger_update_conf_failure(int vid)
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void LifeCycleManager::trigger_resize_success(int vid)
{
trigger([this, vid] {
if ( auto vm = vmpool->get(vid) )
{
VirtualMachine::LcmState state = vm->get_lcm_state();
if (state == VirtualMachine::HOTPLUG_RESIZE)
{
vm->set_state(VirtualMachine::RUNNING);
vm->log("LCM", Log::INFO, "VM resize operation completed.");
}
else
{
vm->log("LCM", Log::ERROR, "hotplug_resize_success, VM in a wrong state");
return;
}
vm->reset_resize();
vmpool->update(vm.get());
}
});
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void LifeCycleManager::trigger_resize_failure(int vid)
{
trigger([this, vid] {
Template deltas;
HostShareCapacity sr, sr_orig;
int vm_uid, vm_gid, hid;
if ( auto vm = vmpool->get(vid) )
{
VirtualMachine::LcmState state = vm->get_lcm_state();
if (state == VirtualMachine::HOTPLUG_RESIZE)
{
vm->set_state(VirtualMachine::RUNNING);
vm->log("LCM", Log::INFO,
"VM hotplug resize operation fails");
}
else
{
vm->log("LCM", Log::ERROR,
"hotplug resize fails, VM in a wrong state");
return;
}
hid = vm->get_hid();
vm->get_capacity(sr);
auto vattr = vm->get_template_attribute("RESIZE");
if (vattr)
{
vm_uid = vm->get_uid();
vm_gid = vm->get_gid();
string error;
float ocpu, ncpu;
long omem, nmem;
unsigned int ovcpu, nvcpu;
vm->get_template_attribute("MEMORY", nmem);
vm->get_template_attribute("CPU", ncpu);
vm->get_template_attribute("VCPU", nvcpu);
vattr->vector_value("CPU", ocpu);
vattr->vector_value("VCPU", ovcpu);
vattr->vector_value("MEMORY", omem);
deltas.add("MEMORY", nmem - omem);
deltas.add("CPU", ncpu - ocpu);
deltas.add("VMS", 0);
vm->resize(ocpu, omem, ovcpu, error);
}
else
{
NebulaLog::error("LCM",
"HOTPLUG_RESIZE failure, unable to revert VM and quotas");
}
vm->get_capacity(sr_orig);
vm->reset_resize();
vmpool->update(vm.get());
}
else
{
return;
}
// Revert host capacity
if (auto host = hpool->get(hid))
{
host->del_capacity(sr);
host->add_capacity(sr_orig);
hpool->update(host.get());
}
// Quota rollback
Quotas::quota_del(Quotas::VM, vm_uid, vm_gid, &deltas);
});
}

View File

@ -52,7 +52,8 @@ class VirtualMachineDriver < OpenNebulaDriver
:disk_snapshot_create => "DISKSNAPSHOTCREATE",
:resize_disk => "RESIZEDISK",
:update_sg => "UPDATESG",
:update_conf => "UPDATECONF"
:update_conf => "UPDATECONF",
:resize => "RESIZE"
}
POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE
@ -98,6 +99,7 @@ class VirtualMachineDriver < OpenNebulaDriver
register_action(ACTION[:resize_disk].to_sym, method("resize_disk"))
register_action(ACTION[:update_sg].to_sym, method("update_sg"))
register_action(ACTION[:update_conf].to_sym, method("update_conf"))
register_action(ACTION[:resize].to_sym, method("resize"))
end
# Decodes the encoded XML driver message received from the core
@ -227,6 +229,11 @@ class VirtualMachineDriver < OpenNebulaDriver
send_message(ACTION[:update_conf],RESULT[:failure],id,error)
end
def resize(id, drv_message)
error = "Action not implemented by driver #{self.class}"
send_message(ACTION[:resize],RESULT[:failure],id,error)
end
private
# Interface to handle the pending events from the ActionManager Interface

View File

@ -154,7 +154,8 @@ public class VirtualMachine extends PoolElement{
"DISK_RESIZE",
"DISK_RESIZE_POWEROFF",
"DISK_RESIZE_UNDEPLOYED",
"HOTPLUG_NIC_POWEROFF"
"HOTPLUG_NIC_POWEROFF",
"HOTPLUG_RESIZE"
};
private static final String[] SHORT_LCM_STATES =
@ -224,7 +225,8 @@ public class VirtualMachine extends PoolElement{
"drsz", // DISK_RESIZE
"drsz", // DISK_RESIZE_POWEROFF
"drsz", // DISK_RESIZE_UNDEPLOYED
"hotp" // HOTPLUG_NIC_POWEROFF
"hotp", // HOTPLUG_NIC_POWEROFF
"hotp" // HOTPLUG_RESIZE
};
/**

View File

@ -154,7 +154,8 @@ LCM_STATE = IntEnum('LCM_STATE', '''
DISK_RESIZE
DISK_RESIZE_POWEROFF
DISK_RESIZE_UNDEPLOYED
HOTPLUG_NIC_POWEROFF''', start=0)
HOTPLUG_NIC_POWEROFF
HOTPLUG_RESIZE''', start=0)
MARKETPLACEAPP_STATES = IntEnum('MARKETPLACEAPP_STATES', '''INIT READY LOCKED
ERROR DISABLED''', start=0)

View File

@ -124,6 +124,7 @@ module OpenNebula
DISK_RESIZE_POWEROFF
DISK_RESIZE_UNDEPLOYED
HOTPLUG_NIC_POWEROFF
HOTPLUG_RESIZE
}
SHORT_VM_STATES={
@ -205,7 +206,8 @@ module OpenNebula
"DISK_RESIZE" => "drsz",
"DISK_RESIZE_POWEROFF" => "drsz",
"DISK_RESIZE_UNDEPLOYED" => "drsz",
"HOTPLUG_NIC_POWEROFF" => "hotp"
"HOTPLUG_NIC_POWEROFF" => "hotp",
"HOTPLUG_RESIZE" => "hotp"
}
HISTORY_ACTION=%w{none migrate live-migrate shutdown shutdown-hard

View File

@ -139,6 +139,7 @@ const EString<VMManagerMessages> vm_msg_t::_type_str({
{"UPDATESG", VMManagerMessages::UPDATESG},
{"DRIVER_CANCEL", VMManagerMessages::DRIVER_CANCEL},
{"LOG", VMManagerMessages::LOG},
{"RESIZE", VMManagerMessages::RESIZE},
});
template<>

View File

@ -1927,7 +1927,9 @@ static int test_set_capacity(VirtualMachine * vm, float cpu, long mem, int vcpu,
int rc;
if ( vm->get_state() == VirtualMachine::POWEROFF )
if ( vm->get_state() == VirtualMachine::POWEROFF ||
(vm->get_state() == VirtualMachine::ACTIVE &&
vm->get_lcm_state() == VirtualMachine::RUNNING))
{
HostShareCapacity sr;
@ -2130,10 +2132,59 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
rc = test_set_capacity(vm.get(), ncpu, nmemory, nvcpu, att.resp_msg);
break;
case VirtualMachine::ACTIVE:
{
if (vm->get_lcm_state() != VirtualMachine::RUNNING)
{
rc = -1;
att.resp_msg = "Cannot resize a VM in state " + vm->state_str();
break;
}
if (vm->is_pinned())
{
rc = -1;
att.resp_msg = "Cannot resize a pinned VM";
break;
}
auto vmm = Nebula::instance().get_vmm();
if (!vmm->is_live_resize(vm->get_vmm_mad()))
{
rc = -1;
att.resp_msg = "Hotplug resize not supported by driver "
+ vm->get_vmm_mad();
break;
}
if (ocpu == ncpu && omemory == nmemory && ovcpu == nvcpu)
{
rc = 0;
att.resp_msg = "Nothing to resize";
break;
}
rc = test_set_capacity(vm.get(), ncpu, nmemory, nvcpu, att.resp_msg);
if (rc == 0)
{
vm->set_state(VirtualMachine::HOTPLUG_RESIZE);
vm->store_resize(ocpu, omemory, ovcpu);
vm->set_resched(false);
auto vmm = Nebula::instance().get_vmm();
vmm->trigger_resize(id);
}
break;
}
case VirtualMachine::STOPPED:
case VirtualMachine::DONE:
case VirtualMachine::SUSPENDED:
case VirtualMachine::ACTIVE:
rc = -1;
att.resp_msg = "Cannot resize a VM in state " + vm->state_str();
break;

View File

@ -98,6 +98,7 @@ VNC_STATES = [
#63, #DISK_RESIZE_POWEROFF
#64 #DISK_RESIZE_UNDEPLOYED
#65 #HOTPLUG_NIC_POWEROFF
#66 #HOTPLUG_RESIZE
]
class OpenNebulaVNC

View File

@ -137,7 +137,8 @@ define(function(require) {
"DISK_RESIZE",
"DISK_RESIZE_POWEROFF",
"DISK_RESIZE_UNDEPLOYED",
"HOTPLUG_NIC_POWEROFF"
"HOTPLUG_NIC_POWEROFF",
"HOTPLUG_RESIZE"
];
var LCM_STATES_CLASSES = [
@ -275,7 +276,8 @@ define(function(require) {
DISK_RESIZE : 62,
DISK_RESIZE_POWEROFF : 63,
DISK_RESIZE_UNDEPLOYED : 64,
HOTPLUG_NIC_POWEROFF : 65
HOTPLUG_NIC_POWEROFF : 65,
HOTPLUG_RESIZE : 66
};
var SHORT_LCM_STATES_STR = [
@ -344,7 +346,8 @@ define(function(require) {
Locale.tr("DISK_RSZ"), // DISK_RESIZE
Locale.tr("DISK_RSZ"), // DISK_RESIZE_POWEROFF
Locale.tr("DISK_RSZ"), // DISK_RESIZE_UNDEPLOYED
Locale.tr("HOTPLUG") // HOTPLUG_NIC_POWEROFF
Locale.tr("HOTPLUG"), // HOTPLUG_NIC_POWEROFF
Locale.tr("HOTPLUG") // HOTPLUG_RESIZE
];
var VNC_STATES = [

View File

@ -908,6 +908,7 @@ define(function(require) {
case OpenNebulaVM.LCM_STATES.DISK_RESIZE:
case OpenNebulaVM.LCM_STATES.DISK_RESIZE_POWEROFF:
case OpenNebulaVM.LCM_STATES.DISK_RESIZE_UNDEPLOYED:
case OpenNebulaVM.LCM_STATES.HOTPLUG_RESIZE:
state_color = "running";
state_str = Locale.tr("RUNNING");
break;

View File

@ -124,6 +124,7 @@ define(function(require) {
LCM_STATE_ACTIONS[ OpenNebulaVM.LCM_STATES.DISK_RESIZE ] = [];
LCM_STATE_ACTIONS[ OpenNebulaVM.LCM_STATES.DISK_RESIZE_POWEROFF ] = [];
LCM_STATE_ACTIONS[ OpenNebulaVM.LCM_STATES.DISK_RESIZE_UNDEPLOYED ] = [];
LCM_STATE_ACTIONS[ OpenNebulaVM.LCM_STATES.HOTPLUG_RESIZE ] = [];
return {
'disableAllStateActions': disableAllStateActions,

View File

@ -290,6 +290,8 @@ int VirtualMachine::lcm_state_from_str(string& st, LcmState& state)
state = DISK_RESIZE_UNDEPLOYED;
} else if ( st == "HOTPLUG_NIC_POWEROFF" ) {
state = HOTPLUG_NIC_POWEROFF;
} else if ( st == "HOTPLUG_RESIZE" ) {
state = HOTPLUG_RESIZE;
} else {
return -1;
}
@ -429,6 +431,8 @@ string& VirtualMachine::lcm_state_to_str(string& st, LcmState state)
st = "DISK_RESIZE_UNDEPLOYED"; break;
case HOTPLUG_NIC_POWEROFF:
st = "HOTPLUG_NIC_POWEROFF"; break;
case HOTPLUG_RESIZE:
st = "HOTPLUG_RESIZE"; break;
}
return st;
@ -740,6 +744,7 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
string value;
long int ivalue;
long int memory;
float fvalue;
set<int> cluster_ids;
set<int> datastore_ids;
@ -812,13 +817,26 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
// ------------------------------------------------------------------------
// Check for CPU, VCPU, MEMORY and TOPOLOGY attributes
// ------------------------------------------------------------------------
if ( user_obj_template->get("MEMORY", ivalue) == false || ivalue <= 0 )
if ( user_obj_template->get("MEMORY", memory) == false || memory <= 0 )
{
goto error_memory;
}
user_obj_template->erase("MEMORY");
obj_template->add("MEMORY", ivalue);
obj_template->add("MEMORY", memory);
// Check optional MEMORY_MAX and MEMORY_SLOTS attribute
if ( user_obj_template->get("MEMORY_MAX", ivalue) && ivalue > 0 )
{
user_obj_template->erase("MEMORY_MAX");
obj_template->add("MEMORY_MAX", ivalue);
}
if ( user_obj_template->get("MEMORY_SLOTS", ivalue) && ivalue > 0 )
{
user_obj_template->erase("MEMORY_SLOTS");
obj_template->add("MEMORY_SLOTS", ivalue);
}
if ( user_obj_template->get("CPU", fvalue) == false || fvalue <= 0 )
{
@ -843,6 +861,13 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
obj_template->add("VCPU", ivalue);
}
// Check optional VCPU_MAX attribute
if ( user_obj_template->get("VCPU_MAX", ivalue) && ivalue > 0 )
{
user_obj_template->erase("VCPU_MAX");
obj_template->add("VCPU_MAX", ivalue);
}
// ------------------------------------------------------------------------
// Check the cost attributes
// ------------------------------------------------------------------------
@ -1989,6 +2014,28 @@ int VirtualMachine::resize(float cpu, long int memory, unsigned int vcpu,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachine::store_resize(float cpu, long int memory, unsigned int vcpu)
{
auto vattr = new VectorAttribute("RESIZE");
vattr->replace("CPU", cpu);
vattr->replace("VCPU", vcpu);
vattr->replace("MEMORY", memory);
obj_template->erase("RESIZE");
obj_template->set(vattr);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachine::reset_resize()
{
obj_template->erase("RESIZE");
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool VirtualMachine::is_imported() const
{
bool imported = false;

View File

@ -413,8 +413,10 @@ int LibVirtDriver::deployment_description_kvm(
int num;
string vcpu;
string vcpu_max;
float cpu;
int memory;
int memory_max;
string emulator_path = "";
@ -617,8 +619,19 @@ int LibVirtDriver::deployment_description_kvm(
// ------------------------------------------------------------------------
get_attribute(vm, host, cluster, "VCPU", vcpu);
get_attribute(vm, host, cluster, "VCPU_MAX", vcpu_max);
if (!vcpu.empty())
if (vcpu.empty())
{
vcpu = vcpu_max;
}
if (!vcpu_max.empty())
{
file << "\t<vcpu current=" << one_util::escape_xml_attr(vcpu) << ">"
<< one_util::escape_xml(vcpu_max) << "</vcpu>" << endl;
}
else if (!vcpu.empty())
{
file << "\t<vcpu>" << one_util::escape_xml(vcpu) << "</vcpu>" << endl;
}
@ -648,6 +661,18 @@ int LibVirtDriver::deployment_description_kvm(
return -1;
}
bool has_memory_max = vm->get_template_attribute("MEMORY_MAX", memory_max);
has_memory_max = has_memory_max && memory < memory_max;
if (!topology && has_memory_max)
{
int slots = 0;
get_attribute(vm, host, cluster, "MEMORY_SLOTS", slots);
file << "\t<maxMemory slots='" << slots
<< "'>" << memory_max * 1024 << "</maxMemory>" << endl;
}
// ------------------------------------------------------------------------
// OS and boot options
// ------------------------------------------------------------------------
@ -722,7 +747,7 @@ int LibVirtDriver::deployment_description_kvm(
cpu_mode = "custom";
}
if ( !cpu_model.empty() || topology != 0 )
if ( !cpu_model.empty() || topology != 0 || has_memory_max )
{
file << "\t<cpu";
@ -741,6 +766,19 @@ int LibVirtDriver::deployment_description_kvm(
file << ">\n";
}
if (nodes.empty() && has_memory_max)
{
int cpus = to_i(vcpu) - 1;
if (cpus < 0)
{
cpus = 0;
}
file << "\t\t<numa>\n\t\t\t<cell id='0' cpus='0-" << cpus
<< "' memory=" << one_util::escape_xml_attr(memory * 1024)
<< " unit='KiB'/>\n\t\t</numa>" << endl;
}
vtopol(file, topology, nodes, numa_tune, mbacking);
file << "\t</cpu>\n";

View File

@ -27,8 +27,6 @@
#include "Nebula.h"
#include <time.h>
using namespace std;
/* ************************************************************************** */
@ -121,6 +119,9 @@ int VirtualMachineManager::start()
register_action(VMManagerMessages::DRIVER_CANCEL,
bind(&VirtualMachineManager::_driver_cancel, this, _1));
register_action(VMManagerMessages::RESIZE,
bind(&VirtualMachineManager::_resize, this, _1));
register_action(VMManagerMessages::LOG,
&VirtualMachineManager::_log);
@ -2330,6 +2331,71 @@ int VirtualMachineManager::updatesg(VirtualMachine * vm, int sgid)
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineManager::trigger_resize(int vid)
{
trigger([this, vid] {
const VirtualMachineManagerDriver * vmd;
string vm_tmpl;
string drv_msg;
ostringstream os;
// Get the VM from the pool
auto vm = vmpool->get(vid);
if (vm == nullptr)
{
return;
}
if (!vm->hasHistory())
{
goto error_history;
}
// Get the driver for this VM
vmd = get(vm->get_vmm_mad());
if ( vmd == nullptr )
{
goto error_driver;
}
// Invoke driver method
drv_msg = format_message(
vm->get_hostname(),
"",
vm->get_deploy_id(),
"",
"",
"",
"",
"",
"",
vm->to_xml(vm_tmpl),
vm->get_ds_id(),
-1);
vmd->write_drv(VMManagerMessages::RESIZE, vid, drv_msg);
return;
error_history:
os << "trigger_resize, VM has no history";
goto error_common;
error_driver:
os << "trigger_resize, error getting driver " << vm->get_vmm_mad();
error_common:
vm->log("VMM", Log::ERROR, os);
return;
});
}
/* ************************************************************************** */
/* MAD Loading */
/* ************************************************************************** */

View File

@ -42,7 +42,8 @@ VirtualMachineManagerDriver::VirtualMachineManagerDriver(
driver_conf(true),
keep_snapshots(false),
ds_live_migration(false),
cold_nic_attach(false)
cold_nic_attach(false),
live_resize(false)
{
char * error_msg = nullptr;
const char * cfile;
@ -111,6 +112,8 @@ VirtualMachineManagerDriver::VirtualMachineManagerDriver(
// -------------------------------------------------------------------------
driver_conf.get("COLD_NIC_ATTACH", cold_nic_attach);
driver_conf.get("LIVE_RESIZE", live_resize);
// -------------------------------------------------------------------------
// Parse IMPORTED_VMS_ACTIONS string and init the action set
// -------------------------------------------------------------------------

View File

@ -807,6 +807,37 @@ void VirtualMachineManager::_driver_cancel(unique_ptr<vm_msg_t> msg)
/* -------------------------------------------------------------------------- */
void VirtualMachineManager::_resize(unique_ptr<vm_msg_t> msg)
{
log_message(msg.get());
int id = msg->oid();
auto lcm = Nebula::instance().get_lcm();
if (!check_vm_state(id, msg.get()))
{
return;
}
if (msg->status() == "SUCCESS" )
{
if ( auto vm = vmpool->get_ro(id) )
{
vm->log("VMM", Log::INFO, "VM hotplug resize successful");
lcm->trigger_resize_success(id);
}
}
else
{
log_error(id, msg->payload(), "Error resizing VM");
lcm->trigger_resize_failure(id);
}
}
/* -------------------------------------------------------------------------- */
void VirtualMachineManager::_log(unique_ptr<vm_msg_t> msg)
{
NebulaLog::log("VMM", log_type(msg->status()[0]), msg->payload());

View File

@ -199,6 +199,12 @@ class DummyDriver < VirtualMachineDriver
send_message(ACTION[:resize_disk], result, id)
end
def resize(id, drv_message)
result = retrieve_result("resize")
send_message(ACTION[:resize], result, id)
end
def poll(id, drv_message)
result = retrieve_result("poll")

View File

@ -1261,6 +1261,23 @@ class ExecDriver < VirtualMachineDriver
action.run(steps, sg_id)
end
#
# RESIZE action
#
def resize(id, drv_message)
xml_data = decode(drv_message)
host = xml_data.elements['HOST'].text
deploy_id = xml_data.elements['DEPLOY_ID'].text
do_action("#{deploy_id}",
id,
host,
ACTION[:resize],
:script_name => 'resize',
:stdin => xml_data.to_s)
end
private
def ensure_xpath(xml_data, id, action, xpath)

View File

@ -20,6 +20,7 @@
# - emulator
# - os [kernel,initrd,boot,root,kernel_cmd,arch,machine,sd_disk_bus]
# - vcpu
# - memory_slots: number of memory slots for hotplug memory
# - features [acpi, pae, apic, hyperv, localtime, guest_agent, virtio_scsi_queues]
# - cpu_model [model]
# - disk [driver, cache, io, discard, total_bytes_sec, total_iops_sec, read_bytes_sec, write_bytes_sec, read_iops_sec, write_iops_sec]
@ -43,6 +44,8 @@ DISK = [ driver = "raw" , cache = "none"]
HYPERV_OPTIONS="<relaxed state='on'/><vapic state='on'/><spinlocks state='on' retries='4096'/>"
MEMORY_SLOTS = 16
SPICE_OPTIONS="
<video>
<model type='vga' heads='1'/>

84
src/vmm_mad/remotes/kvm/resize Executable file
View File

@ -0,0 +1,84 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2020, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
DRIVER_PATH=$(dirname $0)
DOMAIN=$1
# Exit if no stdin data is available
if [ -t 0 ]; then
exit 0
fi
# Read data from stdin data. Extracting the VCPU and MEMORY
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH /VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/VCPU \
/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/MEMORY \
/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/RESIZE/VCPU \
/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/RESIZE/MEMORY)
unset i
VCPU="${XPATH_ELEMENTS[i++]}"
MEM="${XPATH_ELEMENTS[i++]}"
VCPU_OLD="${XPATH_ELEMENTS[i++]}"
MEM_OLD="${XPATH_ELEMENTS[i++]}"
source $(dirname $0)/../../etc/vmm/kvm/kvmrc
source $(dirname $0)/../../scripts_common.sh
# Resize mem
if [ ! -z "$MEM" -a "$MEM" -ne "$MEM_OLD" ]; then
# Extract node id from virsh dumpxml
XML_INFO=$(virsh --connect ${LIBVIRT_URI} dumpxml ${DOMAIN})
IFS= read -r -d '' NODE_ID < <(echo "$XML_INFO" | $XPATH --subtree /domain/cpu/numa/cell/@id)
MEM_DIFF=$(expr $MEM - $MEM_OLD)
case $MEM_DIFF in
-*)
ACTION="detach-device"
MEM_DIFF=${MEM_DIFF#-}
;;
*)
ACTION="attach-device"
;;
esac
# Create tmp file with memory device specification
TMPFILE=$(mktemp /tmp/resize.XXXXXX)
echo -e "<memory model='dimm'>\n\t<target>\n\
<size unit='MiB'>$MEM_DIFF</size>\n\
<node>$NODE_ID</node>\n\t</target>\n</memory>" >$TMPFILE
# Add memory to VM
exec_and_log "virsh --connect ${LIBVIRT_URI} ${ACTION} ${DOMAIN} ${TMPFILE} --live"
# Cleanup
rm $TMPFILE
fi
# Resize VCPU
if [ ! -z "$VCPU" -a "$VCPU" -ne "$VCPU_OLD" ]; then
exec_and_log "virsh --connect ${LIBVIRT_URI} setvcpus ${DOMAIN} ${VCPU} --live --hotpluggable" \
"Failed to resize VCPU to ${VCPU} on ${DOMAIN}"
fi