Statistics
| Branch: | Revision:

root / common.sh.in @ fbf11f1c

History | View | Annotate | Download (14.9 kB)

1
#
2

    
3
# Copyright (C) 2007, 2008, 2009 Google Inc.
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
# General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
# 02110-1301, USA.
19

    
20
AWK="@AWK@"
21
DUMP="@DUMP@"
22
LOSETUP="@LOSETUP@"
23
KPARTX="@KPARTX@"
24
SFDISK="@SFDISK@"
25
QEMU_IMG="@QEMU_IMG@"
26
MKDIR_P="@MKDIR_P@"
27

    
28
CLEANUP=( )
29

    
30
log_error() {
31
  echo "$@" >&2
32
}
33

    
34
debug() {
35
    [ "$IMAGE_DEBUG" == "1" -o "$IMAGE_DEBUG" == "yes" ] &&  $@ || :
36
}
37

    
38
get_api5_arguments() {
39
  GETOPT_RESULT=$*
40
  # Note the quotes around `$TEMP': they are essential!
41
  eval set -- "$GETOPT_RESULT"
42
  while true; do
43
    case "$1" in
44
      -i|-n) instance=$2; shift 2;;
45

    
46
      -o) old_name=$2; shift 2;;
47

    
48
      -b) blockdev=$2; shift 2;;
49

    
50
      -s) swapdev=$2; shift 2;;
51

    
52
      --) shift; break;;
53

    
54
      *)  log_error "Internal error!" >&2; exit 1;;
55
    esac
56
  done
57
  if [ -z "$instance" -o -z "$blockdev" ]; then
58
    log_error "Missing OS API Argument (-i, -n, or -b)"
59
    exit 1
60
  fi
61
  if [ "$SCRIPT_NAME" != "export" -a -z "$swapdev"  ]; then
62
    log_error "Missing OS API Argument -s (swapdev)"
63
    exit 1
64
  fi
65
  if [ "$SCRIPT_NAME" = "rename" -a -z "$old_name"  ]; then
66
    log_error "Missing OS API Argument -o (old_name)"
67
    exit 1
68
  fi
69
}
70

    
71
get_api10_arguments() {
72
  if [ -z "$INSTANCE_NAME" -o -z "$HYPERVISOR" -o -z "$DISK_COUNT" ]; then
73
    log_error "Missing OS API Variable:"
74
    log_error "(INSTANCE_NAME HYPERVISOR or DISK_COUNT)"
75
    exit 1
76
  fi
77
  instance=$INSTANCE_NAME
78
  if [ $DISK_COUNT -lt 1 -o -z "$DISK_0_PATH" ]; then
79
    log_error "At least one disk is needed"
80
    exit 1
81
  fi
82
  if [ "$SCRIPT_NAME" = "export" ]; then
83
    if [ -z "$EXPORT_DEVICE" ]; then
84
      log_error "Missing OS API Variable EXPORT_DEVICE"
85
    fi
86
    blockdev=$EXPORT_DEVICE
87
  elif [ "$SCRIPT_NAME" = "import" ]; then
88
    if [ -z "$IMPORT_DEVICE" ]; then
89
       log_error "Missing OS API Variable IMPORT_DEVICE"
90
    fi
91
    blockdev=$IMPORT_DEVICE
92
  else
93
    blockdev=$DISK_0_PATH
94
  fi
95
  if [ "$SCRIPT_NAME" = "rename" -a -z "$OLD_INSTANCE_NAME" ]; then
96
    log_error "Missing OS API Variable OLD_INSTANCE_NAME"
97
  fi
98
  old_name=$OLD_INSTANCE_NAME
99
}
100

    
101
get_api20_parameters() {
102
  if [ -z "$OSP_IMG_ID" -o -z "$OSP_IMG_FORMAT" -o -z "$OSP_IMG_PASSWD" ]; then
103
    log_error "Missing OS API Parameter:"
104
    log_error "(OSP_IMG_ID or OSP_IMG_FORMAT or OSP_IMG_PASSWD)"
105
    exit 1
106
  fi
107
  IMG_ID=$OSP_IMG_ID
108
  IMG_FORMAT=$OSP_IMG_FORMAT
109
  IMG_PASSWD=$OSP_IMG_PASSWD
110
}
111

    
112
get_os_type() {
113
    target=$1
114
    if [ -z "${target}" ] ; then
115
        log_error "target is not set in get_os_type"
116
        exit 1
117
    fi
118
    if [ -e ${target}/etc/redhat-release ] ; then
119
        OS_TYPE="redhat"
120
    elif [ -e ${target}/etc/debian_version ] ; then
121
        OS_TYPE="debian"
122
    elif [ -e ${target}/etc/gentoo-release ] ; then
123
        OS_TYPE="gentoo"
124
    elif [ -e ${target}/etc/SuSE-release ] ; then
125
        OS_TYPE="suse"
126
    fi
127
}
128

    
129
get_os() {
130
    target=$1
131
    if [ -z "${target}" ] ; then
132
        log_error "target is not set in get_os"
133
        exit 1
134
    fi
135
    if [ -e ${target}/etc/debian_version ] ; then
136
        if [ -e ${target}/etc/lsb-release ] ; then
137
            ID=$(grep ^DISTRIB_ID= ${target}/etc/lsb-release | cut -d= -f2)
138
        fi
139
        if [ "a$ID" = "aUbuntu" ] ; then
140
            OPERATING_SYSTEM="ubuntu"
141
        else
142
            OPERATING_SYSTEM="debian"
143
        fi
144
    elif [ -e ${target}/etc/gentoo-release ] ; then
145
        OPERATING_SYSTEM="gentoo"
146
    elif [ -e ${target}/etc/fedora-release ] ; then
147
        OPERATING_SYSTEM="fedora"
148
    elif [ -e ${target}/etc/redhat-release ] ; then
149
        if [ -n "$(grep -i centos ${target}/etc/redhat-release)" ] ; then
150
            OPERATING_SYSTEM="centos"
151
        else
152
            OPERATING_SYSTEM="redhat"
153
        fi
154
    fi
155
}
156

    
157
get_os_release() {
158
    target=$1
159
    if [ -z "${target}" ] ; then
160
        log_error "target is not set in get_os_release"
161
        exit 1
162
    fi
163
    if [ -e ${target}/etc/debian_version ] ; then
164
        OS_RELEASE="$(cat ${target}/etc/debian_version)"
165
    elif [ -e ${target}/etc/fedora-release ] ; then
166
        OS_RELEASE="$(cat ${target}/etc/fedora-release | awk '{print $3}')"
167
    elif [ -e ${$target}/etc/redhat-release ] ; then
168
        OS_RELEASE="$(cat ${target}/etc/redhat-release | awk '{print $3}')"
169
    fi
170
}
171

    
172
format_disk0() {
173
    local sfdisk_cmd="$SFDISK -uM -H 255 -S 63 --quiet --Linux --DOS $1"
174
    if [  "${SWAP}" = "yes" -a "${BOOT}" = "yes" ] ; then
175
        # Create three partitions:
176
        # 1 - 100MB /boot, bootable
177
        # 2 - Size of Memory, swap
178
        # 3 - Rest
179
        $sfdisk_cmd > /dev/null <<EOF
180
,100,L,*
181
,${SWAP_SIZE},S
182
,,L
183
EOF
184
    elif [  "${SWAP}" = "no" -a "${BOOT}" = "yes" ] ; then
185
        # Create two partitions:
186
        # 1 - 100MB /boot, bootable
187
        # 2 - Rest
188
        $sfdisk_cmd > /dev/null <<EOF
189
,100,L,*
190
,,L
191
EOF
192
    elif [  "${SWAP}" = "yes" -a "${BOOT}" = "no" ] ; then
193
        # Create two partitions:
194
        # 1 - Size of Memory, swap
195
        # 2 - Rest
196
        $sfdisk_cmd > /dev/null <<EOF
197
,$SWAP_SIZE,S
198
,,L
199
EOF
200
    elif [  "${SWAP}" = "no" -a "${BOOT}" = "no" ] ; then
201
        # Create two partitions:
202
        # 1 - Whole
203
        $sfdisk_cmd > /dev/null <<EOF
204
,,L
205
EOF
206
    fi
207
}
208

    
209
mkfs_disk0() {
210
    local mkfs="mkfs.${FILESYSTEM}"
211

    
212
    if [[ "$FILESYSTEM" == ext[123] ]] ; then
213
        # Some GRUB legacy versions like the one used by CentOS 5.x have issues
214
        # with 256 byte inode size which is the default for recent versions of
215
        # e2fsprogs. We'll stick with 128 bytes for now.
216
        mkfs+=" -I 128"
217
    fi
218
    
219
    # Format /
220
    $mkfs -Fq -L / $root_dev > /dev/null
221
    # Format /boot
222
    if [ -n "${boot_dev}" ] ; then
223
        $mkfs -Fq -L /boot $boot_dev > /dev/null
224
    fi
225
    # Format swap
226
    if [ -n "${swap_dev}" ] ; then
227
        # Format swap
228
        mkswap -f $swap_dev > /dev/null
229
    fi
230
    # During reinstalls, ext4 needs a little time after a mkfs so add it here
231
    # and also run a sync to be sure.
232
    sync
233
    sleep 2
234
}
235

    
236
mount_disk0() {
237
    local target=$1
238
    mount $root_dev $target
239
    CLEANUP+=("umount $target")
240
    if [ -n "${boot_dev}" ] ; then
241
        $MKDIR_P $target/boot
242
        mount $boot_dev $target/boot
243
        CLEANUP+=("umount $target/boot")
244
    fi
245
    # sync the file systems before unmounting to ensure everything is flushed
246
    # out
247
    CLEANUP+=("sync")
248
}
249

    
250
map_disk0() {
251
    blockdev="$1"
252
    filesystem_dev_base=`$KPARTX -l -p- $blockdev | \
253
                            grep -m 1 -- "-1.*$blockdev" | \
254
                            $AWK '{print $1}'`
255
    if [ -z "$filesystem_dev_base" ]; then
256
        log_error "Cannot interpret kpartx output and get partition mapping"
257
        exit 1
258
    fi
259
    $KPARTX -a -p- $blockdev > /dev/null
260
    filesystem_dev="/dev/mapper/${filesystem_dev_base/%-1/}"
261
    if [ ! -b "/dev/mapper/$filesystem_dev_base" ]; then
262
        log_error "Can't find kpartx mapped partition: /dev/mapper/$filesystem_dev_base"
263
        exit 1
264
    fi
265
    echo "$filesystem_dev"
266
}
267

    
268
map_partition() {
269
    filesystem_dev="$1"
270
    partition="$2"
271
    if [ "${SWAP}" = "yes" -a "${BOOT}" = "yes" ] ; then
272
        boot_dev="${filesystem_dev}-1"
273
        swap_dev="${filesystem_dev}-2"
274
        root_dev="${filesystem_dev}-3"
275
    elif [ "${SWAP}" = "no" -a "${BOOT}" = "yes" ] ; then
276
        boot_dev="${filesystem_dev}-1"
277
        root_dev="${filesystem_dev}-2"
278
    elif [ "${SWAP}" = "yes" -a "${BOOT}" = "no" ] ; then
279
        swap_dev="${filesystem_dev}-1"
280
        root_dev="${filesystem_dev}-2"
281
    elif [ "${SWAP}" = "no" -a "${BOOT}" = "no" ] ; then
282
        root_dev="${filesystem_dev}-1"
283
    fi
284
    echo "$(eval "echo \${$(echo ${partition}_dev)"})"
285
}
286

    
287
unmap_disk0() {
288
  $KPARTX -d -p- $1
289
}
290

    
291
setup_fstab() {
292
    local target=$1 fs=${FILESYSTEM}
293
    get_os_type $target
294
    cat > $target/etc/fstab <<EOF
295
# /etc/fstab: static file system information.
296
#
297
# <file system>   <mount point>   <type>  <options>       <dump>  <pass>
298
UUID=$root_uuid   /               $fs     defaults        0       1
299
proc              /proc           proc    defaults        0       0
300
EOF
301

    
302
if [ -n "$boot_dev" -a -n "$boot_uuid" ] ; then
303
    cat >> $target/etc/fstab <<EOF
304
UUID=$boot_uuid   /boot           $fs     defaults        1       2
305
EOF
306
fi
307

    
308
if [ -n "$swap_dev" -a -n "$swap_uuid" ] ; then
309
    cat >> $target/etc/fstab <<EOF
310
UUID=$swap_uuid   swap            swap    defaults        0       0
311
EOF
312
fi
313

    
314
# OS Specific fstabs
315
if [ "$OS_TYPE" = "redhat" ] ; then
316
    cat >> $target/etc/fstab <<EOF
317
tmpfs             /dev/shm        tmpfs   defaults        0       0
318
devpts            /dev/pts        devpts  gid=5,mode=620  0       0
319
sysfs             /sys            sysfs   defaults        0       0
320
EOF
321
fi
322

    
323
if [ "$OS_TYPE" = "gentoo" ] ; then
324
    cat >> $target/etc/fstab <<EOF
325
shm               /dev/shm        tmpfs   nodev,nosuid,noexec 0   0
326
EOF
327
fi
328
}
329

    
330
setup_console() {
331
    local target=$1
332
    if [ -z "$target" ] ; then
333
        log_error "target not set for setup_console"
334
        exit 1
335
    fi
336
    # Upstart is on this system, so do this instead
337
    if [ -e ${target}/etc/event.d/tty1 ] ; then
338
        cat ${target}/etc/event.d/tty1 | sed -re 's/tty1/ttyS0/' \
339
            > ${target}/etc/event.d/ttyS0
340
        return
341
    fi
342
    # upstart in karmic and newer
343
    if [ -e ${target}/etc/init/tty1.conf ] ; then
344
        cat ${target}/etc/init/tty1.conf | \
345
        sed -re 's/^exec.*/exec \/sbin\/getty -L 115200 ttyS0 vt102/' \
346
            > ${target}/etc/init/ttyS0.conf
347
        sed -ie 's/tty1/ttyS0/g' ${target}/etc/init/ttyS0.conf
348
        return
349
    fi
350
    get_os $target
351
    case $OPERATING_SYSTEM in
352
        gentoo)
353
            sed -i -e 's/.*ttyS0.*/s0:12345:respawn:\/sbin\/agetty 115200 ttyS0 vt100/' \
354
                ${target}/etc/inittab
355
            ;;
356
        centos)
357
            echo "s0:12345:respawn:/sbin/agetty 115200 ttyS0 vt100" >> \
358
                ${target}/etc/inittab
359
            ;;
360
        debian|ubuntu)
361
            sed -i -e 's/.*T0.*/T0:23:respawn:\/sbin\/getty -L ttyS0 115200 vt100/' \
362
                ${target}/etc/inittab
363
            ;;
364
        *)
365
            echo "No support for your OS in instance-image, skipping..."
366
            ;;
367
    esac
368
}
369

    
370
epilogue() {
371
    local target=$1
372
    if [ -z "$target" ] ; then
373
        log_error "target not set for filesystem_check"
374
        exit 1
375
    fi
376

    
377
    get_os_type $target
378
    if [ "${OS_TYPE}" = "redhat" ]; then
379
        # we have to force a filesystem relabeling for SELinux after messing
380
        # around with the filesystem in redhat-derived OSs
381
        echo "Enforce an automatic relabeling in the initial boot process..."
382
        touch $target/.autorelabel
383
    fi
384
}
385

    
386
cleanup() {
387
  # if something fails here, it souldn't call cleanup again...
388
  trap - EXIT
389

    
390
  if [ ${#CLEANUP[*]} -gt 0 ]; then
391
    LAST_ELEMENT=$((${#CLEANUP[*]}-1))
392
    REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0)
393
    for i in $REVERSE_INDEXES; do
394
        # If something fails here, it's better to retry it for a few times
395
        # before we give up with an error. This is needed for kpartx when
396
        # dealing with ntfs partitions mounted through fuse. umount is not
397
        # synchronous and may return while the partition is still busy. A
398
        # premature attempt to delete partition mappings through kpartx on a
399
        # device that hosts previously mounted ntfs partition may fail with an 
400
        # `device-mapper: remove ioctl failed: Device or resource busy'
401
        # error. A sensible workaround for this is to wait for a while and then
402
        # try again.
403
        local cmd=${CLEANUP[$i]}
404
        $cmd || for interval in 0.25 0.5 1 2 4; do
405
            echo "Command $cmd failed!"
406
            echo "I'll wait for $interval secs and will retry..."
407
            sleep $interval
408
            $cmd && break
409
        done
410
        test $? -eq 1 && { echo "Giving Up..."; exit 1; }
411
    done
412
  fi
413
  echo "Clean UP executed"
414
}
415

    
416
trap cleanup EXIT
417

    
418
DEFAULT_FILE="@DEFAULT_DIR@/ganeti-instance-image"
419
if [ -f "$DEFAULT_FILE" ]; then
420
    . "$DEFAULT_FILE"
421
fi
422

    
423
# note: we don't set a default mirror since debian and ubuntu have
424
# different defaults, and it's better to use the default
425

    
426
# only if the user want to specify a mirror in the defaults file we
427
# will use it, this declaration is to make sure the variable is set
428
: ${CDINSTALL:="no"}
429
: ${BOOT:="no"}
430
: ${SWAP:="yes"}
431
: ${SWAP_SIZE:="${INSTANCE_BE_memory}"}
432
: ${FILESYSTEM:="ext3"}
433
: ${KERNEL_ARGS=""}
434
: ${OVERLAY=""}
435
: ${IMAGE_NAME:=""}
436
: ${IMAGE_TYPE:="dump"}
437
: ${NOMOUNT:="no"}
438
: ${ARCH:=""}
439
: ${CUSTOMIZE_DIR:="@sysconfdir@/ganeti/instance-image/hooks"}
440
: ${VARIANTS_DIR:="@sysconfdir@/ganeti/instance-image/variants"}
441
: ${NETWORKS_DIR:="@sysconfdir@/ganeti/instance-image/networks"}
442
: ${OVERLAYS_DIR:="@sysconfdir@/ganeti/instance-image/overlays"}
443
: ${IMAGE_DIR:="@localstatedir@/cache/ganeti-instance-image"}
444
: ${IMAGE_DEBUG:="no"}
445
: ${TOOLS_DIR:="@OS_DIR@/@OS_NAME@/tools"}
446

    
447
SCRIPT_NAME=$(basename $0)
448
KERNEL_PATH="$INSTANCE_HV_kernel_path"
449

    
450
if [ -f /sbin/blkid -a -x /sbin/blkid ]; then
451
    VOL_ID="/sbin/blkid -c /dev/null -o value -s UUID"
452
    VOL_TYPE="/sbin/blkid -c /dev/null -o value -s TYPE"
453
else
454
    for dir in /lib/udev /sbin; do
455
        if [ -f $dir/vol_id -a -x $dir/vol_id ]; then
456
            VOL_ID="$dir/vol_id -u"
457
            VOL_TYPE="$dir/vol_id -t"
458
        fi
459
    done
460
fi
461

    
462
if [ -z "$VOL_ID" ]; then
463
    log_error "vol_id or blkid not found, please install udev or util-linux"
464
    exit 1
465
fi
466

    
467

    
468
if [ -z "$OS_API_VERSION" -o "$OS_API_VERSION" = "5" ]; then
469
  OS_API_VERSION=5
470
  GETOPT_RESULT=`getopt -o o:n:i:b:s: -n '$0' -- "$@"`
471
  if [ $? != 0 ] ; then log_error "Terminating..."; exit 1 ; fi
472
  get_api5_arguments $GETOPT_RESULT
473
elif [ "$OS_API_VERSION" = "10" -o "$OS_API_VERSION" = "15" ]; then
474
  get_api10_arguments
475
elif [ "$OS_API_VERSION" = "20" ]; then
476
  get_api10_arguments
477
  get_api20_parameters
478
  IMAGE_NAME=$IMG_ID
479
else
480
  log_error "Unknown OS API VERSION $OS_API_VERSION"
481
  exit 1
482
fi
483

    
484
if [ -n "$OS_VARIANT" ]; then
485
  if [ ! -d "$VARIANTS_DIR" ]; then
486
    log_error "OS Variants directory $VARIANTS_DIR doesn't exist"
487
    exit 1
488
  fi
489
  VARIANT_CONFIG="$VARIANTS_DIR/$OS_VARIANT.conf"
490
  if [ -f "$VARIANT_CONFIG" ]; then
491
    . "$VARIANT_CONFIG"
492
  else
493
    if grep -qxF "$OS_VARIANT" variants.list; then
494
      log_error "ERROR: instance-image configuration error"
495
      log_error "  Published variant $OS_VARIANT is missing its config file"
496
      log_error "  Please create $VARIANT_CONFIG or unpublish the variant"
497
      log_error "  (by removing $OS_VARIANT from variants.list)"
498
    else
499
      log_error "Unofficial variant $OS_VARIANT is unsupported"
500
      log_error "Most probably this is a user error, forcing a wrong name"
501
      log_error "To support this variant please create file $VARIANT_CONFIG"
502
    fi
503
    exit 1
504
  fi
505
fi
506