Merge pull request #1930 from weaveworks/issues/1746-always-use-host-netns

Always use host netns
This commit is contained in:
Adam Harrison committed 2016-02-04 12:50:08 +00:00
commit 415e550f86
14 files changed
+105 -154

No files matched your search

+21 -15
View File
@@ -13,24 +13,16 @@ import (
)
const (
WeaveHTTPHost = "127.0.0.1"
WeaveHTTPPort = 6784
)
type Client struct {
baseURL string
resolve func() (string, error)
}
func (client *Client) httpVerb(verb string, url string, values url.Values) (string, error) {
baseURL := client.baseURL
if client.resolve != nil {
addr, err := client.resolve()
if err != nil {
return "", err
}
baseURL = fmt.Sprintf("http://%s:%d", addr, WeaveHTTPPort)
}
url = baseURL + url
url = client.baseURL + url
Log.Debugf("weave %s to %s with %v", verb, url, values)
var body io.Reader
if values != nil {
@@ -59,11 +51,25 @@ func (client *Client) httpVerb(verb string, url string, values url.Values) (stri
}
func NewClient(addr string) *Client {
return &Client{baseURL: fmt.Sprintf("http://%s:%d", addr, WeaveHTTPPort)}
}
func NewClientWithResolver(resolver func() (string, error)) *Client {
return &Client{resolve: resolver}
host := WeaveHTTPHost
port := fmt.Sprintf("%d", WeaveHTTPPort)
switch parts := strings.Split(addr, ":"); len(parts) {
case 0:
case 1:
if parts[0] != "" {
host = parts[0]
}
case 2:
if parts[0] != "" {
host = parts[0]
}
if parts[1] != "" {
port = parts[1]
}
default:
return &Client{baseURL: fmt.Sprintf("http://%s", addr)}
}
return &Client{baseURL: fmt.Sprintf("http://%s:%s", host, port)}
}
func (client *Client) Connect(remote string) error {
+25 -14
View File
@@ -14,7 +14,8 @@ set -e
START=${FIRST_WEAVE:-1}
COUNT=${NUM_WEAVES:-28}
FINISH=$((START+COUNT-1))
PORT=6783
SUBNET=192.168.7
weavedir=$(dirname $0)/..
@@ -26,32 +27,42 @@ random_mac() {
od -txC -An -N6 /dev/urandom | ( read a b c d e f && printf "%02x:$b:$c:$d:$e:$f" $((0x$a & ~1 | 2)) )
}
weave() {
i=$1
shift
WEAVE_CONTAINER_NAME=weave$i WEAVE_HTTP_ADDR=$SUBNET.$i:6784 $weavedir/weave "$@"
}
case "$1" in
launch)
shift 1
echo $(date -R) launching
ip link show multiweave >/dev/null 2>&1 || sudo ip link add name multiweave type bridge
for i in $(seq $START $FINISH); do
WEAVE_CONTAINER_NAME=weave$i WEAVE_PORT=$((5000+i)) $weavedir/weave launch-router --iface '' --name $(random_mac) --nickname weave$i --port $PORT --no-dns "$@"
IP=$SUBNET.$i
sudo ip addr add $IP/24 dev multiweave
weave $i launch-router --datapath '' --iface '' --no-dns --host $IP \
--name $(random_mac) --nickname weave$i "$@"
done
if [ $START -ne 1 ] ; then
status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' weave$((START-1)))
PREV="${status#true }"
fi
echo $(date -R) connecting
[ $START -gt 1 ] || START=2
for i in $(seq $START $FINISH); do
if [ -n "$PREV" ] ; then
echo connecting weave$i to $PREV
WEAVE_CONTAINER_NAME=weave$i $weavedir/weave connect $PREV
fi
status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' weave$i)
PREV="${status#true }"
TO=$SUBNET.$((i-1))
echo connecting weave$i to $TO
weave $i connect $TO
done
echo $(date -R) done
;;
stop)
for i in $(seq $START $FINISH); do
for i in $(seq $FINISH -1 $START); do
IP=$SUBNET.$i
echo Stopping weave$i
WEAVE_CONTAINER_NAME=weave$i $weavedir/weave stop-router
weave $i stop-router
sudo ip addr del $IP/24 dev multiweave || true
done
[ -z "$(ip -4 -o addr show multiweave)" ] && sudo ip link del multiweave
;;
*)
weave "$@"
;;
esac
+3 -13
View File
@@ -7,10 +7,8 @@ import (
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/netlabel"
godocker "github.com/fsouza/go-dockerclient"
"github.com/weaveworks/weave/api"
. "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/common/docker"
)
const (
@@ -18,19 +16,11 @@ const (
)
type ipam struct {
client *docker.Client
weave *api.Client
weave *api.Client
}
func NewIpam(client *docker.Client, version string) (ipamapi.Ipam, error) {
resolver := func() (string, error) {
addr, err := client.GetContainerIP(WeaveContainer)
if _, ok := err.(*godocker.NoSuchContainer); ok {
return "", fmt.Errorf("%s container is not present. Have you launched it?", WeaveContainer)
}
return addr, err
}
return &ipam{client: client, weave: api.NewClientWithResolver(resolver)}, nil
func NewIpam(weave *api.Client) ipamapi.Ipam {
return &ipam{weave: weave}
}
func (i *ipam) GetDefaultAddressSpaces() (string, string, error) {
+3 -4
View File
@@ -7,6 +7,7 @@ import (
"github.com/docker/libnetwork/drivers/remote/api"
"github.com/docker/libnetwork/types"
weaveapi "github.com/weaveworks/weave/api"
. "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/common/docker"
"github.com/weaveworks/weave/common/odp"
@@ -21,22 +22,20 @@ const (
)
type driver struct {
version string
scope string
noMulticastRoute bool
sync.RWMutex
endpoints map[string]struct{}
}
func New(client *docker.Client, version string, scope string, noMulticastRoute bool) (skel.Driver, error) {
func New(client *docker.Client, weave *weaveapi.Client, scope string, noMulticastRoute bool) (skel.Driver, error) {
driver := &driver{
noMulticastRoute: noMulticastRoute,
version: version,
scope: scope,
endpoints: make(map[string]struct{}),
}
_, err := NewWatcher(client, driver)
_, err := NewWatcher(client, weave, driver)
if err != nil {
return nil, err
}
+3 -10
View File
@@ -21,16 +21,9 @@ type watcher struct {
type Watcher interface {
}
func NewWatcher(client *docker.Client, driver *driver) (Watcher, error) {
resolver := func() (string, error) { return client.GetContainerIP(WeaveContainer) }
w := &watcher{client: client, driver: driver,
weave: weaveapi.NewClientWithResolver(resolver)}
err := client.AddObserver(w)
if err != nil {
return nil, err
}
return w, nil
func NewWatcher(client *docker.Client, weave *weaveapi.Client, driver *driver) (Watcher, error) {
w := &watcher{client: client, weave: weave, driver: driver}
return w, client.AddObserver(w)
}
func (w *watcher) ContainerStarted(id string) {
+10 -9
View File
@@ -9,6 +9,7 @@ import (
"syscall"
"github.com/docker/libnetwork/ipamapi"
weaveapi "github.com/weaveworks/weave/api"
. "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/common/docker"
ipamplugin "github.com/weaveworks/weave/plugin/ipam"
@@ -48,19 +49,21 @@ func main() {
Log.Fatalf("unable to connect to docker: %s", err)
}
weave := weaveapi.NewClient(os.Getenv("WEAVE_HTTP_ADDR"))
Log.Println("Weave plugin", version, "Command line options:", os.Args[1:])
Log.Info(dockerClient.Info())
err = run(dockerClient, address, meshAddress, noMulticastRoute)
err = run(dockerClient, weave, address, meshAddress, noMulticastRoute)
if err != nil {
Log.Fatal(err)
}
}
func run(dockerClient *docker.Client, address, meshAddress string, noMulticastRoute bool) error {
func run(dockerClient *docker.Client, weave *weaveapi.Client, address, meshAddress string, noMulticastRoute bool) error {
endChan := make(chan error, 1)
if address != "" {
globalListener, err := listenAndServe(dockerClient, address, noMulticastRoute, endChan, "global", false)
globalListener, err := listenAndServe(dockerClient, weave, address, noMulticastRoute, endChan, "global", false)
if err != nil {
return err
}
@@ -68,7 +71,7 @@ func run(dockerClient *docker.Client, address, meshAddress string, noMulticastRo
defer globalListener.Close()
}
if meshAddress != "" {
meshListener, err := listenAndServe(dockerClient, meshAddress, noMulticastRoute, endChan, "local", true)
meshListener, err := listenAndServe(dockerClient, weave, meshAddress, noMulticastRoute, endChan, "local", true)
if err != nil {
return err
}
@@ -88,17 +91,15 @@ func run(dockerClient *docker.Client, address, meshAddress string, noMulticastRo
}
}
func listenAndServe(dockerClient *docker.Client, address string, noMulticastRoute bool, endChan chan<- error, scope string, withIpam bool) (net.Listener, error) {
d, err := netplugin.New(dockerClient, version, scope, noMulticastRoute)
func listenAndServe(dockerClient *docker.Client, weave *weaveapi.Client, address string, noMulticastRoute bool, endChan chan<- error, scope string, withIpam bool) (net.Listener, error) {
d, err := netplugin.New(dockerClient, weave, scope, noMulticastRoute)
if err != nil {
return nil, err
}
var i ipamapi.Ipam
if withIpam {
if i, err = ipamplugin.NewIpam(dockerClient, version); err != nil {
return nil, err
}
i = ipamplugin.NewIpam(weave)
}
var listener net.Listener
+4 -3
View File
@@ -76,6 +76,7 @@ func main() {
}
mflag.BoolVar(&justVersion, []string{"#version", "-version"}, false, "print version and exit")
mflag.StringVar(&config.Host, []string{"-host"}, "", "router host")
mflag.IntVar(&config.Port, []string{"#port", "-port"}, mesh.Port, "router port")
mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, mesh.ProtocolMinVersion, "minimum weave protocol version")
mflag.StringVar(&ifaceName, []string{"#iface", "-iface"}, "", "name of interface to capture/inject from (disabled if blank)")
@@ -143,7 +144,7 @@ func main() {
networkConfig.PacketLogging = nopPacketLogging{}
}
overlay, bridge := createOverlay(datapathName, ifaceName, config.Port, bufSzMB)
overlay, bridge := createOverlay(datapathName, ifaceName, config.Host, config.Port, bufSzMB)
networkConfig.Bridge = bridge
name := peerName(routerName, bridge.Interface())
@@ -272,7 +273,7 @@ func (nopPacketLogging) LogPacket(string, weave.PacketKey) {
func (nopPacketLogging) LogForwardPacket(string, weave.ForwardPacketKey) {
}
func createOverlay(datapathName string, ifaceName string, port int, bufSzMB int) (weave.NetworkOverlay, weave.Bridge) {
func createOverlay(datapathName string, ifaceName string, host string, port int, bufSzMB int) (weave.NetworkOverlay, weave.Bridge) {
overlay := weave.NewOverlaySwitch()
var bridge weave.Bridge
switch {
@@ -291,7 +292,7 @@ func createOverlay(datapathName string, ifaceName string, port int, bufSzMB int)
default:
bridge = weave.NullBridge{}
}
sleeve := weave.NewSleeveOverlay(port)
sleeve := weave.NewSleeveOverlay(host, port)
overlay.Add("sleeve", sleeve)
overlay.SetCompatOverlay(sleeve)
return overlay, bridge
+3
View File
@@ -48,6 +48,9 @@ func callWeave(args ...string) ([]byte, []byte, error) {
// integration test suite breaking things.
propagateEnv("COVERAGE")
// In case the router control endpoint address is non-standard.
propagateEnv("WEAVE_HTTP_ADDR")
Log.Debug("Calling weave args: ", args, "env: ", cmd.Env)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
+1 -11
View File
@@ -559,17 +559,7 @@ func (proxy *Proxy) getDNSDomain() string {
if proxy.WithoutDNS {
return ""
}
weaveContainer, err := proxy.client.InspectContainer("weave")
var weaveIP string
if err == nil && weaveContainer.NetworkSettings != nil {
weaveIP = weaveContainer.NetworkSettings.IPAddress
}
if weaveIP == "" {
weaveIP = "127.0.0.1"
}
weave := weaveapi.NewClient(weaveIP)
weave := weaveapi.NewClient(os.Getenv("WEAVE_HTTP_ADDR"))
domain, _ := weave.DNSDomain()
return domain
}
+4 -3
View File
@@ -62,6 +62,7 @@ const (
)
type SleeveOverlay struct {
host string
localPort int
// These fields are set in StartConsumingPackets, and not
@@ -76,12 +77,12 @@ type SleeveOverlay struct {
forwarders map[mesh.PeerName]*sleeveForwarder
}
func NewSleeveOverlay(localPort int) NetworkOverlay {
return &SleeveOverlay{localPort: localPort}
func NewSleeveOverlay(host string, localPort int) NetworkOverlay {
return &SleeveOverlay{host: host, localPort: localPort}
}
func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *mesh.Peer, peers *mesh.Peers, consumer OverlayConsumer) error {
localAddr, err := net.ResolveUDPAddr("udp4", fmt.Sprint(":", sleeve.localPort))
localAddr, err := net.ResolveUDPAddr("udp4", fmt.Sprint(sleeve.host, ":", sleeve.localPort))
if err != nil {
return err
}
+2 -2
View File
@@ -7,8 +7,8 @@ C2=10.2.1.47
start_suite "WEAVE_NO_FASTDP operation"
WEAVE_NO_FASTDP=1 WEAVE_DOCKER_ARGS=$ADD_HOST_ARGS weave_on $HOST1 launch
WEAVE_NO_FASTDP=1 WEAVE_DOCKER_ARGS=$ADD_HOST_ARGS weave_on $HOST2 launch $HOST1
WEAVE_NO_FASTDP=1 weave_on $HOST1 launch
WEAVE_NO_FASTDP=1 weave_on $HOST2 launch $HOST1
start_container $HOST1 $C1/24 --name=c1
start_container $HOST2 $C2/24 --name=c2
-3
View File
@@ -135,17 +135,14 @@ function make_template {
function hosts {
hosts=
args=
json=$(mktemp json.XXXXXXXXXX)
gcloud compute instances list --format=json >$json
for name in $(vm_names); do
hostname="$name.$ZONE.$PROJECT"
hosts="$hostname $hosts"
args="--add-host=$hostname:$(internal_ip $json $name) $args"
done
echo export SSH=\"ssh -l vagrant\"
echo export HOSTS=\"$hosts\"
echo export ADD_HOST_ARGS=\"$args\"
rm $json
}
+25 -66
View File
@@ -121,6 +121,7 @@ exec_remote() {
-e WEAVEPROXY_DOCKER_ARGS \
-e WEAVE_PASSWORD \
-e WEAVE_PORT \
-e WEAVE_HTTP_ADDR \
-e WEAVE_CONTAINER_NAME \
-e WEAVE_MTU \
-e WEAVE_NO_FASTDP \
@@ -349,9 +350,10 @@ BRIDGE=weave
DATAPATH=datapath
BRIDGE_IFNAME=vethwe-bridge
DATAPATH_IFNAME=vethwe-datapath
PCAP_IFNAME=vethwe-pcap
CONTAINER_IFNAME=ethwe
PORT=${WEAVE_PORT:-6783}
HTTP_PORT=6784
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
PROXY_PORT=12375
PROXY_CONTAINER_NAME=weaveproxy
COVERAGE_ARGS=""
@@ -675,9 +677,10 @@ destroy_bridge() {
fi
done
# Remove any lingering bridged fastdp veth
# Remove any lingering bridged fastdp and pcap veths
ip link del $DATAPATH_IFNAME >/dev/null 2>&1 || true
ip link del $BRIDGE_IFNAME >/dev/null 2>&1 || true
ip link del $PCAP_IFNAME >/dev/null 2>&1 || true
if [ "$DOCKER_BRIDGE" != "$BRIDGE" ] ; then
run_iptables -t filter -D FORWARD -i $DOCKER_BRIDGE -o $BRIDGE -j DROP 2>/dev/null || true
@@ -774,15 +777,7 @@ connect_container_to_bridge() {
return 1
fi
# Versions of the 'ip' command differ in whether they create a
# veth pair in the 'up' or 'down' state. Furthermore, moving one
# end into a netns normally sets them to 'down'. But, moving an
# end into the default netns is a null operation, so they stay up,
# which leads to errors in 'set name' since that requires the
# interface to be down. So to get a consistent result, we set the
# interface 'down' to begin with.
if ! netnsenter ip link set $GUEST_IFNAME down ||
! netnsenter ip link set $GUEST_IFNAME name $1 ||
if ! netnsenter ip link set $GUEST_IFNAME name $1 ||
! ip link set $LOCAL_IFNAME up ||
! add_iface_$BRIDGE_TYPE $LOCAL_IFNAME ||
! configure_arp_cache $1 "netnsenter" ; then
@@ -807,7 +802,7 @@ router_opts_fastdp() {
}
router_opts_bridge() {
echo "--iface $CONTAINER_IFNAME"
echo "--iface $PCAP_IFNAME"
}
router_opts_bridged_fastdp() {
@@ -832,16 +827,15 @@ setup_router_iface_fastdp() {
}
setup_router_iface_bridge() {
if ! netnsenter ip link show eth0 >/dev/null ; then
echo "Perhaps you are running the docker daemon with container networking disabled (-b=none)." >&2
ip link show $PCAP_IFNAME >/dev/null 2>&1 && return 0
if ! ip link add name $BRIDGE_IFNAME mtu $MTU type veth peer name $PCAP_IFNAME mtu $MTU ||
! ip link set $BRIDGE_IFNAME up ||
! add_iface_bridge $BRIDGE_IFNAME ||
! ip link set $PCAP_IFNAME up ; then
ip link del $PCAP_IFNAME >/dev/null 2>&1 || true
ip link del $BRIDGE_IFNAME >/dev/null 2>&1 || true
return 1
fi
# No-op if already attached
netnsenter ip link show $CONTAINER_IFNAME >/dev/null 2>&1 && return 0
connect_container_to_bridge $CONTAINER_IFNAME &&
netnsenter ethtool -K eth0 tx off >/dev/null &&
netnsenter ip link set $CONTAINER_IFNAME up
}
setup_router_iface_bridged_fastdp() {
@@ -972,26 +966,6 @@ container_id() {
esac
}
container_ip() {
if ! status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' $1 2>/dev/null) ; then
echo "$2" >&2
return 1
fi
case "$status" in
"true ")
#echo "$1 container has no IP address; is Docker networking enabled?" >&2
CONTAINER_IP=127.0.0.1
;;
true*)
CONTAINER_IP="${status#true }"
;;
*)
echo "$3" >&2
return 1
;;
esac
}
http_call() {
addr="$1"
http_verb="$2"
@@ -1014,11 +988,8 @@ http_call_unix() {
}
call_weave() {
container_ip $CONTAINER_NAME \
"$CONTAINER_NAME container is not present. Have you launched it?" \
"$CONTAINER_NAME container is not running." \
|| return 1
if ! http_call $CONTAINER_IP:$HTTP_PORT "$@" ; then
check_running $CONTAINER_NAME || return 1
if ! http_call $HTTP_ADDR "$@" ; then
echo "Call to $CONTAINER_NAME failed." >&2
return 1
fi
@@ -1305,8 +1276,7 @@ check_overlap() {
# with_container_addresses.
ipam_reclaim() {
for CIDR in $3 ; do
# NB: CONTAINER_IP is the IP of the weave container.
http_call $CONTAINER_IP:$HTTP_PORT PUT /ip/$1/${CIDR%/*}?noErrorOnUnknown=true
http_call $HTTP_ADDR PUT /ip/$1/${CIDR%/*}?noErrorOnUnknown=true
done
}
@@ -1362,9 +1332,7 @@ ipam_cidrs() {
if [ "$METHOD" = "POST" ] ; then
# Assignment of a plain IP address; warn if it clashes but carry on
check_overlap $arg || true
if container_ip $CONTAINER_NAME 2>/dev/null ; then
http_call $CONTAINER_IP:$HTTP_PORT PUT /ip/$CONTAINER_ID/${arg%/*} >&2
fi
when_weave_running http_call $HTTP_ADDR PUT /ip/$CONTAINER_ID/${arg%/*} >&2
fi
ALL_CIDRS="$ALL_CIDRS $arg"
fi
@@ -1565,10 +1533,6 @@ launch_router() {
IPRANGE=
IPRANGE_SPECIFIED=
# DNS_PORT_MAPPING is only used if the router runs in a container
# netns. DNS_ROUTER_OPTS is only used if the router runs in the
# host netns.
DNS_PORT_MAPPING="-p $DOCKER_BRIDGE_IP:53:53/udp -p $DOCKER_BRIDGE_IP:53:53/tcp"
DNS_ROUTER_OPTS="--dns-listen-address $DOCKER_BRIDGE_IP:53"
NO_DNS_OPT=
@@ -1603,7 +1567,6 @@ launch_router() {
IPRANGE_SPECIFIED=1
;;
--no-dns)
DNS_PORT_MAPPING=
DNS_ROUTER_OPTS=
NO_DNS_OPT="--no-dns"
ARGS="$ARGS $1"
@@ -1629,15 +1592,11 @@ launch_router() {
fi
fi
[ "$BRIDGE_TYPE" != bridge ] && NETHOST_OPT="--net=host" && HTTP_IP=127.0.0.1
# Set WEAVE_DOCKER_ARGS in the environment in order to supply
# additional parameters, such as resource limits, to docker
# when launching the weave container.
ROUTER_CONTAINER=$(docker run --privileged -d --name=$CONTAINER_NAME \
ROUTER_CONTAINER=$(docker run --privileged --net=host -d --name=$CONTAINER_NAME \
$(docker_sock_options) \
-p $PORT:$CONTAINER_PORT/tcp -p $PORT:$CONTAINER_PORT/udp \
${NETHOST_OPT:-$DNS_PORT_MAPPING} \
-e WEAVE_PASSWORD \
-e WEAVE_CIDR=none \
$WEAVE_DOCKER_ARGS $IMAGE $COVERAGE_ARGS \
@@ -1645,10 +1604,10 @@ launch_router() {
$(router_opts_$BRIDGE_TYPE) \
--ipalloc-range "$IPRANGE" \
--dns-effective-listen-address $DOCKER_BRIDGE_IP \
${NETHOST_OPT:+$DNS_ROUTER_OPTS} $NO_DNS_OPT \
--http-addr $HTTP_IP:$HTTP_PORT \
$DNS_ROUTER_OPTS $NO_DNS_OPT \
--http-addr $HTTP_ADDR \
"$@")
with_container_netns_or_die $CONTAINER_NAME setup_router_iface_$BRIDGE_TYPE
setup_router_iface_$BRIDGE_TYPE
attach_router
}
@@ -1660,9 +1619,7 @@ fetch_router_args() {
}
attach_router() {
err_msg=$(death_msg $CONTAINER_NAME)
container_ip $CONTAINER_NAME "$err_msg" "$err_msg" || return 1
wait_for_status $CONTAINER_NAME http_call $CONTAINER_IP:$HTTP_PORT
wait_for_status $CONTAINER_NAME http_call $HTTP_ADDR
if [ -n "$IPRANGE" ] ; then
# Tell the newly-started weave IP allocator about existing weave IPs
with_container_addresses ipam_reclaim weave:expose $(docker ps -q --no-trunc)
@@ -1704,6 +1661,7 @@ launch_proxy() {
-e DOCKER_BRIDGE \
-e WEAVE_DEBUG \
-e COVERAGE \
-e WEAVE_HTTP_ADDR \
-e EXEC_IMAGE=$EXEC_IMAGE \
--entrypoint=/home/weave/weaveproxy \
$WEAVEPROXY_DOCKER_ARGS $EXEC_IMAGE $COVERAGE_ARGS $PROXY_ARGS)
@@ -1728,6 +1686,7 @@ launch_plugin_if_not_running() {
--net=host \
$(docker_sock_options) \
-v /run/docker/plugins:/run/docker/plugins \
-e WEAVE_HTTP_ADDR \
$PLUGIN_IMAGE "$@") ; then
return 1
fi