Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Projets publics
Ravada-Mirror
Commits
d8c0e8d2
Commit
d8c0e8d2
authored
Oct 09, 2020
by
frankiejol
Browse files
Merge branch 'develop' of
https://github.com/UPC/ravada
into develop
parents
1a63bdad
0a916d6b
Changes
9
Hide whitespace changes
Inline
Side-by-side
lib/Ravada.pm
View file @
d8c0e8d2
...
...
@@ -3709,6 +3709,60 @@ sub _cmd_set_time($self, $request) {
die
"
$@ , retry.
\n
"
if
$@
;
}
sub
_migrate_base
($self, $domain, $node, $uid, $request) {
my
$base
=
Ravada::
Domain
->
open
(
$domain
->
id_base
);
return
if
$base
->
base_in_vm
(
$node
->
id
);
my
$req_base
=
Ravada::
Request
->
set_base_vm
(
id_domain
=>
$base
->
id
,
id_vm
=>
$node
->
id
,
uid
=>
$uid
);
$request
->
after_request
(
$req_base
);
die
"
Base
"
.
$base
->
name
.
"
still not prepared in node
"
.
$node
->
name
.
"
. Retry
\n
";
}
sub
_cmd_migrate
($self, $request) {
my
$uid
=
$request
->
args
('
uid
');
my
$id_domain
=
$request
->
args
('
id_domain
')
or
die
"
ERROR: Missing id_domain
";
my
$user
=
Ravada::Auth::
SQL
->
search_by_id
(
$uid
);
my
$domain
=
$self
->
search_domain_by_id
(
$id_domain
);
die
"
Error: user
"
.
$user
->
name
.
"
not allowed to migrate domain
"
.
$domain
->
name
unless
$user
->
is_operator
;
my
$node
=
Ravada::
VM
->
open
(
$request
->
args
('
id_node
'));
$self
->
_migrate_base
(
$domain
,
$node
,
$uid
,
$request
)
if
$domain
->
id_base
;
if
(
$domain
->
is_active
)
{
if
(
$request
->
defined_arg
('
shutdown
'))
{
my
@timeout
;
@timeout
=
(
timeout
=>
$request
->
defined_arg
('
shutdown_timeout
')
)
if
$request
->
defined_arg
('
shutdown_timeout
');
my
$req_shutdown
=
Ravada::
Request
->
shutdown_domain
(
uid
=>
$uid
,
id_domain
=>
$id_domain
,
@timeout
);
$request
->
after_request
(
$req_shutdown
->
id
);
$request
->
retry
(
10
)
if
!
defined
$request
->
retry
();
die
"
Virtual Machine
"
.
$domain
->
name
.
"
"
.
$request
->
retry
.
"
is active. Shutting down. Retry.
\n
";
}
}
$domain
->
migrate
(
$node
,
$request
);
my
@remote_ip
;
@remote_ip
=
(
remote_ip
=>
$request
->
defined_arg
('
remote_ip
'))
if
$request
->
defined_arg
('
remote_ip
');
$domain
->
start
(
user
=>
$user
,
@remote_ip
)
if
$request
->
defined_arg
('
start
');
}
sub
_clean_requests
($self, $command, $request=undef, $status='requested') {
my
$query
=
"
DELETE FROM requests
"
.
"
WHERE command=?
"
...
...
@@ -4007,6 +4061,7 @@ sub _req_method {
,
shutdown_node
=>
\
&_cmd_shutdown_node
,
start_node
=>
\
&_cmd_start_node
,
connect_node
=>
\
&_cmd_connect_node
,
migrate
=>
\
&_cmd_migrate
#users
,
post_login
=>
\
&_cmd_post_login
...
...
lib/Ravada/Domain.pm
View file @
d8c0e8d2
...
...
@@ -438,8 +438,6 @@ sub _start_checks($self, @args) {
$self
->
_balance_vm
();
}
$self
->
rsync
(
request
=>
$request
)
if
!
$self
->
is_volatile
&&
!
$self
->
_vm
->
is_local
();
}
elsif
(
!
$self
->
is_local
)
{
$self
->
_set_vm
(
$vm_local
,
1
);
}
$self
->
_check_free_vm_memory
();
#TODO: remove them and make it more general now we have nodes
...
...
@@ -476,6 +474,7 @@ sub _search_already_started($self, $fast = 0) {
next
;
}
next
if
!
$domain
;
$vm
->
_add_instance_db
(
$domain
->
id
);
if
(
$domain
->
is_active
||
$domain
->
is_hibernated
)
{
$self
->
_set_vm
(
$vm
,'
force
');
$started
{
$vm
->
id
}
++
;
...
...
@@ -1556,6 +1555,7 @@ sub info($self, $user) {
,
run_timeout
=>
$self
->
run_timeout
,
autostart
=>
$self
->
autostart
,
volatile_clones
=>
$self
->
volatile_clones
,
id_vm
=>
$self
->
_data
('
id_vm
')
};
for
(
qw(comment screenshot id_owner shutdown_disconnected)
)
{
$info
->
{
$_
}
=
$self
->
_data
(
$_
);
...
...
@@ -3906,7 +3906,7 @@ sub rsync($self, @args) {
if
(
$self
->
is_base
)
{
push
@files_base
,(
$self
->
list_files_base
);
}
$files
=
[
$self
->
list_volumes
(
device
=>
'
disk
'
),
@files_base
];
$files
=
[
$self
->
list_volumes
(),
@files_base
];
}
$request
->
status
("
working
")
if
$request
;
...
...
@@ -3970,28 +3970,29 @@ sub _pre_migrate($self, $node, $request = undef) {
$self
->
_check_equal_storage_pools
(
$node
)
if
$self
->
_vm
->
is_active
;
$self
->
_internal_autostart
(
0
);
return
if
!
$self
->
id_base
;
$self
->
check_status
();
confess
"
ERROR: Active domains can't be migrated
"
if
$self
->
is_active
;
my
$base
=
Ravada::
Domain
->
open
(
$self
->
id_base
);
confess
"
ERROR: base
"
.
$base
->
name
.
"
not prepared in node
"
.
$node
->
name
if
(
$self
->
id_base
)
{
my
$base
=
Ravada::
Domain
->
open
(
$self
->
id_base
);
confess
"
ERROR: base
"
.
$base
->
name
.
"
not prepared in node
"
.
$node
->
name
if
!
$base
->
base_in_vm
(
$node
->
id
);
confess
"
ERROR: base id
"
.
$self
->
id_base
.
"
not found.
"
if
!
$base
;
confess
"
ERROR: base id
"
.
$self
->
id_base
.
"
not found.
"
if
!
$base
;
for
my
$file
(
$base
->
list_files_base
)
{
next
if
$node
->
file_exists
(
$file
);
warn
"
Warning: file not found
$file
in
"
.
$node
->
name
;
Ravada::
Request
->
set_base_vm
(
uid
=>
Ravada::Utils::
user_daemon
->
id
,
id_domain
=>
$base
->
id
,
id_vm
=>
$node
->
id
);
return
;
}
for
my
$file
(
$base
->
list_files_base
)
{
next
if
$node
->
file_exists
(
$file
);
warn
"
Warning: file not found
$file
in
"
.
$node
->
name
;
Ravada::
Request
->
set_base_vm
(
uid
=>
Ravada::Utils::
user_daemon
->
id
,
id_domain
=>
$base
->
id
,
id_vm
=>
$node
->
id
);
return
;
}
$self
->
_set_base_vm_db
(
$node
->
id
,
0
)
unless
$node
->
is_local
;
$self
->
_set_base_vm_db
(
$node
->
id
,
0
)
unless
$node
->
is_local
;
}
$node
->
_add_instance_db
(
$self
->
id
);
}
...
...
lib/Ravada/Request.pm
View file @
d8c0e8d2
...
...
@@ -110,6 +110,9 @@ our %VALID_ARG = (
,
shutdown_node
=>
{
id_node
=>
1
,
at
=>
2
}
,
start_node
=>
{
id_node
=>
1
,
at
=>
2
}
,
connect_node
=>
{
backend
=>
2
,
hostname
=>
2
,
id_node
=>
2
,
timeout
=>
2
}
,
migrate
=>
{
uid
=>
1
,
id_node
=>
1
,
id_domain
=>
1
,
start
=>
2
,
remote_ip
=>
2
,
shutdown
=>
2
,
shutdown_timeout
=>
2
}
#users
,
post_login
=>
{
user
=>
1
,
locale
=>
2
}
...
...
@@ -161,6 +164,7 @@ our %COMMAND = (
,
commands
=>
['
prepare_base
','
remove_base
','
set_base_vm
','
rebase_volumes
'
,
'
remove_base_vm
'
,
'
screenshot
'
,
'
migrate
'
]
,
priority
=>
6
}
...
...
public/js/ravada.js
View file @
d8c0e8d2
...
...
@@ -226,7 +226,7 @@
});
}
};
$scope
.
new_node_start
=
true
;
subscribe_nodes
=
function
(
url
,
type
)
{
var
ws
=
new
WebSocket
(
url
);
ws
.
onopen
=
function
(
event
)
{
ws
.
send
(
'
list_nodes/
'
+
type
)
};
...
...
@@ -234,6 +234,19 @@
var
data
=
JSON
.
parse
(
event
.
data
);
$scope
.
$apply
(
function
()
{
$scope
.
nodes
=
data
;
for
(
var
i
=
0
;
i
<
$scope
.
nodes
.
length
;
i
++
)
{
if
(
$scope
.
new_node
)
{
if
(
$scope
.
new_node
.
id
==
$scope
.
nodes
[
i
].
id
)
{
$scope
.
new_node
=
$scope
.
nodes
[
i
];
return
}
}
else
{
if
(
$scope
.
nodes
[
i
].
id
==
$scope
.
showmachine
.
id_vm
)
{
$scope
.
new_node
=
$scope
.
nodes
[
i
];
return
;
}
}
}
});
}
};
...
...
script/rvd_back
View file @
d8c0e8d2
...
...
@@ -3,6 +3,9 @@
use
warnings
;
use
strict
;
no
warnings
"
experimental::signatures
";
use
feature
qw(signatures)
;
use
Data::
Dumper
;
use
Getopt::
Long
;
use
POSIX
"
:sys_wait_h
";
...
...
@@ -39,6 +42,7 @@ my $URL_ISOS;
my
$ALL
;
my
$HIBERNATED
;
my
$DISCONNECTED
;
my
$ACTIVE
;
my
$LIST
;
...
...
@@ -48,6 +52,7 @@ my $SHUTDOWN_DOMAIN;
my
$REMOVE_DOMAIN
;
my
$REBASE
;
my
$RUN_REQUEST
;
my
$MIGRATE
;
my
$IMPORT_DOMAIN_OWNER
;
...
...
@@ -80,12 +85,14 @@ my $USAGE = "$0 "
.
"
--hibernate machine
\n
"
.
"
--shutdown machine
\n
"
.
"
--remove machine
\n
"
.
"
--migrate node machine1 machine2 ... machineN
\n
"
.
"
\n
"
.
"
Operations modifiers:
\n
"
.
"
--all : execute on all virtual machines
\n
"
.
"
For hibernate, it is executed on all the actives
\n
"
.
"
--hibernated: execute on hibernated machines
\n
"
.
"
--disconnected: execute on disconnected machines
\n
"
.
"
--active: execute on active running machines
\n
"
.
"
\n
"
;
...
...
@@ -98,6 +105,7 @@ GetOptions ( help => \$help
,
verbose
=>
\
$VERBOSE
,
rebase
=>
\
$REBASE
,'
no-fork
'
=>
\
$NOFORK
,'
active
'
=>
\
$ACTIVE
,'
start=s
'
=>
\
$START_DOMAIN
,'
config=s
'
=>
\
$FILE_CONFIG
,'
hibernated
'
=>
\
$HIBERNATED
...
...
@@ -119,6 +127,8 @@ GetOptions ( help => \$help
,'
add-locale-repository=s
'
=>
\
$ADD_LOCALE_REPOSITORY
,'
run-request=s
'
=>
\
$RUN_REQUEST
,'
migrate=s
'
=>
\
$MIGRATE
)
or
exit
;
$START
=
1
if
$DEBUG
||
$FILE_CONFIG
||
$NOFORK
;
...
...
@@ -154,6 +164,8 @@ $Ravada::DEBUG=1 if $DEBUG;
$
Ravada::
VERBOSE
=
1
if
$VERBOSE
;
$
Ravada::
CAN_FORK
=
0
if
$NOFORK
;
my
$RVD_BACK
;
###################################################################
###################################################################
...
...
@@ -631,6 +643,65 @@ sub run_request {
.
"
\n
";
}
sub
rvd_back
{
return
$RVD_BACK
if
$RVD_BACK
;
$RVD_BACK
=
Ravada
->
new
(
%CONFIG
);
return
$RVD_BACK
;
}
sub
list_active_machines
{
my
@domains
=
rvd_back
->
list_domains
(
active
=>
1
);
if
(
!
@domains
)
{
die
"
No active domains
\n
";
}
return
@domains
;
}
sub
migrate
($node_name) {
my
$vms
=
rvd_back
->
vm
();
my
(
$node
)
=
grep
{
$_
->
name
eq
$node_name
}
@$vms
or
die
"
Error: Node
$node_name
not found
\n
"
.
Dumper
([
map
{
$_
->
name
}
@$vms
]);
$node
->
start
()
if
!
$node
->
is_active
;
my
@machines
;
if
(
$ACTIVE
)
{
@machines
=
list_active_machines
();
}
else
{
@machines
=
@ARGV
;
}
if
(
!
scalar
(
@machines
))
{
die
"
Error: supply machines to migrate:
\n
"
.
"
rvd_back --migrate=node --active
\n
"
.
"
rvd_back --migrate=node machine1 machine2 machine3
\n
";
}
for
my
$machine
(
@machines
)
{
my
(
$domain
,
$name
,
$id_domain
);
if
(
!
ref
(
$machine
))
{
$domain
=
rvd_back
->
search_domain
(
$machine
)
or
do
{
warn
"
Error: machine
$machine
not found
\n
";
next
;
};
}
else
{
$domain
=
$machine
;
}
$name
=
$domain
->
name
;
$id_domain
=
$domain
->
id
;
if
(
$domain
->
_data
('
id_vm
')
==
$node
->
id
)
{
warn
"
Warning: machine
$name
already in node
$node_name
\n
";
next
;
}
warn
"
migrate
$node_name
$name
\n
";
Ravada::
Request
->
migrate
(
id_node
=>
$node
->
id
,
uid
=>
Ravada::Utils::
user_daemon
->
id
,
id_domain
=>
$id_domain
,
start
=>
$domain
->
is_active
,
shutdown
=>
1
);
}
}
sub
DESTROY
{
}
...
...
@@ -663,6 +734,8 @@ shutdown_domain($SHUTDOWN_DOMAIN, $ALL, $HIBERNATED)
add_locale_repository
(
$ADD_LOCALE_REPOSITORY
)
if
$ADD_LOCALE_REPOSITORY
;
run_request
(
$RUN_REQUEST
)
if
$RUN_REQUEST
;
migrate
(
$MIGRATE
)
if
$MIGRATE
;
}
...
...
t/lib/Test/Ravada.pm
View file @
d8c0e8d2
...
...
@@ -830,6 +830,7 @@ sub wait_request {
.
"
"
.
(
$req
->
error
or
''))
if
$debug
&&
(
time
%
5
==
0
);
sleep
1
;
$done_all
=
0
;
sleep
1
;
}
elsif
(
!
$done
{
$req
->
id
})
{
$t0
=
time
;
$done
{
$req
->
{
id
}}
++
;
...
...
@@ -852,7 +853,8 @@ sub wait_request {
next
if
$skip
{
$req
->
command
};
if
(
$req
->
status
ne
'
done
')
{
$done_all
=
0
;
diag
("
Waiting for request
"
.
$req
->
id
.
"
"
.
$req
->
command
);
diag
("
Waiting for request
"
.
$req
->
id
.
"
"
.
$req
->
command
)
if
$debug
&&
(
time
%
5
==
0
);
last
;
}
}
...
...
t/nodes/10_basic.t
View file @
d8c0e8d2
...
...
@@ -1072,6 +1072,98 @@ sub test_fill_memory($vm, $node, $migrate) {
_remove_clones
(
$base
);
}
sub
test_migrate
($vm, $node) {
my
$domain
=
create_domain
(
$vm
);
$domain
->
migrate
(
$node
);
is
(
$domain
->
_data
('
id_vm
'),
$node
->
id
);
is
(
$domain
->
_vm
->
id
,
$node
->
id
);
$domain
->
start
(
user_admin
);
is
(
$domain
->
_data
('
id_vm
'),
$node
->
id
);
is
(
$domain
->
_vm
->
id
,
$node
->
id
);
is
(
$domain
->
is_active
,
1
);
my
$domain2
=
Ravada::
Domain
->
open
(
$domain
->
id
);
is
(
$domain2
->
is_active
,
1
);
is
(
$domain2
->
_data
('
id_vm
'),
$node
->
id
);
is
(
$domain2
->
_vm
->
id
,
$node
->
id
);
$domain
->
shutdown_now
(
user_admin
);
start_domain_internal
(
$domain
);
my
$domain3
=
Ravada::
Domain
->
open
(
$domain
->
id
);
$domain3
->
start
(
user_admin
);
is
(
$domain3
->
is_active
,
1
);
is
(
$domain3
->
_data
('
id_vm
'),
$node
->
id
);
is
(
$domain3
->
_vm
->
id
,
$node
->
id
);
$domain
->
remove
(
user_admin
);
}
sub
test_check_instances
($vm, $node) {
my
$domain
=
create_domain
(
$vm
);
$domain
->
migrate
(
$node
);
start_domain_internal
(
$domain
);
is
(
$domain
->
_data
('
id_vm
'),
$node
->
id
);
is
(
$domain
->
_vm
->
id
,
$node
->
id
);
my
@instances
=
$domain
->
list_instances
();
is
(
scalar
(
@instances
),
2
);
my
$sth
=
connector
->
dbh
->
prepare
("
DELETE FROM domain_instances WHERE id_domain=?
");
$sth
->
execute
(
$domain
->
id
);
my
@instances2
=
$domain
->
list_instances
();
is
(
scalar
(
@instances2
),
0
);
$domain
->
_data
(
id_vm
=>
$vm
->
id
);
$domain
->
_vm
(
$vm
);
$domain
->
start
(
user_admin
);
is
(
$domain
->
_data
('
id_vm
'),
$node
->
id
);
is
(
$domain
->
_vm
->
id
,
$node
->
id
);
my
@instances3
=
$domain
->
list_instances
();
is
(
scalar
(
@instances3
),
2
,
"
Expecting 2 instances of
"
.
$domain
->
name
);
$domain
->
remove
(
user_admin
);
}
sub
test_migrate_req
($vm, $node) {
my
$domain
=
create_domain
(
$vm
);
$domain
->
start
(
user_admin
);
my
$req
=
Ravada::
Request
->
migrate
(
id_domain
=>
$domain
->
id
,
id_node
=>
$node
->
id
,
uid
=>
user_admin
->
id
,
start
=>
1
,
shutdown
=>
1
,
shutdown_timeout
=>
10
,
remote_ip
=>
'
1.2.2.34
'
,
retry
=>
10
);
for
(
1
..
30
)
{
wait_request
(
debug
=>
1
,
check_error
=>
0
);
is
(
$req
->
status
,'
done
');
last
if
!
$req
->
error
;
diag
(
$req
->
status
);
diag
(
$req
->
error
.
"
try :
"
.
$req
->
retry
);
sleep
1
;
}
is
(
$req
->
error
,'')
or
exit
;
my
$domain3
=
Ravada::
Domain
->
open
(
$domain
->
id
);
is
(
$domain3
->
is_active
,
1
);
is
(
$domain3
->
_data
('
id_vm
'),
$node
->
id
);
is
(
$domain3
->
_vm
->
id
,
$node
->
id
);
$domain
->
remove
(
user_admin
);
}
##################################################################################
clean
();
...
...
@@ -1112,6 +1204,10 @@ for my $vm_name ( vm_names() ) {
start_node
(
$node
);
test_check_instances
(
$vm
,
$node
);
test_migrate
(
$vm
,
$node
);
test_migrate_req
(
$vm
,
$node
);
test_set_vm_fail
(
$vm
,
$node
);
test_volatile_req_clone
(
$vm
,
$node
);
...
...
templates/main/admin_machines.html.ep
View file @
d8c0e8d2
...
...
@@ -280,7 +280,9 @@
<div
ng-show=
"{{machine.is_base}} && !{{machine.is_locked}}"
ng-cloak
><span
class=
"badge badge-pill badge-light"
><
%=
l
'
This
Machine
is
a
base
'
%
></span></div>
</td>
<td
class=
"lgMachNode"
></td>
<td
class=
"lgMachToggle"
><span
ng-hide=
"machine.is_base"
class=
"badge badge-info"
title=
"<%=l 'Node'%>"
>
{{machine.node}}
</span></td>
</tr>
<tr
ng-show=
"show_clones[machine.id] && machine.childs_loading "
>
<td>
<
%=
l
'
Loading
...'
%
>
</td>
...
...
templates/main/vm_options.html.ep
View file @
d8c0e8d2
...
...
@@ -9,6 +9,62 @@
{{showmachine.ip}}
</div>
</div>
<div class="row" ng-show="!nodes">
<div class="col-lg-3 mt-2">
Loading ..
</div>
</div>
<div class="row" ng-show="!showmachine.is_base && nodes.length>1">
<div class="col-lg-3 mt-2">
Node
</div>
<div class="col-lg-3 mt-2">
<select ng-model="new_node"
ng-disabled="pending_request && pending_request.status != 'done'"
ng-options="node.name for node in nodes | orderBy : 'name'">
>
</select>
</div>
</div>
<div class="row"
ng-show="new_node && new_node.id != showmachine.id_vm
&& (!pending_request || pending_request.status == 'done')"
>
<div class="col-lg-3 mt-2">
</div>
<div class="col-lg-9 mt-2 alert alert-warning">
<div>
<input type="checkbox" ng-model="new_node_start"/>
<label for="start"><%=l 'Start after migration' %></label>
</div>
<div ng-show="showmachine.is_active">
This virtual machine is running. It must be shut down before
migrate.
</div>
<div>
Are you sure you want to migrate {{showmachine.name}}
to {{new_node.name}} ?
</div>
<div>
<button type="button" class="btn btn-primary"
ng-click="request('migrate', {
'id_domain': showmachine.id
,'id_node': new_node.id
,'shutdown': 1
,'shutdown_timeout': 20
,'start': new_node_start
,'retry': 10
}); showmachine.id_vm=new_node.id;"
><%=l 'Yes' %> </button>
<button type="button" class="btn btn-danger"
ng-click="new_node=undefined"
><%=l 'No' %></button>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-3 mt-2">
<label class="control-label" for="ram"><%=l 'Max memory (MB)' %></label>
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment