aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_stats.go2
-rw-r--r--pkg/api/handlers/libpod/generate.go34
-rw-r--r--pkg/api/handlers/libpod/play.go53
-rw-r--r--pkg/bindings/containers/attach.go23
-rw-r--r--pkg/bindings/containers/term_unix.go25
-rw-r--r--pkg/bindings/containers/term_windows.go69
-rw-r--r--pkg/bindings/images/build.go47
-rw-r--r--pkg/bindings/play/play.go39
-rw-r--r--pkg/domain/entities/engine_container.go4
-rw-r--r--pkg/domain/infra/abi/containers.go7
-rw-r--r--pkg/domain/infra/abi/play.go39
-rw-r--r--pkg/domain/infra/abi/system.go22
-rw-r--r--pkg/domain/infra/tunnel/play.go9
-rw-r--r--pkg/machine/ignition.go5
-rw-r--r--pkg/machine/qemu/machine.go35
-rw-r--r--pkg/machine/wsl/machine.go7
-rw-r--r--pkg/signal/signal_unix.go99
-rw-r--r--pkg/signal/signal_unsupported.go2
-rw-r--r--pkg/specgen/generate/config_linux.go5
-rw-r--r--pkg/specgen/generate/container_create.go11
-rw-r--r--pkg/specgen/generate/pod_create.go1
-rw-r--r--pkg/systemd/generate/common.go14
-rw-r--r--pkg/systemd/generate/containers.go4
-rw-r--r--pkg/systemd/generate/containers_test.go42
-rw-r--r--pkg/systemd/generate/pods.go3
-rw-r--r--pkg/systemd/generate/pods_test.go44
-rw-r--r--pkg/util/utils.go18
-rw-r--r--pkg/util/utils_linux.go9
28 files changed, 510 insertions, 162 deletions
diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go
index 99f14d02f..77b16b03e 100644
--- a/pkg/api/handlers/compat/containers_stats.go
+++ b/pkg/api/handlers/compat/containers_stats.go
@@ -56,7 +56,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
return
}
- stats, err := ctnr.GetContainerStats(&define.ContainerStats{})
+ stats, err := ctnr.GetContainerStats(nil)
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "failed to obtain Container %s stats", name))
return
diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go
index 7e08dd4a8..28785b00d 100644
--- a/pkg/api/handlers/libpod/generate.go
+++ b/pkg/api/handlers/libpod/generate.go
@@ -25,18 +25,15 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
RestartSec uint `schema:"restartSec"`
StopTimeout uint `schema:"stopTimeout"`
StartTimeout uint `schema:"startTimeout"`
- ContainerPrefix string `schema:"containerPrefix"`
- PodPrefix string `schema:"podPrefix"`
- Separator string `schema:"separator"`
+ ContainerPrefix *string `schema:"containerPrefix"`
+ PodPrefix *string `schema:"podPrefix"`
+ Separator *string `schema:"separator"`
Wants []string `schema:"wants"`
After []string `schema:"after"`
Requires []string `schema:"requires"`
}{
- StartTimeout: 0,
- StopTimeout: util.DefaultContainerConfig().Engine.StopTimeout,
- ContainerPrefix: "container",
- PodPrefix: "pod",
- Separator: "-",
+ StartTimeout: 0,
+ StopTimeout: util.DefaultContainerConfig().Engine.StopTimeout,
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
@@ -44,6 +41,21 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
return
}
+ var ContainerPrefix = "container"
+ if query.ContainerPrefix != nil {
+ ContainerPrefix = *query.ContainerPrefix
+ }
+
+ var PodPrefix = "pod"
+ if query.PodPrefix != nil {
+ PodPrefix = *query.PodPrefix
+ }
+
+ var Separator = "-"
+ if query.Separator != nil {
+ Separator = *query.Separator
+ }
+
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.GenerateSystemdOptions{
Name: query.Name,
@@ -53,9 +65,9 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
RestartPolicy: query.RestartPolicy,
StartTimeout: &query.StartTimeout,
StopTimeout: &query.StopTimeout,
- ContainerPrefix: query.ContainerPrefix,
- PodPrefix: query.PodPrefix,
- Separator: query.Separator,
+ ContainerPrefix: ContainerPrefix,
+ PodPrefix: PodPrefix,
+ Separator: Separator,
RestartSec: &query.RestartSec,
Wants: query.Wants,
After: query.After,
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index 515d0e5cf..90e244ec2 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -1,11 +1,8 @@
package libpod
import (
- "io"
- "io/ioutil"
"net"
"net/http"
- "os"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/libpod"
@@ -16,7 +13,6 @@ import (
"github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
func PlayKube(w http.ResponseWriter, r *http.Request) {
@@ -61,28 +57,6 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
staticMACs = append(staticMACs, mac)
}
- // Fetch the K8s YAML file from the body, and copy it to a temp file.
- tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
- if err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
- return
- }
- defer func() {
- if err := os.Remove(tmpfile.Name()); err != nil {
- logrus.Warn(err)
- }
- }()
- if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
- if err := tmpfile.Close(); err != nil {
- logrus.Warn(err)
- }
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
- return
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
- return
- }
authConf, authfile, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, http.StatusBadRequest, err)
@@ -114,7 +88,8 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
if _, found := r.URL.Query()["start"]; found {
options.Start = types.NewOptionalBool(query.Start)
}
- report, err := containerEngine.PlayKube(r.Context(), tmpfile.Name(), options)
+ report, err := containerEngine.PlayKube(r.Context(), r.Body, options)
+ _ = r.Body.Close()
if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error playing YAML file"))
return
@@ -124,30 +99,10 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
func PlayKubeDown(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
- tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
- if err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
- return
- }
- defer func() {
- if err := os.Remove(tmpfile.Name()); err != nil {
- logrus.Warn(err)
- }
- }()
- if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
- if err := tmpfile.Close(); err != nil {
- logrus.Warn(err)
- }
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
- return
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
- return
- }
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := new(entities.PlayKubeDownOptions)
- report, err := containerEngine.PlayKubeDown(r.Context(), tmpfile.Name(), *options)
+ report, err := containerEngine.PlayKubeDown(r.Context(), r.Body, *options)
+ _ = r.Body.Close()
if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error tearing down YAML file"))
return
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index c6d434c87..f410606e4 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -10,14 +10,12 @@ import (
"net/http"
"net/url"
"os"
- "os/signal"
"reflect"
"strconv"
"time"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/bindings"
- sig "github.com/containers/podman/v4/pkg/signal"
"github.com/containers/podman/v4/utils"
"github.com/moby/term"
"github.com/pkg/errors"
@@ -94,7 +92,8 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
// Unless all requirements are met, don't use "stdin" is a terminal
file, ok := stdin.(*os.File)
- needTTY := ok && terminal.IsTerminal(int(file.Fd())) && ctnr.Config.Tty
+ outFile, outOk := stdout.(*os.File)
+ needTTY := ok && outOk && terminal.IsTerminal(int(file.Fd())) && ctnr.Config.Tty
if needTTY {
state, err := setRawTerminal(file)
if err != nil {
@@ -142,11 +141,10 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
if needTTY {
winChange := make(chan os.Signal, 1)
- signal.Notify(winChange, sig.SIGWINCH)
winCtx, winCancel := context.WithCancel(ctx)
defer winCancel()
-
- attachHandleResize(ctx, winCtx, winChange, false, nameOrID, file)
+ notifyWinChange(winCtx, winChange, file, outFile)
+ attachHandleResize(ctx, winCtx, winChange, false, nameOrID, file, outFile)
}
// If we are attaching around a start, we need to "signal"
@@ -345,9 +343,9 @@ func (f *rawFormatter) Format(entry *logrus.Entry) ([]byte, error) {
// This is intended to not be run as a goroutine, handling resizing for a container
// or exec session. It will call resize once and then starts a goroutine which calls resize on winChange
-func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, isExec bool, id string, file *os.File) {
+func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, isExec bool, id string, file *os.File, outFile *os.File) {
resize := func() {
- w, h, err := terminal.GetSize(int(file.Fd()))
+ w, h, err := getTermSize(file, outFile)
if err != nil {
logrus.Warnf("Failed to obtain TTY size: %v", err)
}
@@ -379,7 +377,7 @@ func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, i
// Configure the given terminal for raw mode
func setRawTerminal(file *os.File) (*terminal.State, error) {
- state, err := terminal.MakeRaw(int(file.Fd()))
+ state, err := makeRawTerm(file)
if err != nil {
return nil, err
}
@@ -402,6 +400,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
// TODO: Make this configurable (can't use streams' InputStream as it's
// buffered)
terminalFile := os.Stdin
+ terminalOutFile := os.Stdout
logrus.Debugf("Starting & Attaching to exec session ID %q", sessionID)
@@ -447,7 +446,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
}
logrus.SetFormatter(&logrus.TextFormatter{})
}()
- w, h, err := terminal.GetSize(int(terminalFile.Fd()))
+ w, h, err := getTermSize(terminalFile, terminalOutFile)
if err != nil {
logrus.Warnf("Failed to obtain TTY size: %v", err)
}
@@ -490,11 +489,11 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
if needTTY {
winChange := make(chan os.Signal, 1)
- signal.Notify(winChange, sig.SIGWINCH)
winCtx, winCancel := context.WithCancel(ctx)
defer winCancel()
- attachHandleResize(ctx, winCtx, winChange, true, sessionID, terminalFile)
+ notifyWinChange(winCtx, winChange, terminalFile, terminalOutFile)
+ attachHandleResize(ctx, winCtx, winChange, true, sessionID, terminalFile, terminalOutFile)
}
if options.GetAttachInput() {
diff --git a/pkg/bindings/containers/term_unix.go b/pkg/bindings/containers/term_unix.go
new file mode 100644
index 000000000..2c976393f
--- /dev/null
+++ b/pkg/bindings/containers/term_unix.go
@@ -0,0 +1,25 @@
+//go:build !windows
+// +build !windows
+
+package containers
+
+import (
+ "context"
+ "os"
+ "os/signal"
+
+ sig "github.com/containers/podman/v4/pkg/signal"
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+func makeRawTerm(stdin *os.File) (*terminal.State, error) {
+ return terminal.MakeRaw(int(stdin.Fd()))
+}
+
+func notifyWinChange(ctx context.Context, winChange chan os.Signal, stdin *os.File, stdout *os.File) {
+ signal.Notify(winChange, sig.SIGWINCH)
+}
+
+func getTermSize(stdin *os.File, stdout *os.File) (width, height int, err error) {
+ return terminal.GetSize(int(stdin.Fd()))
+}
diff --git a/pkg/bindings/containers/term_windows.go b/pkg/bindings/containers/term_windows.go
new file mode 100644
index 000000000..11d4bd50d
--- /dev/null
+++ b/pkg/bindings/containers/term_windows.go
@@ -0,0 +1,69 @@
+package containers
+
+import (
+ "context"
+ "os"
+ "time"
+
+ sig "github.com/containers/podman/v4/pkg/signal"
+ "golang.org/x/crypto/ssh/terminal"
+ "golang.org/x/sys/windows"
+)
+
+func makeRawTerm(stdin *os.File) (*terminal.State, error) {
+ state, err := terminal.MakeRaw(int(stdin.Fd()))
+ if err != nil {
+ return nil, err
+ }
+
+ // Attempt VT if supported (recent versions of Windows 10+)
+ var raw uint32
+ handle := windows.Handle(stdin.Fd())
+ if err := windows.GetConsoleMode(handle, &raw); err != nil {
+ return nil, err
+ }
+
+ tryVT := raw | windows.ENABLE_VIRTUAL_TERMINAL_INPUT
+
+ if err := windows.SetConsoleMode(handle, tryVT); err != nil {
+ if err := windows.SetConsoleMode(handle, raw); err != nil {
+ return nil, err
+ }
+ }
+
+ return state, nil
+}
+
+func notifyWinChange(ctx context.Context, winChange chan os.Signal, stdin *os.File, stdout *os.File) {
+ // Simulate WINCH with polling
+ go func() {
+ var lastW int
+ var lastH int
+
+ d := time.Millisecond * 250
+ timer := time.NewTimer(d)
+ defer timer.Stop()
+ for ; ; timer.Reset(d) {
+ select {
+ case <-ctx.Done():
+ return
+ case <-timer.C:
+ break
+ }
+
+ w, h, err := terminal.GetSize(int(stdout.Fd()))
+ if err != nil {
+ continue
+ }
+ if w != lastW || h != lastH {
+ winChange <- sig.SIGWINCH
+ lastW, lastH = w, h
+ }
+ }
+ }()
+
+}
+
+func getTermSize(stdin *os.File, stdout *os.File) (width, height int, err error) {
+ return terminal.GetSize(int(stdout.Fd()))
+}
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index c508cb767..73d0294e1 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"net/http"
"net/url"
@@ -241,7 +242,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
params.Add("platform", platform)
}
}
- if contextDir, err := filepath.EvalSymlinks(options.ContextDirectory); err == nil {
+ var err error
+ var contextDir string
+ if contextDir, err = filepath.EvalSymlinks(options.ContextDirectory); err == nil {
options.ContextDirectory = contextDir
}
@@ -301,7 +304,6 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
var (
headers http.Header
- err error
)
if options.SystemContext != nil && options.SystemContext.DockerAuthConfig != nil {
headers, err = auth.MakeXRegistryAuthHeader(options.SystemContext, options.SystemContext.DockerAuthConfig.Username, options.SystemContext.DockerAuthConfig.Password)
@@ -325,7 +327,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
}
}
- contextDir, err := filepath.Abs(options.ContextDirectory)
+ contextDir, err = filepath.Abs(options.ContextDirectory)
if err != nil {
logrus.Errorf("Cannot find absolute path of %v: %v", options.ContextDirectory, err)
return nil, err
@@ -556,16 +558,27 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
merr = multierror.Append(merr, err)
return
}
-
- err = filepath.Walk(s, func(path string, info os.FileInfo, err error) error {
+ err = filepath.WalkDir(s, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
- if path == s {
- return nil // skip root dir
+ // check if what we are given is an empty dir, if so then continue w/ it. Else return.
+ // if we are given a file or a symlink, we do not want to exclude it.
+ if d.IsDir() && s == path {
+ var p *os.File
+ p, err = os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer p.Close()
+ _, err = p.Readdir(1)
+ if err != io.EOF {
+ return nil // non empty root dir, need to return
+ } else if err != nil {
+ logrus.Errorf("Error while reading directory %v: %v", path, err)
+ }
}
-
name := filepath.ToSlash(strings.TrimPrefix(path, s+string(filepath.Separator)))
excluded, err := pm.Matches(name) // nolint:staticcheck
@@ -576,7 +589,11 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
return nil
}
- if info.Mode().IsRegular() { // add file item
+ if d.Type().IsRegular() { // add file item
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
di, isHardLink := checkHardLink(info)
if err != nil {
return err
@@ -612,7 +629,11 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
seen[di] = name
}
return err
- } else if info.Mode().IsDir() { // add folders
+ } else if d.IsDir() { // add folders
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
hdr, lerr := tar.FileInfoHeader(info, name)
if lerr != nil {
return lerr
@@ -622,11 +643,15 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
if lerr := tw.WriteHeader(hdr); lerr != nil {
return lerr
}
- } else if info.Mode()&os.ModeSymlink != 0 { // add symlinks as it, not content
+ } else if d.Type()&os.ModeSymlink != 0 { // add symlinks as it, not content
link, err := os.Readlink(path)
if err != nil {
return err
}
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
hdr, lerr := tar.FileInfoHeader(info, link)
if lerr != nil {
return lerr
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index d4018b6b3..8058a8514 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -2,6 +2,7 @@ package play
import (
"context"
+ "io"
"net/http"
"os"
"strconv"
@@ -14,20 +15,25 @@ import (
)
func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.PlayKubeReport, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return KubeWithBody(ctx, f, options)
+}
+
+func KubeWithBody(ctx context.Context, body io.Reader, options *KubeOptions) (*entities.PlayKubeReport, error) {
var report entities.PlayKubeReport
if options == nil {
options = new(KubeOptions)
}
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
- f, err := os.Open(path)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- defer f.Close()
params, err := options.ToParams()
if err != nil {
@@ -46,7 +52,7 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
return nil, err
}
- response, err := conn.DoRequest(ctx, f, http.MethodPost, "/play/kube", params, header)
+ response, err := conn.DoRequest(ctx, body, http.MethodPost, "/play/kube", params, header)
if err != nil {
return nil, err
}
@@ -60,12 +66,6 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
}
func KubeDown(ctx context.Context, path string) (*entities.PlayKubeReport, error) {
- var report entities.PlayKubeReport
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
-
f, err := os.Open(path)
if err != nil {
return nil, err
@@ -75,7 +75,18 @@ func KubeDown(ctx context.Context, path string) (*entities.PlayKubeReport, error
logrus.Warn(err)
}
}()
- response, err := conn.DoRequest(ctx, f, http.MethodDelete, "/play/kube", nil, nil)
+
+ return KubeDownWithBody(ctx, f)
+}
+
+func KubeDownWithBody(ctx context.Context, body io.Reader) (*entities.PlayKubeReport, error) {
+ var report entities.PlayKubeReport
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(ctx, body, http.MethodDelete, "/play/kube", nil, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 5dedceacc..5c169646b 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -67,8 +67,8 @@ type ContainerEngine interface {
NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, error)
NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
- PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
- PlayKubeDown(ctx context.Context, path string, opts PlayKubeDownOptions) (*PlayKubeReport, error)
+ PlayKube(ctx context.Context, body io.Reader, opts PlayKubeOptions) (*PlayKubeReport, error)
+ PlayKubeDown(ctx context.Context, body io.Reader, opts PlayKubeDownOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, specg PodSpec) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrID string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index a5c4647d7..ef2aa99d3 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1429,12 +1429,7 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
reportStats := []define.ContainerStats{}
for _, ctr := range containers {
- prev, ok := containerStats[ctr.ID()]
- if !ok {
- prev = &define.ContainerStats{}
- }
-
- stats, err := ctr.GetContainerStats(prev)
+ stats, err := ctr.GetContainerStats(containerStats[ctr.ID()])
if err != nil {
cause := errors.Cause(err)
if queryAll && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 308a1d0ee..a7555d715 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -33,12 +33,12 @@ import (
v1 "k8s.io/api/core/v1"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
report := &entities.PlayKubeReport{}
validKinds := 0
// read yaml document
- content, err := ioutil.ReadFile(path)
+ content, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
@@ -52,7 +52,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
// sort kube kinds
documentList, err = sortKubeKinds(documentList)
if err != nil {
- return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path)
+ return nil, errors.Wrap(err, "unable to sort kube kinds")
}
ipIndex := 0
@@ -64,7 +64,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
for _, document := range documentList {
kind, err := getKubeKind(document)
if err != nil {
- return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
+ return nil, errors.Wrap(err, "unable to read kube YAML")
}
switch kind {
@@ -73,7 +73,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var podTemplateSpec v1.PodTemplateSpec
if err := yaml.Unmarshal(document, &podYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Pod")
}
podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
@@ -90,7 +90,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Deployment")
}
r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps)
@@ -104,7 +104,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var pvcYAML v1.PersistentVolumeClaim
if err := yaml.Unmarshal(document, &pvcYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube PersistentVolumeClaim", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube PersistentVolumeClaim")
}
r, err := ic.playKubePVC(ctx, &pvcYAML, options)
@@ -118,7 +118,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var configMap v1.ConfigMap
if err := yaml.Unmarshal(document, &configMap); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube ConfigMap", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube ConfigMap")
}
configMaps = append(configMaps, configMap)
default:
@@ -356,7 +356,13 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return nil, err
}
+ ctrNames := make(map[string]string)
for _, initCtr := range podYAML.Spec.InitContainers {
+ // Error out if same name is used for more than one container
+ if _, ok := ctrNames[initCtr.Name]; ok {
+ return nil, errors.Errorf("the pod %q is invalid; duplicate container name %q detected", podName, initCtr.Name)
+ }
+ ctrNames[initCtr.Name] = ""
// Init containers cannot have either of lifecycle, livenessProbe, readinessProbe, or startupProbe set
if initCtr.Lifecycle != nil || initCtr.LivenessProbe != nil || initCtr.ReadinessProbe != nil || initCtr.StartupProbe != nil {
return nil, errors.Errorf("cannot create an init container that has either of lifecycle, livenessProbe, readinessProbe, or startupProbe set")
@@ -400,6 +406,11 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
for _, container := range podYAML.Spec.Containers {
if !strings.Contains("infra", container.Name) {
+ // Error out if the same name is used for more than one container
+ if _, ok := ctrNames[container.Name]; ok {
+ return nil, errors.Errorf("the pod %q is invalid; duplicate container name %q detected", podName, container.Name)
+ }
+ ctrNames[container.Name] = ""
pulledImage, labels, err := ic.getImageAndLabelInfo(ctx, cwd, annotations, writer, container, options)
if err != nil {
return nil, err
@@ -735,14 +746,14 @@ func getBuildFile(imageName string, cwd string) (string, error) {
return "", err
}
-func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
var (
podNames []string
)
reports := new(entities.PlayKubeReport)
// read yaml document
- content, err := ioutil.ReadFile(path)
+ content, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
@@ -756,27 +767,27 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ enti
// sort kube kinds
documentList, err = sortKubeKinds(documentList)
if err != nil {
- return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path)
+ return nil, errors.Wrap(err, "unable to sort kube kinds")
}
for _, document := range documentList {
kind, err := getKubeKind(document)
if err != nil {
- return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
+ return nil, errors.Wrap(err, "unable to read as kube YAML")
}
switch kind {
case "Pod":
var podYAML v1.Pod
if err := yaml.Unmarshal(document, &podYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Pod")
}
podNames = append(podNames, podYAML.ObjectMeta.Name)
case "Deployment":
var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Deployment")
}
var numReplicas int32 = 1
deploymentName := deploymentYAML.ObjectMeta.Name
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index d12d14c1f..4361821d5 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -6,7 +6,6 @@ import (
"net/url"
"os"
"os/exec"
- "path/filepath"
"github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/config"
@@ -269,7 +268,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
}
dfVolumes := make([]*entities.SystemDfVolumeReport, 0, len(vols))
- var reclaimableSize int64
+ var reclaimableSize uint64
for _, v := range vols {
var consInUse int
mountPoint, err := v.MountPoint()
@@ -282,7 +281,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
// TODO: fix this.
continue
}
- volSize, err := sizeOfPath(mountPoint)
+ volSize, err := util.SizeOfPath(mountPoint)
if err != nil {
return nil, err
}
@@ -301,8 +300,8 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
report := entities.SystemDfVolumeReport{
VolumeName: v.Name(),
Links: consInUse,
- Size: volSize,
- ReclaimableSize: reclaimableSize,
+ Size: int64(volSize),
+ ReclaimableSize: int64(reclaimableSize),
}
dfVolumes = append(dfVolumes, &report)
}
@@ -313,19 +312,6 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
}, nil
}
-// sizeOfPath determines the file usage of a given path. it was called volumeSize in v1
-// and now is made to be generic and take a path instead of a libpod volume
-func sizeOfPath(path string) (int64, error) {
- var size int64
- err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
- if err == nil && !info.IsDir() {
- size += info.Size()
- }
- return err
- })
- return size, err
-}
-
func (se *SystemEngine) Reset(ctx context.Context) error {
return se.Libpod.Reset(ctx)
}
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index 55844730b..24b4cf08b 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -2,13 +2,14 @@ package tunnel
import (
"context"
+ "io"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/bindings/play"
"github.com/containers/podman/v4/pkg/domain/entities"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password)
options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps)
options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Networks).WithSeccompProfileRoot(opts.SeccompProfileRoot)
@@ -23,9 +24,9 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entit
if start := opts.Start; start != types.OptionalBoolUndefined {
options.WithStart(start == types.OptionalBoolTrue)
}
- return play.Kube(ic.ClientCtx, path, options)
+ return play.KubeWithBody(ic.ClientCtx, body, options)
}
-func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
- return play.KubeDown(ic.ClientCtx, path)
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+ return play.KubeDownWithBody(ic.ClientCtx, body)
}
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index b2dabb689..fe47437e3 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -6,6 +6,7 @@ package machine
import (
"encoding/json"
"fmt"
+ "io/fs"
"io/ioutil"
"net/url"
"os"
@@ -507,8 +508,8 @@ func getCerts(certsDir string, isDir bool) []File {
)
if isDir {
- err := filepath.Walk(certsDir, func(path string, info os.FileInfo, err error) error {
- if err == nil && !info.IsDir() {
+ err := filepath.WalkDir(certsDir, func(path string, d fs.DirEntry, err error) error {
+ if err == nil && !d.IsDir() {
certPath, err := filepath.Rel(certsDir, path)
if err != nil {
logrus.Warnf("%s", err)
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index faf01b9ad..9ada26b9a 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -98,7 +98,7 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
return nil, err
}
- cmd := append([]string{execPath})
+ cmd := []string{execPath}
// Add memory
cmd = append(cmd, []string{"-m", strconv.Itoa(int(vm.Memory))}...)
// Add cpus
@@ -428,13 +428,29 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
// Disable graphic window when not in debug mode
// Done in start, so we're not suck with the debug level we used on init
- if logrus.GetLevel() != logrus.DebugLevel {
+ if !logrus.IsLevelEnabled(logrus.DebugLevel) {
cmd = append(cmd, "-display", "none")
}
_, err = os.StartProcess(v.CmdLine[0], cmd, attr)
if err != nil {
- return err
+ // check if qemu was not found
+ if !errors.Is(err, os.ErrNotExist) {
+ return err
+ }
+ // lookup qemu again maybe the path was changed, https://github.com/containers/podman/issues/13394
+ cfg, err := config.Default()
+ if err != nil {
+ return err
+ }
+ cmd[0], err = cfg.FindHelperBinary(QemuCommand, true)
+ if err != nil {
+ return err
+ }
+ _, err = os.StartProcess(cmd[0], cmd, attr)
+ if err != nil {
+ return err
+ }
}
fmt.Println("Waiting for VM ...")
socketPath, err := getRuntimeDir()
@@ -697,6 +713,11 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
if !opts.SaveImage {
files = append(files, v.ImagePath)
}
+ socketPath, err := v.getForwardSocketPath()
+ if err != nil {
+ logrus.Error(err)
+ }
+ files = append(files, socketPath)
files = append(files, v.archRemovalFiles()...)
if err := machine.RemoveConnection(v.Name); err != nil {
@@ -773,7 +794,7 @@ func (v *MachineVM) isRunning() (bool, error) {
func (v *MachineVM) isListening() bool {
// Check if we can dial it
- conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "localhost", v.Port), 10*time.Millisecond)
+ conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", v.Port), 10*time.Millisecond)
if err != nil {
return false
}
@@ -870,10 +891,10 @@ func GetVMInfos() ([]*machine.ListResponse, error) {
var listed []*machine.ListResponse
- if err = filepath.Walk(vmConfigDir, func(path string, info os.FileInfo, err error) error {
+ if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
vm := new(MachineVM)
- if strings.HasSuffix(info.Name(), ".json") {
- fullPath := filepath.Join(vmConfigDir, info.Name())
+ if strings.HasSuffix(d.Name(), ".json") {
+ fullPath := filepath.Join(vmConfigDir, d.Name())
b, err := ioutil.ReadFile(fullPath)
if err != nil {
return err
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index 5b0c757f0..5128fa313 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"net/url"
"os"
@@ -1175,10 +1176,10 @@ func GetVMInfos() ([]*machine.ListResponse, error) {
var listed []*machine.ListResponse
- if err = filepath.Walk(vmConfigDir, func(path string, info os.FileInfo, err error) error {
+ if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
vm := new(MachineVM)
- if strings.HasSuffix(info.Name(), ".json") {
- fullPath := filepath.Join(vmConfigDir, info.Name())
+ if strings.HasSuffix(d.Name(), ".json") {
+ fullPath := filepath.Join(vmConfigDir, d.Name())
b, err := ioutil.ReadFile(fullPath)
if err != nil {
return err
diff --git a/pkg/signal/signal_unix.go b/pkg/signal/signal_unix.go
new file mode 100644
index 000000000..f35abddc1
--- /dev/null
+++ b/pkg/signal/signal_unix.go
@@ -0,0 +1,99 @@
+// +build aix darwin dragonfly freebsd netbsd openbsd solaris zos
+
+// Signal handling for Linux only.
+package signal
+
+import (
+ "os"
+ "syscall"
+)
+
+const (
+ sigrtmin = 34
+ sigrtmax = 64
+
+ SIGWINCH = syscall.SIGWINCH
+)
+
+// signalMap is a map of Linux signals.
+// These constants are sourced from the Linux version of golang.org/x/sys/unix
+// (I don't see much risk of this changing).
+// This should work as long as Podman only runs containers on Linux, which seems
+// a safe assumption for now.
+var signalMap = map[string]syscall.Signal{
+ "ABRT": syscall.Signal(0x6),
+ "ALRM": syscall.Signal(0xe),
+ "BUS": syscall.Signal(0x7),
+ "CHLD": syscall.Signal(0x11),
+ "CLD": syscall.Signal(0x11),
+ "CONT": syscall.Signal(0x12),
+ "FPE": syscall.Signal(0x8),
+ "HUP": syscall.Signal(0x1),
+ "ILL": syscall.Signal(0x4),
+ "INT": syscall.Signal(0x2),
+ "IO": syscall.Signal(0x1d),
+ "IOT": syscall.Signal(0x6),
+ "KILL": syscall.Signal(0x9),
+ "PIPE": syscall.Signal(0xd),
+ "POLL": syscall.Signal(0x1d),
+ "PROF": syscall.Signal(0x1b),
+ "PWR": syscall.Signal(0x1e),
+ "QUIT": syscall.Signal(0x3),
+ "SEGV": syscall.Signal(0xb),
+ "STKFLT": syscall.Signal(0x10),
+ "STOP": syscall.Signal(0x13),
+ "SYS": syscall.Signal(0x1f),
+ "TERM": syscall.Signal(0xf),
+ "TRAP": syscall.Signal(0x5),
+ "TSTP": syscall.Signal(0x14),
+ "TTIN": syscall.Signal(0x15),
+ "TTOU": syscall.Signal(0x16),
+ "URG": syscall.Signal(0x17),
+ "USR1": syscall.Signal(0xa),
+ "USR2": syscall.Signal(0xc),
+ "VTALRM": syscall.Signal(0x1a),
+ "WINCH": syscall.Signal(0x1c),
+ "XCPU": syscall.Signal(0x18),
+ "XFSZ": syscall.Signal(0x19),
+ "RTMIN": sigrtmin,
+ "RTMIN+1": sigrtmin + 1,
+ "RTMIN+2": sigrtmin + 2,
+ "RTMIN+3": sigrtmin + 3,
+ "RTMIN+4": sigrtmin + 4,
+ "RTMIN+5": sigrtmin + 5,
+ "RTMIN+6": sigrtmin + 6,
+ "RTMIN+7": sigrtmin + 7,
+ "RTMIN+8": sigrtmin + 8,
+ "RTMIN+9": sigrtmin + 9,
+ "RTMIN+10": sigrtmin + 10,
+ "RTMIN+11": sigrtmin + 11,
+ "RTMIN+12": sigrtmin + 12,
+ "RTMIN+13": sigrtmin + 13,
+ "RTMIN+14": sigrtmin + 14,
+ "RTMIN+15": sigrtmin + 15,
+ "RTMAX-14": sigrtmax - 14,
+ "RTMAX-13": sigrtmax - 13,
+ "RTMAX-12": sigrtmax - 12,
+ "RTMAX-11": sigrtmax - 11,
+ "RTMAX-10": sigrtmax - 10,
+ "RTMAX-9": sigrtmax - 9,
+ "RTMAX-8": sigrtmax - 8,
+ "RTMAX-7": sigrtmax - 7,
+ "RTMAX-6": sigrtmax - 6,
+ "RTMAX-5": sigrtmax - 5,
+ "RTMAX-4": sigrtmax - 4,
+ "RTMAX-3": sigrtmax - 3,
+ "RTMAX-2": sigrtmax - 2,
+ "RTMAX-1": sigrtmax - 1,
+ "RTMAX": sigrtmax,
+}
+
+// CatchAll catches all signals and relays them to the specified channel.
+func CatchAll(sigc chan os.Signal) {
+ panic("Unsupported on non-linux platforms")
+}
+
+// StopCatch stops catching the signals and closes the specified channel.
+func StopCatch(sigc chan os.Signal) {
+ panic("Unsupported on non-linux platforms")
+}
diff --git a/pkg/signal/signal_unsupported.go b/pkg/signal/signal_unsupported.go
index 9d1733c02..45946f142 100644
--- a/pkg/signal/signal_unsupported.go
+++ b/pkg/signal/signal_unsupported.go
@@ -1,4 +1,4 @@
-// +build !linux
+// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!zos
// Signal handling for Linux only.
package signal
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index a5772bc6a..449d8e4e0 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -2,6 +2,7 @@ package generate
import (
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"path"
@@ -101,8 +102,8 @@ func DevicesFromPath(g *generate.Generator, devicePath string) error {
}
// mount the internal devices recursively
- if err := filepath.Walk(resolvedDevicePath, func(dpath string, f os.FileInfo, e error) error {
- if f.Mode()&os.ModeDevice == os.ModeDevice {
+ if err := filepath.WalkDir(resolvedDevicePath, func(dpath string, d fs.DirEntry, e error) error {
+ if d.Type()&os.ModeDevice == os.ModeDevice {
found = true
device := fmt.Sprintf("%s:%s", dpath, filepath.Join(dest, strings.TrimPrefix(dpath, src)))
if devmode != "" {
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index a7a7353d0..28c31c7eb 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -267,7 +267,16 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
"/usr/sbin/init": true,
"/usr/local/sbin/init": true,
}
- if useSystemdCommands[command[0]] || (filepath.Base(command[0]) == "systemd") {
+ // Grab last command incase this is launched from a shell
+ cmd := command
+ if len(command) > 2 {
+ // Podman build will add "/bin/sh" "-c" to
+ // Entrypoint. Remove and search for systemd
+ if command[0] == "/bin/sh" && command[1] == "-c" {
+ cmd = command[2:]
+ }
+ }
+ if useSystemdCommands[cmd[0]] || (filepath.Base(cmd[0]) == "systemd") {
useSystemd = true
}
}
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 68fda3ad7..279507f4c 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -56,6 +56,7 @@ ENTRYPOINT ["/catatonit", "-P"]`, catatonitPath)
CommonBuildOpts: &buildahDefine.CommonBuildOptions{},
Output: imageName,
Quiet: true,
+ IgnoreFile: "/dev/null", // makes sure to not read a local .ignorefile (see #13529)
IIDFile: "/dev/null", // prevents Buildah from writing the ID on stdout
}
if _, _, err := rt.Build(context.Background(), buildOptions, tmpF.Name()); err != nil {
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index a6f8f7cd4..e53d37897 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -137,3 +137,17 @@ func removeArg(arg string, args []string) []string {
}
return newArgs
}
+
+// This function is used to get name of systemd service from prefix, separator, and
+// container/pod name. If prefix is empty, the service name does not include the
+// separator. This is to avoid a situation where service name starts with the separator
+// which is usually hyphen.
+func getServiceName(prefix string, separator string, name string) string {
+ serviceName := name
+
+ if len(prefix) > 0 {
+ serviceName = prefix + separator + name
+ }
+
+ return serviceName
+}
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index ea829c810..c01bb1baf 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -236,7 +236,9 @@ func containerServiceName(ctr *libpod.Container, options entities.GenerateSystem
if options.Name {
nameOrID = ctr.Name()
}
- serviceName := fmt.Sprintf("%s%s%s", options.ContainerPrefix, options.Separator, nameOrID)
+
+ serviceName := getServiceName(options.ContainerPrefix, options.Separator, nameOrID)
+
return nameOrID, serviceName
}
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index 2f653a4b9..b9bf7c317 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -91,6 +91,30 @@ Type=forking
WantedBy=default.target
`
+ goodNameEmptyContainerPrefix := `# foobar.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman foobar.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
+ExecStart=/usr/bin/podman start foobar
+ExecStop=/usr/bin/podman stop -t 10 foobar
+ExecStopPost=/usr/bin/podman stop -t 10 foobar
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+Type=forking
+
+[Install]
+WantedBy=default.target
+`
+
goodNameCustomWants := `# container-foobar.service
# autogenerated by Podman CI
@@ -1206,6 +1230,24 @@ WantedBy=default.target
false,
true,
},
+ {"good with name and empty container-prefix",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "foobar",
+ ContainerNameOrID: "foobar",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ EnvVariable: define.EnvVariable,
+ GraphRoot: "/var/lib/containers/storage",
+ RunRoot: "/var/run/containers/storage",
+ },
+ goodNameEmptyContainerPrefix,
+ false,
+ false,
+ false,
+ false,
+ },
}
for _, tt := range tests {
test := tt
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index 003c23e77..78ae6391b 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -242,7 +242,8 @@ func generatePodInfo(pod *libpod.Pod, options entities.GenerateSystemdOptions) (
nameOrID = pod.Name()
ctrNameOrID = infraCtr.Name()
}
- serviceName := fmt.Sprintf("%s%s%s", options.PodPrefix, options.Separator, nameOrID)
+
+ serviceName := getServiceName(options.PodPrefix, options.Separator, nameOrID)
info := podInfo{
ServiceName: serviceName,
diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go
index b37e0825b..dcb18780c 100644
--- a/pkg/systemd/generate/pods_test.go
+++ b/pkg/systemd/generate/pods_test.go
@@ -67,6 +67,32 @@ WantedBy=default.target
podGood := serviceInfo + headerInfo + podContent
podGoodNoHeaderInfo := serviceInfo + podContent
+ podGoodWithEmptyPrefix := `# 123abc.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman 123abc.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network-online.target
+After=network-online.target
+RequiresMountsFor=/var/run/containers/storage
+Requires=container-1.service container-2.service
+Before=container-1.service container-2.service
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=on-failure
+TimeoutStopSec=102
+ExecStart=/usr/bin/podman start jadda-jadda-infra
+ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra
+ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+Type=forking
+
+[Install]
+WantedBy=default.target
+`
+
podGoodCustomWants := `# pod-123abc.service
# autogenerated by Podman CI
@@ -580,6 +606,24 @@ WantedBy=default.target
false,
false,
},
+ {"pod with empty pod-prefix",
+ podInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "123abc",
+ InfraNameOrID: "jadda-jadda-infra",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ GraphRoot: "/var/lib/containers/storage",
+ RunRoot: "/var/run/containers/storage",
+ RequiredServices: []string{"container-1", "container-2"},
+ CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "bar=arg with space"},
+ },
+ podGoodWithEmptyPrefix,
+ false,
+ false,
+ false,
+ },
}
for _, tt := range tests {
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 925ff9830..be2ed2d02 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -3,6 +3,7 @@ package util
import (
"encoding/json"
"fmt"
+ "io/fs"
"math"
"os"
"os/user"
@@ -731,3 +732,20 @@ func LookupUser(name string) (*user.User, error) {
}
return user.Lookup(name)
}
+
+// SizeOfPath determines the file usage of a given path. it was called volumeSize in v1
+// and now is made to be generic and take a path instead of a libpod volume
+func SizeOfPath(path string) (uint64, error) {
+ var size uint64
+ err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
+ if err == nil && !d.IsDir() {
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
+ size += uint64(info.Size())
+ }
+ return err
+ })
+ return size, err
+}
diff --git a/pkg/util/utils_linux.go b/pkg/util/utils_linux.go
index 288137ca5..dcfda4e1a 100644
--- a/pkg/util/utils_linux.go
+++ b/pkg/util/utils_linux.go
@@ -2,6 +2,7 @@ package util
import (
"fmt"
+ "io/fs"
"os"
"path/filepath"
"syscall"
@@ -23,17 +24,21 @@ func GetContainerPidInformationDescriptors() ([]string, error) {
// Symlinks to nodes are ignored.
func FindDeviceNodes() (map[string]string, error) {
nodes := make(map[string]string)
- err := filepath.Walk("/dev", func(path string, info os.FileInfo, err error) error {
+ err := filepath.WalkDir("/dev", func(path string, d fs.DirEntry, err error) error {
if err != nil {
logrus.Warnf("Error descending into path %s: %v", path, err)
return filepath.SkipDir
}
// If we aren't a device node, do nothing.
- if info.Mode()&(os.ModeDevice|os.ModeCharDevice) == 0 {
+ if d.Type()&(os.ModeDevice|os.ModeCharDevice) == 0 {
return nil
}
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
// We are a device node. Get major/minor.
sysstat, ok := info.Sys().(*syscall.Stat_t)
if !ok {