]>
Commit | Line | Data |
---|---|---|
71d3a659 SG |
1 | #!/bin/sh |
2 | ||
3 | # Client script for LXC container images. | |
4 | # | |
5 | # Copyright © 2014 Stéphane Graber <stgraber@ubuntu.com> | |
6 | # | |
7 | # This library is free software; you can redistribute it and/or | |
8 | # modify it under the terms of the GNU Lesser General Public | |
9 | # License as published by the Free Software Foundation; either | |
10 | # version 2.1 of the License, or (at your option) any later version. | |
11 | ||
12 | # This library is distributed in the hope that it will be useful, | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | # Lesser General Public License for more details. | |
16 | ||
17 | # You should have received a copy of the GNU Lesser General Public | |
18 | # License along with this library; if not, write to the Free Software | |
19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |
20 | # USA | |
21 | ||
22 | set -eu | |
23 | ||
71d3a659 | 24 | LOCALSTATEDIR="@LOCALSTATEDIR@" |
f74e080c SG |
25 | LXC_HOOK_DIR="@LXCHOOKDIR@" |
26 | LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@" | |
71d3a659 SG |
27 | |
28 | # Defaults | |
71d3a659 | 29 | DOWNLOAD_ARCH= |
f74e080c | 30 | DOWNLOAD_BUILD= |
7a930fe7 | 31 | DOWNLOAD_COMPAT_LEVEL=7 |
f74e080c | 32 | DOWNLOAD_DIST= |
71d3a659 | 33 | DOWNLOAD_FLUSH_CACHE="false" |
41670b35 | 34 | DOWNLOAD_FORCE_CACHE="false" |
f74e080c | 35 | DOWNLOAD_INTERACTIVE="false" |
dd2dbcb9 | 36 | DOWNLOAD_KEYID="0xE7FB0CAEC8173D669066514CBAEFF88C22F6E216" |
f74e080c | 37 | DOWNLOAD_LIST_IMAGES="false" |
71d3a659 | 38 | DOWNLOAD_MODE="system" |
b0f0932a | 39 | DOWNLOAD_READY_GPG="false" |
f74e080c SG |
40 | DOWNLOAD_RELEASE= |
41 | DOWNLOAD_SERVER="images.linuxcontainers.org" | |
42 | DOWNLOAD_SHOW_GPG_WARNING="true" | |
43 | DOWNLOAD_SHOW_HTTP_WARNING="true" | |
44 | DOWNLOAD_TARGET="system" | |
45 | DOWNLOAD_URL= | |
46 | DOWNLOAD_USE_CACHE="false" | |
47 | DOWNLOAD_VALIDATE="true" | |
48 | DOWNLOAD_VARIANT="default" | |
edb5452c | 49 | DOWNLOAD_TEMP= |
67e7ac7b | 50 | DOWNLOAD_STANDARD_RESOLVER="false" |
71d3a659 | 51 | |
f74e080c SG |
52 | LXC_MAPPED_GID= |
53 | LXC_MAPPED_UID= | |
71d3a659 SG |
54 | LXC_NAME= |
55 | LXC_PATH= | |
56 | LXC_ROOTFS= | |
71d3a659 | 57 | |
a9a53b50 | 58 | if [ -z "${DOWNLOAD_KEYSERVER:-}" ]; then |
832cb182 | 59 | DOWNLOAD_KEYSERVER="hkp://pool.sks-keyservers.net" |
a6a7c7d1 | 60 | |
832cb182 CB |
61 | # Deal with GPG over http proxy |
62 | if [ -n "${http_proxy:-}" ]; then | |
63 | DOWNLOAD_KEYSERVER="hkp://p80.pool.sks-keyservers.net:80" | |
41440801 | 64 | DOWNLOAD_GPG_PROXY="--keyserver-options http-proxy=\"${http_proxy}\"" |
832cb182 | 65 | fi |
4eb706b3 SG |
66 | fi |
67 | ||
207bf0e4 | 68 | # Make sure the usual locations are in PATH |
655d10ed | 69 | export PATH="$PATH:/usr/sbin:/usr/bin:/sbin:/bin" |
207bf0e4 | 70 | |
71d3a659 SG |
71 | # Some useful functions |
72 | cleanup() { | |
832cb182 CB |
73 | if [ -d "${DOWNLOAD_TEMP}" ]; then |
74 | rm -Rf "${DOWNLOAD_TEMP}" | |
75 | fi | |
71d3a659 SG |
76 | } |
77 | ||
acabe1fa | 78 | wget_wrapper() { |
832cb182 CB |
79 | for _ in $(seq 3); do |
80 | if wget "$@"; then | |
81 | return 0 | |
82 | fi | |
83 | done | |
acabe1fa | 84 | |
832cb182 | 85 | return 1 |
acabe1fa SG |
86 | } |
87 | ||
71d3a659 | 88 | download_file() { |
832cb182 CB |
89 | if ! wget_wrapper -T 30 -q "https://${DOWNLOAD_SERVER}/$1" -O "$2" >/dev/null 2>&1; then |
90 | if ! wget_wrapper -T 30 -q "http://${DOWNLOAD_SERVER}/$1" -O "$2" >/dev/null 2>&1; then | |
91 | if [ "$3" = "noexit" ]; then | |
92 | return 1 | |
93 | else | |
94 | echo "ERROR: Failed to download http://${DOWNLOAD_SERVER}/$1" 1>&2 | |
95 | exit 1 | |
96 | fi | |
97 | elif [ "${DOWNLOAD_SHOW_HTTP_WARNING}" = "true" ]; then | |
98 | DOWNLOAD_SHOW_HTTP_WARNING="false" | |
99 | echo "WARNING: Failed to download the file over HTTPs" 1>&2 | |
100 | echo " The file was instead download over HTTP " 1>&2 | |
101 | echo "A server replay attack may be possible!" 1>&2 | |
71d3a659 | 102 | fi |
832cb182 | 103 | fi |
71d3a659 SG |
104 | } |
105 | ||
fad96766 | 106 | download_sig() { |
832cb182 CB |
107 | if ! download_file "$1" "$2" noexit; then |
108 | if [ "${DOWNLOAD_VALIDATE}" = "true" ]; then | |
109 | if [ "$3" = "normal" ]; then | |
110 | echo "ERROR: Failed to download http://${DOWNLOAD_SERVER}/$1" 1>&2 | |
111 | exit 1 | |
112 | else | |
113 | return 1 | |
114 | fi | |
115 | else | |
116 | return 0 | |
fad96766 | 117 | fi |
832cb182 | 118 | fi |
fad96766 DE |
119 | } |
120 | ||
71d3a659 | 121 | gpg_setup() { |
832cb182 CB |
122 | if [ "${DOWNLOAD_VALIDATE}" = "false" ]; then |
123 | return | |
124 | fi | |
125 | ||
126 | if [ "${DOWNLOAD_READY_GPG}" = "true" ]; then | |
127 | return | |
128 | fi | |
129 | ||
130 | echo "Setting up the GPG keyring" | |
131 | ||
132 | mkdir -p "${DOWNLOAD_TEMP}/gpg" | |
133 | chmod 700 "${DOWNLOAD_TEMP}/gpg" | |
67e7ac7b AD |
134 | |
135 | if [ "${DOWNLOAD_STANDARD_RESOLVER}" = "true" ]; then | |
136 | echo "standard-resolver" > "${DOWNLOAD_TEMP}/gpg/dirmngr.conf" | |
137 | fi | |
832cb182 CB |
138 | export GNUPGHOME="${DOWNLOAD_TEMP}/gpg" |
139 | ||
140 | success= | |
141 | for _ in $(seq 3); do | |
18e18d4c | 142 | if gpg --keyserver "${DOWNLOAD_KEYSERVER}" ${DOWNLOAD_GPG_PROXY:-} \ |
459fef26 | 143 | --recv-keys "${DOWNLOAD_KEYID}" >/dev/null 2>&1; then |
832cb182 CB |
144 | success=1 |
145 | break | |
71d3a659 | 146 | fi |
832cb182 | 147 | done |
71d3a659 | 148 | |
832cb182 CB |
149 | if [ -z "${success}" ]; then |
150 | echo "ERROR: Unable to fetch GPG key from keyserver" | |
151 | exit 1 | |
152 | fi | |
b0f0932a | 153 | |
832cb182 | 154 | DOWNLOAD_READY_GPG="true" |
71d3a659 SG |
155 | } |
156 | ||
157 | gpg_validate() { | |
832cb182 CB |
158 | if [ "${DOWNLOAD_VALIDATE}" = "false" ]; then |
159 | if [ "${DOWNLOAD_SHOW_GPG_WARNING}" = "true" ]; then | |
160 | echo "WARNING: Running without gpg validation!" 1>&2 | |
71d3a659 | 161 | fi |
832cb182 CB |
162 | DOWNLOAD_SHOW_GPG_WARNING="false" |
163 | return 0 | |
164 | fi | |
71d3a659 | 165 | |
832cb182 CB |
166 | if ! gpg --verify "$1" >/dev/null 2>&1; then |
167 | echo "ERROR: Invalid signature for $1" 1>&2 | |
168 | exit 1 | |
169 | fi | |
71d3a659 SG |
170 | } |
171 | ||
172 | in_userns() { | |
832cb182 CB |
173 | [ -e /proc/self/uid_map ] || { echo no; return; } |
174 | while read -r line; do | |
175 | fields="$(echo "$line" | awk '{ print $1 " " $2 " " $3 }')" | |
176 | if [ "${fields}" = "0 0 4294967295" ]; then | |
177 | echo no; | |
178 | return; | |
179 | fi | |
180 | if echo "${fields}" | grep -q " 0 1$"; then | |
181 | echo userns-root; | |
182 | return; | |
183 | fi | |
184 | done < /proc/self/uid_map | |
185 | ||
16a312e1 LP |
186 | if [ -e /proc/1/uid_map ]; then |
187 | if [ "$(cat /proc/self/uid_map)" = "$(cat /proc/1/uid_map)" ]; then | |
188 | echo userns-root | |
189 | return | |
190 | fi | |
191 | fi | |
832cb182 | 192 | echo yes |
71d3a659 SG |
193 | } |
194 | ||
195 | relevant_file() { | |
832cb182 CB |
196 | FILE_PATH="${LXC_CACHE_PATH}/$1" |
197 | ||
198 | if [ -e "${FILE_PATH}-${DOWNLOAD_MODE}" ]; then | |
199 | FILE_PATH="${FILE_PATH}-${DOWNLOAD_MODE}" | |
200 | fi | |
71d3a659 | 201 | |
832cb182 CB |
202 | if [ -e "${FILE_PATH}.${DOWNLOAD_COMPAT_LEVEL}" ]; then |
203 | FILE_PATH="${FILE_PATH}.${DOWNLOAD_COMPAT_LEVEL}" | |
204 | fi | |
205 | ||
206 | echo "${FILE_PATH}" | |
71d3a659 SG |
207 | } |
208 | ||
209 | usage() { | |
832cb182 | 210 | cat <<EOF |
71d3a659 SG |
211 | LXC container image downloader |
212 | ||
7d540a26 | 213 | Special arguments: |
832cb182 CB |
214 | [ -h | --help ]: Print this help message and exit |
215 | [ -l | --list ]: List all available images and exit | |
7d540a26 | 216 | |
71d3a659 SG |
217 | Required arguments: |
218 | [ -d | --dist <distribution> ]: The name of the distribution | |
219 | [ -r | --release <release> ]: Release name/version | |
220 | [ -a | --arch <architecture> ]: Architecture of the container | |
71d3a659 SG |
221 | |
222 | Optional arguments: | |
223 | [ --variant <variant> ]: Variant of the image (default: "default") | |
224 | [ --server <server> ]: Image server (default: "images.linuxcontainers.org") | |
225 | [ --keyid <keyid> ]: GPG keyid (default: 0x...) | |
d2e5c5d1 | 226 | [ --keyserver <keyserver> ]: GPG keyserver to use. Environment variable: DOWNLOAD_KEYSERVER |
71d3a659 SG |
227 | [ --no-validate ]: Disable GPG validation (not recommended) |
228 | [ --flush-cache ]: Flush the local copy (if present) | |
e145b7bb | 229 | [ --force-cache ]: Force the use of the local copy even if expired |
67e7ac7b | 230 | [ --standard-resolver ]: Force the use of the standard resolver |
71d3a659 SG |
231 | |
232 | LXC internal arguments (do not pass manually!): | |
233 | [ --name <name> ]: The container name | |
234 | [ --path <path> ]: The path to the container | |
235 | [ --rootfs <rootfs> ]: The path to the container's rootfs | |
2133f58c SH |
236 | [ --mapped-uid <map> ]: A uid map (user namespaces) |
237 | [ --mapped-gid <map> ]: A gid map (user namespaces) | |
d2e5c5d1 TK |
238 | |
239 | Environment Variables: | |
240 | DOWNLOAD_KEYSERVER : The URL of the key server to use, instead of the default. | |
241 | Can be further overridden by using optional argument --keyserver | |
242 | ||
71d3a659 | 243 | EOF |
832cb182 | 244 | return 0 |
71d3a659 SG |
245 | } |
246 | ||
3f7be9d0 | 247 | if ! options=$(getopt -o d:r:a:hl -l dist:,release:,arch:,help,list,variant:,\ |
3cd988cc | 248 | server:,keyid:,keyserver:,no-validate,flush-cache,force-cache,name:,path:,\ |
3f7be9d0 | 249 | rootfs:,mapped-uid:,mapped-gid: -- "$@"); then |
832cb182 CB |
250 | usage |
251 | exit 1 | |
71d3a659 SG |
252 | fi |
253 | eval set -- "$options" | |
254 | ||
255 | while :; do | |
832cb182 CB |
256 | case "$1" in |
257 | -h|--help) usage && exit 1;; | |
258 | -l|--list) DOWNLOAD_LIST_IMAGES="true"; shift 1;; | |
259 | -d|--dist) DOWNLOAD_DIST="$2"; shift 2;; | |
260 | -r|--release) DOWNLOAD_RELEASE="$2"; shift 2;; | |
261 | -a|--arch) DOWNLOAD_ARCH="$2"; shift 2;; | |
262 | --variant) DOWNLOAD_VARIANT="$2"; shift 2;; | |
263 | --server) DOWNLOAD_SERVER="$2"; shift 2;; | |
264 | --keyid) DOWNLOAD_KEYID="$2"; shift 2;; | |
265 | --keyserver) DOWNLOAD_KEYSERVER="$2"; shift 2;; | |
266 | --no-validate) DOWNLOAD_VALIDATE="false"; shift 1;; | |
267 | --flush-cache) DOWNLOAD_FLUSH_CACHE="true"; shift 1;; | |
268 | --force-cache) DOWNLOAD_FORCE_CACHE="true"; shift 1;; | |
67e7ac7b | 269 | --standard-resolver) STANDARD_RESOLVER="true"; shift 1;; |
832cb182 CB |
270 | --name) LXC_NAME="$2"; shift 2;; |
271 | --path) LXC_PATH="$2"; shift 2;; | |
272 | --rootfs) LXC_ROOTFS="$2"; shift 2;; | |
273 | --mapped-uid) LXC_MAPPED_UID="$2"; shift 2;; | |
274 | --mapped-gid) LXC_MAPPED_GID="$2"; shift 2;; | |
275 | *) break;; | |
276 | esac | |
71d3a659 SG |
277 | done |
278 | ||
279 | # Check for required binaries | |
280 | for bin in tar xz wget; do | |
832cb182 CB |
281 | if ! command -V "${bin}" >/dev/null 2>&1; then |
282 | echo "ERROR: Missing required tool: ${bin}" 1>&2 | |
283 | exit 1 | |
284 | fi | |
71d3a659 SG |
285 | done |
286 | ||
287 | # Check for GPG | |
3f7be9d0 | 288 | if [ "${DOWNLOAD_VALIDATE}" = "true" ]; then |
832cb182 CB |
289 | if ! command -V gpg >/dev/null 2>&1; then |
290 | echo "ERROR: Missing recommended tool: gpg" 1>&2 | |
291 | echo "You can workaround this by using --no-validate" 1>&2 | |
292 | exit 1 | |
293 | fi | |
71d3a659 SG |
294 | fi |
295 | ||
296 | # Check that we have all variables we need | |
3f7be9d0 | 297 | if [ -z "${LXC_NAME}" ] || [ -z "${LXC_PATH}" ] || [ -z "${LXC_ROOTFS}" ]; then |
832cb182 CB |
298 | if [ "${DOWNLOAD_LIST_IMAGES}" != "true" ]; then |
299 | echo "ERROR: Please pass the name, path, and rootfs for the container" 1>&2 | |
300 | exit 1 | |
301 | fi | |
71d3a659 SG |
302 | fi |
303 | ||
3f7be9d0 | 304 | USERNS="$(in_userns)" |
f74e080c | 305 | |
3f7be9d0 | 306 | if [ "${USERNS}" != "no" ]; then |
832cb182 CB |
307 | if [ "${USERNS}" = "yes" ]; then |
308 | if [ -z "${LXC_MAPPED_UID}" ] || [ "${LXC_MAPPED_UID}" = "-1" ]; then | |
309 | echo "ERROR: In a user namespace without a map" 1>&2 | |
310 | exit 1 | |
71d3a659 | 311 | fi |
832cb182 CB |
312 | DOWNLOAD_MODE="user" |
313 | DOWNLOAD_TARGET="user" | |
314 | else | |
315 | DOWNLOAD_MODE="user" | |
316 | DOWNLOAD_TARGET="system" | |
317 | fi | |
71d3a659 SG |
318 | fi |
319 | ||
832cb182 CB |
320 | if [ -z "${DOWNLOAD_DIST}" ] || [ -z "${DOWNLOAD_RELEASE}" ] || [ -z "${DOWNLOAD_ARCH}" ]; then |
321 | DOWNLOAD_INTERACTIVE="true" | |
71d3a659 SG |
322 | fi |
323 | ||
324 | # Trap all exit signals | |
325 | trap cleanup EXIT HUP INT TERM | |
843a5874 | 326 | |
edb5452c SC |
327 | # /tmp may be mounted in tmpfs or noexec |
328 | if mountpoint -q /tmp; then | |
832cb182 | 329 | DOWNLOAD_TEMP="${LXC_PATH}" |
edb5452c SC |
330 | fi |
331 | ||
3f7be9d0 | 332 | if ! command -V mktemp >/dev/null 2>&1; then |
832cb182 | 333 | DOWNLOAD_TEMP="${DOWNLOAD_TEMP}/tmp/lxc-download.$$" |
30c8676e CB |
334 | elif [ -n "${DOWNLOAD_TEMP}" ]; then |
335 | mkdir -p "${DOWNLOAD_TEMP}" | |
eb44984a | 336 | DOWNLOAD_TEMP="$(mktemp -p "${DOWNLOAD_TEMP}" -d)" |
30c8676e CB |
337 | else |
338 | DOWNLOAD_TEMP="${DOWNLOAD_TEMP}$(mktemp -d)" | |
843a5874 | 339 | fi |
71d3a659 | 340 | |
10a5fab6 | 341 | # Simply list images |
832cb182 CB |
342 | if [ "${DOWNLOAD_LIST_IMAGES}" = "true" ] || [ "${DOWNLOAD_INTERACTIVE}" = "true" ]; then |
343 | # Initialize GPG | |
344 | gpg_setup | |
345 | ||
346 | # Grab the index | |
347 | DOWNLOAD_INDEX_PATH="/meta/1.0/index-${DOWNLOAD_MODE}" | |
348 | ||
349 | echo "Downloading the image index" | |
350 | if ! download_file "${DOWNLOAD_INDEX_PATH}.${DOWNLOAD_COMPAT_LEVEL}" "${DOWNLOAD_TEMP}/index" noexit || | |
351 | ! download_sig "${DOWNLOAD_INDEX_PATH}.${DOWNLOAD_COMPAT_LEVEL}.asc" "${DOWNLOAD_TEMP}/index.asc" noexit; then | |
352 | download_file "${DOWNLOAD_INDEX_PATH}" "${DOWNLOAD_TEMP}/index" normal | |
353 | download_sig "${DOWNLOAD_INDEX_PATH}.asc" "${DOWNLOAD_TEMP}/index.asc" normal | |
354 | fi | |
355 | ||
356 | gpg_validate "${DOWNLOAD_TEMP}/index.asc" | |
357 | ||
358 | # Parse it | |
359 | echo "" | |
360 | echo "---" | |
361 | printf "DIST\tRELEASE\tARCH\tVARIANT\tBUILD\n" | |
362 | echo "---" | |
363 | while IFS=';' read -r f1 f2 f3 f4 f5 f6; do | |
364 | [ -n "${DOWNLOAD_DIST}" ] && [ "$f1" != "${DOWNLOAD_DIST}" ] && continue | |
365 | [ -n "${DOWNLOAD_RELEASE}" ] && [ "$f2" != "${DOWNLOAD_RELEASE}" ] && continue | |
366 | [ -n "${DOWNLOAD_ARCH}" ] && [ "$f3" != "${DOWNLOAD_ARCH}" ] && continue | |
367 | [ -n "${DOWNLOAD_VARIANT}" ] && [ "$f4" != "${DOWNLOAD_VARIANT}" ] && continue | |
368 | [ -z "${f5}" ] || [ -z "${f6}" ] && continue | |
369 | ||
370 | printf "%s\t%s\t%s\t%s\t%s\n" "${f1}" "${f2}" "${f3}" "${f4}" "${f5}" | |
371 | unset f1 f2 f3 f4 f5 f6 | |
372 | done < "${DOWNLOAD_TEMP}/index" | |
373 | echo "---" | |
374 | ||
375 | if [ "${DOWNLOAD_LIST_IMAGES}" = "true" ]; then | |
376 | exit 1 | |
377 | fi | |
b0f0932a | 378 | |
832cb182 CB |
379 | # Interactive mode |
380 | echo "" | |
b0f0932a | 381 | |
832cb182 CB |
382 | if [ -z "${DOWNLOAD_DIST}" ]; then |
383 | echo "Distribution: " | |
384 | read -r DOWNLOAD_DIST | |
385 | fi | |
b0f0932a | 386 | |
832cb182 CB |
387 | if [ -z "${DOWNLOAD_RELEASE}" ]; then |
388 | echo "Release: " | |
389 | read -r DOWNLOAD_RELEASE | |
390 | fi | |
b0f0932a | 391 | |
832cb182 CB |
392 | if [ -z "${DOWNLOAD_ARCH}" ]; then |
393 | echo "Architecture: " | |
394 | read -r DOWNLOAD_ARCH | |
395 | fi | |
b0f0932a | 396 | |
832cb182 | 397 | echo "" |
10a5fab6 SG |
398 | fi |
399 | ||
71d3a659 | 400 | # Setup the cache |
3f7be9d0 | 401 | if [ "${DOWNLOAD_TARGET}" = "system" ]; then |
832cb182 | 402 | LXC_CACHE_BASE="${LOCALSTATEDIR}/cache/lxc/" |
71d3a659 | 403 | else |
832cb182 | 404 | LXC_CACHE_BASE="${HOME}/.cache/lxc/" |
71d3a659 SG |
405 | fi |
406 | ||
6dc6f80b | 407 | # Allow the setting of the LXC_CACHE_PATH with the usage of environment variables. |
3f7be9d0 WG |
408 | LXC_CACHE_PATH="${LXC_CACHE_PATH:-"${LXC_CACHE_BASE}"}" |
409 | LXC_CACHE_PATH="${LXC_CACHE_PATH}/download/${DOWNLOAD_DIST}" | |
410 | LXC_CACHE_PATH="${LXC_CACHE_PATH}/${DOWNLOAD_RELEASE}/${DOWNLOAD_ARCH}/" | |
411 | LXC_CACHE_PATH="${LXC_CACHE_PATH}/${DOWNLOAD_VARIANT}" | |
b56661fe | 412 | |
3f7be9d0 | 413 | if [ -d "${LXC_CACHE_PATH}" ]; then |
832cb182 CB |
414 | if [ "${DOWNLOAD_FLUSH_CACHE}" = "true" ]; then |
415 | echo "Flushing the cache..." | |
416 | rm -Rf "${LXC_CACHE_PATH}" | |
417 | elif [ "${DOWNLOAD_FORCE_CACHE}" = "true" ]; then | |
418 | DOWNLOAD_USE_CACHE="true" | |
419 | else | |
420 | DOWNLOAD_USE_CACHE="true" | |
421 | if [ -e "$(relevant_file expiry)" ]; then | |
422 | if [ "$(cat "$(relevant_file expiry)")" -lt "$(date +%s)" ]; then | |
423 | echo "The cached copy has expired, re-downloading..." | |
424 | DOWNLOAD_USE_CACHE="false" | |
425 | fi | |
71d3a659 | 426 | fi |
832cb182 | 427 | fi |
71d3a659 SG |
428 | fi |
429 | ||
430 | # Download what's needed | |
3f7be9d0 | 431 | if [ "${DOWNLOAD_USE_CACHE}" = "false" ]; then |
832cb182 CB |
432 | # Initialize GPG |
433 | gpg_setup | |
434 | ||
435 | # Grab the index | |
436 | DOWNLOAD_INDEX_PATH="/meta/1.0/index-${DOWNLOAD_MODE}" | |
437 | ||
438 | echo "Downloading the image index" | |
439 | if ! download_file "${DOWNLOAD_INDEX_PATH}.${DOWNLOAD_COMPAT_LEVEL}" "${DOWNLOAD_TEMP}/index" noexit || | |
440 | ! download_sig "${DOWNLOAD_INDEX_PATH}.${DOWNLOAD_COMPAT_LEVEL}.asc" "${DOWNLOAD_TEMP}/index.asc" noexit; then | |
441 | download_file "${DOWNLOAD_INDEX_PATH}" "${DOWNLOAD_TEMP}/index" normal | |
442 | download_sig "${DOWNLOAD_INDEX_PATH}.asc" "${DOWNLOAD_TEMP}/index.asc" normal | |
443 | fi | |
444 | ||
445 | gpg_validate "${DOWNLOAD_TEMP}/index.asc" | |
446 | ||
447 | # Parse it | |
448 | while IFS=';' read -r f1 f2 f3 f4 f5 f6; do | |
449 | if [ "${f1}" != "${DOWNLOAD_DIST}" ] || \ | |
450 | [ "${f2}" != "${DOWNLOAD_RELEASE}" ] || \ | |
451 | [ "${f3}" != "${DOWNLOAD_ARCH}" ] || \ | |
452 | [ "${f4}" != "${DOWNLOAD_VARIANT}" ] || \ | |
453 | [ -z "${f6}" ]; then | |
454 | continue | |
71d3a659 SG |
455 | fi |
456 | ||
832cb182 CB |
457 | DOWNLOAD_BUILD="${f5}" |
458 | DOWNLOAD_URL="${f6}" | |
71d3a659 | 459 | |
832cb182 CB |
460 | unset f1 f2 f3 f4 f5 f6 |
461 | break | |
462 | done < "${DOWNLOAD_TEMP}/index" | |
3f7be9d0 | 463 | |
832cb182 CB |
464 | if [ -z "${DOWNLOAD_URL}" ]; then |
465 | echo "ERROR: Couldn't find a matching image" 1>&1 | |
466 | exit 1 | |
467 | fi | |
71d3a659 | 468 | |
832cb182 CB |
469 | if [ -d "${LXC_CACHE_PATH}" ] && [ -f "${LXC_CACHE_PATH}/build_id" ] && \ |
470 | [ "$(cat "${LXC_CACHE_PATH}/build_id")" = "${DOWNLOAD_BUILD}" ]; then | |
471 | echo "The cache is already up to date" | |
472 | echo "Using image from local cache" | |
473 | else | |
474 | # Download the actual files | |
475 | echo "Downloading the rootfs" | |
476 | download_file "${DOWNLOAD_URL}/rootfs.tar.xz" "${DOWNLOAD_TEMP}/rootfs.tar.xz" normal | |
477 | download_sig "${DOWNLOAD_URL}/rootfs.tar.xz.asc" "${DOWNLOAD_TEMP}/rootfs.tar.xz.asc" normal | |
478 | gpg_validate "${DOWNLOAD_TEMP}/rootfs.tar.xz.asc" | |
479 | ||
480 | echo "Downloading the metadata" | |
481 | download_file "${DOWNLOAD_URL}/meta.tar.xz" "${DOWNLOAD_TEMP}/meta.tar.xz" normal | |
482 | download_sig "$DOWNLOAD_URL/meta.tar.xz.asc" "${DOWNLOAD_TEMP}/meta.tar.xz.asc" normal | |
483 | gpg_validate "${DOWNLOAD_TEMP}/meta.tar.xz.asc" | |
484 | ||
485 | if [ -d "${LXC_CACHE_PATH}" ]; then | |
486 | rm -Rf "${LXC_CACHE_PATH}" | |
487 | fi | |
488 | mkdir -p "${LXC_CACHE_PATH}" | |
489 | mv "${DOWNLOAD_TEMP}/rootfs.tar.xz" "${LXC_CACHE_PATH}" | |
490 | if ! tar Jxf "${DOWNLOAD_TEMP}/meta.tar.xz" -C "${LXC_CACHE_PATH}"; then | |
491 | echo "ERROR: Invalid rootfs tarball." 2>&1 | |
492 | exit 1 | |
493 | fi | |
3f7be9d0 | 494 | |
832cb182 | 495 | echo "${DOWNLOAD_BUILD}" > "${LXC_CACHE_PATH}/build_id" |
71d3a659 | 496 | |
832cb182 CB |
497 | if [ -n "${LXC_MAPPED_UID}" ] && [ "${LXC_MAPPED_UID}" != "-1" ]; then |
498 | # As the script is run in strict mode (set -eu), all commands | |
499 | # exiting with non 0 would make the script stop. | |
500 | # || true or || : (more portable) prevents that. | |
501 | chown -R "${LXC_MAPPED_UID}" "${LXC_CACHE_BASE}" >/dev/null 2>&1 || : | |
71d3a659 | 502 | fi |
832cb182 CB |
503 | if [ -n "${LXC_MAPPED_GID}" ] && [ "${LXC_MAPPED_GID}" != "-1" ]; then |
504 | chgrp -R "${LXC_MAPPED_GID}" "${LXC_CACHE_BASE}" >/dev/null 2>&1 || : | |
71d3a659 | 505 | fi |
832cb182 CB |
506 | echo "The image cache is now ready" |
507 | fi | |
71d3a659 | 508 | else |
832cb182 | 509 | echo "Using image from local cache" |
71d3a659 SG |
510 | fi |
511 | ||
512 | # Unpack the rootfs | |
513 | echo "Unpacking the rootfs" | |
fecf101c SG |
514 | |
515 | EXCLUDES="" | |
516 | excludelist=$(relevant_file excludes) | |
517 | if [ -f "${excludelist}" ]; then | |
832cb182 CB |
518 | while read -r line; do |
519 | EXCLUDES="${EXCLUDES} --exclude=${line}" | |
520 | done < "${excludelist}" | |
71d3a659 SG |
521 | fi |
522 | ||
3f7be9d0 WG |
523 | # Do not surround ${EXCLUDES} by quotes. This does not work. The solution could |
524 | # use array but this is not POSIX compliant. The only POSIX compliant solution | |
525 | # is to use a function wrapper, but the latter can't be used here as the args | |
526 | # are dynamic. We thus need to ignore the warning brought by shellcheck. | |
527 | # shellcheck disable=SC2086 | |
832cb182 | 528 | tar --anchored ${EXCLUDES} --numeric-owner -xpJf "${LXC_CACHE_PATH}/rootfs.tar.xz" -C "${LXC_ROOTFS}" |
fecf101c | 529 | |
3f7be9d0 | 530 | mkdir -p "${LXC_ROOTFS}/dev/pts/" |
fecf101c | 531 | |
71d3a659 | 532 | # Setup the configuration |
3f7be9d0 WG |
533 | configfile="$(relevant_file config)" |
534 | fstab="$(relevant_file fstab)" | |
535 | if [ ! -e "${configfile}" ]; then | |
832cb182 CB |
536 | echo "ERROR: meta tarball is missing the configuration file" 1>&2 |
537 | exit 1 | |
71d3a659 SG |
538 | fi |
539 | ||
540 | ## Extract all the network config entries | |
832cb182 | 541 | sed -i -e "/lxc.net.0/{w ${LXC_PATH}/config-network" -e "d}" "${LXC_PATH}/config" |
71d3a659 SG |
542 | |
543 | ## Extract any other config entry | |
3f7be9d0 | 544 | sed -i -e "/lxc./{w ${LXC_PATH}/config-auto" -e "d}" "${LXC_PATH}/config" |
71d3a659 SG |
545 | |
546 | ## Append the defaults | |
832cb182 CB |
547 | { |
548 | echo "" | |
549 | echo "# Distribution configuration" | |
550 | cat "$configfile" | |
551 | } >> "${LXC_PATH}/config" | |
71d3a659 SG |
552 | |
553 | ## Add the container-specific config | |
832cb182 CB |
554 | { |
555 | echo "" | |
556 | echo "# Container specific configuration" | |
557 | if [ -e "${LXC_PATH}/config-auto" ]; then | |
558 | cat "${LXC_PATH}/config-auto" | |
3f7be9d0 | 559 | rm "${LXC_PATH}/config-auto" |
832cb182 CB |
560 | fi |
561 | if [ -e "${fstab}" ]; then | |
562 | echo "lxc.mount.fstab = ${LXC_PATH}/fstab" | |
563 | fi | |
564 | echo "lxc.uts.name = ${LXC_NAME}" | |
565 | } >> "${LXC_PATH}/config" | |
71d3a659 SG |
566 | |
567 | ## Re-add the previously removed network config | |
568 | if [ -e "${LXC_PATH}/config-network" ]; then | |
832cb182 CB |
569 | { |
570 | echo "" | |
571 | echo "# Network configuration" | |
572 | cat "${LXC_PATH}/config-network" | |
3f7be9d0 | 573 | rm "${LXC_PATH}/config-network" |
832cb182 | 574 | } >> "${LXC_PATH}/config" |
71d3a659 SG |
575 | fi |
576 | ||
577 | TEMPLATE_FILES="${LXC_PATH}/config" | |
578 | ||
579 | # Setup the fstab | |
3f7be9d0 | 580 | if [ -e "${fstab}" ]; then |
832cb182 CB |
581 | cp "${fstab}" "${LXC_PATH}/fstab" |
582 | TEMPLATE_FILES="${TEMPLATE_FILES};${LXC_PATH}/fstab" | |
71d3a659 SG |
583 | fi |
584 | ||
585 | # Look for extra templates | |
586 | if [ -e "$(relevant_file templates)" ]; then | |
832cb182 CB |
587 | while read -r line; do |
588 | fullpath="${LXC_ROOTFS}/${line}" | |
589 | [ ! -e "${fullpath}" ] && continue | |
590 | TEMPLATE_FILES="${TEMPLATE_FILES};${fullpath}" | |
591 | done < "$(relevant_file templates)" | |
71d3a659 SG |
592 | fi |
593 | ||
594 | # Replace variables in all templates | |
3f7be9d0 WG |
595 | OLD_IFS=${IFS} |
596 | IFS=";" | |
597 | for file in ${TEMPLATE_FILES}; do | |
598 | [ ! -f "${file}" ] && continue | |
832cb182 CB |
599 | sed -i "s#LXC_NAME#${LXC_NAME}#g" "${file}" |
600 | sed -i "s#LXC_PATH#${LXC_PATH}#g" "${file}" | |
601 | sed -i "s#LXC_ROOTFS#${LXC_ROOTFS}#g" "${file}" | |
602 | sed -i "s#LXC_TEMPLATE_CONFIG#${LXC_TEMPLATE_CONFIG}#g" "${file}" | |
603 | sed -i "s#LXC_HOOK_DIR#${LXC_HOOK_DIR}#g" "${file}" | |
71d3a659 | 604 | done |
3f7be9d0 | 605 | IFS=${OLD_IFS} |
71d3a659 | 606 | |
491a01cf | 607 | # prevent mingetty from calling vhangup(2) since it fails with userns on CentOS / Oracle |
3f7be9d0 | 608 | if [ -f "${LXC_ROOTFS}/etc/init/tty.conf" ]; then |
832cb182 | 609 | sed -i 's|mingetty|mingetty --nohangup|' "${LXC_ROOTFS}/etc/init/tty.conf" |
6e53ca56 SC |
610 | fi |
611 | ||
3f7be9d0 | 612 | if [ -n "${LXC_MAPPED_UID}" ] && [ "${LXC_MAPPED_UID}" != "-1" ]; then |
832cb182 | 613 | chown "${LXC_MAPPED_UID}" "${LXC_PATH}/config" "${LXC_PATH}/fstab" >/dev/null 2>&1 || : |
71d3a659 | 614 | fi |
832cb182 | 615 | |
3f7be9d0 | 616 | if [ -n "${LXC_MAPPED_GID}" ] && [ "${LXC_MAPPED_GID}" != "-1" ]; then |
832cb182 | 617 | chgrp "${LXC_MAPPED_GID}" "${LXC_PATH}/config" "${LXC_PATH}/fstab" >/dev/null 2>&1 || : |
2133f58c | 618 | fi |
71d3a659 SG |
619 | |
620 | if [ -e "$(relevant_file create-message)" ]; then | |
832cb182 CB |
621 | echo "" |
622 | echo "---" | |
623 | cat "$(relevant_file create-message)" | |
71d3a659 SG |
624 | fi |
625 | ||
626 | exit 0 |