Add dns support for the proxy
In the proxy, I swapped the 'flag' library for 'code.google.com/p/getopt', which uses double-dash flags. proxy lets 'weave attach' do dns registration on container start proxy needs to set DNSSearch if not specified
This commit is contained in:
1 parent
444b1482fa
commit
96a69d2303
11 files changed
+229
-102
No files matched your search
@@ -10,6 +10,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
)
|
||||
|
||||
func callWeave(args ...string) ([]byte, error) {
|
||||
args = append([]string{"--local"}, args...)
|
||||
Debug.Print("Calling weave", args)
|
||||
cmd := exec.Command("./weave", args...)
|
||||
cmd.Env = []string{"PROCFS=/hostproc", "PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}
|
||||
out, err := cmd.CombinedOutput()
|
||||
return out, err
|
||||
}
|
||||
|
||||
func weaveCIDRsFromConfig(config *docker.Config) ([]string, bool) {
|
||||
for _, e := range config.Env {
|
||||
if strings.HasPrefix(e, "WEAVE_CIDR=") {
|
||||
result := strings.Trim(e[11:], " ")
|
||||
return strings.Split(strings.TrimSpace(result), " "), result != ""
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -3,20 +3,17 @@ package proxy
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
type createContainerInterceptor struct {
|
||||
client *docker.Client
|
||||
}
|
||||
|
||||
func CreateContainerInterceptor(client *docker.Client) *createContainerInterceptor {
|
||||
return &createContainerInterceptor{
|
||||
client: client,
|
||||
}
|
||||
client *docker.Client
|
||||
withDNS bool
|
||||
}
|
||||
|
||||
type createContainerRequestBody struct {
|
||||
@@ -37,14 +34,14 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) (*http.Re
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, ok := weaveAddrFromConfig(container.Config); ok {
|
||||
image, err := i.client.InspectImage(container.Config.Image)
|
||||
if err != nil {
|
||||
if _, ok := weaveCIDRsFromConfig(container.Config); ok {
|
||||
i.addToVolumesFrom(container.HostConfig, "weaveproxy")
|
||||
if err := i.setWeaveWaitEntrypoint(container.Config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := i.setWeaveDNS(&container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addToVolumesFrom(container.HostConfig, "weaveproxy")
|
||||
setWeaveWaitEntrypoint(image.Config, container.Config)
|
||||
}
|
||||
|
||||
newBody, err := json.Marshal(container)
|
||||
@@ -57,30 +54,79 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) (*http.Re
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func addToVolumesFrom(config *docker.HostConfig, mounts ...string) error {
|
||||
func (i *createContainerInterceptor) addToVolumesFrom(config *docker.HostConfig, mounts ...string) {
|
||||
config.VolumesFrom = append(config.VolumesFrom, mounts...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func setWeaveWaitEntrypoint(image, container *docker.Config) {
|
||||
container.Cmd = combineEntrypoints(image, container)
|
||||
container.Entrypoint = []string{"/home/weavewait/weavewait"}
|
||||
}
|
||||
func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Config) error {
|
||||
var image *docker.Config
|
||||
if !configHasEntrypoint(container) || !configHasCmd(container) {
|
||||
imageInfo, err := i.client.InspectImage(container.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
image = imageInfo.Config
|
||||
}
|
||||
|
||||
func combineEntrypoints(image, container *docker.Config) []string {
|
||||
var entry, command []string
|
||||
if len(container.Entrypoint) > 0 {
|
||||
if configHasEntrypoint(container) {
|
||||
entry = container.Entrypoint
|
||||
} else if len(image.Entrypoint) > 0 {
|
||||
} else if configHasEntrypoint(image) {
|
||||
entry = image.Entrypoint
|
||||
}
|
||||
if len(container.Cmd) > 0 {
|
||||
if configHasCmd(container) {
|
||||
command = container.Cmd
|
||||
} else if len(image.Cmd) > 0 {
|
||||
} else if configHasCmd(image) {
|
||||
command = image.Cmd
|
||||
}
|
||||
|
||||
return append(entry, command...)
|
||||
container.Entrypoint = []string{"/home/weavewait/weavewait"}
|
||||
container.Cmd = append(entry, command...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func configHasEntrypoint(c *docker.Config) bool {
|
||||
return c != nil && len(c.Entrypoint) > 0
|
||||
}
|
||||
func configHasCmd(c *docker.Config) bool {
|
||||
return c != nil && len(c.Cmd) > 0
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) setWeaveDNS(container *createContainerRequestBody) error {
|
||||
if !i.withDNS {
|
||||
return nil
|
||||
}
|
||||
|
||||
dockerBridgeIP, err := getDockerBridgeIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
container.HostConfig.DNS = append(container.HostConfig.DNS, dockerBridgeIP)
|
||||
|
||||
if len(container.HostConfig.DNSSearch) == 0 {
|
||||
container.HostConfig.DNSSearch = []string{"."}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDockerBridgeIP() (string, error) {
|
||||
out, err := callWeave("dns-args")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error fetching weave dns-args: %s", err)
|
||||
}
|
||||
|
||||
var dockerBridgeIP string
|
||||
segments := strings.Split(string(out), " ")
|
||||
for i := 0; i < len(segments)-1; i++ {
|
||||
if segments[i] == "--dns" {
|
||||
dockerBridgeIP = segments[i+1]
|
||||
}
|
||||
}
|
||||
|
||||
if dockerBridgeIP == "" {
|
||||
return "", fmt.Errorf("Docker bridge IP not found in weave output: %s", string(out))
|
||||
}
|
||||
return dockerBridgeIP, nil
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) InterceptResponse(res *http.Response) (*http.Response, error) {
|
||||
|
||||
+33
-35
@@ -11,13 +11,28 @@ import (
|
||||
. "github.com/weaveworks/weave/common"
|
||||
)
|
||||
|
||||
const (
|
||||
RAW_STREAM = "application/vnd.docker.raw-stream"
|
||||
)
|
||||
type Proxy struct {
|
||||
Dial func() (net.Conn, error)
|
||||
client *docker.Client
|
||||
withDNS bool
|
||||
}
|
||||
|
||||
type proxy struct {
|
||||
Dial func() (net.Conn, error)
|
||||
client *docker.Client
|
||||
func NewProxy(targetURL string, withDNS bool) (*Proxy, error) {
|
||||
u, err := url.Parse(targetURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := docker.NewClient(targetURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Proxy{
|
||||
Dial: func() (net.Conn, error) {
|
||||
return net.Dial(targetNetwork(u), targetAddress(u))
|
||||
},
|
||||
client: client,
|
||||
withDNS: withDNS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func targetNetwork(u *url.URL) string {
|
||||
@@ -34,23 +49,6 @@ func targetAddress(u *url.URL) (addr string) {
|
||||
return
|
||||
}
|
||||
|
||||
func NewProxy(targetUrl string) (*proxy, error) {
|
||||
u, err := url.Parse(targetUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := docker.NewClient(targetUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &proxy{
|
||||
Dial: func() (net.Conn, error) {
|
||||
return net.Dial(targetNetwork(u), targetAddress(u))
|
||||
},
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func isWeaveStatus(r *http.Request) bool {
|
||||
return strings.HasPrefix(r.URL.Path, "/weave")
|
||||
}
|
||||
@@ -65,32 +63,32 @@ func isStartContainer(r *http.Request) bool {
|
||||
return err == nil && ok
|
||||
}
|
||||
|
||||
func (proxy *proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
Info.Printf("%s %s", r.Method, r.URL)
|
||||
switch {
|
||||
case isCreateContainer(r):
|
||||
proxy.CreateContainer(w, r)
|
||||
proxy.createContainer(w, r)
|
||||
case isStartContainer(r):
|
||||
proxy.StartContainer(w, r)
|
||||
proxy.startContainer(w, r)
|
||||
case isWeaveStatus(r):
|
||||
proxy.WeaveStatus(w, r)
|
||||
proxy.weaveStatus(w, r)
|
||||
default:
|
||||
proxy.ProxyRequest(w, r)
|
||||
proxy.proxyRequest(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *proxy) WeaveStatus(w http.ResponseWriter, r *http.Request) {
|
||||
func (proxy *Proxy) weaveStatus(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (proxy *proxy) CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
NewClient(proxy.Dial, CreateContainerInterceptor(proxy.client)).ServeHTTP(w, r)
|
||||
func (proxy *Proxy) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||
newClient(proxy.Dial, &createContainerInterceptor{proxy.client, proxy.withDNS}).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (proxy *proxy) StartContainer(w http.ResponseWriter, r *http.Request) {
|
||||
NewClient(proxy.Dial, StartContainerInterceptor(proxy.client)).ServeHTTP(w, r)
|
||||
func (proxy *Proxy) startContainer(w http.ResponseWriter, r *http.Request) {
|
||||
newClient(proxy.Dial, &startContainerInterceptor{proxy.client, proxy.withDNS}).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (proxy *proxy) ProxyRequest(w http.ResponseWriter, r *http.Request) {
|
||||
NewClient(proxy.Dial, NullInterceptor).ServeHTTP(w, r)
|
||||
func (proxy *Proxy) proxyRequest(w http.ResponseWriter, r *http.Request) {
|
||||
newClient(proxy.Dial, &nullInterceptor{}).ServeHTTP(w, r)
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package proxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -11,13 +10,8 @@ import (
|
||||
)
|
||||
|
||||
type startContainerInterceptor struct {
|
||||
client *docker.Client
|
||||
}
|
||||
|
||||
func StartContainerInterceptor(client *docker.Client) Interceptor {
|
||||
return &startContainerInterceptor{
|
||||
client: client,
|
||||
}
|
||||
client *docker.Client
|
||||
withDNS bool
|
||||
}
|
||||
|
||||
func (i *startContainerInterceptor) InterceptRequest(r *http.Request) (*http.Request, error) {
|
||||
@@ -25,21 +19,19 @@ func (i *startContainerInterceptor) InterceptRequest(r *http.Request) (*http.Req
|
||||
}
|
||||
|
||||
func (i *startContainerInterceptor) InterceptResponse(res *http.Response) (*http.Response, error) {
|
||||
containerId := containerFromPath(res.Request.URL.Path)
|
||||
containerID := containerFromPath(res.Request.URL.Path)
|
||||
|
||||
container, err := i.client.InspectContainer(containerId)
|
||||
container, err := i.client.InspectContainer(containerID)
|
||||
if err != nil {
|
||||
Warning.Print("Error Inspecting Container: ", err)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
if cidr, ok := weaveAddrFromConfig(container.Config); ok {
|
||||
Info.Printf("Container %s was started with CIDR \"%s\"", containerId, cidr)
|
||||
args := []string{"attach"}
|
||||
args = append(args, strings.Split(strings.TrimSpace(cidr), " ")...)
|
||||
args = append(args, containerId)
|
||||
if out, err := callWeave(args...); err != nil {
|
||||
Warning.Print("Calling weave failed: ", err, string(out))
|
||||
if cidrs, ok := weaveCIDRsFromConfig(container.Config); ok {
|
||||
Info.Printf("Container %s was started with CIDR \"%s\"", containerID, strings.Join(cidrs, " "))
|
||||
if err := i.attachContainerToWeave(containerID, cidrs); err != nil {
|
||||
Warning.Print("Attaching container to weave failed: ", err)
|
||||
return res, nil
|
||||
}
|
||||
} else {
|
||||
Debug.Print("No Weave CIDR, ignoring")
|
||||
@@ -55,21 +47,10 @@ func containerFromPath(path string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func callWeave(args ...string) ([]byte, error) {
|
||||
args = append([]string{"--local"}, args...)
|
||||
Debug.Print("Calling weave", args)
|
||||
cmd := exec.Command("./weave", args...)
|
||||
cmd.Env = []string{"PROCFS=/hostproc", "PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}
|
||||
out, err := cmd.CombinedOutput()
|
||||
return out, err
|
||||
}
|
||||
|
||||
func weaveAddrFromConfig(config *docker.Config) (string, bool) {
|
||||
for _, e := range config.Env {
|
||||
if strings.HasPrefix(e, "WEAVE_CIDR=") {
|
||||
result := strings.Trim(e[11:], " ")
|
||||
return result, result != ""
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
func (i *startContainerInterceptor) attachContainerToWeave(containerID string, cidrs []string) error {
|
||||
args := []string{"attach"}
|
||||
args = append(args, cidrs...)
|
||||
args = append(args, containerID)
|
||||
_, err := callWeave(args...)
|
||||
return err
|
||||
}
|
||||
@@ -47,6 +47,18 @@ or, equivalently with
|
||||
|
||||
Multiple IP addresses and networks can be supplied in the WEAVE_CIDR variable by space-separating them, as in `WEAVE_CIDR=10.2.1.1/24 10.2.2.1/24`.
|
||||
|
||||
#### Usage with WeaveDNS
|
||||
|
||||
Containers started via the proxy can be automatically configured to use WeaveDNS for name resolution. To accomplish this we need to launch the proxy with the `--with-dns` option
|
||||
|
||||
host1$ weave launch
|
||||
host1$ weave launch-dns 10.2.254.1/24
|
||||
host1$ weave launch-proxy --with-dns
|
||||
|
||||
With this done, any containers launched through the proxy will use weaveDNS for name resolution. WeaveDNS is used in addition to any dns servers specified via the `--dns` option. More details on weaveDNS can be found in the [weaveDNS documentation](weavedns-readme.html).
|
||||
|
||||
More details on weaveDNS can be found in the [weaveDNS documentation](weavedns-readme.html).
|
||||
|
||||
#### Limitations
|
||||
|
||||
* The proxy does not currently support TLS.
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
start_suite "Proxy uses entrypoint from the image with weavewait"
|
||||
weave_on $HOST1 launch-proxy
|
||||
docker_on $HOST1 build -t inspect-ethwe - <<- EOF
|
||||
FROM gliderlabs/alpine
|
||||
ENTRYPOINT ["ip", "link", "show", "ethwe"]
|
||||
EOF
|
||||
|
||||
assert_raises "docker_proxy_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.1/24' inspect-ethwe | grep 'state UP'"
|
||||
|
||||
end_suite
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
C1=10.2.0.78
|
||||
C2=10.2.0.34
|
||||
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
|
||||
docker_proxy_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $NAME gliderlabs/alpine /bin/sh
|
||||
docker_proxy_on $HOST1 run -e WEAVE_CIDR=$C1/24 -dt --name=c1 aanand/docker-dnsutils /bin/sh
|
||||
|
||||
assert_dns_record $HOST1 c1 $NAME $C2
|
||||
|
||||
end_suite
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
start_suite "Proxy allows overridden entrypoint from the container with weavewait"
|
||||
weave_on $HOST1 launch-proxy
|
||||
docker_on $HOST1 build -t false - <<- EOF
|
||||
FROM gliderlabs/alpine
|
||||
ENTRYPOINT ["/bin/false"]
|
||||
EOF
|
||||
|
||||
assert_raises "docker_proxy_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.1/24' --entrypoint '/sbin/ip' false link show ethwe | grep 'state UP'"
|
||||
|
||||
end_suite
|
||||
@@ -27,7 +27,7 @@ usage() {
|
||||
echo "weave setup"
|
||||
echo "weave launch [-password <password>] [-nickname <nickname>] [-iprange <cidr>] <peer> ..."
|
||||
echo "weave launch-dns <cidr>"
|
||||
echo "weave launch-proxy [-H <docker_endpoint>]"
|
||||
echo "weave launch-proxy [-H <docker_endpoint>] [--with-dns]"
|
||||
echo "weave connect <peer>"
|
||||
echo "weave forget <peer>"
|
||||
echo "weave run [--with-dns] [<cidr> ...] <docker run args> ..."
|
||||
|
||||
+22
-7
@@ -1,27 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.google.com/p/getopt"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/proxy"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultTarget = "unix:///var/run/docker.sock"
|
||||
defaultListen = ":12375"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var target, listen string
|
||||
var debug bool
|
||||
var withDNS, debug bool
|
||||
|
||||
flag.StringVar(&target, "H", "unix:///var/run/docker.sock", "docker daemon URL to proxy")
|
||||
flag.StringVar(&listen, "L", ":12375", "address on which to listen")
|
||||
flag.BoolVar(&debug, "debug", false, "log debugging information")
|
||||
flag.Parse()
|
||||
getopt.BoolVarLong(&debug, "debug", 'd', "log debugging information")
|
||||
getopt.StringVar(&target, 'H', fmt.Sprintf("docker daemon URL to proxy (default %s)", defaultTarget))
|
||||
getopt.StringVar(&listen, 'L', fmt.Sprintf("address on which to listen (default %s)", defaultListen))
|
||||
getopt.BoolVarLong(&withDNS, "with-dns", 'w', "register connected containers with weaveDNS")
|
||||
getopt.Parse()
|
||||
|
||||
if target == "" {
|
||||
target = defaultTarget
|
||||
}
|
||||
|
||||
if listen == "" {
|
||||
listen = defaultListen
|
||||
}
|
||||
|
||||
if debug {
|
||||
InitDefaultLogging(true)
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(target)
|
||||
p, err := proxy.NewProxy(target, withDNS)
|
||||
if err != nil {
|
||||
Error.Fatalf("Could not start proxy: %s", err)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user