distribution: fix passing platform struct to puller
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Upstream-commit: 337ba71fc1124603302e28d94e2f08674e31a756 Component: engine
This commit is contained in:
@@ -96,8 +96,14 @@ func (o *copier) createCopyInstruction(args []string, cmdName string) (copyInstr
|
||||
last := len(args) - 1
|
||||
|
||||
// Work in platform-specific filepath semantics
|
||||
inst.dest = fromSlash(args[last], o.platform.OS)
|
||||
separator := string(separator(o.platform.OS))
|
||||
// TODO: This OS switch for paths is NOT correct and should not be supported.
|
||||
// Maintained for backwards compatibility
|
||||
pathOS := runtime.GOOS
|
||||
if o.platform != nil {
|
||||
pathOS = o.platform.OS
|
||||
}
|
||||
inst.dest = fromSlash(args[last], pathOS)
|
||||
separator := string(separator(pathOS))
|
||||
infos, err := o.getCopyInfosForSourcePaths(args[0:last], inst.dest)
|
||||
if err != nil {
|
||||
return inst, errors.Wrapf(err, "%s failed", cmdName)
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/parser"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/shell"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -103,7 +104,7 @@ func dispatchAdd(d dispatchRequest, c *instructions.AddCommand) error {
|
||||
copyInstruction.chownStr = c.Chown
|
||||
copyInstruction.allowLocalDecompression = true
|
||||
|
||||
return d.builder.performCopy(d.state, copyInstruction)
|
||||
return d.builder.performCopy(d, copyInstruction)
|
||||
}
|
||||
|
||||
// COPY foo /path
|
||||
@@ -127,7 +128,7 @@ func dispatchCopy(d dispatchRequest, c *instructions.CopyCommand) error {
|
||||
}
|
||||
copyInstruction.chownStr = c.Chown
|
||||
|
||||
return d.builder.performCopy(d.state, copyInstruction)
|
||||
return d.builder.performCopy(d, copyInstruction)
|
||||
}
|
||||
|
||||
func (d *dispatchRequest) getImageMount(imageRefOrID string) (*imageMount, error) {
|
||||
@@ -145,7 +146,7 @@ func (d *dispatchRequest) getImageMount(imageRefOrID string) (*imageMount, error
|
||||
imageRefOrID = stage.Image
|
||||
localOnly = true
|
||||
}
|
||||
return d.builder.imageSources.Get(imageRefOrID, localOnly, d.state.operatingSystem)
|
||||
return d.builder.imageSources.Get(imageRefOrID, localOnly, d.builder.options.Platform)
|
||||
}
|
||||
|
||||
// FROM [--platform=platform] imagename[:tag | @digest] [AS build-stage-name]
|
||||
@@ -153,22 +154,21 @@ func (d *dispatchRequest) getImageMount(imageRefOrID string) (*imageMount, error
|
||||
func initializeStage(d dispatchRequest, cmd *instructions.Stage) error {
|
||||
d.builder.imageProber.Reset()
|
||||
|
||||
// TODO: pass *platform instead, allow autodetect
|
||||
platform := platforms.DefaultSpec()
|
||||
var platform *specs.Platform
|
||||
if v := cmd.Platform; v != "" {
|
||||
// TODO:
|
||||
// v, err := shlex.ProcessWord(v, toEnvList(metaArgs, nil))
|
||||
// if err != nil {
|
||||
// return nil, nil, errors.Wrapf(err, "failed to process arguments for platform %s", v)
|
||||
// }
|
||||
v, err := d.getExpandedString(d.shlex, v)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to process arguments for platform %s", v)
|
||||
}
|
||||
|
||||
p, err := platforms.Parse(v)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse platform %s", v)
|
||||
}
|
||||
platform = p
|
||||
platform = &p
|
||||
}
|
||||
image, err := d.getFromImage(d.shlex, cmd.BaseName, platform.OS)
|
||||
|
||||
image, err := d.getFromImage(d.shlex, cmd.BaseName, platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -214,82 +214,72 @@ func dispatchTriggeredOnBuild(d dispatchRequest, triggers []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dispatchRequest) getExpandedImageName(shlex *shell.Lex, name string) (string, error) {
|
||||
func (d *dispatchRequest) getExpandedString(shlex *shell.Lex, str string) (string, error) {
|
||||
substitutionArgs := []string{}
|
||||
for key, value := range d.state.buildArgs.GetAllMeta() {
|
||||
substitutionArgs = append(substitutionArgs, key+"="+value)
|
||||
}
|
||||
|
||||
name, err := shlex.ProcessWord(name, substitutionArgs)
|
||||
name, err := shlex.ProcessWord(str, substitutionArgs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// getOsFromFlagsAndStage calculates the operating system if we need to pull an image.
|
||||
// stagePlatform contains the value supplied by optional `--platform=` on
|
||||
// a current FROM statement. b.builder.options.Platform contains the operating
|
||||
// system part of the optional flag passed in the API call (or CLI flag
|
||||
// through `docker build --platform=...`). Precedence is for an explicit
|
||||
// platform indication in the FROM statement.
|
||||
func (d *dispatchRequest) getOsFromFlagsAndStage(stageOS string) string {
|
||||
switch {
|
||||
case stageOS != "":
|
||||
return stageOS
|
||||
case d.builder.options.Platform.OS != "":
|
||||
// Note this is API "platform", but by this point, as the daemon is not
|
||||
// multi-arch aware yet, it is guaranteed to only hold the OS part here.
|
||||
return d.builder.options.Platform.OS
|
||||
default:
|
||||
return "" // Auto-select
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dispatchRequest) getImageOrStage(name string, stageOS string) (builder.Image, error) {
|
||||
func (d *dispatchRequest) getImageOrStage(name string, platform *specs.Platform) (builder.Image, error) {
|
||||
var localOnly bool
|
||||
if im, ok := d.stages.getByName(name); ok {
|
||||
name = im.Image
|
||||
localOnly = true
|
||||
}
|
||||
|
||||
os := d.getOsFromFlagsAndStage(stageOS)
|
||||
if platform == nil {
|
||||
platform = d.builder.options.Platform
|
||||
}
|
||||
|
||||
// Windows cannot support a container with no base image unless it is LCOW.
|
||||
if name == api.NoBaseImageSpecifier {
|
||||
p := platforms.DefaultSpec()
|
||||
if platform != nil {
|
||||
p = *platform
|
||||
}
|
||||
imageImage := &image.Image{}
|
||||
imageImage.OS = runtime.GOOS
|
||||
imageImage.OS = p.OS
|
||||
|
||||
// old windows scratch handling
|
||||
// TODO: scratch should not have an os. It should be nil image.
|
||||
// Windows supports scratch. What is not supported is running containers
|
||||
// from it.
|
||||
if runtime.GOOS == "windows" {
|
||||
switch os {
|
||||
case "windows":
|
||||
return nil, errors.New("Windows does not support FROM scratch")
|
||||
case "linux", "":
|
||||
if platform == nil || platform.OS == "linux" {
|
||||
if !system.LCOWSupported() {
|
||||
return nil, errors.New("Linux containers are not supported on this system")
|
||||
}
|
||||
imageImage.OS = "linux"
|
||||
default:
|
||||
return nil, errors.Errorf("operating system %q is not supported", os)
|
||||
} else if platform.OS == "windows" {
|
||||
return nil, errors.New("Windows does not support FROM scratch")
|
||||
} else {
|
||||
return nil, errors.Errorf("platform %s is not supported", platforms.Format(p))
|
||||
}
|
||||
}
|
||||
return builder.Image(imageImage), nil
|
||||
}
|
||||
imageMount, err := d.builder.imageSources.Get(name, localOnly, os)
|
||||
imageMount, err := d.builder.imageSources.Get(name, localOnly, platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return imageMount.Image(), nil
|
||||
}
|
||||
func (d *dispatchRequest) getFromImage(shlex *shell.Lex, name string, stageOS string) (builder.Image, error) {
|
||||
name, err := d.getExpandedImageName(shlex, name)
|
||||
func (d *dispatchRequest) getFromImage(shlex *shell.Lex, name string, platform *specs.Platform) (builder.Image, error) {
|
||||
name, err := d.getExpandedString(shlex, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.getImageOrStage(name, stageOS)
|
||||
return d.getImageOrStage(name, platform)
|
||||
}
|
||||
|
||||
func dispatchOnbuild(d dispatchRequest, c *instructions.OnbuildCommand) error {
|
||||
|
||||
d.state.runConfig.OnBuild = append(d.state.runConfig.OnBuild, c.Expression)
|
||||
return d.builder.commit(d.state, "ONBUILD "+c.Expression)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
@@ -22,15 +23,17 @@ import (
|
||||
|
||||
func newBuilderWithMockBackend() *Builder {
|
||||
mockBackend := &MockBackend{}
|
||||
defaultPlatform := platforms.DefaultSpec()
|
||||
opts := &types.ImageBuildOptions{Platform: &defaultPlatform}
|
||||
ctx := context.Background()
|
||||
b := &Builder{
|
||||
options: &types.ImageBuildOptions{Platform: runtime.GOOS},
|
||||
options: opts,
|
||||
docker: mockBackend,
|
||||
Stdout: new(bytes.Buffer),
|
||||
clientCtx: ctx,
|
||||
disableCommit: true,
|
||||
imageSources: newImageSources(ctx, builderOptions{
|
||||
Options: &types.ImageBuildOptions{Platform: runtime.GOOS},
|
||||
Options: opts,
|
||||
Backend: mockBackend,
|
||||
}),
|
||||
imageProber: newImageProber(mockBackend, nil, false),
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/builder"
|
||||
dockerimage "github.com/docker/docker/image"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type getAndMountFunc func(string, bool, string) (builder.Image, builder.ROLayer, error)
|
||||
type getAndMountFunc func(string, bool, *specs.Platform) (builder.Image, builder.ROLayer, error)
|
||||
|
||||
// imageSources mounts images and provides a cache for mounted images. It tracks
|
||||
// all images so they can be unmounted at the end of the build.
|
||||
@@ -22,7 +23,7 @@ type imageSources struct {
|
||||
}
|
||||
|
||||
func newImageSources(ctx context.Context, options builderOptions) *imageSources {
|
||||
getAndMount := func(idOrRef string, localOnly bool, osForPull string) (builder.Image, builder.ROLayer, error) {
|
||||
getAndMount := func(idOrRef string, localOnly bool, platform *specs.Platform) (builder.Image, builder.ROLayer, error) {
|
||||
pullOption := backend.PullOptionNoPull
|
||||
if !localOnly {
|
||||
if options.Options.PullParent {
|
||||
@@ -35,7 +36,7 @@ func newImageSources(ctx context.Context, options builderOptions) *imageSources
|
||||
PullOption: pullOption,
|
||||
AuthConfig: options.Options.AuthConfigs,
|
||||
Output: options.ProgressWriter.Output,
|
||||
OS: osForPull,
|
||||
Platform: platform,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,12 +46,12 @@ func newImageSources(ctx context.Context, options builderOptions) *imageSources
|
||||
}
|
||||
}
|
||||
|
||||
func (m *imageSources) Get(idOrRef string, localOnly bool, osForPull string) (*imageMount, error) {
|
||||
func (m *imageSources) Get(idOrRef string, localOnly bool, platform *specs.Platform) (*imageMount, error) {
|
||||
if im, ok := m.byImageID[idOrRef]; ok {
|
||||
return im, nil
|
||||
}
|
||||
|
||||
image, layer, err := m.getImage(idOrRef, localOnly, osForPull)
|
||||
image, layer, err := m.getImage(idOrRef, localOnly, platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -150,7 +150,8 @@ func (b *Builder) exportImage(state *dispatchState, layer builder.RWLayer, paren
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) performCopy(state *dispatchState, inst copyInstruction) error {
|
||||
func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
|
||||
state := req.state
|
||||
srcHash := getSourceHashFromInfos(inst.infos)
|
||||
|
||||
var chownComment string
|
||||
@@ -168,7 +169,7 @@ func (b *Builder) performCopy(state *dispatchState, inst copyInstruction) error
|
||||
return err
|
||||
}
|
||||
|
||||
imageMount, err := b.imageSources.Get(state.imageID, true, state.operatingSystem)
|
||||
imageMount, err := b.imageSources.Get(state.imageID, true, req.builder.options.Platform)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get destination image %q", state.imageID)
|
||||
}
|
||||
@@ -456,7 +457,7 @@ func hostConfigFromOptions(options *types.ImageBuildOptions) *container.HostConf
|
||||
// is too small for builder scenarios where many users are
|
||||
// using RUN statements to install large amounts of data.
|
||||
// Use 127GB as that's the default size of a VHD in Hyper-V.
|
||||
if runtime.GOOS == "windows" && options.Platform.OS == "windows" {
|
||||
if runtime.GOOS == "windows" && options.Platform != nil && options.Platform.OS == "windows" {
|
||||
hc.StorageOpt = make(map[string]string)
|
||||
hc.StorageOpt["size"] = "127GB"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user