Rel v0.50.10 (#3564)
* fix #3455 * Clean up and refactor * fix #3495 #3470 #3455 - fix cmd alias and filters * fix #3535 - revert * fix #3478 - make vulscan a bit less cpu extensive (init stab...) * fix issue with plugin foreground exit * fix#3466-add shared gpu on nodes * fix #3541 - use default namespace when not specified * update deps + release notesmine
parent
e7970c2517
commit
4f5c1a1105
4
Makefile
4
Makefile
|
|
@ -1,5 +1,5 @@
|
|||
NAME := k9s
|
||||
VERSION ?= v0.50.9
|
||||
VERSION ?= v0.50.10
|
||||
PACKAGE := github.com/derailed/$(NAME)
|
||||
OUTPUT_BIN ?= execs/${NAME}
|
||||
GO_FLAGS ?=
|
||||
|
|
@ -13,7 +13,7 @@ BUILD_PLATFORMS ?= linux/amd64,linux/arm64
|
|||
|
||||
SOURCE_DATE_EPOCH ?= $(shell date +%s)
|
||||
ifeq ($(shell uname), Darwin)
|
||||
DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
||||
DATE ?= $(shell TZ=UTC /bin/date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
||||
else
|
||||
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -403,8 +403,13 @@ You can now override the context portForward default address configuration by se
|
|||
liveViewAutoRefresh: false
|
||||
# !!New!! v0.50.8...
|
||||
# Extends the list of supported GPU vendors. The key is the vendor name, the value must correspond to k8s resource driver designation.
|
||||
# Default known GPU vendors:
|
||||
# nvidia: nvidia.com/gpu
|
||||
# nvidia-shared: nvidia.com/gpu.shared
|
||||
# amd: amd.com/gpu
|
||||
# intel: gpu.intel.com/i915
|
||||
gpuVendors:
|
||||
bozo: bozo/gpu
|
||||
bozo: bozo/gpu # extends the gpu vendor and add "bozo"
|
||||
# The path to screen dump. Default: '%temp_dir%/k9s-screens-%username%' (k9s info)
|
||||
screenDumpDir: /tmp/dumps
|
||||
# Represents ui poll intervals in seconds. Default 2.0 secs. Minimum value is 2.0 - values below will be capped to the minimum.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
|
||||
|
||||
# Release v0.50.10
|
||||
|
||||
## Notes
|
||||
|
||||
Thank you to all that contributed with flushing out issues and enhancements for K9s!
|
||||
I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev
|
||||
and see if we're happier with some of the fixes!
|
||||
If you've filed an issue please help me verify and close.
|
||||
|
||||
Your support, kindness and awesome suggestions to make K9s better are, as ever, very much noted and appreciated!
|
||||
Also big thanks to all that have allocated their own time to help others on both slack and on this repo!!
|
||||
|
||||
As you may know, K9s is not pimped out by corps with deep pockets, thus if you feel K9s is helping your Kubernetes journey,
|
||||
please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
|
||||
|
||||
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/zt-3360a389v-ElLHrb0Dp1kAXqYUItSAFA)
|
||||
|
||||
## Maintenance Release!
|
||||
|
||||
---
|
||||
|
||||
## A Word From Our Sponsors...
|
||||
|
||||
To all the good folks below that opted to `pay it forward` and join our sponsorship program, I salute you!!
|
||||
|
||||
* [rufusshrestha](https://github.com/rufusshrestha)
|
||||
* [Ovidijus Balkauskas](https://github.com/Stogas)
|
||||
* [Konrad Konieczny](https://github.com/Psyhackological)
|
||||
* [Serit Tromsø](https://github.com/serit)
|
||||
* [Dennis](https://github.com/dennisTGC)
|
||||
* [LinPr](https://github.com/LinPr)
|
||||
* [franzXaver987](https://github.com/franzXaver987)
|
||||
* [Drew Showalter](https://github.com/one19)
|
||||
* [Sandylen](https://github.com/Sandylen)
|
||||
* [Uriah Carpenter](https://github.com/uriahcarpenter)
|
||||
* [Vector Group](https://github.com/vectorgrp)
|
||||
* [Stefan Roman](https://github.com/katapultcloud)
|
||||
* [Phillip](https://github.com/Loki-Afro)
|
||||
* [Lasse Bang Mikkelsen](https://github.com/lassebm)
|
||||
|
||||
> Sponsorship cancellations since the last release: **19!** 🥹
|
||||
|
||||
---
|
||||
|
||||
## Resolved Issues
|
||||
|
||||
* [#3541](https://github.com/derailed/k9s/issues/3541) ServiceAccount RBAC Rules not displayed if RoleBinding subject doesn't specify namespace
|
||||
* [#3535](https://github.com/derailed/k9s/issues/3535) Current Release process will cause code changes been reverted
|
||||
* [#3525](https://github.com/derailed/k9s/issues/3525) k9s suspends when launching foreground plugin
|
||||
* [#3495](https://github.com/derailed/k9s/issues/3495) Regression: filtering no long works with aliases
|
||||
* [#3478](https://github.com/derailed/k9s/issues/3478) High Disk and CPU usage when imageScans Is enabled in K9s
|
||||
* [#3470](https://github.com/derailed/k9s/issues/3470) Aliases for pods with unequal (!=) label filters not working
|
||||
* [#3466](https://github.com/derailed/k9s/issues/3466) Shared GPU (nvidia.com/gpu.shared) is shown as n/a on K9s node view
|
||||
* [#3455](https://github.com/derailed/k9s/issues/3455) memory command not found
|
||||
|
||||
---
|
||||
|
||||
## Contributed PRs
|
||||
|
||||
Please be sure to give `Big Thanks!` and `ATTA Girls/Boys!` to all the fine contributors for making K9s better for all of us!!
|
||||
|
||||
* [#3558](https://github.com/derailed/k9s/pull/3558) refactor(duplik8s): consolidate duplicate resource commands and updat…
|
||||
* [#3555](https://github.com/derailed/k9s/pull/3555) feat: add dup plugin
|
||||
* [#3543](https://github.com/derailed/k9s/pull/3543) Make "flux trace" more generic
|
||||
* [#3536](https://github.com/derailed/k9s/pull/3536) Add flux-operator resources to flux plugin
|
||||
* [#3528](https://github.com/derailed/k9s/pull/3528) feat(plugins): add pvc debug container plugin
|
||||
* [#3517](https://github.com/derailed/k9s/pull/3517) Feature/refresh rate
|
||||
* [#3516](https://github.com/derailed/k9s/pull/3516) Fixes flickering/jumping issue in context suggestions caused by inconsistent spacing behavior
|
||||
* [#3515](https://github.com/derailed/k9s/pull/3515) Fix/suppress init no resources warning
|
||||
* [#3513](https://github.com/derailed/k9s/pull/3513) fix: Color PV row according to its STATUS column
|
||||
* [#3513](https://github.com/derailed/k9s/pull/3513) fix: Color PV row according to its STATUS column
|
||||
* [#3505](https://github.com/derailed/k9s/pull/3505) docs: Add installation method with gah
|
||||
* [#3503](https://github.com/derailed/k9s/pull/3503) fix(logs): enhance log streaming with retry mechanism and error handling
|
||||
* [#3489](https://github.com/derailed/k9s/pull/3489) feat: Add context deletion functionality
|
||||
* [#3487](https://github.com/derailed/k9s/pull/3487) fsupport core group resources in k9s/plugins/watch-events.yaml
|
||||
* [#3485](https://github.com/derailed/k9s/pull/3485) Add disable-self-subject-access-reviews flag to disable can-i check…
|
||||
* [#3464](https://github.com/derailed/k9s/pull/3464) fix: get-all command in get all plugin
|
||||
|
||||
---
|
||||
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)#
|
||||
39
go.mod
39
go.mod
|
|
@ -29,20 +29,20 @@ require (
|
|||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
|
||||
golang.org/x/text v0.29.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.18.6
|
||||
helm.sh/helm/v3 v3.19.0
|
||||
k8s.io/api v0.34.1
|
||||
k8s.io/apiextensions-apiserver v0.33.3
|
||||
k8s.io/apiextensions-apiserver v0.34.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/cli-runtime v0.34.1
|
||||
k8s.io/client-go v0.34.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kubectl v0.33.4
|
||||
k8s.io/metrics v0.33.4
|
||||
k8s.io/kubectl v0.34.1
|
||||
k8s.io/metrics v0.34.1
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.19.1 // indirect
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
cloud.google.com/go v0.116.0 // indirect
|
||||
cloud.google.com/go/auth v0.13.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
|
||||
|
|
@ -57,7 +57,7 @@ require (
|
|||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/CycloneDX/cyclonedx-go v0.9.2 // indirect
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
|
|
@ -120,7 +120,6 @@ require (
|
|||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.6.0 // indirect
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
|
|
@ -129,7 +128,7 @@ require (
|
|||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/containerd/containerd v1.7.28 // indirect
|
||||
github.com/containerd/containerd/api v1.8.0 // indirect
|
||||
|
|
@ -160,8 +159,8 @@ require (
|
|||
github.com/elliotchance/phpserialize v1.4.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/facebookincubator/nvdtools v0.1.5 // indirect
|
||||
|
|
@ -178,6 +177,7 @@ require (
|
|||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.16.2 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // 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-openapi/jsonpointer v0.21.0 // indirect
|
||||
|
|
@ -312,6 +312,7 @@ require (
|
|||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.22.0 // indirect
|
||||
github.com/sylabs/squashfs v1.0.6 // indirect
|
||||
|
|
@ -331,10 +332,11 @@ require (
|
|||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/zclconf/go-cty v1.16.3 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.31.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.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
|
||||
|
|
@ -357,19 +359,18 @@ require (
|
|||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/api v0.215.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
||||
google.golang.org/grpc v1.68.1 // indirect
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/grpc v1.72.1 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gorm.io/gorm v1.30.0 // indirect
|
||||
gotest.tools/v3 v3.4.0 // indirect
|
||||
k8s.io/apiserver v0.33.3 // indirect
|
||||
k8s.io/component-base v0.33.4 // indirect
|
||||
k8s.io/component-helpers v0.33.4 // indirect
|
||||
k8s.io/apiserver v0.34.1 // indirect
|
||||
k8s.io/component-base v0.34.1 // indirect
|
||||
k8s.io/component-helpers v0.34.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
modernc.org/libc v1.66.3 // indirect
|
||||
|
|
|
|||
98
go.sum
98
go.sum
|
|
@ -1,5 +1,5 @@
|
|||
cel.dev/expr v0.19.1 h1:NciYrtDRIR0lNCnH1LFJegdjspNx9fI59O7TWcua/W4=
|
||||
cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
|
|
@ -90,8 +90,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ
|
|||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
||||
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0 h1:f2Qw/Ehhimh5uO1fayV0QIW7DShEQqhtUfhYc+cBPlw=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0/go.mod h1:2bIszWvQRlJVmJLiuLhukLImRjKPcYdzzsx6darK02A=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.1 h1:oTX4vsorBZo/Zdum6OKPA4o7544hm6smoRv1QjpTwGo=
|
||||
|
|
@ -260,8 +260,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
|
|||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
|
|
@ -307,8 +305,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
|
|||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/containerd/containerd v1.7.28 h1:Nsgm1AtcmEh4AHAJ4gGlNSaKgXiNccU270Dnf81FQ3c=
|
||||
|
|
@ -407,12 +405,16 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m
|
|||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
|
||||
github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE=
|
||||
github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
|
|
@ -483,6 +485,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
|
|||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||
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-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
|
|
@ -648,8 +652,8 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJr
|
|||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
|
||||
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/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4=
|
||||
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0=
|
||||
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 h1:81+kWbE1yErFBMjME0I5k3x3kojjKsWtPYHEAutoPow=
|
||||
|
|
@ -1076,6 +1080,8 @@ github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
|||
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
|
||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
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=
|
||||
|
|
@ -1162,6 +1168,8 @@ github.com/zclconf/go-cty v1.16.3 h1:osr++gw2T61A8KVYHoQiFbFd1Lh3JOCXc/jFLJXKTxk
|
|||
github.com/zclconf/go-cty v1.16.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
|
||||
|
|
@ -1178,12 +1186,12 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
|
|||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w=
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.31.0 h1:G1JQOreVrfhRkner+l4mrGxmfqYCAuy76asTDAo0xsA=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.31.0/go.mod h1:tzQL6E1l+iV44YFTkcAeNQqzXUiekSYP9jjJjXwEd00=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//snGVIM3Tx6QRzlQBao=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
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=
|
||||
|
|
@ -1196,10 +1204,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7Z
|
|||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU=
|
||||
|
|
@ -1223,8 +1231,8 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRa
|
|||
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 v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
|
||||
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.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
|
|
@ -1654,10 +1662,10 @@ google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ6
|
|||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
|
@ -1685,11 +1693,9 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
|
|||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
|
||||
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3 h1:hUfOButuEtpc0UvYiaYRbNwxVYr0mQQOWq6X8beJ9Gc=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3/go.mod h1:jzYlkSMbKypzuu6xoAEijsNVo9ZeDF1u/zCfFgsx7jg=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
|
@ -1739,8 +1745,8 @@ gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
|
|||
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
|
||||
helm.sh/helm/v3 v3.18.6 h1:S/2CqcYnNfLckkHLI0VgQbxgcDaU3N4A/46E3n9wSNY=
|
||||
helm.sh/helm/v3 v3.18.6/go.mod h1:L/dXDR2r539oPlFP1PJqKAC1CUgqHJDLkxKpDGrWnyg=
|
||||
helm.sh/helm/v3 v3.19.0 h1:krVyCGa8fa/wzTZgqw0DUiXuRT5BPdeqE/sQXujQ22k=
|
||||
helm.sh/helm/v3 v3.19.0/go.mod h1:Lk/SfzN0w3a3C3o+TdAKrLwJ0wcZ//t1/SDXAvfgDdc=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
@ -1750,28 +1756,28 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
|||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs=
|
||||
k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8=
|
||||
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
|
||||
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4=
|
||||
k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E=
|
||||
k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
|
||||
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
|
||||
k8s.io/cli-runtime v0.34.1 h1:btlgAgTrYd4sk8vJTRG6zVtqBKt9ZMDeQZo2PIzbL7M=
|
||||
k8s.io/cli-runtime v0.34.1/go.mod h1:aVA65c+f0MZiMUPbseU/M9l1Wo2byeaGwUuQEQVVveE=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/component-base v0.33.4 h1:Jvb/aw/tl3pfgnJ0E0qPuYLT0NwdYs1VXXYQmSuxJGY=
|
||||
k8s.io/component-base v0.33.4/go.mod h1:567TeSdixWW2Xb1yYUQ7qk5Docp2kNznKL87eygY8Rc=
|
||||
k8s.io/component-helpers v0.33.4 h1:DYHQPxWB3XIk7hwAQ4YczUelJ37PcUHfnLeee0qFqV8=
|
||||
k8s.io/component-helpers v0.33.4/go.mod h1:kRgidIgCKFqOW/wy7D8IL3YOT3iaIRZu6FcTEyRr7WU=
|
||||
k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
|
||||
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||
k8s.io/component-helpers v0.34.1 h1:gWhH3CCdwAx5P3oJqZKb4Lg5FYZTWVbdWtOI8n9U4XY=
|
||||
k8s.io/component-helpers v0.34.1/go.mod h1:4VgnUH7UA/shuBur+OWoQC0xfb69sy/93ss0ybZqm3c=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
|
||||
k8s.io/kubectl v0.33.4 h1:nXEI6Vi+oB9hXxoAHyHisXolm/l1qutK3oZQMak4N98=
|
||||
k8s.io/kubectl v0.33.4/go.mod h1:Xe7P9X4DfILvKmlBsVqUtzktkI56lEj22SJW7cFy6nE=
|
||||
k8s.io/metrics v0.33.4 h1:eJ6UdTpKTUQVZbKpUdm5ve39aPpAvvNwLrs13oQcWKc=
|
||||
k8s.io/metrics v0.33.4/go.mod h1:NO/lgFtyIPTurz56debdSh5qRqRfpO8MlkMpau1Ue8U=
|
||||
k8s.io/kubectl v0.34.1 h1:1qP1oqT5Xc93K+H8J7ecpBjaz511gan89KO9Vbsh/OI=
|
||||
k8s.io/kubectl v0.34.1/go.mod h1:JRYlhJpGPyk3dEmJ+BuBiOB9/dAvnrALJEiY/C5qa6A=
|
||||
k8s.io/metrics v0.34.1 h1:374Rexmp1xxgRt64Bi0TsjAM8cA/Y8skwCoPdjtIslE=
|
||||
k8s.io/metrics v0.34.1/go.mod h1:Drf5kPfk2NJrlpcNdSiAAHn/7Y9KqxpRNagByM7Ei80=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import (
|
|||
|
||||
const (
|
||||
// DefaultCallTimeoutDuration is the default api server call timeout duration.
|
||||
DefaultCallTimeoutDuration time.Duration = 15 * time.Second
|
||||
DefaultCallTimeoutDuration time.Duration = 120 * time.Second
|
||||
|
||||
// UsePersistentConfig caches client config to avoid reloads.
|
||||
UsePersistentConfig = true
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func TestCallTimeout(t *testing.T) {
|
|||
e: 1 * time.Minute,
|
||||
},
|
||||
"default": {
|
||||
e: 15 * time.Second,
|
||||
e: client.DefaultCallTimeoutDuration,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,11 +84,11 @@ func NewGVR(s string) *GVR {
|
|||
}
|
||||
|
||||
func (g *GVR) IsCommand() bool {
|
||||
return g != nil && strings.Contains(g.raw, " ")
|
||||
return !g.IsK8sRes()
|
||||
}
|
||||
|
||||
func (g *GVR) IsK8sRes() bool {
|
||||
return strings.Contains(g.raw, "/")
|
||||
return g != nil && (strings.Contains(g.raw, "/") || reservedGVRs.Has(g))
|
||||
}
|
||||
|
||||
// WithSubResource builds a new gvr with a sub resource.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package client
|
||||
|
||||
import "k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
var (
|
||||
// Apps...
|
||||
DpGVR = NewGVR("apps/v1/deployments")
|
||||
|
|
@ -78,3 +80,28 @@ var (
|
|||
RoGVR = NewGVR("rbac.authorization.k8s.io/v1/roles")
|
||||
RobGVR = NewGVR("rbac.authorization.k8s.io/v1/rolebindings")
|
||||
)
|
||||
|
||||
var reservedGVRs = sets.New(
|
||||
CpuGVR,
|
||||
MemGVR,
|
||||
WkGVR,
|
||||
CoGVR,
|
||||
CtGVR,
|
||||
RefGVR,
|
||||
PuGVR,
|
||||
ScnGVR,
|
||||
DirGVR,
|
||||
PfGVR,
|
||||
SdGVR,
|
||||
BeGVR,
|
||||
AliGVR,
|
||||
XGVR,
|
||||
HlpGVR,
|
||||
QGVR,
|
||||
HmGVR,
|
||||
HmhGVR,
|
||||
RbacGVR,
|
||||
PolGVR,
|
||||
UsrGVR,
|
||||
GrpGVR,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,5 +15,4 @@ contexts:
|
|||
name: blee
|
||||
current-context: blee
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users: null
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
|
|
@ -81,19 +82,28 @@ func (a *Aliases) Clear() {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *Aliases) Resolve(command string) (*client.GVR, string, bool) {
|
||||
agvr, ok := a.Get(command)
|
||||
if !ok {
|
||||
return nil, "", false
|
||||
}
|
||||
|
||||
p := cmd.NewInterpreter(agvr.String())
|
||||
func (a *Aliases) Resolve(p *cmd.Interpreter) (*client.GVR, bool) {
|
||||
gvr, ok := a.Get(p.Cmd())
|
||||
if !ok {
|
||||
return agvr, "", true
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return gvr, p.Args(), true
|
||||
if gvr.IsK8sRes() {
|
||||
p.Reset(strings.Replace(p.GetLine(), p.Cmd(), gvr.String(), 1))
|
||||
return gvr, true
|
||||
}
|
||||
|
||||
for gvr.IsCommand() {
|
||||
ap := cmd.NewInterpreter(gvr.String())
|
||||
gvr, ok = a.Get(ap.Cmd())
|
||||
if !ok {
|
||||
return gvr, false
|
||||
}
|
||||
ap.Merge(p)
|
||||
p.Reset(strings.Replace(ap.GetLine(), ap.Cmd(), gvr.String(), 1))
|
||||
}
|
||||
|
||||
return gvr, true
|
||||
}
|
||||
|
||||
// Get retrieves an alias.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/view/cmd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -129,6 +130,131 @@ func TestAliasesSave(t *testing.T) {
|
|||
assert.Len(t, a.Alias, c)
|
||||
}
|
||||
|
||||
func TestAliasResolve(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
exp string
|
||||
ok bool
|
||||
gvr *client.GVR
|
||||
cmd *cmd.Interpreter
|
||||
}{
|
||||
"gvr": {
|
||||
exp: "v1/pods",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods"),
|
||||
},
|
||||
|
||||
"kind": {
|
||||
exp: "pod",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods"),
|
||||
},
|
||||
|
||||
"plural": {
|
||||
exp: "pods",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods"),
|
||||
},
|
||||
|
||||
"short-name": {
|
||||
exp: "po",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods"),
|
||||
},
|
||||
|
||||
"short-name-with-args": {
|
||||
exp: "po 'a in (b,c)' @zorb bozo",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods 'a in (b,c)' @zorb bozo"),
|
||||
},
|
||||
|
||||
"alias": {
|
||||
exp: "pipo",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods"),
|
||||
},
|
||||
|
||||
"toast-command": {
|
||||
exp: "zorg",
|
||||
},
|
||||
|
||||
"alias-no-args": {
|
||||
exp: "wkl",
|
||||
ok: true,
|
||||
gvr: client.WkGVR,
|
||||
cmd: cmd.NewInterpreter("workloads"),
|
||||
},
|
||||
|
||||
"alias-ns-arg": {
|
||||
exp: "pp",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods default"),
|
||||
},
|
||||
|
||||
"multi-alias-ns-inception": {
|
||||
exp: "ppo",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods a=b,b=c default"),
|
||||
},
|
||||
|
||||
"full-alias": {
|
||||
exp: "ppc",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods @fred app=fred default"),
|
||||
},
|
||||
|
||||
"plain-filter": {
|
||||
exp: "po /fred @bozo ns-1",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods /fred @bozo ns-1"),
|
||||
},
|
||||
|
||||
"alias-filter": {
|
||||
exp: "pipo /fred @bozo ns-1",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods /fred @bozo ns-1"),
|
||||
},
|
||||
|
||||
"complex-filter": {
|
||||
exp: "ppc /fred @bozo ns-1",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
cmd: cmd.NewInterpreter("v1/pods @bozo /fred app=fred ns-1"),
|
||||
},
|
||||
}
|
||||
|
||||
a := config.NewAliases()
|
||||
a.Define(client.PodGVR, "po", "pipo", "pod")
|
||||
a.Define(client.PodGVR, client.PodGVR.String())
|
||||
a.Define(client.PodGVR, client.PodGVR.AsResourceName())
|
||||
a.Define(client.WkGVR, client.WkGVR.String(), "workload", "wkl")
|
||||
a.Define(client.NewGVR("pod default"), "pp")
|
||||
a.Define(client.NewGVR("pipo a=b,b=c default"), "ppo")
|
||||
a.Define(client.NewGVR("pod default app=fred @fred"), "ppc")
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
p := cmd.NewInterpreter(u.exp)
|
||||
gvr, ok := a.Resolve(p)
|
||||
assert.Equal(t, u.ok, ok)
|
||||
if ok {
|
||||
assert.Equal(t, u.gvr, gvr)
|
||||
assert.Equal(t, u.cmd.GetLine(), p.GetLine())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers...
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ var KnownGPUVendors = defaultGPUVendors
|
|||
|
||||
var defaultGPUVendors = gpuVendors{
|
||||
"nvidia": "nvidia.com/gpu",
|
||||
"nvidia-shared": "nvidia.com/gpu.shared",
|
||||
"amd": "amd.com/gpu",
|
||||
"intel": "gpu.intel.com/i915",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ k9s:
|
|||
gpuVendors: {}
|
||||
screenDumpDir: /tmp/k9s-test/screen-dumps
|
||||
refreshRate: 2
|
||||
apiServerTimeout: 15s
|
||||
apiServerTimeout: 2m0s
|
||||
maxConnRetry: 5
|
||||
readOnly: false
|
||||
noExitOnCtrlC: false
|
||||
|
|
|
|||
|
|
@ -61,11 +61,6 @@ func (*Alias) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
|||
return oo, nil
|
||||
}
|
||||
|
||||
// AsGVR returns a matching gvr if it exists.
|
||||
func (a *Alias) AsGVR(alias string) (*client.GVR, string, bool) {
|
||||
return a.Resolve(alias)
|
||||
}
|
||||
|
||||
// Get fetch a resource.
|
||||
func (*Alias) Get(_ context.Context, _ string) (runtime.Object, error) {
|
||||
return nil, errors.New("nyi")
|
||||
|
|
|
|||
|
|
@ -16,91 +16,6 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAsGVR(t *testing.T) {
|
||||
a := dao.NewAlias(makeFactory())
|
||||
a.Define(client.PodGVR, "po", "pipo", "pod")
|
||||
a.Define(client.PodGVR, client.PodGVR.String())
|
||||
a.Define(client.PodGVR, client.PodGVR.AsResourceName())
|
||||
a.Define(client.WkGVR, client.WkGVR.String(), "workload", "wkl")
|
||||
a.Define(client.NewGVR("pod default"), "pp")
|
||||
a.Define(client.NewGVR("pipo default"), "ppo")
|
||||
a.Define(client.NewGVR("pod default app=fred @fred"), "ppc")
|
||||
|
||||
uu := map[string]struct {
|
||||
cmd string
|
||||
ok bool
|
||||
gvr *client.GVR
|
||||
exp string
|
||||
}{
|
||||
"gvr": {
|
||||
cmd: "v1/pods",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
},
|
||||
|
||||
"r": {
|
||||
cmd: "pods",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
},
|
||||
|
||||
"alias1": {
|
||||
cmd: "po",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
},
|
||||
|
||||
"alias-2": {
|
||||
cmd: "pipo",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
},
|
||||
|
||||
"missing": {
|
||||
cmd: "zorg",
|
||||
},
|
||||
|
||||
"no-args": {
|
||||
cmd: "wkl",
|
||||
ok: true,
|
||||
gvr: client.WkGVR,
|
||||
},
|
||||
|
||||
"ns-arg": {
|
||||
cmd: "pp",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
exp: "default",
|
||||
},
|
||||
|
||||
"ns-inception": {
|
||||
cmd: "ppo",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
exp: "default",
|
||||
},
|
||||
|
||||
"full-alias": {
|
||||
cmd: "ppc",
|
||||
ok: true,
|
||||
gvr: client.PodGVR,
|
||||
exp: "default app=fred @fred",
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
gvr, exp, ok := a.AsGVR(u.cmd)
|
||||
assert.Equal(t, u.ok, ok)
|
||||
if u.ok {
|
||||
assert.Equal(t, u.gvr, gvr)
|
||||
assert.Equal(t, u.exp, exp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAliasList(t *testing.T) {
|
||||
a := dao.Alias{}
|
||||
a.Init(makeFactory(), client.AliGVR)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func (p *Policy) loadClusterRoleBinding(kind, name string) (render.Policies, err
|
|||
var nn []string
|
||||
for i := range crbs {
|
||||
for _, s := range crbs[i].Subjects {
|
||||
if isSameSubject(kind, ns, n, &s) {
|
||||
if isSameSubject(kind, ns, crbs[i].Namespace, n, &s) {
|
||||
nn = append(nn, crbs[i].RoleRef.Name)
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +174,7 @@ func (p *Policy) fetchRoleBindingNamespaces(kind, name string) (map[string]strin
|
|||
ss := make(map[string]string, len(rbs))
|
||||
for i := range rbs {
|
||||
for _, s := range rbs[i].Subjects {
|
||||
if isSameSubject(kind, ns, n, &s) {
|
||||
if isSameSubject(kind, ns, rbs[i].Namespace, n, &s) {
|
||||
ss[rbs[i].RoleRef.Kind+":"+rbs[i].RoleRef.Name] = rbs[i].Namespace
|
||||
}
|
||||
}
|
||||
|
|
@ -186,13 +186,17 @@ func (p *Policy) fetchRoleBindingNamespaces(kind, name string) (map[string]strin
|
|||
// isSameSubject verifies if the incoming type name and namespace match a subject from a
|
||||
// cluster/roleBinding. A ServiceAccount will always have a namespace and needs to be validated to ensure
|
||||
// we don't display permissions for a ServiceAccount with the same name in a different namespace
|
||||
func isSameSubject(kind, ns, name string, subject *rbacv1.Subject) bool {
|
||||
func isSameSubject(kind, ns, bns, name string, subject *rbacv1.Subject) bool {
|
||||
if subject.Kind != kind || subject.Name != name {
|
||||
return false
|
||||
}
|
||||
if kind == rbacv1.ServiceAccountKind {
|
||||
// Kind and name were checked above, check the namespace
|
||||
return client.IsAllNamespaces(ns) || subject.Namespace == ns
|
||||
cns := subject.Namespace
|
||||
if cns == "" {
|
||||
cns = bns
|
||||
}
|
||||
return client.IsAllNamespaces(ns) || cns == ns
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ func TestIsSameSubject(t *testing.T) {
|
|||
},
|
||||
want: true,
|
||||
},
|
||||
|
||||
"name-does-not-match": {
|
||||
kind: rbacv1.UserKind,
|
||||
name: "foo",
|
||||
|
|
@ -36,6 +37,7 @@ func TestIsSameSubject(t *testing.T) {
|
|||
},
|
||||
want: false,
|
||||
},
|
||||
|
||||
"kind-does-not-match": {
|
||||
kind: rbacv1.GroupKind,
|
||||
name: "foo",
|
||||
|
|
@ -45,6 +47,7 @@ func TestIsSameSubject(t *testing.T) {
|
|||
},
|
||||
want: false,
|
||||
},
|
||||
|
||||
"serviceAccount-all-match": {
|
||||
kind: rbacv1.ServiceAccountKind,
|
||||
name: "foo",
|
||||
|
|
@ -56,6 +59,7 @@ func TestIsSameSubject(t *testing.T) {
|
|||
},
|
||||
want: true,
|
||||
},
|
||||
|
||||
"serviceAccount-namespace-no-match": {
|
||||
kind: rbacv1.ServiceAccountKind,
|
||||
name: "foo",
|
||||
|
|
@ -72,7 +76,7 @@ func TestIsSameSubject(t *testing.T) {
|
|||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
same := isSameSubject(u.kind, u.namespace, u.name, &u.subject)
|
||||
same := isSameSubject(u.kind, u.namespace, u.namespace, u.name, &u.subject)
|
||||
assert.Equal(t, u.want, same)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,9 +132,13 @@ func (c *CmdBuff) resetCancel() {
|
|||
}
|
||||
|
||||
// SetText initializes the buffer with a command.
|
||||
func (c *CmdBuff) SetText(text, suggestion string) {
|
||||
func (c *CmdBuff) SetText(text, suggestion string, wipe bool) {
|
||||
c.mx.Lock()
|
||||
if wipe {
|
||||
c.buff, c.suggestion = []rune(text), suggestion
|
||||
} else {
|
||||
c.buff, c.suggestion = append(c.buff, []rune(text)...), suggestion
|
||||
}
|
||||
c.mx.Unlock()
|
||||
c.fireBufferCompleted(c.GetText(), c.GetSuggestion())
|
||||
}
|
||||
|
|
@ -163,7 +167,7 @@ func (c *CmdBuff) Delete() {
|
|||
if c.Empty() {
|
||||
return
|
||||
}
|
||||
c.SetText(string(c.buff[:len(c.buff)-1]), "")
|
||||
c.SetText(string(c.buff[:len(c.buff)-1]), "", true)
|
||||
c.fireBufferChanged(c.GetText(), c.GetSuggestion())
|
||||
if c.hasCancel() {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -133,5 +133,5 @@ func (f *FishBuff) fireSuggestionChanged(ss []string) {
|
|||
} else {
|
||||
suggest = ss[f.suggestionIndex]
|
||||
}
|
||||
f.SetText(f.GetText(), suggest)
|
||||
f.SetText(f.GetText(), suggest, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,5 +313,5 @@ func (c) Blur() {}
|
|||
func (c) Start() {}
|
||||
func (c) Stop() {}
|
||||
func (c) Init(context.Context) error { return nil }
|
||||
func (c) SetFilter(string) {}
|
||||
func (c) SetLabelSelector(labels.Selector) {}
|
||||
func (c) SetFilter(string, bool) {}
|
||||
func (c) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
|
|
|||
|
|
@ -104,9 +104,13 @@ type Viewer interface {
|
|||
SetCommand(*cmd.Interpreter)
|
||||
}
|
||||
|
||||
// Filterer represents a filterable component.
|
||||
type Filterer interface {
|
||||
SetFilter(string)
|
||||
SetLabelSelector(labels.Selector)
|
||||
// SetFilter sets the filter text.
|
||||
SetFilter(string, bool)
|
||||
|
||||
// SetLabelSelector sets the label selector.
|
||||
SetLabelSelector(labels.Selector, bool)
|
||||
}
|
||||
|
||||
// Cruder performs crud operations.
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@
|
|||
package port
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PortCheck checks if port is free on host.
|
||||
type PortChecker func(PortTunnel) bool
|
||||
type PortChecker func(context.Context, PortTunnel) bool
|
||||
|
||||
// PFAnns represents a collection of port forward annotations.
|
||||
type PFAnns []*PFAnn
|
||||
|
|
@ -39,7 +40,7 @@ func (aa PFAnns) ToTunnels(address string, _ ContainerPortSpecs, available PortC
|
|||
if err != nil {
|
||||
return pts, err
|
||||
}
|
||||
if !available(pt) {
|
||||
if !available(context.Background(), pt) {
|
||||
return pts, fmt.Errorf("port %s is not available on host", pt.LocalPort)
|
||||
}
|
||||
pts = append(pts, pt)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package port_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
|
|
@ -93,7 +94,7 @@ func TestPFsToTunnel(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
f := func(port.PortTunnel) bool {
|
||||
f := func(context.Context, port.PortTunnel) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package port
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
|
|
@ -15,9 +16,9 @@ import (
|
|||
type PortTunnels []PortTunnel
|
||||
|
||||
// CheckAvailable checks if all port tunnels are available.
|
||||
func (t PortTunnels) CheckAvailable() error {
|
||||
func (t PortTunnels) CheckAvailable(ctx context.Context) error {
|
||||
for _, pt := range t {
|
||||
if !IsPortFree(pt) {
|
||||
if !IsPortFree(ctx, pt) {
|
||||
return fmt.Errorf("port %s is not available on host", pt.LocalPort)
|
||||
}
|
||||
}
|
||||
|
|
@ -55,8 +56,9 @@ func (t PortTunnel) PortMap() string {
|
|||
}
|
||||
|
||||
// IsPortFree checks if a address/port pair is available on host.
|
||||
func IsPortFree(t PortTunnel) bool {
|
||||
s, err := net.Listen("tcp", fmt.Sprintf("%s:%s", t.Address, t.LocalPort))
|
||||
func IsPortFree(ctx context.Context, t PortTunnel) bool {
|
||||
var ncfg net.ListenConfig
|
||||
s, err := ncfg.Listen(ctx, "tcp", fmt.Sprintf("%s:%s", t.Address, t.LocalPort))
|
||||
if err != nil {
|
||||
slog.Warn("Port is not available", slogs.Port, t.LocalPort, slogs.Address, t.Address)
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ func TestCronJobRender(t *testing.T) {
|
|||
|
||||
require.NoError(t, c.Render(load(t, "cj"), "", &r))
|
||||
assert.Equal(t, "default/hello", r.ID)
|
||||
assert.Equal(t, model1.Fields{"default", "hello", "0", "*/1 * * * *", "false", "0"}, r.Fields[:6])
|
||||
assert.Equal(t, model1.Fields{"default", "hello", "n/a", "*/1 * * * *", "false", "0"}, r.Fields[:6])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func TestDpRender(t *testing.T) {
|
|||
|
||||
require.NoError(t, c.Render(load(t, "dp"), "", &r))
|
||||
assert.Equal(t, "icx/icx-db", r.ID)
|
||||
assert.Equal(t, model1.Fields{"icx", "icx-db", "0", "1/1", "1", "1"}, r.Fields[:6])
|
||||
assert.Equal(t, model1.Fields{"icx", "icx-db", "n/a", "1/1", "1", "1"}, r.Fields[:6])
|
||||
}
|
||||
|
||||
func BenchmarkDpRender(b *testing.B) {
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ func TestDaemonSetRender(t *testing.T) {
|
|||
|
||||
require.NoError(t, c.Render(load(t, "ds"), "", &r))
|
||||
assert.Equal(t, "kube-system/fluentd-gcp-v3.2.0", r.ID)
|
||||
assert.Equal(t, model1.Fields{"kube-system", "fluentd-gcp-v3.2.0", "0", "2", "2", "2", "2", "2"}, r.Fields[:8])
|
||||
assert.Equal(t, model1.Fields{"kube-system", "fluentd-gcp-v3.2.0", "n/a", "2", "2", "2", "2", "2"}, r.Fields[:8])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,13 +35,14 @@ func ExtractImages(spec *v1.PodSpec) []string {
|
|||
}
|
||||
|
||||
func computeVulScore(ns string, lbls map[string]string, spec *v1.PodSpec) string {
|
||||
if vul.ImgScanner == nil || vul.ImgScanner.ShouldExcludes(ns, lbls) {
|
||||
return "0"
|
||||
if vul.ImgScanner == nil || !vul.ImgScanner.IsInitialized() || vul.ImgScanner.ShouldExcludes(ns, lbls) {
|
||||
return NAValue
|
||||
}
|
||||
ii := ExtractImages(spec)
|
||||
vul.ImgScanner.Enqueue(context.Background(), ii...)
|
||||
sc := vul.ImgScanner.Score(ii...)
|
||||
|
||||
return vul.ImgScanner.Score(ii...)
|
||||
return sc
|
||||
}
|
||||
|
||||
func runesToNum(rr []rune) int64 {
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ func TestJobRender(t *testing.T) {
|
|||
|
||||
require.NoError(t, c.Render(load(t, "job"), "", &r))
|
||||
assert.Equal(t, "default/hello-1567179180", r.ID)
|
||||
assert.Equal(t, model1.Fields{"default", "hello-1567179180", "0", "1/1", "8s", "controller-uid=7473e6d0-cb3b-11e9-990f-42010a800218", "c1", "blang/busybox-bash"}, r.Fields[:8])
|
||||
assert.Equal(t, model1.Fields{"default", "hello-1567179180", "n/a", "1/1", "8s", "controller-uid=7473e6d0-cb3b-11e9-990f-42010a800218", "c1", "blang/busybox-bash"}, r.Fields[:8])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/tview"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
|
@ -48,6 +50,8 @@ var defaultNOHeader = model1.Header{
|
|||
model1.HeaderColumn{Name: "%MEM", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "GPU/A", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "GPU/C", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "SH-GPU/A", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "SH-GPU/C", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "LABELS", Attrs: model1.Attrs{Wide: true}},
|
||||
model1.HeaderColumn{Name: "VALID", Attrs: model1.Attrs{Wide: true}},
|
||||
model1.HeaderColumn{Name: "AGE", Attrs: model1.Attrs{Time: true}},
|
||||
|
|
@ -130,6 +134,8 @@ func (n Node) defaultRow(nwm *NodeWithMetrics, r *model1.Row) error {
|
|||
client.ToPercentageStr(c.mem, a.mem),
|
||||
toMu(a.gpu),
|
||||
toMu(c.gpu),
|
||||
toMu(a.gpuShared),
|
||||
toMu(c.gpuShared),
|
||||
mapToStr(no.Labels),
|
||||
AsStatus(n.diagnose(statuses)),
|
||||
ToAge(no.GetCreationTimestamp()),
|
||||
|
|
@ -203,8 +209,10 @@ func (n *NodeWithMetrics) DeepCopyObject() runtime.Object {
|
|||
}
|
||||
|
||||
type metric struct {
|
||||
cpu, gpu, mem int64
|
||||
lcpu, lgpu, lmem int64
|
||||
cpu, mem int64
|
||||
lcpu, lmem int64
|
||||
gpu, gpuShared int64
|
||||
lgpu int64
|
||||
}
|
||||
|
||||
func gatherNodeMX(no *v1.Node, mx *mv1beta1.NodeMetrics) (c, a metric) {
|
||||
|
|
@ -215,8 +223,38 @@ func gatherNodeMX(no *v1.Node, mx *mv1beta1.NodeMetrics) (c, a metric) {
|
|||
c.mem = mx.Usage.Memory().Value()
|
||||
}
|
||||
|
||||
a.gpu = extractGPU(no.Status.Allocatable).Value()
|
||||
c.gpu = extractGPU(no.Status.Capacity).Value()
|
||||
gpu, gpuShared := extractNodeGPU(no.Status.Allocatable)
|
||||
if gpu != nil {
|
||||
a.gpu = gpu.Value()
|
||||
}
|
||||
if gpuShared != nil {
|
||||
a.gpuShared = gpuShared.Value()
|
||||
}
|
||||
gpu, gpuShared = extractNodeGPU(no.Status.Capacity)
|
||||
if gpu != nil {
|
||||
c.gpu = gpu.Value()
|
||||
}
|
||||
if gpuShared != nil {
|
||||
c.gpuShared = gpuShared.Value()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func extractNodeGPU(rl v1.ResourceList) (main, shared *resource.Quantity) {
|
||||
mm := make(map[string]*resource.Quantity, len(config.KnownGPUVendors))
|
||||
for _, v := range config.KnownGPUVendors {
|
||||
if q, ok := rl[v1.ResourceName(v)]; ok {
|
||||
mm[v] = &q
|
||||
}
|
||||
}
|
||||
for k, v := range mm {
|
||||
if strings.HasSuffix(k, "shared") {
|
||||
shared = v
|
||||
} else {
|
||||
main = v
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,70 @@ import (
|
|||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
func Test_extractNodeGPU(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
rl v1.ResourceList
|
||||
main *resource.Quantity
|
||||
shared *resource.Quantity
|
||||
}{
|
||||
"empty": {},
|
||||
|
||||
"nvidia": {
|
||||
rl: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("3"),
|
||||
v1.ResourceMemory: resource.MustParse("4Gi"),
|
||||
v1.ResourceName("nvidia.com/gpu"): resource.MustParse("2"),
|
||||
},
|
||||
main: makeQ(t, "2"),
|
||||
},
|
||||
|
||||
"nvidia-shared": {
|
||||
rl: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("3"),
|
||||
v1.ResourceMemory: resource.MustParse("4Gi"),
|
||||
v1.ResourceName("nvidia.com/gpu.shared"): resource.MustParse("2"),
|
||||
},
|
||||
shared: makeQ(t, "2"),
|
||||
},
|
||||
|
||||
"nvidia-both": {
|
||||
rl: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("3"),
|
||||
v1.ResourceMemory: resource.MustParse("4Gi"),
|
||||
v1.ResourceName("nvidia.com/gpu.shared"): resource.MustParse("2"),
|
||||
v1.ResourceName("nvidia.com/gpu"): resource.MustParse("5"),
|
||||
},
|
||||
main: makeQ(t, "5"),
|
||||
shared: makeQ(t, "2"),
|
||||
},
|
||||
|
||||
"intel": {
|
||||
rl: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("3"),
|
||||
v1.ResourceMemory: resource.MustParse("4Gi"),
|
||||
v1.ResourceName("gpu.intel.com/i915"): resource.MustParse("5"),
|
||||
},
|
||||
main: makeQ(t, "5"),
|
||||
},
|
||||
|
||||
"unknown-vendor": {
|
||||
rl: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("3"),
|
||||
v1.ResourceMemory: resource.MustParse("4Gi"),
|
||||
v1.ResourceName("bozo/gpu"): resource.MustParse("2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for k, u := range uu {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
m, s := extractNodeGPU(u.rl)
|
||||
assert.Equal(t, u.main, m)
|
||||
assert.Equal(t, u.shared, s)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_gatherNodeMX(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
node v1.Node
|
||||
|
|
@ -125,3 +189,12 @@ func Test_gatherNodeMX(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeQ(t *testing.T, v string) *resource.Quantity {
|
||||
q, err := resource.ParseQuantity(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return &q
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ func TestPodRender(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "default/nginx", r.ID)
|
||||
e := model1.Fields{"default", "nginx", "0", "●", "1/1", "Running", "0", "<unknown>", "100", "100:0", "100", "n/a", "50", "70:170", "71", "29", "0:0", "172.17.0.6", "minikube", "default", "<none>"}
|
||||
e := model1.Fields{"default", "nginx", "n/a", "●", "1/1", "Running", "0", "<unknown>", "100", "100:0", "100", "n/a", "50", "70:170", "71", "29", "0:0", "172.17.0.6", "minikube", "default", "<none>"}
|
||||
assert.Equal(t, e, r.Fields[:21])
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ func TestPodInitRender(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "default/nginx", r.ID)
|
||||
e := model1.Fields{"default", "nginx", "0", "●", "1/1", "Init:0/1", "0", "<unknown>", "10", "100:0", "10", "n/a", "10", "70:170", "14", "5", "0:0", "172.17.0.6", "minikube", "default", "<none>"}
|
||||
e := model1.Fields{"default", "nginx", "n/a", "●", "1/1", "Init:0/1", "0", "<unknown>", "10", "100:0", "10", "n/a", "10", "70:170", "14", "5", "0:0", "172.17.0.6", "minikube", "default", "<none>"}
|
||||
assert.Equal(t, e, r.Fields[:21])
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ func TestPodSidecarRender(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "default/sleep", r.ID)
|
||||
e := model1.Fields{"default", "sleep", "0", "●", "2/2", "Running", "0", "<unknown>", "100", "50:250", "200", "40", "40", "50:80", "80", "50", "0:0", "10.244.0.8", "kind-control-plane", "default", "<none>"}
|
||||
e := model1.Fields{"default", "sleep", "n/a", "●", "2/2", "Running", "0", "<unknown>", "100", "50:250", "200", "40", "40", "50:80", "80", "50", "0:0", "10.244.0.8", "kind-control-plane", "default", "<none>"}
|
||||
assert.Equal(t, e, r.Fields[:21])
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ func TestReplicaSetRender(t *testing.T) {
|
|||
|
||||
require.NoError(t, c.Render(load(t, "rs"), "", &r))
|
||||
assert.Equal(t, "icx/icx-db-7d4b578979", r.ID)
|
||||
assert.Equal(t, model1.Fields{"icx", "icx-db-7d4b578979", "0", "1", "1", "1"}, r.Fields[:6])
|
||||
assert.Equal(t, model1.Fields{"icx", "icx-db-7d4b578979", "n/a", "1", "1", "1"}, r.Fields[:6])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ func TestStatefulSetRender(t *testing.T) {
|
|||
|
||||
require.NoError(t, c.Render(load(t, "sts"), "", &r))
|
||||
assert.Equal(t, "default/nginx-sts", r.ID)
|
||||
assert.Equal(t, model1.Fields{"default", "nginx-sts", "0", "4/4", "app=nginx-sts", "nginx-sts", "nginx", "k8s.gcr.io/nginx-slim:0.8", "app=nginx-sts", ""}, r.Fields[:len(r.Fields)-1])
|
||||
assert.Equal(t, model1.Fields{"default", "nginx-sts", "n/a", "4/4", "app=nginx-sts", "nginx-sts", "nginx", "k8s.gcr.io/nginx-slim:0.8", "app=nginx-sts", ""}, r.Fields[:len(r.Fields)-1])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ const (
|
|||
|
||||
// Context tracks a context logger key.
|
||||
Context = "context"
|
||||
|
||||
// Cluster tracks a cluster logger key.
|
||||
Cluster = "cluster"
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
func TestAppGetCmd(t *testing.T) {
|
||||
a := ui.NewApp(mock.NewMockConfig(t), "")
|
||||
a.Init()
|
||||
a.CmdBuff().SetText("blee", "")
|
||||
a.CmdBuff().SetText("blee", "", true)
|
||||
|
||||
assert.Equal(t, "blee", a.GetCmd())
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ func TestAppGetCmd(t *testing.T) {
|
|||
func TestAppInCmdMode(t *testing.T) {
|
||||
a := ui.NewApp(mock.NewMockConfig(t), "")
|
||||
a.Init()
|
||||
a.CmdBuff().SetText("blee", "")
|
||||
a.CmdBuff().SetText("blee", "", true)
|
||||
assert.False(t, a.InCmdMode())
|
||||
|
||||
a.CmdBuff().SetActive(false)
|
||||
|
|
@ -32,7 +32,7 @@ func TestAppInCmdMode(t *testing.T) {
|
|||
func TestAppResetCmd(t *testing.T) {
|
||||
a := ui.NewApp(mock.NewMockConfig(t), "")
|
||||
a.Init()
|
||||
a.CmdBuff().SetText("blee", "")
|
||||
a.CmdBuff().SetText("blee", "", true)
|
||||
|
||||
a.ResetCmd()
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ func TestAppHasCmd(t *testing.T) {
|
|||
a.ActivateCmd(true)
|
||||
assert.False(t, a.HasCmd())
|
||||
|
||||
a.CmdBuff().SetText("blee", "")
|
||||
a.CmdBuff().SetText("blee", "", true)
|
||||
assert.True(t, a.InCmdMode())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,5 +60,5 @@ func (c) Blur() {}
|
|||
func (c) Start() {}
|
||||
func (c) Stop() {}
|
||||
func (c) Init(context.Context) error { return nil }
|
||||
func (c) SetFilter(string) {}
|
||||
func (c) SetLabelSelector(labels.Selector) {}
|
||||
func (c) SetFilter(string, bool) {}
|
||||
func (c) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ type Suggester interface {
|
|||
// PromptModel represents a prompt buffer.
|
||||
type PromptModel interface {
|
||||
// SetText sets the model text.
|
||||
SetText(txt, sug string)
|
||||
SetText(txt, sug string, clear bool)
|
||||
|
||||
// GetText returns the current text.
|
||||
GetText() string
|
||||
|
|
@ -159,7 +159,7 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|||
p.model.SetActive(false)
|
||||
|
||||
case tcell.KeyEnter, tcell.KeyCtrlE:
|
||||
p.model.SetText(p.model.GetText(), "")
|
||||
p.model.SetText(p.model.GetText(), "", true)
|
||||
p.model.SetActive(false)
|
||||
|
||||
case tcell.KeyCtrlW, tcell.KeyCtrlU:
|
||||
|
|
@ -167,17 +167,17 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
case tcell.KeyUp:
|
||||
if s, ok := m.NextSuggestion(); ok {
|
||||
p.model.SetText(p.model.GetText(), s)
|
||||
p.model.SetText(p.model.GetText(), s, true)
|
||||
}
|
||||
|
||||
case tcell.KeyDown:
|
||||
if s, ok := m.PrevSuggestion(); ok {
|
||||
p.model.SetText(p.model.GetText(), s)
|
||||
p.model.SetText(p.model.GetText(), s, true)
|
||||
}
|
||||
|
||||
case tcell.KeyTab, tcell.KeyRight, tcell.KeyCtrlF:
|
||||
if s, ok := m.CurrentSuggestion(); ok {
|
||||
p.model.SetText(p.model.GetText()+s, "")
|
||||
p.model.SetText(p.model.GetText()+s, "", true)
|
||||
m.ClearSuggestions()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func TestCmdUpdate(t *testing.T) {
|
|||
v.SetModel(m)
|
||||
|
||||
m.AddListener(v)
|
||||
m.SetText("blee", "")
|
||||
m.SetText("blee", "", true)
|
||||
m.Add('!')
|
||||
|
||||
assert.Equal(t, "\x00\x00 [::b]blee!\n", v.GetText(false))
|
||||
|
|
|
|||
|
|
@ -560,7 +560,7 @@ func (t *Table) styleTitle() string {
|
|||
|
||||
buff := t.cmdBuff.GetText()
|
||||
if internal.IsLabelSelector(buff) {
|
||||
if sel, err := TrimLabelSelector(buff); err == nil {
|
||||
if sel, err := ExtractLabelSelector(buff); err == nil {
|
||||
buff = render.Truncate(sel.String(), maxTruncate)
|
||||
}
|
||||
} else if l := t.GetModel().GetLabelSelector(); l != nil && !l.Empty() {
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ func TrimCell(tv *SelectTable, row, col int) string {
|
|||
return strings.TrimSpace(c.Text)
|
||||
}
|
||||
|
||||
// TrimLabelSelector extracts label query.
|
||||
func TrimLabelSelector(s string) (labels.Selector, error) {
|
||||
// ExtractLabelSelector extracts label query.
|
||||
func ExtractLabelSelector(s string) (labels.Selector, error) {
|
||||
selStr := s
|
||||
if strings.Index(s, "-l") == 0 {
|
||||
selStr = strings.TrimSpace(s[2:])
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func TestTruncate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTrimLabelSelector(t *testing.T) {
|
||||
func TestExtractLabelSelector(t *testing.T) {
|
||||
sel, _ := labels.Parse("app=fred,env=blee")
|
||||
uu := map[string]struct {
|
||||
sel string
|
||||
|
|
@ -55,7 +55,7 @@ func TestTrimLabelSelector(t *testing.T) {
|
|||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
sel, err := TrimLabelSelector(u.sel)
|
||||
sel, err := ExtractLabelSelector(u.sel)
|
||||
assert.Equal(t, u.err, err)
|
||||
assert.Equal(t, u.e, sel)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
|
|
@ -36,21 +37,11 @@ type Runner interface {
|
|||
}
|
||||
|
||||
func hasAll(scopes []string) bool {
|
||||
for _, s := range scopes {
|
||||
if s == AllScopes {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(scopes, AllScopes)
|
||||
}
|
||||
|
||||
func includes(aliases []string, s string) bool {
|
||||
for _, a := range aliases {
|
||||
if a == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(aliases, s)
|
||||
}
|
||||
|
||||
func inScope(scopes []string, aliases sets.Set[string]) bool {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
"maps"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
|
@ -241,9 +240,8 @@ func (a *App) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
func (a *App) bindKeys() {
|
||||
a.AddActions(ui.NewKeyActionsFromMap(ui.KeyMap{
|
||||
ui.KeyShift9: ui.NewSharedKeyAction("DumpGOR", a.dumpGOR, false),
|
||||
tcell.KeyCtrlE: ui.NewSharedKeyAction("ToggleHeader", a.toggleHeaderCmd, false),
|
||||
tcell.KeyCtrlG: ui.NewSharedKeyAction("toggleCrumbs", a.toggleCrumbsCmd, false),
|
||||
tcell.KeyCtrlG: ui.NewSharedKeyAction("ToggleCrumbs", a.toggleCrumbsCmd, false),
|
||||
ui.KeyHelp: ui.NewSharedKeyAction("Help", a.helpCmd, false),
|
||||
ui.KeyLeftBracket: ui.NewSharedKeyAction("Go Back", a.previousCommand, false),
|
||||
ui.KeyRightBracket: ui.NewSharedKeyAction("Go Forward", a.nextCommand, false),
|
||||
|
|
@ -254,15 +252,6 @@ func (a *App) bindKeys() {
|
|||
}))
|
||||
}
|
||||
|
||||
func (*App) dumpGOR(evt *tcell.EventKey) *tcell.EventKey {
|
||||
slog.Debug("GOR", slogs.GOR, runtime.NumGoroutine())
|
||||
bb := make([]byte, 5_000_000)
|
||||
runtime.Stack(bb, true)
|
||||
slog.Debug("GOR stack", slogs.Stack, string(bb))
|
||||
|
||||
return evt
|
||||
}
|
||||
|
||||
// ActiveView returns the currently active view.
|
||||
func (a *App) ActiveView() model.Component {
|
||||
return a.Content.GetPrimitive("main").(model.Component)
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ func TestAppNew(t *testing.T) {
|
|||
a := view.NewApp(mock.NewMockConfig(t))
|
||||
_ = a.Init("blee", 10)
|
||||
|
||||
assert.Equal(t, 15, a.GetActions().Len())
|
||||
assert.Equal(t, 14, a.GetActions().Len())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,13 +197,13 @@ func (b *Browser) Stop() {
|
|||
b.Table.Stop()
|
||||
}
|
||||
|
||||
func (b *Browser) SetFilter(s string) {
|
||||
b.CmdBuff().SetText(s, "")
|
||||
func (b *Browser) SetFilter(s string, wipe bool) {
|
||||
b.CmdBuff().SetText(s, "", wipe)
|
||||
}
|
||||
|
||||
func (b *Browser) SetLabelSelector(sel labels.Selector) {
|
||||
func (b *Browser) SetLabelSelector(sel labels.Selector, wipe bool) {
|
||||
if sel != nil {
|
||||
b.CmdBuff().SetText(sel.String(), "")
|
||||
b.CmdBuff().SetText(sel.String(), "", wipe)
|
||||
}
|
||||
b.GetModel().SetLabelSelector(sel)
|
||||
}
|
||||
|
|
@ -214,7 +214,7 @@ func (*Browser) BufferChanged(_, _ string) {}
|
|||
// BufferCompleted indicates input was accepted.
|
||||
func (b *Browser) BufferCompleted(text, _ string) {
|
||||
if internal.IsLabelSelector(text) {
|
||||
if sel, err := ui.TrimLabelSelector(text); err == nil {
|
||||
if sel, err := ui.ExtractLabelSelector(text); err == nil {
|
||||
b.GetModel().SetLabelSelector(sel)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -575,7 +575,7 @@ func (b *Browser) defaultContext() context.Context {
|
|||
ctx = context.WithValue(ctx, internal.KeyGVR, b.GVR())
|
||||
ctx = context.WithValue(ctx, internal.KeyPath, b.Path)
|
||||
if internal.IsLabelSelector(b.CmdBuff().GetText()) {
|
||||
if sel, err := ui.TrimLabelSelector(b.CmdBuff().GetText()); err == nil {
|
||||
if sel, err := ui.ExtractLabelSelector(b.CmdBuff().GetText()); err == nil {
|
||||
ctx = context.WithValue(ctx, internal.KeyLabels, sel)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -46,10 +48,8 @@ func newArgs(p *Interpreter, aa []string) args {
|
|||
arguments[filterKey] = strings.ToLower(a[1:])
|
||||
}
|
||||
|
||||
case strings.Contains(a, labelFlag):
|
||||
if ll := ToLabels(a); len(ll) != 0 {
|
||||
case isLabelArg(a):
|
||||
arguments[labelKey] = strings.ToLower(a)
|
||||
}
|
||||
|
||||
case strings.Index(a, contextFlag) == 0:
|
||||
arguments[contextKey] = a[1:]
|
||||
|
|
@ -80,6 +80,23 @@ func newArgs(p *Interpreter, aa []string) args {
|
|||
return arguments
|
||||
}
|
||||
|
||||
func (a args) String() string {
|
||||
ss := make([]string, 0, len(a))
|
||||
kk := maps.Keys(a)
|
||||
for _, k := range slices.Sorted(kk) {
|
||||
v := a[k]
|
||||
switch k {
|
||||
case filterKey:
|
||||
v = filterFlag + v
|
||||
case contextKey:
|
||||
v = contextFlag + v
|
||||
}
|
||||
ss = append(ss, v)
|
||||
}
|
||||
|
||||
return strings.Join(ss, " ")
|
||||
}
|
||||
|
||||
func (a args) hasFilters() bool {
|
||||
_, fok := a[filterKey]
|
||||
_, zok := a[fuzzyKey]
|
||||
|
|
@ -87,3 +104,13 @@ func (a args) hasFilters() bool {
|
|||
|
||||
return fok || zok || lok
|
||||
}
|
||||
|
||||
func isLabelArg(arg string) bool {
|
||||
for _, flag := range labelFlags {
|
||||
if strings.Contains(arg, flag) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ func TestFlagsNew(t *testing.T) {
|
|||
"label-toast": {
|
||||
i: NewInterpreter("po"),
|
||||
aa: []string{"="},
|
||||
ll: make(args),
|
||||
ll: args{labelKey: "="},
|
||||
},
|
||||
|
||||
"multi-labels": {
|
||||
|
|
|
|||
|
|
@ -10,17 +10,18 @@ import (
|
|||
"github.com/derailed/k9s/internal/client"
|
||||
)
|
||||
|
||||
// ToLabels converts a string into a map of labels.
|
||||
func ToLabels(s string) map[string]string {
|
||||
var (
|
||||
ll = strings.Split(s, ",")
|
||||
lbls = make(map[string]string, len(ll))
|
||||
)
|
||||
for _, l := range ll {
|
||||
kv := strings.Split(l, "=")
|
||||
if len(kv) < 2 || kv[0] == "" || kv[1] == "" {
|
||||
if k, v, ok := splitKv(l); ok {
|
||||
lbls[k] = v
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
lbls[kv[0]] = kv[1]
|
||||
}
|
||||
if len(lbls) == 0 {
|
||||
return nil
|
||||
|
|
@ -29,6 +30,28 @@ func ToLabels(s string) map[string]string {
|
|||
return lbls
|
||||
}
|
||||
|
||||
func splitKv(s string) (k, v string, ok bool) {
|
||||
switch {
|
||||
case strings.Contains(s, labelFlagNotEq):
|
||||
kv := strings.SplitN(s, labelFlagNotEq, 2)
|
||||
if len(kv) == 2 && kv[0] != "" && kv[1] != "" {
|
||||
return strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]), true
|
||||
}
|
||||
case strings.Contains(s, labelFlagEqs):
|
||||
kv := strings.SplitN(s, labelFlagEqs, 2)
|
||||
if len(kv) == 2 && kv[0] != "" && kv[1] != "" {
|
||||
return strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]), true
|
||||
}
|
||||
case strings.Contains(s, labelFlagEq):
|
||||
kv := strings.SplitN(s, labelFlagEq, 2)
|
||||
if len(kv) == 2 && kv[0] != "" && kv[1] != "" {
|
||||
return strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]), true
|
||||
}
|
||||
}
|
||||
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
// ShouldAddSuggest checks if a suggestion match the given command.
|
||||
func ShouldAddSuggest(command, suggest string) (string, bool) {
|
||||
if command != suggest && strings.HasPrefix(suggest, command) {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// Interpreter tracks user prompt input.
|
||||
|
|
@ -43,13 +46,59 @@ func (c *Interpreter) SwitchNS(ns string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Interpreter) Merge(p *Interpreter) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
c.cmd = p.cmd
|
||||
for k, v := range p.args {
|
||||
// if _, ok := c.args[k]; !ok {
|
||||
c.args[k] = v
|
||||
// }
|
||||
}
|
||||
c.line = c.cmd + " " + c.args.String()
|
||||
}
|
||||
|
||||
func (c *Interpreter) grok() {
|
||||
ff := strings.Fields(c.line)
|
||||
if len(ff) == 0 {
|
||||
return
|
||||
}
|
||||
c.cmd = strings.ToLower(ff[0])
|
||||
c.args = newArgs(c, ff[1:])
|
||||
|
||||
var lbls string
|
||||
line := strings.TrimSpace(strings.Replace(c.line, c.cmd, "", 1))
|
||||
if strings.Contains(line, "'") {
|
||||
start, end, ok := quoteIndicies(line)
|
||||
if ok {
|
||||
lbls = line[start+1 : end]
|
||||
line = strings.TrimSpace(strings.Replace(line, "'"+lbls+"'", "", 1))
|
||||
} else {
|
||||
slog.Error("Unmatched single quote in command line", slogs.Line, c.line)
|
||||
line = ""
|
||||
}
|
||||
}
|
||||
ff = strings.Fields(line)
|
||||
if lbls != "" {
|
||||
ff = append(ff, lbls)
|
||||
}
|
||||
c.args = newArgs(c, ff)
|
||||
}
|
||||
|
||||
func quoteIndicies(s string) (start, end int, ok bool) {
|
||||
start, end = -1, -1
|
||||
for i, r := range s {
|
||||
if r == '\'' {
|
||||
if start == -1 {
|
||||
start = i
|
||||
} else if end == -1 {
|
||||
end = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = start != -1 && end != -1
|
||||
return
|
||||
}
|
||||
|
||||
// HasNS returns true if ns is present in prompt.
|
||||
|
|
@ -244,8 +293,6 @@ func (c *Interpreter) HasContext() (string, bool) {
|
|||
}
|
||||
|
||||
// LabelsArg return the labels map if any.
|
||||
func (c *Interpreter) LabelsArg() (map[string]string, bool) {
|
||||
ll, ok := c.args[labelKey]
|
||||
|
||||
return ToLabels(ll), ok
|
||||
func (c *Interpreter) LabelsSelector() (labels.Selector, error) {
|
||||
return labels.Parse(c.args[labelKey])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package cmd_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/view/cmd"
|
||||
|
|
@ -219,34 +220,48 @@ func TestFilterCmd(t *testing.T) {
|
|||
func TestLabelCmd(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
cmd string
|
||||
ok bool
|
||||
labels map[string]string
|
||||
err error
|
||||
labels string
|
||||
}{
|
||||
"empty": {},
|
||||
|
||||
"plain": {
|
||||
cmd: "pod fred=blee",
|
||||
ok: true,
|
||||
labels: map[string]string{"fred": "blee"},
|
||||
labels: "fred=blee",
|
||||
},
|
||||
|
||||
"multi": {
|
||||
cmd: "pod fred=blee,zorg=duh",
|
||||
ok: true,
|
||||
labels: map[string]string{"fred": "blee", "zorg": "duh"},
|
||||
labels: "fred=blee,zorg=duh",
|
||||
},
|
||||
|
||||
"complex-lbls": {
|
||||
cmd: "pod 'fred in (blee,zorg),blee notin (zorg)'",
|
||||
labels: "blee notin (zorg),fred in (blee,zorg)",
|
||||
},
|
||||
|
||||
"no-lbls": {
|
||||
cmd: "pod ns-1",
|
||||
},
|
||||
|
||||
"multi-ns": {
|
||||
cmd: "pod fred=blee,zorg=duh ns1",
|
||||
ok: true,
|
||||
labels: map[string]string{"fred": "blee", "zorg": "duh"},
|
||||
labels: "fred=blee,zorg=duh",
|
||||
},
|
||||
|
||||
"l-arg-spaced": {
|
||||
cmd: "pod fred=blee ",
|
||||
ok: true,
|
||||
labels: map[string]string{"fred": "blee"},
|
||||
labels: "fred=blee",
|
||||
},
|
||||
|
||||
"l-arg-caps": {
|
||||
cmd: "POD FRED=BLEE ",
|
||||
ok: true,
|
||||
labels: map[string]string{"fred": "blee"},
|
||||
labels: "fred=blee",
|
||||
},
|
||||
|
||||
"toast-labels": {
|
||||
cmd: "pod =blee",
|
||||
err: errors.New("found '=', expected: !, identifier, or 'end of string'"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -254,10 +269,10 @@ func TestLabelCmd(t *testing.T) {
|
|||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
p := cmd.NewInterpreter(u.cmd)
|
||||
ll, ok := p.LabelsArg()
|
||||
assert.Equal(t, u.ok, ok)
|
||||
if u.ok {
|
||||
assert.Equal(t, u.labels, ll)
|
||||
ll, err := p.LabelsSelector()
|
||||
assert.Equal(t, u.err, err)
|
||||
if err == nil {
|
||||
assert.Equal(t, u.labels, ll.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -595,3 +610,49 @@ func TestArgs(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_grokLabels(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
cmd string
|
||||
err error
|
||||
lbls string
|
||||
}{
|
||||
"empty": {},
|
||||
|
||||
"no-labels": {
|
||||
cmd: "po @fred",
|
||||
},
|
||||
|
||||
"plain-label": {
|
||||
cmd: "po a=b,b=c @fred",
|
||||
lbls: "a=b,b=c",
|
||||
},
|
||||
|
||||
"label-quotes": {
|
||||
cmd: "po 'a=b,b=c' @fred",
|
||||
lbls: "a=b,b=c",
|
||||
},
|
||||
|
||||
"partial-quotes-label": {
|
||||
cmd: "po 'a=b @fred",
|
||||
lbls: "",
|
||||
},
|
||||
|
||||
"complex": {
|
||||
cmd: "po 'a in (b,c),b notin (c,z)' fred'",
|
||||
lbls: "a in (b,c),b notin (c,z)",
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
p := cmd.NewInterpreter(u.cmd)
|
||||
sel, err := p.LabelsSelector()
|
||||
assert.Equal(t, u.err, err)
|
||||
if err == nil {
|
||||
assert.Equal(t, u.lbls, sel.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,12 +14,25 @@ const (
|
|||
canCmd = "can"
|
||||
nsFlag = "-n"
|
||||
filterFlag = "/"
|
||||
labelFlag = "="
|
||||
labelFlagEq = "="
|
||||
labelFlagEqs = "=="
|
||||
labelFlagNotEq = "!="
|
||||
labelFlagIn = "in"
|
||||
labelFlagNotin = "notin"
|
||||
labelFlagQuote = "'"
|
||||
label
|
||||
fuzzyFlag = "-f"
|
||||
contextFlag = "@"
|
||||
)
|
||||
|
||||
var (
|
||||
labelFlags = []string{
|
||||
labelFlagEq,
|
||||
labelFlagEqs,
|
||||
labelFlagNotEq,
|
||||
labelFlagIn,
|
||||
labelFlagNotin,
|
||||
}
|
||||
rbacRX = regexp.MustCompile(`^can\s+([ugs]):\s*([\w-:]+)\s*$`)
|
||||
|
||||
contextCmd = sets.New(
|
||||
|
|
|
|||
|
|
@ -100,10 +100,13 @@ func (c *Command) contextCmd(p *cmd.Interpreter, pushCmd bool) error {
|
|||
return useContext(c.app, ct)
|
||||
}
|
||||
|
||||
gvr, v, err := c.viewMetaFor(p)
|
||||
gvr, v, comd, err := c.viewMetaFor(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if comd != nil {
|
||||
p = comd
|
||||
}
|
||||
|
||||
return c.exec(p, gvr, c.componentFor(gvr, ct, v), true, pushCmd)
|
||||
}
|
||||
|
|
@ -126,7 +129,7 @@ func (c *Command) aliasCmd(p *cmd.Interpreter, pushCmd bool) error {
|
|||
filter, _ := p.FilterArg()
|
||||
|
||||
v := NewAlias(client.AliGVR)
|
||||
v.SetFilter(filter)
|
||||
v.SetFilter(filter, true)
|
||||
|
||||
return c.exec(p, client.AliGVR, v, false, pushCmd)
|
||||
}
|
||||
|
|
@ -136,7 +139,7 @@ func (c *Command) xrayCmd(p *cmd.Interpreter, pushCmd bool) error {
|
|||
if !ok {
|
||||
return errors.New("invalid command. use `xray xxx`")
|
||||
}
|
||||
gvr, _, ok := c.alias.AsGVR(arg)
|
||||
gvr, ok := c.alias.Resolve(p)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid resource name: %q", arg)
|
||||
}
|
||||
|
|
@ -154,7 +157,7 @@ func (c *Command) xrayCmd(p *cmd.Interpreter, pushCmd bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return c.exec(p, client.NewGVR("xrays"), NewXray(gvr), true, pushCmd)
|
||||
return c.exec(p, client.XGVR, NewXray(gvr), true, pushCmd)
|
||||
}
|
||||
|
||||
// Run execs the command by showing associated display.
|
||||
|
|
@ -162,10 +165,13 @@ func (c *Command) run(p *cmd.Interpreter, fqn string, clearStack, pushCmd bool)
|
|||
if c.specialCmd(p, pushCmd) {
|
||||
return nil
|
||||
}
|
||||
gvr, v, err := c.viewMetaFor(p)
|
||||
gvr, v, comd, err := c.viewMetaFor(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if comd != nil {
|
||||
p.Merge(comd)
|
||||
}
|
||||
|
||||
if context, ok := p.HasContext(); ok {
|
||||
if context != c.app.Config.ActiveContextName() {
|
||||
|
|
@ -206,16 +212,18 @@ func (c *Command) run(p *cmd.Interpreter, fqn string, clearStack, pushCmd bool)
|
|||
}
|
||||
|
||||
co := c.componentFor(gvr, fqn, v)
|
||||
co.SetFilter("")
|
||||
co.SetLabelSelector(labels.Everything())
|
||||
co.SetFilter("", true)
|
||||
co.SetLabelSelector(labels.Everything(), true)
|
||||
if f, ok := p.FilterArg(); ok {
|
||||
co.SetFilter(f)
|
||||
co.SetFilter("/"+f, true)
|
||||
}
|
||||
if f, ok := p.FuzzyArg(); ok {
|
||||
co.SetFilter("-f " + f)
|
||||
co.SetFilter("-f "+f, true)
|
||||
}
|
||||
if ss, ok := p.LabelsArg(); ok {
|
||||
co.SetLabelSelector(labels.SelectorFromSet(ss))
|
||||
if sel, err := p.LabelsSelector(); err == nil {
|
||||
co.SetLabelSelector(sel, false)
|
||||
} else {
|
||||
slog.Error("Unable to grok labels selector", slogs.Error, err)
|
||||
}
|
||||
|
||||
return c.exec(p, gvr, co, clearStack, pushCmd)
|
||||
|
|
@ -292,13 +300,10 @@ func (c *Command) specialCmd(p *cmd.Interpreter, pushCmd bool) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (c *Command) viewMetaFor(p *cmd.Interpreter) (*client.GVR, *MetaViewer, error) {
|
||||
gvr, exp, ok := c.alias.AsGVR(p.Cmd())
|
||||
func (c *Command) viewMetaFor(p *cmd.Interpreter) (*client.GVR, *MetaViewer, *cmd.Interpreter, error) {
|
||||
gvr, ok := c.alias.Resolve(p)
|
||||
if !ok {
|
||||
return client.NoGVR, nil, fmt.Errorf("`%s` command not found", p.Cmd())
|
||||
}
|
||||
if exp != "" {
|
||||
p.Amend(cmd.NewInterpreter(gvr.String() + " " + exp))
|
||||
return client.NoGVR, nil, nil, fmt.Errorf("`%s` command not found", p.Cmd())
|
||||
}
|
||||
|
||||
v := MetaViewer{
|
||||
|
|
@ -310,7 +315,7 @@ func (c *Command) viewMetaFor(p *cmd.Interpreter) (*client.GVR, *MetaViewer, err
|
|||
v = mv
|
||||
}
|
||||
|
||||
return gvr, &v, nil
|
||||
return gvr, &v, p, nil
|
||||
}
|
||||
|
||||
func (*Command) componentFor(gvr *client.GVR, fqn string, v *MetaViewer) ResourceViewer {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ func Test_viewMetaFor(t *testing.T) {
|
|||
uu := map[string]struct {
|
||||
cmd string
|
||||
gvr *client.GVR
|
||||
p *cmd.Interpreter
|
||||
err error
|
||||
}{
|
||||
"empty": {
|
||||
|
|
@ -23,27 +24,37 @@ func Test_viewMetaFor(t *testing.T) {
|
|||
err: errors.New("`` command not found"),
|
||||
},
|
||||
|
||||
"toast-cmd": {
|
||||
"toast": {
|
||||
cmd: "v1/pd",
|
||||
gvr: client.PodGVR,
|
||||
err: errors.New("`v1/pd` command not found"),
|
||||
},
|
||||
|
||||
"gvr-cmd": {
|
||||
"gvr": {
|
||||
cmd: "v1/pods",
|
||||
gvr: client.PodGVR,
|
||||
p: cmd.NewInterpreter("v1/pods"),
|
||||
err: errors.New("blah"),
|
||||
},
|
||||
|
||||
"alias-cmd": {
|
||||
"short-name": {
|
||||
cmd: "po",
|
||||
gvr: client.PodGVR,
|
||||
p: cmd.NewInterpreter("v1/pods"),
|
||||
err: errors.New("blee"),
|
||||
},
|
||||
|
||||
"full-cmd": {
|
||||
"custom-alias": {
|
||||
cmd: "pdl",
|
||||
gvr: client.PodGVR,
|
||||
p: cmd.NewInterpreter("v1/pods @fred app=blee default"),
|
||||
err: errors.New("blee"),
|
||||
},
|
||||
|
||||
"inception": {
|
||||
cmd: "pdal blee",
|
||||
gvr: client.PodGVR,
|
||||
p: cmd.NewInterpreter("v1/pods @fred app=blee blee"),
|
||||
err: errors.New("blee"),
|
||||
},
|
||||
}
|
||||
|
|
@ -55,16 +66,18 @@ func Test_viewMetaFor(t *testing.T) {
|
|||
}
|
||||
c.alias.Define(client.PodGVR, "po", "pod", "pods", client.PodGVR.String())
|
||||
c.alias.Define(client.NewGVR("pod default"), "pd")
|
||||
c.alias.Define(client.NewGVR("pod default app=blee @fred"), "pdl")
|
||||
c.alias.Define(client.NewGVR("pod @fred app=blee default"), "pdl")
|
||||
c.alias.Define(client.NewGVR("pdl"), "pdal")
|
||||
|
||||
for k, u := range uu {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
p := cmd.NewInterpreter(u.cmd)
|
||||
gvr, _, err := c.viewMetaFor(p)
|
||||
gvr, _, acmd, err := c.viewMetaFor(p)
|
||||
if err != nil {
|
||||
assert.Equal(t, u.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.Equal(t, u.gvr, gvr)
|
||||
assert.Equal(t, u.p, acmd)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ func NewDetails(app *App, title, subject, contentType string, searchable bool) *
|
|||
}
|
||||
|
||||
func (*Details) SetCommand(*cmd.Interpreter) {}
|
||||
func (*Details) SetFilter(string) {}
|
||||
func (*Details) SetLabelSelector(labels.Selector) {}
|
||||
func (*Details) SetFilter(string, bool) {}
|
||||
func (*Details) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
||||
// Init initializes the viewer.
|
||||
func (d *Details) Init(_ context.Context) error {
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ func (d *Dir) applyCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
args = append(args, "apply")
|
||||
args = append(args, opts...)
|
||||
args = append(args, sel)
|
||||
res, err := runKu(d.App(), &shellOpts{clear: false, args: args})
|
||||
res, err := runKu(context.Background(), d.App(), &shellOpts{clear: false, args: args})
|
||||
if err != nil {
|
||||
res = "status:\n " + err.Error() + "\nmessage:\n" + fmtResults(res)
|
||||
} else {
|
||||
|
|
@ -260,7 +260,7 @@ func (d *Dir) delCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
args = append(args, "delete")
|
||||
args = append(args, opts...)
|
||||
args = append(args, sel)
|
||||
res, err := runKu(d.App(), &shellOpts{clear: false, args: args})
|
||||
res, err := runKu(context.Background(), d.App(), &shellOpts{clear: false, args: args})
|
||||
if err != nil {
|
||||
res = "status:\n " + err.Error() + "\nmessage:\n" + fmtResults(res)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ func execute(opts *shellOpts, statusChan chan<- string) error {
|
|||
}
|
||||
}()
|
||||
|
||||
var interrupted bool
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||
go func(cancel context.CancelFunc) {
|
||||
|
|
@ -191,6 +192,7 @@ func execute(opts *shellOpts, statusChan chan<- string) error {
|
|||
case <-ctx.Done():
|
||||
slog.Debug("Signal context canceled!")
|
||||
}
|
||||
interrupted = true
|
||||
}(cancel)
|
||||
|
||||
cmds := make([]*exec.Cmd, 0, 1)
|
||||
|
|
@ -224,8 +226,8 @@ func execute(opts *shellOpts, statusChan chan<- string) error {
|
|||
|
||||
var o, e bytes.Buffer
|
||||
err := pipe(ctx, opts, statusChan, &o, &e, cmds...)
|
||||
if err != nil {
|
||||
slog.Error("Exec failed",
|
||||
if err != nil && !interrupted {
|
||||
slog.Error("Pipe Exec failed",
|
||||
slogs.Error, err,
|
||||
slogs.Command, cmds,
|
||||
)
|
||||
|
|
@ -235,7 +237,7 @@ func execute(opts *shellOpts, statusChan chan<- string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runKu(a *App, opts *shellOpts) (string, error) {
|
||||
func runKu(ctx context.Context, a *App, opts *shellOpts) (string, error) {
|
||||
bin, err := exec.LookPath("kubectl")
|
||||
if errors.Is(err, exec.ErrDot) {
|
||||
slog.Error("Kubectl exec can not reside in current working directory", slogs.Error, err)
|
||||
|
|
@ -261,10 +263,10 @@ func runKu(a *App, opts *shellOpts) (string, error) {
|
|||
}
|
||||
opts.binary, opts.background = bin, false
|
||||
|
||||
return oneShoot(opts)
|
||||
return oneShoot(ctx, opts)
|
||||
}
|
||||
|
||||
func oneShoot(opts *shellOpts) (string, error) {
|
||||
func oneShoot(ctx context.Context, opts *shellOpts) (string, error) {
|
||||
if opts.clear {
|
||||
clearScreen()
|
||||
}
|
||||
|
|
@ -273,7 +275,7 @@ func oneShoot(opts *shellOpts) (string, error) {
|
|||
slogs.Bin, opts.binary,
|
||||
slogs.Args, strings.Join(opts.args, " "),
|
||||
)
|
||||
cmd := exec.Command(opts.binary, opts.args...)
|
||||
cmd := exec.CommandContext(ctx, opts.binary, opts.args...)
|
||||
|
||||
var err error
|
||||
buff := bytes.NewBufferString("")
|
||||
|
|
@ -573,12 +575,21 @@ func pipe(_ context.Context, opts *shellOpts, statusChan chan<- string, w, e *by
|
|||
|
||||
slog.Debug("Exec started")
|
||||
err := cmd.Run()
|
||||
slog.Debug("Running exec done", slogs.Error, err)
|
||||
var ex *exec.ExitError
|
||||
// Check if exec failed from a signal
|
||||
if errors.As(err, &ex) && !ex.Exited() {
|
||||
return nil
|
||||
}
|
||||
slog.Debug("Command exec done", slogs.Error, err)
|
||||
if err == nil {
|
||||
statusChan <- fmt.Sprintf("Command completed successfully: %q", cmd.String())
|
||||
}
|
||||
close(statusChan)
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("command failed. Check logs: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ func NewHelp(app *App) *Help {
|
|||
}
|
||||
|
||||
func (*Help) SetCommand(*cmd.Interpreter) {}
|
||||
func (*Help) SetFilter(string) {}
|
||||
func (*Help) SetLabelSelector(labels.Selector) {}
|
||||
func (*Help) SetFilter(string, bool) {}
|
||||
func (*Help) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
||||
// Init initializes the component.
|
||||
func (h *Help) Init(ctx context.Context) error {
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ func showReplicasets(app *App, path string, labelSel labels.Selector, fieldSel s
|
|||
ctx = context.WithValue(ctx, internal.KeyPath, path)
|
||||
return context.WithValue(ctx, internal.KeyFields, fieldSel)
|
||||
})
|
||||
v.SetLabelSelector(labelSel)
|
||||
v.SetLabelSelector(labelSel, true)
|
||||
|
||||
ns, _ := client.Namespaced(path)
|
||||
if err := app.Config.SetActiveNamespace(ns); err != nil {
|
||||
|
|
@ -159,7 +159,7 @@ func showReplicasets(app *App, path string, labelSel labels.Selector, fieldSel s
|
|||
func showPods(app *App, path string, labelSel labels.Selector, fieldSel string) {
|
||||
v := NewPod(client.PodGVR)
|
||||
v.SetContextFn(podCtx(app, path, fieldSel))
|
||||
v.SetLabelSelector(labelSel)
|
||||
v.SetLabelSelector(labelSel, true)
|
||||
|
||||
ns, _ := client.Namespaced(path)
|
||||
if err := app.Config.SetActiveNamespace(ns); err != nil {
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ func NewLiveView(app *App, title string, m model.ResourceViewer) *LiveView {
|
|||
}
|
||||
|
||||
func (*LiveView) SetCommand(*cmd.Interpreter) {}
|
||||
func (*LiveView) SetFilter(string) {}
|
||||
func (*LiveView) SetLabelSelector(labels.Selector) {}
|
||||
func (*LiveView) SetFilter(string, bool) {}
|
||||
func (*LiveView) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
||||
// Init initializes the viewer.
|
||||
func (v *LiveView) Init(_ context.Context) error {
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ func NewLog(gvr *client.GVR, opts *dao.LogOptions) *Log {
|
|||
}
|
||||
|
||||
func (*Log) SetCommand(*cmd.Interpreter) {}
|
||||
func (*Log) SetFilter(string) {}
|
||||
func (*Log) SetLabelSelector(labels.Selector) {}
|
||||
func (*Log) SetFilter(string, bool) {}
|
||||
func (*Log) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
||||
// Init initializes the viewer.
|
||||
func (l *Log) Init(ctx context.Context) (err error) {
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ func runForward(v ResourceViewer, pf watch.Forwarder, f *portforward.PortForward
|
|||
}
|
||||
|
||||
func startFwdCB(v ResourceViewer, path string, pts port.PortTunnels) error {
|
||||
if err := pts.CheckAvailable(); err != nil {
|
||||
if err := pts.CheckAvailable(context.Background()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ package view
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
|
|
@ -30,8 +31,8 @@ func NewPicker() *Picker {
|
|||
}
|
||||
|
||||
func (*Picker) SetCommand(*cmd.Interpreter) {}
|
||||
func (*Picker) SetFilter(string) {}
|
||||
func (*Picker) SetLabelSelector(labels.Selector) {}
|
||||
func (*Picker) SetFilter(string, bool) {}
|
||||
func (*Picker) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
||||
// Init initializes the view.
|
||||
func (p *Picker) Init(ctx context.Context) error {
|
||||
|
|
@ -48,7 +49,7 @@ func (p *Picker) Init(ctx context.Context) error {
|
|||
p.ShowSecondaryText(false)
|
||||
p.SetShortcutColor(pickerView.ShortcutColor.Color())
|
||||
p.SetSelectedBackgroundColor(pickerView.FocusColor.Color())
|
||||
p.SetTitle(" [aqua::b]Containers Picker ")
|
||||
p.SetTitle(fmt.Sprintf(" [%s::b]Containers Picker ", app.Styles.Frame().Title.FgColor.String()))
|
||||
|
||||
p.SetInputCapture(func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if a, ok := p.actions.Get(evt.Key()); ok {
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ func (*Pulse) InCmdMode() bool {
|
|||
}
|
||||
|
||||
func (*Pulse) SetCommand(*cmd.Interpreter) {}
|
||||
func (*Pulse) SetFilter(string) {}
|
||||
func (*Pulse) SetLabelSelector(labels.Selector) {}
|
||||
func (*Pulse) SetFilter(string, bool) {}
|
||||
func (*Pulse) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
||||
// StylesChanged notifies the skin changed.
|
||||
func (p *Pulse) StylesChanged(s *config.Styles) {
|
||||
|
|
@ -417,8 +417,8 @@ func (p *Pulse) enterCmd(*tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
p.Stop()
|
||||
res := client.NewGVR(s.ID()).R()
|
||||
if res == "cpu" || res == "mem" {
|
||||
res = p.app.Config.K9s.DefaultView
|
||||
if res == "cpu" || res == "memory" {
|
||||
res = client.PodGVR.String()
|
||||
}
|
||||
p.App().SetFocus(p.App().Main)
|
||||
p.App().gotoResource(res+" "+p.model.GetNamespace(), "", false, true)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func TestTableViewFilter(t *testing.T) {
|
|||
v.Refresh()
|
||||
|
||||
v.CmdBuff().SetActive(true)
|
||||
v.CmdBuff().SetText("blee", "")
|
||||
v.CmdBuff().SetText("blee", "", true)
|
||||
|
||||
assert.Equal(t, 5, v.GetRowCount())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ func (w *Workload) defaultContext(gvr *client.GVR, fqn string) context.Context {
|
|||
ctx = context.WithValue(ctx, internal.KeyPath, fqn)
|
||||
}
|
||||
if internal.IsLabelSelector(w.GetTable().CmdBuff().GetText()) {
|
||||
if sel, err := ui.TrimLabelSelector(w.GetTable().CmdBuff().GetText()); err == nil {
|
||||
if sel, err := ui.ExtractLabelSelector(w.GetTable().CmdBuff().GetText()); err == nil {
|
||||
ctx = context.WithValue(ctx, internal.KeyLabels, sel)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ func NewXray(gvr *client.GVR) ResourceViewer {
|
|||
}
|
||||
|
||||
func (*Xray) SetCommand(*cmd.Interpreter) {}
|
||||
func (*Xray) SetFilter(string) {}
|
||||
func (*Xray) SetLabelSelector(labels.Selector) {}
|
||||
func (*Xray) SetFilter(string, bool) {}
|
||||
func (*Xray) SetLabelSelector(labels.Selector, bool) {}
|
||||
|
||||
// Init initializes the view.
|
||||
func (x *Xray) Init(ctx context.Context) error {
|
||||
|
|
@ -611,7 +611,7 @@ func (x *Xray) defaultContext() context.Context {
|
|||
if x.CmdBuff().Empty() {
|
||||
ctx = context.WithValue(ctx, internal.KeyLabels, labels.Everything())
|
||||
} else {
|
||||
if sel, err := ui.TrimLabelSelector(x.CmdBuff().GetText()); err == nil {
|
||||
if sel, err := ui.ExtractLabelSelector(x.CmdBuff().GetText()); err == nil {
|
||||
ctx = context.WithValue(ctx, internal.KeyLabels, sel)
|
||||
}
|
||||
}
|
||||
|
|
@ -690,7 +690,7 @@ func (x *Xray) styleTitle() string {
|
|||
return title
|
||||
}
|
||||
if internal.IsLabelSelector(buff) {
|
||||
if sel, err := ui.TrimLabelSelector(buff); err == nil {
|
||||
if sel, err := ui.ExtractLabelSelector(buff); err == nil {
|
||||
buff = sel.String()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,10 @@ func (s *Scan) Dump(w io.Writer) error {
|
|||
|
||||
func (s *Scan) run(mm *match.Matches, store vulnerability.MetadataProvider) error {
|
||||
for m := range mm.Enumerate() {
|
||||
meta, err := store.VulnerabilityMetadata(vulnerability.Reference{ID: m.Vulnerability.ID, Namespace: m.Vulnerability.Namespace})
|
||||
meta, err := store.VulnerabilityMetadata(vulnerability.Reference{
|
||||
ID: m.Vulnerability.ID,
|
||||
Namespace: m.Vulnerability.Namespace,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,30 +82,37 @@ func (s *imageScanner) setScan(img string, sc *Scan) {
|
|||
|
||||
// Init initializes image vulnerability database.
|
||||
func (s *imageScanner) Init(name, version string) {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
defer func(t time.Time) {
|
||||
slog.Debug("VulDb initialization complete",
|
||||
slogs.Elapsed, time.Since(t),
|
||||
)
|
||||
}(time.Now())
|
||||
|
||||
id := clio.Identification{Name: name, Version: version}
|
||||
s.opts = options.DefaultGrype(id)
|
||||
s.opts.GenerateMissingCPEs = true
|
||||
opts := options.DefaultGrype(clio.Identification{Name: name, Version: version})
|
||||
opts.GenerateMissingCPEs = true
|
||||
|
||||
var err error
|
||||
s.provider, s.status, err = grype.LoadVulnerabilityDB(
|
||||
s.opts.ToClientConfig(),
|
||||
s.opts.ToCuratorConfig(),
|
||||
s.opts.DB.AutoUpdate,
|
||||
provider, status, err := grype.LoadVulnerabilityDB(
|
||||
opts.ToClientConfig(),
|
||||
opts.ToCuratorConfig(),
|
||||
opts.DB.AutoUpdate,
|
||||
)
|
||||
if err != nil {
|
||||
s.log.Error("VulDb load failed", slogs.Error, err)
|
||||
return
|
||||
}
|
||||
s.mx.Lock()
|
||||
s.opts, s.provider, s.status = opts, provider, status
|
||||
s.mx.Unlock()
|
||||
|
||||
if e := validateDBLoad(err, s.status); e != nil {
|
||||
if e := validateDBLoad(err, status); e != nil {
|
||||
s.log.Error("VulDb validate failed", slogs.Error, e)
|
||||
return
|
||||
}
|
||||
|
||||
s.mx.Lock()
|
||||
s.initialized = true
|
||||
s.mx.Unlock()
|
||||
slog.Debug("VulDB initialized")
|
||||
}
|
||||
|
||||
// Stop closes scan database.
|
||||
|
|
@ -130,7 +137,7 @@ func (s *imageScanner) Score(ii ...string) string {
|
|||
return sc.String()
|
||||
}
|
||||
|
||||
func (s *imageScanner) isInitialized() bool {
|
||||
func (s *imageScanner) IsInitialized() bool {
|
||||
s.mx.RLock()
|
||||
defer s.mx.RUnlock()
|
||||
|
||||
|
|
@ -138,9 +145,6 @@ func (s *imageScanner) isInitialized() bool {
|
|||
}
|
||||
|
||||
func (s *imageScanner) Enqueue(ctx context.Context, images ...string) {
|
||||
if !s.isInitialized() {
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, imgScanTimeout)
|
||||
defer cancel()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
name: k9s
|
||||
base: core22
|
||||
version: 'v0.50.9'
|
||||
version: 'v0.50.10'
|
||||
summary: K9s is a CLI to view and manage your Kubernetes clusters.
|
||||
description: |
|
||||
K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session.
|
||||
|
|
|
|||
Loading…
Reference in New Issue