Bump fsouza/go-dockerclient godep

This commit is contained in:
derekwaynecarr
2015-08-03 16:48:13 -04:00
parent 8cd7431b3d
commit 6399d4c8c4
172 changed files with 9719 additions and 621 deletions

View File

@@ -1,42 +0,0 @@
#!/bin/bash
readonly GOPATH="${GOPATH%%:*}"
main() {
check_fmt
check_lint
}
check_fmt() {
eval "set -e"
for file in $(_list_go_files) ; do
gofmt $file | diff -u $file -
done
eval "set +e"
}
check_lint() {
_install_linter
for file in $(_list_go_files) ; do
if [[ ! "$(${GOPATH}/bin/golint $file)" =~ ^[[:blank:]]*$ ]] ; then
_lint_verbose && exit 1
fi
done
}
_lint_verbose() {
for file in $(_list_go_files) ; do $GOPATH/bin/golint $file ; done
}
_install_linter() {
if [[ ! -x "${GOPATH}/bin/golint" ]] ; then
go get -u -f github.com/golang/lint/golint
fi
}
_list_go_files() {
git ls-files '*.go' | grep -v '^vendor/'
}
main "$@"

View File

@@ -22,7 +22,8 @@ import (
"time"
"github.com/fsouza/go-dockerclient"
"github.com/fsouza/go-dockerclient/vendor/github.com/gorilla/mux"
"github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/stdcopy"
"github.com/fsouza/go-dockerclient/external/github.com/gorilla/mux"
)
var nameRegexp = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_.-]+$`)
@@ -48,6 +49,7 @@ type DockerServer struct {
failures map[string]string
multiFailures []map[string]string
execCallbacks map[string]func()
statsCallbacks map[string]func(string) docker.Stats
customHandlers map[string]http.Handler
handlerMutex sync.RWMutex
cChan chan<- *docker.Container
@@ -75,6 +77,7 @@ func NewServer(bind string, containerChan chan<- *docker.Container, hook func(*h
hook: hook,
failures: make(map[string]string),
execCallbacks: make(map[string]func()),
statsCallbacks: make(map[string]func(string) docker.Stats),
customHandlers: make(map[string]http.Handler),
cChan: containerChan,
}
@@ -106,6 +109,7 @@ func (s *DockerServer) buildMuxer() {
s.mux.Path("/containers/{id:.*}/attach").Methods("POST").HandlerFunc(s.handlerWrapper(s.attachContainer))
s.mux.Path("/containers/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeContainer))
s.mux.Path("/containers/{id:.*}/exec").Methods("POST").HandlerFunc(s.handlerWrapper(s.createExecContainer))
s.mux.Path("/containers/{id:.*}/stats").Methods("GET").HandlerFunc(s.handlerWrapper(s.statsContainer))
s.mux.Path("/exec/{id:.*}/resize").Methods("POST").HandlerFunc(s.handlerWrapper(s.resizeExecContainer))
s.mux.Path("/exec/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startExecContainer))
s.mux.Path("/exec/{id:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectExecContainer))
@@ -153,6 +157,15 @@ func (s *DockerServer) PrepareExec(id string, callback func()) {
s.execCallbacks[id] = callback
}
// PrepareStats adds a callback that will be called for each container stats
// call.
//
// This callback function will be called multiple times if stream is set to
// true when stats is called.
func (s *DockerServer) PrepareStats(id string, callback func(string) docker.Stats) {
s.statsCallbacks[id] = callback
}
// PrepareFailure adds a new expected failure based on a URL regexp it receives
// an id for the failure.
func (s *DockerServer) PrepareFailure(id string, urlRegexp string) {
@@ -271,10 +284,10 @@ func (s *DockerServer) handlerWrapper(f func(http.ResponseWriter, *http.Request)
func (s *DockerServer) listContainers(w http.ResponseWriter, r *http.Request) {
all := r.URL.Query().Get("all")
s.cMut.RLock()
result := make([]docker.APIContainers, len(s.containers))
for i, container := range s.containers {
result := make([]docker.APIContainers, 0, len(s.containers))
for _, container := range s.containers {
if all == "1" || container.State.Running {
result[i] = docker.APIContainers{
result = append(result, docker.APIContainers{
ID: container.ID,
Image: container.Image,
Command: fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " ")),
@@ -282,7 +295,7 @@ func (s *DockerServer) listContainers(w http.ResponseWriter, r *http.Request) {
Status: container.State.String(),
Ports: container.NetworkSettings.PortMappingAPI(),
Names: []string{fmt.Sprintf("/%s", container.Name)},
}
})
}
}
s.cMut.RUnlock()
@@ -334,7 +347,10 @@ func (s *DockerServer) findImageByID(id string) (string, int, error) {
}
func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
var config docker.Config
var config struct {
*docker.Config
HostConfig *docker.HostConfig
}
defer r.Body.Close()
err := json.NewDecoder(r.Body).Decode(&config)
if err != nil {
@@ -350,7 +366,6 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
w.WriteHeader(http.StatusCreated)
ports := map[docker.Port][]docker.PortBinding{}
for port := range config.ExposedPorts {
ports[port] = []docker.PortBinding{{
@@ -369,13 +384,16 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
args = config.Cmd[1:]
}
generatedID := s.generateID()
config.Config.Hostname = generatedID[:12]
container := docker.Container{
Name: name,
ID: s.generateID(),
Created: time.Now(),
Path: path,
Args: args,
Config: &config,
Name: name,
ID: generatedID,
Created: time.Now(),
Path: path,
Args: args,
Config: config.Config,
HostConfig: config.HostConfig,
State: docker.State{
Running: false,
Pid: mathrand.Int() % 50000,
@@ -392,8 +410,18 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
},
}
s.cMut.Lock()
if container.Name != "" {
for _, c := range s.containers {
if c.Name == container.Name {
defer s.cMut.Unlock()
http.Error(w, "there's already a container with this name", http.StatusConflict)
return
}
}
}
s.containers = append(s.containers, &container)
s.cMut.Unlock()
w.WriteHeader(http.StatusCreated)
s.notify(&container)
var c = struct{ ID string }{ID: container.ID}
json.NewEncoder(w).Encode(c)
@@ -434,6 +462,30 @@ func (s *DockerServer) inspectContainer(w http.ResponseWriter, r *http.Request)
json.NewEncoder(w).Encode(container)
}
func (s *DockerServer) statsContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
_, _, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
stream, _ := strconv.ParseBool(r.URL.Query().Get("stream"))
callback := s.statsCallbacks[id]
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
encoder := json.NewEncoder(w)
for {
var stats docker.Stats
if callback != nil {
stats = callback(id)
}
encoder.Encode(stats)
if !stream {
break
}
}
}
func (s *DockerServer) topContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
@@ -466,6 +518,14 @@ func (s *DockerServer) startContainer(w http.ResponseWriter, r *http.Request) {
}
s.cMut.Lock()
defer s.cMut.Unlock()
defer r.Body.Close()
var hostConfig docker.HostConfig
err = json.NewDecoder(r.Body).Decode(&hostConfig)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
container.HostConfig = &hostConfig
if container.State.Running {
http.Error(w, "Container already running", http.StatusBadRequest)
return
@@ -545,7 +605,7 @@ func (s *DockerServer) attachContainer(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
outStream := newStdWriter(conn, stdout)
outStream := stdcopy.NewStdWriter(conn, stdcopy.Stdout)
if container.State.Running {
fmt.Fprintf(outStream, "Container %q is running\n", container.ID)
} else {
@@ -636,11 +696,11 @@ func (s *DockerServer) commitContainer(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{"ID":%q}`, image.ID)
}
func (s *DockerServer) findContainer(id string) (*docker.Container, int, error) {
func (s *DockerServer) findContainer(idOrName string) (*docker.Container, int, error) {
s.cMut.RLock()
defer s.cMut.RUnlock()
for i, container := range s.containers {
if container.ID == id {
if container.ID == idOrName || container.Name == idOrName {
return container, i, nil
}
}
@@ -771,10 +831,9 @@ func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) {
func (s *DockerServer) inspectImage(w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"]
s.iMut.RLock()
defer s.iMut.RUnlock()
if id, ok := s.imgIDs[name]; ok {
s.iMut.Lock()
defer s.iMut.Unlock()
for _, img := range s.images {
if img.ID == id {
w.Header().Set("Content-Type", "application/json")

View File

@@ -5,6 +5,7 @@
package testing
import (
"bytes"
"encoding/json"
"fmt"
"math/rand"
@@ -14,6 +15,7 @@ import (
"os"
"reflect"
"strings"
"sync"
"testing"
"time"
@@ -180,7 +182,7 @@ func TestListRunningContainers(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if len(got) == 0 {
if len(got) != 0 {
t.Errorf("ListRunningContainers: Want 0. Got %d.", len(got))
}
}
@@ -190,8 +192,8 @@ func TestCreateContainer(t *testing.T) {
server.imgIDs = map[string]string{"base": "a1234"}
server.buildMuxer()
recorder := httptest.NewRecorder()
body := `{"Hostname":"", "User":"", "Memory":0, "MemorySwap":0, "AttachStdin":false, "AttachStdout":true, "AttachStderr":true,
"PortSpecs":null, "Tty":false, "OpenStdin":false, "StdinOnce":false, "Env":null, "Cmd":["date"], "Image":"base", "Volumes":{}, "VolumesFrom":""}`
body := `{"Hostname":"", "User":"ubuntu", "Memory":0, "MemorySwap":0, "AttachStdin":false, "AttachStdout":true, "AttachStderr":true,
"PortSpecs":null, "Tty":false, "OpenStdin":false, "StdinOnce":false, "Env":null, "Cmd":["date"], "Image":"base", "Volumes":{}, "VolumesFrom":"","HostConfig":{"Binds":["/var/run/docker.sock:/var/run/docker.sock:rw"]}}`
request, _ := http.NewRequest("POST", "/containers/create", strings.NewReader(body))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusCreated {
@@ -209,6 +211,16 @@ func TestCreateContainer(t *testing.T) {
if stored.State.Running {
t.Errorf("CreateContainer should not set container to running state.")
}
if stored.Config.User != "ubuntu" {
t.Errorf("CreateContainer: wrong config. Expected: %q. Returned: %q.", "ubuntu", stored.Config.User)
}
if stored.Config.Hostname != returned.ID[:12] {
t.Errorf("CreateContainer: wrong hostname. Expected: %q. Returned: %q.", returned.ID[:12], stored.Config.Hostname)
}
expectedBind := []string{"/var/run/docker.sock:/var/run/docker.sock:rw"}
if !reflect.DeepEqual(stored.HostConfig.Binds, expectedBind) {
t.Errorf("CreateContainer: wrong host config. Expected: %v. Returned %v.", expectedBind, stored.HostConfig.Binds)
}
}
func TestCreateContainerWithNotifyChannel(t *testing.T) {
@@ -241,6 +253,57 @@ func TestCreateContainerInvalidBody(t *testing.T) {
}
}
func TestCreateContainerDuplicateName(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
server.imgIDs = map[string]string{"base": "a1234"}
addContainers(&server, 1)
server.containers[0].Name = "mycontainer"
recorder := httptest.NewRecorder()
body := `{"Hostname":"", "User":"ubuntu", "Memory":0, "MemorySwap":0, "AttachStdin":false, "AttachStdout":true, "AttachStderr":true,
"PortSpecs":null, "Tty":false, "OpenStdin":false, "StdinOnce":false, "Env":null, "Cmd":["date"], "Image":"base", "Volumes":{}, "VolumesFrom":"","HostConfig":{"Binds":["/var/run/docker.sock:/var/run/docker.sock:rw"]}}`
request, _ := http.NewRequest("POST", "/containers/create?name=mycontainer", strings.NewReader(body))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusConflict {
t.Errorf("CreateContainer: wrong status. Want %d. Got %d.", http.StatusConflict, recorder.Code)
}
}
func TestCreateMultipleContainersEmptyName(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
server.imgIDs = map[string]string{"base": "a1234"}
addContainers(&server, 1)
server.containers[0].Name = ""
recorder := httptest.NewRecorder()
body := `{"Hostname":"", "User":"ubuntu", "Memory":0, "MemorySwap":0, "AttachStdin":false, "AttachStdout":true, "AttachStderr":true,
"PortSpecs":null, "Tty":false, "OpenStdin":false, "StdinOnce":false, "Env":null, "Cmd":["date"], "Image":"base", "Volumes":{}, "VolumesFrom":"","HostConfig":{"Binds":["/var/run/docker.sock:/var/run/docker.sock:rw"]}}`
request, _ := http.NewRequest("POST", "/containers/create", strings.NewReader(body))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusCreated {
t.Errorf("CreateContainer: wrong status. Want %d. Got %d.", http.StatusCreated, recorder.Code)
}
var returned docker.Container
err := json.NewDecoder(recorder.Body).Decode(&returned)
if err != nil {
t.Fatal(err)
}
stored := server.containers[1]
if returned.ID != stored.ID {
t.Errorf("CreateContainer: ID mismatch. Stored: %q. Returned: %q.", stored.ID, returned.ID)
}
if stored.State.Running {
t.Errorf("CreateContainer should not set container to running state.")
}
if stored.Config.User != "ubuntu" {
t.Errorf("CreateContainer: wrong config. Expected: %q. Returned: %q.", "ubuntu", stored.Config.User)
}
expectedBind := []string{"/var/run/docker.sock:/var/run/docker.sock:rw"}
if !reflect.DeepEqual(stored.HostConfig.Binds, expectedBind) {
t.Errorf("CreateContainer: wrong host config. Expected: %v. Returned %v.", expectedBind, stored.HostConfig.Binds)
}
}
func TestCreateContainerInvalidName(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
@@ -500,9 +563,15 @@ func TestStartContainer(t *testing.T) {
server := DockerServer{}
addContainers(&server, 1)
server.buildMuxer()
memory := int64(536870912)
hostConfig := docker.HostConfig{Memory: memory}
configBytes, err := json.Marshal(hostConfig)
if err != nil {
t.Fatal(err)
}
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/containers/%s/start", server.containers[0].ID)
request, _ := http.NewRequest("POST", path, nil)
request, _ := http.NewRequest("POST", path, bytes.NewBuffer(configBytes))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Errorf("StartContainer: wrong status code. Want %d. Got %d.", http.StatusOK, recorder.Code)
@@ -510,6 +579,9 @@ func TestStartContainer(t *testing.T) {
if !server.containers[0].State.Running {
t.Error("StartContainer: did not set the container to running state")
}
if gotMemory := server.containers[0].HostConfig.Memory; gotMemory != memory {
t.Errorf("StartContainer: wrong HostConfig. Wants %d of memory. Got %d", memory, gotMemory)
}
}
func TestStartContainerWithNotifyChannel(t *testing.T) {
@@ -521,7 +593,7 @@ func TestStartContainerWithNotifyChannel(t *testing.T) {
server.buildMuxer()
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/containers/%s/start", server.containers[1].ID)
request, _ := http.NewRequest("POST", path, nil)
request, _ := http.NewRequest("POST", path, bytes.NewBuffer([]byte("{}")))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Errorf("StartContainer: wrong status code. Want %d. Got %d.", http.StatusOK, recorder.Code)
@@ -536,7 +608,7 @@ func TestStartContainerNotFound(t *testing.T) {
server.buildMuxer()
recorder := httptest.NewRecorder()
path := "/containers/abc123/start"
request, _ := http.NewRequest("POST", path, nil)
request, _ := http.NewRequest("POST", path, bytes.NewBuffer([]byte("null")))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusNotFound {
t.Errorf("StartContainer: wrong status code. Want %d. Got %d.", http.StatusNotFound, recorder.Code)
@@ -550,7 +622,7 @@ func TestStartContainerAlreadyRunning(t *testing.T) {
server.buildMuxer()
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/containers/%s/start", server.containers[0].ID)
request, _ := http.NewRequest("POST", path, nil)
request, _ := http.NewRequest("POST", path, bytes.NewBuffer([]byte("null")))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusBadRequest {
t.Errorf("StartContainer: wrong status code. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
@@ -821,6 +893,22 @@ func TestRemoveContainer(t *testing.T) {
}
}
func TestRemoveContainerByName(t *testing.T) {
server := DockerServer{}
addContainers(&server, 1)
server.buildMuxer()
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/containers/%s", server.containers[0].Name)
request, _ := http.NewRequest("DELETE", path, nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusNoContent {
t.Errorf("RemoveContainer: wrong status. Want %d. Got %d.", http.StatusNoContent, recorder.Code)
}
if len(server.containers) > 0 {
t.Error("RemoveContainer: did not remove the container.")
}
}
func TestRemoveContainerNotFound(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
@@ -1507,3 +1595,87 @@ func waitExec(url, execID string, running bool, maxTry int) (*docker.ExecInspect
}
return exec, err
}
func TestStatsContainer(t *testing.T) {
server, err := NewServer("127.0.0.1:0", nil, nil)
if err != nil {
t.Fatal(err)
}
defer server.Stop()
addContainers(server, 2)
server.buildMuxer()
expected := docker.Stats{}
expected.CPUStats.CPUUsage.TotalUsage = 20
server.PrepareStats(server.containers[0].ID, func(id string) docker.Stats {
return expected
})
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/containers/%s/stats?stream=false", server.containers[0].ID)
request, _ := http.NewRequest("GET", path, nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Errorf("StatsContainer: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
}
body := recorder.Body.Bytes()
var got docker.Stats
err = json.Unmarshal(body, &got)
if err != nil {
t.Fatal(err)
}
got.Read = time.Time{}
if !reflect.DeepEqual(got, expected) {
t.Errorf("StatsContainer: wrong value. Want %#v. Got %#v.", expected, got)
}
}
type safeWriter struct {
sync.Mutex
*httptest.ResponseRecorder
}
func (w *safeWriter) Write(buf []byte) (int, error) {
w.Lock()
defer w.Unlock()
return w.ResponseRecorder.Write(buf)
}
func TestStatsContainerStream(t *testing.T) {
server, err := NewServer("127.0.0.1:0", nil, nil)
if err != nil {
t.Fatal(err)
}
defer server.Stop()
addContainers(server, 2)
server.buildMuxer()
expected := docker.Stats{}
expected.CPUStats.CPUUsage.TotalUsage = 20
server.PrepareStats(server.containers[0].ID, func(id string) docker.Stats {
time.Sleep(50 * time.Millisecond)
return expected
})
recorder := &safeWriter{
ResponseRecorder: httptest.NewRecorder(),
}
path := fmt.Sprintf("/containers/%s/stats?stream=true", server.containers[0].ID)
request, _ := http.NewRequest("GET", path, nil)
go func() {
server.ServeHTTP(recorder, request)
}()
time.Sleep(200 * time.Millisecond)
recorder.Lock()
defer recorder.Unlock()
body := recorder.Body.Bytes()
parts := bytes.Split(body, []byte("\n"))
if len(parts) < 2 {
t.Errorf("StatsContainer: wrong number of parts. Want at least 2. Got %#v.", len(parts))
}
var got docker.Stats
err = json.Unmarshal(parts[0], &got)
if err != nil {
t.Fatal(err)
}
got.Read = time.Time{}
if !reflect.DeepEqual(got, expected) {
t.Errorf("StatsContainer: wrong value. Want %#v. Got %#v.", expected, got)
}
}

View File

@@ -1,43 +0,0 @@
// Copyright 2014 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package testing
import (
"encoding/binary"
"errors"
"io"
)
type stdType [8]byte
var (
stdin = stdType{0: 0}
stdout = stdType{0: 1}
stderr = stdType{0: 2}
)
type stdWriter struct {
io.Writer
prefix stdType
sizeBuf []byte
}
func (w *stdWriter) Write(buf []byte) (n int, err error) {
if w == nil || w.Writer == nil {
return 0, errors.New("Writer not instanciated")
}
binary.BigEndian.PutUint32(w.prefix[4:], uint32(len(buf)))
buf = append(w.prefix[:], buf...)
n, err = w.Writer.Write(buf)
return n - 8, err
}
func newStdWriter(w io.Writer, t stdType) *stdWriter {
if len(t) != 8 {
return nil
}
return &stdWriter{Writer: w, prefix: t, sizeBuf: make([]byte, 4)}
}