]>
git.proxmox.com Git - pve-manager.git/blob - lib/PVE.old/ConfigServer.pm
3 package PVE
::ConfigServer
;
26 our @EXPORT = qw($pve_config_daemon);
27 our $pve_config_daemon;
29 my $get_userid = sub { # private method
32 if ($pve_config_daemon) {
33 return $pve_config_daemon->{pve
}->{username
};
39 my $get_ticket = sub { # private method
42 if ($pve_config_daemon) {
43 return $pve_config_daemon->{pve
}->{ticket
};
49 sub alive
{ ##SOAP_EXPORT##
55 sub update_ticket
{ ##SOAP_EXPORT##
58 # ticket is magically updated by the server before
59 # this function is called.
60 my $ticket = $class->$get_ticket();
65 sub ping
{ ##SOAP_EXPORT##
68 my $userid = $class->$get_userid();
70 my $cinfo = PVE
::Cluster
::clusterinfo
();
72 my $status = { time => time (), insync
=> 1 };
74 $status->{uptime
} = PVE
::Utils
::get_uptime
();
75 $status->{cpuinfo
} = PVE
::Utils
::get_cpu_info
();
76 $status->{meminfo
} = PVE
::Utils
::get_memory_info
();
77 $status->{hdinfo
}->{root
} = PVE
::Utils
::get_hd_info
('/');
79 my $procstat = PVE
::Utils
::read_proc_stat
();
80 $status->{cpu
} = $procstat->{cpu
};
81 $status->{wait} = $procstat->{wait};
83 my $syncstatus = PVE
::Config
::read_file
("syncstatus");
85 foreach my $ni (@{$cinfo->{nodes
}}) {
87 next if $cinfo->{local}->{cid
} == $cid; # skip local CID
88 my $lastsync = defined ($syncstatus->{$cid}) ?
89 $syncstatus->{$cid}->{lastsync
} : 0;
90 $status->{"lastsync_$cid"} = $lastsync;
91 my $sdiff = time() - $lastsync;
92 $sdiff = 0 if $sdiff < 0;
93 $status->{insync
} = 0 if ($sdiff > (60*3));
99 sub vzlist
{ ##SOAP_EXPORT##
102 my $userid = $class->$get_userid();
108 $res = PVE
::OpenVZ
::vmlist
();
114 syslog
('err', "ERROR: $err");
122 my $qmlist = PVE
::Qemu
::vmlist
();
124 foreach my $vekey (keys %$qmlist) {
125 if (!$res->{$vekey}) {
126 $res->{$vekey} = $qmlist->{$vekey};
128 syslog
('err', "found duplicated ID '$vekey' - ignoring qemu instance\n");
136 syslog
('err', "ERROR: $err");
141 $res->{lasttime
} = time();
143 my $pc = PVE
::Config
::update_file
('pcounter', 'vzlist');
144 $res->{version
} = $pc->{vzlist
};
149 sub vmlogview
{ ##SOAP_EXPORT##
150 my ($class, $cid, $veid, $service) = @_;
152 my $userid = $class->$get_userid();
154 my $filename = "/var/lib/vz/private/$veid/var/log/syslog";
156 if ($service eq 'init') {
157 $filename = "/var/lib/vz/private/$veid/var/log/init.log";
158 } elsif ($service eq 'syslog') {
159 # some systems (rh,centos) logs to messages instead
160 my $msglog = "/var/lib/vz/private/$veid/var/log/messages";
161 if ((! -f
$filename) && (-f
$msglog)) {
170 open (TMP
, "tail -$limit $filename|");
171 while (my $line = <TMP
>) {
180 sub vmconfig
{ ##SOAP_EXPORT##
181 my ($class, $veid, $type) = @_;
183 my $userid = $class->$get_userid();
185 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
189 $res->{vzlist
} = $class->vzlist();
191 if (($type eq 'qemu') && !$res->{vzlist
}->{qemu
}) {
192 die "unable to get qemu-server vm list - server not running?\n";
194 if (($type eq 'openvz') && !$res->{vzlist
}->{openvz
}) {
195 die "unable to get openvz vm list?\n";
198 if (my $d = $res->{vzlist
}->{"VEID_$veid"}) {
199 die "virtualization type mismatch" if $type ne $d->{type
};
201 if ($d->{type
} eq 'openvz') {
202 $res->{config
} = PVE
::Config
::get_veconfig
($veid);
203 } elsif ($d->{type
} eq 'qemu') {
204 $res->{config
} = PVE
::Config
::get_qmconfig
($veid);
206 die "internal error";
209 die "unable to get configuration data for VEID '$veid'";
215 sub cluster_vzlist
{ ##SOAP_EXPORT##
216 my ($class, $cid, $vzlist) = @_;
218 my $userid = $class->$get_userid();
220 my $newlist = PVE
::Config
::update_file
('vzlist', $vzlist, $cid);
222 my $vmops = PVE
::Config
::read_file
("vmops");
224 PVE
::Utils
::foreach_vmrec
($vmops, sub {
225 my ($cid, $vmid, $d, $ckey, $vmkey) = @_;
226 my $old = $newlist->{$ckey}->{$vmkey};
228 # command still running ?
230 if ($old && PVE
::Utils
::check_process
($d->{pid
}, $d->{pstart
})) {
232 $old->{status
} = $d->{command
};
234 if ($d->{command
} eq 'migrate') {
235 PVE
::Utils
::foreach_vmrec
($newlist, sub {
236 my ($ncid, $nvmid, $nd) = @_;
237 $nd->{status
} = 'migrate' if ($nvmid eq $vmid);
246 # start long running workers
247 # $data append to the returned uniquely identifier, which
248 # has the following format: "UPID:$pid-$pstart:$startime:$dtype:$data"
249 # STDIN is redirected to /dev/null
250 # STDOUT,STDERR are redirected to the filename returned by upid_decode
251 # that file is locked wit flock to make sure only one process
254 my $fork_worker = sub { # private method
255 my ($class, $dtype, $data, $function) = @_;
259 $dtype = 'unknown' if !defined ($dtype);
261 $data = '' if !defined ($data);
263 my $starttime = time ();
265 my @psync = POSIX
::pipe();
267 # detect filename with faked PID
268 my $tmp = PVE
::Utils
::upid_decode
("UPID:0-0:0:$dtype:$data");
269 my $filename = $tmp->{filename
};
275 $lockfh = IO
::File-
>new ($filename, O_WRONLY
|O_CREAT
) ||
276 die "unable to open output file - $!\n";
278 my $wwwid = getpwnam('www-data');
279 chown $wwwid, $filename;
281 if (!flock ($lockfh, LOCK_EX
|LOCK_NB
)) {
282 undef $lockfh; # close
283 die "unable to lock output file\n";
286 if (!truncate ($lockfh, 0)) {
287 die "unable to truncate output file - $!\n";
291 if (($cpid = fork()) == 0) {
293 $SIG{INT
} = $SIG{QUIT
} = $SIG{TERM
} = sub { die "received interrupt\n"; };
295 $SIG{CHLD
} = $SIG{PIPE
} = 'DEFAULT';
297 # set sess/process group - we want to be able to kill the
298 # whole process group
301 POSIX
::close ($psync[0]);
303 PVE
::Config
::inotify_close
();
305 # we close the socket
306 my $httpd = $pve_config_daemon->{_daemon
};
309 # same algorythm as used inside SA
312 my $fd = fileno (STDIN
);
314 POSIX
::close(0) if $fd != 0;
316 if (!open (STDIN
, "</dev/null")) {
322 $fd = fileno(STDOUT
);
324 POSIX
::close (1) if $fd != 1;
327 if (!open (STDOUT
, ">&", $lockfh)) {
332 STDOUT-
>autoflush (1);
334 if (!open (STDOUT
, ">/dev/null")) {
340 # redirect STDERR to STDOUT
341 $fd = fileno (STDERR
);
343 POSIX
::close(2) if $fd != 2;
345 if (!open (STDERR
, ">&1")) {
350 STDERR-
>autoflush (1);
352 my $pstart = PVE
::Utils
::read_proc_starttime
($$) ||
353 die "unable to read process starttime";
355 my $upid = PVE
::Utils
::upid_encode
({
356 pid
=> $$, pstart
=> $pstart, starttime
=> $starttime,
357 type
=> $dtype, data
=> $data });
360 POSIX
::write ($psync[1], $upid, length ($upid));
361 POSIX
::close ($psync[1]);
365 die "should not be reached";
368 POSIX
::close ($psync[1]);
370 # sync with child (wait until child starts)
372 POSIX
::read($psync[0], $upid, 4096);
373 POSIX
::close ($psync[0]);
376 undef $lockfh; # close
379 my $uh = PVE
::Utils
::upid_decode
($upid);
381 !($uh->{pid
} == $cpid && $uh->{starttime
} == $starttime &&
382 $uh->{type
} eq $dtype && $uh->{data
} eq $data)) {
383 syslog
('err', "got strange upid - $upid\n");
386 PVE
::Utils
::register_worker
($cpid);
391 # UPID: unique worker process descriptor
393 # general format used by fork_worker is
394 # UPID:$pid-$pstart:$start:$type:$data
396 # $pid ... process id of worker
397 # $pstart ... process start time from /proc/pid/stat
398 # $start ... time (epoch) when process started
399 # $type ... string to identity format of $data
400 # $data ... arbitrary text
402 # speicalized format we use is
403 # UPID:$pid-$pstart:$start:vmops:$command:$cid:$veid
405 # $command ... create, start, stop, destroy
406 # $cid,$veid ... cluster identity of VE
408 # Note: PIDs are recycled, so to test if a process is still running
409 # we use (PID,PSTART) pair.
411 my $vmcommand = sub { # private method
412 my ($class, $userid, $command, $cid, $veid, $code) = @_;
417 $userid = 'unknown' if !$userid;
419 my $cinfo = PVE
::Cluster
::clusterinfo
();
421 if ($cid != $cinfo->{local}->{cid
}) {
422 $remip = $cinfo->{"CID_$cid"}->{ip
};
423 # we force tty allocation in order to tranfer signals (kill)
424 $remcmd = ['/usr/bin/ssh', '-t', '-t', '-n', '-o', 'BatchMode=yes', $remip];
435 $res = &$code ($upid, $remip, $remcmd, $cinfo);
437 my $ticket = $class->$get_ticket();
439 my $rcon = PVE
::ConfigClient
::connect ($ticket, $cinfo, $cid);
440 if (my $vzlist = $rcon->vzlist()->result) {
441 PVE
::Config
::update_file
('vzlist', $vzlist, $cid);
448 syslog
('err', $err);
449 print STDERR
"\n$err";
453 print STDERR
"\n"; # flush
457 if (my $uid = $class->$fork_worker ('vmops', "$command:$cid:$veid:$userid", $realcmd)) {
459 PVE
::Config
::update_file
("vmops", $uid);
467 sub apl_start_download
{ ##SOAP_EXPORT##
468 my ($class, $aplname) = @_;
470 my $userid = $class->$get_userid();
472 my $pkglist = PVE
::APLInfo
::load_data
();
476 if (!$pkglist || !$aplname || !($data = $pkglist->{'all'}->{$aplname})) {
477 syslog
('err', "download failed: no aplinfo for appliance '$aplname'");
486 my $tmp = "/tmp/apldownload-$$-tmp.dat";
489 my $msg = "starting download: $aplname";
490 syslog
('info', $msg);
491 print STDERR
"$msg\n";
493 my $src = $data->{location
};
494 my $dest = "/var/lib/vz/template/cache/$aplname";
497 my $md5 = (split (/\s/, `md5sum '$dest'`))[0];
499 if ($md5 && (lc($md5) eq lc($data->{md5sum
}))) {
500 $msg = "file already exists $md5 - no need to download";
501 syslog
('info', $msg);
502 print STDERR
"$msg\n";
508 my $pvecfg = PVE
::Config
::read_file
('pvecfg');
509 if ($pvecfg && $pvecfg->{http_proxy
}) {
510 $ENV{http_proxy
} = $pvecfg->{http_proxy
};
513 my @cmd = ('/usr/bin/wget', '--progress=dot:mega', '-O', $tmp, $src);
514 if (system (@cmd) != 0) {
515 die "download failed - $!\n";
518 my $md5 = (split (/\s/, `md5sum '$tmp'`))[0];
520 if (!$md5 || (lc($md5) ne lc($data->{md5sum
}))) {
521 die "wrong checksum: $md5 != $data->{md5sum}\n";
524 if (system ('mv', $tmp, $dest) != 0) {
525 die "unable to save file - $!\n";
534 syslog
('err', $err);
535 print STDERR
"\n\ndownload failed: $err";
539 syslog
('info', "download finished");
540 print STDERR
"download finished\n";
545 if (my $uid = $class->$fork_worker ('apldownload', "$userid:$aplname", $realcmd)) {
552 sub vmconfig_set
{ ##SOAP_EXPORT##
553 my ($class, $cid, $veid, $type, $settings) = @_;
555 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
557 my $userid = $class->$get_userid();
559 my $cinfo = PVE
::Cluster
::clusterinfo
();
564 if ($cid != $cinfo->{local}->{cid
}) {
565 $remip = $cinfo->{"CID_$cid"}->{ip
};
566 $remcmd = ['/usr/bin/ssh', '-n', '-o', 'BatchMode=yes', $remip];
569 return if !$settings;
573 foreach my $key (keys %$settings) {
574 die "invalid key '$key'" if $key !~ m/^\w+$/;
575 my $v = $settings->{$key};
576 next if !defined ($v);
577 if (ref ($v) eq 'ARRAY') {
578 foreach my $v1 (@$v) {
579 push @$param, "--$key", $remip ? PVE
::Utils
::shellquote
($v1) : $v1;
582 push @$param, "--$key", $remip ? PVE
::Utils
::shellquote
($v) : $v;
586 return if scalar (@$param) == 0;
588 $remip = 'localhost' if !$remip;
590 syslog
('info', "apply settings to VM $veid on node $cid ($remip)");
594 if ($type eq 'openvz') {
595 @cmd = (@$remcmd, '/usr/bin/pvectl', 'vzset', $veid, @$param);
597 @cmd = (@$remcmd, '/usr/sbin/qm', 'set', $veid, @$param);
600 if (system (@cmd) != 0) {
601 my $cmdstr = join (' ', @cmd);
602 my $msg = "unable to apply VM settings, command failed: $cmdstr\n";
603 syslog
('err', $msg);
607 my $msg = "VM $veid settings applied";
608 syslog
('info', $msg);
611 # set cdrom for qemu/kvm
612 sub vmconfig_setcdrom
{ ##SOAP_EXPORT##
613 my ($class, $cid, $veid, $device, $volid) = @_;
615 my $userid = $class->$get_userid();
617 my $cinfo = PVE
::Cluster
::clusterinfo
();
622 if ($cid != $cinfo->{local}->{cid
}) {
623 $remip = $cinfo->{"CID_$cid"}->{ip
};
624 $remcmd = ['/usr/bin/ssh', '-n', '-o', 'BatchMode=yes', $remip];
629 die "invalid device name '$device'" if $device !~ m/^\w+$/;
631 push @$param, "--$device", $remip ? PVE
::Utils
::shellquote
($volid) : $volid;
633 return if scalar (@$param) == 0;
635 $remip = 'localhost' if !$remip;
637 syslog
('info', "setting cdrom on VM $veid on node $cid ($remip)");
639 my @cmd = (@$remcmd, '/usr/sbin/qm', 'cdrom', $veid, @$param);
641 if (system (@cmd) != 0) {
642 my $cmdstr = join (' ', @cmd);
643 my $msg = "unable to set cdrom, command failed: $cmdstr\n";
644 syslog
('err', $msg);
648 my $msg = "VM $veid set cdrom";
649 syslog
('info', $msg);
652 # delete unused qemu/kvm disk images
653 sub qemu_unlink_disk
{ ##SOAP_EXPORT##
654 my ($class, $cid, $veid, $filename) = @_;
656 my $userid = $class->$get_userid();
658 my $cinfo = PVE
::Cluster
::clusterinfo
();
663 if ($cid != $cinfo->{local}->{cid
}) {
664 $remip = $cinfo->{"CID_$cid"}->{ip
};
665 $remcmd = ['/usr/bin/ssh', '-n', '-o', 'BatchMode=yes', $remip];
668 $remip = 'localhost' if !$remip;
670 syslog
('info', "delete image '$filename' on VM $veid on node $cid ($remip)");
672 my @cmd = (@$remcmd, '/usr/sbin/qm', 'unlink', $veid, $filename);
674 if (system (@cmd) != 0) {
675 my $cmdstr = join (' ', @cmd);
676 my $msg = "unable to delete image, command failed: $cmdstr\n";
677 syslog
('err', $msg);
681 my $msg = "VM $veid image '$filename' successfuly deleted";
682 syslog
('info', $msg);
685 sub vmcommand_create
{ ##SOAP_EXPORT##
686 my ($class, $cid, $veid, $type, $settings) = @_;
688 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
690 my $userid = $class->$get_userid();
692 return $class->$vmcommand ($userid, 'create', $cid, $veid, sub {
693 my ($upid, $remip, $remcmd, $cinfo) = @_;
698 if ($type eq 'openvz') {
699 @cmd = (@$remcmd, '/usr/bin/pvectl', 'vzcreate', $veid);
701 @cmd = (@$remcmd, '/usr/sbin/qm', 'create', $veid);
704 foreach my $key (keys %$settings) {
705 die "invalid key '$key'" if $key !~ m/^\w+$/;
706 my $v = $settings->{$key};
707 next if !defined ($v);
708 if (ref ($v) eq 'ARRAY') {
709 foreach my $v1 (@$v) {
710 push @cmd, "--$key", $remip ? PVE
::Utils
::shellquote
($v1) : $v1;
713 push @cmd, "--$key", $remip ? PVE
::Utils
::shellquote
($v) : $v;
717 $remip = 'localhost' if !$remip;
719 syslog
('info', "creating new VM $veid on node $cid ($remip)");
721 my $cmdstr = join (' ', @cmd);
724 if (system (@cmd) != 0) {
726 my $msg = "unable to apply VM settings - $!";
727 syslog
('err', $msg);
732 my $msg = "VM $veid created";
733 syslog
('info', $msg);
740 sub vmcommand_destroy
{ ##SOAP_EXPORT##
741 my ($class, $cid, $veid, $type) = @_;
743 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
745 my $userid = $class->$get_userid();
747 return $class->$vmcommand ($userid, 'destroy', $cid, $veid, sub {
748 my ($upid, $remip, $remcmd, $cinfo) = @_;
750 $remip = 'localhost' if !$remip;
752 syslog
('info', "destroying VM $veid on node $cid ($remip)");
756 if ($type eq 'openvz') {
757 @cmd = (@$remcmd, '/usr/sbin/vzctl', 'destroy', $veid);
759 @cmd = (@$remcmd, '/usr/sbin/qm', 'destroy', $veid);
762 my $cmdstr = join (' ', @cmd);
766 if (system (@cmd) != 0) {
767 my $msg = "VM $veid destroy failed - $!";
768 syslog
('err', $msg);
773 my $msg = "VM $veid destroyed";
774 syslog
('info', $msg);
781 sub vmcommand_stop
{ ##SOAP_EXPORT##
782 my ($class, $cid, $veid, $type, $force) = @_;
784 my $userid = $class->$get_userid();
786 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
788 return $class->$vmcommand ($userid, 'stop', $cid, $veid, sub {
789 my ($upid, $remip, $remcmd, $cinfo) = @_;
791 $remip = 'localhost' if !$remip;
793 syslog
('info', "stopping VM $veid on node $cid ($remip)");
797 if ($type eq 'openvz') {
798 @cmd = (@$remcmd, '/usr/sbin/vzctl', 'stop', $veid);
799 push @cmd, '--fast' if $force;
801 @cmd = (@$remcmd, '/usr/sbin/qm', $force ?
'stop' : 'shutdown', $veid);
804 my $cmdstr = join (' ', @cmd);
808 if (system (@cmd) != 0) {
809 my $msg = "VM $veid stop failed - $!";
810 syslog
('err', $msg);
815 my $msg = "VM $veid stopped";
816 syslog
('info', $msg);
823 sub vmcommand_umount
{ ##SOAP_EXPORT##
824 my ($class, $cid, $veid, $type) = @_;
826 die "unknown virtualization type '$type'\n" if $type ne 'openvz';
828 my $userid = $class->$get_userid();
830 return $class->$vmcommand ($userid, 'umount', $cid, $veid, sub {
831 my ($upid, $remip, $remcmd, $cinfo) = @_;
833 $remip = 'localhost' if !$remip;
835 syslog
('info', "unmounting VM $veid on node $cid ($remip)");
839 @cmd = (@$remcmd, '/usr/sbin/vzctl', 'umount', $veid);
841 my $cmdstr = join (' ', @cmd);
845 if (system (@cmd) != 0) {
846 my $msg = "VM $veid umount failed - $!";
847 syslog
('err', $msg);
852 my $msg = "VM $veid unmounted";
853 syslog
('info', $msg);
860 sub vmcommand_start
{ ##SOAP_EXPORT##
861 my ($class, $cid, $veid, $type) = @_;
863 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
865 my $userid = $class->$get_userid();
867 return $class->$vmcommand ($userid, 'start', $cid, $veid, sub {
868 my ($upid, $remip, $remcmd, $cinfo) = @_;
870 $remip = 'localhost' if !$remip;
872 syslog
('info', "starting VM $veid on node $cid ($remip)");
876 if ($type eq 'openvz') {
877 @cmd = (@$remcmd, '/usr/sbin/vzctl', 'start', $veid);
879 @cmd = (@$remcmd, '/usr/sbin/qm', 'start', $veid);
882 my $cmdstr = join (' ', @cmd);
886 if (system (@cmd) != 0) {
887 my $msg = "VM $veid start failed - $!";
888 syslog
('err', $msg);
893 my $msg = "VM $veid started";
894 syslog
('info', $msg);
901 sub vmcommand_restart
{ ##SOAP_EXPORT##
902 my ($class, $cid, $veid, $type) = @_;
904 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
906 my $userid = $class->$get_userid();
908 return $class->$vmcommand ($userid, 'restart', $cid, $veid, sub {
909 my ($upid, $remip, $remcmd, $cinfo) = @_;
911 $remip = 'localhost' if !$remip;
913 syslog
('info', "restarting VM $veid on node $cid ($remip)");
917 if ($type eq 'openvz') {
918 @cmd = (@$remcmd, '/usr/sbin/vzctl', 'restart', $veid);
920 @cmd = (@$remcmd, '/usr/sbin/qm', 'reset', $veid);
922 my $cmdstr = join (' ', @cmd);
926 if (system (@cmd) != 0) {
927 my $msg = "VM $veid restart failed - $!";
928 syslog
('err', $msg);
933 my $msg = "VM $veid restarted";
934 syslog
('info', $msg);
941 sub vmcommand_migrate
{ ##SOAP_EXPORT##
942 my ($class, $cid, $veid, $type, $target, $online) = @_;
944 die "unknown virtualization type '$type'\n" if !($type eq 'openvz' || $type eq 'qemu');
946 my $userid = $class->$get_userid();
948 my $cinfo = PVE
::Cluster
::clusterinfo
();
950 return $class->$vmcommand ($userid, 'migrate', $cid, $veid, sub {
951 my ($upid, $remip, $remcmd, $cinfo) = @_;
953 $remip = 'localhost' if !$remip;
955 my $targetip = $cinfo->{"CID_$target"}->{ip
};
957 syslog
('info', "migrating VM $veid from node $cid ($remip) to node $target ($targetip)");
961 if ($type eq 'openvz') {
962 @cmd = (@$remcmd, '/usr/sbin/vzmigrate');
963 push @cmd, '--online' if $online;
964 push @cmd, $targetip;
967 @cmd = (@$remcmd, '/usr/sbin/qmigrate');
968 push @cmd, '--online' if $online;
969 push @cmd, $targetip;
973 my $cmdstr = join (' ', @cmd);
977 if (system (@cmd) != 0) {
978 my $msg = "VM $veid migration failed - $!";
979 syslog
('err', $msg);
984 my $msg = "VM $veid migration done";
985 syslog
('info', $msg);
992 my $next_vnc_port = sub { # private method
994 for (my $p = 5900; $p < 6000; $p++) {
996 my $sock = IO
::Socket
::INET-
>new (Listen
=> 5,
997 LocalAddr
=> 'localhost',
1008 die "unable to find free vnc port";
1011 sub create_vnc_proxy
{ ##SOAP_EXPORT##
1012 my ($class, $cid, $veid) = @_;
1017 my $userid = $class->$get_userid();
1019 my $cinfo = PVE
::Cluster
::clusterinfo
();
1021 if ($cid != $cinfo->{local}->{cid
}) {
1022 $remip = $cinfo->{"CID_$cid"}->{ip
};
1023 $remcmd = ['/usr/bin/ssh', '-T', '-o', 'BatchMode=yes', $remip];
1026 my $port = $class->$next_vnc_port();
1027 # generate ticket, olny first 8 character used by vnc
1028 my $ticket = Digest
::SHA1
::sha1_base64
($userid, rand(), time());
1035 syslog
('info', "starting vnc proxy $upid\n");
1037 my $qmcmd = [@$remcmd, "/usr/sbin/qm", 'vncproxy', $veid , $ticket];
1039 my $qmstr = join (' ', @$qmcmd);
1041 # also redirect stderr (else we get RFB protocol errors)
1042 my @cmd = ('/bin/nc', '-l', '-p', $port, '-w', $timeout, '-c', "$qmstr 2>/dev/null");
1044 my $cmdstr = join (' ', @cmd);
1045 syslog
('info', "CMD: $cmdstr");
1047 if (system (@cmd) != 0) {
1048 my $msg = "VM $veid vnc proxy failed - $?";
1049 syslog
('err', $msg);
1056 if (my $uid = $class->$fork_worker ('vncproxy', "$cid:$veid:$userid:$port:$ticket", $realcmd)) {
1057 return { port
=> $port, ticket
=> $ticket};
1064 sub create_vnc_console
{ ##SOAP_EXPORT##
1065 my ($class, $cid, $veid, $type, $status) = @_;
1067 my $userid = $class->$get_userid();
1072 $userid = 'unknown' if !$userid;
1074 my $cinfo = PVE
::Cluster
::clusterinfo
();
1076 if ($cid != $cinfo->{local}->{cid
}) {
1077 $remip = $cinfo->{"CID_$cid"}->{ip
};
1078 $remcmd = ['/usr/bin/ssh', '-t', $remip];
1081 my $port = $class->$next_vnc_port();
1082 # generate ticket, olny first 8 character used by vnc
1083 my $ticket = Digest
::SHA1
::sha1_base64
($userid, rand(), time());
1085 my $timeout = 1; # immediately exit when last client disconnects
1090 syslog
('info', "starting vnc console $upid\n");
1094 my $pwfile = "/tmp/.vncpwfile.$$";
1098 if ($type eq 'openvz') {
1099 if ($status eq 'running') {
1100 $vzcmd = [ '/usr/sbin/vzctl', 'enter', $veid ];
1101 } elsif ($status eq 'mounted') {
1102 $vzcmd = [ "/usr/bin/pvebash", $veid, 'root'];
1104 $vzcmd = [ "/usr/bin/pvebash", $veid, 'private'];
1106 } elsif ($type eq 'qemu') {
1107 $vzcmd = [ "/usr/sbin/qm", 'monitor', $veid ];
1109 $vzcmd = [ '/bin/true' ]; # should not be reached
1112 my @cmd = ('/usr/bin/vncterm', '-rfbport', $port,
1113 '-passwdfile', "rm:$pwfile",
1114 '-timeout', $timeout, '-c', @$remcmd, @$vzcmd);
1116 my $cmdstr = join (' ', @cmd);
1117 syslog
('info', "CMD: $cmdstr");
1119 my $fh = IO
::File-
>new ($pwfile, "w", 0600);
1120 print $fh "$ticket\n";
1123 if (system (@cmd) != 0) {
1124 my $msg = "VM $veid console viewer failed - $?";
1125 syslog
('err', $msg);
1132 if (my $uid = $class->$fork_worker ('vncview', "$cid:$veid:$userid:$port:$ticket", $realcmd)) {
1134 #PVE::Config::update_file ("vncview", $uid);
1136 return { port
=> $port, ticket
=> $ticket};
1143 sub service_cmd
{ ##SOAP_EXPORT##
1144 my ($class, $service, $cmd) = @_;
1146 my $userid = $class->$get_userid();
1149 my $res = PVE
::Utils
::service_cmd
($service, $cmd);
1150 syslog
('info', $res) if $res;
1151 syslog
('info', "service command '$service $cmd' successful");
1155 syslog
('err', "service command '$service $cmd' failed : $err");
1159 my $service_list = {
1160 apache
=> { short
=> 'WWW', long
=> 'Web Server' },
1161 pvetunnel
=> { short
=> 'ClusterTunnel',
1162 long
=> 'PVE Cluster Tunnel Daemon' },
1163 pvemirror
=> { short
=> 'ClusterSync',
1164 long
=> 'PVE Cluster Synchronization Daemon' },
1165 postfix
=> { short
=> 'SMTP', long
=> 'Simple Mail Tranfer Protocol' },
1166 ntpd
=> { short
=> 'NTP', long
=> 'Network Time Protocol' },
1167 sshd
=> { short
=> 'SSH', long
=> 'Secure Shell Daemon' },
1168 # bind => { short => 'BIND', long => 'Local DNS Cache' },
1169 # pvedaemon => { short => 'NodeManager', long => 'PVE Node Manager Daemon' },
1172 sub service_state_all
{ ##SOAP_EXPORT##
1175 my $userid = $class->$get_userid();
1179 foreach my $s (keys %{$service_list}) {
1180 $res->{$s} = $service_list->{$s};
1181 $res->{$s}->{status
} = PVE
::Utils
::service_state
($s);
1187 sub restart_server
{ ##SOAP_EXPORT##
1188 my ($class, $poweroff) = @_;
1190 my $userid = $class->$get_userid();
1193 system ("(sleep 2;/sbin/poweroff)&");
1195 system ("(sleep 2;shutdown -r now)&");
1199 sub check_worker
{ ##SOAP_EXPORT##
1200 my ($class, $upid, $killit) = @_;
1202 my $userid = $class->$get_userid();
1204 if (my $upid_hash = PVE
::Utils
::upid_decode
($upid)) {
1206 my $pid = $upid_hash->{pid
};
1208 # test if still running
1209 return 0 if !PVE
::Utils
::check_process
($pid, $upid_hash->{pstart
});
1213 # send kill to process group (negative pid)
1216 kill (15, $kpid); # send TERM signal
1218 # give max 5 seconds to shut down
1219 # note: waitpid only work for child processes, but not
1220 # for processes spanned by other processes, so we use
1221 # kill to detect if the worker is still running
1222 for (my $i = 0; $i < 5; $i++) {
1223 last if !kill (0, $kpid);
1227 if (kill (0, $kpid)) {
1228 kill (9, $kpid); # kill if still alive
1231 return 0; # killed, not running
1240 sub kvm_version
{ ##SOAP_EXPORT##
1243 my $userid = $class->$get_userid();
1245 return PVE
::QemuServer
::kvm_version
();
1248 sub install_template
{ ##SOAP_EXPORT##
1249 my ($class, $storeid, $type, $tmpname, $filename) = @_;
1251 my $userid = $class->$get_userid();
1253 my $cfg = PVE
::Config
::read_file
("storagecfg");
1255 PVE
::Storage
::install_template
($cfg, $storeid, $type, $tmpname, $filename);
1258 sub delete_volume
{ ##SOAP_EXPORT##
1259 my ($class, $volid) = @_;
1261 my $userid = $class->$get_userid();
1263 my $cfg = PVE
::Config
::read_file
("storagecfg");
1265 PVE
::Storage
::vdisk_free
($cfg, $volid);
1268 sub get_config_data
{ ##SOAP_EXPORT##
1269 my ($class, $id, $full) = @_;
1271 my $userid = $class->$get_userid();
1273 return PVE
::Config
::read_file
($id, $full);
1276 sub set_config_data
{ ##SOAP_EXPORT##
1277 my ($class, $id, $data, $full) = @_;
1279 my $userid = $class->$get_userid();
1281 return PVE
::Config
::write_file
($id, $data, $full);
1284 sub update_config_data
{ ##SOAP_EXPORT##
1285 my ($class, $id, $data, @param) = @_;
1287 my $userid = $class->$get_userid();
1289 return PVE
::Config
::update_file
($id, $data, @param);
1292 sub discard_config_changes
{ ##SOAP_EXPORT##
1293 my ($class, $id, $full) = @_;
1295 my $userid = $class->$get_userid();
1297 return PVE
::Config
::discard_changes
($id, $full);
1300 sub modify_user
{ ##SOAP_EXPORT##
1301 my ($class, $username, $group, $pw, $comment) = @_;
1303 my $userid = $class->$get_userid();
1305 return PVE
::Utils
::modify_user
($username, $group, $pw, $comment);
1308 sub storage_list_volumes
{ ##SOAP_EXPORT##
1309 my ($class, $storeid) = @_;
1311 my $userid = $class->$get_userid();
1313 my $cfg = PVE
::Config
::read_file
("storagecfg");
1315 return PVE
::Storage
::vdisk_list
($cfg, $storeid);
1318 sub storage_list_iso
{ ##SOAP_EXPORT##
1319 my ($class, $storeid) = @_;
1321 my $userid = $class->$get_userid();
1323 my $cfg = PVE
::Config
::read_file
("storagecfg");
1325 return PVE
::Storage
::template_list
($cfg, $storeid, 'iso');
1328 sub storage_list_vztmpl
{ ##SOAP_EXPORT##
1329 my ($class, $storeid) = @_;
1331 my $userid = $class->$get_userid();
1333 my $cfg = PVE
::Config
::read_file
("storagecfg");
1335 return PVE
::Storage
::template_list
($cfg, $storeid, 'vztmpl');
1338 sub storage_list_backups
{ ##SOAP_EXPORT##
1339 my ($class, $storeid) = @_;
1341 my $userid = $class->$get_userid();
1343 my $cfg = PVE
::Config
::read_file
("storagecfg");
1345 return PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
1348 sub storage_list_vgs
{ ##SOAP_EXPORT##
1351 my $userid = $class->$get_userid();
1353 my $cfg = PVE
::Config
::read_file
("storagecfg");
1355 return PVE
::Storage
::lvm_vgs
();
1358 sub storage_add
{ ##SOAP_EXPORT##
1359 my ($class, $storeid, $type, $param) = @_;
1361 my $userid = $class->$get_userid();
1363 PVE
::Storage
::storage_add
($storeid, $type, $param);
1366 sub storage_set
{ ##SOAP_EXPORT##
1367 my ($class, $storeid, $param, $digest) = @_;
1369 my $userid = $class->$get_userid();
1371 PVE
::Storage
::storage_set
($storeid, $param, $digest);
1374 sub storage_remove
{ ##SOAP_EXPORT##
1375 my ($class, $storeid, $digest) = @_;
1377 my $userid = $class->$get_userid();
1379 PVE
::Storage
::storage_remove
($storeid, $digest);
1382 sub storage_enable
{ ##SOAP_EXPORT##
1383 my ($class, $storeid, $digest) = @_;
1385 my $userid = $class->$get_userid();
1387 PVE
::Storage
::storage_enable
($storeid, $digest);
1390 sub storage_disable
{ ##SOAP_EXPORT##
1391 my ($class, $storeid, $digest) = @_;
1393 my $userid = $class->$get_userid();
1395 PVE
::Storage
::storage_disable
($storeid, $digest);
1398 sub storage_scan_nfs
{ ##SOAP_EXPORT##
1399 my ($class, $server) = @_;
1401 my $userid = $class->$get_userid();
1403 return PVE
::Storage
::scan_nfs
($server);
1406 sub storage_scan_iscsi
{ ##SOAP_EXPORT##
1407 my ($class, $portal, $skip_used) = @_;
1409 my $userid = $class->$get_userid();
1411 my $res = PVE
::Storage
::scan_iscsi
($portal);
1413 return $res if !$skip_used;
1415 my $cfg = PVE
::Config
::read_file
("storagecfg");
1418 foreach my $target (keys %$res) {
1419 if (!PVE
::Storage
::target_is_used
($cfg, $target)) {
1420 $unused->{$target} = $res->{target
}
1426 sub storage_user_info
{ ##SOAP_EXPORT##
1427 my ($class, $vmid) = @_;
1429 my $userid = $class->$get_userid();
1431 my $cfg = PVE
::Config
::read_file
("storagecfg");
1433 my $info = PVE
::Storage
::storage_info
($cfg);
1435 my $res = { cfg
=> $cfg };
1437 foreach my $storeid (PVE
::Storage
::storage_ids
($cfg)) {
1438 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
1440 next if $scfg->{disable
};
1442 # fixme: check user access rights - pass username with connection?
1444 $res->{info
}->{$storeid} = $info->{$storeid};
1446 if ($scfg->{content
}->{rootdir
}) {
1447 $res->{rootdir
}->{$storeid} = 1;
1448 $res->{rootdir_default
} = $storeid
1449 if !$res->{rootdir_default
};
1452 if ($scfg->{content
}->{vztmpl
}) {
1453 $res->{vztmpl
}->{$storeid} = 1;
1454 $res->{vztmpl_default
} = $storeid
1455 if !$res->{vztmpl_default
};
1458 if ($scfg->{content
}->{images
}) {
1459 $res->{images
}->{$storeid} = 1;
1460 $res->{images_default
} = $storeid
1461 if !$res->{images_default
};
1464 if ($scfg->{content
}->{iso
}) {
1465 $res->{iso
}->{$storeid} = 1;
1466 $res->{iso_default
} = $storeid
1467 if !$res->{iso_default
};
1470 if ($scfg->{content
}->{backup
}) {
1471 $res->{backup
}->{$storeid} = 1;
1472 $res->{backup_default
} = $storeid
1473 if !$res->{backup_default
};
1479 $res->{imagelist
} = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
1486 sub get_storage_status
{ ##SOAP_EXPORT##
1489 my $userid = $class->$get_userid();
1491 # fixme: check user access rights
1493 my $cfg = PVE
::Config
::read_file
("storagecfg");
1495 my $info = PVE
::Storage
::storage_info
($cfg);
1497 return { cfg
=> $cfg, info
=> $info };
1500 ##FILTER_DATA## do not remove this line
1502 package PVE
::SOAPSerializer
;
1509 @ISA = qw
(SOAP
::Serializer
);
1514 my $self = $class->SUPER::new
(@_);
1516 # SOAP Serializer bug fix:
1517 # "a string with embeded URI 'http://exsample.com'" is encoded as URI!
1518 # should be a string instead
1520 # [95, sub { $_[0] =~ /^(urn:)|(http:\/\/)/i; }, 'as_anyURI'],
1521 # regex should be: /^((urn:)|(http:\/\/))/i;
1522 # so we disbale that
1523 delete $self->{_typelookup
}->{'anyURI'};
1525 # SOAP Serializer bug fix:
1526 # by default utf8 strings are serialized as base64Binary - unfortunately
1527 # that way the utf8 flags gets lost, so we provide our own encoding
1528 # see bug #2860559 on sourgeforge project page
1529 $self->{_typelookup
}->{'utf8string'} =
1530 [5, sub { Encode
::is_utf8
($_[0]) }, 'as_utf8string'],
1536 my ($self, $value, $name, $type, $attr) = @_;
1540 {'xsi:type' => 'xsd:string', %$attr},
1541 HTML
::Entities
::encode_entities_numeric
($value)
1545 package PVE
::SOAPTransport
;
1549 use SOAP
::Transport
::HTTP
;
1551 use PVE
::SafeSyslog
;
1553 use POSIX
qw(EINTR);
1554 use POSIX
":sys_wait_h";
1559 # This is a quite simple pre-fork server
1561 @ISA = qw(SOAP::Transport::HTTP::Daemon);
1565 my $max_workers = 2; # pre-forked worker processes
1566 my $max_requests = 500; # max requests per worker
1568 sub worker_finished
{
1571 syslog
('info', "worker $cpid finished");
1574 sub finish_workers
{
1576 foreach my $cpid (keys %$workers) {
1577 my $waitpid = waitpid ($cpid, WNOHANG
);
1578 if (defined($waitpid) && ($waitpid == $cpid)) {
1579 delete ($workers->{$cpid});
1580 worker_finished
($cpid);
1586 foreach my $cpid (keys %$workers) {
1587 if (!kill(0, $cpid)) {
1588 waitpid($cpid, POSIX
::WNOHANG
());
1589 delete $workers->{$cpid};
1590 worker_finished
($cpid);
1599 foreach my $cpid (keys %$workers) {
1603 my $need = $max_workers - $count;
1605 return if $need <= 0;
1607 syslog
('info', "starting $need worker(s)");
1612 if (!defined ($pid)) {
1613 syslog
('err', "can't fork worker");
1615 } elsif ($pid) { #parent
1616 $workers->{$pid} = 1;
1617 $0 = 'pvedaemon worker';
1618 syslog
('info', "worker $pid started");
1621 $SIG{TERM
} = $SIG{QUIT
} = 'DEFAULT';
1624 $self->{reload_config
} = 1;
1628 # try to init inotify
1629 PVE
::Config
::inotify_init
();
1631 $self->handle_requests ();
1633 syslog
('err', $@) if $@;
1641 sub terminate_server
{
1643 foreach my $cpid (keys %$workers) {
1644 kill (15, $cpid); # TERM childs
1647 # nicely shutdown childs (give them max 10 seconds to shut down)
1648 my $previous_alarm = alarm (10);
1650 local $SIG{ALRM
} = sub { die "Timed Out!\n" };
1652 1 while ((my $pid = waitpid (-1, 0)) > 0);
1655 alarm ($previous_alarm);
1657 foreach my $cpid (keys %$workers) {
1658 !kill (0, $cpid) || kill (9, $cpid); # KILL childs still alive!
1664 my $daemon = $self->new;
1666 $self->{httpdaemon
} = $daemon;
1669 my $old_sig_chld = $SIG{CHLD
};
1670 local $SIG{CHLD
} = sub {
1675 my $old_sig_term = $SIG{TERM
};
1676 local $SIG{TERM
} = sub {
1677 terminate_server
();
1680 local $SIG{QUIT
} = sub {
1685 local $SIG{USR1
} = 'IGNORE';
1687 local $SIG{HUP
} = sub {
1688 syslog
("info", "received reload request");
1689 foreach my $cpid (keys %$workers) {
1690 kill (10, $cpid); # SIGUSR1 childs
1694 for (;;) { # forever
1695 $self->start_workers ();
1697 $self->test_workers ();
1703 syslog
('err', "ERROR: $err");
1707 sub send_basic_auth_request
{
1710 my $realm = 'PVE SOAP Server';
1711 my $auth_request_res = HTTP
::Response-
>new(401, 'Unauthorized');
1712 $auth_request_res->header('WWW-Authenticate' => qq{Basic realm="$realm"});
1713 $auth_request_res->is_error(1);
1714 $auth_request_res->error_as_HTML(1);
1715 $c->send_response($auth_request_res);
1719 my ($c, $code, $msg) = @_;
1721 $c->send_response(HTTP
::Response-
>new($code, $msg));
1724 sub decode_basic_auth
{
1727 my $authtxt = $h->header('Authorization');
1728 return undef if !$authtxt;
1729 my ($test, $auth) = split /\s+/, $authtxt;
1730 return undef if !$auth;
1732 my $enc = MIME
::Base64
::decode
($auth);
1737 sub extract_auth_cookie
{
1740 my $txt = $h->header('Cookie') || '';
1742 return ($txt =~ /(?:^|\s)PVEAuthTicket=([^;]*)/)[0];
1746 my ($peerport, $sockport) = @_;
1748 my $filename = "/proc/net/tcp";
1750 my $fh = IO
::File-
>new($filename, "r") ||
1751 die "unable to open file '$filename'\n";
1755 my $remoteaddr = sprintf "0100007F:%04X", $sockport;
1756 my $localaddr = sprintf "0100007F:%04X", $peerport;
1758 while (defined (my $line = <$fh>)) {
1760 my @data = split (/\s+/, $line);
1761 if ($data[1] eq $localaddr &&
1762 $data[2] eq $remoteaddr) {
1764 $user = getpwuid ($uid);
1771 die "unable to identify user connection\n" if !$user;
1777 my ($daemon, $c, $r) = @_;
1779 # my $cuser = ident_user ($c->peerport, $c->sockport);
1781 my $h = $r->headers;
1782 my $action = $h->header('SOAPAction');
1783 if ($action !~ m
|^(\"?
)http
://proxmox
.com
/PVE
/ConfigServer\#
(\w
+)(\"?
)$|) {
1784 send_error
($c, 400, "Invalid SOAPAction");
1788 my $ticket = extract_auth_cookie
($h);
1789 my $authheader = $h->header('Authorization');
1792 if (!$authheader || $authheader !~ m/^Basic\s+\S+$/) {
1793 send_basic_auth_request
($c);
1800 $daemon->request($r);
1805 my $auth = (split /\s+/, $authheader)[1];
1806 my $enc = MIME
::Base64
::decode
($auth);
1808 ($user, $pw) = split (/:/, $enc, 2);
1809 if ($group = PVE
::Utils
::is_valid_user
($user, $pw)) {
1810 $ticket = PVE
::Utils
::create_auth_ticket
($daemon->{pve
}->{secret
}, $user, $group);
1813 $daemon->make_fault($SOAP::Constants
::FAULT_CLIENT
,
1814 'Basic authentication failed');
1815 $c->send_response($daemon->response);
1819 ($user, $group) = PVE
::Utils
::verify_ticket
($daemon->{pve
}->{secret
}, $ticket);
1820 if (!($user && $group)) {
1821 $daemon->make_fault($SOAP::Constants
::FAULT_CLIENT
,
1822 "Ticket authentication failed - invalid ticket '$ticket'");
1823 $c->send_response($daemon->response);
1826 if ($method eq 'update_ticket') {
1827 $ticket = PVE
::Utils
::create_auth_ticket
($daemon->{pve
}->{secret
}, $user, $group);
1830 $daemon->make_fault($SOAP::Constants
::FAULT_CLIENT
,
1831 'Ticket authentication failed - no ticket');
1832 $c->send_response($daemon->response);
1836 return ($user, $group, $ticket, $update);
1839 sub handle_requests
{
1842 my $daemon = $self->{httpdaemon
};
1846 my $sel = IO
::Select-
>new();
1847 $sel->add ($daemon->{_daemon
});
1852 if (scalar (@ready = $sel->can_read($timeout))) {
1854 if (!$daemon->{pve
}->{secret
} || $self->{reload_config
}) {
1855 $self->{reload_config
} = undef;
1856 syslog
("info", "reloading configuration")
1857 if $self->{reload_config
};
1858 $daemon->{pve
}->{secret
} = PVE
::Utils
::load_auth_secret
();
1862 while (($c = $daemon->accept) || ($! == EINTR
)) {
1863 next if !$c; # EINTR
1867 $daemon->{pve
}->{username
} = undef;
1868 $daemon->{pve
}->{groupname
} = undef;
1869 $daemon->{pve
}->{ticket
} = undef;
1872 while (my $r = $c->get_request) {
1874 my ($user, $group, $ticket, $update) = handle_login
($daemon, $c, $r);
1877 $daemon->{pve
}->{username
} = $user;
1878 $daemon->{pve
}->{groupname
} = $group;
1879 $daemon->{pve
}->{ticket
} = $ticket;
1880 $daemon->SOAP::Transport
::HTTP
::Server
::handle
;
1883 $daemon->response->header ("Set-Cookie" => "PVEAuthTicket=$ticket");
1886 $c->send_response($daemon->response);
1890 # we only handle one request per connection, because
1891 # we want to minimize the number of connections
1898 last if !$c || ($rcount >= $max_requests);
1902 PVE
::Config
::poll
(); # read inotify events
1907 package PVE
::ConfigClient
;
1914 my ($soaphost, $soapport) = PVE
::Config
::soap_host_port
();
1916 sub __create_soaplite
{
1917 my ($timeout, $port, $ticket, $username, $password) = @_;
1919 my $cookie_jar = HTTP
::Cookies-
>new (ignore_discard
=> 1);
1922 $cookie_jar->set_cookie(0, 'PVEAuthTicket', $ticket, '/', $soaphost);
1925 my $soap = SOAP
::Lite
1926 -> serializer
(PVE
::SOAPSerializer-
>new)
1927 -> ns
('http://proxmox.com/PVE/ConfigServer')
1929 my($soap, $res) = @_;
1930 die ref $res ?
$res->faultstring : $soap->transport->status, "\n";
1932 -> proxy
("http://$soaphost:$port", timeout
=> $timeout,
1933 cookie_jar
=> $cookie_jar);
1935 if ($username && defined($password)) {
1936 $soap->proxy->credentials ("$soaphost:$port", 'PVE SOAP Server',
1937 $username, $password);
1944 my ($ticket, $cinfo, $cid) = @_;
1946 die "no ticket specified" if !$ticket;
1948 # set longet timeout for local connection
1949 my $timeout = $cid ?
10 : 120;
1951 my $port = $soapport;
1954 die "invalid cluster ID '$cid'"
1955 if $cid !~ m/^\d+$/;
1957 die "no config for cluster node '$cid'"
1958 if !($cinfo && ($ni = $cinfo->{"CID_$cid"}));
1960 $port = $ni->{configport
};
1963 return __create_soaplite
($timeout, $port, $ticket);
1969 die "no ticket specified" if !$ticket;
1972 if ($ticket !~ m/^((\S+)::\w+::\d+::[0-9a-f]{40})(::[0-9a-f]{40})?$/) {
1973 die "got invalid ticket '$ticket'\n";
1976 $ticket = $1; # strip second checksum used by PVE::AuthCookieHandler
1982 my $soap = __create_soaplite
($timeout, $soapport, $ticket);
1984 my $nt = $soap->update_ticket()->result;
1986 if ($ticket !~ m/^${username}::\w+::\d+::[0-9a-f]{40}$/) {
1987 die "got invalid ticket '$ticket'\n";
1993 sub request_ticket
{
1994 my ($username, $password) = @_;
1996 die "no username specified\n" if !$username;
1997 die "no password specified for user '$username'\n" if !defined ($password);
2001 my $soap = __create_soaplite
($timeout, $soapport, undef, $username, $password);
2003 my $ticket = $soap->update_ticket()->result;
2005 if ($ticket !~ m/^${username}::\w+::\d+::[0-9a-f]{40}$/) {
2006 die "got invalid ticket '$ticket'\n";