mirror of
https://github.com/containers/podman.git
synced 2025-06-29 06:57:13 +08:00
Merge pull request #16203 from dfr/freebsd-top
Add support for 'podman top' on FreeBSD
This commit is contained in:
@ -279,3 +279,11 @@ func (c *Container) getConmonPidFd() int {
|
|||||||
// keeping things simple for now.
|
// keeping things simple for now.
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) jailName() string {
|
||||||
|
if c.state.NetNS != nil {
|
||||||
|
return c.state.NetNS.Name + "." + c.ID()
|
||||||
|
} else {
|
||||||
|
return c.ID()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
131
libpod/container_top_freebsd.go
Normal file
131
libpod/container_top_freebsd.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
//go:build freebsd
|
||||||
|
// +build freebsd
|
||||||
|
|
||||||
|
package libpod
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/containers/podman/v4/libpod/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
|
"github.com/google/shlex"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var isDescriptor = map[string]bool{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
allDescriptors, err := util.GetContainerPidInformationDescriptors()
|
||||||
|
if err != nil {
|
||||||
|
// Should never happen
|
||||||
|
logrus.Debugf("failed call to util.GetContainerPidInformationDescriptors()")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, d := range allDescriptors {
|
||||||
|
isDescriptor[d] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top gathers statistics about the running processes in a container. It returns a
|
||||||
|
// []string for output
|
||||||
|
func (c *Container) Top(descriptors []string) ([]string, error) {
|
||||||
|
conStat, err := c.State()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to look up state for %s: %w", c.ID(), err)
|
||||||
|
}
|
||||||
|
if conStat != define.ContainerStateRunning {
|
||||||
|
return nil, errors.New("top can only be used on running containers")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to 'ps -ef' compatible descriptors
|
||||||
|
if len(descriptors) == 0 {
|
||||||
|
descriptors = []string{"user", "pid", "ppid", "pcpu", "etime", "tty", "time", "args"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If everything in descriptors is a supported AIX format
|
||||||
|
// descriptor, we use 'ps -ao <descriptors>', otherwise we pass
|
||||||
|
// everything straight through to ps.
|
||||||
|
supportedDescriptors := true
|
||||||
|
for _, d := range descriptors {
|
||||||
|
if _, ok := isDescriptor[d]; !ok {
|
||||||
|
supportedDescriptors = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if supportedDescriptors {
|
||||||
|
descriptors = []string{"-ao", strings.Join(descriptors, ",")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that the descriptors to ps(1) must be shlexed (see #12452).
|
||||||
|
psDescriptors := []string{}
|
||||||
|
for _, d := range descriptors {
|
||||||
|
shSplit, err := shlex.Split(d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing ps args: %w", err)
|
||||||
|
}
|
||||||
|
for _, s := range shSplit {
|
||||||
|
if s != "" {
|
||||||
|
psDescriptors = append(psDescriptors, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"-J",
|
||||||
|
c.jailName(),
|
||||||
|
}
|
||||||
|
args = append(args, psDescriptors...)
|
||||||
|
|
||||||
|
output, err := c.execPS(args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("executing ps(1): %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) execPS(args []string) ([]string, error) {
|
||||||
|
cmd := exec.Command("ps", args...)
|
||||||
|
stdoutPipe, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stderrPipe, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
stdout := []string{}
|
||||||
|
go func() {
|
||||||
|
scanner := bufio.NewScanner(stdoutPipe)
|
||||||
|
for scanner.Scan() {
|
||||||
|
stdout = append(stdout, scanner.Text())
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
stderr := []string{}
|
||||||
|
go func() {
|
||||||
|
scanner := bufio.NewScanner(stderrPipe)
|
||||||
|
for scanner.Scan() {
|
||||||
|
stderr = append(stderr, scanner.Text())
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return nil, fmt.Errorf("ps(1) command failed: %w, output: %s", err, strings.Join(stderr, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout, nil
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
//go:build !linux
|
//go:build !linux && !freebsd
|
||||||
// +build !linux
|
// +build !linux,!freebsd
|
||||||
|
|
||||||
package libpod
|
package libpod
|
||||||
|
|
||||||
|
@ -20,13 +20,9 @@ import (
|
|||||||
func (c *Container) getPlatformContainerStats(stats *define.ContainerStats, previousStats *define.ContainerStats) error {
|
func (c *Container) getPlatformContainerStats(stats *define.ContainerStats, previousStats *define.ContainerStats) error {
|
||||||
now := uint64(time.Now().UnixNano())
|
now := uint64(time.Now().UnixNano())
|
||||||
|
|
||||||
jailName := c.ID()
|
entries, err := rctl.GetRacct("jail:" + c.jailName())
|
||||||
if c.state.NetNS != nil {
|
|
||||||
jailName = c.state.NetNS.Name + "." + jailName
|
|
||||||
}
|
|
||||||
entries, err := rctl.GetRacct("jail:" + jailName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to read accounting for %s: %w", jailName, err)
|
return fmt.Errorf("unable to read accounting for %s: %w", c.jailName(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current total usage is less than what was previously
|
// If the current total usage is less than what was previously
|
||||||
|
@ -4,13 +4,29 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runtime-tools/generate"
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetContainerPidInformationDescriptors() ([]string, error) {
|
func GetContainerPidInformationDescriptors() ([]string, error) {
|
||||||
return []string{}, errors.New("this function is not supported on freebsd")
|
// These are chosen to match the set of AIX format descriptors
|
||||||
|
// supported in Linux - FreeBSD ps does support (many) others.
|
||||||
|
return []string{
|
||||||
|
"args",
|
||||||
|
"comm",
|
||||||
|
"etime",
|
||||||
|
"group",
|
||||||
|
"nice",
|
||||||
|
"pcpu",
|
||||||
|
"pgid",
|
||||||
|
"pid",
|
||||||
|
"ppid",
|
||||||
|
"rgroup",
|
||||||
|
"ruser",
|
||||||
|
"time",
|
||||||
|
"tty",
|
||||||
|
"user",
|
||||||
|
"vsz",
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddPrivilegedDevices(g *generate.Generator, systemdMode bool) error {
|
func AddPrivilegedDevices(g *generate.Generator, systemdMode bool) error {
|
||||||
|
Reference in New Issue
Block a user