osops-tools-contrib/multi/superhaproxy

347 lines
7.9 KiB
Bash
Executable File

#!/bin/bash
#Document the bridge setup....
#ovs-vsctl set bridge shabr stp_enable=false
#FIXME not all of them work... hardcoding for now.
#mirror=$(curl -s http://nl.alpinelinux.org/alpine/MIRRORS.txt | shuf | head -n 1)
mirror="http://dl-6.alpinelinux.org/alpine/"
#FIXME write some logic to detect this.
version=2.6.5-r1
statedir=/var/lib/superhaproxy
wrapperurl='http://git.haproxy.org/?p=haproxy-1.6.git;a=blob_plain;f=src/haproxy-systemd-wrapper.c;hb=HEAD'
#FIXME make this configurable
bridge=shabr
function init_config {
name="$1"
ip=$(crudini --get "$statedir/containers/$name/container.ini" superhaproxy ip)
subnet=$(crudini --get "$statedir/containers/$name/container.ini" superhaproxy subnet)
gateway=$(crudini --get "$statedir/containers/$name/container.ini" superhaproxy gateway)
mtu=$(crudini --get "$statedir/containers/$name/container.ini" superhaproxy mtu)
}
function get_pid_file {
echo "$statedir/containers/$1/container.pid"
}
function get_pid {
echo "$(< "$statedir/containers/$1/container.pid")"
}
function get_dump_dir {
echo "$statedir/dumps/$1"
}
function get_container_dir {
echo "$statedir/containers/$1"
}
if [ "x$1" == "x" ]
then
echo "Usage:"
echo " init"
echo " list"
echo " create"
echo " show"
echo " start"
echo " stop"
echo " reload"
echo " pid"
echo " pstree"
echo " shell"
echo " hatop"
echo " dump local"
echo " restore local"
exit -1
fi
if [ "x$1" == "xinit" ]
then
mkdir -p $statedir
if [ ! -d $statedir/alpine-tools ]
then
mkdir -p $statedir/alpine-tools
pushd $statedir/alpine-tools
curl ${mirror}/latest-stable/main/x86_64/apk-tools-static-${version}.apk | tar -zxf -
popd
fi
if [ ! -d $statedir/rootimg ]
then
mkdir -p $statedir/rootimg
$statedir/alpine-tools/sbin/apk.static -X ${mirror}/latest-stable/main -U --allow-untrusted --root $statedir/rootimg --initdb add alpine-base haproxy
#FIXME this makes way too big a binary. Remove once alpine provides the wrapper
curl -s "$wrapperurl" -o $statedir/wrapper.c
gcc --static -o $statedir/rootimg/usr/sbin/haproxy-systemd-wrapper $statedir/wrapper.c
#FIXME criu doesn't support checkpinting the chroot yet.
sed -i '/chroot/d' $statedir/rootimg/etc/haproxy/haproxy.cfg
fi
mkdir -p $statedir/containers
mkdir -p $statedir/dumps
mkdir -p $statedir/action-scripts
exit 0
fi
if [ "x$1" == "xlist" ]
then
ls $statedir/containers/ | cat
exit 0
fi
if [ "x$1" == "xcreate" ]
then
shift
ip=""
name=""
subnet="255.255.255.0"
gateway=""
mtu=9000
while getopts ":i:m:n:s:g:" opt; do
case ${opt} in
i )
ip="$OPTARG"
;;
m )
mtu="$OPTARG"
;;
s )
subnet="$OPTARG"
;;
n )
name="$OPTARG"
;;
\? ) echo "Usage: superhaproxy create [-m mtu] [-s subnetmask] [-g gatewayip] -i ip_address -n name"
exit -1
;;
esac
done
if [ "x$name" == "x" ]
then
echo "You must specify a name with -n"
exit -1
fi
if [ "x$ip" == "x" ]
then
echo "You must specify an ip with -i"
exit -1
fi
cp -a $statedir/rootimg "$statedir/containers/$name"
touch "$statedir/containers/$name/container.ini"
crudini --set "$statedir/containers/$name/container.ini" superhaproxy ip "$ip"
crudini --set "$statedir/containers/$name/container.ini" superhaproxy mtu "$mtu"
crudini --set "$statedir/containers/$name/container.ini" superhaproxy subnet "$subnet"
crudini --set "$statedir/containers/$name/container.ini" superhaproxy gateway "$gateway"
exit 0
fi
if [ "x$1" == "xshow" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
init_config "$name"
echo "IP: $ip"
echo "Subnet Mask: $subnet"
if [ "x$gateay" != "x" ]
then
echo "Gateway: $gateway"
fi
echo "MTU: $mtu"
exit 0
fi
if [ "x$1" == "xstart" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
init_config "$name"
container="$(get_container_dir "$name")"
#FIXME ensure escaping is correct.
unshare --net --mount --pid --fork -- bash -c "/usr/bin/setsid -- /bin/bash -c 'mount --make-rprivate /; mount --bind $container /tmp; cd /tmp; mkdir -p old; pivot_root . old; mount --bind /old/dev /dev; mount /proc /proc -t proc; umount -l old; exec /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid </dev/null >/dev/null 2>&1'" &
sleep 1
awk '{print $1}' /proc/$!/task/$!/children > "$container/container.pid"
P="$(get_pid "$name")"
ovs-vsctl del-port $bridge "sha$(get_pid "$name")" > /dev/null 2>&1
ip link add sha$P type veth peer name shai$P
ip link set dev sha$P mtu "$mtu" up
ip link set shai$P netns $P name eth0
nsenter -t $P -n ip addr add "$ip/$subnet" dev eth0
nsenter -t $P -n ip link set dev eth0 mtu "$mtu" up
ovs-vsctl add-port $bridge sha$P
exit $?
fi
if [ "x$1" == "xpid" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
get_pid $name
exit 0
fi
if [ "x$1" == "xpstree" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
pstree -p $(get_pid "$name")
exit 0
fi
if [ "x$1" == "xstop" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
kill $(get_pid "$name")
ovs-vsctl del-port $bridge "sha$(get_pid "$name")"
exit 0
fi
if [ "x$1" == "xshell" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
nsenter -n -m -p -t $(get_pid "$name") /bin/busybox sh
exit 0
fi
if [ "x$1" == "xhatop" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
hatop -s "$(get_container_dir "$name")/var/lib/haproxy/stats"
exit 0
fi
if [ "x$1" == "xreload" ]
then
name="$2"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
kill -USR2 $(get_pid "$name")
exit 0
fi
if [ "x$1" == "xdump" ]
then
subcmd="$2"
if [ "x$subcmd" != "xlocal" ]
then
echo "only local is supported at the moment"
exit -1
fi
name="$3"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
if [ "x$subcmd" == "xlocal" ]
then
dumpdir=$(get_dump_dir "$name")
rm -rf "$dumpdir"
mkdir -p "$dumpdir"
criu dump -D "$dumpdir" -t "$(get_pid "$name")" --tcp-established --shell-job --ext-mount-map /dev:dev
exit $?
fi
exit 0
fi
if [ "x$1" == "xrestore" ]
then
subcmd="$2"
if [ "x$subcmd" != "xlocal" ]
then
echo "only local is supported at the moment"
exit -1
fi
name="$3"
if [ "x$name" == "x" ]
then
echo "You must specify a name"
exit -1
fi
if [ "x$subcmd" == "xlocal" ]
then
tmpid=$$
pidfile=$(get_pid_file "$name")
as="$statedir/action-scripts/$name.sh"
cat > "$as" <<EOF
#!/bin/bash
if [ "x\${CRTOOLS_SCRIPT_ACTION}" == "xpost-restore" ]
then
P=\$(cat "$pidfile")
ip link set dev sha$tmpid name "sha\$P"
ip link set dev "sha\$P" mtu 9000 up
ovs-vsctl add-port $bridge "sha\$P"
fi
EOF
chmod +x "$as"
dumpdir=$(get_dump_dir "$name")
container="$(get_container_dir "$name")"
if [ ! -d "$dumpdir" ]
then
echo "Dump does not exist"
exit -1
fi
rm -f "$(get_pid_file "$name")"
ovs-vsctl del-port $bridge "sha$(get_pid "$name")" > /dev/null 2>&1
mount --bind "$container" "$container"
criu restore -d -D "$dumpdir" --shell-job --tcp-established --ext-mount-map dev:/dev --root "$container" --veth-pair eth0="sha$tmpid" --action-script "$as" --pidfile "$(get_pid_file "$name")"
res=$?
umount "$container"
exit $res
fi
exit 0
fi
#migrate
#rsync -avz --delete -e ssh /var/lib/superhaproxy/containers/foo 192.168.0.20:/var/lib/superhaproxy/containers/
# procedure:
# * initial rsync of container
# * dump on local host
# * second rsync of container
# * rsync of images
# * restore on remote host
# * On success
# * rm container and dump on localhost
# * On failure
# * If autofailback
# * Restore container local
# * on restore failure
# * Try starting remote, if works, remove local container/images all done.
# * If failed to start remote, try and start local
# * If state all still local, remove remote data.
echo "Unknown command: $1"
exit -1