diff --git a/270_use_name_as_hostname_test.sh b/270_use_name_as_hostname_test.sh new file mode 100755 index 00000000..317d893f --- /dev/null +++ b/270_use_name_as_hostname_test.sh @@ -0,0 +1,36 @@ +#! /bin/bash + +. ./config.sh + +NAME=c1 +DOMAIN=weave.local. +HOSTNAME=$NAME-hostname.$DOMAIN + +# Docker inspect hostname + domainname of container $2 on host $1 +docker_inspect_fqdn() { + docker_on $1 inspect --format='{{.Config.Hostname}}.{{.Config.Domainname}}' $2 +} + +# Start container with args $2.. and assert fqdn of $1 +assert_expected_fqdn() { + EXPECTED_FQDN=$1 + shift + start_container_with_dns $HOST1 "$@" + assert "docker_inspect_fqdn $HOST1 $NAME" $EXPECTED_FQDN + docker_on $HOST1 rm -f $NAME +} + +start_suite "Use container name as hostname" + +weave_on $HOST1 launch -iprange 10.2.0.0/24 + +assert_expected_fqdn "$NAME.$DOMAIN" --name=$NAME +assert_expected_fqdn "$NAME.$DOMAIN" --name $NAME +assert_expected_fqdn "$HOSTNAME" --name=$NAME -h $HOSTNAME +assert_expected_fqdn "$HOSTNAME" --name=$NAME --hostname=$HOSTNAME +assert_expected_fqdn "$HOSTNAME" --name=$NAME --hostname $HOSTNAME +assert_expected_fqdn "$HOSTNAME" -h $HOSTNAME --name=$NAME +assert_expected_fqdn "$HOSTNAME" --hostname=$HOSTNAME --name=$NAME +assert_expected_fqdn "$HOSTNAME" --hostname $HOSTNAME --name=$NAME + +end_suite diff --git a/nameserver/http.go b/nameserver/http.go index ce438bee..2854d5f8 100644 --- a/nameserver/http.go +++ b/nameserver/http.go @@ -34,6 +34,10 @@ func ServeHTTP(listener net.Listener, version string, server *DNSServer, domain fmt.Fprintln(w, db.Status()) }) + muxRouter.Methods("GET").Path("/domain").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, db.Domain()) + }) + muxRouter.Methods("PUT").Path("/name/{id:.+}/{ip:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { reqError := func(msg string, logmsg string, logargs ...interface{}) { httpErrorAndLog(Warning, w, msg, http.StatusBadRequest, logmsg, logargs...) diff --git a/nameserver/server.go b/nameserver/server.go index 598e8171..194a2eb4 100644 --- a/nameserver/server.go +++ b/nameserver/server.go @@ -15,6 +15,7 @@ import ( const ( DefaultServerPort = 53 // The default server port + DefaultHTTPPort = 6785 // The default http port DefaultCLICfgFile = "/etc/resolv.conf" // default "resolv.conf" file to try to load DefaultLocalTTL = 30 // default TTL for responses for local domain queries DefaultUDPBuflen = 4096 // bigger than the default 512 diff --git a/prog/weavedns/main.go b/prog/weavedns/main.go index 9b6ab270..8702719a 100644 --- a/prog/weavedns/main.go +++ b/prog/weavedns/main.go @@ -46,7 +46,7 @@ func main() { flag.StringVar(&domain, "domain", weavedns.DefaultLocalDomain, "local domain (ie, 'weave.local.')") flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up") flag.IntVar(&dnsPort, "dnsport", weavedns.DefaultServerPort, "port to listen to DNS requests") - flag.IntVar(&httpPort, "httpport", 6785, "port to listen to HTTP requests") + flag.IntVar(&httpPort, "httpport", weavedns.DefaultHTTPPort, "port to listen to HTTP requests") flag.IntVar(&cacheLen, "cache", weavedns.DefaultCacheLen, "cache length") flag.IntVar(&ttl, "ttl", weavedns.DefaultLocalTTL, "TTL (in secs) for responses for local names") flag.BoolVar(&watch, "watch", true, "watch the docker socket for container events") diff --git a/proxy/create_container_interceptor.go b/proxy/create_container_interceptor.go index 4bd59e61..b1f10522 100644 --- a/proxy/create_container_interceptor.go +++ b/proxy/create_container_interceptor.go @@ -3,12 +3,14 @@ package proxy import ( "bytes" "encoding/json" + "fmt" "io/ioutil" "net/http" "strings" "github.com/fsouza/go-dockerclient" . "github.com/weaveworks/weave/common" + "github.com/weaveworks/weave/nameserver" ) type createContainerInterceptor struct{ proxy *Proxy } @@ -43,7 +45,7 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error { if err := i.setWeaveWaitEntrypoint(container.Config); err != nil { return err } - if err := i.setWeaveDNS(&container); err != nil { + if err := i.setWeaveDNS(&container, r); err != nil { return err } } @@ -78,7 +80,7 @@ func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Co return nil } -func (i *createContainerInterceptor) setWeaveDNS(container *createContainerRequestBody) error { +func (i *createContainerInterceptor) setWeaveDNS(container *createContainerRequestBody, r *http.Request) error { if !i.proxy.WithDNS { return nil } @@ -88,9 +90,40 @@ func (i *createContainerInterceptor) setWeaveDNS(container *createContainerReque if len(container.HostConfig.DNSSearch) == 0 { container.HostConfig.DNSSearch = []string{"."} } + + name := r.URL.Query().Get("name") + if container.Hostname == "" && name != "" { + container.Hostname = name + container.Domainname = i.getDNSDomain() + } + return nil } +func (i *createContainerInterceptor) getDNSDomain() (domain string) { + domain = nameserver.DefaultLocalDomain + dnsContainer, err := i.proxy.client.InspectContainer("weavedns") + if err != nil || + dnsContainer.NetworkSettings == nil || + dnsContainer.NetworkSettings.IPAddress == "" { + return + } + + url := fmt.Sprintf("http://%s:%d/domain", dnsContainer.NetworkSettings.IPAddress, nameserver.DefaultHTTPPort) + resp, err := http.Get(url) + if err != nil || resp.StatusCode != http.StatusOK { + return + } + defer resp.Body.Close() + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return + } + + return string(b) +} + func (i *createContainerInterceptor) InterceptResponse(r *http.Response) error { return nil } diff --git a/site/proxy.md b/site/proxy.md index 5f2ae23b..0c666afe 100644 --- a/site/proxy.md +++ b/site/proxy.md @@ -127,7 +127,9 @@ option, i.e. Now any containers started via the proxy, and with a `WEAVE_CIDR=...` environment variable (or even without it, if IPAM is -[configured](#ipam)), will use weaveDNS for name resolution. +[configured](#ipam)), will use weaveDNS for name resolution. If not +provided, the hostname will default to the container name and will be +registered in weaveDNS. ## Multi-host example diff --git a/site/weavedns.md b/site/weavedns.md index 4564482f..bddd0bab 100644 --- a/site/weavedns.md +++ b/site/weavedns.md @@ -29,20 +29,28 @@ other over the weave network. One such container needs to be started on every weave host, by invoking the weave script command `launch-dns`. Application containers are then instructed to use weaveDNS as their nameserver by supplying the `--with-dns` option when -starting them. Giving any container a hostname in the `.weave.local` -domain registers it in weaveDNS. For example: +starting them; containers so started also automatically register their +container name in the weaveDNS domain. For example: ```bash $ weave launch $ weave launch-dns 10.2.254.1/24 -$ weave run 10.2.1.25/24 -ti -h pingme.weave.local ubuntu -$ shell1=$(weave run --with-dns 10.2.1.26/24 -ti -h ubuntu.weave.local ubuntu) +$ weave run --with-dns 10.2.1.25/24 -ti --name=pingme ubuntu +$ shell1=$(weave run --with-dns 10.2.1.26/24 -ti --name=ubuntu ubuntu) $ docker attach $shell1 root@ubuntu:/# ping pingme ... ``` +If you start an application container sans `--with-dns` you can still register +it in weaveDNS simply by giving the container a hostname in the +`.weave.local.` domain: + +``` +$ weave run 10.2.1.25/24 -ti -h pingme.weave.local ubuntu +``` + Each weaveDNS container started with `launch-dns` needs to be given its own, unique, IP address, in a subnet that is a) common to all weaveDNS containers, b) disjoint from the application subnets, and c) @@ -55,7 +63,7 @@ use weaveDNS on a second host we would run: ```bash host2$ weave launch $HOST1 host2$ weave launch-dns 10.2.254.2/24 -host2$ shell2=$(weave run --with-dns 10.2.1.36/24 -ti -h ubuntu2.weave.local ubuntu) +host2$ shell2=$(weave run --with-dns 10.2.1.36/24 -ti --name=ubuntu2 ubuntu) host2$ docker attach $shell2 root@ubuntu2:/# ping pingme @@ -110,7 +118,7 @@ Returning to our earlier example, let us start an additional `pingme` container, this time on the 2nd host, and then run some ping tests... ```bash -host2$ weave run 10.2.1.35/24 -ti -h pingme.weave.local ubuntu +host2$ weave run --with-dns 10.2.1.35/24 -ti --name=pingme ubuntu host2$ docker attach $shell2 root@ubuntu2:/# ping -nq -c 1 pingme diff --git a/test/630_proxy_dns_test.sh b/test/630_proxy_dns_test.sh index 21cd42c4..ddc9b2d4 100755 --- a/test/630_proxy_dns_test.sh +++ b/test/630_proxy_dns_test.sh @@ -4,15 +4,17 @@ C1=10.2.0.78 C2=10.2.0.34 -NAME=seetwo.weave.local +C1_NAME=c1.weave.local +C2_NAME=seetwo.weave.local start_suite "Proxy registers containers with dns" weave_on $HOST1 launch-dns 10.2.254.1/24 weave_on $HOST1 launch-proxy --with-dns -proxy docker_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $NAME $SMALL_IMAGE /bin/sh -proxy docker_on $HOST1 run -e WEAVE_CIDR=$C1/24 -dt --name=c1 $DNS_IMAGE /bin/sh +proxy docker_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $C2_NAME $DNS_IMAGE /bin/sh +proxy docker_on $HOST1 run -e WEAVE_CIDR=$C1/24 -dt --name=c1 $DNS_IMAGE /bin/sh -assert_dns_record $HOST1 c1 $NAME $C2 +assert_dns_record $HOST1 c1 $C2_NAME $C2 +assert_dns_record $HOST1 c2 $C1_NAME $C1 end_suite diff --git a/weave b/weave index 59fa8f30..5f83abd0 100755 --- a/weave +++ b/weave @@ -648,16 +648,45 @@ dns_args() { docker_bridge_ip DNS_ARG="--dns $DOCKER_BRIDGE_IP" DNS_SEARCH_ARG="--dns-search=." - for arg in "$@" ; do - case $arg in + NAME_ARG="" + HOSTNAME_SPECIFIED=false + while [ $# -gt 0 ] ; do + case "$1" in --dns-search=*) DNS_SEARCH_ARG="" + shift + ;; + --name) + NAME_ARG="$2" + shift 2 + ;; + --name=*) + NAME_ARG="${1#*=}" + shift + ;; + -h|--hostname|--hostname=*) + HOSTNAME_SPECIFIED=true + shift ;; *) + shift ;; esac done DNS_ARGS="$DNS_ARG $DNS_SEARCH_ARG" + if [ -n "$NAME_ARG" -a "$HOSTNAME_SPECIFIED" = "false" ] ; then + DNS_ARGS="$DNS_ARGS --hostname=$NAME_ARG.$(dns_domain)" + fi +} + +# Use the weaveDNS REST API to determine the local domain. If weaveDNS is not +# running, return the default value ('weave.local.') +dns_domain() { + if DOMAIN=$(http_call $DNS_CONTAINER_NAME $DNS_HTTP_PORT GET /domain 2>/dev/null) ; then + echo $DOMAIN + else + echo 'weave.local.' + fi } # Print an error to stderr and return with an indicative exit status @@ -687,9 +716,9 @@ with_container_fqdn() { COMMAND="$2" shift 2 - CONTAINER_FQDN=$(docker inspect --format='{{.Config.Hostname}}.{{.Config.Domainname}}.' $CONTAINER 2>/dev/null) || return 0 + CONTAINER_FQDN=$(docker inspect --format='{{.Config.Hostname}}.{{.Config.Domainname}}' $CONTAINER 2>/dev/null) || return 0 - if echo "$CONTAINER_FQDN" | grep -qv '\.\.$' ; then + if echo "$CONTAINER_FQDN" | grep -Eq '[^.]+\..+' ; then $COMMAND "$CONTAINER" "$CONTAINER_FQDN" "$@" fi } @@ -1069,6 +1098,9 @@ case "$COMMAND" in dns_args "$@" echo -n $DNS_ARGS ;; + dns-domain) + echo $(dns_domain) + ;; docker-bridge-ip) docker_bridge_ip echo -n $DOCKER_BRIDGE_IP