This file is indexed.

/usr/bin/cloud-localds is in cloud-image-utils 0.30-0ubuntu5.

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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#!/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
                             can be anything supported by qemu-img or
                             tar, tar-seed-local, tar-seed-net
     -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
     -N | --network-config F write network config file to local datasource
     -m | --dsmode      M    add 'dsmode' ('local' or 'net') to the metadata
                             default in cloud-init is 'net', meaning network is
                             required.
     -V | --vendor-data F    vendor-data file
     -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 "${@}"
}

has_cmd() {
	command -v "$1" >/dev/null 2>&1
}

short_opts="hH:i:d:f:m:N:o:V:v"
long_opts="disk-format:,dsmode:,filesystem:,help,hostname:,interfaces:,"
long_opts="${long_opts}network-config:,output:,vendor-data:,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=""
vendordata=""
filesystem=""
diskformat=$DEF_DISK_FORMAT
interfaces=_unset
dsmode=""
hostname=""
ncname="network-config"


while [ $# -ne 0 ]; do
	cur=${1}; next=${2};
	case "$cur" in
		-h|--help) Usage ; exit 0;;
		-d|--disk-format) diskformat=$next; shift;;
		-f|--filesystem) filesystem=$next; shift;;
		-H|--hostname) hostname=$next; shift;;
		-i|--interfaces) interfaces=$next; shift;;
		-N|--network-config) netcfg=$next; shift;;
		-m|--dsmode) dsmode=$next; shift;;
		-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
		-V|--vendor-data) vendordata="$next";;
		--) 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

case "$diskformat" in
	tar|tar-seed-local|tar-seed-net)
		if [ "${filesystem:-tar}" != "tar" ]; then
			fail "diskformat=tar is incompatible with filesystem"
		fi
		filesystem="$diskformat"
		;;
	tar*)
		fail "supported 'tar' formats are tar, tar-seed-local, tar-seed-net"
esac

if [ -z "$filesystem" ]; then
	filesystem="$DEF_FILESYSTEM"
fi
if [ "$filesystem" = "iso" ]; then
	filesystem="iso9660"
fi

case "$filesystem" in
	tar*)
		has_cmd tar ||
			fail "missing 'tar'. Required for --filesystem=$filesystem";;
	vfat)
		has_cmd mkfs.vfat ||
			fail "missing 'mkfs.vfat'. Required for --filesystem=vfat."
		has_cmd mcopy ||
			fail "missing 'mcopy'. Required for --filesystem=vfat."
		;;
	iso9660)
		has_cmd genisoimage ||
			fail "missing 'genisoimage'.  Required for --filesystem=iso9660."
		;;
	*) fail "unknown filesystem $filesystem";;
esac

case "$diskformat" in
	tar*|raw) :;;
	*) has_cmd "qemu-img" ||
		fail "missing 'qemu-img'.  Required for --disk-format=$diskformat."
esac

[ "$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

files=( "${TEMP_D}/user-data" "${TEMP_D}/meta-data" )
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 [ -n "$netcfg" ]; then
	cp "$netcfg" "${TEMP_D}/$ncname" ||
		fail "failed to copy network config"
	files[${#files[@]}]="$TEMP_D/$ncname"
fi

if [ -n "$vendordata" ]; then
	cp "$vendordata" "${TEMP_D}/vendor-data" ||
		fail "failed to copy vendor data"
	files[${#files[@]}]="$TEMP_D/vendor-data"
fi

files_rel=( )
for f in "${files[@]}"; do
	files_rel[${#files_rel[@]}]="${f#${TEMP_D}/}"
done

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-data"
tar_opts=( --owner=root --group=root )

case "$filesystem" in
	tar)
		tar "${tar_opts[@]}" -C "${TEMP_D}" -cf "$img" "${files_rel[@]}" ||
			fail "failed to create tarball of ${files_rel[*]}"
		;;
	tar-seed-local|tar-seed-net)
		if [ "$filesystem" = "tar-seed-local" ]; then
			path="var/lib/cloud/seed/nocloud"
		else
			path="var/lib/cloud/seed/nocloud-net"
		fi
		mkdir -p "${TEMP_D}/${path}" ||
			fail "failed making path for seed files"
		mv "${files[@]}" "${TEMP_D}/$path" ||
			fail "failed moving files"
		tar "${tar_opts[@]}" -C "${TEMP_D}" -cf "$img" "${path}" ||
			fail "failed to create tarball with $path"
		;;
	iso9660)
		genisoimage -output "$img" -volid cidata \
			-joliet -rock "${files[@]}" > "$TEMP_D/err" 2>&1 ||
			{ cat "$TEMP_D/err" 1>&2; fail "failed to genisoimage"; }
		;;
	vfat)
		truncate --size 128K "$img" || fail "failed truncate image"
		out=$(mkfs.vfat -n cidata "$img" 2>&1) ||
			{ error "failed: mkfs.vfat -n cidata $img"; error "$out"; }
		mcopy -oi "$img" "${files[@]}" :: ||
			fail "failed to copy user-data, meta-data to img"
		;;
esac

[ "$output" = "-" ] && output="$TEMP_D/final"
if [ "${diskformat#tar}" != "$diskformat" -o "$diskformat" = "raw" ]; then
	cp "$img" "$output" ||
		fail "failed to copy image to $output"
else
	qemu-img convert -f raw -O "$diskformat" "$img" "$output" ||
		fail "failed to convert to disk format $diskformat"
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