~smoser/curtin/yakkety.lp1666986

1 by Scott Moser
Import upstream version 0.1.0~bzr54
1
#!/bin/bash
2
3
VERBOSITY=0
4
TEMP_D=""
5
HTTP_PID=""
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
6
XKVM_PID=""
7
HTTP_PORT_TRIES=${HTTP_PORT_TRIES:-5}
8
HTTP_PORT_MIN=${HTTP_PORT_MIN:-12000}
9
HTTP_PORT_MAX=${HTTP_PORT_MAX:-65500}
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
10
MY_D=$(dirname "$0")
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
11
DEFAULT_ROOT_ARG="root=LABEL=cloudimg-rootfs"
1 by Scott Moser
Import upstream version 0.1.0~bzr54
12
13
error() { echo "$@" 1>&2; }
14
15
Usage() {
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
16
    cat <<EOF
1 by Scott Moser
Import upstream version 0.1.0~bzr54
17
Usage: ${0##*/} [ options ] boot-image curtin install [args]
18
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
19
   boot the image 'boot-image', so that it will run
1.1.1 by Scott Moser
Import upstream version 0.1.0~bzr75
20
      curtin install [args]
21
   after booting. 'curtin install [args]' can be any command'
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
22
1 by Scott Moser
Import upstream version 0.1.0~bzr54
23
   options:
1.1.6 by Scott Moser
Import upstream version 0.1.0~bzr93
24
           --add  F[:T] add file 'F' to the curtin archive at T
1 by Scott Moser
Import upstream version 0.1.0~bzr54
25
      -a | --append     append args to kernel cmdline (--kernel)
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
26
      -A | --arch   A   assume guest kernel architecture A
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
27
      -d | --disk   D   add a disk 'D' format
28
                        (path[:size][:driver][:bsize][:devopts])
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
29
                        driver can be specified without size using path::driver
30
                        driver defaults to virtio-blk
31
                        bsize <logical>[,<physical>][,<min_io_size>]
32
                        bsize defaults to 512b sector size
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
33
                        opts is a comma delimitted list of property=value
34
                        elements. Examine qemu-kvm -device scsi-hd,? for
35
                        details.
36
           --vnc D      use -vnc D (mutually exclusive with --silent)
1 by Scott Moser
Import upstream version 0.1.0~bzr54
37
      -h | --help       show this message
38
      -i | --initrd F   use initramfs F
39
      -k | --kernel F   use kernel K
40
           --mem    K   memory in Kb
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
41
      -n | --netdev     netdev can be 'user' or a bridge
1 by Scott Moser
Import upstream version 0.1.0~bzr54
42
      -p | --publish F  make file 'F' available in web server
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
43
           --silent     use -nographic
44
           --vnc D      use -vnc D (mutually exclusive with --silent)
45
                        directly through to qemu-system.
46
                        Note, qemu adds 5900 to port numbers. (:0 = port 5900)
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
47
           --serial-log F  : log to F (default 'serial.log')
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
48
           --root-arg X pass 'X' through as the root= param when booting a
49
                        kernel.  default: $DEFAULT_ROOT_PARAM
1 by Scott Moser
Import upstream version 0.1.0~bzr54
50
      -v | --verbose    be more verbose
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
51
           --no-install-deps  do not install insert '--install-deps'
52
                              on curtin command invocations
1 by Scott Moser
Import upstream version 0.1.0~bzr54
53
1.1.40 by Scott Moser
Import upstream version 0.1.0~bzr415
54
    the following are passed through to xkvm:
55
        --uefi-nvram
56
        --bios
57
1 by Scott Moser
Import upstream version 0.1.0~bzr54
58
   use of --kernel/--initrd will seed cloud-init via cmdline
59
   rather than the local datasource
1.1.1 by Scott Moser
Import upstream version 0.1.0~bzr75
60
61
   Example:
62
    * boot myboot.img, and install my-root.tar.gz
63
      ${0##*/} myboot.img --publish my-root.tar.gz curtin \
64
         install PUBURL/my-root.tar.gz
65
1 by Scott Moser
Import upstream version 0.1.0~bzr54
66
EOF
67
}
68
69
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
70
cleanup() {
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
71
    local msg="" pid=""
72
    [ ! -d "$TEMP_D" ] || msg="${msg:+$msg }remove temp dir ${TEMP_D}."
73
    [ -z "$HTTP_PID" ] || msg="${msg:+$msg }kill http pid ${HTTP_PID}."
74
    [ -z "$XKVM_PID" ] || msg="${msg:+$msg }kill xkvm pid ${XKVM_PID}."
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
75
    debug 1 "cleaning up [${SECONDS}s].${msg:+ $msg}"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
76
    [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
77
    for pid in ${XKVM_PID} ${HTTP_PID}; do
78
        kill $pid
79
    done
80
}
81
sighandle() {
82
    debug 1 "recieved $1"
83
    exit ${2:-1}
84
}
85
86
register_signal_handlers() {
87
    local cur
88
    for cur in TERM INT; do
89
        trap "sighandle $cur" "SIG$cur"
90
    done
1 by Scott Moser
Import upstream version 0.1.0~bzr54
91
}
92
93
debug() {
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
94
    local level=${1}; shift;
95
    [ "${level}" -gt "${VERBOSITY}" ] && return
96
    error "${@}"
1 by Scott Moser
Import upstream version 0.1.0~bzr54
97
}
98
99
get_my_ip() {
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
100
    [ -z "$IP_ADDR" ] || { _RET="${IP_ADDR}"; return 0; }
101
    local Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
102
    local iface ipaddr="" tmpf=""
103
    # work around LP: #1483440
104
    cp "/proc/net/route" "${TEMP_D}/current-route"
105
    while read Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT; do
106
        [ "$Mask" = "00000000" ] && break
107
    done < "${TEMP_D}/current-route"
108
    iface="$Iface"
109
    ipaddr=$(LC_ALL=C /sbin/ip -4 addr list dev "$iface" scope global) || return
110
    ipaddr=${ipaddr#* inet }
111
    ipaddr=${ipaddr%%/*}
112
    _RET="$ipaddr"
1 by Scott Moser
Import upstream version 0.1.0~bzr54
113
}
114
115
write_metadata() {
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
116
    cat <<EOF
1 by Scott Moser
Import upstream version 0.1.0~bzr54
117
instance-id: 'inst-${RANDOM}'
118
EOF
119
}
120
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
121
write_pstate_config() {
122
    local pstate="$1" config1="$2" config2="$3"
123
    cat > "$config1" <<EOF
124
#cloud-config
125
power_state:
126
  mode: "$pstate"
127
EOF
128
    sed -e "s,PSTATE,$pstate," > "$config2" <<"EOF"
129
#upstart-job
130
# precise does not do cloud-config poweroff
131
description "power-state for precise"
132
start on stopped cloud-final
133
console output
134
task
135
script
136
  [ "$(lsb_release -sc)" = "precise" ] || exit 0
137
  target="PSTATE"
138
  msg="precise-powerstate: $target"
139
  case "$target" in
140
     on) exit 0;;
141
     off|poweroff) shutdown -P now "$msg";;
142
     reboot) shutdown -r now "$msg";;
143
     *) echo "$msg : unknown target"; exit 1;;
144
  esac
145
  echo "$msg"
146
  exit 0
147
end script
148
EOF
149
}
150
1 by Scott Moser
Import upstream version 0.1.0~bzr54
151
write_userdata() {
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
152
    local x
153
    cat <<EOF
1 by Scott Moser
Import upstream version 0.1.0~bzr54
154
#cloud-config-archive
155
- type: text/cloud-config
156
  content: |
157
   password: passw0rd
158
   chpasswd: { expire: False }
159
   output: {all: '| tee -a /var/log/cloud-init-output.log'}
160
EOF
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
161
    for x in "$@"; do
162
        printf "%s\n" "- |" && sed 's,^,  ,' "$x" || return
163
    done
1 by Scott Moser
Import upstream version 0.1.0~bzr54
164
}
165
166
xkvm_check() {
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
167
    command -v xkvm >/dev/null 2>&1 && return
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
168
    [ -x "$MY_D/xkvm" ] && PATH="$MY_D:$PATH" && return
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
169
    cat 1>&2 <<EOF
1.1.21 by Scott Moser
Import upstream version 0.1.0~bzr200
170
Unable to find 'xkvm' in PATH, should be in curtin's tools/ dir
1 by Scott Moser
Import upstream version 0.1.0~bzr54
171
EOF
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
172
    return 1
173
}
174
175
_start_http() {
176
    local pubdir="$1" ip="$2" port="$3"
177
    local statfile="_datesum" contents="" burl="http://$ip:$port"
178
    local found="" hpid="" ret=""
179
    contents="$$:$(date +%s.%N)"
180
    echo "$contents" > "$pubdir/$statfile"
181
    ( set -eb; cd "$pubdir" &&
182
        exec python -m SimpleHTTPServer "$port" ) >"$pubdir/ws.log" 2>&1 &
183
    hpid=$!
184
    HTTP_PID=$hpid  # set so cleanup cleans up during wget
185
    debug 3 "checking web service [pid=$hpid] on $burl"
186
    found=$(env -u http_proxy wget -q --waitretry=0.4 --retry-connrefused \
187
        --tries=10 "$burl/$statfile" --timeout=4 -O - 2>/dev/null) &&
188
        [ "$found" = "$contents" ] && {
189
            _RET=$hpid
190
            return 0
191
        }
192
    ret=$?
193
    kill $hpid && HTTP_PID=""
194
    return $ret
195
}
196
197
start_http() {
198
    # start_http(pubdir, ip, port="", tries=5)
199
    # starts a web service at 'port' that serves files in 'pubdir'
200
    # waits until it is verified to be lisenting at ip
201
    # if port is not provided, '$tries' random ports are tried.
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
202
    #
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
203
    # sets HTTP_PID and returns in _RET the port selected.
204
    local pubdir="$1" ip="$2" port="$3" tries="${4:-5}" i=""
205
    [ -z "$ip" ] && ip="localhost"
206
    local pmin="$HTTP_PORT_MIN" pmax="$HTTP_PORT_MAX" ret="" tried=""
207
    local ptries=""
208
    ptries=( )
209
    if [ -n "$port" ]; then
210
        ptries=( $port )
211
    elif [ $(($pmax-$pmin+1)) -le $tries ]; then
212
        # if tries spans the whole range, then just try them all
213
        local range=$(($pmax-$pmin+1))
214
        for((i=0;i<$range;i++)); do
215
            ptries[$i]=$((pmin+$i))
216
        done
217
    else
218
        for((i=0;i<$tries;i++)); do
219
            ptries[$i]="random"
220
        done
221
    fi
222
    for port in "${ptries[@]}"; do
223
        [ "$port" = "random" ] && port=$(($pmin+($RANDOM%($pmax+1-$pmin))))
224
        debug 2 "trying http server $ip:$port"
225
        _start_http "$pubdir" "$ip" "$port" &&
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
226
            HTTP_PID="$_RET" && _RET="$port" &&
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
227
            debug 1 "serving $pubdir at http://$ip:$port/ in pid $HTTP_PID" &&
228
            return 0
229
        ret=$?
230
        tried="$tried $port"
231
    done
232
    error "failed to start http on service on $ip tried ports: ${tried# }"
233
    return $ret
1 by Scott Moser
Import upstream version 0.1.0~bzr54
234
}
235
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
236
find_apt_proxy() {
237
    # pick an apt proxy for the guest
238
    local out=""
239
240
    # if user set uncommon 'apt_proxy', then trust it
241
    [ -n "$apt_proxy" ] && echo "$apt_proxy" && return 0
242
243
    # see if the host has an apt proxy configured, and use it
244
    if command -v apt-config >/dev/null 2>&1; then
245
        out=$(apt-config shell x Acquire::HTTP::Proxy) &&
246
        out=$(sh -c 'eval $1 && echo $x' -- "$out") && [ -n "$out" ] &&
247
        echo "$out" && return
248
    fi
249
250
    return 1
251
}
252
1 by Scott Moser
Import upstream version 0.1.0~bzr54
253
main() {
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
254
    local short_opts="a:A:d:h:i:k:n:p:v"
1.1.40 by Scott Moser
Import upstream version 0.1.0~bzr415
255
    local long_opts="add:,append:,arch:,bios:,disk:,dowait,help,initrd:,kernel:,mem:,netdev:,no-dowait,power:,publish:,root-arg:,silent,serial-log:,uefi-nvram:,verbose,vnc:"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
256
    local getopt_out=""
257
    getopt_out=$(getopt --name "${0##*/}" \
258
        --options "${short_opts}" --long "${long_opts}" -- "$@") &&
259
        eval set -- "${getopt_out}" ||
260
        { bad_Usage; return 1; }
261
262
    local seed=""
263
    local bootimg="" bootimg_dist="" target="" mem="1024"
264
    local udata="" ip="" http_port="${HTTP_PORT}" burl=""
265
    local tmp="" top_d
266
    local initrd="" kernel="" uappend="" iargs="" disk_args=""
267
    local pubs="" disks="" pstate="null"
1.1.40 by Scott Moser
Import upstream version 0.1.0~bzr415
268
    local bsize="512"
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
269
    local netdevs="" install_deps="--install-deps"
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
270
    local arch_hint=""
271
    local video="-curses -vga std" serial_log="serial.log"
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
272
    local root_arg="$DEFAULT_ROOT_ARG"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
273
    # dowait: run xkvm with a '&' and then 'wait' on the pid.
274
    #  the reason to do this or not do this has to do with interactivity
275
    #  if detached with &, then user input will not go to xkvm.
276
    #  if *not* detached, then signal handling is blocked until
277
    #  the foreground subprocess returns. which means we can't handle
278
    #  a sigterm and kill xkvm.
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
279
    #  We default to dowait=false if input and output are a terminal
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
280
    local dowait=""
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
281
    [ -t 0 -a -t 1 ] && dowait=false || dowait=true
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
282
    pubs=( )
283
    disks=( )
284
    addfiles=( )
285
    netdevs=( )
286
    pt=( )
287
288
    # if output is to a terminal, then set dowait default to false
289
    [ -t 0 ] && dowait=false || dowait=true
290
    while [ $# -ne 0 ]; do
291
        cur=${1}; next=${2};
292
        case "$cur" in
293
               --add) addfiles[${#addfiles[@]}]="$next"; shift;;
294
            -a|--append) uappend="$next"; shift;;
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
295
            -A|--arch) arch_hint="$next"; shift;;
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
296
            -d|--disk) disks[${#disks[@]}]="$next"; shift;;
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
297
               --dowait) pt[${#pt[@]}]="$cur"; dowait=true;;
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
298
            -h|--help) Usage ; exit 0;;
299
            -i|--initrd) initrd="$next"; shift;;
300
            -k|--kernel) kernel="$next"; shift;;
301
               --mem) mem="$next"; shift;;
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
302
            -n|--netdev) netdevs[${#netdevs[@]}]="$next"; shift;;
303
               --no-dowait) pt[${#pt[@]}]="$cur"; dowait=false;;
304
               --no-install-deps) install_deps="";;
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
305
               --power)
306
                case "$next" in
307
                    off) pstate="poweroff";;
308
                    on|none)  pstate="null";;
309
                    reboot) pstate="$next";;
310
                    *) error "Invalid power state, must be: off, on, reboot";;
311
                esac
312
                shift;;
313
            -p|--publish) pubs[${#pub[@]}]="$next"; shift;;
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
314
               --root-arg) root_arg="$next";;
315
               --serial-log) serial_log="$next"; shift;;
316
               --silent) video="-nographic";;
1.1.40 by Scott Moser
Import upstream version 0.1.0~bzr415
317
            --uefi-nvram|--bios)
318
                # handle all --opt=* pass through here.
319
                pt[${#pt[@]}]="$cur=$next";;
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
320
            -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
321
               --vnc)
322
                    video="-vnc $next"
323
                    debug 1 "VNC requested - $next"
324
                    shift;;
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
325
            --) shift; break;;
326
        esac
327
        shift;
328
    done
329
330
    # handle passing through '-v' if given
331
    local t=""
332
    for((i=0;i<${VERBOSITY};i++)); do t="${t}v"; done
333
    [ -n "$t" ] && pt[${#pt[@]}]="-$t"
334
335
    [ $# -ge 0 ] || { bad_Usage "must provide boot-image"; return 1; }
336
    bootimg_dist="$1"
337
    shift
338
    cmdargs=( "$@" )
339
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
340
    xkvm_check || return
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
341
    TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
342
        { error "failed to make tempdir"; return 1; }
343
344
    trap cleanup EXIT
345
    register_signal_handlers
346
347
    if [ "${#disks[@]}" -eq 0 ]; then
348
        disks=( "${TEMP_D}/disk1.img" )
349
    fi
350
351
    bootimg_dist=$(readlink -f "$bootimg_dist") ||
352
        { error "bad bootimg $bootimg_dist"; return 1; }
353
354
    [ -z "$initrd" -o -f "$initrd" ] ||
355
        { error "initrd not a file: $initrd"; return 1; }
356
    [ -z "$kernel" -o -f "$kernel" ] ||
357
        { error "kernel not a file: $kernel"; return 1; }
358
359
    tmp=$(dirname "$0") && top_d=$(cd "$tmp" && cd .. && pwd) ||
360
        { error "failed to get dir for $0"; return 1; }
361
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
362
    local disk="" src="" size="" fmt="" out="" id="" driver="" if=""
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
363
    local split_input="" serial=""
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
364
    disk_args=( )
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
365
    id=1
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
366
    for disk in "${disks[@]}"; do
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
367
        ((id++))
368
        # 1=src
369
        # 2=src:size
370
        # 3=src:size:driver
371
        # 4=src:size:driver:bsize
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
372
        # 5=src:size:driver:bsize:devopts
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
373
        src=$(echo $disk | awk -F: '{print $1}')
374
        size=$(echo $disk | awk -F: '{print $2}')
375
        driver=$(echo $disk | awk -F: '{print $3}')
376
        bsize=$(echo $disk | awk -F: '{print $4}')
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
377
        devopts=$(echo $disk | awk -F: '{print $5}')
378
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
379
        if [ -z "${src}" ]; then
380
            error "Failed to provide disk source"
381
            exit 1
382
        fi
383
384
        if [ -z "${size}" ]; then
385
            size=5G
386
        fi
387
388
        if [ -z "${driver}" ]; then
389
            driver="virtio-blk"
390
        fi
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
391
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
392
        if [ -z "${bsize}" ]; then
393
            bsize="512"
394
        fi
395
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
396
        if [ ! -f "$src" ]; then
397
            qemu-img create -f raw "${src}" "$size" ||
398
                { error "failed create $src of size $size"; return 1; }
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
399
            fmt="raw"
400
        else
401
            out=$(LANG=C qemu-img info "$src") &&
402
                fmt=$(echo "$out" | awk '$0 ~ /^file format:/ { print $3 }') ||
403
                { error "failed to determine format of $src"; return 1; }
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
404
        fi
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
405
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
406
        # prepend comma if passing devopts
407
        if [ -n "${devopts}" ]; then
408
            devopts=",${devopts}"
409
        fi
410
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
411
        # set logical/physical size blocksz is logical:phys
412
        local logbs=$(round_up ${bsize%%:*})
413
        local phybs=$(round_up ${bsize##*:})
414
        local bs_args="logical_block_size=$logbs"
415
              bs_args="${bs_args},physical_block_size=$phybs"
416
              bs_args="${bs_args},min_io_size=$logbs"
417
418
        disk_args=( "${disk_args[@]}" "-drive"
419
            "file=${src},if=none,cache=unsafe,format=$fmt,id=drv${id},index=$id" )
420
421
        disk_args=( "${disk_args[@]}" "-device"
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
422
            "${driver},drive=drv${id},${bs_args}${devopts}" )
423
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
424
    done
425
426
    get_my_ip || { error "failed to get your ip. set IP_ADDR"; return 1; }
427
    ip=${_RET}
428
429
    local tok src pub fpath
430
    # tok in pubs looks like file[:pubname]
431
    # link them into the temp dir for publishing
432
    for tok in "${pubs[@]}"; do
433
        case "$tok" in
434
            *:*) src="${tok%:*}"; pub="${tok##*:}";;
435
            *) src=${tok}; pub="";;
436
        esac
437
        fpath=$(readlink -f "$src") ||
438
            { error "'$src': failed to get path"; return 1; }
439
        if [ -n "$pub" ]; then
440
            pub="${src##*/}"
441
        fi
442
        ln -sf "$fpath" "${TEMP_D}/${pub}"
443
    done
444
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
445
    start_http "${TEMP_D}" "$ip" "$http_port" "${HTTP_TRIES}" </dev/null ||
446
        { error "failed to start http service"; return 1; }
447
    http_port=$_RET
448
    burl="http://$ip:${http_port}/"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
449
    # now replace PUBURL anywhere in cmdargs
450
    for((i=0;i<${#cmdargs[@]};i++)); do
451
        cmdargs[$i]=${cmdargs[$i]//PUBURL/$burl}
452
    done
453
454
    local addargs="" f=""
455
    addargs=( )
456
    for f in "${addfiles[@]}"; do
457
        if [ "${f#*:}" != "$f" ]; then
458
            addargs[${#addargs[@]}]="--add=$f"
459
        else
460
            addargs[${#addargs[@]}]="--add=$f:${f##*/}"
461
        fi
462
    done
463
464
    # We now pack up --config= options for the user
465
    # potentially should check to make sure they've not already done this
466
    # as this updating could then be destructive / annoying
467
    # specifically, it could be annoying if you had a config inside
468
    # the image that you were meaning to reference, and we copied (or tried)
469
    # the file from the host.
470
    for((i=1;i<${#cmdargs[@]};i++)); do
471
        cur=${cmdargs[$i]}
472
        next=${cmdargs[$i+1]}
473
        stuffed_cfg=""
474
        fpath=""
475
        case "$cur" in
476
            --config|-c)
477
                fpath=$next;
478
                cmdargs[$i+1]="config/${fpath##*/}"
479
                ;;
480
            --config=*)
481
                fpath=${cur#--config=}
482
                cmdargs[$i]="--config=config/${fpath##*/}"
483
                ;;
484
            *) continue;;
485
        esac
486
        addargs[${#addargs[@]}]="--add=config/${fpath##*/}:$fpath"
487
    done
488
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
489
    if [ "${cmdargs[0]}" = "curtin" -a -n "$install_deps" ]; then
490
        # if this is a 'curtin' command, then also insert --install-deps
491
        debug 1 "adding --install-deps to command"
492
        cmdargs=( curtin $install_deps "${cmdargs[@]:1}" )
493
    fi
494
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
495
    PYTHONPATH="${top_d}${PYTHONPATH:+${PYTHONPATH}}" \
496
        "${top_d}/bin/curtin" pack "${addargs[@]}" -- \
497
        "${cmdargs[@]}" > "${TEMP_D}/install-cmd" ||
498
        { error "failed to pack"; return 1; }
499
500
    udata="${TEMP_D}/user-data"
501
    mdata="${TEMP_D}/meta-data"
502
503
    local ccfiles=""
504
    ccfiles=( )
505
    if [ -n "${pstate}" ]; then
1.1.32 by Scott Moser
Import upstream version 0.1.0~bzr314
506
        write_pstate_config "$pstate" "${TEMP_D}/pstate.1" "${TEMP_D}/pstate.2"
507
        ccfiles[${#ccfiles[@]}]="${TEMP_D}/pstate.1"
508
        ccfiles[${#ccfiles[@]}]="${TEMP_D}/pstate.2"
509
    fi
510
511
    if tmp=$(find_apt_proxy); then
512
        debug 1 "using $tmp for proxy"
513
        printf '#cloud-config\napt_proxy: "%s"\n' "$tmp" > "${TEMP_D}/cc-proxy"
514
        ccfiles[${#ccfiles[@]}]="${TEMP_D}/cc-proxy"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
515
    fi
516
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
517
    if command -v ssh-keys-list >/dev/null 2>&1; then
518
        ssh-keys-list cloud-config > "${TEMP_D}/cc-ssh-keys" &&
519
            ccfiles[${#ccfiles[@]}]="${TEMP_D}/cc-ssh-keys" ||
520
            { error "failed to get users ssh keys."; return 1; }
521
    fi
522
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
523
    write_metadata > "$mdata" || { error "failed to write meta-data"; return 1; }
524
    write_userdata "${TEMP_D}/install-cmd" "${ccfiles[@]}" > "$udata"  ||
525
        { error "failed to write user-data"; return 1; }
526
527
    bootimg="${TEMP_D}/boot.img"
528
    qemu-img create -f qcow2 -b "${bootimg_dist}" "$bootimg" 2G ||
529
        { error "failed create from ${bootimg_dist}"; return 1; }
530
531
    local seedargs=""
532
    seedargs=()
533
    if [ -n "$kernel" ]; then
534
        local append="" root=""
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
535
        # Note: root_arg is by default done by LABEL.  This assumes
536
        # a.) our root device is not multipath
537
        # b.) no other disks attached will have this LABEL
538
        # c.) the LABEL is in fact correct.
539
        # all of these assumptions are true under vmtest.
540
        if [ -z "$root_arg" ]; then
541
            debug 1 "WARN: root_arg is empty with kernel."
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
542
        fi
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
543
        append="${root_arg:+${root_arg} }ds=nocloud-net;seedfrom=$burl"
544
545
        local console_name=""
546
        case "${arch_hint}" in
547
            s390x) console_name="";;
548
            ppc64*) console_name="hvc0";;
549
            *) console_name="ttyS0";;
550
        esac
551
        if [ -n "$console_name" ]; then
552
            append="${append} console=${console_name}"
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
553
        fi
554
        append="${append} $uappend"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
555
        seedargs=( "${seedargs[@]}" -kernel "$kernel" )
556
        [ -n "$initrd" ] && seedargs=( "${seedargs[@]}" -initrd "$initrd" )
557
        seedargs=( "${seedargs[@]}" -append "$append" )
558
    else
559
        seed="${TEMP_D}/seed.img"
560
        cloud-localds "$seed" "$udata" "$mdata" ||
561
            { error "failed cloud-localds"; return 1; }
562
        seedargs=( "-drive" "file=${seed},if=virtio,media=cdrom" )
563
    fi
564
565
    local netargs
566
    netargs=( )
567
    for dev in "${netdevs[@]}"; do
1.1.34 by Scott Moser
Import upstream version 0.1.0~bzr359
568
        netargs=( "${netargs[@]}" "--netdev=${dev}" )
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
569
    done
570
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
571
    local cmd serial_args="" chardev_arg=""
572
    [ "${serial_log}" = "none" ] && serial_log=""
573
    if [ -n "${serial_log}" ]; then
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
574
        if [ "${arch_hint}" = "s390x" ]; then
575
            if [ "${serial_log}" = "stdio" ]; then
576
                chardev_arg="stdio"
577
            else
578
                chardev_arg="file,path=${serial_log}"
579
            fi
580
                serial_args="-nodefaults -chardev ${chardev_arg},id=charconsole0 -device sclpconsole,chardev=charconsole0,id=console0"
581
        else
582
            serial_args="-serial file:${serial_log}"
583
            #debug mode serial_args="-serial ${serial_log} -monitor stdio"
584
        fi
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
585
    fi
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
586
    # -monitor stdio
587
    cmd=(
1.1.34 by Scott Moser
Import upstream version 0.1.0~bzr359
588
        xkvm "${pt[@]}" "${netargs[@]}" --
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
589
        -m ${mem} ${serial_args} ${video}
590
        -drive "file=$bootimg,if=none,cache=unsafe,format=qcow2,id=boot,index=0"
591
        -device "virtio-blk,drive=boot"
1.1.34 by Scott Moser
Import upstream version 0.1.0~bzr359
592
        "${disk_args[@]}"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
593
        "${seedargs[@]}"
1.1.34 by Scott Moser
Import upstream version 0.1.0~bzr359
594
        )
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
595
1.1.33 by Scott Moser
Import upstream version 0.1.0~bzr351
596
    debug 1 "running with dowait=$dowait: ${cmd[*]}"
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
597
    local sstart=$SECONDS
598
    if $dowait; then
599
        "${cmd[@]}" &
600
        XKVM_PID=$!
601
        debug 1 "xkvm pid: $XKVM_PID. launch pid: $$"
602
        wait "${XKVM_PID}"
603
        ret=$?
604
        XKVM_PID=""
605
    else
606
        "${cmd[@]}"
607
        ret=$?
608
    fi
609
    debug 1 "xkvm returned $ret took $(($SECONDS-$sstart))"
610
611
    return $ret
612
}
613
1.1.39 by Scott Moser
Import upstream version 0.1.0~bzr399
614
random_wwn() {
615
    # wwn must be a int64, less than (1 << 63) - 1
616
    # we achieve this by combining 4 (1 << 15) ints
617
    printf "0x%04x%04x%04x%04x" $RANDOM $RANDOM $RANDOM $RANDOM
618
}
1.1.36 by Scott Moser
Import upstream version 0.1.0~bzr385
619
620
round_up() {
621
    local size="${1}"
622
    local multiple="${2:-512}"
623
    local max_size=$((32 * 1024)) # 32k max
624
625
    size=$(( (($size + $multiple - 1) / $multiple) * $multiple))
626
    if [ $size -gt $max_size ]; then
627
        echo $max_size
628
        return
629
    elif [ $size -lt $multiple ]; then
630
        echo $multiple
631
        return
632
    fi
633
    echo $size
634
}
635
636
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
637
test_start_http() {
638
    # run this like:
639
    #  HTTP_PORT_MIN=59000 HTTP_PORT_MAX=63001 ./tools/launch \
640
    #     /tmp/smfoo localhost
641
    VERBOSITY=3
642
    trap cleanup EXIT
643
    register_signal_handlers
644
    echo "mypid: $$"
645
    start_http "$@" || { ret=$?; echo "returned $ret"; return $ret; }
646
    ret=$?
647
    port=$_RET
648
    echo "pid $HTTP_PID is serving on $port"
649
    sleep ${SLEEPTIME:-3} &
650
    XKVM_PID=$!
651
    wait $XKVM_PID
652
    ret=$?
653
    XKVM_PID=""
654
    return $ret
1 by Scott Moser
Import upstream version 0.1.0~bzr54
655
}
656
657
main "$@"
658
1.1.30 by Scott Moser
Import upstream version 0.1.0~bzr275
659
# vi: ts=4 expandtab