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

Feature #941 bases (#943)

* test(bases): check bases listing from older releases

issue #941

* wip(bases): show info about remote bases

issue #941

* wip(frontend): bases in remote nodes

- show information
- set and remove base
- responsive listing

issue #941

* wip(frontend): add and remove base routes

issue#941

* wip(frontend): show if node is local

* wip(bases): new method to remove base

issue #941

* test(frontend): list clones by node

issue #941

* feature(frontend): show clones by base

issue #941

* refactor(frontend): refresh nodes

issue #941

* refactor(frontend): disable node-button in some cases

issue #941
parent affaf44a
......@@ -2829,6 +2829,10 @@ sub _refresh_volatile_domains($self) {
}
}
sub _cmd_remove_base_vm {
return _cmd_set_base_vm(@_);
}
sub _cmd_set_base_vm {
my $self = shift;
my $request = shift;
......@@ -2848,6 +2852,8 @@ sub _cmd_set_base_vm {
die "USER $uid not authorized to set base vm"
if !$user->is_admin;
$domain->prepare_base($user) if $value && !$domain->is_base;
$domain->set_base_vm(
id_vm => $id_vm
,user => $user
......@@ -2896,6 +2902,7 @@ sub _req_method {
,cmd_cleanup => \&_cmd_cleanup
,remove_base => \&_cmd_remove_base
,set_base_vm => \&_cmd_set_base_vm
,remove_base_vm => \&_cmd_set_base_vm
,refresh_vms => \&_cmd_refresh_vms
,ping_backend => \&_cmd_ping_backend
,prepare_base => \&_cmd_prepare_base
......
......@@ -1047,6 +1047,7 @@ sub info($self, $user) {
,msg_timeout => ( $self->_msg_timeout or undef)
,has_clones => ( $self->has_clones or undef)
,needs_restart => ( $self->needs_restart or 0)
,type => $self->type
};
eval {
$info->{display_url} = $self->display($user) if $self->is_active;
......@@ -1070,6 +1071,8 @@ sub info($self, $user) {
$info->{$_} = $internal_info->{$_};
}
$info->{bases} = $self->_bases_vm();
$info->{clones} = $self->_clones_vm();
return $info;
}
......@@ -1365,7 +1368,7 @@ sub clones {
_init_connector();
my $sth = $$CONNECTOR->dbh->prepare("SELECT id, name FROM domains "
my $sth = $$CONNECTOR->dbh->prepare("SELECT id, id_vm, name FROM domains "
." WHERE id_base = ? AND (is_base=NULL OR is_base=0)");
$sth->execute($self->id);
my @clones;
......@@ -2877,7 +2880,10 @@ sub list_vms($self) {
$sth->execute($self->id);
my @vms;
while (my $id_vm = $sth->fetchrow) {
push @vms,(Ravada::VM->open($id_vm));
my $vm;
eval { $vm = Ravada::VM->open($id_vm) };
confess "id_domain: ".$self->id."\n".$@ if $@;
push @vms,($vm);
}
return @vms;
}
......@@ -2911,6 +2917,39 @@ sub base_in_vm($self,$id_vm) {
return $enabled;
}
sub _bases_vm($self) {
my $sth = $$CONNECTOR->dbh->prepare(
"SELECT vms.id, vms.name, vms.hostname, vms.vm_type, b.enabled, b.id_domain FROM vms"
." LEFT JOIN bases_vm b ON vms.id = b.id_vm"
." WHERE "
." vms.vm_type=? "
);
$sth->execute($self->type );
my %base;
while ( my ($id_vm , $name, $address, $type, $enabled, $id_domain ) = $sth->fetchrow) {
if ( defined $id_domain && $id_domain != $self->id && !$base{$id_vm}) {
$enabled = 0;
}
$enabled = 1 if $self->is_base && $address =~ /localhost|^127/
&& $type eq $self->type;
$base{$id_vm} = ($enabled or 0);
}
return \%base;
}
sub _clones_vm($self) {
return {} if !$self->is_base;
my @clones = $self->clones;
my %clones;
for my $clone (@clones) {
push @{$clones{$clone->{id_vm}}}, ( $clone->{id} );
}
return \%clones;
}
=head2 is_local
Returns wether this domain is in the local host
......
......@@ -474,6 +474,8 @@ sub list_vms($self, $type=undef) {
$row->{action_remove} = 'disabled' if length defined $row->{machines}[0] > 0;
$row->{action_remove} = 'disabled' if $row->{hostname} eq 'localhost';
$row->{action_remove} = 'disabled' if length defined $row->{bases}[0] > 0;
$row->{is_local} = 0;
$row->{is_local} = 1 if $row->{hostname} =~ /^(localhost|127)/;
delete $row->{vm_type};
lock_hash(%$row);
push @list,($row);
......
......@@ -1132,7 +1132,7 @@ sub remove_base_vm {
bless($self,$class);
return $self->_new_request(
command => 'set_base_vm'
command => 'remove_base_vm'
, args => encode_json($args)
);
......
......@@ -271,10 +271,16 @@
else value=0;
$http.get("/machine/public/"+machineId+"/"+value);
};
$scope.toggle_base= function(vmId,machineId) {
$http.get("/machine/toggle_base_vm/" +vmId+ "/" +machineId+".json")
$scope.set_base= function(vmId,machineId, value) {
if (value == 0 || !value) {
url = 'remove_base_vm';
} else {
url = 'set_base_vm';
}
$http.get("/machine/"+url+"/" +vmId+ "/" +machineId+".json")
.then(function(response) {
$scope.getReqs();
$scope.refresh_machine();
});
};
//On load code
......@@ -298,10 +304,15 @@
if( pending < $scope.pending_before) {
if($scope.showmachine) {
$scope.init($scope.showmachine.id);
$scope.list_nodes();
}
setTimeout(function () {
$scope.init($scope.showmachine.id);
}, 2000);
} else {
setTimeout(function () {
$scope.refresh_machine();
}, 30000);
}
$scope.pending_before = pending;
});
......@@ -380,6 +391,12 @@
$scope.ldap_attributes_domain = response.data.list;
$scope.ldap_attributes_default = response.data.default;
});
};
$scope.list_nodes = function() {
$http.get('/list_nodes.json').then(function(response) {
$scope.nodes = response.data;
});
};
$scope.removed_hardware = [];
$scope.pending_before = 10;
......
......@@ -470,9 +470,14 @@ get '/machine/prepare/(:id).(:type)' => sub {
return prepare_machine($c);
};
get '/machine/toggle_base_vm/(:id_vm)/(:id_domain).(:type)' => sub {
get '/machine/set_base_vm/(:id_vm)/(:id_domain).(:type)' => sub {
my $c = shift;
return toggle_base_vm($c);
return set_base_vm($c, 1);
};
get '/machine/remove_base_vm/(:id_vm)/(:id_domain).(:type)' => sub {
my $c = shift;
return set_base_vm($c, 0);
};
get '/machine/remove_b/(:id).(:type)' => sub {
......@@ -1841,8 +1846,7 @@ sub copy_screenshot {
$c->render(json => { request => $req->id});
}
sub toggle_base_vm {
my $c = shift;
sub set_base_vm( $c, $new_value) {
my $id_vm = $c->stash('id_vm');
my $domain = Ravada::Front::Domain->open($c->stash('id_domain'));
......@@ -1850,15 +1854,20 @@ sub toggle_base_vm {
if ($USER->id != $domain->id && !$USER->is_admin) {
return $c->render(json => {message => 'access denied'});
}
my $new_value = 0;
$new_value = 1 if !$domain->is_base || !$domain->base_in_vm($id_vm);
my $req = Ravada::Request->set_base_vm(
value => $new_value
, id_vm => $id_vm
if ($new_value) {
my $req = Ravada::Request->set_base_vm(
id_vm => $id_vm
, id_domain => $domain->id
, uid => $USER->id
);
);
} else {
my $req = Ravada::Request->remove_base_vm(
id_vm => $id_vm
, id_domain => $domain->id
, uid => $USER->id
);
}
return $c->render(json => {message => 'processing request'});
}
......
......@@ -308,7 +308,14 @@ sub test_volatile_tmp_owner($vm, $node) {
sub test_clone_remote($vm, $node) {
my $base = create_domain($vm);
$base->prepare_base(user_admin);
my $bases_vm = $base->_bases_vm();
is($bases_vm->{$vm->id},1) or exit;
$base->set_base_vm(user => user_admin, node => $node);
$bases_vm = $base->_bases_vm();
is($bases_vm->{$node->id},1) or exit;
$base->migrate($node);
my $clone = $base->clone(
......@@ -316,7 +323,35 @@ sub test_clone_remote($vm, $node) {
,user => user_admin
);
ok($clone->_vm->name, $node->name);
_test_old_base($base, $vm);
_test_clones($base, $vm);
$clone->remove(user_admin);
$base->remove(user_admin);
}
sub _test_old_base($base, $vm) {
my $sth = connector->dbh->prepare(
"DELETE FROM bases_vm "
." WHERE id_domain=? AND id_vm=?"
);
$sth->execute($base->id, $vm->id);
my $base_f = Ravada::Front::Domain->open($base->id);
my $info = $base_f->info(user_admin);
is($info->{bases}->{$vm->id},1) ;
is(scalar keys %{$info->{bases}}, 2);
}
sub _test_clones($base, $vm) {
my $info = $base->info(user_admin);
ok($info->{clones}) or return;
ok($info->{clones}->{$vm->id}) or return;
is(scalar @{$info->{clones}->{$vm->id}},1 );
}
##################################################################################
clean();
......
......@@ -7,47 +7,30 @@
<%=l 'This base can\'t be removed because the domain has clones.' %>
</div>
<div class="form-group">
<div ng-hide="showmachine">
... Loading ...
</div>
has clones = <%= $domain->has_clones %><br/>
{{nodes}}
<form class="form-inline" action="<%= $action %>" method="post">
% for my $node (@$nodes) {
% my $local = ($node->{hostname} eq 'localhost' || $node->{hostname} eq '127.0.0.1');
<div class="row">
<div class="col-md-1">
% my $node_disabled_msg = '';
% if ( $domain->is_locked) {
% $node_disabled_msg = "Domain ".$domain->name." is locked";
% }
% if ($domain->has_clones && $local) {
% $node_disabled_msg = "Domain has ".$domain->has_clones." clones in local node";
% }
% if ( !$node->{is_active} ) {
% $node_disabled_msg = "Node inactive";
% }
% if ( !$node->{enabled} ) {
% $node_disabled_msg = "Node disabled";
% }
% my $node_disabled = 0;
% $node_disabled = 1 if $node_disabled_msg;
<input type="checkbox"
ng-disabled="<%= $node_disabled %>"
% if ($domain->is_base && $domain->base_in_vm($node->{id})) {
checked
% }
ng-click="toggle_base(<%= $node->{id} %>, <%= $domain->id %>)"
></div>
{{showmachine.base}}
<div class="row" ng-repeat="node in nodes">
<div class="col-md-2">
<label class="control-label" for="<%= $node->{id}%>"><%= $node->{name} %></label>
</div>
<div class="col-md-5">
node disabled = <%= $node_disabled_msg %>
<br/>
</div>
</div>
% }
</form>
<div class="col-md-1" ng-show="{{node.type == showmachine.type}}">
<input type="checkbox" ng-checked="showmachine.bases[node.id]"
ng-click="set_base(node.id, showmachine.id, !showmachine.bases[node.id])"
ng-disabled="pending_requests
|| !node.is_active
|| showmachine.clones[node.id]
|| ( node.is_local && showmachine.has_clones)">
</div>
<div class="col-md-2" ng-show="{{node.type == showmachine.type}}">
{{node.name}}
</div>
<div class="col-md-4" ng-show="{{node.type == showmachine.type}}">
<div ng-hide="node.is_active">Node down</div>
<div ng-hide="node.enabled">Node disabled</div>
<div ng-show="node.is_local && showmachine.has_clones">This base has clones</div>
<div ng-show="!node.is_local && showmachine.clones[node.id]">This node has {{ showmachine.clones[node.id].length }} clones</div>
</div>
</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