-
Notifications
You must be signed in to change notification settings - Fork 0
/
flatcar-postinst
335 lines (306 loc) · 16.7 KB
/
flatcar-postinst
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
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#!/bin/bash
# Copyright (c) 2014 The CoreOS Authors.
# Copyright (c) 2023 The Flatcar Maintainers.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
set -euo pipefail
umask 0022
# This instead of "/oem" works because it is a symlink to /oem on newer systems
# and we keep it /usr/share/oem because that is the correct path on older systems
# that process this update to the new version which will then use /oem
OEM_MNT="/usr/share/oem"
INSTALL_MNT=$(dirname "$0")
INSTALL_DEV="$1"
# Figure out if the slot id is A or B
INSTALL_LABEL=$(blkid -o value -s PARTLABEL "${INSTALL_DEV}")
case "${INSTALL_LABEL}" in
ROOT-A|USR-A)
SLOT=A;;
ROOT-B|USR-B)
SLOT=B;;
*)
echo "Unknown LABEL ${INSTALL_LABEL}" >&2
exit 1
esac
# If the OEM provides a hook, call it
if [[ -x "${OEM_MNT}/bin/oem-postinst" ]]; then
"${OEM_MNT}/bin/oem-postinst" "${SLOT}" "${INSTALL_MNT}"
fi
# Gather metadata about upcoming OS image.
# shellcheck source=/dev/null
source "${INSTALL_MNT}/lib/os-release"
NEXT_VERSION_ID=${VERSION_ID}
NEXT_VERSION="${VERSION}"
# shellcheck source=/dev/null
source /usr/lib/os-release
tee_journal() {
tee >(systemd-cat -t coreos-postinst)
}
# Workaround when updating from old update-engine clients that don't pass the proxy env vars:
get_unit_env_val() {
local varname="$1"
local envfiles=()
envfiles=( $({ systemctl show --property=EnvironmentFiles --property=EnvironmentFile update-engine.service || true ; } | { grep -P -o "EnvironmentFiles=\K[^ ]*" || true ; }) )
# Note: Values with space won't be correctly parsed because they get truncated to first space when we ignore quoting for '"Environment="VAR1=a b" Environment=VAR2=c' cases.
# Also, for reading env files we drop quotes with sed first before grepping to at least remove unnecessary quotes but we also still truncate.
{ systemctl show --property=Environment update-engine.service || true ; } | { sed "s/[\"']//g" - "${envfiles[@]}" || true ; } | grep -m 1 -Ph -o "${varname}=\K[^ ]*"
# This propagates the grep return code for the function
}
if [ "${ALL_PROXY-unset}" = "unset" ] && [ "${HTTP_PROXY-unset}" = "unset" ] && [ "${HTTPS_PROXY-unset}" = "unset" ]; then
VARVAL=$(get_unit_env_val ALL_PROXY || echo unset)
if [ "${VARVAL}" != "unset" ]; then
export ALL_PROXY="${VARVAL}"
fi
VARVAL=$(get_unit_env_val HTTP_PROXY || echo unset)
if [ "${VARVAL}" != "unset" ]; then
export HTTP_PROXY="${VARVAL}"
fi
VARVAL=$(get_unit_env_val HTTPS_PROXY || echo unset)
if [ "${VARVAL}" != "unset" ]; then
export HTTPS_PROXY="${VARVAL}"
fi
fi
OEMID=$({ grep -m 1 -o "^ID=.*" "${OEM_MNT}"/oem-release || true ; } | cut -d = -f 2)
# Must not be used as "if sysext_download; then" or "sysext_download ||" because that makes set -e a no-op, and also must not use "( sysext_download )" because we want to set the global SUCCESS variable.
sysext_download() {
local name="$1" # Payload name
local target="$2" # Path to write the payload to, writing does not need to be atomic because the caller later does an atomic move
local from="$3" # Either path to XML dump or the constant "release-server"
local target_tmpdir=
local extracted_filename=
local ARG=()
local loader=
local ret
SUCCESS=false
extracted_filename=$(basename "${target}")
target_tmpdir="$(dirname "${target}")/ue-rs/"
set +e
(
set -e
rm -rf "${target_tmpdir}"
mkdir -p "${target_tmpdir}"
if [ "${from}" = "release-server" ]; then
ARG=("-u" "https://update.release.flatcar-linux.net/${FLATCAR_BOARD}/${NEXT_VERSION}/${name}")
elif [ "${from}" = "bincache-server" ]; then
ARG=("-u" "https://bincache.flatcar-linux.net/images/${FLATCAR_BOARD/-usr}/${NEXT_VERSION}/${name}")
else
ARG=("-i" "${from}" -m "*${name}" -t)
fi
# Using "${INSTALL_MNT}" here is ok because it was verified first by update-engine
loader=$(ls "${INSTALL_MNT}"/lib64/ld-linux-*.so.* | head -n 1)
# A simple LD_LIBRARY_PATH is not enough if the loader is too old
"${loader}" --library-path "${INSTALL_MNT}"/lib64 "${INSTALL_MNT}"/bin/download_sysext -p /usr/share/update_engine/update-payload-key.pub.pem -o "${target_tmpdir}" -n "${extracted_filename}" "${ARG[@]}"
mv "${target_tmpdir}/${extracted_filename}" "${target}"
)
ret=$?
set -e
rm -rf "${target_tmpdir}"
if [ "${ret}" -eq 0 ]; then
SUCCESS=true
fi
}
# Workaround to support updating from old airgapped clients that can't directly reach the Internet:
# Extract the XML response from the service logs if we don't have one for this action run.
if ! { [ -e /var/lib/update_engine/prefs/full-response ] && [ $(stat -L --printf='%Y' /var/lib/update_engine/prefs/full-response) -ge $(stat -L --printf='%Y' /var/lib/update_engine/prefs/previous-version) ] ; }; then
{ journalctl -b 0 -u update-engine -o cat --no-pager || true ; } | { grep -Pzo "(?s)Omaha request response: .*?/response>" || true ; } | tr '\n' ' ' | tr '\0' '\n' | sed 's/Omaha request response: //g' | { tail -n 3 || true ; } | head -n 1 > /var/lib/update_engine/prefs/full-response
fi
# To know whether an OEM update payload is expected we can't rely on checking if the Omaha response contains one
# because users may run their own instance and forget to supply it, or this is an old instance that doesn't hand us
# the XML dump over. In both cases we do a fallback download and rely on a hardcoded list of OEM sysexts which we
# anyway need to maintain for the migration actions. Besides checking that an entry in the list exists we can also
# check for the active-oem-OEM flag file to support custom OEMs (but they must be part of the Omaha response).
if [ "${OEMID}" != "" ] && { [ -e "${INSTALL_MNT}/share/flatcar/oems/${OEMID}" ] || [ -e "${OEM_MNT}/sysext/active-oem-${OEMID}" ]; }; then
mkdir -p "${OEM_MNT}"/sysext/ /etc/flatcar/oem-sysext/
# Delete sysext images that belonged to the now overwritten /usr partition but keep the sysext image for the current version
KEEP="${OEM_MNT}/sysext/oem-${OEMID}-${VERSION}.raw"
if [ ! -e "${KEEP}" ]; then
KEEP="/etc/flatcar/oem-sysext/oem-${OEMID}-${VERSION}.raw"
fi
if [ ! -e "${KEEP}" ]; then
KEEP="${OEM_MNT}/sysext/oem-${OEMID}-initial.raw" # It may not exist as well but that's ok (also, it can only exist on the OEM partition)
fi
shopt -s nullglob
for OLD_IMAGE in "${OEM_MNT}"/sysext/oem*raw /etc/flatcar/oem-sysext/oem*raw; do
if [ "${OLD_IMAGE}" != "${KEEP}" ] && [ -f "${OLD_IMAGE}" ]; then
rm -f "${OLD_IMAGE}"
fi
done
# Note that in the case of VERSION=NEXT_VERSION we will replace the running sysext and maybe it's better
# to do so than not because it allows to recover from a corrupted file (where the corruption happened on disk).
# However, as soon as update-engine would already download the payload, we should skip the overwriting.
SUCCESS=false
# Preferred is to download from the location given by the Omaha response
# which only works with a new update-engine client that creates "full-response",
# and we also have to check that this file was created fresh for this update operation
# (relies on the reset of /var/lib/update_engine/prefs/previous-version that old clients also do)
if [ -e /var/lib/update_engine/prefs/full-response ] && [ $(stat -L --printf='%Y' /var/lib/update_engine/prefs/full-response) -ge $(stat -L --printf='%Y' /var/lib/update_engine/prefs/previous-version) ]; then
rm -f "/var/lib/update_engine/oem-${OEMID}.raw"
sysext_download "oem-${OEMID}.gz" "/var/lib/update_engine/oem-${OEMID}.raw" /var/lib/update_engine/prefs/full-response
fi
# If that was not provided due to updating from an old version or if the download failed, try the release server or bincache
if [ "${SUCCESS}" = false ]; then
rm -f "/var/lib/update_engine/oem-${OEMID}.raw"
PAYLOADSERVER=release-server
PAYLOADNAME="oem-${OEMID}.gz"
if [ "$(md5sum /usr/share/update_engine/update-payload-key.pub.pem | cut -d " " -f 1)" = "7192addf4a7f890c0057d21653eff2ea" ]; then
PAYLOADSERVER=bincache-server
PAYLOADNAME="flatcar_test_update-oem-${OEMID}.gz"
fi
echo "Falling back to ${PAYLOADSERVER} for extension 'oem-${OEMID}'" >&2
sysext_download "${PAYLOADNAME}" "/var/lib/update_engine/oem-${OEMID}.raw" "${PAYLOADSERVER}"
fi
if [ "${SUCCESS}" = false ]; then
rm -f "/var/lib/update_engine/oem-${OEMID}.raw"
echo "Failed to download required OEM update payload" >&2
exit 1
fi
NEW_SYSEXT="${OEM_MNT}/sysext/oem-${OEMID}-${NEXT_VERSION}.raw"
# We don't need to check if it's the initial MVP OEM because it's an update payload provided for a particular version
echo "Trying to place /var/lib/update_engine/oem-${OEMID}-${NEXT_VERSION}.raw on OEM partition" >&2
if ! mv "/var/lib/update_engine/oem-${OEMID}.raw" "${NEW_SYSEXT}"; then
rm -f "${NEW_SYSEXT}"
echo "That failed, moving it to right location on root partition" >&2
NEW_SYSEXT="/etc/flatcar/oem-sysext/oem-${OEMID}-${NEXT_VERSION}.raw"
mv "/var/lib/update_engine/oem-${OEMID}.raw" "${NEW_SYSEXT}"
fi
if [ -e "${KEEP}" ] && [ -e "${NEW_SYSEXT}" ] && [ ! -e "${OEM_MNT}/sysext/active-oem-${OEMID}" ]; then
if [ -e "${INSTALL_MNT}/share/flatcar/oems/${OEMID}" ]; then
touch "${OEM_MNT}/sysext/migrate-oem-${OEMID}"
fi
touch "${OEM_MNT}/sysext/active-oem-${OEMID}"
fi
fi
# Download official Flatcar extensions
# The enabled-sysext.conf file is read from /etc and /usr and contains one name per line,
# and when the name is prefixed with a "-" it means that the extension should be disabled if enabled by default in the file from /usr.
# It may contain comments starting with "#" at the beginning of a line or after a name.
# The file is also used in bootengine to know which extensions to enable.
# Note that we don't need "{ grep || true ; }" to suppress the match return code because in for _ in $(grep...) return codes are ignored
for NAME in $(grep -h -o '^[^#]*' /etc/flatcar/enabled-sysext.conf /usr/share/flatcar/enabled-sysext.conf | grep -v -x -f <(grep '^-' /etc/flatcar/enabled-sysext.conf | cut -d - -f 2-) | grep -v -P '^(-).*'); do
KEEP="/etc/flatcar/sysext/flatcar-${NAME}-${VERSION}.raw"
shopt -s nullglob
# Delete sysext images that belonged to the now overwritten /usr partition but keep the sysext image for the current version
for OLD_IMAGE in /etc/flatcar/sysext/flatcar*raw; do
if [ "${OLD_IMAGE}" != "${KEEP}" ] && [ -f "${OLD_IMAGE}" ]; then
rm -f "${OLD_IMAGE}"
fi
done
# Note that in the case of VERSION=NEXT_VERSION we will replace the running sysext and maybe it's better
# to do so than not because it allows to recover from a corrupted file (where the corruption happened on disk)
SUCCESS=false
# Preferred is to download from the location given by the Omaha response
# which only works with a new update-engine client that creates "full-response",
# and we also have to check that this file was created fresh for this update operation
# (relies on the reset of /var/lib/update_engine/prefs/previous-version that old clients also do)
if [ -e /var/lib/update_engine/prefs/full-response ] && [ $(stat -L --printf='%Y' /var/lib/update_engine/prefs/full-response) -ge $(stat -L --printf='%Y' /var/lib/update_engine/prefs/previous-version) ]; then
rm -f "/var/lib/update_engine/flatcar-${NAME}.raw"
sysext_download "flatcar-${NAME}.gz" "/var/lib/update_engine/flatcar-${NAME}.raw" /var/lib/update_engine/prefs/full-response
fi
# If that was not provided due to updating from an old version or if the download failed, try the release server or bincache
if [ "${SUCCESS}" = false ]; then
rm -f "/var/lib/update_engine/flatcar-${NAME}.raw"
PAYLOADSERVER=release-server
PAYLOADNAME="flatcar-${NAME}.gz"
if [ "$(md5sum /usr/share/update_engine/update-payload-key.pub.pem | cut -d " " -f 1)" = "7192addf4a7f890c0057d21653eff2ea" ]; then
PAYLOADSERVER=bincache-server
PAYLOADNAME="flatcar_test_update-flatcar-${NAME}.gz"
fi
echo "Falling back to ${PAYLOADSERVER} for extension 'flatcar-${NAME}'" >&2
sysext_download "${PAYLOADNAME}" "/var/lib/update_engine/flatcar-${NAME}.raw" "${PAYLOADSERVER}"
fi
if [ "${SUCCESS}" = false ]; then
rm -f "/var/lib/update_engine/flatcar-${NAME}.raw"
echo "Failed to download required OEM update payload" >&2
exit 1
fi
mv "/var/lib/update_engine/flatcar-${NAME}.raw" "/etc/flatcar/sysext/flatcar-${NAME}-${NEXT_VERSION}.raw"
done
# A mkdir -p /etc/extensions was done for the OEM sysext symlink when the /etc overlay
# was already set up but we didn't ship /etc/extensions in the lowerdir. Since overlayfs
# creates any folders that don't exist in the lowerdir as opaque it means that when
# they appear later in the lowerdir through an update, the lowerdir folder is ignored.
# That happened in the update from, e.g., 3760.1.0 to 3794.0.0 to where /etc/extensions
# wasn't present in /usr/share/flatcar/etc/.
# To fix this, remove any opaque markers for this directory. Other common folders which
# we introduce later in the lowerdir could also be handled that way, e.g., /etc/cni/.
if mountpoint -q /etc; then
unshare -m sh -c "umount /etc && mkdir -p /etc/extensions && attr -R -r overlay.opaque /etc/extensions || true"
fi
# Keep old nodes on cgroup v1
if [[ "${BUILD_ID}" != "dev-"* ]]; then
if [ "${VERSION_ID%%.*}" -lt 2956 ]; then
# if there is an explicit setting, don't touch it. Otherwise...
if ! grep -q systemd.unified_cgroup_hierarchy "${OEM_MNT}/grub.cfg" 2>/dev/null; then
cat >>"${OEM_MNT}/grub.cfg" <<EOF
# Automatically added during update from ${VERSION_ID} to ${NEXT_VERSION_ID}
# Flatcar has migrated to cgroup v2. Your node has been kept on cgroup v1.
# Migrate at your own convenience by changing the value to '=1', or remove this
# line if you don't need to switch back ('systemd.legacy_systemd_cgroup_controller' only has effect for '=0').
# For more details visit:
# https://kinvolk.io/docs/flatcar-container-linux/latest/container-runtimes/switching-to-unified-cgroups
set linux_append="\$linux_append systemd.unified_cgroup_hierarchy=0 systemd.legacy_systemd_cgroup_controller"
EOF
fi
if ( systemctl show -p ExecStart containerd | \
grep -qF '/usr/bin/env PATH=${TORCX_BINDIR}:${PATH} ${TORCX_BINDIR}/containerd --config ${TORCX_UNPACKDIR}${TORCX_IMAGEDIR}${CONTAINERD_CONFIG}' ) && \
( systemctl show -p Environment containerd | \
grep -qF 'CONTAINERD_CONFIG=/usr/share/containerd/config.toml' ); then
mkdir -p /etc/systemd/system/containerd.service.d/
cat >/etc/systemd/system/containerd.service.d/10-use-cgroupfs.conf <<EOF
# Automatically created during update from ${VERSION_ID} to ${NEXT_VERSION_ID}
# Flatcar has migrated to cgroup v2. Your node has been kept on cgroup v1.
# For more details visit:
# https://kinvolk.io/docs/flatcar-container-linux/latest/container-runtimes/switching-to-unified-cgroups
[Service]
Environment=CONTAINERD_CONFIG=/usr/share/containerd/config-cgroupfs.toml
EOF
fi
fi
fi
# use the cgpt binary from the image to ensure compatibility
CGPT=
for bindir in bin/old_bins bin sbin; do
if [[ -x "${INSTALL_MNT}/${bindir}/cgpt" ]]; then
CGPT="${INSTALL_MNT}/${bindir}/cgpt"
break
fi
done
if [[ -z "${CGPT}" ]]; then
echo "Failed to locate the cgpt binary in ${INSTALL_MNT}" >&2
exit 1
fi
call_cgpt() {
"${LDSO}" --library-path "${LIBS}" "${CGPT}" "$@"
}
# locate the dynamic linker
LDSO=
# While glibc 2.33 has /lib64/ld-2.33.so, glibc 2.34 does not have
# that, but only /lib64/ld-linux-x86-64.so.2. So we should also check
# ld-linux-* as well.
#
# glibc 2.35 installs a symlink to the dynamic linker under
# /usr/bin/ld.so. Check this one too.
#
# Since we derive library path from the linker path, make sure we are
# dealing with the actual executable, not with a symlink. We do it by
# using realpath on the found file.
for l in "${INSTALL_MNT}"/{,usr/}bin/ld.so "${INSTALL_MNT}"/lib*/ld-2.??.so "${INSTALL_MNT}"/lib*/ld-linux-*.so.?; do
if [[ -x "$l" ]]; then
LDSO=$(realpath "$l")
break
fi
done
if [[ -z "${LDSO}" ]]; then
echo "Failed to locate ld.so in ${INSTALL_MNT}" >&2
exit 1
fi
LIBS="${LDSO%/*}"
# Mark the new install with one try and the highest priority
call_cgpt repair "${INSTALL_DEV}"
call_cgpt add -S0 -T1 "${INSTALL_DEV}"
call_cgpt prioritize "${INSTALL_DEV}"
call_cgpt show "${INSTALL_DEV}"
cat "${INSTALL_MNT}/share/flatcar/release"
echo "Setup ${INSTALL_LABEL} (${INSTALL_DEV}) for next boot."
# Create the Ubuntu-compatible /run/reboot-required flag file for kured
touch /run/reboot-required