reproducible_debian_live_build.sh 8.55 KB
Newer Older
1
2
3
#!/bin/bash
# vim: set noexpandtab:

4
# Copyright 2021-2022 Holger Levsen <holger@layer-acht.org>
5
# Copyright 2021-2022 Roland Clobus <rclobus@rclobus.nl>
6
7
# released under the GPLv2

8
9
# Coding convention: enforced by 'shfmt'

10
DEBUG=false
11
12
13
14
15
16
. /srv/jenkins/bin/common-functions.sh
common_init "$@"

# common code for tests.reproducible-builds.org
. /srv/jenkins/bin/reproducible_common.sh
set -e
17
set -o pipefail # see eg http://petereisentraut.blogspot.com/2010/11/pipefail.html
18

19
20
21
22
23
24
25
26
# Copy a single file to the web server
#
# Argument 1 = description (one word)
# Argument 2 = absolute path of a file that will be published on the web server
# Argument 3 = filename for the published file
publish_file() {
	local DESCRIPTION=$1
	local ORIGINAL_FILE=$2
27
28
	local PUBLISHED_NAME
	PUBLISHED_NAME=$(basename "$3")
29

30
	ssh jenkins@jenkins.debian.net "${DESCRIPTION}" "${ORIGINAL_FILE}" "${PUBLISHED_NAME}"
31
32
}

33
cleanup() {
34
	local RESULT=$1
35
36
	output_echo "Publishing results."

37
	if [ "${RESULT}" == "success" ]; then
38
		output_echo "Info: no differences found."
39

40
41
42
43
		# Upload the ISO file and its summary to the web server
		ISONAME=${CONFIGURATION}-${DEBIAN_VERSION}.iso
		publish_file ISOfile ${RESULTSDIR}/b1/${PROJECTNAME}/${CONFIGURATION}/live-image-amd64.hybrid.iso ${ISONAME}
		publish_file Summary ${RESULTSDIR}/summary_build1.txt ${CONFIGURATION}-${DEBIAN_VERSION}.txt
44
45
46
47
48
49
50
51

		# Invoke openQA
		DESKTOP=${CONFIGURATION}
		if [ ${DESKTOP} == "smallest-build" ]; then
			DESKTOP="text"
		elif [ ${DESKTOP} == "standard" ]; then
			DESKTOP="text"
		fi
52
53
		CHECKSUM=$(grep "Checksum:" ${RESULTSDIR}/summary_build1.txt | cut -f 2 -d " ")
		#openqa-cli api -X POST isos ISO=${SNAPSHOT_TIMESTAMP}_${DEBIAN_VERSION}_${CONFIGURATION}.iso DISTRI=debian VERSION=${DEBIAN_VERSION}_${CONFIGURATION} FLAVOR=live-build ARCH=x86_64 BUILD=:${CONFIGURATION}_${DEBIAN_VERSION}_${SNAPSHOT_TIMESTAMP} DESKTOP=${DESKTOP} CHECKSUM=${CHECKSUM} TIMESTAMP=${SNAPSHOT_TIMESTAMP} ISO_URL=https://tests.reproducible-builds.org/debian_live_build/${ISONAME} --odn --apikey ${OPENQA_APIKEY} --apisecret ${OPENQA_APISECRET}
54
55
56
	else
		if [ -f "${RESULTSDIR}/${PROJECTNAME}/${CONFIGURATION}/live-image-amd64.hybrid.iso.html" ]; then
			# Publish the output of diffoscope, there are differences
57
			publish_file DiffoscopeOutput ${RESULTSDIR}/${PROJECTNAME}/${CONFIGURATION}/live-image-amd64.hybrid.iso.html ${CONFIGURATION}-${DEBIAN_VERSION}.html
58
59
		else
			output_echo "Error: Something went wrong."
60
			printenv >environment.txt
61
			publish_file Environment ${PWD}/environment.txt ${CONFIGURATION}-${DEBIAN_VERSION}.txt
62
63
64
		fi
	fi

65
	output_echo "Cleanup ${RESULT}"
66
67
68
69
70
71
72
73
	# Cleanup the workspace
	if [ ! -z "${BUILDDIR}" ]; then
		sudo rm -rf --one-file-system ${BUILDDIR}
	fi
	# Cleanup the results
	if [ ! -z "${RESULTSDIR}" ]; then
		rm -rf --one-file-system ${RESULTSDIR}
	fi
74
75
}

76
77
78
79
#
# main: follow https://wiki.debian.org/ReproducibleInstalls/LiveImages
#

80
81
82
83
84
85
# Argument 1 = image type
export CONFIGURATION="$1"

# Argument 2 = Debian version
export DEBIAN_VERSION="$2"

86
87
88
89
90
91
# Two arguments are required
if [ -z "${CONFIGURATION}" -o -z "${DEBIAN_VERSION}" ]; then
	output_echo "Error: Bad command line arguments."
	exit 1
fi

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# Configuration option: Select the server for the repository
# Allowed values:
#  auto (default): Detect the best available server
#  snapshot (preferred): Use a snapshot server
#  archive (fallback): Use deb.debian.org if a snapshot server is not available
#
# Note that 'archive' allows only for a time window of about 6 hours to test for reproducibility
export REPOSERVER=auto

if [ "${REPOSERVER}" == "auto" ]; then
	set +e # We are interested in the return value
	wget --quiet --no-hsts http://snapshot.notset.fr/mr/timestamp/debian/latest --output-document latest
	RETURNVALUE=$?
	rm -f latest
	set -e
	if [ ${RETURNVALUE} -eq 0 ]; then
		export REPOSERVER=snapshot
	else
		# The snapshot server is not available
		output_echo "Info: The snapshot server is not available, using deb.debian.org instead."
		export REPOSERVER=archive
	fi
fi

116
117
118
119
120
# Cleanup if something goes wrong
trap cleanup INT TERM EXIT

if $DEBUG; then
	export WGET_OPTIONS=
121
else
122
	export WGET_OPTIONS=--quiet
123
124
fi

125
# Randomize start time
126
127
delay_start

128
129
# Generate and use an isolated workspace
export PROJECTNAME="live-build"
Roland Clobus's avatar
Roland Clobus committed
130
mkdir -p /srv/workspace/live-build
131
export BUILDDIR=$(mktemp --tmpdir=/srv/workspace/live-build -d -t ${CONFIGURATION}-${DEBIAN_VERSION}.XXXXXXXX)
132
cd ${BUILDDIR}
133
export RESULTSDIR=$(mktemp --tmpdir=/srv/reproducible-results -d -t ${PROJECTNAME}-${CONFIGURATION}-${DEBIAN_VERSION}-XXXXXXXX) # accessible in schroots, used to compare results
134

135
136
137
138
139
# Fetch the rebuild script (and nothing else)
git clone https://salsa.debian.org/live-team/live-build.git rebuild_script --no-checkout --depth 1
cd rebuild_script
git checkout HEAD test/rebuild.sh
cd ..
140
141

# First build
142
143
144
output_echo "Running the rebuild script for the 1st build."
set +e # We are interested in the return value
# The 3rd argument is provided to allow for local testing of this script.
145
146
147
# - If SNAPSHOT_TIMESTAMP is already set, use that value
# - If SNAPSHOT_TIMESTAMP is not set, use REPOSERVER
export SNAPSHOT_TIMESTAMP="${SNAPSHOT_TIMESTAMP:-${REPOSERVER}}"
148
149
150
151
rebuild_script/test/rebuild.sh "$1" "$2" "${SNAPSHOT_TIMESTAMP}"
RETURNVALUE=$?
grep --quiet --no-messages "Build result: 0" summary.txt
BUILD_OK_FOUND=$?
152
set -e
153

154
155
if [ ${RETURNVALUE} -eq 99 -a "${SNAPSHOT_TIMESTAMP}" == "archive" ]; then
	# The archive was updated while building. Retry
156
	output_echo "Info: during the first build the archive was updated, now trying again."
157
158
	rebuild_script/test/rebuild.sh "$1" "$2" "${SNAPSHOT_TIMESTAMP}"
elif [ ${RETURNVALUE} -ne 0 -o ${BUILD_OK_FOUND} -ne 0 ]; then
159
160
161
162
163
164
165
166
	# Something went wrong. Perhaps an alternative timestamp is proposed
	SNAPSHOT_TIMESTAMP=$(grep --no-messages "Alternative timestamp:" summary.txt | cut -f 3 -d " ")
	if [ -z ${SNAPSHOT_TIMESTAMP} ]; then
		output_echo "Error: the image could not be built, no alternative was proposed."
		exit 1
	fi
	output_echo "Warning: the build failed with ${RETURNVALUE}. The latest snapshot might not be complete (yet). Now trying again using the previous snapshot instead."
	rebuild_script/test/rebuild.sh "$1" "$2" "${SNAPSHOT_TIMESTAMP}"
167
168
169
170
171
172
else
	# Determine the value of SNAPSHOT_TIMESTAMP for the second build
	# If 'archive' is used for the first build, use it for the second build too and hope that the same timestamp will still be available
	if [ "${SNAPSHOT_TIMESTAMP}" != "archive" ]; then
		export SNAPSHOT_TIMESTAMP=$(grep --no-messages "Snapshot timestamp:" summary.txt | cut -f 3 -d " ")
	fi
173
174
175
fi

# Move the image away
176
177
mkdir -p ${RESULTSDIR}/b1/${PROJECTNAME}/${CONFIGURATION}
mv live-image-amd64.hybrid.iso ${RESULTSDIR}/b1/${PROJECTNAME}/${CONFIGURATION}
178
mv summary.txt ${RESULTSDIR}/summary_build1.txt
Roland Clobus's avatar
Roland Clobus committed
179

180
# Second build
181
output_echo "Running the rebuild script for the 2nd build."
182
set +e # We are interested in the return value
183
rebuild_script/test/rebuild.sh "$1" "$2" "${SNAPSHOT_TIMESTAMP}"
184
185
186
RETURNVALUE=$?
set -e

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
if [ "${SNAPSHOT_TIMESTAMP}" == "archive" ]; then
	if [ ${RETURNVALUE} -eq 99 ]; then
		# The archive was updated while building. The content might not be consistent.
		# Discard the first build and retry
		output_echo "Info: during the second build the archive was updated, now trying again."
		mv live-image-amd64.hybrid.iso ${RESULTSDIR}/b1/${PROJECTNAME}/${CONFIGURATION}
		mv summary.txt ${RESULTSDIR}/summary_build1.txt
		rebuild_script/test/rebuild.sh "$1" "$2" "${SNAPSHOT_TIMESTAMP}"
	elif [ $(stat ${RESULTSDIR}/b1/${PROJECTNAME}/${CONFIGURATION}/live-image-amd64.hybrid.iso live-image-amd64.hybrid.iso | grep Modify: | uniq | wc -l) -ne 1 ]; then
		# The timestamps are different. Discard the first build and retry
		output_echo "Info: between the builds the archive was updated, now trying again."
		mv live-image-amd64.hybrid.iso ${RESULTSDIR}/b1/${PROJECTNAME}/${CONFIGURATION}
		mv summary.txt ${RESULTSDIR}/summary_build1.txt
		rebuild_script/test/rebuild.sh "$1" "$2" "${SNAPSHOT_TIMESTAMP}"
	fi
202
fi
203

204
# Move the image away
205
206
mkdir -p ${RESULTSDIR}/b2/${PROJECTNAME}/${CONFIGURATION}
mv live-image-amd64.hybrid.iso ${RESULTSDIR}/b2/${PROJECTNAME}/${CONFIGURATION}
207
mv summary.txt ${RESULTSDIR}/summary_build2.txt
208
209

# Clean up
210
output_echo "Running lb clean after the 2nd build."
211
sudo lb clean --purge
212

213
214
215
# The workspace is no longer required
cd ..

216
# Run diffoscope on the images
217
output_echo "Calling diffoscope on the results."
218
TIMEOUT="240m"
219
DIFFOSCOPE="$(schroot --directory /tmp -c chroot:jenkins-reproducible-${DBDSUITE}-diffoscope diffoscope -- --version 2>&1)"
220
TMPDIR=${RESULTSDIR}
221
call_diffoscope ${PROJECTNAME} ${CONFIGURATION}/live-image-amd64.hybrid.iso
222

223
cleanup success
224

225
226
# Turn off the trap
trap - INT TERM EXIT
227

228
229
# We reached the end, return with PASS
exit 0