Merge lp:~smoser/cloud-initramfs-tools/updateroot into lp:cloud-initramfs-tools

Proposed by Scott Moser
Status: Merged
Merged at revision: 136
Proposed branch: lp:~smoser/cloud-initramfs-tools/updateroot
Merge into: lp:cloud-initramfs-tools
Diff against target: 346 lines (+295/-1)
8 files modified
Makefile (+1/-1)
debian/cloud-initramfs-updateroot.install (+2/-0)
debian/cloud-initramfs-updateroot.postinst (+13/-0)
debian/cloud-initramfs-updateroot.postrm (+14/-0)
debian/control (+9/-0)
updateroot/doc/README.txt (+69/-0)
updateroot/hooks/updateroot (+26/-0)
updateroot/scripts/init-bottom/updateroot (+161/-0)
To merge this branch: bzr merge lp:~smoser/cloud-initramfs-tools/updateroot
Reviewer Review Type Date Requested Status
cloud-initramfs-tools Pending
Review via email: mp+312901@code.launchpad.net
To post a comment you must log in.
127. By Scott Moser

merge from trunk

128. By Scott Moser

some improvements, fewer subshells

no more subshells, use 'setf' to control setting of 'set -f'.
This allows us to restore it to its previous setting.

Also
 * bug fix here for determining if the rootmnt is writable.
 * bug fix with incorrect logic on mounting rw
 * pass arguments (rootmnt) into apply_updateroot

129. By Scott Moser

merge with trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2016-12-09 10:21:49 +0000
3+++ Makefile 2017-01-10 22:22:27 +0000
4@@ -1,4 +1,4 @@
5-MODULES = growroot rescuevol overlayroot dyn-netconf copymods rooturl
6+MODULES = growroot rescuevol overlayroot dyn-netconf copymods rooturl updateroot
7 INITRAMFS_D = /usr/share/initramfs-tools
8 IRD = $(DESTDIR)/$(INITRAMFS_D)
9 ULIB_PRE = $(DESTDIR)/usr/lib/cloud-initramfs-
10
11=== added file 'debian/cloud-initramfs-updateroot.install'
12--- debian/cloud-initramfs-updateroot.install 1970-01-01 00:00:00 +0000
13+++ debian/cloud-initramfs-updateroot.install 2017-01-10 22:22:27 +0000
14@@ -0,0 +1,2 @@
15+usr/share/initramfs-tools/hooks/updateroot
16+usr/share/initramfs-tools/scripts/*/updateroot
17
18=== added file 'debian/cloud-initramfs-updateroot.postinst'
19--- debian/cloud-initramfs-updateroot.postinst 1970-01-01 00:00:00 +0000
20+++ debian/cloud-initramfs-updateroot.postinst 2017-01-10 22:22:27 +0000
21@@ -0,0 +1,13 @@
22+#!/bin/sh
23+set -e
24+
25+case "$1" in
26+ configure)
27+ dpkg-trigger update-initramfs;;
28+ *) exit 0;;
29+esac
30+
31+#DEBHELPER#
32+exit 0
33+
34+# vi: ts=4 noexpandtab
35
36=== added file 'debian/cloud-initramfs-updateroot.postrm'
37--- debian/cloud-initramfs-updateroot.postrm 1970-01-01 00:00:00 +0000
38+++ debian/cloud-initramfs-updateroot.postrm 2017-01-10 22:22:27 +0000
39@@ -0,0 +1,14 @@
40+#!/bin/sh
41+set -e
42+
43+case "$1" in
44+ remove|purge)
45+ dpkg-trigger update-initramfs;;
46+ *) exit 0;;
47+esac
48+
49+#DEBHELPER#
50+exit 0
51+
52+# vi: ts=4 noexpandtab
53+
54
55=== modified file 'debian/control'
56--- debian/control 2016-12-09 10:21:49 +0000
57+++ debian/control 2017-01-10 22:22:27 +0000
58@@ -85,3 +85,12 @@
59 Description: use a tarball or squashfs image in a url as the root filesystem
60 Allows user to pass in root=http://example.com/your.tar.gz
61 Root filesystem will be tmpfs from that url.
62+
63+Package: cloud-initramfs-updateroot
64+Architecture: all
65+Depends: initramfs-tools,
66+ ${misc:Depends},
67+ ${shlibs:Depends}
68+Description: extract a tarball over root filesystem before pivot
69+ Allows kernel command line updateroot=http://your.tar.gz
70+ And then tarball will be pulled and extracted over the root.
71
72=== added directory 'updateroot'
73=== added directory 'updateroot/doc'
74=== added file 'updateroot/doc/README.txt'
75--- updateroot/doc/README.txt 1970-01-01 00:00:00 +0000
76+++ updateroot/doc/README.txt 2017-01-10 22:22:27 +0000
77@@ -0,0 +1,69 @@
78+updateroot is an initramfs module that allows you to update
79+the root filesystem before changing to it.
80+
81+Each updateroot= on the kernel command line will be downloaded
82+and extracted over the top of the root filesystem. Support is
83+present for gzip, xz or no compression as long as urls end in
84+.tar.gz, .tgz, .tar.xz, .txz or .tar.
85+
86+Any files in a .updateroot/ directory inside the tarball that
87+are executable will be executed inside the target before
88+init is started.
89+
90+To demo this, first install the cloud-initramfs-updateroot and
91+cloud-initramfs-rooturl packages. That will update your initramfs
92+to have these modules.
93+
94+$ sudo dpkg -i cloud-initramfs-updateroot_*.deb clodu-initramfs-rooturl*.deb
95+update-initramfs: Generating /boot/initrd.img-4.4.0-23-generic
96+$ sudo update-initramfs -u -k $(uname -r)
97+
98+# make local copies for permissions and shorter cmdline
99+$ sudo cat /boot/vmlinu?-$(uname -r) > kernel
100+$ cp /boot/initrd.img-$(uname -r) initrd
101+
102+# create 'seed.tar' with a nocloud seed
103+$ cat > user-data <<EOF
104+#cloud-config
105+password: passw0rd
106+chpasswd: { expire: False }
107+ssh_pwauth: True
108+EOF
109+$ echo "instance-id: $(uuidgen || echo i-abcdefg)" > meta-data
110+$ cloud-localds --disk-format=tar-seed-local seed.tar user-data meta-data
111+
112+# download the latest xenial squashfs
113+$ iurl="http://cloud-images.ubuntu.com/daily/server/xenial/20160523"
114+$ wget "$iurl/xenial-server-cloudimg-amd64.squashfs"
115+
116+# serve those files on a python simple web server note that
117+# 10.0.2.2 works for the host address in a qemu user mode networking
118+$ python -m SimpleHTTPServer 9999 &
119+$ burl="http://10.0.2.2:9999"
120+
121+# set cmdline variable
122+$ cmdline="root=$burl/xenial-server-cloudimg-amd64.squashfs"
123+$ cmdline="$cmdline updateroot=$burl/seed.tar"
124+$ cmdline="$cmdline overlayroot=tmpfs"
125+$ cmdline="$cmdline console=ttyS0 -v"
126+
127+# now boot a qemu guest with no disks and 1G memory.
128+$ qemu-system-x86_64 -enable-kvm \
129+ -device virtio-net-pci,netdev=net00 \
130+ -netdev type=user,id=net00 \
131+ -m 1G -nographic -kernel kernel -initrd initrd \
132+ -append "$cmdline"
133+
134+The system should boot to a login prompt and let you in as 'ubuntu:passw0rd'
135+
136+Log in and you'll see something like:
137+
138+$ df -h /
139+Filesystem Size Used Avail Use% Mounted on
140+overlayroot 497M 59M 438M 12% /
141+
142+$ egrep "(/media|overlay)" /proc/mounts
143+/dev/loop0 /media/root-ro squashfs ro,relatime 0 0
144+tmpfs-root /media/root-rw tmpfs rw,relatime 0 0
145+overlayroot / overlayfs rw,relatime,lowerdir=/media/root-ro,upperdir=/media/root-rw//overlay,workdir=/media/root-rw//overlay-workdir 0 0
146+
147
148=== added directory 'updateroot/hooks'
149=== added file 'updateroot/hooks/updateroot'
150--- updateroot/hooks/updateroot 1970-01-01 00:00:00 +0000
151+++ updateroot/hooks/updateroot 2017-01-10 22:22:27 +0000
152@@ -0,0 +1,26 @@
153+#!/bin/sh
154+set -e
155+
156+prereqs() {
157+ local o="/scripts/init-bottom/overlayroot" p=""
158+ for p in "$DESTDIR/" ""; do
159+ [ -e "$p$o" ] && echo "overlayroot" && return 0
160+ done
161+}
162+
163+[ "$1" = "prereqs" ] && { prereqs; exit; }
164+
165+. /usr/share/initramfs-tools/hook-functions
166+
167+needs="tar xz" #gzip gunzip"
168+for need in $needs; do fp=$(which $need) && copy_exec "$fp" /bin; done
169+
170+## The busybox versions of gzip and gunzip are sufficient, so use them rather
171+## than the full programs via copy_exec. However, because of odd behavior in
172+## initramfs-tools, if we put symlinks in /bin, then
173+## initramfs-tools/hooks/busybox will remove them. So instead, use /sbin
174+bbox="gzip gunzip"
175+[ -d "$DESTDIR/sbin" ] || mkdir -p "$DESTDIR/sbin"
176+for need in $bbox; do ln -sf ../bin/busybox "$DESTDIR/sbin/$need"; done
177+
178+# vi: ts=4 noexpandtab
179
180=== added directory 'updateroot/scripts'
181=== added directory 'updateroot/scripts/init-bottom'
182=== added file 'updateroot/scripts/init-bottom/updateroot'
183--- updateroot/scripts/init-bottom/updateroot 1970-01-01 00:00:00 +0000
184+++ updateroot/scripts/init-bottom/updateroot 2017-01-10 22:22:27 +0000
185@@ -0,0 +1,161 @@
186+#!/bin/sh
187+# Copyright, 2016 Scott Moser <smoser@ubuntu.com>
188+#
189+# This program is free software: you can redistribute it and/or modify
190+# it under the terms of the GNU General Public License as published by
191+# the Free Software Foundation, either version 3 of the License, or
192+# (at your option) any later version.
193+#
194+# This program is distributed in the hope that it will be useful,
195+# but WITHOUT ANY WARRANTY; without even the implied warranty of
196+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
197+# GNU General Public License for more details.
198+#
199+# You should have received a copy of the GNU General Public License
200+# along with this program. If not, see
201+# <http://www.gnu.org/licenses/>.
202+VERBOSITY="1"
203+
204+prereqs() {
205+ local o="/scripts/init-bottom/overlayroot" p=""
206+ # basically we run after overlayroot but do not depend on it
207+ for p in "$DESTDIR/" ""; do
208+ [ -e "$p$o" ] && echo "overlayroot" && return 0
209+ done
210+}
211+
212+[ "$1" != "prereqs" ] || { prereqs; exit; }
213+
214+setf() {
215+ # setf 0|1
216+ # set pathname expansion (-f) off or on
217+ # off is an alias for 0
218+ # on is an alias for 1
219+ # stores the current setting in the unscoped variable 'setf'
220+ # returns the previous setting:
221+ # 0 if pathname expansion was off
222+ # 1 if pathname expansion was on
223+ # setf restore [setting]
224+ # restore pathname expansion to 'setting'.
225+ # if setting is not provided, defaults to variable 'setf'
226+ if [ "$1" = "restore" ]; then
227+ local val=${2:-${setf:-"-"}}
228+ [ "$val" = "0" ] && val="-" || val="+"
229+ set ${val}f
230+ return
231+ fi
232+
233+ local f="" n="0" d=/ r="1"
234+ setf="+"
235+ for f in "$d/"*; do
236+ [ $n -gt 1 ] && break
237+ n=$(($n+1))
238+ done
239+ [ $n -eq 1 -a "$f" = "$d/*" ] && setf="-" && r="0"
240+ case "$1" in
241+ off|0) set -f;;
242+ on|1) set +f;;
243+ esac
244+ return $r
245+}
246+
247+debug() {
248+ local v=$1
249+ shift
250+ [ $v -lt $VERBOSITY ] && return 0
251+ echo "::" "$@"
252+}
253+
254+extract_urls() {
255+ local target="$1" url="" zopt="" script="" fails="" ret=""
256+ shift
257+ for url in "$@"; do
258+ case "$url" in
259+ *.tar.gz|*.tgz) zopt="z";;
260+ *.tar.xz|*.txz) zopt="J";;
261+ *) zopt="";;
262+ esac
263+ debug 1 "# updateroot [$zopt] $url"
264+ wget "$url" -O - | tar -C "$target" -xp${zopt}f -
265+ done
266+ if [ ! -d "$target/.updateroot" ]; then
267+ return 0
268+ fi
269+
270+ fails=0
271+ setf on; set -- "$target/.updateroot/"*; setf restore
272+ for script in "$@"; do
273+ [ -f "$script" -a -x "$script" ] || continue
274+ debug 1 "running ${script#$target} in target root"
275+ chroot "$target" "${script#$target}" || {
276+ fails=$(($fails+1))
277+ ret=$?
278+ log_warn "script '${script#$target/}' exited $ret"
279+ }
280+ done
281+ [ $fails -eq 0 ] || exit 1
282+}
283+
284+apply_updateroot() {
285+ local rootmnt="$1" cmdline="$2" ret=""
286+ local cmdline urls
287+ if [ "$cmdline" = "" ]; then
288+ if ! read cmdline < /proc/cmdline; then
289+ log_warn "no /proc/cmdline?"
290+ return 1
291+ fi
292+ fi
293+ setf off; set -- $cmdline; setf restore
294+ for tok in "$@"; do
295+ case "$tok" in
296+ updateroot=http://*) urls="${urls} ${tok#*=}";;
297+ esac
298+ done
299+ urls=${urls# }
300+
301+ setf off; set -- $urls; setf restore
302+ if [ $# -eq 0 ]; then
303+ debug 1 "no updateroot urls configured in cmdline"
304+ return 0
305+ fi
306+
307+ if ! configure_networking; then
308+ log_warn "failed configuring networking [$?]"
309+ return 1
310+ fi
311+
312+ # only mount rw if not already rw
313+ local need_remount="false" ret=0 created=true
314+ local tfile="$rootmnt/.updateroot.touch"
315+ [ -e "$tfile" ] || created=false
316+ if ! ( : >> "$tfile" ) >/dev/null 2>&1; then
317+ mount -o remount,rw "$rootmnt"
318+ ret=$?
319+ if $created; then
320+ rm -f "$tfile"
321+ fi
322+ if [ $ret -ne 0 ]; then
323+ log_warn "failed mount '$rootmnt' as rw [$ret]."
324+ return 1;
325+ fi
326+ need_remount="true"
327+ fi
328+
329+ extract_urls "$rootmnt" "$@"
330+ ret=$?
331+
332+ if [ "${need_remount}" = "true" ]; then
333+ mount -o remount,ro "$rootmnt" || {
334+ log_warn "failed remounting root '$rootmnt' as ro [$?]!"
335+ return 1
336+ }
337+ fi
338+
339+ return $ret
340+}
341+
342+. /scripts/functions
343+
344+apply_updateroot "$rootmnt"
345+
346+# vi: ts=4 noexpandtab

Subscribers

People subscribed via source and target branches