]>
git.proxmox.com Git - pve-guest-common.git/blob - src/PVE/VZDump/Common.pm
1 package PVE
::VZDump
::Common
;
8 use PVE
::SafeSyslog
qw(syslog);
10 use PVE
::Cluster
qw(cfs_register_file);
11 use PVE
::JSONSchema
qw(get_standard_option);
13 # NOTE: this is the legacy config, nowadays jobs.cfg is used (handled in pve-manager)
16 \
&parse_vzdump_cron_config
,
17 \
&write_vzdump_cron_config
,
20 my $dowhash_to_dow = sub {
24 push @da, $num ?
1 : 'mon' if $d->{mon
};
25 push @da, $num ?
2 : 'tue' if $d->{tue
};
26 push @da, $num ?
3 : 'wed' if $d->{wed
};
27 push @da, $num ?
4 : 'thu' if $d->{thu
};
28 push @da, $num ?
5 : 'fri' if $d->{fri
};
29 push @da, $num ?
6 : 'sat' if $d->{sat
};
30 push @da, $num ?
7 : 'sun' if $d->{sun
};
35 our $PROPERTY_STRINGS = {
36 'fleecing' => 'backup-fleecing',
37 'performance' => 'backup-performance',
38 'prune-backups' => 'prune-backups',
41 my sub parse_property_strings
{
44 for my $opt (keys $PROPERTY_STRINGS->%*) {
45 next if !defined($opts->{$opt});
47 my $format = $PROPERTY_STRINGS->{$opt};
48 $opts->{$opt} = PVE
::JSONSchema
::parse_property_string
($format, $opts->{$opt});
52 # parse crontab style day of week
54 my ($dowstr, $noerr) = @_;
56 my $dowmap = {mon
=> 1, tue
=> 2, wed
=> 3, thu
=> 4,
57 fri
=> 5, sat
=> 6, sun
=> 7};
58 my $rdowmap = { '1' => 'mon', '2' => 'tue', '3' => 'wed', '4' => 'thu',
59 '5' => 'fri', '6' => 'sat', '7' => 'sun', '0' => 'sun'};
63 $dowstr = '1,2,3,4,5,6,7' if $dowstr eq '*';
65 foreach my $day (PVE
::Tools
::split_list
($dowstr)) {
66 if ($day =~ m/^(mon|tue|wed|thu|fri|sat|sun)-(mon|tue|wed|thu|fri|sat|sun)$/i) {
67 for (my $i = $dowmap->{lc($1)}; $i <= $dowmap->{lc($2)}; $i++) {
68 my $r = $rdowmap->{$i};
71 } elsif ($day =~ m/^(mon|tue|wed|thu|fri|sat|sun|[0-7])$/i) {
72 $day = $rdowmap->{$day} if $day =~ m/\d/;
75 return undef if $noerr;
76 die "unable to parse day of week '$dowstr'\n";
83 PVE
::JSONSchema
::register_format
('backup-fleecing', {
85 description
=> "Enable backup fleecing. Cache backup data from blocks where new guest"
86 ." writes happen on specified storage instead of copying them directly to the backup"
87 ." target. This can help guest IO performance and even prevent hangs, at the cost of"
88 ." requiring more storage space.",
94 storage
=> get_standard_option
('pve-storage-id', {
95 description
=> "Use this storage to storage fleecing images. For efficient space usage,"
96 ." it's best to use a local storage that supports discard and either thin provisioning"
100 }, \
&verify_backup_fleecing
);
102 sub verify_backup_fleecing
{
103 my ($param, $noerr) = @_;
105 if (!$param->{storage
} && $param->{enabled
}) {
107 die "'storage' parameter is required when 'enabled' is set\n";
113 PVE
::JSONSchema
::register_format
('backup-performance', {
115 description
=> "Applies to VMs. Allow up to this many IO workers at the same time.",
122 'pbs-entries-max' => {
123 description
=> "Applies to container backups sent to PBS. Limits the number of entries"
124 ." allowed in memory at a given time to avoid unintended OOM situations. Increase it to"
125 ." enable backups of containers with a large amount of files.",
135 type
=> 'string', format
=> 'pve-vmid-list',
136 description
=> "The ID of the guest system you want to backup.",
137 completion
=> \
&PVE
::Cluster
::complete_local_vmid
,
140 node
=> get_standard_option
('pve-node', {
141 description
=> "Only run if executed on this node.",
142 completion
=> \
&PVE
::Cluster
::get_nodelist
,
147 description
=> "Backup all known guest systems on this host.",
153 description
=> "Exclude temporary files and logs.",
159 description
=> "Compress dump file.",
161 enum
=> ['0', '1', 'gzip', 'lzo', 'zstd'],
166 description
=> "Use pigz instead of gzip when N>0. N=1 uses half of cores, N>1 uses N as"
173 description
=> "Zstd threads. N=0 uses half of the available cores, if N is set to a value"
174 ." bigger than 0, N is used as thread count.",
180 description
=> "Be quiet.",
186 description
=> "Backup mode.",
188 default => 'snapshot',
189 enum
=> [ 'snapshot', 'suspend', 'stop' ],
192 type
=> 'string', format
=> 'pve-vmid-list',
193 description
=> "Exclude specified guest systems (assumes --all)",
198 description
=> "Exclude certain files/directories (shell globs). Paths starting with '/'"
199 ." are anchored to the container's root, other paths match relative to each"
208 format
=> 'email-or-username-list',
209 description
=> "Deprecated: Use notification targets/matchers instead. Comma-separated list"
210 ." of email addresses or users that should receive email notifications.",
213 mailnotification
=> {
215 description
=> "Deprecated: use notification targets/matchers instead." .
216 " Specify when to send a notification mail",
218 enum
=> [ 'always', 'failure' ],
221 'notification-mode' => {
223 description
=> "Determine which notification system to use. If set to 'legacy-sendmail',"
224 ." vzdump will consider the mailto/mailnotification parameters and send emails to the"
225 ." specified address(es) via the 'sendmail' command. If set to 'notification-system',"
226 ." a notification will be sent via PVE's notification system, and the mailto and"
227 ." mailnotification will be ignored. If set to 'auto' (default setting), an email will"
228 ." be sent if mailto is set, and the notification system will be used if not.",
230 enum
=> ['auto', 'legacy-sendmail', 'notification-system'],
233 'notification-policy' => {
235 description
=> "Deprecated: Do not use",
237 enum
=> [ 'always', 'failure', 'never'],
240 'notification-target' => {
242 format
=> 'pve-configid',
243 description
=> "Deprecated: Do not use",
248 description
=> "Store temporary files to specified directory.",
253 description
=> "Store resulting files to specified directory.",
258 description
=> "Use specified hook script.",
261 storage
=> get_standard_option
('pve-storage-id', {
262 description
=> "Store resulting file to this storage.",
263 completion
=> \
&complete_backup_storage
,
268 description
=> "Stop running backup jobs on this host.",
274 description
=> "Limit I/O bandwidth (in KiB/s).",
281 description
=> "Set IO priority when using the BFQ scheduler. For snapshot and suspend"
282 ." mode backups of VMs, this only affects the compressor. A value of 8 means the idle"
283 ." priority is used, otherwise the best-effort priority is used with the specified"
292 description
=> "Other performance-related settings.",
293 format
=> 'backup-performance',
298 description
=> "Options for backup fleecing (VM only).",
299 format
=> 'backup-fleecing',
304 description
=> "Maximal time to wait for the global lock (minutes).",
307 default => 3*60, # 3 hours
311 description
=> "Maximal time to wait until a guest system is stopped (minutes).",
314 default => 10, # 10 minutes
316 # FIXME remove with PVE 8.0 or PVE 9.0
319 description
=> "Deprecated: use 'prune-backups' instead. " .
320 "Maximal number of backup files per guest system.",
324 'prune-backups' => get_standard_option
('prune-backups', {
325 description
=> "Use these retention options instead of those from the storage configuration.",
327 default => "keep-all=1",
331 description
=> "Prune older backups according to 'prune-backups'.",
337 description
=> 'Backup all known guest systems included in the specified pool.',
340 'notes-template' => {
342 description
=> "Template string for generating notes for the backup(s). It can contain"
343 ." variables which will be replaced by their values. Currently supported are"
344 ." {{cluster}}, {{guestname}}, {{node}}, and {{vmid}}, but more might be added in the"
345 ." future. Needs to be a single line, newline and backslash need to be escaped as '\\n'"
346 ." and '\\\\' respectively.",
347 requires
=> 'storage',
353 description
=> "If true, mark backup(s) as protected.",
354 requires
=> 'storage',
363 # add JSON properties for create and set function
364 sub json_config_properties
{
367 foreach my $opt (keys %$confdesc) {
368 $prop->{$opt} = $confdesc->{$opt};
374 my $vzdump_properties = {
375 additionalProperties
=> 0,
376 properties
=> json_config_properties
({}),
379 sub parse_vzdump_cron_config
{
380 my ($filename, $raw) = @_;
382 my $jobs = []; # correct jobs
384 my $ejobs = []; # mailfomerd lines
386 my $jid = 1; # we start at 1
388 my $digest = Digest
::SHA
::sha1_hex
(defined($raw) ?
$raw : '');
390 while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
393 next if $line =~ m/^\#/;
394 next if $line =~ m/^\s*$/;
395 next if $line =~ m/^PATH\s*=/; # we always overwrite path
397 if ($line =~ m
|^(\d
+)\s
+(\d
+)\s
+\
*\s
+\
*\s
+(\S
+)\s
+root\s
+(/\S+/)?
(#)?vzdump(\s+(.*))?$|) {
399 my $minute = int($1);
405 my $dowhash = parse_dow
($dow, 1);
406 die "unable to parse day of week '$dow' in '$filename'\n" if !$dowhash;
408 my $args = PVE
::Tools
::split_args
($param);
409 my $opts = PVE
::JSONSchema
::get_options
($vzdump_properties, $args, 'vmid');
411 $opts->{enabled
} = !defined($enabled);
412 $opts->{id
} = "$digest:$jid";
414 $opts->{starttime
} = sprintf "%02d:%02d", $hour, $minute;
415 $opts->{dow
} = &$dowhash_to_dow($dowhash);
417 parse_property_strings
($opts);
423 syslog
('err', "parse error in '$filename': $err");
424 push @$ejobs, { line
=> $line };
426 } elsif ($line =~ m
|^\S
+\s
+(\S
+)\s
+\S
+\s
+\S
+\s
+\S
+\s
+\S
+\s
+(\S
.*)$|) {
427 syslog
('err', "warning: malformed line in '$filename'");
428 push @$ejobs, { line
=> $line };
430 syslog
('err', "ignoring malformed line in '$filename'");
435 $res->{digest
} = $digest;
436 $res->{jobs
} = $jobs;
437 $res->{ejobs
} = $ejobs;
442 sub write_vzdump_cron_config
{
443 my ($filename, $cfg) = @_;
445 my $out = "# cluster wide vzdump cron schedule\n";
446 $out .= "# Automatically generated file - do not edit\n\n";
447 $out .= "PATH=\"/usr/sbin:/usr/bin:/sbin:/bin\"\n\n";
449 my $jobs = $cfg->{jobs
} || [];
450 foreach my $job (@$jobs) {
451 my $enabled = ($job->{enabled
}) ?
'' : '#';
452 my $dh = parse_dow
($job->{dow
});
454 if ($dh->{mon
} && $dh->{tue
} && $dh->{wed
} && $dh->{thu
} &&
455 $dh->{fri
} && $dh->{sat
} && $dh->{sun
}) {
458 $dow = &$dowhash_to_dow($dh, 1);
464 die "no job start time specified\n" if !$job->{starttime
};
465 if ($job->{starttime
} =~ m/^(\d{1,2}):(\d{1,2})$/) {
466 ($hour, $minute) = (int($1), int($2));
467 die "hour '$hour' out of range\n" if $hour < 0 || $hour > 23;
468 die "minute '$minute' out of range\n" if $minute < 0 || $minute > 59;
470 die "unable to parse job start time\n";
473 $job->{quiet
} = 1; # we do not want messages from cron
475 my $cmd = command_line
($job);
477 $out .= sprintf "$minute $hour * * %-11s root $enabled$cmd\n", $dow;
480 my $ejobs = $cfg->{ejobs
} || [];
481 foreach my $job (@$ejobs) {
482 $out .= "$job->{line}\n" if $job->{line
};
493 if ($param->{vmid
}) {
494 $cmd .= " " . join(' ', PVE
::Tools
::split_list
($param->{vmid
}));
497 foreach my $p (keys %$param) {
498 next if $p eq 'id' || $p eq 'vmid' || $p eq 'starttime' ||
499 $p eq 'dow' || $p eq 'stdout' || $p eq 'enabled';
500 my $v = $param->{$p};
501 my $pd = $confdesc->{$p} || die "no such vzdump option '$p'\n";
502 if ($p eq 'exclude-path') {
503 foreach my $path (@$v) {
504 $cmd .= " --$p " . PVE
::Tools
::shellquote
($path);
507 $v = join(",", PVE
::Tools
::split_list
($v)) if $p eq 'mailto';
508 $v = PVE
::JSONSchema
::print_property_string
($v, $PROPERTY_STRINGS->{$p})
509 if $PROPERTY_STRINGS->{$p};
511 $cmd .= " --$p " . PVE
::Tools
::shellquote
($v) if defined($v) && $v ne '';
518 # bash completion helpers
519 sub complete_backup_storage
{
521 my $cfg = PVE
::Storage
::config
();
522 my $ids = $cfg->{ids
};
524 my $nodename = PVE
::INotify
::nodename
();
527 foreach my $sid (keys %$ids) {
528 my $scfg = $ids->{$sid};
529 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $nodename, 1);
530 next if !$scfg->{content
}->{backup
};