2012-01-30 12:02:56 +01:00
package PVE::API2Tools ;
use strict ;
use warnings ;
2015-01-01 16:54:21 +01:00
use Net::IP ;
2017-05-29 07:49:17 +02:00
use PVE::Exception qw( raise_param_exc ) ;
2013-08-01 11:35:48 +02:00
use PVE::Tools ;
2015-05-12 12:12:47 +02:00
use PVE::INotify ;
2017-05-29 07:49:17 +02:00
use PVE::Cluster ;
2013-08-01 11:35:48 +02:00
use Digest::MD5 qw( md5_hex ) ;
2013-09-09 11:33:25 +02:00
use URI ;
use URI::Escape ;
2013-12-10 09:46:00 +01:00
use PVE::SafeSyslog ;
2013-08-01 11:35:48 +02:00
my $ hwaddress ;
sub get_hwaddress {
return $ hwaddress if defined ( $ hwaddress ) ;
my $ fn = '/etc/ssh/ssh_host_rsa_key.pub' ;
my $ sshkey = PVE::Tools:: file_get_contents ( $ fn ) ;
$ hwaddress = uc ( md5_hex ( $ sshkey ) ) ;
return $ hwaddress ;
}
2012-01-30 12:02:56 +01:00
2012-03-26 10:26:26 +02:00
sub extract_node_stats {
my ( $ node , $ members , $ rrd ) = @ _ ;
my $ entry = {
id = > "node/$node" ,
node = > $ node ,
type = > "node" ,
2017-11-03 09:51:32 +01:00
status = > 'unknown' ,
2012-03-26 10:26:26 +02:00
} ;
if ( my $ d = $ rrd - > { "pve2-node/$node" } ) {
if ( ! $ members || # no cluster
( $ members - > { $ node } && $ members - > { $ node } - > { online } ) ) {
$ entry - > { uptime } = ( $ d - > [ 0 ] || 0 ) + 0 ;
$ entry - > { cpu } = ( $ d - > [ 5 ] || 0 ) + 0 ;
$ entry - > { mem } = ( $ d - > [ 8 ] || 0 ) + 0 ;
$ entry - > { disk } = ( $ d - > [ 12 ] || 0 ) + 0 ;
2017-11-03 09:51:32 +01:00
$ entry - > { status } = 'online' ;
2012-03-26 10:26:26 +02:00
}
$ entry - > { level } = $ d - > [ 1 ] ;
$ entry - > { maxcpu } = ( $ d - > [ 4 ] || 0 ) + 0 ;
$ entry - > { maxmem } = ( $ d - > [ 7 ] || 0 ) + 0 ;
$ entry - > { maxdisk } = ( $ d - > [ 11 ] || 0 ) + 0 ;
}
2017-11-03 09:51:32 +01:00
if ( $ members && $ members - > { $ node } &&
! $ members - > { $ node } - > { online } ) {
$ entry - > { status } = 'offline' ;
}
2012-03-26 10:26:26 +02:00
return $ entry ;
}
2012-01-30 12:02:56 +01:00
sub extract_vm_stats {
my ( $ vmid , $ data , $ rrd ) = @ _ ;
my $ entry = {
id = > "$data->{type}/$vmid" ,
vmid = > $ vmid + 0 ,
node = > $ data - > { node } ,
type = > $ data - > { type } ,
2017-11-03 09:51:34 +01:00
status = > 'unknown' ,
2012-01-30 12:02:56 +01:00
} ;
2013-01-17 10:02:47 +01:00
my $ d ;
if ( $ d = $ rrd - > { "pve2-vm/$vmid" } ) {
2012-01-30 12:02:56 +01:00
$ entry - > { uptime } = ( $ d - > [ 0 ] || 0 ) + 0 ;
$ entry - > { name } = $ d - > [ 1 ] ;
2013-01-17 09:37:11 +01:00
$ entry - > { status } = $ entry - > { uptime } ? 'running' : 'stopped' ;
2012-01-30 12:02:56 +01:00
$ entry - > { maxcpu } = ( $ d - > [ 3 ] || 0 ) + 0 ;
$ entry - > { cpu } = ( $ d - > [ 4 ] || 0 ) + 0 ;
$ entry - > { maxmem } = ( $ d - > [ 5 ] || 0 ) + 0 ;
$ entry - > { mem } = ( $ d - > [ 6 ] || 0 ) + 0 ;
$ entry - > { maxdisk } = ( $ d - > [ 7 ] || 0 ) + 0 ;
$ entry - > { disk } = ( $ d - > [ 8 ] || 0 ) + 0 ;
2012-07-05 13:24:03 +02:00
$ entry - > { netin } = ( $ d - > [ 9 ] || 0 ) + 0 ;
$ entry - > { netout } = ( $ d - > [ 10 ] || 0 ) + 0 ;
$ entry - > { diskread } = ( $ d - > [ 11 ] || 0 ) + 0 ;
$ entry - > { diskwrite } = ( $ d - > [ 12 ] || 0 ) + 0 ;
2013-01-17 09:37:11 +01:00
2013-01-17 10:02:47 +01:00
} elsif ( $ d = $ rrd - > { "pve2.3-vm/$vmid" } ) {
2013-01-17 09:37:11 +01:00
$ entry - > { uptime } = ( $ d - > [ 0 ] || 0 ) + 0 ;
$ entry - > { name } = $ d - > [ 1 ] ;
$ entry - > { status } = $ d - > [ 2 ] ;
$ entry - > { template } = $ d - > [ 3 ] + 0 ;
$ entry - > { maxcpu } = ( $ d - > [ 5 ] || 0 ) + 0 ;
$ entry - > { cpu } = ( $ d - > [ 6 ] || 0 ) + 0 ;
$ entry - > { maxmem } = ( $ d - > [ 7 ] || 0 ) + 0 ;
$ entry - > { mem } = ( $ d - > [ 8 ] || 0 ) + 0 ;
$ entry - > { maxdisk } = ( $ d - > [ 9 ] || 0 ) + 0 ;
$ entry - > { disk } = ( $ d - > [ 10 ] || 0 ) + 0 ;
$ entry - > { netin } = ( $ d - > [ 11 ] || 0 ) + 0 ;
$ entry - > { netout } = ( $ d - > [ 12 ] || 0 ) + 0 ;
$ entry - > { diskread } = ( $ d - > [ 13 ] || 0 ) + 0 ;
$ entry - > { diskwrite } = ( $ d - > [ 14 ] || 0 ) + 0 ;
2012-01-30 12:02:56 +01:00
} ;
return $ entry ;
2017-11-03 09:51:39 +01:00
}
2012-01-30 12:02:56 +01:00
sub extract_storage_stats {
my ( $ storeid , $ scfg , $ node , $ rrd ) = @ _ ;
my $ entry = {
id = > "storage/$node/$storeid" ,
storage = > $ storeid ,
node = > $ node ,
type = > 'storage' ,
2017-11-03 09:51:33 +01:00
status = > 'unknown' ,
2012-01-30 12:02:56 +01:00
} ;
if ( my $ d = $ rrd - > { "pve2-storage/$node/$storeid" } ) {
$ entry - > { maxdisk } = ( $ d - > [ 1 ] || 0 ) + 0 ;
$ entry - > { disk } = ( $ d - > [ 2 ] || 0 ) + 0 ;
2017-11-03 09:51:33 +01:00
$ entry - > { status } = 'available' ;
2012-01-30 12:02:56 +01:00
}
return $ entry ;
2017-11-03 09:51:39 +01:00
}
2012-01-30 12:02:56 +01:00
2013-09-09 11:33:25 +02:00
sub parse_http_proxy {
my ( $ proxyenv ) = @ _ ;
my $ uri = URI - > new ( $ proxyenv ) ;
my $ scheme = $ uri - > scheme ;
my $ host = $ uri - > host ;
my $ port = $ uri - > port || 3128 ;
my ( $ username , $ password ) ;
if ( defined ( my $ p_auth = $ uri - > userinfo ( ) ) ) {
( $ username , $ password ) = map URI::Escape:: uri_unescape ( $ _ ) , split ( ":" , $ p_auth , 2 ) ;
}
return ( "$host:$port" , $ username , $ password ) ;
}
2013-12-10 09:46:00 +01:00
sub run_spiceterm {
my ( $ authpath , $ permissions , $ vmid , $ node , $ proxy , $ title , $ shcmd ) = @ _ ;
my $ rpcenv = PVE::RPCEnvironment:: get ( ) ;
my $ authuser = $ rpcenv - > get_user ( ) ;
2015-05-12 12:12:47 +02:00
my $ nodename = PVE::INotify:: nodename ( ) ;
my $ family = PVE::Tools:: get_host_address_family ( $ nodename ) ;
my $ port = PVE::Tools:: next_spice_port ( $ family ) ;
2013-12-10 10:51:27 +01:00
my ( $ ticket , undef , $ remote_viewer_config ) =
PVE::AccessControl:: remote_viewer_config ( $ authuser , $ vmid , $ node , $ proxy , $ title , $ port ) ;
2013-12-10 09:46:00 +01:00
2014-01-16 08:49:13 +01:00
my $ timeout = 40 ;
2013-12-10 09:46:00 +01:00
my $ cmd = [ '/usr/bin/spiceterm' , '--port' , $ port , '--addr' , '127.0.0.1' ,
'--timeout' , $ timeout , '--authpath' , $ authpath ,
'--permissions' , $ permissions ] ;
my $ dcconf = PVE::Cluster:: cfs_read_file ( 'datacenter.cfg' ) ;
push @$ cmd , '--keymap' , $ dcconf - > { keyboard } if $ dcconf - > { keyboard } ;
push @$ cmd , '--' , @$ shcmd ;
my $ realcmd = sub {
my $ upid = shift ;
syslog ( 'info' , "starting spiceterm $upid - $title\n" ) ;
my $ cmdstr = join ( ' ' , @$ cmd ) ;
syslog ( 'info' , "launch command: $cmdstr" ) ;
2013-12-10 13:11:33 +01:00
eval {
2013-12-10 09:46:00 +01:00
foreach my $ k ( keys % ENV ) {
2013-12-10 13:11:33 +01:00
next if $ k eq 'PATH' || $ k eq 'TERM' || $ k eq 'USER' || $ k eq 'HOME' || $ k eq 'LANG' || $ k eq 'LANGUAGE' ;
2013-12-10 09:46:00 +01:00
delete $ ENV { $ k } ;
}
$ ENV { PWD } = '/' ;
$ ENV { SPICE_TICKET } = $ ticket ;
2013-12-10 13:11:33 +01:00
2017-02-28 12:22:56 +01:00
PVE::Tools:: run_command ( $ cmd , errmsg = > 'spiceterm failed\n' , keeplocale = > 1 ) ;
2013-12-10 09:46:00 +01:00
} ;
if ( my $ err = $@ ) {
syslog ( 'err' , $ err ) ;
}
return ;
} ;
if ( $ vmid ) {
$ rpcenv - > fork_worker ( 'spiceproxy' , $ vmid , $ authuser , $ realcmd ) ;
} else {
$ rpcenv - > fork_worker ( 'spiceshell' , undef , $ authuser , $ realcmd ) ;
}
2013-12-10 10:51:27 +01:00
2013-12-10 09:46:00 +01:00
PVE::Tools:: wait_for_vnc_port ( $ port ) ;
2013-12-10 10:51:27 +01:00
return $ remote_viewer_config ;
2013-12-10 09:46:00 +01:00
}
2015-01-01 16:54:21 +01:00
sub read_proxy_config {
my $ conffile = "/etc/default/pveproxy" ;
# Note: evaluate with bash
my $ shcmd = ". $conffile;\n" ;
$ shcmd . = 'echo \"ALLOW_FROM:\$ALLOW_FROM\";' ;
$ shcmd . = 'echo \"DENY_FROM:\$DENY_FROM\";' ;
$ shcmd . = 'echo \"POLICY:\$POLICY\";' ;
$ shcmd . = 'echo \"CIPHERS:\$CIPHERS\";' ;
2016-01-26 15:09:12 +01:00
$ shcmd . = 'echo \"DHPARAMS:\$DHPARAMS\";' ;
2015-01-01 16:54:21 +01:00
my $ data = - f $ conffile ? `bash -c "$shcmd"` : '' ;
my $ res = { } ;
while ( $ data =~ s/^(.*)\n// ) {
my ( $ key , $ value ) = split ( /:/ , $ 1 , 2 ) ;
next if ! $ value ;
if ( $ key eq 'ALLOW_FROM' || $ key eq 'DENY_FROM' ) {
my $ ips = [] ;
foreach my $ ip ( split ( /,/ , $ value ) ) {
$ ip = "0/0" if $ ip eq 'all' ;
push @$ ips , Net::IP - > new ( $ ip ) || die Net::IP:: Error ( ) . "\n" ;
}
$ res - > { $ key } = $ ips ;
} elsif ( $ key eq 'POLICY' ) {
die "unknown policy '$value'\n" if $ value !~ m/^(allow|deny)$/ ;
$ res - > { $ key } = $ value ;
} elsif ( $ key eq 'CIPHERS' ) {
$ res - > { $ key } = $ value ;
2016-01-26 15:09:12 +01:00
} elsif ( $ key eq 'DHPARAMS' ) {
$ res - > { $ key } = $ value ;
2015-01-01 16:54:21 +01:00
} else {
# silently skip everythin else?
}
}
return $ res ;
}
2017-05-29 07:49:17 +02:00
sub resolve_proxyto {
my ( $ rpcenv , $ proxyto_callback , $ proxyto , $ uri_param ) = @ _ ;
my $ node ;
if ( $ proxyto_callback ) {
$ node = $ proxyto_callback - > ( $ rpcenv , $ proxyto , $ uri_param ) ;
die "internal error - proxyto_callback returned nothing\n"
if ! $ node ;
} else {
$ node = $ uri_param - > { $ proxyto } ;
raise_param_exc ( { $ proxyto = > "proxyto parameter does not exists" } )
if ! $ node ;
}
return $ node ;
}
2012-01-30 12:02:56 +01:00
1 ;