Merge pull request #16203 from dfr/freebsd-top

Add support for 'podman top' on FreeBSD
This commit is contained in:
OpenShift Merge Robot
2022-10-18 10:52:43 -04:00
committed by GitHub
5 changed files with 162 additions and 11 deletions

View File

@ -279,3 +279,11 @@ func (c *Container) getConmonPidFd() int {
// keeping things simple for now.
return -1
}
func (c *Container) jailName() string {
if c.state.NetNS != nil {
return c.state.NetNS.Name + "." + c.ID()
} else {
return c.ID()
}
}

View 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
}

View File

@ -1,5 +1,5 @@
//go:build !linux
// +build !linux
//go:build !linux && !freebsd
// +build !linux,!freebsd
package libpod

View File

@ -20,13 +20,9 @@ import (
func (c *Container) getPlatformContainerStats(stats *define.ContainerStats, previousStats *define.ContainerStats) error {
now := uint64(time.Now().UnixNano())
jailName := c.ID()
if c.state.NetNS != nil {
jailName = c.state.NetNS.Name + "." + jailName
}
entries, err := rctl.GetRacct("jail:" + jailName)
entries, err := rctl.GetRacct("jail:" + c.jailName())
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

View File

@ -4,13 +4,29 @@
package util
import (
"errors"
"github.com/opencontainers/runtime-tools/generate"
)
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 {