~julian-edwards/maas/commissioning_error_check_bug_1239668

« back to all changes in this revision

Viewing changes to scripts/maas-import-ephemerals

  • Committer: Tarmac
  • Author(s): Raphael Badin
  • Date: 2013-10-09 07:58:23 UTC
  • mfrom: (1656.2.4 use-new-import-script)
  • Revision ID: tarmac-20131009075823-f68tyd0oxs2sbi50
[r=andreserl][bug=][author=rvb] Use maas-import-ephemerals.py instead of maas-import-ephemerals.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/bin/bash
2
 
#
3
 
# maas-import-ephemerals - sync and import ephemeral images
4
 
#
5
 
# Copyright (C) 2011-2012 Canonical
6
 
#
7
 
# Authors:
8
 
#    Scott Moser <scott.moser@canonical.com>
9
 
#
10
 
# This program is free software: you can redistribute it and/or modify
11
 
# it under the terms of the GNU Affero General Public License as
12
 
# published by the Free Software Foundation, version 3 of the License.
13
 
#
14
 
# This program is distributed in the hope that it will be useful,
15
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
# GNU Affero General Public License for more details.
18
 
#
19
 
# You should have received a copy of the GNU Affero General Public License
20
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
 
22
 
# WARNING: This script is obsolescent.  It is being replaced with
23
 
# maas-import-ephemerals.py.
24
 
 
25
 
VERBOSITY=0
26
 
 
27
 
# Mirror to load cloud images from.  When the cluster controller runs the
28
 
# import scripts, it provides a setting from the server side.
29
 
CLOUD_IMAGES_ARCHIVE=${CLOUD_IMAGES_ARCHIVE:-https://maas.ubuntu.com/images}
30
 
 
31
 
# iSCSI targets configuration file.
32
 
SYS_TGT_CONF="/etc/tgt/targets.conf"
33
 
 
34
 
# Prefix for iSCSI target name.
35
 
TARGET_NAME_PREFIX="iqn.2004-05.com.ubuntu:maas:"
36
 
 
37
 
# TODO: What's this for?  If set, it gets run on a downloaded disk.img,
38
 
# kernel, and initrd.
39
 
EPH_UPDATE_CMD=""
40
 
 
41
 
# TODO: DATA_DIR seems to be the root of a directory tree that's exposed over
42
 
# iSCSI for download by nodes.  Can we confirm this?
43
 
DATA_DIR="/var/lib/maas/ephemeral"
44
 
 
45
 
# Optional configuration script that may set variables for use by this
46
 
# script.  It gets sourced later on.
47
 
CONFIG="/etc/maas/import_ephemerals"
48
 
 
49
 
RELEASES="precise"
50
 
ARCHES="amd64/generic i386/generic armhf/highbank"
51
 
BUILD_NAME="ephemeral"
52
 
STREAM="released"
53
 
 
54
 
# DATA_DIR layout is like:
55
 
#   tgt.conf
56
 
#   tgt.conf.d/
57
 
#     <name>.conf ->
58
 
#        ../release/stream/arch/serial.conf
59
 
#   release/
60
 
#     stream/
61
 
#       arch/
62
 
#         serial/
63
 
#           kernel
64
 
#           disk.img
65
 
#           initrd
66
 
#           my.conf
67
 
 
68
 
error() { echo "$@" 1>&2; }
69
 
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
70
 
 
71
 
 
72
 
Usage() {
73
 
    cat <<EOF
74
 
Usage: ${0##*/} [ options ] <<ARGUMENTS>>
75
 
 
76
 
   Import ephemeral (enlistment/commissioning) images into maas.
77
 
   Settings are read from $CONFIG.
78
 
EOF
79
 
}
80
 
 
81
 
 
82
 
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
83
 
 
84
 
 
85
 
cleanup() {
86
 
    [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
87
 
}
88
 
 
89
 
 
90
 
debug() {
91
 
    local level=${1}; shift;
92
 
    [ "${level}" -gt "${VERBOSITY}" ] && return
93
 
    error "${@}"
94
 
}
95
 
 
96
 
 
97
 
uniq_major_arches() {
98
 
    # print on stdout a uniq set of arches out of the list of arch/subarch
99
 
    # pairs supplied in $@
100
 
    # Eg. armhf/highbank armhf/armadaxp i386/generic amd64/generic ->
101
 
    #           "armhf\ni386\namd64\n"
102
 
    local arch
103
 
    for arch in "$@"; do echo "${arch%%/*}"; done|uniq
104
 
}
105
 
 
106
 
 
107
 
subarches() {
108
 
    # print on stdout a list of subarches available for a given major arch $1
109
 
    # given a list of arch/subarch pairs in $2-
110
 
    # Eg. armhf armhf/highbank armhf/armadaxp i386/generic ->
111
 
    #           "highbank\narmadaxp\n"
112
 
    local major_arch="$1" candidate
113
 
    shift
114
 
    for candidate in "$@"; do
115
 
        case "$candidate" in
116
 
            "$major_arch"/*) echo "${candidate#*/}" ;;
117
 
            *) ;;
118
 
        esac
119
 
    done
120
 
}
121
 
 
122
 
 
123
 
query_remote() {
124
 
    # query /query data at CLOUD_IMAGES_ARCHIVE
125
 
    # returns 7 values prefixed with 'r_'
126
 
    local iarch=$1 irelease=$2 istream=$3 out=""
127
 
    local burl="${CLOUD_IMAGES_ARCHIVE}/query"
128
 
    local url="$burl/$irelease/$istream/${STREAM}-dl.current.txt"
129
 
    local target="$TEMP_D/query/$release.$stream"
130
 
    mkdir -p -- "$TEMP_D/query"
131
 
    if [ ! -f "$TEMP_D/query/$release.$stream" ]; then
132
 
        wget -q "$url" -O "$target.tmp" && mv "$target.tmp" "$target" ||
133
 
            { error "failed to get $url"; return 1; }
134
 
    fi
135
 
 
136
 
    r_release=""; r_stream=""; r_label=""; r_serial="";
137
 
    r_arch=""; r_url=""; r_name=""
138
 
 
139
 
    out=$(awk '-F\t' '$1 == release && $2 == stream && $5 == arch { print $3, $4, $6, $7 }' \
140
 
        "arch=$iarch" "release=$irelease" "stream=$istream" \
141
 
        "$target") && [ -n "$out" ] ||
142
 
        return 1
143
 
 
144
 
    set -- ${out}
145
 
    r_release=$irelease
146
 
    r_stream=$istream
147
 
    r_label=$1;
148
 
    r_serial=$2;
149
 
    r_arch=$iarch
150
 
    r_url=$3
151
 
    r_name=$4
152
 
    return
153
 
}
154
 
 
155
 
 
156
 
query_local() {
157
 
    local iarch=$1 irelease=$2 istream=$3 out=""
158
 
    local label="" name="" serial="" url=""
159
 
 
160
 
    local found=""
161
 
    for i in "${DATA_DIR}/"$irelease/$istream/$iarch/*/info; do
162
 
        [ -f "$i" ] && found=$i
163
 
    done
164
 
    found=$(LC_ALL=C;
165
 
        cd "${DATA_DIR}/$irelease/$istream/$iarch" 2>/dev/null || exit 0;
166
 
        for d in [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]*; do
167
 
            [ -f "$d/info" ] && f=$d; done;
168
 
        [ -n "$f" ] && echo "$PWD/$f/info")
169
 
 
170
 
    l_release=""; l_stream=""; l_label=""; l_serial="";
171
 
    l_arch=""; l_url=""; l_name=""; l_dir="";
172
 
    if [ -n "$found" ]; then
173
 
        . "$found"
174
 
        l_release="$release";
175
 
        l_stream="$stream";
176
 
        l_label="$label";
177
 
        l_serial="$serial";
178
 
        l_arch="$arch";
179
 
        l_url="$url";
180
 
        l_name="$name";
181
 
        l_dir="${found%/*}";
182
 
    fi
183
 
}
184
 
 
185
 
 
186
 
serial_gt() {
187
 
    # is $1 a larger serial than $2 ?
188
 
    local a=${1:-0} b=${2:-0}
189
 
    case "$a" in
190
 
        *.[0-9]) a="${a%.*}${a##*.}";;
191
 
    esac
192
 
    case "$b" in
193
 
        *.[0-9]) b="${b%.*}${b##*.}";;
194
 
    esac
195
 
    [ $a -gt $b ]
196
 
}
197
 
 
198
 
 
199
 
prep_dir() {
200
 
    local wd="$1" exdir="" tarball=""
201
 
    shift
202
 
    local release=$1 stream=$2 label=$3 serial=$4 arch=$5 url=$6 name=$7
203
 
    local furl="$CLOUD_IMAGES_ARCHIVE/$url"
204
 
 
205
 
    mkdir -p "$wd"
206
 
    cat > "$wd/info" <<EOF
207
 
release=$release
208
 
stream=$stream
209
 
label=$label
210
 
serial=$serial
211
 
arch=$arch
212
 
url=$url
213
 
name=$name
214
 
EOF
215
 
 
216
 
    # download
217
 
    local cachepath="${TARBALL_CACHE_D}/${name}.tar.gz" rmtar=""
218
 
    if [ -f "$cachepath" ]; then
219
 
        tarball="${cachepath}"
220
 
    elif [ -n "$TARBALL_CACHE_D" ]; then
221
 
        mkdir -p "$TARBALL_CACHE_D"
222
 
        debug 1 "downloading $name from $furl to local cache"
223
 
        wget "$furl" --progress=dot:mega -O "${cachepath}.part$$" &&
224
 
            mv "$cachepath.part$$" "$cachepath" || {
225
 
            rm "$cachepath.part$$"
226
 
            error "failed to download $furl";
227
 
            return 1;
228
 
        }
229
 
        tarball="${cachepath}"
230
 
    else
231
 
        debug 1 "downloading $name from $furl"
232
 
        tarball="$wd/dist.tar.gz"
233
 
        wget "$furl" --progress=dot:mega -O "${tarball}" ||
234
 
            { error "failed to download $furl"; return 1; }
235
 
        rmtar="$tarball"
236
 
    fi
237
 
 
238
 
    # Extract the tarball.
239
 
    exdir="$wd/.xx"
240
 
    mkdir -p "$exdir" &&
241
 
        debug 1 "extracting tarball" &&
242
 
        tar -Sxzf - -C  "$exdir" < "$tarball" ||
243
 
        { error "failed to extract tarball from $furl"; return 1; }
244
 
 
245
 
    # Create root disk
246
 
    uec2roottar "$tarball" || { error "failed to create root image"; return 1; }
247
 
 
248
 
    # Look for our files in the extracted tarball.
249
 
    local x="" img="" kernel="" initrd=""
250
 
    for x in "$exdir/"*.img; do
251
 
        [ -f "$x" ] && img="$x" && break
252
 
    done
253
 
 
254
 
    for x in "$exdir/kernel" "$exdir/"*-vmlinuz*; do
255
 
        [ -f "$x" ] && kernel="$x" && break
256
 
    done
257
 
 
258
 
    for x in "$exdir/initrd" "$exdir/"*-initrd*; do
259
 
        [ -f "$x" ] && initrd="$x" && break
260
 
    done
261
 
 
262
 
    # Rename/move files extracted from tarballs to the target dir.
263
 
    [ -n "$img" ] || { error "failed to find image in $furl"; return 1; }
264
 
    mv "$img" "$wd/disk.img" ||
265
 
        { error "failed to move extracted image to $wd/disk.img"; return 1; }
266
 
 
267
 
    [ -z "$kernel" ] || mv "$kernel" "$wd/linux" ||
268
 
        { error "failed to move extracted kernel to $wd/linux"; return 1; }
269
 
 
270
 
    [ -z "$initrd" ] || mv "$initrd" "$wd/initrd.gz" ||
271
 
        { error "failed to move extracted initrd to $wd/initrd.gz"; return 1; }
272
 
 
273
 
    [ ! -d "$exdir/subarch" ] || mv "$exdir/subarch" "$wd/" ||
274
 
        { error "failed to move extracted subarch to $wd/subarch"; return 1; }
275
 
 
276
 
    rm -Rf "$exdir" || { error "failed to cleanup extraction dir"; return 1; }
277
 
    { [ -z "$rmtar" ] || rm "$rmtar"; } ||
278
 
        { error "failed to remove temporary tarball $rmtar"; return 1; }
279
 
 
280
 
    if [ -n "$EPH_UPDATE_CMD" ]; then
281
 
        # update
282
 
        debug 1 "invoking: ${EPH_UPDATE_CMD[*]} ./disk.img ./kernel ./initrd"
283
 
        "${EPH_UPDATE_CMD[@]}" "$wd/disk.img" "$wd/kernel" "$wd/initrd" ||
284
 
            { error "failed to apply updates to $img"; return 1; }
285
 
    else
286
 
        [ -n "$kernel" -a -n "$initrd" ] || {
287
 
            error "missing kernel or initrd in tarball. set \$EPH_UPDATE_CMD";
288
 
            # TODO: Set it to what!?
289
 
            return 1;
290
 
        }
291
 
    fi
292
 
 
293
 
    return 0
294
 
}
295
 
 
296
 
 
297
 
write_tgt_conf() {
298
 
    local file="$1" target_name="$2" image="$3"
299
 
    shift 2;
300
 
    local release=$1 stream=$2 label=$3 serial=$4 arch=$5 url=$6 name=$7
301
 
    cat > "$file" <<EOF
302
 
<target ${target_name}>
303
 
    readonly 1
304
 
    backing-store "$image"
305
 
</target>
306
 
EOF
307
 
}
308
 
 
309
 
 
310
 
copy_first_available() {
311
 
    # Copy file $1 or $2 (the first that is available) to destination $3.
312
 
    local preferred_file="$1" alternate_file="$2" destination="$3"
313
 
    local actual=""
314
 
 
315
 
    if [ -f "${preferred_file}" ]; then
316
 
        actual="${preferred_file}"
317
 
    elif [ -f "${alternate_file}" ]; then
318
 
        actual="${alternate_file}"
319
 
    else
320
 
        error "Could not copy to ${destination}."
321
 
        error "Neither ${preferred_file} nor ${alternate_file} exists."
322
 
        return 1
323
 
    fi
324
 
 
325
 
    cp -- "${actual}" "${destination}" ||
326
 
        { error "Could not copy ${actual} to ${destination}."; return 1; }
327
 
    return 0
328
 
}
329
 
 
330
 
 
331
 
install_tftp_image() {
332
 
    # Make image in directory $1, for architecture $2 and subarchitecture $3,
333
 
    # and OS release $4, available over TFTP for netbooting nodes.  Only the
334
 
    # kernel and initrd are needed.
335
 
 
336
 
    local src="$1" arch="$2" subarch="$3" release="$4" tmpdir=""
337
 
 
338
 
    # Create image in a temporary directory; the installation process
339
 
    # deletes it.
340
 
    tmpdir="$(mktemp -d)"
341
 
 
342
 
    if [ -f "$src/subarch/$subarch/linux" -a \
343
 
            -f "$src/subarch/$subarch/initrd.gz" ]; then
344
 
        cp "$src/subarch/$subarch/linux" "$tmpdir/linux" || return 1
345
 
        cp "$src/subarch/$subarch/initrd.gz" "$tmpdir/initrd.gz" || return 1
346
 
    else
347
 
        copy_first_available "$src/linux" "$src/kernel" "$tmpdir/linux" ||
348
 
            return 1
349
 
        copy_first_available "$src/initrd.gz" "$src/initrd" "$tmpdir/initrd.gz" ||
350
 
            return 1
351
 
        copy_first_available "$src/dist-root.tar.gz" "" "$tmpdir/root.tar.gz" ||
352
 
            return 1
353
 
    fi
354
 
 
355
 
    local cmd out=""
356
 
    cmd=( maas-provision install-pxe-image
357
 
          "--arch=$arch" "--subarch=$subarch" "--release=$release"
358
 
          --purpose="commissioning" --image="$tmpdir" --symlink="xinstall")
359
 
    debug 2 "${cmd[@]}"
360
 
    out=$("${cmd[@]}" 2>&1) ||
361
 
        { error "cmd failed:" "${cmd[@]}"; error "$out"; return 1; }
362
 
}
363
 
 
364
 
 
365
 
short_opts="hciuv"
366
 
long_opts="help,verbose"
367
 
getopt_out=$(getopt --name "${0##*/}" \
368
 
    --options "${short_opts}" --long "${long_opts}" -- "$@") &&
369
 
    eval set -- "${getopt_out}" ||
370
 
    bad_Usage
371
 
 
372
 
while [ $# -ne 0 ]; do
373
 
    cur=${1}; next=${2};
374
 
    case "$cur" in
375
 
        -h|--help) Usage ; exit 0;;
376
 
        -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
377
 
        --) shift; break;;
378
 
    esac
379
 
    shift;
380
 
done
381
 
 
382
 
[ ! -f "$CONFIG" ] || . "$CONFIG"
383
 
[ ! -f ".${CONFIG}" ] || . ".${CONFIG}"
384
 
 
385
 
 
386
 
mkdir -p "$DATA_DIR" "$DATA_DIR/.working" ||
387
 
    fail "failed to make $DATA_DIR"
388
 
 
389
 
TEMP_D=$(mktemp -d "$DATA_DIR/.working/${0##*/}.XXXXXX") ||
390
 
   fail "failed to make tempdir"
391
 
trap cleanup EXIT
392
 
 
393
 
tgt_conf_d="$DATA_DIR/tgt.conf.d"
394
 
tgt_conf="${DATA_DIR}/tgt.conf"
395
 
 
396
 
mkdir -p "$tgt_conf_d" ||
397
 
    fail "failed to make directories"
398
 
if [ ! -f "${tgt_conf}" ]; then
399
 
    cat > "${tgt_conf}" <<EOF
400
 
include ${DATA_DIR}/tgt.conf.d/*.conf
401
 
default-driver iscsi
402
 
EOF
403
 
fi
404
 
 
405
 
updates=0
406
 
for release in $RELEASES; do
407
 
    for arch in $(uniq_major_arches $ARCHES); do
408
 
        query_local "$arch" "$release" "$BUILD_NAME" ||
409
 
            fail "failed to query local for $release/$arch"
410
 
        query_remote "$arch" "$release" "$BUILD_NAME" ||
411
 
            fail "remote query of $CLOUD_IMAGES_ARCHIVE failed"
412
 
 
413
 
        info="rel: $r_release, arch: $arch: name: $r_name"
414
 
        debug 2 "$info"
415
 
        debug 2 "local  serial=$l_serial l_name=$l_name dir=$l_dir"
416
 
        debug 2 "remote serial=$r_serial r_name=$r_name url=$r_url"
417
 
 
418
 
        # if remote is newer, need to update.  Note that if there is no local
419
 
        # data, 'l_serial' will be "", which serial_gt considers zero
420
 
        if serial_gt "$r_serial" "$l_serial"; then
421
 
            # an update is needed remote serial is newer than local
422
 
            updates=$(($updates+1))
423
 
 
424
 
            msg="updating [${l_name:+${l_name} to }$r_name]"
425
 
            debug 0 "$release/$arch: $msg"
426
 
            wd="${TEMP_D}/$release/$arch"
427
 
            prep_dir "$wd" \
428
 
                "$r_release" "$r_stream" "$r_label" \
429
 
                "$r_serial" "$r_arch" "$r_url" "$r_name" ||
430
 
                fail "failed to prepare image for $release/$arch"
431
 
 
432
 
            final_d="${r_release}/${r_stream}/${r_arch}/${r_serial}"
433
 
            fpfinal_d="${DATA_DIR}/${final_d}"
434
 
            mkdir -p "${fpfinal_d}"
435
 
 
436
 
            mv "$wd/"* "${fpfinal_d}/" ||
437
 
                fail "failed to move contents to final directory ${fpfinal_d}"
438
 
            name="${r_name}"
439
 
        else
440
 
            debug 0 "$release/$arch: up to date [$l_name]"
441
 
 
442
 
            fpfinal_d="${l_dir}"
443
 
            final_d="${l_release}/${l_stream}/${l_arch}/${l_serial}"
444
 
 
445
 
            name="${l_name}"
446
 
        fi
447
 
 
448
 
        for subarch in $(subarches "$arch" $ARCHES); do
449
 
                # Even if there was no need to update the image, we make sure
450
 
                # it gets installed.
451
 
                debug 1 "adding images for $release/$arch/$subarch to maas"
452
 
                install_tftp_image "$fpfinal_d" "$arch" "$subarch" "$release" ||
453
 
                    fail "failed to install tftp image [$info]"
454
 
        done
455
 
 
456
 
        target_name="${TARGET_NAME_PREFIX}${name}"
457
 
        rel_tgt="../${final_d}/tgt.conf"
458
 
 
459
 
        # iscsi_update
460
 
        write_tgt_conf "${fpfinal_d}/tgt.conf" "$target_name" \
461
 
            "${fpfinal_d}/disk.img" ||
462
 
            fail "failed to write tgt.conf for $release/$arch"
463
 
 
464
 
        ln -sf "$rel_tgt" "${tgt_conf_d}/${name}.conf" ||
465
 
            fail "failed to symlink ${name}.conf into place"
466
 
 
467
 
        ver_out="${TEMP_D}/verify.${target_name}"
468
 
        tgt-admin --conf "$SYS_TGT_CONF" --update "${target_name}" &&
469
 
            tgt-admin --conf "$SYS_TGT_CONF" --show > "${ver_out}" &&
470
 
            grep -q "^Target [0-9][0-9]*: ${target_name}" "${ver_out}" || {
471
 
            mv "${fpfinal_d}/info" "${fpfinal_d}/info.failed"
472
 
            tgt-admin --conf "$SYS_TGT_CONF" --delete "$target_name"
473
 
            rm "${tgt_conf_d}/${name}.conf"
474
 
            fail "failed tgt-admin add for $name"
475
 
        }
476
 
 
477
 
    done
478
 
done
479
 
 
480
 
 
481
 
## cleanup
482
 
# here, go through anything non-current,
483
 
#   * remove the tgt config
484
 
#   * if tgt-show has entry:
485
 
#     * remove from tgt-admin by name && remove directories
486
 
#   * else
487
 
#     * remove directory
488
 
 
489
 
# vi: ts=4 expandtab