From 0e9716d5b06685b7cfb05f9c1259072d5140e3e8 Mon Sep 17 00:00:00 2001 From: "Jonathan Leibiusky @xetorthio" Date: Tue, 8 Aug 2017 10:10:52 -0300 Subject: [PATCH] Set session host Add ping to L2 router --- config/config.go | 3 ++- docker/docker.go | 5 ++++ docker/mock.go | 5 ++++ handlers/ping.go | 19 +-------------- pwd/client_test.go | 3 +++ pwd/instance_test.go | 6 +++++ pwd/session.go | 57 +++++++++++++------------------------------- pwd/session_test.go | 5 +++- router/l2/l2.go | 34 ++++++++++++++++++++++++++ 9 files changed, 76 insertions(+), 61 deletions(-) diff --git a/config/config.go b/config/config.go index 7de0c62..4514116 100644 --- a/config/config.go +++ b/config/config.go @@ -20,7 +20,7 @@ const ( var NameFilter = regexp.MustCompile(PWDHostPortGroupRegex) var AliasFilter = regexp.MustCompile(AliasPortGroupRegex) -var SSLPortNumber, PortNumber, Key, Cert, SessionsFile, PWDContainerName, L2ContainerName, L2Subdomain, PWDCName, HashKey, SSHKeyPath string +var SSLPortNumber, PortNumber, Key, Cert, SessionsFile, PWDContainerName, L2ContainerName, L2Subdomain, PWDCName, HashKey, SSHKeyPath, L2RouterIP string var MaxLoadAvg float64 func ParseFlags() { @@ -31,6 +31,7 @@ func ParseFlags() { flag.StringVar(&SessionsFile, "save", "./pwd/sessions", "Tell where to store sessions file") flag.StringVar(&PWDContainerName, "name", "pwd", "Container name used to run PWD (used to be able to connect it to the networks it creates)") flag.StringVar(&L2ContainerName, "l2", "l2", "Container name used to run L2 Router") + flag.StringVar(&L2RouterIP, "l2-ip", "", "Host IP address for L2 router ping response") flag.StringVar(&L2Subdomain, "l2-subdomain", "direct", "Subdomain to the L2 Router") flag.StringVar(&PWDCName, "cname", "", "CNAME given to this host") flag.StringVar(&HashKey, "hash_key", "salmonrosado", "Hash key to use for cookies") diff --git a/docker/docker.go b/docker/docker.go index f1a2a50..2b0569f 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -33,6 +33,7 @@ type DockerApi interface { CreateNetwork(id string) error ConnectNetwork(container, network, ip string) (string, error) GetDaemonInfo() (types.Info, error) + GetDaemonHost() string GetSwarmPorts() ([]string, []uint16, error) GetPorts() ([]uint16, error) GetContainerStats(name string) (io.ReadCloser, error) @@ -102,6 +103,10 @@ func (d *docker) GetDaemonInfo() (types.Info, error) { return d.c.Info(context.Background()) } +func (d *docker) GetDaemonHost() string { + return d.c.DaemonHost() +} + func (d *docker) GetSwarmPorts() ([]string, []uint16, error) { hosts := []string{} ports := []uint16{} diff --git a/docker/mock.go b/docker/mock.go index 3304cf8..2abb070 100644 --- a/docker/mock.go +++ b/docker/mock.go @@ -28,6 +28,11 @@ func (m *Mock) GetDaemonInfo() (types.Info, error) { return args.Get(0).(types.Info), args.Error(1) } +func (m *Mock) GetDaemonHost() string { + args := m.Called() + return args.String(0) +} + func (m *Mock) GetSwarmPorts() ([]string, []uint16, error) { args := m.Called() return args.Get(0).([]string), args.Get(1).([]uint16), args.Error(2) diff --git a/handlers/ping.go b/handlers/ping.go index ccf5cec..66a41be 100644 --- a/handlers/ping.go +++ b/handlers/ping.go @@ -1,23 +1,6 @@ package handlers -import ( - "log" - "net/http" - - "github.com/play-with-docker/play-with-docker/config" - "github.com/shirou/gopsutil/load" -) +import "net/http" func Ping(rw http.ResponseWriter, req *http.Request) { - // Get system load average of the last 5 minutes and compare it against a threashold. - - a, err := load.Avg() - if err != nil { - log.Println("Cannot get system load average!", err) - } else { - if a.Load5 > config.MaxLoadAvg { - log.Printf("System load average is too high [%f]\n", a.Load5) - rw.WriteHeader(http.StatusInsufficientStorage) - } - } } diff --git a/pwd/client_test.go b/pwd/client_test.go index df4ab30..9e5294a 100644 --- a/pwd/client_test.go +++ b/pwd/client_test.go @@ -23,6 +23,7 @@ func TestClientNew(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("SessionCount").Return(1, nil) @@ -59,6 +60,7 @@ func TestClientCount(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("SessionCount").Return(1, nil) @@ -93,6 +95,7 @@ func TestClientResizeViewPort(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("SessionCount").Return(1, nil) diff --git a/pwd/instance_test.go b/pwd/instance_test.go index dc0a065..a0edeea 100644 --- a/pwd/instance_test.go +++ b/pwd/instance_test.go @@ -47,6 +47,7 @@ func TestInstanceNew(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("SessionCount").Return(1, nil) @@ -69,6 +70,7 @@ func TestInstanceNew(t *testing.T) { IsDockerHost: true, SessionId: session.Id, Session: session, + SessionHost: session.Host, ProxyHost: router.EncodeHost(session.Id, "10.0.0.1", router.HostOpts{}), } expectedContainerOpts := docker.CreateContainerOpts{ @@ -109,6 +111,7 @@ func TestInstanceNew_WithNotAllowedImage(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("SessionCount").Return(1, nil) @@ -132,6 +135,7 @@ func TestInstanceNew_WithNotAllowedImage(t *testing.T) { SessionId: session.Id, IsDockerHost: false, Session: session, + SessionHost: session.Host, ProxyHost: router.EncodeHost(session.Id, "10.0.0.1", router.HostOpts{}), } expectedContainerOpts := docker.CreateContainerOpts{ @@ -171,6 +175,7 @@ func TestInstanceNew_WithCustomHostname(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("SessionCount").Return(1, nil) @@ -192,6 +197,7 @@ func TestInstanceNew_WithCustomHostname(t *testing.T) { Image: "redis", IsDockerHost: false, Session: session, + SessionHost: session.Host, SessionId: session.Id, ProxyHost: router.EncodeHost(session.Id, "10.0.0.1", router.HostOpts{}), } diff --git a/pwd/session.go b/pwd/session.go index 2f0cdbb..362d08b 100644 --- a/pwd/session.go +++ b/pwd/session.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "math" + "net/url" "path" "path/filepath" "strings" @@ -61,15 +62,28 @@ func (p *pwd) SessionNew(duration time.Duration, stack, stackName, imageName str log.Printf("NewSession id=[%s]\n", s.Id) - if err := p.docker(s.Id).CreateNetwork(s.Id); err != nil { + dockerClient := p.docker(s.Id) + u, _ := url.Parse(dockerClient.GetDaemonHost()) + if u.Host == "" { + s.Host = "localhost" + } else { + chunks := strings.Split(u.Host, ":") + s.Host = chunks[0] + } + + if err := dockerClient.CreateNetwork(s.Id); err != nil { log.Println("ERROR NETWORKING") return nil, err } log.Printf("Network [%s] created for session [%s]\n", s.Id, s.Id) - if err := p.connectToNetwork(s); err != nil { + ip, err := dockerClient.ConnectNetwork(config.L2ContainerName, s.Id, s.PwdIpAddress) + if err != nil { + log.Println(err) return nil, err } + s.PwdIpAddress = ip + log.Printf("Connected %s to network [%s]\n", config.PWDContainerName, s.Id) if err := p.storage.SessionPut(s); err != nil { log.Println(err) @@ -278,42 +292,3 @@ func (p *pwd) SessionSetup(session *types.Session, conf SessionSetupConf) error return nil } - -/* -// This function should be called any time a session needs to be prepared: -// 1. Like when it is created -// 2. When it was loaded from storage -func (p *pwd) prepareSession(session *types.Session) (bool, error) { - session.Lock() - defer session.Unlock() - - if isSessionPrepared(session.Id) { - return false, nil - } - - // Connect PWD daemon to the new network - if err := p.connectToNetwork(session); err != nil { - return false, err - } - - for _, i := range session.Instances { - // wire the session back to the instance - i.Session = session - go p.InstanceAttachTerminal(i) - } - preparedSessions[session.Id] = true - - return true, nil -} -*/ - -func (p *pwd) connectToNetwork(s *types.Session) error { - ip, err := p.docker(s.Id).ConnectNetwork(config.L2ContainerName, s.Id, s.PwdIpAddress) - if err != nil { - log.Println("ERROR NETWORKING") - return err - } - s.PwdIpAddress = ip - log.Printf("Connected %s to network [%s]\n", config.PWDContainerName, s.Id) - return nil -} diff --git a/pwd/session_test.go b/pwd/session_test.go index 705695d..4feaa15 100644 --- a/pwd/session_test.go +++ b/pwd/session_test.go @@ -24,6 +24,7 @@ func TestSessionNew(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("SessionCount").Return(1, nil) @@ -53,6 +54,7 @@ func TestSessionNew(t *testing.T) { assert.Equal(t, "stackPath", s.Stack) assert.Equal(t, "stackName", s.StackName) assert.Equal(t, "imageName", s.ImageName) + assert.Equal(t, "localhost", s.Host) assert.False(t, s.Ready) assert.Equal(t, "10.0.0.1", s.PwdIpAddress) @@ -74,13 +76,14 @@ func TestSessionSetup(t *testing.T) { _g.On("NewId").Return("aaaabbbbcccc") _f.On("GetForSession", "aaaabbbbcccc").Return(_d, nil) _d.On("CreateNetwork", "aaaabbbbcccc").Return(nil) + _d.On("GetDaemonHost").Return("localhost") _d.On("ConnectNetwork", config.L2ContainerName, "aaaabbbbcccc", "").Return("10.0.0.1", nil) _s.On("SessionPut", mock.AnythingOfType("*types.Session")).Return(nil) _s.On("InstanceCreate", "aaaabbbbcccc", mock.AnythingOfType("*types.Instance")).Return(nil) _s.On("SessionCount").Return(1, nil) _s.On("InstanceCount").Return(0, nil) - _d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", PwdIpAddress: "10.0.0.1", ContainerName: "aaaabbbb_manager1", Hostname: "manager1", Privileged: true}).Return("10.0.0.2", nil) + _d.On("CreateContainer", docker.CreateContainerOpts{Image: "franela/dind", SessionId: "aaaabbbbcccc", PwdIpAddress: "10.0.0.1", ContainerName: "aaaabbbb_manager1", Hostname: "manager1", Privileged: true, HostFQDN: "localhost"}).Return("10.0.0.2", nil) _f.On("GetForInstance", "aaaabbbbcccc", "aaaabbbb_manager1").Return(_d, nil) _d.On("SwarmInit").Return(&docker.SwarmTokens{Manager: "managerToken", Worker: "workerToken"}, nil) _e.M.On("Emit", event.INSTANCE_NEW, "aaaabbbbcccc", []interface{}{"aaaabbbb_manager1", "10.0.0.2", "manager1"}).Return() diff --git a/router/l2/l2.go b/router/l2/l2.go index 38c0e1d..3582330 100644 --- a/router/l2/l2.go +++ b/router/l2/l2.go @@ -6,14 +6,19 @@ import ( "fmt" "log" "net" + "net/http" "os" + "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" + "github.com/gorilla/mux" "github.com/play-with-docker/play-with-docker/config" "github.com/play-with-docker/play-with-docker/router" + "github.com/shirou/gopsutil/load" + "github.com/urfave/negroni" ) func director(protocol router.Protocol, host string) (*net.TCPAddr, error) { @@ -128,7 +133,36 @@ func main() { } go monitorNetworks() + ro := mux.NewRouter() + ro.HandleFunc("/ping", ping).Methods("GET") + n := negroni.Classic() + n.UseHandler(ro) + + httpServer := http.Server{ + Addr: "0.0.0.0:8080", + Handler: n, + IdleTimeout: 30 * time.Second, + ReadHeaderTimeout: 5 * time.Second, + } + go httpServer.ListenAndServe() + r := router.NewRouter(director, config.SSHKeyPath) r.ListenAndWait(":443", ":53", ":22") defer r.Close() } + +func ping(rw http.ResponseWriter, req *http.Request) { + // Get system load average of the last 5 minutes and compare it against a threashold. + + a, err := load.Avg() + if err != nil { + log.Println("Cannot get system load average!", err) + } else { + if a.Load5 > config.MaxLoadAvg { + log.Printf("System load average is too high [%f]\n", a.Load5) + rw.WriteHeader(http.StatusInsufficientStorage) + } + } + + fmt.Fprintf(rw, `{"ip": "%s"}`, config.L2RouterIP) +}