Merge lp:~apw/ubuntu-archive-tools/copy-proposed-kernels-routing-updates into lp:ubuntu-archive-tools

Proposed by Andy Whitcroft
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
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-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.

To post a comment you must log in.
Revision history for this message
Steve Langasek (vorlon) wrote :

Various suggestions for improvement, but nothing that I think should necessarily block landing this.

review: Needs Fixing
Revision history for this message
Andy Whitcroft (apw) :
Revision history for this message
Andy Whitcroft (apw) wrote :

Ok updated version pushed which covers the easily fixable things.

Revision history for this message
Steve Langasek (vorlon) :
Revision history for this message
Steve Langasek (vorlon) :
review: Approve
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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.")

Subscribers

People subscribed via source and target branches