mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
executed phase2 of the plan
This commit is contained in:
parent
1d12ef109d
commit
56e691c662
31 changed files with 3210 additions and 922 deletions
200
go.mod
200
go.mod
|
|
@ -1,16 +1,14 @@
|
|||
module github.com/christophe-duc/lazypodman
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.23.6
|
||||
go 1.24.2
|
||||
|
||||
require (
|
||||
github.com/OpenPeeDeeP/xdg v0.2.1-0.20190312153938-4ba9e1eb294c
|
||||
github.com/boz/go-throttle v0.0.0-20160922054636-fdc4eab740c1
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||
github.com/docker/cli v27.1.1+incompatible
|
||||
github.com/docker/docker v28.5.2+incompatible
|
||||
github.com/fatih/color v1.10.0
|
||||
github.com/containers/podman/v5 v5.7.1
|
||||
github.com/docker/docker v28.5.1+incompatible
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/go-errors/errors v1.5.1
|
||||
github.com/gookit/color v1.5.0
|
||||
github.com/imdario/mergo v0.3.16
|
||||
|
|
@ -20,66 +18,180 @@ require (
|
|||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221023210126-718a4caea996
|
||||
github.com/jesseduffield/yaml v0.0.0-20190702115811-b900b7e08b56
|
||||
github.com/mattn/go-runewidth v0.0.15
|
||||
github.com/mattn/go-runewidth v0.0.16
|
||||
github.com/mcuadros/go-lookup v0.0.0-20171110082742-5650f26be767
|
||||
github.com/mgutz/str v1.2.0
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
|
||||
github.com/samber/lo v1.31.0
|
||||
github.com/sasha-s/go-deadlock v0.3.1
|
||||
github.com/sasha-s/go-deadlock v0.3.5
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||
github.com/aead/serpent v0.0.0-20160714141033-fba169763ea6 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/checkpoint-restore/checkpointctl v1.4.0 // indirect
|
||||
github.com/checkpoint-restore/go-criu/v7 v7.2.0 // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v1.0.0-rc.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.17.0 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.2.3 // indirect
|
||||
github.com/containernetworking/cni v1.3.0 // indirect
|
||||
github.com/containernetworking/plugins v1.8.0 // indirect
|
||||
github.com/containers/buildah v1.42.2 // indirect
|
||||
github.com/containers/conmon v2.0.20+incompatible // indirect
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
|
||||
github.com/containers/luksy v0.0.0-20250910190358-2cf5bc928957 // indirect
|
||||
github.com/containers/ocicrypt v1.2.1 // indirect
|
||||
github.com/containers/psgo v1.9.1-0.20250826150930-4ae76f200c86 // indirect
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.6.0 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.5.2 // indirect
|
||||
github.com/disiqueira/gotree/v3 v3.0.2 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.4 // indirect
|
||||
github.com/docker/go-connections v0.6.0 // indirect
|
||||
github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/ebitengine/purego v0.9.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fsouza/go-dockerclient v1.12.2 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20241109141217-c266b19b28e9 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/go-containerregistry v0.20.6 // indirect
|
||||
github.com/google/go-intervals v0.0.2 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hpcloud/tail v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.32 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mistifyio/go-zfs/v3 v3.1.0 // indirect
|
||||
github.com/moby/buildkit v0.25.1 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/go-archive v0.1.0 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/sys/capability v0.4.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/moby/sys/user v0.4.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/nxadm/tail v1.4.11 // indirect
|
||||
github.com/opencontainers/cgroups v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runc v1.3.4 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.1 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 // indirect
|
||||
github.com/opencontainers/selinux v1.13.1 // indirect
|
||||
github.com/openshift/imagebuilder v1.2.19 // indirect
|
||||
github.com/pkg/sftp v1.13.9 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/proglottis/gpgme v0.1.5 // indirect
|
||||
github.com/seccomp/libseccomp-golang v0.11.1 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.1 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.9 // indirect
|
||||
github.com/sigstore/fulcio v1.7.1 // indirect
|
||||
github.com/sigstore/protobuf-specs v0.4.1 // indirect
|
||||
github.com/sigstore/sigstore v1.9.5 // indirect
|
||||
github.com/skeema/knownhosts v1.3.2 // indirect
|
||||
github.com/smallstep/pkcs7 v0.1.1 // indirect
|
||||
github.com/spf13/cobra v1.10.1 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
|
||||
github.com/sylabs/sif/v2 v2.22.0 // indirect
|
||||
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
github.com/vbatts/tar-split v0.12.1 // indirect
|
||||
github.com/vbauerster/mpb/v8 v8.10.2 // indirect
|
||||
github.com/vishvananda/netlink v1.3.1 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.etcd.io/bbolt v1.4.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
go.podman.io/common v0.66.1 // indirect
|
||||
go.podman.io/image/v5 v5.38.0 // indirect
|
||||
go.podman.io/storage v1.61.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/mod v0.28.0 // indirect
|
||||
golang.org/x/net v0.45.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
|
||||
google.golang.org/grpc v1.72.2 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
tags.cncf.io/container-device-interface v1.0.1 // indirect
|
||||
tags.cncf.io/container-device-interface/specs-go v1.0.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/gdamore/tcell/v2 v2.7.4 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/goccy/go-yaml v1.11.0
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/onsi/ginkgo v1.8.0 // indirect
|
||||
github.com/onsi/gomega v1.5.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/term v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gotest.tools/v3 v3.5.1 // indirect
|
||||
)
|
||||
|
|
|
|||
541
go.sum
541
go.sum
|
|
@ -1,13 +1,46 @@
|
|||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/OpenPeeDeeP/xdg v0.2.1-0.20190312153938-4ba9e1eb294c h1:YDsGA6tou+tAxVe0Dre29iSbQ8TrWdWfwOisKArJT5E=
|
||||
github.com/OpenPeeDeeP/xdg v0.2.1-0.20190312153938-4ba9e1eb294c/go.mod h1:tMoSueLQlMf0TCldjrJLNIjAc5qAOIcHt5REi88/Ygo=
|
||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
github.com/aead/serpent v0.0.0-20160714141033-fba169763ea6 h1:5L8Mj9Co9sJVgW3TpYk2gxGJnDjsYuboNTcRmbtGKGs=
|
||||
github.com/aead/serpent v0.0.0-20160714141033-fba169763ea6/go.mod h1:3HgLJ9d18kXMLQlJvIY3+FszZYMxCz8WfE2MQ7hDY0w=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/boz/go-throttle v0.0.0-20160922054636-fdc4eab740c1 h1:1fx+RA5lk1ZkzPAUP7DEgZnVHYxEcHO77vQO/V8z/2Q=
|
||||
github.com/boz/go-throttle v0.0.0-20160922054636-fdc4eab740c1/go.mod h1:z0nyIb42Zs97wyX1V+8MbEFhHeTw1OgFQfR6q57ZuHc=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/checkpoint-restore/checkpointctl v1.4.0 h1:3kRns56TArwiyHOMakaumUgSZZlB1hZBkjVgR6IeZ3E=
|
||||
github.com/checkpoint-restore/checkpointctl v1.4.0/go.mod h1:ynQ52zQBazgcTZuxpwTFzRinIcAf0haDTC1X1LA/FKA=
|
||||
github.com/checkpoint-restore/go-criu/v7 v7.2.0 h1:qGiWA4App1gGlEfIJ68WR9jbezV9J7yZdjzglezcqKo=
|
||||
github.com/checkpoint-restore/go-criu/v7 v7.2.0/go.mod h1:u0LCWLg0w4yqqu14aXhiB4YD3a1qd8EcCEg7vda5dwo=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
|
|
@ -16,28 +49,76 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X
|
|||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
|
||||
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.17.0 h1:+TyQIsR/zSFI1Rm31EQBwpAA1ovYgIKHy7kctL3sLcE=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.17.0/go.mod h1:s06tWAiJcXQo9/8AReBCIo/QxcXFZ2n4qfsRnpl71SM=
|
||||
github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=
|
||||
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
|
||||
github.com/containernetworking/cni v1.3.0 h1:v6EpN8RznAZj9765HhXQrtXgX+ECGebEYEmnuFjskwo=
|
||||
github.com/containernetworking/cni v1.3.0/go.mod h1:Bs8glZjjFfGPHMw6hQu82RUgEPNGEaBb9KS5KtNMnJ4=
|
||||
github.com/containernetworking/plugins v1.8.0 h1:WjGbV/0UQyo8A4qBsAh6GaDAtu1hevxVxsEuqtBqUFk=
|
||||
github.com/containernetworking/plugins v1.8.0/go.mod h1:JG3BxoJifxxHBhG3hFyxyhid7JgRVBu/wtooGEvWf1c=
|
||||
github.com/containers/buildah v1.42.2 h1:be4mKtMOtvuW3R1TYWP+MupxzCaq6PRn7+m1iZH9YbE=
|
||||
github.com/containers/buildah v1.42.2/go.mod h1:SDA+ClXamnZPV7GBS2uKY0dfXKfvTykSUA+kJWa1mNg=
|
||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/luksy v0.0.0-20250910190358-2cf5bc928957 h1:WxixhZ0typ8o668V0V7RVCZb3lNs58UF42RbwlQ4vdE=
|
||||
github.com/containers/luksy v0.0.0-20250910190358-2cf5bc928957/go.mod h1:fGPsLPRi1etbHfe5o6sdx6ajsW810tI43uyF6ugmP/o=
|
||||
github.com/containers/ocicrypt v1.2.1 h1:0qIOTT9DoYwcKmxSt8QJt+VzMY18onl9jUXsxpVhSmM=
|
||||
github.com/containers/ocicrypt v1.2.1/go.mod h1:aD0AAqfMp0MtwqWgHM1bUwe1anx0VazI108CRrSKINQ=
|
||||
github.com/containers/podman/v5 v5.7.1 h1:rxt3Fl3JS85ZnWZU7jTqR9YOk9fYFqI/2Gy6UMooAhk=
|
||||
github.com/containers/podman/v5 v5.7.1/go.mod h1:+3SYEQiTjid9pnoFMF8jKWVOymTzIQCFGDsZ28b5nqw=
|
||||
github.com/containers/psgo v1.9.1-0.20250826150930-4ae76f200c86 h1:bYj0TVlkRZtMJYd6SbFOi1gjUJDJmVsYCpJla3URD7Y=
|
||||
github.com/containers/psgo v1.9.1-0.20250826150930-4ae76f200c86/go.mod h1:52GX23ST30pXpeviDvNpOCXoHqr+WJDv+7BjEH+AabY=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=
|
||||
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
|
||||
github.com/cyphar/filepath-securejoin v0.5.2 h1:w/T2bhKr4pgwG0SUGjU4S/Is9+zUknLh5ROTJLzWX8E=
|
||||
github.com/cyphar/filepath-securejoin v0.5.2/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWhkNRq8=
|
||||
github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE=
|
||||
github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
|
||||
github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
||||
github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
|
||||
github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
|
||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||
github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8 h1:IMfrF5LCzP2Vhw7j4IIH3HxPsCLuZYjDqFAM/C88ulg=
|
||||
github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8/go.mod h1:LFyLie6XcDbyKGeVK6bHe+9aJTYCxWLBg5IrJZOaXKA=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k=
|
||||
github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
|
||||
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fsouza/go-dockerclient v1.12.2 h1:+pbP/SacoHfqaVZuiudvcdYGd9jzU7y9EcgoBOHivEI=
|
||||
github.com/fsouza/go-dockerclient v1.12.2/go.mod h1:ZGCkAsnBGjnTRG9wV6QaICPJ5ig2KlaxTccDQy5WQ38=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
|
||||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||
|
|
@ -46,32 +127,68 @@ github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7
|
|||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54=
|
||||
github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20241109141217-c266b19b28e9 h1:Kzr9J0S0V2PRxiX6B6xw1kWjzsIyjLO2Ibi4fNTaYBM=
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20241109141217-c266b19b28e9/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU=
|
||||
github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
|
||||
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
|
||||
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY=
|
||||
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
|
||||
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
|
||||
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM=
|
||||
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
|
||||
github.com/jesseduffield/asciigraph v0.0.0-20190605104717-6d88e39309ee h1:7Zi/OQlGbMz4MT2V1+prN/gv1C64NDyVb/MbJnS0ZfA=
|
||||
|
|
@ -84,164 +201,396 @@ github.com/jesseduffield/lazycore v0.0.0-20221023210126-718a4caea996 h1:CH1en6Gp
|
|||
github.com/jesseduffield/lazycore v0.0.0-20221023210126-718a4caea996/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ=
|
||||
github.com/jesseduffield/yaml v0.0.0-20190702115811-b900b7e08b56 h1:33wSxJWU/f2TAozHYtJ8zqBxEnEVYM+22moLoiAkxvg=
|
||||
github.com/jesseduffield/yaml v0.0.0-20190702115811-b900b7e08b56/go.mod h1:FZJBwOhE+RXz8EVZfY+xnbCw2cVOwxlK3/aIi581z/s=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=
|
||||
github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
|
||||
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ=
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
|
||||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
|
||||
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mcuadros/go-lookup v0.0.0-20171110082742-5650f26be767 h1:BrhJNdEFWGuiJk/3/SwsG5Rex3zjFxYsDi2bpd7382Y=
|
||||
github.com/mcuadros/go-lookup v0.0.0-20171110082742-5650f26be767/go.mod h1:ct+byCpkFokm4J0tiuAvB8cf2ttm6GcCe89Yr25nGKg=
|
||||
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
|
||||
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mistifyio/go-zfs/v3 v3.1.0 h1:FZaylcg0hjUp27i23VcJJQiuBeAZjrC8lPqCGM1CopY=
|
||||
github.com/mistifyio/go-zfs/v3 v3.1.0/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k=
|
||||
github.com/moby/buildkit v0.25.1 h1:j7IlVkeNbEo+ZLoxdudYCHpmTsbwKvhgc/6UJ/mY/o8=
|
||||
github.com/moby/buildkit v0.25.1/go.mod h1:phM8sdqnvgK2y1dPDnbwI6veUCXHOZ6KFSl6E164tkc=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
|
||||
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
|
||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
|
||||
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
|
||||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/ginkgo/v2 v2.26.0 h1:1J4Wut1IlYZNEAWIV3ALrT9NfiaGW2cDCJQSFQMs/gE=
|
||||
github.com/onsi/ginkgo/v2 v2.26.0/go.mod h1:qhEywmzWTBUY88kfO0BRvX4py7scov9yR+Az2oavUzw=
|
||||
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
||||
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
|
||||
github.com/opencontainers/cgroups v0.0.5 h1:DRITAqcOnY0uSBzIpt1RYWLjh5DPDiqUs4fY6Y0ktls=
|
||||
github.com/opencontainers/cgroups v0.0.5/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/opencontainers/runc v1.3.4 h1:+lwmPUTzbgv0JFqu8zBU2WtHYbm+JPPS9hxB/PvWd30=
|
||||
github.com/opencontainers/runc v1.3.4/go.mod h1:o1wyv76EDlTkcf0KTFgN8bMWLPvgF/HfX709lDv+rr4=
|
||||
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
|
||||
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 h1:2xZEHOdeQBV6PW8ZtimN863bIOl7OCW/X10K0cnxKeA=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2/go.mod h1:MXdPzqAA8pHC58USHqNCSjyLnRQ6D+NjbpP+02Z1U/0=
|
||||
github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE=
|
||||
github.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg=
|
||||
github.com/openshift/imagebuilder v1.2.19 h1:Xqq36KMJgsRU2MPaLRML23Myvk+AaY8pE8VJ6m6Vmy4=
|
||||
github.com/openshift/imagebuilder v1.2.19/go.mod h1:fdbnfQWjxMBoB/jrvEzUk+UT1zqvtZZj7oQ7GU6RD9I=
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/proglottis/gpgme v0.1.5 h1:KCGyOw8sQ+SI96j6G8D8YkOGn+1TwbQTT9/zQXoVlz0=
|
||||
github.com/proglottis/gpgme v0.1.5/go.mod h1:5LoXMgpE4bttgwwdv9bLs/vwqv3qV7F4glEEZ7mRKrM=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM=
|
||||
github.com/samber/lo v1.31.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
|
||||
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
|
||||
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
|
||||
github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=
|
||||
github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5E=
|
||||
github.com/sebdah/goldie/v2 v2.7.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||
github.com/seccomp/libseccomp-golang v0.11.1 h1:wuk4ZjSx6kyQII4rj6G6fvVzRHQaSiPvccJazDagu4g=
|
||||
github.com/seccomp/libseccomp-golang v0.11.1/go.mod h1:5m1Lk8E9OwgZTTVz4bBOer7JuazaBa+xTkM895tDiWc=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.1 h1:nZZaNz4DiERIQguNy0cL5qTdn9lR8XKHf4RUyG1Sx3g=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.1/go.mod h1:np53YzT0zXGMv6x4iEWc9Z59uR+x+ndLwCLqPYpLXVU=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/shirou/gopsutil/v4 v4.25.9 h1:JImNpf6gCVhKgZhtaAHJ0serfFGtlfIlSC08eaKdTrU=
|
||||
github.com/shirou/gopsutil/v4 v4.25.9/go.mod h1:gxIxoC+7nQRwUl/xNhutXlD8lq+jxTgpIkEf3rADHL8=
|
||||
github.com/sigstore/fulcio v1.7.1 h1:RcoW20Nz49IGeZyu3y9QYhyyV3ZKQ85T+FXPKkvE+aQ=
|
||||
github.com/sigstore/fulcio v1.7.1/go.mod h1:7lYY+hsd8Dt+IvKQRC+KEhWpCZ/GlmNvwIa5JhypMS8=
|
||||
github.com/sigstore/protobuf-specs v0.4.1 h1:5SsMqZbdkcO/DNHudaxuCUEjj6x29tS2Xby1BxGU7Zc=
|
||||
github.com/sigstore/protobuf-specs v0.4.1/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc=
|
||||
github.com/sigstore/sigstore v1.9.5 h1:Wm1LT9yF4LhQdEMy5A2JeGRHTrAWGjT3ubE5JUSrGVU=
|
||||
github.com/sigstore/sigstore v1.9.5/go.mod h1:VtxgvGqCmEZN9X2zhFSOkfXxvKUjpy8RpUW39oCtoII=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg=
|
||||
github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow=
|
||||
github.com/smallstep/pkcs7 v0.1.1 h1:x+rPdt2W088V9Vkjho4KtoggyktZJlMduZAtRHm68LU=
|
||||
github.com/smallstep/pkcs7 v0.1.1/go.mod h1:dL6j5AIz9GHjVEBTXtW+QliALcgM19RtXaTeyxI+AfA=
|
||||
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
|
||||
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw=
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/sylabs/sif/v2 v2.22.0 h1:Y+xXufp4RdgZe02SR3nWEg7S6q4tPWN237WHYzkDSKA=
|
||||
github.com/sylabs/sif/v2 v2.22.0/go.mod h1:W1XhWTmG1KcG7j5a3KSYdMcUIFvbs240w/MMVW627hs=
|
||||
github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc=
|
||||
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||
github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
|
||||
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/vbauerster/mpb/v8 v8.10.2 h1:2uBykSHAYHekE11YvJhKxYmLATKHAGorZwFlyNw4hHM=
|
||||
github.com/vbauerster/mpb/v8 v8.10.2/go.mod h1:+Ja4P92E3/CorSZgfDtK46D7AVbDqmBQRTmyTqPElo0=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk=
|
||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
||||
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.podman.io/common v0.66.1 h1:zDyd4HhVgQAN8LupBHCnhtM3FEOJ9DwmThjulXZq2qA=
|
||||
go.podman.io/common v0.66.1/go.mod h1:aNd2a0S7pY+fx1X5kpQYuF4hbwLU8ZOccuVrhu7h1Xc=
|
||||
go.podman.io/image/v5 v5.38.0 h1:aUKrCANkPvze1bnhLJsaubcfz0d9v/bSDLnwsXJm6G4=
|
||||
go.podman.io/image/v5 v5.38.0/go.mod h1:hSIoIUzgBnmc4DjoIdzk63aloqVbD7QXDMkSE/cvG90=
|
||||
go.podman.io/storage v1.61.0 h1:5hD/oyRYt1f1gxgvect+8syZBQhGhV28dCw2+CZpx0Q=
|
||||
go.podman.io/storage v1.61.0/go.mod h1:A3UBK0XypjNZ6pghRhuxg62+2NIm5lcUGv/7XyMhMUI=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
|
||||
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e h1:UdXH7Kzbj+Vzastr5nVfccbmFsmYNygVLSPk1pEfDoY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||
tags.cncf.io/container-device-interface v1.0.1 h1:KqQDr4vIlxwfYh0Ed/uJGVgX+CHAkahrgabg6Q8GYxc=
|
||||
tags.cncf.io/container-device-interface v1.0.1/go.mod h1:JojJIOeW3hNbcnOH2q0NrWNha/JuHoDZcmYxAZwb2i0=
|
||||
tags.cncf.io/container-device-interface/specs-go v1.0.0 h1:8gLw29hH1ZQP9K1YtAzpvkHCjjyIxHZYzBAvlQ+0vD8=
|
||||
tags.cncf.io/container-device-interface/specs-go v1.0.0/go.mod h1:u86hoFWqnh3hWz3esofRFKbI261bUlvUfLKGrDhJkgQ=
|
||||
|
|
|
|||
4
main.go
4
main.go
|
|
@ -8,10 +8,10 @@ import (
|
|||
"runtime"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/integrii/flaggy"
|
||||
"github.com/christophe-duc/lazypodman/pkg/app"
|
||||
"github.com/christophe-duc/lazypodman/pkg/commands"
|
||||
"github.com/christophe-duc/lazypodman/pkg/config"
|
||||
"github.com/christophe-duc/lazypodman/pkg/utils"
|
||||
"github.com/jesseduffield/yaml"
|
||||
|
|
@ -88,7 +88,7 @@ func main() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
if client.IsErrConnectionFailed(err) {
|
||||
if commands.IsConnectionFailed(err) {
|
||||
log.Println(app.Tr.ConnectionFailed)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ type App struct {
|
|||
Config *config.AppConfig
|
||||
Log *logrus.Entry
|
||||
OSCommand *commands.OSCommand
|
||||
DockerCommand *commands.DockerCommand
|
||||
PodmanCommand *commands.PodmanCommand
|
||||
Gui *gui.Gui
|
||||
Tr *i18n.TranslationSet
|
||||
ErrorChan chan error
|
||||
|
|
@ -43,12 +43,12 @@ func NewApp(config *config.AppConfig) (*App, error) {
|
|||
|
||||
// here is the place to make use of the docker-compose.yml file in the current directory
|
||||
|
||||
app.DockerCommand, err = commands.NewDockerCommand(app.Log, app.OSCommand, app.Tr, app.Config, app.ErrorChan)
|
||||
app.PodmanCommand, err = commands.NewPodmanCommand(app.Log, app.OSCommand, app.Tr, app.Config, app.ErrorChan)
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
app.closers = append(app.closers, app.DockerCommand)
|
||||
app.Gui, err = gui.NewGui(app.Log, app.DockerCommand, app.OSCommand, app.Tr, config, app.ErrorChan)
|
||||
app.closers = append(app.closers, app.PodmanCommand)
|
||||
app.Gui, err = gui.NewGui(app.Log, app.PodmanCommand, app.OSCommand, app.Tr, config, app.ErrorChan)
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
|
|
@ -77,6 +77,14 @@ func (app *App) KnownError(err error) (string, bool) {
|
|||
originalError: "Got permission denied while trying to connect to the Docker daemon socket",
|
||||
newError: app.Tr.CannotAccessDockerSocketError,
|
||||
},
|
||||
{
|
||||
originalError: "Got permission denied while trying to connect to the Podman",
|
||||
newError: app.Tr.CannotAccessDockerSocketError,
|
||||
},
|
||||
{
|
||||
originalError: "permission denied while trying to connect",
|
||||
newError: app.Tr.CannotAccessDockerSocketError,
|
||||
},
|
||||
}
|
||||
|
||||
for _, mapping := range mappings {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ import (
|
|||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/christophe-duc/lazypodman/pkg/i18n"
|
||||
"github.com/christophe-duc/lazypodman/pkg/utils"
|
||||
|
|
@ -17,7 +14,7 @@ import (
|
|||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// Container : A docker Container
|
||||
// Container represents a Podman container
|
||||
type Container struct {
|
||||
Name string
|
||||
ServiceName string
|
||||
|
|
@ -27,24 +24,26 @@ type Container struct {
|
|||
OneOff bool
|
||||
ProjectName string
|
||||
ID string
|
||||
Container container.Summary
|
||||
Client *client.Client
|
||||
Summary ContainerSummary
|
||||
Runtime ContainerRuntime
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
StatHistory []*RecordedStats
|
||||
Details container.InspectResponse
|
||||
Details *ContainerDetails
|
||||
MonitoringStats bool
|
||||
DockerCommand LimitedDockerCommand
|
||||
PodmanCommand LimitedPodmanCommand
|
||||
Tr *i18n.TranslationSet
|
||||
|
||||
StatsMutex deadlock.Mutex
|
||||
}
|
||||
|
||||
// Remove removes the container
|
||||
func (c *Container) Remove(options container.RemoveOptions) error {
|
||||
func (c *Container) Remove(force bool, removeVolumes bool) error {
|
||||
c.Log.Warn(fmt.Sprintf("removing container %s", c.Name))
|
||||
if err := c.Client.ContainerRemove(context.Background(), c.ID, options); err != nil {
|
||||
if strings.Contains(err.Error(), "Stop the container before attempting removal or force remove") {
|
||||
ctx := context.Background()
|
||||
if err := c.Runtime.RemoveContainer(ctx, c.ID, force, removeVolumes); err != nil {
|
||||
if strings.Contains(err.Error(), "Stop the container before attempting removal or force remove") ||
|
||||
strings.Contains(err.Error(), "container is running") {
|
||||
return ComplexError{
|
||||
Code: MustStopContainer,
|
||||
Message: err.Error(),
|
||||
|
|
@ -60,25 +59,29 @@ func (c *Container) Remove(options container.RemoveOptions) error {
|
|||
// Stop stops the container
|
||||
func (c *Container) Stop() error {
|
||||
c.Log.Warn(fmt.Sprintf("stopping container %s", c.Name))
|
||||
return c.Client.ContainerStop(context.Background(), c.ID, container.StopOptions{})
|
||||
ctx := context.Background()
|
||||
return c.Runtime.StopContainer(ctx, c.ID, nil)
|
||||
}
|
||||
|
||||
// Pause pauses the container
|
||||
func (c *Container) Pause() error {
|
||||
c.Log.Warn(fmt.Sprintf("pausing container %s", c.Name))
|
||||
return c.Client.ContainerPause(context.Background(), c.ID)
|
||||
ctx := context.Background()
|
||||
return c.Runtime.PauseContainer(ctx, c.ID)
|
||||
}
|
||||
|
||||
// Unpause unpauses the container
|
||||
func (c *Container) Unpause() error {
|
||||
c.Log.Warn(fmt.Sprintf("unpausing container %s", c.Name))
|
||||
return c.Client.ContainerUnpause(context.Background(), c.ID)
|
||||
ctx := context.Background()
|
||||
return c.Runtime.UnpauseContainer(ctx, c.ID)
|
||||
}
|
||||
|
||||
// Restart restarts the container
|
||||
func (c *Container) Restart() error {
|
||||
c.Log.Warn(fmt.Sprintf("restarting container %s", c.Name))
|
||||
return c.Client.ContainerRestart(context.Background(), c.ID, container.StopOptions{})
|
||||
ctx := context.Background()
|
||||
return c.Runtime.RestartContainer(ctx, c.ID, nil)
|
||||
}
|
||||
|
||||
// Attach attaches the container
|
||||
|
|
@ -88,44 +91,47 @@ func (c *Container) Attach() (*exec.Cmd, error) {
|
|||
}
|
||||
|
||||
// verify that we can in fact attach to this container
|
||||
if !c.Details.Config.OpenStdin {
|
||||
if c.Details.Config != nil && !c.Details.Config.OpenStdin {
|
||||
return nil, errors.New(c.Tr.UnattachableContainerError)
|
||||
}
|
||||
|
||||
if c.Container.State == "exited" {
|
||||
if c.Summary.State == "exited" {
|
||||
return nil, errors.New(c.Tr.CannotAttachStoppedContainerError)
|
||||
}
|
||||
|
||||
c.Log.Warn(fmt.Sprintf("attaching to container %s", c.Name))
|
||||
// TODO: use SDK
|
||||
cmd := c.OSCommand.NewCmd("docker", "attach", "--sig-proxy=false", c.ID)
|
||||
// Use podman attach command
|
||||
cmd := c.OSCommand.NewCmd("podman", "attach", "--sig-proxy=false", c.ID)
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// Top returns process information
|
||||
func (c *Container) Top(ctx context.Context) (container.TopResponse, error) {
|
||||
detail, err := c.Inspect()
|
||||
func (c *Container) Top(ctx context.Context) (TopResponse, error) {
|
||||
details, err := c.Inspect()
|
||||
if err != nil {
|
||||
return container.TopResponse{}, err
|
||||
return TopResponse{}, err
|
||||
}
|
||||
|
||||
// check container status
|
||||
if !detail.State.Running {
|
||||
return container.TopResponse{}, errors.New("container is not running")
|
||||
if details.State == nil || !details.State.Running {
|
||||
return TopResponse{}, errors.New("container is not running")
|
||||
}
|
||||
|
||||
return c.Client.ContainerTop(ctx, c.ID, []string{})
|
||||
}
|
||||
titles, processes, err := c.Runtime.ContainerTop(ctx, c.ID)
|
||||
if err != nil {
|
||||
return TopResponse{}, err
|
||||
}
|
||||
|
||||
// PruneContainers prunes containers
|
||||
func (c *DockerCommand) PruneContainers() error {
|
||||
_, err := c.Client.ContainersPrune(context.Background(), filters.Args{})
|
||||
return err
|
||||
return TopResponse{
|
||||
Titles: titles,
|
||||
Processes: processes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Inspect returns details about the container
|
||||
func (c *Container) Inspect() (container.InspectResponse, error) {
|
||||
return c.Client.ContainerInspect(context.Background(), c.ID)
|
||||
func (c *Container) Inspect() (*ContainerDetails, error) {
|
||||
ctx := context.Background()
|
||||
return c.Runtime.InspectContainer(ctx, c.ID)
|
||||
}
|
||||
|
||||
// RenderTop returns details about the container
|
||||
|
|
@ -142,5 +148,10 @@ func (c *Container) RenderTop(ctx context.Context) (string, error) {
|
|||
// Sometimes it takes some time for a container to have its details loaded
|
||||
// after it starts.
|
||||
func (c *Container) DetailsLoaded() bool {
|
||||
return c.Details.ContainerJSONBase != nil
|
||||
return c.Details != nil
|
||||
}
|
||||
|
||||
// GetState returns the container state from the Summary
|
||||
func (c *Container) GetState() string {
|
||||
return c.Summary.State
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,425 +0,0 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
ogLog "log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
cliconfig "github.com/docker/cli/cli/config"
|
||||
ddocker "github.com/docker/cli/cli/context/docker"
|
||||
ctxstore "github.com/docker/cli/cli/context/store"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/christophe-duc/lazypodman/pkg/commands/ssh"
|
||||
"github.com/christophe-duc/lazypodman/pkg/config"
|
||||
"github.com/christophe-duc/lazypodman/pkg/i18n"
|
||||
"github.com/christophe-duc/lazypodman/pkg/utils"
|
||||
"github.com/sasha-s/go-deadlock"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
dockerHostEnvKey = "DOCKER_HOST"
|
||||
)
|
||||
|
||||
// DockerCommand is our main docker interface
|
||||
type DockerCommand struct {
|
||||
Log *logrus.Entry
|
||||
OSCommand *OSCommand
|
||||
Tr *i18n.TranslationSet
|
||||
Config *config.AppConfig
|
||||
Client *client.Client
|
||||
InDockerComposeProject bool
|
||||
ErrorChan chan error
|
||||
ContainerMutex deadlock.Mutex
|
||||
ServiceMutex deadlock.Mutex
|
||||
|
||||
Closers []io.Closer
|
||||
}
|
||||
|
||||
var _ io.Closer = &DockerCommand{}
|
||||
|
||||
// LimitedDockerCommand is a stripped-down DockerCommand with just the methods the container/service/image might need
|
||||
type LimitedDockerCommand interface {
|
||||
NewCommandObject(CommandObject) CommandObject
|
||||
}
|
||||
|
||||
// CommandObject is what we pass to our template resolvers when we are running a custom command. We do not guarantee that all fields will be populated: just the ones that make sense for the current context
|
||||
type CommandObject struct {
|
||||
DockerCompose string
|
||||
Service *Service
|
||||
Container *Container
|
||||
Image *Image
|
||||
Volume *Volume
|
||||
Network *Network
|
||||
}
|
||||
|
||||
// NewCommandObject takes a command object and returns a default command object with the passed command object merged in
|
||||
func (c *DockerCommand) NewCommandObject(obj CommandObject) CommandObject {
|
||||
defaultObj := CommandObject{DockerCompose: c.Config.UserConfig.CommandTemplates.DockerCompose}
|
||||
_ = mergo.Merge(&defaultObj, obj)
|
||||
return defaultObj
|
||||
}
|
||||
|
||||
// NewDockerCommand it runs docker commands
|
||||
func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*DockerCommand, error) {
|
||||
dockerHost, err := determineDockerHost()
|
||||
if err != nil {
|
||||
ogLog.Printf("> could not determine host %v", err)
|
||||
}
|
||||
|
||||
// NOTE: Inject the determined docker host to the environment. This allows the
|
||||
// `SSHHandler.HandleSSHDockerHost()` to create a local unix socket tunneled
|
||||
// over SSH to the specified ssh host.
|
||||
if strings.HasPrefix(dockerHost, "ssh://") {
|
||||
os.Setenv(dockerHostEnvKey, dockerHost)
|
||||
}
|
||||
|
||||
tunnelCloser, err := ssh.NewSSHHandler(osCommand).HandleSSHDockerHost()
|
||||
if err != nil {
|
||||
ogLog.Fatal(err)
|
||||
}
|
||||
|
||||
// Retrieve the docker host from the environment which could have been set by
|
||||
// the `SSHHandler.HandleSSHDockerHost()` and override `dockerHost`.
|
||||
dockerHostFromEnv := os.Getenv(dockerHostEnvKey)
|
||||
if dockerHostFromEnv != "" {
|
||||
dockerHost = dockerHostFromEnv
|
||||
}
|
||||
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation(), client.WithHost(dockerHost))
|
||||
if err != nil {
|
||||
ogLog.Fatal(err)
|
||||
}
|
||||
|
||||
dockerCommand := &DockerCommand{
|
||||
Log: log,
|
||||
OSCommand: osCommand,
|
||||
Tr: tr,
|
||||
Config: config,
|
||||
Client: cli,
|
||||
ErrorChan: errorChan,
|
||||
InDockerComposeProject: true,
|
||||
Closers: []io.Closer{tunnelCloser},
|
||||
}
|
||||
|
||||
dockerCommand.setDockerComposeCommand(config)
|
||||
|
||||
err = osCommand.RunCommand(
|
||||
utils.ApplyTemplate(
|
||||
config.UserConfig.CommandTemplates.CheckDockerComposeConfig,
|
||||
dockerCommand.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
dockerCommand.InDockerComposeProject = false
|
||||
log.Warn(err.Error())
|
||||
}
|
||||
|
||||
return dockerCommand, nil
|
||||
}
|
||||
|
||||
func (c *DockerCommand) setDockerComposeCommand(config *config.AppConfig) {
|
||||
if config.UserConfig.CommandTemplates.DockerCompose != "docker compose" {
|
||||
return
|
||||
}
|
||||
|
||||
// it's possible that a user is still using docker-compose, so we'll check if 'docker comopose' is available, and if not, we'll fall back to 'docker-compose'
|
||||
err := c.OSCommand.RunCommand("docker compose version")
|
||||
if err != nil {
|
||||
config.UserConfig.CommandTemplates.DockerCompose = "docker-compose"
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DockerCommand) Close() error {
|
||||
return utils.CloseMany(c.Closers)
|
||||
}
|
||||
|
||||
func (c *DockerCommand) CreateClientStatMonitor(container *Container) {
|
||||
container.MonitoringStats = true
|
||||
stream, err := c.Client.ContainerStats(context.Background(), container.ID, true)
|
||||
if err != nil {
|
||||
// not creating error panel because if we've disconnected from docker we'll
|
||||
// have already created an error panel
|
||||
c.Log.Error(err)
|
||||
container.MonitoringStats = false
|
||||
return
|
||||
}
|
||||
|
||||
defer stream.Body.Close()
|
||||
|
||||
scanner := bufio.NewScanner(stream.Body)
|
||||
for scanner.Scan() {
|
||||
data := scanner.Bytes()
|
||||
var stats ContainerStats
|
||||
_ = json.Unmarshal(data, &stats)
|
||||
|
||||
recordedStats := &RecordedStats{
|
||||
ClientStats: stats,
|
||||
DerivedStats: DerivedStats{
|
||||
CPUPercentage: stats.CalculateContainerCPUPercentage(),
|
||||
MemoryPercentage: stats.CalculateContainerMemoryUsage(),
|
||||
},
|
||||
RecordedAt: time.Now(),
|
||||
}
|
||||
|
||||
container.appendStats(recordedStats, c.Config.UserConfig.Stats.MaxDuration)
|
||||
}
|
||||
|
||||
container.MonitoringStats = false
|
||||
}
|
||||
|
||||
func (c *DockerCommand) RefreshContainersAndServices(currentServices []*Service, currentContainers []*Container) ([]*Container, []*Service, error) {
|
||||
c.ServiceMutex.Lock()
|
||||
defer c.ServiceMutex.Unlock()
|
||||
|
||||
containers, err := c.GetContainers(currentContainers)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var services []*Service
|
||||
// we only need to get these services once because they won't change in the runtime of the program
|
||||
if currentServices != nil {
|
||||
services = currentServices
|
||||
} else {
|
||||
services, err = c.GetServices()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
c.assignContainersToServices(containers, services)
|
||||
|
||||
return containers, services, nil
|
||||
}
|
||||
|
||||
func (c *DockerCommand) assignContainersToServices(containers []*Container, services []*Service) {
|
||||
L:
|
||||
for _, service := range services {
|
||||
for _, ctr := range containers {
|
||||
if !ctr.OneOff && ctr.ServiceName == service.Name {
|
||||
service.Container = ctr
|
||||
continue L
|
||||
}
|
||||
}
|
||||
service.Container = nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetContainers gets the docker containers
|
||||
func (c *DockerCommand) GetContainers(existingContainers []*Container) ([]*Container, error) {
|
||||
c.ContainerMutex.Lock()
|
||||
defer c.ContainerMutex.Unlock()
|
||||
|
||||
containers, err := c.Client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownContainers := make([]*Container, len(containers))
|
||||
|
||||
for i, ctr := range containers {
|
||||
var newContainer *Container
|
||||
|
||||
// check if we already have data stored against the container
|
||||
for _, existingContainer := range existingContainers {
|
||||
if existingContainer.ID == ctr.ID {
|
||||
newContainer = existingContainer
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// initialise the container if it's completely new
|
||||
if newContainer == nil {
|
||||
newContainer = &Container{
|
||||
ID: ctr.ID,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
Tr: c.Tr,
|
||||
}
|
||||
}
|
||||
|
||||
newContainer.Container = ctr
|
||||
// if the container is made with a name label we will use that
|
||||
if name, ok := ctr.Labels["name"]; ok {
|
||||
newContainer.Name = name
|
||||
} else {
|
||||
if len(ctr.Names) > 0 {
|
||||
newContainer.Name = strings.TrimLeft(ctr.Names[0], "/")
|
||||
} else {
|
||||
newContainer.Name = ctr.ID
|
||||
}
|
||||
}
|
||||
newContainer.ServiceName = ctr.Labels["com.docker.compose.service"]
|
||||
newContainer.ProjectName = ctr.Labels["com.docker.compose.project"]
|
||||
newContainer.ContainerNumber = ctr.Labels["com.docker.compose.container"]
|
||||
newContainer.OneOff = ctr.Labels["com.docker.compose.oneoff"] == "True"
|
||||
|
||||
ownContainers[i] = newContainer
|
||||
}
|
||||
|
||||
c.SetContainerDetails(ownContainers)
|
||||
|
||||
return ownContainers, nil
|
||||
}
|
||||
|
||||
// GetServices gets services
|
||||
func (c *DockerCommand) GetServices() ([]*Service, error) {
|
||||
if !c.InDockerComposeProject {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
composeCommand := c.Config.UserConfig.CommandTemplates.DockerCompose
|
||||
output, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("%s config --services", composeCommand))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// output looks like:
|
||||
// service1
|
||||
// service2
|
||||
|
||||
lines := utils.SplitLines(output)
|
||||
services := make([]*Service, len(lines))
|
||||
for i, str := range lines {
|
||||
services[i] = &Service{
|
||||
Name: str,
|
||||
ID: str,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (c *DockerCommand) RefreshContainerDetails(containers []*Container) error {
|
||||
c.ContainerMutex.Lock()
|
||||
defer c.ContainerMutex.Unlock()
|
||||
|
||||
c.SetContainerDetails(containers)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Attaches the details returned from docker inspect to each of the containers
|
||||
// this contains a bit more info than what you get from the go-docker client
|
||||
func (c *DockerCommand) SetContainerDetails(containers []*Container) {
|
||||
wg := sync.WaitGroup{}
|
||||
for _, ctr := range containers {
|
||||
ctr := ctr
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
details, err := c.Client.ContainerInspect(context.Background(), ctr.ID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
} else {
|
||||
ctr.Details = details
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// ViewAllLogs attaches to a subprocess viewing all the logs from docker-compose
|
||||
func (c *DockerCommand) ViewAllLogs() (*exec.Cmd, error) {
|
||||
cmd := c.OSCommand.ExecutableFromString(
|
||||
utils.ApplyTemplate(
|
||||
c.OSCommand.Config.UserConfig.CommandTemplates.ViewAllLogs,
|
||||
c.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
|
||||
c.OSCommand.PrepareForChildren(cmd)
|
||||
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// DockerComposeConfig returns the result of 'docker-compose config'
|
||||
func (c *DockerCommand) DockerComposeConfig() string {
|
||||
output, err := c.OSCommand.RunCommandWithOutput(
|
||||
utils.ApplyTemplate(
|
||||
c.OSCommand.Config.UserConfig.CommandTemplates.DockerComposeConfig,
|
||||
c.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
output = err.Error()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// determineDockerHost tries to the determine the docker host that we should connect to
|
||||
// in the following order of decreasing precedence:
|
||||
// - value of "DOCKER_HOST" environment variable
|
||||
// - host retrieved from the current context (specified via DOCKER_CONTEXT)
|
||||
// - "default docker host" for the host operating system, otherwise
|
||||
func determineDockerHost() (string, error) {
|
||||
// If the docker host is explicitly set via the "DOCKER_HOST" environment variable,
|
||||
// then its a no-brainer :shrug:
|
||||
if os.Getenv("DOCKER_HOST") != "" {
|
||||
return os.Getenv("DOCKER_HOST"), nil
|
||||
}
|
||||
|
||||
currentContext := os.Getenv("DOCKER_CONTEXT")
|
||||
if currentContext == "" {
|
||||
cf, err := cliconfig.Load(cliconfig.Dir())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
currentContext = cf.CurrentContext
|
||||
}
|
||||
|
||||
// On some systems (windows) `default` is stored in the docker config as the currentContext.
|
||||
if currentContext == "" || currentContext == "default" {
|
||||
// If a docker context is neither specified via the "DOCKER_CONTEXT" environment variable nor via the
|
||||
// $HOME/.docker/config file, then we fall back to connecting to the "default docker host" meant for
|
||||
// the host operating system.
|
||||
return defaultDockerHost, nil
|
||||
}
|
||||
|
||||
storeConfig := ctxstore.NewConfig(
|
||||
func() interface{} { return &ddocker.EndpointMeta{} },
|
||||
ctxstore.EndpointTypeGetter(ddocker.DockerEndpoint, func() interface{} { return &ddocker.EndpointMeta{} }),
|
||||
)
|
||||
|
||||
st := ctxstore.New(cliconfig.ContextStoreDir(), storeConfig)
|
||||
md, err := st.GetMetadata(currentContext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dockerEP, ok := md.Endpoints[ddocker.DockerEndpoint]
|
||||
if !ok {
|
||||
return "", err
|
||||
}
|
||||
dockerEPMeta, ok := dockerEP.(ddocker.EndpointMeta)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("expected docker.EndpointMeta, got %T", dockerEP)
|
||||
}
|
||||
|
||||
if dockerEPMeta.Host != "" {
|
||||
return dockerEPMeta.Host, nil
|
||||
}
|
||||
|
||||
// We might end up here, if the context was created with the `host` set to an empty value (i.e. '').
|
||||
// For example:
|
||||
// ```sh
|
||||
// docker context create foo --docker "host="
|
||||
// ```
|
||||
// In such scenario, we mimic the `docker` cli and try to connect to the "default docker host".
|
||||
return defaultDockerHost, nil
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
//go:build !windows
|
||||
|
||||
package commands
|
||||
|
||||
const (
|
||||
defaultDockerHost = "unix:///var/run/docker.sock"
|
||||
)
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package commands
|
||||
|
||||
const (
|
||||
defaultDockerHost = "npipe:////./pipe/docker_engine"
|
||||
)
|
||||
|
|
@ -35,15 +35,15 @@ func NewDummyLog() *logrus.Entry {
|
|||
return log.WithField("test", "test")
|
||||
}
|
||||
|
||||
// NewDummyDockerCommand creates a new dummy DockerCommand for testing
|
||||
func NewDummyDockerCommand() *DockerCommand {
|
||||
return NewDummyDockerCommandWithOSCommand(NewDummyOSCommand())
|
||||
// NewDummyPodmanCommand creates a new dummy PodmanCommand for testing
|
||||
func NewDummyPodmanCommand() *PodmanCommand {
|
||||
return NewDummyPodmanCommandWithOSCommand(NewDummyOSCommand())
|
||||
}
|
||||
|
||||
// NewDummyDockerCommandWithOSCommand creates a new dummy DockerCommand for testing
|
||||
func NewDummyDockerCommandWithOSCommand(osCommand *OSCommand) *DockerCommand {
|
||||
// NewDummyPodmanCommandWithOSCommand creates a new dummy PodmanCommand for testing
|
||||
func NewDummyPodmanCommandWithOSCommand(osCommand *OSCommand) *PodmanCommand {
|
||||
newAppConfig := NewDummyAppConfig()
|
||||
return &DockerCommand{
|
||||
return &PodmanCommand{
|
||||
Log: NewDummyLog(),
|
||||
OSCommand: osCommand,
|
||||
Tr: i18n.NewTranslationSet(NewDummyLog(), newAppConfig.UserConfig.Gui.Language),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package commands
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"golang.org/x/xerrors"
|
||||
|
|
@ -12,6 +13,21 @@ const (
|
|||
MustStopContainer = iota
|
||||
)
|
||||
|
||||
// IsConnectionFailed checks if the error indicates a connection failure to Podman
|
||||
func IsConnectionFailed(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
errStr := err.Error()
|
||||
return strings.Contains(errStr, "connection refused") ||
|
||||
strings.Contains(errStr, "no such host") ||
|
||||
strings.Contains(errStr, "socket not found") ||
|
||||
strings.Contains(errStr, "cannot connect") ||
|
||||
strings.Contains(errStr, "unable to connect") ||
|
||||
strings.Contains(errStr, "dial unix") ||
|
||||
strings.Contains(errStr, "permission denied")
|
||||
}
|
||||
|
||||
// WrapError wraps an error for the sake of showing a stack trace at the top level
|
||||
// the go-errors package, for some reason, does not return nil when you try to wrap
|
||||
// a non-error, so we're just doing it here
|
||||
|
|
|
|||
|
|
@ -4,37 +4,31 @@ import (
|
|||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/fatih/color"
|
||||
"github.com/christophe-duc/lazypodman/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Image : A docker Image
|
||||
// Image represents a Podman image
|
||||
type Image struct {
|
||||
Name string
|
||||
Tag string
|
||||
ID string
|
||||
Image image.Summary
|
||||
Client *client.Client
|
||||
Summary ImageSummary
|
||||
Runtime ContainerRuntime
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
DockerCommand LimitedDockerCommand
|
||||
PodmanCommand LimitedPodmanCommand
|
||||
}
|
||||
|
||||
// Remove removes the image
|
||||
func (i *Image) Remove(options image.RemoveOptions) error {
|
||||
if _, err := i.Client.ImageRemove(context.Background(), i.ID, options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
func (i *Image) Remove(force bool) error {
|
||||
ctx := context.Background()
|
||||
return i.Runtime.RemoveImage(ctx, i.ID, force)
|
||||
}
|
||||
|
||||
func getHistoryResponseItemDisplayStrings(layer image.HistoryResponseItem) []string {
|
||||
func getHistoryResponseItemDisplayStrings(layer ImageHistoryEntry) []string {
|
||||
tag := ""
|
||||
if len(layer.Tags) > 0 {
|
||||
tag = layer.Tags[0]
|
||||
|
|
@ -75,12 +69,13 @@ func getHistoryResponseItemDisplayStrings(layer image.HistoryResponseItem) []str
|
|||
|
||||
// RenderHistory renders the history of the image
|
||||
func (i *Image) RenderHistory() (string, error) {
|
||||
history, err := i.Client.ImageHistory(context.Background(), i.ID)
|
||||
ctx := context.Background()
|
||||
history, err := i.Runtime.ImageHistory(ctx, i.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tableBody := lo.Map(history, func(layer image.HistoryResponseItem, _ int) []string {
|
||||
tableBody := lo.Map(history, func(layer ImageHistoryEntry, _ int) []string {
|
||||
return getHistoryResponseItemDisplayStrings(layer)
|
||||
})
|
||||
|
||||
|
|
@ -89,55 +84,3 @@ func (i *Image) RenderHistory() (string, error) {
|
|||
|
||||
return utils.RenderTable(table)
|
||||
}
|
||||
|
||||
// RefreshImages returns a slice of docker images
|
||||
func (c *DockerCommand) RefreshImages() ([]*Image, error) {
|
||||
images, err := c.Client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownImages := make([]*Image, len(images))
|
||||
|
||||
for i, img := range images {
|
||||
firstTag := ""
|
||||
tags := img.RepoTags
|
||||
if len(tags) > 0 {
|
||||
firstTag = tags[0]
|
||||
}
|
||||
|
||||
nameParts := strings.Split(firstTag, ":")
|
||||
tag := ""
|
||||
name := "none"
|
||||
if len(nameParts) > 1 {
|
||||
tag = nameParts[len(nameParts)-1]
|
||||
name = strings.Join(nameParts[:len(nameParts)-1], ":")
|
||||
|
||||
for prefix, replacement := range c.Config.UserConfig.Replacements.ImageNamePrefixes {
|
||||
if strings.HasPrefix(name, prefix) {
|
||||
name = strings.Replace(name, prefix, replacement, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ownImages[i] = &Image{
|
||||
ID: img.ID,
|
||||
Name: name,
|
||||
Tag: tag,
|
||||
Image: img,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return ownImages, nil
|
||||
}
|
||||
|
||||
// PruneImages prunes images
|
||||
func (c *DockerCommand) PruneImages() error {
|
||||
_, err := c.Client.ImagesPrune(context.Background(), filters.Args{})
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,52 +3,21 @@ package commands
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Network : A docker Network
|
||||
// Network represents a Podman network
|
||||
type Network struct {
|
||||
Name string
|
||||
Network network.Inspect
|
||||
Client *client.Client
|
||||
Summary NetworkSummary
|
||||
Runtime ContainerRuntime
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
DockerCommand LimitedDockerCommand
|
||||
}
|
||||
|
||||
// RefreshNetworks gets the networks and stores them
|
||||
func (c *DockerCommand) RefreshNetworks() ([]*Network, error) {
|
||||
networks, err := c.Client.NetworkList(context.Background(), network.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownNetworks := make([]*Network, len(networks))
|
||||
|
||||
for i, nw := range networks {
|
||||
ownNetworks[i] = &Network{
|
||||
Name: nw.Name,
|
||||
Network: nw,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return ownNetworks, nil
|
||||
}
|
||||
|
||||
// PruneNetworks prunes networks
|
||||
func (c *DockerCommand) PruneNetworks() error {
|
||||
_, err := c.Client.NetworksPrune(context.Background(), filters.Args{})
|
||||
return err
|
||||
PodmanCommand LimitedPodmanCommand
|
||||
}
|
||||
|
||||
// Remove removes the network
|
||||
func (v *Network) Remove() error {
|
||||
return v.Client.NetworkRemove(context.Background(), v.Name)
|
||||
ctx := context.Background()
|
||||
return v.Runtime.RemoveNetwork(ctx, v.Name)
|
||||
}
|
||||
|
|
|
|||
650
pkg/commands/podman.go
Normal file
650
pkg/commands/podman.go
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
ogLog "log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/christophe-duc/lazypodman/pkg/commands/ssh"
|
||||
"github.com/christophe-duc/lazypodman/pkg/config"
|
||||
"github.com/christophe-duc/lazypodman/pkg/i18n"
|
||||
"github.com/christophe-duc/lazypodman/pkg/utils"
|
||||
"github.com/sasha-s/go-deadlock"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
containerHostEnvKey = "CONTAINER_HOST"
|
||||
)
|
||||
|
||||
// PodmanCommand is our main podman interface
|
||||
type PodmanCommand struct {
|
||||
Log *logrus.Entry
|
||||
OSCommand *OSCommand
|
||||
Tr *i18n.TranslationSet
|
||||
Config *config.AppConfig
|
||||
Runtime ContainerRuntime
|
||||
InDockerComposeProject bool
|
||||
ErrorChan chan error
|
||||
ContainerMutex deadlock.Mutex
|
||||
ServiceMutex deadlock.Mutex
|
||||
|
||||
Closers []io.Closer
|
||||
}
|
||||
|
||||
var _ io.Closer = &PodmanCommand{}
|
||||
|
||||
// LimitedPodmanCommand is a stripped-down PodmanCommand with just the methods the container/service/image might need
|
||||
type LimitedPodmanCommand interface {
|
||||
NewCommandObject(CommandObject) CommandObject
|
||||
}
|
||||
|
||||
// CommandObject is what we pass to our template resolvers when we are running a custom command.
|
||||
// We do not guarantee that all fields will be populated: just the ones that make sense for the current context
|
||||
type CommandObject struct {
|
||||
DockerCompose string
|
||||
Service *Service
|
||||
Container *Container
|
||||
Image *Image
|
||||
Volume *Volume
|
||||
Network *Network
|
||||
}
|
||||
|
||||
// NewCommandObject takes a command object and returns a default command object with the passed command object merged in
|
||||
func (c *PodmanCommand) NewCommandObject(obj CommandObject) CommandObject {
|
||||
defaultObj := CommandObject{DockerCompose: c.Config.UserConfig.CommandTemplates.DockerCompose}
|
||||
_ = mergo.Merge(&defaultObj, obj)
|
||||
return defaultObj
|
||||
}
|
||||
|
||||
// NewPodmanCommand creates a new PodmanCommand with the appropriate runtime.
|
||||
// It tries socket mode first, then falls back to libpod if available.
|
||||
func NewPodmanCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*PodmanCommand, error) {
|
||||
var runtime ContainerRuntime
|
||||
var err error
|
||||
var closers []io.Closer
|
||||
|
||||
// Determine the socket path
|
||||
socketPath := detectSocketPath()
|
||||
|
||||
// Handle SSH tunneling for remote hosts
|
||||
if strings.HasPrefix(socketPath, "ssh://") {
|
||||
os.Setenv(containerHostEnvKey, socketPath)
|
||||
tunnelCloser, tunnelErr := ssh.NewSSHHandler(osCommand).HandleSSHDockerHost()
|
||||
if tunnelErr != nil {
|
||||
ogLog.Printf("> SSH tunnel setup failed: %v", tunnelErr)
|
||||
} else {
|
||||
closers = append(closers, tunnelCloser)
|
||||
}
|
||||
// Re-check for updated socket path after SSH setup
|
||||
if updatedPath := os.Getenv(containerHostEnvKey); updatedPath != "" {
|
||||
socketPath = updatedPath
|
||||
}
|
||||
}
|
||||
|
||||
// Try socket mode first
|
||||
if socketPath != "" {
|
||||
runtime, err = NewSocketRuntime(socketPath)
|
||||
if err != nil {
|
||||
log.Warnf("Socket connection failed (%s): %v, trying libpod", socketPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to libpod if socket mode failed
|
||||
if runtime == nil {
|
||||
runtime, err = NewLibpodRuntime()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no Podman runtime available: socket error and libpod unavailable: %v", err)
|
||||
}
|
||||
log.Infof("Using libpod runtime (socket-less mode)")
|
||||
} else {
|
||||
log.Infof("Using socket runtime at %s", socketPath)
|
||||
}
|
||||
|
||||
podmanCommand := &PodmanCommand{
|
||||
Log: log,
|
||||
OSCommand: osCommand,
|
||||
Tr: tr,
|
||||
Config: config,
|
||||
Runtime: runtime,
|
||||
ErrorChan: errorChan,
|
||||
InDockerComposeProject: true,
|
||||
Closers: closers,
|
||||
}
|
||||
|
||||
podmanCommand.setComposeCommand(config)
|
||||
|
||||
err = osCommand.RunCommand(
|
||||
utils.ApplyTemplate(
|
||||
config.UserConfig.CommandTemplates.CheckDockerComposeConfig,
|
||||
podmanCommand.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
podmanCommand.InDockerComposeProject = false
|
||||
log.Warn(err.Error())
|
||||
}
|
||||
|
||||
return podmanCommand, nil
|
||||
}
|
||||
|
||||
// setComposeCommand detects and sets the appropriate compose command
|
||||
func (c *PodmanCommand) setComposeCommand(config *config.AppConfig) {
|
||||
// If user has explicitly set a compose command, respect it
|
||||
if config.UserConfig.CommandTemplates.DockerCompose != "docker compose" &&
|
||||
config.UserConfig.CommandTemplates.DockerCompose != "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Try podman-compose first
|
||||
if err := c.OSCommand.RunCommand("podman-compose version"); err == nil {
|
||||
config.UserConfig.CommandTemplates.DockerCompose = "podman-compose"
|
||||
return
|
||||
}
|
||||
|
||||
// Try podman compose (built-in, if available)
|
||||
if err := c.OSCommand.RunCommand("podman compose version"); err == nil {
|
||||
config.UserConfig.CommandTemplates.DockerCompose = "podman compose"
|
||||
return
|
||||
}
|
||||
|
||||
// Fall back to docker-compose for compatibility
|
||||
if err := c.OSCommand.RunCommand("docker-compose version"); err == nil {
|
||||
config.UserConfig.CommandTemplates.DockerCompose = "docker-compose"
|
||||
return
|
||||
}
|
||||
|
||||
// Default to podman-compose
|
||||
config.UserConfig.CommandTemplates.DockerCompose = "podman-compose"
|
||||
}
|
||||
|
||||
func (c *PodmanCommand) Close() error {
|
||||
var errs []error
|
||||
if c.Runtime != nil {
|
||||
if err := c.Runtime.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if err := utils.CloseMany(c.Closers); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errs[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateClientStatMonitor starts monitoring stats for a container
|
||||
func (c *PodmanCommand) CreateClientStatMonitor(container *Container) {
|
||||
container.MonitoringStats = true
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
statsChan, errChan := c.Runtime.ContainerStats(ctx, container.ID, true)
|
||||
|
||||
go func() {
|
||||
for err := range errChan {
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for stats := range statsChan {
|
||||
recordedStats := &RecordedStats{
|
||||
ClientStats: convertStatsEntryToContainerStats(stats),
|
||||
DerivedStats: DerivedStats{
|
||||
CPUPercentage: calculateCPUPercentageFromEntry(stats),
|
||||
MemoryPercentage: calculateMemoryPercentageFromEntry(stats),
|
||||
},
|
||||
RecordedAt: time.Now(),
|
||||
}
|
||||
|
||||
container.appendStats(recordedStats, c.Config.UserConfig.Stats.MaxDuration)
|
||||
}
|
||||
|
||||
container.MonitoringStats = false
|
||||
}
|
||||
|
||||
// convertStatsEntryToContainerStats converts the new stats format to the legacy format
|
||||
func convertStatsEntryToContainerStats(entry ContainerStatsEntry) ContainerStats {
|
||||
return ContainerStats{
|
||||
Read: entry.Read,
|
||||
Preread: entry.PreRead,
|
||||
PidsStats: struct {
|
||||
Current int `json:"current"`
|
||||
}{
|
||||
Current: entry.PidsStats.Current,
|
||||
},
|
||||
CPUStats: struct {
|
||||
CPUUsage struct {
|
||||
TotalUsage int64 `json:"total_usage"`
|
||||
PercpuUsage []int64 `json:"percpu_usage"`
|
||||
UsageInKernelmode int64 `json:"usage_in_kernelmode"`
|
||||
UsageInUsermode int64 `json:"usage_in_usermode"`
|
||||
} `json:"cpu_usage"`
|
||||
SystemCPUUsage int64 `json:"system_cpu_usage"`
|
||||
OnlineCpus int `json:"online_cpus"`
|
||||
ThrottlingData struct {
|
||||
Periods int `json:"periods"`
|
||||
ThrottledPeriods int `json:"throttled_periods"`
|
||||
ThrottledTime int `json:"throttled_time"`
|
||||
} `json:"throttling_data"`
|
||||
}{
|
||||
CPUUsage: struct {
|
||||
TotalUsage int64 `json:"total_usage"`
|
||||
PercpuUsage []int64 `json:"percpu_usage"`
|
||||
UsageInKernelmode int64 `json:"usage_in_kernelmode"`
|
||||
UsageInUsermode int64 `json:"usage_in_usermode"`
|
||||
}{
|
||||
TotalUsage: entry.CPUStats.CPUUsage.TotalUsage,
|
||||
PercpuUsage: entry.CPUStats.CPUUsage.PercpuUsage,
|
||||
UsageInKernelmode: entry.CPUStats.CPUUsage.UsageInKernelmode,
|
||||
UsageInUsermode: entry.CPUStats.CPUUsage.UsageInUsermode,
|
||||
},
|
||||
SystemCPUUsage: entry.CPUStats.SystemCPUUsage,
|
||||
OnlineCpus: entry.CPUStats.OnlineCpus,
|
||||
},
|
||||
PrecpuStats: struct {
|
||||
CPUUsage struct {
|
||||
TotalUsage int64 `json:"total_usage"`
|
||||
PercpuUsage []int64 `json:"percpu_usage"`
|
||||
UsageInKernelmode int64 `json:"usage_in_kernelmode"`
|
||||
UsageInUsermode int64 `json:"usage_in_usermode"`
|
||||
} `json:"cpu_usage"`
|
||||
SystemCPUUsage int64 `json:"system_cpu_usage"`
|
||||
OnlineCpus int `json:"online_cpus"`
|
||||
ThrottlingData struct {
|
||||
Periods int `json:"periods"`
|
||||
ThrottledPeriods int `json:"throttled_periods"`
|
||||
ThrottledTime int `json:"throttled_time"`
|
||||
} `json:"throttling_data"`
|
||||
}{
|
||||
CPUUsage: struct {
|
||||
TotalUsage int64 `json:"total_usage"`
|
||||
PercpuUsage []int64 `json:"percpu_usage"`
|
||||
UsageInKernelmode int64 `json:"usage_in_kernelmode"`
|
||||
UsageInUsermode int64 `json:"usage_in_usermode"`
|
||||
}{
|
||||
TotalUsage: entry.PreCPUStats.CPUUsage.TotalUsage,
|
||||
PercpuUsage: entry.PreCPUStats.CPUUsage.PercpuUsage,
|
||||
UsageInKernelmode: entry.PreCPUStats.CPUUsage.UsageInKernelmode,
|
||||
UsageInUsermode: entry.PreCPUStats.CPUUsage.UsageInUsermode,
|
||||
},
|
||||
SystemCPUUsage: entry.PreCPUStats.SystemCPUUsage,
|
||||
OnlineCpus: entry.PreCPUStats.OnlineCpus,
|
||||
},
|
||||
MemoryStats: struct {
|
||||
Usage int `json:"usage"`
|
||||
MaxUsage int `json:"max_usage"`
|
||||
Stats struct {
|
||||
ActiveAnon int `json:"active_anon"`
|
||||
ActiveFile int `json:"active_file"`
|
||||
Cache int `json:"cache"`
|
||||
Dirty int `json:"dirty"`
|
||||
HierarchicalMemoryLimit int64 `json:"hierarchical_memory_limit"`
|
||||
HierarchicalMemswLimit int64 `json:"hierarchical_memsw_limit"`
|
||||
InactiveAnon int `json:"inactive_anon"`
|
||||
InactiveFile int `json:"inactive_file"`
|
||||
MappedFile int `json:"mapped_file"`
|
||||
Pgfault int `json:"pgfault"`
|
||||
Pgmajfault int `json:"pgmajfault"`
|
||||
Pgpgin int `json:"pgpgin"`
|
||||
Pgpgout int `json:"pgpgout"`
|
||||
Rss int `json:"rss"`
|
||||
RssHuge int `json:"rss_huge"`
|
||||
TotalActiveAnon int `json:"total_active_anon"`
|
||||
TotalActiveFile int `json:"total_active_file"`
|
||||
TotalCache int `json:"total_cache"`
|
||||
TotalDirty int `json:"total_dirty"`
|
||||
TotalInactiveAnon int `json:"total_inactive_anon"`
|
||||
TotalInactiveFile int `json:"total_inactive_file"`
|
||||
TotalMappedFile int `json:"total_mapped_file"`
|
||||
TotalPgfault int `json:"total_pgfault"`
|
||||
TotalPgmajfault int `json:"total_pgmajfault"`
|
||||
TotalPgpgin int `json:"total_pgpgin"`
|
||||
TotalPgpgout int `json:"total_pgpgout"`
|
||||
TotalRss int `json:"total_rss"`
|
||||
TotalRssHuge int `json:"total_rss_huge"`
|
||||
TotalUnevictable int `json:"total_unevictable"`
|
||||
TotalWriteback int `json:"total_writeback"`
|
||||
Unevictable int `json:"unevictable"`
|
||||
Writeback int `json:"writeback"`
|
||||
} `json:"stats"`
|
||||
Limit int64 `json:"limit"`
|
||||
}{
|
||||
Usage: int(entry.MemoryStats.Usage),
|
||||
MaxUsage: int(entry.MemoryStats.MaxUsage),
|
||||
Limit: entry.MemoryStats.Limit,
|
||||
},
|
||||
Name: entry.Name,
|
||||
ID: entry.ID,
|
||||
}
|
||||
}
|
||||
|
||||
func calculateCPUPercentageFromEntry(stats ContainerStatsEntry) float64 {
|
||||
cpuDelta := float64(stats.CPUStats.CPUUsage.TotalUsage - stats.PreCPUStats.CPUUsage.TotalUsage)
|
||||
systemDelta := float64(stats.CPUStats.SystemCPUUsage - stats.PreCPUStats.SystemCPUUsage)
|
||||
|
||||
if systemDelta > 0 && cpuDelta > 0 {
|
||||
return (cpuDelta / systemDelta) * 100.0
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func calculateMemoryPercentageFromEntry(stats ContainerStatsEntry) float64 {
|
||||
if stats.MemoryStats.Limit > 0 {
|
||||
return float64(stats.MemoryStats.Usage) / float64(stats.MemoryStats.Limit) * 100.0
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func (c *PodmanCommand) RefreshContainersAndServices(currentServices []*Service, currentContainers []*Container) ([]*Container, []*Service, error) {
|
||||
c.ServiceMutex.Lock()
|
||||
defer c.ServiceMutex.Unlock()
|
||||
|
||||
containers, err := c.GetContainers(currentContainers)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var services []*Service
|
||||
// we only need to get these services once because they won't change in the runtime of the program
|
||||
if currentServices != nil {
|
||||
services = currentServices
|
||||
} else {
|
||||
services, err = c.GetServices()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
c.assignContainersToServices(containers, services)
|
||||
|
||||
return containers, services, nil
|
||||
}
|
||||
|
||||
func (c *PodmanCommand) assignContainersToServices(containers []*Container, services []*Service) {
|
||||
L:
|
||||
for _, service := range services {
|
||||
for _, ctr := range containers {
|
||||
if !ctr.OneOff && ctr.ServiceName == service.Name {
|
||||
service.Container = ctr
|
||||
continue L
|
||||
}
|
||||
}
|
||||
service.Container = nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetContainers gets the podman containers
|
||||
func (c *PodmanCommand) GetContainers(existingContainers []*Container) ([]*Container, error) {
|
||||
c.ContainerMutex.Lock()
|
||||
defer c.ContainerMutex.Unlock()
|
||||
|
||||
ctx := context.Background()
|
||||
containers, err := c.Runtime.ListContainers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownContainers := make([]*Container, len(containers))
|
||||
|
||||
for i, ctr := range containers {
|
||||
var newContainer *Container
|
||||
|
||||
// check if we already have data stored against the container
|
||||
for _, existingContainer := range existingContainers {
|
||||
if existingContainer.ID == ctr.ID {
|
||||
newContainer = existingContainer
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// initialise the container if it's completely new
|
||||
if newContainer == nil {
|
||||
newContainer = &Container{
|
||||
ID: ctr.ID,
|
||||
Runtime: c.Runtime,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
PodmanCommand: c,
|
||||
Tr: c.Tr,
|
||||
}
|
||||
}
|
||||
|
||||
newContainer.Summary = ctr
|
||||
// if the container is made with a name label we will use that
|
||||
if name, ok := ctr.Labels["name"]; ok {
|
||||
newContainer.Name = name
|
||||
} else {
|
||||
if len(ctr.Names) > 0 {
|
||||
newContainer.Name = strings.TrimLeft(ctr.Names[0], "/")
|
||||
} else {
|
||||
newContainer.Name = ctr.ID
|
||||
}
|
||||
}
|
||||
// Compose labels work the same way with podman-compose
|
||||
newContainer.ServiceName = ctr.Labels["com.docker.compose.service"]
|
||||
newContainer.ProjectName = ctr.Labels["com.docker.compose.project"]
|
||||
newContainer.ContainerNumber = ctr.Labels["com.docker.compose.container"]
|
||||
newContainer.OneOff = ctr.Labels["com.docker.compose.oneoff"] == "True"
|
||||
|
||||
ownContainers[i] = newContainer
|
||||
}
|
||||
|
||||
c.SetContainerDetails(ownContainers)
|
||||
|
||||
return ownContainers, nil
|
||||
}
|
||||
|
||||
// GetServices gets services
|
||||
func (c *PodmanCommand) GetServices() ([]*Service, error) {
|
||||
if !c.InDockerComposeProject {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
composeCommand := c.Config.UserConfig.CommandTemplates.DockerCompose
|
||||
output, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("%s config --services", composeCommand))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// output looks like:
|
||||
// service1
|
||||
// service2
|
||||
|
||||
lines := utils.SplitLines(output)
|
||||
services := make([]*Service, len(lines))
|
||||
for i, str := range lines {
|
||||
services[i] = &Service{
|
||||
Name: str,
|
||||
ID: str,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
PodmanCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (c *PodmanCommand) RefreshContainerDetails(containers []*Container) error {
|
||||
c.ContainerMutex.Lock()
|
||||
defer c.ContainerMutex.Unlock()
|
||||
|
||||
c.SetContainerDetails(containers)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetContainerDetails attaches the details returned from container inspect to each of the containers
|
||||
func (c *PodmanCommand) SetContainerDetails(containers []*Container) {
|
||||
ctx := context.Background()
|
||||
wg := sync.WaitGroup{}
|
||||
for _, ctr := range containers {
|
||||
ctr := ctr
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
details, err := c.Runtime.InspectContainer(ctx, ctr.ID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
} else {
|
||||
ctr.Details = details
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// ViewAllLogs attaches to a subprocess viewing all the logs from compose
|
||||
func (c *PodmanCommand) ViewAllLogs() (*exec.Cmd, error) {
|
||||
cmd := c.OSCommand.ExecutableFromString(
|
||||
utils.ApplyTemplate(
|
||||
c.OSCommand.Config.UserConfig.CommandTemplates.ViewAllLogs,
|
||||
c.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
|
||||
c.OSCommand.PrepareForChildren(cmd)
|
||||
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// DockerComposeConfig returns the result of 'compose config'
|
||||
func (c *PodmanCommand) DockerComposeConfig() string {
|
||||
output, err := c.OSCommand.RunCommandWithOutput(
|
||||
utils.ApplyTemplate(
|
||||
c.OSCommand.Config.UserConfig.CommandTemplates.DockerComposeConfig,
|
||||
c.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
output = err.Error()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// PruneContainers prunes containers using the runtime
|
||||
func (c *PodmanCommand) PruneContainers() error {
|
||||
return c.Runtime.PruneContainers(context.Background())
|
||||
}
|
||||
|
||||
// PruneImages prunes images using the runtime
|
||||
func (c *PodmanCommand) PruneImages() error {
|
||||
return c.Runtime.PruneImages(context.Background())
|
||||
}
|
||||
|
||||
// PruneVolumes prunes volumes using the runtime
|
||||
func (c *PodmanCommand) PruneVolumes() error {
|
||||
return c.Runtime.PruneVolumes(context.Background())
|
||||
}
|
||||
|
||||
// PruneNetworks prunes networks using the runtime
|
||||
func (c *PodmanCommand) PruneNetworks() error {
|
||||
return c.Runtime.PruneNetworks(context.Background())
|
||||
}
|
||||
|
||||
// RefreshImages returns a slice of podman images
|
||||
func (c *PodmanCommand) RefreshImages() ([]*Image, error) {
|
||||
ctx := context.Background()
|
||||
images, err := c.Runtime.ListImages(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownImages := make([]*Image, len(images))
|
||||
|
||||
for i, img := range images {
|
||||
firstTag := ""
|
||||
tags := img.RepoTags
|
||||
if len(tags) > 0 {
|
||||
firstTag = tags[0]
|
||||
}
|
||||
|
||||
nameParts := strings.Split(firstTag, ":")
|
||||
tag := ""
|
||||
name := "none"
|
||||
if len(nameParts) > 1 {
|
||||
tag = nameParts[len(nameParts)-1]
|
||||
name = strings.Join(nameParts[:len(nameParts)-1], ":")
|
||||
|
||||
for prefix, replacement := range c.Config.UserConfig.Replacements.ImageNamePrefixes {
|
||||
if strings.HasPrefix(name, prefix) {
|
||||
name = strings.Replace(name, prefix, replacement, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ownImages[i] = &Image{
|
||||
ID: img.ID,
|
||||
Name: name,
|
||||
Tag: tag,
|
||||
Summary: img,
|
||||
Runtime: c.Runtime,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
PodmanCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return ownImages, nil
|
||||
}
|
||||
|
||||
// RefreshVolumes gets the volumes and stores them
|
||||
func (c *PodmanCommand) RefreshVolumes() ([]*Volume, error) {
|
||||
ctx := context.Background()
|
||||
volumes, err := c.Runtime.ListVolumes(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownVolumes := make([]*Volume, len(volumes))
|
||||
|
||||
for i, vol := range volumes {
|
||||
ownVolumes[i] = &Volume{
|
||||
Name: vol.Name,
|
||||
Summary: vol,
|
||||
Runtime: c.Runtime,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
PodmanCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return ownVolumes, nil
|
||||
}
|
||||
|
||||
// RefreshNetworks gets the networks and stores them
|
||||
func (c *PodmanCommand) RefreshNetworks() ([]*Network, error) {
|
||||
ctx := context.Background()
|
||||
networks, err := c.Runtime.ListNetworks(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownNetworks := make([]*Network, len(networks))
|
||||
|
||||
for i, nw := range networks {
|
||||
ownNetworks[i] = &Network{
|
||||
Name: nw.Name,
|
||||
Summary: nw,
|
||||
Runtime: c.Runtime,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
PodmanCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return ownNetworks, nil
|
||||
}
|
||||
48
pkg/commands/podman_host_unix.go
Normal file
48
pkg/commands/podman_host_unix.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//go:build !windows
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// detectSocketPath determines the Podman socket path to use.
|
||||
// It checks in the following order:
|
||||
// 1. CONTAINER_HOST environment variable (Podman standard)
|
||||
// 2. Rootless socket: /run/user/{uid}/podman/podman.sock
|
||||
// 3. Rootful socket: /run/podman/podman.sock
|
||||
// 4. Legacy Docker socket: /var/run/docker.sock (for compatibility)
|
||||
func detectSocketPath() string {
|
||||
// 1. Check CONTAINER_HOST environment variable (Podman standard)
|
||||
if host := os.Getenv("CONTAINER_HOST"); host != "" {
|
||||
return host
|
||||
}
|
||||
|
||||
// Also check DOCKER_HOST for backward compatibility
|
||||
if host := os.Getenv("DOCKER_HOST"); host != "" {
|
||||
return host
|
||||
}
|
||||
|
||||
// 2. Check for rootless socket
|
||||
uid := os.Getuid()
|
||||
rootlessPath := fmt.Sprintf("/run/user/%d/podman/podman.sock", uid)
|
||||
if _, err := os.Stat(rootlessPath); err == nil {
|
||||
return "unix://" + rootlessPath
|
||||
}
|
||||
|
||||
// 3. Check for rootful socket
|
||||
rootfulPath := "/run/podman/podman.sock"
|
||||
if _, err := os.Stat(rootfulPath); err == nil {
|
||||
return "unix://" + rootfulPath
|
||||
}
|
||||
|
||||
// 4. Legacy Docker socket path (for compatibility)
|
||||
dockerPath := "/var/run/docker.sock"
|
||||
if _, err := os.Stat(dockerPath); err == nil {
|
||||
return "unix://" + dockerPath
|
||||
}
|
||||
|
||||
// Return empty string - will fall back to libpod if available
|
||||
return ""
|
||||
}
|
||||
25
pkg/commands/podman_host_windows.go
Normal file
25
pkg/commands/podman_host_windows.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//go:build windows
|
||||
|
||||
package commands
|
||||
|
||||
import "os"
|
||||
|
||||
// detectSocketPath determines the Podman socket path to use on Windows.
|
||||
// It checks in the following order:
|
||||
// 1. CONTAINER_HOST environment variable (Podman standard)
|
||||
// 2. Default Podman machine named pipe
|
||||
func detectSocketPath() string {
|
||||
// Check CONTAINER_HOST environment variable
|
||||
if host := os.Getenv("CONTAINER_HOST"); host != "" {
|
||||
return host
|
||||
}
|
||||
|
||||
// Also check DOCKER_HOST for backward compatibility
|
||||
if host := os.Getenv("DOCKER_HOST"); host != "" {
|
||||
return host
|
||||
}
|
||||
|
||||
// Default to Podman machine socket
|
||||
// Podman machine on Windows uses named pipes
|
||||
return "npipe:////./pipe/podman-machine-default"
|
||||
}
|
||||
48
pkg/commands/runtime.go
Normal file
48
pkg/commands/runtime.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package commands
|
||||
|
||||
import "context"
|
||||
|
||||
// ContainerRuntime abstracts Podman operations for both socket and socket-less modes.
|
||||
// This interface allows the application to work with either:
|
||||
// - Socket mode: using pkg/bindings (stable REST API)
|
||||
// - Socket-less mode: using libpod directly (requires Linux + CGO)
|
||||
type ContainerRuntime interface {
|
||||
// Container operations
|
||||
ListContainers(ctx context.Context) ([]ContainerSummary, error)
|
||||
InspectContainer(ctx context.Context, id string) (*ContainerDetails, error)
|
||||
StartContainer(ctx context.Context, id string) error
|
||||
StopContainer(ctx context.Context, id string, timeout *int) error
|
||||
PauseContainer(ctx context.Context, id string) error
|
||||
UnpauseContainer(ctx context.Context, id string) error
|
||||
RestartContainer(ctx context.Context, id string, timeout *int) error
|
||||
RemoveContainer(ctx context.Context, id string, force bool, volumes bool) error
|
||||
ContainerTop(ctx context.Context, id string) ([]string, [][]string, error)
|
||||
PruneContainers(ctx context.Context) error
|
||||
ContainerStats(ctx context.Context, id string, stream bool) (<-chan ContainerStatsEntry, <-chan error)
|
||||
|
||||
// Image operations
|
||||
ListImages(ctx context.Context) ([]ImageSummary, error)
|
||||
InspectImage(ctx context.Context, id string) (*ImageDetails, error)
|
||||
ImageHistory(ctx context.Context, id string) ([]ImageHistoryEntry, error)
|
||||
RemoveImage(ctx context.Context, id string, force bool) error
|
||||
PruneImages(ctx context.Context) error
|
||||
|
||||
// Volume operations
|
||||
ListVolumes(ctx context.Context) ([]VolumeSummary, error)
|
||||
RemoveVolume(ctx context.Context, name string, force bool) error
|
||||
PruneVolumes(ctx context.Context) error
|
||||
|
||||
// Network operations
|
||||
ListNetworks(ctx context.Context) ([]NetworkSummary, error)
|
||||
RemoveNetwork(ctx context.Context, name string) error
|
||||
PruneNetworks(ctx context.Context) error
|
||||
|
||||
// Events streams container/image/volume/network events
|
||||
Events(ctx context.Context) (<-chan Event, <-chan error)
|
||||
|
||||
// Lifecycle
|
||||
Close() error
|
||||
|
||||
// Mode returns "socket" or "libpod" to indicate which runtime mode is active
|
||||
Mode() string
|
||||
}
|
||||
517
pkg/commands/runtime_libpod.go
Normal file
517
pkg/commands/runtime_libpod.go
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
//go:build linux && cgo
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/containers/podman/v5/libpod"
|
||||
"github.com/containers/podman/v5/libpod/define"
|
||||
)
|
||||
|
||||
// LibpodRuntime implements ContainerRuntime using libpod directly.
|
||||
// This mode does not require a Podman socket and works directly with the container runtime.
|
||||
// It requires CGO and is only available on Linux.
|
||||
type LibpodRuntime struct {
|
||||
runtime *libpod.Runtime
|
||||
}
|
||||
|
||||
// NewLibpodRuntime creates a new LibpodRuntime.
|
||||
func NewLibpodRuntime() (*LibpodRuntime, error) {
|
||||
runtime, err := libpod.NewRuntime(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LibpodRuntime{runtime: runtime}, nil
|
||||
}
|
||||
|
||||
// Mode returns "libpod" to indicate this is the direct libpod runtime.
|
||||
func (r *LibpodRuntime) Mode() string {
|
||||
return "libpod"
|
||||
}
|
||||
|
||||
// Close shuts down the libpod runtime.
|
||||
func (r *LibpodRuntime) Close() error {
|
||||
if r.runtime != nil {
|
||||
_, err := r.runtime.Shutdown(false)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container operations
|
||||
|
||||
// ListContainers returns all containers.
|
||||
func (r *LibpodRuntime) ListContainers(ctx context.Context) ([]ContainerSummary, error) {
|
||||
ctrs, err := r.runtime.GetAllContainers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertLibpodContainerList(ctrs)
|
||||
}
|
||||
|
||||
// InspectContainer returns detailed information about a container.
|
||||
func (r *LibpodRuntime) InspectContainer(ctx context.Context, id string) (*ContainerDetails, error) {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ctr.Inspect(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertLibpodContainerInspect(data), nil
|
||||
}
|
||||
|
||||
// StartContainer starts a stopped container.
|
||||
func (r *LibpodRuntime) StartContainer(ctx context.Context, id string) error {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctr.Start(ctx, false)
|
||||
}
|
||||
|
||||
// StopContainer stops a running container.
|
||||
func (r *LibpodRuntime) StopContainer(ctx context.Context, id string, timeout *int) error {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t := uint(10) // default timeout
|
||||
if timeout != nil {
|
||||
t = uint(*timeout)
|
||||
}
|
||||
return ctr.StopWithTimeout(t)
|
||||
}
|
||||
|
||||
// PauseContainer pauses a running container.
|
||||
func (r *LibpodRuntime) PauseContainer(ctx context.Context, id string) error {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctr.Pause()
|
||||
}
|
||||
|
||||
// UnpauseContainer unpauses a paused container.
|
||||
func (r *LibpodRuntime) UnpauseContainer(ctx context.Context, id string) error {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctr.Unpause()
|
||||
}
|
||||
|
||||
// RestartContainer restarts a container.
|
||||
func (r *LibpodRuntime) RestartContainer(ctx context.Context, id string, timeout *int) error {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t := uint(10) // default timeout
|
||||
if timeout != nil {
|
||||
t = uint(*timeout)
|
||||
}
|
||||
return ctr.RestartWithTimeout(ctx, t)
|
||||
}
|
||||
|
||||
// RemoveContainer removes a container.
|
||||
func (r *LibpodRuntime) RemoveContainer(ctx context.Context, id string, force bool, removeVolumes bool) error {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var timeout uint = 10
|
||||
_, _, err = r.runtime.RemoveContainerAndDependencies(ctx, ctr, force, removeVolumes, &timeout)
|
||||
return err
|
||||
}
|
||||
|
||||
// ContainerTop returns process information from a container.
|
||||
func (r *LibpodRuntime) ContainerTop(ctx context.Context, id string) ([]string, [][]string, error) {
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
result, err := ctr.Top([]string{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
return result[0], result[1:], nil
|
||||
}
|
||||
|
||||
// PruneContainers removes all stopped containers.
|
||||
func (r *LibpodRuntime) PruneContainers(ctx context.Context) error {
|
||||
_, err := r.runtime.PruneContainers(ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// ContainerStats streams container statistics.
|
||||
func (r *LibpodRuntime) ContainerStats(ctx context.Context, id string, stream bool) (<-chan ContainerStatsEntry, <-chan error) {
|
||||
statsChan := make(chan ContainerStatsEntry)
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(statsChan)
|
||||
defer close(errChan)
|
||||
|
||||
ctr, err := r.runtime.LookupContainer(id)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
stats, err := ctr.GetContainerStats(nil)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
entry := convertLibpodContainerStats(stats)
|
||||
select {
|
||||
case statsChan <- entry:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
if !stream {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
return statsChan, errChan
|
||||
}
|
||||
|
||||
// Image operations
|
||||
|
||||
// ListImages returns all images.
|
||||
func (r *LibpodRuntime) ListImages(ctx context.Context) ([]ImageSummary, error) {
|
||||
imgs, err := r.runtime.ImageRuntime().GetImages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertLibpodImageList(imgs), nil
|
||||
}
|
||||
|
||||
// InspectImage returns detailed information about an image.
|
||||
func (r *LibpodRuntime) InspectImage(ctx context.Context, id string) (*ImageDetails, error) {
|
||||
img, _, err := r.runtime.ImageRuntime().LookupImage(id, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertLibpodImageInspect(img), nil
|
||||
}
|
||||
|
||||
// ImageHistory returns the history of an image.
|
||||
func (r *LibpodRuntime) ImageHistory(ctx context.Context, id string) ([]ImageHistoryEntry, error) {
|
||||
img, _, err := r.runtime.ImageRuntime().LookupImage(id, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
history, err := img.History(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertLibpodImageHistory(history), nil
|
||||
}
|
||||
|
||||
// RemoveImage removes an image.
|
||||
func (r *LibpodRuntime) RemoveImage(ctx context.Context, id string, force bool) error {
|
||||
img, _, err := r.runtime.ImageRuntime().LookupImage(id, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = r.runtime.ImageRuntime().RemoveImages(ctx, []string{img.ID()}, &libimage.RemoveImagesOptions{Force: force})
|
||||
return err
|
||||
}
|
||||
|
||||
// PruneImages removes unused images.
|
||||
func (r *LibpodRuntime) PruneImages(ctx context.Context) error {
|
||||
_, err := r.runtime.ImageRuntime().PruneImages(ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Volume operations
|
||||
|
||||
// ListVolumes returns all volumes.
|
||||
func (r *LibpodRuntime) ListVolumes(ctx context.Context) ([]VolumeSummary, error) {
|
||||
vols, err := r.runtime.GetAllVolumes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertLibpodVolumeList(vols), nil
|
||||
}
|
||||
|
||||
// RemoveVolume removes a volume.
|
||||
func (r *LibpodRuntime) RemoveVolume(ctx context.Context, name string, force bool) error {
|
||||
vol, err := r.runtime.LookupVolume(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var timeout uint = 10
|
||||
return r.runtime.RemoveVolume(ctx, vol, force, &timeout)
|
||||
}
|
||||
|
||||
// PruneVolumes removes unused volumes.
|
||||
func (r *LibpodRuntime) PruneVolumes(ctx context.Context) error {
|
||||
_, err := r.runtime.PruneVolumes(ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Network operations
|
||||
|
||||
// ListNetworks returns all networks.
|
||||
func (r *LibpodRuntime) ListNetworks(ctx context.Context) ([]NetworkSummary, error) {
|
||||
nets, err := r.runtime.Network().NetworkList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertLibpodNetworkList(nets), nil
|
||||
}
|
||||
|
||||
// RemoveNetwork removes a network.
|
||||
func (r *LibpodRuntime) RemoveNetwork(ctx context.Context, name string) error {
|
||||
_, err := r.runtime.Network().NetworkRemove(name)
|
||||
return err
|
||||
}
|
||||
|
||||
// PruneNetworks removes unused networks.
|
||||
func (r *LibpodRuntime) PruneNetworks(ctx context.Context) error {
|
||||
_, err := r.runtime.Network().NetworkPrune(nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Events streams container runtime events.
|
||||
// For libpod, we use a polling approach since direct event streaming requires more setup.
|
||||
func (r *LibpodRuntime) Events(ctx context.Context) (<-chan Event, <-chan error) {
|
||||
eventChan := make(chan Event)
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(eventChan)
|
||||
defer close(errChan)
|
||||
|
||||
// Libpod events require more complex setup; for now use periodic polling
|
||||
// by sending empty events that trigger refreshes
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
// Send a synthetic event to trigger refresh
|
||||
event := Event{
|
||||
Type: "refresh",
|
||||
Action: "poll",
|
||||
Time: time.Now().Unix(),
|
||||
}
|
||||
select {
|
||||
case eventChan <- event:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return eventChan, errChan
|
||||
}
|
||||
|
||||
// Conversion functions
|
||||
|
||||
func convertLibpodContainerList(ctrs []*libpod.Container) ([]ContainerSummary, error) {
|
||||
result := make([]ContainerSummary, len(ctrs))
|
||||
for i, ctr := range ctrs {
|
||||
state, err := ctr.State()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := ctr.Config()
|
||||
command := ""
|
||||
if len(config.Command) > 0 {
|
||||
command = config.Command[0]
|
||||
}
|
||||
result[i] = ContainerSummary{
|
||||
ID: ctr.ID(),
|
||||
Names: []string{ctr.Name()},
|
||||
Image: config.RootfsImageName,
|
||||
ImageID: config.RootfsImageID,
|
||||
Command: command,
|
||||
Created: config.CreatedTime.Unix(),
|
||||
State: state.String(),
|
||||
Status: state.String(),
|
||||
Labels: config.Labels,
|
||||
Pod: ctr.PodID(),
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func convertLibpodContainerInspect(data *define.InspectContainerData) *ContainerDetails {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
details := &ContainerDetails{
|
||||
ID: data.ID,
|
||||
Name: data.Name,
|
||||
Created: data.Created,
|
||||
Path: data.Path,
|
||||
Args: data.Args,
|
||||
Image: data.Image,
|
||||
ImageID: data.ImageName,
|
||||
ResolvConfPath: data.ResolvConfPath,
|
||||
HostnamePath: data.HostnamePath,
|
||||
HostsPath: data.HostsPath,
|
||||
LogPath: data.LogPath,
|
||||
RestartCount: int(data.RestartCount),
|
||||
Driver: data.Driver,
|
||||
MountLabel: data.MountLabel,
|
||||
ProcessLabel: data.ProcessLabel,
|
||||
AppArmorProfile: data.AppArmorProfile,
|
||||
}
|
||||
|
||||
if data.State != nil {
|
||||
details.State = &ContainerState{
|
||||
Status: data.State.Status,
|
||||
Running: data.State.Running,
|
||||
Paused: data.State.Paused,
|
||||
Restarting: data.State.Restarting,
|
||||
OOMKilled: data.State.OOMKilled,
|
||||
Dead: data.State.Dead,
|
||||
Pid: data.State.Pid,
|
||||
ExitCode: int(data.State.ExitCode),
|
||||
Error: data.State.Error,
|
||||
StartedAt: data.State.StartedAt,
|
||||
FinishedAt: data.State.FinishedAt,
|
||||
}
|
||||
}
|
||||
|
||||
if data.Config != nil {
|
||||
details.Config = &ContainerConfig{
|
||||
Hostname: data.Config.Hostname,
|
||||
Domainname: data.Config.Domainname,
|
||||
User: data.Config.User,
|
||||
AttachStdin: data.Config.AttachStdin,
|
||||
AttachStdout: data.Config.AttachStdout,
|
||||
AttachStderr: data.Config.AttachStderr,
|
||||
Tty: data.Config.Tty,
|
||||
OpenStdin: data.Config.OpenStdin,
|
||||
StdinOnce: data.Config.StdinOnce,
|
||||
Env: data.Config.Env,
|
||||
Cmd: data.Config.Cmd,
|
||||
Image: data.Config.Image,
|
||||
WorkingDir: data.Config.WorkingDir,
|
||||
Entrypoint: data.Config.Entrypoint,
|
||||
OnBuild: data.Config.OnBuild,
|
||||
Labels: data.Config.Labels,
|
||||
StopSignal: data.Config.StopSignal,
|
||||
}
|
||||
}
|
||||
|
||||
return details
|
||||
}
|
||||
|
||||
func convertLibpodContainerStats(stats *define.ContainerStats) ContainerStatsEntry {
|
||||
return ContainerStatsEntry{
|
||||
Read: time.Now(),
|
||||
PreRead: time.Now().Add(-time.Second),
|
||||
CPUStats: CPUStats{
|
||||
CPUUsage: CPUUsage{
|
||||
TotalUsage: int64(stats.CPU),
|
||||
},
|
||||
SystemCPUUsage: int64(stats.SystemNano),
|
||||
},
|
||||
MemoryStats: MemoryStats{
|
||||
Usage: int64(stats.MemUsage),
|
||||
Limit: int64(stats.MemLimit),
|
||||
},
|
||||
PidsStats: PidsStats{
|
||||
Current: int(stats.PIDs),
|
||||
},
|
||||
Name: stats.Name,
|
||||
ID: stats.ContainerID,
|
||||
}
|
||||
}
|
||||
|
||||
func convertLibpodImageList(imgs []*libimage.Image) []ImageSummary {
|
||||
result := make([]ImageSummary, len(imgs))
|
||||
for i, img := range imgs {
|
||||
result[i] = ImageSummary{
|
||||
ID: img.ID(),
|
||||
RepoTags: img.Names(),
|
||||
Created: img.Created().Unix(),
|
||||
Size: img.Size(),
|
||||
Labels: img.Labels(),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertLibpodImageInspect(img *libimage.Image) *ImageDetails {
|
||||
if img == nil {
|
||||
return nil
|
||||
}
|
||||
return &ImageDetails{
|
||||
ID: img.ID(),
|
||||
RepoTags: img.Names(),
|
||||
Created: img.Created(),
|
||||
Size: img.Size(),
|
||||
Architecture: img.Architecture(),
|
||||
Os: img.OS(),
|
||||
}
|
||||
}
|
||||
|
||||
func convertLibpodImageHistory(history []*libimage.ImageHistoryLayer) []ImageHistoryEntry {
|
||||
result := make([]ImageHistoryEntry, len(history))
|
||||
for i, layer := range history {
|
||||
result[i] = ImageHistoryEntry{
|
||||
ID: layer.ID,
|
||||
Created: layer.Created.Unix(),
|
||||
CreatedBy: layer.CreatedBy,
|
||||
Tags: layer.Tags,
|
||||
Size: layer.Size,
|
||||
Comment: layer.Comment,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertLibpodVolumeList(vols []*libpod.Volume) []VolumeSummary {
|
||||
result := make([]VolumeSummary, len(vols))
|
||||
for i, vol := range vols {
|
||||
result[i] = VolumeSummary{
|
||||
Name: vol.Name(),
|
||||
Driver: vol.Driver(),
|
||||
Mountpoint: vol.MountPoint(),
|
||||
CreatedAt: vol.CreatedTime(),
|
||||
Labels: vol.Labels(),
|
||||
Scope: vol.Scope(),
|
||||
Options: vol.Options(),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertLibpodNetworkList(nets []types.Network) []NetworkSummary {
|
||||
result := make([]NetworkSummary, len(nets))
|
||||
for i, nw := range nets {
|
||||
result[i] = NetworkSummary{
|
||||
Name: nw.Name,
|
||||
ID: nw.ID,
|
||||
Created: nw.Created,
|
||||
Driver: nw.Driver,
|
||||
Labels: nw.Labels,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
137
pkg/commands/runtime_libpod_stub.go
Normal file
137
pkg/commands/runtime_libpod_stub.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
//go:build !linux || !cgo
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// LibpodRuntime is a stub for non-Linux platforms.
|
||||
// The real implementation requires CGO and is only available on Linux.
|
||||
type LibpodRuntime struct{}
|
||||
|
||||
// ErrLibpodNotAvailable is returned when libpod is not available on the current platform.
|
||||
var ErrLibpodNotAvailable = errors.New("libpod runtime not available on this platform (requires Linux with CGO)")
|
||||
|
||||
// NewLibpodRuntime returns an error on non-Linux platforms.
|
||||
func NewLibpodRuntime() (*LibpodRuntime, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
// Mode returns "libpod".
|
||||
func (r *LibpodRuntime) Mode() string {
|
||||
return "libpod"
|
||||
}
|
||||
|
||||
// Close is a no-op on non-Linux platforms.
|
||||
func (r *LibpodRuntime) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container operations - all return ErrLibpodNotAvailable
|
||||
|
||||
func (r *LibpodRuntime) ListContainers(ctx context.Context) ([]ContainerSummary, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) InspectContainer(ctx context.Context, id string) (*ContainerDetails, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) StartContainer(ctx context.Context, id string) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) StopContainer(ctx context.Context, id string, timeout *int) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) PauseContainer(ctx context.Context, id string) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) UnpauseContainer(ctx context.Context, id string) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) RestartContainer(ctx context.Context, id string, timeout *int) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) RemoveContainer(ctx context.Context, id string, force bool, volumes bool) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) ContainerTop(ctx context.Context, id string) ([]string, [][]string, error) {
|
||||
return nil, nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) PruneContainers(ctx context.Context) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) ContainerStats(ctx context.Context, id string, stream bool) (<-chan ContainerStatsEntry, <-chan error) {
|
||||
errChan := make(chan error, 1)
|
||||
errChan <- ErrLibpodNotAvailable
|
||||
close(errChan)
|
||||
return nil, errChan
|
||||
}
|
||||
|
||||
// Image operations - all return ErrLibpodNotAvailable
|
||||
|
||||
func (r *LibpodRuntime) ListImages(ctx context.Context) ([]ImageSummary, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) InspectImage(ctx context.Context, id string) (*ImageDetails, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) ImageHistory(ctx context.Context, id string) ([]ImageHistoryEntry, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) RemoveImage(ctx context.Context, id string, force bool) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) PruneImages(ctx context.Context) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
// Volume operations - all return ErrLibpodNotAvailable
|
||||
|
||||
func (r *LibpodRuntime) ListVolumes(ctx context.Context) ([]VolumeSummary, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) RemoveVolume(ctx context.Context, name string, force bool) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) PruneVolumes(ctx context.Context) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
// Network operations - all return ErrLibpodNotAvailable
|
||||
|
||||
func (r *LibpodRuntime) ListNetworks(ctx context.Context) ([]NetworkSummary, error) {
|
||||
return nil, ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) RemoveNetwork(ctx context.Context, name string) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
func (r *LibpodRuntime) PruneNetworks(ctx context.Context) error {
|
||||
return ErrLibpodNotAvailable
|
||||
}
|
||||
|
||||
// Events returns an error channel on non-Linux platforms.
|
||||
func (r *LibpodRuntime) Events(ctx context.Context) (<-chan Event, <-chan error) {
|
||||
errChan := make(chan error, 1)
|
||||
errChan <- ErrLibpodNotAvailable
|
||||
close(errChan)
|
||||
return nil, errChan
|
||||
}
|
||||
535
pkg/commands/runtime_socket.go
Normal file
535
pkg/commands/runtime_socket.go
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/containers/podman/v5/pkg/bindings"
|
||||
"github.com/containers/podman/v5/pkg/bindings/containers"
|
||||
"github.com/containers/podman/v5/pkg/bindings/images"
|
||||
"github.com/containers/podman/v5/pkg/bindings/network"
|
||||
"github.com/containers/podman/v5/pkg/bindings/system"
|
||||
"github.com/containers/podman/v5/pkg/bindings/volumes"
|
||||
"github.com/containers/podman/v5/pkg/domain/entities"
|
||||
)
|
||||
|
||||
// SocketRuntime implements ContainerRuntime using Podman's REST API bindings.
|
||||
// This is the preferred mode when a Podman socket is available.
|
||||
type SocketRuntime struct {
|
||||
conn context.Context
|
||||
}
|
||||
|
||||
// NewSocketRuntime creates a new SocketRuntime connected to the given socket path.
|
||||
// The socketPath should be in the format "unix:///path/to/podman.sock".
|
||||
func NewSocketRuntime(socketPath string) (*SocketRuntime, error) {
|
||||
conn, err := bindings.NewConnection(context.Background(), socketPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SocketRuntime{conn: conn}, nil
|
||||
}
|
||||
|
||||
// Mode returns "socket" to indicate this is the socket-based runtime.
|
||||
func (r *SocketRuntime) Mode() string {
|
||||
return "socket"
|
||||
}
|
||||
|
||||
// Close cleans up any resources. For socket mode, this is a no-op.
|
||||
func (r *SocketRuntime) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container operations
|
||||
|
||||
// ListContainers returns all containers.
|
||||
func (r *SocketRuntime) ListContainers(ctx context.Context) ([]ContainerSummary, error) {
|
||||
all := true
|
||||
opts := &containers.ListOptions{
|
||||
All: &all,
|
||||
}
|
||||
podmanContainers, err := containers.List(r.conn, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertPodmanContainerList(podmanContainers), nil
|
||||
}
|
||||
|
||||
// InspectContainer returns detailed information about a container.
|
||||
func (r *SocketRuntime) InspectContainer(ctx context.Context, id string) (*ContainerDetails, error) {
|
||||
data, err := containers.Inspect(r.conn, id, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertPodmanContainerInspect(data), nil
|
||||
}
|
||||
|
||||
// StartContainer starts a stopped container.
|
||||
func (r *SocketRuntime) StartContainer(ctx context.Context, id string) error {
|
||||
return containers.Start(r.conn, id, nil)
|
||||
}
|
||||
|
||||
// StopContainer stops a running container.
|
||||
func (r *SocketRuntime) StopContainer(ctx context.Context, id string, timeout *int) error {
|
||||
opts := &containers.StopOptions{}
|
||||
if timeout != nil {
|
||||
t := uint(*timeout)
|
||||
opts.Timeout = &t
|
||||
}
|
||||
return containers.Stop(r.conn, id, opts)
|
||||
}
|
||||
|
||||
// PauseContainer pauses a running container.
|
||||
func (r *SocketRuntime) PauseContainer(ctx context.Context, id string) error {
|
||||
return containers.Pause(r.conn, id, nil)
|
||||
}
|
||||
|
||||
// UnpauseContainer unpauses a paused container.
|
||||
func (r *SocketRuntime) UnpauseContainer(ctx context.Context, id string) error {
|
||||
return containers.Unpause(r.conn, id, nil)
|
||||
}
|
||||
|
||||
// RestartContainer restarts a container.
|
||||
func (r *SocketRuntime) RestartContainer(ctx context.Context, id string, timeout *int) error {
|
||||
opts := &containers.RestartOptions{}
|
||||
if timeout != nil {
|
||||
t := *timeout
|
||||
opts.Timeout = &t
|
||||
}
|
||||
return containers.Restart(r.conn, id, opts)
|
||||
}
|
||||
|
||||
// RemoveContainer removes a container.
|
||||
func (r *SocketRuntime) RemoveContainer(ctx context.Context, id string, force bool, removeVolumes bool) error {
|
||||
opts := &containers.RemoveOptions{
|
||||
Force: &force,
|
||||
Volumes: &removeVolumes,
|
||||
}
|
||||
_, err := containers.Remove(r.conn, id, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
// ContainerTop returns process information from a container.
|
||||
func (r *SocketRuntime) ContainerTop(ctx context.Context, id string) ([]string, [][]string, error) {
|
||||
result, err := containers.Top(r.conn, id, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return result.Titles, result.Processes, nil
|
||||
}
|
||||
|
||||
// PruneContainers removes all stopped containers.
|
||||
func (r *SocketRuntime) PruneContainers(ctx context.Context) error {
|
||||
_, err := containers.Prune(r.conn, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// ContainerStats streams container statistics.
|
||||
func (r *SocketRuntime) ContainerStats(ctx context.Context, id string, stream bool) (<-chan ContainerStatsEntry, <-chan error) {
|
||||
statsChan := make(chan ContainerStatsEntry)
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(statsChan)
|
||||
defer close(errChan)
|
||||
|
||||
opts := &containers.StatsOptions{
|
||||
Stream: &stream,
|
||||
}
|
||||
|
||||
reportChan, err := containers.Stats(r.conn, []string{id}, opts)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
for report := range reportChan {
|
||||
if report.Error != nil {
|
||||
errChan <- report.Error
|
||||
return
|
||||
}
|
||||
|
||||
for _, stat := range report.Stats {
|
||||
entry := convertPodmanContainerStats(stat)
|
||||
select {
|
||||
case statsChan <- entry:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return statsChan, errChan
|
||||
}
|
||||
|
||||
// Image operations
|
||||
|
||||
// ListImages returns all images.
|
||||
func (r *SocketRuntime) ListImages(ctx context.Context) ([]ImageSummary, error) {
|
||||
opts := &images.ListOptions{}
|
||||
podmanImages, err := images.List(r.conn, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertPodmanImageList(podmanImages), nil
|
||||
}
|
||||
|
||||
// InspectImage returns detailed information about an image.
|
||||
func (r *SocketRuntime) InspectImage(ctx context.Context, id string) (*ImageDetails, error) {
|
||||
data, err := images.GetImage(r.conn, id, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertPodmanImageInspect(data), nil
|
||||
}
|
||||
|
||||
// ImageHistory returns the history of an image.
|
||||
func (r *SocketRuntime) ImageHistory(ctx context.Context, id string) ([]ImageHistoryEntry, error) {
|
||||
history, err := images.History(r.conn, id, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertPodmanImageHistory(history), nil
|
||||
}
|
||||
|
||||
// RemoveImage removes an image.
|
||||
func (r *SocketRuntime) RemoveImage(ctx context.Context, id string, force bool) error {
|
||||
opts := &images.RemoveOptions{
|
||||
Force: &force,
|
||||
}
|
||||
_, errs := images.Remove(r.conn, []string{id}, opts)
|
||||
if len(errs) > 0 {
|
||||
return errs[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PruneImages removes unused images.
|
||||
func (r *SocketRuntime) PruneImages(ctx context.Context) error {
|
||||
_, err := images.Prune(r.conn, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Volume operations
|
||||
|
||||
// ListVolumes returns all volumes.
|
||||
func (r *SocketRuntime) ListVolumes(ctx context.Context) ([]VolumeSummary, error) {
|
||||
opts := &volumes.ListOptions{}
|
||||
podmanVolumes, err := volumes.List(r.conn, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertPodmanVolumeList(podmanVolumes), nil
|
||||
}
|
||||
|
||||
// RemoveVolume removes a volume.
|
||||
func (r *SocketRuntime) RemoveVolume(ctx context.Context, name string, force bool) error {
|
||||
opts := &volumes.RemoveOptions{
|
||||
Force: &force,
|
||||
}
|
||||
return volumes.Remove(r.conn, name, opts)
|
||||
}
|
||||
|
||||
// PruneVolumes removes unused volumes.
|
||||
func (r *SocketRuntime) PruneVolumes(ctx context.Context) error {
|
||||
_, err := volumes.Prune(r.conn, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Network operations
|
||||
|
||||
// ListNetworks returns all network.
|
||||
func (r *SocketRuntime) ListNetworks(ctx context.Context) ([]NetworkSummary, error) {
|
||||
opts := &network.ListOptions{}
|
||||
podmanNetworks, err := network.List(r.conn, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertPodmanNetworkList(podmanNetworks), nil
|
||||
}
|
||||
|
||||
// RemoveNetwork removes a network.
|
||||
func (r *SocketRuntime) RemoveNetwork(ctx context.Context, name string) error {
|
||||
_, err := network.Remove(r.conn, name, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// PruneNetworks removes unused network.
|
||||
func (r *SocketRuntime) PruneNetworks(ctx context.Context) error {
|
||||
_, err := network.Prune(r.conn, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Events streams container runtime events.
|
||||
func (r *SocketRuntime) Events(ctx context.Context) (<-chan Event, <-chan error) {
|
||||
eventChan := make(chan Event)
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(eventChan)
|
||||
defer close(errChan)
|
||||
|
||||
opts := &system.EventsOptions{}
|
||||
podmanEventChan, err := system.Events(r.conn, nil, opts)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
for podmanEvent := range podmanEventChan {
|
||||
event := Event{
|
||||
Type: string(podmanEvent.Type),
|
||||
Action: string(podmanEvent.Action),
|
||||
Actor: EventActor{
|
||||
ID: podmanEvent.Actor.ID,
|
||||
Attributes: podmanEvent.Actor.Attributes,
|
||||
},
|
||||
Time: podmanEvent.Time,
|
||||
}
|
||||
select {
|
||||
case eventChan <- event:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return eventChan, errChan
|
||||
}
|
||||
|
||||
// Conversion functions
|
||||
|
||||
func convertPodmanContainerList(podmanContainers []entities.ListContainer) []ContainerSummary {
|
||||
result := make([]ContainerSummary, len(podmanContainers))
|
||||
for i, c := range podmanContainers {
|
||||
result[i] = ContainerSummary{
|
||||
ID: c.ID,
|
||||
Names: c.Names,
|
||||
Image: c.Image,
|
||||
ImageID: c.ImageID,
|
||||
Command: commandToString(c.Command),
|
||||
Created: c.Created.Unix(),
|
||||
State: c.State,
|
||||
Status: c.Status,
|
||||
Ports: convertPodmanPorts(c.Ports),
|
||||
Labels: c.Labels,
|
||||
SizeRw: c.Size.RwSize,
|
||||
SizeRootFs: c.Size.RootFsSize,
|
||||
Pod: c.Pod,
|
||||
PodName: c.PodName,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func commandToString(cmd []string) string {
|
||||
if len(cmd) == 0 {
|
||||
return ""
|
||||
}
|
||||
// Return the command as JSON for consistency with Docker
|
||||
data, _ := json.Marshal(cmd)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func convertPodmanPorts(ports []entities.PortMapping) []PortMapping {
|
||||
result := make([]PortMapping, len(ports))
|
||||
for i, p := range ports {
|
||||
result[i] = PortMapping{
|
||||
IP: p.HostIP,
|
||||
PrivatePort: p.ContainerPort,
|
||||
PublicPort: p.HostPort,
|
||||
Type: p.Protocol,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertPodmanContainerInspect(data *entities.InspectContainerData) *ContainerDetails {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
details := &ContainerDetails{
|
||||
ID: data.ID,
|
||||
Name: data.Name,
|
||||
Created: data.Created,
|
||||
Path: data.Path,
|
||||
Args: data.Args,
|
||||
Image: data.Image,
|
||||
ImageID: data.ImageName,
|
||||
ResolvConfPath: data.ResolvConfPath,
|
||||
HostnamePath: data.HostnamePath,
|
||||
HostsPath: data.HostsPath,
|
||||
LogPath: data.LogPath,
|
||||
RestartCount: int(data.RestartCount),
|
||||
Driver: data.Driver,
|
||||
MountLabel: data.MountLabel,
|
||||
ProcessLabel: data.ProcessLabel,
|
||||
AppArmorProfile: data.AppArmorProfile,
|
||||
}
|
||||
|
||||
if data.State != nil {
|
||||
details.State = &ContainerState{
|
||||
Status: data.State.Status,
|
||||
Running: data.State.Running,
|
||||
Paused: data.State.Paused,
|
||||
Restarting: data.State.Restarting,
|
||||
OOMKilled: data.State.OOMKilled,
|
||||
Dead: data.State.Dead,
|
||||
Pid: data.State.Pid,
|
||||
ExitCode: int(data.State.ExitCode),
|
||||
Error: data.State.Error,
|
||||
StartedAt: data.State.StartedAt,
|
||||
FinishedAt: data.State.FinishedAt,
|
||||
}
|
||||
|
||||
if data.State.Health != nil {
|
||||
details.State.Health = &HealthState{
|
||||
Status: data.State.Health.Status,
|
||||
FailingStreak: data.State.Health.FailingStreak,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if data.Config != nil {
|
||||
details.Config = &ContainerConfig{
|
||||
Hostname: data.Config.Hostname,
|
||||
Domainname: data.Config.Domainname,
|
||||
User: data.Config.User,
|
||||
AttachStdin: data.Config.AttachStdin,
|
||||
AttachStdout: data.Config.AttachStdout,
|
||||
AttachStderr: data.Config.AttachStderr,
|
||||
Tty: data.Config.Tty,
|
||||
OpenStdin: data.Config.OpenStdin,
|
||||
StdinOnce: data.Config.StdinOnce,
|
||||
Env: data.Config.Env,
|
||||
Cmd: data.Config.Cmd,
|
||||
Image: data.Config.Image,
|
||||
WorkingDir: data.Config.WorkingDir,
|
||||
Entrypoint: data.Config.Entrypoint,
|
||||
OnBuild: data.Config.OnBuild,
|
||||
Labels: data.Config.Labels,
|
||||
StopSignal: data.Config.StopSignal,
|
||||
}
|
||||
}
|
||||
|
||||
return details
|
||||
}
|
||||
|
||||
func convertPodmanContainerStats(stat entities.ContainerStats) ContainerStatsEntry {
|
||||
return ContainerStatsEntry{
|
||||
Read: time.Now(),
|
||||
PreRead: time.Now().Add(-time.Second),
|
||||
CPUStats: CPUStats{
|
||||
CPUUsage: CPUUsage{
|
||||
TotalUsage: int64(stat.CPU),
|
||||
},
|
||||
SystemCPUUsage: int64(stat.CPUSystemNano),
|
||||
OnlineCpus: int(stat.CPUNano),
|
||||
},
|
||||
PreCPUStats: CPUStats{},
|
||||
MemoryStats: MemoryStats{
|
||||
Usage: int64(stat.MemUsage),
|
||||
Limit: int64(stat.MemLimit),
|
||||
},
|
||||
PidsStats: PidsStats{
|
||||
Current: int(stat.PIDs),
|
||||
},
|
||||
Name: stat.Name,
|
||||
ID: stat.ContainerID,
|
||||
}
|
||||
}
|
||||
|
||||
func convertPodmanImageList(podmanImages []*entities.ImageSummary) []ImageSummary {
|
||||
result := make([]ImageSummary, len(podmanImages))
|
||||
for i, img := range podmanImages {
|
||||
result[i] = ImageSummary{
|
||||
ID: img.ID,
|
||||
ParentID: img.ParentId,
|
||||
RepoTags: img.RepoTags,
|
||||
RepoDigests: img.RepoDigests,
|
||||
Created: img.Created,
|
||||
Size: img.Size,
|
||||
SharedSize: img.SharedSize,
|
||||
VirtualSize: img.VirtualSize,
|
||||
Labels: img.Labels,
|
||||
Containers: img.Containers,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertPodmanImageInspect(data *entities.ImageInspectReport) *ImageDetails {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
details := &ImageDetails{
|
||||
ID: data.ID,
|
||||
RepoTags: data.RepoTags,
|
||||
RepoDigests: data.RepoDigests,
|
||||
Parent: data.Parent,
|
||||
Comment: data.Comment,
|
||||
Created: *data.Created,
|
||||
Author: data.Author,
|
||||
Architecture: data.Architecture,
|
||||
Os: data.Os,
|
||||
Size: data.Size,
|
||||
VirtualSize: data.VirtualSize,
|
||||
}
|
||||
|
||||
if data.RootFS != nil {
|
||||
details.RootFS = RootFS{
|
||||
Type: data.RootFS.Type,
|
||||
Layers: data.RootFS.Layers,
|
||||
}
|
||||
}
|
||||
|
||||
return details
|
||||
}
|
||||
|
||||
func convertPodmanImageHistory(history []*entities.ImageHistoryLayer) []ImageHistoryEntry {
|
||||
result := make([]ImageHistoryEntry, len(history))
|
||||
for i, layer := range history {
|
||||
result[i] = ImageHistoryEntry{
|
||||
ID: layer.ID,
|
||||
Created: layer.Created.Unix(),
|
||||
CreatedBy: layer.CreatedBy,
|
||||
Tags: layer.Tags,
|
||||
Size: layer.Size,
|
||||
Comment: layer.Comment,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertPodmanVolumeList(podmanVolumes []*entities.VolumeListReport) []VolumeSummary {
|
||||
result := make([]VolumeSummary, len(podmanVolumes))
|
||||
for i, vol := range podmanVolumes {
|
||||
result[i] = VolumeSummary{
|
||||
Name: vol.Name,
|
||||
Driver: vol.Driver,
|
||||
Mountpoint: vol.Mountpoint,
|
||||
CreatedAt: vol.CreatedAt,
|
||||
Labels: vol.Labels,
|
||||
Scope: vol.Scope,
|
||||
Options: vol.Options,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertPodmanNetworkList(podmanNetworks []entities.NetworkListReport) []NetworkSummary {
|
||||
result := make([]NetworkSummary, len(podmanNetworks))
|
||||
for i, nw := range podmanNetworks {
|
||||
result[i] = NetworkSummary{
|
||||
Name: nw.Name,
|
||||
ID: nw.ID,
|
||||
Created: nw.Created,
|
||||
Driver: nw.Driver,
|
||||
Labels: nw.Labels,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
426
pkg/commands/runtime_types.go
Normal file
426
pkg/commands/runtime_types.go
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
package commands
|
||||
|
||||
import "time"
|
||||
|
||||
// ContainerSummary provides runtime-agnostic container information.
|
||||
// This replaces Docker's container.Summary type.
|
||||
type ContainerSummary struct {
|
||||
ID string
|
||||
Names []string
|
||||
Image string
|
||||
ImageID string
|
||||
Command string
|
||||
Created int64
|
||||
State string
|
||||
Status string
|
||||
Ports []PortMapping
|
||||
Labels map[string]string
|
||||
SizeRw int64
|
||||
SizeRootFs int64
|
||||
// Podman-specific fields
|
||||
Pod string
|
||||
PodName string
|
||||
}
|
||||
|
||||
// PortMapping represents a container port mapping.
|
||||
type PortMapping struct {
|
||||
IP string
|
||||
PrivatePort uint16
|
||||
PublicPort uint16
|
||||
Type string
|
||||
}
|
||||
|
||||
// ContainerDetails provides full container inspection data.
|
||||
// This replaces Docker's container.InspectResponse type.
|
||||
type ContainerDetails struct {
|
||||
ID string
|
||||
Name string
|
||||
Created time.Time
|
||||
Path string
|
||||
Args []string
|
||||
State *ContainerState
|
||||
Image string
|
||||
ImageID string
|
||||
ResolvConfPath string
|
||||
HostnamePath string
|
||||
HostsPath string
|
||||
LogPath string
|
||||
RestartCount int
|
||||
Driver string
|
||||
Platform string
|
||||
MountLabel string
|
||||
ProcessLabel string
|
||||
AppArmorProfile string
|
||||
Config *ContainerConfig
|
||||
NetworkSettings *NetworkSettings
|
||||
Mounts []Mount
|
||||
}
|
||||
|
||||
// ContainerState represents the state of a container.
|
||||
type ContainerState struct {
|
||||
Status string
|
||||
Running bool
|
||||
Paused bool
|
||||
Restarting bool
|
||||
OOMKilled bool
|
||||
Dead bool
|
||||
Pid int
|
||||
ExitCode int
|
||||
Error string
|
||||
StartedAt time.Time
|
||||
FinishedAt time.Time
|
||||
Health *HealthState
|
||||
}
|
||||
|
||||
// HealthState represents the health check state of a container.
|
||||
type HealthState struct {
|
||||
Status string
|
||||
FailingStreak int
|
||||
Log []HealthLog
|
||||
}
|
||||
|
||||
// HealthLog represents a health check log entry.
|
||||
type HealthLog struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
ExitCode int
|
||||
Output string
|
||||
}
|
||||
|
||||
// ContainerConfig represents container configuration.
|
||||
type ContainerConfig struct {
|
||||
Hostname string
|
||||
Domainname string
|
||||
User string
|
||||
AttachStdin bool
|
||||
AttachStdout bool
|
||||
AttachStderr bool
|
||||
ExposedPorts map[string]struct{}
|
||||
Tty bool
|
||||
OpenStdin bool
|
||||
StdinOnce bool
|
||||
Env []string
|
||||
Cmd []string
|
||||
Image string
|
||||
Volumes map[string]struct{}
|
||||
WorkingDir string
|
||||
Entrypoint []string
|
||||
OnBuild []string
|
||||
Labels map[string]string
|
||||
StopSignal string
|
||||
StopTimeout *int
|
||||
Shell []string
|
||||
}
|
||||
|
||||
// NetworkSettings represents container network settings.
|
||||
type NetworkSettings struct {
|
||||
Bridge string
|
||||
SandboxID string
|
||||
HairpinMode bool
|
||||
LinkLocalIPv6Address string
|
||||
LinkLocalIPv6PrefixLen int
|
||||
Ports map[string][]PortBinding
|
||||
SandboxKey string
|
||||
Networks map[string]*EndpointSettings
|
||||
}
|
||||
|
||||
// PortBinding represents a port binding.
|
||||
type PortBinding struct {
|
||||
HostIP string
|
||||
HostPort string
|
||||
}
|
||||
|
||||
// EndpointSettings represents network endpoint settings.
|
||||
type EndpointSettings struct {
|
||||
IPAMConfig *EndpointIPAMConfig
|
||||
Links []string
|
||||
Aliases []string
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
Gateway string
|
||||
IPAddress string
|
||||
IPPrefixLen int
|
||||
IPv6Gateway string
|
||||
GlobalIPv6Address string
|
||||
GlobalIPv6PrefixLen int
|
||||
MacAddress string
|
||||
DriverOpts map[string]string
|
||||
}
|
||||
|
||||
// EndpointIPAMConfig represents IPAM configuration for an endpoint.
|
||||
type EndpointIPAMConfig struct {
|
||||
IPv4Address string
|
||||
IPv6Address string
|
||||
LinkLocalIPs []string
|
||||
}
|
||||
|
||||
// Mount represents a container mount.
|
||||
type Mount struct {
|
||||
Type string
|
||||
Name string
|
||||
Source string
|
||||
Destination string
|
||||
Driver string
|
||||
Mode string
|
||||
RW bool
|
||||
Propagation string
|
||||
}
|
||||
|
||||
// ContainerStatsEntry provides runtime-agnostic container stats.
|
||||
// This is used for streaming stats from the runtime.
|
||||
type ContainerStatsEntry struct {
|
||||
Read time.Time
|
||||
PreRead time.Time
|
||||
CPUStats CPUStats
|
||||
PreCPUStats CPUStats
|
||||
MemoryStats MemoryStats
|
||||
PidsStats PidsStats
|
||||
Networks map[string]NetworkStats
|
||||
BlkioStats BlkioStats
|
||||
Name string
|
||||
ID string
|
||||
}
|
||||
|
||||
// CPUStats represents CPU usage statistics.
|
||||
type CPUStats struct {
|
||||
CPUUsage CPUUsage
|
||||
SystemCPUUsage int64
|
||||
OnlineCpus int
|
||||
ThrottlingData ThrottlingData
|
||||
}
|
||||
|
||||
// CPUUsage represents CPU usage breakdown.
|
||||
type CPUUsage struct {
|
||||
TotalUsage int64
|
||||
PercpuUsage []int64
|
||||
UsageInKernelmode int64
|
||||
UsageInUsermode int64
|
||||
}
|
||||
|
||||
// ThrottlingData represents CPU throttling data.
|
||||
type ThrottlingData struct {
|
||||
Periods int
|
||||
ThrottledPeriods int
|
||||
ThrottledTime int64
|
||||
}
|
||||
|
||||
// MemoryStats represents memory usage statistics.
|
||||
type MemoryStats struct {
|
||||
Usage int64
|
||||
MaxUsage int64
|
||||
Limit int64
|
||||
Stats MemoryStatsDetails
|
||||
}
|
||||
|
||||
// MemoryStatsDetails provides detailed memory statistics.
|
||||
type MemoryStatsDetails struct {
|
||||
ActiveAnon int64
|
||||
ActiveFile int64
|
||||
Cache int64
|
||||
Dirty int64
|
||||
HierarchicalMemoryLimit int64
|
||||
HierarchicalMemswLimit int64
|
||||
InactiveAnon int64
|
||||
InactiveFile int64
|
||||
MappedFile int64
|
||||
Pgfault int64
|
||||
Pgmajfault int64
|
||||
Pgpgin int64
|
||||
Pgpgout int64
|
||||
Rss int64
|
||||
RssHuge int64
|
||||
TotalActiveAnon int64
|
||||
TotalActiveFile int64
|
||||
TotalCache int64
|
||||
TotalDirty int64
|
||||
TotalInactiveAnon int64
|
||||
TotalInactiveFile int64
|
||||
TotalMappedFile int64
|
||||
TotalPgfault int64
|
||||
TotalPgmajfault int64
|
||||
TotalPgpgin int64
|
||||
TotalPgpgout int64
|
||||
TotalRss int64
|
||||
TotalRssHuge int64
|
||||
TotalUnevictable int64
|
||||
TotalWriteback int64
|
||||
Unevictable int64
|
||||
Writeback int64
|
||||
}
|
||||
|
||||
// PidsStats represents PID statistics.
|
||||
type PidsStats struct {
|
||||
Current int
|
||||
Limit int64
|
||||
}
|
||||
|
||||
// NetworkStats represents network I/O statistics.
|
||||
type NetworkStats struct {
|
||||
RxBytes int64
|
||||
RxPackets int64
|
||||
RxErrors int64
|
||||
RxDropped int64
|
||||
TxBytes int64
|
||||
TxPackets int64
|
||||
TxErrors int64
|
||||
TxDropped int64
|
||||
}
|
||||
|
||||
// BlkioStats represents block I/O statistics.
|
||||
type BlkioStats struct {
|
||||
IoServiceBytesRecursive []BlkioStatEntry
|
||||
IoServicedRecursive []BlkioStatEntry
|
||||
IoQueueRecursive []BlkioStatEntry
|
||||
IoServiceTimeRecursive []BlkioStatEntry
|
||||
IoWaitTimeRecursive []BlkioStatEntry
|
||||
IoMergedRecursive []BlkioStatEntry
|
||||
IoTimeRecursive []BlkioStatEntry
|
||||
SectorsRecursive []BlkioStatEntry
|
||||
}
|
||||
|
||||
// BlkioStatEntry represents a single block I/O stat entry.
|
||||
type BlkioStatEntry struct {
|
||||
Major int64
|
||||
Minor int64
|
||||
Op string
|
||||
Value int64
|
||||
}
|
||||
|
||||
// ImageSummary provides runtime-agnostic image information.
|
||||
// This replaces Docker's image.Summary type.
|
||||
type ImageSummary struct {
|
||||
ID string
|
||||
ParentID string
|
||||
RepoTags []string
|
||||
RepoDigests []string
|
||||
Created int64
|
||||
Size int64
|
||||
SharedSize int64
|
||||
VirtualSize int64
|
||||
Labels map[string]string
|
||||
Containers int64
|
||||
}
|
||||
|
||||
// ImageDetails provides full image inspection data.
|
||||
type ImageDetails struct {
|
||||
ID string
|
||||
RepoTags []string
|
||||
RepoDigests []string
|
||||
Parent string
|
||||
Comment string
|
||||
Created time.Time
|
||||
Container string
|
||||
DockerVersion string
|
||||
Author string
|
||||
Config *ContainerConfig
|
||||
Architecture string
|
||||
Os string
|
||||
OsVersion string
|
||||
Size int64
|
||||
VirtualSize int64
|
||||
RootFS RootFS
|
||||
Metadata ImageMetadata
|
||||
}
|
||||
|
||||
// RootFS represents the root filesystem of an image.
|
||||
type RootFS struct {
|
||||
Type string
|
||||
Layers []string
|
||||
}
|
||||
|
||||
// ImageMetadata represents image metadata.
|
||||
type ImageMetadata struct {
|
||||
LastTagTime time.Time
|
||||
}
|
||||
|
||||
// ImageHistoryEntry represents a layer in image history.
|
||||
type ImageHistoryEntry struct {
|
||||
ID string
|
||||
Created int64
|
||||
CreatedBy string
|
||||
Tags []string
|
||||
Size int64
|
||||
Comment string
|
||||
}
|
||||
|
||||
// VolumeSummary provides runtime-agnostic volume information.
|
||||
// This replaces Docker's volume.Volume type.
|
||||
type VolumeSummary struct {
|
||||
Name string
|
||||
Driver string
|
||||
Mountpoint string
|
||||
CreatedAt time.Time
|
||||
Status map[string]interface{}
|
||||
Labels map[string]string
|
||||
Scope string
|
||||
Options map[string]string
|
||||
UsageData *VolumeUsageData
|
||||
}
|
||||
|
||||
// VolumeUsageData represents volume usage statistics.
|
||||
type VolumeUsageData struct {
|
||||
Size int64
|
||||
RefCount int64
|
||||
}
|
||||
|
||||
// NetworkSummary provides runtime-agnostic network information.
|
||||
// This replaces Docker's network.Inspect type.
|
||||
type NetworkSummary struct {
|
||||
Name string
|
||||
ID string
|
||||
Created time.Time
|
||||
Scope string
|
||||
Driver string
|
||||
EnableIPv6 bool
|
||||
IPAM IPAM
|
||||
Internal bool
|
||||
Attachable bool
|
||||
Ingress bool
|
||||
Containers map[string]EndpointResource
|
||||
Options map[string]string
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
// IPAM represents IP Address Management configuration.
|
||||
type IPAM struct {
|
||||
Driver string
|
||||
Options map[string]string
|
||||
Config []IPAMConfig
|
||||
}
|
||||
|
||||
// IPAMConfig represents IPAM configuration for a network.
|
||||
type IPAMConfig struct {
|
||||
Subnet string
|
||||
IPRange string
|
||||
Gateway string
|
||||
AuxAddress map[string]string
|
||||
}
|
||||
|
||||
// EndpointResource represents a container endpoint on a network.
|
||||
type EndpointResource struct {
|
||||
Name string
|
||||
EndpointID string
|
||||
MacAddress string
|
||||
IPv4Address string
|
||||
IPv6Address string
|
||||
}
|
||||
|
||||
// TopResponse represents the response from ContainerTop.
|
||||
type TopResponse struct {
|
||||
Titles []string
|
||||
Processes [][]string
|
||||
}
|
||||
|
||||
// Event represents a container runtime event (container start/stop, image pull, etc.)
|
||||
type Event struct {
|
||||
Type string // "container", "image", "volume", "network"
|
||||
Action string // "start", "stop", "create", "delete", etc.
|
||||
Actor EventActor
|
||||
Time int64
|
||||
}
|
||||
|
||||
// EventActor represents the actor (container, image, etc.) that triggered an event.
|
||||
type EventActor struct {
|
||||
ID string
|
||||
Attributes map[string]string
|
||||
}
|
||||
|
|
@ -4,24 +4,23 @@ import (
|
|||
"context"
|
||||
"os/exec"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/christophe-duc/lazypodman/pkg/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Service : A docker Service
|
||||
// Service represents a compose service
|
||||
type Service struct {
|
||||
Name string
|
||||
ID string
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
Container *Container
|
||||
DockerCommand LimitedDockerCommand
|
||||
PodmanCommand LimitedPodmanCommand
|
||||
}
|
||||
|
||||
// Remove removes the service's containers
|
||||
func (s *Service) Remove(options container.RemoveOptions) error {
|
||||
return s.Container.Remove(options)
|
||||
func (s *Service) Remove(force bool, removeVolumes bool) error {
|
||||
return s.Container.Remove(force, removeVolumes)
|
||||
}
|
||||
|
||||
// Stop stops the service's containers
|
||||
|
|
@ -47,7 +46,7 @@ func (s *Service) Start() error {
|
|||
func (s *Service) runCommand(templateCmdStr string) error {
|
||||
command := utils.ApplyTemplate(
|
||||
templateCmdStr,
|
||||
s.DockerCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
s.PodmanCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
)
|
||||
return s.OSCommand.RunCommand(command)
|
||||
}
|
||||
|
|
@ -62,7 +61,7 @@ func (s *Service) ViewLogs() (*exec.Cmd, error) {
|
|||
templateString := s.OSCommand.Config.UserConfig.CommandTemplates.ViewServiceLogs
|
||||
command := utils.ApplyTemplate(
|
||||
templateString,
|
||||
s.DockerCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
s.PodmanCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
)
|
||||
|
||||
cmd := s.OSCommand.ExecutableFromString(command)
|
||||
|
|
@ -76,7 +75,7 @@ func (s *Service) RenderTop(ctx context.Context) (string, error) {
|
|||
templateString := s.OSCommand.Config.UserConfig.CommandTemplates.ServiceTop
|
||||
command := utils.ApplyTemplate(
|
||||
templateString,
|
||||
s.DockerCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
s.PodmanCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
)
|
||||
|
||||
return s.OSCommand.RunCommandWithOutputContext(ctx, command)
|
||||
|
|
|
|||
|
|
@ -3,54 +3,21 @@ package commands
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Volume : A docker Volume
|
||||
// Volume represents a Podman volume
|
||||
type Volume struct {
|
||||
Name string
|
||||
Volume *volume.Volume
|
||||
Client *client.Client
|
||||
Summary VolumeSummary
|
||||
Runtime ContainerRuntime
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
DockerCommand LimitedDockerCommand
|
||||
}
|
||||
|
||||
// RefreshVolumes gets the volumes and stores them
|
||||
func (c *DockerCommand) RefreshVolumes() ([]*Volume, error) {
|
||||
result, err := c.Client.VolumeList(context.Background(), volume.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
volumes := result.Volumes
|
||||
|
||||
ownVolumes := make([]*Volume, len(volumes))
|
||||
|
||||
for i, vol := range volumes {
|
||||
ownVolumes[i] = &Volume{
|
||||
Name: vol.Name,
|
||||
Volume: vol,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
return ownVolumes, nil
|
||||
}
|
||||
|
||||
// PruneVolumes prunes volumes
|
||||
func (c *DockerCommand) PruneVolumes() error {
|
||||
_, err := c.Client.VolumesPrune(context.Background(), filters.Args{})
|
||||
return err
|
||||
PodmanCommand LimitedPodmanCommand
|
||||
}
|
||||
|
||||
// Remove removes the volume
|
||||
func (v *Volume) Remove(force bool) error {
|
||||
return v.Client.VolumeRemove(context.Background(), v.Name, force)
|
||||
ctx := context.Background()
|
||||
return v.Runtime.RemoveVolume(ctx, v.Name, force)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ import (
|
|||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/fatih/color"
|
||||
"github.com/christophe-duc/lazypodman/pkg/commands"
|
||||
"github.com/christophe-duc/lazypodman/pkg/tasks"
|
||||
|
|
@ -105,48 +103,42 @@ func (gui *Gui) promptToReturn() {
|
|||
}
|
||||
|
||||
func (gui *Gui) writeContainerLogs(ctr *commands.Container, ctx context.Context, writer io.Writer) error {
|
||||
readCloser, err := gui.DockerCommand.Client.ContainerLogs(ctx, ctr.ID, container.LogsOptions{
|
||||
ShowStdout: true,
|
||||
ShowStderr: true,
|
||||
Timestamps: gui.Config.UserConfig.Logs.Timestamps,
|
||||
Since: gui.Config.UserConfig.Logs.Since,
|
||||
Tail: gui.Config.UserConfig.Logs.Tail,
|
||||
Follow: true,
|
||||
})
|
||||
if err != nil {
|
||||
// Build podman logs command
|
||||
args := []string{"logs", "--follow"}
|
||||
|
||||
if gui.Config.UserConfig.Logs.Timestamps {
|
||||
args = append(args, "--timestamps")
|
||||
}
|
||||
if gui.Config.UserConfig.Logs.Since != "" {
|
||||
args = append(args, "--since", gui.Config.UserConfig.Logs.Since)
|
||||
}
|
||||
if gui.Config.UserConfig.Logs.Tail != "" {
|
||||
args = append(args, "--tail", gui.Config.UserConfig.Logs.Tail)
|
||||
}
|
||||
args = append(args, ctr.ID)
|
||||
|
||||
cmd := ctr.OSCommand.NewCmd("podman", args...)
|
||||
cmd.Stdout = writer
|
||||
cmd.Stderr = writer
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
gui.Log.Error(err)
|
||||
return err
|
||||
}
|
||||
defer readCloser.Close()
|
||||
|
||||
if !ctr.DetailsLoaded() {
|
||||
// loop until the details load or context is cancelled, using timer
|
||||
ticker := time.NewTicker(time.Millisecond * 100)
|
||||
defer ticker.Stop()
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
if ctr.DetailsLoaded() {
|
||||
break outer
|
||||
}
|
||||
}
|
||||
// Wait for context cancellation or command completion
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if err := ctr.OSCommand.Kill(cmd); err != nil {
|
||||
gui.Log.Warn(err)
|
||||
}
|
||||
return nil
|
||||
case err := <-done:
|
||||
return err
|
||||
}
|
||||
|
||||
if ctr.Details.Config.Tty {
|
||||
_, err = io.Copy(writer, readCloser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
_, err = stdcopy.StdCopy(writer, writer, readCloser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/christophe-duc/lazypodman/pkg/commands"
|
||||
|
|
@ -255,7 +254,7 @@ func (gui *Gui) refreshContainersAndServices() error {
|
|||
originalSelectedLineIdx := gui.Panels.Services.SelectedIdx
|
||||
selectedService, isServiceSelected := gui.Panels.Services.List.TryGet(originalSelectedLineIdx)
|
||||
|
||||
containers, services, err := gui.DockerCommand.RefreshContainersAndServices(
|
||||
containers, services, err := gui.PodmanCommand.RefreshContainersAndServices(
|
||||
gui.Panels.Services.List.GetAllItems(),
|
||||
gui.Panels.Containers.List.GetAllItems(),
|
||||
)
|
||||
|
|
@ -283,7 +282,7 @@ func (gui *Gui) refreshContainersAndServices() error {
|
|||
}
|
||||
|
||||
func (gui *Gui) renderContainersAndServices() error {
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
if gui.PodmanCommand.InDockerComposeProject {
|
||||
if err := gui.Panels.Services.RerenderList(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -308,14 +307,13 @@ func (gui *Gui) handleContainersRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
handleMenuPress := func(configOptions container.RemoveOptions) error {
|
||||
handleMenuPress := func(force bool, removeVolumes bool) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RemovingStatus, func() error {
|
||||
if err := ctr.Remove(configOptions); err != nil {
|
||||
if err := ctr.Remove(force, removeVolumes); err != nil {
|
||||
if commands.HasErrorCode(err, commands.MustStopContainer) {
|
||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.MustForceToRemoveContainer, func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RemovingStatus, func() error {
|
||||
configOptions.Force = true
|
||||
return ctr.Remove(configOptions)
|
||||
return ctr.Remove(true, removeVolumes)
|
||||
})
|
||||
}, nil)
|
||||
}
|
||||
|
|
@ -327,12 +325,12 @@ func (gui *Gui) handleContainersRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
|
||||
menuItems := []*types.MenuItem{
|
||||
{
|
||||
LabelColumns: []string{gui.Tr.Remove, "docker rm " + ctr.ID[1:10]},
|
||||
OnPress: func() error { return handleMenuPress(container.RemoveOptions{}) },
|
||||
LabelColumns: []string{gui.Tr.Remove, "podman rm " + ctr.ID[1:10]},
|
||||
OnPress: func() error { return handleMenuPress(false, false) },
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{gui.Tr.RemoveWithVolumes, "docker rm --volumes " + ctr.ID[1:10]},
|
||||
OnPress: func() error { return handleMenuPress(container.RemoveOptions{RemoveVolumes: true}) },
|
||||
LabelColumns: []string{gui.Tr.RemoveWithVolumes, "podman rm --volumes " + ctr.ID[1:10]},
|
||||
OnPress: func() error { return handleMenuPress(false, true) },
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +414,7 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error {
|
|||
func (gui *Gui) handlePruneContainers() error {
|
||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneContainers, func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
||||
err := gui.DockerCommand.PruneContainers()
|
||||
err := gui.PodmanCommand.PruneContainers()
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
|
@ -446,7 +444,7 @@ func (gui *Gui) handleContainersExecShell(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
|
||||
func (gui *Gui) containerExecShell(container *commands.Container) error {
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{
|
||||
Container: container,
|
||||
})
|
||||
|
||||
|
|
@ -463,7 +461,7 @@ func (gui *Gui) handleContainersCustomCommand(g *gocui.Gui, v *gocui.View) error
|
|||
return nil
|
||||
}
|
||||
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{
|
||||
Container: ctr,
|
||||
})
|
||||
|
||||
|
|
@ -490,7 +488,7 @@ func (gui *Gui) handleRemoveContainers() error {
|
|||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmRemoveContainers, func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RemovingStatus, func() error {
|
||||
for _, ctr := range gui.Panels.Containers.List.GetAllItems() {
|
||||
if err := ctr.Remove(container.RemoveOptions{Force: true}); err != nil {
|
||||
if err := ctr.Remove(true, false); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -517,7 +515,7 @@ func (gui *Gui) handleContainersBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
|
||||
bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Containers...)
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{})
|
||||
|
||||
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
|
||||
throttle "github.com/boz/go-throttle"
|
||||
|
|
@ -27,7 +25,7 @@ import (
|
|||
type Gui struct {
|
||||
g *gocui.Gui
|
||||
Log *logrus.Entry
|
||||
DockerCommand *commands.DockerCommand
|
||||
PodmanCommand *commands.PodmanCommand
|
||||
OSCommand *commands.OSCommand
|
||||
State guiState
|
||||
Config *config.AppConfig
|
||||
|
|
@ -125,7 +123,7 @@ func getScreenMode(config *config.AppConfig) WindowMaximisation {
|
|||
}
|
||||
|
||||
// NewGui builds a new gui handler
|
||||
func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand *commands.OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*Gui, error) {
|
||||
func NewGui(log *logrus.Entry, podmanCommand *commands.PodmanCommand, oSCommand *commands.OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*Gui, error) {
|
||||
initialState := guiState{
|
||||
Platform: *oSCommand.Platform,
|
||||
Panels: &panelStates{
|
||||
|
|
@ -141,7 +139,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
|||
|
||||
gui := &Gui{
|
||||
Log: log,
|
||||
DockerCommand: dockerCommand,
|
||||
PodmanCommand: podmanCommand,
|
||||
OSCommand: oSCommand,
|
||||
State: initialState,
|
||||
Config: config,
|
||||
|
|
@ -292,7 +290,7 @@ func (gui *Gui) setPanels() {
|
|||
}
|
||||
|
||||
func (gui *Gui) updateContainerDetails() error {
|
||||
return gui.DockerCommand.RefreshContainerDetails(gui.Panels.Containers.List.GetAllItems())
|
||||
return gui.PodmanCommand.RefreshContainerDetails(gui.Panels.Containers.List.GetAllItems())
|
||||
}
|
||||
|
||||
func (gui *Gui) refresh() {
|
||||
|
|
@ -328,50 +326,38 @@ func (gui *Gui) listenForEvents(ctx context.Context, refresh func()) {
|
|||
|
||||
onError := func(err error) {
|
||||
if err != nil {
|
||||
gui.ErrorChan <- errors.Errorf("Docker event stream returned error: %s\nRetry count: %d", err.Error(), errorCount)
|
||||
gui.ErrorChan <- errors.Errorf("Podman event stream returned error: %s\nRetry count: %d", err.Error(), errorCount)
|
||||
}
|
||||
errorCount++
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
|
||||
outer:
|
||||
// Try to use the runtime's event stream if available
|
||||
eventChan, errChan := gui.PodmanCommand.Runtime.Events(ctx)
|
||||
|
||||
for {
|
||||
messageChan, errChan := gui.DockerCommand.Client.Events(context.Background(), events.ListOptions{})
|
||||
|
||||
if errorCount > 0 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case err := <-errChan:
|
||||
onError(err)
|
||||
continue outer
|
||||
default:
|
||||
// If we're here then we lost connection to docker and we just got it back.
|
||||
// The reason we do this refresh explicitly is because successfully
|
||||
// reconnecting with docker does not mean it's going to send us a new
|
||||
// event any time soon.
|
||||
|
||||
// Assuming the confirmation prompt currently holds the given error
|
||||
_ = gui.closeConfirmationPrompt()
|
||||
refresh()
|
||||
errorCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case message := <-messageChan:
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case event := <-eventChan:
|
||||
if event.Type != "" {
|
||||
// We could be more granular about what events should trigger which refreshes.
|
||||
// At the moment it's pretty efficient though, and it might not be worth
|
||||
// the maintenance burden of mapping specific events to specific refreshes
|
||||
refresh()
|
||||
|
||||
gui.Log.Infof("received event of type: %s", message.Type)
|
||||
case err := <-errChan:
|
||||
gui.Log.Infof("received event of type: %s", event.Type)
|
||||
}
|
||||
case err := <-errChan:
|
||||
if err != nil {
|
||||
onError(err)
|
||||
continue outer
|
||||
// Attempt to reconnect
|
||||
if errorCount > 0 {
|
||||
_ = gui.closeConfirmationPrompt()
|
||||
refresh()
|
||||
errorCount = 0
|
||||
}
|
||||
// Re-establish event stream
|
||||
eventChan, errChan = gui.PodmanCommand.Runtime.Events(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -459,7 +445,7 @@ func (gui *Gui) ShouldRefresh(key string) bool {
|
|||
}
|
||||
|
||||
func (gui *Gui) initiallyFocusedViewName() string {
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
if gui.PodmanCommand.InDockerComposeProject {
|
||||
return "services"
|
||||
}
|
||||
return "containers"
|
||||
|
|
@ -485,7 +471,7 @@ func (gui *Gui) monitorContainerStats(ctx context.Context) {
|
|||
case <-ticker.C:
|
||||
for _, container := range gui.Panels.Containers.List.GetAllItems() {
|
||||
if !container.MonitoringStats {
|
||||
go gui.DockerCommand.CreateClientStatMonitor(container)
|
||||
go gui.PodmanCommand.CreateClientStatMonitor(container)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/christophe-duc/lazypodman/pkg/commands"
|
||||
|
|
@ -101,7 +100,7 @@ func (gui *Gui) reloadImages() error {
|
|||
}
|
||||
|
||||
func (gui *Gui) refreshStateImages() error {
|
||||
images, err := gui.DockerCommand.RefreshImages()
|
||||
images, err := gui.PodmanCommand.RefreshImages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -121,9 +120,9 @@ func (gui *Gui) FilterString(view *gocui.View) string {
|
|||
|
||||
func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
type removeImageOption struct {
|
||||
description string
|
||||
command string
|
||||
configOptions image.RemoveOptions
|
||||
description string
|
||||
command string
|
||||
force bool
|
||||
}
|
||||
|
||||
img, err := gui.Panels.Images.GetSelectedItem()
|
||||
|
|
@ -133,27 +132,17 @@ func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
|
||||
shortSha := img.ID[7:17]
|
||||
|
||||
// TODO: have a way of toggling in a menu instead of showing each permutation as a separate menu item
|
||||
// Simplified menu - Podman's rmi handles pruning automatically
|
||||
options := []*removeImageOption{
|
||||
{
|
||||
description: gui.Tr.Remove,
|
||||
command: "docker image rm " + shortSha,
|
||||
configOptions: image.RemoveOptions{PruneChildren: true, Force: false},
|
||||
description: gui.Tr.Remove,
|
||||
command: "podman image rm " + shortSha,
|
||||
force: false,
|
||||
},
|
||||
{
|
||||
description: gui.Tr.RemoveWithoutPrune,
|
||||
command: "docker image rm --no-prune " + shortSha,
|
||||
configOptions: image.RemoveOptions{PruneChildren: false, Force: false},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.RemoveWithForce,
|
||||
command: "docker image rm --force " + shortSha,
|
||||
configOptions: image.RemoveOptions{PruneChildren: true, Force: true},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.RemoveWithoutPruneWithForce,
|
||||
command: "docker image rm --no-prune --force " + shortSha,
|
||||
configOptions: image.RemoveOptions{PruneChildren: false, Force: true},
|
||||
description: gui.Tr.RemoveWithForce,
|
||||
command: "podman image rm --force " + shortSha,
|
||||
force: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +153,7 @@ func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
color.New(color.FgRed).Sprint(option.command),
|
||||
},
|
||||
OnPress: func() error {
|
||||
if err := img.Remove(option.configOptions); err != nil {
|
||||
if err := img.Remove(option.force); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +171,7 @@ func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
func (gui *Gui) handlePruneImages() error {
|
||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneImages, func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
||||
err := gui.DockerCommand.PruneImages()
|
||||
err := gui.PodmanCommand.PruneImages()
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
|
@ -197,7 +186,7 @@ func (gui *Gui) handleImagesCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{
|
||||
Image: img,
|
||||
})
|
||||
|
||||
|
|
@ -215,7 +204,7 @@ func (gui *Gui) handleImagesBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
|
||||
bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Images...)
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{})
|
||||
|
||||
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ func (gui *Gui) reloadNetworks() error {
|
|||
}
|
||||
|
||||
func (gui *Gui) refreshStateNetworks() error {
|
||||
networks, err := gui.DockerCommand.RefreshNetworks()
|
||||
networks, err := gui.PodmanCommand.RefreshNetworks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -140,7 +140,7 @@ func (gui *Gui) handleNetworksRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
func (gui *Gui) handlePruneNetworks() error {
|
||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneNetworks, func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
||||
err := gui.DockerCommand.PruneNetworks()
|
||||
err := gui.PodmanCommand.PruneNetworks()
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ func (gui *Gui) handleNetworksCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{
|
||||
Network: network,
|
||||
})
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ func (gui *Gui) handleNetworksBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
|
||||
bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Networks...)
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{})
|
||||
|
||||
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
|||
return &panels.SideListPanel[*commands.Project]{
|
||||
ContextState: &panels.ContextState[*commands.Project]{
|
||||
GetMainTabs: func() []panels.MainTab[*commands.Project] {
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
if gui.PodmanCommand.InDockerComposeProject {
|
||||
return []panels.MainTab[*commands.Project]{
|
||||
{
|
||||
Key: "logs",
|
||||
|
|
@ -79,7 +79,7 @@ func (gui *Gui) refreshProject() error {
|
|||
|
||||
func (gui *Gui) getProjectName() string {
|
||||
projectName := path.Base(gui.Config.ProjectDir)
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
if gui.PodmanCommand.InDockerComposeProject {
|
||||
for _, service := range gui.Panels.Services.List.GetAllItems() {
|
||||
container := service.Container
|
||||
if container != nil && container.DetailsLoaded() {
|
||||
|
|
@ -122,7 +122,7 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
|
|||
cmd := gui.OSCommand.RunCustomCommand(
|
||||
utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.AllLogs,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{}),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
|
|||
|
||||
func (gui *Gui) renderDockerComposeConfig(_project *commands.Project) tasks.TaskFunc {
|
||||
return gui.NewSimpleRenderStringTask(func() string {
|
||||
return utils.ColoredYamlString(gui.DockerCommand.DockerComposeConfig())
|
||||
return utils.ColoredYamlString(gui.PodmanCommand.DockerComposeConfig())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ func lazypodmanTitle() string {
|
|||
|
||||
// handleViewAllLogs switches to a subprocess viewing all the logs from docker-compose
|
||||
func (gui *Gui) handleViewAllLogs(g *gocui.Gui, v *gocui.View) error {
|
||||
c, err := gui.DockerCommand.ViewAllLogs()
|
||||
c, err := gui.PodmanCommand.ViewAllLogs()
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
|
|||
return presentation.GetServiceDisplayStrings(&gui.Config.UserConfig.Gui, service)
|
||||
},
|
||||
Hide: func() bool {
|
||||
return !gui.DockerCommand.InDockerComposeProject
|
||||
return !gui.PodmanCommand.InDockerComposeProject
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -292,7 +292,7 @@ func (gui *Gui) handleProjectUp(g *gocui.Gui, v *gocui.View) error {
|
|||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmUpProject, func(g *gocui.Gui, v *gocui.View) error {
|
||||
cmdStr := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.Up,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
return gui.WithWaitingStatus(gui.Tr.UppingProjectStatus, func() error {
|
||||
|
|
@ -307,12 +307,12 @@ func (gui *Gui) handleProjectUp(g *gocui.Gui, v *gocui.View) error {
|
|||
func (gui *Gui) handleProjectDown(g *gocui.Gui, v *gocui.View) error {
|
||||
downCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.Down,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
downWithVolumesCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.DownWithVolumes,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{}),
|
||||
)
|
||||
|
||||
options := []*commandOption{
|
||||
|
|
@ -363,12 +363,12 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
|
||||
rebuildCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RebuildService,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
)
|
||||
|
||||
recreateCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RecreateService,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
)
|
||||
|
||||
options := []*commandOption{
|
||||
|
|
@ -376,7 +376,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
description: gui.Tr.Restart,
|
||||
command: utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RestartService,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
),
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error {
|
||||
|
|
@ -391,7 +391,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
description: gui.Tr.Recreate,
|
||||
command: utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RecreateService,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
),
|
||||
onPress: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error {
|
||||
|
|
@ -406,7 +406,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
description: gui.Tr.Rebuild,
|
||||
command: utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RebuildService,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
gui.PodmanCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
),
|
||||
onPress: func() error {
|
||||
return gui.runSubprocess(gui.OSCommand.RunCustomCommand(rebuildCommand))
|
||||
|
|
@ -433,7 +433,7 @@ func (gui *Gui) handleServicesCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{
|
||||
Service: service,
|
||||
Container: service.Container,
|
||||
})
|
||||
|
|
@ -466,7 +466,7 @@ L:
|
|||
|
||||
func (gui *Gui) handleServicesBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
||||
bulkCommands := gui.Config.UserConfig.BulkCommands.Services
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{})
|
||||
|
||||
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ func (gui *Gui) createAllViews() error {
|
|||
|
||||
gui.Views.Containers.Highlight = true
|
||||
gui.Views.Containers.SelBgColor = selectedLineBgColor
|
||||
if gui.Config.UserConfig.Gui.ShowAllContainers || !gui.DockerCommand.InDockerComposeProject {
|
||||
if gui.Config.UserConfig.Gui.ShowAllContainers || !gui.PodmanCommand.InDockerComposeProject {
|
||||
gui.Views.Containers.Title = gui.Tr.ContainersTitle
|
||||
} else {
|
||||
gui.Views.Containers.Title = gui.Tr.StandaloneContainersTitle
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ func (gui *Gui) reloadVolumes() error {
|
|||
}
|
||||
|
||||
func (gui *Gui) refreshStateVolumes() error {
|
||||
volumes, err := gui.DockerCommand.RefreshVolumes()
|
||||
volumes, err := gui.PodmanCommand.RefreshVolumes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ func (gui *Gui) handleVolumesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
func (gui *Gui) handlePruneVolumes() error {
|
||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneVolumes, func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
||||
err := gui.DockerCommand.PruneVolumes()
|
||||
err := gui.PodmanCommand.PruneVolumes()
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@ func (gui *Gui) handleVolumesCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{
|
||||
Volume: volume,
|
||||
})
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ func (gui *Gui) handleVolumesBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
|
||||
bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Volumes...)
|
||||
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||
commandObject := gui.PodmanCommand.NewCommandObject(commands.CommandObject{})
|
||||
|
||||
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue