#!/usr/bin/perl use strict; use warnings; use IO::File; use File::Find; use File::stat; use PVE::APLInfo; use PVE::CertHelpers; use PVE::Certificate; use PVE::Cluster::Setup; use PVE::Cluster; use PVE::DataCenterConfig; use PVE::INotify; use PVE::NodeConfig; use PVE::RPCEnvironment; use PVE::SafeSyslog; use PVE::Tools; use PVE::API2::ACME; use PVE::API2::APT; use PVE::API2::Subscription; initlog ('pveupdate', 'daemon'); die "please run as root\n" if $> != 0; $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin'; PVE::INotify::inotify_init(); my $rpcenv = PVE::RPCEnvironment->init('cli'); $rpcenv->init_request(); $rpcenv->set_language($ENV{LANG}); $rpcenv->set_user('root@pam'); my $nodename = PVE::INotify::nodename(); eval { PVE::API2::Subscription->update({ node => $nodename }); }; if (my $err = $@) { syslog ('err', "update subscription info failed: $err"); } my $dccfg = PVE::Cluster::cfs_read_file('datacenter.cfg'); eval { PVE::APLInfo::update($dccfg->{http_proxy}); }; if (my $err = $@) { syslog ('err', "update appliance info failed - see /var/log/pveam.log for details"); } my $info = eval { PVE::API2::Subscription::read_etc_subscription() }; my $notify_on = $dccfg->{notify}->{'package-updates'} // 'auto'; my $notify = 0; if ($notify_on eq 'auto') { # hosts with subscriptions are likely production system and thus want infos about new packages $notify = ($info && $info->{status} eq 'active') ? 1 : 0; } elsif ($notify_on eq 'always') { $notify = 1; } elsif ($notify_on eq 'never') { $notify = 0; } else { warn "unexpected package-updates notify configuration value '$notify_on'\n"; } eval { PVE::API2::APT->update_database({ node => $nodename, notify => $notify, quiet => 1 }); }; if (my $err = $@) { syslog ('err', "update apt database failed: $err"); } eval { my $node_config = PVE::NodeConfig::load_config($nodename); my $acme_node_config = PVE::NodeConfig::get_acme_conf($node_config); if ($acme_node_config && $acme_node_config->{domains}) { my $cert = PVE::CertHelpers::cert_path_prefix($nodename).".pem"; if (-e $cert) { if (PVE::Certificate::check_expiry($cert, time() + 30*24*60*60)) { PVE::API2::ACME->renew_certificate({ node => $nodename }); } else { syslog ('info', 'Custom certificate does not expire soon, skipping ACME renewal.'); } } else { syslog ('info', 'ACME config found for node, but no custom certificate exists. Skipping ACME renewal until initial certificate has been deployed.'); } } }; syslog ('err', "Renewing ACME certificate failed: $@") if $@; eval { my $certpath = PVE::CertHelpers::default_cert_path_prefix($nodename).".pem"; my $capath = "/etc/pve/pve-root-ca.pem"; my $renew = sub { my ($msg) = @_; # get CA info my $cainfo = PVE::Certificate::get_certificate_info($capath); # get cert and check issuer and chain metadata my $certinfo = PVE::Certificate::get_certificate_info($certpath); if ($certinfo->{issuer} ne $cainfo->{subject}) { die "SSL certificate ($certpath) is not issued by root CA ($capath)!\n"; } # check if cert is really signed by the ca # TODO: replace by low level ssleay interface if version 1.86 is available PVE::Tools::run_command(['/usr/bin/openssl', 'verify', '-CAfile', $capath, $certpath]); print "PVE certificate $msg\n"; # create new certificate my $ip = PVE::Cluster::remote_node_ip($nodename); PVE::Cluster::Setup::gen_pve_ssl_cert(1, $nodename, $ip); print "Restarting pveproxy after renewing certificate\n"; PVE::Tools::run_command(['systemctl', 'reload-or-restart', 'pveproxy']); }; if (PVE::Certificate::check_expiry($certpath, time() + 14*24*60*60)) { # expires in next 2 weeks $renew->("expires soon, renewing..."); } elsif (!PVE::Certificate::check_expiry($certpath, time() + 2*365*24*60*60)) { # expires in more than 2 years $renew->("expires in more than 2 years, renewing to reduce certificate life-span for client compatibility..."); } }; syslog ('err', "Checking/Renewing SSL certificate failed: $@") if $@; sub cleanup_tasks { my $taskdir = "/var/log/pve/tasks"; my $filename = "$taskdir/index.1"; my $fh = IO::File->new($filename, O_RDONLY); return if !$fh; my $endtime = 0; while (defined(my $line = <$fh>)) { if ($line =~ m/^(\S+)(\s([0-9A-Za-z]{8})(\s(\S.*))?)?$/) { $endtime = hex($3); last; } } close($fh); return if !$endtime; # print "delete task older that $endtime\n" . localtime($endtime) . "\n"; my $count = 0; my $wanted = sub { my $filename = $_; return if $filename !~ m/^UPID:/; my $st; if (($st = stat($filename)) && ($st->mtime < $endtime)) { unlink($filename); $count++; } }; foreach my $subdir (qw(0 1 2 3 4 5 6 7 8 9 A B C D E F)) { my $path = "$taskdir/$subdir"; find($wanted, $path); } if ($count) { syslog('info', "cleanup removed $count task logs"); } } cleanup_tasks(); exit (0);