mirror of
https://github.com/containers/podman.git
synced 2025-08-06 11:32:07 +08:00
Resurrect auto-port reassignment, but for all providers
- Updates common to pull in new locked edit [NO NEW TESTS NEEDED] Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
This commit is contained in:
2
go.mod
2
go.mod
@ -11,7 +11,7 @@ require (
|
||||
github.com/checkpoint-restore/go-criu/v7 v7.0.0
|
||||
github.com/containernetworking/plugins v1.4.0
|
||||
github.com/containers/buildah v1.34.1-0.20240229193131-f5d7689ef4cd
|
||||
github.com/containers/common v0.57.1-0.20240229165734-cec09922602e
|
||||
github.com/containers/common v0.57.1-0.20240304165751-a0d555c70d52
|
||||
github.com/containers/conmon v2.0.20+incompatible
|
||||
github.com/containers/gvisor-tap-vsock v0.7.3
|
||||
github.com/containers/image/v5 v5.29.3-0.20240229213915-cdc68020a24f
|
||||
|
4
go.sum
4
go.sum
@ -76,8 +76,8 @@ github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7w
|
||||
github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0=
|
||||
github.com/containers/buildah v1.34.1-0.20240229193131-f5d7689ef4cd h1:4cHNzaywyyJsCAtwUKMZm8r/wqm/WuNC70GfnI3kh18=
|
||||
github.com/containers/buildah v1.34.1-0.20240229193131-f5d7689ef4cd/go.mod h1:3fn5edBIPpIOPJYdnxBdTF7bjnBHhqZwYK5a6ApNdyk=
|
||||
github.com/containers/common v0.57.1-0.20240229165734-cec09922602e h1:TPgCd6bWFyliJxCXEiCI1LnbB3kBUkpx1dw51ngDjWI=
|
||||
github.com/containers/common v0.57.1-0.20240229165734-cec09922602e/go.mod h1:8irlyBcVooYx0F+YmoY7PQPAIgdJvCj17bvL7PqeaxI=
|
||||
github.com/containers/common v0.57.1-0.20240304165751-a0d555c70d52 h1:+rq1qOOEv/2Sa1A9Tmv7yKuOzea8W2n6kFUH+bon61Y=
|
||||
github.com/containers/common v0.57.1-0.20240304165751-a0d555c70d52/go.mod h1:h92alKzSekxVC+VDaX4gt7RJpXvJKF79a9TnULZ5ZDc=
|
||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||
github.com/containers/gvisor-tap-vsock v0.7.3 h1:yORnf15sP+sLFhxLNLgmB5/lOhldn9dRMHx/tmYtSOQ=
|
||||
|
@ -313,6 +313,11 @@ func (a AppleHVStubber) StopHostNetworking(_ *vmconfigs.MachineConfig, _ define.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppleHVStubber) UpdateSSHPort(mc *vmconfigs.MachineConfig, port int) error {
|
||||
// managed by gvproxy on this backend, so nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppleHVStubber) VMType() define.VMType {
|
||||
return define.AppleHvVirt
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
//go:build amd64 || arm64
|
||||
|
||||
package connection
|
||||
|
||||
import (
|
||||
@ -14,19 +16,8 @@ func AddSSHConnectionsToPodmanSocket(uid, port int, identityPath, name, remoteUs
|
||||
fmt.Println("An ignition path was provided. No SSH connection was added to Podman")
|
||||
return nil
|
||||
}
|
||||
uri := makeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername)
|
||||
uriRoot := makeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root")
|
||||
|
||||
cons := []connection{
|
||||
{
|
||||
name: name,
|
||||
uri: uri,
|
||||
},
|
||||
{
|
||||
name: name + "-root",
|
||||
uri: uriRoot,
|
||||
},
|
||||
}
|
||||
cons := createConnections(name, uid, port, remoteUsername)
|
||||
|
||||
// The first connection defined when connections is empty will become the default
|
||||
// regardless of IsDefault, so order according to rootful
|
||||
@ -36,3 +27,19 @@ func AddSSHConnectionsToPodmanSocket(uid, port int, identityPath, name, remoteUs
|
||||
|
||||
return addConnection(cons, identityPath, opts.IsDefault)
|
||||
}
|
||||
|
||||
func createConnections(name string, uid, port int, remoteUsername string) []connection {
|
||||
uri := makeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername)
|
||||
uriRoot := makeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root")
|
||||
|
||||
return []connection{
|
||||
{
|
||||
name: name,
|
||||
uri: uri,
|
||||
},
|
||||
{
|
||||
name: name + "-root",
|
||||
uri: uriRoot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -55,14 +55,17 @@ func addConnection(cons []connection, identity string, isDefault bool) error {
|
||||
})
|
||||
}
|
||||
|
||||
func ChangeConnectionURI(name string, uri fmt.Stringer) error {
|
||||
func UpdateConnectionPairPort(name string, port, uid int, remoteUsername string, identityPath string) error {
|
||||
cons := createConnections(name, uid, port, remoteUsername)
|
||||
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||
dst, ok := cfg.Connection.Connections[name]
|
||||
if !ok {
|
||||
return errors.New("connection not found")
|
||||
for _, con := range cons {
|
||||
dst := config.Destination{
|
||||
IsMachine: true,
|
||||
URI: con.uri.String(),
|
||||
Identity: identityPath,
|
||||
}
|
||||
cfg.Connection.Connections[name] = dst
|
||||
}
|
||||
dst.URI = uri.String()
|
||||
cfg.Connection.Connections[name] = dst
|
||||
|
||||
return nil
|
||||
})
|
||||
|
@ -446,6 +446,11 @@ func (h HyperVStubber) PostStartNetworking(mc *vmconfigs.MachineConfig, noInfo b
|
||||
return err
|
||||
}
|
||||
|
||||
func (h HyperVStubber) UpdateSSHPort(mc *vmconfigs.MachineConfig, port int) error {
|
||||
// managed by gvproxy on this backend, so nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h HyperVStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
|
||||
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, h.VMType(), mc.Name)
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
//go:build amd64 || arm64
|
||||
|
||||
package ignition
|
||||
|
||||
import (
|
||||
|
@ -1,4 +1,4 @@
|
||||
//go:build !darwin
|
||||
//go:build linux || freebsd
|
||||
|
||||
package qemu
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//go:build windows && amd64
|
||||
//go:build tempoff
|
||||
|
||||
package qemu
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//go:build !darwin
|
||||
//go:build linux || freebsd
|
||||
|
||||
package qemu
|
||||
|
||||
@ -352,6 +352,11 @@ func (q *QEMUStubber) PostStartNetworking(mc *vmconfigs.MachineConfig, noInfo bo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *QEMUStubber) UpdateSSHPort(mc *vmconfigs.MachineConfig, port int) error {
|
||||
// managed by gvproxy on this backend, so nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *QEMUStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
|
||||
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, q.VMType(), mc.Name)
|
||||
}
|
||||
|
@ -11,8 +11,10 @@ import (
|
||||
"github.com/containers/common/pkg/config"
|
||||
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
||||
"github.com/containers/podman/v5/pkg/machine"
|
||||
"github.com/containers/podman/v5/pkg/machine/connection"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/containers/podman/v5/pkg/machine/env"
|
||||
"github.com/containers/podman/v5/pkg/machine/ports"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -91,6 +93,14 @@ func startHostForwarder(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvid
|
||||
}
|
||||
|
||||
func startNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) (string, machine.APIForwardingState, error) {
|
||||
// Check if SSH port is in use, and reassign if necessary
|
||||
if !ports.IsLocalPortAvailable(mc.SSH.Port) {
|
||||
logrus.Warnf("detected port conflict on machine ssh port [%d], reassigning", mc.SSH.Port)
|
||||
if err := reassignSSHPort(mc, provider); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// Provider has its own networking code path (e.g. WSL)
|
||||
if provider.UseProviderNetworkSetup() {
|
||||
return "", 0, provider.StartNetworking(mc, nil)
|
||||
@ -153,6 +163,53 @@ func conductVMReadinessCheck(mc *vmconfigs.MachineConfig, maxBackoffs int, backo
|
||||
return
|
||||
}
|
||||
|
||||
func reassignSSHPort(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) error {
|
||||
newPort, err := ports.AllocateMachinePort()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
success := false
|
||||
defer func() {
|
||||
if !success {
|
||||
if err := ports.ReleaseMachinePort(newPort); err != nil {
|
||||
logrus.Warnf("could not release port allocation as part of failure rollback (%d): %s", newPort, err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Write a transient invalid port, to force a retry on failure
|
||||
oldPort := mc.SSH.Port
|
||||
mc.SSH.Port = 0
|
||||
if err := mc.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ports.ReleaseMachinePort(oldPort); err != nil {
|
||||
logrus.Warnf("could not release current ssh port allocation (%d): %s", oldPort, err.Error())
|
||||
}
|
||||
|
||||
// Update the backend's settings if relevant (e.g. WSL)
|
||||
if err := provider.UpdateSSHPort(mc, newPort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mc.SSH.Port = newPort
|
||||
if err := connection.UpdateConnectionPairPort(mc.Name, newPort, mc.HostUser.UID, mc.SSH.RemoteUsername, mc.SSH.IdentityPath); err != nil {
|
||||
return fmt.Errorf("could not update remote connection configuration: %w", err)
|
||||
}
|
||||
|
||||
// Write updated port back
|
||||
if err := mc.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// inform defer routine not to release the port
|
||||
success = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isListening(port int) bool {
|
||||
// Check if we can dial it
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", port), 10*time.Millisecond)
|
||||
|
@ -96,6 +96,7 @@ type VMProvider interface { //nolint:interfacebloat
|
||||
UserModeNetworkEnabled(mc *MachineConfig) bool
|
||||
UseProviderNetworkSetup() bool
|
||||
RequireExclusiveActive() bool
|
||||
UpdateSSHPort(mc *MachineConfig, port int) error
|
||||
}
|
||||
|
||||
// HostUser describes the host user
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"github.com/containers/podman/v5/pkg/machine/connection"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/containers/podman/v5/pkg/machine/lock"
|
||||
"github.com/containers/podman/v5/utils"
|
||||
"github.com/containers/podman/v5/pkg/machine/ports"
|
||||
"github.com/containers/storage/pkg/ioutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -78,8 +78,7 @@ func NewMachineConfig(opts define.InitOptions, dirs *define.MachineDirs, sshIden
|
||||
}
|
||||
mc.Resources = mrc
|
||||
|
||||
// TODO WSL had a locking port mechanism, we should consider this.
|
||||
sshPort, err := utils.GetRandomPort()
|
||||
sshPort, err := ports.AllocateMachinePort()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -204,6 +203,11 @@ func (mc *MachineConfig) Remove(saveIgnition, saveImage bool) ([]string, func()
|
||||
if err := mc.configPath.Delete(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if err := ports.ReleaseMachinePort(mc.SSH.Port); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return errorhandling.JoinErrors(errs)
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman/v5/pkg/machine/ocipull"
|
||||
"github.com/containers/podman/v5/pkg/machine/ports"
|
||||
"github.com/containers/podman/v5/pkg/machine/shim/diskpull"
|
||||
"github.com/containers/podman/v5/pkg/machine/stdpull"
|
||||
"github.com/containers/podman/v5/pkg/machine/wsl/wutil"
|
||||
@ -111,7 +110,7 @@ func (w WSLStubber) Remove(mc *vmconfigs.MachineConfig) ([]string, func() error,
|
||||
if err := runCmdPassThrough(wutil.FindWSL(), "--unregister", machine.ToDist(mc.Name)); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
return ports.ReleaseMachinePort(mc.SSH.Port)
|
||||
return nil
|
||||
}
|
||||
|
||||
return []string{}, wslRemoveFunc, nil
|
||||
@ -205,15 +204,6 @@ func (w WSLStubber) PostStartNetworking(mc *vmconfigs.MachineConfig, noInfo bool
|
||||
func (w WSLStubber) StartVM(mc *vmconfigs.MachineConfig) (func() error, func() error, error) {
|
||||
dist := machine.ToDist(mc.Name)
|
||||
|
||||
// TODO The original code checked to see if the SSH port was actually open and re-assigned if it was
|
||||
// we could consider this but it should be higher up the stack
|
||||
// if !machine.IsLocalPortAvailable(v.Port) {
|
||||
// logrus.Warnf("SSH port conflict detected, reassigning a new port")
|
||||
// if err := v.reassignSshPort(); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
|
||||
err := wslInvoke(dist, "/root/bootstrap")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("the WSL bootstrap script failed: %w", err)
|
||||
@ -279,6 +269,16 @@ func (w WSLStubber) StopHostNetworking(mc *vmconfigs.MachineConfig, vmType defin
|
||||
return stopUserModeNetworking(mc)
|
||||
}
|
||||
|
||||
func (w WSLStubber) UpdateSSHPort(mc *vmconfigs.MachineConfig, port int) error {
|
||||
dist := machine.ToDist(mc.Name)
|
||||
|
||||
if err := wslInvoke(dist, "sh", "-c", fmt.Sprintf(changePort, port)); err != nil {
|
||||
return fmt.Errorf("could not change SSH port for guest OS: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WSLStubber) VMType() define.VMType {
|
||||
return define.WSLVirt
|
||||
}
|
||||
|
144
vendor/github.com/containers/common/pkg/cgroups/cgroups_linux.go
generated
vendored
144
vendor/github.com/containers/common/pkg/cgroups/cgroups_linux.go
generated
vendored
@ -13,6 +13,9 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
|
||||
@ -22,6 +25,7 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -30,6 +34,10 @@ var (
|
||||
// ErrCgroupV1Rootless means the cgroup v1 were attempted to be used in rootless environment
|
||||
ErrCgroupV1Rootless = errors.New("no support for CGroups V1 in rootless environments")
|
||||
ErrStatCgroup = errors.New("no cgroup available for gathering user statistics")
|
||||
|
||||
isUnifiedOnce sync.Once
|
||||
isUnified bool
|
||||
isUnifiedErr error
|
||||
)
|
||||
|
||||
// CgroupControl controls a cgroup hierarchy
|
||||
@ -731,3 +739,139 @@ func SystemCPUUsage() (uint64, error) {
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 cgroup2 mode.
|
||||
func IsCgroup2UnifiedMode() (bool, error) {
|
||||
isUnifiedOnce.Do(func() {
|
||||
var st syscall.Statfs_t
|
||||
if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil {
|
||||
isUnified, isUnifiedErr = false, err
|
||||
} else {
|
||||
isUnified, isUnifiedErr = st.Type == unix.CGROUP2_SUPER_MAGIC, nil
|
||||
}
|
||||
})
|
||||
return isUnified, isUnifiedErr
|
||||
}
|
||||
|
||||
// UserConnection returns an user connection to D-BUS
|
||||
func UserConnection(uid int) (*systemdDbus.Conn, error) {
|
||||
return systemdDbus.NewConnection(func() (*dbus.Conn, error) {
|
||||
return dbusAuthConnection(uid, dbus.SessionBusPrivateNoAutoStartup)
|
||||
})
|
||||
}
|
||||
|
||||
// UserOwnsCurrentSystemdCgroup checks whether the current EUID owns the
|
||||
// current cgroup.
|
||||
func UserOwnsCurrentSystemdCgroup() (bool, error) {
|
||||
uid := os.Geteuid()
|
||||
|
||||
cgroup2, err := IsCgroup2UnifiedMode()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
f, err := os.Open("/proc/self/cgroup")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.SplitN(line, ":", 3)
|
||||
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
var cgroupPath string
|
||||
|
||||
if cgroup2 {
|
||||
cgroupPath = filepath.Join(cgroupRoot, parts[2])
|
||||
} else {
|
||||
if parts[1] != "name=systemd" {
|
||||
continue
|
||||
}
|
||||
cgroupPath = filepath.Join(cgroupRoot, "systemd", parts[2])
|
||||
}
|
||||
|
||||
st, err := os.Stat(cgroupPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
s := st.Sys()
|
||||
if s == nil {
|
||||
return false, fmt.Errorf("stat cgroup path %s", cgroupPath)
|
||||
}
|
||||
|
||||
if int(s.(*syscall.Stat_t).Uid) != uid {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return false, fmt.Errorf("parsing file /proc/self/cgroup: %w", err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// rmDirRecursively delete recursively a cgroup directory.
|
||||
// It differs from os.RemoveAll as it doesn't attempt to unlink files.
|
||||
// On cgroupfs we are allowed only to rmdir empty directories.
|
||||
func rmDirRecursively(path string) error {
|
||||
killProcesses := func(signal syscall.Signal) {
|
||||
if signal == unix.SIGKILL {
|
||||
if err := os.WriteFile(filepath.Join(path, "cgroup.kill"), []byte("1"), 0o600); err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// kill all the processes that are still part of the cgroup
|
||||
if procs, err := os.ReadFile(filepath.Join(path, "cgroup.procs")); err == nil {
|
||||
for _, pidS := range strings.Split(string(procs), "\n") {
|
||||
if pid, err := strconv.Atoi(pidS); err == nil {
|
||||
_ = unix.Kill(pid, signal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Remove(path); err == nil || errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
entries, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, i := range entries {
|
||||
if i.IsDir() {
|
||||
if err := rmDirRecursively(filepath.Join(path, i.Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attempts := 0
|
||||
for {
|
||||
err := os.Remove(path)
|
||||
if err == nil || errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, unix.EBUSY) {
|
||||
// send a SIGTERM after 3 second
|
||||
if attempts == 300 {
|
||||
killProcesses(unix.SIGTERM)
|
||||
}
|
||||
// send SIGKILL after 8 seconds
|
||||
if attempts == 800 {
|
||||
killProcesses(unix.SIGKILL)
|
||||
}
|
||||
// give up after 10 seconds
|
||||
if attempts < 1000 {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
attempts++
|
||||
continue
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("remove %s: %w", path, err)
|
||||
}
|
||||
}
|
||||
|
162
vendor/github.com/containers/common/pkg/cgroups/cgroups_supported.go
generated
vendored
162
vendor/github.com/containers/common/pkg/cgroups/cgroups_supported.go
generated
vendored
@ -1,162 +0,0 @@
|
||||
//go:build linux
|
||||
|
||||
package cgroups
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/godbus/dbus/v5"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
isUnifiedOnce sync.Once
|
||||
isUnified bool
|
||||
isUnifiedErr error
|
||||
)
|
||||
|
||||
// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 cgroup2 mode.
|
||||
func IsCgroup2UnifiedMode() (bool, error) {
|
||||
isUnifiedOnce.Do(func() {
|
||||
var st syscall.Statfs_t
|
||||
if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil {
|
||||
isUnified, isUnifiedErr = false, err
|
||||
} else {
|
||||
isUnified, isUnifiedErr = st.Type == unix.CGROUP2_SUPER_MAGIC, nil
|
||||
}
|
||||
})
|
||||
return isUnified, isUnifiedErr
|
||||
}
|
||||
|
||||
// UserConnection returns an user connection to D-BUS
|
||||
func UserConnection(uid int) (*systemdDbus.Conn, error) {
|
||||
return systemdDbus.NewConnection(func() (*dbus.Conn, error) {
|
||||
return dbusAuthConnection(uid, dbus.SessionBusPrivateNoAutoStartup)
|
||||
})
|
||||
}
|
||||
|
||||
// UserOwnsCurrentSystemdCgroup checks whether the current EUID owns the
|
||||
// current cgroup.
|
||||
func UserOwnsCurrentSystemdCgroup() (bool, error) {
|
||||
uid := os.Geteuid()
|
||||
|
||||
cgroup2, err := IsCgroup2UnifiedMode()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
f, err := os.Open("/proc/self/cgroup")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.SplitN(line, ":", 3)
|
||||
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
var cgroupPath string
|
||||
|
||||
if cgroup2 {
|
||||
cgroupPath = filepath.Join(cgroupRoot, parts[2])
|
||||
} else {
|
||||
if parts[1] != "name=systemd" {
|
||||
continue
|
||||
}
|
||||
cgroupPath = filepath.Join(cgroupRoot, "systemd", parts[2])
|
||||
}
|
||||
|
||||
st, err := os.Stat(cgroupPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
s := st.Sys()
|
||||
if s == nil {
|
||||
return false, fmt.Errorf("stat cgroup path %s", cgroupPath)
|
||||
}
|
||||
|
||||
if int(s.(*syscall.Stat_t).Uid) != uid {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return false, fmt.Errorf("parsing file /proc/self/cgroup: %w", err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// rmDirRecursively delete recursively a cgroup directory.
|
||||
// It differs from os.RemoveAll as it doesn't attempt to unlink files.
|
||||
// On cgroupfs we are allowed only to rmdir empty directories.
|
||||
func rmDirRecursively(path string) error {
|
||||
killProcesses := func(signal syscall.Signal) {
|
||||
if signal == unix.SIGKILL {
|
||||
if err := os.WriteFile(filepath.Join(path, "cgroup.kill"), []byte("1"), 0o600); err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// kill all the processes that are still part of the cgroup
|
||||
if procs, err := os.ReadFile(filepath.Join(path, "cgroup.procs")); err == nil {
|
||||
for _, pidS := range strings.Split(string(procs), "\n") {
|
||||
if pid, err := strconv.Atoi(pidS); err == nil {
|
||||
_ = unix.Kill(pid, signal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Remove(path); err == nil || errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
entries, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, i := range entries {
|
||||
if i.IsDir() {
|
||||
if err := rmDirRecursively(filepath.Join(path, i.Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attempts := 0
|
||||
for {
|
||||
err := os.Remove(path)
|
||||
if err == nil || errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, unix.EBUSY) {
|
||||
// send a SIGTERM after 3 second
|
||||
if attempts == 300 {
|
||||
killProcesses(unix.SIGTERM)
|
||||
}
|
||||
// send SIGKILL after 8 seconds
|
||||
if attempts == 800 {
|
||||
killProcesses(unix.SIGKILL)
|
||||
}
|
||||
// give up after 10 seconds
|
||||
if attempts < 1000 {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
attempts++
|
||||
continue
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("remove %s: %w", path, err)
|
||||
}
|
||||
}
|
8
vendor/github.com/containers/common/pkg/cgroups/cgroups_unsupported.go
generated
vendored
8
vendor/github.com/containers/common/pkg/cgroups/cgroups_unsupported.go
generated
vendored
@ -3,10 +3,7 @@
|
||||
package cgroups
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
|
||||
)
|
||||
|
||||
// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 cgroup2 mode.
|
||||
@ -23,8 +20,3 @@ func UserOwnsCurrentSystemdCgroup() (bool, error) {
|
||||
func rmDirRecursively(path string) error {
|
||||
return os.RemoveAll(path)
|
||||
}
|
||||
|
||||
// UserConnection returns an user connection to D-BUS
|
||||
func UserConnection(uid int) (*systemdDbus.Conn, error) {
|
||||
return nil, fmt.Errorf("systemd d-bus is not supported on this platform")
|
||||
}
|
||||
|
80
vendor/github.com/containers/common/pkg/cgroups/systemd.go
generated
vendored
80
vendor/github.com/containers/common/pkg/cgroups/systemd.go
generated
vendored
@ -1,80 +0,0 @@
|
||||
//go:build !linux
|
||||
|
||||
package cgroups
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/godbus/dbus/v5"
|
||||
)
|
||||
|
||||
func systemdCreate(path string, c *systemdDbus.Conn) error {
|
||||
slice, name := filepath.Split(path)
|
||||
slice = strings.TrimSuffix(slice, "/")
|
||||
|
||||
var lastError error
|
||||
for i := 0; i < 2; i++ {
|
||||
properties := []systemdDbus.Property{
|
||||
systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)),
|
||||
systemdDbus.PropWants(slice),
|
||||
}
|
||||
pMap := map[string]bool{
|
||||
"DefaultDependencies": false,
|
||||
"MemoryAccounting": true,
|
||||
"CPUAccounting": true,
|
||||
"BlockIOAccounting": true,
|
||||
}
|
||||
if i == 0 {
|
||||
pMap["Delegate"] = true
|
||||
}
|
||||
for k, v := range pMap {
|
||||
p := systemdDbus.Property{
|
||||
Name: k,
|
||||
Value: dbus.MakeVariant(v),
|
||||
}
|
||||
properties = append(properties, p)
|
||||
}
|
||||
|
||||
ch := make(chan string)
|
||||
_, err := c.StartTransientUnitContext(context.TODO(), name, "replace", properties, ch)
|
||||
if err != nil {
|
||||
lastError = err
|
||||
continue
|
||||
}
|
||||
<-ch
|
||||
return nil
|
||||
}
|
||||
return lastError
|
||||
}
|
||||
|
||||
/*
|
||||
systemdDestroyConn is copied from containerd/cgroups/systemd.go file, that
|
||||
has the following license:
|
||||
Copyright The containerd Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
func systemdDestroyConn(path string, c *systemdDbus.Conn) error {
|
||||
name := filepath.Base(path)
|
||||
|
||||
ch := make(chan string)
|
||||
_, err := c.StopUnitContext(context.TODO(), name, "replace", ch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
<-ch
|
||||
return nil
|
||||
}
|
54
vendor/github.com/containers/common/pkg/config/connections.go
generated
vendored
54
vendor/github.com/containers/common/pkg/config/connections.go
generated
vendored
@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containers/storage/pkg/ioutils"
|
||||
"github.com/containers/storage/pkg/lockfile"
|
||||
)
|
||||
|
||||
const connectionsFile = "podman-connections.json"
|
||||
@ -64,28 +65,24 @@ type Farm struct {
|
||||
ReadWrite bool
|
||||
}
|
||||
|
||||
func readConnectionConf() (*ConnectionsFile, string, error) {
|
||||
path, err := connectionsConfigFile()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
func readConnectionConf(path string) (*ConnectionsFile, error) {
|
||||
conf := new(ConnectionsFile)
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
// return empty config if file does not exists
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return conf, path, nil
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
err = json.NewDecoder(f).Decode(conf)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("parse %q: %w", path, err)
|
||||
return nil, fmt.Errorf("parse %q: %w", path, err)
|
||||
}
|
||||
return conf, path, nil
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func writeConnectionConf(path string, conf *ConnectionsFile) error {
|
||||
@ -113,7 +110,20 @@ func writeConnectionConf(path string, conf *ConnectionsFile) error {
|
||||
// The function will read and write the file automatically and the
|
||||
// callback function just needs to modify the cfg as needed.
|
||||
func EditConnectionConfig(callback func(cfg *ConnectionsFile) error) error {
|
||||
conf, path, err := readConnectionConf()
|
||||
path, err := connectionsConfigFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lockPath := path + ".lock"
|
||||
lock, err := lockfile.GetLockFile(lockPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("obtain lock file: %w", err)
|
||||
}
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
conf, err := readConnectionConf(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read connections file: %w", err)
|
||||
}
|
||||
@ -139,7 +149,11 @@ func makeConnection(name string, dst Destination, def, readWrite bool) *Connecti
|
||||
|
||||
// GetConnection return the connection for the given name or if def is set to true then return the default connection.
|
||||
func (c *Config) GetConnection(name string, def bool) (*Connection, error) {
|
||||
conConf, _, err := readConnectionConf()
|
||||
path, err := connectionsConfigFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conConf, err := readConnectionConf(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -167,7 +181,11 @@ func (c *Config) GetConnection(name string, def bool) (*Connection, error) {
|
||||
|
||||
// GetAllConnections return all configured connections
|
||||
func (c *Config) GetAllConnections() ([]Connection, error) {
|
||||
conConf, _, err := readConnectionConf()
|
||||
path, err := connectionsConfigFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conConf, err := readConnectionConf(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -222,7 +240,11 @@ func (c *Config) GetDefaultFarmConnections() (string, []Connection, error) {
|
||||
// if def is true it will use the default farm instead of the name.
|
||||
// Returns the name of the farm and the connections for it.
|
||||
func (c *Config) getFarmConnections(name string, def bool) (string, []Connection, error) {
|
||||
conConf, _, err := readConnectionConf()
|
||||
path, err := connectionsConfigFile()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
conConf, err := readConnectionConf(path)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -259,7 +281,11 @@ func makeFarm(name string, cons []string, def, readWrite bool) Farm {
|
||||
|
||||
// GetAllFarms returns all configured farms
|
||||
func (c *Config) GetAllFarms() ([]Farm, error) {
|
||||
conConf, _, err := readConnectionConf()
|
||||
path, err := connectionsConfigFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conConf, err := readConnectionConf(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -171,7 +171,7 @@ github.com/containers/buildah/pkg/sshagent
|
||||
github.com/containers/buildah/pkg/util
|
||||
github.com/containers/buildah/pkg/volumes
|
||||
github.com/containers/buildah/util
|
||||
# github.com/containers/common v0.57.1-0.20240229165734-cec09922602e
|
||||
# github.com/containers/common v0.57.1-0.20240304165751-a0d555c70d52
|
||||
## explicit; go 1.20
|
||||
github.com/containers/common/internal
|
||||
github.com/containers/common/internal/attributedstring
|
||||
|
Reference in New Issue
Block a user