aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/server/handler_api.go95
-rw-r--r--pkg/api/server/register_containers.go8
-rw-r--r--pkg/api/server/register_events.go4
-rw-r--r--pkg/api/server/register_images.go4
-rw-r--r--pkg/domain/infra/abi/containers.go70
-rw-r--r--pkg/domain/infra/abi/manifest.go3
-rw-r--r--pkg/domain/infra/tunnel/containers.go53
-rw-r--r--pkg/domain/infra/tunnel/helpers.go11
-rw-r--r--pkg/domain/infra/tunnel/manifest.go10
-rw-r--r--pkg/machine/e2e/init_test.go19
-rw-r--r--pkg/machine/e2e/set_test.go20
-rw-r--r--pkg/specgen/generate/container.go18
-rw-r--r--pkg/systemd/generate/common.go24
-rw-r--r--pkg/systemd/generate/containers.go12
-rw-r--r--pkg/systemd/generate/containers_test.go143
15 files changed, 355 insertions, 139 deletions
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index a3aa681d0..57cafa5f6 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -1,7 +1,10 @@
package server
import (
+ "bufio"
+ "errors"
"fmt"
+ "net"
"net/http"
"runtime"
@@ -9,34 +12,54 @@ import (
"github.com/sirupsen/logrus"
)
+type BufferedResponseWriter struct {
+ b *bufio.Writer
+ w http.ResponseWriter
+}
+
// APIHandler is a wrapper to enhance HandlerFunc's and remove redundant code
func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Wrapper to hide some boilerplate
- fn := func(w http.ResponseWriter, r *http.Request) {
- if err := r.ParseForm(); err != nil {
- logrus.WithFields(logrus.Fields{
- "X-Reference-Id": r.Header.Get("X-Reference-Id"),
- }).Info("Failed Request: unable to parse form: " + err.Error())
- }
+ s.apiWrapper(h, w, r, false)
+ }
+}
+
+// An API Handler to help historical clients with broken parsing that expect
+// streaming JSON payloads to be reliably messaged framed (full JSON record
+// always fits in each read())
+func (s *APIServer) StreamBufferedAPIHandler(h http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ // Wrapper to hide some boilerplate
+ s.apiWrapper(h, w, r, true)
+ }
+}
- cv := version.APIVersion[version.Compat][version.CurrentAPI]
- w.Header().Set("API-Version", fmt.Sprintf("%d.%d", cv.Major, cv.Minor))
+func (s *APIServer) apiWrapper(h http.HandlerFunc, w http.ResponseWriter, r *http.Request, buffer bool) {
+ if err := r.ParseForm(); err != nil {
+ logrus.WithFields(logrus.Fields{
+ "X-Reference-Id": r.Header.Get("X-Reference-Id"),
+ }).Info("Failed Request: unable to parse form: " + err.Error())
+ }
- lv := version.APIVersion[version.Libpod][version.CurrentAPI].String()
- w.Header().Set("Libpod-API-Version", lv)
- w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")")
+ cv := version.APIVersion[version.Compat][version.CurrentAPI]
+ w.Header().Set("API-Version", fmt.Sprintf("%d.%d", cv.Major, cv.Minor))
- if s.CorsHeaders != "" {
- w.Header().Set("Access-Control-Allow-Origin", s.CorsHeaders)
- w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth, Connection, Upgrade, X-Registry-Config")
- w.Header().Set("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
- }
+ lv := version.APIVersion[version.Libpod][version.CurrentAPI].String()
+ w.Header().Set("Libpod-API-Version", lv)
+ w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")")
- h(w, r)
- }
- fn(w, r)
+ if s.CorsHeaders != "" {
+ w.Header().Set("Access-Control-Allow-Origin", s.CorsHeaders)
+ w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth, Connection, Upgrade, X-Registry-Config")
+ w.Header().Set("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
}
+
+ if buffer {
+ w = newBufferedResponseWriter(w)
+ }
+
+ h(w, r)
}
// VersionedPath prepends the version parsing code
@@ -44,3 +67,37 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
func VersionedPath(p string) string {
return "/v{version:[0-9][0-9A-Za-z.-]*}" + p
}
+
+func (w *BufferedResponseWriter) Header() http.Header {
+ return w.w.Header()
+}
+
+func (w *BufferedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ _ = w.b.Flush()
+ if wrapped, ok := w.w.(http.Hijacker); ok {
+ return wrapped.Hijack()
+ }
+
+ return nil, nil, errors.New("ResponseWriter does not support hijacking")
+}
+
+func (w *BufferedResponseWriter) Write(b []byte) (int, error) {
+ return w.b.Write(b)
+}
+
+func (w *BufferedResponseWriter) WriteHeader(statusCode int) {
+ w.w.WriteHeader(statusCode)
+}
+
+func (w *BufferedResponseWriter) Flush() {
+ _ = w.b.Flush()
+ if wrapped, ok := w.w.(http.Flusher); ok {
+ wrapped.Flush()
+ }
+}
+func newBufferedResponseWriter(rw http.ResponseWriter) *BufferedResponseWriter {
+ return &BufferedResponseWriter{
+ bufio.NewWriterSize(rw, 8192),
+ rw,
+ }
+}
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index e2ecdb6af..b319fc14a 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -397,9 +397,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// $ref: "#/responses/containerNotFound"
// 500:
// $ref: "#/responses/internalError"
- r.HandleFunc(VersionedPath("/containers/{name}/stats"), s.APIHandler(compat.StatsContainer)).Methods(http.MethodGet)
+ r.HandleFunc(VersionedPath("/containers/{name}/stats"), s.StreamBufferedAPIHandler(compat.StatsContainer)).Methods(http.MethodGet)
// Added non version path to URI to support docker non versioned paths
- r.HandleFunc("/containers/{name}/stats", s.APIHandler(compat.StatsContainer)).Methods(http.MethodGet)
+ r.HandleFunc("/containers/{name}/stats", s.StreamBufferedAPIHandler(compat.StatsContainer)).Methods(http.MethodGet)
// swagger:operation POST /containers/{name}/stop compat ContainerStop
// ---
// tags:
@@ -455,9 +455,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// $ref: "#/responses/containerNotFound"
// 500:
// $ref: "#/responses/internalError"
- r.HandleFunc(VersionedPath("/containers/{name}/top"), s.APIHandler(compat.TopContainer)).Methods(http.MethodGet)
+ r.HandleFunc(VersionedPath("/containers/{name}/top"), s.StreamBufferedAPIHandler(compat.TopContainer)).Methods(http.MethodGet)
// Added non version path to URI to support docker non versioned paths
- r.HandleFunc("/containers/{name}/top", s.APIHandler(compat.TopContainer)).Methods(http.MethodGet)
+ r.HandleFunc("/containers/{name}/top", s.StreamBufferedAPIHandler(compat.TopContainer)).Methods(http.MethodGet)
// swagger:operation POST /containers/{name}/unpause compat ContainerUnpause
// ---
// tags:
diff --git a/pkg/api/server/register_events.go b/pkg/api/server/register_events.go
index 76f9ec619..3442b3eab 100644
--- a/pkg/api/server/register_events.go
+++ b/pkg/api/server/register_events.go
@@ -34,9 +34,9 @@ func (s *APIServer) registerEventsHandlers(r *mux.Router) error {
// description: returns a string of json data describing an event
// 500:
// "$ref": "#/responses/internalError"
- r.Handle(VersionedPath("/events"), s.APIHandler(compat.GetEvents)).Methods(http.MethodGet)
+ r.Handle(VersionedPath("/events"), s.StreamBufferedAPIHandler(compat.GetEvents)).Methods(http.MethodGet)
// Added non version path to URI to support docker non versioned paths
- r.Handle("/events", s.APIHandler(compat.GetEvents)).Methods(http.MethodGet)
+ r.Handle("/events", s.StreamBufferedAPIHandler(compat.GetEvents)).Methods(http.MethodGet)
// swagger:operation GET /libpod/events system SystemEventsLibpod
// ---
// tags:
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 1bfedd77e..d71e0d470 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -702,9 +702,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// $ref: "#/responses/badParamError"
// 500:
// $ref: "#/responses/internalError"
- r.Handle(VersionedPath("/build"), s.APIHandler(compat.BuildImage)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/build"), s.StreamBufferedAPIHandler(compat.BuildImage)).Methods(http.MethodPost)
// Added non version path to URI to support docker non versioned paths
- r.Handle("/build", s.APIHandler(compat.BuildImage)).Methods(http.MethodPost)
+ r.Handle("/build", s.StreamBufferedAPIHandler(compat.BuildImage)).Methods(http.MethodPost)
/*
libpod endpoints
*/
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 04eb85504..f12e17c09 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -40,6 +40,7 @@ import (
// is specified. It also returns a list of the corresponding input name used to lookup each container.
func getContainersAndInputByContext(all, latest bool, names []string, filters map[string][]string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) {
var ctr *libpod.Container
+ var filteredCtrs []*libpod.Container
ctrs = []*libpod.Container{}
filterFuncs := make([]libpod.ContainerFilter, 0, len(filters))
@@ -58,7 +59,17 @@ func getContainersAndInputByContext(all, latest bool, names []string, filters ma
}
rawInput = []string{}
for _, candidate := range ctrs {
- rawInput = append(rawInput, candidate.ID())
+ if len(names) > 0 {
+ for _, name := range names {
+ if candidate.ID() == name || candidate.Name() == name {
+ rawInput = append(rawInput, candidate.ID())
+ filteredCtrs = append(filteredCtrs, candidate)
+ }
+ }
+ ctrs = filteredCtrs
+ } else {
+ rawInput = append(rawInput, candidate.ID())
+ }
}
case all:
ctrs, err = runtime.GetAllContainers()
@@ -860,38 +871,7 @@ func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID s
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
reports := []*entities.ContainerStartReport{}
var exitCode = define.ExecErrorCodeGeneric
- containersNamesOrIds := namesOrIds
- all := options.All
- if len(options.Filters) > 0 {
- all = false
- filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
- if len(options.Filters) > 0 {
- for k, v := range options.Filters {
- generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
- if err != nil {
- return nil, err
- }
- filterFuncs = append(filterFuncs, generatedFunc)
- }
- }
- candidates, err := ic.Libpod.GetContainers(filterFuncs...)
- if err != nil {
- return nil, err
- }
- containersNamesOrIds = []string{}
- for _, candidate := range candidates {
- if options.All {
- containersNamesOrIds = append(containersNamesOrIds, candidate.ID())
- continue
- }
- for _, nameOrID := range namesOrIds {
- if nameOrID == candidate.ID() || nameOrID == candidate.Name() {
- containersNamesOrIds = append(containersNamesOrIds, nameOrID)
- }
- }
- }
- }
- ctrs, rawInputs, err := getContainersAndInputByContext(all, options.Latest, containersNamesOrIds, options.Filters, ic.Libpod)
+ ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod)
if err != nil {
return nil, err
}
@@ -1035,6 +1015,15 @@ func (ic *ContainerEngine) Diff(ctx context.Context, namesOrIDs []string, opts e
}
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
+ removeContainer := func(ctr *libpod.Container, force bool) error {
+ var timeout *uint
+ if err := ic.Libpod.RemoveContainer(ctx, ctr, force, true, timeout); err != nil {
+ logrus.Debugf("unable to remove container %s after failing to start and attach to it: %v", ctr.ID(), err)
+ return err
+ }
+ return nil
+ }
+
warn, err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec)
if err != nil {
return nil, err
@@ -1055,6 +1044,8 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
if opts.CIDFile != "" {
if err := util.CreateCidFile(opts.CIDFile, ctr.ID()); err != nil {
+ // If you fail to create CIDFile then remove the container
+ _ = removeContainer(ctr, true)
return nil, err
}
}
@@ -1072,6 +1063,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
if err := ctr.Start(ctx, true); err != nil {
// This means the command did not exist
report.ExitCode = define.ExitCode(err)
+ if opts.Rm {
+ if rmErr := removeContainer(ctr, true); rmErr != nil && !errors.Is(rmErr, define.ErrNoSuchCtr) {
+ logrus.Errorf("Container %s failed to be removed", ctr.ID())
+ }
+ }
return &report, err
}
@@ -1088,10 +1084,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
return &report, nil
}
if opts.Rm {
- var timeout *uint
- if deleteError := ic.Libpod.RemoveContainer(ctx, ctr, true, false, timeout); deleteError != nil {
- logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID())
- }
+ _ = removeContainer(ctr, true)
}
if errors.Is(err, define.ErrWillDeadlock) {
logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err)
@@ -1103,8 +1096,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
report.ExitCode = ic.GetContainerExitCode(ctx, ctr)
if opts.Rm && !ctr.ShouldRestart(ctx) {
- var timeout *uint
- if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true, timeout); err != nil {
+ if err := removeContainer(ctr, false); err != nil {
if errors.Is(err, define.ErrNoSuchCtr) ||
errors.Is(err, define.ErrCtrRemoved) {
logrus.Infof("Container %s was already removed, skipping --rm", ctr.ID())
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 60f727234..6606b2cd0 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -334,7 +334,8 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin
}
if opts.Rm {
- if _, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, []string{manifestList.ID()}, nil); len(rmErrors) > 0 {
+ rmOpts := &libimage.RemoveImagesOptions{LookupManifest: true}
+ if _, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, []string{manifestList.ID()}, rmOpts); len(rmErrors) > 0 {
return "", fmt.Errorf("error removing manifest after push: %w", rmErrors[0])
}
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index fcabff7c4..0bf792879 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -623,36 +623,7 @@ 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
- containersNamesOrIds := namesOrIds
- all := options.All
- if len(options.Filters) > 0 {
- all = false
- containersNamesOrIds = []string{}
- opts := new(containers.ListOptions).WithFilters(options.Filters).WithAll(true)
- candidates, listErr := containers.List(ic.ClientCtx, opts)
- if listErr != nil {
- return nil, listErr
- }
- for _, candidate := range candidates {
- if options.All {
- containersNamesOrIds = append(containersNamesOrIds, candidate.ID)
- continue
- }
- for _, nameOrID := range namesOrIds {
- if nameOrID == candidate.ID {
- containersNamesOrIds = append(containersNamesOrIds, nameOrID)
- continue
- }
- for _, containerName := range candidate.Names {
- if containerName == nameOrID {
- containersNamesOrIds = append(containersNamesOrIds, nameOrID)
- continue
- }
- }
- }
- }
- }
- ctrs, err := getContainersByContext(ic.ClientCtx, all, false, containersNamesOrIds)
+ ctrs, namesOrIds, err := getContainersAndInputByContext(ic.ClientCtx, options.All, false, namesOrIds, options.Filters)
if err != nil {
return nil, err
}
@@ -771,8 +742,17 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
for _, w := range con.Warnings {
fmt.Fprintf(os.Stderr, "%s\n", w)
}
+ removeContainer := func(id string, force bool) error {
+ removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(force)
+ reports, err := containers.Remove(ic.ClientCtx, id, removeOptions)
+ logIfRmError(id, err, reports)
+ return err
+ }
+
if opts.CIDFile != "" {
if err := util.CreateCidFile(opts.CIDFile, con.ID); err != nil {
+ // If you fail to create CIDFile then remove the container
+ _ = removeContainer(con.ID, true)
return nil, err
}
}
@@ -784,6 +764,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
err := containers.Start(ic.ClientCtx, con.ID, new(containers.StartOptions).WithRecursive(true))
if err != nil {
report.ExitCode = define.ExitCode(err)
+ if opts.Rm {
+ if rmErr := removeContainer(con.ID, true); rmErr != nil && !errors.Is(rmErr, define.ErrNoSuchCtr) {
+ logrus.Errorf("Container %s failed to be removed", con.ID)
+ }
+ }
}
return &report, err
}
@@ -796,10 +781,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
report.ExitCode = define.ExitCode(err)
if opts.Rm {
- reports, rmErr := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true))
- if rmErr != nil || reports[0].Err != nil {
- logrus.Debugf("unable to remove container %s after failing to start and attach to it", con.ID)
- }
+ _ = removeContainer(con.ID, false)
}
return &report, err
}
@@ -815,8 +797,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
if !shouldRestart {
- reports, err := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true))
- logIfRmError(con.ID, err, reports)
+ _ = removeContainer(con.ID, false)
}
}()
}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 9ff1641f0..20ea07948 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -31,8 +31,17 @@ func getContainersAndInputByContext(contextWithConnection context.Context, all,
rawInputs := []string{}
switch {
case len(filters) > 0:
+ namesOrIDs = nil
for i := range allContainers {
- namesOrIDs = append(namesOrIDs, allContainers[i].ID)
+ if len(namesOrIDs) > 0 {
+ for _, name := range namesOrIDs {
+ if name == allContainers[i].ID {
+ namesOrIDs = append(namesOrIDs, allContainers[i].ID)
+ }
+ }
+ } else {
+ namesOrIDs = append(namesOrIDs, allContainers[i].ID)
+ }
}
case all:
for i := range allContainers {
diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go
index d2554f198..4a3148fac 100644
--- a/pkg/domain/infra/tunnel/manifest.go
+++ b/pkg/domain/infra/tunnel/manifest.go
@@ -110,5 +110,15 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin
}
}
digest, err := manifests.Push(ir.ClientCtx, name, destination, options)
+ if err != nil {
+ return "", fmt.Errorf("error adding to manifest list %s: %w", name, err)
+ }
+
+ if opts.Rm {
+ if _, rmErrors := ir.Remove(ctx, []string{name}, entities.ImageRemoveOptions{LookupManifest: true}); len(rmErrors) > 0 {
+ return "", fmt.Errorf("error removing manifest after push: %w", rmErrors[0])
+ }
+ }
+
return digest, err
}
diff --git a/pkg/machine/e2e/init_test.go b/pkg/machine/e2e/init_test.go
index b246dc4da..859a3ca46 100644
--- a/pkg/machine/e2e/init_test.go
+++ b/pkg/machine/e2e/init_test.go
@@ -3,7 +3,7 @@ package e2e_test
import (
"io/ioutil"
"os"
- "runtime"
+ "strconv"
"time"
"github.com/containers/podman/v4/pkg/machine"
@@ -80,7 +80,7 @@ var _ = Describe("podman machine init", func() {
It("machine init with cpus, disk size, memory, timezone", func() {
name := randomString()
i := new(initMachine)
- session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath).withCPUs(2).withDiskSize(102).withMemory(4000).withTimezone("Pacific/Honolulu")).run()
+ session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath).withCPUs(2).withDiskSize(102).withMemory(4096).withTimezone("Pacific/Honolulu")).run()
Expect(err).To(BeNil())
Expect(session).To(Exit(0))
@@ -102,18 +102,13 @@ var _ = Describe("podman machine init", func() {
Expect(diskSession.outputToString()).To(ContainSubstring("102 GiB"))
sshMemory := sshMachine{}
- memorySession, err := mb.setName(name).setCmd(sshMemory.withSSHComand([]string{"cat", "/proc/meminfo", "|", "numfmt", "--field", "2", "--from-unit=Ki", "--to-unit=Mi", "|", "sed", "'s/ kB/M/g'", "|", "grep", "MemTotal"})).run()
+ memorySession, err := mb.setName(name).setCmd(sshMemory.withSSHComand([]string{"cat", "/proc/meminfo", "|", "grep", "-i", "'memtotal'", "|", "grep", "-o", "'[[:digit:]]*'"})).run()
Expect(err).To(BeNil())
Expect(memorySession).To(Exit(0))
- switch runtime.GOOS {
- // os's handle memory differently
- case "linux":
- Expect(memorySession.outputToString()).To(ContainSubstring("3822"))
- case "darwin":
- Expect(memorySession.outputToString()).To(ContainSubstring("3824"))
- default:
- // add windows when testing on that platform
- }
+ foundMemory, err := strconv.Atoi(memorySession.outputToString())
+ Expect(err).To(BeNil())
+ Expect(foundMemory).To(BeNumerically(">", 3800000))
+ Expect(foundMemory).To(BeNumerically("<", 4200000))
sshTimezone := sshMachine{}
timezoneSession, err := mb.setName(name).setCmd(sshTimezone.withSSHComand([]string{"date"})).run()
diff --git a/pkg/machine/e2e/set_test.go b/pkg/machine/e2e/set_test.go
index 4839e33da..a32bb72f2 100644
--- a/pkg/machine/e2e/set_test.go
+++ b/pkg/machine/e2e/set_test.go
@@ -1,7 +1,7 @@
package e2e_test
import (
- "runtime"
+ "strconv"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -29,7 +29,7 @@ var _ = Describe("podman machine set", func() {
Expect(session).To(Exit(0))
set := setMachine{}
- setSession, err := mb.setName(name).setCmd(set.withCPUs(2).withDiskSize(102).withMemory(4000)).run()
+ setSession, err := mb.setName(name).setCmd(set.withCPUs(2).withDiskSize(102).withMemory(4096)).run()
Expect(err).To(BeNil())
Expect(setSession).To(Exit(0))
@@ -56,18 +56,14 @@ var _ = Describe("podman machine set", func() {
Expect(diskSession.outputToString()).To(ContainSubstring("102 GiB"))
sshMemory := sshMachine{}
- memorySession, err := mb.setName(name).setCmd(sshMemory.withSSHComand([]string{"cat", "/proc/meminfo", "|", "numfmt", "--field", "2", "--from-unit=Ki", "--to-unit=Mi", "|", "sed", "'s/ kB/M/g'", "|", "grep", "MemTotal"})).run()
+ memorySession, err := mb.setName(name).setCmd(sshMemory.withSSHComand([]string{"cat", "/proc/meminfo", "|", "grep", "-i", "'memtotal'", "|", "grep", "-o", "'[[:digit:]]*'"})).run()
Expect(err).To(BeNil())
Expect(memorySession).To(Exit(0))
- switch runtime.GOOS {
- // it seems macos and linux handle memory differently
- case "linux":
- Expect(memorySession.outputToString()).To(ContainSubstring("3822"))
- case "darwin":
- Expect(memorySession.outputToString()).To(ContainSubstring("3824"))
- default:
- // windows can go here if we ever run tests there
- }
+ foundMemory, err := strconv.Atoi(memorySession.outputToString())
+ Expect(err).To(BeNil())
+ Expect(foundMemory).To(BeNumerically(">", 3800000))
+ Expect(foundMemory).To(BeNumerically("<", 4200000))
+
// Setting a running machine results in 125
runner, err := mb.setName(name).setCmd(set.withCPUs(4)).run()
Expect(err).To(BeNil())
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 2248c9235..b6701b1ce 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -191,16 +191,24 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
// - "container" denotes the container should join the VM of the SandboxID
// (the infra container)
if len(s.Pod) > 0 {
- annotations[ann.SandboxID] = s.Pod
+ p, err := r.LookupPod(s.Pod)
+ if err != nil {
+ return nil, err
+ }
+ sandboxID := p.ID()
+ if p.HasInfraContainer() {
+ infra, err := p.InfraContainer()
+ if err != nil {
+ return nil, err
+ }
+ sandboxID = infra.ID()
+ }
+ annotations[ann.SandboxID] = sandboxID
annotations[ann.ContainerType] = ann.ContainerTypeContainer
// Check if this is an init-ctr and if so, check if
// the pod is running. we do not want to add init-ctrs to
// a running pod because it creates confusion for us.
if len(s.InitContainerType) > 0 {
- p, err := r.LookupPod(s.Pod)
- if err != nil {
- return nil, err
- }
containerStatuses, err := p.Status()
if err != nil {
return nil, err
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index 60b0c4b52..b0a441d54 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -42,7 +42,7 @@ RequiresMountsFor={{{{.RunRoot}}}}
// filterPodFlags removes --pod, --pod-id-file and --infra-conmon-pidfile from the specified command.
// argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint.
func filterPodFlags(command []string, argCount int) []string {
- processed := []string{}
+ processed := make([]string, 0, len(command))
for i := 0; i < len(command)-argCount; i++ {
s := command[i]
if s == "--pod" || s == "--pod-id-file" || s == "--infra-conmon-pidfile" {
@@ -63,7 +63,7 @@ func filterPodFlags(command []string, argCount int) []string {
// filterCommonContainerFlags removes --sdnotify, --rm and --cgroups from the specified command.
// argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint.
func filterCommonContainerFlags(command []string, argCount int) []string {
- processed := []string{}
+ processed := make([]string, 0, len(command))
for i := 0; i < len(command)-argCount; i++ {
s := command[i]
@@ -71,7 +71,7 @@ func filterCommonContainerFlags(command []string, argCount int) []string {
case s == "--rm":
// Boolean flags support --flag and --flag={true,false}.
continue
- case s == "--sdnotify", s == "--cgroups", s == "--cidfile", s == "--restart":
+ case s == "--cgroups", s == "--cidfile", s == "--restart":
i++
continue
case strings.HasPrefix(s, "--rm="),
@@ -111,6 +111,24 @@ func escapeSystemdArg(arg string) string {
return arg
}
+func removeSdNotifyArg(args []string, argCount int) []string {
+ processed := make([]string, 0, len(args))
+ for i := 0; i < len(args)-argCount; i++ {
+ s := args[i]
+
+ switch {
+ case s == "--sdnotify":
+ i++
+ continue
+ case strings.HasPrefix(s, "--sdnotify="):
+ continue
+ }
+ processed = append(processed, s)
+ }
+ processed = append(processed, args[len(args)-argCount:]...)
+ return processed
+}
+
func removeDetachArg(args []string, argCount int) []string {
// "--detach=false" could also be in the container entrypoint
// split them off so we do not remove it there
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index 6596ef73b..1f8c519b7 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -378,6 +378,9 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
fs.StringArrayP("env", "e", nil, "")
fs.String("sdnotify", "", "")
fs.String("restart", "", "")
+ // have to define extra -h flag to prevent help error when parsing -h hostname
+ // https://github.com/containers/podman/issues/15124
+ fs.StringP("help", "h", "", "")
if err := fs.Parse(remainingCmd); err != nil {
return "", fmt.Errorf("parsing remaining command-line arguments: %w", err)
}
@@ -403,8 +406,13 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
// Default to --sdnotify=conmon unless already set by the
// container.
- hasSdnotifyParam := fs.Lookup("sdnotify").Changed
- if !hasSdnotifyParam {
+ sdnotifyFlag := fs.Lookup("sdnotify")
+ if !sdnotifyFlag.Changed {
+ startCommand = append(startCommand, "--sdnotify=conmon")
+ } else if sdnotifyFlag.Value.String() == libpodDefine.SdNotifyModeIgnore {
+ // If ignore is set force conmon otherwise the unit with Type=notify will fail.
+ logrus.Infof("Forcing --sdnotify=conmon for container %s", info.ContainerNameOrID)
+ remainingCmd = removeSdNotifyArg(remainingCmd, fs.NArg())
startCommand = append(startCommand, "--sdnotify=conmon")
}
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index 640aa298e..873cbfbb3 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -2,6 +2,7 @@ package generate
import (
"fmt"
+ "strings"
"testing"
"github.com/containers/podman/v4/pkg/domain/entities"
@@ -317,6 +318,39 @@ NotifyAccess=all
WantedBy=default.target
`
+ goodWithNameAndSdnotifyIgnore := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network-online.target
+After=network-online.target
+RequiresMountsFor=/var/run/containers/storage
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=on-failure
+TimeoutStopSec=70
+ExecStartPre=/bin/rm -f %t/%n.ctr-id
+ExecStart=/usr/bin/podman container run \
+ --cidfile=%t/%n.ctr-id \
+ --cgroups=no-conmon \
+ --rm \
+ --sdnotify=conmon \
+ -d \
+ --replace \
+ --name jadda-jadda \
+ --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space"
+ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
+ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
+Type=notify
+NotifyAccess=all
+
+[Install]
+WantedBy=default.target
+`
+
goodWithExplicitShortDetachParam := `# jadda-jadda.service
# autogenerated by Podman CI
@@ -781,6 +815,37 @@ NotifyAccess=all
WantedBy=default.target
`
+ goodNewWithHostname := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network-online.target
+After=network-online.target
+RequiresMountsFor=/var/run/containers/storage
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=on-failure
+TimeoutStopSec=70
+ExecStartPre=/bin/rm -f %t/%n.ctr-id
+ExecStart=/usr/bin/podman run \
+ --cidfile=%t/%n.ctr-id \
+ --cgroups=no-conmon \
+ --rm \
+ --sdnotify=conmon \
+ -d \
+ -h hostname awesome-image:latest
+ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
+ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
+Type=notify
+NotifyAccess=all
+
+[Install]
+WantedBy=default.target
+`
+
templateGood := `# container-foo@.service
# autogenerated by Podman CI
@@ -992,7 +1057,7 @@ WantedBy=default.target
false,
false,
},
- {"good with name and sdnotify",
+ {"good with name and --sdnotify=container",
containerInfo{
Executable: "/usr/bin/podman",
ServiceName: "jadda-jadda",
@@ -1011,6 +1076,63 @@ WantedBy=default.target
false,
false,
},
+ {"good with name and --sdnotify container",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "container", "run", "--sdnotify", "container", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"},
+ EnvVariable: define.EnvVariable,
+ GraphRoot: "/var/lib/containers/storage",
+ RunRoot: "/var/run/containers/storage",
+ },
+ strings.ReplaceAll(goodWithNameAndSdnotify, "--sdnotify=container", "--sdnotify container"),
+ true,
+ false,
+ false,
+ false,
+ },
+ {"good with name and --sdnotify=ignore",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "container", "run", "--sdnotify=ignore", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"},
+ EnvVariable: define.EnvVariable,
+ GraphRoot: "/var/lib/containers/storage",
+ RunRoot: "/var/run/containers/storage",
+ },
+ goodWithNameAndSdnotifyIgnore,
+ true,
+ false,
+ false,
+ false,
+ },
+ {"good with name and --sdnotify ignore",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "container", "run", "--sdnotify", "ignore", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"},
+ EnvVariable: define.EnvVariable,
+ GraphRoot: "/var/lib/containers/storage",
+ RunRoot: "/var/run/containers/storage",
+ },
+ goodWithNameAndSdnotifyIgnore,
+ true,
+ false,
+ false,
+ false,
+ },
{"good with explicit short detach param",
containerInfo{
Executable: "/usr/bin/podman",
@@ -1341,6 +1463,25 @@ WantedBy=default.target
false,
false,
},
+ {"good with -h hostname",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ GraphRoot: "/var/lib/containers/storage",
+ RunRoot: "/var/run/containers/storage",
+ CreateCommand: []string{"I'll get stripped", "create", "-h", "hostname", "awesome-image:latest"},
+ EnvVariable: define.EnvVariable,
+ },
+ goodNewWithHostname,
+ true,
+ false,
+ false,
+ false,
+ },
{"good template",
containerInfo{
Executable: "/usr/bin/podman",