Unverified Commit fa1ee60c authored by Fernando Verdugo's avatar Fernando Verdugo Committed by GitHub
Browse files

Merge branch 'master' into 646_check_po

parents 76b64b83 9e1e111c
......@@ -6,6 +6,8 @@
[![Follow twitter](https://img.shields.io/twitter/follow/ravada_vdi.svg?style=social&label=Twitter&style=flat-square)](https://twitter.com/ravada_vdi)
[![Telegram Group](https://img.shields.io/badge/Telegram-Group-blue.svg)](https://t.me/ravadavdi)
[![Project Status: Active - The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)
## Remote Virtual Desktops Manager
......
......@@ -13,11 +13,14 @@ use Ravada;
use Ravada::Auth::SQL;
use Ravada::Auth::LDAP;
$|=1;
my $help;
my ($DEBUG, $ADD_USER );
my $VERBOSE = $ENV{TERM};
my $FILE_CONFIG_DEFAULT = "/etc/ravada.conf";
my $FILE_CONFIG;
......@@ -34,6 +37,7 @@ my $TEST_LDAP;
my $URL_ISOS;
my $ALL;
my $HIBERNATED;
my $DISCONNECTED;
my $LIST;
......@@ -70,6 +74,7 @@ my $USAGE = "$0 "
." --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"
."\n"
;
......@@ -88,6 +93,7 @@ GetOptions ( help => \$help
,'url-isos=s'=> \$URL_ISOS
,'shutdown:s'=> \$SHUTDOWN_DOMAIN
,'hibernate:s'=> \$HIBERNATE_DOMAIN
,'disconnected'=> \$DISCONNECTED
,'make-admin=s' => \$MAKE_ADMIN_USER
,'remove-admin=s' => \$REMOVE_ADMIN_USER
,'change-password'=> \$CHANGE_PASSWORD
......@@ -113,11 +119,12 @@ die "Only root can do that\n" if $> && ( $ADD_USER || $ADD_USER_LDAP || $IMPORT_
die "ERROR: Missing file config $FILE_CONFIG\n"
if $FILE_CONFIG && ! -e $FILE_CONFIG;
die "ERROR: Shutdown requires a domain name, or --all or --hibernated\n"
if defined $SHUTDOWN_DOMAIN && !$SHUTDOWN_DOMAIN && !$ALL && !$HIBERNATED;
die "ERROR: Shutdown requires a domain name, or --all , --hibernated , --disconnected\n"
if defined $SHUTDOWN_DOMAIN && !$SHUTDOWN_DOMAIN && !$ALL && !$HIBERNATED
&& !$DISCONNECTED;
die "ERROR: Hibernate requires a domain name, or --all\n"
if defined $HIBERNATE_DOMAIN && !$HIBERNATE_DOMAIN && !$ALL;
die "ERROR: Hibernate requires a domain name, or --all , --disconnected\n"
if defined $HIBERNATE_DOMAIN && !$HIBERNATE_DOMAIN && !$ALL && !$DISCONNECTED;
my %CONFIG;
%CONFIG = ( config => $FILE_CONFIG ) if $FILE_CONFIG;
......@@ -348,6 +355,12 @@ sub list {
print $domain->name."\t";
if ($domain->is_active) {
print "active";
my $status = $domain->client_status;
if ( $domain->remote_ip ) {
$status .= " , " if $status;
$status .= $domain->remote_ip;
}
print " ( $status ) " if $status;
} elsif ($domain->is_hibernated) {
print "hibernated";
} else {
......@@ -368,15 +381,22 @@ sub hibernate {
my $found = 0;
for my $domain ($rvd_back->list_domains) {
if ( ($all && $domain->is_active)
|| ($domain_name && $domain->name eq $domain_name)) {
|| ($domain_name && $domain->name eq $domain_name)
|| ($DISCONNECTED && $domain->client_status
&& $domain->client_status eq 'disconnected')
) {
$found++;
if (!$domain->is_active) {
warn "WARNING: Virtual machine ".$domain->name
." is already down.\n";
next;
}
if ( $DISCONNECTED && $domain->client_status
&& $domain->client_status eq 'disconnected') {
next if _verify_connection($domain);
}
if ($domain->can_hibernate) {
$domain->hibernate();
$domain->hibernate( $Ravada::USER_DAEMON);
$down++;
} else {
warn "WARNING: Virtual machine ".$domain->name
......@@ -388,7 +408,7 @@ sub hibernate {
}
print "$down machines hibernated.\n";
warn "ERROR: Domain $domain_name not found.\n"
if !$all && !$found;
if !$domain_name && !$found;
}
sub start_domain {
......@@ -427,9 +447,12 @@ sub shutdown_domain {
my $down = 0;
my $found = 0;
DOMAIN:
for my $domain ($rvd_back->list_domains) {
if ((defined $domain_name && $domain->name eq $domain_name)
|| ($hibernated && $domain->is_hibernated)
|| ($DISCONNECTED
&& ( $domain->client_status && $domain->client_status eq 'disconnected' ))
|| $all ){
$found++;
if (!$domain->is_active && !$domain->is_hibernated) {
......@@ -441,8 +464,14 @@ sub shutdown_domain {
if ($domain->is_hibernated) {
$domain->start(user => $Ravada::USER_DAEMON);
}
$domain->shutdown(user => $Ravada::USER_DAEMON, timeout => 60);
if ($DISCONNECTED && $domain->client_status
&& $domain->client_status eq 'disconnected') {
next DOMAIN if _verify_connection($domain);
}
print "Shutting down ".$domain->name.".\n";
eval { $domain->shutdown(user => $Ravada::USER_DAEMON, timeout => 300) };
warn $@ if $@;
$down++;
}
}
......@@ -451,6 +480,25 @@ sub shutdown_domain {
print "$down domains shut down.\n";
}
sub _verify_connection {
my $domain = shift;
print "Verifying connection for ".$domain->name
." ".($domain->remote_ip or '')." "
if $VERBOSE;
for ( 1 .. 25 ) {
if ( $domain->client_status(1)
&& $domain->client_status(1) ne 'disconnected' ) {
print "\n\t".$domain->client_status." ".$domain->remote_ip
." Shutdown dismissed.\n";
return 1;
}
print "." if $VERBOSE && !($_ % 5);
sleep 1;
}
print "\n" if $VERBOSE;
return 0;
}
sub test_ldap {
my $rvd_back = Ravada->new(%CONFIG);
eval { Ravada::Auth::LDAP::_init_ldap_admin() };
......
......@@ -132,8 +132,8 @@ sub BUILD {
$self->_create_tables();
$self->_upgrade_tables();
$self->_init_user_daemon();
$self->_update_data();
$self->_init_user_daemon();
}
sub _init_user_daemon {
......@@ -651,10 +651,75 @@ sub _update_data {
$self->_remove_old_isos();
$self->_update_isos();
$self->_update_grants();
$self->_enable_grants();
$self->_update_user_grants();
$self->_update_domain_drivers_types();
$self->_update_domain_drivers_options();
$self->_update_old_qemus();
}
sub _update_grants($self) {
my $sth = $CONNECTOR->dbh->prepare(
"UPDATE grant_types"
." SET name='create_machine' "
." WHERE name = 'create_domain'"
);
$sth->execute();
}
sub _null_grants($self) {
my $sth = $CONNECTOR->dbh->prepare("SELECT count(*) FROM grant_types "
." WHERE enabled = NULL "
);
$sth->execute;
my ($count) = $sth->fetchrow;
exit if !$count && $self->{_null}++;
return $count;
}
sub _enable_grants($self) {
return if $self->_null_grants();
my $sth = $CONNECTOR->dbh->prepare(
"UPDATE grant_types set enabled=0"
);
$sth->execute;
my @grants = (
'change_settings', 'change_settings_all', 'change_settings_clones'
,'clone', 'clone_all', 'create_base', 'create_machine'
,'grant'
,'manage_users'
,'remove', 'remove_all', 'remove_clone', 'remove_clone_all'
,'shutdown_all', 'shutdown_clone'
);
$sth = $CONNECTOR->dbh->prepare("SELECT id,name FROM grant_types");
$sth->execute;
my %grant_exists;
while (my ($id, $name) = $sth->fetchrow ) {
$grant_exists{$name} = $id;
}
$sth = $CONNECTOR->dbh->prepare(
"UPDATE grant_types set enabled=1 WHERE name=?"
);
my %done;
for my $name ( sort @grants ) {
die "Duplicate grant $name " if $done{$name};
die "Permission $name doesn't exist at table grant_types"
."\n".Dumper(\%grant_exists)
if !$grant_exists{$name};
$sth->execute($name);
}
}
sub _update_old_qemus($self) {
......@@ -831,6 +896,8 @@ sub _upgrade_tables {
$self->_upgrade_table('domains_network','allowed','int not null default 1');
$self->_upgrade_table('grant_types','enabled','int not null default 1');
}
......@@ -2184,8 +2251,8 @@ sub _refresh_down_domains($self, $active_domain, $active_vm) {
$sth->execute();
while ( my ($id_domain, $name, $id_vm) = $sth->fetchrow ) {
next if exists $active_domain->{$id_domain};
my $domain = Ravada::Domain->open($id_domain);
if (defined $id_vm && !$active_vm->{$id_vm}) {
my $domain = Ravada::Domain->open($id_domain) or next;
if (defined $id_vm && !$active_vm->{$id_vm} ) {
$domain->_set_data(status => 'shutdown');
} else {
my $status = 'shutdown';
......
......@@ -345,9 +345,9 @@ sub is_operator {
my $self = shift;
return $self->is_admin()
|| $self->can_shutdown_clone()
|| $self->can_hibernate_clone()
# || $self->can_hibernate_clone()
|| $self->can_change_settings_clones()
|| $self->can_remove_clone()
# || $self->can_remove_clone()
|| $self->can_remove_clone_all()
|| $self->can_create_base()
|| $self->can_create_machine();
......@@ -554,18 +554,22 @@ sub can_do($self, $grant) {
}
sub _load_grants($self) {
my $sth = $$CON->dbh->prepare(
"SELECT gt.name, gu.allowed"
my $sth;
eval { $sth= $$CON->dbh->prepare(
"SELECT gt.name, gu.allowed, gt.enabled"
." FROM grant_types gt LEFT JOIN grants_user gu "
." ON gt.id = gu.id_grant "
." AND gu.id_user=?"
);
$sth->execute($self->id);
my ($name, $allowed);
$sth->bind_columns(\($name, $allowed));
};
confess $@ if $@;
my ($name, $allowed, $enabled);
$sth->bind_columns(\($name, $allowed, $enabled));
while ($sth->fetch) {
$self->{_grant}->{$name} = $allowed;# or undef);
$self->{_grant}->{$name} = $allowed if $enabled;
$self->{_grant_disabled}->{$name} = !$enabled;
}
$sth->finish;
}
......@@ -580,7 +584,7 @@ sub grant_user_permissions($self,$user) {
$self->grant($user, 'clone');
$self->grant($user, 'change_settings');
$self->grant($user, 'remove');
$self->grant($user, 'screenshot');
# $self->grant($user, 'screenshot');
}
=head2 grant_operator_permissions
......@@ -614,6 +618,7 @@ Grant an user all the permissions
sub grant_admin_permissions($self,$user) {
my $sth = $$CON->dbh->prepare(
"SELECT name FROM grant_types "
." WHERE enabled=1"
);
$sth->execute();
while ( my ($name) = $sth->fetchrow) {
......@@ -654,6 +659,10 @@ Grant an user a specific permission, or revoke it
=cut
sub grant($self,$user,$permission,$value=1) {
confess "ERROR: permission '$permission' disabled "
if $self->{_grant_disabled}->{$permission};
if ( !$self->can_grant() && $self->name ne $Ravada::USER_DAEMON_NAME ) {
my @perms = $self->list_permissions();
confess "ERROR: ".$self->name." can't grant permissions for ".$user->name."\n"
......@@ -713,7 +722,9 @@ sub list_all_permissions($self) {
return if !$self->is_admin;
my $sth = $$CON->dbh->prepare(
"SELECT * FROM grant_types ORDER BY name"
"SELECT * FROM grant_types"
." WHERE enabled=1 "
." ORDER BY name "
);
$sth->execute;
my @list;
......
......@@ -264,7 +264,7 @@ sub _allow_remove($self, $user) {
confess "ERROR: Undefined user" if !defined $user;
die "ERROR: remove not allowed for user ".$user->name
if (!$user->can_remove());
unless $user->can_remove() || $user->is_admin;
$self->_check_has_clones() if $self->is_known();
if ( $self->is_known
......@@ -1946,8 +1946,8 @@ sub internal_id {
=head2 volatile_clones
Allows or disables the volatile clones option. If enabled, clones from this
virtual machine will be removed on shutdown
Enables or disables a domain volatile clones feature. Volatile clones are
removed when shut down
=cut
......@@ -1955,11 +1955,23 @@ sub volatile_clones($self, $value=undef) {
return $self->_data('volatile_clones', $value);
}
=head2 status
Returns the status of the virtual machine as a string.
Allowed values are: active, down, hibernated and paused
Sets or gets the status of a virtual machine
$machine->status('active');
Valid values are:
=over
=item * active
=item * down
=item * hibernated
=back
=cut
......
......@@ -380,7 +380,7 @@ Returns a reference to a list of the ISOs known by the system
sub iso_file {
my $self = shift;
my $vm = $self->search_vm('KVM');
my @isos = $vm->search_volume_path_re(qr(.*\.iso$));
my @isos = sort { "\L$a" cmp "\L$b" } $vm->search_volume_path_re(qr(.*\.iso$));
#TODO remove path from device
return \@isos;
}
......
......@@ -301,6 +301,12 @@ msgstr "Usuario"
msgid "Password"
msgstr "Contraseña"
msgid "password"
msgstr "contraseña"
msgid "Password"
msgstr "Contraseña"
msgid "Start session"
msgstr "Iniciar sesión"
......
......@@ -9,7 +9,7 @@ msgstr ""
"PO-Revision-Date: 2017-05-02 16:20+0200\n"
"Last-Translator: Fernando Verdugo fernando@etsetb.upc.edu\n"
"Language-Team: \n"
"Language: jp\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
......
......@@ -132,6 +132,7 @@ sub search_domain {
return if !defined $id;#
return $domain;
}
return;
}
sub list_networks {
......
......@@ -295,6 +295,8 @@
$scope.copy_password= function() {
$scope.view_password=1;
var copyTextarea = document.querySelector('.js-copytextarea');
if (copyTextarea) {
copyTextarea.select();
try {
var successful = document.execCommand('copy');
......@@ -303,6 +305,8 @@
} catch (err) {
console.log('Oops, unable to copy');
}
}
};
};
......
......@@ -438,7 +438,7 @@ get '/machine/pause/(:id).(:type)' => sub {
get '/machine/hybernate/(:id).(:type)' => sub {
my $c = shift;
return access_denied($c) if !$USER ->can_hibernate_all();
return access_denied($c) if !$USER ->is_admin();
return hybernate_machine($c);
};
......
/* any user should be allowed these */
INSERT INTO grant_types(name,description) VALUES('clone',"can clone public virtual machines.");
INSERT INTO grant_types(name,description) VALUES('change_settings',"can change the settings of owned virtual machines.");
INSERT INTO grant_types(name,description) VALUES('remove',"can remove any virtual machines owned by the user.");
INSERT INTO grant_types(name,description,enabled) VALUES('clone',"can clone public virtual machines.",1);
INSERT INTO grant_types(name,description,enabled) VALUES('change_settings',"can change the settings of owned virtual machines.",1);
INSERT INTO grant_types(name,description,enabled) VALUES('remove',"can remove any virtual machine owned by the user.",1);
INSERT INTO grant_types(name,description) VALUES('screenshot',"can take a screenshot of any virtual machine owned by the user.");
/* managers should be allowed these */
......@@ -10,13 +10,13 @@ INSERT INTO grant_types(name,description) VALUES('create_machine',"can create vi
INSERT INTO grant_types(name,description) VALUES('create_base',"can create bases.");
/* managers should be allowed these */
INSERT INTO grant_types(name,description) VALUES('change_settings_clones',"can change the settings of any virtual machines cloned from one base owned by the user.");
INSERT INTO grant_types(name,description) VALUES('change_settings_clones',"can change the settings of any virtual machine cloned from one base owned by the user.");
INSERT INTO grant_types(name,description) VALUES('remove_clone',"can remove clones from virtual machines owned by the user.");
INSERT INTO grant_types(name,description) VALUES('shutdown_clone',"can shutdown clones from virtual machines owned by the user.");
INSERT INTO grant_types(name,description) VALUES('hibernate_clone',"can hibernate clones from virtual machines owned by the user.");
/* operators should be allowed these */
INSERT INTO grant_types(name,description) VALUES('change_settings_all',"can change the settings of any virtual machines.");
INSERT INTO grant_types(name,description) VALUES('change_settings_all',"can change the settings of any virtual machine.");
INSERT INTO grant_types(name,description) VALUES('remove_clone_all',"can remove any clone.");
INSERT INTO grant_types(name,description) VALUES('hibernate_clone_all',"can hibernate any clone.");
......@@ -27,5 +27,5 @@ INSERT INTO grant_types(name,description) VALUES('shutdown_all',"can shutdown an
INSERT INTO grant_types(name,description) VALUES('hibernate_all',"can hibernate any virtual machine.");
INSERT INTO grant_types(name,description) VALUES('screenshot_all',"can take a screenshot of any virtual machine.");
INSERT INTO grant_types(name,description) VALUES('grant','can grant permissions to other users');
INSERT INTO grant_types(name,description, enabled) VALUES('grant','can grant permissions to other users', 1);
INSERT INTO grant_types(name,description) VALUES('manage_users','can manage users.');
......@@ -2,6 +2,7 @@ CREATE TABLE `grant_types` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(32) NOT NULL,
`description` varchar(255) NOT NULL,
`enabled` int default NULL,
UNIQUE(`name`),
UNIQUE(`description`),
PRIMARY KEY (`id`)
......
CREATE TABLE `grant_types` (
`id` integer NOT NULL primary key AUTOINCREMENT,
`name` char(32) NOT NULL,
`description` varchar(255) NOT NULL,
UNIQUE (`name`),
UNIQUE (`description`)
`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT
, `name` char(32) NOT NULL
, `description` varchar(255) NOT NULL
, `enabled` integer default NULL
, UNIQUE(`name`)
, UNIQUE(`description`)
);
......@@ -18,6 +18,9 @@ my $test = Test::SQL::Data->new(config => 't/etc/sql.conf');
my $CONFIG_FILE = 't/etc/ravada_ldap_1.conf';
init($test->connector, $CONFIG_FILE);
rvd_back();
my $RVD_FRONT;
my $USER_DATA;
......
......@@ -129,7 +129,6 @@ sub rvd_back {
, config => ( $CONFIG or $DEFAULT_CONFIG)
, warn_error => 0
);
$rvd->_update_isos();
$USER_ADMIN = create_user('admin','admin',1) if !$USER_ADMIN;
$ARG_CREATE_DOM{KVM} = [ id_iso => search_id_iso('Alpine') ];
......@@ -155,7 +154,6 @@ sub init {
$Ravada::CONNECTOR = $CONNECTOR if !$Ravada::CONNECTOR;
Ravada::Auth::SQL::_init_connector($CONNECTOR);
$USER_ADMIN = create_user('admin','admin',1) if $create_user;
$Ravada::Domain::MIN_FREE_MEMORY = 512*1024;
......
......@@ -29,31 +29,31 @@ sub test_defaults {
ok($user->can_clone);
ok($user->can_change_settings);
ok($user->can_screenshot);
# ok($user->can_screenshot);
ok($user->can_remove);
ok(!$user->can_remove_clone);
ok(!$user->can_clone_all);
# ok(!$user->can_clone_all);
ok(!$user->can_change_settings_all);
ok(!$user->can_change_settings_clones);
ok(!$user->can_screenshot_all);
# ok(!$user->can_screenshot_all);
ok(!$user->can_grant);
ok(!$user->can_create_base);
ok(!$user->can_create_machine);
ok(!$user->can_remove_all);
# ok(!$user->can_remove_all);
ok(!$user->can_remove_clone_all);
ok(!$user->can_shutdown_clone);
# ok(!$user->can_shutdown_clone);
ok(!$user->can_shutdown_all);
ok(!$user->can_hibernate_clone);
ok(!$user->can_hibernate_all);
ok(!$user->can_hibernate_clone_all);
# ok(!$user->can_hibernate_clone);
# ok(!$user->can_hibernate_all);
# ok(!$user->can_hibernate_clone_all);
ok(!$user->can_manage_users);
......@@ -134,6 +134,7 @@ sub test_remove_clone {
ok($clone2, "Expecting ".$clone->name." not removed");
$usera->grant($user,'remove_clone');
is($user->can_remove_clone, 1);
eval { $clone->remove($user); };
is($@,'');
......@@ -173,7 +174,8 @@ sub test_view_clones {
my $clones;
eval{ $clones = rvd_front->list_clones() };
is(scalar @$clones,0) or return;
is($@,'');
is(scalar @$clones,0, Dumper($clones)) or return;
my $clone = $domain->clone(user => $usera,name => new_domain_name());
eval{ $clones = rvd_front->list_clones() };
......@@ -212,6 +214,7 @@ sub test_shutdown_clone {
is($clone->is_active,1) or return;
$usera->grant($user,'shutdown_clone');
is($user->can_shutdown_clone,1);
eval { $clone->shutdown_now($user); };
is($@,'');
......@@ -635,11 +638,18 @@ sub test_change_settings($vm_name) {
is($user->can_change_settings($clone->id), 1);
is($usera->can_change_settings($clone->id), 1);