Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion docs/spec.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,19 @@
"type": "object",
"description": "Artifacts describes all the artifacts to include in the package."
},
"BaseImage": {
"properties": {
"rootfs": {
"$ref": "#/$defs/Source",
"description": "Rootfs represents an image rootfs."
}
},
"additionalProperties": false,
"type": "object",
"required": [
"rootfs"
]
},
"BuildStep": {
"properties": {
"command": {
Expand Down Expand Up @@ -487,7 +500,14 @@
},
"base": {
"type": "string",
"description": "Base is the base image to use for the output image.\nThis only affects the output image, not the intermediate build image."
"description": "Deprecated: Use [Bases] instead."
},
"Bases": {
"items": {
"$ref": "#/$defs/BaseImage"
},
"type": "array",
"description": "Bases is used to specify a list of base images to build images for. The\nintent of allowing multiple bases is for cases, such as Windows, where you\nmay want to publish multiple versions of a base image in one image.\n\nWindows is the example here because of the way Windows works, the image\nthat the base is based off of must match the OS version of the host machine.\nTherefore it is common to have multiple Windows images in one with a\ndifferent value for the os version field of the platform.\n\nFor the most part implementations are not expected to support multiple base\nimages and may error out if multiple are specified.\n\nThis should not be set if [Base] is also set."
},
"post": {
"$ref": "#/$defs/PostInstall",
Expand All @@ -500,6 +520,9 @@
},
"additionalProperties": false,
"type": "object",
"required": [
"Bases"
],
"description": "ImageConfig is the configuration for the output image."
},
"PackageConfig": {
Expand Down
29 changes: 20 additions & 9 deletions frontend/azlinux/handle_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func handleContainer(w worker) gwclient.BuildFunc {
return nil, nil, fmt.Errorf("error creating rpm: %w", err)
}

img, err := resolveBaseConfig(ctx, w, client, platform, spec, targetKey)
img, err := resolveBaseConfig(ctx, w, sOpt, platform, spec, targetKey)
if err != nil {
return nil, nil, errors.Wrap(err, "could not resolve base image config")
}
Expand All @@ -50,9 +50,13 @@ func specToContainerLLB(w worker, spec *dalec.Spec, targetKey string, rpmDir llb
return llb.Scratch(), err
}

rootfs := llb.Scratch()
if ref := dalec.GetBaseOutputImage(spec, targetKey); ref != "" {
rootfs = llb.Image(ref, llb.WithMetaResolver(sOpt.Resolver), dalec.WithConstraints(opts...))
bi, err := spec.GetSingleBase(targetKey)
if err != nil {
return llb.Scratch(), err
}
rootfs, err := bi.ToState(sOpt, opts...)
if err != nil {
return llb.Scratch(), err
}

installTimeRepos := spec.GetInstallRepos(targetKey)
Expand Down Expand Up @@ -84,13 +88,20 @@ func specToContainerLLB(w worker, spec *dalec.Spec, targetKey string, rpmDir llb
return rootfs, nil
}

func resolveBaseConfig(ctx context.Context, w worker, resolver llb.ImageMetaResolver, platform *ocispecs.Platform, spec *dalec.Spec, targetKey string) (*dalec.DockerImageSpec, error) {
func resolveBaseConfig(ctx context.Context, w worker, sOpt dalec.SourceOpts, platform *ocispecs.Platform, spec *dalec.Spec, targetKey string) (*dalec.DockerImageSpec, error) {
var img *dalec.DockerImageSpec

if ref := dalec.GetBaseOutputImage(spec, targetKey); ref != "" {
_, _, dt, err := resolver.ResolveImageConfig(ctx, ref, sourceresolver.Opt{Platform: platform})
bi, err := spec.GetSingleBase(targetKey)
if err != nil {
return nil, errors.Wrap(err, "error resolving base image config")
}

if bi != nil {
dt, err := bi.ResolveImageConfig(ctx, sOpt, sourceresolver.Opt{
Platform: platform,
})
if err != nil {
return nil, errors.Wrap(err, "error resolving base image config")
return nil, err
}

var i dalec.DockerImageSpec
Expand All @@ -100,7 +111,7 @@ func resolveBaseConfig(ctx context.Context, w worker, resolver llb.ImageMetaReso
img = &i
} else {
var err error
img, err = w.DefaultImageConfig(ctx, resolver, platform)
img, err = w.DefaultImageConfig(ctx, sOpt.Resolver, platform)
if err != nil {
return nil, errors.Wrap(err, "error resolving default image config")
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/azlinux/handle_depsonly.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func handleDepsOnly(w worker) gwclient.BuildFunc {
return nil, nil, err
}

img, err := resolveBaseConfig(ctx, w, client, platform, spec, targetKey)
img, err := resolveBaseConfig(ctx, w, sOpt, platform, spec, targetKey)
if err != nil {
return nil, nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions frontend/azlinux/handle_rpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func handleRPM(w worker) gwclient.BuildFunc {
if imgRef, err := runTests(ctx, client, w, spec, sOpt, st, targetKey, pg); err != nil {
// return the container ref in case of error so it can be used to debug
// the installed package state.
cfg, _ := resolveBaseConfig(ctx, w, client, platform, spec, targetKey)
cfg, _ := resolveBaseConfig(ctx, w, sOpt, platform, spec, targetKey)
return imgRef, cfg, err
}

Expand Down Expand Up @@ -94,7 +94,7 @@ func runTests(ctx context.Context, client gwclient.Client, w worker, spec *dalec
}

err = frontend.RunTests(ctx, client, spec, ref, withDeps, targetKey)
return ref, errors.Wrap(err, "TESTS FAILED")
return ref, err
}

var azlinuxRepoPlatform = dalec.RepoPlatformConfig{
Expand Down
6 changes: 5 additions & 1 deletion frontend/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,18 @@ func fillPlatformArgs(prefix string, args map[string]string, platform ocispecs.P
type PlatformBuildFunc func(ctx context.Context, client gwclient.Client, platform *ocispecs.Platform, spec *dalec.Spec, targetKey string) (gwclient.Reference, *dalec.DockerImageSpec, error)

// BuildWithPlatform is a helper function to build a spec with a given platform
// It takes care of looping through each tarrget platform and executing the build with the platform args substituted in the spec.
// It takes care of looping through each target platform and executing the build with the platform args substituted in the spec.
// This also deals with the docker-style multi-platform output.
func BuildWithPlatform(ctx context.Context, client gwclient.Client, f PlatformBuildFunc) (*gwclient.Result, error) {
dc, err := dockerui.NewClient(client)
if err != nil {
return nil, err
}
return BuildWithPlatformFromUIClient(ctx, client, dc, f)
}

// Like [BuildWithPlatform] but with a pre-initialized dockerui.Client
func BuildWithPlatformFromUIClient(ctx context.Context, client gwclient.Client, dc *dockerui.Client, f PlatformBuildFunc) (*gwclient.Result, error) {
rb, err := dc.Build(ctx, func(ctx context.Context, platform *ocispecs.Platform, idx int) (gwclient.Reference, *dalec.DockerImageSpec, *dalec.DockerImageSpec, error) {
spec, err := LoadSpec(ctx, dc, platform)
if err != nil {
Expand Down
24 changes: 16 additions & 8 deletions frontend/deb/distro/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@ import (
)

func (c *Config) BuildContainer(worker llb.State, sOpt dalec.SourceOpts, client gwclient.Client, spec *dalec.Spec, targetKey string, debSt llb.State, opts ...llb.ConstraintsOpt) (llb.State, error) {
base := dalec.GetBaseOutputImage(spec, targetKey)
if base == "" {
base = c.DefaultOutputImage
bi, err := spec.GetSingleBase(targetKey)
if err != nil {
return llb.Scratch(), err
}

if base == "" {
return llb.Scratch(), fmt.Errorf("no output image ref specified, cannot build from scratch")
var baseImg llb.State
if bi != nil {
img, err := bi.ToState(sOpt, opts...)
if err != nil {
return llb.Scratch(), err
}
baseImg = img
} else {
if c.DefaultOutputImage == "" {
return llb.Scratch(), fmt.Errorf("no output image ref specified, cannot build from scratch")
}
baseImg = llb.Image(c.DefaultOutputImage, llb.WithMetaResolver(sOpt.Resolver), dalec.WithConstraints(opts...))
}

opts = append(opts, dalec.ProgressGroup("Build Container Image"))
Expand All @@ -31,8 +41,6 @@ func (c *Config) BuildContainer(worker llb.State, sOpt dalec.SourceOpts, client
return llb.Scratch(), err
}

baseImg := llb.Image(base, llb.WithMetaResolver(sOpt.Resolver), dalec.WithConstraints(opts...))

debug := llb.Scratch().File(llb.Mkfile("debug", 0o644, []byte(`debug=2`)), opts...)
opts = append(opts, dalec.ProgressGroup("Install spec package"))

Expand Down Expand Up @@ -93,7 +101,7 @@ func (c *Config) HandleContainer(ctx context.Context, client gwclient.Client) (*
return nil, nil, err
}

img, err := c.BuildImageConfig(ctx, client, spec, platform, targetKey)
img, err := c.BuildImageConfig(ctx, sOpt, spec, platform, targetKey)
if err != nil {
return nil, nil, err
}
Expand Down
18 changes: 11 additions & 7 deletions frontend/deb/distro/distro.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ type Config struct {
ExtraRepos []dalec.PackageRepositoryConfig
}

func (cfg *Config) BuildImageConfig(ctx context.Context, resolver llb.ImageMetaResolver, spec *dalec.Spec, platform *ocispecs.Platform, targetKey string) (*dalec.DockerImageSpec, error) {
img, err := resolveConfig(ctx, resolver, spec, platform, targetKey)
func (cfg *Config) BuildImageConfig(ctx context.Context, sOpt dalec.SourceOpts, spec *dalec.Spec, platform *ocispecs.Platform, targetKey string) (*dalec.DockerImageSpec, error) {
img, err := resolveConfig(ctx, sOpt, spec, platform, targetKey)
if err != nil {
return nil, err
}
Expand All @@ -52,17 +52,21 @@ func (cfg *Config) BuildImageConfig(ctx context.Context, resolver llb.ImageMetaR
return img, nil
}

func resolveConfig(ctx context.Context, resolver llb.ImageMetaResolver, spec *dalec.Spec, platform *ocispecs.Platform, targetKey string) (*dalec.DockerImageSpec, error) {
ref := dalec.GetBaseOutputImage(spec, targetKey)
if ref == "" {
func resolveConfig(ctx context.Context, sOpt dalec.SourceOpts, spec *dalec.Spec, platform *ocispecs.Platform, targetKey string) (*dalec.DockerImageSpec, error) {
bi, err := spec.GetSingleBase(targetKey)
if err != nil {
return nil, err
}

if bi == nil {
return dalec.BaseImageConfig(platform), nil
}

_, _, dt, err := resolver.ResolveImageConfig(ctx, ref, sourceresolver.Opt{
dt, err := bi.ResolveImageConfig(ctx, sOpt, sourceresolver.Opt{
Platform: platform,
})
if err != nil {
return nil, err
return nil, errors.Wrap(err, "error resolving base image config")
}

var img dalec.DockerImageSpec
Expand Down
2 changes: 1 addition & 1 deletion frontend/deb/distro/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func (cfg *Config) HandleDeb(ctx context.Context, client gwclient.Client) (*gwcl
}

if ref, err := cfg.runTests(ctx, client, spec, sOpt, targetKey, ctr, pg); err != nil {
cfg, _ := cfg.BuildImageConfig(ctx, client, spec, platform, targetKey)
cfg, _ := cfg.BuildImageConfig(ctx, sOpt, spec, platform, targetKey)
return ref, cfg, err
}

Expand Down
17 changes: 10 additions & 7 deletions frontend/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,7 @@ func GetBuildArg(client gwclient.Client, k string) (string, bool) {
return "", false
}

func SourceOptFromClient(ctx context.Context, c gwclient.Client) (dalec.SourceOpts, error) {
dc, err := dockerui.NewClient(c)
if err != nil {
return dalec.SourceOpts{}, err
}

func SourceOptFromUIClient(ctx context.Context, c gwclient.Client, dc *dockerui.Client) dalec.SourceOpts {
return dalec.SourceOpts{
Resolver: c,
Forward: ForwarderFromClient(ctx, c),
Expand All @@ -125,7 +120,15 @@ func SourceOptFromClient(ctx context.Context, c gwclient.Client) (dalec.SourceOp
}
return st, nil
},
}, nil
}
}

func SourceOptFromClient(ctx context.Context, c gwclient.Client) (dalec.SourceOpts, error) {
dc, err := dockerui.NewClient(c)
if err != nil {
return dalec.SourceOpts{}, err
}
return SourceOptFromUIClient(ctx, c, dc), nil
}

var (
Expand Down
Loading
Loading