Merge ~ogayot/curtin:apt-pinning into curtin:master

Proposed by Olivier Gayot
Status: Merged
Approved by: Dan Bungert
Approved revision: 4a5bede1b0d8b09817c42c52b0027a2c4dbd4fa2
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~ogayot/curtin:apt-pinning
Merge into: curtin:master
Diff against target: 159 lines (+101/-0)
4 files modified
curtin/commands/apt_config.py (+38/-0)
doc/topics/apt_source.rst (+2/-0)
examples/apt-source.yaml (+12/-0)
tests/unittests/test_apt_source.py (+49/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Dan Bungert Approve
Review via email: mp+413788@code.launchpad.net

Commit message

Implement support for APT preferences in apt-config

Description of the change

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.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:fd826f643aea700409e517a18577131d4800bc72

No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want jenkins to rebuild you need to trigger it yourself):
https://code.launchpad.net/~ogayot/curtin/+git/curtin/+merge/413788/+edit-commit-message

https://jenkins.ubuntu.com/server/job/curtin-ci/220/
Executed test runs:
    SUCCESS: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-amd64/220/
    FAILURE: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-arm64/220/
    SUCCESS: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-ppc64el/220/
    SUCCESS: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-s390x/220/

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/curtin-ci/220//rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Dan Bungert (dbungert) :
Revision history for this message
Olivier Gayot (ogayot) :
Revision history for this message
Dan Bungert (dbungert) :
review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:4a5bede1b0d8b09817c42c52b0027a2c4dbd4fa2

No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want jenkins to rebuild you need to trigger it yourself):
https://code.launchpad.net/~ogayot/curtin/+git/curtin/+merge/413788/+edit-commit-message

https://jenkins.ubuntu.com/server/job/curtin-ci/223/
Executed test runs:
    SUCCESS: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-amd64/223/
    SUCCESS: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-arm64/223/
    SUCCESS: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-ppc64el/223/
    SUCCESS: https://jenkins.ubuntu.com/server/job/curtin-ci/nodes=metal-s390x/223/

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/curtin-ci/223//rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/curtin/commands/apt_config.py b/curtin/commands/apt_config.py
2index 9ea2d30..be4a039 100644
3--- a/curtin/commands/apt_config.py
4+++ b/curtin/commands/apt_config.py
5@@ -28,6 +28,9 @@ APT_LISTS = "/var/lib/apt/lists"
6 APT_CONFIG_FN = "/etc/apt/apt.conf.d/94curtin-config"
7 APT_PROXY_FN = "/etc/apt/apt.conf.d/90curtin-aptproxy"
8
9+# Files to store pinning information
10+APT_PREFERENCES_FN = "/etc/apt/preferences.d/90curtin.pref"
11+
12 # Default keyserver to use
13 DEFAULT_KEYSERVER = "keyserver.ubuntu.com"
14
15@@ -81,6 +84,11 @@ def handle_apt(cfg, target=None):
16 except (IOError, OSError):
17 LOG.exception("Failed to apply proxy or apt config info:")
18
19+ try:
20+ apply_apt_preferences(cfg, target + APT_PREFERENCES_FN)
21+ except (IOError, OSError):
22+ LOG.exception("Failed to apply apt preferences.")
23+
24 # Process 'apt_source -> sources {dict}'
25 if 'sources' in cfg:
26 params = mirrors
27@@ -595,6 +603,36 @@ def apply_apt_proxy_config(cfg, proxy_fname, config_fname):
28 LOG.debug("no apt config configured, removed %s", config_fname)
29
30
31+def preference_to_str(preference):
32+ """ Return a textual representation of a given preference as specified in
33+ apt_preferences(5).
34+ """
35+
36+ return """\
37+Package: {package}
38+Pin: {pin}
39+Pin-Priority: {pin_priority}
40+""".format(package=preference["package"],
41+ pin=preference["pin"],
42+ pin_priority=preference["pin-priority"])
43+
44+
45+def apply_apt_preferences(cfg, pref_fname):
46+ """ Apply apt preferences if any is provided.
47+ """
48+
49+ prefs = cfg.get("preferences")
50+ if not prefs:
51+ if os.path.isfile(pref_fname):
52+ util.del_file(pref_fname)
53+ LOG.debug("no apt preferences configured, removed %s", pref_fname)
54+ return
55+ prefs_as_strings = [preference_to_str(pref) for pref in prefs]
56+ print(prefs_as_strings)
57+ LOG.debug("write apt preferences info to %s.", pref_fname)
58+ util.write_file(pref_fname, "\n".join(prefs_as_strings))
59+
60+
61 def apt_command(args):
62 """ Main entry point for curtin apt-config standalone command
63 This does not read the global config as handled by curthooks, but
64diff --git a/doc/topics/apt_source.rst b/doc/topics/apt_source.rst
65index cf0f8bd..924ee80 100644
66--- a/doc/topics/apt_source.rst
67+++ b/doc/topics/apt_source.rst
68@@ -31,6 +31,8 @@ Features
69
70 - add arbitrary apt.conf settings
71
72+ - add arbitrary apt preferences
73+
74 - provide debconf configurations
75
76 - disabling suites (=pockets)
77diff --git a/examples/apt-source.yaml b/examples/apt-source.yaml
78index f0f7108..e9543ae 100644
79--- a/examples/apt-source.yaml
80+++ b/examples/apt-source.yaml
81@@ -152,6 +152,18 @@ apt:
82 # The following example is also the builtin default if nothing is specified
83 add_apt_repo_match: '^[\w-]+:\w'
84
85+ # 1.9 preferences
86+ #
87+ # Any apt preferences that will be made available to apt
88+ # see the APT_PREFERENCES(5) man page for details about what can be specified
89+ preferences:
90+ - package: python3-*
91+ pin: origin *ubuntu.com*
92+ pin-priority: 200
93+ - package: python-*
94+ pin: origin *ubuntu.com*
95+ pin-priority: -1
96+
97
98 ##############################################################################
99 # Section 2: source list entries
100diff --git a/tests/unittests/test_apt_source.py b/tests/unittests/test_apt_source.py
101index 48fb820..267711f 100644
102--- a/tests/unittests/test_apt_source.py
103+++ b/tests/unittests/test_apt_source.py
104@@ -572,6 +572,55 @@ class TestAptSourceConfig(CiTestCase):
105 'Acquire::ftp::Proxy "foobar3";\n'
106 'Acquire::https::Proxy "foobar4";\n'))
107
108+ def test_preference_to_str(self):
109+ """ test_preference_to_str - Test converting a preference dict to
110+ textual representation.
111+ """
112+ preference = {
113+ "package": "*",
114+ "pin": "release a=unstable",
115+ "pin-priority": 50,
116+ }
117+
118+ expected = """\
119+Package: *
120+Pin: release a=unstable
121+Pin-Priority: 50
122+"""
123+ self.assertEqual(expected, apt_config.preference_to_str(preference))
124+
125+ @staticmethod
126+ def test_apply_apt_preferences():
127+ """ test_apply_apt_preferences - Test apt preferences configuration
128+ """
129+ cfg = {
130+ "preferences": [
131+ {
132+ "package": "*",
133+ "pin": "release a=unstable",
134+ "pin-priority": 50,
135+ }, {
136+ "package": "dummy-unwanted-package",
137+ "pin": "origin *ubuntu.com*",
138+ "pin-priority": -1,
139+ }
140+ ]
141+ }
142+
143+ expected_content = """\
144+Package: *
145+Pin: release a=unstable
146+Pin-Priority: 50
147+
148+Package: dummy-unwanted-package
149+Pin: origin *ubuntu.com*
150+Pin-Priority: -1
151+"""
152+ with mock.patch.object(util, "write_file") as mockobj:
153+ apt_config.apply_apt_preferences(cfg, "preferencesfn")
154+
155+ mockobj.assert_called_with("preferencesfn", expected_content)
156+
157 def test_mirror(self):
158 """test_mirror - Test defining a mirror"""
159 pmir = "http://us.archive.ubuntu.com/ubuntu/"

Subscribers

People subscribed via source and target branches