summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/exec.go2
-rw-r--r--pkg/domain/infra/abi/play.go17
-rw-r--r--pkg/machine/config.go3
-rw-r--r--pkg/machine/ignition.go28
-rw-r--r--pkg/machine/pull.go4
-rw-r--r--pkg/machine/qemu/config.go7
-rw-r--r--pkg/machine/qemu/machine.go70
-rw-r--r--pkg/machine/qemu/options_darwin_arm64.go1
-rw-r--r--pkg/specgen/generate/oci.go6
-rw-r--r--pkg/util/utils.go2
-rw-r--r--pkg/util/utils_supported.go50
11 files changed, 161 insertions, 29 deletions
diff --git a/pkg/api/handlers/compat/exec.go b/pkg/api/handlers/compat/exec.go
index c6f7e0318..def16d1b5 100644
--- a/pkg/api/handlers/compat/exec.go
+++ b/pkg/api/handlers/compat/exec.go
@@ -73,7 +73,7 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
// Run the exit command after 5 minutes, to mimic Docker's exec cleanup
// behavior.
- libpodConfig.ExitCommandDelay = 5 * 60
+ libpodConfig.ExitCommandDelay = runtimeConfig.Engine.ExitCommandDelay
sessID, err := ctr.ExecCreate(libpodConfig)
if err != nil {
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 213d8ceb7..155b06105 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -28,7 +28,7 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- yamlv3 "gopkg.in/yaml.v3"
+ yamlv2 "gopkg.in/yaml.v2"
v1apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
)
@@ -365,7 +365,13 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
}
+ 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")
@@ -414,6 +420,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
@@ -650,7 +661,7 @@ func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) {
func splitMultiDocYAML(yamlContent []byte) ([][]byte, error) {
var documentList [][]byte
- d := yamlv3.NewDecoder(bytes.NewReader(yamlContent))
+ d := yamlv2.NewDecoder(bytes.NewReader(yamlContent))
for {
var o interface{}
// read individual document
@@ -664,7 +675,7 @@ func splitMultiDocYAML(yamlContent []byte) ([][]byte, error) {
if o != nil {
// back to bytes
- document, err := yamlv3.Marshal(o)
+ document, err := yamlv2.Marshal(o)
if err != nil {
return nil, errors.Wrapf(err, "individual doc yaml could not be marshalled")
}
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index efb1eda15..b3b105150 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -1,3 +1,4 @@
+//go:build amd64 || arm64
// +build amd64 arm64
package machine
@@ -28,6 +29,8 @@ type InitOptions struct {
Username string
ReExec bool
Rootful bool
+ // The numberical userid of the user that called machine
+ UID string
}
type QemuMachineStatus = string
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index 47b1836f0..b2dabb689 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -51,6 +51,7 @@ type DynamicIgnition struct {
Name string
Key string
TimeZone string
+ UID int
VMName string
WritePath string
}
@@ -63,12 +64,13 @@ func NewIgnitionFile(ign DynamicIgnition) error {
ignVersion := Ignition{
Version: "3.2.0",
}
-
ignPassword := Passwd{
Users: []PasswdUser{
{
Name: ign.Name,
SSHAuthorizedKeys: []SSHAuthorizedKey{SSHAuthorizedKey(ign.Key)},
+ // Set the UID of the core user inside the machine
+ UID: intToPtr(ign.UID),
},
{
Name: "root",
@@ -289,9 +291,7 @@ func getDirs(usrName string) []Directory {
}
func getFiles(usrName string) []File {
- var (
- files []File
- )
+ files := make([]File, 0)
lingerExample := `[Unit]
Description=A systemd user unit demo
@@ -310,6 +310,7 @@ machine_enabled=true
delegateConf := `[Service]
Delegate=memory pids cpu io
`
+ subUID := `%s:100000:1000000`
// Add a fake systemd service to get the user socket rolling
files = append(files, File{
@@ -344,6 +345,25 @@ Delegate=memory pids cpu io
},
})
+ // Setup /etc/subuid and /etc/subgid
+ for _, sub := range []string{"/etc/subuid", "/etc/subgid"} {
+ files = append(files, File{
+ Node: Node{
+ Group: getNodeGrp("root"),
+ Path: sub,
+ User: getNodeUsr("root"),
+ Overwrite: boolToPtr(true),
+ },
+ FileEmbedded1: FileEmbedded1{
+ Append: nil,
+ Contents: Resource{
+ Source: encodeDataURLPtr(fmt.Sprintf(subUID, usrName)),
+ },
+ Mode: intToPtr(0744),
+ },
+ })
+ }
+
// Set delegate.conf so cpu,io subsystem is delegated to non-root users as well for cgroupv2
// by default
files = append(files, File{
diff --git a/pkg/machine/pull.go b/pkg/machine/pull.go
index 280b47f96..cf1e708b1 100644
--- a/pkg/machine/pull.go
+++ b/pkg/machine/pull.go
@@ -19,8 +19,8 @@ import (
"github.com/containers/storage/pkg/archive"
"github.com/sirupsen/logrus"
"github.com/ulikunitz/xz"
- "github.com/vbauerster/mpb/v6"
- "github.com/vbauerster/mpb/v6/decor"
+ "github.com/vbauerster/mpb/v7"
+ "github.com/vbauerster/mpb/v7/decor"
)
// GenericDownload is used when a user provides a URL
diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go
index c619b7dd4..b39334be0 100644
--- a/pkg/machine/qemu/config.go
+++ b/pkg/machine/qemu/config.go
@@ -1,8 +1,11 @@
+//go:build (amd64 && !windows) || (arm64 && !windows)
// +build amd64,!windows arm64,!windows
package qemu
-import "time"
+import (
+ "time"
+)
type Provider struct{}
@@ -35,6 +38,8 @@ type MachineVM struct {
RemoteUsername string
// Whether this machine should run in a rootful or rootless manner
Rootful bool
+ // UID is the numerical id of the user that called machine
+ UID int
}
type Mount struct {
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 9beec2173..3b4548c17 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -88,11 +88,16 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
vm.Memory = opts.Memory
vm.DiskSize = opts.DiskSize
- // Look up the executable
- execPath, err := exec.LookPath(QemuCommand)
+ // Find the qemu executable
+ cfg, err := config.Default()
+ if err != nil {
+ return nil, err
+ }
+ execPath, err := cfg.FindHelperBinary(QemuCommand, true)
if err != nil {
return nil, err
}
+
cmd := append([]string{execPath})
// Add memory
cmd = append(cmd, []string{"-m", strconv.Itoa(int(vm.Memory))}...)
@@ -245,12 +250,13 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
}
}
v.Mounts = mounts
+ v.UID = os.Getuid()
// Add location of bootable image
v.CmdLine = append(v.CmdLine, "-drive", "if=virtio,file="+v.ImagePath)
// This kind of stinks but no other way around this r/n
if len(opts.IgnitionPath) < 1 {
- uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/user/1000/podman/podman.sock", strconv.Itoa(v.Port), v.RemoteUsername)
+ uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", fmt.Sprintf("/run/user/%d/podman/podman.sock", v.UID), strconv.Itoa(v.Port), v.RemoteUsername)
uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root")
identity := filepath.Join(sshDir, v.Name)
@@ -296,7 +302,16 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
// only if the virtualdisk size is less than
// the given disk size
if opts.DiskSize<<(10*3) > originalDiskSize {
- resize := exec.Command("qemu-img", []string{"resize", v.ImagePath, strconv.Itoa(int(opts.DiskSize)) + "G"}...)
+ // Find the qemu executable
+ cfg, err := config.Default()
+ if err != nil {
+ return false, err
+ }
+ resizePath, err := cfg.FindHelperBinary("qemu-img", true)
+ if err != nil {
+ return false, err
+ }
+ resize := exec.Command(resizePath, []string{"resize", v.ImagePath, strconv.Itoa(int(opts.DiskSize)) + "G"}...)
resize.Stdout = os.Stdout
resize.Stderr = os.Stderr
if err := resize.Run(); err != nil {
@@ -319,6 +334,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
VMName: v.Name,
TimeZone: opts.TimeZone,
WritePath: v.IgnitionFilePath,
+ UID: v.UID,
}
err = machine.NewIgnitionFile(ign)
return err == nil, err
@@ -459,7 +475,17 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
for _, mount := range v.Mounts {
fmt.Printf("Mounting volume... %s:%s\n", mount.Source, mount.Target)
// create mountpoint directory if it doesn't exist
- err = v.SSH(name, machine.SSHOptions{Args: []string{"-q", "--", "sudo", "mkdir", "-p", mount.Target}})
+ // because / is immutable, we have to monkey around with permissions
+ // if we dont mount in /home or /mnt
+ args := []string{"-q", "--"}
+ if !strings.HasPrefix(mount.Target, "/home") || !strings.HasPrefix(mount.Target, "/mnt") {
+ args = append(args, "sudo", "chattr", "-i", "/", ";")
+ }
+ args = append(args, "sudo", "mkdir", "-p", mount.Target)
+ if !strings.HasPrefix(mount.Target, "/home") || !strings.HasPrefix(mount.Target, "/mnt") {
+ args = append(args, ";", "sudo", "chattr", "+i", "/", ";")
+ }
+ err = v.SSH(name, machine.SSHOptions{Args: args})
if err != nil {
return err
}
@@ -653,7 +679,7 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
if err != nil {
return "", nil, err
}
- if running {
+ if running && !opts.Force {
return "", nil, errors.Errorf("running vm %q cannot be destroyed", v.Name)
}
@@ -667,6 +693,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 {
@@ -790,7 +821,16 @@ func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {
// executes qemu-image info to get the virtual disk size
// of the diskimage
func getDiskSize(path string) (uint64, error) {
- diskInfo := exec.Command("qemu-img", "info", "--output", "json", path)
+ // Find the qemu executable
+ cfg, err := config.Default()
+ if err != nil {
+ return 0, err
+ }
+ qemuPathDir, err := cfg.FindHelperBinary("qemu-img", true)
+ if err != nil {
+ return 0, err
+ }
+ diskInfo := exec.Command(qemuPathDir, "info", "--output", "json", path)
stdout, err := diskInfo.StdoutPipe()
if err != nil {
return 0, err
@@ -952,7 +992,7 @@ func (v *MachineVM) setupAPIForwarding(cmd []string) ([]string, string, apiForwa
return cmd, "", noForwarding
}
- destSock := "/run/user/1000/podman/podman.sock"
+ destSock := fmt.Sprintf("/run/user/%d/podman/podman.sock", v.UID)
forwardUser := "core"
if v.Rootful {
@@ -1064,16 +1104,15 @@ func waitAndPingAPI(sock string) {
func waitAPIAndPrintInfo(forwardState apiForwardingState, forwardSock string, rootFul bool, name string) {
if forwardState != noForwarding {
+ suffix := ""
+ if name != machine.DefaultMachineName {
+ suffix = " " + name
+ }
waitAndPingAPI(forwardSock)
if !rootFul {
fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n")
fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n")
fmt.Printf("issues with non-podman clients, you can switch using the following command: \n")
-
- suffix := ""
- if name != machine.DefaultMachineName {
- suffix = " " + name
- }
fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix)
}
@@ -1087,8 +1126,9 @@ func waitAPIAndPrintInfo(forwardState apiForwardingState, forwardSock string, ro
fmt.Printf("\nThe system helper service is not installed; the default Docker API socket\n")
fmt.Printf("address can't be used by podman. ")
if helper := findClaimHelper(); len(helper) > 0 {
- fmt.Printf("If you would like to install it run the\nfollowing command:\n")
- fmt.Printf("\n\tsudo %s install\n\n", helper)
+ fmt.Printf("If you would like to install it run the\nfollowing commands:\n")
+ fmt.Printf("\n\tsudo %s install\n", helper)
+ fmt.Printf("\tpodman machine stop%s; podman machine start%s\n\n", suffix, suffix)
}
case machineLocal:
fmt.Printf("\nAnother process was listening on the default Docker API socket address.\n")
diff --git a/pkg/machine/qemu/options_darwin_arm64.go b/pkg/machine/qemu/options_darwin_arm64.go
index 727a275d2..5b6cdc86d 100644
--- a/pkg/machine/qemu/options_darwin_arm64.go
+++ b/pkg/machine/qemu/options_darwin_arm64.go
@@ -45,6 +45,7 @@ func getOvmfDir(imagePath, vmName string) string {
*/
func getEdk2CodeFd(name string) string {
dirs := []string{
+ "/opt/homebrew/opt/podman/libexec/share/qemu",
"/usr/local/share/qemu",
"/opt/homebrew/share/qemu",
}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 8b3550e36..1cc3a463f 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -332,6 +332,11 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
// Devices
+ // set the default rule at the beginning of device configuration
+ if !inUserNS && !s.Privileged {
+ g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
+ }
+
var userDevices []spec.LinuxDevice
if s.Privileged {
// If privileged, we need to add all the host devices to the
@@ -363,7 +368,6 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
// set the devices cgroup when not running in a user namespace
if !inUserNS && !s.Privileged {
- g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
for _, dev := range s.DeviceCgroupRule {
g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index bdd1e1383..925ff9830 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -463,6 +463,8 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
var (
rootlessConfigHomeDirOnce sync.Once
rootlessConfigHomeDir string
+ rootlessRuntimeDirOnce sync.Once
+ rootlessRuntimeDir string
)
type tomlOptionsConfig struct {
diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go
index e9d6bfa31..848b35a45 100644
--- a/pkg/util/utils_supported.go
+++ b/pkg/util/utils_supported.go
@@ -6,21 +6,67 @@ package util
// should work to take darwin from this
import (
+ "fmt"
"os"
"path/filepath"
"syscall"
- cutil "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// GetRuntimeDir returns the runtime directory
func GetRuntimeDir() (string, error) {
+ var rootlessRuntimeDirError error
+
if !rootless.IsRootless() {
return "", nil
}
- return cutil.GetRuntimeDir()
+
+ rootlessRuntimeDirOnce.Do(func() {
+ runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
+ uid := fmt.Sprintf("%d", rootless.GetRootlessUID())
+ if runtimeDir == "" {
+ tmpDir := filepath.Join("/run", "user", uid)
+ if err := os.MkdirAll(tmpDir, 0700); err != nil {
+ logrus.Debug(err)
+ }
+ st, err := os.Stat(tmpDir)
+ if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && (st.Mode().Perm()&0700 == 0700) {
+ runtimeDir = tmpDir
+ }
+ }
+ if runtimeDir == "" {
+ tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("podman-run-%s", uid))
+ if err := os.MkdirAll(tmpDir, 0700); err != nil {
+ logrus.Debug(err)
+ }
+ st, err := os.Stat(tmpDir)
+ if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && (st.Mode().Perm()&0700 == 0700) {
+ runtimeDir = tmpDir
+ }
+ }
+ if runtimeDir == "" {
+ home := os.Getenv("HOME")
+ if home == "" {
+ rootlessRuntimeDirError = fmt.Errorf("neither XDG_RUNTIME_DIR nor HOME was set non-empty")
+ return
+ }
+ resolvedHome, err := filepath.EvalSymlinks(home)
+ if err != nil {
+ rootlessRuntimeDirError = errors.Wrapf(err, "cannot resolve %s", home)
+ return
+ }
+ runtimeDir = filepath.Join(resolvedHome, "rundir")
+ }
+ rootlessRuntimeDir = runtimeDir
+ })
+
+ if rootlessRuntimeDirError != nil {
+ return "", rootlessRuntimeDirError
+ }
+ return rootlessRuntimeDir, nil
}
// GetRootlessConfigHomeDir returns the config home directory when running as non root