mirror of https://github.com/docker/docs.git
commit
2606db4486
|
@ -105,7 +105,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/samalba/dockerclient",
|
||||
"Rev": "15ebe064ca62ad0d64834e7ef0d4ed8ce9d02cde"
|
||||
"Rev": "68832c185bb6304fed26a986891fd27b6ed17987"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
||||
|
|
|
@ -14,8 +14,25 @@ type AuthConfig struct {
|
|||
}
|
||||
|
||||
// encode the auth configuration struct into base64 for the X-Registry-Auth header
|
||||
func (c *AuthConfig) encode() string {
|
||||
func (c *AuthConfig) encode() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
json.NewEncoder(&buf).Encode(c)
|
||||
return base64.URLEncoding.EncodeToString(buf.Bytes())
|
||||
if err := json.NewEncoder(&buf).Encode(c); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
// ConfigFile holds parameters for authenticating during a BuildImage request
|
||||
type ConfigFile struct {
|
||||
Configs map[string]AuthConfig `json:"configs,omitempty"`
|
||||
rootPath string
|
||||
}
|
||||
|
||||
// encode the configuration struct into base64 for the X-Registry-Config header
|
||||
func (c *ConfigFile) encode() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(c); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(buf.Bytes()), nil
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
func TestAuthEncode(t *testing.T) {
|
||||
a := AuthConfig{Username: "foo", Password: "password", Email: "bar@baz.com"}
|
||||
expected := "eyJ1c2VybmFtZSI6ImZvbyIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJlbWFpbCI6ImJhckBiYXouY29tIn0K"
|
||||
got := a.encode()
|
||||
got, _ := a.encode()
|
||||
|
||||
if expected != got {
|
||||
t.Errorf("testAuthEncode failed. Expected [%s] got [%s]", expected, got)
|
||||
|
|
|
@ -235,21 +235,30 @@ func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*js
|
|||
resultChan := make(chan decodingResult)
|
||||
|
||||
go func() {
|
||||
decoder := json.NewDecoder(stream)
|
||||
stopped := make(chan struct{})
|
||||
decodeChan := make(chan decodingResult)
|
||||
|
||||
go func() {
|
||||
<-stopChan
|
||||
stream.Close()
|
||||
stopped <- struct{}{}
|
||||
decoder := json.NewDecoder(stream)
|
||||
for {
|
||||
decodeResult := decode(decoder)
|
||||
decodeChan <- decodeResult
|
||||
if decodeResult.err != nil {
|
||||
close(decodeChan)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
defer close(resultChan)
|
||||
|
||||
for {
|
||||
decodeResult := decode(decoder)
|
||||
select {
|
||||
case <-stopped:
|
||||
case <-stopChan:
|
||||
stream.Close()
|
||||
for range decodeChan {
|
||||
}
|
||||
return
|
||||
default:
|
||||
case decodeResult := <-decodeChan:
|
||||
resultChan <- decodeResult
|
||||
if decodeResult.err != nil {
|
||||
stream.Close()
|
||||
|
@ -257,6 +266,7 @@ func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*js
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
return resultChan
|
||||
|
@ -366,13 +376,17 @@ func (client *DockerClient) StartMonitorEvents(cb Callback, ec chan error, args
|
|||
go func() {
|
||||
eventErrChan, err := client.MonitorEvents(nil, client.eventStopChan)
|
||||
if err != nil {
|
||||
ec <- err
|
||||
if ec != nil {
|
||||
ec <- err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for e := range eventErrChan {
|
||||
if e.Error != nil {
|
||||
ec <- err
|
||||
if ec != nil {
|
||||
ec <- err
|
||||
}
|
||||
return
|
||||
}
|
||||
cb(&e.Event, ec, args...)
|
||||
|
@ -447,7 +461,11 @@ func (client *DockerClient) PullImage(name string, auth *AuthConfig) error {
|
|||
uri := fmt.Sprintf("/%s/images/create?%s", APIVersion, v.Encode())
|
||||
req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
|
||||
if auth != nil {
|
||||
req.Header.Add("X-Registry-Auth", auth.encode())
|
||||
encoded_auth, err := auth.encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("X-Registry-Auth", encoded_auth)
|
||||
}
|
||||
resp, err := client.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
|
@ -521,8 +539,12 @@ func (client *DockerClient) RemoveContainer(id string, force, volumes bool) erro
|
|||
return err
|
||||
}
|
||||
|
||||
func (client *DockerClient) ListImages() ([]*Image, error) {
|
||||
uri := fmt.Sprintf("/%s/images/json", APIVersion)
|
||||
func (client *DockerClient) ListImages(all bool) ([]*Image, error) {
|
||||
argAll := 0
|
||||
if all {
|
||||
argAll = 1
|
||||
}
|
||||
uri := fmt.Sprintf("/%s/images/json?all=%d", APIVersion, argAll)
|
||||
data, err := client.doRequest("GET", uri, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -615,3 +637,58 @@ func (client *DockerClient) ImportImage(source string, repository string, tag st
|
|||
}
|
||||
return client.doStreamRequest("POST", "/images/create?"+v.Encode(), in, nil)
|
||||
}
|
||||
|
||||
func (client *DockerClient) BuildImage(image *BuildImage) (io.ReadCloser, error) {
|
||||
v := url.Values{}
|
||||
|
||||
if image.DockerfileName != "" {
|
||||
v.Set("dockerfile", image.DockerfileName)
|
||||
}
|
||||
if image.RepoName != "" {
|
||||
v.Set("t", image.RepoName)
|
||||
}
|
||||
if image.RemoteURL != "" {
|
||||
v.Set("remote", image.RemoteURL)
|
||||
}
|
||||
if image.NoCache {
|
||||
v.Set("nocache", "1")
|
||||
}
|
||||
if image.Pull {
|
||||
v.Set("pull", "1")
|
||||
}
|
||||
if image.Remove {
|
||||
v.Set("rm", "1")
|
||||
} else {
|
||||
v.Set("rm", "0")
|
||||
}
|
||||
if image.ForceRemove {
|
||||
v.Set("forcerm", "1")
|
||||
}
|
||||
if image.SuppressOutput {
|
||||
v.Set("q", "1")
|
||||
}
|
||||
|
||||
v.Set("memory", strconv.FormatInt(image.Memory, 10))
|
||||
v.Set("memswap", strconv.FormatInt(image.MemorySwap, 10))
|
||||
v.Set("cpushares", strconv.FormatInt(image.CpuShares, 10))
|
||||
v.Set("cpuperiod", strconv.FormatInt(image.CpuPeriod, 10))
|
||||
v.Set("cpuquota", strconv.FormatInt(image.CpuQuota, 10))
|
||||
v.Set("cpusetcpus", image.CpuSetCpus)
|
||||
v.Set("cpusetmems", image.CpuSetMems)
|
||||
v.Set("cgroupparent", image.CgroupParent)
|
||||
|
||||
headers := make(map[string]string)
|
||||
if image.Config != nil {
|
||||
encoded_config, err := image.Config.encode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
headers["X-Registry-Config"] = encoded_config
|
||||
}
|
||||
if image.Context != nil {
|
||||
headers["Content-Type"] = "application/tar"
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("/%s/build?%s", APIVersion, v.Encode())
|
||||
return client.doStreamRequest("POST", uri, image.Context, headers)
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ func handleContainerLogs(w http.ResponseWriter, r *http.Request) {
|
|||
for ; i < 50; i++ {
|
||||
line := fmt.Sprintf("line %d", i)
|
||||
if getBoolValue(r.Form.Get("timestamps")) {
|
||||
l := &jsonlog.JSONLog{Log: line, Created: time.Now()}
|
||||
l := &jsonlog.JSONLog{Log: line, Created: time.Now().UTC()}
|
||||
line = fmt.Sprintf("%s %s", l.Created.Format(timeutils.RFC3339NanoFixed), line)
|
||||
}
|
||||
if i%2 == 0 && stderr {
|
||||
|
|
|
@ -35,10 +35,11 @@ type Client interface {
|
|||
PullImage(name string, auth *AuthConfig) error
|
||||
LoadImage(reader io.Reader) error
|
||||
RemoveContainer(id string, force, volumes bool) error
|
||||
ListImages() ([]*Image, error)
|
||||
ListImages(all bool) ([]*Image, error)
|
||||
RemoveImage(name string) ([]*ImageDelete, error)
|
||||
PauseContainer(name string) error
|
||||
UnpauseContainer(name string) error
|
||||
RenameContainer(oldName string, newName string) error
|
||||
ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error)
|
||||
BuildImage(image *BuildImage) (io.ReadCloser, error)
|
||||
}
|
||||
|
|
|
@ -116,8 +116,8 @@ func (client *MockClient) RemoveContainer(id string, force, volumes bool) error
|
|||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (client *MockClient) ListImages() ([]*dockerclient.Image, error) {
|
||||
args := client.Mock.Called()
|
||||
func (client *MockClient) ListImages(all bool) ([]*dockerclient.Image, error) {
|
||||
args := client.Mock.Called(all)
|
||||
return args.Get(0).([]*dockerclient.Image), args.Error(1)
|
||||
}
|
||||
|
||||
|
@ -150,3 +150,8 @@ func (client *MockClient) ImportImage(source string, repository string, tag stri
|
|||
args := client.Mock.Called(source, repository, tag, tar)
|
||||
return args.Get(0).(io.ReadCloser), args.Error(1)
|
||||
}
|
||||
|
||||
func (client *MockClient) BuildImage(image *dockerclient.BuildImage) (io.ReadCloser, error) {
|
||||
args := client.Mock.Called(image)
|
||||
return args.Get(0).(io.ReadCloser), args.Error(1)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dockerclient
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/units"
|
||||
|
@ -415,3 +416,24 @@ type LogConfig struct {
|
|||
Type string `json:"type"`
|
||||
Config map[string]string `json:"config"`
|
||||
}
|
||||
|
||||
type BuildImage struct {
|
||||
Config *ConfigFile
|
||||
DockerfileName string
|
||||
Context io.Reader
|
||||
RemoteURL string
|
||||
RepoName string
|
||||
SuppressOutput bool
|
||||
NoCache bool
|
||||
Remove bool
|
||||
ForceRemove bool
|
||||
Pull bool
|
||||
Memory int64
|
||||
MemorySwap int64
|
||||
CpuShares int64
|
||||
CpuPeriod int64
|
||||
CpuQuota int64
|
||||
CpuSetCpus string
|
||||
CpuSetMems string
|
||||
CgroupParent string
|
||||
}
|
||||
|
|
|
@ -620,31 +620,6 @@ func proxyRandom(c *context, w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
}
|
||||
|
||||
// Proxy a request to a random node and force refresh
|
||||
func proxyRandomAndForceRefresh(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
engine, err := c.cluster.RANDOMENGINE()
|
||||
if err != nil {
|
||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if engine == nil {
|
||||
httpError(w, "no node available in the cluster", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
cb := func(resp *http.Response) {
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
engine.RefreshImages()
|
||||
}
|
||||
}
|
||||
|
||||
if err := proxyAsync(c.tlsConfig, engine.Addr, w, r, cb); err != nil {
|
||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// POST /commit
|
||||
func postCommit(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
|
@ -678,6 +653,50 @@ func postCommit(c *context, w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// POST /build
|
||||
func postBuild(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
buildImage := &dockerclient.BuildImage{
|
||||
DockerfileName: r.Form.Get("dockerfile"),
|
||||
RepoName: r.Form.Get("t"),
|
||||
RemoteURL: r.Form.Get("remote"),
|
||||
NoCache: boolValue(r, "nocache"),
|
||||
Pull: boolValue(r, "pull"),
|
||||
Remove: boolValue(r, "rm"),
|
||||
ForceRemove: boolValue(r, "forcerm"),
|
||||
SuppressOutput: boolValue(r, "q"),
|
||||
Memory: int64ValueOrZero(r, "memory"),
|
||||
MemorySwap: int64ValueOrZero(r, "memswap"),
|
||||
CpuShares: int64ValueOrZero(r, "cpushares"),
|
||||
CpuPeriod: int64ValueOrZero(r, "cpuperiod"),
|
||||
CpuQuota: int64ValueOrZero(r, "cpuquota"),
|
||||
CpuSetCpus: r.Form.Get("cpusetcpus"),
|
||||
CpuSetMems: r.Form.Get("cpusetmems"),
|
||||
CgroupParent: r.Form.Get("cgroupparent"),
|
||||
Context: r.Body,
|
||||
}
|
||||
|
||||
authEncoded := r.Header.Get("X-Registry-Auth")
|
||||
if authEncoded != "" {
|
||||
buf, err := base64.URLEncoding.DecodeString(r.Header.Get("X-Registry-Auth"))
|
||||
if err == nil {
|
||||
json.Unmarshal(buf, &buildImage.Config)
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
wf := NewWriteFlusher(w)
|
||||
|
||||
err := c.cluster.BuildImage(buildImage, wf)
|
||||
if err != nil {
|
||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// POST /containers/{name:.*}/rename
|
||||
func postRenameContainer(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
_, container, err := getContainerFromVars(c, mux.Vars(r))
|
||||
|
|
|
@ -51,7 +51,7 @@ var routes = map[string]map[string]handler{
|
|||
"POST": {
|
||||
"/auth": proxyRandom,
|
||||
"/commit": postCommit,
|
||||
"/build": proxyRandomAndForceRefresh,
|
||||
"/build": postBuild,
|
||||
"/images/create": postImagesCreate,
|
||||
"/images/load": postImagesLoad,
|
||||
"/images/{name:.*}/push": proxyImageTagOptional,
|
||||
|
|
|
@ -163,3 +163,11 @@ func intValueOrZero(r *http.Request, k string) int {
|
|||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func int64ValueOrZero(r *http.Request, k string) int64 {
|
||||
val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
|
|
@ -53,3 +53,24 @@ func TestIntValueOrZero(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInti64ValueOrZero(t *testing.T) {
|
||||
cases := map[string]int64{
|
||||
"": 0,
|
||||
"asdf": 0,
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
}
|
||||
|
||||
for c, e := range cases {
|
||||
v := url.Values{}
|
||||
v.Set("test", c)
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a := int64ValueOrZero(r, "test")
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,4 +68,7 @@ type Cluster interface {
|
|||
|
||||
// RenameContainer rename a container
|
||||
RenameContainer(container *Container, newName string) error
|
||||
|
||||
// BuildImage build an image
|
||||
BuildImage(*dockerclient.BuildImage, io.Writer) error
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ func (e *Engine) RemoveImage(image *Image, name string) ([]*dockerclient.ImageDe
|
|||
|
||||
// RefreshImages refreshes the list of images on the engine.
|
||||
func (e *Engine) RefreshImages() error {
|
||||
images, err := e.client.ListImages()
|
||||
images, err := e.client.ListImages(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -614,3 +614,9 @@ func (e *Engine) RenameContainer(container *Container, newName string) error {
|
|||
// refresh container
|
||||
return e.refreshContainer(container.Id, true)
|
||||
}
|
||||
|
||||
// BuildImage build an image
|
||||
func (e *Engine) BuildImage(buildImage *dockerclient.BuildImage) (io.ReadCloser, error) {
|
||||
|
||||
return e.client.BuildImage(buildImage)
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ func TestEngineCpusMemory(t *testing.T) {
|
|||
client.On("Info").Return(mockInfo, nil)
|
||||
client.On("Version").Return(mockVersion, nil)
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil)
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil)
|
||||
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
|
||||
|
||||
assert.NoError(t, engine.ConnectWithClient(client))
|
||||
|
@ -85,7 +85,7 @@ func TestEngineSpecs(t *testing.T) {
|
|||
client.On("Info").Return(mockInfo, nil)
|
||||
client.On("Version").Return(mockVersion, nil)
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil)
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil)
|
||||
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
|
||||
|
||||
assert.NoError(t, engine.ConnectWithClient(client))
|
||||
|
@ -114,7 +114,7 @@ func TestEngineState(t *testing.T) {
|
|||
|
||||
// The client will return one container at first, then a second one will appear.
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{{Id: "one"}}, nil).Once()
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("InspectContainer", "one").Return(&dockerclient.ContainerInfo{Config: &dockerclient.ContainerConfig{CpuShares: 100}}, nil).Once()
|
||||
client.On("ListContainers", true, false, fmt.Sprintf("{%q:[%q]}", "id", "two")).Return([]dockerclient.Container{{Id: "two"}}, nil).Once()
|
||||
client.On("InspectContainer", "two").Return(&dockerclient.ContainerInfo{Config: &dockerclient.ContainerConfig{CpuShares: 100}}, nil).Once()
|
||||
|
@ -159,7 +159,7 @@ func TestCreateContainer(t *testing.T) {
|
|||
client.On("Version").Return(mockVersion, nil)
|
||||
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil).Once()
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil).Once()
|
||||
assert.NoError(t, engine.ConnectWithClient(client))
|
||||
assert.True(t, engine.isConnected())
|
||||
|
||||
|
@ -172,7 +172,7 @@ func TestCreateContainer(t *testing.T) {
|
|||
id := "id1"
|
||||
client.On("CreateContainer", &mockConfig, name).Return(id, nil).Once()
|
||||
client.On("ListContainers", true, false, fmt.Sprintf(`{"id":[%q]}`, id)).Return([]dockerclient.Container{{Id: id}}, nil).Once()
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: &config.ContainerConfig}, nil).Once()
|
||||
container, err := engine.Create(config, name, false)
|
||||
assert.Nil(t, err)
|
||||
|
@ -195,7 +195,7 @@ func TestCreateContainer(t *testing.T) {
|
|||
client.On("CreateContainer", &mockConfig, name).Return("", dockerclient.ErrNotFound).Once()
|
||||
client.On("CreateContainer", &mockConfig, name).Return(id, nil).Once()
|
||||
client.On("ListContainers", true, false, fmt.Sprintf(`{"id":[%q]}`, id)).Return([]dockerclient.Container{{Id: id}}, nil).Once()
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: &config.ContainerConfig}, nil).Once()
|
||||
container, err = engine.Create(config, name, true)
|
||||
assert.Nil(t, err)
|
||||
|
@ -241,7 +241,7 @@ func TestUsedCpus(t *testing.T) {
|
|||
client.On("Info").Return(mockInfo, nil)
|
||||
client.On("Version").Return(mockVersion, nil)
|
||||
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil).Once()
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{{Id: "test"}}, nil).Once()
|
||||
client.On("InspectContainer", "test").Return(&dockerclient.ContainerInfo{Config: &dockerclient.ContainerConfig{CpuShares: cpuShares}}, nil).Once()
|
||||
engine.ConnectWithClient(client)
|
||||
|
@ -268,7 +268,7 @@ func TestContainerRemovedDuringRefresh(t *testing.T) {
|
|||
|
||||
client.On("Info").Return(mockInfo, nil)
|
||||
client.On("Version").Return(mockVersion, nil)
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil)
|
||||
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{container1, container2}, nil)
|
||||
client.On("InspectContainer", "c1").Return(info1, errors.New("Not found"))
|
||||
|
|
|
@ -510,3 +510,31 @@ func (c *Cluster) RANDOMENGINE() (*cluster.Engine, error) {
|
|||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// BuildImage build an image
|
||||
func (c *Cluster) BuildImage(buildImage *dockerclient.BuildImage, out io.Writer) error {
|
||||
c.scheduler.Lock()
|
||||
|
||||
// get an engine
|
||||
config := &cluster.ContainerConfig{dockerclient.ContainerConfig{
|
||||
CpuShares: buildImage.CpuShares,
|
||||
Memory: buildImage.Memory,
|
||||
}}
|
||||
n, err := c.scheduler.SelectNodeForContainer(c.listNodes(), config)
|
||||
c.scheduler.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader, err := c.slaves[n.ID].engine.BuildImage(buildImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(out, reader); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.slaves[n.ID].engine.RefreshImages()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -598,3 +598,31 @@ func (c *Cluster) RenameContainer(container *cluster.Container, newName string)
|
|||
st.Name = newName
|
||||
return c.store.Replace(container.Id, st)
|
||||
}
|
||||
|
||||
// BuildImage build an image
|
||||
func (c *Cluster) BuildImage(buildImage *dockerclient.BuildImage, out io.Writer) error {
|
||||
c.scheduler.Lock()
|
||||
|
||||
// get an engine
|
||||
config := &cluster.ContainerConfig{dockerclient.ContainerConfig{
|
||||
CpuShares: buildImage.CpuShares,
|
||||
Memory: buildImage.Memory,
|
||||
}}
|
||||
n, err := c.scheduler.SelectNodeForContainer(c.listNodes(), config)
|
||||
c.scheduler.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader, err := c.engines[n.ID].BuildImage(buildImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(out, reader); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.engines[n.ID].RefreshImages()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ func TestImportImage(t *testing.T) {
|
|||
client.On("Version").Return(mockVersion, nil)
|
||||
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil).Once()
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil)
|
||||
|
||||
// connect client
|
||||
engine.ConnectWithClient(client)
|
||||
|
@ -175,7 +175,7 @@ func TestLoadImage(t *testing.T) {
|
|||
client.On("Version").Return(mockVersion, nil)
|
||||
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
|
||||
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil).Once()
|
||||
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
|
||||
client.On("ListImages", false).Return([]*dockerclient.Image{}, nil)
|
||||
|
||||
// connect client
|
||||
engine.ConnectWithClient(client)
|
||||
|
|
|
@ -7,4 +7,17 @@ function teardown() {
|
|||
stop_docker
|
||||
}
|
||||
|
||||
@test "docker build" {
|
||||
start_docker 2
|
||||
swarm_manage
|
||||
|
||||
run docker_swarm images -q
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${#lines[@]}" -eq 0 ]
|
||||
|
||||
docker_swarm build -t test $TESTDATA/build
|
||||
|
||||
run docker_swarm images -q
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${#lines[@]}" -eq 1 ]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue