This commit is contained in:
Jonathan Leibiusky @xetorthio
2017-07-25 16:36:10 -03:00
parent 8424479e76
commit 53e6078cc5
22 changed files with 307 additions and 144 deletions

View File

@@ -11,12 +11,13 @@ import (
)
func TestClientNew(t *testing.T) {
docker := &mockDocker{}
d := &mockDocker{}
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
sp := &mockSessionProvider{docker: d}
p := NewPWD(docker, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, err := p.SessionNew(time.Hour, "", "", "")
assert.Nil(t, err)
@@ -27,12 +28,13 @@ func TestClientNew(t *testing.T) {
assert.Contains(t, session.Clients, client)
}
func TestClientCount(t *testing.T) {
docker := &mockDocker{}
d := &mockDocker{}
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
sp := &mockSessionProvider{docker: d}
p := NewPWD(docker, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, err := p.SessionNew(time.Hour, "", "", "")
assert.Nil(t, err)
@@ -45,9 +47,10 @@ func TestClientCount(t *testing.T) {
func TestClientResizeViewPort(t *testing.T) {
wg := sync.WaitGroup{}
wg.Add(1)
docker := &mockDocker{}
d := &mockDocker{}
tasks := &mockTasks{}
e := event.NewLocalBroker()
sp := &mockSessionProvider{docker: d}
broadcastedSessionId := ""
broadcastedArgs := []interface{}{}
@@ -60,7 +63,7 @@ func TestClientResizeViewPort(t *testing.T) {
storage := &mockStorage{}
p := NewPWD(docker, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, err := p.SessionNew(time.Hour, "", "", "")
assert.Nil(t, err)

View File

@@ -7,7 +7,7 @@ import (
dockerTypes "github.com/docker/docker/api/types"
units "github.com/docker/go-units"
"github.com/play-with-docker/play-with-docker/docker"
"github.com/play-with-docker/play-with-docker/provider"
"github.com/play-with-docker/play-with-docker/pwd/types"
)
@@ -20,11 +20,12 @@ type collectStatsTask struct {
previousCPU uint64
previousSystem uint64
docker docker.DockerApi
sessionProvider provider.SessionProvider
}
func (c collectStatsTask) Run(i *types.Instance) error {
reader, err := c.docker.GetContainerStats(i.Name)
docker, _ := c.sessionProvider.GetDocker(i.SessionId)
reader, err := docker.GetContainerStats(i.Name)
if err != nil {
log.Println("Error while trying to collect instance stats", err)
return err

View File

@@ -15,6 +15,7 @@ import (
"github.com/play-with-docker/play-with-docker/docker"
"github.com/play-with-docker/play-with-docker/event"
"github.com/play-with-docker/play-with-docker/pwd/types"
"github.com/play-with-docker/play-with-docker/router"
"golang.org/x/text/encoding"
)
@@ -46,7 +47,7 @@ type InstanceConfig struct {
func (p *pwd) InstanceResizeTerminal(instance *types.Instance, rows, cols uint) error {
defer observeAction("InstanceResizeTerminal", time.Now())
return p.docker.ContainerResize(instance.Name, rows, cols)
return p.docker(instance.SessionId).ContainerResize(instance.Name, rows, cols)
}
func (p *pwd) InstanceAttachTerminal(instance *types.Instance) error {
@@ -54,7 +55,7 @@ func (p *pwd) InstanceAttachTerminal(instance *types.Instance) error {
if getInstanceTermConn(instance.SessionId, instance.Name) != nil {
return nil
}
conn, err := p.docker.CreateAttachConnection(instance.Name)
conn, err := p.docker(instance.SessionId).CreateAttachConnection(instance.Name)
if err != nil {
return err
@@ -84,7 +85,7 @@ func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, fileName, dest str
return fmt.Errorf("Could not download file [%s]. Status code: %d\n", url, resp.StatusCode)
}
copyErr := p.docker.CopyToContainer(instance.Name, dest, fileName, resp.Body)
copyErr := p.docker(instance.SessionId).CopyToContainer(instance.Name, dest, fileName, resp.Body)
if copyErr != nil {
return fmt.Errorf("Error while downloading file [%s]. Error: %s\n", url, copyErr)
@@ -96,7 +97,7 @@ func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, fileName, dest str
func (p *pwd) getInstanceCWD(instance *types.Instance) (string, error) {
b := bytes.NewBufferString("")
if c, err := p.docker.ExecAttach(instance.Name, []string{"bash", "-c", `pwdx $(</var/run/cwd)`}, b); c > 0 {
if c, err := p.docker(instance.SessionId).ExecAttach(instance.Name, []string{"bash", "-c", `pwdx $(</var/run/cwd)`}, b); c > 0 {
log.Println(b.String())
return "", fmt.Errorf("Error %d trying to get CWD", c)
} else if err != nil {
@@ -122,7 +123,7 @@ func (p *pwd) InstanceUploadFromReader(instance *types.Instance, fileName, dest
}
}
copyErr := p.docker.CopyToContainer(instance.Name, finalDest, fileName, reader)
copyErr := p.docker(instance.SessionId).CopyToContainer(instance.Name, finalDest, fileName, reader)
if copyErr != nil {
return fmt.Errorf("Error while uploading file [%s]. Error: %s\n", fileName, copyErr)
@@ -171,7 +172,7 @@ func (p *pwd) InstanceDelete(session *types.Session, instance *types.Instance) e
if conn != nil {
conn.Close()
}
err := p.docker.DeleteContainer(instance.Name)
err := p.docker(session.Id).DeleteContainer(instance.Name)
if err != nil && !strings.Contains(err.Error(), "No such container") {
log.Println(err)
return err
@@ -243,7 +244,7 @@ func (p *pwd) InstanceNew(session *types.Session, conf InstanceConfig) (*types.I
}
}
ip, err := p.docker.CreateContainer(opts)
ip, err := p.docker(session.Id).CreateContainer(opts)
if err != nil {
return nil, err
}
@@ -261,6 +262,7 @@ func (p *pwd) InstanceNew(session *types.Session, conf InstanceConfig) (*types.I
instance.ServerKey = conf.ServerKey
instance.CACert = conf.CACert
instance.Session = session
instance.Proxy = router.EncodeHost(session.Id, ip, router.HostOpts{})
// For now this condition holds through. In the future we might need a more complex logic.
instance.IsDockerHost = opts.Privileged
@@ -304,7 +306,7 @@ func (p *pwd) InstanceAllowedImages() []string {
func (p *pwd) InstanceExec(instance *types.Instance, cmd []string) (int, error) {
defer observeAction("InstanceExec", time.Now())
return p.docker.Exec(instance.Name, cmd)
return p.docker(instance.SessionId).Exec(instance.Name, cmd)
}
func getInstanceTermConn(sessionId, instanceName string) net.Conn {

View File

@@ -12,6 +12,7 @@ import (
"github.com/play-with-docker/play-with-docker/docker"
"github.com/play-with-docker/play-with-docker/event"
"github.com/play-with-docker/play-with-docker/pwd/types"
"github.com/play-with-docker/play-with-docker/router"
"github.com/stretchr/testify/assert"
)
@@ -28,12 +29,13 @@ func TestInstanceResizeTerminal(t *testing.T) {
return nil
}
sp := &mockSessionProvider{docker: docker}
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
p := NewPWD(docker, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
err := p.InstanceResizeTerminal(&types.Instance{Name: "foobar"}, 24, 80)
@@ -50,12 +52,13 @@ func TestInstanceNew(t *testing.T) {
containerOpts = opts
return "10.0.0.1", nil
}
sp := &mockSessionProvider{docker: dock}
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
p := NewPWD(dock, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, err := p.SessionNew(time.Hour, "", "", "")
@@ -74,6 +77,7 @@ func TestInstanceNew(t *testing.T) {
IsDockerHost: true,
SessionId: session.Id,
Session: session,
Proxy: router.EncodeHost(session.Id, "10.0.0.1", router.HostOpts{}),
}
assert.Equal(t, expectedInstance, *instance)
@@ -101,12 +105,13 @@ func TestInstanceNew_Concurrency(t *testing.T) {
i++
return fmt.Sprintf("10.0.0.%d", i), nil
}
sp := &mockSessionProvider{docker: dock}
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
p := NewPWD(dock, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, err := p.SessionNew(time.Hour, "", "", "")
@@ -142,12 +147,13 @@ func TestInstanceNew_WithNotAllowedImage(t *testing.T) {
containerOpts = opts
return "10.0.0.1", nil
}
sp := &mockSessionProvider{docker: dock}
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
p := NewPWD(dock, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, err := p.SessionNew(time.Hour, "", "", "")
@@ -166,6 +172,7 @@ func TestInstanceNew_WithNotAllowedImage(t *testing.T) {
SessionId: session.Id,
IsDockerHost: false,
Session: session,
Proxy: instance.Proxy,
}
assert.Equal(t, expectedInstance, *instance)
@@ -191,12 +198,13 @@ func TestInstanceNew_WithCustomHostname(t *testing.T) {
containerOpts = opts
return "10.0.0.1", nil
}
sp := &mockSessionProvider{docker: dock}
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
p := NewPWD(dock, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, err := p.SessionNew(time.Hour, "", "", "")
@@ -215,6 +223,7 @@ func TestInstanceNew_WithCustomHostname(t *testing.T) {
IsDockerHost: false,
Session: session,
SessionId: session.Id,
Proxy: instance.Proxy,
}
assert.Equal(t, expectedInstance, *instance)
@@ -238,8 +247,9 @@ func TestInstanceAllowedImages(t *testing.T) {
tasks := &mockTasks{}
e := event.NewLocalBroker()
storage := &mockStorage{}
sp := &mockSessionProvider{docker: dock}
p := NewPWD(dock, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
expectedImages := []string{config.GetDindImageName(), "franela/dind:overlay2-dev", "franela/ucp:2.4.1"}
@@ -264,8 +274,9 @@ func TestTermConnAssignment(t *testing.T) {
// return error connection to unlock the goroutine
return errConn{}, nil
}
sp := &mockSessionProvider{docker: dock}
p := NewPWD(dock, tasks, e, storage)
p := NewPWD(sp, tasks, e, storage)
session, _ := p.SessionNew(time.Hour, "", "", "")
mockInstance := &types.Instance{
Name: fmt.Sprintf("%s_redis-master", session.Id[:8]),

View File

@@ -6,6 +6,7 @@ import (
"github.com/play-with-docker/play-with-docker/docker"
"github.com/play-with-docker/play-with-docker/event"
"github.com/play-with-docker/play-with-docker/provider"
"github.com/play-with-docker/play-with-docker/pwd/types"
"github.com/play-with-docker/play-with-docker/storage"
"github.com/prometheus/client_golang/prometheus"
@@ -44,11 +45,11 @@ func init() {
}
type pwd struct {
docker docker.DockerApi
tasks SchedulerApi
event event.EventApi
storage storage.StorageApi
clientCount int32
sessionProvider provider.SessionProvider
tasks SchedulerApi
event event.EventApi
storage storage.StorageApi
clientCount int32
}
type PWDApi interface {
@@ -80,8 +81,16 @@ type PWDApi interface {
ClientCount() int
}
func NewPWD(d docker.DockerApi, t SchedulerApi, e event.EventApi, s storage.StorageApi) *pwd {
return &pwd{docker: d, tasks: t, event: e, storage: s}
func NewPWD(sp provider.SessionProvider, t SchedulerApi, e event.EventApi, s storage.StorageApi) *pwd {
return &pwd{sessionProvider: sp, tasks: t, event: e, storage: s}
}
func (p *pwd) docker(sessionId string) docker.DockerApi {
d, err := p.sessionProvider.GetDocker(sessionId)
if err != nil {
panic("Should not have got here. Session always need to be validated before calling this.")
}
return d
}
func (p *pwd) setGauges() {

View File

@@ -62,7 +62,7 @@ func (p *pwd) SessionNew(duration time.Duration, stack, stackName, imageName str
log.Printf("NewSession id=[%s]\n", s.Id)
if err := p.docker.CreateNetwork(s.Id); err != nil {
if err := p.docker(s.Id).CreateNetwork(s.Id); err != nil {
log.Println("ERROR NETWORKING")
return nil, err
}
@@ -101,14 +101,14 @@ func (p *pwd) SessionClose(s *types.Session) error {
}
}
// Disconnect PWD daemon from the network
if err := p.docker.DisconnectNetwork(config.PWDContainerName, s.Id); err != nil {
if err := p.docker(s.Id).DisconnectNetwork(config.PWDContainerName, s.Id); err != nil {
if !strings.Contains(err.Error(), "is not connected to the network") {
log.Println("ERROR NETWORKING")
return err
}
}
log.Printf("Disconnected pwd from network [%s]\n", s.Id)
if err := p.docker.DeleteNetwork(s.Id); err != nil {
if err := p.docker(s.Id).DeleteNetwork(s.Id); err != nil {
if !strings.Contains(err.Error(), "not found") {
log.Println(err)
return err
@@ -168,7 +168,7 @@ func (p *pwd) SessionDeployStack(s *types.Session) error {
cmd := fmt.Sprintf("docker swarm init --advertise-addr eth0 && docker-compose -f %s pull && docker stack deploy -c %s %s", file, file, s.StackName)
w := sessionBuilderWriter{sessionId: s.Id, event: p.event}
code, err := p.docker.ExecAttach(i.Name, []string{"sh", "-c", cmd}, &w)
code, err := p.docker(s.Id).ExecAttach(i.Name, []string{"sh", "-c", cmd}, &w)
if err != nil {
log.Printf("Error executing stack [%s]: %s\n", s.Stack, err)
return err
@@ -218,7 +218,7 @@ func (p *pwd) SessionSetup(session *types.Session, conf SessionSetupConf) error
return err
}
if i.Docker == nil {
dock, err := p.docker.New(i.IP, i.Cert, i.Key)
dock, err := p.docker(session.Id).New(i.IP, i.Cert, i.Key)
if err != nil {
return err
}
@@ -254,7 +254,7 @@ func (p *pwd) SessionSetup(session *types.Session, conf SessionSetupConf) error
if c.IsSwarmManager || c.IsSwarmWorker {
// check if we have connection to the daemon, if not, create it
if i.Docker == nil {
dock, err := p.docker.New(i.IP, i.Cert, i.Key)
dock, err := p.docker(session.Id).New(i.IP, i.Cert, i.Key)
if err != nil {
log.Println(err)
return
@@ -334,7 +334,7 @@ func (p *pwd) scheduleSessionClose(s *types.Session) {
}
func (p *pwd) connectToNetwork(s *types.Session) error {
ip, err := p.docker.ConnectNetwork(config.PWDContainerName, s.Id, s.PwdIpAddress)
ip, err := p.docker(s.Id).ConnectNetwork(config.PWDContainerName, s.Id, s.PwdIpAddress)
if err != nil {
log.Println("ERROR NETWORKING")
return err

View File

@@ -0,0 +1,11 @@
package pwd
import "github.com/play-with-docker/play-with-docker/docker"
type mockSessionProvider struct {
docker docker.DockerApi
}
func (p *mockSessionProvider) GetDocker(sessionId string) (docker.DockerApi, error) {
return p.docker, nil
}

View File

@@ -30,6 +30,7 @@ func TestSessionNew(t *testing.T) {
connectIP = ip
return "10.0.0.1", nil
}
sp := &mockSessionProvider{docker: docker}
var scheduledSession *types.Session
tasks := &mockTasks{}
@@ -44,7 +45,7 @@ func TestSessionNew(t *testing.T) {
return nil
}
p := NewPWD(docker, tasks, ev, storage)
p := NewPWD(sp, tasks, ev, storage)
before := time.Now()
@@ -166,11 +167,12 @@ func TestSessionSetup(t *testing.T) {
assert.Fail(t, "Shouldn't have reached here.")
return nil, nil
}
sp := &mockSessionProvider{docker: dock}
tasks := &mockTasks{}
ev := event.NewLocalBroker()
storage := &mockStorage{}
p := NewPWD(dock, tasks, ev, storage)
p := NewPWD(sp, tasks, ev, storage)
s, e := p.SessionNew(time.Hour, "", "", "")
assert.Nil(t, e)
@@ -215,6 +217,7 @@ func TestSessionSetup(t *testing.T) {
IsDockerHost: true,
Session: s,
Docker: manager1Received.Docker,
Proxy: manager1Received.Proxy,
}, manager1Received)
manager2 := fmt.Sprintf("%s_manager2", s.Id[:8])
@@ -229,6 +232,7 @@ func TestSessionSetup(t *testing.T) {
SessionId: s.Id,
Session: s,
Docker: manager2Received.Docker,
Proxy: manager2Received.Proxy,
}, manager2Received)
manager3 := fmt.Sprintf("%s_manager3", s.Id[:8])
@@ -243,6 +247,7 @@ func TestSessionSetup(t *testing.T) {
IsDockerHost: true,
Session: s,
Docker: manager3Received.Docker,
Proxy: manager3Received.Proxy,
}, manager3Received)
worker1 := fmt.Sprintf("%s_worker1", s.Id[:8])
@@ -257,6 +262,7 @@ func TestSessionSetup(t *testing.T) {
IsDockerHost: true,
Session: s,
Docker: worker1Received.Docker,
Proxy: worker1Received.Proxy,
}, worker1Received)
other := fmt.Sprintf("%s_other", s.Id[:8])
@@ -271,6 +277,7 @@ func TestSessionSetup(t *testing.T) {
IsDockerHost: true,
Session: s,
Docker: otherReceived.Docker,
Proxy: otherReceived.Proxy,
}, otherReceived)
assert.True(t, swarmInitOnMaster1)
@@ -284,8 +291,9 @@ func TestSessionPrepareOnce(t *testing.T) {
tasks := &mockTasks{}
ev := event.NewLocalBroker()
storage := &mockStorage{}
sp := &mockSessionProvider{docker: dock}
p := NewPWD(dock, tasks, ev, storage)
p := NewPWD(sp, tasks, ev, storage)
session := &types.Session{Id: "1234"}
prepared, err := p.prepareSession(session)
assert.True(t, preparedSessions[session.Id])

View File

@@ -16,6 +16,7 @@ import (
"github.com/docker/go-connections/tlsconfig"
"github.com/play-with-docker/play-with-docker/docker"
"github.com/play-with-docker/play-with-docker/event"
"github.com/play-with-docker/play-with-docker/provider"
"github.com/play-with-docker/play-with-docker/pwd/types"
)
@@ -112,8 +113,8 @@ func (sch *scheduler) Schedule(s *types.Session) {
func (sch *scheduler) Unschedule(s *types.Session) {
}
func NewScheduler(e event.EventApi, d docker.DockerApi) *scheduler {
func NewScheduler(e event.EventApi, sp provider.SessionProvider) *scheduler {
s := &scheduler{event: e}
s.periodicTasks = []periodicTask{&collectStatsTask{docker: d}, &checkSwarmStatusTask{}, &checkUsedPortsTask{}, &checkSwarmUsedPortsTask{}}
s.periodicTasks = []periodicTask{&collectStatsTask{sessionProvider: sp}, &checkSwarmStatusTask{}, &checkUsedPortsTask{}, &checkSwarmUsedPortsTask{}}
return s
}

View File

@@ -30,6 +30,7 @@ type Instance struct {
IsDockerHost bool `json:"is_docker_host" bson:"is_docker_host"`
SessionId string `json:"session_id" bson:"session_id"`
SessionPrefix string `json:"session_prefix" bson:"session_prefix"`
Proxy string `json:"proxy" bson:"proxy"`
Docker docker.DockerApi `json:"-"`
Session *Session `json:"-" bson:"-"`
ctx context.Context `json:"-" bson:"-"`