2014-06-24 01:28:06 +00:00
|
|
|
/*
|
2015-05-01 16:19:44 +00:00
|
|
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
2014-06-24 01:28:06 +00:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
package dockertools
|
2014-06-24 01:28:06 +00:00
|
|
|
|
|
|
|
import (
|
2015-05-08 17:30:59 +00:00
|
|
|
"encoding/json"
|
2014-06-19 12:29:42 +00:00
|
|
|
"fmt"
|
2015-10-05 15:45:36 +00:00
|
|
|
"math/rand"
|
2015-04-09 21:31:44 +00:00
|
|
|
"os"
|
2014-09-09 04:33:17 +00:00
|
|
|
"reflect"
|
2015-03-26 22:06:27 +00:00
|
|
|
"sort"
|
2014-07-23 16:53:31 +00:00
|
|
|
"sync"
|
2015-09-14 23:18:21 +00:00
|
|
|
"time"
|
2014-06-19 12:29:42 +00:00
|
|
|
|
2015-06-04 21:36:59 +00:00
|
|
|
docker "github.com/fsouza/go-dockerclient"
|
2015-05-08 17:30:59 +00:00
|
|
|
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api"
|
2015-09-09 17:45:01 +00:00
|
|
|
"k8s.io/kubernetes/pkg/util/sets"
|
2014-06-24 01:28:06 +00:00
|
|
|
)
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// FakeDockerClient is a simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup.
|
2015-09-14 23:18:21 +00:00
|
|
|
// TODO: create a proper constructor for FakeDockerClient, so we won't need to check if ContainerMap is not nil.
|
2014-06-24 01:28:06 +00:00
|
|
|
type FakeDockerClient struct {
|
2014-09-09 04:33:17 +00:00
|
|
|
sync.Mutex
|
2015-04-08 02:03:43 +00:00
|
|
|
ContainerList []docker.APIContainers
|
|
|
|
ExitedContainerList []docker.APIContainers
|
|
|
|
Container *docker.Container
|
|
|
|
ContainerMap map[string]*docker.Container
|
|
|
|
Image *docker.Image
|
|
|
|
Images []docker.APIImages
|
2015-04-09 18:57:53 +00:00
|
|
|
Errors map[string]error
|
2015-04-08 02:03:43 +00:00
|
|
|
called []string
|
|
|
|
Stopped []string
|
|
|
|
pulled []string
|
|
|
|
Created []string
|
|
|
|
Removed []string
|
2015-09-09 17:45:01 +00:00
|
|
|
RemovedImages sets.String
|
2015-04-08 02:03:43 +00:00
|
|
|
VersionInfo docker.Env
|
2015-04-21 00:26:40 +00:00
|
|
|
Information docker.Env
|
2015-05-08 16:48:31 +00:00
|
|
|
ExecInspect *docker.ExecInspect
|
2015-05-06 03:50:45 +00:00
|
|
|
execCmd []string
|
2015-10-05 15:45:36 +00:00
|
|
|
EnableSleep bool
|
2014-06-24 01:28:06 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 05:11:27 +00:00
|
|
|
func (f *FakeDockerClient) ClearCalls() {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-06-24 01:28:06 +00:00
|
|
|
f.called = []string{}
|
2014-12-17 05:11:27 +00:00
|
|
|
f.Stopped = []string{}
|
|
|
|
f.pulled = []string{}
|
|
|
|
f.Created = []string{}
|
|
|
|
f.Removed = []string{}
|
2014-06-24 01:28:06 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
func (f *FakeDockerClient) AssertCalls(calls []string) (err error) {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(calls, f.called) {
|
|
|
|
err = fmt.Errorf("expected %#v, got %#v", calls, f.called)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-04-08 02:03:43 +00:00
|
|
|
func (f *FakeDockerClient) AssertCreated(created []string) error {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
|
|
|
|
actualCreated := []string{}
|
|
|
|
for _, c := range f.Created {
|
|
|
|
dockerName, _, err := ParseDockerName(c)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
actualCreated = append(actualCreated, dockerName.ContainerName)
|
|
|
|
}
|
|
|
|
sort.StringSlice(created).Sort()
|
|
|
|
sort.StringSlice(actualCreated).Sort()
|
|
|
|
if !reflect.DeepEqual(created, actualCreated) {
|
|
|
|
return fmt.Errorf("expected %#v, got %#v", created, actualCreated)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FakeDockerClient) AssertStopped(stopped []string) error {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
sort.StringSlice(stopped).Sort()
|
|
|
|
sort.StringSlice(f.Stopped).Sort()
|
|
|
|
if !reflect.DeepEqual(stopped, f.Stopped) {
|
|
|
|
return fmt.Errorf("expected %#v, got %#v", stopped, f.Stopped)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-03-26 22:06:27 +00:00
|
|
|
func (f *FakeDockerClient) AssertUnorderedCalls(calls []string) (err error) {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
|
2015-04-06 16:29:51 +00:00
|
|
|
expected := make([]string, len(calls))
|
|
|
|
actual := make([]string, len(f.called))
|
|
|
|
copy(expected, calls)
|
|
|
|
copy(actual, f.called)
|
2015-03-26 22:06:27 +00:00
|
|
|
|
2015-04-07 21:25:10 +00:00
|
|
|
sort.StringSlice(expected).Sort()
|
2015-04-06 16:29:51 +00:00
|
|
|
sort.StringSlice(actual).Sort()
|
2015-03-26 22:06:27 +00:00
|
|
|
|
|
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
|
|
err = fmt.Errorf("expected(sorted) %#v, got(sorted) %#v", expected, actual)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-04-09 18:57:53 +00:00
|
|
|
func (f *FakeDockerClient) popError(op string) error {
|
|
|
|
if f.Errors == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
err, ok := f.Errors[op]
|
|
|
|
if ok {
|
|
|
|
delete(f.Errors, op)
|
|
|
|
return err
|
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// ListContainers is a test-spy implementation of DockerInterface.ListContainers.
|
|
|
|
// It adds an entry "list" to the internal method call record.
|
2014-06-24 01:28:06 +00:00
|
|
|
func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-07-23 16:53:31 +00:00
|
|
|
f.called = append(f.called, "list")
|
2015-04-09 18:57:53 +00:00
|
|
|
err := f.popError("list")
|
2015-04-08 02:03:43 +00:00
|
|
|
if options.All {
|
2015-04-09 18:57:53 +00:00
|
|
|
return append(f.ContainerList, f.ExitedContainerList...), err
|
2015-04-08 02:03:43 +00:00
|
|
|
}
|
2015-04-16 17:51:33 +00:00
|
|
|
return append([]docker.APIContainers{}, f.ContainerList...), err
|
2014-06-24 01:28:06 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// InspectContainer is a test-spy implementation of DockerInterface.InspectContainer.
|
|
|
|
// It adds an entry "inspect" to the internal method call record.
|
2014-06-24 01:28:06 +00:00
|
|
|
func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-10-03 07:34:18 +00:00
|
|
|
f.called = append(f.called, "inspect_container")
|
2015-04-09 18:57:53 +00:00
|
|
|
err := f.popError("inspect_container")
|
2014-10-28 00:29:55 +00:00
|
|
|
if f.ContainerMap != nil {
|
|
|
|
if container, ok := f.ContainerMap[id]; ok {
|
2015-04-09 18:57:53 +00:00
|
|
|
return container, err
|
2014-10-28 00:29:55 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-09 18:57:53 +00:00
|
|
|
return f.Container, err
|
2014-06-24 01:28:06 +00:00
|
|
|
}
|
|
|
|
|
2014-10-03 07:34:18 +00:00
|
|
|
// InspectImage is a test-spy implementation of DockerInterface.InspectImage.
|
|
|
|
// It adds an entry "inspect" to the internal method call record.
|
|
|
|
func (f *FakeDockerClient) InspectImage(name string) (*docker.Image, error) {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
f.called = append(f.called, "inspect_image")
|
2015-04-09 18:57:53 +00:00
|
|
|
err := f.popError("inspect_image")
|
|
|
|
return f.Image, err
|
2014-10-03 07:34:18 +00:00
|
|
|
}
|
|
|
|
|
2015-10-05 15:45:36 +00:00
|
|
|
// Sleeps random amount of time with the normal distribution with given mean and stddev
|
|
|
|
// (in milliseconds), we never sleep less than cutOffMillis
|
|
|
|
func (f *FakeDockerClient) normalSleep(mean, stdDev, cutOffMillis int) {
|
|
|
|
if !f.EnableSleep {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cutoff := (time.Duration)(cutOffMillis) * time.Millisecond
|
|
|
|
delay := (time.Duration)(rand.NormFloat64()*float64(stdDev)+float64(mean)) * time.Millisecond
|
|
|
|
if delay < cutoff {
|
|
|
|
delay = cutoff
|
|
|
|
}
|
|
|
|
time.Sleep(delay)
|
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// CreateContainer is a test-spy implementation of DockerInterface.CreateContainer.
|
|
|
|
// It adds an entry "create" to the internal method call record.
|
2014-06-24 01:28:06 +00:00
|
|
|
func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-07-23 16:53:31 +00:00
|
|
|
f.called = append(f.called, "create")
|
2015-10-05 15:45:36 +00:00
|
|
|
if err := f.popError("create"); err != nil {
|
|
|
|
return nil, err
|
2015-04-09 18:57:53 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
f.Created = append(f.Created, c.Name)
|
|
|
|
// This is not a very good fake. We'll just add this container's name to the list.
|
|
|
|
// Docker likes to add a '/', so copy that behavior.
|
|
|
|
name := "/" + c.Name
|
|
|
|
f.ContainerList = append(f.ContainerList, docker.APIContainers{ID: name, Names: []string{name}, Image: c.Config.Image})
|
|
|
|
container := docker.Container{ID: name, Name: name, Config: c.Config}
|
|
|
|
if f.ContainerMap != nil {
|
|
|
|
containerCopy := container
|
|
|
|
f.ContainerMap[name] = &containerCopy
|
|
|
|
}
|
|
|
|
f.normalSleep(200, 50, 50)
|
|
|
|
return &container, nil
|
2014-06-24 01:28:06 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// StartContainer is a test-spy implementation of DockerInterface.StartContainer.
|
|
|
|
// It adds an entry "start" to the internal method call record.
|
2014-06-24 01:28:06 +00:00
|
|
|
func (f *FakeDockerClient) StartContainer(id string, hostConfig *docker.HostConfig) error {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-07-23 16:53:31 +00:00
|
|
|
f.called = append(f.called, "start")
|
2015-10-05 15:45:36 +00:00
|
|
|
if err := f.popError("start"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
f.Container = &docker.Container{
|
|
|
|
ID: id,
|
|
|
|
Name: id, // For testing purpose, we set name to id
|
|
|
|
Config: &docker.Config{Image: "testimage"},
|
|
|
|
HostConfig: hostConfig,
|
|
|
|
State: docker.State{
|
|
|
|
Running: true,
|
|
|
|
Pid: os.Getpid(),
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
},
|
|
|
|
NetworkSettings: &docker.NetworkSettings{IPAddress: "1.2.3.4"},
|
|
|
|
}
|
|
|
|
if f.ContainerMap != nil {
|
|
|
|
container, ok := f.ContainerMap[id]
|
|
|
|
if !ok {
|
|
|
|
container = &docker.Container{ID: id, Name: id}
|
2015-04-09 18:57:53 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
container.HostConfig = hostConfig
|
|
|
|
container.State = docker.State{
|
|
|
|
Running: true,
|
|
|
|
Pid: os.Getpid(),
|
|
|
|
StartedAt: time.Now(),
|
2015-09-14 23:18:21 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
container.NetworkSettings = &docker.NetworkSettings{IPAddress: "2.3.4.5"}
|
|
|
|
f.ContainerMap[id] = container
|
2014-11-07 06:41:16 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
f.normalSleep(200, 50, 50)
|
|
|
|
return nil
|
2014-06-24 01:28:06 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// StopContainer is a test-spy implementation of DockerInterface.StopContainer.
|
|
|
|
// It adds an entry "stop" to the internal method call record.
|
2014-06-24 01:28:06 +00:00
|
|
|
func (f *FakeDockerClient) StopContainer(id string, timeout uint) error {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-07-23 16:53:31 +00:00
|
|
|
f.called = append(f.called, "stop")
|
2015-10-05 15:45:36 +00:00
|
|
|
if err := f.popError("stop"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
f.Stopped = append(f.Stopped, id)
|
|
|
|
var newList []docker.APIContainers
|
|
|
|
for _, container := range f.ContainerList {
|
|
|
|
if container.ID == id {
|
|
|
|
f.ExitedContainerList = append(f.ExitedContainerList, container)
|
|
|
|
continue
|
2014-07-03 05:35:50 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
newList = append(newList, container)
|
|
|
|
}
|
|
|
|
f.ContainerList = newList
|
|
|
|
if f.ContainerMap != nil {
|
|
|
|
container, ok := f.ContainerMap[id]
|
|
|
|
if !ok {
|
|
|
|
container = &docker.Container{
|
|
|
|
ID: id,
|
|
|
|
Name: id,
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
StartedAt: time.Now().Add(-time.Second),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
},
|
2015-09-14 23:18:21 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
} else {
|
|
|
|
container.State.FinishedAt = time.Now()
|
|
|
|
container.State.Running = false
|
2015-09-14 23:18:21 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
f.ContainerMap[id] = container
|
2014-07-03 05:35:50 +00:00
|
|
|
}
|
2015-10-05 15:45:36 +00:00
|
|
|
f.normalSleep(200, 50, 50)
|
|
|
|
return nil
|
2014-06-24 01:28:06 +00:00
|
|
|
}
|
2014-06-24 23:31:33 +00:00
|
|
|
|
2014-10-28 00:29:55 +00:00
|
|
|
func (f *FakeDockerClient) RemoveContainer(opts docker.RemoveContainerOptions) error {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
f.called = append(f.called, "remove")
|
2015-04-09 18:57:53 +00:00
|
|
|
err := f.popError("remove")
|
|
|
|
if err == nil {
|
|
|
|
f.Removed = append(f.Removed, opts.ID)
|
|
|
|
}
|
2015-09-14 23:18:21 +00:00
|
|
|
if f.ContainerMap != nil {
|
|
|
|
delete(f.ContainerMap, opts.ID)
|
|
|
|
}
|
2015-04-09 18:57:53 +00:00
|
|
|
return err
|
2014-10-28 00:29:55 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 19:41:32 +00:00
|
|
|
// Logs is a test-spy implementation of DockerInterface.Logs.
|
|
|
|
// It adds an entry "logs" to the internal method call record.
|
|
|
|
func (f *FakeDockerClient) Logs(opts docker.LogsOptions) error {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
f.called = append(f.called, "logs")
|
2015-04-09 18:57:53 +00:00
|
|
|
return f.popError("logs")
|
2014-08-27 19:41:32 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// PullImage is a test-spy implementation of DockerInterface.StopContainer.
|
|
|
|
// It adds an entry "pull" to the internal method call record.
|
2014-06-19 12:29:42 +00:00
|
|
|
func (f *FakeDockerClient) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-07-23 16:53:31 +00:00
|
|
|
f.called = append(f.called, "pull")
|
2015-04-09 18:57:53 +00:00
|
|
|
err := f.popError("pull")
|
|
|
|
if err == nil {
|
|
|
|
registry := opts.Registry
|
|
|
|
if len(registry) != 0 {
|
|
|
|
registry = registry + "/"
|
|
|
|
}
|
2015-05-08 17:30:59 +00:00
|
|
|
authJson, _ := json.Marshal(auth)
|
|
|
|
f.pulled = append(f.pulled, fmt.Sprintf("%s%s:%s using %s", registry, opts.Repository, opts.Tag, string(authJson)))
|
2015-03-17 00:51:20 +00:00
|
|
|
}
|
2015-04-09 18:57:53 +00:00
|
|
|
return err
|
2014-06-19 12:29:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-14 10:08:48 +00:00
|
|
|
func (f *FakeDockerClient) Version() (*docker.Env, error) {
|
|
|
|
return &f.VersionInfo, nil
|
|
|
|
}
|
|
|
|
|
2015-04-21 00:26:40 +00:00
|
|
|
func (f *FakeDockerClient) Info() (*docker.Env, error) {
|
|
|
|
return &f.Information, nil
|
|
|
|
}
|
|
|
|
|
2015-05-06 03:50:45 +00:00
|
|
|
func (f *FakeDockerClient) CreateExec(opts docker.CreateExecOptions) (*docker.Exec, error) {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
f.execCmd = opts.Cmd
|
|
|
|
f.called = append(f.called, "create_exec")
|
2015-08-08 01:52:23 +00:00
|
|
|
return &docker.Exec{ID: "12345678"}, nil
|
2014-10-14 10:08:48 +00:00
|
|
|
}
|
2014-12-22 19:54:07 +00:00
|
|
|
|
2014-10-14 10:08:48 +00:00
|
|
|
func (f *FakeDockerClient) StartExec(_ string, _ docker.StartExecOptions) error {
|
2015-05-06 03:50:45 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
f.called = append(f.called, "start_exec")
|
2014-10-14 10:08:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-07-28 04:48:55 +00:00
|
|
|
func (f *FakeDockerClient) AttachToContainer(opts docker.AttachToContainerOptions) error {
|
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
f.called = append(f.called, "attach")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-05-08 16:48:31 +00:00
|
|
|
func (f *FakeDockerClient) InspectExec(id string) (*docker.ExecInspect, error) {
|
|
|
|
return f.ExecInspect, f.popError("inspect_exec")
|
|
|
|
}
|
|
|
|
|
2014-12-22 19:54:07 +00:00
|
|
|
func (f *FakeDockerClient) ListImages(opts docker.ListImagesOptions) ([]docker.APIImages, error) {
|
2015-04-09 18:57:53 +00:00
|
|
|
err := f.popError("list_images")
|
|
|
|
return f.Images, err
|
2014-12-22 19:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FakeDockerClient) RemoveImage(image string) error {
|
2015-04-09 18:57:53 +00:00
|
|
|
err := f.popError("remove_image")
|
|
|
|
if err == nil {
|
|
|
|
f.RemovedImages.Insert(image)
|
|
|
|
}
|
|
|
|
return err
|
2014-12-22 19:54:07 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// FakeDockerPuller is a stub implementation of DockerPuller.
|
2014-06-24 23:31:33 +00:00
|
|
|
type FakeDockerPuller struct {
|
2014-09-09 04:33:17 +00:00
|
|
|
sync.Mutex
|
|
|
|
|
2014-10-02 18:58:58 +00:00
|
|
|
HasImages []string
|
2014-06-24 23:31:33 +00:00
|
|
|
ImagesPulled []string
|
|
|
|
|
|
|
|
// Every pull will return the first error here, and then reslice
|
|
|
|
// to remove it. Will give nil errors if this slice is empty.
|
|
|
|
ErrorsToInject []error
|
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// Pull records the image pull attempt, and optionally injects an error.
|
2015-05-08 17:53:00 +00:00
|
|
|
func (f *FakeDockerPuller) Pull(image string, secrets []api.Secret) (err error) {
|
2014-09-09 04:33:17 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2014-06-24 23:31:33 +00:00
|
|
|
f.ImagesPulled = append(f.ImagesPulled, image)
|
|
|
|
|
2014-07-23 16:53:31 +00:00
|
|
|
if len(f.ErrorsToInject) > 0 {
|
|
|
|
err = f.ErrorsToInject[0]
|
|
|
|
f.ErrorsToInject = f.ErrorsToInject[1:]
|
2014-06-24 23:31:33 +00:00
|
|
|
}
|
2014-07-23 16:53:31 +00:00
|
|
|
return err
|
2014-06-24 23:31:33 +00:00
|
|
|
}
|
2014-09-26 04:53:17 +00:00
|
|
|
|
|
|
|
func (f *FakeDockerPuller) IsImagePresent(name string) (bool, error) {
|
2014-10-02 18:58:58 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
|
|
|
if f.HasImages == nil {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
for _, s := range f.HasImages {
|
|
|
|
if s == name {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil
|
2014-09-26 04:53:17 +00:00
|
|
|
}
|