Skip to content

Commit f9d20a2

Browse files
committed
build: add support for --push
* add test Signed-off-by: danishprakash <[email protected]>
1 parent e676f85 commit f9d20a2

File tree

12 files changed

+190
-57
lines changed

12 files changed

+190
-57
lines changed

cmd/buildah/push.go

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

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

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

define/build.go

+1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ type BuildOptions struct {
170170
// image that's meant to be run using krun as a VM instead of a conventional
171171
// process-type container.
172172
ConfidentialWorkload ConfidentialWorkloadOptions
173+
Push bool
173174
// Additional tags to add to the image that we write, if we know of a
174175
// way to add them.
175176
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"
@@ -108,9 +109,37 @@ type Secret struct {
108109

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

116145
// ConfidentialWorkloadOptions encapsulates options which control whether or not

docs/buildah-build.1.md

+6
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ Supported _keys_ are:
703703

704704
Valid _type_ values are:
705705
- **local**: write the resulting build files to a directory on the client-side.
706+
- **image**: writes the build results as an image to local storage.
707+
- **registry**: pushes the resulting build image to the registry. Shorthand for `type=image,push=true`.
706708
- **tar**: write the resulting files as a single tarball (.tar).
707709

708710
If no type is specified, the value defaults to **local**.
@@ -765,6 +767,10 @@ Raise an error if the image is not present locally.
765767

766768
Defaults to *true*.
767769

770+
**--push**
771+
772+
Shorthand for "--output=type=registry"
773+
768774
**--quiet**, **-q**
769775

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

imagebuildah/executor.go

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type Executor struct {
7373
registry string
7474
ignoreUnrecognizedInstructions bool
7575
quiet bool
76+
push bool
7677
runtime string
7778
runtimeArgs []string
7879
transientMounts []Mount
@@ -242,6 +243,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
242243
registry: options.Registry,
243244
ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions,
244245
quiet: options.Quiet,
246+
push: options.Push, // TODO: not needed if planning to update buildOutput in cli/build
245247
runtime: options.Runtime,
246248
runtimeArgs: options.RuntimeArgs,
247249
transientMounts: transientMounts,
@@ -935,6 +937,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
935937
}
936938
}
937939
stageID, stageRef, stageOnlyBaseImage, stageErr := b.buildStage(ctx, cleanupStages, stages, index)
940+
938941
if stageErr != nil {
939942
cancel = true
940943
ch <- Result{

imagebuildah/stage_executor.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error {
764764
options.ConfigureNetwork = define.NetworkEnabled
765765
case "none":
766766
options.ConfigureNetwork = define.NetworkDisabled
767-
case "", "default":
767+
case "":
768768
// do nothing
769769
default:
770770
return fmt.Errorf(`unsupported value %q for "RUN --network", must be either "host" or "none"`, run.Network)
@@ -1151,7 +1151,7 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string,
11511151
canGenerateBuildOutput := (s.executor.buildOutput != "" && lastStage)
11521152
if canGenerateBuildOutput {
11531153
logrus.Debugf("Generating custom build output with options %q", s.executor.buildOutput)
1154-
buildOutputOption, err = parse.GetBuildOutput(s.executor.buildOutput)
1154+
buildOutputOption, err = parse.GetBuildOutput(s.executor.buildOutput, s.executor.output)
11551155
if err != nil {
11561156
return "", nil, false, fmt.Errorf("failed to parse build output: %w", err)
11571157
}
@@ -2206,7 +2206,17 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
22062206
return imgID, ref, nil
22072207
}
22082208

2209-
func (s *StageExecutor) generateBuildOutput(buildOutputOpts define.BuildOutputOption) error {
2209+
func (s *StageExecutor) generateBuildOutput(opts define.BuildOutputOption) error {
2210+
if opts.Type == define.BuildOutputImage {
2211+
if opts.Push {
2212+
err := internalUtil.PushImage(s.executor.store, opts)
2213+
if err != nil {
2214+
return fmt.Errorf("failed to export build output: %w", err)
2215+
}
2216+
}
2217+
return nil
2218+
}
2219+
22102220
extractRootfsOpts := buildah.ExtractRootfsOptions{}
22112221
if unshare.IsRootless() {
22122222
// In order to maintain as much parity as possible
@@ -2226,7 +2236,7 @@ func (s *StageExecutor) generateBuildOutput(buildOutputOpts define.BuildOutputOp
22262236
return fmt.Errorf("failed to extract rootfs from given container image: %w", err)
22272237
}
22282238
defer rc.Close()
2229-
err = internalUtil.ExportFromReader(rc, buildOutputOpts)
2239+
err = internalUtil.ExportFromReader(rc, opts)
22302240
if err != nil {
22312241
return fmt.Errorf("failed to export build output: %w", err)
22322242
}

internal/util/util.go

+31-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"
@@ -50,6 +52,29 @@ func NormalizePlatform(platform v1.Platform) v1.Platform {
5052
}
5153
}
5254

55+
// PushImage copies contents of the image to a new location
56+
func PushImage(store storage.Store, opts define.BuildOutputOption) error {
57+
libimageOptions := &libimage.PushOptions{}
58+
libimageOptions.Writer = os.Stdout
59+
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: &types.SystemContext{}})
60+
if err != nil {
61+
return err
62+
}
63+
64+
imageRef, err := util.ImageStringToImageReference(opts.Image)
65+
if err != nil {
66+
return fmt.Errorf("failed to convert image to ImageReference")
67+
}
68+
69+
dest := fmt.Sprintf("%s:%s", imageRef.Transport().Name(), imageRef.StringWithinTransport())
70+
_, err = runtime.Push(context.Background(), opts.Image, dest, libimageOptions)
71+
if err != nil {
72+
return fmt.Errorf("failed while pushing image %+q: %w", opts.ImageRef, err)
73+
}
74+
75+
return nil
76+
}
77+
5378
// ExportFromReader reads bytes from given reader and exports to external tar, directory or stdout.
5479
func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
5580
var err error
@@ -59,7 +84,8 @@ func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
5984
return err
6085
}
6186
}
62-
if opts.IsDir {
87+
switch opts.Type {
88+
case define.BuildOutputLocal:
6389
// In order to keep this feature as close as possible to
6490
// buildkit it was decided to preserve ownership when
6591
// invoked as root since caller already has access to artifacts
@@ -81,7 +107,7 @@ func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
81107
if err != nil {
82108
return fmt.Errorf("failed while performing untar at %q: %w", opts.Path, err)
83109
}
84-
} else {
110+
case define.BuildOutputTar:
85111
outFile := os.Stdout
86112
if !opts.IsStdout {
87113
outFile, err = os.Create(opts.Path)
@@ -94,7 +120,10 @@ func ExportFromReader(input io.Reader, opts define.BuildOutputOption) error {
94120
if err != nil {
95121
return fmt.Errorf("failed while performing copy to %q: %w", opts.Path, err)
96122
}
123+
default:
124+
return fmt.Errorf("build output type %s not supported", opts.Type)
97125
}
126+
98127
return nil
99128
}
100129

pkg/cli/build.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
288288
timestamp = &t
289289
}
290290
if c.Flag("output").Changed {
291-
buildOption, err := parse.GetBuildOutput(iopts.BuildOutput)
291+
buildOption, err := parse.GetBuildOutput(iopts.BuildOutput, output)
292292
if err != nil {
293293
return options, nil, nil, err
294294
}
@@ -303,6 +303,15 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
303303
return options, nil, nil, err
304304
}
305305
}
306+
307+
if c.Flag("push").Changed {
308+
if len(iopts.BuildOutput) == 0 {
309+
iopts.BuildOutput = "type=registry"
310+
} else {
311+
return options, nil, nil, fmt.Errorf("cannot set both --push and --output")
312+
}
313+
}
314+
306315
var cacheTo []reference.Named
307316
var cacheFrom []reference.Named
308317
cacheTo = nil
@@ -410,6 +419,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
410419
Platforms: platforms,
411420
PullPolicy: pullPolicy,
412421
PullPushRetryDelay: pullPushRetryDelay,
422+
Push: iopts.Push,
413423
Quiet: iopts.Quiet,
414424
RemoveIntermediateCtrs: iopts.Rm,
415425
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
@@ -281,6 +282,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
281282
fs.BoolVar(&flags.Stdin, "stdin", false, "pass stdin into containers")
282283
fs.StringArrayVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image")
283284
fs.StringVarP(&flags.BuildOutput, "output", "o", "", "output destination (format: type=local,dest=path)")
285+
fs.BoolVar(&flags.Push, "push", false, "Shorthand for `--output=type=registry`")
284286
fs.StringVar(&flags.Target, "target", "", "set the target build stage to build")
285287
fs.Int64Var(&flags.Timestamp, "timestamp", 0, "set created timestamp to the specified epoch seconds to allow for deterministic builds, defaults to current time")
286288
fs.BoolVar(&flags.TLSVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")

0 commit comments

Comments
 (0)