Skip to content
Open
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
57 changes: 39 additions & 18 deletions add.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"github.com/tonistiigi/dchapes-mode"
mode "github.com/tonistiigi/dchapes-mode"
"go.podman.io/buildah/copier"
"go.podman.io/buildah/define"
"go.podman.io/buildah/internal/tmpdir"
Expand Down Expand Up @@ -129,7 +129,13 @@ type AddAndCopyOptions struct {
}

// getURL writes a tar archive containing the named content
func getURL(src string, chown *idtools.IDPair, mountpoint, renameTarget string, writer io.Writer, chmod string, srcDigest digest.Digest, certPath string, insecureSkipTLSVerify types.OptionalBool, timestamp *time.Time) error {
func getURL(ctx context.Context, src string, chown *idtools.IDPair, mountpoint, renameTarget string, writer io.Writer, chmod string, srcDigest digest.Digest, certPath string, insecureSkipTLSVerify types.OptionalBool, timestamp *time.Time) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
}

url, err := url.Parse(src)
if err != nil {
return err
Expand All @@ -152,7 +158,11 @@ func getURL(src string, chown *idtools.IDPair, mountpoint, renameTarget string,
Proxy: http.ProxyFromEnvironment,
}
httpClient := &http.Client{Transport: tr}
response, err := httpClient.Get(src)
request, err := http.NewRequestWithContext(ctx, http.MethodGet, src, nil)
if err != nil {
return err
}
response, err := httpClient.Do(request)
if err != nil {
return err
}
Expand Down Expand Up @@ -184,7 +194,7 @@ func getURL(src string, chown *idtools.IDPair, mountpoint, renameTarget string,
}
// Figure out the size of the content.
size := response.ContentLength
var responseBody io.Reader = response.Body
responseBody := io.Reader(response.Body)
if size < 0 {
// Create a temporary file and copy the content to it, so that
// we can figure out how much content there is.
Expand Down Expand Up @@ -307,10 +317,21 @@ func getParentsPrefixToRemoveAndParentsToSkip(pattern string, contextDir string)
return prefix, out
}

// Add copies the contents of the specified sources into the container's root
// Add() calls AddContext() with context.Background().
func (b *Builder) Add(destination string, extract bool, options AddAndCopyOptions, sources ...string) error {
return b.AddContext(context.Background(), destination, extract, options, sources...)
}

// AddContext copies the contents of the specified sources into the container's root
// filesystem, optionally extracting contents of local files that look like
// non-empty archives.
func (b *Builder) Add(destination string, extract bool, options AddAndCopyOptions, sources ...string) error {
func (b *Builder) AddContext(ctx context.Context, destination string, extract bool, options AddAndCopyOptions, sources ...string) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
}

mountPoint, err := b.Mount(b.MountLabel)
if err != nil {
return err
Expand Down Expand Up @@ -374,7 +395,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
DisallowWildcard: options.AllowWildcard == types.OptionalBoolFalse,
AllowEmptyWildcard: options.AllowEmptyWildcard == types.OptionalBoolTrue,
}
localSourceStats, err = copier.Stat(contextDir, contextDir, statOptions, localSources)
localSourceStats, err = copier.StatContext(ctx, contextDir, contextDir, statOptions, localSources)
if err != nil {
return fmt.Errorf("checking on sources under %q: %w", contextDir, err)
}
Expand Down Expand Up @@ -466,7 +487,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
statOptions := copier.StatOptions{
CheckForArchives: extract,
}
destStats, err := copier.Stat(mountPoint, filepath.Join(mountPoint, b.WorkDir()), statOptions, []string{extractDirectory})
destStats, err := copier.StatContext(ctx, mountPoint, filepath.Join(mountPoint, b.WorkDir()), statOptions, []string{extractDirectory})
if err != nil {
return fmt.Errorf("checking on destination %v: %w", extractDirectory, err)
}
Expand Down Expand Up @@ -496,7 +517,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
// Make sure that, if it's a symlink, we'll chroot to the target of the link;
// knowing that target requires that we resolve it within the chroot.
evalOptions := copier.EvalOptions{}
evaluated, err := copier.Eval(mountPoint, extractDirectory, evalOptions)
evaluated, err := copier.EvalContext(ctx, mountPoint, extractDirectory, evalOptions)
if err != nil {
return fmt.Errorf("checking on destination %v: %w", extractDirectory, err)
}
Expand Down Expand Up @@ -559,7 +580,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
if !strings.HasPrefix(putDirAbs, stagingDirAbs+string(os.PathSeparator)) && putDirAbs != stagingDirAbs {
return fmt.Errorf("destination path %q escapes staging directory", destination)
}
if err := copier.Mkdir(putRoot, putDirAbs, mkdirOptions); err != nil {
if err := copier.MkdirContext(ctx, putRoot, putDirAbs, mkdirOptions); err != nil {
return fmt.Errorf("ensuring target directory exists: %w", err)
}
tempPath := putDir
Expand All @@ -570,7 +591,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
tempPath = filepath.Dir(tempPath)
}
} else {
if err := copier.Mkdir(mountPoint, extractDirectory, mkdirOptions); err != nil {
if err := copier.MkdirContext(ctx, mountPoint, extractDirectory, mkdirOptions); err != nil {
return fmt.Errorf("ensuring target directory exists: %w", err)
}

Expand Down Expand Up @@ -599,7 +620,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
defer wg.Done()
defer pipeWriter.Close()
var cloneDir, subdir string
cloneDir, subdir, getErr = define.TempDirForURL(tmpdir.GetTempDir(), "", src)
cloneDir, subdir, getErr = define.TempDirForURLContext(ctx, tmpdir.GetTempDir(), "", src)
if getErr != nil {
return
}
Expand All @@ -621,12 +642,12 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
}
writer := io.WriteCloser(pipeWriter)
repositoryDir := filepath.Join(cloneDir, subdir)
getErr = copier.Get(repositoryDir, repositoryDir, getOptions, []string{"."}, writer)
getErr = copier.GetContext(ctx, repositoryDir, repositoryDir, getOptions, []string{"."}, writer)
}()
} else {
go func() {
getErr = retry.IfNecessary(context.TODO(), func() error {
return getURL(src, chownFiles, mountPoint, renameTarget, pipeWriter, options.Chmod, srcDigest, options.CertPath, options.InsecureSkipTLSVerify, options.Timestamp)
getErr = retry.IfNecessary(ctx, func() error {
return getURL(ctx, src, chownFiles, mountPoint, renameTarget, pipeWriter, options.Chmod, srcDigest, options.CertPath, options.InsecureSkipTLSVerify, options.Timestamp)
}, &retry.Options{
MaxRetry: options.MaxRetries,
Delay: options.RetryDelay,
Expand Down Expand Up @@ -656,7 +677,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
IgnoreDevices: userns.RunningInUserNS(),
Timestamp: options.Timestamp,
}
putErr = copier.Put(putRoot, putDir, putOptions, io.TeeReader(pipeReader, hasher))
putErr = copier.PutContext(ctx, putRoot, putDir, putOptions, io.TeeReader(pipeReader, hasher))
}
hashCloser.Close()
pipeReader.Close()
Expand Down Expand Up @@ -788,7 +809,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
AllowEmptyWildcard: options.AllowEmptyWildcard == types.OptionalBoolTrue,
NoDerefSymlinks: options.FollowSymlink == types.OptionalBoolFalse,
}
getErr = copier.Get(contextDir, contextDir, getOptions, []string{globbedToGlobbable(globbed)}, writer)
getErr = copier.GetContext(ctx, contextDir, contextDir, getOptions, []string{globbedToGlobbable(globbed)}, writer)
closeErr = writer.Close()
if renameTarget != "" && renamedItems > 1 {
renameErr = fmt.Errorf("internal error: renamed %d items when we expected to only rename 1", renamedItems)
Expand Down Expand Up @@ -820,7 +841,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
IgnoreDevices: userns.RunningInUserNS(),
Timestamp: options.Timestamp,
}
putErr = copier.Put(putRoot, putDir, putOptions, io.TeeReader(pipeReader, hasher))
putErr = copier.PutContext(ctx, putRoot, putDir, putOptions, io.TeeReader(pipeReader, hasher))
}
hashCloser.Close()
pipeReader.Close()
Expand Down
3 changes: 1 addition & 2 deletions buildah_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package buildah

import (
"context"
"flag"
"os"
"testing"
Expand Down Expand Up @@ -46,7 +45,7 @@ func TestOpenBuilderCommonBuildOpts(t *testing.T) {
// or builder must enable sometime of locking mechanism i.e if
// routine is creating Builder other's must wait for it.
// Tracked here: https://github.com/containers/buildah/issues/5967
ctx := context.TODO()
ctx := t.Context()
store, err := storage.GetStore(types.StoreOptions{
RunRoot: t.TempDir(),
GraphRoot: t.TempDir(),
Expand Down
17 changes: 15 additions & 2 deletions chroot/run_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package chroot

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -51,10 +52,21 @@ type runUsingChrootExecSubprocOptions struct {
NoPivot bool
}

// RunUsingChroot runs a chrooted process, using some of the settings from the
// RunUsingChroot() calls RunUsingChrootContext() with context.Background().
func RunUsingChroot(spec *specs.Spec, bundlePath, homeDir string, stdin io.Reader, stdout, stderr io.Writer, noPivot bool) (err error) {
return RunUsingChrootContext(context.Background(), spec, bundlePath, homeDir, stdin, stdout, stderr, noPivot)
}

// RunUsingChrootContext runs a chrooted process, using some of the settings from the
// passed-in spec, and using the specified bundlePath to hold temporary files,
// directories, and mountpoints.
func RunUsingChroot(spec *specs.Spec, bundlePath, homeDir string, stdin io.Reader, stdout, stderr io.Writer, noPivot bool) (err error) {
func RunUsingChrootContext(ctx context.Context, spec *specs.Spec, bundlePath, homeDir string, stdin io.Reader, stdout, stderr io.Writer, noPivot bool) (err error) {
select {
case <-ctx.Done():
return ctx.Err()
default:
}

var confwg sync.WaitGroup
var homeFound bool
for _, env := range spec.Process.Env {
Expand Down Expand Up @@ -127,6 +139,7 @@ func RunUsingChroot(spec *specs.Spec, bundlePath, homeDir string, stdin io.Reade

// Start the grandparent subprocess.
cmd := unshare.Command(runUsingChrootCommand)
cmd.Cmd = reexec.CommandContext(ctx, runUsingChrootCommand) // TODO: add an unshare.CommandContext()
setPdeathsig(cmd.Cmd)
cmd.Stdin, cmd.Stdout, cmd.Stderr = stdin, stdout, stderr
cmd.Dir = "/"
Expand Down
12 changes: 12 additions & 0 deletions chroot/unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package chroot

import (
"context"
"fmt"
"io"

Expand All @@ -11,5 +12,16 @@ import (

// RunUsingChroot is not supported.
func RunUsingChroot(spec *specs.Spec, bundlePath, homeDir string, stdin io.Reader, stdout, stderr io.Writer) (err error) {
return RunUsingChrootContext(context.Background(), spec, bundlePath, homeDir, stdin, stdout, stderr)
}

// RunUsingChrootContext is not supported.
func RunUsingChrootContext(ctx context.Context, spec *specs.Spec, bundlePath, homeDir string, stdin io.Reader, stdout, stderr io.Writer) (err error) {
select {
case <-ctx.Done():
return ctx.Err()
default:
}

return fmt.Errorf("--isolation chroot is not supported on this platform")
}
2 changes: 1 addition & 1 deletion cmd/buildah/addcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ func addAndCopyCmd(c *cobra.Command, args []string, verb string, iopts addCopyRe
}

extractLocalArchives := verb == "ADD"
err = builder.Add(dest, extractLocalArchives, options, args...)
err = builder.AddContext(getContext(), dest, extractLocalArchives, options, args...)
if err != nil {
return fmt.Errorf("adding content to container %q: %w", builder.Container, err)
}
Expand Down
26 changes: 24 additions & 2 deletions cmd/buildah/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"errors"
"fmt"
"os"
"os/signal"
"sync"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand Down Expand Up @@ -157,11 +159,31 @@ func openImage(ctx context.Context, sc *types.SystemContext, store storage.Store
return builder, nil
}

// getContext returns a context.TODO
// getContext returns a context that may have a timeout, and which cancels if
// it receives os.Interrupt
func getContext() context.Context {
return context.TODO()
ctx, _ := getContextWithCancel()
return ctx
}

func getContextCancel() context.CancelFunc {
_, cancel := getContextWithCancel()
return cancel
}

var getContextWithCancel = sync.OnceValues(func() (context.Context, context.CancelFunc) {
var ctx context.Context
var cancel1, cancel2 func()
if rootCmd.PersistentFlags().Changed("experimental-timeout") {
ctx, cancel1 = context.WithTimeout(context.Background(), globalFlagResults.ExperimentalTimeout)
} else {
ctx = context.Background()
cancel1 = func() {}
}
ctx, cancel2 = signal.NotifyContext(ctx, os.Interrupt)
return ctx, func() { cancel1(); cancel2() }
})

func getUserFlags() pflag.FlagSet {
fs := pflag.FlagSet{}
fs.String("user", "", "`user[:group]` to run the command as")
Expand Down
9 changes: 5 additions & 4 deletions cmd/buildah/from.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -110,7 +111,7 @@ newer: only pull images when newer images exist on the registry than those in th
rootCmd.AddCommand(fromCommand)
}

func onBuild(builder *buildah.Builder, quiet bool) error {
func onBuild(ctx context.Context, builder *buildah.Builder, quiet bool) error {
ctr := 0
for _, onBuildSpec := range builder.OnBuild() {
ctr = ctr + 1
Expand All @@ -129,7 +130,7 @@ func onBuild(builder *buildah.Builder, quiet bool) error {
dest = args[size-1]
args = args[:size-1]
}
if err := builder.Add(dest, command == "ADD", buildah.AddAndCopyOptions{}, args...); err != nil {
if err := builder.AddContext(ctx, dest, command == "ADD", buildah.AddAndCopyOptions{}, args...); err != nil {
return err
}
case "ANNOTATION":
Expand Down Expand Up @@ -170,7 +171,7 @@ func onBuild(builder *buildah.Builder, quiet bool) error {
if quiet {
stdout = io.Discard
}
if err := builder.Run(args, buildah.RunOptions{Stdout: stdout}); err != nil {
if err := builder.RunContext(ctx, args, buildah.RunOptions{Stdout: stdout}); err != nil {
return err
}
case "SHELL":
Expand Down Expand Up @@ -305,7 +306,7 @@ func fromCmd(c *cobra.Command, args []string, iopts fromReply) error {
return err
}

if err := onBuild(builder, iopts.quiet); err != nil {
if err := onBuild(getContext(), builder, iopts.quiet); err != nil {
return err
}

Expand Down
3 changes: 1 addition & 2 deletions cmd/buildah/images.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -133,7 +132,7 @@ func imagesCmd(c *cobra.Command, args []string, iopts *imageResults) error {
return err
}

ctx := context.Background()
ctx := getContext()

options := &libimage.ListImagesOptions{}
if len(iopts.filter) > 0 {
Expand Down
Loading
Loading