347 lines
7.9 KiB
Bash
Executable File
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
|