1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
From: Bastian Blank <waldi@debian.org>
Date: Tue, 16 Aug 2022 15:45:11 +0200
Subject: [PATCH] config: Support APT automated mirror selection
From 8dffe8af24604e1949cc991c1db181a69695d945 Mon Sep 17 00:00:00 2001
Forwarded: https://github.com/canonical/cloud-init/pull/1670
---
cloudinit/config/cc_apt_configure.py | 22 ++++++-
.../config/schemas/schema-cloud-config-v1.json | 5 ++
.../config/test_apt_configure_mirrorlists_v3.py | 69 ++++++++++++++++++++++
3 files changed, 95 insertions(+), 1 deletion(-)
create mode 100644 tests/unittests/config/test_apt_configure_mirrorlists_v3.py
Index: cloud-init/cloudinit/config/cc_apt_configure.py
===================================================================
--- cloud-init.orig/cloudinit/config/cc_apt_configure.py
+++ cloud-init/cloudinit/config/cc_apt_configure.py
@@ -146,7 +146,10 @@ def apply_apt(cfg, cloud, gpg):
matcher = re.compile(matchcfg).search
_ensure_dependencies(cfg, matcher, cloud)
- if util.is_false(cfg.get("preserve_sources_list", False)):
+ if util.is_true(cfg.get("generate_mirrorlists", False)):
+ generate_mirrorlists(cfg, mirrors, cloud)
+
+ elif util.is_false(cfg.get("preserve_sources_list", False)):
keys = add_mirror_keys(cfg, cloud, gpg)
generate_sources_list(cfg, release, mirrors, cloud, keys)
rename_apt_lists(mirrors, arch)
@@ -590,6 +593,23 @@ def generate_sources_list(cfg, release,
util.del_file(apt_sources_list)
+def generate_mirrorlists(cfg, mirrors, cloud):
+ """generate_mirrorlists
+ create one file for every mirror for apt-transport-mirror(1)"""
+ aptmir = pathlib.Path("/etc/apt/mirrors")
+ util.ensure_dir(str(aptmir))
+ util.write_file(
+ str(aptmir / f"{cloud.distro.name}.list"),
+ f"{mirrors['PRIMARY']}\n",
+ mode=0o644,
+ )
+ util.write_file(
+ str(aptmir / f"{cloud.distro.name}-security.list"),
+ f"{mirrors['SECURITY']}\n",
+ mode=0o644,
+ )
+
+
def add_apt_key_raw(key, file_name, gpg, hardened=False):
"""
actual adding of a key as defined in key argument
Index: cloud-init/cloudinit/config/schemas/schema-cloud-config-v1.json
===================================================================
--- cloud-init.orig/cloudinit/config/schemas/schema-cloud-config-v1.json
+++ cloud-init/cloudinit/config/schemas/schema-cloud-config-v1.json
@@ -1054,6 +1054,11 @@
"default": false,
"description": "By default, cloud-init will generate a new sources list in ``/etc/apt/sources.list.d`` based on any changes specified in cloud config. To disable this behavior and preserve the sources list from the pristine image, set **preserve_sources_list** to ``true``.\n\nThe **preserve_sources_list** option overrides all other config keys that would alter ``sources.list`` or ``sources.list.d``, **except** for additional sources to be added to ``sources.list.d``."
},
+ "generate_mirrorlists": {
+ "type": "boolean",
+ "default": false,
+ "description": "Write lists for APT automated mirror selection (``apt-transport-mirror(1)``). It will write separate lists for both the PRIMARY and SECURITY mirror into ``/etc/apt/mirrors/${DIST}.list`` and ``/etc/apt/mirrors/${DIST}-security.list``. Those can then be used in the APT source.list as ``mirror+file:///etc/apt/mirrors/${DIST}.list``. No ``/etc/apt/sources.list`` will be writte in this case."
+ },
"disable_suites": {
"type": "array",
"items": {
Index: cloud-init/tests/unittests/config/test_apt_configure_mirrorlists_v3.py
===================================================================
--- /dev/null
+++ cloud-init/tests/unittests/config/test_apt_configure_mirrorlists_v3.py
@@ -0,0 +1,80 @@
+# This file is part of cloud-init. See LICENSE file for license information.
+
+""" test_apt_custom_mirrorlists
+Test generation of apt mirror lists
+"""
+import logging
+import shutil
+import tempfile
+from contextlib import ExitStack
+from unittest import mock
+
+import pytest
+
+from cloudinit import subp, util
+from cloudinit.config import cc_apt_configure
+from tests.unittests import helpers as t_help
+from tests.unittests.util import get_cloud
+
+LOG = logging.getLogger(__name__)
+
+@pytest.fixture
+def mock_lsb_release():
+ """Fixture to mock lsb_release"""
+ with mock.patch("cloudinit.util.lsb_release") as mock_lsr:
+ mock_lsr.return_value = {"codename": "fakerel"}
+ yield mock_lsr
+
+@pytest.fixture
+def mock_dpkg_arch():
+ """Fixture to mock get_dpkg_architecture"""
+ with mock.patch("cloudinit.util.get_dpkg_architecture") as mock_arch:
+ mock_arch.return_value = "amd64"
+ yield mock_arch
+
+@pytest.fixture
+def temp_root():
+ """Fixture to create and clean up a temporary directory"""
+ root_dir = tempfile.mkdtemp()
+ try:
+ yield root_dir
+ finally:
+ shutil.rmtree(root_dir)
+
+def test_apt_v3_mirrors_list(mock_lsb_release, mock_dpkg_arch, temp_root):
+ """Test generation of mirrorlists"""
+ # Configuration for apt mirror list generation
+ cfg = {"apt": {"generate_mirrorlists": True}}
+
+ # Get cloud instance
+ mycloud = get_cloud("ubuntu")
+
+ # Use ExitStack to manage multiple context managers
+ with ExitStack() as stack:
+ # Mock write_file and ensure_dir
+ mock_writefile = stack.enter_context(
+ mock.patch.object(util, "write_file")
+ )
+ stack.enter_context(mock.patch.object(util, "ensure_dir"))
+
+ # Call the apt configuration handler
+ cc_apt_configure.handle("test", cfg, mycloud, None)
+
+ # Assert that write_file was called with expected arguments
+ assert mock_writefile.call_count == 2
+
+ # Check the specific calls to write_file
+ mock_writefile.assert_has_calls([
+ mock.call(
+ "/etc/apt/mirrors/ubuntu.list",
+ "http://archive.ubuntu.com/ubuntu/\n",
+ mode=0o644,
+ ),
+ mock.call(
+ "/etc/apt/mirrors/ubuntu-security.list",
+ "http://security.ubuntu.com/ubuntu/\n",
+ mode=0o644,
+ )
+ ], any_order=True)
+
+# vi: ts=4 expandtab
|