Olivier Gayot has proposed merging ~ogayot/curtin:apt-pinning into curtin:master.
Requested reviews: curtin developers (curtin-dev) For more details, see: https://code.launchpad.net/~ogayot/curtin/+git/curtin/+merge/413788 Implement support for APT preferences in apt-config apt-config now supports a set of APT preferences (i.e. pinning rules) as in the following example: apt: preferences: - {package: "python3-*", pin: "origin *ubuntu.com*", pin-priority: 200} - {package: "python-*", pin: "origin *ubuntu.com*", pin-priority: -1} These preferences are deployed under <target>/etc/apt/preferences.d/90-curtin.pref using the format specified in apt_preferences(5). Package: python3-* Pin: origin *ubuntu.com* Pin-Priority: 200 Package: python-* Pin: origin *ubuntu.com* Pin-Priority: -1 If no preferences are configured, we drop the file 90-curtin.pref if it exists. -- Your team curtin developers is requested to review the proposed merge of ~ogayot/curtin:apt-pinning into curtin:master.
diff --git a/curtin/commands/apt_config.py b/curtin/commands/apt_config.py index 9ea2d30..be4a039 100644 --- a/curtin/commands/apt_config.py +++ b/curtin/commands/apt_config.py @@ -28,6 +28,9 @@ APT_LISTS = "/var/lib/apt/lists" APT_CONFIG_FN = "/etc/apt/apt.conf.d/94curtin-config" APT_PROXY_FN = "/etc/apt/apt.conf.d/90curtin-aptproxy" +# Files to store pinning information +APT_PREFERENCES_FN = "/etc/apt/preferences.d/90curtin.pref" + # Default keyserver to use DEFAULT_KEYSERVER = "keyserver.ubuntu.com" @@ -81,6 +84,11 @@ def handle_apt(cfg, target=None): except (IOError, OSError): LOG.exception("Failed to apply proxy or apt config info:") + try: + apply_apt_preferences(cfg, target + APT_PREFERENCES_FN) + except (IOError, OSError): + LOG.exception("Failed to apply apt preferences.") + # Process 'apt_source -> sources {dict}' if 'sources' in cfg: params = mirrors @@ -595,6 +603,36 @@ def apply_apt_proxy_config(cfg, proxy_fname, config_fname): LOG.debug("no apt config configured, removed %s", config_fname) +def preference_to_str(preference): + """ Return a textual representation of a given preference as specified in + apt_preferences(5). + """ + + return """\ +Package: {package} +Pin: {pin} +Pin-Priority: {pin_priority} +""".format(package=preference["package"], + pin=preference["pin"], + pin_priority=preference["pin-priority"]) + + +def apply_apt_preferences(cfg, pref_fname): + """ Apply apt preferences if any is provided. + """ + + prefs = cfg.get("preferences") + if not prefs: + if os.path.isfile(pref_fname): + util.del_file(pref_fname) + LOG.debug("no apt preferences configured, removed %s", pref_fname) + return + prefs_as_strings = [preference_to_str(pref) for pref in prefs] + print(prefs_as_strings) + LOG.debug("write apt preferences info to %s.", pref_fname) + util.write_file(pref_fname, "\n".join(prefs_as_strings)) + + def apt_command(args): """ Main entry point for curtin apt-config standalone command This does not read the global config as handled by curthooks, but diff --git a/doc/topics/apt_source.rst b/doc/topics/apt_source.rst index cf0f8bd..924ee80 100644 --- a/doc/topics/apt_source.rst +++ b/doc/topics/apt_source.rst @@ -31,6 +31,8 @@ Features - add arbitrary apt.conf settings + - add arbitrary apt preferences + - provide debconf configurations - disabling suites (=pockets) diff --git a/examples/apt-source.yaml b/examples/apt-source.yaml index f0f7108..e9543ae 100644 --- a/examples/apt-source.yaml +++ b/examples/apt-source.yaml @@ -152,6 +152,18 @@ apt: # The following example is also the builtin default if nothing is specified add_apt_repo_match: '^[\w-]+:\w' + # 1.9 preferences + # + # Any apt preferences that will be made available to apt + # see the APT_PREFERENCES(5) man page for details about what can be specified + preferences: + - package: python3-* + pin: origin *ubuntu.com* + pin-priority: 200 + - package: python-* + pin: origin *ubuntu.com* + pin-priority: -1 + ############################################################################## # Section 2: source list entries diff --git a/tests/unittests/test_apt_source.py b/tests/unittests/test_apt_source.py index 48fb820..267711f 100644 --- a/tests/unittests/test_apt_source.py +++ b/tests/unittests/test_apt_source.py @@ -572,6 +572,55 @@ class TestAptSourceConfig(CiTestCase): 'Acquire::ftp::Proxy "foobar3";\n' 'Acquire::https::Proxy "foobar4";\n')) + def test_preference_to_str(self): + """ test_preference_to_str - Test converting a preference dict to + textual representation. + """ + preference = { + "package": "*", + "pin": "release a=unstable", + "pin-priority": 50, + } + + expected = """\ +Package: * +Pin: release a=unstable +Pin-Priority: 50 +""" + self.assertEqual(expected, apt_config.preference_to_str(preference)) + + @staticmethod + def test_apply_apt_preferences(): + """ test_apply_apt_preferences - Test apt preferences configuration + """ + cfg = { + "preferences": [ + { + "package": "*", + "pin": "release a=unstable", + "pin-priority": 50, + }, { + "package": "dummy-unwanted-package", + "pin": "origin *ubuntu.com*", + "pin-priority": -1, + } + ] + } + + expected_content = """\ +Package: * +Pin: release a=unstable +Pin-Priority: 50 + +Package: dummy-unwanted-package +Pin: origin *ubuntu.com* +Pin-Priority: -1 +""" + with mock.patch.object(util, "write_file") as mockobj: + apt_config.apply_apt_preferences(cfg, "preferencesfn") + + mockobj.assert_called_with("preferencesfn", expected_content) + def test_mirror(self): """test_mirror - Test defining a mirror""" pmir = "http://us.archive.ubuntu.com/ubuntu/"
-- Mailing list: https://launchpad.net/~curtin-dev Post to : curtin-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~curtin-dev More help : https://help.launchpad.net/ListHelp