vendor c/psgo@v1.7.1

psgo added support for listing supplementary groups via
two new descriptors:

* `groups` for supplementary groups inside the container
* `hgroups` for the counterpart on the host

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2021-09-20 14:48:58 +02:00
parent b906ecbb5b
commit 5875e409e2
17 changed files with 116 additions and 66 deletions

2
go.mod

@ -16,7 +16,7 @@ require (
github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.16.0 github.com/containers/image/v5 v5.16.0
github.com/containers/ocicrypt v1.1.2 github.com/containers/ocicrypt v1.1.2
github.com/containers/psgo v1.6.0 github.com/containers/psgo v1.7.1
github.com/containers/storage v1.36.0 github.com/containers/storage v1.36.0
github.com/coreos/go-systemd/v22 v22.3.2 github.com/coreos/go-systemd/v22 v22.3.2
github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3 github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3

4
go.sum

@ -259,8 +259,8 @@ github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgU
github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/containers/ocicrypt v1.1.2 h1:Ez+GAMP/4GLix5Ywo/fL7O0nY771gsBIigiqUm1aXz0= github.com/containers/ocicrypt v1.1.2 h1:Ez+GAMP/4GLix5Ywo/fL7O0nY771gsBIigiqUm1aXz0=
github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/containers/psgo v1.6.0 h1:jkl/5kndKmJ/bnSFq8in6xRDAzgW26GnNuTxoycNFvk= github.com/containers/psgo v1.7.1 h1:2N6KADeFvBm1aI2iXxu6+/Xh7CCkdh8p8F3F/cpIU5I=
github.com/containers/psgo v1.6.0/go.mod h1:ggVhB2KQi9qGZdqSlczqN0BwcJdotmpRru87S1anRO8= github.com/containers/psgo v1.7.1/go.mod h1:mWGpFzW73qWFA+blhF6l7GuKzbrACkYgr/ajiNQR+RM=
github.com/containers/storage v1.23.5/go.mod h1:ha26Q6ngehFNhf3AWoXldvAvwI4jFe3ETQAf/CeZPyM= github.com/containers/storage v1.23.5/go.mod h1:ha26Q6ngehFNhf3AWoXldvAvwI4jFe3ETQAf/CeZPyM=
github.com/containers/storage v1.35.0/go.mod h1:qzYhasQP2/V9D9XdO+vRwkHBhsBO0oznMLzzRDQ8s20= github.com/containers/storage v1.35.0/go.mod h1:qzYhasQP2/V9D9XdO+vRwkHBhsBO0oznMLzzRDQ8s20=
github.com/containers/storage v1.36.0 h1:OelxllCW19tnNngYuZw2ty/zLabVMG5rSs3KSwO1Lzc= github.com/containers/storage v1.36.0 h1:OelxllCW19tnNngYuZw2ty/zLabVMG5rSs3KSwO1Lzc=

@ -73,6 +73,12 @@ var _ = Describe("Podman top", func() {
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0)) Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1))
// Just a smoke test since groups may change over time.
result = podmanTest.Podman([]string{"container", "top", "test", "groups", "hgroups"})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1))
}) })
It("podman top with options", func() { It("podman top with options", func() {

2
vendor/github.com/containers/psgo/.codespellrc generated vendored Normal file

@ -0,0 +1,2 @@
[codespell]
skip = ./vendor,./.git

6
vendor/github.com/containers/psgo/.golangci.yml generated vendored Normal file

@ -0,0 +1,6 @@
# For documentation, see https://golangci-lint.run/usage/configuration/
linters:
enable:
- errorlint
- gofumpt

@ -1,19 +0,0 @@
language: go
sudo: required
servics:
- docker
go:
- tip
before_install:
- sudo add-apt-repository ppa:duggan/bats --yes
- sudo apt-get update -qq
- sudo apt-get install -qq bats
script:
- make validate
- make build
- make test

@ -1,28 +1,25 @@
export GO111MODULE=off
export GOPROXY=https://proxy.golang.org
SHELL= /bin/bash SHELL= /bin/bash
GO ?= go GO ?= go
BUILD_DIR := ./bin BUILD_DIR := ./bin
BIN_DIR := /usr/local/bin BIN_DIR := /usr/local/bin
NAME := psgo NAME := psgo
PROJECT := github.com/containers/psgo
BATS_TESTS := *.bats BATS_TESTS := *.bats
GO_SRC=$(shell find . -name \*.go)
GO_BUILD=$(GO) build # Not all platforms support -buildmode=pie, plus it's incompatible with -race.
# Go module support: set `-mod=vendor` to use the vendored sources ifeq ($(shell $(GO) env GOOS),linux)
ifeq ($(shell go help mod >/dev/null 2>&1 && echo true), true) ifeq (,$(filter $(shell $(GO) env GOARCH),mips mipsle mips64 mips64le ppc64 riscv64))
GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor ifeq (,$(findstring -race,$(EXTRA_BUILD_FLAGS)))
GO_BUILDMODE := "-buildmode=pie"
endif
endif
endif endif
GO_BUILD := $(GO) build $(GO_BUILDMODE)
GOBIN ?= $(GO)/bin
all: validate build all: validate build
.PHONY: build .PHONY: build
build: $(GO_SRC) build:
$(GO_BUILD) -buildmode=pie -o $(BUILD_DIR)/$(NAME) $(PROJECT)/sample $(GO_BUILD) $(EXTRA_BUILD_FLAGS) -o $(BUILD_DIR)/$(NAME) ./sample
.PHONY: clean .PHONY: clean
clean: clean:
@ -30,13 +27,13 @@ clean:
.PHONY: vendor .PHONY: vendor
vendor: vendor:
GO111MODULE=on go mod tidy go mod tidy
GO111MODULE=on go mod vendor go mod vendor
GO111MODULE=on go mod verify go mod verify
.PHONY: validate .PHONY: validate
validate: .install.lint validate:
$(GOBIN)/golangci-lint run golangci-lint run
.PHONY: test .PHONY: test
test: test-unit test-integration test: test-unit test-integration
@ -47,17 +44,12 @@ test-integration:
.PHONY: test-unit .PHONY: test-unit
test-unit: test-unit:
go test -v $(PROJECT) $(GO) test -v $(EXTRA_TEST_FLAGS) ./...
go test -v $(PROJECT)/internal/...
.PHONY: install .PHONY: install
install: install:
sudo install -D -m755 $(BUILD_DIR)/$(NAME) $(BIN_DIR) sudo install -D -m755 $(BUILD_DIR)/$(NAME) $(BIN_DIR)
.PHONY: .install.lint
.install.lint:
VERSION=1.24.0 GOBIN=$(GOBIN) sh ./hack/install_golangci.sh
.PHONY: uninstall .PHONY: uninstall
uninstall: uninstall:
sudo rm $(BIN_DIR)/$(NAME) sudo rm $(BIN_DIR)/$(NAME)

@ -73,8 +73,12 @@ The ps library is compatible with all AIX format descriptors of the ps command-l
- Set of inheritable capabilities. See capabilities(7) for more information. - Set of inheritable capabilities. See capabilities(7) for more information.
- **capprm** - **capprm**
- Set of permitted capabilities. See capabilities(7) for more information. - Set of permitted capabilities. See capabilities(7) for more information.
- **groups**
- Supplmentary groups inside the container.
- **hgroup** - **hgroup**
- The corresponding effective group of a container process on the host. - The corresponding effective group of a container process on the host.
- **hgroups**
- Supplmentary groups on the host.
- **hpid** - **hpid**
- The corresponding host PID of a container process. - The corresponding host PID of a container process.
- **huser** - **huser**

@ -1,10 +1,9 @@
module github.com/containers/psgo module github.com/containers/psgo
go 1.13 go 1.14
require ( require (
github.com/opencontainers/runc v1.0.2 github.com/opencontainers/runc v1.0.2
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2
) )

@ -39,7 +39,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=

@ -54,7 +54,7 @@ func BootTime() (int64, error) {
btimeSec, err := strconv.ParseInt(btimeStr, 10, 64) btimeSec, err := strconv.ParseInt(btimeStr, 10, 64)
if err != nil { if err != nil {
return 0, fmt.Errorf("error parsing boot time from /proc/stat: %s", err) return 0, fmt.Errorf("error parsing boot time from /proc/stat: %w", err)
} }
bootTime = &btimeSec bootTime = &btimeSec
return btimeSec, nil return btimeSec, nil

@ -59,7 +59,7 @@ func ReadMappings(path string) ([]IDMap, error) {
for { for {
line, _, err := buf.ReadLine() line, _, err := buf.ReadLine()
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF { //nolint:errorlint // False positive, see https://github.com/polyfloyd/go-errorlint/pull/12
return mappings, nil return mappings, nil
} }
return nil, fmt.Errorf("cannot read line from %s: %w", path, err) return nil, fmt.Errorf("cannot read line from %s: %w", path, err)

@ -52,7 +52,7 @@ func GetPIDs() ([]string, error) {
return pids, nil return pids, nil
} }
// GetPIDsFromCgroup returns a strings slice of all pids listesd in pid's pids // GetPIDsFromCgroup returns a strings slice of all pids listed in pid's pids
// cgroup. It automatically detects if we're running in unified mode or not. // cgroup. It automatically detects if we're running in unified mode or not.
func GetPIDsFromCgroup(pid string) ([]string, error) { func GetPIDsFromCgroup(pid string) ([]string, error) {
unified, err := cgroups.IsCgroup2UnifiedMode() unified, err := cgroups.IsCgroup2UnifiedMode()
@ -65,11 +65,12 @@ func GetPIDsFromCgroup(pid string) ([]string, error) {
return getPIDsFromCgroupV1(pid) return getPIDsFromCgroupV1(pid)
} }
// getPIDsFromCgroupV1 returns a strings slice of all pids listesd in pid's pids // getPIDsFromCgroupV1 returns a strings slice of all pids listed in pid's pids
// cgroup. // cgroup.
func getPIDsFromCgroupV1(pid string) ([]string, error) { func getPIDsFromCgroupV1(pid string) ([]string, error) {
// First, find the corresponding path to the PID cgroup. // First, find the corresponding path to the PID cgroup.
f, err := os.Open(fmt.Sprintf("/proc/%s/cgroup", pid)) pidPath := fmt.Sprintf("/proc/%s/cgroup", pid)
f, err := os.Open(pidPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -83,7 +84,8 @@ func getPIDsFromCgroupV1(pid string) ([]string, error) {
continue continue
} }
if fields[1] == "pids" { if fields[1] == "pids" {
cgroupPath = fmt.Sprintf("/sys/fs/cgroup/pids/%s/cgroup.procs", fields[2]) cgroupPath = filepath.Join(cgroups.CgroupRoot, "pids", fields[2], "cgroup.procs")
break
} }
} }
@ -94,7 +96,18 @@ func getPIDsFromCgroupV1(pid string) ([]string, error) {
// Second, extract the PIDs inside the cgroup. // Second, extract the PIDs inside the cgroup.
f, err = os.Open(cgroupPath) f, err = os.Open(cgroupPath)
if err != nil { if err != nil {
return nil, err if os.IsNotExist(err) {
// OCI runtimes might mount the container cgroup at the root, breaking what it showed
// in /proc/$PID/cgroup and the path.
// Check if the PID still exists to make sure the process is still alive.
if _, errStat := os.Stat(pidPath); errStat == nil {
cgroupPath = filepath.Join(cgroups.CgroupRoot, "pids", "cgroup.procs")
f, err = os.Open(cgroupPath)
}
}
if err != nil {
return nil, err
}
} }
defer f.Close() defer f.Close()
@ -107,7 +120,7 @@ func getPIDsFromCgroupV1(pid string) ([]string, error) {
return pids, nil return pids, nil
} }
// getPIDsFromCgroupV2 returns a strings slice of all pids listesd in pid's pids // getPIDsFromCgroupV2 returns a strings slice of all pids listed in pid's pids
// cgroup. // cgroup.
func getPIDsFromCgroupV2(pid string) ([]string, error) { func getPIDsFromCgroupV2(pid string) ([]string, error) {
// First, find the corresponding path to the PID cgroup. // First, find the corresponding path to the PID cgroup.
@ -124,8 +137,10 @@ func getPIDsFromCgroupV2(pid string) ([]string, error) {
if len(fields) != 3 { if len(fields) != 3 {
continue continue
} }
cgroupSlice = fields[2] if fields[1] == "" {
break cgroupSlice = fields[2]
break
}
} }
if cgroupSlice == "" { if cgroupSlice == "" {

@ -182,7 +182,7 @@ func readStatusUserNS(pid string) ([]string, error) {
c := exec.Command(args[0], args[1:]...) c := exec.Command(args[0], args[1:]...)
output, err := c.CombinedOutput() output, err := c.CombinedOutput()
if err != nil { if err != nil {
return nil, fmt.Errorf("error executing %q: %v", strings.Join(args, " "), err) return nil, fmt.Errorf("error executing %q: %w", strings.Join(args, " "), err)
} }
return strings.Split(string(output), "\n"), nil return strings.Split(string(output), "\n"), nil

@ -215,7 +215,7 @@ func (p *Process) StartTime() (time.Time, error) {
return time.Unix(sinceBoot+bootTime, 0), nil return time.Unix(sinceBoot+bootTime, 0), nil
} }
// CPUTime returns the cumlative CPU time of process p as a time.Duration. // CPUTime returns the cumulative CPU time of process p as a time.Duration.
func (p *Process) CPUTime() (time.Duration, error) { func (p *Process) CPUTime() (time.Duration, error) {
user, err := strconv.ParseInt(p.Stat.Utime, 10, 64) user, err := strconv.ParseInt(p.Stat.Utime, 10, 64)
if err != nil { if err != nil {

@ -174,6 +174,11 @@ var (
header: "GROUP", header: "GROUP",
procFn: processGROUP, procFn: processGROUP,
}, },
{
normal: "groups",
header: "GROUPS",
procFn: processGROUPS,
},
{ {
code: "%P", code: "%P",
normal: "ppid", normal: "ppid",
@ -305,6 +310,12 @@ var (
onHost: true, onHost: true,
procFn: processHGROUP, procFn: processHGROUP,
}, },
{
normal: "hgroups",
header: "HGROUPS",
onHost: true,
procFn: processHGROUPS,
},
{ {
normal: "rss", normal: "rss",
header: "RSS", header: "RSS",
@ -620,14 +631,29 @@ func findHostProcess(p *process.Process, ctx *psContext) *process.Process {
} }
// processGROUP returns the effective group ID of the process. This will be // processGROUP returns the effective group ID of the process. This will be
// the textual group ID, if it can be optained, or a decimal representation // the textual group ID, if it can be obtained, or a decimal representation
// otherwise. // otherwise.
func processGROUP(p *process.Process, ctx *psContext) (string, error) { func processGROUP(p *process.Process, ctx *psContext) (string, error) {
return process.LookupGID(p.Status.Gids[1]) return process.LookupGID(p.Status.Gids[1])
} }
// processGROUPS returns the supplementary groups of the process separated by
// comma. This will be the textual group ID, if it can be obtained, or a
// decimal representation otherwise.
func processGROUPS(p *process.Process, ctx *psContext) (string, error) {
var err error
groups := make([]string, len(p.Status.Groups))
for i, g := range p.Status.Groups {
groups[i], err = process.LookupGID(g)
if err != nil {
return "", err
}
}
return strings.Join(groups, ","), nil
}
// processRGROUP returns the real group ID of the process. This will be // processRGROUP returns the real group ID of the process. This will be
// the textual group ID, if it can be optained, or a decimal representation // the textual group ID, if it can be obtained, or a decimal representation
// otherwise. // otherwise.
func processRGROUP(p *process.Process, ctx *psContext) (string, error) { func processRGROUP(p *process.Process, ctx *psContext) (string, error) {
return process.LookupGID(p.Status.Gids[0]) return process.LookupGID(p.Status.Gids[0])
@ -639,14 +665,14 @@ func processPPID(p *process.Process, ctx *psContext) (string, error) {
} }
// processUSER returns the effective user name of the process. This will be // processUSER returns the effective user name of the process. This will be
// the textual user ID, if it can be optained, or a decimal representation // the textual user ID, if it can be obtained, or a decimal representation
// otherwise. // otherwise.
func processUSER(p *process.Process, ctx *psContext) (string, error) { func processUSER(p *process.Process, ctx *psContext) (string, error) {
return process.LookupUID(p.Status.Uids[1]) return process.LookupUID(p.Status.Uids[1])
} }
// processRUSER returns the effective user name of the process. This will be // processRUSER returns the effective user name of the process. This will be
// the textual user ID, if it can be optained, or a decimal representation // the textual user ID, if it can be obtained, or a decimal representation
// otherwise. // otherwise.
func processRUSER(p *process.Process, ctx *psContext) (string, error) { func processRUSER(p *process.Process, ctx *psContext) (string, error) {
return process.LookupUID(p.Status.Uids[0]) return process.LookupUID(p.Status.Uids[0])
@ -867,6 +893,26 @@ func processHGROUP(p *process.Process, ctx *psContext) (string, error) {
return "?", nil return "?", nil
} }
// processHGROUPS returns the supplementary groups of the corresponding host
// process of the (container) or "?" if no corresponding process could be
// found.
func processHGROUPS(p *process.Process, ctx *psContext) (string, error) {
if hp := findHostProcess(p, ctx); hp != nil {
groups := hp.Status.Groups
if ctx.opts != nil && len(ctx.opts.GIDMap) > 0 {
var err error
for i, g := range groups {
groups[i], err = findID(g, ctx.opts.GIDMap, process.LookupGID, "/proc/sys/fs/overflowgid")
if err != nil {
return "", err
}
}
}
return strings.Join(groups, ","), nil
}
return "?", nil
}
// processRSS returns the resident set size of process p in KiB (1024-byte // processRSS returns the resident set size of process p in KiB (1024-byte
// units). // units).
func processRSS(p *process.Process, ctx *psContext) (string, error) { func processRSS(p *process.Process, ctx *psContext) (string, error) {

2
vendor/modules.txt vendored

@ -191,7 +191,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7
github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/spec
github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils
github.com/containers/ocicrypt/utils/keyprovider github.com/containers/ocicrypt/utils/keyprovider
# github.com/containers/psgo v1.6.0 # github.com/containers/psgo v1.7.1
github.com/containers/psgo github.com/containers/psgo
github.com/containers/psgo/internal/capabilities github.com/containers/psgo/internal/capabilities
github.com/containers/psgo/internal/cgroups github.com/containers/psgo/internal/cgroups