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

Feature booking (#1512)

feat: bookings

* feat(cli): manage LDAP groups and users
* feat(frontend): manage LDAP groups and users

issue #1337
parent 1f45a31e
...@@ -4,7 +4,7 @@ TZ=Europe/Madrid ...@@ -4,7 +4,7 @@ TZ=Europe/Madrid
# If you change password remember update dockerfy/dockers/back/ravada.conf # If you change password remember update dockerfy/dockers/back/ravada.conf
MYSQL_DATABASE=ravada MYSQL_DATABASE=ravada
MYSQL_ROOT_PASSWORD=Pword12345* MYSQL_ROOT_PASSWORD=Pword12345*
MYSQL_HOST=127.0.0.1 MYSQL_HOST=0.0.0.0
MYSQL_PORT=33306 MYSQL_PORT=33306
MYSQL_USER=rvd_user MYSQL_USER=rvd_user
MYSQL_PASSWORD=Pword12345* MYSQL_PASSWORD=Pword12345*
......
...@@ -11,6 +11,8 @@ services: ...@@ -11,6 +11,8 @@ services:
env_file: .env env_file: .env
command: --default-authentication-plugin=mysql_native_password command: --default-authentication-plugin=mysql_native_password
restart: unless-stopped restart: unless-stopped
ports:
- "33306:33306"
ravada-front: ravada-front:
container_name: ravada-front container_name: ravada-front
...@@ -24,10 +26,9 @@ services: ...@@ -24,10 +26,9 @@ services:
networks: networks:
- ravada_network - ravada_network
#By default download from dockerhub #By default download from dockerhub
image: ravada/front
env_file: .env env_file: .env
#If you want to local build #If you want to local build
#build: dockers/front/. build: dockers/front/.
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
...@@ -50,10 +51,9 @@ services: ...@@ -50,10 +51,9 @@ services:
networks: networks:
- ravada_network - ravada_network
#By default download from dockerhub #By default download from dockerhub
image: ravada/back
env_file: .env env_file: .env
#If you want to local build #If you want to local build
#build: dockers/back/. build: dockers/back/.
privileged: true privileged: true
restart: unless-stopped restart: unless-stopped
......
...@@ -14,12 +14,13 @@ RUN apt-get update \ ...@@ -14,12 +14,13 @@ RUN apt-get update \
liblwp-useragent-determined-perl libvirt-clients supervisor net-tools openssh-client apt-utils curl libpbkdf2-tiny-perl \ liblwp-useragent-determined-perl libvirt-clients supervisor net-tools openssh-client apt-utils curl libpbkdf2-tiny-perl \
libio-stringy-perl libvirt-daemon-system libvirt-clients netcat-openbsd qemu-kvm qemu-utils iproute2 wget bridge-utils firewalld dnsmasq iptables ebtables \ libio-stringy-perl libvirt-daemon-system libvirt-clients netcat-openbsd qemu-kvm qemu-utils iproute2 wget bridge-utils firewalld dnsmasq iptables ebtables \
libnet-openssh-perl libdatetime-format-dateparse-perl file\ libnet-openssh-perl libdatetime-format-dateparse-perl file\
&& apt-get clean && apt-get clean \
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV TZ=Europe/Madrid
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata \
RUN echo "listen_tls = 0" >> /etc/libvirt/libvirtd.conf \ RUN echo "listen_tls = 0" >> /etc/libvirt/libvirtd.conf \
&& echo 'listen_tcp = 1' >> /etc/libvirt/libvirtd.conf \ && echo 'listen_tcp = 1' >> /etc/libvirt/libvirtd.conf \
# && mkdir -p /root/.ssh \ # && mkdir -p /root/.ssh \
...@@ -40,5 +41,5 @@ COPY supervisord.conf /etc/supervisord.conf ...@@ -40,5 +41,5 @@ COPY supervisord.conf /etc/supervisord.conf
#ADD src/ravada /ravada #ADD src/ravada /ravada
COPY ravada.conf /etc/ravada.conf COPY ravada.conf /etc/ravada.conf
WORKDIR /ravada WORKDIR /ravada
ENV PERL5LIB /ravada/lib
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
db: db:
user: rvd_user user: rvd_user
password: Pword12345* password: Pword12345*
host: ravada-mysql host: ravada-mysql
\ No newline at end of file
ldap:
server: 10.1.36.224
admin_user:
dn: cn=Directory Manager
password: 12345678
base: 'dc=example,dc=com'
...@@ -13,12 +13,16 @@ RUN apt-get update \ ...@@ -13,12 +13,16 @@ RUN apt-get update \
libfile-rsync-perl libdate-calc-perl libparallel-forkmanager-perl libdatetime-perl libencode-locale-perl netcat-openbsd \ libfile-rsync-perl libdate-calc-perl libparallel-forkmanager-perl libdatetime-perl libencode-locale-perl netcat-openbsd \
libio-stringy-perl libvirt-clients liblwp-useragent-determined-perl supervisor net-tools apt-utils lsof mysql-client \ libio-stringy-perl libvirt-clients liblwp-useragent-determined-perl supervisor net-tools apt-utils lsof mysql-client \
curl bash vim wget libnet-openssh-perl libdatetime-format-dateparse-perl \ curl bash vim wget libnet-openssh-perl libdatetime-format-dateparse-perl \
&& apt-get clean && apt-get clean \
ENV TZ=Europe/Madrid
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata \ RUN DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN mkdir -p /var/log/supervisor \ RUN mkdir -p /var/log/supervisor \
&& mkdir -p /run/sshd && mkdir -p /run/sshd
......
db: db:
user: rvd_user user: rvd_user
password: Pword12345* password: Pword12345*
host: ravada-mysql host: ravada-mysql
\ No newline at end of file
ldap:
server: 10.1.36.224
admin_user:
dn: cn=Directory Manager
password: 12345678
base: 'dc=example,dc=com'
...@@ -7,7 +7,7 @@ logfile_maxbytes=0 ...@@ -7,7 +7,7 @@ logfile_maxbytes=0
[program:rvd_front] [program:rvd_front]
environment=PERL5LIB="./lib" environment=PERL5LIB="./lib"
command=morbo ./script/rvd_front command=morbo -v ./script/rvd_front
autostart=true autostart=true
autorestart=true autorestart=true
startsecs=5 startsecs=5
......
https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css morris.js/ https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css morris.js/
https://use.fontawesome.com/releases/v5.10.1/fontawesome-free-5.10.1-web.zip https://use.fontawesome.com/releases/v5.10.1/fontawesome-free-5.10.1-web.zip
https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.7.0/introjs.css intro.js/bin/ https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.7.0/introjs.css intro.js/bin/
https://code.jquery.com/jquery-3.5.0.min.js jquery/ https://code.jquery.com/jquery-3.5.1.slim.min.js jquery/
https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js
https://jqueryui.com/resources/download/jquery-ui-1.11.4.zip https://jqueryui.com/resources/download/jquery-ui-1.11.4.zip
https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js
https://code.angularjs.org/1.7.8/angular-1.7.8.zip https://code.angularjs.org/1.7.8/angular-1.7.8.zip
https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap.min.js https://cdn.jsdelivr.net/npm/ui-bootstrap4@3.0.6/dist/ui-bootstrap-tpls.js
https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js raphael.js/ https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js raphael.js/
https://github.com/snapappointments/bootstrap-select/archive/v1.13.15.zip https://github.com/snapappointments/bootstrap-select/archive/v1.13.15.zip
https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js morris.js/ https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js morris.js/
...@@ -17,3 +18,13 @@ https://readthedocs.org/projects/ravada/badge/?version=latest ../img/latest.svg ...@@ -17,3 +18,13 @@ https://readthedocs.org/projects/ravada/badge/?version=latest ../img/latest.svg
https://img.shields.io/badge/License-AGPL%20v3-blue.svg ../img/License-AGPL%20v3-blue.svg https://img.shields.io/badge/License-AGPL%20v3-blue.svg ../img/License-AGPL%20v3-blue.svg
https://download.cksource.com/CKEditor/CKEditor/CKEditor%204.12.1/ckeditor_4.12.1_standard_easyimage.zip https://download.cksource.com/CKEditor/CKEditor/CKEditor%204.12.1/ckeditor_4.12.1_standard_easyimage.zip
https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.js angular-material/ https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.js angular-material/
# bookings
https://cdn.jsdelivr.net/npm/fullcalendar@5.1.0/main.css bookings/
https://cdn.jsdelivr.net/npm/clockpicker@0.0.7/dist/bootstrap-clockpicker.min.css bookings/
https://cdn.jsdelivr.net/npm/angularjs-toast@latest/angularjs-toast.css bookings/
https://cdn.jsdelivr.net/npm/angularjs-toast@latest/angularjs-toast.js bookings/
https://cdn.jsdelivr.net/npm/fullcalendar@5.1.0/main.min.js bookings/
https://cdn.jsdelivr.net/npm/fullcalendar-scheduler@5.1.0/locales-all.min.js bookings/
https://cdn.jsdelivr.net/npm/moment@2.27.0/min/moment-with-locales.min.js bookings/
https://cdn.jsdelivr.net/npm/angular-moment@1.3.0/angular-moment.min.js bookings/
https://cdn.jsdelivr.net/npm/clockpicker@0.0.7/dist/bootstrap-clockpicker.min.js bookings/
...@@ -44,10 +44,12 @@ sub download($url, $dst = $DIR_FALLBACK) { ...@@ -44,10 +44,12 @@ sub download($url, $dst = $DIR_FALLBACK) {
print "$url downloaded to $dst\n"; print "$url downloaded to $dst\n";
$res->content->asset->move_to($dst); $res->content->asset->move_to($dst);
} }
elsif ($res->is_error) { print $res->message."\n" } elsif ($res->is_error) { print $res->message."\n"; exit }
elsif ($res->code == 301) { print $res->headers->location."\n" } elsif ($res->code == 301) { print $res->headers->location."\n" }
else { print "Error ".$res->code." ".$res->message else { print "Error ".$res->code." ".$res->message
." downloading $url\n"} ." downloading $url\n";
exit;
}
return $dst; return $dst;
} }
......
...@@ -9,7 +9,8 @@ use Carp qw(carp croak cluck); ...@@ -9,7 +9,8 @@ use Carp qw(carp croak cluck);
use Data::Dumper; use Data::Dumper;
use DBIx::Connector; use DBIx::Connector;
use File::Copy; use File::Copy;
use Hash::Util qw(unlock_hash lock_hash); use Hash::Util qw(lock_hash unlock_hash);
use IPC::Run3 qw(run3);
use JSON::XS; use JSON::XS;
use Moose; use Moose;
use POSIX qw(WNOHANG); use POSIX qw(WNOHANG);
...@@ -23,6 +24,7 @@ no warnings "experimental::signatures"; ...@@ -23,6 +24,7 @@ no warnings "experimental::signatures";
use feature qw(signatures); use feature qw(signatures);
use Ravada::Auth; use Ravada::Auth;
use Ravada::Booking;
use Ravada::Request; use Ravada::Request;
use Ravada::Repository::ISO; use Ravada::Repository::ISO;
use Ravada::VM::Void; use Ravada::VM::Void;
...@@ -1085,21 +1087,34 @@ sub _add_indexes_generic($self) { ...@@ -1085,21 +1087,34 @@ sub _add_indexes_generic($self) {
,settings => [ ,settings => [
"index(id_parent,name)" "index(id_parent,name)"
] ]
,booking_entries => [
"index(id_booking)"
]
,booking_entry_ldap_groups => [
"index(id_booking_entry,ldap_group)"
]
,booking_entry_users => [
"index(id_booking_entry,id_user)"
]
,booking_entry_bases => [
"index(id_booking_entry,id_base)"
]
,vms=> [ ,vms=> [
"unique(hostname, vm_type)" "unique(hostname, vm_type)"
] ]
); );
my $if_not_exists = ''; my $if_not_exists = '';
$if_not_exists = ' IF NOT EXISTS ' if $CONNECTOR->dbh->{Driver}{Name} =~ /sqlite|mariadb/i; $if_not_exists = ' IF NOT EXISTS ' if $CONNECTOR->dbh->{Driver}{Name} =~ /sqlite|mariadb/i;
for my $table ( keys %index ) { for my $table ( keys %index ) {
my $known = $self->_get_indexes($table); my $known;
for my $change (@{$index{$table}} ) { for my $change (@{$index{$table}} ) {
my ($type,$fields ) =$change =~ /(\w+)\((.*)\)/; my ($type,$fields ) =$change =~ /(\w+)\((.*)\)/;
my ($name) = $change =~ /:(.*)/; my ($name) = $change =~ /:(.*)/;
$name = $fields if !$name; $name = $fields if !$name;
$name =~ s/,/_/g; $name =~ s/,/_/g;
$name =~ s/ //g; $name =~ s/ //g;
$known = $self->_get_indexes($table) if !defined $known;
next if $known->{$name}; next if $known->{$name};
$type .=" INDEX " if $type=~ /^unique/i; $type .=" INDEX " if $type=~ /^unique/i;
...@@ -1183,6 +1198,8 @@ sub _add_grants($self) { ...@@ -1183,6 +1198,8 @@ sub _add_grants($self) {
$self->_add_grant('screenshot', 1,"Can get a screenshot of own virtual machines."); $self->_add_grant('screenshot', 1,"Can get a screenshot of own virtual machines.");
$self->_add_grant('start_many',0,"Can have more than one machine started."); $self->_add_grant('start_many',0,"Can have more than one machine started.");
$self->_add_grant('expose_ports',0,"Can expose virtual machine ports."); $self->_add_grant('expose_ports',0,"Can expose virtual machine ports.");
$self->_add_grant('view_groups',0,'Can view groups.');
$self->_add_grant('manage_groups',0,'Can manage groups.');
$self->_add_grant('start_limit',0,"can have their own limit on started machines.", 1); $self->_add_grant('start_limit',0,"can have their own limit on started machines.", 1);
} }
...@@ -1254,6 +1271,8 @@ sub _enable_grants($self) { ...@@ -1254,6 +1271,8 @@ sub _enable_grants($self) {
,'shutdown', 'shutdown_all', 'shutdown_clone' ,'shutdown', 'shutdown_all', 'shutdown_clone'
,'reboot', 'reboot_all', 'reboot_clones' ,'reboot', 'reboot_all', 'reboot_clones'
,'screenshot' ,'screenshot'
,'start_many'
,'view_groups', 'manage_groups'
,'start_limit', 'start_many' ,'start_limit', 'start_many'
); );
...@@ -1312,6 +1331,7 @@ sub _set_url_isos($self, $new_url='http://localhost/iso/') { ...@@ -1312,6 +1331,7 @@ sub _set_url_isos($self, $new_url='http://localhost/iso/') {
$sth->finish; $sth->finish;
} }
sub _upgrade_table { sub _upgrade_table {
my $self = shift; my $self = shift;
my ($table, $field, $definition) = @_; my ($table, $field, $definition) = @_;
...@@ -1455,6 +1475,8 @@ sub _create_tables { ...@@ -1455,6 +1475,8 @@ sub _create_tables {
# return if $CONNECTOR->dbh->{Driver}{Name} !~ /mysql/i; # return if $CONNECTOR->dbh->{Driver}{Name} !~ /mysql/i;
my $driver = lc($CONNECTOR->dbh->{Driver}{Name}); my $driver = lc($CONNECTOR->dbh->{Driver}{Name});
$driver = 'mysql' if $driver =~ /mariadb/i;
$DIR_SQL =~ s{(.*)/.*}{$1/$driver}; $DIR_SQL =~ s{(.*)/.*}{$1/$driver};
opendir my $ls,$DIR_SQL or die "$! $DIR_SQL"; opendir my $ls,$DIR_SQL or die "$! $DIR_SQL";
...@@ -1473,7 +1495,7 @@ sub _sql_create_tables($self) { ...@@ -1473,7 +1495,7 @@ sub _sql_create_tables($self) {
my %tables = ( my %tables = (
domain_displays => { domain_displays => {
id => 'integer NOT NULL PRIMARY KEY AUTO_INCREMENT' id => 'integer NOT NULL PRIMARY KEY AUTO_INCREMENT'
,id_domain => 'integer NOT NULL references domains(id)' ,id_domain => 'integer NOT NULL references domains(id) on delete cascade'
,port => 'char(5) DEFAULT NULL' ,port => 'char(5) DEFAULT NULL'
,ip => 'varchar(254)' ,ip => 'varchar(254)'
,listen_ip => 'varchar(254)' ,listen_ip => 'varchar(254)'
...@@ -1492,6 +1514,46 @@ sub _sql_create_tables($self) { ...@@ -1492,6 +1514,46 @@ sub _sql_create_tables($self) {
, name => 'varchar(64) NOT NULL' , name => 'varchar(64) NOT NULL'
, value => 'varchar(128) DEFAULT NULL' , value => 'varchar(128) DEFAULT NULL'
} }
,bookings => {
id => 'integer NOT NULL PRIMARY KEY AUTO_INCREMENT'
,title => 'varchar(80)'
,description => 'varchar(255)'
,date_start => 'date not null'
,date_end => 'date not null'
,id_owner => 'int not null'
,background_color => 'varchar(20)'
,date_created => 'datetime DEFAULT CURRENT_TIMESTAMP'
}
,booking_entries => {
id => 'integer NOT NULL PRIMARY KEY AUTO_INCREMENT'
,title => 'varchar(80)'
,description => 'varchar(255)'
,id_booking => 'int not null references bookings(id) ON DELETE CASCADE'
,time_start => 'time not null'
,time_end => 'time not null'
,date_booking => 'date'
,visibility => "enum ('private','public') default 'public'"
}
,booking_entry_ldap_groups => {
id => 'integer NOT NULL PRIMARY KEY AUTO_INCREMENT'
,id_booking_entry
=> 'int not null references booking_entries(id) ON DELETE CASCADE'
,ldap_group => 'varchar(255) not null'
}
,booking_entry_users => {
id => 'integer NOT NULL PRIMARY KEY AUTO_INCREMENT'
,id_booking_entry
=> 'int not null references booking_entries(id) ON DELETE CASCADE'
,id_user => 'int not null references users(id) ON DELETE CASCADE'
}
,booking_entry_bases=> {
id => 'integer NOT NULL PRIMARY KEY AUTO_INCREMENT'
,id_booking_entry
=> 'int not null references booking_entries(id) ON DELETE CASCADE'
,id_base => 'int not null references domains(id) ON DELETE CASCADE'
}
); );
for my $table ( keys %tables ) { for my $table ( keys %tables ) {
my $sth = $CONNECTOR->dbh->table_info('%',undef,$table,'TABLE'); my $sth = $CONNECTOR->dbh->table_info('%',undef,$table,'TABLE');
...@@ -1588,6 +1650,16 @@ sub _sql_insert_defaults($self){ ...@@ -1588,6 +1650,16 @@ sub _sql_insert_defaults($self){
,name => 'start_limit' ,name => 'start_limit'
,value => 1 ,value => 1
} }
,{
id_parent => $id_backend
,name => 'time_zone'
,value => _default_time_zone()
}
,{
id_parent => $id_backend
,name => 'bookings'
,value => 0
}
,{ ,{
id_parent => $id_backend id_parent => $id_backend
,name => 'debug' ,name => 'debug'
...@@ -1623,6 +1695,26 @@ sub _sql_insert_defaults($self){ ...@@ -1623,6 +1695,26 @@ sub _sql_insert_defaults($self){
} }
} }
sub _default_time_zone() {
return $ENV{TZ} if exists $ENV{TZ};
my $timedatectl = `which timedatectl`;
chomp $timedatectl;
if (!$timedatectl) {
warn "Warning: No time zone found, checked TZ, missing timedatectl";
return 'UTC';
}
my @cmd = ( $timedatectl, '-p', 'Timezone','show');
my ($in, $out, $err);
run3(\@cmd,\$in,\$out,\$err);
my ($tz) = $out =~ /=(.*)/;
chomp $out;
if (!$tz) {
warn "Warning: No timezone found in @cmd\n$out";
return 'UTC'
}
return $tz;
}
sub _sql_insert_values($self, $table, $entry) { sub _sql_insert_values($self, $table, $entry) {
my $sql = "INSERT INTO $table " my $sql = "INSERT INTO $table "
."( " ."( "
...@@ -1638,11 +1730,21 @@ sub _sql_insert_values($self, $table, $entry) { ...@@ -1638,11 +1730,21 @@ sub _sql_insert_values($self, $table, $entry) {
} }
sub _port_definition($driver, $definition0){ sub _port_definition($driver, $definition0){
return $definition0 if $driver eq 'mysql'; return $definition0 if $driver =~ /mysql|mariadb/i;
if ($driver eq 'sqlite') { if ($driver eq 'sqlite') {
$definition0 =~ s/(.*) AUTO_INCREMENT$/$1 AUTOINCREMENT/i; $definition0 =~ s/(.*) AUTO_INCREMENT$/$1 AUTOINCREMENT/i;
return $definition0 if $definition0 =~ /^(int|integer|char|varchar) /i; return $definition0 if $definition0 =~ /^(int|integer|char|varchar) /i;
if ($definition0 =~ /^enum /) {
my ($default) = $definition0 =~ / (default.*)/i;
$default = '' if !defined $default;
my @found = $definition0 =~ /'(.*?)'/g;
my ($size) = sort map { length($_) } @found;
return " varchar($size) $default";
}
} }
return $definition0;
} }
sub _clean_iso_mini { sub _clean_iso_mini {
...@@ -1723,7 +1825,6 @@ sub _upgrade_tables { ...@@ -1723,7 +1825,6 @@ sub _upgrade_tables {
#$self->_upgrade_table('domains','display_file','text DEFAULT NULL'); #$self->_upgrade_table('domains','display_file','text DEFAULT NULL');
$self->_upgrade_table('domains','info','varchar(255) DEFAULT NULL'); $self->_upgrade_table('domains','info','varchar(255) DEFAULT NULL');
$self->_upgrade_table('domains','internal_id','varchar(64) DEFAULT NULL'); $self->_upgrade_table('domains','internal_id','varchar(64) DEFAULT NULL');
$self->_upgrade_table('domains','id_vm','int default null');
$self->_upgrade_table('domains','volatile_clones','int NOT NULL default 0'); $self->_upgrade_table('domains','volatile_clones','int NOT NULL default 0');
$self->_upgrade_table('domains','comment',"varchar(80) DEFAULT ''"); $self->_upgrade_table('domains','comment',"varchar(80) DEFAULT ''");
...@@ -1814,6 +1915,8 @@ sub _connect_dbh { ...@@ -1814,6 +1915,8 @@ sub _connect_dbh {
, PrintError=> 0 }); , PrintError=> 0 });
$con->dbh(); $con->dbh();
}; };
$con->dbh->do("PRAGMA foreign_keys = ON") if $driver =~ /sqlite/i;
return $con if $con && !$@; return $con if $con && !$@;
sleep 1; sleep 1;
warn "Try $try $@\n"; warn "Try $try $@\n";
...@@ -1993,7 +2096,7 @@ sub _connect_vm { ...@@ -1993,7 +2096,7 @@ sub _connect_vm {
sub _create_vm_lxc { sub _create_vm_lxc {
my $self = shift; my $self = shift;
return; return ;
} }
sub _create_vm_void { sub _create_vm_void {
...@@ -2631,6 +2734,7 @@ sub process_requests { ...@@ -2631,6 +2734,7 @@ sub process_requests {
next if $duplicated{$req->command.":$domain"}++; next if $duplicated{$req->command.":$domain"}++;
push @reqs,($req); push @reqs,($req);
} }
$sth->finish;
for my $req (sort { $a->priority <=> $b->priority } @reqs) { for my $req (sort { $a->priority <=> $b->priority } @reqs) {
next if $req eq 'refresh_vms' && scalar@reqs > 2; next if $req eq 'refresh_vms' && scalar@reqs > 2;
...@@ -2652,7 +2756,6 @@ sub process_requests { ...@@ -2652,7 +2756,6 @@ sub process_requests {
# sleep 1 if $DEBUG; # sleep 1 if $DEBUG;
} }
$sth->finish;
$self->_timeout_requests(); $self->_timeout_requests();
} }
...@@ -4702,6 +4805,38 @@ sub import_domain { ...@@ -4702,6 +4805,38 @@ sub import_domain {
sub _cmd_enforce_limits($self, $request=undef) { sub _cmd_enforce_limits($self, $request=undef) {
_enforce_limits_active($self, $request); _enforce_limits_active($self, $request);
$self->_shutdown_disconnected(); $self->_shutdown_disconnected();
$self->_shutdown_bookings() if $self->setting('/backend/bookings');
}
sub _shutdown_bookings($self) {
my @bookings = Ravada::Booking::bookings();
return if !scalar(@bookings);
my @domains = $self->list_domains_data(status => 'active');
for my $dom ( @domains ) {
next if $dom->{autostart};
next if $self->_user_is_admin($dom->{id_owner});
if ( Ravada::Booking::user_allowed($dom->{id_owner}, $dom->{id_base}) ) {
# warn "\tuser $dom->{id_owner} allowed to start clones from $dom->{id_base}";
next;
}
my $user = Ravada::Auth::SQL->search_by_id($dom->{id_owner});
$user->send_message("The server is booked. Shutting down ".$dom->{name});
Ravada::Request->shutdown_domain(
uid => Ravada::Utils::user_daemon->id
,id_domain => $dom->{id}
);
}
}
sub _user_is_admin($self, $id_user) {
my $sth = $CONNECTOR->dbh->prepare("SELECT is_admin FROM users where id=? ");
$sth->execute($id_user);