]> git.proxmox.com Git - pve-manager.git/blob - bin/pveupdate
56d5d718655b5f920e80c77e7428ef25cccc3865
[pve-manager.git] / bin / pveupdate
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use IO::File;
7 use File::Find;
8 use File::stat;
9
10 use PVE::CertHelpers;
11 use PVE::Certificate;
12 use PVE::NodeConfig;
13 use PVE::INotify;
14 use PVE::Cluster;
15 use PVE::Cluster::Setup;
16 use PVE::DataCenterConfig;
17 use PVE::APLInfo;
18 use PVE::SafeSyslog;
19 use PVE::RPCEnvironment;
20 use PVE::Tools;
21 use PVE::API2::Subscription;
22 use PVE::API2::APT;
23 use PVE::API2::ACME;
24
25 initlog ('pveupdate', 'daemon');
26
27 die "please run as root\n" if $> != 0;
28
29 $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
30
31 PVE::INotify::inotify_init();
32
33 my $rpcenv = PVE::RPCEnvironment->init('cli');
34
35 $rpcenv->init_request();
36 $rpcenv->set_language($ENV{LANG});
37 $rpcenv->set_user('root@pam');
38
39 my $nodename = PVE::INotify::nodename();
40
41 eval { PVE::API2::Subscription->update({ node => $nodename }); };
42 if (my $err = $@) {
43 syslog ('err', "update subscription info failed: $err");
44 }
45
46 my $dccfg = PVE::Cluster::cfs_read_file('datacenter.cfg');
47 eval { PVE::APLInfo::update($dccfg->{http_proxy}); };
48 if (my $err = $@) {
49 syslog ('err', "update appliance info failed - see /var/log/pveam.log for details");
50 }
51
52 my $info = PVE::INotify::read_file('subscription');
53 # We assume that users with subscriptions want informations
54 # about new packages.
55 my $notify = ($info && $info->{status} eq 'Active') ? 1 : 0;
56 eval { PVE::API2::APT->update_database({ node => $nodename, notify => $notify, quiet => 1 }); };
57 if (my $err = $@) {
58 syslog ('err', "update apt database failed: $err");
59 }
60
61 eval {
62 my $node_config = PVE::NodeConfig::load_config($nodename);
63 if ($node_config && $node_config->{acme}) {
64 my $cert = PVE::CertHelpers::cert_path_prefix($nodename).".pem";
65 if (-e $cert) {
66 if (PVE::Certificate::check_expiry($cert, time() + 30*24*60*60)) {
67 PVE::API2::ACME->renew_certificate({ node => $nodename });
68 } else {
69 syslog ('info', 'Custom certificate does not expire soon, skipping ACME renewal.');
70 }
71 } else {
72 syslog ('info', 'ACME config found for node, but no custom certificate exists. Skipping ACME renewal until initial certificate has been deployed.');
73 }
74 }
75 };
76 syslog ('err', "Renewing ACME certificate failed: $@") if $@;
77
78 eval {
79 my $certpath = PVE::CertHelpers::default_cert_path_prefix($nodename).".pem";
80 my $capath = "/etc/pve/pve-root-ca.pem";
81
82 my $renew = sub {
83 my ($msg) = @_;
84
85 # get CA info
86 my $cainfo = PVE::Certificate::get_certificate_info($capath);
87
88 # get cert and check issuer and chain metadata
89 my $certinfo = PVE::Certificate::get_certificate_info($certpath);
90 if ($certinfo->{issuer} ne $cainfo->{subject}) {
91 die "SSL certificate ($certpath) is not issued by root CA ($capath)!\n";
92 }
93
94 # check if cert is really signed by the ca
95 # TODO: replace by low level ssleay interface if version 1.86 is available
96 PVE::Tools::run_command(['/usr/bin/openssl', 'verify', '-CAfile', $capath, $certpath]);
97
98 print "PVE certificate $msg\n";
99 # create new certificate
100 my $ip = PVE::Cluster::remote_node_ip($nodename);
101 PVE::Cluster::Setup::gen_pve_ssl_cert(1, $nodename, $ip);
102
103 print "Restarting pveproxy after renewing certificate\n";
104 PVE::Tools::run_command(['systemctl', 'reload-or-restart', 'pveproxy']);
105 };
106
107 if (PVE::Certificate::check_expiry($certpath, time() + 14*24*60*60)) {
108 # expires in next 2 weeks
109 $renew->("expires soon, renewing...");
110 } elsif (!PVE::Certificate::check_expiry($certpath, time() + 2*365*24*60*60)) {
111 # expires in more than 2 years
112 $renew->("expires in more than 2 years, renewing to reduce certificate life-span for client compatibility...");
113 }
114 };
115 syslog ('err', "Checking/Renewing SSL certificate failed: $@") if $@;
116
117 sub cleanup_tasks {
118
119 my $taskdir = "/var/log/pve/tasks";
120 my $filename = "$taskdir/index.1";
121
122 my $fh = IO::File->new($filename, O_RDONLY);
123 return if !$fh;
124
125 my $endtime = 0;
126 while (defined(my $line = <$fh>)) {
127 if ($line =~ m/^(\S+)(\s([0-9A-Za-z]{8})(\s(\S.*))?)?$/) {
128 $endtime = hex($3);
129 last;
130 }
131 }
132 close($fh);
133
134 return if !$endtime;
135
136 # print "delete task older that $endtime\n" . localtime($endtime) . "\n";
137
138 my $count = 0;
139
140 my $wanted = sub {
141 my $filename = $_;
142
143 return if $filename !~ m/^UPID:/;
144
145 my $st;
146 if (($st = stat($filename)) && ($st->mtime < $endtime)) {
147 unlink($filename);
148 $count++;
149 }
150 };
151
152 foreach my $subdir (qw(0 1 2 3 4 5 6 7 8 9 A B C D E F)) {
153 my $path = "$taskdir/$subdir";
154 find($wanted, $path);
155 }
156
157 if ($count) {
158 syslog('info', "cleanup removed $count task logs");
159 }
160 }
161
162 cleanup_tasks();
163
164 exit (0);