-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use supermin in unprivileged environments #190
Changes from 5 commits
d0f9aa0
d909410
c444585
8c380d0
f302c82
91d8f2a
18a0752
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,32 @@ | ||
# Shared shell script library | ||
|
||
DIR=$(dirname $0) | ||
|
||
info() { | ||
echo "info: $@" 1>&2 | ||
} | ||
|
||
fatal() { | ||
echo "error: $@" 1>&2; exit 1 | ||
info "$@"; exit 1 | ||
} | ||
|
||
_privileged= | ||
jlebon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
has_privileges() { | ||
if [ -z "${_privileged:-}" ]; then | ||
if [ -n "${FORCE_UNPRIVILEGED:-}" ]; then | ||
info "Detected FORCE_UNPRIVILEGED; using virt" | ||
_privileged=0 | ||
elif ! capsh --print | grep -q 'Current.*cap_sys_admin'; then | ||
info "Missing CAP_SYS_ADMIN; using virt" | ||
_privileged=0 | ||
elif ! sudo true; then | ||
info "Missing sudo privs; using virt" | ||
_privileged=0 | ||
else | ||
_privileged=1 | ||
fi | ||
fi | ||
[ ${_privileged} == 1 ] | ||
} | ||
|
||
preflight() { | ||
|
@@ -28,27 +53,25 @@ preflight() { | |
fatal "Unable to find /dev/kvm" | ||
fi | ||
|
||
if ! capsh --print | grep -q 'Current.*cap_sys_admin'; then | ||
fatal "This container must currently be run with --privileged" | ||
fi | ||
|
||
if ! sudo true; then | ||
fatal "The user must currently have sudo privileges" | ||
fi | ||
|
||
# permissions on /dev/kvm vary by (host) distro. If it's | ||
# not writable, recreate it. | ||
if ! [ -w /dev/kvm ]; then | ||
sudo rm -f /dev/kvm | ||
sudo mknod /dev/kvm c 10 232 | ||
sudo setfacl -m u:$USER:rw /dev/kvm | ||
if ! has_privileges; then | ||
fatal "running unprivileged, and /dev/kvm not writable" | ||
else | ||
sudo rm -f /dev/kvm | ||
sudo mknod /dev/kvm c 10 232 | ||
sudo setfacl -m u:$USER:rw /dev/kvm | ||
fi | ||
fi | ||
} | ||
|
||
prepare_build() { | ||
preflight | ||
if ! [ -d repo ]; then | ||
fatal "No $(pwd)/repo found; did you run coreos-assembler init?" | ||
elif ! has_privileges && [ ! -f cache/cache.qcow2 ]; then | ||
fatal "No cache.qcow2 found; did you run coreos-assembler init?" | ||
fi | ||
|
||
export workdir=$(pwd) | ||
|
@@ -95,10 +118,6 @@ prepare_build() { | |
} | ||
|
||
runcompose() { | ||
local treecompose_args="" | ||
if ! grep -q '^# disable-unified-core' "${manifest}"; then | ||
treecompose_args="${treecompose_args} --unified-core" | ||
fi | ||
# Implement support for automatic local overrides: | ||
# https://github.com/coreos/coreos-assembler/issues/118 | ||
local overridesdir=${workdir}/overrides/ | ||
|
@@ -126,10 +145,86 @@ EOF | |
fi | ||
|
||
rm -f ${changed_stamp} | ||
set -x | ||
sudo rpm-ostree compose tree --repo=${workdir}/repo-build --cachedir=${workdir}/cache \ | ||
--touch-if-changed "${changed_stamp}" \ | ||
${treecompose_args} \ | ||
${TREECOMPOSE_FLAGS:-} ${manifest} "$@" | ||
set +x | ||
|
||
set - rpm-ostree compose tree --repo=${workdir}/repo \ | ||
--cachedir=${workdir}/cache --touch-if-changed "${changed_stamp}" \ | ||
${manifest} "$@" | ||
|
||
if ! grep -q '^# disable-unified-core' "${manifest}"; then | ||
set - "$@" --unified-core | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. colin had told me that I could drop this check so I did in my fork. i.e. it is safe to assume anything using coreos-assembler will be using unified core in the future. |
||
fi | ||
|
||
echo "Running: $@" | ||
|
||
# this is the heart of the privs vs no privs dual path | ||
if has_privileges; then | ||
sudo "$@" | ||
else | ||
runvm "$@" | ||
fi | ||
} | ||
|
||
runvm() { | ||
local vmpreparedir=${workdir}/tmp/supermin.prepare | ||
local vmbuilddir=${workdir}/tmp/supermin.build | ||
|
||
# use REBUILDVM=1 if e.g. hacking on rpm-ostree/ostree and wanting to get | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the problem with not building the vm every time is that it can get out of date (i.e. new deps needed, etc). This is probably fine for your local dev case, but not ideal for having to go do something in your CI. I converted my master branch to just rebuild it every time. I found it didn't really add that much extra time to the compose. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. then again, if we are doing it for fetch and build then it starts to get a bit more heavyweight There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's the thing. We're calling this now both on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we could make fetch unprivileged without too much effort BTW. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
right, but if we are in "unpriv mode" we still need to run it in the VM so it can access the cache I think. |
||
# the new bits in the VM | ||
if [ ! -f ${vmbuilddir}/.done ] || [ -n "${REBUILDVM:-}" ]; then | ||
rm -rf ${vmpreparedir} ${vmbuilddir} | ||
mkdir -p ${vmpreparedir} ${vmbuilddir} | ||
|
||
local rpms= | ||
# then add all the base deps | ||
for dep in $(grep -v '^#' ${DIR}/vmdeps.txt); do | ||
rpms+="$dep " | ||
done | ||
|
||
supermin --prepare --use-installed $rpms -o "${vmpreparedir}" | ||
|
||
# the reason we do a heredoc here is so that the var substition takes | ||
# place immediately instead of having to proxy them through to the VM | ||
cat > "${vmpreparedir}/init" <<EOF | ||
#!/bin/bash | ||
set -xeuo pipefail | ||
workdir=${workdir} | ||
$(cat ${DIR}/supermin-init-prelude.sh) | ||
rc=0 | ||
sh ${TMPDIR}/cmd.sh || rc=\$? | ||
echo \$rc > ${workdir}/tmp/rc | ||
/sbin/fstrim -v ${workdir}/cache | ||
/sbin/reboot -f | ||
EOF | ||
chmod a+x ${vmpreparedir}/init | ||
(cd ${vmpreparedir} && tar -czf init.tar.gz --remove-files init) | ||
supermin --build "${vmpreparedir}" --size 5G -f ext2 -o "${vmbuilddir}" | ||
touch "${vmbuilddir}/.done" | ||
fi | ||
|
||
echo "$@" > ${TMPDIR}/cmd.sh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in this case this works because I've actually seen issues running in openshift where having $TMPDIR be on the nfs mounted volume caused real issues for me so I changed it to not be exported: dustymabe@7ecba34 |
||
|
||
# support local dev cases where src/config is a symlink | ||
srcvirtfs= | ||
if [ -L "${workdir}/src/config" ]; then | ||
# qemu follows symlinks | ||
srcvirtfs="-virtfs local,id=source,path=${workdir}/src/config,security_model=none,mount_tag=source" | ||
fi | ||
|
||
qemu-kvm -nodefaults -nographic -m 2048 -no-reboot \ | ||
-kernel "${vmbuilddir}/kernel" \ | ||
-initrd "${vmbuilddir}/initrd" \ | ||
-netdev user,id=eth0,hostname=supermin \ | ||
-device virtio-net-pci,netdev=eth0 \ | ||
-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3 \ | ||
-drive if=none,id=drive-scsi0-0-0-0,snapshot=on,file="${vmbuilddir}/root" \ | ||
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=1 \ | ||
-drive if=none,id=drive-scsi0-0-0-1,discard=unmap,file="${workdir}/cache/cache.qcow2" \ | ||
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=1,drive=drive-scsi0-0-0-1,id=scsi0-0-0-1 \ | ||
-virtfs local,id=workdir,path="${workdir}",security_model=none,mount_tag=workdir \ | ||
${srcvirtfs} -serial stdio -append "root=/dev/sda console=ttyS0 selinux=1 enforcing=0 autorelabel=1" | ||
|
||
if [ ! -f ${workdir}/tmp/rc ]; then | ||
fatal "Couldn't find rc file, something went terribly wrong!" | ||
fi | ||
return $(cat ${workdir}/tmp/rc) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# For privileged ops | ||
supermin | ||
|
||
# We default to builder user, but sudo where necessary | ||
sudo | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
mount -t proc /proc /proc | ||
mount -t sysfs /sys /sys | ||
mount -t devtmpfs devtmpfs /dev | ||
|
||
# load selinux policy | ||
LANG=C /sbin/load_policy -i | ||
|
||
# load kernel module for 9pnet_virtio for 9pfs mount | ||
/sbin/modprobe 9pnet_virtio | ||
|
||
# need fuse module for rofiles-fuse/bwrap during post scripts run | ||
/sbin/modprobe fuse | ||
|
||
# set up networking | ||
/usr/sbin/dhclient eth0 | ||
jlebon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# set up workdir | ||
mkdir -p ${workdir} | ||
mount -t 9p -o rw,trans=virtio,version=9p2000.L workdir ${workdir} | ||
if [ -L ${workdir}/src/config ]; then | ||
mkdir -p $(readlink ${workdir}/src/config) | ||
mount -t 9p -o rw,trans=virtio,version=9p2000.L source ${workdir}/src/config | ||
fi | ||
mkdir -p ${workdir}/cache | ||
mount /dev/sdb1 ${workdir}/cache | ||
|
||
cd ${workdir} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Base deps for a viable VM environment. | ||
|
||
# bare essentials | ||
bash vim-minimal coreutils util-linux procps-ng kmod kernel-modules | ||
|
||
# for composes | ||
rpm-ostree distribution-gpg-keys jq | ||
|
||
# for clean reboot | ||
systemd | ||
|
||
# networking | ||
dhcp-client bind-export-libs iproute | ||
|
||
# SELinux | ||
selinux-policy selinux-policy-targeted policycoreutils |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
./src/vmdeps.txt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dustymabe I slightly modified your patch here to put it in
/var/tmp
instead of/tmp
since the former is less likely to be on tmpfs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good