2017-06-07 19:03:52 -04:00
|
|
|
package container
|
|
|
|
|
|
|
|
import (
|
2018-05-03 21:02:44 -04:00
|
|
|
"context"
|
2017-08-31 17:07:16 -04:00
|
|
|
"io"
|
|
|
|
|
2017-06-07 19:03:52 -04:00
|
|
|
"github.com/docker/docker/api/types"
|
2017-08-31 17:07:16 -04:00
|
|
|
"github.com/docker/docker/api/types/container"
|
|
|
|
"github.com/docker/docker/api/types/network"
|
2017-06-07 19:03:52 -04:00
|
|
|
"github.com/docker/docker/client"
|
2020-05-27 14:32:22 -04:00
|
|
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
2017-06-07 19:03:52 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type fakeClient struct {
|
|
|
|
client.Client
|
2018-11-21 08:41:51 -05:00
|
|
|
inspectFunc func(string) (types.ContainerJSON, error)
|
|
|
|
execInspectFunc func(execID string) (types.ContainerExecInspect, error)
|
|
|
|
execCreateFunc func(container string, config types.ExecConfig) (types.IDResponse, error)
|
|
|
|
createContainerFunc func(config *container.Config,
|
|
|
|
hostConfig *container.HostConfig,
|
|
|
|
networkingConfig *network.NetworkingConfig,
|
2020-05-27 14:32:22 -04:00
|
|
|
platform *specs.Platform,
|
2018-11-21 08:41:51 -05:00
|
|
|
containerName string) (container.ContainerCreateCreatedBody, error)
|
|
|
|
containerStartFunc func(container string, options types.ContainerStartOptions) error
|
|
|
|
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
|
|
|
|
infoFunc func() (types.Info, error)
|
|
|
|
containerStatPathFunc func(container, path string) (types.ContainerPathStat, error)
|
|
|
|
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
|
|
|
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
|
|
|
|
waitFunc func(string) (<-chan container.ContainerWaitOKBody, <-chan error)
|
|
|
|
containerListFunc func(types.ContainerListOptions) ([]types.Container, error)
|
|
|
|
containerExportFunc func(string) (io.ReadCloser, error)
|
|
|
|
containerExecResizeFunc func(id string, options types.ResizeOptions) error
|
Return zero exit-code when force-removing non-existing containers
When using `docker rm` / `docker container rm` with the `-f` / `--force` option, attempts to remove non-existing containers should print a warning, but should return a zero exit code ("successful").
Currently, a non-zero exit code is returned, marking the removal as "failed";
$ docker rm -fv 798c9471b695
Error: No such container: 798c9471b695
$ echo $?
1
The command should match the behavior of `rm` / `rm -f`, with the exception that
a warning is printed (instead of silently ignored):
Running `rm` with `-f` silences output and returns a zero exit code:
touch some-file && rm -f no-such-file some-file; echo exit code: $?; ls -la
# exit code: 0
# total 0
# drwxr-xr-x 2 sebastiaan staff 64 Aug 14 12:17 .
# drwxr-xr-x 199 sebastiaan staff 6368 Aug 14 12:13 ..
mkdir some-directory && rm -rf no-such-directory some-directory; echo exit code: $?; ls -la
# exit code: 0
# total 0
# drwxr-xr-x 2 sebastiaan staff 64 Aug 14 12:17 .
# drwxr-xr-x 199 sebastiaan staff 6368 Aug 14 12:13 ..
Note that other reasons for a delete to fail should still result in a non-zero
exit code, matching the behavior of `rm`. For instance, in the example below,
the `rm` failed because directories can only be removed if the `-r` option is used;
touch some-file && mkdir some-directory && rm -f some-directory no-such-file some-file; echo exit code: $?; ls -la
# rm: some-directory: is a directory
# exit code: 1
# total 0
# drwxr-xr-x 3 sebastiaan staff 96 Aug 14 14:15 .
# drwxr-xr-x 199 sebastiaan staff 6368 Aug 14 12:13 ..
# drwxr-xr-x 2 sebastiaan staff 64 Aug 14 14:15 some-directory
This patch updates the `docker rm` / `docker container rm` command to not produce
an error when attempting to remove a missing containers, and instead only print
the error, but return a zero (0) exit code.
With this patch applied:
docker create --name mycontainer busybox \
&& docker rm nosuchcontainer mycontainer; \
echo exit code: $?; \
docker ps -a --filter name=mycontainer
# df23cc8573f00e97d6e948b48d9ea7d75ce3b4faaab4fe1d3458d3bfa451f39d
# mycontainer
# Error: No such container: nosuchcontainer
# exit code: 0
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-08-14 10:04:32 -04:00
|
|
|
containerRemoveFunc func(ctx context.Context, container string, options types.ContainerRemoveOptions) error
|
2018-11-21 08:41:51 -05:00
|
|
|
Version string
|
2017-06-07 19:03:52 -04:00
|
|
|
}
|
|
|
|
|
2018-02-15 11:58:17 -05:00
|
|
|
func (f *fakeClient) ContainerList(_ context.Context, options types.ContainerListOptions) ([]types.Container, error) {
|
|
|
|
if f.containerListFunc != nil {
|
|
|
|
return f.containerListFunc(options)
|
|
|
|
}
|
|
|
|
return []types.Container{}, nil
|
|
|
|
}
|
|
|
|
|
2017-05-09 18:35:25 -04:00
|
|
|
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (types.ContainerJSON, error) {
|
|
|
|
if f.inspectFunc != nil {
|
|
|
|
return f.inspectFunc(containerID)
|
2017-06-07 19:03:52 -04:00
|
|
|
}
|
|
|
|
return types.ContainerJSON{}, nil
|
|
|
|
}
|
2017-05-09 18:35:25 -04:00
|
|
|
|
|
|
|
func (f *fakeClient) ContainerExecCreate(_ context.Context, container string, config types.ExecConfig) (types.IDResponse, error) {
|
|
|
|
if f.execCreateFunc != nil {
|
|
|
|
return f.execCreateFunc(container, config)
|
|
|
|
}
|
|
|
|
return types.IDResponse{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (types.ContainerExecInspect, error) {
|
|
|
|
if f.execInspectFunc != nil {
|
|
|
|
return f.execInspectFunc(execID)
|
|
|
|
}
|
|
|
|
return types.ContainerExecInspect{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeClient) ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error {
|
|
|
|
return nil
|
|
|
|
}
|
2017-08-31 17:07:16 -04:00
|
|
|
|
|
|
|
func (f *fakeClient) ContainerCreate(
|
|
|
|
_ context.Context,
|
|
|
|
config *container.Config,
|
|
|
|
hostConfig *container.HostConfig,
|
|
|
|
networkingConfig *network.NetworkingConfig,
|
2020-05-27 14:32:22 -04:00
|
|
|
platform *specs.Platform,
|
2017-08-31 17:07:16 -04:00
|
|
|
containerName string,
|
|
|
|
) (container.ContainerCreateCreatedBody, error) {
|
|
|
|
if f.createContainerFunc != nil {
|
2020-05-27 14:32:22 -04:00
|
|
|
return f.createContainerFunc(config, hostConfig, networkingConfig, platform, containerName)
|
2017-08-31 17:07:16 -04:00
|
|
|
}
|
|
|
|
return container.ContainerCreateCreatedBody{}, nil
|
|
|
|
}
|
|
|
|
|
Return zero exit-code when force-removing non-existing containers
When using `docker rm` / `docker container rm` with the `-f` / `--force` option, attempts to remove non-existing containers should print a warning, but should return a zero exit code ("successful").
Currently, a non-zero exit code is returned, marking the removal as "failed";
$ docker rm -fv 798c9471b695
Error: No such container: 798c9471b695
$ echo $?
1
The command should match the behavior of `rm` / `rm -f`, with the exception that
a warning is printed (instead of silently ignored):
Running `rm` with `-f` silences output and returns a zero exit code:
touch some-file && rm -f no-such-file some-file; echo exit code: $?; ls -la
# exit code: 0
# total 0
# drwxr-xr-x 2 sebastiaan staff 64 Aug 14 12:17 .
# drwxr-xr-x 199 sebastiaan staff 6368 Aug 14 12:13 ..
mkdir some-directory && rm -rf no-such-directory some-directory; echo exit code: $?; ls -la
# exit code: 0
# total 0
# drwxr-xr-x 2 sebastiaan staff 64 Aug 14 12:17 .
# drwxr-xr-x 199 sebastiaan staff 6368 Aug 14 12:13 ..
Note that other reasons for a delete to fail should still result in a non-zero
exit code, matching the behavior of `rm`. For instance, in the example below,
the `rm` failed because directories can only be removed if the `-r` option is used;
touch some-file && mkdir some-directory && rm -f some-directory no-such-file some-file; echo exit code: $?; ls -la
# rm: some-directory: is a directory
# exit code: 1
# total 0
# drwxr-xr-x 3 sebastiaan staff 96 Aug 14 14:15 .
# drwxr-xr-x 199 sebastiaan staff 6368 Aug 14 12:13 ..
# drwxr-xr-x 2 sebastiaan staff 64 Aug 14 14:15 some-directory
This patch updates the `docker rm` / `docker container rm` command to not produce
an error when attempting to remove a missing containers, and instead only print
the error, but return a zero (0) exit code.
With this patch applied:
docker create --name mycontainer busybox \
&& docker rm nosuchcontainer mycontainer; \
echo exit code: $?; \
docker ps -a --filter name=mycontainer
# df23cc8573f00e97d6e948b48d9ea7d75ce3b4faaab4fe1d3458d3bfa451f39d
# mycontainer
# Error: No such container: nosuchcontainer
# exit code: 0
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-08-14 10:04:32 -04:00
|
|
|
func (f *fakeClient) ContainerRemove(ctx context.Context, container string, options types.ContainerRemoveOptions) error {
|
|
|
|
if f.containerRemoveFunc != nil {
|
|
|
|
return f.containerRemoveFunc(ctx, container, options)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-08-31 17:07:16 -04:00
|
|
|
func (f *fakeClient) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
|
|
|
|
if f.imageCreateFunc != nil {
|
|
|
|
return f.imageCreateFunc(parentReference, options)
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeClient) Info(_ context.Context) (types.Info, error) {
|
|
|
|
if f.infoFunc != nil {
|
|
|
|
return f.infoFunc()
|
|
|
|
}
|
|
|
|
return types.Info{}, nil
|
|
|
|
}
|
2017-10-30 17:52:08 -04:00
|
|
|
|
|
|
|
func (f *fakeClient) ContainerStatPath(_ context.Context, container, path string) (types.ContainerPathStat, error) {
|
|
|
|
if f.containerStatPathFunc != nil {
|
|
|
|
return f.containerStatPathFunc(container, path)
|
|
|
|
}
|
|
|
|
return types.ContainerPathStat{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeClient) CopyFromContainer(_ context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
|
|
|
if f.containerCopyFromFunc != nil {
|
|
|
|
return f.containerCopyFromFunc(container, srcPath)
|
|
|
|
}
|
|
|
|
return nil, types.ContainerPathStat{}, nil
|
|
|
|
}
|
2017-11-13 04:53:13 -05:00
|
|
|
|
|
|
|
func (f *fakeClient) ContainerLogs(_ context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) {
|
|
|
|
if f.logFunc != nil {
|
|
|
|
return f.logFunc(container, options)
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
2017-12-19 18:36:50 -05:00
|
|
|
|
|
|
|
func (f *fakeClient) ClientVersion() string {
|
|
|
|
return f.Version
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeClient) ContainerWait(_ context.Context, container string, _ container.WaitCondition) (<-chan container.ContainerWaitOKBody, <-chan error) {
|
|
|
|
if f.waitFunc != nil {
|
|
|
|
return f.waitFunc(container)
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
2018-02-27 06:14:07 -05:00
|
|
|
|
|
|
|
func (f *fakeClient) ContainerStart(_ context.Context, container string, options types.ContainerStartOptions) error {
|
|
|
|
if f.containerStartFunc != nil {
|
|
|
|
return f.containerStartFunc(container, options)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2018-09-18 12:29:56 -04:00
|
|
|
|
|
|
|
func (f *fakeClient) ContainerExport(_ context.Context, container string) (io.ReadCloser, error) {
|
|
|
|
if f.containerExportFunc != nil {
|
|
|
|
return f.containerExportFunc(container)
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
2018-11-21 08:41:51 -05:00
|
|
|
|
|
|
|
func (f *fakeClient) ContainerExecResize(_ context.Context, id string, options types.ResizeOptions) error {
|
|
|
|
if f.containerExecResizeFunc != nil {
|
|
|
|
return f.containerExecResizeFunc(id, options)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|