summaryrefslogtreecommitdiffstats
path: root/bin/schroot-create.sh
blob: f86f6d319bac31562a5ce938eadc76ed0e11b99f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
#!/bin/bash

# Copyright 2012-2017 Holger Levsen <holger@layer-acht.org>
# Copyright      2013 Antonio Terceiro <terceiro@debian.org>
# Copyright      2014 Joachim Breitner <nomeata@debian.org>
# Copyright      2015 MAttia Rizzolo <mattia@mapreri.org>
# released under the GPLv=2

DEBUG=false
. /srv/jenkins/bin/common-functions.sh
common_init "$@"

# bootstraps a new chroot for schroot, and then moves it into the right location

# $1 = schroot name
# $2 = base distro/suite
# $3 $4 ... = extra packages to install

if [ $# -lt 2 ]; then
	echo "usage: $0 TARGET SUITE [backports] [reproducible] [ARG1 ARG2 ...]"
	exit 1
fi

# initialize vars
declare -a EXTRA_SOURCES
for i in $(seq 0 7) ; do
	EXTRA_SOURCES[$i]=""
done
CONTRIB=""

if [ "$1" = "torbrowser-launcher" ] ; then
	CONTRIB="contrib"
	shift
fi

if [ "$1" = "backports" ] ; then
	EXTRA_SOURCES[2]="deb $MIRROR ${SUITE}-backports main $CONTRIB"
	EXTRA_SOURCES[3]="deb-src $MIRROR ${SUITE}-backports main $CONTRIB"
	shift
fi

if [ "$1" = "reproducible" ] ; then
	EXTRA_SOURCES[4]="deb http://reproducible.alioth.debian.org/debian/ ./"
	EXTRA_SOURCES[5]="deb-src http://reproducible.alioth.debian.org/debian/ ./"
	REPRODUCIBLE=true
	shift
fi


TARGET="$1"
shift
SUITE="$1"
shift

TMPLOG=$(mktemp --tmpdir=$TMPDIR schroot-create-XXXXXXXX)

if [ "$SUITE" = "experimental" ] ; then
	# experimental cannot be bootstrapped
	SUITE=sid
	EXTRA_SOURCES[0]="deb $MIRROR experimental main $CONTRIB"
	EXTRA_SOURCES[1]="deb-src $MIRROR experimental main $CONTRIB"
elif [ "$SUITE" != "unstable" ] && [ "$SUITE" != "sid" ] ; then
	EXTRA_SOURCES[6]="deb http://security.debian.org $SUITE/updates main $CONTRIB"
	EXTRA_SOURCES[7]="deb-src http://security.debian.org $SUITE/updates main $CONTRIB"
fi

export SCHROOT_TARGET=$(mktemp -d -p $SCHROOT_BASE/ schroot-install-$TARGET-XXXX)
if [ -z "$SCHROOT_TARGET" ]; then
	echo "Could not create a directory to create the chroot in, aborting."
	exit 1
fi
sudo chmod +x $SCHROOT_TARGET	# workaround #844220 / #872812

#
# create script to add key for reproducible repo
# and configuring APT to ignore Release file expiration (since the host may
# have the date set far in the future)
#
reproducible_setup() {
	cat > $1 <<- EOF
echo "-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)

mQINBFQsy/gBEADKGF55qQpXxpTn7E0Vvqho82/HFB/yT9N2wD8TkrejhJ1I6hfJ
zFXD9fSi8WnNpLc6IjcaepuvvO4cpIQ8620lIuONQZU84sof8nAO0LDoMp/QdN3j
VViXRXQtoUmTAzlOBNpyb8UctAoSzPVgO3jU1Ngr1LWi36hQPvQWSYPNmbsDkGVE
unB0p8DCN88Yq4z2lDdlHgFIy0IDNixuRp/vBouuvKnpe9zyOkijV83Een0XSUsZ
jmoksFzLzjChlS5fAL3FjtLO5XJGng46dibySWwYx2ragsrNUUSkqTTmU7bOVu9a
zlnQNGR09kJRM77UoET5iSXXroK7xQ26UJkhorW2lXE5nQ97QqX7igWp2u0G74RB
e6y3JqH9W8nV+BHuaCVmW0/j+V/l7T3XGAcbjZw1A4w5kj8YGzv3BpztXxqyHQsy
piewXLTBn8dvgDqd1DLXI5gGxC3KGGZbC7v0rQlu2N6OWg2QRbcVKqlE5HeZxmGV
vwGQs/vcChc3BuxJegw/bnP+y0Ys5tsVLw+kkxM5wbpqhWw+hgOlGHKpJLNpmBxn
T+o84iUWTzpvHgHiw6ShJK50AxSbNzDWdbo7p6e0EPHG4Gj41bwO4zVzmQrFz//D
txVBvoATTZYMLF5owdCO+rO6s/xuC3s04pk7GpmDmi/G51oiz7hIhxJyhQARAQAB
tC5EZWJpYW4gUmVwcm9kdWNpYmxlIEJ1aWxkcyBBcmNoaXZlIFNpZ25pbmcgS2V5
iQI9BBMBCAAnAhsDBQsJCAcDBRUKCQgLBRYDAgEAAh4BAheABQJW+pswBQkIcWme
AAoJEF23ymfqWaMfuzcP+QG3oG4gmwvEmiNYSQZZouRCkPyi7VUjZPdY88ZI4l9e
KECfjE/VXMr9W5B4QQXqbWAqXkZGNTRB+OWcwcpwcwdRnCX1PfchC6Rm5hc+OOg1
Wl3pHhsZ+JaztQ9poAy8IRSYdGIH6qsTOWglAR1iPeklimFIzrrfpoUe+pT3fidQ
UoCtq6Y2wrevi9l+6ZCCO2fZGJ+8jQGSWF2XNUGgv43vyS+O/YKYeq7u87hEqxwI
k3gfcvD0AKIqX3ST0f6ABsF9YXy4pfnfJeH7xVDOyMH4A8YemNniKE40LSrZVUbW
QMkJC3VjUF+nSOM+nQSgdSQ2XKfygagv1rWcVqj0etVbcjIMgF+YtQtX5WhXo1de
XTUO1y0rsCyX7mbfEqBDVCGMOvQmwrwk0uLGzzdgzam3/ZTgPoy+n5Adg4x1gU30
nh5rjOKWAyzbLNCt9KXmps+PwuwPSR643q/zr/r4WJTruSyVJAMjwXf8tbYYg8X3
unSrmrxS5T0YA3TfY34ThtHtmjA9d2lzv270ALc3ELv83fTnQ/3Sxkwu+KKIagXQ
KzXCKzHjI89kJT5+7GBHd/nLG1z/3yw/TBzH5zSTgwC+3/EHNMH7WrY2DOzdEZTF
peNsYNcna2Ca8Imozzc5L424lXN3MaiTql7Y1lZJFF5Y/wznbjUQj/5YXj3LVB3W
=5CAZ
-----END PGP PUBLIC KEY BLOCK-----" > /etc/apt/trusted.gpg.d/reproducible.asc
apt-key list
echo
echo "Configuring APT to ignore the Release file expiration"
echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/398future
echo "Configuring APT to not download package descriptions"
echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/10no-package-descriptions
echo
EOF
}

robust_chroot_apt() {
	set +e
	sudo chroot $SCHROOT_TARGET apt-get $@ | tee $TMPLOG
	local RESULT=$(egrep 'Failed to fetch.*(Unable to connect to|Connection failed|Size mismatch|Cannot initiate the connection to|Bad Gateway|Service Unavailable)' $TMPLOG || true)
	set -e
	if [ ! -z "$RESULT" ] ; then
		echo "$(date -u) - 'apt-get $@' failed, sleeping 5min before retrying..."
		sleep 5m
		sudo chroot $SCHROOT_TARGET apt-get $@ || ( echo "$(date -u ) - 2nd 'apt-get $@' failed, giving up..." ; exit 1 )
	fi
	rm -f $TMPLOG
}

bootstrap() {
	mkdir -p "$SCHROOT_TARGET/etc/dpkg/dpkg.cfg.d"
	echo force-unsafe-io > "$SCHROOT_TARGET/etc/dpkg/dpkg.cfg.d/02dpkg-unsafe-io"

	echo "Bootstraping $SUITE into $SCHROOT_TARGET now."
	set +e
	sudo debootstrap $SUITE $SCHROOT_TARGET $MIRROR | tee $TMPLOG
	local RESULT=$(egrep "E: (Couldn't download packages|Invalid Release signature)" $TMPLOG || true)
	set -e
	if [ ! -z "$RESULT" ] ; then
		echo "$(date -u) - initial debootstrap failed, sleeping 5min before retrying..."
		sudo rm -rf --one-file-system $SCHROOT_TARGET
		sleep 5m
		sudo debootstrap $SUITE $SCHROOT_TARGET $MIRROR || ( echo "$(date -u ) - 2nd debootstrap failed, giving up..." ; exit 1 )
	fi
	rm -f $TMPLOG

	echo -e '#!/bin/sh\nexit 101'              | sudo tee   $SCHROOT_TARGET/usr/sbin/policy-rc.d >/dev/null
	sudo chmod +x $SCHROOT_TARGET/usr/sbin/policy-rc.d
	if [ ! -z "$http_proxy" ] ; then
		echo "Acquire::http::Proxy \"$http_proxy\";" | sudo tee    $SCHROOT_TARGET/etc/apt/apt.conf.d/80proxy >/dev/null
	fi
	echo "# generated by $BUILD_URL"              | sudo tee    $SCHROOT_TARGET/etc/apt/sources.list > /dev/null
	echo "deb $MIRROR $SUITE main $CONTRIB"       | sudo tee -a $SCHROOT_TARGET/etc/apt/sources.list > /dev/null
	echo "deb-src $MIRROR $SUITE main $CONTRIB"   | sudo tee -a $SCHROOT_TARGET/etc/apt/sources.list > /dev/null
	for i in $(seq 0 7) ; do
		[ -z "${EXTRA_SOURCES[$i]}" ] || echo "${EXTRA_SOURCES[$i]}"                     | sudo tee -a $SCHROOT_TARGET/etc/apt/sources.list >/dev/null
	done

	if $REPRODUCIBLE ; then
		TMPFILE=$(mktemp -u)
		reproducible_setup $SCHROOT_TARGET/$TMPFILE
		sudo chroot $SCHROOT_TARGET bash $TMPFILE
		rm $SCHROOT_TARGET/$TMPFILE
	fi


	robust_chroot_apt update
	if [ -n "$1" ] ; then
		for d in proc dev dev/pts ; do
			sudo mount --bind /$d $SCHROOT_TARGET/$d
		done
		set -x
		robust_chroot_apt update
		# first, (if), install diffoscope with all recommends...
		if [ "$1" = "diffoscope" ] ; then
			# we could also use $SCRIPT_HEADER (set in bin/common-functions.sh) in our generated scripts
			# instead of using the next line, maybe we should…
			echo 'debconf debconf/frontend select noninteractive' | sudo chroot $SCHROOT_TARGET debconf-set-selections
			robust_chroot_apt install -y --install-recommends diffoscope
		fi
		robust_chroot_apt install -y --no-install-recommends sudo
		robust_chroot_apt install -y --no-install-recommends $@
		# try to use diffoscope from experimental if available
		if ([ "$SUITE" != "unstable" ] && [ "$SUITE" != "experimental" ]) && [ "$1" = "diffoscope" ] ; then
			# always try to use diffoscope from unstable on stretch/buster
			echo "deb $MIRROR unstable main"        | sudo tee -a $SCHROOT_TARGET/etc/apt/sources.list > /dev/null
			robust_chroot_apt update
			# install diffoscope from unstable without re-adding all recommends...
			sudo chroot $SCHROOT_TARGET apt-get install -y -t unstable --no-install-recommends diffoscope || echo "Warning: diffoscope from unstable is uninstallable at the moment."
		fi
		if [ "$SUITE" != "experimental" ] && [ "$1" = "diffoscope" ] ; then
			echo "deb $MIRROR experimental main"        | sudo tee -a $SCHROOT_TARGET/etc/apt/sources.list > /dev/null
			robust_chroot_apt update
			# install diffoscope from experimental without re-adding all recommends...
			sudo chroot $SCHROOT_TARGET apt-get install -y -t experimental --no-install-recommends diffoscope || echo "Warning: diffoscope from experimental is uninstallable at the moment."
		fi
		if ! $DEBUG ; then set +x ; fi
		if [ "$1" = "diffoscope" ] ; then
			echo
			sudo chroot $SCHROOT_TARGET dpkg -l diffoscope
			echo
		fi
		# umount in reverse order
		for d in dev/pts dev proc ; do
			sudo umount -l $SCHROOT_TARGET/$d
		done
		# configure sudo inside just like outside
		echo "jenkins    ALL=NOPASSWD: ALL" | sudo tee -a $SCHROOT_TARGET/etc/sudoers.d/jenkins >/dev/null
		sudo chroot $SCHROOT_TARGET chown root.root /etc/sudoers.d/jenkins
		sudo chroot $SCHROOT_TARGET chmod 700 /etc/sudoers.d/jenkins
	fi
}

cleanup() {
	if [ -d $SCHROOT_TARGET ]; then
		sudo rm -rf --one-file-system $SCHROOT_TARGET || ( echo "Warning: $SCHROOT_TARGET could not be fully removed on forced cleanup." ; ls $SCHROOT_TARGET -la )
	fi
	rm -f $TMPLOG
}
trap cleanup INT TERM EXIT
bootstrap $@

trap - INT TERM EXIT

# pivot the new schroot in place
rand=$RANDOM
if [ -d $SCHROOT_BASE/"$TARGET" ]
then
	# no needed for torbrowser-launcher as race conditions are mostly avoided by timings
	if [ "${TARGET:0:19}" != "torbrowser-launcher" ] ; then
		cleanup_schroot_sessions
	fi
	echo "$(date -u ) - $SCHROOT_BASE/$TARGET exists, moving it away to $SCHROOT_BASE/$TARGET-$rand"
	set +e
	sudo mv $SCHROOT_BASE/"$TARGET" $SCHROOT_BASE/"$TARGET"-"$rand"
	RESULT=$?
	set -e
	if [ $RESULT -ne 0 ] ; then
		echo
		ls -R $SCHROOT_BASE/"$TARGET"
		echo
		exit 1
	fi
fi

# no needed for torbrowser-launcher as race conditions are mostly avoided by timings
if [ "${TARGET:0:19}" != "torbrowser-launcher" ] ; then
	cleanup_schroot_sessions
fi
echo "$(date -u ) - renaming $SCHROOT_TARGET to $SCHROOT_BASE/$TARGET"
set +e
sudo mv $SCHROOT_TARGET $SCHROOT_BASE/"$TARGET"
RESULT=$?
set -e
if [ $RESULT -ne 0 ] ; then
	echo
	ls -R $SCHROOT_TARGET
	echo
	exit 1
fi

if [ -d $SCHROOT_BASE/"$TARGET"-"$rand" ] ; then
	sudo rm -rf --one-file-system $SCHROOT_BASE/"$TARGET"-"$rand" || ( echo "Warning: $SCHROOT_BASE/${TARGET}-$rand could not be fully removed." ; ls $SCHROOT_BASE/${TARGET}-$rand -la )
fi

# write the schroot config
echo "Writing configuration"
sudo tee /etc/schroot/chroot.d/jenkins-"$TARGET" <<-__END__
	[jenkins-$TARGET]
	description=Jenkins schroot $TARGET
	directory=$SCHROOT_BASE/$TARGET
	type=directory
	root-users=jenkins
	source-root-users=jenkins
	union-type=overlay
	__END__

echo "schroot $TARGET set up successfully in $SCHROOT_BASE/$TARGET - exiting now."