Merge ~morphis/snappy-hwe-snaps/+git/build-scripts:feature/ephemeral-lp-builds into ~snappy-hwe-team/snappy-hwe-snaps/+git/build-scripts:master

Proposed by Simon Fels
Status: Merged
Approved by: Konrad Zapałowicz
Approved revision: ecda8713547a287d878a1abe05a4230ee227c243
Merged at revision: 45da531c71d6f7ac545a741397dc87f2e7ab8e09
Proposed branch: ~morphis/snappy-hwe-snaps/+git/build-scripts:feature/ephemeral-lp-builds
Merge into: ~snappy-hwe-team/snappy-hwe-snaps/+git/build-scripts:master
Diff against target: 372 lines (+144/-125)
3 files modified
dev/null (+0/-111)
jobs/generic-build-snap-worker (+63/-0)
scripts/trigger-lp-build.py (+81/-14)
Reviewer Review Type Date Requested Status
System Enablement Bot continuous-integration Approve
Konrad Zapałowicz (community) code Approve
Jim Hodapp (community) Approve
Review via email: mp+317594@code.launchpad.net

Description of the change

Rework snap-build job to create ephemeral snap builds on launchpad

This makes our build much more reliable as we offload the actual build
to launchpad and can also build for multiple architectures instead of
just building the host architecture our jenkins agents runs as.

We use the jenkins-ci-builds repository on launchpad as staging area
for our builds.

Example build using this is at https://jenkins.canonical.com/system-enablement/job/morphis-generic-build-snap/1/

This got reworked a bit more. We will now trigger one generic-snap-build-worker job per architecture from the generic-snap-build job so that have individual builds per architecture instead of a big one for all.

See https://jenkins.canonical.com/system-enablement/job/generic-build-snap-worker/ and https://jenkins.canonical.com/system-enablement/job/morphis-generic-build-snap/ for the proposed setup. generic-build-snap-worker will be triggered with the ARCH= flag set. generic-build-snap can be tuned at a later point to use a architecture whitelist for each snap.

To post a comment you must log in.
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Konrad Zapałowicz (kzapalowicz) wrote :

LGTM

review: Approve (code)
Revision history for this message
Jim Hodapp (jhodapp) wrote :

LGTM

review: Approve
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Konrad Zapałowicz (kzapalowicz) wrote :

ack

review: Approve (code)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Konrad Zapałowicz (kzapalowicz) wrote :

approving on behalf of Jim who is not in the EU timezone and the other maintainer is the author of this MP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/jobs/generic-build-snap b/jobs/generic-build-snap
2deleted file mode 100755
3index 82c27cf..0000000
4--- a/jobs/generic-build-snap
5+++ /dev/null
6@@ -1,27 +0,0 @@
7-#!/bin/sh
8-#
9-# Copyright (C) 2016 Canonical Ltd
10-#
11-# This program is free software: you can redistribute it and/or modify
12-# it under the terms of the GNU General Public License version 3 as
13-# published by the Free Software Foundation.
14-#
15-# This program is distributed in the hope that it will be useful,
16-# but WITHOUT ANY WARRANTY; without even the implied warranty of
17-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18-# GNU General Public License for more details.
19-#
20-# You should have received a copy of the GNU General Public License
21-# along with this program. If not, see <http://www.gnu.org/licenses/>.
22-
23-set -x
24-
25-sudo $WORKSPACE/build-scripts/scripts/snap-build \
26- $WORKSPACE \
27- $SERIES \
28- $TARGET_GIT_REPO \
29- $TARGET_GIT_REPO_BRANCH \
30- $SOURCE_GIT_REPO \
31- $SOURCE_GIT_REPO_BRANCH \
32- $REVISION \
33- $FORCE
34\ No newline at end of file
35diff --git a/jobs/generic-build-snap-worker b/jobs/generic-build-snap-worker
36new file mode 100755
37index 0000000..0cfd16e
38--- /dev/null
39+++ b/jobs/generic-build-snap-worker
40@@ -0,0 +1,63 @@
41+#!/bin/sh
42+#
43+# Copyright (C) 2016 Canonical Ltd
44+#
45+# This program is free software: you can redistribute it and/or modify
46+# it under the terms of the GNU General Public License version 3 as
47+# published by the Free Software Foundation.
48+#
49+# This program is distributed in the hope that it will be useful,
50+# but WITHOUT ANY WARRANTY; without even the implied warranty of
51+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52+# GNU General Public License for more details.
53+#
54+# You should have received a copy of the GNU General Public License
55+# along with this program. If not, see <http://www.gnu.org/licenses/>.
56+
57+set -x
58+
59+[ -e $WORKSPACE/src ] && rm -rf $WORKSPACE/src
60+
61+git clone -b $TARGET_GIT_REPO_BRANCH $TARGET_GIT_REPO $WORKSPACE/src
62+cd $WORKSPACE/src
63+
64+if [ ! -e snapcraft.yaml ] ; then
65+ echo "ERROR: Failed to build snap as no snapcraft.yaml exists!"
66+ exit 1
67+fi
68+
69+git config user.name "System Enablement CI Bot"
70+git config user.email "ce-system-enablement@lists.canonical.com"
71+
72+if [ -n "$SOURCE_GIT_REPO" ]; then
73+ git remote add other $SOURCE_GIT_REPO
74+ git fetch other
75+ git merge \
76+ --no-ff \
77+ -m "Merge remote tracking branch other/$SOURCE_GIT_REPO_BRANCH" \
78+ $REVISION
79+fi
80+
81+SNAP_NAME=$(grep "name:" snapcraft.yaml | awk '{print $2}')
82+SNAP_REV=$(git rev-parse --short HEAD)
83+CI_BRANCH=build/$SNAP_NAME-$BUILD_ID-$SNAP_REV
84+git checkout -b $CI_BRANCH
85+git remote add jenkins-ci git+ssh://system-enablement-ci-bot@git.launchpad.net/~snappy-hwe-team/snappy-hwe-snaps/+git/jenkins-ci-builds
86+git push jenkins-ci $CI_BRANCH
87+
88+EXTRA_ARGS=
89+if [ -n "$ARCHITECTURES" ]; then
90+ EXTRA_ARGS="$EXTRA_ARGS --architectures=$ARCHITECTURES"
91+fi
92+
93+$WORKSPACE/build-scripts/scripts/trigger-lp-build.py \
94+ -s $SNAP_NAME -n \
95+ --git-repo=https://git.launchpad.net/~snappy-hwe-team/snappy-hwe-snaps/+git/jenkins-ci-builds \
96+ --git-repo-branch=$CI_BRANCH \
97+ $EXTRA_ARGS
98+# When build has finished (regardless of its result) we remove our CI branch
99+# to keep the CI repository clean.
100+git push jenkins-ci :$CI_BRANCH
101+if [ $? -ne 0 ]; then
102+ exit 1
103+fi
104diff --git a/scripts/snap-build b/scripts/snap-build
105deleted file mode 100755
106index abe40b4..0000000
107--- a/scripts/snap-build
108+++ /dev/null
109@@ -1,111 +0,0 @@
110-#!/bin/bash
111-#
112-# Copyright (C) 2016 Canonical Ltd
113-#
114-# This program is free software: you can redistribute it and/or modify
115-# it under the terms of the GNU General Public License version 3 as
116-# published by the Free Software Foundation.
117-#
118-# This program is distributed in the hope that it will be useful,
119-# but WITHOUT ANY WARRANTY; without even the implied warranty of
120-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
121-# GNU General Public License for more details.
122-#
123-# You should have received a copy of the GNU General Public License
124-# along with this program. If not, see <http://www.gnu.org/licenses/>.
125-
126-set -x
127-set -e
128-
129-# Fix certain builds that require a locale set
130-export LC_ALL=C
131-
132-WORKSPACE=$1
133-SERIES=$2
134-TARGET_GIT_REPO=$3
135-TARGET_GIT_REPO_BRANCH=$4
136-SOURCE_GIT_REPO=$5
137-SOURCE_GIT_REPO_BRANCH=$6
138-REVISION=$7
139-FORCE=$8
140-
141-BUILD_ROOTFS_TARBALL=$WORKSPACE/snap-build-$SERIES.tar
142-
143-if [ ! -e $BUILD_ROOTFS_TARBALL ] || [ "$REBUILD_ROOTFS" -eq "1" ] ; then
144- sudo $WORKSPACE/build-scripts/scripts/build-rootfs-create $SERIES $BUILD_ROOTFS_TARBALL
145-fi
146-
147-cd $WORKSPACE
148-
149-# Cleanup environment a bit
150-[ -e build ] && rm -rf build
151-[ -e results ] && rm -rf results
152-
153-mkdir build
154-mkdir results
155-
156-tar xf $BUILD_ROOTFS_TARBALL -C build
157-
158-cat << EOF > build/rootfs/do-build.sh
159-#!/bin/bash
160-set -x
161-set -e
162-
163-export TERM=linux
164-export DEBIAN_FRONTEND=noninteractive
165-
166-# HACK: As we're not able to talk with parts.snapcraft.io yet
167-# we need to fake the parts registry here as otherwise we can't
168-# process our builds.
169-export SNAPCRAFT_PARTS_URI=http://dev.null
170-export XDG_DATA_HOME=/build/xdg-data
171-mkdir -p /build/xdg-data/snapcraft
172-touch /build/xdg-data/snapcraft/parts.yaml
173-echo "{If-Modified-Since: '`date`'}" > /build/xdg-data/snapcraft/headers.yaml
174-
175-# Add missing package sources to the system to get necessary
176-# updates for snapcraft & co
177-echo "deb http://de.archive.ubuntu.com/ubuntu/ $SERIES-updates main" >> /etc/apt/sources.list
178-echo "deb http://archive.ubuntu.com/ubuntu/ $SERIES-updates universe" >> /etc/apt/sources.list
179-
180-# Make sure all required things are installed
181-apt-get update
182-apt-get -y --force-yes upgrade
183-apt-get -y --force-yes install snapcraft git
184-
185-mkdir -p /build
186-git clone -b $TARGET_GIT_REPO_BRANCH $TARGET_GIT_REPO /build/src
187-cd /build/src
188-
189-git config user.name "System Enablement CI Bot"
190-git config user.email "ce-system-enablement@lists.canonical.com"
191-
192-if [ -n "$SOURCE_GIT_REPO" ]; then
193- git remote add other $SOURCE_GIT_REPO
194- git fetch other
195- git merge \
196- --no-ff \
197- -m "Merge remote tracking branch other/$SOURCE_GIT_REPO_BRANCH" \
198- $REVISION
199-fi
200-
201-# Only attempt to build projects where we have a valid snapcraft project.
202-# For all others we just make sure we can merge source to target.
203-if [ ! -e "/build/src/snapcraft.yaml" ] && [ ! -e "/build/src/.snapcraft.yaml" ] ; then
204- echo "WARNING: Project does not contain a snapcraft.yaml file!"
205- exit 0
206-fi
207-
208-find /build/src
209-snapcraft --version
210-snapcraft
211-EOF
212-
213-chmod +x build/rootfs/do-build.sh
214-chroot build/rootfs /do-build.sh
215-
216-# Copy snaps to their target directory where jenkins will
217-# pick them up and provide as buid artifacts
218-cp build/rootfs/build/src/*.snap results/ || true
219-
220-rm -rf build
221diff --git a/scripts/trigger-lp-build.py b/scripts/trigger-lp-build.py
222index 7f0f544..ed3d3e8 100755
223--- a/scripts/trigger-lp-build.py
224+++ b/scripts/trigger-lp-build.py
225@@ -3,7 +3,11 @@
226 import os
227 import sys
228 import time
229+import random
230 import smtplib
231+import string
232+import urllib2
233+import zlib
234
235 from datetime import datetime
236 from os.path import basename
237@@ -18,9 +22,21 @@ parser.add_argument('-s', '--snap', required=True,
238 help="Name of the snap to build")
239 parser.add_argument('-p', '--publish', action='store_true',
240 help="Trigger a publish build instead of a daily (default)")
241+parser.add_argument('-n', '--new', action='store_true', help="Create a new ephemeral snap build on launchpad")
242+parser.add_argument('--git-repo', help="Git repository to be used for new ephemeral snap build")
243+parser.add_argument('--git-repo-branch', help="Git repository branch to be used for new ephemeral snap build")
244+parser.add_argument('-a', '--architectures', help="Specify architectures to build for. Separate multiple architectures by ','")
245
246 args = vars(parser.parse_args())
247
248+ephemeral_build=False
249+
250+if args['new']:
251+ ephemeral_build=True
252+ if not 'git_repo' in args or not 'git_repo_branch' in args:
253+ print("ERROR: No git repository or a branch supplied")
254+ sys.exit(1)
255+
256 series = 'xenial'
257
258 lp_app = se_utils.get_config_option("lp_app")
259@@ -29,28 +45,70 @@ credential_store_path = se_utils.get_config_option('credential_store_path')
260 launchpad = se_utils.get_launchpad(None, credential_store_path, lp_app, lp_env)
261
262 team = launchpad.people['snappy-hwe-team']
263-
264-build_name = "%s-daily" % args["snap"]
265-if args["publish"] == True:
266- build_name = "%s-publish" % args["snap"]
267-
268-snap = launchpad.snaps.getByName(name=build_name, owner=team)
269 ubuntu = launchpad.distributions['ubuntu']
270 release = ubuntu.getSeries(name_or_version=series)
271 primary_archive = ubuntu.getArchive(name='primary')
272
273+snap=None
274+if ephemeral_build:
275+ snap_arches=[]
276+ if 'architectures' in args and len(args['architectures']) > 0:
277+ snap_arches = args["architectures"].split(",")
278+
279+ if len(snap_arches) == 0:
280+ print("WARNING: No architectures to build specified. Will only build for amd64.")
281+ snap_arches=["amd64"]
282+
283+ processors=[]
284+ for arch in snap_arches:
285+ try:
286+ p = launchpad.processors.getByName(name=arch)
287+ processors.append(p.self_link)
288+ except:
289+ print("ERROR: Failed to find processor for '{}' architecture".format(arch))
290+ sys.exit(1)
291+
292+ build_name = 'ci-%s-%s' % (args["snap"], ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(16)))
293+ snap = launchpad.snaps.new(name=build_name,
294+ processors=processors,
295+ auto_build=False, distro_series=release,
296+ git_repository_url=args['git_repo'],
297+ git_path='%s' % args["git_repo_branch"],
298+ owner=team)
299+else:
300+ build_name = "%s-daily" % args["snap"]
301+ if args["publish"] == True:
302+ build_name = "%s-publish" % args["snap"]
303+ snap = launchpad.snaps.getByName(name=build_name, owner=team)
304+
305+if snap == None:
306+ print("ERROR: Failed to create snap build on launchpad")
307+
308+# Not every snap is build agains all arches.
309+arches = [processor.name for processor in snap.processors]
310+if not ephemeral_build and "architectures" in args:
311+ wanted_arches = args["architectures"].split(",")
312+ possible_arches = []
313+ for arch in wanted_arches:
314+ if not arch in arches:
315+ print("WARNING: Can't build snap for architecture {} as it is not enabled in the build job".format(args["snap"]))
316+ continue
317+ possible_arches.append(arch)
318+ arches = possible_arches
319+
320+if len(arches) == 0:
321+ print("ERROR: No architectures available to build for")
322+ sys.exit(1)
323+
324 # Add a big fat warning that we don't really care about fixing things when
325 # the job will be canceled after the following lines are printed out.
326-print("!!!!!!! POINT OF NO RETURN !!!!!!!")
327+print("!!!!!!! POINT OF NO RETURN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
328 print("DO NOT CANCEL THIS JOB AFTER THIS OR BAD THINGS WILL HAPPEN")
329-print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
330+print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
331
332 stamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
333 print("Trying to trigger builds at: {}".format(stamp))
334
335-# Not every snap is build agains all arches.
336-arches = [processor.name for processor in snap.processors]
337-
338 # We will now trigger a build for each whitelisted architecture, collect the
339 # build job url and the wait for all builds to finish and collect their results
340 # to vote for a successful or failed build.
341@@ -60,7 +118,7 @@ for build_arch in arches:
342 request = snap.requestBuild(archive=primary_archive, distro_arch_series=arch, pocket='Proposed')
343 build_id = str(request).rsplit('/', 1)[-1]
344 triggered_builds.append(build_id)
345- print("Arch: {} is building under: {}".format(build_arch, request))
346+ print("Arch: {} is building under: {}".format(build_arch, request.web_link))
347
348 failures = []
349 while len(triggered_builds):
350@@ -90,12 +148,21 @@ if len(failures):
351 except:
352 print ("Could not get failure data for {} (was there an LP timeout?)".format(build))
353 continue
354- buildlog = response[build]['build_log_url']
355+ buildlog = response[failure]['build_log_url']
356 if buildlog != 'None':
357- print(buildlog)
358 arch = str(buildlog).split('_')[4]
359 print("{} snap {} build at {} failed for id: {} log: {}".format(args["snap"], arch, stamp, failure, buildlog))
360+ # For ephermal builds we need to print out the log file as it will be gone after
361+ # the launchpad build is removed.
362+ if ephemeral_build:
363+ response = urllib2.urlopen(buildlog)
364+ log_data = zlib.decompress(response.read(), 16+zlib.MAX_WBITS)
365+ print(log_data)
366
367+if ephemeral_build:
368+ snap.lp_delete()
369+
370+if len(failures):
371 # Let the build fail as at least a single snap has failed to build
372 sys.exit(1)
373

Subscribers

People subscribed via source and target branches

to all changes: