]>
git.proxmox.com Git - pmg-api.git/blob - src/PMG/Backup.pm
aff8814a52cc1bab01eb4ea840cb79fb40267535
13 use PMG
::Utils
qw(postgres_admin_cmd);
15 my $sa_custom_config_fn = "/etc/mail/spamassassin/custom.cf";
18 my ($dbh, $table, $ofh, $seq, $seqcol) = @_;
20 my $sth = $dbh->column_info(undef, undef, $table, undef);
22 my $attrs = $sth->fetchall_arrayref({});
25 foreach my $ref (@$attrs) {
26 push @col_arr, $ref->{COLUMN_NAME
};
31 my $cols = join (', ', @col_arr);
32 $cols || die "unable to fetch column definitions: ERROR";
34 print $ofh "COPY $table ($cols) FROM stdin;\n";
36 my $cmd = "COPY $table ($cols) TO STDOUT";
40 while ($dbh->pg_getcopydata($data) >= 0) {
46 if ($seq && $seqcol) {
47 print $ofh "SELECT setval('$seq', max($seqcol)) FROM $table;\n\n";
54 print $ofh "SET client_encoding = 'SQL_ASCII';\n";
55 print $ofh "SET check_function_bodies = false;\n\n";
57 my $dbh = PMG
::DBTools
::open_ruledb
();
59 print $ofh "BEGIN TRANSACTION;\n\n";
64 # read a consistent snapshot
65 $dbh->do("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
67 dump_table
($dbh, 'attribut', $ofh);
68 dump_table
($dbh, 'object', $ofh, 'object_id_seq', 'id');
69 dump_table
($dbh, 'objectgroup', $ofh, 'objectgroup_id_seq', 'id');
70 dump_table
($dbh, 'rule', $ofh, 'rule_id_seq', 'id');
71 dump_table
($dbh, 'rulegroup', $ofh);
72 dump_table
($dbh, 'userprefs', $ofh);
74 # we do not save the following tables: cgreylist, cmailstore, cmsreceivers, clusterinfo
78 $dbh->rollback(); # end read-only transaction
84 print $ofh "COMMIT TRANSACTION;\n\n";
90 print $ofh "SET client_encoding = 'SQL_ASCII';\n";
91 print $ofh "SET check_function_bodies = false;\n\n";
93 my $dbh = PMG
::DBTools
::open_ruledb
();
98 # read a consistent snapshot
99 $dbh->do("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
101 print $ofh "BEGIN TRANSACTION;\n\n";
103 dump_table
($dbh, 'dailystat', $ofh);
104 dump_table
($dbh, 'domainstat', $ofh);
105 dump_table
($dbh, 'virusinfo', $ofh);
106 dump_table
($dbh, 'localstat', $ofh);
108 # drop/create the index is a little bit faster (20%)
110 print $ofh "DROP INDEX cstatistic_time_index;\n\n";
111 print $ofh "ALTER TABLE cstatistic DROP CONSTRAINT cstatistic_id_key;\n\n";
112 print $ofh "ALTER TABLE cstatistic DROP CONSTRAINT cstatistic_pkey;\n\n";
113 dump_table
($dbh, 'cstatistic', $ofh, 'cstatistic_id_seq', 'id');
114 print $ofh "ALTER TABLE ONLY cstatistic ADD CONSTRAINT cstatistic_pkey PRIMARY KEY (cid, rid);\n\n";
115 print $ofh "ALTER TABLE ONLY cstatistic ADD CONSTRAINT cstatistic_id_key UNIQUE (id);\n\n";
116 print $ofh "CREATE INDEX CStatistic_Time_Index ON CStatistic (Time);\n\n";
118 print $ofh "DROP INDEX CStatistic_ID_Index;\n\n";
119 dump_table
($dbh, 'creceivers', $ofh);
120 print $ofh "CREATE INDEX CStatistic_ID_Index ON CReceivers (CStatistic_CID, CStatistic_RID);\n\n";
122 dump_table
($dbh, 'statinfo', $ofh);
124 print $ofh "COMMIT TRANSACTION;\n\n";
128 $dbh->rollback(); # end read-only transaction
135 # this function assumes that directory $dirname exists and is empty
137 my ($dirname, $include_statistics) = @_;
139 die "No backupdir provided!\n" if !defined($dirname);
142 my $dbfn = "Proxmox_ruledb.sql";
143 my $statfn = "Proxmox_statdb.sql";
144 my $tarfn = "config_backup.tar";
145 my $sigfn = "proxmox_backup_v1.md5";
146 my $verfn = "version.txt";
150 # dump the database first
151 my $fh = PMG
::AtomicFile-
>open("$dirname/$dbfn", "w") ||
152 die "cant open '$dirname/$dbfn' - $! :ERROR";
158 if ($include_statistics) {
159 # dump the statistic db
160 my $sfh = PMG
::AtomicFile-
>open("$dirname/$statfn", "w") ||
161 die "cant open '$dirname/$statfn' - $! :ERROR";
168 my $pkg = PMG
::pmgcfg
::package();
169 my $release = PMG
::pmgcfg
::release
();
171 my $vfh = PMG
::AtomicFile-
>open ("$dirname/$verfn", "w") ||
172 die "cant open '$dirname/$verfn' - $! :ERROR";
176 print $vfh "product: $pkg\nversion: $release\nbackuptime:$time:$now\n";
181 push @$extra_cfgs, $sa_custom_config_fn;
183 my $extradb = $include_statistics ?
$statfn : '';
185 my $extra = join(' ', @$extra_cfgs);
187 system("/bin/tar cf $dirname/$tarfn -C / " .
188 "/etc/pmg $extra>/dev/null 2>&1") == 0 ||
189 die "unable to create system configuration backup: ERROR";
191 system("cd $dirname; md5sum $tarfn $dbfn $extradb $verfn> $sigfn") == 0 ||
192 die "unable to create backup signature: ERROR";
202 sub pmg_backup_pack
{
203 my ($filename, $include_statistics) = @_;
206 my $dirname = "/tmp/proxbackup_$$.$time";
210 my $targetdir = dirname
($filename);
211 mkdir $targetdir; # try to create target dir
213 die "unable to access target directory '$targetdir'\n";
216 # create backup directory
219 pmg_backup
($dirname, $include_statistics);
221 system("rm -f $filename; tar czf $filename --strip-components=1 -C $dirname .") == 0 ||
222 die "unable to create backup archive: ERROR";
235 my ($filename, $restore_database, $restore_config, $restore_statistics) = @_;
237 my $dbname = 'Proxmox_ruledb';
240 my $dirname = "/tmp/proxrestore_$$.$time";
241 my $dbfn = "Proxmox_ruledb.sql";
242 my $statfn = "Proxmox_statdb.sql";
243 my $tarfn = "config_backup.tar";
244 my $sigfn = "proxmox_backup_v1.md5";
248 # directory indicates that the files were restored from a PBS remote
249 if ( -d
$filename ) {
250 $dirname = $filename;
257 # remove any leftovers
259 # create a temporary directory
262 system("cd $dirname; tar xzf $filename >/dev/null 2>&1") == 0 ||
263 die "unable to extract backup archive: ERROR";
266 system("cd $dirname; md5sum -c $sigfn") == 0 ||
267 die "proxmox backup signature check failed: ERROR";
269 if ($restore_config) {
270 # restore the tar file
271 mkdir "$dirname/config/";
272 system("tar xpf $dirname/$tarfn -C $dirname/config/") == 0 ||
273 die "unable to restore configuration tar archive: ERROR";
275 -d
"$dirname/config/etc/pmg" ||
276 die "backup does not contain a valid system configuration directory (/etc/pmg)\n";
277 # unlink unneeded files
278 unlink "$dirname/config/etc/pmg/cluster.conf"; # never restore cluster config
279 rmtree
"$dirname/config/etc/pmg/master";
281 # remove current config, but keep directory for INotify
282 rmtree
("/etc/pmg", { keep_root
=> 1 });
284 system("cp -a $dirname/config/etc/pmg/* /etc/pmg/") == 0 ||
285 die "unable to restore system configuration: ERROR";
287 if (-f
"$dirname/config/${sa_custom_config_fn}") {
288 my $data = PVE
::Tools
::file_get_contents
(
289 "$dirname/config/${sa_custom_config_fn}", 1024*1024);
290 PVE
::Tools
::file_set_contents
($sa_custom_config_fn, $data);
293 my $cfg = PMG
::Config-
>new();
294 my $ruledb = PMG
::RuleDB-
>new();
295 my $rulecache = PMG
::RuleCache-
>new($ruledb);
296 $cfg->rewrite_config($rulecache, 1);
299 if ($restore_database) {
300 # recreate the database
302 # stop all services accessing the database
303 PMG
::Utils
::service_wait_stopped
(40, $PMG::Utils
::db_service_list
);
305 print "Destroy existing rule database\n";
306 PMG
::DBTools
::delete_ruledb
($dbname);
308 print "Create new database\n";
309 my $dbh = PMG
::DBTools
::create_ruledb
($dbname);
311 system("cat $dirname/$dbfn|psql $dbname >/dev/null 2>&1") == 0 ||
312 die "unable to restore rule database: ERROR";
314 if ($restore_statistics) {
315 if (-f
"$dirname/$statfn") {
316 system("cat $dirname/$statfn|psql $dbname >/dev/null 2>&1") == 0 ||
317 die "unable to restore statistic database: ERROR";
321 print STDERR
"run analyze to speed up database queries\n";
322 postgres_admin_cmd
('psql', { input
=> 'analyze;' }, $dbname);
324 print "Analyzing/Upgrading existing Databases...";
325 my $ruledb = PMG
::RuleDB-
>new($dbh);
326 PMG
::DBTools
::upgradedb
($ruledb);
329 # cleanup old spam/virus storage
330 PMG
::MailQueue
::create_spooldirs
(0, 1);
332 my $cfg = PMG
::Config-
>new();
333 my $rulecache = PMG
::RuleCache-
>new($ruledb);
334 $cfg->rewrite_config($rulecache, 1);
336 # and restart services as soon as possible
337 foreach my $service (reverse @$PMG::Utils
::db_service_list
) {
338 eval { PVE
::Tools
::run_command
(['systemctl', 'start', $service]); };