diff options
| author | erkin <e.altunbas@vyos.io> | 2021-02-06 14:38:16 +0300 |
|---|---|---|
| committer | erkin <e.altunbas@vyos.io> | 2021-02-06 14:38:16 +0300 |
| commit | aed34f6991b6e87a3f178b95a13fccb7953a3dc9 (patch) | |
| tree | 1d8544480c0acb9e5fc0d768dbf74637791f076f /scripts | |
| parent | 74dafca28ac91a166851d2fd718a9d6bc18f3511 (diff) | |
| download | vyatta-config-mgmt-aed34f6991b6e87a3f178b95a13fccb7953a3dc9.tar.gz vyatta-config-mgmt-aed34f6991b6e87a3f178b95a13fccb7953a3dc9.zip | |
T3285, T661: Schedule commit-confirm reboots through systemd
Notify logged in users of the impending reboot
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/commit-confirm-notify.py | 30 | ||||
| -rwxr-xr-x | scripts/vyatta-config-mgmt.pl | 101 |
2 files changed, 81 insertions, 50 deletions
diff --git a/scripts/commit-confirm-notify.py b/scripts/commit-confirm-notify.py new file mode 100755 index 0000000..eb7859f --- /dev/null +++ b/scripts/commit-confirm-notify.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import os +import sys +import time + +# Minutes before reboot to trigger notification. +intervals = [1, 5, 15, 60] + +def notify(interval): + s = "" if interval == 1 else "s" + time.sleep((minutes - interval) * 60) + message = ('"[commit-confirm] System is going to reboot in ' + f'{interval} minute{s} to rollback the last commit.\n' + 'Confirm your changes to cancel the reboot."') + os.system("wall -n " + message) + +if __name__ == "__main__": + # Must be run as root to call wall(1) without a banner. + if len(sys.argv) != 2 or os.getuid() != 0: + exit(1) + minutes = int(sys.argv[1]) + # Drop the argument from the list so that the notification + # doesn't kick in immediately. + if minutes in intervals: + intervals.remove(minutes) + for interval in sorted(intervals, reverse=True): + if minutes >= interval: + notify(interval) + minutes -= (minutes - interval) + exit(0) diff --git a/scripts/vyatta-config-mgmt.pl b/scripts/vyatta-config-mgmt.pl index 0d23fcb..0a8528c 100755 --- a/scripts/vyatta-config-mgmt.pl +++ b/scripts/vyatta-config-mgmt.pl @@ -48,7 +48,8 @@ my $commit_hook_dir = cm_get_commit_hook_dir(); my $archive_dir = cm_get_archive_dir(); my $config_file = "$archive_dir/config.boot"; my $lr_conf_file = cm_get_lr_conf_file(); -my $confirm_job_file = '/var/run/confirm.job'; + +my $job_name = "commit-confirm"; my $debug = 0; @@ -85,18 +86,6 @@ sub check_valid_rev { exit 1; } -sub parse_at_output { - my @lines = @_; - foreach my $line (@lines) { - if ($line =~ /error/) { - return (1, '', ''); - } elsif ($line =~ /job (\d+) (.*)$/) { - return (0, $1, $2); - } - } - return (1, '', ''); -} - sub filter_file_lines { my ($diff) = @_; @@ -177,7 +166,7 @@ if ($action eq 'valid-uri') { } elsif ($scheme eq 'scp') { } elsif ($scheme eq 'sftp') { } else { - print "Unsupported URI scheme\n"; + print "Unsupported URI scheme.\n"; exit 1; } exit 0; @@ -267,7 +256,7 @@ if ($action eq 'diff') { if ($args < 0) { my $rc = system("cli-shell-api sessionChanged"); if (defined $rc and $rc > 0) { - print "No changes between working and active configurations\n"; + print "No changes between working and active configurations.\n"; exit 0; } my $show_args = '--show-show-defaults --show-context-diff'; @@ -277,7 +266,7 @@ if ($action eq 'diff') { if (defined $diff and length($diff) > 0) { print "$diff"; } else { - print "No changes between working and active configurations\n"; + print "No changes between working and active configurations.\n"; exit 0; } } elsif ($args eq 0) { @@ -292,7 +281,7 @@ if ($action eq 'diff') { print "$diff"; } else { print "No changes between working and " - . "revision $rev1 configurations\n"; + . "revision $rev1 configurations.\n"; } system("rm $outfile"); } elsif ($args eq 1) { @@ -313,7 +302,7 @@ if ($action eq 'diff') { print "$diff"; } else { print "No changes between revision $rev1 and " - . "revision $rev2 configurations\n"; + . "revision $rev2 configurations.\n"; } system("rm $outfile2"); system("rm $outfile"); @@ -333,18 +322,18 @@ if ($action eq 'diff') { my $diff = `cli-shell-api showConfig --show-cfg1 $outfile2 --show-cfg2 $outfile --show-commands --show-show-defaults --show-context-diff`; if (defined $diff and length($diff) > 0) { my @difflines = split('\n', $diff); - foreach my $line (@difflines){ - my @words = split(' ', $line); - my $elements = scalar(@words); - my @non_leaf = @words[0 .. ($elements - 2)] ; - my $path = join(' ', @non_leaf); - $path =~ s/'//g; - my $cmd = "$path " . @words[($elements - 1)]; - print "$cmd\n"; + foreach my $line (@difflines) { + my @words = split(' ', $line); + my $elements = scalar(@words); + my @non_leaf = @words[0 .. ($elements - 2)] ; + my $path = join(' ', @non_leaf); + $path =~ s/'//g; + my $cmd = "$path " . @words[($elements - 1)]; + print "$cmd\n"; } } else { print "No changes between revision $rev1 and " - . "revision $rev2 configurations\n"; + . "revision $rev2 configurations.\n"; } system("rm $outfile2"); system("rm $outfile"); @@ -353,23 +342,27 @@ if ($action eq 'diff') { } if ($action eq 'commit-confirm') { - die "Error: no minutes" if ! defined $minutes; + die "Error: no minutes defined." if ! defined $minutes; print "commit-confirm [$minutes]\n" if $debug; - if (-e $confirm_job_file) { - print "Another confirm is pending\n"; + + # Check if there's already a timer. + system("systemctl is-active --quiet ${job_name}.timer"); + if ($? == 0) { + print "Another confirm is pending.\n"; exit 0; } + my $max_revs = cm_get_max_revs(); if (!defined $max_revs or $max_revs <= 0) { print "commit-revisions is not configured.\n\n"; exit 1; } check_integer($minutes); - print "commit confirm will be automatically reboot in $minutes" - . " minutes unless confirmed\n"; - if (prompt("Proceed? [confirm]", -y1d=>"y")) { + print "commit-confirm will automatically reboot in $minutes" + . " minutes unless changes are confirmed.\n"; + if (prompt("Proceed?", -y1d=>"y")) { } else { - print "commit-confirm canceled\n"; + print "commit-confirm canceled.\n"; exit 1; } @@ -378,29 +371,37 @@ if ($action eq 'commit-confirm') { $rollback_config .= "\n"; my $config_rb = cm_get_config_rb(); cm_write_file($config_rb, $rollback_config); - - $cmd = "/opt/vyatta/sbin/vyatta-config-mgmt.pl --action rollback" - . " --file $config_rb"; - @lines = `echo sudo sg vyattacfg \\"$cmd\\" | at now + $minutes minutes 2>&1`; - my ($err, $job, $time) = parse_at_output(@lines); - if ($err) { - print "Error: unable to schedule reboot\n"; + + my $command = "/opt/vyatta/sbin/vyatta-config-mgmt.pl --action rollback " + . "--file $config_rb"; + # Schedule a systemd timer to run rollback $minutes later. + system("sudo systemd-run --quiet --on-active=${minutes}m --unit=${job_name} " + . "sg vyattacfg \"${command}\""); + # Check if the timer was created. + system("systemctl is-active --quiet ${job_name}.timer"); + if ($? != 0) { + print "Error: unable to schedule reboot.\n"; exit 1; } - system("echo $job > $confirm_job_file"); + print "Reboot scheduled for commit-confirm. " + . "Confirm your changes to cancel the reboot.\n"; + # Call the script to notify the users of the impending reboot. + system("sudo -b /opt/vyatta/sbin/commit-confirm-notify.py ${minutes}"); exit 0; } if ($action eq 'confirm') { - if (! -e $confirm_job_file) { - print "No confirm pending\n"; - exit 0; + # Check if timer exists. + system("systemctl is-active --quiet ${job_name}.timer"); + if ($? != 0) { + print "No confirm pending.\n"; + } else { + # If so, stop it. + system("sudo systemctl stop --quiet ${job_name}.timer"); + # Kill the notification daemon if it's still running. + system("sudo pkill -f commit-confirm-notify.py"); + print "Reboot timer stopped.\n"; } - my $job = `cat $confirm_job_file`; - chomp $job; - system("sudo atrm $job"); - system("sudo rm -f $confirm_job_file"); - # log confirm exit 0; } |
