diff --git a/prog/weaveproxy/main.go b/prog/weaveproxy/main.go index 815b1ef5..36d1db9d 100644 --- a/prog/weaveproxy/main.go +++ b/prog/weaveproxy/main.go @@ -51,6 +51,8 @@ func main() { mflag.BoolVar(&justVersion, []string{"#version", "-version"}, false, "print version and exit") mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)") ListVar(&c.ListenAddrs, []string{"H"}, defaultListenAddrs, "addresses on which to listen") + mflag.StringVar(&c.HostnameMatch, []string{"-hostname-match"}, "(.*)", "Regexp pattern to apply on container names (e.g. '^aws-[0-9]+-(.*)$')") + mflag.StringVar(&c.HostnameReplacement, []string{"-hostname-replacement"}, "$1", "Expression to generate hostnames based on matches from --hostname-match (e.g. 'my-app-$1')") mflag.BoolVar(&c.NoDefaultIPAM, []string{"#-no-default-ipam", "-no-default-ipalloc"}, false, "do not automatically allocate addresses for containers without a WEAVE_CIDR") mflag.BoolVar(&c.NoRewriteHosts, []string{"no-rewrite-hosts"}, false, "do not automatically rewrite /etc/hosts. Use if you need the docker IP to remain in /etc/hosts") mflag.StringVar(&c.TLSConfig.CACert, []string{"#tlscacert", "-tlscacert"}, "", "Trust certs signed only by this CA") diff --git a/proxy/create_container_interceptor.go b/proxy/create_container_interceptor.go index 8e3cca04..75a67b89 100644 --- a/proxy/create_container_interceptor.go +++ b/proxy/create_container_interceptor.go @@ -58,7 +58,9 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error { if err := i.setWeaveWaitEntrypoint(container.Config); err != nil { return err } - if err := i.setWeaveDNS(&container, r.URL.Query().Get("name")); err != nil { + containerName := r.URL.Query().Get("name") + hostname := i.proxy.hostnameMatchRegexp.ReplaceAllString(containerName, i.proxy.HostnameReplacement) + if err := i.setWeaveDNS(&container, hostname); err != nil { return err } } diff --git a/proxy/proxy.go b/proxy/proxy.go index 0e1969f2..9b5dce04 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -15,11 +15,13 @@ import ( ) const ( - defaultCaFile = "ca.pem" - defaultKeyFile = "key.pem" - defaultCertFile = "cert.pem" - dockerSock = "/var/run/docker.sock" - dockerSockUnix = "unix://" + dockerSock + defaultCaFile = "ca.pem" + defaultKeyFile = "key.pem" + defaultCertFile = "cert.pem" + dockerSock = "/var/run/docker.sock" + dockerSockUnix = "unix://" + dockerSock + substitutionPatternName = "pattern" + substitutionReplacementName = "replacement" ) var ( @@ -29,19 +31,22 @@ var ( ) type Config struct { - ListenAddrs []string - NoDefaultIPAM bool - NoRewriteHosts bool - TLSConfig TLSConfig - Version string - WithDNS bool - WithoutDNS bool + HostnameMatch string + HostnameReplacement string + ListenAddrs []string + NoDefaultIPAM bool + NoRewriteHosts bool + TLSConfig TLSConfig + Version string + WithDNS bool + WithoutDNS bool } type Proxy struct { Config - client *docker.Client - dockerBridgeIP string + client *docker.Client + dockerBridgeIP string + hostnameMatchRegexp *regexp.Regexp } func NewProxy(c Config) (*Proxy, error) { @@ -65,6 +70,12 @@ func NewProxy(c Config) (*Proxy, error) { p.dockerBridgeIP = string(dockerBridgeIP) } + p.hostnameMatchRegexp, err = regexp.Compile(c.HostnameMatch) + if err != nil { + err := fmt.Errorf("Incorrect hostname match '%s': %s", c.HostnameMatch, err.Error()) + return nil, err + } + return p, nil } diff --git a/site/proxy.md b/site/proxy.md index 453c81de..ed031dc5 100644 --- a/site/proxy.md +++ b/site/proxy.md @@ -130,6 +130,35 @@ automatically if it is running at the point when they are started - see the [weaveDNS usage](weavedns.html#usage) section for an in-depth explanation of the behaviour and how to control it. +Typicaly, the proxy will pass on container names as-is to [weaveDNS](weavedns.html) +for registration. However, there are situations in which the final container +name is out of the user's control (e.g. when using Docker orchestrators which +append control/namespacing identifiers to the original container names). + +For those situations, the proxy provides two flags: `--hostname-match ` +and `--hostname-replacement `. When launching a container, its name +matched against regular expression ``. Then, based on that match, +`` will be used to generate a hostname, which will ultimately be +handed over to weaveDNS for registration. + +For instance, if we launch the proxy using +`--hostname-match '^aws-[0-9]+-(.*)$'` and `--hostname-replacement 'my-app-$1'` + + host1$ weave launch-router && weave launch-dns && weave launch-proxy --hostname-match '^aws-[0-9]+-(.*)$' and --hostname-replacement 'my-app-$1' + host1$ eval "$(weave env)" + +then, running a container named `aws-12798186823-foo` will lead to weaveDNS registering +hostname `my-app-foo` and not `aws-12798186823-foo`. + + host1$ docker run -ti --name=aws-12798186823-foo ubuntu ping my-app-foo + PING my-app-foo.weave.local (10.32.0.2) 56(84) bytes of data. + 64 bytes from my-app-foo.weave.local (10.32.0.2): icmp_seq=1 ttl=64 time=0.027 ms + 64 bytes from my-app-foo.weave.local (10.32.0.2): icmp_seq=2 ttl=64 time=0.067 ms + +Note how regexp substitution groups should be prepended with a dollar sign +(e.g. `$1`). For further details on the regular expression syntax please see +[Google's re2 documentation](https://github.com/google/re2/wiki/Syntax). + ## Securing the docker communication with TLS If you are diff --git a/test/680_proxy_hostname_derivation.sh b/test/680_proxy_hostname_derivation.sh new file mode 100755 index 00000000..e4940dae --- /dev/null +++ b/test/680_proxy_hostname_derivation.sh @@ -0,0 +1,32 @@ +#! /bin/bash + +. ./config.sh + +C1=10.2.0.78 +C2=10.2.0.34 +C3=10.2.0.57 +CNAME1=qiuds71y827hdi-seeone-1io9qd9i0wd +NAME1=seeone.weave.local +CNAME2=124DJKSNK812-seetwo-128hbaJ881 +NAME2=seetwo.weave.local +CNAME3=doesnotmatchpattern +NAME3=doesnotmatchpattern.weave.local + +start_container() { + proxy docker_on $HOST1 run "$@" -dt $DNS_IMAGE /bin/sh +} + +start_suite "Hostname derivation through container name substitutions" + +weave_on $HOST1 launch-dns 10.2.254.1/24 +weave_on $HOST1 launch-proxy --hostname-match '^[^-]+-(?P[^-]*)-[^-]+$' --hostname-replacement '$appname' + +start_container -e WEAVE_CIDR=$C1/24 --name=$CNAME1 +start_container -e WEAVE_CIDR=$C2/24 --name=$CNAME2 +start_container -e WEAVE_CIDR=$C3/24 --name=$CNAME3 + +assert_dns_a_record $HOST1 $CNAME1 $NAME2 $C2 +assert_dns_a_record $HOST1 $CNAME2 $NAME3 $C3 +assert_dns_a_record $HOST1 $CNAME3 $NAME1 $C1 + +end_suite diff --git a/weave b/weave index c7983f68..9588d26b 100755 --- a/weave +++ b/weave @@ -37,6 +37,7 @@ weave launch-router [--password ] [--nickname ] weave launch-dns [] weave launch-proxy [-H ] [--with-dns | --without-dns] [--no-default-ipalloc] [--no-rewrite-hosts] + [[--hostname-match ] [--hostname-replacement ]] weave connect [--replace] [ ...] weave forget ... weave run [--with-dns | --without-dns] [ ...]