bundles/apt: support spreading unattended-upgrades in a group

This commit is contained in:
Franzi 2023-05-20 07:46:23 +02:00
parent 92cca7f396
commit 048fb83ee7
Signed by: kunsi
GPG key ID: 12E3D2136B818350
5 changed files with 81 additions and 24 deletions

View file

@ -24,13 +24,18 @@ def patchday(metadata):
day = metadata.get('apt/unattended-upgrades/day')
hour = metadata.get('apt/unattended-upgrades/hour')
spread = metadata.get('apt/unattended-upgrades/spread_in_group', None)
if spread is not None:
spread_nodes = sorted(repo.nodes_in_group(spread))
day += spread_nodes.index(node)
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,
day=day%7,
),
},
},

View file

@ -1,31 +1,18 @@
% for monitored_node in sorted(repo.nodes):
<%
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)
)
) and not monitored_node.metadata.get('icinga_options/exclude_from_monitoring', False)
%>\
% if auto_updates_enabled:
object ScheduledDowntime "unattended_upgrades" {
host_name = "${monitored_node.name}"
% for dt in downtimes:
object ScheduledDowntime "${dt['name']}" {
host_name = "${dt['host']}"
author = "unattended-upgrades"
comment = "Downtime for upgrade-and-reboot of node ${monitored_node.name}"
author = "${dt['name']}"
comment = "${dt['comment']}"
fixed = true
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}"
% endif
% for d,t in dt['times'].items():
"${d}" = "${t}"
% endfor
}
child_options = "DowntimeTriggeredChildren"
}
% endif
% endfor

View file

@ -346,7 +346,8 @@ svc_systemd = {
# The actual hosts and services management starts here
bundles = set()
for rnode in repo.nodes:
downtimes = []
for rnode in sorted(repo.nodes):
if rnode.metadata.get('icinga_options/exclude_from_monitoring', False):
continue
@ -388,6 +389,41 @@ for rnode in repo.nodes:
bundles |= set(rnode.metadata.get('icinga2_api', {}).keys())
if rnode.has_any_bundle(['apt', 'c3voc-addons']):
day = rnode.metadata.get('apt/unattended-upgrades/day')
hour = rnode.metadata.get('apt/unattended-upgrades/hour')
minute = rnode.magic_number%30
spread = rnode.metadata.get('apt/unattended-upgrades/spread_in_group', None)
if spread is not None:
spread_nodes = sorted(repo.nodes_in_group(spread))
day += spread_nodes.index(rnode)
downtimes.append({
'name': 'unattended-upgrades',
'host': rnode.name,
'comment': f'Downtime for upgrade-and-reboot of node {rnode.name}',
'times': {
DAYS_TO_STRING[day%7]: f'{hour}:{minute}-{hour}:{minute+30}',
},
})
elif (
rnode.has_bundle('pacman')
and rnode.metadata.get('pacman/unattended-upgrades/is_enabled', False)
):
day = rnode.metadata.get('pacman/unattended-upgrades/day')
hour = rnode.metadata.get('pacman/unattended-upgrades/hour')
minute = rnode.magic_number%30
downtimes.append({
'name': 'unattended-upgrades',
'host': rnode.name,
'comment': f'Downtime for upgrade-and-reboot of node {rnode.name}',
'times': {
DAYS_TO_STRING[day%7]: f'{hour}:{minute}-{hour}:{minute+30}',
},
})
files['/etc/icinga2/conf.d/groups.conf'] = {
'source': 'icinga2/groups.conf',
'content_type': 'mako',
@ -408,7 +444,7 @@ files['/etc/icinga2/conf.d/downtimes.conf'] = {
'source': 'icinga2/downtimes.conf',
'content_type': 'mako',
'context': {
'days': DAYS_TO_STRING,
'downtimes': downtimes,
},
'owner': 'nagios',
'group': 'nagios',

View file

@ -11,6 +11,11 @@ groups['dns'] = {
'powerdns',
},
'metadata': {
'apt': {
'unattended-upgrades': {
'spread_in_group': 'dns',
},
},
'powerdns': {
# Overridden in node metadata for primary server
'is_secondary': True,

View file

@ -0,0 +1,24 @@
from bundlewrap.exceptions import BundleError
from bundlewrap.utils.text import bold, green, yellow
from bundlewrap.utils.ui import io
def test(repo, **kwargs):
for node in repo.nodes:
if not node.has_bundle('apt'):
continue
spread = node.metadata.get('apt/unattended-upgrades/spread_in_group', None)
if spread is None:
continue
for rnode in repo.nodes_in_group(spread):
rspread = rnode.metadata.get('apt/unattended-upgrades/spread_in_group', None)
if spread != rspread:
raise BundleError(f'{node.name} sets apt/unattended-upgrades/spread_in_group to "{spread}", but node {rnode.name} in that group does set "{rspread}"!')
io.stdout('{x} {node} apt/unattended-upgrades/spread_in_group matches'.format(
x=green(""),
node=bold(node.name),
))