Files
weave/weaver/weave
T

248 lines
7.6 KiB
Bash
Executable File

#!/bin/sh
set -e
usage() {
echo "Usage:"
echo "weave launch <ipaddr>/<subnet> [-passwd <passwd>] <peer_host> ..."
echo "weave run <ipaddr>/<subnet> <docker run args> ..."
echo "weave expose <ipaddr>/<subnet>"
echo "weave hide <ipaddr>/<subnet>"
echo "weave status"
echo "weave version"
echo "weave stop"
echo "weave reset"
exit 1
}
# utility function to check whether a command can be executed by the shell
# see http://stackoverflow.com/questions/592620/how-to-check-if-a-program-exists-from-a-bash-script
command_exists () {
command -v $1 >/dev/null 2>&1
}
[ `id -u` = 0 ] || {
echo "weave must be run as 'root'"
exit 1
}
[ $# -gt 0 ] || usage
BRIDGE=weave
CONTAINER_IFNAME=ethwe
MTU=65535
COMMAND=$1
shift 1
check_command_and_run() {
if command_exists $1
then
shift 1
"$@"
else
echo "Cannot find $1; please install it. Continuing without it." >&2
fi
}
create_bridge() {
[ ! -d /sys/class/net/$BRIDGE ] && {
ip link add dev $BRIDGE type bridge
ip link set dev $BRIDGE address 7a:$(od -txC -An -N5 /dev/random | tr \ : | tail -c+2)
# Attempting to set the bridge MTU to a high value directly
# fails. Bridges take the lowest MTU of their interfaces. So
# instead we create a temporary interface with the desired
# MTU, attach that to the bridge, and then remove it again.
ip link add name v${CONTAINER_IFNAME}du mtu $MTU type dummy
ip link set dev v${CONTAINER_IFNAME}du master $BRIDGE
ip link del dev v${CONTAINER_IFNAME}du
# disable offloading
check_command_and_run ethtool ethtool -K $BRIDGE tx off >/dev/null
}
ip link set dev $BRIDGE up
}
destroy_bridge() {
if [ -d /sys/class/net/$BRIDGE ] ; then
ip link del dev $BRIDGE
fi
}
run_iptables() {
# -w is recent addition to iptables
if [ -z "$CHECKED_IPTABLES_W" ] ; then
if iptables -S -w >/dev/null 2>&1 ; then
IPTABLES_W=-w
fi
CHECKED_IPTABLES_W=1
fi
iptables $IPTABLES_W "$@"
}
add_nat_rule() {
if ! run_iptables -t nat -C "$@" >/dev/null 2>&1
then
run_iptables -t nat -A "$@" >/dev/null
fi
}
setup_masquerading() {
run_iptables -t nat -N WEAVE >/dev/null 2>&1 || true
add_nat_rule POSTROUTING -j WEAVE
add_nat_rule WEAVE -o $BRIDGE ! -s $1 -j MASQUERADE
add_nat_rule WEAVE -s $1 ! -o $BRIDGE -j MASQUERADE
}
stop_masquerading() {
run_iptables -t nat -F WEAVE >/dev/null 2>&1 || true
run_iptables -t nat -D POSTROUTING -j WEAVE >/dev/null 2>&1 || true
run_iptables -t nat -X WEAVE >/dev/null 2>&1 || true
}
# the following borrows from https://github.com/jpetazzo/pipework
configure_container_networking() {
DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' $1)
[ "$DOCKERPID" = 0 ] && {
echo "Docker inspect returned invalid PID 0"
exit 1
}
[ "$DOCKERPID" = "<no value>" ] && {
echo "Container $1 unknown to Docker."
exit 1
}
NSPID=$DOCKERPID
[ ! -d /var/run/netns ] && mkdir -p /var/run/netns
[ -f /var/run/netns/$NSPID ] && rm -f /var/run/netns/$NSPID
ln -s /proc/$NSPID/ns/net /var/run/netns/$NSPID
LOCAL_IFNAME="v${CONTAINER_IFNAME}pl${NSPID}"
GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}"
ip link add name $LOCAL_IFNAME mtu $MTU type veth peer name $GUEST_IFNAME mtu $MTU
ip link set $LOCAL_IFNAME master $BRIDGE
ip link set $LOCAL_IFNAME up
ip link set $GUEST_IFNAME netns $NSPID
ip netns exec $NSPID ip link set $GUEST_IFNAME name $CONTAINER_IFNAME
ip netns exec $NSPID ip addr add $2 dev $CONTAINER_IFNAME
ip netns exec $NSPID ip link set $CONTAINER_IFNAME up
check_command_and_run ethtool ip netns exec $NSPID ethtool -K $3 tx off >/dev/null
[ -f /var/run/netns/$NSPID ] && rm -f /var/run/netns/$NSPID
}
case "$COMMAND" in
launch)
[ $# -gt 0 ] || usage
IPADDR=$1
shift 1
case $(docker inspect --format '{{ .State.Running }} {{ .Config.Image }}' weave 2>/dev/null) in
"true zettio/weave")
echo "Weave is already running." >&2
exit 1
;;
"false zettio/weave")
docker rm weave >/dev/null
;;
true*)
echo "Found another running container named 'weave'. Aborting." >&2
exit 1
;;
false*)
echo "Found another container named 'weave'. Aborting." >&2
exit 1
;;
esac
create_bridge
stop_masquerading
setup_masquerading $IPADDR
# We set the router name to the bridge mac since that is
# stable across re-creations of the containers.
#
# TODO use the mac of one of the physical host interfaces
# (eth0, wlan0, etc) so the name becomes stable across host
# restarts.
MACADDR=`cat /sys/class/net/$BRIDGE/address`
CONTAINER=$(docker run --privileged -d --name=weave -p 6783:6783/tcp -p 6783:6783/udp $WEAVE_DOCKER_ARGS zettio/weave -name $MACADDR "$@")
configure_container_networking $CONTAINER $IPADDR eth0
echo $CONTAINER
;;
status)
if ! DOCKERIP=$(docker inspect --format='{{ .NetworkSettings.IPAddress }}' weave 2>/dev/null) ; then
echo "Weave is not running." >&2
exit 1
fi
if [ -z "$DOCKERIP" ] ; then
echo "Weave is not running." >&2
exit 1
fi
if command_exists wget ; then
wget -O - -q $DOCKERIP:6784/status
elif command_exists curl ; then
curl $DOCKERIP:6784/status
else
echo "Cannot find wget or curl. Install one of them for 'weave status' to function." >&2
exit 1
fi
;;
version)
# Try the running container first; if no luck try the image
if ! DOCKERIMAGE=$(docker inspect --format='{{ .Image }}' weave 2>/dev/null) ; then
if ! DOCKERIMAGE=$(docker inspect --format='{{ .Id }}' zettio/weave 2>/dev/null) ; then
echo "Unable to find zettio/weave image." >&2
exit 1
fi
fi
docker images --no-trunc | grep $DOCKERIMAGE | grep -v latest | tr -s ' ' | cut -d ' ' -f 2
;;
run)
[ $# -gt 0 ] || usage
IPADDR=$1
shift 1
create_bridge
CONTAINER=$(docker run -d "$@")
configure_container_networking $CONTAINER $IPADDR $CONTAINER_IFNAME
echo $CONTAINER
;;
expose)
[ $# -gt 0 ] || usage
IPADDR=$1
shift 1
create_bridge
if ! ip addr list dev $BRIDGE | grep -qF $IPADDR
then
ip addr add dev $BRIDGE $IPADDR
fi
;;
hide)
[ $# -gt 0 ] || usage
IPADDR=$1
shift 1
create_bridge
if ip addr list dev $BRIDGE | grep -qF $IPADDR
then
ip addr del dev $BRIDGE $IPADDR
fi
;;
stop)
if ! docker kill weave >/dev/null 2>&1 ; then
echo "Weave is not running."
fi
docker rm -f weave >/dev/null 2>&1 || true
check_command_and_run conntrack conntrack -D -p udp --dport 6783 >/dev/null 2>&1 || true
stop_masquerading
;;
reset)
docker kill weave >/dev/null 2>&1 || true
docker rm -f weave >/dev/null 2>&1 || true
check_command_and_run conntrack conntrack -D -p udp --dport 6783 >/dev/null 2>&1 || true
stop_masquerading
destroy_bridge
;;
*)
echo "Unknown weave command '$COMMAND'"
usage
;;
esac