moby/builder/dockerfile/containerbackend.go
Sebastiaan van Stijn 8758d08bb4
api: remove handling of HostConfig on POST /containers/{id}/start (api < v1.24)
API v1.20 (Docker Engine v1.11.0) and older allowed a HostConfig to be passed
when starting a container. This feature was deprecated in API v1.21 (Docker
Engine v1.10.0) in 3e7405aea8, and removed in
API v1.23 (Docker Engine v1.12.0) in commit 0a8386c8be.

API v1.23 and older are deprecated, and this patch removes the feature.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 18:44:44 +01:00

138 lines
3.9 KiB
Go

package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"context"
"fmt"
"io"
"github.com/containerd/log"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/builder"
containerpkg "github.com/docker/docker/container"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/stringid"
"github.com/pkg/errors"
)
type containerManager struct {
tmpContainers map[string]struct{}
backend builder.ExecBackend
}
// newContainerManager creates a new container backend
func newContainerManager(docker builder.ExecBackend) *containerManager {
return &containerManager{
backend: docker,
tmpContainers: make(map[string]struct{}),
}
}
// Create a container
func (c *containerManager) Create(ctx context.Context, runConfig *container.Config, hostConfig *container.HostConfig) (container.CreateResponse, error) {
ctr, err := c.backend.ContainerCreateIgnoreImagesArgsEscaped(ctx, backend.ContainerCreateConfig{
Config: runConfig,
HostConfig: hostConfig,
})
if err != nil {
return ctr, err
}
c.tmpContainers[ctr.ID] = struct{}{}
return ctr, nil
}
var errCancelled = errors.New("build cancelled")
// Run a container by ID
func (c *containerManager) Run(ctx context.Context, cID string, stdout, stderr io.Writer) (err error) {
attached := make(chan struct{})
errCh := make(chan error, 1)
go func() {
errCh <- c.backend.ContainerAttachRaw(cID, nil, stdout, stderr, true, attached)
}()
select {
case err := <-errCh:
return err
case <-attached:
}
finished := make(chan struct{})
cancelErrCh := make(chan error, 1)
go func() {
select {
case <-ctx.Done():
log.G(ctx).Debugln("Build cancelled, removing container:", cID)
err = c.backend.ContainerRm(cID, &backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true})
if err != nil {
_, _ = fmt.Fprintf(stdout, "Removing container %s: %v\n", stringid.TruncateID(cID), err)
}
cancelErrCh <- errCancelled
case <-finished:
cancelErrCh <- nil
}
}()
if err := c.backend.ContainerStart(ctx, cID, "", ""); err != nil {
close(finished)
logCancellationError(cancelErrCh, "error from ContainerStart: "+err.Error())
return err
}
// Block on reading output from container, stop on err or chan closed
if err := <-errCh; err != nil {
close(finished)
logCancellationError(cancelErrCh, "error from errCh: "+err.Error())
return err
}
waitC, err := c.backend.ContainerWait(ctx, cID, containerpkg.WaitConditionNotRunning)
if err != nil {
close(finished)
logCancellationError(cancelErrCh, fmt.Sprintf("unable to begin ContainerWait: %s", err))
return err
}
if status := <-waitC; status.ExitCode() != 0 {
close(finished)
logCancellationError(cancelErrCh,
fmt.Sprintf("a non-zero code from ContainerWait: %d", status.ExitCode()))
return &statusCodeError{code: status.ExitCode(), err: status.Err()}
}
close(finished)
return <-cancelErrCh
}
func logCancellationError(cancelErrCh chan error, msg string) {
if cancelErr := <-cancelErrCh; cancelErr != nil {
log.G(context.TODO()).Debugf("Build cancelled (%v): %s", cancelErr, msg)
}
}
type statusCodeError struct {
code int
err error
}
func (e *statusCodeError) Error() string {
if e.err == nil {
return ""
}
return e.err.Error()
}
func (e *statusCodeError) StatusCode() int {
return e.code
}
// RemoveAll containers managed by this container manager
func (c *containerManager) RemoveAll(stdout io.Writer) {
for containerID := range c.tmpContainers {
if err := c.backend.ContainerRm(containerID, &backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil && !errdefs.IsNotFound(err) {
_, _ = fmt.Fprintf(stdout, "Removing intermediate container %s: %v\n", stringid.TruncateID(containerID), err)
continue
}
delete(c.tmpContainers, containerID)
_, _ = fmt.Fprintf(stdout, " ---> Removed intermediate container %s\n", stringid.TruncateID(containerID))
}
}