Merge lp:~smoser/maas-images/lp1689557-build-squashfs-trusty into lp:maas-images

Proposed by Scott Moser
Status: Merged
Merged at revision: 376
Proposed branch: lp:~smoser/maas-images/lp1689557-build-squashfs-trusty
Merge into: lp:maas-images
Diff against target: 293 lines (+289/-0)
1 file modified
bin/img2squashfs (+289/-0)
To merge this branch: bzr merge lp:~smoser/maas-images/lp1689557-build-squashfs-trusty
Reviewer Review Type Date Requested Status
Lee Trager (community) Approve
Review via email: mp+323920@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

This is a work in progress.
The goal of the branch is to allow creation of a squashfs image in the output from a build of trusty or precise (which do not have a .squashfs image).

Currently, what happens in those case is output contains the -root.tar.xz output.

The plan is to change meph2/stream.py 'create_version' to create a squashfs image if the input wasnt squashfs and the config indicated squashfs.

Revision history for this message
Lee Trager (ltrager) wrote :

Thanks for coding this up. I've been successfully using it with lp:~ltrager/maas-images/v3_squashfs_only Feel free to land otherwise I'll land it with my branch.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'bin/img2squashfs'
--- bin/img2squashfs 1970-01-01 00:00:00 +0000
+++ bin/img2squashfs 2017-05-11 14:54:13 +0000
@@ -0,0 +1,289 @@
1#!/bin/bash
2
3VERBOSITY=1
4TEMP_D=""
5VALID_FORMATS=( auto img-tar root-image root-image-gz root-tar squashfs-image
6 dir )
7
8error() { echo "$@" 1>&2; }
9fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
10
11Usage() {
12 cat <<EOF
13Usage: ${0##*/} [ options ] source-image output-squash-image
14
15 convert 'source-image' into a squashfs filesystem image.
16
17 source-image is a file in one of:
18 ${VALID_FORMATS[*]}
19
20 output-squash-image will be a squashfs image.
21
22 options:
23 -v | --verbose increase verbosity
24 -f | --format F source-image is of format F. default: auto.
25 must be one of:
26 auto: determine based on file and name heuristics
27 img-tar: tarball of root image (image file named .img)
28 root-image: filesytem (ext[234] in a file)
29 root-image-gz: root-image that is compressed with gzip
30 root-tar: tarball of / (supports .tar.xz .tar.gz)
31 squashfs-image: a squahsfs image (.squashfs)
32 -O | --owner O change ownership of output to O (user:group)
33
34 Example:
35 ${0##*/} --format=my.tar.gz my.squashfs
36EOF
37}
38
39bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
40cleanup() {
41 [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
42}
43
44ddebug() {
45 local level="$1"; shift;
46 [ "${level}" -gt "${VERBOSITY}" ] && return
47 error "$(date -R):" "$@"
48}
49
50debug() {
51 local level=${1}; shift;
52 [ "${level}" -gt "${VERBOSITY}" ] && return
53 error "${@}"
54}
55
56inargs() {
57 #inargs(needle, [haystack])
58 # return true if needle is in haystack
59 local needle="$1" i=""
60 shift
61 for i in "$@"; do
62 [ "$i" = "$needle" ] && return 0
63 done
64 return 1
65}
66
67get_img_from_tar() {
68 # given 'img' (image.tar.gz), extract it and put the .img file in 'out'
69 local img="$1" out="$2" tempd="$3"
70 local mtmp=$(mktemp -d "${tempd}/img_from_tar.XXXXXX")
71 tar -C "$mtmp" -Sxf "$img" ||
72 { error "failed to extract $img"; return 1; }
73 local f="" found=""
74 for f in "${mtmp}/"*; do
75 [ ! -f "$f" -o "${f%.img}" = "$f" ] && continue
76 [ -z "$found" ] ||
77 { error "multiple .img found in $img"; return 1; }
78 found="$f"
79 done
80 [ -n "$found" ] || { error "no .img in $img"; return 1; }
81 mv "$found" "$out" && rm -Rf "$mtmp"
82}
83
84determine_format() {
85 local input="$1" fmt="$2" fout=""
86 inargs "$fmt" "${VALID_FORMATS[@]}" || {
87 error "provided '--format=$fmt' not a valid format:" \
88 "${VALID_FORMATS[*]}"
89 return 1;
90 }
91 [ "$fmt" != "auto" ] && _RET="$fmt" && return 0
92 if [ -d "$input" ]; then
93 debug 1 "${input} is a directory";
94 _RET="$dir"
95 return
96 fi
97 fout=$(LANG=C file "$input") ||
98 { error "failed: file $input"; return 1; }
99 case "${fout#$input: }" in
100 "gzip compressed"*)
101 fout=$(zcat "$input" | file -)
102 case "${fout#*: }" in
103 POSIX\ tar*) fmt="img-tar";;
104 *) fmt="root-image-gz";;
105 esac
106 ;;
107 "POSIX tar"*) fmt="img-tar";;
108 *ext[234]\ filesystem*) fmt="root-image";;
109 *[Ss]quashfs*) fmt="squashfs-image";;
110 *)
111 # if the above failed (on trusty a .tar.gz file was reported
112 # as a Minux file system) then try filename based heuristics
113 case "$input" in
114 *-root.t??|*-root.tar|*-root.tar.??) fmt="root-tar";;
115 *.tar.gz|*.tgz|*.tar) fmt="img-tar";;
116 *.gz) fmt="root-image-gz";;
117 *.squashfs) fmt="squashfs-image";;
118 *)
119 error "WARN: file '$input' did not match name hueristics"
120 fmt="root-image";;
121 esac
122 debug 1 "guessing $input is $fmt based on name and 'file' [$fout]";;
123 esac
124 debug 1 "determined format is $fmt"
125 _RET="$fmt"
126}
127
128get_usable_input() {
129 # given 'input' in format 'fmt' return:
130 # _RET_fmt: the format of _RET_PATH. either
131 # fs-image : a mountable filesystem image.
132 # dir : a directory
133 # _RET_path: full path to a file in tempd
134 local input="$1" fmt="$2" tempd="$3" cmd=""
135 case "$fmt" in
136 img-tar)
137 _RET_fmt="fs-image"
138 _RET_path="fs-image"
139 get_img_from_tar "$input" "${tempd}/fs-image" "${tempd}"
140 return;;
141 root-image-gz)
142 _RET_fmt="fs-image"
143 _RET_path="$tempd/fs-image"
144 zcat -c "$input" > "$tempd/fs-image.tmp" &&
145 mv "$tempd/fs-image.tmp" "$tempd/fs-image"
146 return;;
147 root-image)
148 _RET_fmt="fs-image"
149 _RET_path="$tempd/fs-image"
150 ln -s "$(readlink -f "$input")" "${tempd}/fs-image"
151 return;;
152 squashfs-image)
153 _RET_fmt="squashfs-image"
154 _RET_PATH="${tempd}/fs-image"
155 ln -s "$(readlink -f "$input")" "${tempd}/fs-image"
156 return;;
157 root-tar)
158 _RET_fmt="dir"
159 _RET_path="${tempd}/fs-dir"
160 mkdir "${_RET_path}"
161 cmd=( tar -C "${_RET_path}" -xpSf "$input" \
162 --numeric-owner --xattrs "--xattrs-include=*" )
163 debug 1 "extracting $fmt with ${cmd[*]}"
164 "${cmd[@]}" || {
165 error "failed: extracting $fmt with ${cmd[*]}"
166 return 1;
167 }
168 return
169 ;;
170 dir)
171 _RET_fmt="dir"
172 _RET_PATH="${tempd}/fs-dir"
173 ln -s "$(readlink -f "$input")" "${tempd}/fs-dir"
174 return;;
175 *)
176 error "Unknown format '$fmt'";
177 return 1;;
178 esac
179}
180
181
182dir2squashfs() {
183 local src_d="$1" out="$2" owner="${3:-$(id -u):$(id -g)}"
184 local tmpfile ret="" cmd=""
185 tmpfile="${out}.${0##*/}.$$" || return
186 cmd=( mksquashfs "$src_d" "$tmpfile" -xattrs -comp xz )
187 ddebug 1 "starting: ${cmd[*]}"
188 "${cmd[@]}"
189 ret=$?
190 ddebug 1 "finished: returned $ret"
191 if [ $ret -eq 0 ]; then
192 chown "$owner" "$tmpfile" ||
193 { error "failed chown $owner $tmpfile"; return 1; }
194 mv "$tmpfile" "$out" ||
195 { error "failed to move file to $out"; return 1; }
196 else
197 rm -f "$tmpfile"
198 error "mksquashfs failed [$ret]: ${cmd[*]}."
199 fi
200 return $ret
201}
202
203fsimage2squashfs() {
204 local src="$1" out="$2" owner="$3"
205 local sudo="sudo"
206 [ "$(id -u )" = "0" ] && sudo=""
207 local cmd=""
208 cmd=( mount-image-callback "$src" --
209 "$0" dir2squashfs _MOUNTPOINT_ "$out" $owner )
210 debug 1 "calling ${cmd[*]}"
211 "${cmd[@]}"
212}
213
214main() {
215 local short_opts="hf:O:v"
216 local long_opts="help,format:,owner:,verbose"
217 local getopt_out=""
218 getopt_out=$(getopt --name "${0##*/}" \
219 --options "${short_opts}" --long "${long_opts}" -- "$@") &&
220 eval set -- "${getopt_out}" ||
221 { bad_Usage; return; }
222
223 local cur="" next="" input="" output="" owner="" fmt_in="auto" fmt=""
224 while [ $# -ne 0 ]; do
225 cur="$1"; next="$2";
226 case "$cur" in
227 -h|--help) Usage ; exit 0;;
228 -f|--format) fmt_in="$next"; shift;;
229 -O|--owner) owner="$next"; shift;;
230 -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
231 --) shift; break;;
232 esac
233 shift;
234 done
235
236 [ $# -eq 2 ] || { bad_Usage "must provide input and output."; return; }
237 src_in="$1"
238 output="$2"
239
240 TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
241 { error "failed to make tempdir"; return 1; }
242 trap cleanup EXIT
243 local tempd="${TEMP_D}"
244
245 determine_format "${src_in}" "${fmt_in}" || return
246 local fmt="${_RET}"
247 debug 1 "format of '${src_in}' is '$fmt'"
248
249 case "$fmt" in
250 dir|squashfs-image|root-tar) :;;
251 *)
252 [ "$(id -u)" = "0" ] || {
253 error "Cannot convert $fmt to squashfs as non-root";
254 return 1;
255 }
256 esac
257 get_usable_input "${src_in}" "$fmt" "$tempd" || return
258 local cfmt="${_RET_fmt}" tpath="${_RET_path}"
259
260 debug 1 "got format '$cfmt' at temp path '$tpath'"
261 if [ "$cfmt" = "squashfs-image" ]; then
262 local tmpf="$output.$$"
263 cp "$src_in" "$tmpf" &&
264 { [ -z "$owner" ] || chown "$owner" "$tmpf" ; } &&
265 mv "$tmpf" "$output" || {
266 rm -f "$tmpf"
267 error "failed copying $src_in to $output"
268 return 1
269 }
270 elif [ -f "$tpath" ]; then
271 fsimage2squashfs "$tpath" "$output" "$owner" || return
272 elif [ -d "$tpath" ]; then
273 dir2squashfs "$tpath" "$output" || return
274 else
275 error "failed. path='$tpath' cfmt=${cfmt}"
276 return 1
277 fi
278 error "output in $output. took ${SECONDS}s."
279 return 0
280}
281
282if [ "$1" = "dir2squashfs" ]; then
283 shift
284 dir2squashfs "$@"
285else
286 main "$@"
287fi
288
289# vi: ts=4 expandtab

Subscribers

People subscribed via source and target branches