This allow to rebalance a node, with defining max mem/cpu threshold. we migrate vms until we are under threshold.
Signed-off-by: Alexandre Derumier <[email protected]> --- PVE/API2/Nodes.pm | 130 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 3 deletions(-) diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm index 25199249..35e138c7 100644 --- a/PVE/API2/Nodes.pm +++ b/PVE/API2/Nodes.pm @@ -2010,6 +2010,130 @@ __PACKAGE__->register_method ({ }}); +__PACKAGE__->register_method ({ + name => 'rebalance', + path => 'rebalance', + method => 'POST', + proxyto => 'node', + protected => 1, + permissions => { + check => ['perm', '/', [ 'VM.Migrate' ]], + }, + description => "Rebalance VMs and Containers.", + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + mem_threshold => { + description => "target mem % threshold", + type => 'integer', + minimum => 1 + }, + cpu_threshold => { + description => "target mem % threshold", + type => 'integer', + minimum => 1 + }, + }, + }, + returns => { + type => 'string', + }, + code => sub { + my ($param) = @_; + + my $rpcenv = PVE::RPCEnvironment::get(); + my $authuser = $rpcenv->get_user(); + + my $nodename = $param->{node}; + $nodename = PVE::INotify::nodename() if $nodename eq 'localhost'; + + my $mem_threshold = $param->{mem_threshold}; + my $cpu_threshold = $param->{cpu_threshold}; + + PVE::Cluster::check_cfs_quorum(); + + my $members = PVE::Cluster::get_members(); + my $maxWorkers = 1; + my $storecfg = PVE::Storage::config(); + + my $code = sub { + $rpcenv->{type} = 'priv'; # to start tasks in background + + my $vmlist = &$get_filtered_vmlist($nodename, undef, 0, 1); + my $workers = {}; + + my $rrd = PVE::Cluster::rrd_dump(); + + my $node_stats = PVE::API2Tools::extract_node_stats($nodename, $members, $rrd); + my $node_mem_pct = $node_stats->{mem} / $node_stats->{maxmem} * 100; + my $node_cpu_pct = $node_stats->{cpu} / $node_stats->{maxcpu}; + + return if ($node_mem_pct < $mem_threshold && $node_cpu_pct < $cpu_threshold); + + my $vmlist_stats = {}; + foreach my $vmid (sort keys %$vmlist) { + my $d = $vmlist->{$vmid}; + my $vmconf = PVE::QemuConfig->load_config($vmid); + my $vm_stats = PVE::API2Tools::extract_vm_stats($vmid, $d, $rrd); + my $vm_cpu = $vm_stats->{cpu} * $vm_stats->{maxcpu}; + my $vm_mem = $vm_stats->{mem}; + $vmlist_stats->{$vmid}->{cpu} = $vm_cpu; + $vmlist_stats->{$vmid}->{mem} = $vm_mem; + } + + my @vmlist_array; + #order vmlist with bigger usage to reduce number of vm migration + if ($node_mem_pct < $mem_threshold && $node_cpu_pct < $cpu_threshold) { + #order by cpu, then ram ? + @vmlist_array = sort { $a->{mem} <=> $b->{mem} || $a->{cpu} <=> $b->{cpu} } keys %$vmlist_stats; + } elsif ($node_mem_pct < $mem_threshold) { + #order by mem usage first + @vmlist_array = sort { $a->{mem} <=> $b->{mem} } keys %$vmlist_stats; + } elsif ($node_cpu_pct < $cpu_threshold) { + #order by cpu usage first + @vmlist_array = sort { $a->{cpu} <=> $b->{cpu} } keys %$vmlist_stats; + } + + foreach my $vmid (@vmlist_array) { + my $d = $vmlist->{$vmid}; + my $target = find_best_node_target($vmid, $d, $nodename, $storecfg, $mem_threshold/100, $cpu_threshold/100); + if(!$target) { + warn "couldn't find a target for vmid $vmid\n"; + next; + } + + my $pid; + eval { $pid = &$create_migrate_worker($nodename, $d->{type}, $vmid, $target); }; + $target = $param->{target}; + warn $@ if $@; + next if !$pid; + + $workers->{$pid} = 1; + while (scalar(keys %$workers) >= $maxWorkers) { + foreach my $p (keys %$workers) { + if (!PVE::ProcFSTools::check_process_running($p)) { + delete $workers->{$p}; + } + } + sleep(1); + } + } + while (scalar(keys %$workers)) { + foreach my $p (keys %$workers) { + if (!PVE::ProcFSTools::check_process_running($p)) { + delete $workers->{$p}; + } + } + sleep(1); + } + return; + }; + + return $rpcenv->fork_worker('rebalance', undef, $authuser, $code); + + }}); + __PACKAGE__->register_method ({ name => 'get_etc_hosts', path => 'hosts', @@ -2123,14 +2247,14 @@ sub dotprod { } sub find_best_node_target { - my($vmid, $d, $nodename, $storecfg) = @_; + my($vmid, $d, $nodename, $storecfg, $mem_threshold, $cpu_threshold) = @_; my $vmconf = PVE::QemuConfig->load_config($vmid); my $members = PVE::Cluster::get_members(); my $rrd = PVE::Cluster::rrd_dump(); my $nodelist = PVE::Cluster::get_nodelist(); - my $mem_threshold = 0.8; - my $cpu_threshold = 0.8; + $mem_threshold = 0.8 if !$mem_threshold; + $cpu_threshold = 0.8 if !$cpu_threshold; my $vm_stats = PVE::API2Tools::extract_vm_stats($vmid, $d, $rrd); my $vm_cpu = $vm_stats->{cpu} * $vm_stats->{maxcpu}; my $vm_mem = $vm_stats->{mem}; -- 2.20.1 _______________________________________________ pve-devel mailing list [email protected] https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
