Skip to content

Commit

Permalink
Merge pull request #5855 from freedomofpress/adjust-apt-timers-and-more
Browse files Browse the repository at this point in the history
Makes unattended-upgrades sequencing more similar to cron-apt
  • Loading branch information
emkll authored Mar 9, 2021
2 parents d26125e + 74fadb8 commit 98ebab8
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 36 deletions.
20 changes: 16 additions & 4 deletions install_files/ansible-base/roles/common/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
---
# Set the time at which the servers reboot to apply nightly updates
# and aid in clearing memory. Only the hour is configurable.
daily_reboot_time: 4 # An integer between 0 and 23

disabled_kernel_modules:
- btusb
- bluetooth
Expand Down Expand Up @@ -53,3 +49,19 @@ unused_packages:
- wireless-tools
- wpasupplicant
- snapd

# Template declaration for setting the upgrade time to a predictable time,
# matching the 'daily_reboot_time' time via sdconfig.
unattended_upgrades_timer_overrides:
- src: apt-daily-timer-override.j2
dest: /etc/systemd/system/apt-daily.timer.d/override.conf
- src: apt-daily-upgrade-timer-override.j2
dest: /etc/systemd/system/apt-daily-upgrade.timer.d/override.conf

# Set the time at which the servers reboot to apply nightly updates
# and aid in clearing memory. Only the hour is configurable, via sdconfig.
# The other options are for unattended-upgrades, when to run
# 'apt-get update' and 'apt-get upgrade'.
daily_reboot_time: 4 # An integer between 0 and 23
daily_update_time: "{{ (daily_reboot_time|int - 2) % 24 }}"
daily_upgrade_time: "{{ (daily_reboot_time|int - 1) % 24 }}"
4 changes: 4 additions & 0 deletions install_files/ansible-base/roles/common/handlers/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@
- name: update apt cache
apt:
update_cache: yes

- name: systemd daemon-reload
systemd:
daemon_reload: yes
1 change: 1 addition & 0 deletions install_files/ansible-base/roles/common/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
when:
- ansible_distribution_release == "focal"
tags:
- ua
- reboot

- include: remove_unused_packages.yml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
# Configuration for unattended upgrades is almost exclusively managed by the
# securedrop-config package under Focal.

- name: Create override dirs for apt-daily timers
file:
state: directory
mode: "0755"
path: "{{ item.dest|dirname }}"
with_items: "{{ unattended_upgrades_timer_overrides }}"

- name: Add overrides for apt-daily timers
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "0644"
notify: systemd daemon-reload
with_items: "{{ unattended_upgrades_timer_overrides }}"

# Ensure daemon-reload has happened before starting/enabling
- meta: flush_handlers

- name: Ensure apt-daily and apt-daily-upgrade services are unmasked, started and enabled.
systemd:
name: "{{ item }}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// time instead of immediately
// Default: "now"
Unattended-Upgrade::Automatic-Reboot-Time "{{ daily_reboot_time }}:00";
APT::Periodic::Enable "1";
{% endif %}
// Don't install packages from "Recommends" field, we'll manage dependencies
// explicitly to avoid pulling in packages from e.g. universe.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Timer]
OnCalendar=
OnCalendar=*-*-* {{ daily_update_time }}:00
RandomizedDelaySec=20m
Persistent=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Timer]
OnCalendar=
OnCalendar=*-*-* {{ daily_upgrade_time }}:00
RandomizedDelaySec=20m
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,7 @@ Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
// Here we set the dpkg options to force the old conffile if it's already present
// or force the default config if no config is present
// see https://github.com/freedomofpress/securedrop/pull/911
Dpkg::Options "force-confdef";
Dpkg::Options "force-confold";
Dpkg::Options {
"--force-confdef";
"--force-confold";
}
91 changes: 61 additions & 30 deletions molecule/testinfra/common/test_automatic_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,18 +187,46 @@ def test_cron_apt_cron_jobs(host, cron_job):
assert not f.exists


def test_unattended_upgrades_config(host):
apt_config_options = {
"APT::Install-Recommends": "false",
"Dpkg::Options": [
"--force-confold",
"--force-confdef",
],
"APT::Periodic::Update-Package-Lists": "1",
"APT::Periodic::Unattended-Upgrade": "1",
"APT::Periodic::AutocleanInterval": "1",
"APT::Periodic::Enable": "1",
"Unattended-Upgrade::AutoFixInterruptedDpkg": "true",
"Unattended-Upgrade::Automatic-Reboot": "true",
"Unattended-Upgrade::Automatic-Reboot-Time": "4:00",
"Unattended-Upgrade::Automatic-Reboot-WithUsers": "true",
"Unattended-Upgrade::Origins-Pattern": [
"origin=${distro_id},archive=${distro_codename}",
"origin=${distro_id},archive=${distro_codename}-security",
"origin=${distro_id},archive=${distro_codename}-updates",
"origin=SecureDrop,codename=${distro_codename}",
],
}


@pytest.mark.parametrize("k, v", apt_config_options.items())
def test_unattended_upgrades_config(host, k, v):
"""
Ensures the apt and unattended-upgrades config is correct only under Ubuntu Focal
"""
Ensures the 50unattended-upgrades config is correct only under Ubuntu Focal
"""
f = host.file('/etc/apt/apt.conf.d/50unattended-upgrades')
if host.system_info.codename != "xenial":
assert f.is_file
assert f.user == "root"
assert f.mode == 0o644
assert f.contains("origin=SecureDrop,codename=${distro_codename}")
assert f.contains('Dpkg::Options "force-confold";')
assert f.contains('Dpkg::Options "force-confdef";')
if host.system_info.codename == "xenial":
return True
# Dump apt config to inspect end state, apt will build config
# from all conf files on disk, e.g. 80securedrop.
c = host.run("apt-config dump --format '%v%n' {}".format(k))
assert c.rc == 0
# Some values are lists, so support that in the params
if hasattr(v, "__getitem__"):
for i in v:
assert i in c.stdout
else:
assert v in c.stdout


def test_unattended_securedrop_specific(host):
Expand All @@ -218,25 +246,6 @@ def test_unattended_securedrop_specific(host):
assert not f.contains("Automatic-Reboot-Time")


@pytest.mark.parametrize('option', [
'APT::Periodic::Update-Package-Lists "1";',
'APT::Periodic::Unattended-Upgrade "1";',
'APT::Periodic::AutocleanInterval "1";',
])
def test_auto_upgrades_config(host, option):
"""
Ensures the 20auto-upgrades config is correct only under Ubuntu Focal
"""
f = host.file('/etc/apt/apt.conf.d/20auto-upgrades')
if host.system_info.codename == "xenial":
assert not f.exists
else:
assert f.is_file
assert f.user == "root"
assert f.mode == 0o644
assert f.contains('^{}$'.format(option))


def test_unattended_upgrades_functional(host):
"""
Ensure unatteded-upgrades completes successfully and ensures all packages
Expand Down Expand Up @@ -275,6 +284,28 @@ def test_apt_daily_services_and_timers_enabled(host, service):
assert s.is_enabled


def test_apt_daily_timer_schedule(host):
"""
Timer for running apt-daily, i.e. 'apt-get update', should be 2h
before the daily_reboot_time.
"""
if host.system_info.codename != "xenial":
c = host.run("systemctl show apt-daily.timer")
assert "TimersCalendar={ OnCalendar=*-*-* 02:00:00 ;" in c.stdout
assert "RandomizedDelayUSec=20m" in c.stdout


def test_apt_daily_upgrade_timer_schedule(host):
"""
Timer for running apt-daily-upgrade, i.e. 'apt-get upgrade', should be 1h
before the daily_reboot_time, and 1h after the apt-daily time.
"""
if host.system_info.codename != "xenial":
c = host.run("systemctl show apt-daily-upgrade.timer")
assert "TimersCalendar={ OnCalendar=*-*-* 03:00:00 ;" in c.stdout
assert "RandomizedDelayUSec=20m" in c.stdout


def test_reboot_required_cron(host):
"""
Unatteded-upgrades does not reboot the system if the updates don't require it.
Expand Down

0 comments on commit 98ebab8

Please sign in to comment.