Unverified Commit 8da04807 authored by Francesc Guasch's avatar Francesc Guasch Committed by GitHub
Browse files

feat(backend): check free memory (#776)

* test(backend): test free memory error

issue #746

* feat(frontend): show request error if any

issue #746

* feat(backend): check free VM memory

closes issue #746

* wip(backend): check real free memory available

Before we could be misleaded by the use of
overcommitting memory allocation

issue #746
parent 06d8d5db
......@@ -1020,6 +1020,7 @@ sub _upgrade_tables {
$self->_upgrade_table('vms','vm_type',"char(20) NOT NULL DEFAULT 'KVM'");
$self->_upgrade_table('vms','connection_args',"text DEFAULT NULL");
$self->_upgrade_table('vms','min_free_memory',"text DEFAULT NULL");
$self->_upgrade_table('requests','at_time','int(11) DEFAULT NULL');
......
......@@ -223,6 +223,7 @@ sub _start_preconditions{
_allow_manage(@_);
}
$self->_check_free_memory();
$self->_check_free_vm_memory();
_check_used_memory(@_);
}
......@@ -410,6 +411,24 @@ sub _check_free_memory{
if ( $stat->memstats->{realfree} < $MIN_FREE_MEMORY );
}
sub _check_free_vm_memory {
my $self = shift;
return if !$self->_vm->min_free_memory;
return if $self->_vm->free_memory > $self->_vm->min_free_memory;
die "ERROR: No free memory. Only "._gb($self->_vm->free_memory)." out of "
._gb($self->_vm->min_free_memory)." GB required.\n";
}
sub _gb($mem=0) {
my $gb = $mem / 1024 / 1024 ;
$gb =~ s/(\d+\.\d).*/$1/;
return ($gb);
}
sub _check_used_memory {
my $self = shift;
my $used_memory = 0;
......
......@@ -47,6 +47,8 @@ requires 'import_domain';
requires 'ping';
requires 'is_active';
requires 'free_memory';
############################################################
has 'host' => (
......@@ -472,6 +474,18 @@ sub default_storage_pool_name {
return $self->_data('default_storage');
}
=head2 min_free_memory
Returns the minimun free memory necessary to start a new virtual machine
=cut
sub min_free_memory {
my $self = shift;
return $self->_data('min_free_memory');
}
=head2 list_drivers
Lists the drivers available for this Virtual Machine Manager
......
......@@ -1930,4 +1930,24 @@ sub is_active($self) {
return 0;
}
sub free_memory($self) {
return $self->_free_memory_available();
}
# TODO: enable this check from free memory with a config flag
# though I don't think it would be suitable to use
# Insights welcome
sub _free_memory_overcommit($self) {
my $info = $self->vm->get_node_memory_stats();
return ($info->{free} + $info->{buffers} + $info->{cached});
}
sub _free_memory_available($self) {
my $info = $self->vm->get_node_memory_stats();
my $used = 0;
for my $domain ( $self->list_domains(active => 1) ) {
$used += $domain->domain->get_info->{memory};
}
return $info->{total} - $used;
}
1;
......@@ -179,6 +179,7 @@ sub ping { return 1 }
sub is_active { return 1 }
sub free_memory { return 1000 * 1000}
#########################################################################3
1;
#!perl
use strict;
use warnings;
use Data::Dumper;
use Test::More;
use Test::SQL::Data;
use lib 't/lib';
use Test::Ravada;
my $test = Test::SQL::Data->new(config => 't/etc/sql.conf');
init($test->connector);
clean();
#################################################################################
sub test_min_freemem {
my $vm = shift;
my $sth = $test->connector->dbh->prepare(
"UPDATE vms SET min_free_memory=? "
." WHERE id=?"
);
my $min_free_memory = $vm->free_memory * 2;
ok($min_free_memory > 0
&& $min_free_memory !~ /^0+\.0+$/
,"[".$vm->type."] Expecting some free memory on the VM , got $min_free_memory");
$sth->execute( $min_free_memory, $vm->id );
$sth->finish;
my $type = $vm->type;
$type = 'KVM' if $type =~ /qemu/i;
$vm->disconnect;
delete $vm->{_data};
ok($vm) or return;
is($vm->min_free_memory, $min_free_memory) or exit;
my $domain = create_domain($vm->type);
my $req = Ravada::Request->start_domain(
uid => user_admin->id
,id_domain => $domain->id
,remote_ip => 'localhost'
);
ok($req);
rvd_back->_process_requests_dont_fork();
is($req->status, 'done');
like($req->error, qr'memory'i);
$domain->remove(user_admin);
}
#################################################################################
for my $vm_name ( vm_names() ) {
init($test->connector, 't/etc/ravada_freemem.conf');
my $vm;
eval { $vm = rvd_back->search_vm($vm_name) };
warn $@ if $@;
SKIP: {
my $msg = "SKIPPED test: No $vm_name VM found ";
if ($vm && $vm_name =~ /kvm/i && $>) {
$msg = "SKIPPED: Test must run as root";
$vm = undef;
}
diag($msg) if !$vm;
skip $msg if !$vm;
diag("Testing free mem on $vm_name");
test_min_freemem($vm);
}
}
clean();
done_testing();
......@@ -60,7 +60,9 @@
</div>
<div class="panel-body"
ng-show="domain && request.status == 'done' && !domain.is_active">
The machine has shut down. <button type="submit" onclick="location.reload('forceGet')">Start again</button>
<div ng-show="request.error">{{request.error}}</div>
<div ng-show="request.error == ''">The machine has shut down.</div>
<button type="submit" onclick="location.reload('forceGet')">Start again</button>
</div>
</div>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment