/usr/bin/cloud-localds is in cloud-image-utils 0.27-0ubuntu9.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | #!/bin/bash
VERBOSITY=0
TEMP_D=""
DEF_DISK_FORMAT="raw"
DEF_FILESYSTEM="iso9660"
CR="
"
error() { echo "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] output user-data [meta-data]
Create a disk for cloud-init to utilize nocloud
options:
-h | --help show usage
-d | --disk-format D disk format to output. default: raw
-H | --hostname H set hostname in metadata to H
-f | --filesystem F filesystem format (vfat or iso), default: iso9660
-i | --interfaces F write network interfaces file into metadata
-m | --dsmode M add 'dsmode' ('local' or 'net') to the metadata
default in cloud-init is 'net', meaning network is
required.
-v | --verbose increase verbosity
Note, --dsmode, --hostname, and --interfaces are incompatible
with metadata.
Example:
* cat my-user-data
#cloud-config
password: passw0rd
chpasswd: { expire: False }
ssh_pwauth: True
* echo "instance-id: \$(uuidgen || echo i-abcdefg)" > my-meta-data
* ${0##*/} my-seed.img my-user-data my-meta-data
* kvm -net nic -net user,hostfwd=tcp::2222-:22 \\
-drive file=disk1.img,if=virtio -drive file=my-seed.img,if=virtio
* ssh -p 2222 ubuntu@localhost
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
cleanup() {
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
}
debug() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
error "${@}"
}
short_opts="hH:i:d:f:m:o:v"
long_opts="disk-format:,dsmode:,filesystem:,help,hostname:,interfaces:,output:,verbose"
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
bad_Usage
## <<insert default variables here>>
output=""
userdata=""
metadata=""
filesystem=$DEF_FILESYSTEM
diskformat=$DEF_DISK_FORMAT
interfaces=_unset
dsmode=""
hostname=""
while [ $# -ne 0 ]; do
cur=${1}; next=${2};
case "$cur" in
-h|--help) Usage ; exit 0;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
-d|--disk-format) diskformat=$next; shift;;
-f|--filesystem) filesystem=$next; shift;;
-m|--dsmode) dsmode=$next; shift;;
-i|--interfaces) interfaces=$next; shift;;
-H|--hostname) hostname=$next; shift;;
--) shift; break;;
esac
shift;
done
## check arguments here
## how many args do you expect?
[ $# -ge 2 ] || bad_Usage "must provide output, userdata"
[ $# -le 3 ] || bad_Usage "confused by additional args"
output=$1
userdata=$2
metadata=$3
if [ -n "$metadata" ]; then
[ "$interfaces" = "_unset" -a -z "$dsmode" -a -z "$hostname" ] ||
fail "metadata is incompatible with:" \
"--interfaces, --hostname, --dsmode"
fi
[ "$interfaces" = "_unset" -o -r "$interfaces" ] ||
fail "$interfaces: not a readable file"
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
fail "failed to make tempdir"
trap cleanup EXIT
if [ -n "$metadata" ]; then
cp "$metadata" "$TEMP_D/meta-data" || fail "$metadata: failed to copy"
else
instance_id="iid-local01"
iface_data=""
[ "$interfaces" != "_unset" ] &&
iface_data=$(sed ':a;N;$!ba;s/\n/\\n/g' "$interfaces")
# write json formatted user-data (json is a subset of yaml)
mdata=""
for kv in "instance-id:$instance_id" "local-hostname:$hostname" \
"interfaces:${iface_data}" "dsmode:$dsmode"; do
key=${kv%%:*}
val=${kv#*:}
[ -n "$val" ] || continue
mdata="${mdata:+${mdata},${CR}}\"$key\": \"$val\""
done
printf "{\n%s\n}\n" "$mdata" > "${TEMP_D}/meta-data"
fi
if [ "$userdata" = "-" ]; then
cat > "$TEMP_D/user-data" || fail "failed to read from stdin"
else
cp "$userdata" "$TEMP_D/user-data" || fail "$userdata: failed to copy"
fi
## alternatively, create a vfat filesystem with same files
img="$TEMP_D/seed.img"
truncate --size 100K "$img" || fail "failed truncate image"
case "$filesystem" in
iso9660|iso)
genisoimage -output "$img" -volid cidata \
-joliet -rock "$TEMP_D/user-data" "$TEMP_D/meta-data" \
> "$TEMP_D/err" 2>&1 ||
{ cat "$TEMP_D/err" 1>&2; fail "failed to genisoimage"; }
;;
vfat)
mkfs.vfat -n cidata "$img" || fail "failed mkfs.vfat"
mcopy -oi "$img" "$TEMP_D/user-data" "$TEMP_D/meta-data" :: ||
fail "failed to copy user-data, meta-data to img"
;;
*) fail "unknown filesystem $filesystem";;
esac
[ "$output" = "-" ] && output="$TEMP_D/final"
if [ "$diskformat" != "raw" ]; then
qemu-img convert -f raw -O "$diskformat" "$img" "$output" ||
fail "failed to convert to disk format $diskformat"
else
cp "$img" "$output" ||
fail "failed to copy image to $output"
fi
[ "$output" != "$TEMP_D/final" ] || { cat "$output" && output="-"; } ||
fail "failed to write to -"
debug 1 "wrote ${output} with filesystem=$filesystem and diskformat=$diskformat"
# vi: ts=4 noexpandtab
|