mirror of
https://github.com/moby/moby.git
synced 2026-07-12 10:35:14 +00:00
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) in3e7405aea8, and removed in API v1.23 (Docker Engine v1.12.0) in commit0a8386c8be. API v1.23 and older are deprecated, and this patch removes the feature. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
139 lines
3.9 KiB
Go
139 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))
|
|
}
|
|
}
|