diff --git a/README.md b/README.md index d92e518..3d29196 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,41 @@ disco ===== -Dead Simple COnfiguration management and continuous integration for linux like systems \ No newline at end of file +Dead Simple COnfiguration management and continuous integration for linux like systems + +DISCO is just now beginning development. Expect what you find here to do irreparable damage +to any system you run it on. I ONLY run disco on a throwaway VM at current. + +Why disco? +===== + +Because puppet, chef, cfengine, etc, are all great tools, but they all fall +short of the mark, in terms of simplicity, ease of use, and reliability. +None of them really follow the UNIX philosophy of "do one thing, do it well, +and don't reinvent the wheel". + +No, really, why did you name it "disco"? +===== +I wanted an acronym based off of "Dead Simple Continuous Integration", and this was +the closest I found. + +Requirements +===== + +DISCO assumes that you: + + - have at least one server capable of running rsyncd, sshd and bash 4+ + - have one or more clients capable of running bash 4+, ssh, rsync, and fuse-unionfs + +While that's a very simple requirements list, it currently restricts it to recent Linux +systems. You may or may not be able to use this tool on FreeBSD or Mac OS X, I haven't +tried. Due to the way it executes, this tool will probably never, ever execute properly +on Windows. + +Why focus so much on linux? +===== + +Because if we try to do everything and the kitchen sink, for every OS out there, we run +the risk of falling short in the same ways the other CI tools have. By limiting our scope +and problem space to recent GNU/Linux systems, we can write a much simpler tool in a +much shorter amount of time that is much simpler to understand. \ No newline at end of file diff --git a/client/bin/disco-fs-diff b/client/bin/disco-fs-diff new file mode 100755 index 0000000..ce57d3a --- /dev/null +++ b/client/bin/disco-fs-diff @@ -0,0 +1,41 @@ +#!/bin/bash + +OLDPWD=$(pwd) + +DISCOROOT=/var/disco/testfs + +COLOR_CYAN=$(echo -e '\033[0;36;40m'); +COLOR_MAGENTA=$(echo -e '\033[0;35;40m'); +COLOR_GREEN=$(echo -e '\033[0;32;40m'); +COLOR_YELLOW=$(echo -e '\033[0;33;40m'); +COLOR_BLUE=$(echo -e '\033[0;34;40m'); +COLOR_RED=$(echo -e '\033[0;31;40m'); +COLOR_NORMAL=$(echo -e '\033[0m'); + +cd $DISCOROOT + +diff -r ./rootfs ./scratchfs |\ + grep -v "^Only in ./rootfs" |\ + sed s/"^Only in \.\/scratchfs\(.*\): \(.*\)"/"info: File: created \1\/\2 : (CONTENT)"/g |\ + sed s/"\/\/"/"\/"/g |\ + grep -v "File: created /.unionfs" |\ + sed s/"^Binary files .\/rootfs\(.*\) and .\/scratchfs.*"/"info: File: modified \1 : (OLDMD5SUM) => (NEWMD5SUM)"/g |\ + sed s/"^diff -r .\/rootfs\(.*\) .\/scratchfs\(.*\)"/"info: File: modified \1 :"/g > /tmp/$$.discofsdiff + +find ./scratchfs/.unionfs -iname "*_HIDDEN~" |\ + sed s/"^.\/scratchfs\/.unionfs\(.*\)_HIDDEN~"/"info: File: deleted \1"/g >> /tmp/$$.discofsdiff + +#Find the permissions/timestamp diffs from rsync +rsync -ani ./scratchfs/* ./rootfs/ | grep -v .unionfs + + +# Swap out the (CONTENT) and (MD5SUM) hashes for actual content and md5s +cat /tmp/$$.discofsdiff | python ${OLDPWD}/disco-fs-fixup.py > /tmp/$$.newfile +mv /tmp/$$.newfile n/tmp/$$.discofsdiff + + +cat /tmp/$$.discofsdiff |\ + sed s/"^info:\(.*\)"/"${COLOR_CYAN}info:\1${COLOR_NORMAL}"/g + #sed s/"^warning: \(.*\)"/"${COLOR_YELLOW}warning: \1${COLOR_NORMAL}"/g + +cd $OLDPWD \ No newline at end of file diff --git a/client/bin/disco-fs-mount b/client/bin/disco-fs-mount new file mode 100755 index 0000000..b6f9981 --- /dev/null +++ b/client/bin/disco-fs-mount @@ -0,0 +1,76 @@ +#!/bin/bash + +DISCOCFG=/etc/disco +DISCOROOT=/var/disco/testfs + +mount | grep $DISCOROOT >/dev/null 2>&1 + +if [ $? -eq 0 ]; then + echo "disco chroot is already mounted, please exec disco-fs-unmount and try again." + exit 1 +fi + +# Cleanup old junk +rm -rf ${DISCOROOT}/scratchfs +rm -rf ${DISCOROOT}/restricted/bin/* + +# Prepare all the mountpoint directories +mkdir -p ${DISCOROOT}/chroot +mkdir -p ${DISCOROOT}/execs/bin +mkdir -p ${DISCOROOT}/proc/proc +mkdir -p ${DISCOROOT}/sysfs/sys +mkdir -p ${DISCOROOT}/rootfs +mkdir -p ${DISCOROOT}/scratchfs +mkdir -p ${DISCOROOT}/dev/dev +mkdir -p ${DISCOROOT}/restricted/bin + +# Setup all the commands for the bash restricted execution environment + +mkdir -p ${DISCOCFG}/restricted.d +for file in $(cat ${DISCOCFG}/restricted.d/* 2>/dev/null | grep -v "^#") +do + mkdir -p ${DISCOROOT}/restricted/bin$(echo $file | dirname $file) + ln -s $file ${DISCOROOT}/restricted/bin/$file +done + +# Setup some more restricted execution stuff, but only if we actually have $NOOP + +if [ "$NOOP" != "" ]; then + # Here we play a pretty lame trick on the user. /bin/bash will always exist + # (unfortunately), but we can force everything else to our rbash wrapper, + # forcing restricted execution. The user can get around this by calling + # /bin/bash directly, but that's on the user. TNMP, RTFM! + ln -s /bin/bash ${DISCOROOT}/restricted/bin/rbash + for dir in /usr/bin /usr/local/bin /usr/sbin; + do + mkdir -p ${DISCOROOT}/restricted/${dir} + echo "#!/bin/bash --restricted\neval \$@" > ${DISCOROOT}/restricted/${dir}/bash + chmod +x ${DISCOROOT}/restricted/${dir}/bash + done +fi + +# We need SOME special files in /dev like /dev/null, so make them here + +mknod ${DISCOROOT}/dev/dev/null c 1 3 +chmod 666 ${DISCOROOT}/dev/dev/null + +# Mount all the (real filesystem) layers individually + +mount --bind -o ro / ${DISCOROOT}/rootfs 2>&1 | grep -v "seems to be mounted read-write" +mount -o remount,ro ${DISCOROOT}/rootfs +mount -t proc -o ro none ${DISCOROOT}/proc/proc +mount -t sysfs -o ro none ${DISCOROOT}/sysfs/sys + +# Setup filesystem layers. The read/write ones go on the top, with scratchfs ALWAYS on top. +FSLAYERS="${DISCOROOT}/scratchfs=rw" +FSLAYERS="${FSLAYERS}:${DISCOROOT}/dev=rw" +FSLAYERS="${FSLAYERS}:${DISCOROOT}/restricted=ro" +FSLAYERS="${FSLAYERS}:${DISCOROOT}/execs=ro" +FSLAYERS="${FSLAYERS}:${DISCOROOT}/proc=ro" +FSLAYERS="${FSLAYERS}:${DISCOROOT}/sysfs=ro" +FSLAYERS="${FSLAYERS}:${DISCOROOT}/rootfs=ro" + +# Here we go +unionfs -o cow,dev,dirs=$FSLAYERS ${DISCOROOT}/chroot + +exit 0 \ No newline at end of file diff --git a/client/bin/disco-fs-unmount b/client/bin/disco-fs-unmount new file mode 100755 index 0000000..81c3fc8 --- /dev/null +++ b/client/bin/disco-fs-unmount @@ -0,0 +1,24 @@ +#!/bin/bash + +DISCOROOT=/var/disco/testfs + +mount | grep $DISCOROOT > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "disco chroot is not mounted" + exit 1 +fi + +umount ${DISCOROOT}/chroot +umount ${DISCOROOT}/proc/proc +umount ${DISCOROOT}/sysfs/sys +umount ${DISCOROOT}/rootfs +mount | grep $DISCOROOT > /dev/null 2>&1 +if [ $? -eq 0 ]; then + # Sometimes required + umount ${DISCOROOT}/rootfs +fi + +rm -rf ${DISCOROOT}/scratchfs/* ${DISCOROOT}/scratchfs/.unionfs +rm -rf ${DISCOROOT}/dev/* + +exit 0 \ No newline at end of file diff --git a/client/bin/disco-sh-exec b/client/bin/disco-sh-exec new file mode 100755 index 0000000..f87aa5a --- /dev/null +++ b/client/bin/disco-sh-exec @@ -0,0 +1,19 @@ +#!/bin/bash + +DISCOROOT=/var/disco/testfs + +mount | grep $DISCOROOT >/dev/null 2>&1 +if [ $? -ne 0 ]; then + ./disco-fs-mount +fi + +# Strip out any shebang and put the script in the root +mkdir -p ${DISCOROOT}/execs/$(dirname $2) +cat $1 | sed s/'^#!.*'/''/g > ${DISCOROOT}/execs/$2 +if [ "$NOOP" != "" ]; then + chroot ${DISCOROOT}/chroot /bin/bash --restricted $2 +else + chroot ${DISCOROOT}/chroot /bin/bash $2 +fi +./disco-fs-unmount +exit $? diff --git a/client/bin/disco-sh-shell b/client/bin/disco-sh-shell new file mode 100755 index 0000000..963169d --- /dev/null +++ b/client/bin/disco-sh-shell @@ -0,0 +1,15 @@ +#!/bin/bash + +DISCOROOT=/var/disco/testfs + +mount | grep $DISCOROOT >/dev/null 2>&1 +if [ $? -ne 0 ]; then + ./disco-fs-mount +fi +if [ "$NOOP" != "" ]; then + chroot ${DISCOROOT}/chroot /bin/rbash +else + chroot ${DISCOROOT}/chroot /bin/bash +fi +./disco-fs-unmount +exit $?