mirror of https://github.com/docker/docs.git
Merge pull request #1162 from jimmyxian/add-support-force-remove-image
Add support force remove image
This commit is contained in:
commit
fc0cc899e6
|
@ -104,7 +104,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/samalba/dockerclient",
|
"ImportPath": "github.com/samalba/dockerclient",
|
||||||
"Rev": "68832c185bb6304fed26a986891fd27b6ed17987"
|
"Rev": "8802d66ce78e69ff16692f6fa89ad969a5711b8b"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Callback used to listen to Docker's events
|
// Callback used to listen to Docker's events
|
||||||
|
@ -42,6 +43,20 @@ func main() {
|
||||||
log.Println(info)
|
log.Println(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build a docker image
|
||||||
|
// some.tar contains the build context (Dockerfile any any files it needs to add/copy)
|
||||||
|
dockerBuildContext, err := os.Open("some.tar")
|
||||||
|
defer dockerBuildContext.Close()
|
||||||
|
buildImageConfig := &dockerclient.BuildImage{
|
||||||
|
Context: dockerBuildContext,
|
||||||
|
RepoName: "your_image_name",
|
||||||
|
SuppressOutput: false,
|
||||||
|
}
|
||||||
|
reader, err := docker.BuildImage(buildImageConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Create a container
|
// Create a container
|
||||||
containerConfig := &dockerclient.ContainerConfig{
|
containerConfig := &dockerclient.ContainerConfig{
|
||||||
Image: "ubuntu:14.04",
|
Image: "ubuntu:14.04",
|
||||||
|
|
|
@ -272,6 +272,56 @@ func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*js
|
||||||
return resultChan
|
return resultChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ExecCreate(config *ExecConfig) (string, error) {
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/exec", APIVersion, config.Container)
|
||||||
|
resp, err := client.doRequest("POST", uri, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
var createExecResp struct {
|
||||||
|
Id string
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(resp, &createExecResp); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return createExecResp.Id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ExecStart(id string, config *ExecConfig) error {
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("/%s/exec/%s/start", APIVersion, id)
|
||||||
|
if _, err := client.doRequest("POST", uri, data, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ExecResize(id string, width, height int) error {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
w := strconv.Itoa(width)
|
||||||
|
h := strconv.Itoa(height)
|
||||||
|
|
||||||
|
v.Set("w", w)
|
||||||
|
v.Set("h", h)
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("/%s/exec/%s/resize?%s", APIVersion, id, v.Encode())
|
||||||
|
if _, err := client.doRequest("POST", client.URL.String()+uri, nil, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
|
func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
|
||||||
data, err := json.Marshal(config)
|
data, err := json.Marshal(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -312,6 +362,26 @@ func (client *DockerClient) KillContainer(id, signal string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) Wait(id string) <-chan WaitResult {
|
||||||
|
ch := make(chan WaitResult)
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/wait", APIVersion, id)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
data, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
ch <- WaitResult{ExitCode: -1, Error: err}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
StatusCode int `json:"StatusCode"`
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &result)
|
||||||
|
ch <- WaitResult{ExitCode: result.StatusCode, Error: err}
|
||||||
|
}()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
func (client *DockerClient) MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error) {
|
func (client *DockerClient) MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error) {
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
if options != nil {
|
if options != nil {
|
||||||
|
@ -556,8 +626,14 @@ func (client *DockerClient) ListImages(all bool) ([]*Image, error) {
|
||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *DockerClient) RemoveImage(name string) ([]*ImageDelete, error) {
|
func (client *DockerClient) RemoveImage(name string, force bool) ([]*ImageDelete, error) {
|
||||||
uri := fmt.Sprintf("/%s/images/%s", APIVersion, name)
|
argForce := 0
|
||||||
|
if force {
|
||||||
|
argForce = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
args := fmt.Sprintf("force=%d", argForce)
|
||||||
|
uri := fmt.Sprintf("/%s/images/%s?%s", APIVersion, name, args)
|
||||||
data, err := client.doRequest("DELETE", uri, nil, nil)
|
data, err := client.doRequest("DELETE", uri, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -586,30 +662,6 @@ func (client *DockerClient) UnpauseContainer(id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *DockerClient) Exec(config *ExecConfig) (string, error) {
|
|
||||||
data, err := json.Marshal(config)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
uri := fmt.Sprintf("/containers/%s/exec", config.Container)
|
|
||||||
resp, err := client.doRequest("POST", uri, data, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
var createExecResp struct {
|
|
||||||
Id string
|
|
||||||
}
|
|
||||||
if err = json.Unmarshal(resp, &createExecResp); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
uri = fmt.Sprintf("/exec/%s/start", createExecResp.Id)
|
|
||||||
resp, err = client.doRequest("POST", uri, data, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return createExecResp.Id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (client *DockerClient) RenameContainer(oldName string, newName string) error {
|
func (client *DockerClient) RenameContainer(oldName string, newName string) error {
|
||||||
uri := fmt.Sprintf("/containers/%s/rename?name=%s", oldName, newName)
|
uri := fmt.Sprintf("/containers/%s/rename?name=%s", oldName, newName)
|
||||||
_, err := client.doRequest("POST", uri, nil, nil)
|
_, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/stdcopy"
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
)
|
)
|
||||||
|
@ -47,6 +48,26 @@ func TestKillContainer(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWait(t *testing.T) {
|
||||||
|
client := testDockerClient(t)
|
||||||
|
|
||||||
|
// This provokes an error on the server.
|
||||||
|
select {
|
||||||
|
case wr := <-client.Wait("1234"):
|
||||||
|
assertEqual(t, wr.ExitCode, int(-1), "")
|
||||||
|
case <-time.After(2 * time.Second):
|
||||||
|
t.Fatal("Timed out!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid case.
|
||||||
|
select {
|
||||||
|
case wr := <-client.Wait("valid-id"):
|
||||||
|
assertEqual(t, wr.ExitCode, int(0), "")
|
||||||
|
case <-time.After(2 * time.Second):
|
||||||
|
t.Fatal("Timed out!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPullImage(t *testing.T) {
|
func TestPullImage(t *testing.T) {
|
||||||
client := testDockerClient(t)
|
client := testDockerClient(t)
|
||||||
err := client.PullImage("busybox", nil)
|
err := client.PullImage("busybox", nil)
|
||||||
|
|
|
@ -29,6 +29,7 @@ func init() {
|
||||||
r.HandleFunc(baseURL+"/containers/{id}/logs", handleContainerLogs).Methods("GET")
|
r.HandleFunc(baseURL+"/containers/{id}/logs", handleContainerLogs).Methods("GET")
|
||||||
r.HandleFunc(baseURL+"/containers/{id}/changes", handleContainerChanges).Methods("GET")
|
r.HandleFunc(baseURL+"/containers/{id}/changes", handleContainerChanges).Methods("GET")
|
||||||
r.HandleFunc(baseURL+"/containers/{id}/kill", handleContainerKill).Methods("POST")
|
r.HandleFunc(baseURL+"/containers/{id}/kill", handleContainerKill).Methods("POST")
|
||||||
|
r.HandleFunc(baseURL+"/containers/{id}/wait", handleWait).Methods("POST")
|
||||||
r.HandleFunc(baseURL+"/images/create", handleImagePull).Methods("POST")
|
r.HandleFunc(baseURL+"/images/create", handleImagePull).Methods("POST")
|
||||||
r.HandleFunc(baseURL+"/events", handleEvents).Methods("GET")
|
r.HandleFunc(baseURL+"/events", handleEvents).Methods("GET")
|
||||||
testHTTPServer = httptest.NewServer(handlerAccessLog(r))
|
testHTTPServer = httptest.NewServer(handlerAccessLog(r))
|
||||||
|
@ -46,6 +47,15 @@ func handleContainerKill(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "{%q:%q", "Id", "421373210afd132")
|
fmt.Fprintf(w, "{%q:%q", "Id", "421373210afd132")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleWait(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
if vars["id"] == "valid-id" {
|
||||||
|
fmt.Fprintf(w, `{"StatusCode":0}`)
|
||||||
|
} else {
|
||||||
|
http.Error(w, "failed", 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handleImagePull(w http.ResponseWriter, r *http.Request) {
|
func handleImagePull(w http.ResponseWriter, r *http.Request) {
|
||||||
imageName := r.URL.Query()["fromImage"][0]
|
imageName := r.URL.Query()["fromImage"][0]
|
||||||
responses := []map[string]interface{}{{
|
responses := []map[string]interface{}{{
|
||||||
|
|
|
@ -16,11 +16,14 @@ type Client interface {
|
||||||
CreateContainer(config *ContainerConfig, name string) (string, error)
|
CreateContainer(config *ContainerConfig, name string) (string, error)
|
||||||
ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error)
|
ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error)
|
||||||
ContainerChanges(id string) ([]*ContainerChanges, error)
|
ContainerChanges(id string) ([]*ContainerChanges, error)
|
||||||
Exec(config *ExecConfig) (string, error)
|
ExecCreate(config *ExecConfig) (string, error)
|
||||||
|
ExecStart(id string, config *ExecConfig) error
|
||||||
|
ExecResize(id string, width, height int) error
|
||||||
StartContainer(id string, config *HostConfig) error
|
StartContainer(id string, config *HostConfig) error
|
||||||
StopContainer(id string, timeout int) error
|
StopContainer(id string, timeout int) error
|
||||||
RestartContainer(id string, timeout int) error
|
RestartContainer(id string, timeout int) error
|
||||||
KillContainer(id, signal string) error
|
KillContainer(id, signal string) error
|
||||||
|
Wait(id string) <-chan WaitResult
|
||||||
// MonitorEvents takes options and an optional stop channel, and returns
|
// MonitorEvents takes options and an optional stop channel, and returns
|
||||||
// an EventOrError channel. If an error is ever sent, then no more
|
// an EventOrError channel. If an error is ever sent, then no more
|
||||||
// events will be sent. If a stop channel is provided, events will stop
|
// events will be sent. If a stop channel is provided, events will stop
|
||||||
|
@ -36,7 +39,7 @@ type Client interface {
|
||||||
LoadImage(reader io.Reader) error
|
LoadImage(reader io.Reader) error
|
||||||
RemoveContainer(id string, force, volumes bool) error
|
RemoveContainer(id string, force, volumes bool) error
|
||||||
ListImages(all bool) ([]*Image, error)
|
ListImages(all bool) ([]*Image, error)
|
||||||
RemoveImage(name string) ([]*ImageDelete, error)
|
RemoveImage(name string, force bool) ([]*ImageDelete, error)
|
||||||
PauseContainer(name string) error
|
PauseContainer(name string) error
|
||||||
UnpauseContainer(name string) error
|
UnpauseContainer(name string) error
|
||||||
RenameContainer(oldName string, newName string) error
|
RenameContainer(oldName string, newName string) error
|
||||||
|
|
|
@ -70,6 +70,11 @@ func (client *MockClient) KillContainer(id, signal string) error {
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) Wait(id string) <-chan dockerclient.WaitResult {
|
||||||
|
args := client.Mock.Called(id)
|
||||||
|
return args.Get(0).(<-chan dockerclient.WaitResult)
|
||||||
|
}
|
||||||
|
|
||||||
func (client *MockClient) MonitorEvents(options *dockerclient.MonitorEventsOptions, stopChan <-chan struct{}) (<-chan dockerclient.EventOrError, error) {
|
func (client *MockClient) MonitorEvents(options *dockerclient.MonitorEventsOptions, stopChan <-chan struct{}) (<-chan dockerclient.EventOrError, error) {
|
||||||
args := client.Mock.Called(options, stopChan)
|
args := client.Mock.Called(options, stopChan)
|
||||||
return args.Get(0).(<-chan dockerclient.EventOrError), args.Error(1)
|
return args.Get(0).(<-chan dockerclient.EventOrError), args.Error(1)
|
||||||
|
@ -121,8 +126,8 @@ func (client *MockClient) ListImages(all bool) ([]*dockerclient.Image, error) {
|
||||||
return args.Get(0).([]*dockerclient.Image), args.Error(1)
|
return args.Get(0).([]*dockerclient.Image), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *MockClient) RemoveImage(name string) ([]*dockerclient.ImageDelete, error) {
|
func (client *MockClient) RemoveImage(name string, force bool) ([]*dockerclient.ImageDelete, error) {
|
||||||
args := client.Mock.Called(name)
|
args := client.Mock.Called(name, force)
|
||||||
return args.Get(0).([]*dockerclient.ImageDelete), args.Error(1)
|
return args.Get(0).([]*dockerclient.ImageDelete), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +141,21 @@ func (client *MockClient) UnpauseContainer(name string) error {
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *MockClient) Exec(config *dockerclient.ExecConfig) (string, error) {
|
func (client *MockClient) ExecCreate(config *dockerclient.ExecConfig) (string, error) {
|
||||||
args := client.Mock.Called(config)
|
args := client.Mock.Called(config)
|
||||||
return args.String(0), args.Error(1)
|
return args.String(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ExecStart(id string, config *dockerclient.ExecConfig) error {
|
||||||
|
args := client.Mock.Called(id, config)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ExecResize(id string, width, height int) error {
|
||||||
|
args := client.Mock.Called(id, width, height)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
func (client *MockClient) RenameContainer(oldName string, newName string) error {
|
func (client *MockClient) RenameContainer(oldName string, newName string) error {
|
||||||
args := client.Mock.Called(oldName, newName)
|
args := client.Mock.Called(oldName, newName)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
|
|
|
@ -324,6 +324,11 @@ type EventOrError struct {
|
||||||
Error error
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WaitResult struct {
|
||||||
|
ExitCode int
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
type decodingResult struct {
|
type decodingResult struct {
|
||||||
result interface{}
|
result interface{}
|
||||||
err error
|
err error
|
||||||
|
|
|
@ -511,8 +511,9 @@ func deleteImages(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var name = mux.Vars(r)["name"]
|
var name = mux.Vars(r)["name"]
|
||||||
|
force := boolValue(r, "force")
|
||||||
|
|
||||||
out, err := c.cluster.RemoveImages(name)
|
out, err := c.cluster.RemoveImages(name, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|
|
@ -21,7 +21,7 @@ type Cluster interface {
|
||||||
Image(IDOrName string) *Image
|
Image(IDOrName string) *Image
|
||||||
|
|
||||||
// Remove images from the cluster
|
// Remove images from the cluster
|
||||||
RemoveImages(name string) ([]*dockerclient.ImageDelete, error)
|
RemoveImages(name string, force bool) ([]*dockerclient.ImageDelete, error)
|
||||||
|
|
||||||
// Return all containers
|
// Return all containers
|
||||||
Containers() Containers
|
Containers() Containers
|
||||||
|
|
|
@ -179,8 +179,8 @@ func (e *Engine) updateSpecs() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveImage deletes an image from the engine.
|
// RemoveImage deletes an image from the engine.
|
||||||
func (e *Engine) RemoveImage(image *Image, name string) ([]*dockerclient.ImageDelete, error) {
|
func (e *Engine) RemoveImage(image *Image, name string, force bool) ([]*dockerclient.ImageDelete, error) {
|
||||||
return e.client.RemoveImage(name)
|
return e.client.RemoveImage(name, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshImages refreshes the list of images on the engine.
|
// RefreshImages refreshes the list of images on the engine.
|
||||||
|
|
|
@ -221,7 +221,7 @@ func (c *Cluster) Image(IDOrName string) *cluster.Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveImages removes images from the cluster
|
// RemoveImages removes images from the cluster
|
||||||
func (c *Cluster) RemoveImages(name string) ([]*dockerclient.ImageDelete, error) {
|
func (c *Cluster) RemoveImages(name string, force bool) ([]*dockerclient.ImageDelete, error) {
|
||||||
return nil, errNotSupported
|
return nil, errNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,7 @@ func (c *Cluster) Image(IDOrName string) *cluster.Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveImages removes all the images that match `name` from the cluster
|
// RemoveImages removes all the images that match `name` from the cluster
|
||||||
func (c *Cluster) RemoveImages(name string) ([]*dockerclient.ImageDelete, error) {
|
func (c *Cluster) RemoveImages(name string, force bool) ([]*dockerclient.ImageDelete, error) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ func (c *Cluster) RemoveImages(name string) ([]*dockerclient.ImageDelete, error)
|
||||||
for _, e := range c.engines {
|
for _, e := range c.engines {
|
||||||
for _, image := range e.Images(true) {
|
for _, image := range e.Images(true) {
|
||||||
if image.Match(name, true) {
|
if image.Match(name, true) {
|
||||||
content, err := image.Engine.RemoveImage(image, name)
|
content, err := image.Engine.RemoveImage(image, name, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("%s: %s", image.Engine.Name, err.Error()))
|
errs = append(errs, fmt.Sprintf("%s: %s", image.Engine.Name, err.Error()))
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -78,3 +78,27 @@ function teardown() {
|
||||||
[[ "${output}" == *"busybox"* ]]
|
[[ "${output}" == *"busybox"* ]]
|
||||||
[[ "${output}" != *"testimage"* ]]
|
[[ "${output}" != *"testimage"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "docker rmi --force" {
|
||||||
|
start_docker_with_busybox 1
|
||||||
|
start_docker 1
|
||||||
|
|
||||||
|
swarm_manage
|
||||||
|
|
||||||
|
# make sure same image id have two repo-tags
|
||||||
|
docker_swarm tag busybox:latest testimage:latest
|
||||||
|
|
||||||
|
run docker_swarm images
|
||||||
|
[[ "${output}" == *"busybox"* ]]
|
||||||
|
[[ "${output}" == *"testimage"* ]]
|
||||||
|
|
||||||
|
# get busybox image id
|
||||||
|
busybox_id=`docker_swarm inspect --format='{{.Id}}' busybox:latest`
|
||||||
|
|
||||||
|
# test rmi with force
|
||||||
|
docker_swarm rmi -f ${busybox_id}
|
||||||
|
|
||||||
|
run docker_swarm images
|
||||||
|
[[ "${output}" != *"busybox"* ]]
|
||||||
|
[[ "${output}" != *"testimage"* ]]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue