36b3af2e3d
PR Check / Code Quality: Format (push) Failing after 1s
PR Check / Code Quality: Lint (darwin) (push) Failing after 0s
PR Check / Code Quality: Lint (freebsd) (push) Failing after 1s
PR Check / Code Quality: Lint (windows) (push) Failing after 1s
PR Check / Code Quality: Lint (linux) (push) Failing after 1s
PR Check / Security: Vulnerability Scan (push) Failing after 0s
Update Documentation / update-docs (push) Failing after 2s
PR Check / Code Quality: Vendor (push) Failing after 1s
PR Check / Code Quality: Coverage (push) Failing after 0s
PR Check / Tests: Unit (macos-latest) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04-arm) (push) Has been cancelled
PR Check / Tests: Unit (windows-latest) (push) Has been cancelled
132 lines
3.3 KiB
Go
132 lines
3.3 KiB
Go
package proc
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pranshuparmar/witr/pkg/model"
|
|
)
|
|
|
|
// ContainerRuntime is a backend (docker, podman, …) that can list containers
|
|
// and resolve a container's main host PID.
|
|
type ContainerRuntime interface {
|
|
Name() string
|
|
Available() bool
|
|
List() []*model.ContainerMatch
|
|
HostPID(id string) int
|
|
}
|
|
|
|
var registeredRuntimes []ContainerRuntime
|
|
|
|
func registerRuntime(rt ContainerRuntime) {
|
|
registeredRuntimes = append(registeredRuntimes, rt)
|
|
}
|
|
|
|
// ResolveContainer queries every available container runtime and returns the
|
|
// merged set of matches against the query. Match predicate is substring
|
|
// (case-insensitive) across name, image, and command, unless exact is true in
|
|
// which case any of those fields must equal the query.
|
|
func ResolveContainer(query string, exact bool) []*model.ContainerMatch {
|
|
q := strings.ToLower(query)
|
|
var out []*model.ContainerMatch
|
|
seen := make(map[string]bool)
|
|
for _, rt := range registeredRuntimes {
|
|
if !rt.Available() {
|
|
continue
|
|
}
|
|
for _, c := range rt.List() {
|
|
if !matchContainer(c, q, exact) {
|
|
continue
|
|
}
|
|
key := rt.Name() + "|" + c.ID
|
|
if seen[key] {
|
|
continue
|
|
}
|
|
seen[key] = true
|
|
out = append(out, c)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func matchContainer(c *model.ContainerMatch, query string, exact bool) bool {
|
|
fields := []string{
|
|
strings.ToLower(c.Name),
|
|
strings.ToLower(c.Image),
|
|
strings.ToLower(c.Command),
|
|
strings.ToLower(c.ComposeProject),
|
|
strings.ToLower(c.ComposeService),
|
|
}
|
|
for _, f := range fields {
|
|
if f == "" {
|
|
continue
|
|
}
|
|
if exact {
|
|
if f == query {
|
|
return true
|
|
}
|
|
} else if strings.Contains(f, query) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ListAllContainers returns every container reported by every available
|
|
// runtime, deduped by runtime|id. Used by the TUI's Containers tab.
|
|
func ListAllContainers() []*model.ContainerMatch {
|
|
var out []*model.ContainerMatch
|
|
seen := make(map[string]bool)
|
|
for _, rt := range registeredRuntimes {
|
|
if !rt.Available() {
|
|
continue
|
|
}
|
|
for _, c := range rt.List() {
|
|
key := rt.Name() + "|" + c.ID
|
|
if seen[key] {
|
|
continue
|
|
}
|
|
seen[key] = true
|
|
out = append(out, c)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ResolveContainerHostPID returns the PID of the container's main process on
|
|
// the host. Returns 0 if the runtime can't be reached or the PID isn't
|
|
// available (container not running, namespaced PID, etc.).
|
|
func ResolveContainerHostPID(runtime, id string) int {
|
|
for _, rt := range registeredRuntimes {
|
|
if rt.Name() == runtime && rt.Available() {
|
|
return rt.HostPID(id)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// enrichingRuntime is implemented by runtimes that can supply additional
|
|
// per-container details via a follow-up call, used when a single match is
|
|
// resolved and the caller wants richer metadata than the initial list scan
|
|
// produced.
|
|
type enrichingRuntime interface {
|
|
Enrich(*model.ContainerMatch)
|
|
}
|
|
|
|
// EnrichContainer asks the originating runtime to fill in any extra fields
|
|
// available via a per-container query (e.g. crictl inspect). No-op when the
|
|
// runtime doesn't expose extra detail.
|
|
func EnrichContainer(match *model.ContainerMatch) {
|
|
if match == nil {
|
|
return
|
|
}
|
|
for _, rt := range registeredRuntimes {
|
|
if rt.Name() != match.Runtime || !rt.Available() {
|
|
continue
|
|
}
|
|
if e, ok := rt.(enrichingRuntime); ok {
|
|
e.Enrich(match)
|
|
}
|
|
return
|
|
}
|
|
}
|