Skip to content

Commit 5c25e1e

Browse files
committed
build: add support for --push
* pass systemCtx to push util * fix test Signed-off-by: Danish Prakash <[email protected]>
1 parent 49406e1 commit 5c25e1e

File tree

12 files changed

+183
-45
lines changed

12 files changed

+183
-45
lines changed

cmd/buildah/push.go

+2-19
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/containers/image/v5/manifest"
1717
"github.com/containers/image/v5/pkg/compression"
1818
"github.com/containers/image/v5/transports"
19-
"github.com/containers/image/v5/transports/alltransports"
2019
"github.com/containers/storage"
2120
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
2221
"github.com/sirupsen/logrus"
@@ -148,25 +147,9 @@ func pushCmd(c *cobra.Command, args []string, iopts pushOptions) error {
148147
return err
149148
}
150149

151-
dest, err := alltransports.ParseImageName(destSpec)
152-
// add the docker:// transport to see if they neglected it.
150+
dest, err := util.ImageStringToImageReference(destSpec)
153151
if err != nil {
154-
destTransport := strings.Split(destSpec, ":")[0]
155-
if t := transports.Get(destTransport); t != nil {
156-
return err
157-
}
158-
159-
if strings.Contains(destSpec, "://") {
160-
return err
161-
}
162-
163-
destSpec = "docker://" + destSpec
164-
dest2, err2 := alltransports.ParseImageName(destSpec)
165-
if err2 != nil {
166-
return err
167-
}
168-
dest = dest2
169-
logrus.Debugf("Assuming docker:// as the transport method for DESTINATION: %s", destSpec)
152+
return fmt.Errorf("generating image reference: %w", err)
170153
}
171154

172155
systemContext, err := parse.SystemContextFromOptions(c)

define/build.go

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ type BuildOptions struct {
171171
// image that's meant to be run using krun as a VM instead of a conventional
172172
// process-type container.
173173
ConfidentialWorkload ConfidentialWorkloadOptions
174+
Push bool
174175
// Additional tags to add to the image that we write, if we know of a
175176
// way to add them.
176177
AdditionalTags []string

define/types.go

+31-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"strings"
1616

1717
"github.com/containers/image/v5/manifest"
18+
imageTypes "github.com/containers/image/v5/types"
1819
"github.com/containers/storage/pkg/archive"
1920
"github.com/containers/storage/pkg/chrootarchive"
2021
"github.com/containers/storage/pkg/ioutils"
@@ -111,9 +112,37 @@ type Secret struct {
111112

112113
// BuildOutputOptions contains the the outcome of parsing the value of a build --output flag
113114
type BuildOutputOption struct {
114-
Path string // Only valid if !IsStdout
115-
IsDir bool
115+
ImageRef imageTypes.ImageReference
116+
Image string
116117
IsStdout bool
118+
Path string // Only valid if !IsStdout
119+
Push bool
120+
Type BuildOutputType
121+
122+
// Deprecated: Use Type instead to determine output type
123+
IsDir bool
124+
}
125+
126+
type BuildOutputType int
127+
128+
const (
129+
_ BuildOutputType = iota
130+
BuildOutputImage
131+
BuildOutputLocal
132+
BuildOutputTar
133+
)
134+
135+
// String converts a BuildOutputType into a string.
136+
func (t BuildOutputType) String() string {
137+
switch t {
138+
case BuildOutputImage:
139+
return "image"
140+
case BuildOutputLocal:
141+
return "local"
142+
case BuildOutputTar:
143+
return "tar"
144+
}
145+
return fmt.Sprintf("unrecognized build output type %d", t)
117146
}
118147

119148
// ConfidentialWorkloadOptions encapsulates options which control whether or not

docs/buildah-build.1.md

+6
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,8 @@ Supported _keys_ are:
717717

718718
Valid _type_ values are:
719719
- **local**: write the resulting build files to a directory on the client-side.
720+
- **image**: writes the build results as an image to local storage.
721+
- **registry**: pushes the resulting build image to the registry. Shorthand for `type=image,push=true`.
720722
- **tar**: write the resulting files as a single tarball (.tar).
721723

722724
If no type is specified, the value defaults to **local**.
@@ -774,6 +776,10 @@ registries.conf if newer. Raise an error if a base or SBOM scanner image is
774776
not found in the registries when image with the same name is not present
775777
locally.
776778

779+
**--push**
780+
781+
Shorthand for "--output=type=registry"
782+
777783
**--quiet**, **-q**
778784

779785
Suppress output messages which indicate which instruction is being processed,

imagebuildah/executor.go

+3
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ type Executor struct {
7474
registry string
7575
ignoreUnrecognizedInstructions bool
7676
quiet bool
77+
push bool
7778
runtime string
7879
runtimeArgs []string
7980
transientMounts []Mount
@@ -245,6 +246,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
245246
registry: options.Registry,
246247
ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions,
247248
quiet: options.Quiet,
249+
push: options.Push, // TODO: not needed if planning to update buildOutput in cli/build
248250
runtime: options.Runtime,
249251
runtimeArgs: options.RuntimeArgs,
250252
transientMounts: transientMounts,
@@ -950,6 +952,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
950952
}
951953
}
952954
stageID, stageRef, stageOnlyBaseImage, stageErr := b.buildStage(ctx, cleanupStages, stages, index)
955+
953956
if stageErr != nil {
954957
cancel = true
955958
ch <- Result{

imagebuildah/stage_executor.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -1268,7 +1268,7 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string,
12681268
canGenerateBuildOutput := (s.executor.buildOutput != "" && lastStage)
12691269
if canGenerateBuildOutput {
12701270
logrus.Debugf("Generating custom build output with options %q", s.executor.buildOutput)
1271-
buildOutputOption, err = parse.GetBuildOutput(s.executor.buildOutput)
1271+
buildOutputOption, err = parse.GetBuildOutput(s.executor.buildOutput, s.executor.output)
12721272
if err != nil {
12731273
return "", nil, false, fmt.Errorf("failed to parse build output: %w", err)
12741274
}
@@ -2363,7 +2363,17 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
23632363
return imgID, ref, nil
23642364
}
23652365

2366-
func (s *StageExecutor) generateBuildOutput(buildOutputOpts define.BuildOutputOption) error {
2366+
func (s *StageExecutor) generateBuildOutput(opts define.BuildOutputOption) error {
2367+
if opts.Type == define.BuildOutputImage {
2368+
if opts.Push {
2369+
err := internalUtil.PushImage(s.executor.store, opts, s.executor.systemContext)
2370+
if err != nil {
2371+
return fmt.Errorf("failed to export build output: %w", err)
2372+
}
2373+
}
2374+
return nil
2375+
}
2376+
23672377
extractRootfsOpts := buildah.ExtractRootfsOptions{}
23682378
if unshare.IsRootless() {
23692379
// In order to maintain as much parity as possible
@@ -2383,7 +2393,7 @@ func (s *StageExecutor) generateBuildOutput(buildOutputOpts define.BuildOutputOp
23832393
return fmt.Errorf("failed to extract rootfs from given container image: %w", err)
23842394
}
23852395
defer rc.Close()
2386-
err = internalUtil.ExportFromReader(rc, buildOutputOpts)
2396+
err = internalUtil.ExportFromReader(rc, opts)
23872397
if err != nil {
23882398
return fmt.Errorf("failed to export build output: %w", err)
23892399
}

internal/util/util.go

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package util
22

33
import (
4+
"context"
45
"fmt"
56
"io"
67
"os"
78
"path/filepath"
89

910
"github.com/containers/buildah/define"
11+
"github.com/containers/buildah/util"
1012
"github.com/containers/common/libimage"
1113
lplatform "github.com/containers/common/libimage/platform"
1214
"github.com/containers/image/v5/types"
@@ -32,6 +34,7 @@ func LookupImage(ctx *types.SystemContext, store storage.Store, image string) (*
3234
return nil, err
3335
}
3436
return localImage, nil
37+
//
3538
}
3639

3740
// NormalizePlatform validates and translate the platform to the canonical value.
@@ -50,6 +53,29 @@ func NormalizePlatform(platform v1.Platform) v1.Platform {
5053
}
5154
}
5255

56+
// PushImage copies contents of the image to a new location
57+
func PushImage(store storage.Store, opts define.BuildOutputOption, systemCtx *types.SystemContext) error {
58+
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemCtx})
59+
if err != nil {
60+
return err
61+
}
62+
63+
imageRef, err := util.ImageStringToImageReference(opts.Image)
64+
if err != nil {
65+
return fmt.Errorf("failed to convert image to ImageReference")
66+
}
67+
68+
libimageOptions := &libimage.PushOptions{}
69+
libimageOptions.Writer = os.Stdout
70+
dest := fmt.Sprintf("%s:%s", imageRef.Transport().Name(), imageRef.StringWithinTransport())
71+
_, err = runtime.Push(context.Background(), opts.Image, dest, libimageOptions)
72+
if err != nil {
73+
return fmt.Errorf("failed while pushing image %+q: %w", opts.ImageRef, err)
74+
}
75+
76+
return nil
77+
}
78+
5379
// ExportFromReader reads bytes from given reader and exports to external tar, directory or stdout.
5480
func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
5581
var err error
@@ -59,7 +85,8 @@ func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
5985
return err
6086
}
6187
}
62-
if opts.IsDir {
88+
switch opts.Type {
89+
case define.BuildOutputLocal:
6390
// In order to keep this feature as close as possible to
6491
// buildkit it was decided to preserve ownership when
6592
// invoked as root since caller already has access to artifacts
@@ -81,7 +108,7 @@ func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
81108
if err != nil {
82109
return fmt.Errorf("failed while performing untar at %q: %w", opts.Path, err)
83110
}
84-
} else {
111+
case define.BuildOutputTar:
85112
outFile := os.Stdout
86113
if !opts.IsStdout {
87114
outFile, err = os.Create(opts.Path)
@@ -94,7 +121,10 @@ func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
94121
if err != nil {
95122
return fmt.Errorf("failed while performing copy to %q: %w", opts.Path, err)
96123
}
124+
default:
125+
return fmt.Errorf("build output type %s not supported", opts.Type)
97126
}
127+
98128
return nil
99129
}
100130

pkg/cli/build.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
265265
timestamp = &t
266266
}
267267
if c.Flag("output").Changed {
268-
buildOption, err := parse.GetBuildOutput(iopts.BuildOutput)
268+
buildOption, err := parse.GetBuildOutput(iopts.BuildOutput, output)
269269
if err != nil {
270270
return options, nil, nil, err
271271
}
@@ -280,6 +280,15 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
280280
return options, nil, nil, err
281281
}
282282
}
283+
284+
if c.Flag("push").Changed {
285+
if len(iopts.BuildOutput) == 0 {
286+
iopts.BuildOutput = "type=registry"
287+
} else {
288+
return options, nil, nil, fmt.Errorf("cannot set both --push and --output")
289+
}
290+
}
291+
283292
var cacheTo []reference.Named
284293
var cacheFrom []reference.Named
285294
cacheTo = nil
@@ -399,6 +408,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
399408
OutputFormat: format,
400409
Platforms: platforms,
401410
PullPolicy: pullPolicy,
411+
Push: iopts.Push,
402412
Quiet: iopts.Quiet,
403413
RemoveIntermediateCtrs: iopts.Rm,
404414
ReportWriter: reporter,

pkg/cli/common.go

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type BudResults struct {
8585
Pull string
8686
PullAlways bool
8787
PullNever bool
88+
Push bool
8889
Quiet bool
8990
IdentityLabel bool
9091
Rm bool
@@ -305,6 +306,7 @@ newer: only pull base and SBOM scanner images when newer images exist on the r
305306
fs.BoolVar(&flags.Stdin, "stdin", false, "pass stdin into containers")
306307
fs.StringArrayVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image")
307308
fs.StringVarP(&flags.BuildOutput, "output", "o", "", "output destination (format: type=local,dest=path)")
309+
fs.BoolVar(&flags.Push, "push", false, "Shorthand for `--output=type=registry`")
308310
fs.StringVar(&flags.Target, "target", "", "set the target build stage to build")
309311
fs.Int64Var(&flags.Timestamp, "timestamp", 0, "set created timestamp to the specified epoch seconds to allow for deterministic builds, defaults to current time")
310312
fs.BoolVar(&flags.TLSVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")

0 commit comments

Comments
 (0)