Merge component 'engine' from git@github.com:moby/moby master
This commit is contained in:
@ -120,7 +120,7 @@ RUN set -x \
|
||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
||||
# with a heads-up.
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ RUN set -x \
|
||||
# bootstrap, so we use golang-go (1.6) as bootstrap to build Go from source code.
|
||||
# We don't use the official ARMv6 released binaries as a GOROOT_BOOTSTRAP, because
|
||||
# not all ARM64 platforms support 32-bit mode. 32-bit mode is optional for ARMv8.
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash
|
||||
|
||||
@ -71,7 +71,7 @@ RUN cd /usr/local/lvm2 \
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install Go
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
|
||||
@ -95,7 +95,7 @@ RUN set -x \
|
||||
|
||||
# Install Go
|
||||
# NOTE: official ppc64le go binaries weren't available until go 1.6.4 and 1.7.4
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ RUN cd /usr/local/lvm2 \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ RUN set -x \
|
||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
||||
# with a heads-up.
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
|
||||
@ -161,7 +161,7 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref
|
||||
# Environment variable notes:
|
||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||
# - FROM_DOCKERFILE is used for detection of building within a container.
|
||||
ENV GO_VERSION=1.8.1 `
|
||||
ENV GO_VERSION=1.8.3 `
|
||||
GIT_VERSION=2.11.1 `
|
||||
GOPATH=C:\go `
|
||||
FROM_DOCKERFILE=1
|
||||
|
||||
@ -77,7 +77,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
||||
}
|
||||
|
||||
if runtime.GOOS != "windows" && options.SecurityOpt != nil {
|
||||
return nil, fmt.Errorf("the daemon on this platform does not support --security-opt to build")
|
||||
return nil, fmt.Errorf("The daemon on this platform does not support setting security options on build")
|
||||
}
|
||||
|
||||
var buildUlimits = []*units.Ulimit{}
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errExperimentalFeature = errors.New("This experimental feature is disabled by default. Start the Docker daemon with --experimental in order to enable it.")
|
||||
errExperimentalFeature = errors.New("This experimental feature is disabled by default. Start the Docker daemon in experimental mode in order to enable it.")
|
||||
)
|
||||
|
||||
// ExperimentalRoute defines an experimental API route that can be enabled or disabled.
|
||||
|
||||
@ -1048,6 +1048,10 @@ definitions:
|
||||
type: "string"
|
||||
description: "Mount path of the volume on the host."
|
||||
x-nullable: false
|
||||
CreatedAt:
|
||||
type: "string"
|
||||
format: "dateTime"
|
||||
description: "Time volume was created."
|
||||
Status:
|
||||
type: "object"
|
||||
description: |
|
||||
@ -1101,6 +1105,7 @@ definitions:
|
||||
com.example.some-label: "some-value"
|
||||
com.example.some-other-label: "some-other-value"
|
||||
Scope: "local"
|
||||
CreatedAt: "2016-06-07T20:31:11.853781916Z"
|
||||
|
||||
Network:
|
||||
type: "object"
|
||||
@ -2174,9 +2179,6 @@ definitions:
|
||||
Runtime:
|
||||
description: "Runtime is the type of runtime specified for the task executor."
|
||||
type: "string"
|
||||
RuntimeData:
|
||||
description: "RuntimeData is the payload sent to be used with the runtime for the executor."
|
||||
type: "array"
|
||||
Networks:
|
||||
type: "array"
|
||||
items:
|
||||
@ -3122,7 +3124,7 @@ paths:
|
||||
all processes in the container. Freezing the process requires the process to
|
||||
be running. As a result, paused containers are both `Running` _and_ `Paused`.
|
||||
|
||||
Use the `Status` field instead to determin if a container's state is "running".
|
||||
Use the `Status` field instead to determine if a container's state is "running".
|
||||
type: "boolean"
|
||||
Paused:
|
||||
description: "Whether this container is paused."
|
||||
|
||||
@ -67,9 +67,6 @@ type TaskSpec struct {
|
||||
ForceUpdate uint64
|
||||
|
||||
Runtime RuntimeType `json:",omitempty"`
|
||||
// TODO (ehazlett): this should be removed and instead
|
||||
// use struct tags (proto) for the runtimes
|
||||
RuntimeData []byte `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Resources represents resources (CPU/Memory).
|
||||
|
||||
@ -7,6 +7,9 @@ package types
|
||||
// swagger:model Volume
|
||||
type Volume struct {
|
||||
|
||||
// Time volume was created.
|
||||
CreatedAt string `json:"CreatedAt,omitempty"`
|
||||
|
||||
// Name of the volume driver used by the volume.
|
||||
// Required: true
|
||||
Driver string `json:"Driver"`
|
||||
|
||||
@ -7,12 +7,11 @@ package builder
|
||||
import (
|
||||
"io"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -36,21 +35,10 @@ type Source interface {
|
||||
// Backend abstracts calls to a Docker Daemon.
|
||||
type Backend interface {
|
||||
ImageBackend
|
||||
ExecBackend
|
||||
|
||||
// ContainerAttachRaw attaches to container.
|
||||
ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error
|
||||
// ContainerCreate creates a new Docker container and returns potential warnings
|
||||
ContainerCreate(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||
// ContainerRm removes a container specified by `id`.
|
||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||
// Commit creates a new Docker image from an existing Docker container.
|
||||
Commit(string, *backend.ContainerCommitConfig) (string, error)
|
||||
// ContainerKill stops the container execution abruptly.
|
||||
ContainerKill(containerID string, sig uint64) error
|
||||
// ContainerStart starts a new container
|
||||
ContainerStart(containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
||||
// ContainerWait stops processing until the given container is stopped.
|
||||
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
||||
// ContainerCreateWorkdir creates the workdir
|
||||
ContainerCreateWorkdir(containerID string) error
|
||||
|
||||
@ -59,6 +47,8 @@ type Backend interface {
|
||||
// TODO: extract in the builder instead of passing `decompress`
|
||||
// TODO: use containerd/fs.changestream instead as a source
|
||||
CopyOnBuild(containerID string, destPath string, srcRoot string, srcPath string, decompress bool) error
|
||||
|
||||
ImageCacheBuilder
|
||||
}
|
||||
|
||||
// ImageBackend are the interface methods required from an image component
|
||||
@ -66,6 +56,22 @@ type ImageBackend interface {
|
||||
GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (Image, ReleaseableLayer, error)
|
||||
}
|
||||
|
||||
// ExecBackend contains the interface methods required for executing containers
|
||||
type ExecBackend interface {
|
||||
// ContainerAttachRaw attaches to container.
|
||||
ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error
|
||||
// ContainerCreate creates a new Docker container and returns potential warnings
|
||||
ContainerCreate(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||
// ContainerRm removes a container specified by `id`.
|
||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||
// ContainerKill stops the container execution abruptly.
|
||||
ContainerKill(containerID string, sig uint64) error
|
||||
// ContainerStart starts a new container
|
||||
ContainerStart(containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
||||
// ContainerWait stops processing until the given container is stopped.
|
||||
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
||||
}
|
||||
|
||||
// Result is the output produced by a Builder
|
||||
type Result struct {
|
||||
ImageID string
|
||||
|
||||
@ -2,8 +2,9 @@ package dockerfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/docker/docker/runconfig/opts"
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/runconfig/opts"
|
||||
)
|
||||
|
||||
// builtinAllowedBuildArgs is list of built-in allowed build args
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package dockerfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"bytes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@ -35,8 +35,6 @@ var validCommitCommands = map[string]bool{
|
||||
"workdir": true,
|
||||
}
|
||||
|
||||
var defaultLogConfig = container.LogConfig{Type: "none"}
|
||||
|
||||
// BuildManager is shared across all Builder objects
|
||||
type BuildManager struct {
|
||||
backend builder.Backend
|
||||
@ -100,14 +98,13 @@ type Builder struct {
|
||||
docker builder.Backend
|
||||
clientCtx context.Context
|
||||
|
||||
tmpContainers map[string]struct{}
|
||||
buildStages *buildStages
|
||||
disableCommit bool
|
||||
cacheBusted bool
|
||||
buildArgs *buildArgs
|
||||
imageCache builder.ImageCache
|
||||
imageSources *imageSources
|
||||
pathCache pathCache
|
||||
buildStages *buildStages
|
||||
disableCommit bool
|
||||
buildArgs *buildArgs
|
||||
imageSources *imageSources
|
||||
pathCache pathCache
|
||||
containerManager *containerManager
|
||||
imageProber ImageProber
|
||||
}
|
||||
|
||||
// newBuilder creates a new Dockerfile builder from an optional dockerfile and a Options.
|
||||
@ -117,29 +114,23 @@ func newBuilder(clientCtx context.Context, options builderOptions) *Builder {
|
||||
config = new(types.ImageBuildOptions)
|
||||
}
|
||||
b := &Builder{
|
||||
clientCtx: clientCtx,
|
||||
options: config,
|
||||
Stdout: options.ProgressWriter.StdoutFormatter,
|
||||
Stderr: options.ProgressWriter.StderrFormatter,
|
||||
Aux: options.ProgressWriter.AuxFormatter,
|
||||
Output: options.ProgressWriter.Output,
|
||||
docker: options.Backend,
|
||||
tmpContainers: map[string]struct{}{},
|
||||
buildArgs: newBuildArgs(config.BuildArgs),
|
||||
buildStages: newBuildStages(),
|
||||
imageSources: newImageSources(clientCtx, options),
|
||||
pathCache: options.PathCache,
|
||||
clientCtx: clientCtx,
|
||||
options: config,
|
||||
Stdout: options.ProgressWriter.StdoutFormatter,
|
||||
Stderr: options.ProgressWriter.StderrFormatter,
|
||||
Aux: options.ProgressWriter.AuxFormatter,
|
||||
Output: options.ProgressWriter.Output,
|
||||
docker: options.Backend,
|
||||
buildArgs: newBuildArgs(config.BuildArgs),
|
||||
buildStages: newBuildStages(),
|
||||
imageSources: newImageSources(clientCtx, options),
|
||||
pathCache: options.PathCache,
|
||||
imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache),
|
||||
containerManager: newContainerManager(options.Backend),
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) resetImageCache() {
|
||||
if icb, ok := b.docker.(builder.ImageCacheBuilder); ok {
|
||||
b.imageCache = icb.MakeImageCache(b.options.CacheFrom)
|
||||
}
|
||||
b.cacheBusted = false
|
||||
}
|
||||
|
||||
// Build runs the Dockerfile builder by parsing the Dockerfile and executing
|
||||
// the instructions from the file.
|
||||
func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*builder.Result, error) {
|
||||
@ -216,14 +207,14 @@ func (b *Builder) dispatchDockerfileWithCancellation(dockerfile *parser.Result,
|
||||
}
|
||||
if state, err = b.dispatch(opts); err != nil {
|
||||
if b.options.ForceRemove {
|
||||
b.clearTmp()
|
||||
b.containerManager.RemoveAll(b.Stdout)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Fprintf(b.Stdout, " ---> %s\n", stringid.TruncateID(state.imageID))
|
||||
if b.options.Remove {
|
||||
b.clearTmp()
|
||||
b.containerManager.RemoveAll(b.Stdout)
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +249,9 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con
|
||||
return config, nil
|
||||
}
|
||||
|
||||
b := newBuilder(context.Background(), builderOptions{})
|
||||
b := newBuilder(context.Background(), builderOptions{
|
||||
Options: &types.ImageBuildOptions{NoCache: true},
|
||||
})
|
||||
|
||||
dockerfile, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n")))
|
||||
if err != nil {
|
||||
|
||||
143
components/engine/builder/dockerfile/containerbackend.go
Normal file
143
components/engine/builder/dockerfile/containerbackend.go
Normal file
@ -0,0 +1,143 @@
|
||||
package dockerfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/builder"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
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(runConfig *container.Config, hostConfig *container.HostConfig) (container.ContainerCreateCreatedBody, error) {
|
||||
container, err := c.backend.ContainerCreate(types.ContainerCreateConfig{
|
||||
Config: runConfig,
|
||||
HostConfig: hostConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return container, err
|
||||
}
|
||||
c.tmpContainers[container.ID] = struct{}{}
|
||||
return container, 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)
|
||||
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():
|
||||
logrus.Debugln("Build cancelled, killing and removing container:", cID)
|
||||
c.backend.ContainerKill(cID, 0)
|
||||
c.removeContainer(cID, stdout)
|
||||
cancelErrCh <- errCancelled
|
||||
case <-finished:
|
||||
cancelErrCh <- nil
|
||||
}
|
||||
}()
|
||||
|
||||
if err := c.backend.ContainerStart(cID, nil, "", ""); 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: err}
|
||||
}
|
||||
|
||||
close(finished)
|
||||
return <-cancelErrCh
|
||||
}
|
||||
|
||||
func logCancellationError(cancelErrCh chan error, msg string) {
|
||||
if cancelErr := <-cancelErrCh; cancelErr != nil {
|
||||
logrus.Debugf("Build cancelled (%v): ", cancelErr, msg)
|
||||
}
|
||||
}
|
||||
|
||||
type statusCodeError struct {
|
||||
code int
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *statusCodeError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *statusCodeError) StatusCode() int {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (c *containerManager) removeContainer(containerID string, stdout io.Writer) error {
|
||||
rmConfig := &types.ContainerRmConfig{
|
||||
ForceRemove: true,
|
||||
RemoveVolume: true,
|
||||
}
|
||||
if err := c.backend.ContainerRm(containerID, rmConfig); err != nil {
|
||||
fmt.Fprintf(stdout, "Error removing intermediate container %s: %v\n", stringid.TruncateID(containerID), err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveAll containers managed by this container manager
|
||||
func (c *containerManager) RemoveAll(stdout io.Writer) {
|
||||
for containerID := range c.tmpContainers {
|
||||
if err := c.removeContainer(containerID, stdout); err != nil {
|
||||
return
|
||||
}
|
||||
delete(c.tmpContainers, containerID)
|
||||
fmt.Fprintf(stdout, "Removing intermediate container %s\n", stringid.TruncateID(containerID))
|
||||
}
|
||||
}
|
||||
@ -19,11 +19,11 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/builder/dockerfile/parser"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/pkg/errors"
|
||||
@ -218,7 +218,7 @@ func from(req dispatchRequest) error {
|
||||
return err
|
||||
}
|
||||
|
||||
req.builder.resetImageCache()
|
||||
req.builder.imageProber.Reset()
|
||||
image, err := req.builder.getFromImage(req.shlex, req.args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
@ -398,24 +398,15 @@ func workdir(req dispatchRequest) error {
|
||||
|
||||
comment := "WORKDIR " + runConfig.WorkingDir
|
||||
runConfigWithCommentCmd := copyRunConfig(runConfig, withCmdCommentString(comment))
|
||||
if hit, err := req.builder.probeCache(req.state, runConfigWithCommentCmd); err != nil || hit {
|
||||
containerID, err := req.builder.probeAndCreate(req.state, runConfigWithCommentCmd)
|
||||
if err != nil || containerID == "" {
|
||||
return err
|
||||
}
|
||||
if err := req.builder.docker.ContainerCreateWorkdir(containerID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container, err := req.builder.docker.ContainerCreate(types.ContainerCreateConfig{
|
||||
Config: runConfigWithCommentCmd,
|
||||
// Set a log config to override any default value set on the daemon
|
||||
HostConfig: &container.HostConfig{LogConfig: defaultLogConfig},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.builder.tmpContainers[container.ID] = struct{}{}
|
||||
if err := req.builder.docker.ContainerCreateWorkdir(container.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return req.builder.commitContainer(req.state, container.ID, runConfigWithCommentCmd)
|
||||
return req.builder.commitContainer(req.state, containerID, runConfigWithCommentCmd)
|
||||
}
|
||||
|
||||
// RUN some command yo
|
||||
@ -471,7 +462,16 @@ func run(req dispatchRequest) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := req.builder.run(cID, runConfig.Cmd); err != nil {
|
||||
if err := req.builder.containerManager.Run(req.builder.clientCtx, cID, req.builder.Stdout, req.builder.Stderr); err != nil {
|
||||
if err, ok := err.(*statusCodeError); ok {
|
||||
// TODO: change error type, because jsonmessage.JSONError assumes HTTP
|
||||
return &jsonmessage.JSONError{
|
||||
Message: fmt.Sprintf(
|
||||
"The command '%s' returned a non-zero code: %d",
|
||||
strings.Join(runConfig.Cmd, " "), err.StatusCode()),
|
||||
Code: err.StatusCode(),
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
@ -54,7 +55,6 @@ func newBuilderWithMockBackend() *Builder {
|
||||
options: &types.ImageBuildOptions{},
|
||||
docker: mockBackend,
|
||||
buildArgs: newBuildArgs(make(map[string]*string)),
|
||||
tmpContainers: make(map[string]struct{}),
|
||||
Stdout: new(bytes.Buffer),
|
||||
clientCtx: ctx,
|
||||
disableCommit: true,
|
||||
@ -62,7 +62,9 @@ func newBuilderWithMockBackend() *Builder {
|
||||
Options: &types.ImageBuildOptions{},
|
||||
Backend: mockBackend,
|
||||
}),
|
||||
buildStages: newBuildStages(),
|
||||
buildStages: newBuildStages(),
|
||||
imageProber: newImageProber(mockBackend, nil, false),
|
||||
containerManager: newContainerManager(mockBackend),
|
||||
}
|
||||
return b
|
||||
}
|
||||
@ -479,9 +481,12 @@ func TestRunWithBuildArgs(t *testing.T) {
|
||||
return "", nil
|
||||
},
|
||||
}
|
||||
b.imageCache = imageCache
|
||||
|
||||
mockBackend := b.docker.(*MockBackend)
|
||||
mockBackend.makeImageCacheFunc = func(_ []string) builder.ImageCache {
|
||||
return imageCache
|
||||
}
|
||||
b.imageProber = newImageProber(mockBackend, nil, false)
|
||||
mockBackend.getImageFunc = func(_ string) (builder.Image, builder.ReleaseableLayer, error) {
|
||||
return &mockImage{
|
||||
id: "abcdef",
|
||||
|
||||
63
components/engine/builder/dockerfile/imageprobe.go
Normal file
63
components/engine/builder/dockerfile/imageprobe.go
Normal file
@ -0,0 +1,63 @@
|
||||
package dockerfile
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/builder"
|
||||
)
|
||||
|
||||
// ImageProber exposes an Image cache to the Builder. It supports resetting a
|
||||
// cache.
|
||||
type ImageProber interface {
|
||||
Reset()
|
||||
Probe(parentID string, runConfig *container.Config) (string, error)
|
||||
}
|
||||
|
||||
type imageProber struct {
|
||||
cache builder.ImageCache
|
||||
reset func() builder.ImageCache
|
||||
cacheBusted bool
|
||||
}
|
||||
|
||||
func newImageProber(cacheBuilder builder.ImageCacheBuilder, cacheFrom []string, noCache bool) ImageProber {
|
||||
if noCache {
|
||||
return &nopProber{}
|
||||
}
|
||||
|
||||
reset := func() builder.ImageCache {
|
||||
return cacheBuilder.MakeImageCache(cacheFrom)
|
||||
}
|
||||
return &imageProber{cache: reset(), reset: reset}
|
||||
}
|
||||
|
||||
func (c *imageProber) Reset() {
|
||||
c.cache = c.reset()
|
||||
c.cacheBusted = false
|
||||
}
|
||||
|
||||
// Probe checks if cache match can be found for current build instruction.
|
||||
// It returns the cachedID if there is a hit, and the empty string on miss
|
||||
func (c *imageProber) Probe(parentID string, runConfig *container.Config) (string, error) {
|
||||
if c.cacheBusted {
|
||||
return "", nil
|
||||
}
|
||||
cacheID, err := c.cache.GetCache(parentID, runConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(cacheID) == 0 {
|
||||
logrus.Debugf("[BUILDER] Cache miss: %s", runConfig.Cmd)
|
||||
c.cacheBusted = true
|
||||
return "", nil
|
||||
}
|
||||
logrus.Debugf("[BUILDER] Use cached version: %s", runConfig.Cmd)
|
||||
return cacheID, nil
|
||||
}
|
||||
|
||||
type nopProber struct{}
|
||||
|
||||
func (c *nopProber) Reset() {}
|
||||
|
||||
func (c *nopProber) Probe(_ string, _ *container.Config) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
@ -9,12 +9,9 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -74,20 +71,11 @@ func (b *Builder) performCopy(state *dispatchState, inst copyInstruction) error
|
||||
runConfigWithCommentCmd := copyRunConfig(
|
||||
state.runConfig,
|
||||
withCmdCommentString(fmt.Sprintf("%s %s in %s ", inst.cmdName, srcHash, inst.dest)))
|
||||
if hit, err := b.probeCache(state, runConfigWithCommentCmd); err != nil || hit {
|
||||
containerID, err := b.probeAndCreate(state, runConfigWithCommentCmd)
|
||||
if err != nil || containerID == "" {
|
||||
return err
|
||||
}
|
||||
|
||||
container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
|
||||
Config: runConfigWithCommentCmd,
|
||||
// Set a log config to override any default value set on the daemon
|
||||
HostConfig: &container.HostConfig{LogConfig: defaultLogConfig},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.tmpContainers[container.ID] = struct{}{}
|
||||
|
||||
// Twiddle the destination when it's a relative path - meaning, make it
|
||||
// relative to the WORKINGDIR
|
||||
dest, err := normaliseDest(inst.cmdName, state.runConfig.WorkingDir, inst.dest)
|
||||
@ -96,11 +84,11 @@ func (b *Builder) performCopy(state *dispatchState, inst copyInstruction) error
|
||||
}
|
||||
|
||||
for _, info := range inst.infos {
|
||||
if err := b.docker.CopyOnBuild(container.ID, dest, info.root, info.path, inst.allowLocalDecompression); err != nil {
|
||||
if err := b.docker.CopyOnBuild(containerID, dest, info.root, info.path, inst.allowLocalDecompression); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return b.commitContainer(state, container.ID, runConfigWithCommentCmd)
|
||||
return b.commitContainer(state, containerID, runConfigWithCommentCmd)
|
||||
}
|
||||
|
||||
// For backwards compat, if there's just one info then use it as the
|
||||
@ -186,166 +174,65 @@ func getShell(c *container.Config) []string {
|
||||
return append([]string{}, c.Shell[:]...)
|
||||
}
|
||||
|
||||
// probeCache checks if cache match can be found for current build instruction.
|
||||
// If an image is found, probeCache returns `(true, nil)`.
|
||||
// If no image is found, it returns `(false, nil)`.
|
||||
// If there is any error, it returns `(false, err)`.
|
||||
func (b *Builder) probeCache(dispatchState *dispatchState, runConfig *container.Config) (bool, error) {
|
||||
c := b.imageCache
|
||||
if c == nil || b.options.NoCache || b.cacheBusted {
|
||||
return false, nil
|
||||
}
|
||||
cache, err := c.GetCache(dispatchState.imageID, runConfig)
|
||||
if err != nil {
|
||||
cachedID, err := b.imageProber.Probe(dispatchState.imageID, runConfig)
|
||||
if cachedID == "" || err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(cache) == 0 {
|
||||
logrus.Debugf("[BUILDER] Cache miss: %s", runConfig.Cmd)
|
||||
b.cacheBusted = true
|
||||
return false, nil
|
||||
}
|
||||
|
||||
fmt.Fprint(b.Stdout, " ---> Using cache\n")
|
||||
logrus.Debugf("[BUILDER] Use cached version: %s", runConfig.Cmd)
|
||||
dispatchState.imageID = string(cache)
|
||||
b.buildStages.update(dispatchState.imageID, runConfig)
|
||||
|
||||
dispatchState.imageID = string(cachedID)
|
||||
b.buildStages.update(dispatchState.imageID, runConfig)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var defaultLogConfig = container.LogConfig{Type: "none"}
|
||||
|
||||
func (b *Builder) probeAndCreate(dispatchState *dispatchState, runConfig *container.Config) (string, error) {
|
||||
if hit, err := b.probeCache(dispatchState, runConfig); err != nil || hit {
|
||||
return "", err
|
||||
}
|
||||
// Set a log config to override any default value set on the daemon
|
||||
hostConfig := &container.HostConfig{LogConfig: defaultLogConfig}
|
||||
container, err := b.containerManager.Create(runConfig, hostConfig)
|
||||
return container.ID, err
|
||||
}
|
||||
|
||||
func (b *Builder) create(runConfig *container.Config) (string, error) {
|
||||
resources := container.Resources{
|
||||
CgroupParent: b.options.CgroupParent,
|
||||
CPUShares: b.options.CPUShares,
|
||||
CPUPeriod: b.options.CPUPeriod,
|
||||
CPUQuota: b.options.CPUQuota,
|
||||
CpusetCpus: b.options.CPUSetCPUs,
|
||||
CpusetMems: b.options.CPUSetMems,
|
||||
Memory: b.options.Memory,
|
||||
MemorySwap: b.options.MemorySwap,
|
||||
Ulimits: b.options.Ulimits,
|
||||
}
|
||||
|
||||
// TODO: why not embed a hostconfig in builder?
|
||||
hostConfig := &container.HostConfig{
|
||||
SecurityOpt: b.options.SecurityOpt,
|
||||
Isolation: b.options.Isolation,
|
||||
ShmSize: b.options.ShmSize,
|
||||
Resources: resources,
|
||||
NetworkMode: container.NetworkMode(b.options.NetworkMode),
|
||||
// Set a log config to override any default value set on the daemon
|
||||
LogConfig: defaultLogConfig,
|
||||
ExtraHosts: b.options.ExtraHosts,
|
||||
}
|
||||
|
||||
// Create the container
|
||||
c, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
|
||||
Config: runConfig,
|
||||
HostConfig: hostConfig,
|
||||
})
|
||||
hostConfig := hostConfigFromOptions(b.options)
|
||||
container, err := b.containerManager.Create(runConfig, hostConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, warning := range c.Warnings {
|
||||
// TODO: could this be moved into containerManager.Create() ?
|
||||
for _, warning := range container.Warnings {
|
||||
fmt.Fprintf(b.Stdout, " ---> [Warning] %s\n", warning)
|
||||
}
|
||||
|
||||
b.tmpContainers[c.ID] = struct{}{}
|
||||
fmt.Fprintf(b.Stdout, " ---> Running in %s\n", stringid.TruncateID(c.ID))
|
||||
return c.ID, nil
|
||||
fmt.Fprintf(b.Stdout, " ---> Running in %s\n", stringid.TruncateID(container.ID))
|
||||
return container.ID, nil
|
||||
}
|
||||
|
||||
var errCancelled = errors.New("build cancelled")
|
||||
|
||||
func (b *Builder) run(cID string, cmd []string) (err error) {
|
||||
attached := make(chan struct{})
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
errCh <- b.docker.ContainerAttachRaw(cID, nil, b.Stdout, b.Stderr, true, attached)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-attached:
|
||||
func hostConfigFromOptions(options *types.ImageBuildOptions) *container.HostConfig {
|
||||
resources := container.Resources{
|
||||
CgroupParent: options.CgroupParent,
|
||||
CPUShares: options.CPUShares,
|
||||
CPUPeriod: options.CPUPeriod,
|
||||
CPUQuota: options.CPUQuota,
|
||||
CpusetCpus: options.CPUSetCPUs,
|
||||
CpusetMems: options.CPUSetMems,
|
||||
Memory: options.Memory,
|
||||
MemorySwap: options.MemorySwap,
|
||||
Ulimits: options.Ulimits,
|
||||
}
|
||||
|
||||
finished := make(chan struct{})
|
||||
cancelErrCh := make(chan error, 1)
|
||||
go func() {
|
||||
select {
|
||||
case <-b.clientCtx.Done():
|
||||
logrus.Debugln("Build cancelled, killing and removing container:", cID)
|
||||
b.docker.ContainerKill(cID, 0)
|
||||
b.removeContainer(cID)
|
||||
cancelErrCh <- errCancelled
|
||||
case <-finished:
|
||||
cancelErrCh <- nil
|
||||
}
|
||||
}()
|
||||
|
||||
if err := b.docker.ContainerStart(cID, nil, "", ""); err != nil {
|
||||
close(finished)
|
||||
if cancelErr := <-cancelErrCh; cancelErr != nil {
|
||||
logrus.Debugf("Build cancelled (%v) and got an error from ContainerStart: %v",
|
||||
cancelErr, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Block on reading output from container, stop on err or chan closed
|
||||
if err := <-errCh; err != nil {
|
||||
close(finished)
|
||||
if cancelErr := <-cancelErrCh; cancelErr != nil {
|
||||
logrus.Debugf("Build cancelled (%v) and got an error from errCh: %v",
|
||||
cancelErr, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
waitC, err := b.docker.ContainerWait(b.clientCtx, cID, containerpkg.WaitConditionNotRunning)
|
||||
if err != nil {
|
||||
// Unable to begin waiting for container.
|
||||
close(finished)
|
||||
if cancelErr := <-cancelErrCh; cancelErr != nil {
|
||||
logrus.Debugf("Build cancelled (%v) and unable to begin ContainerWait: %d", cancelErr, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if status := <-waitC; status.ExitCode() != 0 {
|
||||
close(finished)
|
||||
if cancelErr := <-cancelErrCh; cancelErr != nil {
|
||||
logrus.Debugf("Build cancelled (%v) and got a non-zero code from ContainerWait: %d", cancelErr, status.ExitCode())
|
||||
}
|
||||
// TODO: change error type, because jsonmessage.JSONError assumes HTTP
|
||||
return &jsonmessage.JSONError{
|
||||
Message: fmt.Sprintf("The command '%s' returned a non-zero code: %d", strings.Join(cmd, " "), status.ExitCode()),
|
||||
Code: status.ExitCode(),
|
||||
}
|
||||
}
|
||||
close(finished)
|
||||
return <-cancelErrCh
|
||||
}
|
||||
|
||||
func (b *Builder) removeContainer(c string) error {
|
||||
rmConfig := &types.ContainerRmConfig{
|
||||
ForceRemove: true,
|
||||
RemoveVolume: true,
|
||||
}
|
||||
if err := b.docker.ContainerRm(c, rmConfig); err != nil {
|
||||
fmt.Fprintf(b.Stdout, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) clearTmp() {
|
||||
for c := range b.tmpContainers {
|
||||
if err := b.removeContainer(c); err != nil {
|
||||
return
|
||||
}
|
||||
delete(b.tmpContainers, c)
|
||||
fmt.Fprintf(b.Stdout, "Removing intermediate container %s\n", stringid.TruncateID(c))
|
||||
return &container.HostConfig{
|
||||
SecurityOpt: options.SecurityOpt,
|
||||
Isolation: options.Isolation,
|
||||
ShmSize: options.ShmSize,
|
||||
Resources: resources,
|
||||
NetworkMode: container.NetworkMode(options.NetworkMode),
|
||||
// Set a log config to override any default value set on the daemon
|
||||
LogConfig: defaultLogConfig,
|
||||
ExtraHosts: options.ExtraHosts,
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,13 +3,11 @@ package dockerfile
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"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/image"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
@ -18,10 +16,7 @@ type MockBackend struct {
|
||||
containerCreateFunc func(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||
commitFunc func(string, *backend.ContainerCommitConfig) (string, error)
|
||||
getImageFunc func(string) (builder.Image, builder.ReleaseableLayer, error)
|
||||
}
|
||||
|
||||
func (m *MockBackend) TagImageWithReference(image.ID, reference.Named) error {
|
||||
return nil
|
||||
makeImageCacheFunc func(cacheFrom []string) builder.ImageCache
|
||||
}
|
||||
|
||||
func (m *MockBackend) ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error {
|
||||
@ -74,6 +69,13 @@ func (m *MockBackend) GetImageAndReleasableLayer(ctx context.Context, refOrID st
|
||||
return &mockImage{id: "theid"}, &mockLayer{}, nil
|
||||
}
|
||||
|
||||
func (m *MockBackend) MakeImageCache(cacheFrom []string) builder.ImageCache {
|
||||
if m.makeImageCacheFunc != nil {
|
||||
return m.makeImageCacheFunc(cacheFrom)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type mockImage struct {
|
||||
id string
|
||||
config *container.Config
|
||||
|
||||
@ -41,6 +41,7 @@ func Detect(config backend.BuildConfig) (remote builder.Source, dockerfile *pars
|
||||
}
|
||||
|
||||
func newArchiveRemote(rc io.ReadCloser, dockerfilePath string) (builder.Source, *parser.Result, error) {
|
||||
defer rc.Close()
|
||||
c, err := MakeTarSumContext(rc)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/spf13/pflag"
|
||||
@ -46,7 +45,7 @@ func NewCommonOptions() *CommonOptions {
|
||||
// InstallFlags adds flags for the common options on the FlagSet
|
||||
func (commonOpts *CommonOptions) InstallFlags(flags *pflag.FlagSet) {
|
||||
if dockerCertPath == "" {
|
||||
dockerCertPath = cli.ConfigurationDir()
|
||||
dockerCertPath = ConfigurationDir()
|
||||
}
|
||||
|
||||
flags.BoolVarP(&commonOpts.Debug, "debug", "D", false, "Enable debug mode")
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -26,7 +25,7 @@ func TestCommonOptionsInstallFlags(t *testing.T) {
|
||||
}
|
||||
|
||||
func defaultPath(filename string) string {
|
||||
return filepath.Join(cli.ConfigurationDir(), filename)
|
||||
return filepath.Join(ConfigurationDir(), filename)
|
||||
}
|
||||
|
||||
func TestCommonOptionsInstallFlagsWithDefaults(t *testing.T) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package cli
|
||||
package flags
|
||||
|
||||
import (
|
||||
"os"
|
||||
@ -247,6 +247,12 @@ func (cli *Client) UpdateClientVersion(v string) {
|
||||
|
||||
}
|
||||
|
||||
// DaemonHost returns the host associated with this instance of the Client.
|
||||
// This operation doesn't acquire a mutex.
|
||||
func (cli *Client) DaemonHost() string {
|
||||
return cli.host
|
||||
}
|
||||
|
||||
// ParseHost verifies that the given host strings is valid.
|
||||
func ParseHost(host string) (string, string, string, error) {
|
||||
protoAddrParts := strings.SplitN(host, "://", 2)
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
||||
// ContainerWait waits until the specified continer is in a certain state
|
||||
// ContainerWait waits until the specified container is in a certain state
|
||||
// indicated by the given condition, either "not-running" (default),
|
||||
// "next-exit", or "removed".
|
||||
//
|
||||
|
||||
@ -31,6 +31,7 @@ type CommonAPIClient interface {
|
||||
SystemAPIClient
|
||||
VolumeAPIClient
|
||||
ClientVersion() string
|
||||
DaemonHost() string
|
||||
ServerVersion(ctx context.Context) (types.Version, error)
|
||||
UpdateClientVersion(v string)
|
||||
}
|
||||
|
||||
@ -24,14 +24,18 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
|
||||
headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
|
||||
}
|
||||
|
||||
// ensure that the image is tagged
|
||||
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
|
||||
service.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||
}
|
||||
|
||||
// Contact the registry to retrieve digest and platform information
|
||||
if options.QueryRegistry {
|
||||
distributionInspect, err := cli.DistributionInspect(ctx, service.TaskTemplate.ContainerSpec.Image, options.EncodedRegistryAuth)
|
||||
distErr = err
|
||||
if err == nil {
|
||||
// now pin by digest if the image doesn't already contain a digest
|
||||
img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest)
|
||||
if img != "" {
|
||||
if img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest); img != "" {
|
||||
service.TaskTemplate.ContainerSpec.Image = img
|
||||
}
|
||||
// add platforms that are compatible with the service
|
||||
@ -55,22 +59,33 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
|
||||
}
|
||||
|
||||
// imageWithDigestString takes an image string and a digest, and updates
|
||||
// the image string if it didn't originally contain a digest. It assumes
|
||||
// that the image string is not an image ID
|
||||
// the image string if it didn't originally contain a digest. It returns
|
||||
// an empty string if there are no updates.
|
||||
func imageWithDigestString(image string, dgst digest.Digest) string {
|
||||
ref, err := reference.ParseAnyReference(image)
|
||||
namedRef, err := reference.ParseNormalizedNamed(image)
|
||||
if err == nil {
|
||||
if _, isCanonical := ref.(reference.Canonical); !isCanonical {
|
||||
namedRef, _ := ref.(reference.Named)
|
||||
if _, isCanonical := namedRef.(reference.Canonical); !isCanonical {
|
||||
// ensure that image gets a default tag if none is provided
|
||||
img, err := reference.WithDigest(namedRef, dgst)
|
||||
if err == nil {
|
||||
return img.String()
|
||||
return reference.FamiliarString(img)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// imageWithTagString takes an image string, and returns a tagged image
|
||||
// string, adding a 'latest' tag if one was not provided. It returns an
|
||||
// emptry string if a canonical reference was provided
|
||||
func imageWithTagString(image string) string {
|
||||
namedRef, err := reference.ParseNormalizedNamed(image)
|
||||
if err == nil {
|
||||
return reference.FamiliarString(reference.TagNameOnly(namedRef))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// updateServicePlatforms updates the Platforms in swarm.Placement to list
|
||||
// all compatible platforms for the service, as found in distributionInspect
|
||||
// and returns a pointer to the new or updated swarm.Placement struct
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
@ -121,3 +122,92 @@ func TestServiceCreateCompatiblePlatforms(t *testing.T) {
|
||||
t.Fatalf("expected `service_amd64`, got %s", r.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceCreateDigestPinning(t *testing.T) {
|
||||
dgst := "sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96"
|
||||
dgstAlt := "sha256:37ffbf3f7497c07584dc9637ffbf3f7497c0758c0537ffbf3f7497c0c88e2bb7"
|
||||
serviceCreateImage := ""
|
||||
pinByDigestTests := []struct {
|
||||
img string // input image provided by the user
|
||||
expected string // expected image after digest pinning
|
||||
}{
|
||||
// default registry returns familiar string
|
||||
{"docker.io/library/alpine", "alpine:latest@" + dgst},
|
||||
// provided tag is preserved and digest added
|
||||
{"alpine:edge", "alpine:edge@" + dgst},
|
||||
// image with provided alternative digest remains unchanged
|
||||
{"alpine@" + dgstAlt, "alpine@" + dgstAlt},
|
||||
// image with provided tag and alternative digest remains unchanged
|
||||
{"alpine:edge@" + dgstAlt, "alpine:edge@" + dgstAlt},
|
||||
// image on alternative registry does not result in familiar string
|
||||
{"alternate.registry/library/alpine", "alternate.registry/library/alpine:latest@" + dgst},
|
||||
// unresolvable image does not get a digest
|
||||
{"cannotresolve", "cannotresolve:latest"},
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
if strings.HasPrefix(req.URL.Path, "/services/create") {
|
||||
// reset and set image received by the service create endpoint
|
||||
serviceCreateImage = ""
|
||||
var service swarm.ServiceSpec
|
||||
if err := json.NewDecoder(req.Body).Decode(&service); err != nil {
|
||||
return nil, fmt.Errorf("could not parse service create request")
|
||||
}
|
||||
serviceCreateImage = service.TaskTemplate.ContainerSpec.Image
|
||||
|
||||
b, err := json.Marshal(types.ServiceCreateResponse{
|
||||
ID: "service_id",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewReader(b)),
|
||||
}, nil
|
||||
} else if strings.HasPrefix(req.URL.Path, "/distribution/cannotresolve") {
|
||||
// unresolvable image
|
||||
return nil, fmt.Errorf("cannot resolve image")
|
||||
} else if strings.HasPrefix(req.URL.Path, "/distribution/") {
|
||||
// resolvable images
|
||||
b, err := json.Marshal(registrytypes.DistributionInspect{
|
||||
Descriptor: v1.Descriptor{
|
||||
Digest: digest.Digest(dgst),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewReader(b)),
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected URL '%s'", req.URL.Path)
|
||||
}),
|
||||
}
|
||||
|
||||
// run pin by digest tests
|
||||
for _, p := range pinByDigestTests {
|
||||
r, err := client.ServiceCreate(context.Background(), swarm.ServiceSpec{
|
||||
TaskTemplate: swarm.TaskSpec{
|
||||
ContainerSpec: swarm.ContainerSpec{
|
||||
Image: p.img,
|
||||
},
|
||||
},
|
||||
}, types.ServiceCreateOptions{QueryRegistry: true})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if r.ID != "service_id" {
|
||||
t.Fatalf("expected `service_id`, got %s", r.ID)
|
||||
}
|
||||
|
||||
if p.expected != serviceCreateImage {
|
||||
t.Fatalf("expected image %s, got %s", p.expected, serviceCreateImage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,11 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
|
||||
|
||||
query.Set("version", strconv.FormatUint(version.Index, 10))
|
||||
|
||||
// ensure that the image is tagged
|
||||
if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
|
||||
service.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||
}
|
||||
|
||||
// Contact the registry to retrieve digest and platform information
|
||||
// This happens only when the image has changed
|
||||
if options.QueryRegistry {
|
||||
@ -42,8 +47,7 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
|
||||
distErr = err
|
||||
if err == nil {
|
||||
// now pin by digest if the image doesn't already contain a digest
|
||||
img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest)
|
||||
if img != "" {
|
||||
if img := imageWithDigestString(service.TaskTemplate.ContainerSpec.Image, distributionInspect.Descriptor.Digest); img != "" {
|
||||
service.TaskTemplate.ContainerSpec.Image = img
|
||||
}
|
||||
// add platforms that are compatible with the service
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/pkg/chrootarchive"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/symlink"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
@ -220,7 +221,9 @@ func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
|
||||
warnings = append(warnings, err.Error())
|
||||
} else if shmPath != "" {
|
||||
if err := unmount(shmPath); err != nil && !os.IsNotExist(err) {
|
||||
warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err))
|
||||
if mounted, mErr := mount.Mounted(shmPath); mounted || mErr != nil {
|
||||
warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ const (
|
||||
WaitConditionRemoved
|
||||
)
|
||||
|
||||
// Wait waits until the continer is in a certain state indicated by the given
|
||||
// Wait waits until the container is in a certain state indicated by the given
|
||||
// condition. A context must be used for cancelling the request, controlling
|
||||
// timeouts, and avoiding goroutine leaks. Wait must be called without holding
|
||||
// the state lock. Returns a channel from which the caller will receive the
|
||||
|
||||
@ -12,7 +12,7 @@ RUN update-alternatives --install /usr/bin/go go /usr/lib/go-1.6/bin/go 100
|
||||
# Install Go
|
||||
# aarch64 doesn't have official go binaries, so use the version of go installed from
|
||||
# the image to build go from source.
|
||||
ENV GO_VERSION 1.7.5
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash
|
||||
|
||||
@ -9,7 +9,7 @@ RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools bu
|
||||
# Install Go
|
||||
# aarch64 doesn't have official go binaries, so use the version of go installed from
|
||||
# the image to build go from source.
|
||||
ENV GO_VERSION 1.7.5
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash
|
||||
|
||||
@ -11,7 +11,7 @@ RUN update-alternatives --install /usr/bin/go go /usr/lib/go-1.6/bin/go 100
|
||||
# Install Go
|
||||
# aarch64 doesn't have official go binaries, so use the version of go installed from
|
||||
# the image to build go from source.
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash
|
||||
|
||||
@ -9,7 +9,7 @@ RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools bu
|
||||
# Install Go
|
||||
# aarch64 doesn't have official go binaries, so use the version of go installed from
|
||||
# the image to build go from source.
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash
|
||||
|
||||
@ -10,7 +10,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config vim-common libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list.d
|
||||
RUN apt-get update && apt-get install -y -t wheezy-backports btrfs-tools --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM ubuntu:trusty
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM ubuntu:xenial
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config vim-common libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM ubuntu:yakkety
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config vim-common libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM ubuntu:zesty
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config vim-common libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.7.5
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
# GOARM is the ARM architecture version which is unrelated to the above Golang version
|
||||
ENV GOARM 6
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" | tar xzC /usr/local
|
||||
|
||||
@ -6,7 +6,7 @@ FROM armhf/ubuntu:trusty
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM armhf/ubuntu:xenial
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config vim-common libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM armhf/ubuntu:yakkety
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config vim-common libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM ppc64le/ubuntu:trusty
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM ppc64le/ubuntu:xenial
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libseccomp-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM ppc64le/ubuntu:yakkety
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev pkg-config vim-common libseccomp-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM s390x/ubuntu:xenial
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config libsystemd-dev vim-common --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ FROM s390x/ubuntu:yakkety
|
||||
|
||||
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential cmake curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev pkg-config libsystemd-dev vim-common --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GO_VERSION 1.7.5
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ FROM amazonlinux:latest
|
||||
RUN yum groupinstall -y "Development Tools"
|
||||
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.7.5
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ RUN yum groupinstall -y "Development Tools"
|
||||
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
|
||||
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ RUN dnf -y upgrade
|
||||
RUN dnf install -y @development-tools fedora-packager
|
||||
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ RUN dnf -y upgrade
|
||||
RUN dnf install -y @development-tools fedora-packager
|
||||
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ FROM opensuse:13.2
|
||||
RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build
|
||||
RUN zypper --non-interactive install libbtrfs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkg-config selinux-policy selinux-policy-devel systemd-devel tar git cmake vim systemd-rpm-macros
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ RUN yum install -y kernel-uek-devel-4.1.12-32.el6uek
|
||||
RUN yum groupinstall -y "Development Tools"
|
||||
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ FROM oraclelinux:7
|
||||
RUN yum groupinstall -y "Development Tools"
|
||||
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ FROM photon:1.0
|
||||
RUN tdnf install -y wget curl ca-certificates gzip make rpm-build sed gcc linux-api-headers glibc-devel binutils libseccomp libltdl-devel elfutils
|
||||
RUN tdnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkg-config selinux-policy selinux-policy-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ RUN yum groupinstall --skip-broken -y "Development Tools"
|
||||
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
|
||||
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.7.4
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
#
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/ppc64le/generate.sh"!
|
||||
#
|
||||
|
||||
FROM ppc64le/centos:7
|
||||
|
||||
RUN yum groupinstall -y "Development Tools"
|
||||
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
|
||||
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
|
||||
ENV DOCKER_BUILDTAGS pkcs11 seccomp selinux
|
||||
ENV RUNC_BUILDTAGS seccomp selinux
|
||||
|
||||
@ -8,7 +8,7 @@ RUN dnf -y upgrade
|
||||
RUN dnf install -y @development-tools fedora-packager
|
||||
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel systemd-devel tar git cmake
|
||||
|
||||
ENV GO_VERSION 1.8.1
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ set -e
|
||||
# usage: ./generate.sh [versions]
|
||||
# ie: ./generate.sh
|
||||
# to update all Dockerfiles in this directory
|
||||
# or: ./generate.sh
|
||||
# to only update fedora-23/Dockerfile
|
||||
# or: ./generate.sh centos-7
|
||||
# to only update centos-7/Dockerfile
|
||||
# or: ./generate.sh fedora-newversion
|
||||
# to create a new folder and a Dockerfile within it
|
||||
|
||||
@ -20,8 +20,9 @@ versions=( "${versions[@]%/}" )
|
||||
for version in "${versions[@]}"; do
|
||||
distro="${version%-*}"
|
||||
suite="${version##*-}"
|
||||
from="${distro}:${suite}"
|
||||
from="ppc64le/${distro}:${suite}"
|
||||
installer=yum
|
||||
|
||||
if [[ "$distro" == "fedora" ]]; then
|
||||
installer=dnf
|
||||
fi
|
||||
@ -33,7 +34,7 @@ for version in "${versions[@]}"; do
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/ppc64le/generate.sh"!
|
||||
#
|
||||
|
||||
FROM ppc64le/$from
|
||||
FROM $from
|
||||
EOF
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
@ -42,14 +43,33 @@ for version in "${versions[@]}"; do
|
||||
runcBuildTags=
|
||||
|
||||
case "$from" in
|
||||
# add centos and opensuse tools install bits later
|
||||
fedora:*)
|
||||
ppc64le/fedora:*)
|
||||
echo "RUN ${installer} -y upgrade" >> "$version/Dockerfile"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
case "$from" in
|
||||
ppc64le/centos:*)
|
||||
# get "Development Tools" packages dependencies
|
||||
echo 'RUN yum groupinstall -y "Development Tools"' >> "$version/Dockerfile"
|
||||
|
||||
if [[ "$version" == "centos-7" ]]; then
|
||||
echo 'RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs' >> "$version/Dockerfile"
|
||||
fi
|
||||
;;
|
||||
ppc64le/opensuse:*)
|
||||
# Add the ppc64le repo (hopefully the image is updated soon)
|
||||
# get rpm-build and curl packages and dependencies
|
||||
echo "RUN zypper addrepo -n ppc64le-oss -f https://download.opensuse.org/ports/ppc/distribution/leap/${suite}/repo/oss/ ppc64le-oss" >> "$version/Dockerfile"
|
||||
echo "RUN zypper addrepo -n ppc64le-updates -f https://download.opensuse.org/ports/update/${suite}/ ppc64le-updates" >> "$version/Dockerfile"
|
||||
echo 'RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build' >> "$version/Dockerfile"
|
||||
;;
|
||||
*)
|
||||
echo "RUN ${installer} install -y @development-tools fedora-packager" >> "$version/Dockerfile"
|
||||
;;
|
||||
esac
|
||||
|
||||
# this list is sorted alphabetically; please keep it that way
|
||||
packages=(
|
||||
btrfs-progs-devel # for "btrfs/ioctl.h" (and "version.h" if possible)
|
||||
device-mapper-devel # for "libdevmapper.h"
|
||||
@ -60,15 +80,20 @@ for version in "${versions[@]}"; do
|
||||
pkgconfig # for the pkg-config command
|
||||
selinux-policy
|
||||
selinux-policy-devel
|
||||
sqlite-devel # for "sqlite3.h"
|
||||
systemd-devel # for "sd-journal.h" and libraries
|
||||
tar # older versions of dev-tools do not have tar
|
||||
git # required for containerd and runc clone
|
||||
cmake # tini build
|
||||
vim-common # tini build
|
||||
)
|
||||
|
||||
# opensuse does not have the right libseccomp libs
|
||||
case "$from" in
|
||||
# add opensuse libseccomp package substitution when adding build support
|
||||
ppc64le/opensuse:*)
|
||||
packages=( "${packages[@]/libseccomp-devel}" )
|
||||
runcBuildTags="selinux"
|
||||
;;
|
||||
*)
|
||||
extraBuildTags+=' seccomp'
|
||||
runcBuildTags="seccomp selinux"
|
||||
@ -76,7 +101,17 @@ for version in "${versions[@]}"; do
|
||||
esac
|
||||
|
||||
case "$from" in
|
||||
# add opensuse btrfs package substitution when adding build support
|
||||
ppc64le/opensuse:*)
|
||||
packages=( "${packages[@]/btrfs-progs-devel/libbtrfs-devel}" )
|
||||
packages=( "${packages[@]/pkgconfig/pkg-config}" )
|
||||
packages=( "${packages[@]/vim-common/vim}" )
|
||||
if [[ "$from" == "ppc64le/opensuse:13."* ]]; then
|
||||
packages+=( systemd-rpm-macros )
|
||||
fi
|
||||
|
||||
# use zypper
|
||||
echo "RUN zypper --non-interactive install ${packages[*]}" >> "$version/Dockerfile"
|
||||
;;
|
||||
*)
|
||||
echo "RUN ${installer} install -y ${packages[*]}" >> "$version/Dockerfile"
|
||||
;;
|
||||
@ -84,12 +119,15 @@ for version in "${versions[@]}"; do
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
|
||||
awk '$1 == "ENV" && $2 == "GO_VERSION" { print; exit }' ../../../../Dockerfile.ppc64le >> "$version/Dockerfile"
|
||||
echo 'RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" | tar xzC /usr/local' >> "$version/Dockerfile"
|
||||
echo 'ENV PATH $PATH:/usr/local/go/bin' >> "$version/Dockerfile"
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
echo 'ENV AUTO_GOPATH 1' >> "$version/Dockerfile"
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
# print build tags in alphabetical order
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/ppc64le/generate.sh"!
|
||||
#
|
||||
|
||||
FROM ppc64le/opensuse:42.1
|
||||
|
||||
RUN zypper addrepo -n ppc64le-oss -f https://download.opensuse.org/ports/ppc/distribution/leap/42.1/repo/oss/ ppc64le-oss
|
||||
RUN zypper addrepo -n ppc64le-updates -f https://download.opensuse.org/ports/update/42.1/ ppc64le-updates
|
||||
RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build
|
||||
RUN zypper --non-interactive install libbtrfs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkg-config selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar git cmake vim
|
||||
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
|
||||
ENV DOCKER_BUILDTAGS pkcs11 selinux
|
||||
ENV RUNC_BUILDTAGS selinux
|
||||
|
||||
10
components/engine/contrib/builder/rpm/s390x/build.sh
Executable file
10
components/engine/contrib/builder/rpm/s390x/build.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||
|
||||
set -x
|
||||
./generate.sh
|
||||
for d in */; do
|
||||
docker build -t "dockercore/builder-rpm:$(basename "$d")" "$d"
|
||||
done
|
||||
@ -0,0 +1,19 @@
|
||||
#
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/s390x/generate.sh"!
|
||||
#
|
||||
|
||||
FROM sinenomine/clefos-base-s390x
|
||||
|
||||
|
||||
RUN touch /var/lib/rpm/* && yum groupinstall -y "Development Tools"
|
||||
RUN touch /var/lib/rpm/* && yum install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar git cmake vim-common
|
||||
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
|
||||
ENV DOCKER_BUILDTAGS pkcs11 seccomp selinux
|
||||
ENV RUNC_BUILDTAGS seccomp selinux
|
||||
RUN ln -s /usr/bin/gcc /usr/bin/s390x-linux-gnu-gcc
|
||||
145
components/engine/contrib/builder/rpm/s390x/generate.sh
Executable file
145
components/engine/contrib/builder/rpm/s390x/generate.sh
Executable file
@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# This file is used to auto-generate Dockerfiles for making rpms via 'make rpm'
|
||||
#
|
||||
# usage: ./generate.sh [versions]
|
||||
# ie: ./generate.sh
|
||||
# to update all Dockerfiles in this directory
|
||||
# or: ./generate.sh centos-7
|
||||
# to only update centos-7/Dockerfile
|
||||
# or: ./generate.sh fedora-newversion
|
||||
# to create a new folder and a Dockerfile within it
|
||||
|
||||
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||
|
||||
versions=( "$@" )
|
||||
if [ ${#versions[@]} -eq 0 ]; then
|
||||
versions=( */ )
|
||||
fi
|
||||
versions=( "${versions[@]%/}" )
|
||||
|
||||
for version in "${versions[@]}"; do
|
||||
echo "${versions[@]}"
|
||||
distro="${version%-*}"
|
||||
suite="${version##*-}"
|
||||
case "$distro" in
|
||||
*opensuse*)
|
||||
from="opensuse/s390x:tumbleweed"
|
||||
;;
|
||||
*clefos*)
|
||||
from="sinenomine/${distro}"
|
||||
;;
|
||||
*)
|
||||
echo No appropriate or supported image available.
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
installer=yum
|
||||
|
||||
mkdir -p "$version"
|
||||
echo "$version -> FROM $from"
|
||||
cat > "$version/Dockerfile" <<-EOF
|
||||
#
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/s390x/generate.sh"!
|
||||
#
|
||||
|
||||
FROM $from
|
||||
|
||||
EOF
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
extraBuildTags='pkcs11'
|
||||
runcBuildTags=
|
||||
|
||||
case "$from" in
|
||||
*clefos*)
|
||||
# Fix for RHBZ #1213602 + get "Development Tools" packages dependencies
|
||||
echo 'RUN touch /var/lib/rpm/* && yum groupinstall -y "Development Tools"' >> "$version/Dockerfile"
|
||||
;;
|
||||
*opensuse*)
|
||||
echo "RUN zypper ar https://download.opensuse.org/ports/zsystems/tumbleweed/repo/oss/ tumbleweed" >> "$version/Dockerfile"
|
||||
# get rpm-build and curl packages and dependencies
|
||||
echo 'RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build' >> "$version/Dockerfile"
|
||||
;;
|
||||
*)
|
||||
echo No appropriate or supported image available.
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
packages=(
|
||||
btrfs-progs-devel # for "btrfs/ioctl.h" (and "version.h" if possible)
|
||||
device-mapper-devel # for "libdevmapper.h"
|
||||
glibc-static
|
||||
libseccomp-devel # for "seccomp.h" & "libseccomp.so"
|
||||
libselinux-devel # for "libselinux.so"
|
||||
libtool-ltdl-devel # for pkcs11 "ltdl.h"
|
||||
pkgconfig # for the pkg-config command
|
||||
selinux-policy
|
||||
selinux-policy-devel
|
||||
sqlite-devel # for "sqlite3.h"
|
||||
systemd-devel # for "sd-journal.h" and libraries
|
||||
tar # older versions of dev-tools do not have tar
|
||||
git # required for containerd and runc clone
|
||||
cmake # tini build
|
||||
vim-common # tini build
|
||||
)
|
||||
|
||||
case "$from" in
|
||||
*clefos*)
|
||||
extraBuildTags+=' seccomp'
|
||||
runcBuildTags="seccomp selinux"
|
||||
;;
|
||||
*opensuse*)
|
||||
packages=( "${packages[@]/libseccomp-devel}" )
|
||||
runcBuildTags="selinux"
|
||||
;;
|
||||
*)
|
||||
echo No appropriate or supported image available.
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$from" in
|
||||
*clefos*)
|
||||
# Same RHBZ fix needed on all yum lines
|
||||
echo "RUN touch /var/lib/rpm/* && ${installer} install -y ${packages[*]}" >> "$version/Dockerfile"
|
||||
;;
|
||||
*opensuse*)
|
||||
packages=( "${packages[@]/btrfs-progs-devel/libbtrfs-devel}" )
|
||||
packages=( "${packages[@]/pkgconfig/pkg-config}" )
|
||||
packages=( "${packages[@]/vim-common/vim}" )
|
||||
|
||||
packages+=( systemd-rpm-macros ) # for use of >= opensuse:13.*
|
||||
|
||||
# use zypper
|
||||
echo "RUN zypper --non-interactive install ${packages[*]}" >> "$version/Dockerfile"
|
||||
;;
|
||||
*)
|
||||
echo No appropriate or supported image available.
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
awk '$1 == "ENV" && $2 == "GO_VERSION" { print; exit }' ../../../../Dockerfile.s390x >> "$version/Dockerfile"
|
||||
echo 'RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" | tar xzC /usr/local' >> "$version/Dockerfile"
|
||||
echo 'ENV PATH $PATH:/usr/local/go/bin' >> "$version/Dockerfile"
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
echo 'ENV AUTO_GOPATH 1' >> "$version/Dockerfile"
|
||||
|
||||
echo >> "$version/Dockerfile"
|
||||
|
||||
# print build tags in alphabetical order
|
||||
buildTags=$( echo "selinux $extraBuildTags" | xargs -n1 | sort -n | tr '\n' ' ' | sed -e 's/[[:space:]]*$//' )
|
||||
|
||||
echo "ENV DOCKER_BUILDTAGS $buildTags" >> "$version/Dockerfile"
|
||||
echo "ENV RUNC_BUILDTAGS $runcBuildTags" >> "$version/Dockerfile"
|
||||
# TODO: Investigate why "s390x-linux-gnu-gcc" is required
|
||||
echo "RUN ln -s /usr/bin/gcc /usr/bin/s390x-linux-gnu-gcc" >> "$version/Dockerfile"
|
||||
done
|
||||
@ -0,0 +1,20 @@
|
||||
#
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/s390x/generate.sh"!
|
||||
#
|
||||
|
||||
FROM opensuse/s390x:tumbleweed
|
||||
|
||||
|
||||
RUN zypper ar https://download.opensuse.org/ports/zsystems/tumbleweed/repo/oss/ tumbleweed
|
||||
RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build
|
||||
RUN zypper --non-interactive install libbtrfs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkg-config selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar git cmake vim systemd-rpm-macros
|
||||
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" | tar xzC /usr/local
|
||||
ENV PATH $PATH:/usr/local/go/bin
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
|
||||
ENV DOCKER_BUILDTAGS pkcs11 selinux
|
||||
ENV RUNC_BUILDTAGS selinux
|
||||
RUN ln -s /usr/bin/gcc /usr/bin/s390x-linux-gnu-gcc
|
||||
@ -157,6 +157,7 @@ while [ $# -gt 0 ]; do
|
||||
echo "skipping existing ${layerId:0:12}"
|
||||
continue
|
||||
fi
|
||||
token="$(curl -fsSL "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$image:pull" | jq --raw-output '.token')"
|
||||
curl -fSL --progress \
|
||||
-H "Authorization: Bearer $token" \
|
||||
"https://registry-1.docker.io/v2/$image/blobs/$layerDigest" \
|
||||
@ -229,6 +230,7 @@ while [ $# -gt 0 ]; do
|
||||
echo "skipping existing ${layerId:0:12}"
|
||||
continue
|
||||
fi
|
||||
token="$(curl -fsSL "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$image:pull" | jq --raw-output '.token')"
|
||||
curl -fSL --progress -H "Authorization: Bearer $token" "https://registry-1.docker.io/v2/$image/blobs/$imageLayer" -o "$dir/$layerId/layer.tar" # -C -
|
||||
done
|
||||
;;
|
||||
|
||||
@ -10,6 +10,23 @@
|
||||
<string>Dockerfile</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.other.special-method.dockerfile</string>
|
||||
</dict>
|
||||
<key>2</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.other.special-method.dockerfile</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>match</key>
|
||||
<string>^\s*\b(FROM)\b.*?\b(AS)\b</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
|
||||
@ -31,7 +31,11 @@ func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerA
|
||||
return err
|
||||
}
|
||||
if container.IsPaused() {
|
||||
err := fmt.Errorf("Container %s is paused. Unpause the container before attach", prefixOrName)
|
||||
err := fmt.Errorf("Container %s is paused, unpause the container before attach.", prefixOrName)
|
||||
return errors.NewRequestConflictError(err)
|
||||
}
|
||||
if container.IsRestarting() {
|
||||
err := fmt.Errorf("Container %s is restarting, wait until the container is running.", prefixOrName)
|
||||
return errors.NewRequestConflictError(err)
|
||||
}
|
||||
|
||||
|
||||
@ -36,9 +36,9 @@ func networkFromGRPC(n *swarmapi.Network) types.Network {
|
||||
IPAMOptions: ipamFromGRPC(n.IPAM),
|
||||
}
|
||||
|
||||
if n.Spec.ConfigFrom != "" {
|
||||
if n.Spec.GetNetwork() != "" {
|
||||
network.Spec.ConfigFrom = &networktypes.ConfigReference{
|
||||
Network: n.Spec.ConfigFrom,
|
||||
Network: n.Spec.GetNetwork(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,9 +169,9 @@ func BasicNetworkFromGRPC(n swarmapi.Network) basictypes.NetworkResource {
|
||||
Labels: n.Spec.Annotations.Labels,
|
||||
}
|
||||
|
||||
if n.Spec.ConfigFrom != "" {
|
||||
if n.Spec.GetNetwork() != "" {
|
||||
nr.ConfigFrom = networktypes.ConfigReference{
|
||||
Network: n.Spec.ConfigFrom,
|
||||
Network: n.Spec.GetNetwork(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,7 +221,9 @@ func BasicNetworkCreateToGRPC(create basictypes.NetworkCreateRequest) swarmapi.N
|
||||
ns.IPAM.Configs = ipamSpec
|
||||
}
|
||||
if create.ConfigFrom != nil {
|
||||
ns.ConfigFrom = create.ConfigFrom.Network
|
||||
ns.ConfigFrom = &swarmapi.NetworkSpec_Network{
|
||||
Network: create.ConfigFrom.Network,
|
||||
}
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
@ -100,7 +100,6 @@ func serviceSpecFromGRPC(spec *swarmapi.ServiceSpec) (*types.ServiceSpec, error)
|
||||
return nil, fmt.Errorf("unknown task runtime type: %s", t.Generic.Payload.TypeUrl)
|
||||
}
|
||||
|
||||
taskTemplate.RuntimeData = t.Generic.Payload.Value
|
||||
default:
|
||||
return nil, fmt.Errorf("error creating service; unsupported runtime %T", t)
|
||||
}
|
||||
@ -176,7 +175,6 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
|
||||
Kind: string(types.RuntimePlugin),
|
||||
Payload: &gogotypes.Any{
|
||||
TypeUrl: string(types.RuntimeURLPlugin),
|
||||
Value: s.TaskTemplate.RuntimeData,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -597,9 +597,9 @@ func (c *containerConfig) networkCreateRequest(name string) (clustertypes.Networ
|
||||
Scope: netconst.SwarmScope,
|
||||
}
|
||||
|
||||
if na.Network.Spec.ConfigFrom != "" {
|
||||
if na.Network.Spec.GetNetwork() != "" {
|
||||
options.ConfigFrom = &network.ConfigReference{
|
||||
Network: na.Network.Spec.ConfigFrom,
|
||||
Network: na.Network.Spec.GetNetwork(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -88,10 +88,6 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if !req.ForceNewCluster {
|
||||
clearPersistentState(c.root)
|
||||
}
|
||||
|
||||
nr, err := c.newNodeRunner(nodeStartConfig{
|
||||
forceNewCluster: req.ForceNewCluster,
|
||||
autolock: req.AutoLockManagers,
|
||||
@ -109,16 +105,14 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) {
|
||||
c.mu.Unlock()
|
||||
|
||||
if err := <-nr.Ready(); err != nil {
|
||||
c.mu.Lock()
|
||||
c.nr = nil
|
||||
c.mu.Unlock()
|
||||
if !req.ForceNewCluster { // if failure on first attempt don't keep state
|
||||
if err := clearPersistentState(c.root); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
c.mu.Lock()
|
||||
c.nr = nil
|
||||
c.mu.Unlock()
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
state := nr.State()
|
||||
@ -166,8 +160,6 @@ func (c *Cluster) Join(req types.JoinRequest) error {
|
||||
return err
|
||||
}
|
||||
|
||||
clearPersistentState(c.root)
|
||||
|
||||
nr, err := c.newNodeRunner(nodeStartConfig{
|
||||
RemoteAddr: req.RemoteAddrs[0],
|
||||
ListenAddr: net.JoinHostPort(listenHost, listenPort),
|
||||
@ -193,6 +185,9 @@ func (c *Cluster) Join(req types.JoinRequest) error {
|
||||
c.mu.Lock()
|
||||
c.nr = nil
|
||||
c.mu.Unlock()
|
||||
if err := clearPersistentState(c.root); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@ -64,31 +64,35 @@ type cmdProbe struct {
|
||||
|
||||
// exec the healthcheck command in the container.
|
||||
// Returns the exit code and probe output (if any)
|
||||
func (p *cmdProbe) run(ctx context.Context, d *Daemon, container *container.Container) (*types.HealthcheckResult, error) {
|
||||
|
||||
cmdSlice := strslice.StrSlice(container.Config.Healthcheck.Test)[1:]
|
||||
func (p *cmdProbe) run(ctx context.Context, d *Daemon, cntr *container.Container) (*types.HealthcheckResult, error) {
|
||||
cmdSlice := strslice.StrSlice(cntr.Config.Healthcheck.Test)[1:]
|
||||
if p.shell {
|
||||
cmdSlice = append(getShell(container.Config), cmdSlice...)
|
||||
cmdSlice = append(getShell(cntr.Config), cmdSlice...)
|
||||
}
|
||||
entrypoint, args := d.getEntrypointAndArgs(strslice.StrSlice{}, cmdSlice)
|
||||
execConfig := exec.NewConfig()
|
||||
execConfig.OpenStdin = false
|
||||
execConfig.OpenStdout = true
|
||||
execConfig.OpenStderr = true
|
||||
execConfig.ContainerID = container.ID
|
||||
execConfig.ContainerID = cntr.ID
|
||||
execConfig.DetachKeys = []byte{}
|
||||
execConfig.Entrypoint = entrypoint
|
||||
execConfig.Args = args
|
||||
execConfig.Tty = false
|
||||
execConfig.Privileged = false
|
||||
execConfig.User = container.Config.User
|
||||
execConfig.Env = container.Config.Env
|
||||
execConfig.User = cntr.Config.User
|
||||
|
||||
d.registerExecCommand(container, execConfig)
|
||||
d.LogContainerEvent(container, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "))
|
||||
linkedEnv, err := d.setupLinkedContainers(cntr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
execConfig.Env = container.ReplaceOrAppendEnvValues(cntr.CreateDaemonEnvironment(execConfig.Tty, linkedEnv), execConfig.Env)
|
||||
|
||||
d.registerExecCommand(cntr, execConfig)
|
||||
d.LogContainerEvent(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "))
|
||||
|
||||
output := &limitedBuffer{}
|
||||
err := d.ContainerExecStart(ctx, execConfig.ID, nil, output, output)
|
||||
err = d.ContainerExecStart(ctx, execConfig.ID, nil, output, output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -97,7 +101,7 @@ func (p *cmdProbe) run(ctx context.Context, d *Daemon, container *container.Cont
|
||||
return nil, err
|
||||
}
|
||||
if info.ExitCode == nil {
|
||||
return nil, fmt.Errorf("Healthcheck for container %s has no exit code!", container.ID)
|
||||
return nil, fmt.Errorf("Healthcheck for container %s has no exit code!", cntr.ID)
|
||||
}
|
||||
// Note: Go's json package will handle invalid UTF-8 for us
|
||||
out := output.String()
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package loggerutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
@ -11,6 +12,7 @@ import (
|
||||
// RotateFileWriter is Logger implementation for default Docker logging.
|
||||
type RotateFileWriter struct {
|
||||
f *os.File // store for closing
|
||||
closed bool
|
||||
mu sync.Mutex
|
||||
capacity int64 //maximum size of each file
|
||||
currentSize int64 // current size of the latest file
|
||||
@ -42,6 +44,10 @@ func NewRotateFileWriter(logPath string, capacity int64, maxFiles int) (*RotateF
|
||||
//WriteLog write log message to File
|
||||
func (w *RotateFileWriter) Write(message []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
if w.closed {
|
||||
w.mu.Unlock()
|
||||
return -1, errors.New("cannot write because the output file was closed")
|
||||
}
|
||||
if err := w.checkCapacityAndRotate(); err != nil {
|
||||
w.mu.Unlock()
|
||||
return -1, err
|
||||
@ -100,6 +106,8 @@ func rotate(name string, maxFiles int) error {
|
||||
|
||||
// LogPath returns the location the given writer logs to.
|
||||
func (w *RotateFileWriter) LogPath() string {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.f.Name()
|
||||
}
|
||||
|
||||
@ -120,5 +128,14 @@ func (w *RotateFileWriter) NotifyRotateEvict(sub chan interface{}) {
|
||||
|
||||
// Close closes underlying file and signals all readers to stop.
|
||||
func (w *RotateFileWriter) Close() error {
|
||||
return w.f.Close()
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if w.closed {
|
||||
return nil
|
||||
}
|
||||
if err := w.f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
w.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
|
||||
// In s.Windows.Resources
|
||||
cpuShares := uint16(c.HostConfig.CPUShares)
|
||||
cpuPercent := uint8(c.HostConfig.CPUPercent)
|
||||
cpuMaximum := uint16(c.HostConfig.CPUPercent) * 100
|
||||
cpuCount := uint64(c.HostConfig.CPUCount)
|
||||
if c.HostConfig.NanoCPUs > 0 {
|
||||
if isHyperV {
|
||||
@ -128,21 +128,24 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
leftoverNanoCPUs := c.HostConfig.NanoCPUs % 1e9
|
||||
if leftoverNanoCPUs != 0 {
|
||||
cpuCount++
|
||||
cpuPercent = uint8(c.HostConfig.NanoCPUs * 100 / int64(cpuCount) / 1e9)
|
||||
cpuMaximum = uint16(c.HostConfig.NanoCPUs / int64(cpuCount) / (1e9 / 10000))
|
||||
if cpuMaximum < 1 {
|
||||
// The requested NanoCPUs is so small that we rounded to 0, use 1 instead
|
||||
cpuMaximum = 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cpuPercent = uint8(c.HostConfig.NanoCPUs * 100 / int64(sysinfo.NumCPU()) / 1e9)
|
||||
|
||||
if cpuPercent < 1 {
|
||||
cpuMaximum = uint16(c.HostConfig.NanoCPUs / int64(sysinfo.NumCPU()) / (1e9 / 10000))
|
||||
if cpuMaximum < 1 {
|
||||
// The requested NanoCPUs is so small that we rounded to 0, use 1 instead
|
||||
cpuPercent = 1
|
||||
cpuMaximum = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
memoryLimit := uint64(c.HostConfig.Memory)
|
||||
s.Windows.Resources = &specs.WindowsResources{
|
||||
CPU: &specs.WindowsCPUResources{
|
||||
Percent: &cpuPercent,
|
||||
Maximum: &cpuMaximum,
|
||||
Shares: &cpuShares,
|
||||
Count: &cpuCount,
|
||||
},
|
||||
|
||||
@ -216,7 +216,7 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
||||
if !until.IsZero() && img.Created.After(until) {
|
||||
continue
|
||||
}
|
||||
if !matchLabels(pruneFilters, img.Config.Labels) {
|
||||
if img.Config != nil && !matchLabels(pruneFilters, img.Config.Labels) {
|
||||
continue
|
||||
}
|
||||
topImages[id] = img
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
@ -32,12 +31,6 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
||||
}
|
||||
|
||||
dnsSearch := daemon.getDNSSearchSettings(container)
|
||||
if dnsSearch != nil {
|
||||
osv := system.GetOSVersion()
|
||||
if osv.Build < 14997 {
|
||||
return nil, fmt.Errorf("dns-search option is not supported on the current platform")
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the layer folder of the layer options
|
||||
layerOpts := &libcontainerd.LayerOption{}
|
||||
@ -45,10 +38,6 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get layer metadata - %s", err)
|
||||
}
|
||||
if hvOpts.IsHyperV {
|
||||
hvOpts.SandboxPath = filepath.Dir(m["dir"])
|
||||
}
|
||||
|
||||
layerOpts.LayerFolderPath = m["dir"]
|
||||
|
||||
// Generate the layer paths of the layer options
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
dockererrors "github.com/docker/docker/api/errors"
|
||||
@ -28,9 +29,11 @@ type mounts []container.Mount
|
||||
|
||||
// volumeToAPIType converts a volume.Volume to the type used by the Engine API
|
||||
func volumeToAPIType(v volume.Volume) *types.Volume {
|
||||
createdAt, _ := v.CreatedAt()
|
||||
tv := &types.Volume{
|
||||
Name: v.Name(),
|
||||
Driver: v.DriverName(),
|
||||
Name: v.Name(),
|
||||
Driver: v.DriverName(),
|
||||
CreatedAt: createdAt.Format(time.RFC3339),
|
||||
}
|
||||
if v, ok := v.(volume.DetailedVolume); ok {
|
||||
tv.Labels = v.Labels()
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
dcli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/flags"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakestorage"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
@ -406,7 +406,7 @@ func (s *DockerTrustSuite) TearDownTest(c *check.C) {
|
||||
}
|
||||
|
||||
// Remove trusted keys and metadata after test
|
||||
os.RemoveAll(filepath.Join(dcli.ConfigurationDir(), "trust"))
|
||||
os.RemoveAll(filepath.Join(flags.ConfigurationDir(), "trust"))
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
|
||||
@ -2,8 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
@ -69,6 +72,8 @@ func (s *DockerSuite) TestVolumesAPIInspect(c *check.C) {
|
||||
config := volumetypes.VolumesCreateBody{
|
||||
Name: "test",
|
||||
}
|
||||
// sampling current time minus a minute so to now have false positive in case of delays
|
||||
now := time.Now().Truncate(time.Minute)
|
||||
status, b, err := request.SockRequest("POST", "/volumes/create", config, daemonHost())
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(status, check.Equals, http.StatusCreated, check.Commentf(string(b)))
|
||||
@ -87,4 +92,12 @@ func (s *DockerSuite) TestVolumesAPIInspect(c *check.C) {
|
||||
c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(b)))
|
||||
c.Assert(json.Unmarshal(b, &vol), checker.IsNil)
|
||||
c.Assert(vol.Name, checker.Equals, config.Name)
|
||||
|
||||
// comparing CreatedAt field time for the new volume to now. Removing a minute from both to avoid false positive
|
||||
testCreatedAt, err := time.Parse(time.RFC3339, strings.TrimSpace(vol.CreatedAt))
|
||||
c.Assert(err, check.IsNil)
|
||||
testCreatedAt = testCreatedAt.Truncate(time.Minute)
|
||||
if !testCreatedAt.Equal(now) {
|
||||
c.Assert(fmt.Errorf("Time Volume is CreatedAt not equal to current time"), check.NotNil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,3 +139,26 @@ func (s *DockerSuite) TestHealth(c *check.C) {
|
||||
c.Check(out, checker.Equals, "[CMD cat /my status]\n")
|
||||
|
||||
}
|
||||
|
||||
// Github #33021
|
||||
func (s *DockerSuite) TestUnsetEnvVarHealthCheck(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
|
||||
|
||||
imageName := "testhealth"
|
||||
buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
|
||||
HEALTHCHECK --interval=1s --timeout=5s --retries=5 CMD /bin/sh -c "sleep 1"
|
||||
ENTRYPOINT /bin/sh -c "sleep 600"`))
|
||||
|
||||
name := "env_test_health"
|
||||
// No health status before starting
|
||||
dockerCmd(c, "run", "-d", "--name", name, "-e", "FOO", imageName)
|
||||
defer func() {
|
||||
dockerCmd(c, "rm", "-f", name)
|
||||
dockerCmd(c, "rmi", imageName)
|
||||
}()
|
||||
|
||||
// Start
|
||||
dockerCmd(c, "start", name)
|
||||
waitForHealthStatus(c, name, "starting", "healthy")
|
||||
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ func (s *DockerSuite) TestImagesFilterLabelMatch(c *check.C) {
|
||||
}
|
||||
|
||||
// Regression : #15659
|
||||
func (s *DockerSuite) TestImagesFilterLabelWithCommit(c *check.C) {
|
||||
func (s *DockerSuite) TestCommitWithFilterLabel(c *check.C) {
|
||||
// Create a container
|
||||
dockerCmd(c, "run", "--name", "bar", "busybox", "/bin/sh")
|
||||
// Commit with labels "using changes"
|
||||
|
||||
@ -44,7 +44,7 @@ func (s *DockerSuite) TestNetHostname(c *check.C) {
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictNetworkHostname.Error())
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=container", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, "--net: invalid net mode: invalid container format container:<name|id>")
|
||||
c.Assert(out, checker.Contains, "Invalid network mode: invalid container format container:<name|id>")
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=weird", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, "network weird not found")
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
dcli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/flags"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
@ -294,7 +294,7 @@ func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
|
||||
})
|
||||
|
||||
// Assert that we rotated the snapshot key to the server by checking our local keystore
|
||||
contents, err := ioutil.ReadDir(filepath.Join(dcli.ConfigurationDir(), "trust/private/tuf_keys", privateRegistryURL, "dockerclitrusted/pushtest"))
|
||||
contents, err := ioutil.ReadDir(filepath.Join(flags.ConfigurationDir(), "trust/private/tuf_keys", privateRegistryURL, "dockerclitrusted/pushtest"))
|
||||
c.Assert(err, check.IsNil, check.Commentf("Unable to read local tuf key files"))
|
||||
// Check that we only have 1 key (targets key)
|
||||
c.Assert(contents, checker.HasLen, 1)
|
||||
@ -399,7 +399,7 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C)
|
||||
s.assertTargetNotInRoles(c, repoName, "latest", "targets")
|
||||
|
||||
// Try pull after push
|
||||
os.RemoveAll(filepath.Join(dcli.ConfigurationDir(), "trust"))
|
||||
os.RemoveAll(filepath.Join(flags.ConfigurationDir(), "trust"))
|
||||
|
||||
cli.Docker(cli.Args("pull", targetName), trustedCmd).Assert(c, icmd.Expected{
|
||||
Out: "Status: Image is up to date",
|
||||
@ -436,7 +436,7 @@ func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c
|
||||
s.assertTargetNotInRoles(c, repoName, "latest", "targets")
|
||||
|
||||
// Try pull after push
|
||||
os.RemoveAll(filepath.Join(dcli.ConfigurationDir(), "trust"))
|
||||
os.RemoveAll(filepath.Join(flags.ConfigurationDir(), "trust"))
|
||||
|
||||
// pull should fail because none of these are the releases role
|
||||
cli.Docker(cli.Args("pull", targetName), trustedCmd).Assert(c, icmd.Expected{
|
||||
@ -472,7 +472,7 @@ func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *
|
||||
s.assertTargetNotInRoles(c, repoName, "latest", "targets")
|
||||
|
||||
// Try pull after push
|
||||
os.RemoveAll(filepath.Join(dcli.ConfigurationDir(), "trust"))
|
||||
os.RemoveAll(filepath.Join(flags.ConfigurationDir(), "trust"))
|
||||
|
||||
// pull should fail because none of these are the releases role
|
||||
cli.Docker(cli.Args("pull", targetName), trustedCmd).Assert(c, icmd.Expected{
|
||||
|
||||
@ -448,7 +448,7 @@ func (s *DockerSwarmSuite) TestOverlayAttachableReleaseResourcesOnFailure(c *che
|
||||
out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "--ip", "10.10.9.33", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
// Attempt to attach another contianer with same IP, must fail
|
||||
// Attempt to attach another container with same IP, must fail
|
||||
_, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c2", "--ip", "10.10.9.33", "busybox", "top")
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
@ -2002,6 +2002,35 @@ func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *check.C) {
|
||||
}
|
||||
}
|
||||
|
||||
const defaultRetryCount = 10
|
||||
|
||||
func waitForEvent(c *check.C, d *daemon.Swarm, since string, filter string, event string, retry int) string {
|
||||
if retry < 1 {
|
||||
c.Fatalf("retry count %d is invalid. It should be no less than 1", retry)
|
||||
return ""
|
||||
}
|
||||
var out string
|
||||
for i := 0; i < retry; i++ {
|
||||
until := daemonUnixTime(c)
|
||||
var err error
|
||||
if len(filter) > 0 {
|
||||
out, err = d.Cmd("events", "--since", since, "--until", until, filter)
|
||||
} else {
|
||||
out, err = d.Cmd("events", "--since", since, "--until", until)
|
||||
}
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
if strings.Contains(out, event) {
|
||||
return strings.TrimSpace(out)
|
||||
}
|
||||
// no need to sleep after last retry
|
||||
if i < retry-1 {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
c.Fatalf("docker events output '%s' doesn't contain event '%s'", out, event)
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmClusterEventsSource(c *check.C) {
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, true)
|
||||
@ -2013,21 +2042,13 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsSource(c *check.C) {
|
||||
networkID := strings.TrimSpace(out)
|
||||
c.Assert(networkID, checker.Not(checker.Equals), "")
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
// d1 is a manager
|
||||
out, err = d1.Cmd("events", "--since=0", "--until", until, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "network create "+networkID)
|
||||
|
||||
// d2 is a manager
|
||||
out, err = d2.Cmd("events", "--since=0", "--until", until, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "network create "+networkID)
|
||||
// d1, d2 are managers that can get swarm events
|
||||
waitForEvent(c, d1, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount)
|
||||
waitForEvent(c, d2, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount)
|
||||
|
||||
// d3 is a worker, not able to get cluster events
|
||||
out, err = d3.Cmd("events", "--since=0", "--until", until, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "network create ")
|
||||
out = waitForEvent(c, d3, "0", "-f scope=swarm", "", 1)
|
||||
c.Assert(out, checker.Not(checker.Contains), "network create ")
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmClusterEventsScope(c *check.C) {
|
||||
@ -2038,24 +2059,17 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsScope(c *check.C) {
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
serviceID := strings.Split(out, "\n")[0]
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
// scope swarm filters cluster events
|
||||
out, err = d.Cmd("events", "--since=0", "--until", until, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "service create "+serviceID)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "container create ")
|
||||
out = waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount)
|
||||
c.Assert(out, checker.Not(checker.Contains), "container create ")
|
||||
|
||||
// without scope all events are returned
|
||||
out, err = d.Cmd("events", "--since=0", "--until", until)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "service create "+serviceID)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "container create ")
|
||||
// all events are returned if scope is not specified
|
||||
waitForEvent(c, d, "0", "", "service create "+serviceID, 1)
|
||||
waitForEvent(c, d, "0", "", "container create ", defaultRetryCount)
|
||||
|
||||
// scope local only show non-cluster events
|
||||
out, err = d.Cmd("events", "--since=0", "--until", until, "-f scope=local")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "service create ")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "container create ")
|
||||
// scope local only shows non-cluster events
|
||||
out = waitForEvent(c, d, "0", "-f scope=local", "container create ", 1)
|
||||
c.Assert(out, checker.Not(checker.Contains), "service create ")
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmClusterEventsType(c *check.C) {
|
||||
@ -2072,17 +2086,12 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsType(c *check.C) {
|
||||
networkID := strings.TrimSpace(out)
|
||||
c.Assert(networkID, checker.Not(checker.Equals), "")
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
// filter by service
|
||||
out, err = d.Cmd("events", "--since=0", "--until", until, "-f type=service")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "service create "+serviceID)
|
||||
out = waitForEvent(c, d, "0", "-f type=service", "service create "+serviceID, defaultRetryCount)
|
||||
c.Assert(out, checker.Not(checker.Contains), "network create")
|
||||
|
||||
// filter by network
|
||||
out, err = d.Cmd("events", "--since=0", "--until", until, "-f type=network")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "network create "+networkID)
|
||||
out = waitForEvent(c, d, "0", "-f type=network", "network create "+networkID, defaultRetryCount)
|
||||
c.Assert(out, checker.Not(checker.Contains), "service create")
|
||||
}
|
||||
|
||||
@ -2094,40 +2103,36 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsService(c *check.C) {
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
serviceID := strings.Split(out, "\n")[0]
|
||||
|
||||
t1 := daemonUnixTime(c)
|
||||
// validate service create event
|
||||
out, err = d.Cmd("events", "--since=0", "--until", t1, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "service create "+serviceID)
|
||||
waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount)
|
||||
|
||||
t1 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("service", "update", "--force", "--detach=false", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
t2 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("events", "--since", t1, "--until", t2, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "service update "+serviceID)
|
||||
// wait for service update start
|
||||
out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount)
|
||||
c.Assert(out, checker.Contains, "updatestate.new=updating")
|
||||
|
||||
// allow service update complete. This is a service with 1 instance
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount)
|
||||
c.Assert(out, checker.Contains, "updatestate.new=completed, updatestate.old=updating")
|
||||
|
||||
// scale service
|
||||
t2 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("service", "scale", "test=3")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
t3 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("events", "--since", t2, "--until", t3, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "service update "+serviceID)
|
||||
out = waitForEvent(c, d, t2, "-f scope=swarm", "service update "+serviceID, defaultRetryCount)
|
||||
c.Assert(out, checker.Contains, "replicas.new=3, replicas.old=1")
|
||||
|
||||
// remove service
|
||||
t3 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("service", "rm", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
t4 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("events", "--since", t3, "--until", t4, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "service remove "+serviceID)
|
||||
waitForEvent(c, d, t3, "-f scope=swarm", "service remove "+serviceID, defaultRetryCount)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmClusterEventsNode(c *check.C) {
|
||||
@ -2136,38 +2141,28 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsNode(c *check.C) {
|
||||
d3 := s.AddDaemon(c, true, true)
|
||||
|
||||
d3ID := d3.NodeID
|
||||
waitForEvent(c, d1, "0", "-f scope=swarm", "node create "+d3ID, defaultRetryCount)
|
||||
|
||||
t1 := daemonUnixTime(c)
|
||||
out, err := d1.Cmd("events", "--since=0", "--until", t1, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "node create "+d3ID)
|
||||
|
||||
out, err = d1.Cmd("node", "update", "--availability=pause", d3ID)
|
||||
out, err := d1.Cmd("node", "update", "--availability=pause", d3ID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
t2 := daemonUnixTime(c)
|
||||
// filter by type
|
||||
out, err = d1.Cmd("events", "--since", t1, "--until", t2, "-f type=node")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "node update "+d3ID)
|
||||
out = waitForEvent(c, d1, t1, "-f type=node", "node update "+d3ID, defaultRetryCount)
|
||||
c.Assert(out, checker.Contains, "availability.new=pause, availability.old=active")
|
||||
|
||||
t2 := daemonUnixTime(c)
|
||||
out, err = d1.Cmd("node", "demote", d3ID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
t3 := daemonUnixTime(c)
|
||||
// filter by type and scope
|
||||
out, err = d1.Cmd("events", "--since", t2, "--until", t3, "-f type=node", "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "node update "+d3ID)
|
||||
waitForEvent(c, d1, t2, "-f type=node", "node update "+d3ID, defaultRetryCount)
|
||||
|
||||
t3 := daemonUnixTime(c)
|
||||
out, err = d1.Cmd("node", "rm", "-f", d3ID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
t4 := daemonUnixTime(c)
|
||||
// filter by type and scope
|
||||
out, err = d1.Cmd("events", "--since", t3, "--until", t4, "-f type=node", "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "node remove "+d3ID)
|
||||
// filter by scope
|
||||
waitForEvent(c, d1, t3, "-f scope=swarm", "node remove "+d3ID, defaultRetryCount)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmClusterEventsNetwork(c *check.C) {
|
||||
@ -2178,20 +2173,15 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsNetwork(c *check.C) {
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
networkID := strings.TrimSpace(out)
|
||||
|
||||
t1 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("events", "--since=0", "--until", t1, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "network create "+networkID)
|
||||
waitForEvent(c, d, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount)
|
||||
|
||||
// remove network
|
||||
t1 := daemonUnixTime(c)
|
||||
out, err = d.Cmd("network", "rm", "foo")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
t2 := daemonUnixTime(c)
|
||||
// filtered by network
|
||||
out, err = d.Cmd("events", "--since", t1, "--until", t2, "-f type=network")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "network remove "+networkID)
|
||||
waitForEvent(c, d, t1, "-f type=network", "network remove "+networkID, defaultRetryCount)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmClusterEventsSecret(c *check.C) {
|
||||
@ -2206,15 +2196,10 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsSecret(c *check.C) {
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
|
||||
t1 := daemonUnixTime(c)
|
||||
out, err := d.Cmd("events", "--since=0", "--until", t1, "-f scope=swarm")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "secret create "+id)
|
||||
waitForEvent(c, d, "0", "-f scope=swarm", "secret create "+id, defaultRetryCount)
|
||||
|
||||
t1 := daemonUnixTime(c)
|
||||
d.DeleteSecret(c, id)
|
||||
t2 := daemonUnixTime(c)
|
||||
// filtered by secret
|
||||
out, err = d.Cmd("events", "--since", t1, "--until", t2, "-f type=secret")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "secret remove "+id)
|
||||
waitForEvent(c, d, t1, "-f type=secret", "secret remove "+id, defaultRetryCount)
|
||||
}
|
||||
|
||||
@ -217,13 +217,14 @@ func SockRequestRaw(method, endpoint string, data io.Reader, ct, daemon string,
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
client.Close()
|
||||
return resp, nil, err
|
||||
}
|
||||
body := ioutils.NewReadCloserWrapper(resp.Body, func() error {
|
||||
defer resp.Body.Close()
|
||||
return client.Close()
|
||||
})
|
||||
if err != nil {
|
||||
client.Close()
|
||||
}
|
||||
|
||||
return resp, body, err
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
dcli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/flags"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
icmd "github.com/docker/docker/pkg/testutil/cmd"
|
||||
@ -108,7 +108,7 @@ func newTestNotary(c *check.C) (*testNotary, error) {
|
||||
"skipTLSVerify": true
|
||||
}
|
||||
}`
|
||||
if _, err = fmt.Fprintf(clientConfig, template, filepath.Join(dcli.ConfigurationDir(), "trust"), notaryURL); err != nil {
|
||||
if _, err = fmt.Fprintf(clientConfig, template, filepath.Join(flags.ConfigurationDir(), "trust"), notaryURL); err != nil {
|
||||
os.RemoveAll(tmp)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -49,7 +49,6 @@ const defaultOwner = "docker"
|
||||
// | VolumePath | \\?\\Volume{GUIDa} | |
|
||||
// | LayerFolderPath | %root%\windowsfilter\containerID | %root%\windowsfilter\containerID (servicing only) |
|
||||
// | Layers[] | ID=GUIDb;Path=%root%\windowsfilter\layerID | ID=GUIDb;Path=%root%\windowsfilter\layerID |
|
||||
// | SandboxPath | | %root%\windowsfilter |
|
||||
// | HvRuntime | | ImagePath=%root%\BaseLayerID\UtilityVM |
|
||||
// +-----------------+--------------------------------------------+---------------------------------------------------+
|
||||
//
|
||||
@ -88,7 +87,6 @@ const defaultOwner = "docker"
|
||||
// }],
|
||||
// "HostName": "475c2c58933b",
|
||||
// "MappedDirectories": [],
|
||||
// "SandboxPath": "C:\\\\control\\\\windowsfilter",
|
||||
// "HvPartition": true,
|
||||
// "EndpointList": ["e1bb1e61-d56f-405e-b75d-fd520cefa0cb"],
|
||||
// "DNSSearchList": "a.com,b.com,c.com",
|
||||
@ -128,8 +126,8 @@ func (clnt *client) Create(containerID string, checkpoint string, checkpointDir
|
||||
if spec.Windows.Resources.CPU.Shares != nil {
|
||||
configuration.ProcessorWeight = uint64(*spec.Windows.Resources.CPU.Shares)
|
||||
}
|
||||
if spec.Windows.Resources.CPU.Percent != nil {
|
||||
configuration.ProcessorMaximum = int64(*spec.Windows.Resources.CPU.Percent) * 100 // ProcessorMaximum is a value between 1 and 10000
|
||||
if spec.Windows.Resources.CPU.Maximum != nil {
|
||||
configuration.ProcessorMaximum = int64(*spec.Windows.Resources.CPU.Maximum)
|
||||
}
|
||||
}
|
||||
if spec.Windows.Resources.Memory != nil {
|
||||
@ -159,7 +157,6 @@ func (clnt *client) Create(containerID string, checkpoint string, checkpointDir
|
||||
}
|
||||
if h, ok := option.(*HyperVIsolationOption); ok {
|
||||
configuration.HvPartition = h.IsHyperV
|
||||
configuration.SandboxPath = h.SandboxPath
|
||||
continue
|
||||
}
|
||||
if l, ok := option.(*LayerOption); ok {
|
||||
|
||||
@ -49,7 +49,7 @@ type remote struct {
|
||||
stateDir string
|
||||
rpcAddr string
|
||||
startDaemon bool
|
||||
closeManually bool
|
||||
closedManually bool
|
||||
debugLog bool
|
||||
rpcConn *grpc.ClientConn
|
||||
clients []*client
|
||||
@ -154,7 +154,7 @@ func (r *remote) handleConnectionChange() {
|
||||
logrus.Debugf("libcontainerd: containerd health check returned error: %v", err)
|
||||
|
||||
if r.daemonPid != -1 {
|
||||
if r.closeManually {
|
||||
if r.closedManually {
|
||||
// Well, we asked for it to stop, just return
|
||||
return
|
||||
}
|
||||
@ -180,7 +180,7 @@ func (r *remote) Cleanup() {
|
||||
if r.daemonPid == -1 {
|
||||
return
|
||||
}
|
||||
r.closeManually = true
|
||||
r.closedManually = true
|
||||
r.rpcConn.Close()
|
||||
// Ask the daemon to quit
|
||||
syscall.Kill(r.daemonPid, syscall.SIGTERM)
|
||||
@ -280,10 +280,23 @@ func (r *remote) startEventsMonitor() error {
|
||||
er := &containerd.EventsRequest{
|
||||
Timestamp: tsp,
|
||||
}
|
||||
events, err := r.apiClient.Events(context.Background(), er, grpc.FailFast(false))
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
var events containerd.API_EventsClient
|
||||
for {
|
||||
events, err = r.apiClient.Events(context.Background(), er, grpc.FailFast(false))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
logrus.Warnf("libcontainerd: failed to get events from containerd: %q", err)
|
||||
|
||||
if r.closedManually {
|
||||
// ignore error if grpc remote connection is closed manually
|
||||
return nil
|
||||
}
|
||||
|
||||
<-time.After(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
go r.handleEventStream(events)
|
||||
return nil
|
||||
}
|
||||
@ -293,7 +306,7 @@ func (r *remote) handleEventStream(events containerd.API_EventsClient) {
|
||||
e, err := events.Recv()
|
||||
if err != nil {
|
||||
if grpc.ErrorDesc(err) == transport.ErrConnClosing.Desc &&
|
||||
r.closeManually {
|
||||
r.closedManually {
|
||||
// ignore error if grpc remote connection is closed manually
|
||||
return
|
||||
}
|
||||
@ -414,6 +427,18 @@ func (r *remote) runContainerdDaemon() error {
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// unless strictly necessary, do not add anything in between here
|
||||
// as the reaper goroutine below needs to kick in as soon as possible
|
||||
// and any "return" from code paths added here will defeat the reaper
|
||||
// process.
|
||||
|
||||
r.daemonWaitCh = make(chan struct{})
|
||||
go func() {
|
||||
cmd.Wait()
|
||||
close(r.daemonWaitCh)
|
||||
}() // Reap our child when needed
|
||||
|
||||
logrus.Infof("libcontainerd: new containerd process, pid: %d", cmd.Process.Pid)
|
||||
if err := setOOMScore(cmd.Process.Pid, r.oomScore); err != nil {
|
||||
system.KillProcess(cmd.Process.Pid)
|
||||
@ -424,11 +449,6 @@ func (r *remote) runContainerdDaemon() error {
|
||||
return err
|
||||
}
|
||||
|
||||
r.daemonWaitCh = make(chan struct{})
|
||||
go func() {
|
||||
cmd.Wait()
|
||||
close(r.daemonWaitCh)
|
||||
}() // Reap our child when needed
|
||||
r.daemonPid = cmd.Process.Pid
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -39,10 +39,9 @@ type FlushOption struct {
|
||||
}
|
||||
|
||||
// HyperVIsolationOption is a CreateOption that indicates whether the runtime
|
||||
// should start the container as a Hyper-V container, and if so, the sandbox path.
|
||||
// should start the container as a Hyper-V container.
|
||||
type HyperVIsolationOption struct {
|
||||
IsHyperV bool
|
||||
SandboxPath string `json:",omitempty"`
|
||||
IsHyperV bool
|
||||
}
|
||||
|
||||
// LayerOption is a CreateOption that indicates to the runtime the layer folder
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM golang:1.7.5-alpine
|
||||
FROM golang:1.8.3-alpine
|
||||
|
||||
RUN apk add -U git bash curl gcc musl-dev make
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ FROM aarch64/ubuntu:xenial
|
||||
|
||||
RUN apt-get update && apt-get install -y git golang-go curl
|
||||
|
||||
ENV GO_VERSION 1.7.5
|
||||
ENV GO_VERSION 1.8.3
|
||||
ENV GOARCH arm64
|
||||
ENV PATH /go/bin:/usr/src/go/bin:$PATH
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
make
|
||||
|
||||
ENV GO_VERSION 1.7.5
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user