Merge pull request #40725 from cpuguy83/check_img_platform
Accept platform spec on container create
This commit is contained in:
commit
5c10ea6ae8
|
@ -9,6 +9,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
"github.com/docker/docker/api/server/httputils"
|
"github.com/docker/docker/api/server/httputils"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/backend"
|
"github.com/docker/docker/api/types/backend"
|
||||||
|
@ -19,6 +20,7 @@ import (
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
|
@ -502,6 +504,28 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var platform *specs.Platform
|
||||||
|
if versions.GreaterThanOrEqualTo(version, "1.41") {
|
||||||
|
if v := r.Form.Get("platform"); v != "" {
|
||||||
|
p, err := platforms.Parse(v)
|
||||||
|
if err != nil {
|
||||||
|
return errdefs.InvalidParameter(err)
|
||||||
|
}
|
||||||
|
platform = &p
|
||||||
|
}
|
||||||
|
defaultPlatform := platforms.DefaultSpec()
|
||||||
|
if platform == nil {
|
||||||
|
platform = &defaultPlatform
|
||||||
|
}
|
||||||
|
if platform.OS == "" {
|
||||||
|
platform.OS = defaultPlatform.OS
|
||||||
|
}
|
||||||
|
if platform.Architecture == "" {
|
||||||
|
platform.Architecture = defaultPlatform.Architecture
|
||||||
|
platform.Variant = defaultPlatform.Variant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if hostConfig != nil && hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
|
if hostConfig != nil && hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
|
||||||
// Don't set a limit if either no limit was specified, or "unlimited" was
|
// Don't set a limit if either no limit was specified, or "unlimited" was
|
||||||
// explicitly set.
|
// explicitly set.
|
||||||
|
@ -516,6 +540,7 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
||||||
HostConfig: hostConfig,
|
HostConfig: hostConfig,
|
||||||
NetworkingConfig: networkingConfig,
|
NetworkingConfig: networkingConfig,
|
||||||
AdjustCPUShares: adjustCPUShares,
|
AdjustCPUShares: adjustCPUShares,
|
||||||
|
Platform: platform,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -3,6 +3,7 @@ package types // import "github.com/docker/docker/api/types"
|
||||||
import (
|
import (
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// configs holds structs used for internal communication between the
|
// configs holds structs used for internal communication between the
|
||||||
|
@ -15,6 +16,7 @@ type ContainerCreateConfig struct {
|
||||||
Config *container.Config
|
Config *container.Config
|
||||||
HostConfig *container.HostConfig
|
HostConfig *container.HostConfig
|
||||||
NetworkingConfig *network.NetworkingConfig
|
NetworkingConfig *network.NetworkingConfig
|
||||||
|
Platform *specs.Platform
|
||||||
AdjustCPUShares bool
|
AdjustCPUShares bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,20 +5,23 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type configWrapper struct {
|
type configWrapper struct {
|
||||||
*container.Config
|
*container.Config
|
||||||
HostConfig *container.HostConfig
|
HostConfig *container.HostConfig
|
||||||
NetworkingConfig *network.NetworkingConfig
|
NetworkingConfig *network.NetworkingConfig
|
||||||
|
Platform *specs.Platform
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerCreate creates a new container based in the given configuration.
|
// ContainerCreate creates a new container based in the given configuration.
|
||||||
// It can be associated with a name, but it's not mandatory.
|
// It can be associated with a name, but it's not mandatory.
|
||||||
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) {
|
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *specs.Platform, containerName string) (container.ContainerCreateCreatedBody, error) {
|
||||||
var response container.ContainerCreateCreatedBody
|
var response container.ContainerCreateCreatedBody
|
||||||
|
|
||||||
if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
|
if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
|
||||||
|
@ -30,7 +33,15 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
|
||||||
hostConfig.AutoRemove = false
|
hostConfig.AutoRemove = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cli.NewVersionError("1.41", "specify container image platform"); platform != nil && err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
|
if platform != nil {
|
||||||
|
query.Set("platform", platforms.Format(*platform))
|
||||||
|
}
|
||||||
|
|
||||||
if containerName != "" {
|
if containerName != "" {
|
||||||
query.Set("name", containerName)
|
query.Set("name", containerName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func TestContainerCreateError(t *testing.T) {
|
||||||
client := &Client{
|
client := &Client{
|
||||||
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
||||||
}
|
}
|
||||||
_, err := client.ContainerCreate(context.Background(), nil, nil, nil, "nothing")
|
_, err := client.ContainerCreate(context.Background(), nil, nil, nil, nil, "nothing")
|
||||||
if !errdefs.IsSystem(err) {
|
if !errdefs.IsSystem(err) {
|
||||||
t.Fatalf("expected a Server Error while testing StatusInternalServerError, got %T", err)
|
t.Fatalf("expected a Server Error while testing StatusInternalServerError, got %T", err)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ func TestContainerCreateError(t *testing.T) {
|
||||||
client = &Client{
|
client = &Client{
|
||||||
client: newMockClient(errorMock(http.StatusNotFound, "Server error")),
|
client: newMockClient(errorMock(http.StatusNotFound, "Server error")),
|
||||||
}
|
}
|
||||||
_, err = client.ContainerCreate(context.Background(), nil, nil, nil, "nothing")
|
_, err = client.ContainerCreate(context.Background(), nil, nil, nil, nil, "nothing")
|
||||||
if err == nil || !IsErrNotFound(err) {
|
if err == nil || !IsErrNotFound(err) {
|
||||||
t.Fatalf("expected a Server Error while testing StatusNotFound, got %T", err)
|
t.Fatalf("expected a Server Error while testing StatusNotFound, got %T", err)
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func TestContainerCreateImageNotFound(t *testing.T) {
|
||||||
client := &Client{
|
client := &Client{
|
||||||
client: newMockClient(errorMock(http.StatusNotFound, "No such image")),
|
client: newMockClient(errorMock(http.StatusNotFound, "No such image")),
|
||||||
}
|
}
|
||||||
_, err := client.ContainerCreate(context.Background(), &container.Config{Image: "unknown_image"}, nil, nil, "unknown")
|
_, err := client.ContainerCreate(context.Background(), &container.Config{Image: "unknown_image"}, nil, nil, nil, "unknown")
|
||||||
if err == nil || !IsErrNotFound(err) {
|
if err == nil || !IsErrNotFound(err) {
|
||||||
t.Fatalf("expected an imageNotFound error, got %v, %T", err, err)
|
t.Fatalf("expected an imageNotFound error, got %v, %T", err, err)
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ func TestContainerCreateWithName(t *testing.T) {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := client.ContainerCreate(context.Background(), nil, nil, nil, "container_name")
|
r, err := client.ContainerCreate(context.Background(), nil, nil, nil, nil, "container_name")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -106,14 +106,14 @@ func TestContainerCreateAutoRemove(t *testing.T) {
|
||||||
client: newMockClient(autoRemoveValidator(false)),
|
client: newMockClient(autoRemoveValidator(false)),
|
||||||
version: "1.24",
|
version: "1.24",
|
||||||
}
|
}
|
||||||
if _, err := client.ContainerCreate(context.Background(), nil, &container.HostConfig{AutoRemove: true}, nil, ""); err != nil {
|
if _, err := client.ContainerCreate(context.Background(), nil, &container.HostConfig{AutoRemove: true}, nil, nil, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
client = &Client{
|
client = &Client{
|
||||||
client: newMockClient(autoRemoveValidator(true)),
|
client: newMockClient(autoRemoveValidator(true)),
|
||||||
version: "1.25",
|
version: "1.25",
|
||||||
}
|
}
|
||||||
if _, err := client.ContainerCreate(context.Background(), nil, &container.HostConfig{AutoRemove: true}, nil, ""); err != nil {
|
if _, err := client.ContainerCreate(context.Background(), nil, &container.HostConfig{AutoRemove: true}, nil, nil, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
volumetypes "github.com/docker/docker/api/types/volume"
|
volumetypes "github.com/docker/docker/api/types/volume"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
|
// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
|
||||||
|
@ -47,7 +48,7 @@ type CommonAPIClient interface {
|
||||||
type ContainerAPIClient interface {
|
type ContainerAPIClient interface {
|
||||||
ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error)
|
ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error)
|
||||||
ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error)
|
ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error)
|
||||||
ContainerCreate(ctx context.Context, config *containertypes.Config, hostConfig *containertypes.HostConfig, networkingConfig *networktypes.NetworkingConfig, containerName string) (containertypes.ContainerCreateCreatedBody, error)
|
ContainerCreate(ctx context.Context, config *containertypes.Config, hostConfig *containertypes.HostConfig, networkingConfig *networktypes.NetworkingConfig, platform *specs.Platform, containerName string) (containertypes.ContainerCreateCreatedBody, error)
|
||||||
ContainerDiff(ctx context.Context, container string) ([]containertypes.ContainerChangeResponseItem, error)
|
ContainerDiff(ctx context.Context, container string) ([]containertypes.ContainerChangeResponseItem, error)
|
||||||
ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error)
|
ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error)
|
||||||
ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error)
|
ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error)
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (daemon *Daemon) containerCreate(opts createOpts) (containertypes.Container
|
||||||
|
|
||||||
os := runtime.GOOS
|
os := runtime.GOOS
|
||||||
if opts.params.Config.Image != "" {
|
if opts.params.Config.Image != "" {
|
||||||
img, err := daemon.imageService.GetImage(opts.params.Config.Image)
|
img, err := daemon.imageService.GetImage(opts.params.Config.Image, opts.params.Platform)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
os = img.OS
|
os = img.OS
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func (daemon *Daemon) create(opts createOpts) (retC *container.Container, retErr
|
||||||
|
|
||||||
os := runtime.GOOS
|
os := runtime.GOOS
|
||||||
if opts.params.Config.Image != "" {
|
if opts.params.Config.Image != "" {
|
||||||
img, err = daemon.imageService.GetImage(opts.params.Config.Image)
|
img, err = daemon.imageService.GetImage(opts.params.Config.Image, opts.params.Platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ func (i *ImageService) MakeImageCache(sourceRefs []string) builder.ImageCache {
|
||||||
cache := cache.New(i.imageStore)
|
cache := cache.New(i.imageStore)
|
||||||
|
|
||||||
for _, ref := range sourceRefs {
|
for _, ref := range sourceRefs {
|
||||||
img, err := i.GetImage(ref)
|
img, err := i.GetImage(ref, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("Could not look up %s for cache resolution, skipping: %+v", ref, err)
|
logrus.Warnf("Could not look up %s for cache resolution, skipping: %+v", ref, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -3,9 +3,12 @@ package images // import "github.com/docker/docker/daemon/images"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrImageDoesNotExist is error returned when no image can be found for a reference.
|
// ErrImageDoesNotExist is error returned when no image can be found for a reference.
|
||||||
|
@ -25,7 +28,39 @@ func (e ErrImageDoesNotExist) Error() string {
|
||||||
func (e ErrImageDoesNotExist) NotFound() {}
|
func (e ErrImageDoesNotExist) NotFound() {}
|
||||||
|
|
||||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||||
func (i *ImageService) GetImage(refOrID string) (*image.Image, error) {
|
func (i *ImageService) GetImage(refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error) {
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil || retImg == nil || platform == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This allows us to tell clients that we don't have the image they asked for
|
||||||
|
// Where this gets hairy is the image store does not currently support multi-arch images, e.g.:
|
||||||
|
// An image `foo` may have a multi-arch manifest, but the image store only fetches the image for a specific platform
|
||||||
|
// The image store does not store the manifest list and image tags are assigned to architecture specific images.
|
||||||
|
// So we can have a `foo` image that is amd64 but the user requested armv7. If the user looks at the list of images.
|
||||||
|
// This may be confusing.
|
||||||
|
// The alternative to this is to return a errdefs.Conflict error with a helpful message, but clients will not be
|
||||||
|
// able to automatically tell what causes the conflict.
|
||||||
|
if retImg.OS != platform.OS {
|
||||||
|
retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified OS platform: wanted: %s, actual: %s", refOrID, platform.OS, retImg.OS))
|
||||||
|
retImg = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if retImg.Architecture != platform.Architecture {
|
||||||
|
retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified platform cpu architecture: wanted: %s, actual: %s", refOrID, platform.Architecture, retImg.Architecture))
|
||||||
|
retImg = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only validate variant if retImg has a variant set.
|
||||||
|
// The image variant may not be set since it's a newer field.
|
||||||
|
if platform.Variant != "" && retImg.Variant != "" && retImg.Variant != platform.Variant {
|
||||||
|
retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified platform cpu architecture variant: wanted: %s, actual: %s", refOrID, platform.Variant, retImg.Variant))
|
||||||
|
retImg = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
ref, err := reference.ParseAnyReference(refOrID)
|
ref, err := reference.ParseAnyReference(refOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errdefs.InvalidParameter(err)
|
return nil, errdefs.InvalidParameter(err)
|
||||||
|
|
|
@ -161,7 +161,7 @@ func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConf
|
||||||
if err := i.pullImageWithReference(ctx, ref, platform, nil, pullRegistryAuth, output); err != nil {
|
if err := i.pullImageWithReference(ctx, ref, platform, nil, pullRegistryAuth, output); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return i.GetImage(name)
|
return i.GetImage(name, platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.
|
// GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.
|
||||||
|
@ -184,7 +184,7 @@ func (i *ImageService) GetImageAndReleasableLayer(ctx context.Context, refOrID s
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.PullOption != backend.PullOptionForcePull {
|
if opts.PullOption != backend.PullOptionForcePull {
|
||||||
image, err := i.GetImage(refOrID)
|
image, err := i.GetImage(refOrID, opts.Platform)
|
||||||
if err != nil && opts.PullOption == backend.PullOptionNoPull {
|
if err != nil && opts.PullOption == backend.PullOptionNoPull {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (i *ImageService) ImageDelete(imageRef string, force, prune bool) ([]types.
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
records := []types.ImageDeleteResponseItem{}
|
records := []types.ImageDeleteResponseItem{}
|
||||||
|
|
||||||
img, err := i.GetImage(imageRef)
|
img, err := i.GetImage(imageRef, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ func (i *ImageService) LogImageEvent(imageID, refName, action string) {
|
||||||
|
|
||||||
// LogImageEventWithAttributes generates an event related to an image with specific given attributes.
|
// LogImageEventWithAttributes generates an event related to an image with specific given attributes.
|
||||||
func (i *ImageService) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
|
func (i *ImageService) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
|
||||||
img, err := i.GetImage(imageID)
|
img, err := i.GetImage(imageID, nil)
|
||||||
if err == nil && img.Config != nil {
|
if err == nil && img.Config != nil {
|
||||||
// image has not been removed yet.
|
// image has not been removed yet.
|
||||||
// it could be missing if the event is `delete`.
|
// it could be missing if the event is `delete`.
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
// name by walking the image lineage.
|
// name by walking the image lineage.
|
||||||
func (i *ImageService) ImageHistory(name string) ([]*image.HistoryResponseItem, error) {
|
func (i *ImageService) ImageHistory(name string) ([]*image.HistoryResponseItem, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
img, err := i.GetImage(name)
|
img, err := i.GetImage(name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (i *ImageService) ImageHistory(name string) ([]*image.HistoryResponseItem,
|
||||||
if id == "" {
|
if id == "" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
histImg, err = i.GetImage(id.String())
|
histImg, err = i.GetImage(id.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
// LookupImage looks up an image by name and returns it as an ImageInspect
|
// LookupImage looks up an image by name and returns it as an ImageInspect
|
||||||
// structure.
|
// structure.
|
||||||
func (i *ImageService) LookupImage(name string) (*types.ImageInspect, error) {
|
func (i *ImageService) LookupImage(name string) (*types.ImageInspect, error) {
|
||||||
img, err := i.GetImage(name)
|
img, err := i.GetImage(name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "no such image: %s", name)
|
return nil, errors.Wrapf(err, "no such image: %s", name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
// TagImage creates the tag specified by newTag, pointing to the image named
|
// TagImage creates the tag specified by newTag, pointing to the image named
|
||||||
// imageName (alternatively, imageName can also be an image ID).
|
// imageName (alternatively, imageName can also be an image ID).
|
||||||
func (i *ImageService) TagImage(imageName, repository, tag string) (string, error) {
|
func (i *ImageService) TagImage(imageName, repository, tag string) (string, error) {
|
||||||
img, err := i.GetImage(imageName)
|
img, err := i.GetImage(imageName, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ func (i *ImageService) Images(imageFilters filters.Args, all bool, withExtraAttr
|
||||||
|
|
||||||
var beforeFilter, sinceFilter *image.Image
|
var beforeFilter, sinceFilter *image.Image
|
||||||
err = imageFilters.WalkValues("before", func(value string) error {
|
err = imageFilters.WalkValues("before", func(value string) error {
|
||||||
beforeFilter, err = i.GetImage(value)
|
beforeFilter, err = i.GetImage(value, nil)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -77,7 +77,7 @@ func (i *ImageService) Images(imageFilters filters.Args, all bool, withExtraAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
err = imageFilters.WalkValues("since", func(value string) error {
|
err = imageFilters.WalkValues("since", func(value string) error {
|
||||||
sinceFilter, err = i.GetImage(value)
|
sinceFilter, err = i.GetImage(value, nil)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -317,7 +317,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis
|
||||||
if psFilters.Contains("ancestor") {
|
if psFilters.Contains("ancestor") {
|
||||||
ancestorFilter = true
|
ancestorFilter = true
|
||||||
psFilters.WalkValues("ancestor", func(ancestor string) error {
|
psFilters.WalkValues("ancestor", func(ancestor string) error {
|
||||||
img, err := daemon.imageService.GetImage(ancestor)
|
img, err := daemon.imageService.GetImage(ancestor, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("Error while looking up for image %v", ancestor)
|
logrus.Warnf("Error while looking up for image %v", ancestor)
|
||||||
return nil
|
return nil
|
||||||
|
@ -581,7 +581,7 @@ func (daemon *Daemon) refreshImage(s *container.Snapshot, ctx *listContext) (*ty
|
||||||
c := s.Container
|
c := s.Container
|
||||||
image := s.Image // keep the original ref if still valid (hasn't changed)
|
image := s.Image // keep the original ref if still valid (hasn't changed)
|
||||||
if image != s.ImageID {
|
if image != s.ImageID {
|
||||||
img, err := daemon.imageService.GetImage(image)
|
img, err := daemon.imageService.GetImage(image, nil)
|
||||||
if _, isDNE := err.(images.ErrImageDoesNotExist); err != nil && !isDNE {
|
if _, isDNE := err.(images.ErrImageDoesNotExist); err != nil && !isDNE {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ const (
|
||||||
|
|
||||||
func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||||
|
|
||||||
img, err := daemon.imageService.GetImage(string(c.ImageID))
|
img, err := daemon.imageService.GetImage(string(c.ImageID), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -523,7 +523,7 @@ func (s *DockerSuite) TestContainerAPIBadPort(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "")
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.ErrorContains(c, err, `invalid port specification: "aa80"`)
|
assert.ErrorContains(c, err, `invalid port specification: "aa80"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,7 +537,7 @@ func (s *DockerSuite) TestContainerAPICreate(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "")
|
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
out, _ := dockerCmd(c, "start", "-a", container.ID)
|
out, _ := dockerCmd(c, "start", "-a", container.ID)
|
||||||
|
@ -550,7 +550,7 @@ func (s *DockerSuite) TestContainerAPICreateEmptyConfig(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &containertypes.Config{}, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "")
|
_, err = cli.ContainerCreate(context.Background(), &containertypes.Config{}, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
|
|
||||||
expected := "No command specified"
|
expected := "No command specified"
|
||||||
assert.ErrorContains(c, err, expected)
|
assert.ErrorContains(c, err, expected)
|
||||||
|
@ -574,7 +574,7 @@ func (s *DockerSuite) TestContainerAPICreateMultipleNetworksConfig(c *testing.T)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networkingConfig, "")
|
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networkingConfig, nil, "")
|
||||||
msg := err.Error()
|
msg := err.Error()
|
||||||
// network name order in error message is not deterministic
|
// network name order in error message is not deterministic
|
||||||
assert.Assert(c, strings.Contains(msg, "Container cannot be connected to network endpoints"))
|
assert.Assert(c, strings.Contains(msg, "Container cannot be connected to network endpoints"))
|
||||||
|
@ -609,7 +609,7 @@ func UtilCreateNetworkMode(c *testing.T, networkMode containertypes.NetworkMode)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "")
|
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||||
|
@ -636,7 +636,7 @@ func (s *DockerSuite) TestContainerAPICreateWithCpuSharesCpuset(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "")
|
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||||
|
@ -948,7 +948,7 @@ func (s *DockerSuite) TestContainerAPIStart(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, name)
|
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, name)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
||||||
|
@ -1272,7 +1272,7 @@ func (s *DockerSuite) TestPostContainerAPICreateWithStringOrSliceEntrypoint(c *t
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "echotest")
|
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "echotest")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
||||||
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
||||||
|
@ -1299,7 +1299,7 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *testing.T)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "echotest")
|
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "echotest")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
||||||
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
||||||
|
@ -1342,7 +1342,7 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *tes
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config2, &hostConfig, &networktypes.NetworkingConfig{}, "capaddtest1")
|
_, err = cli.ContainerCreate(context.Background(), &config2, &hostConfig, &networktypes.NetworkingConfig{}, nil, "capaddtest1")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1356,7 +1356,7 @@ func (s *DockerSuite) TestContainerAPICreateNoHostConfig118(c *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("v1.18"))
|
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("v1.18"))
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "")
|
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,7 +1407,7 @@ func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *testing.T
|
||||||
}
|
}
|
||||||
name := "wrong-cpuset-cpus"
|
name := "wrong-cpuset-cpus"
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig1, &networktypes.NetworkingConfig{}, name)
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig1, &networktypes.NetworkingConfig{}, nil, name)
|
||||||
expected := "Invalid value 1-42,, for cpuset cpus"
|
expected := "Invalid value 1-42,, for cpuset cpus"
|
||||||
assert.ErrorContains(c, err, expected)
|
assert.ErrorContains(c, err, expected)
|
||||||
|
|
||||||
|
@ -1417,7 +1417,7 @@ func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *testing.T
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
name = "wrong-cpuset-mems"
|
name = "wrong-cpuset-mems"
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig2, &networktypes.NetworkingConfig{}, name)
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig2, &networktypes.NetworkingConfig{}, nil, name)
|
||||||
expected = "Invalid value 42-3,1-- for cpuset mems"
|
expected = "Invalid value 42-3,1-- for cpuset mems"
|
||||||
assert.ErrorContains(c, err, expected)
|
assert.ErrorContains(c, err, expected)
|
||||||
}
|
}
|
||||||
|
@ -1436,7 +1436,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeNegative(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "")
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.ErrorContains(c, err, "SHM size can not be less than 0")
|
assert.ErrorContains(c, err, "SHM size can not be less than 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1453,7 +1453,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *testin
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "")
|
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||||
|
@ -1480,7 +1480,7 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "")
|
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||||
|
@ -1511,7 +1511,7 @@ func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "")
|
container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||||
|
@ -1537,7 +1537,7 @@ func (s *DockerSuite) TestPostContainersCreateMemorySwappinessHostConfigOmitted(
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "")
|
container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
containerJSON, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||||
|
@ -1568,7 +1568,7 @@ func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *tes
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
name := "oomscoreadj-over"
|
name := "oomscoreadj-over"
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, name)
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, name)
|
||||||
|
|
||||||
expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]"
|
expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]"
|
||||||
assert.ErrorContains(c, err, expected)
|
assert.ErrorContains(c, err, expected)
|
||||||
|
@ -1578,7 +1578,7 @@ func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *tes
|
||||||
}
|
}
|
||||||
|
|
||||||
name = "oomscoreadj-low"
|
name = "oomscoreadj-low"
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, name)
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, name)
|
||||||
|
|
||||||
expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]"
|
expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]"
|
||||||
assert.ErrorContains(c, err, expected)
|
assert.ErrorContains(c, err, expected)
|
||||||
|
@ -1610,7 +1610,7 @@ func (s *DockerSuite) TestContainerAPIStatsWithNetworkDisabled(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, name)
|
_, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, nil, name)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
||||||
|
@ -1926,7 +1926,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
||||||
for i, x := range cases {
|
for i, x := range cases {
|
||||||
x := x
|
x := x
|
||||||
c.Run(fmt.Sprintf("case %d", i), func(c *testing.T) {
|
c.Run(fmt.Sprintf("case %d", i), func(c *testing.T) {
|
||||||
_, err = apiClient.ContainerCreate(context.Background(), &x.config, &x.hostConfig, &networktypes.NetworkingConfig{}, "")
|
_, err = apiClient.ContainerCreate(context.Background(), &x.config, &x.hostConfig, &networktypes.NetworkingConfig{}, nil, "")
|
||||||
if len(x.msg) > 0 {
|
if len(x.msg) > 0 {
|
||||||
assert.ErrorContains(c, err, x.msg, "%v", cases[i].config)
|
assert.ErrorContains(c, err, x.msg, "%v", cases[i].config)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1959,7 +1959,7 @@ func (s *DockerSuite) TestContainerAPICreateMountsBindRead(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "test")
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, "test")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
out, _ := dockerCmd(c, "start", "-a", "test")
|
out, _ := dockerCmd(c, "start", "-a", "test")
|
||||||
|
@ -2106,6 +2106,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
||||||
&containertypes.Config{Image: testImg},
|
&containertypes.Config{Image: testImg},
|
||||||
&containertypes.HostConfig{Mounts: []mounttypes.Mount{x.spec}},
|
&containertypes.HostConfig{Mounts: []mounttypes.Mount{x.spec}},
|
||||||
&networktypes.NetworkingConfig{},
|
&networktypes.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
"")
|
"")
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
|
@ -2213,7 +2214,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsTmpfs(c *testing.T) {
|
||||||
Mounts: []mounttypes.Mount{x.cfg},
|
Mounts: []mounttypes.Mount{x.cfg},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, cName)
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, nil, cName)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
out, _ := dockerCmd(c, "start", "-a", cName)
|
out, _ := dockerCmd(c, "start", "-a", cName)
|
||||||
for _, option := range x.expectedOptions {
|
for _, option := range x.expectedOptions {
|
||||||
|
|
|
@ -65,7 +65,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsBindNamedPipe(c *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nil, name)
|
nil, nil, name)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
err = client.ContainerStart(ctx, name, types.ContainerStartOptions{})
|
err = client.ContainerStart(ctx, name, types.ContainerStartOptions{})
|
||||||
|
|
|
@ -578,7 +578,7 @@ func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndMounts(c *testing
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, "app")
|
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "app")
|
||||||
|
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
containertypes "github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
@ -17,6 +18,7 @@ import (
|
||||||
ctr "github.com/docker/docker/integration/internal/container"
|
ctr "github.com/docker/docker/integration/internal/container"
|
||||||
"github.com/docker/docker/oci"
|
"github.com/docker/docker/oci"
|
||||||
"github.com/docker/docker/testutil/request"
|
"github.com/docker/docker/testutil/request"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
"gotest.tools/v3/poll"
|
"gotest.tools/v3/poll"
|
||||||
|
@ -57,6 +59,7 @@ func TestCreateFailsWhenIdentifierDoesNotExist(t *testing.T) {
|
||||||
&container.Config{Image: tc.image},
|
&container.Config{Image: tc.image},
|
||||||
&container.HostConfig{},
|
&container.HostConfig{},
|
||||||
&network.NetworkingConfig{},
|
&network.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
||||||
|
@ -81,6 +84,7 @@ func TestCreateLinkToNonExistingContainer(t *testing.T) {
|
||||||
Links: []string{"no-such-container"},
|
Links: []string{"no-such-container"},
|
||||||
},
|
},
|
||||||
&network.NetworkingConfig{},
|
&network.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
assert.Check(t, is.ErrorContains(err, "could not get container for no-such-container"))
|
assert.Check(t, is.ErrorContains(err, "could not get container for no-such-container"))
|
||||||
|
@ -120,6 +124,7 @@ func TestCreateWithInvalidEnv(t *testing.T) {
|
||||||
},
|
},
|
||||||
&container.HostConfig{},
|
&container.HostConfig{},
|
||||||
&network.NetworkingConfig{},
|
&network.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
||||||
|
@ -166,6 +171,7 @@ func TestCreateTmpfsMountsTarget(t *testing.T) {
|
||||||
Tmpfs: map[string]string{tc.target: ""},
|
Tmpfs: map[string]string{tc.target: ""},
|
||||||
},
|
},
|
||||||
&network.NetworkingConfig{},
|
&network.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
||||||
|
@ -235,6 +241,7 @@ func TestCreateWithCustomMaskedPaths(t *testing.T) {
|
||||||
&config,
|
&config,
|
||||||
&hc,
|
&hc,
|
||||||
&network.NetworkingConfig{},
|
&network.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -361,6 +368,7 @@ func TestCreateWithCapabilities(t *testing.T) {
|
||||||
&container.Config{Image: "busybox"},
|
&container.Config{Image: "busybox"},
|
||||||
&tc.hostConfig,
|
&tc.hostConfig,
|
||||||
&network.NetworkingConfig{},
|
&network.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
if tc.expectedError == "" {
|
if tc.expectedError == "" {
|
||||||
|
@ -439,6 +447,7 @@ func TestCreateWithCustomReadonlyPaths(t *testing.T) {
|
||||||
&config,
|
&config,
|
||||||
&hc,
|
&hc,
|
||||||
&network.NetworkingConfig{},
|
&network.NetworkingConfig{},
|
||||||
|
nil,
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -522,7 +531,7 @@ func TestCreateWithInvalidHealthcheckParams(t *testing.T) {
|
||||||
cfg.Healthcheck.StartPeriod = tc.startPeriod
|
cfg.Healthcheck.StartPeriod = tc.startPeriod
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.ContainerCreate(ctx, &cfg, &container.HostConfig{}, nil, "")
|
resp, err := client.ContainerCreate(ctx, &cfg, &container.HostConfig{}, nil, nil, "")
|
||||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||||
|
|
||||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||||
|
@ -581,3 +590,34 @@ func TestCreateTmpfsOverrideAnonymousVolume(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that if the referenced image platform does not match the requested platform on container create that we get an
|
||||||
|
// error.
|
||||||
|
func TestCreateDifferentPlatform(t *testing.T) {
|
||||||
|
defer setupTest(t)()
|
||||||
|
c := testEnv.APIClient()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
img, _, err := c.ImageInspectWithRaw(ctx, "busybox:latest")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, img.Architecture != "")
|
||||||
|
|
||||||
|
t.Run("different os", func(t *testing.T) {
|
||||||
|
p := specs.Platform{
|
||||||
|
OS: img.Os + "DifferentOS",
|
||||||
|
Architecture: img.Architecture,
|
||||||
|
Variant: img.Variant,
|
||||||
|
}
|
||||||
|
_, err := c.ContainerCreate(ctx, &containertypes.Config{Image: "busybox:latest"}, &containertypes.HostConfig{}, nil, &p, "")
|
||||||
|
assert.Assert(t, client.IsErrNotFound(err), err)
|
||||||
|
})
|
||||||
|
t.Run("different cpu arch", func(t *testing.T) {
|
||||||
|
p := specs.Platform{
|
||||||
|
OS: img.Os,
|
||||||
|
Architecture: img.Architecture + "DifferentArch",
|
||||||
|
Variant: img.Variant,
|
||||||
|
}
|
||||||
|
_, err := c.ContainerCreate(ctx, &containertypes.Config{Image: "busybox:latest"}, &containertypes.HostConfig{}, nil, &p, "")
|
||||||
|
assert.Assert(t, client.IsErrNotFound(err), err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func testIpcNonePrivateShareable(t *testing.T, mode string, mustBeMounted bool,
|
||||||
client := testEnv.APIClient()
|
client := testEnv.APIClient()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, nil, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ func testIpcContainer(t *testing.T, donorMode string, mustWork bool) {
|
||||||
client := testEnv.APIClient()
|
client := testEnv.APIClient()
|
||||||
|
|
||||||
// create and start the "donor" container
|
// create and start the "donor" container
|
||||||
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, nil, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||||
name1 := resp.ID
|
name1 := resp.ID
|
||||||
|
@ -148,7 +148,7 @@ func testIpcContainer(t *testing.T, donorMode string, mustWork bool) {
|
||||||
|
|
||||||
// create and start the second container
|
// create and start the second container
|
||||||
hostCfg.IpcMode = containertypes.IpcMode("container:" + name1)
|
hostCfg.IpcMode = containertypes.IpcMode("container:" + name1)
|
||||||
resp, err = client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
resp, err = client.ContainerCreate(ctx, &cfg, &hostCfg, nil, nil, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||||
name2 := resp.ID
|
name2 := resp.ID
|
||||||
|
@ -204,7 +204,7 @@ func TestAPIIpcModeHost(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
client := testEnv.APIClient()
|
client := testEnv.APIClient()
|
||||||
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, nil, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||||
name := resp.ID
|
name := resp.ID
|
||||||
|
@ -241,7 +241,7 @@ func testDaemonIpcPrivateShareable(t *testing.T, mustBeShared bool, arg ...strin
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
resp, err := c.ContainerCreate(ctx, &cfg, &containertypes.HostConfig{}, nil, "")
|
resp, err := c.ContainerCreate(ctx, &cfg, &containertypes.HostConfig{}, nil, nil, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ func TestContainerNetworkMountsNoChown(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
ctrCreate, err := cli.ContainerCreate(ctx, &config, &hostConfig, &network.NetworkingConfig{}, "")
|
ctrCreate, err := cli.ContainerCreate(ctx, &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
// container will exit immediately because of no tty, but we only need the start sequence to test the condition
|
// container will exit immediately because of no tty, but we only need the start sequence to test the condition
|
||||||
err = cli.ContainerStart(ctx, ctrCreate.ID, types.ContainerStartOptions{})
|
err = cli.ContainerStart(ctx, ctrCreate.ID, types.ContainerStartOptions{})
|
||||||
|
@ -174,7 +174,7 @@ func TestMountDaemonRoot(t *testing.T) {
|
||||||
c, err := client.ContainerCreate(ctx, &containertypes.Config{
|
c, err := client.ContainerCreate(ctx, &containertypes.Config{
|
||||||
Image: "busybox",
|
Image: "busybox",
|
||||||
Cmd: []string{"true"},
|
Cmd: []string{"true"},
|
||||||
}, hc, nil, "")
|
}, hc, nil, nil, "")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if test.expected != "" {
|
if test.expected != "" {
|
||||||
|
|
|
@ -77,7 +77,7 @@ func TestDaemonRestartKillContainers(t *testing.T) {
|
||||||
defer d.Stop(t)
|
defer d.Stop(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
resp, err := client.ContainerCreate(ctx, c.config, c.hostConfig, nil, "")
|
resp, err := client.ContainerCreate(ctx, c.config, c.hostConfig, nil, nil, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
defer client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
defer client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ type TestContainerConfig struct {
|
||||||
Config *container.Config
|
Config *container.Config
|
||||||
HostConfig *container.HostConfig
|
HostConfig *container.HostConfig
|
||||||
NetworkingConfig *network.NetworkingConfig
|
NetworkingConfig *network.NetworkingConfig
|
||||||
|
Platform *specs.Platform
|
||||||
}
|
}
|
||||||
|
|
||||||
// create creates a container with the specified options
|
// create creates a container with the specified options
|
||||||
|
@ -41,7 +43,7 @@ func create(ctx context.Context, t *testing.T, client client.APIClient, ops ...f
|
||||||
op(config)
|
op(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.ContainerCreate(ctx, config.Config, config.HostConfig, config.NetworkingConfig, config.Name)
|
return client.ContainerCreate(ctx, config.Config, config.HostConfig, config.NetworkingConfig, config.Platform, config.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a container with the specified options, asserting that there was no error
|
// Create creates a container with the specified options, asserting that there was no error
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
networktypes "github.com/docker/docker/api/types/network"
|
networktypes "github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/strslice"
|
"github.com/docker/docker/api/types/strslice"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WithName sets the name of the container
|
// WithName sets the name of the container
|
||||||
|
@ -205,3 +206,10 @@ func WithExtraHost(extraHost string) func(*TestContainerConfig) {
|
||||||
c.HostConfig.ExtraHosts = append(c.HostConfig.ExtraHosts, extraHost)
|
c.HostConfig.ExtraHosts = append(c.HostConfig.ExtraHosts, extraHost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithPlatform specifies the desired platform the image should have.
|
||||||
|
func WithPlatform(p *specs.Platform) func(*TestContainerConfig) {
|
||||||
|
return func(c *TestContainerConfig) {
|
||||||
|
c.Platform = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ func TestReadPluginNoRead(t *testing.T) {
|
||||||
cfg,
|
cfg,
|
||||||
&container.HostConfig{LogConfig: container.LogConfig{Type: "test"}},
|
&container.HostConfig{LogConfig: container.LogConfig{Type: "test"}},
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
assert.Assert(t, err)
|
assert.Assert(t, err)
|
||||||
|
|
|
@ -155,7 +155,7 @@ COPY . /static`); err != nil {
|
||||||
// Start the container
|
// Start the container
|
||||||
b, err := c.ContainerCreate(context.Background(), &containertypes.Config{
|
b, err := c.ContainerCreate(context.Background(), &containertypes.Config{
|
||||||
Image: image,
|
Image: image,
|
||||||
}, &containertypes.HostConfig{}, nil, container)
|
}, &containertypes.HostConfig{}, nil, nil, container)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
err = c.ContainerStart(context.Background(), b.ID, types.ContainerStartOptions{})
|
err = c.ContainerStart(context.Background(), b.ID, types.ContainerStartOptions{})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
Loading…
Reference in New Issue