Merge lp:~smoser/cloud-utils/trunk.mic-lxd into lp:cloud-utils

Proposed by Scott Moser
Status: Merged
Merged at revision: 312
Proposed branch: lp:~smoser/cloud-utils/trunk.mic-lxd
Merge into: lp:cloud-utils
Diff against target: 192 lines (+103/-26)
1 file modified
bin/mount-image-callback (+103/-26)
To merge this branch: bzr merge lp:~smoser/cloud-utils/trunk.mic-lxd
Reviewer Review Type Date Requested Status
Registry Administrators Pending
Review via email: mp+305641@code.launchpad.net

Commit message

mount-image-callback: add lxd container support.

given lxd container on local system 'x1', you can now do:
   sudo mount-image-callback -vv --system-resolvconf \
       lxd:x1 -- chroot _MOUNTPOINT_ apt-get update

using mic to chroot into a lxd container is useful compared to 'lxc-chroot'
or simply chroot /path/to/container/rootfs because:
a.) lxc-chroot puts in own network namespace (meaning network doesnt work without bringing it up).
b.) chroot /path/to/container does not set resolvconf or system mounts
c.) mic knows assumed paths to lxd container
d.) mic uses lxc-usernsexec to join the appropriate user namespace.

Along the way, we add two little tools that can be used:
 uns-switch: user namespace switch ... switch to the user based on some environment variables that mic sets up
 mchroot: mic chroot. reads $MOUNTPOINT.

To post a comment you must log in.
Revision history for this message
Ryan Harper (raharper) wrote :

\o/

Nice!

Revision history for this message
Scott Moser (smoser) wrote :

we also have to someway account for changing uid/gid mapping on the files that are modified in the target.
so as this is, it doesnt work.

Revision history for this message
Ryan Harper (raharper) wrote :

followed up with LXD folks, and they suggested lxc-usernsexec, here's how I got it working

1) look up "root" user in /etc/subuid

SHIFT=$(awk -F: '/^root/ {print $2":"$3}' /etc/subuid)
echo $SHIFT
165536:65536

Then instead of just chroot, do:

sudo lxc-usernsexec -m b:0:$SHIFT -- chroot ...

lp:~smoser/cloud-utils/trunk.mic-lxd updated
304. By Scott Moser

seems functional at this point.

305. By Scott Moser

mention lack of usernsexec

306. By Scott Moser

white space consistentcy

Revision history for this message
Scott Moser (smoser) wrote :

I dont think this is fabulous at the moment, but it scratches a very nice itch

$ lxc init ubuntu-daily:xenial x1
$ sudo mount-image-callback --system-resolvconf lxd:x1 -- mchroot sh -ec '
    echo deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc)-proposed main universe |
       tee /etc/apt/sources.list.d/proposed.list
    apt-get update -qy
    apt-get dist-upgrade -qy'

$ lxc start x1

Revision history for this message
Ryan Harper (raharper) wrote :

One more fix; I think the list of umounts is missing being updated, as this leaves them mounted.

% sudo mount-image-callback -v --system-mounts --system-resolvconf lxd:x1 chroot _MOUNTPOINT_ -- /bin/bash
using directory at /var/lib/lxd/containers/x1/rootfs for lxd:x1 (true)
replaced string _MOUNTPOINT_ in arguments arg 1
added helper uns-switch for chroot
replacing /etc/resolvconf
invoking: MOUNTPOINT=/var/lib/lxd/containers/x1/rootfs uns-switch chroot /var/lib/lxd/containers/x1/rootfs /bin/bash
# exit
exit
cmd returned 0. unmounting /var/lib/lxd/containers/x1/rootfs
% grep x1.zfs /proc/mounts
lxd-zfs/containers/x1 /var/lib/lxd/containers/x1.zfs zfs rw,relatime,xattr,noacl 0 0
udev /var/lib/lxd/containers/x1.zfs/rootfs/dev devtmpfs rw,nosuid,relatime,size=3915008k,nr_inodes=978752,mode=755 0 0
proc /var/lib/lxd/containers/x1.zfs/rootfs/proc proc rw,nosuid,nodev,noexec,relatime 0 0
sysfs /var/lib/lxd/containers/x1.zfs/rootfs/sys sysfs rw,nosuid,nodev,noexec,relatime 0 0

Revision history for this message
Ryan Harper (raharper) wrote :

I think this fixes that and handles the nbd case where the bind mounts disappear automatically.

http://paste.ubuntu.com/23183820/

Revision history for this message
Ryan Harper (raharper) wrote :

OK, this is better:

http://paste.ubuntu.com/23183888/

Only add to the UMOUNTS list if we're doing a lxd ns switch.

lp:~smoser/cloud-utils/trunk.mic-lxd updated
307. By Scott Moser

fix unmounting system mounts

go through the mounts that we did backwards when unmounting.
we are still unmounting recursively, but if you do them in
backwards order generally that should be ok.

we still do recursive so that if you did:
 mount-image-callback my.img chroot /
   % mount -t tmpfs /dev/ /dev
   % exit

it would unmount the thing in there.

This may have to change at some point to avoid unmounting things
we did *not* mount (since we are now operating possibly on a directory
that might already have mounts under it).

308. By Scott Moser

merge with trunk

309. By Scott Moser

move nbd mounting out of main

310. By Scott Moser

merge with trunk

311. 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 'bin/mount-image-callback'
2--- bin/mount-image-callback 2016-10-05 13:15:20 +0000
3+++ bin/mount-image-callback 2016-10-05 13:44:01 +0000
4@@ -16,6 +16,10 @@
5 mount a file to a temporary mount point and then
6 invoke the provided cmd with args
7
8+ supported 'file' are:
9+ lxd:name : the rootfs for lxd container 'name'
10+ file : any disk format supported by qemu-nbd
11+
12 the temporary mountpoint will be put in an a environment variable
13 named MOUNTPOINT.
14
15@@ -81,8 +85,10 @@
16 }
17
18 do_umounts() {
19- local um="" fails=0 mydir="$PWD/"
20- for um in "$@"; do
21+ local um="" fails=0 mydir="$PWD/" mounts="" i=0
22+ mounts=( "$@" )
23+ for((i=${#mounts[@]}-1;i>=0;i--)); do
24+ um=${mounts[$i]}
25 um=$(readlink -f "$um") || {
26 error "WARNING: failed to get full path to '$um'";
27 fails=$(($fails+1))
28@@ -140,6 +146,46 @@
29 fi
30 }
31
32+add_bin() {
33+ cat > "$1" || { error "failed to write to $1"; return 1; }
34+ chmod 755 "$1" || { error "failed to set perms on $1"; return 1; }
35+}
36+
37+add_helpers() {
38+ local d="$1"
39+ local umap="$1" gmap="$2"
40+ [ -d "$1" ] || mkdir -p "$1"
41+ add_bin "$d/uns-switch" <<"EOF" || return 1
42+#!/bin/sh
43+[ $# -eq 0 ] && set -- ${SHELL:-/bin/bash}
44+if [ -z "$MIC_SUBUID" -a -z "$MIC_SUBGID" ]; then
45+ exec "$@"
46+fi
47+exec lxc-usernsexec ${MIC_SUBUID:+-m u:0:${MIC_SUBUID}} \
48+ ${MIC_SUBGID:+-m g:0:${MIC_SUBGID}} -- "$@"
49+EOF
50+ add_bin "$d/mchroot" <<"EOF" || return 1
51+#!/bin/sh
52+exec uns-switch chroot "$MOUNTPOINT" "$@"
53+EOF
54+ return
55+}
56+
57+get_subid() {
58+ local id="$1" file="$2"
59+ awk -F: '$1 == id { printf("%s:%s\n", $2, $3); exit(0); }' \
60+ id="$id" "$file"
61+}
62+
63+set_subids() {
64+ local id="$1" out="" muid="" mgid=""
65+ [ -z "$id" ] && return 0
66+ muid=$(get_subid "$id" /etc/subuid) &&
67+ mgid=$(get_subid "$id" /etc/subgid) &&
68+ [ -n "$muid" -a -n "$mgid" ] &&
69+ export MIC_SUBGID="$muid" MIC_SUBUID="$mgid" && return
70+}
71+
72 mount_overlay() {
73 local lower="$1" upper="$2" workdir="$3"
74 local olayopts="lowerdir=$lower,upperdir=$upper"
75@@ -346,14 +392,38 @@
76 return 1;
77 }
78
79+ local uns_switch=false
80 img_in="$1"
81 shift 1
82
83- img=$(readlink -f "$img_in") ||
84- { error "failed to get full path to $img_in"; return 1; }
85-
86- [ -f "$img" ] ||
87- { error "$img: not a file"; return 1; }
88+ case "$img_in" in
89+ lxd:*)
90+ if [ "$ptnum" != "auto" ]; then
91+ error "--ptnum incompatible with directory"
92+ return 1;
93+ fi
94+ command -v lxc-usernsexec >/dev/null 2>&1 || {
95+ error "lxd support needs lxc-usernsexec";
96+ return 1;
97+ }
98+ img="/var/lib/lxd/containers/${img_in#lxd:}/rootfs"
99+ [ -d "$img" ] || {
100+ error "${img_in}: no rootfs in $img. Not a container?"
101+ return 1;
102+ }
103+ set_subids lxd || {
104+ error "failed reading subids for lxd";
105+ return 1;
106+ }
107+ uns_switch=true
108+ ;;
109+ *)
110+ img=$(readlink -f "$img_in") ||
111+ { error "failed to get full path to $img_in"; return 1; }
112+ [ -f "$img" ] ||
113+ { error "$img: not a file"; return 1; }
114+ ;;
115+ esac
116
117 [ "$(id -u)" = "0" ] ||
118 { error "sorry, must be root"; return 1; }
119@@ -364,7 +434,6 @@
120 if [ -z "$mp" ]; then
121 mp="${TEMP_D}/mp"
122 mkdir "$mp" || return
123- mp_is_tmp=true
124 else
125 [ -d "$mp" ] ||
126 { error "mountpoint '$mp': not a directory"; return 1; }
127@@ -380,24 +449,17 @@
128 img_mp=$mp
129 fi
130
131- local cmd="" arg="" found=false
132- cmd=( )
133- for arg in "$@"; do
134- if [ "${arg}" = "_MOUNTPOINT_" ]; then
135- debug 1 "replaced string _MOUNTPOINT_ in arguments arg ${#cmd[@]}"
136- arg=$mp
137- fi
138- cmd[${#cmd[@]}]="$arg"
139- done
140-
141- if [ "${cmd[0]##*/}" = "bash" -o "${cmd[0]##*/}" = "sh" ] &&
142- [ ${#cmd[@]} -eq 0 ]; then
143- debug 1 "invoking shell ${cmd[0]}"
144- error "MOUNTPOINT=$mp"
145- fi
146-
147 out=""
148- if [ "$ptnum" = "auto" -o "$ptnum" = "0" ] &&
149+ if [ -d "$img" ]; then
150+ debug 1 "using directory at $img for $img_in"
151+ mp=$img
152+ if $overlay; then
153+ debug 1 "mounting $img to $mp"
154+ mount --bind "$img" "$img_mp" ||
155+ { error "failed to mount --bind '$img' '$mp'"; return 1; }
156+ UMOUNTS[${#UMOUNTS[@]}]="$mp"
157+ fi
158+ elif [ "$ptnum" = "auto" -o "$ptnum" = "0" ] &&
159 out=$(set -f; mount -o "loop,$rwmode" $opts "$img" "$img_mp" 2>&1); then
160 debug 1 "mounted simple filesystem image $rwmode in '$img_in'"
161 UMOUNTS[${UMOUNT[@]}]="$img_mp"
162@@ -430,8 +492,10 @@
163 for bindmp in $bmounts; do
164 [ -d "$mp${bindmp}" ] || mkdir "$mp${bindmp}" ||
165 { error "failed mkdir $bindmp in mount"; return 1; }
166- mount --bind "$bindmp" "$mp/${bindmp}" ||
167+ mount --bind "$bindmp" "$mp${bindmp}" ||
168 { error "failed bind mount '$bindmp'"; return 1; }
169+ UMOUNTS[${#UMOUNTS[@]}]="$mp${bindmp}"
170+ debug 1 "mounted $bindmp to $mp${bindmp}"
171 done
172
173 if ${system_resolvconf}; then
174@@ -462,6 +526,19 @@
175 error "MOUNTPOINT=$mp"
176 fi
177
178+ if $uns_switch && [ "$1" = "chroot" ]; then
179+ debug 1 "added helper uns-switch for chroot"
180+ cmd=( uns-switch "${cmd[@]}" )
181+ elif $uns_switch; then
182+ debug 1 "uns-switch helper can be used for changing user map"
183+ fi
184+
185+ add_helpers "$TEMP_D/bin" "$SUBUID" "$SUBGID" || {
186+ error "failed to add helpers to $TEMP_D";
187+ return 1;
188+ }
189+ PATH="$TEMP_D/bin:$PATH"
190+
191 local startwd="$PWD"
192 debug 1 "invoking: MOUNTPOINT=$mp" "${cmd[@]}"
193

Subscribers

People subscribed via source and target branches