Skip to content

Commit

Permalink
Make SessionSetup faster and support for command execution
Browse files Browse the repository at this point in the history
  • Loading branch information
xetorthio committed Sep 11, 2017
1 parent 8604478 commit fe299fe
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 120 deletions.
56 changes: 8 additions & 48 deletions docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
)

type DockerApi interface {
GetClient() *client.Client
CreateNetwork(id string, opts types.NetworkCreate) error
ConnectNetwork(container, network, ip string) (string, error)
NetworkInspect(id string) (types.NetworkResource, error)
Expand All @@ -49,7 +50,7 @@ type DockerApi interface {
DisconnectNetwork(containerId, networkId string) error
DeleteNetwork(id string) error
Exec(instanceName string, command []string) (int, error)
SwarmInit() (*SwarmTokens, error)
SwarmInit(advertiseAddr string) (*SwarmTokens, error)
SwarmJoin(addr, token string) error
ConfigCreate(name string, labels map[string]string, data []byte) error
ConfigDelete(name string) error
Expand All @@ -64,6 +65,10 @@ type docker struct {
c *client.Client
}

func (d *docker) GetClient() *client.Client {
return d.c
}

func (d *docker) ConfigCreate(name string, labels map[string]string, data []byte) error {
config := swarm.ConfigSpec{}
config.Name = name
Expand Down Expand Up @@ -467,53 +472,8 @@ func (d *docker) DeleteNetwork(id string) error {
return nil
}

/*
func (d *docker) New(ip string, cert, key []byte) (DockerApi, error) {
// We check if the client needs to use TLS
var tlsConfig *tls.Config
if len(cert) > 0 && len(key) > 0 {
tlsConfig = tlsconfig.ClientDefault()
tlsConfig.InsecureSkipVerify = true
tlsCert, err := tls.X509KeyPair(cert, key)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{tlsCert}
}
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 1 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext}
if tlsConfig != nil {
transport.TLSClientConfig = tlsConfig
}
cli := &http.Client{
Transport: transport,
}
c, err := client.NewClient(fmt.Sprintf("http://%s:2375", ip), api.DefaultVersion, cli, nil)
if err != nil {
return nil, fmt.Errorf("Could not connect to DinD docker daemon. %s", err)
}
// try to connect up to 5 times and then give up
for i := 0; i < 5; i++ {
_, err := c.Ping(context.Background())
if err != nil {
if client.IsErrConnectionFailed(err) {
// connection has failed, maybe instance is not ready yet, sleep and retry
log.Printf("Connection to [%s] has failed, maybe instance is not ready yet, sleeping and retrying in 1 second. Try #%d\n", fmt.Sprintf("http://%s:2375", ip), i+1)
time.Sleep(time.Second)
continue
}
return nil, err
}
}
return NewDocker(c), nil
}
*/
func (d *docker) SwarmInit() (*SwarmTokens, error) {
req := swarm.InitRequest{AdvertiseAddr: "eth0", ListenAddr: "0.0.0.0:2377"}
func (d *docker) SwarmInit(advertiseAddr string) (*SwarmTokens, error) {
req := swarm.InitRequest{AdvertiseAddr: advertiseAddr, ListenAddr: "0.0.0.0:2377"}
_, err := d.c.SwarmInit(context.Background(), req)

if err != nil {
Expand Down
12 changes: 10 additions & 2 deletions docker/local_cached_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ func (f *localCachedFactory) GetForSession(sessionId string) (DockerApi, error)
defer f.rw.Unlock()

if f.sessionClient != nil {
return f.sessionClient, nil
if err := f.check(f.sessionClient.GetClient()); err == nil {
return f.sessionClient, nil
} else {
f.sessionClient.GetClient().Close()
}
}

c, err := client.NewEnvClient()
Expand Down Expand Up @@ -69,7 +73,11 @@ func (f *localCachedFactory) GetForInstance(instance *types.Instance) (DockerApi
defer c.rw.Unlock()

if c.client != nil {
return c.client, nil
if err := f.check(c.client.GetClient()); err == nil {
return c.client, nil
} else {
c.client.GetClient().Close()
}
}

// Need to create client to the DinD docker daemon
Expand Down
10 changes: 8 additions & 2 deletions docker/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ import (
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/stretchr/testify/mock"
)

type Mock struct {
mock.Mock
}

func (m *Mock) GetClient() *client.Client {
args := m.Called()
return args.Get(0).(*client.Client)
}

func (m *Mock) CreateNetwork(id string, opts types.NetworkCreate) error {
args := m.Called(id, opts)
return args.Error(0)
Expand Down Expand Up @@ -96,8 +102,8 @@ func (m *Mock) Exec(instanceName string, command []string) (int, error) {
args := m.Called(instanceName, command)
return args.Int(0), args.Error(1)
}
func (m *Mock) SwarmInit() (*SwarmTokens, error) {
args := m.Called()
func (m *Mock) SwarmInit(advertiseAddr string) (*SwarmTokens, error) {
args := m.Called(advertiseAddr)
return args.Get(0).(*SwarmTokens), args.Error(1)
}
func (m *Mock) SwarmJoin(addr, token string) error {
Expand Down
8 changes: 8 additions & 0 deletions provisioner/dind.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ func (d *DinD) InstanceDelete(session *types.Session, instance *types.Instance)
return nil
}

func (d *DinD) InstanceExec(instance *types.Instance, cmd []string) (int, error) {
dockerClient, err := d.factory.GetForSession(instance.SessionId)
if err != nil {
return -1, err
}
return dockerClient.Exec(instance.Name, cmd)
}

func (d *DinD) InstanceResizeTerminal(instance *types.Instance, rows, cols uint) error {
dockerClient, err := d.factory.GetForSession(instance.SessionId)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions provisioner/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func OutOfCapacity(e error) bool {
type InstanceProvisionerApi interface {
InstanceNew(session *types.Session, conf types.InstanceConfig) (*types.Instance, error)
InstanceDelete(session *types.Session, instance *types.Instance) error
InstanceExec(instance *types.Instance, cmd []string) (int, error)

InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error
InstanceGetTerminal(instance *types.Instance) (net.Conn, error)
Expand Down
35 changes: 35 additions & 0 deletions provisioner/windows.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package provisioner

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -121,6 +123,39 @@ func (d *windows) InstanceDelete(session *types.Session, instance *types.Instanc
return d.releaseInstance(instance.WindowsId)
}

type execRes struct {
ExitCode int `json:"exit_code"`
Error string `json:"error"`
Stdout string `json:"stdout"`
Stderr string `json:"stderr"`
}

func (d *windows) InstanceExec(instance *types.Instance, cmd []string) (int, error) {
execBody := struct {
Cmd []string `json:"cmd"`
}{Cmd: cmd}

b, err := json.Marshal(execBody)
if err != nil {
return -1, err
}
resp, err := http.Post(fmt.Sprintf("http://%s:222/exec", instance.IP), "application/json", bytes.NewReader(b))
if err != nil {
log.Println(err)
return -1, err
}
if resp.StatusCode != 200 {
log.Printf("Error exec on instance %s. Got %d\n", instance.Name, resp.StatusCode)
return -1, fmt.Errorf("Error exec on instance %s. Got %d\n", instance.Name, resp.StatusCode)
}
var ex execRes
err = json.NewDecoder(resp.Body).Decode(&ex)
if err != nil {
return -1, err
}
return ex.ExitCode, nil
}

func (d *windows) releaseInstance(instanceId string) error {
return d.storage.WindowsInstanceDelete(instanceId)
}
Expand Down
8 changes: 6 additions & 2 deletions pwd/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,14 @@ func (p *pwd) InstanceNew(session *types.Session, conf types.InstanceConfig) (*t
func (p *pwd) InstanceExec(instance *types.Instance, cmd []string) (int, error) {
defer observeAction("InstanceExec", time.Now())

dockerClient, err := p.dockerFactory.GetForSession(instance.SessionId)
prov, err := p.getProvisioner(instance.Type)
if err != nil {
return -1, err
}
exitCode, err := prov.InstanceExec(instance, cmd)
if err != nil {
log.Println(err)
return -1, err
}
return dockerClient.Exec(instance.Name, cmd)
return exitCode, nil
}
Loading

0 comments on commit fe299fe

Please sign in to comment.