bundles/pacman: add opt-in unattended-upgrades
Some checks failed
kunsi/bundlewrap/pipeline/head There was a failure building this commit
Some checks failed
kunsi/bundlewrap/pipeline/head There was a failure building this commit
This commit is contained in:
parent
14b402cdf3
commit
60c31d2d11
8 changed files with 182 additions and 1 deletions
|
@ -1,5 +1,14 @@
|
||||||
% for monitored_node in sorted(monitored_nodes):
|
% for monitored_node in sorted(monitored_nodes):
|
||||||
% if monitored_node.has_any_bundle(['apt', 'c3voc-addons']):
|
<%
|
||||||
|
auto_updates_enabled = (
|
||||||
|
monitored_node.has_any_bundle(['apt', 'c3voc-addons'])
|
||||||
|
or (
|
||||||
|
monitored_node.has_bundle('pacman')
|
||||||
|
and monitored_node.metadata.get('pacman/unattended-upgrades/is_enabled', False)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
%>\
|
||||||
|
% if auto_updates_enabled:
|
||||||
object ScheduledDowntime "unattended_upgrades" {
|
object ScheduledDowntime "unattended_upgrades" {
|
||||||
host_name = "${monitored_node.name}"
|
host_name = "${monitored_node.name}"
|
||||||
|
|
||||||
|
@ -9,7 +18,11 @@ object ScheduledDowntime "unattended_upgrades" {
|
||||||
fixed = true
|
fixed = true
|
||||||
|
|
||||||
ranges = {
|
ranges = {
|
||||||
|
% if monitored_node.has_bundle('pacman'):
|
||||||
|
"${days[monitored_node.metadata.get('pacman/unattended-upgrades/day')]}" = "${monitored_node.metadata.get('pacman/unattended-upgrades/hour')}:${monitored_node.magic_number%30}-${monitored_node.metadata.get('pacman/unattended-upgrades/hour')}:${(monitored_node.magic_number%30)+30}"
|
||||||
|
% else:
|
||||||
"${days[monitored_node.metadata.get('apt/unattended-upgrades/day')]}" = "${monitored_node.metadata.get('apt/unattended-upgrades/hour')}:${monitored_node.magic_number%30}-${monitored_node.metadata.get('apt/unattended-upgrades/hour')}:${(monitored_node.magic_number%30)+30}"
|
"${days[monitored_node.metadata.get('apt/unattended-upgrades/day')]}" = "${monitored_node.metadata.get('apt/unattended-upgrades/hour')}:${monitored_node.magic_number%30}-${monitored_node.metadata.get('apt/unattended-upgrades/hour')}:${(monitored_node.magic_number%30)+30}"
|
||||||
|
% endif
|
||||||
}
|
}
|
||||||
|
|
||||||
child_options = "DowntimeTriggeredChildren"
|
child_options = "DowntimeTriggeredChildren"
|
||||||
|
|
38
bundles/pacman/files/check_unattended_upgrades
Normal file
38
bundles/pacman/files/check_unattended_upgrades
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
statusfile="/var/tmp/unattended_upgrades.status"
|
||||||
|
if ! [[ -f "$statusfile" ]]
|
||||||
|
then
|
||||||
|
echo "Status file not found"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
mtime=$(stat -c %Y $statusfile)
|
||||||
|
now=$(date +%s)
|
||||||
|
if (( $now - $mtime > 60*60*24*8 ))
|
||||||
|
then
|
||||||
|
echo "Status file is older than 8 days!"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
exitcode=$(cat $statusfile)
|
||||||
|
case "$exitcode" in
|
||||||
|
abort_ssh)
|
||||||
|
echo "Upgrades skipped due to active SSH login"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
0)
|
||||||
|
if [[ -f /var/run/reboot-required ]]
|
||||||
|
then
|
||||||
|
echo "OK, but updates require a reboot"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Last exitcode was $exitcode"
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
18
bundles/pacman/files/do-unattended-upgrades
Normal file
18
bundles/pacman/files/do-unattended-upgrades
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -xeuo pipefail
|
||||||
|
|
||||||
|
pacman -Syu
|
||||||
|
|
||||||
|
% for affected, restarts in sorted(restart_triggers.items()):
|
||||||
|
up_since=$(systemctl show "${affected}" | sed -n 's/^ActiveEnterTimestamp=//p' || echo 0)
|
||||||
|
up_since_ts=$(date -d "$up_since" +%s || echo 0)
|
||||||
|
now=$(date +%s)
|
||||||
|
|
||||||
|
if [ $((now - up_since_ts)) -lt 3600 ]
|
||||||
|
then
|
||||||
|
% for restart in sorted(restarts):
|
||||||
|
systemctl restart "${restart}" || true
|
||||||
|
% endfor
|
||||||
|
fi
|
||||||
|
% endfor
|
53
bundles/pacman/files/upgrade-and-reboot
Normal file
53
bundles/pacman/files/upgrade-and-reboot
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# With systemd, we can force logging to the journal. This is better than
|
||||||
|
# spamming the world with cron mails. You can then view these logs using
|
||||||
|
# "journalctl -rat upgrade-and-reboot".
|
||||||
|
if which logger >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
# Dump stdout and stderr to logger, which will then put everything
|
||||||
|
# into the journal.
|
||||||
|
exec 1> >(logger -t upgrade-and-reboot -p user.info)
|
||||||
|
exec 2> >(logger -t upgrade-and-reboot -p user.error)
|
||||||
|
fi
|
||||||
|
|
||||||
|
. /etc/upgrade-and-reboot.conf
|
||||||
|
|
||||||
|
echo "Starting upgrade-and-reboot for node $nodename ..."
|
||||||
|
|
||||||
|
statusfile="/var/tmp/unattended_upgrades.status"
|
||||||
|
# Workaround, because /var/tmp is usually 1777
|
||||||
|
[[ "$UID" == 0 ]] && chown root:root "$statusfile"
|
||||||
|
|
||||||
|
logins=$(ps h -C sshd -o euser | awk '$1 != "root" && $1 != "sshd" && $1 != "sshmon"')
|
||||||
|
if [[ -n "$logins" ]]
|
||||||
|
then
|
||||||
|
echo "Will abort now, there are active SSH logins: $logins"
|
||||||
|
echo "abort_ssh" > "$statusfile"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
softlockdir=/var/lib/bundlewrap/soft-$nodename
|
||||||
|
mkdir -p "$softlockdir"
|
||||||
|
printf '{"comment": "UPDATE", "date": %s, "expiry": %s, "id": "UNATTENDED", "items": ["*"], "user": "root@localhost"}\n' \
|
||||||
|
$(date +%s) \
|
||||||
|
$(date -d 'now + 30 mins' +%s) \
|
||||||
|
>"$softlockdir"/UNATTENDED
|
||||||
|
trap 'rm -f "$softlockdir"/UNATTENDED' EXIT
|
||||||
|
|
||||||
|
do-unattended-upgrades
|
||||||
|
ret=$?
|
||||||
|
|
||||||
|
echo "$ret" > "$statusfile"
|
||||||
|
if (( $ret != 0 ))
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$reboot_mail_to" ]]
|
||||||
|
then
|
||||||
|
date | mail -s "SYSREBOOTNOW $nodename" "$reboot_mail_to"
|
||||||
|
fi
|
||||||
|
systemctl reboot
|
||||||
|
|
||||||
|
echo "upgrade-and-reboot for node $nodename is DONE"
|
3
bundles/pacman/files/upgrade-and-reboot.conf
Normal file
3
bundles/pacman/files/upgrade-and-reboot.conf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
nodename="${node.name}"
|
||||||
|
reboot_mail_to="${node.metadata.get('apt/unattended-upgrades/reboot_mail_to', '')}"
|
||||||
|
auto_reboot_enabled="${node.metadata.get('apt/unattended-upgrades/reboot_enabled', True)}"
|
|
@ -7,6 +7,22 @@ files = {
|
||||||
'/etc/pacman.conf': {
|
'/etc/pacman.conf': {
|
||||||
'content_type': 'mako',
|
'content_type': 'mako',
|
||||||
},
|
},
|
||||||
|
'/etc/upgrade-and-reboot.conf': {
|
||||||
|
'content_type': 'mako',
|
||||||
|
},
|
||||||
|
'/usr/local/sbin/upgrade-and-reboot': {
|
||||||
|
'mode': '0700',
|
||||||
|
},
|
||||||
|
'/usr/local/sbin/do-unattended-upgrades': {
|
||||||
|
'content_type': 'mako',
|
||||||
|
'mode': '0700',
|
||||||
|
'context': {
|
||||||
|
'restart_triggers': node.metadata.get('pacman/restart_triggers', {}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'/usr/local/share/icinga/plugins/check_unattended_upgrades': {
|
||||||
|
'mode': '0755',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_systemd['paccache.timer'] = {
|
svc_systemd['paccache.timer'] = {
|
||||||
|
|
|
@ -6,5 +6,42 @@ defaults = {
|
||||||
},
|
},
|
||||||
'parallel_downloads': 4,
|
'parallel_downloads': 4,
|
||||||
'repository': 'http://ftp.uni-kl.de/pub/linux/archlinux/$repo/os/$arch',
|
'repository': 'http://ftp.uni-kl.de/pub/linux/archlinux/$repo/os/$arch',
|
||||||
|
'unattended-upgrades': {
|
||||||
|
'day': 5,
|
||||||
|
'hour': 21,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'cron/jobs/upgrade-and-reboot',
|
||||||
|
'icinga2_api/pacman/services',
|
||||||
|
)
|
||||||
|
def patchday(metadata):
|
||||||
|
if not metadata.get('pacman/unattended-upgrades/is_enabled', False):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
day = metadata.get('pacman/unattended-upgrades/day')
|
||||||
|
hour = metadata.get('pacman/unattended-upgrades/hour')
|
||||||
|
|
||||||
|
return {
|
||||||
|
'cron': {
|
||||||
|
'jobs': {
|
||||||
|
'upgrade-and-reboot': '{minute} {hour} * * {day} root /usr/local/sbin/upgrade-and-reboot'.format(
|
||||||
|
minute=node.magic_number % 30,
|
||||||
|
hour=hour,
|
||||||
|
day=day,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'icinga2_api': {
|
||||||
|
'pacman': {
|
||||||
|
'services': {
|
||||||
|
'UNATTENDED UPGRADES': {
|
||||||
|
'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_unattended_upgrades',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,9 @@ nodes['aurto'] = {
|
||||||
'additional_config': {
|
'additional_config': {
|
||||||
'Include = /etc/pacman.d/aurto',
|
'Include = /etc/pacman.d/aurto',
|
||||||
},
|
},
|
||||||
|
'unattended-upgrades': {
|
||||||
|
'is_enabled': True,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'sudo': {
|
'sudo': {
|
||||||
'extra_configs': {
|
'extra_configs': {
|
||||||
|
|
Loading…
Reference in a new issue