]> git.proxmox.com Git - pmg-api.git/blame - PMG/Service/pmgmirror.pm
close #1887: register tls_policy file with reader/writer
[pmg-api.git] / PMG / Service / pmgmirror.pm
CommitLineData
132089d5
DM
1package PMG::Service::pmgmirror;
2
3use strict;
4use warnings;
5use Data::Dumper;
9430b6d4 6use Time::HiRes qw (gettimeofday tv_interval);
132089d5
DM
7
8use PVE::SafeSyslog;
9use PVE::Tools qw(extract_param);
10use PVE::INotify;
11use PVE::Daemon;
83ad364b 12use PVE::ProcFSTools;
132089d5 13
9430b6d4 14use PMG::Ticket;
132089d5
DM
15use PMG::RESTEnvironment;
16use PMG::DBTools;
17use PMG::RuleDB;
18use PMG::Cluster;
19use PMG::ClusterConfig;
20use PMG::Statistic;
21
22use base qw(PVE::Daemon);
23
24my $cmdline = [$0, @ARGV];
25
26my %daemon_options = (restart_on_error => 5, stop_wait_time => 5);
27
28my $daemon = __PACKAGE__->new('pmgmirror', $cmdline, %daemon_options);
29
30my $restart_request = 0;
31my $next_update = 0;
32
33my $cycle = 0;
2c26c08d 34my $updatetime = 60*2;
9430b6d4 35my $maxtimediff = 5;
132089d5 36
83ad364b 37my $initial_memory_usage;
132089d5
DM
38
39sub init {
83ad364b 40 # syslog('INIT');
132089d5
DM
41}
42
43sub hup {
44 my ($self) = @_;
45
46 $restart_request = 1;
47}
48
9430b6d4
DM
49sub sync_data_from_node {
50 my ($dbh, $rdb, $cinfo, $ni, $ticket, $rsynctime_ref) = @_;
2c26c08d 51
9430b6d4
DM
52 my $ctime = PMG::DBTools::get_remote_time($rdb);
53 my $ltime = time();
54
55 my $timediff = abs($ltime - $ctime);
56 if ($timediff > $maxtimediff) {
57 die "large time difference (> $timediff seconds) - not syncing\n";
58 }
59
60 if ($ni->{type} eq 'master') {
61 PMG::Cluster::sync_ruledb_from_master($dbh, $rdb, $ni, $ticket);
62 PMG::Cluster::sync_deleted_nodes_from_master($dbh, $rdb, $cinfo, $ni, $rsynctime_ref);
63 }
64
65 PMG::Cluster::sync_quarantine_db($dbh, $rdb, $ni, $rsynctime_ref);
66
67 PMG::Cluster::sync_greylist_db($dbh, $rdb, $ni);
68
69 PMG::Cluster::sync_userprefs_db($dbh, $rdb, $ni);
70
71 PMG::Cluster::sync_statistic_db($dbh, $rdb, $ni);
72
73 if ($ni->{type} eq 'master') {
74 PMG::Cluster::sync_domainstat_db($dbh, $rdb, $ni);
75
76 PMG::Cluster::sync_dailystat_db($dbh, $rdb, $ni);
77
78 PMG::Cluster::sync_virusinfo_db($dbh, $rdb, $ni);
79 }
5e1408fd
DM
80
81 PMG::Cluster::sync_localstat_db($dbh, $rdb, $ni);
9430b6d4
DM
82}
83
84sub cluster_sync {
2c26c08d
DM
85
86 my $cinfo = PMG::ClusterConfig->new(); # reload
87 my $role = $cinfo->{local}->{type} // '-';
88
89 return if $role eq '-';
90 return if !$cinfo->{master}; # just to be sure
91
9430b6d4 92 my $start_time = [ gettimeofday() ];
2c26c08d
DM
93
94 syslog ('info', "starting cluster syncronization");
95
96 my $master_ip = $cinfo->{master}->{ip};
97 my $master_name = $cinfo->{master}->{name};
98
9430b6d4
DM
99 if ($role ne 'master') {
100 PMG::Cluster::sync_config_from_master($master_name, $master_ip);
101 }
2c26c08d 102
9430b6d4 103 my $csynctime = tv_interval($start_time);
2c26c08d
DM
104
105 $cinfo = PMG::ClusterConfig->new(); # reload
106 $role = $cinfo->{local}->{type} // '-';
107
108 return if $role eq '-';
109 return if !$cinfo->{master}; # just to be sure
110
9430b6d4
DM
111 my $ticket = PMG::Ticket::assemble_ticket('root@pam');
112
113 my $dbh = PMG::DBTools::open_ruledb();
114
115 my $errcount = 0;
116
117 my $rsynctime = 0;
118
119 my $sync_node = sub {
120 my ($ni) = @_;
121
122 my $rdb;
123 eval {
124 $rdb = PMG::DBTools::open_ruledb(undef, '/var/run/pmgtunnel', $ni->{cid});
125 sync_data_from_node($dbh, $rdb, $cinfo, $ni, $ticket, \$rsynctime);
126 };
127 my $err = $@;
128
129 $rdb->disconnect() if $rdb;
130
131 if ($err) {
132 $errcount++;
133 syslog ('err', "database sync '$ni->{name}' failed - $err");
964c7db5
DM
134 } else {
135 PMG::DBTools::create_clusterinfo_default($dbh, $ni->{cid}, 'lastsync', 0, undef);
136 PMG::DBTools::write_maxint_clusterinfo($dbh, $ni->{cid}, 'lastsync', time());
9430b6d4
DM
137 }
138 };
139
140 # sync data from master first
141 if ($cinfo->{master}->{cid} ne $cinfo->{local}->{cid}) {
142 $sync_node->($cinfo->{master});
d6750ad4
DM
143
144 # rewrite config after sync from master
145 my $cfg = PMG::Config->new();
146 my $ruledb = PMG::RuleDB->new($dbh);
147 my $rulecache = PMG::RuleCache->new($ruledb);
148 $cfg->rewrite_config($rulecache, 1);
9430b6d4
DM
149 }
150
151 foreach my $ni (values %{$cinfo->{ids}}) {
152 next if $ni->{cid} eq $cinfo->{local}->{cid};
153 next if $ni->{cid} eq $cinfo->{master}->{cid};
154 $sync_node->($ni);
155 }
156
157 $dbh->disconnect();
158
159 my $cptime = tv_interval($start_time);
2c26c08d 160
9430b6d4 161 my $dbtime = $cptime - $rsynctime - $csynctime;
2c26c08d 162
9430b6d4 163 syslog('info', sprintf("cluster syncronization finished (%d errors, %.2f seconds " .
2c26c08d 164 "(files %.2f, database %.2f, config %.2f))",
9430b6d4 165 $errcount, $cptime, $rsynctime, $dbtime, $csynctime));
2c26c08d
DM
166
167}
168
132089d5
DM
169sub run {
170 my ($self) = @_;
171
172 for (;;) { # forever
173
174 $next_update = time() + $updatetime;
175
9430b6d4
DM
176 eval {
177 # Note: do nothing in first cycle (give pmgtunnel some time to startup)
178 cluster_sync() if $cycle > 0;
179 };
132089d5 180 if (my $err = $@) {
b902c0b8 181 syslog('err', "sync error: $err");
132089d5
DM
182 }
183
83ad364b
DM
184 $cycle++;
185
186 last if $self->{terminate};
187
188 my $mem = PVE::ProcFSTools::read_memory_usage();
189
190 if (!defined($initial_memory_usage) || ($cycle < 10)) {
191 $initial_memory_usage = $mem->{resident};
192 } else {
193 my $diff = $mem->{resident} - $initial_memory_usage;
194 if ($diff > 5*1024*1024) {
195 syslog ('info', "restarting server after $cycle cycles to " .
196 "reduce memory usage (free $mem->{resident} ($diff) bytes)");
197 $self->restart_daemon();
198 }
199 }
200
132089d5
DM
201 my $wcount = 0;
202 while ((time() < $next_update) &&
203 ($wcount < $updatetime) && # protect against time wrap
204 !$restart_request && !$self->{terminate}) {
205
206 $wcount++; sleep (1);
207 };
208
209 last if $self->{terminate};
210
211 $self->restart_daemon() if $restart_request;
212 }
213}
214
215$daemon->register_start_command("Start the Database Mirror Daemon");
216$daemon->register_stop_command("Stop the Database Mirror Daemon");
217$daemon->register_restart_command(1, "Restart the Database Mirror Daemon");
218
219our $cmddef = {
220 start => [ __PACKAGE__, 'start', []],
221 restart => [ __PACKAGE__, 'restart', []],
222 stop => [ __PACKAGE__, 'stop', []],
223};
224
2251;