Merge lp:~apw/ubuntu-archive-tools/copy-proposed-kernels-routing-updates into lp:ubuntu-archive-tools
- copy-proposed-kernels-routing-updates
- Merge into trunk
Status: | Merged |
---|---|
Merge reported by: | Andy Whitcroft |
Merged at revision: | not available |
Proposed branch: | lp:~apw/ubuntu-archive-tools/copy-proposed-kernels-routing-updates |
Merge into: | lp:ubuntu-archive-tools |
Diff against target: |
381 lines (+303/-32) 1 file modified
copy-proposed-kernel (+303/-32) |
To merge this branch: | bzr merge lp:~apw/ubuntu-archive-tools/copy-proposed-kernels-routing-updates |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Steve Langasek | Approve | ||
Review via email: mp+365420@code.launchpad.net |
Commit message
Update to support full routing for the linux-fips and linux-ibm-gt kernels. Also brings routing for the split copy from build-ppa -> signing-ppa -> proposed for ESM and FIPS. By default copy-proposed-
This fits with deployed changes to the kernel workflow manager which changes the meaning of promote-to-proposed to mean "do the AA review and move to the next step", and adds promote-
Description of the change
Andy Whitcroft (apw) : | # |
Andy Whitcroft (apw) wrote : | # |
Ok updated version pushed which covers the easily fixable things.
Steve Langasek (vorlon) : | # |
Steve Langasek (vorlon) : | # |
- 1212. By Andy Whitcroft
-
copy-proposed-
kernel: add support for routing via signing PPAs Update to support full routing for the linux-fips and linux-ibm-gt
kernels. Also brings routing for the split copy from build-ppa ->
signing-ppa -> proposed for ESM and FIPS. By default copy-proposed-kernel
will copy from the build-ppa to the next step; either proposed or signing
as needed. The second copy is triggered (once built in the signing PPA)
via a second copy-proposed-kernel --from-signing pass. This fits with deployed changes to the kernel workflow manager which
changes the meaning of promote-to-proposed to mean "do the AA review and
move to the next step", and adds promote-signing- to-proposed to request
the second copy. It monitors builds in the signing PPAs.Signed-off-by: Andy Whitcroft <email address hidden>
Preview Diff
1 | === modified file 'copy-proposed-kernel' |
2 | --- copy-proposed-kernel 2018-08-14 08:31:43 +0000 |
3 | +++ copy-proposed-kernel 2019-04-03 20:06:41 +0000 |
4 | @@ -24,47 +24,310 @@ |
5 | from __future__ import print_function |
6 | |
7 | import argparse |
8 | +from contextlib import contextmanager |
9 | +from copy import copy |
10 | +from StringIO import StringIO |
11 | import sys |
12 | +import unittest |
13 | |
14 | from launchpadlib.launchpad import Launchpad |
15 | |
16 | |
17 | +class TestBase(unittest.TestCase): |
18 | + class FakeArgs: |
19 | + def __init__(self, **kwargs): |
20 | + self.series = None |
21 | + self.source = None |
22 | + self.security = False |
23 | + self.security2 = False |
24 | + self.esm = False |
25 | + self.fips = False |
26 | + self.ibmgt = False |
27 | + self.to_signing = False |
28 | + self.from_signing = False |
29 | + |
30 | + self.update(**kwargs) |
31 | + |
32 | + def update(self, **kwargs): |
33 | + for (key, value) in kwargs.items(): |
34 | + setattr(self, key, value) |
35 | + return self |
36 | + |
37 | + @contextmanager |
38 | + def capture(self): |
39 | + new_out, new_err = StringIO(), StringIO() |
40 | + old_out, old_err = sys.stdout, sys.stderr |
41 | + try: |
42 | + sys.stdout, sys.stderr = new_out, new_err |
43 | + yield sys.stdout, sys.stderr |
44 | + finally: |
45 | + sys.stdout, sys.stderr = old_out, old_err |
46 | + |
47 | + |
48 | +class TestRouting(TestBase): |
49 | + def test_default(self): |
50 | + expected = ('~canonical-kernel-team/ubuntu/ppa', 'ubuntu', False) |
51 | + result = routing(self.FakeArgs()) |
52 | + self.assertEqual(expected, result) |
53 | + |
54 | + def test_security(self): |
55 | + expected = ('~canonical-kernel-security-team/ubuntu/ppa', 'ubuntu', True) |
56 | + result = routing(self.FakeArgs(security=True)) |
57 | + self.assertEqual(expected, result) |
58 | + |
59 | + def test_security2(self): |
60 | + expected = ('~canonical-kernel-security-team/ubuntu/ppa2', 'ubuntu', True) |
61 | + result = routing(self.FakeArgs(security2=True)) |
62 | + self.assertEqual(expected, result) |
63 | + |
64 | + def test_to_signing(self): |
65 | + expected = ('~canonical-kernel-team/ubuntu/ppa', None, False) |
66 | + result = routing(self.FakeArgs(to_signing=True)) |
67 | + self.assertEqual(expected, result) |
68 | + |
69 | + def test_from_signing(self): |
70 | + expected = (None, 'ubuntu', False) |
71 | + result = routing(self.FakeArgs(from_signing=True)) |
72 | + self.assertEqual(expected, result) |
73 | + |
74 | + def test_esm(self): |
75 | + expected = ('~canonical-kernel-esm/ubuntu/ppa', '~canonical-kernel-esm/ubuntu/proposed', False) |
76 | + result = routing(self.FakeArgs(esm=True)) |
77 | + self.assertEqual(expected, result) |
78 | + |
79 | + def test_esm_security(self): |
80 | + expected = ('~canonical-kernel-security-team/ubuntu/esm', '~canonical-kernel-esm/ubuntu/proposed', False) |
81 | + result = routing(self.FakeArgs(esm=True, security=True)) |
82 | + self.assertEqual(expected, result) |
83 | + |
84 | + def test_esm_security2(self): |
85 | + expected = (None, '~canonical-kernel-esm/ubuntu/proposed', False) |
86 | + result = routing(self.FakeArgs(esm=True, security2=True)) |
87 | + self.assertEqual(expected, result) |
88 | + |
89 | + def test_esm_to_signing(self): |
90 | + expected = ('~canonical-kernel-esm/ubuntu/ppa', '~canonical-signing/ubuntu/esm', False) |
91 | + result = routing(self.FakeArgs(esm=True, to_signing=True)) |
92 | + self.assertEqual(expected, result) |
93 | + |
94 | + def test_esm_from_signing(self): |
95 | + expected = ('~canonical-signing/ubuntu/esm', '~canonical-kernel-esm/ubuntu/proposed', False) |
96 | + result = routing(self.FakeArgs(esm=True, from_signing=True)) |
97 | + self.assertEqual(expected, result) |
98 | + |
99 | + # Autorouting will enable to_signing, the user will then want to switch us |
100 | + # to from_signing in order to perform phase two copies. To ensure this is |
101 | + # simple we make from_signing take presidence over to_signing. Test this |
102 | + # is honoured correctly. |
103 | + def test_esm_from_signing_override_to_signing(self): |
104 | + expected = ('~canonical-signing/ubuntu/esm', '~canonical-kernel-esm/ubuntu/proposed', False) |
105 | + result = routing(self.FakeArgs(esm=True, to_signing=True, from_signing=True)) |
106 | + self.assertEqual(expected, result) |
107 | + |
108 | + def test_fips(self): |
109 | + expected = ('~ubuntu-advantage/ubuntu/fips-kernel-source', '~ubuntu-advantage/ubuntu/fips-proposed', False) |
110 | + result = routing(self.FakeArgs(fips=True)) |
111 | + self.assertEqual(expected, result) |
112 | + |
113 | + def test_fips_security(self): |
114 | + expected = ('~canonical-kernel-security-team/ubuntu/ppa', '~ubuntu-advantage/ubuntu/fips-proposed', False) |
115 | + result = routing(self.FakeArgs(fips=True, security=True)) |
116 | + self.assertEqual(expected, result) |
117 | + |
118 | + def test_fips_security2(self): |
119 | + expected = ('~canonical-kernel-security-team/ubuntu/ppa2', '~ubuntu-advantage/ubuntu/fips-proposed', False) |
120 | + result = routing(self.FakeArgs(fips=True, security2=True)) |
121 | + self.assertEqual(expected, result) |
122 | + |
123 | + def test_fips_to_signing(self): |
124 | + expected = ('~ubuntu-advantage/ubuntu/fips-kernel-source', '~canonical-signing/ubuntu/fips', False) |
125 | + result = routing(self.FakeArgs(fips=True, to_signing=True)) |
126 | + self.assertEqual(expected, result) |
127 | + |
128 | + def test_fips_from_signing(self): |
129 | + expected = ('~canonical-signing/ubuntu/fips', '~ubuntu-advantage/ubuntu/fips-proposed', False) |
130 | + result = routing(self.FakeArgs(fips=True, from_signing=True)) |
131 | + self.assertEqual(expected, result) |
132 | + |
133 | + def test_ibmgt(self): |
134 | + expected = ('~ibm-cloud/ubuntu/build', '~ibm-cloud/ubuntu/proposed', False) |
135 | + result = routing(self.FakeArgs(ibmgt=True)) |
136 | + self.assertEqual(expected, result) |
137 | + |
138 | + def test_ibmgt_security(self): |
139 | + expected = ('~canonical-kernel-security-team/ubuntu/ppa', '~ibm-cloud/ubuntu/proposed', False) |
140 | + result = routing(self.FakeArgs(ibmgt=True, security=True)) |
141 | + self.assertEqual(expected, result) |
142 | + |
143 | + def test_ibmgt_security2(self): |
144 | + expected = ('~canonical-kernel-security-team/ubuntu/ppa2', '~ibm-cloud/ubuntu/proposed', False) |
145 | + result = routing(self.FakeArgs(ibmgt=True, security2=True)) |
146 | + self.assertEqual(expected, result) |
147 | + |
148 | + |
149 | +def routing(args): |
150 | + unembargo = False |
151 | + |
152 | + # Default routing. |
153 | + security_name = ( |
154 | + '~canonical-kernel-security-team/ubuntu/ppa', |
155 | + '~canonical-kernel-security-team/ubuntu/ppa2', |
156 | + ) |
157 | + signing = None |
158 | + |
159 | + # ESM specific routing |
160 | + if args.esm: |
161 | + ppa_name = '~canonical-kernel-esm/ubuntu/ppa' |
162 | + to = '~canonical-kernel-esm/ubuntu/proposed' |
163 | + signing = '~canonical-signing/ubuntu/esm' |
164 | + security_name = ( |
165 | + '~canonical-kernel-security-team/ubuntu/esm', |
166 | + None, |
167 | + ) |
168 | + |
169 | + # FIPS specific routing |
170 | + elif args.fips: |
171 | + ppa_name = '~ubuntu-advantage/ubuntu/fips-kernel-source' |
172 | + to = '~ubuntu-advantage/ubuntu/fips-proposed' |
173 | + signing = '~canonical-signing/ubuntu/fips' |
174 | + |
175 | + # IBMGT specific routing |
176 | + elif args.ibmgt: |
177 | + ppa_name = '~ibm-cloud/ubuntu/build' |
178 | + to = '~ibm-cloud/ubuntu/proposed' |
179 | + |
180 | + # Default routing. |
181 | + else: |
182 | + ppa_name = '~canonical-kernel-team/ubuntu/ppa' |
183 | + to = 'ubuntu' |
184 | + if args.security or args.security2: |
185 | + # Allow us to unembargo when releasing from security to ubuntu. |
186 | + unembargo = True |
187 | + |
188 | + # Handle security routing. |
189 | + if args.security: |
190 | + ppa_name = security_name[0] |
191 | + elif args.security2: |
192 | + ppa_name = security_name[1] |
193 | + |
194 | + # Handle signing routing. |
195 | + if args.from_signing: |
196 | + ppa_name = signing |
197 | + elif args.to_signing: |
198 | + to = signing |
199 | + |
200 | + return (ppa_name, to, unembargo) |
201 | + |
202 | +class TestAutoRoute(TestBase): |
203 | + def test_default(self): |
204 | + results = self.FakeArgs(series='bionic', source='linux') |
205 | + expected = copy(results).update() |
206 | + with self.capture() as (out, err): |
207 | + auto_route(results) |
208 | + self.assertEqual(expected.__dict__, results.__dict__) |
209 | + self.assertEqual('', out.getvalue().strip()) |
210 | + |
211 | + def test_esm_precise_linux(self): |
212 | + results = self.FakeArgs(series='precise', source='linux') |
213 | + expected = copy(results).update(esm=True) |
214 | + with self.capture() as (out, err): |
215 | + auto_route(results) |
216 | + self.assertEqual(expected.__dict__, results.__dict__) |
217 | + self.assertIn('from and to ESM', out.getvalue().strip()) |
218 | + self.assertNotIn('via signing', out.getvalue().strip()) |
219 | + |
220 | + def test_esm_precise_linux_lts_trusty(self): |
221 | + results = self.FakeArgs(series='precise', source='linux-lts-trusty') |
222 | + expected = copy(results).update(esm=True, to_signing=True) |
223 | + with self.capture() as (out, err): |
224 | + auto_route(results) |
225 | + self.assertEqual(expected.__dict__, results.__dict__) |
226 | + self.assertIn('from and to ESM', out.getvalue().strip()) |
227 | + self.assertIn('via signing', out.getvalue().strip()) |
228 | + |
229 | + def test_fips_bionic_linux_fips(self): |
230 | + results = self.FakeArgs(series='bionic', source='linux-fips') |
231 | + expected = copy(results).update(fips=True, to_signing=True) |
232 | + with self.capture() as (out, err): |
233 | + auto_route(results) |
234 | + self.assertEqual(expected.__dict__, results.__dict__) |
235 | + self.assertIn('from and to FIPS', out.getvalue().strip()) |
236 | + self.assertIn('via signing', out.getvalue().strip()) |
237 | + |
238 | + def test_ibmgt_bionic_linux_ibmgt(self): |
239 | + results = self.FakeArgs(series='bionic', source='linux-ibm-gt') |
240 | + expected = copy(results).update(ibmgt=True) |
241 | + with self.capture() as (out, err): |
242 | + auto_route(results) |
243 | + self.assertEqual(expected.__dict__, results.__dict__) |
244 | + self.assertIn('from and to IBM-GT', out.getvalue().strip()) |
245 | + self.assertNotIn('via signing', out.getvalue().strip()) |
246 | + |
247 | +def auto_route(args): |
248 | + before = (args.esm, args.fips, args.ibmgt, args.to_signing) |
249 | + |
250 | + if args.series == 'precise': |
251 | + args.esm = True |
252 | + if args.esm: |
253 | + if not (args.series == 'precise' and args.source in ('linux', 'linux-meta')): |
254 | + args.to_signing = True |
255 | + |
256 | + if args.source.endswith('-fips'): |
257 | + args.fips = True |
258 | + if args.fips: |
259 | + args.to_signing = True |
260 | + |
261 | + if args.source.endswith('-ibm-gt'): |
262 | + args.ibmgt = True |
263 | + |
264 | + if before != (args.esm, args.fips, args.ibmgt, args.to_signing): |
265 | + msg = "NOTE: directing copy " |
266 | + if args.esm: |
267 | + msg += "from and to ESM" |
268 | + elif args.fips: |
269 | + msg += "from and to FIPS" |
270 | + elif args.ibmgt: |
271 | + msg += "from and to IBM-GT PPAs" |
272 | + if args.to_signing: |
273 | + msg += " via signing" |
274 | + print(msg) |
275 | + |
276 | + |
277 | +# SELF-TESTS: |
278 | +if len(sys.argv) >= 2 and sys.argv[1] == '--self-test': |
279 | + unittest.main(argv=[sys.argv[0]] + sys.argv[2:]) |
280 | + sys.exit(0) |
281 | + |
282 | parser = argparse.ArgumentParser(description='Copy a proposed kernel to the apropriate archive pocket') |
283 | parser.add_argument('--dry-run', action='store_true', help='Do everything but actually copy the package') |
284 | parser.add_argument('--security', '-S', action='store_true', help='Copy from the kernel security PPA') |
285 | parser.add_argument('--security2', action='store_true', help='Copy from the kernel security PPA2') |
286 | parser.add_argument('--esm', '-E', action='store_true', help='Copy from the kernel ESM PPA and to the kernel ESM proposed PPA') |
287 | +parser.add_argument('--fips', action='store_true', help='Copy from the kernel FIPS PPA and to the kernel FIPS proposed PPA') |
288 | +parser.add_argument('--ibmgt', action='store_true', help='Copy from the kernel IBM-GT build PPA to the corresponding proposed PPA') |
289 | parser.add_argument('--no-auto', action='store_true', help='Turn off automatic detection of ESM et al based on series') |
290 | +parser.add_argument('--to-signing', action='store_true', help='Copy from the kernel ESM/FIPS PPA to the ESM/FIPS signing PPA') |
291 | +parser.add_argument('--from-signing', action='store_true', help='Copy from the ESM/FIPS signing PPA to the ESM/FIPS proposed PPA') |
292 | parser.add_argument('series', action='store', help='The series the source package is in') |
293 | parser.add_argument('source', action='store', help='The source package name') |
294 | |
295 | args = parser.parse_args() |
296 | |
297 | -to = 'ubuntu' |
298 | -ppa_name = '~canonical-kernel-team/ubuntu/ppa' |
299 | -security = False |
300 | - |
301 | # If we are allowed to intuit destinations do so: |
302 | # 1) precise is now destined for the ESM PPAs |
303 | if not args.no_auto: |
304 | - if args.series == 'precise' and not args.esm: |
305 | - print("NOTE: directing copy from and to ESM for precise") |
306 | - args.esm = True |
307 | - |
308 | -if args.esm: |
309 | - ppa_name = '~canonical-kernel-esm/ubuntu/ppa' |
310 | - to = '~canonical-kernel-esm/ubuntu/proposed' |
311 | - to_pocket = 'release' |
312 | -if args.security: |
313 | - ppa_name = '~canonical-kernel-security-team/ubuntu/ppa' |
314 | - if not args.esm: |
315 | - security = True |
316 | - else: |
317 | - ppa_name = '~canonical-kernel-security-team/ubuntu/esm' |
318 | -if args.security2: |
319 | - ppa_name = '~canonical-kernel-security-team/ubuntu/ppa2' |
320 | - if not args.esm: |
321 | - security = True |
322 | + auto_route(args) |
323 | + |
324 | +(ppa_name, to, security) = routing(args) |
325 | + |
326 | +##print("ppa_name<{}> to<{}>".format(ppa_name, to)) |
327 | + |
328 | +if ppa_name is None: |
329 | + print("ERROR: bad source PPA") |
330 | + sys.exit(1) |
331 | +if to is None: |
332 | + print("ERROR: bad destination") |
333 | + sys.exit(1) |
334 | |
335 | (release, pkg) = (args.series, args.source) |
336 | |
337 | @@ -75,26 +338,34 @@ |
338 | kernel_ppa = launchpad.archives.getByReference( |
339 | reference=ppa_name) |
340 | |
341 | +# Grab a reference to the 'to' archive and select a pocket. |
342 | +to_archive = launchpad.archives.getByReference(reference=to) |
343 | +if to == 'ubuntu': |
344 | + to_pocket = 'proposed' |
345 | +else: |
346 | + to_pocket = 'release' |
347 | + |
348 | # get current version in PPA for that series |
349 | versions = kernel_ppa.getPublishedSources( |
350 | source_name=pkg, exact_match=True, status='Published', pocket='Release', |
351 | distro_series=distro_series) |
352 | -assert versions.total_size == 1 |
353 | -version = versions[0].source_package_version |
354 | +version = None |
355 | +if versions.total_size == 1: |
356 | + version = versions[0].source_package_version |
357 | |
358 | include_binaries = (pkg not in ('debian-installer') |
359 | and not pkg.startswith('linux-signed')) |
360 | - |
361 | -# Grab a reference to the 'to' archive and select a pocket. |
362 | -to_archive = launchpad.archives.getByReference(reference=to) |
363 | -if to == 'ubuntu': |
364 | - to_pocket = 'proposed' |
365 | -else: |
366 | - to_pocket = 'release' |
367 | +if args.from_signing: |
368 | + include_binaries = True |
369 | |
370 | print("""Copying {}/{}: |
371 | From: {} release |
372 | - To: {} {}""".format(pkg, version, kernel_ppa, to_archive, to_pocket)) |
373 | + To: {} {} |
374 | + Binaries: {}""".format(pkg, version, kernel_ppa, to_archive, to_pocket, include_binaries)) |
375 | + |
376 | +if not version: |
377 | + print("ERROR: no version to copy") |
378 | + sys.exit(1) |
379 | |
380 | if args.dry_run: |
381 | print("Dry run; no packages copied.") |
Various suggestions for improvement, but nothing that I think should necessarily block landing this.