Commit f54efe70 authored by Francesc Guasch's avatar Francesc Guasch
Browse files

Merge branch '265_net' of https://github.com/frankiejol/ravada into 265_net

parents 50fed293 be40dec3
......@@ -3,9 +3,8 @@
**Implemented enhancements:**
- Improve URL for viewing domains [\#200]
- View Domains at fullscreen [\#30]
- Add graphics options in VM settings [\#260]
**Fixed bugs:**
- Hibernated domains restart with new spice password [\#263]
- KVM domains start when creating base [\#271]
......@@ -4,7 +4,7 @@ Architecture: all
Section: utils
Priority: optional
Maintainer: Francesc Guasch <frankie@telecos.upc.edu>
Depends: perl (>=5.18),libmojolicious-perl,mysql-common,libauthen-passphrase-perl,libdbd-mysql-perl,libdbi-perl,libdbix-connector-perl,libipc-run3-perl,libnet-ldap-perl,libproc-pid-file-perl,libvirt-bin,libsys-virt-perl,libxml-libxml-perl,libconfig-yaml-perl,libmoose-perl,libjson-xs-perl,qemu-utils,perlmagick,libmoosex-types-netaddr-ip-perl,libsys-statistics-linux-perl,libio-interface-perl,libiptables-chainmgr-perl,libnet-dns-perl,wget,liblocale-maketext-lexicon-perl,libmojolicious-plugin-i18n-perl,libdbd-sqlite3-perl, debconf (>= 0.2.26), adduser, libdigest-sha-perl, qemu-kvm
Depends: perl (>=5.18),libmojolicious-perl,mysql-common,libauthen-passphrase-perl,libdbd-mysql-perl,libdbi-perl,libdbix-connector-perl,libipc-run3-perl,libnet-ldap-perl,libproc-pid-file-perl,libvirt-bin,libsys-virt-perl,libxml-libxml-perl,libconfig-yaml-perl,libmoose-perl,libjson-xs-perl,qemu-utils,perlmagick,libmoosex-types-netaddr-ip-perl,libsys-statistics-linux-perl,libio-interface-perl,libiptables-chainmgr-perl,libnet-dns-perl,wget,liblocale-maketext-lexicon-perl,libmojolicious-plugin-i18n-perl,libdbd-sqlite3-perl, debconf (>= 0.2.26), adduser, libdigest-sha-perl, qemu-kvm, net-tools
Description: Remote Virtual Desktops Manager
Ravada is a software that allows the user to connect to a
remote virtual desktop.
<domain type='kvm'>
<name>Win10-AESS</name>
<uuid>161cbacf-2e6c-4266-a4e6-6a21a7eb6057</uuid>
<memory unit='KiB'>4194304</memory>
<currentMemory unit='KiB'>4194304</currentMemory>
<vcpu placement='static' current='2'>4</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-xenial'>hvm</type>
</os>
<features>
<acpi/>
<apic/>
<hyperv>
<relaxed state='on'/>
<vapic state='on'/>
<spinlocks state='on' retries='8191'/>
</hyperv>
</features>
<cpu mode='host-model'>
<model fallback='allow'/>
</cpu>
<clock offset='localtime'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
<timer name='hypervclock' present='yes'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/bin/kvm-spice</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='directsync' io='native'/>
<source file='/var/lib/libvirt/images.2/Win10-AESS-lm-ap.qcow2'/>
<target dev='vda' bus='virtio'/>
<boot order='1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</disk>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images.2/Win10-AESS-yg-yx.SWAP.qcow2'/>
<target dev='vdb' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<target dev='hdb' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<target dev='hdc' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='1' target='0' unit='0'/>
</disk>
<controller type='pci' index='0' model='pci-root'/>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='virtio-serial' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</controller>
<controller type='usb' index='0' model='nec-xhci'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</controller>
<interface type='network'>
<mac address='52:54:00:73:6b:3d'/>
<source network='default'/>
<model type='rtl8139'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<channel type='spicevmc'>
<target type='virtio' name='com.redhat.spice.0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='spice' autoport='yes' listen='147.83.68.31'>
<listen type='address' address='147.83.68.31'/>
<image compression='auto_glz'/>
<jpeg compression='auto'/>
<zlib compression='auto'/>
<playback compression='on'/>
<streaming mode='filter'/>
</graphics>
<sound model='ich6'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</sound>
<video>
<model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<redirdev bus='usb' type='spicevmc'>
<address type='usb' bus='0' port='1'/>
</redirdev>
<redirdev bus='usb' type='spicevmc'>
<address type='usb' bus='0' port='2'/>
</redirdev>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
</memballoon>
</devices>
</domain>
<volume type='file'>
<name>Windows10.img</name>
<key>/var/lib/libvirt/images/Windows10.img</key>
<source>
</source>
<capacity unit='bytes'>30179869696</capacity>
<allocation unit='bytes'>29525151744</allocation>
<target>
<path>/var/lib/libvirt/images/Windows10.img</path>
<format type='qcow2'/>
<permissions>
<mode>0644</mode>
<owner>0</owner>
<group>0</group>
</permissions>
<timestamps>
<atime>1498839828.853774877</atime>
<mtime>1497405600.641821227</mtime>
<ctime>1497405628.097957375</ctime>
</timestamps>
</target>
</volume>
<domain type='kvm'>
<name>windows_7</name>
<uuid>346aa4dc-4908-429b-8e66-0f49dd4d0df6</uuid>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-yakkety'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<hyperv>
<relaxed state='on'/>
<vapic state='on'/>
<spinlocks state='on' retries='8191'/>
</hyperv>
</features>
<cpu mode='custom' match='exact'>
<model fallback='allow'>Penryn</model>
</cpu>
<clock offset='localtime'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
<timer name='hypervclock' present='yes'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/bin/kvm-spice</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/win7-donotcrash.qcow2'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/home/TELECOMBCN/jalarcon/Escriptori/ISOs/Win_Pro_7w_SP1_32BIT_English.iso'/>
<target dev='hdb' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
<controller type='usb' index='0' model='ich9-ehci1'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x7'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci1'>
<master startport='0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci2'>
<master startport='2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x1'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci3'>
<master startport='4'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'/>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='virtio-serial' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</controller>
<interface type='network'>
<mac address='52:54:00:1a:51:0c'/>
<source network='default'/>
<model type='rtl8139'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<channel type='spicevmc'>
<target type='virtio' name='com.redhat.spice.0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
<input type='tablet' bus='usb'>
<address type='usb' bus='0' port='1'/>
</input>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='spice' autoport='yes'>
<listen type='address'/>
<image compression='off'/>
</graphics>
<sound model='ich6'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</sound>
<video>
<model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<redirdev bus='usb' type='spicevmc'>
<address type='usb' bus='0' port='2'/>
</redirdev>
<redirdev bus='usb' type='spicevmc'>
<address type='usb' bus='0' port='3'/>
</redirdev>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</memballoon>
</devices>
</domain>
......@@ -3,7 +3,7 @@ package Ravada;
use warnings;
use strict;
our $VERSION = '0.2.9-alpha';
our $VERSION = '0.2.9-beta';
use Carp qw(carp croak);
use Data::Dumper;
......@@ -31,6 +31,8 @@ eval {
$VALID_VM{KVM} = 1;
};
$VALID_VM{Void} = 1 if $0 =~ /\.t$/;
no warnings "experimental::signatures";
use feature qw(signatures);
......@@ -226,13 +228,20 @@ sub _update_isos {
,xml_volume => 'yakkety64-volume.xml'
}
,debian_stretch => {
name =>'Debian Stretch 64 bits XFCE'
,description => 'Debian 9.0 Stretch 64 bits'
name =>'Debian Stretch 64 bits'
,description => 'Debian 9.0 Stretch 64 bits (XFCE desktop)'
,url => 'https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-9.0.0-amd64-xfce-CD-1.iso'
,md5 => '9346436c0cf1862af71cb0a03d9a703c'
,xml => 'jessie-amd64.xml'
,xml_volume => 'jessie-volume.xml'
}
,windows_7 => {
name => 'Windows 7'
,description => 'Windows 7 64 bits. Requires an user provided ISO image.'
.'<a target="_blank" href="http://ravada.readthedocs.io/en/latest/docs/new_iso_image.html">[help]</a>'
,xml => 'windows_7.xml'
,xml_volume => 'windows10-volume.xml'
}
);
$self->_update_table($table, $field, \%data);
......@@ -490,6 +499,24 @@ sub _upgrade_table {
return 1;
}
sub _remove_field {
my $self = shift;
my ($table, $field ) = @_;
my $dbh = $CONNECTOR->dbh;
return if $CONNECTOR->dbh->{Driver}{Name} !~ /mysql/i;
my $sth = $dbh->column_info(undef,undef,$table,$field);
my $row = $sth->fetchrow_hashref;
$sth->finish;
return if !$row;
warn "INFO: removing $field to $table\n" if $0 !~ /\.t$/;
$dbh->do("alter table $table drop column $field");
return 1;
}
sub _create_table {
my $self = shift;
my $table = shift;
......@@ -815,13 +842,6 @@ sub search_domain {
my $name = shift;
my $import = shift;
my $vm = $self->search_vm('Void');
warn "No Void VM" if !$vm;
return if !$vm;
my $domain = $vm->search_domain($name, $import);
return $domain if $domain;
my @vms;
eval { @vms = $self->vm };
return if $@ && $@ =~ /No VMs found/i;
......@@ -838,6 +858,12 @@ sub search_domain {
return $domain if $id || $import;
}
return if !$VALID_VM{'Void'};
my $vm = $self->search_vm('Void');
warn "No Void VM" if !$vm;
return if !$vm;
my $domain = $vm->search_domain($name, $import);
return $domain if $domain;
return;
}
......@@ -1645,6 +1671,28 @@ sub _cmd_force_shutdown {
}
sub _cmd_expose {
my ($self, $request) = @_;
my $uid = $request->args('uid');
my $user = Ravada::Auth::SQL->search_by_id( $uid);
my $domain = $self->search_domain_by_id($request->args('id_domain'));
$domain->expose($user, $request->args('port'), $request->args('name'));
}
sub _cmd_remove_expose {
my ($self, $request) = @_;
my $uid = $request->args('uid');
my $user = Ravada::Auth::SQL->search_by_id( $uid);
my $domain = $self->search_domain_by_id($request->args('id_domain'));
$domain->remove_expose($user, $request->args('port'));
}
sub _cmd_list_vm_types {
my $self = shift;
my $request = shift;
......@@ -1705,6 +1753,7 @@ sub _req_method {
start => \&_cmd_start
,pause => \&_cmd_pause
,create => \&_cmd_create
,expose => \&_cmd_expose
,remove => \&_cmd_remove
,resume => \&_cmd_resume
,download => \&_cmd_download
......@@ -1719,6 +1768,7 @@ sub _req_method {
,rename_domain => \&_cmd_rename_domain
,open_iptables => \&_cmd_open_iptables
,list_vm_types => \&_cmd_list_vm_types
,remove_expose => \&_cmd_remove_expose
,force_shutdown => \&_cmd_force_shutdown
);
......@@ -1752,6 +1802,9 @@ sub search_vm {
confess "Missing VM type" if !$type;
confess "Invalid VM type '$type'\n"
if !$VALID_VM{$type} && !$VALID_VM{uc($type)} && $type ne 'Void';
my $class = 'Ravada::VM::'.uc($type);
if ($type =~ /Void/i) {
......@@ -1769,6 +1822,31 @@ sub search_vm {
return;
}
=head2 valid_vms
Returns a list of valid VM types in this system
my @valid = $ravada->valid_vms();
=cut
sub valid_vms {
return ( sort keys %VALID_VM );
}
=head2 valid_vm
Returns true if a VM type is valid
=cut
sub valid_vm {
my $self = shift;
my $type = shift;
return $VALID_VM{$type};
}
=head2 import_domain
Imports a domain in Ravada
......@@ -1807,13 +1885,7 @@ Returns the version of the module
=cut
sub version {
my $version = $VERSION;
if ($version =~ /(alpha|beta)$/) {
my $rev_count = `git rev-list --count --all`;
chomp $rev_count;
$version .= $rev_count;
}
return $version;
return $VERSION;
}
......
......@@ -137,7 +137,7 @@ before 'remove' => \&_pre_remove_domain;
before 'prepare_base' => \&_pre_prepare_base;
after 'prepare_base' => \&_post_prepare_base;
before 'start' => \&_start_preconditions;
before 'start' => \&_pre_start;
after 'start' => \&_post_start;
before 'pause' => \&_allow_manage;
......@@ -164,6 +164,12 @@ after 'rename' => \&_post_rename;
after 'screenshot' => \&_post_screenshot;
##################################################
#
sub BUILD {
my $self = shift;
$self->is_known();
}
sub _vm_connect {
my $self = shift;
......@@ -175,7 +181,7 @@ sub _vm_disconnect {
$self->_vm->disconnect();
}
sub _start_preconditions{
sub _pre_start {
my ($self) = @_;
if (scalar @_ %2 ) {
......@@ -183,6 +189,7 @@ sub _start_preconditions{
} else {
_allow_manage(@_);
}
_clean_iptables();
_check_free_memory();
_check_used_memory(@_);
......@@ -191,11 +198,16 @@ sub _start_preconditions{
sub _update_description {
my $self = shift;
return if defined $self->description
&& defined $self->_data('description')
&& $self->description eq $self->_data('description');
my $sth = $$CONNECTOR->dbh->prepare(
"UPDATE domains SET description=? "
." WHERE id=?");
." WHERE id=? ");
$sth->execute($self->description,$self->id);
$sth->finish;
$self->{_data}->{description} = $self->{description};
}
sub _allow_manage_args {
......@@ -400,17 +412,35 @@ sub _data {
return $self->{_data}->{$field};
}
sub __open {
my $self = shift;
=head2 open
my %args = @_;
Open a domain
Argument: id
Returns: Domain object read only
=cut
sub open($class, $id) {
my $self = {};
bless $self,$class;
my $row = $self->_select_domain_db ( id => $id );
die "Domain id = $id not found"
if !keys %$row;
die "Domain ".$row->{name}." has no VM "
.Dumper($row) if !$row->{vm};
my $vm0 = {};
my $vm_class = "Ravada::VM::".$row->{vm};
bless $vm0, $vm_class;
my $id = $args{id} or confess "Missing required argument id";
delete $args{id};
my $vm = $vm0->new( readonly => 1);
my $row = $self->_select_domain_db ( );
return $self->search_domain($row->{name});
# confess $row;
return $vm->search_domain($row->{name});
}
=head2 is_known
......@@ -448,6 +478,7 @@ sub _select_domain_db {
$sth->finish;
$self->{_data} = $row;
$self->description($row->{description}) if defined $row->{description};
return $row if $row->{id};
}
......@@ -531,7 +562,7 @@ sub _display_file_spice($self,$user) {
} else {
$ret .= "port=$port\n";
}
$ret .="password=%s\n" if $self->spice_password();
# $ret .="password=%s\n" if $self->spice_password();
$ret .=
"fullscreen=1\n"
......@@ -579,7 +610,7 @@ sub _insert_db {
eval { $sth->execute( map { $field{$_} } sort keys %field ) };
if ($@) {
#warn "$query\n".Dumper(\%field);
die $@;
confess $@;
}
$sth->finish;
......@@ -612,10 +643,19 @@ sub _after_remove_domain {
$self->_remove_files_base();
}
return if !$self->{_data};
$self->_remove_ports_db();
$self->_remove_base_db();
$self->_remove_domain_db();
}
sub _remove_ports_db {
my $self = shift;
my $sth = $$CONNECTOR->dbh->prepare("DELETE FROM domain_ports where id_domain=?");
$sth->execute($self->id);
$sth->finish;
}
sub _remove_domain_db {
my $self = shift;
......@@ -906,20 +946,21 @@ sub clone {
my $id_base = $self->id;
return $self->_vm->create_domain(
my $clone = $self->_vm->create_domain(
name => $name
,id_base => $id_base
,id_owner => $uid
,vm => $self->vm
,_vm => $self->_vm
);
$clone->description($self->description) if defined $self->description;
return $clone;