From: Stoiko Ivanov <s.ivanov@proxmox.com>
To: pmg-devel@lists.proxmox.com
Subject: [pmg-devel] [PATCH pmg-api v3 6/7] add scheduled backup to PBS remotes
Date: Mon, 16 Nov 2020 12:01:14 +0100 [thread overview]
Message-ID: <20201116110118.7483-8-s.ivanov@proxmox.com> (raw)
In-Reply-To: <20201116110118.7483-1-s.ivanov@proxmox.com>
PMG::PBSSchedule contains methods for creating/deleting systemd-timer units,
which will run a backup to a configured PBS remote.
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
debian/pmg-pbsbackup@.service | 6 ++
debian/rules | 1 +
src/Makefile | 3 +-
src/PMG/API2/PBS/Job.pm | 130 ++++++++++++++++++++++++++++++++++
src/PMG/CLI/pmgbackup.pm | 6 ++
src/PMG/PBSSchedule.pm | 104 +++++++++++++++++++++++++++
6 files changed, 249 insertions(+), 1 deletion(-)
create mode 100644 debian/pmg-pbsbackup@.service
create mode 100644 src/PMG/PBSSchedule.pm
diff --git a/debian/pmg-pbsbackup@.service b/debian/pmg-pbsbackup@.service
new file mode 100644
index 0000000..37aa23b
--- /dev/null
+++ b/debian/pmg-pbsbackup@.service
@@ -0,0 +1,6 @@
+[Unit]
+Description=Backup to PBS remote %I
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/pmgbackup pbsjob run %I
diff --git a/debian/rules b/debian/rules
index bab4d98..5a2cf7a 100755
--- a/debian/rules
+++ b/debian/rules
@@ -20,6 +20,7 @@ override_dh_installinit:
dh_systemd_enable --name=pmgspamreport pmgspamreport.service
dh_systemd_enable --name=pmgreport pmgreport.service
dh_systemd_enable --name=pmgsync pmgsync.service
+ dh_systemd_enable --no-enable --name=pmg-pbsbackup@ pmg-pbsbackup@.service
override_dh_systemd_start:
dh_systemd_start pmg-hourly.timer pmg-daily.timer pmgspamreport.timer pmgreport.timer
diff --git a/src/Makefile b/src/Makefile
index fb42f21..9d5c335 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -15,7 +15,7 @@ CRONSCRIPTS = pmg-hourly pmg-daily
CLI_CLASSES = $(addprefix PMG/CLI/, $(addsuffix .pm, ${CLITOOLS}))
SERVICE_CLASSES = $(addprefix PMG/Service/, $(addsuffix .pm, ${SERVICES}))
-SERVICE_UNITS = $(addprefix debian/, $(addsuffix .service, ${SERVICES}))
+SERVICE_UNITS = $(addprefix debian/, $(addsuffix .service, ${SERVICES} pmg-pbsbackup@))
TIMER_UNITS = $(addprefix debian/, $(addsuffix .timer, ${CRONSCRIPTS} pmgspamreport pmgreport))
CLI_BINARIES = $(addprefix bin/, ${CLITOOLS} ${CLISCRIPTS} ${CRONSCRIPTS})
@@ -67,6 +67,7 @@ LIBSOURCES = \
PMG/Unpack.pm \
PMG/Backup.pm \
PMG/PBSConfig.pm \
+ PMG/PBSSchedule.pm \
PMG/RuleCache.pm \
PMG/Statistic.pm \
PMG/UserConfig.pm \
diff --git a/src/PMG/API2/PBS/Job.pm b/src/PMG/API2/PBS/Job.pm
index dee1754..4b686ec 100644
--- a/src/PMG/API2/PBS/Job.pm
+++ b/src/PMG/API2/PBS/Job.pm
@@ -14,6 +14,7 @@ use PVE::PBSClient;
use PMG::RESTEnvironment;
use PMG::Backup;
use PMG::PBSConfig;
+use PMG::PBSSchedule;
use base qw(PVE::RESTHandler);
@@ -368,4 +369,133 @@ __PACKAGE__->register_method ({
return $rpcenv->fork_worker('pbs_restore', undef, $authuser, $worker);
}});
+__PACKAGE__->register_method ({
+ name => 'create_timer',
+ path => '{remote}/timer',
+ method => 'POST',
+ description => "Create backup schedule",
+ proxyto => 'node',
+ protected => 1,
+ permissions => { check => [ 'admin', 'audit' ] },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ remote => {
+ description => "Proxmox Backup Server ID.",
+ type => 'string', format => 'pve-configid',
+ },
+ schedule => {
+ description => "Schedule for the backup (OnCalendar setting of the systemd.timer)",
+ type => 'string', pattern => '[0-9a-zA-Z*.:,\-/ ]+',
+ default => 'daily', optional => 1,
+ },
+ delay => {
+ description => "Randomized delay to add to the starttime (RandomizedDelaySec setting of the systemd.timer)",
+ type => 'string', pattern => '[0-9a-zA-Z. ]+',
+ default => 'daily', optional => 1,
+ },
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $remote = $param->{remote};
+ my $schedule = $param->{schedule} // 'daily';
+ my $delay = $param->{delay} // '5min';
+
+ my $conf = PMG::PBSConfig->new();
+
+ my $remote_config = $conf->{ids}->{$remote};
+ die "PBS remote '$remote' does not exist\n" if !$remote_config;
+ die "PBS remote '$remote' is disabled\n" if $remote_config->{disable};
+
+ PMG::PBSSchedule::create_schedule($remote, $schedule, $delay);
+
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'delete_timer',
+ path => '{remote}/timer',
+ method => 'DELETE',
+ description => "Delete backup schedule",
+ proxyto => 'node',
+ protected => 1,
+ permissions => { check => [ 'admin', 'audit' ] },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ remote => {
+ description => "Proxmox Backup Server ID.",
+ type => 'string', format => 'pve-configid',
+ },
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $remote = $param->{remote};
+
+ PMG::PBSSchedule::delete_schedule($remote);
+
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'list_timer',
+ path => '{remote}/timer',
+ method => 'GET',
+ description => "Get timer specification",
+ proxyto => 'node',
+ protected => 1,
+ permissions => { check => [ 'admin', 'audit' ] },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ remote => {
+ description => "Proxmox Backup Server ID.",
+ type => 'string', format => 'pve-configid',
+ },
+ },
+ },
+ returns => { type => 'object', properties => {
+ remote => {
+ description => "Proxmox Backup Server ID.",
+ type => 'string', format => 'pve-configid',
+ optional => 1,
+ },
+ schedule => {
+ description => "Schedule for the backup (OnCalendar setting of the systemd.timer)",
+ type => 'string', pattern => '[0-9a-zA-Z*.:,\-/ ]+',
+ default => 'daily', optional => 1,
+ },
+ delay => {
+ description => "Randomized delay to add to the starttime (RandomizedDelaySec setting of the systemd.timer)",
+ type => 'string', pattern => '[0-9a-zA-Z. ]+',
+ default => 'daily', optional => 1,
+ },
+ unitfile => {
+ description => "unit file for the systemd.timer unit",
+ type => 'string', optional => 1,
+ },
+ }},
+ code => sub {
+ my ($param) = @_;
+
+ my $remote = $param->{remote};
+
+ my $schedules = PMG::PBSSchedule::get_schedules();
+ my @data = grep {$_->{remote} eq $remote} @$schedules;
+
+ my $res = {};
+ if (scalar(@data) == 1) {
+ $res = $data[0];
+ }
+
+ return $res
+ }});
+
1;
diff --git a/src/PMG/CLI/pmgbackup.pm b/src/PMG/CLI/pmgbackup.pm
index 228f5ab..e40da25 100644
--- a/src/PMG/CLI/pmgbackup.pm
+++ b/src/PMG/CLI/pmgbackup.pm
@@ -85,6 +85,12 @@ our $cmddef = {
forget => ['PMG::API2::PBS::Job', 'forget_snapshot', ['remote', 'time'], { node => $nodename} ],
run => ['PMG::API2::PBS::Job', 'run_backup', ['remote'], { node => $nodename} ],
restore => ['PMG::API2::PBS::Job', 'restore', ['remote'], { node => $nodename} ],
+ create => ['PMG::API2::PBS::Job', 'create_timer', ['remote'], { node => $nodename }],
+ delete => ['PMG::API2::PBS::Job', 'delete_timer', ['remote'], { node => $nodename }],
+ schedule => ['PMG::API2::PBS::Job', 'list_timer', ['remote'], { node => $nodename }, sub {
+ my ($data, $schema, $options) = @_;
+ PVE::CLIFormatter::print_api_result($data, $schema, ['remote', 'schedule', 'delay'], $options);
+ }, $PVE::RESTHandler::standard_output_options ],
},
};
diff --git a/src/PMG/PBSSchedule.pm b/src/PMG/PBSSchedule.pm
new file mode 100644
index 0000000..6663f55
--- /dev/null
+++ b/src/PMG/PBSSchedule.pm
@@ -0,0 +1,104 @@
+package PMG::PBSSchedule;
+
+use strict;
+use warnings;
+
+use PVE::Tools qw(run_command file_set_contents file_get_contents trim dir_glob_foreach);
+use PVE::Systemd;
+
+# systemd timer
+sub get_schedules {
+ my ($param) = @_;
+
+ my $result = [];
+
+ my $systemd_dir = '/etc/systemd/system';
+
+ dir_glob_foreach($systemd_dir, '^pmg-pbsbackup@.+\.timer$', sub {
+ my ($filename) = @_;
+ my $remote;
+ if ($filename =~ /^pmg-pbsbackup\@(.+)\.timer$/) {
+ $remote = PVE::Systemd::unescape_unit($1);
+ } else {
+ die 'Unrecognized timer name!\n';
+ }
+
+ my $unitfile = "$systemd_dir/$filename";
+ my $unit = PVE::Systemd::read_ini($unitfile);
+
+ push @$result, {
+ unitfile => $unitfile,
+ remote => $remote,
+ schedule => $unit->{'Timer'}->{'OnCalendar'},
+ delay => $unit->{'Timer'}->{'RandomizedDelaySec'},
+ };
+ });
+
+ return $result;
+
+}
+
+sub create_schedule {
+ my ($remote, $schedule, $delay) = @_;
+
+ my $unit_name = 'pmg-pbsbackup@' . PVE::Systemd::escape_unit($remote);
+ #my $service_unit = $unit_name . '.service';
+ my $timer_unit = $unit_name . '.timer';
+ my $timer_unit_path = "/etc/systemd/system/$timer_unit";
+
+ # create systemd timer
+ run_command(['systemd-analyze', 'calendar', $schedule], errmsg => "Invalid schedule specification", outfunc => sub {});
+ run_command(['systemd-analyze', 'timespan', $delay], errmsg => "Invalid delay specification", outfunc => sub {});
+ my $timer = {
+ 'Unit' => {
+ 'Description' => "Timer for PBS Backup to remote $remote",
+ },
+ 'Timer' => {
+ 'OnCalendar' => $schedule,
+ 'RandomizedDelaySec' => $delay,
+ },
+ 'Install' => {
+ 'WantedBy' => 'timers.target',
+ },
+ };
+
+ eval {
+ PVE::Systemd::write_ini($timer, $timer_unit_path);
+ run_command(['systemctl', 'daemon-reload']);
+ run_command(['systemctl', 'enable', $timer_unit]);
+ run_command(['systemctl', 'start', $timer_unit]);
+
+ };
+ if (my $err = $@) {
+ die "Creating backup schedule for $remote failed: $err\n";
+ }
+
+ return;
+}
+
+sub delete_schedule {
+ my ($remote) = @_;
+
+ my $schedules = get_schedules();
+
+ die "Schedule for $remote not found!\n" if !grep {$_->{remote} eq $remote} @$schedules;
+
+ my $unit_name = 'pmg-pbsbackup@' . PVE::Systemd::escape_unit($remote);
+ my $service_unit = $unit_name . '.service';
+ my $timer_unit = $unit_name . '.timer';
+ my $timer_unit_path = "/etc/systemd/system/$timer_unit";
+
+ eval {
+ run_command(['systemctl', 'disable', $timer_unit]);
+ unlink($timer_unit_path) || die "delete '$timer_unit_path' failed - $!\n";
+ run_command(['systemctl', 'daemon-reload']);
+
+ };
+ if (my $err = $@) {
+ die "Removing backup schedule for $remote failed: $err\n";
+ }
+
+ return;
+}
+
+1;
--
2.20.1
next prev parent reply other threads:[~2020-11-16 11:02 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-16 11:01 [pmg-devel] [PATCH pve-common/pmg-api/pmg-gui v3] add initial PBS integration Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pve-common v3 1/1] add PBSClient module Stoiko Ivanov
2020-11-17 8:49 ` [pmg-devel] applied: " Thomas Lamprecht
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-api v3 1/7] debian: drop duplicate ', ' in dependencies Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-api v3 2/7] add initial SectionConfig for PBS Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-api v3 3/7] Add API2 module for PBS configuration Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-api v3 4/7] Add API2 module for per-node backups to PBS Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-api v3 5/7] pbs-integration: add CLI calls to pmgbackup Stoiko Ivanov
2020-11-16 11:01 ` Stoiko Ivanov [this message]
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-api v3 7/7] add /etc/pmg/pbs to cluster-sync Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-gui v3 1/3] Make Backup/Restore panel a menuentry Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-gui v3 2/3] refactor RestoreWindow for PBS Stoiko Ivanov
2020-11-16 11:01 ` [pmg-devel] [PATCH pmg-gui v3 3/3] add PBSConfig tab to Backup menu Stoiko Ivanov
2020-11-17 17:22 ` [pmg-devel] applied-series: [PATCH pve-common/pmg-api/pmg-gui v3] add initial PBS integration Thomas Lamprecht
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201116110118.7483-8-s.ivanov@proxmox.com \
--to=s.ivanov@proxmox.com \
--cc=pmg-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal