aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/auth.go3
-rw-r--r--pkg/api/handlers/compat/containers_create.go1
-rw-r--r--pkg/api/handlers/compat/images_build.go2
-rw-r--r--pkg/api/handlers/libpod/containers_create.go5
-rw-r--r--pkg/api/handlers/libpod/images_pull.go31
-rw-r--r--pkg/api/handlers/libpod/images_push.go2
-rw-r--r--pkg/api/handlers/libpod/manifests.go4
-rw-r--r--pkg/api/handlers/types.go3
-rw-r--r--pkg/bindings/images/pull.go13
-rw-r--r--pkg/bindings/images/push.go9
-rw-r--r--pkg/bindings/images/types.go2
-rw-r--r--pkg/bindings/images/types_pull_options.go16
-rw-r--r--pkg/bindings/manifests/manifests.go6
-rw-r--r--pkg/bindings/test/images_test.go24
-rw-r--r--pkg/bindings/test/manifests_test.go23
-rw-r--r--pkg/domain/entities/images.go2
-rw-r--r--pkg/domain/entities/pods.go1
-rw-r--r--pkg/domain/infra/abi/containers.go24
-rw-r--r--pkg/domain/infra/abi/images.go3
-rw-r--r--pkg/domain/infra/abi/parse/parse.go5
-rw-r--r--pkg/domain/infra/tunnel/containers.go16
-rw-r--r--pkg/domain/infra/tunnel/images.go1
-rw-r--r--pkg/env/env.go20
-rw-r--r--pkg/machine/pull.go4
-rw-r--r--pkg/machine/qemu/machine.go8
-rw-r--r--pkg/specgen/generate/container.go36
-rw-r--r--pkg/specgen/generate/validate.go6
-rw-r--r--pkg/specgen/specgen.go3
-rw-r--r--pkg/specgenutil/specgen.go8
29 files changed, 205 insertions, 76 deletions
diff --git a/pkg/api/handlers/compat/auth.go b/pkg/api/handlers/compat/auth.go
index 37d2b784d..ee478b9e3 100644
--- a/pkg/api/handlers/compat/auth.go
+++ b/pkg/api/handlers/compat/auth.go
@@ -1,7 +1,6 @@
package compat
import (
- "context"
"encoding/json"
"errors"
"fmt"
@@ -44,7 +43,7 @@ func Auth(w http.ResponseWriter, r *http.Request) {
fmt.Println("Authenticating with existing credentials...")
registry := stripAddressOfScheme(authConfig.ServerAddress)
- if err := DockerClient.CheckAuth(context.Background(), sysCtx, authConfig.Username, authConfig.Password, registry); err == nil {
+ if err := DockerClient.CheckAuth(r.Context(), sysCtx, authConfig.Username, authConfig.Password, registry); err == nil {
utils.WriteResponse(w, http.StatusOK, entities.AuthReport{
IdentityToken: "",
Status: "Login Succeeded",
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 9fff8b4c8..d4f5d5f36 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -408,6 +408,7 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C
Systemd: "true", // podman default
TmpFS: parsedTmp,
TTY: cc.Config.Tty,
+ EnvMerge: cc.EnvMerge,
UnsetEnv: cc.UnsetEnv,
UnsetEnvAll: cc.UnsetEnvAll,
User: cc.Config.User,
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index a00f0b089..020991cc7 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -694,7 +694,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
success bool
)
- runCtx, cancel := context.WithCancel(context.Background())
+ runCtx, cancel := context.WithCancel(r.Context())
go func() {
defer cancel()
imageID, _, err = runtime.Build(r.Context(), buildOptions, containerFiles...)
diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go
index 1307c267a..429f45f91 100644
--- a/pkg/api/handlers/libpod/containers_create.go
+++ b/pkg/api/handlers/libpod/containers_create.go
@@ -1,7 +1,6 @@
package libpod
import (
- "context"
"encoding/json"
"fmt"
"net/http"
@@ -63,12 +62,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), runtime, &sg, false, nil)
+ rtSpec, spec, opts, err := generate.MakeContainer(r.Context(), runtime, &sg, false, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- ctr, err := generate.ExecuteCreate(context.Background(), runtime, rtSpec, spec, false, opts...)
+ ctr, err := generate.ExecuteCreate(r.Context(), runtime, rtSpec, spec, false, opts...)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index 7e24ae5ac..57b2e3a78 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -82,17 +82,32 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
pullOptions.IdentityToken = authConf.IdentityToken
}
- writer := channel.NewWriter(make(chan []byte))
- defer writer.Close()
-
- pullOptions.Writer = writer
-
pullPolicy, err := config.ParsePullPolicy(query.PullPolicy)
if err != nil {
utils.Error(w, http.StatusBadRequest, err)
return
}
+ // Let's keep thing simple when running in quiet mode and pull directly.
+ if query.Quiet {
+ images, err := runtime.LibimageRuntime().Pull(r.Context(), query.Reference, pullPolicy, pullOptions)
+ var report entities.ImagePullReport
+ if err != nil {
+ report.Error = err.Error()
+ }
+ for _, image := range images {
+ report.Images = append(report.Images, image.ID())
+ // Pull last ID from list and publish in 'id' stanza. This maintains previous API contract
+ report.ID = image.ID()
+ }
+ utils.WriteResponse(w, http.StatusOK, report)
+ return
+ }
+
+ writer := channel.NewWriter(make(chan []byte))
+ defer writer.Close()
+ pullOptions.Writer = writer
+
var pulledImages []*libimage.Image
var pullError error
runCtx, cancel := context.WithCancel(r.Context())
@@ -118,10 +133,8 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
select {
case s := <-writer.Chan():
report.Stream = string(s)
- if !query.Quiet {
- if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to encode json: %v", err)
- }
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to encode json: %v", err)
}
flush()
case <-runCtx.Done():
diff --git a/pkg/api/handlers/libpod/images_push.go b/pkg/api/handlers/libpod/images_push.go
index e931fd2f9..be6f5b131 100644
--- a/pkg/api/handlers/libpod/images_push.go
+++ b/pkg/api/handlers/libpod/images_push.go
@@ -90,7 +90,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
// Let's keep thing simple when running in quiet mode and push directly.
if query.Quiet {
- if err := imageEngine.Push(context.Background(), source, destination, options); err != nil {
+ if err := imageEngine.Push(r.Context(), source, destination, options); err != nil {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err))
return
}
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index fa83bbfe1..8391def5c 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -293,7 +293,7 @@ func ManifestPushV3(w http.ResponseWriter, r *http.Request) {
options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
imageEngine := abi.ImageEngine{Libpod: runtime}
- digest, err := imageEngine.ManifestPush(context.Background(), source, query.Destination, options)
+ digest, err := imageEngine.ManifestPush(r.Context(), source, query.Destination, options)
if err != nil {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", query.Destination, err))
return
@@ -367,7 +367,7 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) {
// Let's keep thing simple when running in quiet mode and push directly.
if query.Quiet {
- digest, err := imageEngine.ManifestPush(context.Background(), source, destination, options)
+ digest, err := imageEngine.ManifestPush(r.Context(), source, destination, options)
if err != nil {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err))
return
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index b533e131c..aab905878 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -127,6 +127,7 @@ type CreateContainerConfig struct {
dockerContainer.Config // desired container configuration
HostConfig dockerContainer.HostConfig // host dependent configuration for container
NetworkingConfig dockerNetwork.NetworkingConfig // network configuration for container
+ EnvMerge []string // preprocess env variables from image before injecting into containers
UnsetEnv []string // unset specified default environment variables
UnsetEnvAll bool // unset all default environment variables
}
@@ -162,7 +163,7 @@ type ExecStartConfig struct {
func ImageDataToImageInspect(ctx context.Context, l *libimage.Image) (*ImageInspect, error) {
options := &libimage.InspectOptions{WithParent: true, WithSize: true}
- info, err := l.Inspect(context.Background(), options)
+ info, err := l.Inspect(ctx, options)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
index 1a4aa3038..109981c63 100644
--- a/pkg/bindings/images/pull.go
+++ b/pkg/bindings/images/pull.go
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"net/http"
"os"
"strconv"
@@ -57,10 +56,14 @@ func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string,
return nil, response.Process(err)
}
- // Historically pull writes status to stderr
- stderr := io.Writer(os.Stderr)
+ var writer io.Writer
if options.GetQuiet() {
- stderr = ioutil.Discard
+ writer = io.Discard
+ } else if progressWriter := options.GetProgressWriter(); progressWriter != nil {
+ writer = progressWriter
+ } else {
+ // Historically push writes status to stderr
+ writer = os.Stderr
}
dec := json.NewDecoder(response.Body)
@@ -84,7 +87,7 @@ func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string,
switch {
case report.Stream != "":
- fmt.Fprint(stderr, report.Stream)
+ fmt.Fprint(writer, report.Stream)
case report.Error != "":
pullErrors = append(pullErrors, errors.New(report.Error))
case len(report.Images) > 0:
diff --git a/pkg/bindings/images/push.go b/pkg/bindings/images/push.go
index 5069dd780..f1e059f8c 100644
--- a/pkg/bindings/images/push.go
+++ b/pkg/bindings/images/push.go
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"net/http"
"os"
"strconv"
@@ -58,12 +57,14 @@ func Push(ctx context.Context, source string, destination string, options *PushO
return response.Process(err)
}
- // Historically push writes status to stderr
- writer := io.Writer(os.Stderr)
+ var writer io.Writer
if options.GetQuiet() {
- writer = ioutil.Discard
+ writer = io.Discard
} else if progressWriter := options.GetProgressWriter(); progressWriter != nil {
writer = progressWriter
+ } else {
+ // Historically push writes status to stderr
+ writer = os.Stderr
}
dec := json.NewDecoder(response.Body)
diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go
index 7b28c499e..3ecfb9e09 100644
--- a/pkg/bindings/images/types.go
+++ b/pkg/bindings/images/types.go
@@ -182,6 +182,8 @@ type PullOptions struct {
Policy *string
// Password for authenticating against the registry.
Password *string
+ // ProgressWriter is a writer where pull progress are sent.
+ ProgressWriter *io.Writer
// Quiet can be specified to suppress pull progress when pulling. Ignored
// for remote calls.
Quiet *bool
diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go
index 4cd525185..c1a88fd9e 100644
--- a/pkg/bindings/images/types_pull_options.go
+++ b/pkg/bindings/images/types_pull_options.go
@@ -2,6 +2,7 @@
package images
import (
+ "io"
"net/url"
"github.com/containers/podman/v4/pkg/bindings/internal/util"
@@ -107,6 +108,21 @@ func (o *PullOptions) GetPassword() string {
return *o.Password
}
+// WithProgressWriter set field ProgressWriter to given value
+func (o *PullOptions) WithProgressWriter(value io.Writer) *PullOptions {
+ o.ProgressWriter = &value
+ return o
+}
+
+// GetProgressWriter returns value of field ProgressWriter
+func (o *PullOptions) GetProgressWriter() io.Writer {
+ if o.ProgressWriter == nil {
+ var z io.Writer
+ return z
+ }
+ return *o.ProgressWriter
+}
+
// WithQuiet set field Quiet to given value
func (o *PullOptions) WithQuiet(value bool) *PullOptions {
o.Quiet = &value
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index 49e4089f5..0163d21a0 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -182,12 +182,14 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt
return "", response.Process(err)
}
- // Historically push writes status to stderr
- writer := io.Writer(os.Stderr)
+ var writer io.Writer
if options.GetQuiet() {
writer = io.Discard
} else if progressWriter := options.GetProgressWriter(); progressWriter != nil {
writer = progressWriter
+ } else {
+ // Historically push writes status to stderr
+ writer = os.Stderr
}
dec := json.NewDecoder(response.Body)
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 9c9796661..53c5a1e83 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -1,11 +1,14 @@
package bindings_test
import (
+ "bytes"
+ "fmt"
"net/http"
"os"
"path/filepath"
"time"
+ podmanRegistry "github.com/containers/podman/v4/hack/podman-registry-go"
"github.com/containers/podman/v4/pkg/bindings"
"github.com/containers/podman/v4/pkg/bindings/containers"
"github.com/containers/podman/v4/pkg/bindings/images"
@@ -362,9 +365,14 @@ var _ = Describe("Podman images", func() {
It("Image Pull", func() {
rawImage := "docker.io/library/busybox:latest"
- pulledImages, err := images.Pull(bt.conn, rawImage, nil)
+ var writer bytes.Buffer
+ pullOpts := new(images.PullOptions).WithProgressWriter(&writer)
+ pulledImages, err := images.Pull(bt.conn, rawImage, pullOpts)
Expect(err).NotTo(HaveOccurred())
Expect(len(pulledImages)).To(Equal(1))
+ output := writer.String()
+ Expect(output).To(ContainSubstring("Trying to pull "))
+ Expect(output).To(ContainSubstring("Getting image source signatures"))
exists, err := images.Exists(bt.conn, rawImage, nil)
Expect(err).NotTo(HaveOccurred())
@@ -380,7 +388,19 @@ var _ = Describe("Podman images", func() {
})
It("Image Push", func() {
- Skip("TODO: implement test for image push to registry")
+ registry, err := podmanRegistry.Start()
+ Expect(err).To(BeNil())
+
+ var writer bytes.Buffer
+ pushOpts := new(images.PushOptions).WithUsername(registry.User).WithPassword(registry.Password).WithSkipTLSVerify(true).WithProgressWriter(&writer).WithQuiet(false)
+ err = images.Push(bt.conn, alpine.name, fmt.Sprintf("localhost:%s/test:latest", registry.Port), pushOpts)
+ Expect(err).ToNot(HaveOccurred())
+
+ output := writer.String()
+ Expect(output).To(ContainSubstring("Copying blob "))
+ Expect(output).To(ContainSubstring("Copying config "))
+ Expect(output).To(ContainSubstring("Writing manifest to image destination"))
+ Expect(output).To(ContainSubstring("Storing signatures"))
})
It("Build no options", func() {
diff --git a/pkg/bindings/test/manifests_test.go b/pkg/bindings/test/manifests_test.go
index 6a34ef5a6..d6749f920 100644
--- a/pkg/bindings/test/manifests_test.go
+++ b/pkg/bindings/test/manifests_test.go
@@ -1,9 +1,12 @@
package bindings_test
import (
+ "bytes"
+ "fmt"
"net/http"
"time"
+ podmanRegistry "github.com/containers/podman/v4/hack/podman-registry-go"
"github.com/containers/podman/v4/pkg/bindings"
"github.com/containers/podman/v4/pkg/bindings/images"
"github.com/containers/podman/v4/pkg/bindings/manifests"
@@ -12,7 +15,7 @@ import (
"github.com/onsi/gomega/gexec"
)
-var _ = Describe("podman manifest", func() {
+var _ = Describe("Podman manifests", func() {
var (
bt *bindingTest
s *gexec.Session
@@ -172,7 +175,21 @@ var _ = Describe("podman manifest", func() {
Expect(list.Manifests[0].Platform.OS).To(Equal("foo"))
})
- It("push manifest", func() {
- Skip("TODO: implement test for manifest push to registry")
+ It("Manifest Push", func() {
+ registry, err := podmanRegistry.Start()
+ Expect(err).To(BeNil())
+
+ name := "quay.io/libpod/foobar:latest"
+ _, err = manifests.Create(bt.conn, name, []string{alpine.name}, nil)
+ Expect(err).ToNot(HaveOccurred())
+
+ var writer bytes.Buffer
+ pushOpts := new(images.PushOptions).WithUsername(registry.User).WithPassword(registry.Password).WithAll(true).WithSkipTLSVerify(true).WithProgressWriter(&writer).WithQuiet(false)
+ _, err = manifests.Push(bt.conn, name, fmt.Sprintf("localhost:%s/test:latest", registry.Port), pushOpts)
+ Expect(err).ToNot(HaveOccurred())
+
+ output := writer.String()
+ Expect(output).To(ContainSubstring("Writing manifest list to image destination"))
+ Expect(output).To(ContainSubstring("Storing list signatures"))
})
})
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 21c1372b9..cad11b0ab 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -156,6 +156,8 @@ type ImagePullOptions struct {
SkipTLSVerify types.OptionalBool
// PullPolicy whether to pull new image
PullPolicy config.PullPolicy
+ // Writer is used to display copy information including progress bars.
+ Writer io.Writer
}
// ImagePullReport is the response from pulling one or more images.
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index 14ce370c1..33ca2c807 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -263,6 +263,7 @@ type ContainerCreateOptions struct {
TTY bool
Timezone string
Umask string
+ EnvMerge []string
UnsetEnv []string
UnsetEnvAll bool
UIDMap []string
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 08d845d70..0a8e5bc2f 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -381,7 +381,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
// this will fail and code will fall through to removing the container from libpod.`
tmpNames := []string{}
for _, ctr := range names {
- report := reports.RmReport{Id: ctr, RawInput: ctr}
+ report := reports.RmReport{Id: ctr}
report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force)
//nolint:gocritic
if report.Err == nil {
@@ -938,13 +938,15 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
if err != nil {
return nil, err
}
+ idToRawInput := map[string]string{}
+ if len(rawInputs) == len(ctrs) {
+ for i := range ctrs {
+ idToRawInput[ctrs[i].ID()] = rawInputs[i]
+ }
+ }
// There can only be one container if attach was used
for i := range ctrs {
ctr := ctrs[i]
- rawInput := ctr.ID()
- if !options.All {
- rawInput = rawInputs[i]
- }
ctrState, err := ctr.State()
if err != nil {
return nil, err
@@ -958,7 +960,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
// Exit cleanly immediately
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
- RawInput: rawInput,
+ RawInput: idToRawInput[ctr.ID()],
Err: nil,
ExitCode: 0,
})
@@ -969,7 +971,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
logrus.Debugf("Deadlock error: %v", err)
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
- RawInput: rawInput,
+ RawInput: idToRawInput[ctr.ID()],
Err: err,
ExitCode: define.ExitCode(err),
})
@@ -979,7 +981,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
if ctrRunning {
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
- RawInput: rawInput,
+ RawInput: idToRawInput[ctr.ID()],
Err: nil,
ExitCode: 0,
})
@@ -989,7 +991,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
if err != nil {
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
- RawInput: rawInput,
+ RawInput: idToRawInput[ctr.ID()],
Err: err,
ExitCode: exitCode,
})
@@ -1004,7 +1006,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
exitCode = ic.GetContainerExitCode(ctx, ctr)
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
- RawInput: rawInput,
+ RawInput: idToRawInput[ctr.ID()],
Err: err,
ExitCode: exitCode,
})
@@ -1017,7 +1019,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
// If the container is in a pod, also set to recursively start dependencies
report := &entities.ContainerStartReport{
Id: ctr.ID(),
- RawInput: rawInput,
+ RawInput: idToRawInput[ctr.ID()],
ExitCode: 125,
}
if err := ctr.Start(ctx, true); err != nil {
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 77d1bf0db..f9839f62f 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -237,8 +237,9 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
pullOptions.Variant = options.Variant
pullOptions.SignaturePolicyPath = options.SignaturePolicy
pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
+ pullOptions.Writer = options.Writer
- if !options.Quiet {
+ if !options.Quiet && pullOptions.Writer == nil {
pullOptions.Writer = os.Stderr
}
diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go
index 19699589b..fb2876bb2 100644
--- a/pkg/domain/infra/abi/parse/parse.go
+++ b/pkg/domain/infra/abi/parse/parse.go
@@ -86,8 +86,11 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error)
if err != nil {
return nil, fmt.Errorf("cannot convert Timeout %s to an integer: %w", splitO[1], err)
}
+ if intTimeout < 0 {
+ return nil, fmt.Errorf("volume timeout cannot be negative (got %d)", intTimeout)
+ }
logrus.Debugf("Removing timeout from options and adding WithTimeout for Timeout %d", intTimeout)
- libpodOptions = append(libpodOptions, libpod.WithVolumeDriverTimeout(intTimeout))
+ libpodOptions = append(libpodOptions, libpod.WithVolumeDriverTimeout(uint(intTimeout)))
default:
finalVal = append(finalVal, o)
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 046509140..023bee430 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -672,10 +672,16 @@ func logIfRmError(id string, err error, reports []*reports.RmReport) {
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
reports := []*entities.ContainerStartReport{}
var exitCode = define.ExecErrorCodeGeneric
- ctrs, namesOrIds, err := getContainersAndInputByContext(ic.ClientCtx, options.All, false, namesOrIds, options.Filters)
+ ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, options.All, false, namesOrIds, options.Filters)
if err != nil {
return nil, err
}
+ idToRawInput := map[string]string{}
+ if len(rawInputs) == len(ctrs) {
+ for i := range ctrs {
+ idToRawInput[ctrs[i].ID] = rawInputs[i]
+ }
+ }
removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(false)
removeContainer := func(id string) {
reports, err := containers.Remove(ic.ClientCtx, id, removeOptions)
@@ -683,15 +689,11 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
}
// There can only be one container if attach was used
- for i, ctr := range ctrs {
+ for _, ctr := range ctrs {
name := ctr.ID
- rawInput := ctr.ID
- if !options.All {
- rawInput = namesOrIds[i]
- }
report := entities.ContainerStartReport{
Id: name,
- RawInput: rawInput,
+ RawInput: idToRawInput[name],
ExitCode: exitCode,
}
ctrRunning := ctr.State == define.ContainerStateRunning.String()
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index bb3014099..2716aaf2a 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -110,6 +110,7 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.
options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithArch(opts.Arch).WithOS(opts.OS)
options.WithVariant(opts.Variant).WithPassword(opts.Password)
options.WithQuiet(opts.Quiet).WithUsername(opts.Username).WithPolicy(opts.PullPolicy.String())
+ options.WithProgressWriter(opts.Writer)
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
if s == types.OptionalBoolTrue {
options.WithSkipTLSVerify(true)
diff --git a/pkg/env/env.go b/pkg/env/env.go
index 8af9fd77c..fb7949ad8 100644
--- a/pkg/env/env.go
+++ b/pkg/env/env.go
@@ -37,6 +37,22 @@ func Slice(m map[string]string) []string {
return env
}
+// Map transforms the specified slice of environment variables into a
+// map.
+func Map(slice []string) map[string]string {
+ envmap := make(map[string]string, len(slice))
+ for _, val := range slice {
+ data := strings.SplitN(val, "=", 2)
+
+ if len(data) > 1 {
+ envmap[data[0]] = data[1]
+ } else {
+ envmap[data[0]] = ""
+ }
+ }
+ return envmap
+}
+
// Join joins the two environment maps with override overriding base.
func Join(base map[string]string, override map[string]string) map[string]string {
if len(base) == 0 {
@@ -87,10 +103,6 @@ func parseEnv(env map[string]string, line string) error {
}
// trim the front of a variable, but nothing else
name := strings.TrimLeft(data[0], whiteSpaces)
- if strings.ContainsAny(name, whiteSpaces) {
- return fmt.Errorf("name %q has white spaces, poorly formatted name", name)
- }
-
if len(data) > 1 {
env[name] = data[1]
} else {
diff --git a/pkg/machine/pull.go b/pkg/machine/pull.go
index 26b6adc67..22a1b4c0a 100644
--- a/pkg/machine/pull.go
+++ b/pkg/machine/pull.go
@@ -213,8 +213,8 @@ func decompressXZ(src string, output io.WriteCloser) error {
var read io.Reader
var cmd *exec.Cmd
// Prefer xz utils for fastest performance, fallback to go xi2 impl
- if _, err := exec.LookPath("xzcat"); err == nil {
- cmd = exec.Command("xzcat", "-k", src)
+ if _, err := exec.LookPath("xz"); err == nil {
+ cmd = exec.Command("xz", "-d", "-c", "-k", src)
read, err = cmd.StdoutPipe()
if err != nil {
return err
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 20e3a3bb1..e97b68e31 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -545,12 +545,12 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return err
}
defer fd.Close()
- dnr, err := os.OpenFile("/dev/null", os.O_RDONLY, 0755)
+ dnr, err := os.OpenFile(os.DevNull, os.O_RDONLY, 0755)
if err != nil {
return err
}
defer dnr.Close()
- dnw, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755)
+ dnw, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0755)
if err != nil {
return err
}
@@ -1216,11 +1216,11 @@ func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) {
}
attr := new(os.ProcAttr)
- dnr, err := os.OpenFile("/dev/null", os.O_RDONLY, 0755)
+ dnr, err := os.OpenFile(os.DevNull, os.O_RDONLY, 0755)
if err != nil {
return "", noForwarding, err
}
- dnw, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755)
+ dnw, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0755)
if err != nil {
return "", noForwarding, err
}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index ec85f0f79..d57efa0d1 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -19,6 +19,7 @@ import (
"github.com/containers/podman/v4/pkg/signal"
"github.com/containers/podman/v4/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/openshift/imagebuilder"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -131,6 +132,17 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
defaultEnvs = envLib.Join(envLib.DefaultEnvVariables(), envLib.Join(defaultEnvs, envs))
}
+ for _, e := range s.EnvMerge {
+ processedWord, err := imagebuilder.ProcessWord(e, envLib.Slice(defaultEnvs))
+ if err != nil {
+ return nil, fmt.Errorf("unable to process variables for --env-merge %s: %w", e, err)
+ }
+ splitWord := strings.Split(processedWord, "=")
+ if _, ok := defaultEnvs[splitWord[0]]; ok {
+ defaultEnvs[splitWord[0]] = splitWord[1]
+ }
+ }
+
for _, e := range s.UnsetEnv {
delete(defaultEnvs, e)
}
@@ -140,10 +152,8 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
}
// First transform the os env into a map. We need it for the labels later in
// any case.
- osEnv, err := envLib.ParseSlice(os.Environ())
- if err != nil {
- return nil, fmt.Errorf("error parsing host environment variables: %w", err)
- }
+ osEnv := envLib.Map(os.Environ())
+
// Caller Specified defaults
if s.EnvHost {
defaultEnvs = envLib.Join(defaultEnvs, osEnv)
@@ -347,9 +357,21 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s
conf.Systemd = tmpSystemd
conf.Mounts = tmpMounts
- if conf.Spec != nil && conf.Spec.Linux != nil && conf.Spec.Linux.Resources != nil {
- if specg.ResourceLimits == nil {
- specg.ResourceLimits = conf.Spec.Linux.Resources
+ if conf.Spec != nil {
+ if conf.Spec.Linux != nil && conf.Spec.Linux.Resources != nil {
+ if specg.ResourceLimits == nil {
+ specg.ResourceLimits = conf.Spec.Linux.Resources
+ }
+ }
+ if conf.Spec.Process != nil && conf.Spec.Process.Env != nil {
+ env := make(map[string]string)
+ for _, entry := range conf.Spec.Process.Env {
+ split := strings.Split(entry, "=")
+ if len(split) == 2 {
+ env[split[0]] = split[1]
+ }
+ }
+ specg.Env = env
}
}
diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go
index 9c933d747..3c5d5fb96 100644
--- a/pkg/specgen/generate/validate.go
+++ b/pkg/specgen/generate/validate.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/sysinfo"
+ "github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/utils"
)
@@ -19,6 +20,11 @@ func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error
sysInfo := sysinfo.New(true)
+ if s.ResourceLimits != nil && rootless.IsRootless() {
+ s.ResourceLimits = nil
+ warnings = append(warnings, "Resource limits are not supported and ignored on cgroups V1 rootless systems")
+ }
+
if s.ResourceLimits == nil {
return warnings, nil
}
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index b90f07ef8..51b6736a9 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -204,6 +204,9 @@ type ContainerBasicConfig struct {
// The execution domain system allows Linux to provide limited support
// for binaries compiled under other UNIX-like operating systems.
Personality *spec.LinuxPersonality `json:"personality,omitempty"`
+ // EnvMerge takes the specified environment variables from image and preprocess them before injecting them into the
+ // container.
+ EnvMerge []string `json:"envmerge,omitempty"`
// UnsetEnv unsets the specified default environment variables from the image or from buildin or containers.conf
// Optional.
UnsetEnv []string `json:"unsetenv,omitempty"`
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index 7392e7b44..8c2c59fed 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -362,10 +362,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
// First transform the os env into a map. We need it for the labels later in
// any case.
- osEnv, err := envLib.ParseSlice(os.Environ())
- if err != nil {
- return fmt.Errorf("error parsing host environment variables: %w", err)
- }
+ osEnv := envLib.Map(os.Environ())
if !s.EnvHost {
s.EnvHost = c.EnvHost
@@ -839,6 +836,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
if !s.Volatile {
s.Volatile = c.Rm
}
+ if len(s.EnvMerge) == 0 || len(c.EnvMerge) != 0 {
+ s.EnvMerge = c.EnvMerge
+ }
if len(s.UnsetEnv) == 0 || len(c.UnsetEnv) != 0 {
s.UnsetEnv = c.UnsetEnv
}