mirror of
https://github.com/containers/podman.git
synced 2026-03-13 08:01:19 +08:00
Instead of creating a slice and then appending to it, let's inline the initial slice into append. This may or may not result in less slice reallocations, but it is silencing the prealloc linter warnings. This commit is part of series fixing issues reported by prealloc linter from golangci-lint v2.8.0. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
132 lines
3.0 KiB
Go
132 lines
3.0 KiB
Go
//go:build !remote
|
|
|
|
package libpod
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/containers/podman/v6/libpod/define"
|
|
"github.com/containers/podman/v6/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(strings.Join(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{"-o", 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)
|
|
}
|
|
}
|
|
}
|
|
|
|
jailName, err := c.jailName()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting jail name: %w", err)
|
|
}
|
|
|
|
args := append([]string{"-J", jailName}, psDescriptors...)
|
|
|
|
output, err := execPS(args)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("executing ps(1): %w", err)
|
|
}
|
|
|
|
return output, nil
|
|
}
|
|
|
|
func 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
|
|
}
|