Rel v0.40.11 (#3239)
* Fix #3222 - add gvr title config option * Fix #3224 - pod shell use default co annotation * Fix #3226 - yaml search busted * Fix #3210 - description line is buggy -> update ro icons * deps-update * spring cleaning * update deps + add stale issues * cleanup secretsmine
parent
88e04217a2
commit
3a03b67af0
|
|
@ -18,7 +18,7 @@ jobs:
|
|||
cache-dependency-path: go.sum
|
||||
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@v6.5.2
|
||||
uses: golangci/golangci-lint-action@v7.0.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
reporter: github-pr-check
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
name: Closeout Stale Issues
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 2 * * *"
|
||||
|
||||
jobs:
|
||||
close-issues:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-issue-stale: 30
|
||||
days-before-issue-close: 14
|
||||
stale-issue-label: "stale"
|
||||
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
|
||||
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
|
||||
days-before-pr-stale: 30
|
||||
days-before-pr-close: 14
|
||||
stale-pr-label: "stale"
|
||||
stale-pr-message: "This PR is stale because it has been open for 30 days with no activity."
|
||||
close-pr-message: "This PR was closed because it has been inactive for 14 days since being marked as stale."
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
239
.golangci.yml
239
.golangci.yml
|
|
@ -1,6 +1,5 @@
|
|||
# options for analysis running
|
||||
version: "2"
|
||||
run:
|
||||
# default concurrency is an available CPU number
|
||||
concurrency: 8
|
||||
|
||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||
|
|
@ -8,118 +7,113 @@ run:
|
|||
|
||||
# exit code when at least one issue was found, default is 1
|
||||
issues-exit-code: 1
|
||||
|
||||
# include test files or not, default is true
|
||||
tests: true
|
||||
|
||||
# which dirs to skip: they won't be analyzed;
|
||||
# can use regexp here: generated.*, regexp is applied on full path;
|
||||
# default value is empty list, but next dirs are always skipped independently
|
||||
# from this option's value:
|
||||
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
|
||||
# skip-dirs:
|
||||
# - ^test.*
|
||||
formatters:
|
||||
enable:
|
||||
- gci
|
||||
- gofmt
|
||||
# - gofumpt
|
||||
- goimports
|
||||
# - golines
|
||||
|
||||
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
|
||||
# If invoked with -mod=readonly, the go command is disallowed from the implicit
|
||||
# automatic updating of go.mod described above. Instead, it fails when any changes
|
||||
# to go.mod are needed. This setting is most useful to check that go.mod does
|
||||
# not need updates, such as in a continuous integration and testing system.
|
||||
# If invoked with -mod=vendor, the go command assumes that the vendor
|
||||
# directory holds the correct copies of dependencies and ignores
|
||||
# the dependency descriptions in go.mod.
|
||||
modules-download-mode: readonly
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- sloglint
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
- \\.(generated\\.deepcopy|pb)\\.go$
|
||||
|
||||
# which files to skip: they will be analyzed, but issues from them
|
||||
# won't be reported. Default value is empty list, but there is
|
||||
# no need to include all autogenerated files, we confidently recognize
|
||||
# autogenerated files. If it's not please let us know.
|
||||
# skip-files:
|
||||
# - ".*\\.my\\.go$"
|
||||
# - lib/bad.go
|
||||
|
||||
# all available settings of specific linters
|
||||
linters-settings:
|
||||
gocyclo:
|
||||
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||
settings:
|
||||
gocyclo:
|
||||
min-complexity: 35
|
||||
|
||||
govet:
|
||||
enable:
|
||||
- nilness
|
||||
goimports:
|
||||
local-prefixes: github.com/cilium/cilium
|
||||
unused:
|
||||
parameters-are-used: true
|
||||
local-variables-are-used: true
|
||||
field-writes-are-uses: true
|
||||
post-statements-are-reads: true
|
||||
exported-fields-are-used: true
|
||||
generated-is-used: true
|
||||
goheader:
|
||||
values:
|
||||
regexp:
|
||||
PROJECT: 'K9s'
|
||||
template: |-
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
Copyright Authors of {{ PROJECT }}
|
||||
gosec:
|
||||
includes:
|
||||
- G402
|
||||
sloglint:
|
||||
# Enforce not mixing key-value pairs and attributes.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-mixed-arguments
|
||||
# Default: true
|
||||
no-mixed-args: true
|
||||
# Enforce using key-value pairs only (overrides no-mixed-args, incompatible with attr-only).
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-value-pairs-only
|
||||
# Default: false
|
||||
kv-only: true
|
||||
# Enforce using attributes only (overrides no-mixed-args, incompatible with kv-only).
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#attributes-only
|
||||
# Default: false
|
||||
attr-only: false
|
||||
# Enforce not using global loggers.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all global loggers
|
||||
# - "default": report only the default slog logger
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global
|
||||
# Default: ""
|
||||
no-global: ""
|
||||
# Enforce using methods that accept a context.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all contextless calls
|
||||
# - "scope": report only if a context exists in the scope of the outermost function
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only
|
||||
# Default: ""
|
||||
context: ""
|
||||
# Enforce using static values for log messages.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages
|
||||
# Default: false
|
||||
static-msg: false
|
||||
# Enforce using constants instead of raw keys.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-raw-keys
|
||||
# Default: false
|
||||
no-raw-keys: true
|
||||
# Enforce a single key naming convention.
|
||||
# Values: snake, kebab, camel, pascal
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention
|
||||
# Default: ""
|
||||
key-naming-case: camel
|
||||
# Enforce not using specific keys.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#forbidden-keys
|
||||
# Default: []
|
||||
forbidden-keys:
|
||||
- time
|
||||
- level
|
||||
- msg
|
||||
- source
|
||||
# Enforce putting arguments on separate lines.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#arguments-on-separate-lines
|
||||
# Default: false
|
||||
args-on-sep-lines: false
|
||||
govet:
|
||||
enable:
|
||||
- nilness
|
||||
|
||||
goimports:
|
||||
local-prefixes: github.com/derailed/k9s
|
||||
|
||||
unused:
|
||||
parameters-are-used: true
|
||||
local-variables-are-used: true
|
||||
field-writes-are-uses: true
|
||||
post-statements-are-reads: true
|
||||
exported-fields-are-used: true
|
||||
generated-is-used: true
|
||||
|
||||
goheader:
|
||||
values:
|
||||
regexp:
|
||||
PROJECT: 'K9s'
|
||||
template: |-
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
Copyright Authors of {{ PROJECT }}
|
||||
|
||||
gosec:
|
||||
includes:
|
||||
- G402
|
||||
|
||||
sloglint:
|
||||
# Enforce not mixing key-value pairs and attributes.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-mixed-arguments
|
||||
# Default: true
|
||||
no-mixed-args: true
|
||||
# Enforce using key-value pairs only (overrides no-mixed-args, incompatible with attr-only).
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-value-pairs-only
|
||||
# Default: false
|
||||
kv-only: true
|
||||
# Enforce using attributes only (overrides no-mixed-args, incompatible with kv-only).
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#attributes-only
|
||||
# Default: false
|
||||
attr-only: false
|
||||
# Enforce not using global loggers.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all global loggers
|
||||
# - "default": report only the default slog logger
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global
|
||||
# Default: ""
|
||||
no-global: ""
|
||||
# Enforce using methods that accept a context.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all contextless calls
|
||||
# - "scope": report only if a context exists in the scope of the outermost function
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only
|
||||
# Default: ""
|
||||
context: ""
|
||||
# Enforce using static values for log messages.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages
|
||||
# Default: false
|
||||
static-msg: false
|
||||
# Enforce using constants instead of raw keys.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-raw-keys
|
||||
# Default: false
|
||||
no-raw-keys: true
|
||||
# Enforce a single key naming convention.
|
||||
# Values: snake, kebab, camel, pascal
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention
|
||||
# Default: ""
|
||||
key-naming-case: camel
|
||||
# Enforce not using specific keys.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#forbidden-keys
|
||||
# Default: []
|
||||
forbidden-keys:
|
||||
- time
|
||||
- level
|
||||
- msg
|
||||
- source
|
||||
# Enforce putting arguments on separate lines.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#arguments-on-separate-lines
|
||||
# Default: false
|
||||
args-on-sep-lines: false
|
||||
|
||||
|
||||
issues:
|
||||
|
|
@ -132,10 +126,13 @@ issues:
|
|||
exclude-rules:
|
||||
- linters: [staticcheck]
|
||||
text: "SA1019" # this is rule for deprecated method
|
||||
|
||||
- linters: [staticcheck]
|
||||
text: "SA9003: empty branch"
|
||||
|
||||
- linters: [staticcheck]
|
||||
text: "SA2001: empty critical section"
|
||||
|
||||
- linters: [err113]
|
||||
text: "do not define dynamic errors, use wrapped static errors instead" # This rule to avoid opinionated check fmt.Errorf("text")
|
||||
# Skip goimports check on generated files
|
||||
|
|
@ -145,28 +142,4 @@ issues:
|
|||
# Skip goheader check on files imported and modified from upstream k8s
|
||||
- path: "pkg/ipam/(cidrset|service)/.+\\.go"
|
||||
linters:
|
||||
- goheader
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- err113
|
||||
- gofmt
|
||||
- goimports
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- unused
|
||||
- goheader
|
||||
- gosec
|
||||
- gomodguard
|
||||
- gosimple
|
||||
- errcheck
|
||||
- gocyclo
|
||||
- gosec
|
||||
- gosimple
|
||||
- misspell
|
||||
- prealloc
|
||||
- typecheck
|
||||
- sloglint
|
||||
|
||||
- goheader
|
||||
|
|
@ -436,6 +436,8 @@ You can now override the context portForward default address configuration by se
|
|||
skin: dracula # => assumes the file skins/dracula.yaml is present in the $XDG_DATA_HOME/k9s/skins directory
|
||||
# Allows to set certain views default fullscreen mode. (yaml, helm history, describe, value_extender, details, logs) Default false
|
||||
defaultsToFullScreen: false
|
||||
# Show full resource GVR (Group/Version/Resource) vs just R. Default: false.
|
||||
useGVRTitleFormat: false
|
||||
# Toggles icons display as not all terminal support these chars.
|
||||
noIcons: false
|
||||
# Toggles whether k9s should check for the latest revision from the GitHub repository releases. Default is false.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
|
||||
|
||||
# Release v0.40.11
|
||||
|
||||
## 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/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
|
||||
|
||||
## Maintenance Release!
|
||||
|
||||
## Videos Are In The Can!
|
||||
|
||||
Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content...
|
||||
|
||||
* [K9s v0.40.0 -Column Blow- Sneak peek](https://youtu.be/iy6RDozAM4A)
|
||||
* [K9s v0.31.0 Configs+Sneak peek](https://youtu.be/X3444KfjguE)
|
||||
* [K9s v0.30.0 Sneak peek](https://youtu.be/mVBc1XneRJ4)
|
||||
* [Vulnerability Scans](https://youtu.be/ULkl0MsaidU)
|
||||
|
||||
---
|
||||
|
||||
## Resolved Issues
|
||||
|
||||
* [#3226](https://github.com/derailed/k9s/issues/3226) Filter view will show mess when filtering some string
|
||||
* [#3224](https://github.com/derailed/k9s/issues/3224) Respect kubectl.kubernetes.io/default-container annotation
|
||||
* [#3222](https://github.com/derailed/k9s/issues/3222) Option to Display Resource Names Without API Version Prefix
|
||||
* [#3210](https://github.com/derailed/k9s/issues/3210) Description line is buggy
|
||||
|
||||
---
|
||||
|
||||
## 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!!
|
||||
|
||||
* [#3237](https://github.com/derailed/k9s/pull/3237) fix: List CRDs which has k8s.io in their names
|
||||
* [#3223](https://github.com/derailed/k9s/pull/3223) Fixed skin config ref of in_the_navy to in-the-navy
|
||||
* [#3110](https://github.com/derailed/k9s/pull/3110) feat: add splashless option to suppress splash screen on start
|
||||
|
||||
---
|
||||
|
||||
<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)
|
||||
|
|
@ -48,9 +48,9 @@ func printInfo(cmd *cobra.Command, args []string) error {
|
|||
|
||||
func printLogo(c color.Paint) {
|
||||
for _, l := range ui.LogoSmall {
|
||||
fmt.Fprintln(out, color.Colorize(l, c))
|
||||
_, _ = fmt.Fprintln(out, color.Colorize(l, c))
|
||||
}
|
||||
fmt.Fprintln(out)
|
||||
_, _ = fmt.Fprintln(out)
|
||||
}
|
||||
|
||||
// getScreenDumpDirForInfo get default screen dump config dir or from config.K9sConfigFile configuration.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import (
|
|||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/view"
|
||||
|
||||
"github.com/lmittmann/tint"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/spf13/cobra"
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ func printVersion(short bool) {
|
|||
|
||||
func printTuple(fmat, section, value string, outputColor color.Paint) {
|
||||
if outputColor != -1 {
|
||||
fmt.Fprintf(out, fmat, color.Colorize(section+":", outputColor), value)
|
||||
_, _ = fmt.Fprintf(out, fmat, color.Colorize(section+":", outputColor), value)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(out, fmat, section, value)
|
||||
_, _ = fmt.Fprintf(out, fmat, section, value)
|
||||
}
|
||||
|
|
|
|||
55
go.mod
55
go.mod
|
|
@ -1,15 +1,15 @@
|
|||
module github.com/derailed/k9s
|
||||
|
||||
go 1.24.0
|
||||
go 1.24.1
|
||||
|
||||
require (
|
||||
github.com/adrg/xdg v0.5.3
|
||||
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837
|
||||
github.com/anchore/grype v0.86.1
|
||||
github.com/anchore/syft v1.20.0
|
||||
github.com/anchore/grype v0.87.0
|
||||
github.com/anchore/syft v1.21.0
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/cenkalti/backoff/v4 v4.3.0
|
||||
github.com/derailed/tcell/v2 v2.3.1-rc.3
|
||||
github.com/derailed/tcell/v2 v2.3.1-rc.4
|
||||
github.com/derailed/tview v0.8.5
|
||||
github.com/fatih/color v1.18.0
|
||||
github.com/fsnotify/fsnotify v1.8.0
|
||||
|
|
@ -78,11 +78,12 @@ require (
|
|||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 // indirect
|
||||
github.com/anchore/stereoscope v0.0.13 // indirect
|
||||
github.com/anchore/stereoscope v0.1.0 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/aquasecurity/go-pep440-version v0.0.1 // indirect
|
||||
github.com/aquasecurity/go-version v0.0.1 // indirect
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.288 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
|
|
@ -96,9 +97,12 @@ require (
|
|||
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/lipgloss v1.0.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
||||
github.com/cloudflare/circl v1.3.8 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||
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.0 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/containerd/containerd v1.7.27 // indirect
|
||||
|
|
@ -111,13 +115,13 @@ require (
|
|||
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
|
||||
github.com/containerd/ttrpc v1.2.7 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/cli v27.5.0+incompatible // indirect
|
||||
github.com/docker/cli v28.0.1+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v28.0.0+incompatible // indirect
|
||||
github.com/docker/docker v28.0.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
|
|
@ -145,7 +149,7 @@ require (
|
|||
github.com/glebarez/sqlite v1.11.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.14.0 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
|
|
@ -156,12 +160,12 @@ require (
|
|||
github.com/go-test/deep v1.1.1 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-containerregistry v0.20.3 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/licensecheck v0.3.1 // indirect
|
||||
|
|
@ -179,7 +183,7 @@ require (
|
|||
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.6 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.8 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
|
|
@ -198,7 +202,7 @@ require (
|
|||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d // indirect
|
||||
|
|
@ -214,7 +218,6 @@ require (
|
|||
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
|
|
@ -234,7 +237,7 @@ require (
|
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
|
|
@ -242,7 +245,7 @@ require (
|
|||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/gomega v1.35.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
github.com/openvex/go-vex v0.2.5 // indirect
|
||||
|
|
@ -252,7 +255,7 @@ require (
|
|||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/profile v1.7.0 // indirect
|
||||
|
|
@ -266,6 +269,7 @@ require (
|
|||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rubenv/sql-migrate v1.7.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c // indirect
|
||||
github.com/saferwall/pe v1.5.6 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
|
|
@ -276,16 +280,17 @@ require (
|
|||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb // indirect
|
||||
github.com/spdx/tools-golang v0.5.5 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/afero v1.14.0 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.20.2 // indirect
|
||||
github.com/sylabs/squashfs v1.0.4 // indirect
|
||||
github.com/sylabs/squashfs v1.0.5 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/vbatts/go-mtree v0.5.4 // indirect
|
||||
|
|
@ -315,7 +320,7 @@ require (
|
|||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/oauth2 v0.25.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
|
|
@ -342,7 +347,7 @@ require (
|
|||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.35.0 // indirect
|
||||
modernc.org/sqlite v1.36.1 // indirect
|
||||
oras.land/oras-go v1.2.5 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.18.0 // indirect
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@ const (
|
|||
cacheNSKey = "validNamespaces"
|
||||
)
|
||||
|
||||
var (
|
||||
supportedMetricsAPIVersions = []string{"v1beta1"}
|
||||
)
|
||||
var supportedMetricsAPIVersions = []string{"v1beta1"}
|
||||
|
||||
// NamespaceNames tracks a collection of namespace names.
|
||||
type NamespaceNames map[string]struct{}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,6 @@ func (c *Config) CurrentClusterName() (string, error) {
|
|||
}
|
||||
|
||||
return ct.Cluster, nil
|
||||
|
||||
}
|
||||
|
||||
// CurrentContextName returns the currently active config context.
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func TestCallTimeout(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestConfigCurrentContext(t *testing.T) {
|
||||
var kubeConfig = "./testdata/config"
|
||||
kubeConfig := "./testdata/config"
|
||||
|
||||
uu := map[string]struct {
|
||||
context string
|
||||
|
|
|
|||
|
|
@ -240,7 +240,6 @@ func TestClusterLoad(t *testing.T) {
|
|||
eSize: 0,
|
||||
},
|
||||
"ok": {
|
||||
|
||||
nodes: &v1.NodeList{
|
||||
Items: []v1.Node{
|
||||
makeNode("n1", "100m", "4Mi", "50m", "2Mi"),
|
||||
|
|
|
|||
|
|
@ -556,6 +556,7 @@ func TestConfigSaveFile(t *testing.T) {
|
|||
cfg.K9s.ReadOnly = true
|
||||
cfg.K9s.Logger.TailCount = 500
|
||||
cfg.K9s.Logger.BufferSize = 800
|
||||
cfg.K9s.UI.UseFullGVRTitle = true
|
||||
cfg.Validate("ct-1-1", "cl-1")
|
||||
|
||||
path := filepath.Join("/tmp", "k9s.yaml")
|
||||
|
|
|
|||
|
|
@ -51,5 +51,5 @@ func (c *Config) Validate(conn client.Connection, contextName, clusterName strin
|
|||
func (c *Config) Dump(w io.Writer) {
|
||||
bb, _ := yaml.Marshal(&c)
|
||||
|
||||
fmt.Fprintf(w, "%s\n", string(bb))
|
||||
_, _ = fmt.Fprintf(w, "%s\n", string(bb))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ func NewContextFromConfig(cfg *api.Context) *Context {
|
|||
ct.Namespace, ct.ClusterName = NewActiveNamespace(cfg.Namespace), cfg.Cluster
|
||||
|
||||
return ct
|
||||
|
||||
}
|
||||
|
||||
// NewContextFromKubeConfig returns a new instance based on kubesettings or an error.
|
||||
|
|
|
|||
|
|
@ -63,9 +63,10 @@ func TestHelperInList(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEnsureDirPathNone(t *testing.T) {
|
||||
var mod os.FileMode = 0744
|
||||
const mod = 0744
|
||||
|
||||
dir := filepath.Join("/tmp", "k9s-test")
|
||||
os.Remove(dir)
|
||||
_ = os.Remove(dir)
|
||||
|
||||
path := filepath.Join(dir, "duh.yaml")
|
||||
assert.NoError(t, data.EnsureDirPath(path, mod))
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -127,10 +126,7 @@ func initK9sEnvLocs() error {
|
|||
|
||||
AppDumpsDir = filepath.Join(AppConfigDir, "screen-dumps")
|
||||
if err := data.EnsureFullPath(AppDumpsDir, data.DefaultDirMod); err != nil {
|
||||
slog.Warn("Unable to create screen-dumps dir",
|
||||
slogs.Dir, AppDumpsDir,
|
||||
slogs.Error, err,
|
||||
)
|
||||
slog.Warn("Unable to create screen-dumps dir", slogs.Dir, AppDumpsDir, slogs.Error, err)
|
||||
}
|
||||
AppBenchmarksDir = filepath.Join(AppConfigDir, "benchmarks")
|
||||
if err := data.EnsureFullPath(AppBenchmarksDir, data.DefaultDirMod); err != nil {
|
||||
|
|
|
|||
|
|
@ -17,15 +17,15 @@ func Test_initXDGLocs(t *testing.T) {
|
|||
tmp, err := UserTmpDir()
|
||||
assert.NoError(t, err)
|
||||
|
||||
os.Unsetenv("XDG_CONFIG_HOME")
|
||||
os.Unsetenv("XDG_CACHE_HOME")
|
||||
os.Unsetenv("XDG_STATE_HOME")
|
||||
os.Unsetenv("XDG_DATA_HOME")
|
||||
assert.NoError(t, os.Unsetenv("XDG_CONFIG_HOME"))
|
||||
assert.NoError(t, os.Unsetenv("XDG_CACHE_HOME"))
|
||||
assert.NoError(t, os.Unsetenv("XDG_STATE_HOME"))
|
||||
assert.NoError(t, os.Unsetenv("XDG_DATA_HOME"))
|
||||
|
||||
os.Setenv("XDG_CONFIG_HOME", filepath.Join(tmp, "k9s-xdg", "config"))
|
||||
os.Setenv("XDG_CACHE_HOME", filepath.Join(tmp, "k9s-xdg", "cache"))
|
||||
os.Setenv("XDG_STATE_HOME", filepath.Join(tmp, "k9s-xdg", "state"))
|
||||
os.Setenv("XDG_DATA_HOME", filepath.Join(tmp, "k9s-xdg", "data"))
|
||||
assert.NoError(t, os.Setenv("XDG_CONFIG_HOME", filepath.Join(tmp, "k9s-xdg", "config")))
|
||||
assert.NoError(t, os.Setenv("XDG_CACHE_HOME", filepath.Join(tmp, "k9s-xdg", "cache")))
|
||||
assert.NoError(t, os.Setenv("XDG_STATE_HOME", filepath.Join(tmp, "k9s-xdg", "state")))
|
||||
assert.NoError(t, os.Setenv("XDG_DATA_HOME", filepath.Join(tmp, "k9s-xdg", "data")))
|
||||
xdg.Reload()
|
||||
|
||||
uu := map[string]struct {
|
||||
|
|
|
|||
|
|
@ -39,17 +39,17 @@ func TestInitLogLoc(t *testing.T) {
|
|||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
os.Unsetenv(config.K9sEnvLogsDir)
|
||||
os.Unsetenv("XDG_STATE_HOME")
|
||||
os.Unsetenv(config.K9sEnvConfigDir)
|
||||
assert.NoError(t, os.Unsetenv(config.K9sEnvLogsDir))
|
||||
assert.NoError(t, os.Unsetenv("XDG_STATE_HOME"))
|
||||
assert.NoError(t, os.Unsetenv(config.K9sEnvConfigDir))
|
||||
switch k {
|
||||
case "log-env":
|
||||
os.Setenv(config.K9sEnvLogsDir, u.dir)
|
||||
assert.NoError(t, os.Setenv(config.K9sEnvLogsDir, u.dir))
|
||||
case "xdg-env":
|
||||
os.Setenv("XDG_STATE_HOME", u.dir)
|
||||
assert.NoError(t, os.Setenv("XDG_STATE_HOME", u.dir))
|
||||
xdg.Reload()
|
||||
case "cfg-env":
|
||||
os.Setenv(config.K9sEnvConfigDir, u.dir)
|
||||
assert.NoError(t, os.Setenv(config.K9sEnvConfigDir, u.dir))
|
||||
}
|
||||
err := config.InitLogLoc()
|
||||
assert.NoError(t, err)
|
||||
|
|
@ -60,7 +60,7 @@ func TestInitLogLoc(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEnsureBenchmarkCfg(t *testing.T) {
|
||||
os.Setenv(config.K9sEnvConfigDir, "/tmp/test-config")
|
||||
assert.NoError(t, os.Setenv(config.K9sEnvConfigDir, "/tmp/test-config"))
|
||||
assert.NoError(t, config.InitLocs())
|
||||
defer assert.NoError(t, os.RemoveAll("/tmp/test-config"))
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
"noIcons": {"type": "boolean"},
|
||||
"reactive": {"type": "boolean"},
|
||||
"skin": {"type": "string"},
|
||||
"defaultsToFullScreen": {"type": "boolean"}
|
||||
"defaultsToFullScreen": {"type": "boolean"},
|
||||
"useFullGVRTitle": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"shellPod": {
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ func Test_k9sOverrides(t *testing.T) {
|
|||
assert.Equal(t, u.sl, u.k.IsSplashless())
|
||||
assert.Equal(t, u.hl, u.k.IsHeadless())
|
||||
assert.Equal(t, u.ll, u.k.IsLogoless())
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func EnsureDir(d string) error {
|
|||
|
||||
func NewMockConfig() *config.Config {
|
||||
if _, err := os.Stat("/tmp/test"); errors.Is(err, os.ErrExist) {
|
||||
os.RemoveAll("/tmp/test")
|
||||
_ = os.RemoveAll("/tmp/test")
|
||||
}
|
||||
config.AppContextsDir = "/tmp/test"
|
||||
cl, ct := "cl-1", "ct-1-1"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ k9s:
|
|||
reactive: false
|
||||
noIcons: false
|
||||
defaultsToFullScreen: false
|
||||
useFullGVRTitle: false
|
||||
skipLatestRevCheck: false
|
||||
disablePodCounting: false
|
||||
shellPod:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ k9s:
|
|||
reactive: false
|
||||
noIcons: false
|
||||
defaultsToFullScreen: false
|
||||
useFullGVRTitle: true
|
||||
skipLatestRevCheck: false
|
||||
disablePodCounting: false
|
||||
shellPod:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ k9s:
|
|||
reactive: false
|
||||
noIcons: false
|
||||
defaultsToFullScreen: false
|
||||
useFullGVRTitle: false
|
||||
skipLatestRevCheck: false
|
||||
disablePodCounting: false
|
||||
shellPod:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ type UI struct {
|
|||
// DefaultsToFullScreen toggles fullscreen on views like logs, yaml, details.
|
||||
DefaultsToFullScreen bool `json:"defaultsToFullScreen" yaml:"defaultsToFullScreen"`
|
||||
|
||||
// UseFullGVRTitle toggles the display of full GVR (group/version/resource) vs R in views title.
|
||||
UseFullGVRTitle bool `json:"useFullGVRTitle" yaml:"useFullGVRTitle"`
|
||||
|
||||
manualHeadless *bool
|
||||
manualLogoless *bool
|
||||
manualCrumbsless *bool
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import (
|
|||
|
||||
func TestAsGVR(t *testing.T) {
|
||||
a := dao.NewAlias(makeFactory())
|
||||
a.Aliases.Define("v1/pods", "po", "pod", "pods")
|
||||
a.Aliases.Define("workloads", "workloads", "workload", "wkl")
|
||||
a.Define("v1/pods", "po", "pod", "pods")
|
||||
a.Define("workloads", "workloads", "workload", "wkl")
|
||||
|
||||
uu := map[string]struct {
|
||||
cmd string
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
package dao
|
||||
|
||||
var (
|
||||
_ Accessor = (*ConfigMap)(nil)
|
||||
)
|
||||
var _ Accessor = (*ConfigMap)(nil)
|
||||
|
||||
// ConfigMap represents a configmap resource.
|
||||
type ConfigMap struct {
|
||||
|
|
|
|||
|
|
@ -321,8 +321,8 @@ func hasConfigMap(spec *v1.PodSpec, name string) bool {
|
|||
}
|
||||
|
||||
for _, v := range spec.Volumes {
|
||||
if cm := v.VolumeSource.ConfigMap; cm != nil {
|
||||
if cm.LocalObjectReference.Name == name {
|
||||
if cm := v.ConfigMap; cm != nil {
|
||||
if cm.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -375,7 +375,7 @@ func hasSecret(f Factory, spec *v1.PodSpec, ns, name string, wait bool) (bool, e
|
|||
}
|
||||
|
||||
for _, v := range spec.Volumes {
|
||||
if sec := v.VolumeSource.Secret; sec != nil {
|
||||
if sec := v.Secret; sec != nil {
|
||||
if sec.SecretName == name {
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,13 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/render/helm"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -20,13 +20,15 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultServiceAccount = "default"
|
||||
defaultContainerAnnotation = "kubectl.kubernetes.io/default-container"
|
||||
defaultServiceAccount = "default"
|
||||
|
||||
// DefaultContainerAnnotation represents the annotation key for the default container.
|
||||
DefaultContainerAnnotation = "kubectl.kubernetes.io/default-container"
|
||||
)
|
||||
|
||||
// GetDefaultContainer returns a container name if specified in an annotation.
|
||||
func GetDefaultContainer(m metav1.ObjectMeta, spec v1.PodSpec) (string, bool) {
|
||||
defaultContainer, ok := m.Annotations[defaultContainerAnnotation]
|
||||
defaultContainer, ok := m.Annotations[DefaultContainerAnnotation]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
|
@ -38,7 +40,7 @@ func GetDefaultContainer(m metav1.ObjectMeta, spec v1.PodSpec) (string, bool) {
|
|||
}
|
||||
slog.Warn("Container not found. Annotation ignored",
|
||||
slogs.CO, defaultContainer,
|
||||
slogs.Annotation, defaultContainerAnnotation,
|
||||
slogs.Annotation, DefaultContainerAnnotation,
|
||||
)
|
||||
|
||||
return "", false
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*ImageScan)(nil)
|
||||
)
|
||||
var _ Accessor = (*ImageScan)(nil)
|
||||
|
||||
// ImageScan represents vulnerability scans.
|
||||
type ImageScan struct {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ func (j *Job) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
for _, r := range j.ObjectMeta.OwnerReferences {
|
||||
for _, r := range j.OwnerReferences {
|
||||
if r.Name == n {
|
||||
ll = append(ll, o)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ func (n *Node) Drain(path string, opts DrainOptions, w io.Writer) error {
|
|||
dd, errs := h.GetPodsForDeletion(path)
|
||||
if len(errs) != 0 {
|
||||
for _, e := range errs {
|
||||
if _, err := h.ErrOut.Write([]byte(fmt.Sprintf("[%s] %s\n", path, e.Error()))); err != nil {
|
||||
if _, err := fmt.Fprintf(h.ErrOut, "[%s] %s\n", path, e.Error()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ func (n *Node) Drain(path string, opts DrainOptions, w io.Writer) error {
|
|||
if err := h.DeleteOrEvictPods(dd.Pods()); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(h.Out, "Node %s drained!", path)
|
||||
_, _ = fmt.Fprintf(h.Out, "Node %s drained!", path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
package dao
|
||||
|
||||
var (
|
||||
_ Accessor = (*Namespace)(nil)
|
||||
)
|
||||
var _ Accessor = (*Namespace)(nil)
|
||||
|
||||
// Namespace represents a namespace resource.
|
||||
type Namespace struct {
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ func (p *Pod) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, error) {
|
|||
return nil, errors.New("expecting Deployment resource")
|
||||
}
|
||||
// Just pick controller less pods...
|
||||
if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
if len(pod.OwnerReferences) > 0 {
|
||||
continue
|
||||
}
|
||||
if serviceAccountMatches(pod.Spec.ServiceAccountName, n) {
|
||||
|
|
@ -273,7 +273,7 @@ func (p *Pod) Scan(ctx context.Context, gvr client.GVR, fqn string, wait bool) (
|
|||
return nil, errors.New("expecting Pod resource")
|
||||
}
|
||||
// Just pick controller less pods...
|
||||
if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
if len(pod.OwnerReferences) > 0 {
|
||||
continue
|
||||
}
|
||||
switch gvr {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ func TestGetDefaultContainer(t *testing.T) {
|
|||
"container_not_present": {
|
||||
po: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{"kubectl.kubernetes.io/default-container": "container1"},
|
||||
Annotations: map[string]string{DefaultContainerAnnotation: "container1"},
|
||||
},
|
||||
},
|
||||
wantContainer: "",
|
||||
|
|
@ -38,7 +38,7 @@ func TestGetDefaultContainer(t *testing.T) {
|
|||
"container_found": {
|
||||
po: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{"kubectl.kubernetes.io/default-container": "container1"},
|
||||
Annotations: map[string]string{DefaultContainerAnnotation: "container1"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{Name: "container1"}},
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func (r *ReplicaSet) Load(f Factory, path string) (*appsv1.ReplicaSet, error) {
|
|||
}
|
||||
|
||||
func getRSRevision(rs *appsv1.ReplicaSet) (int64, error) {
|
||||
revision := rs.ObjectMeta.Annotations["deployment.kubernetes.io/revision"]
|
||||
revision := rs.Annotations["deployment.kubernetes.io/revision"]
|
||||
if rs.Status.Replicas != 0 {
|
||||
return 0, errors.New("can not rollback current replica")
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ func getRSRevision(rs *appsv1.ReplicaSet) (int64, error) {
|
|||
}
|
||||
|
||||
func controllerInfo(rs *appsv1.ReplicaSet) (string, string, string, error) {
|
||||
for _, ref := range rs.ObjectMeta.OwnerReferences {
|
||||
for _, ref := range rs.OwnerReferences {
|
||||
if ref.Controller == nil {
|
||||
continue
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ func controllerInfo(rs *appsv1.ReplicaSet) (string, string, string, error) {
|
|||
}
|
||||
return ref.Name, ref.Kind, group, nil
|
||||
}
|
||||
return "", "", "", fmt.Errorf("unable to find controller for replicaset: %s", rs.ObjectMeta.Name)
|
||||
return "", "", "", fmt.Errorf("unable to find controller for replicaset: %s", rs.Name)
|
||||
}
|
||||
|
||||
// Rollback reverses the last deployment.
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ import (
|
|||
"k8s.io/client-go/scale"
|
||||
)
|
||||
|
||||
var _ Scalable = (*Scaler)(nil)
|
||||
var _ ReplicasGetter = (*Scaler)(nil)
|
||||
var (
|
||||
_ Scalable = (*Scaler)(nil)
|
||||
_ ReplicasGetter = (*Scaler)(nil)
|
||||
)
|
||||
|
||||
// Scaler represents a generic resource with scaling.
|
||||
type Scaler struct {
|
||||
|
|
|
|||
|
|
@ -16,46 +16,41 @@ import (
|
|||
// Secret represents a secret K8s resource.
|
||||
type Secret struct {
|
||||
Resource
|
||||
decode bool
|
||||
decodeData bool
|
||||
}
|
||||
|
||||
// Describe describes a secret that can be encoded or decoded.
|
||||
func (s *Secret) Describe(path string) (string, error) {
|
||||
encodedDescription, err := s.Generic.Describe(path)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !s.decode {
|
||||
if !s.decodeData {
|
||||
return encodedDescription, nil
|
||||
}
|
||||
|
||||
return s.Decode(encodedDescription, path)
|
||||
}
|
||||
|
||||
// SetDecode sets the decode flag.
|
||||
func (s *Secret) SetDecode(flag bool) {
|
||||
s.decode = flag
|
||||
// SetDecodeData toggles decode mode.
|
||||
func (s *Secret) SetDecodeData(b bool) {
|
||||
s.decodeData = b
|
||||
}
|
||||
|
||||
// Decode removes the encoded part from the secret's description and appends the
|
||||
// secret's decoded data.
|
||||
func (s *Secret) Decode(encodedDescription, path string) (string, error) {
|
||||
o, err := s.getFactory().Get(s.GVR(), path, true, labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
dataEndIndex := strings.Index(encodedDescription, "====")
|
||||
|
||||
if dataEndIndex == -1 {
|
||||
return "", fmt.Errorf("unable to find data section in secret description")
|
||||
}
|
||||
|
||||
dataEndIndex += 4
|
||||
|
||||
if dataEndIndex >= len(encodedDescription) {
|
||||
return "", fmt.Errorf("data section in secret description is invalid")
|
||||
}
|
||||
|
|
@ -64,19 +59,19 @@ func (s *Secret) Decode(encodedDescription, path string) (string, error) {
|
|||
// More details about the reasoning of index: https://github.com/kubernetes/kubectl/blob/v0.29.0/pkg/describe/describe.go#L2542
|
||||
body := encodedDescription[0:dataEndIndex]
|
||||
|
||||
d, err := ExtractSecrets(o.(*unstructured.Unstructured))
|
||||
|
||||
data, err := ExtractSecrets(o)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
decodedSecrets := []string{}
|
||||
|
||||
for k, v := range d {
|
||||
decodedSecrets = append(decodedSecrets, "\n", k, ":\t", v)
|
||||
decodedSecrets := make([]string, 0, len(data))
|
||||
for k, v := range data {
|
||||
line := fmt.Sprintf("%s: %s", k, v)
|
||||
decodedSecrets = append(decodedSecrets, strings.TrimSpace(line))
|
||||
}
|
||||
|
||||
return body + strings.Join(decodedSecrets, ""), nil
|
||||
return body + "\n" + strings.Join(decodedSecrets, "\n"), nil
|
||||
|
||||
}
|
||||
|
||||
// ExtractSecrets takes an unstructured object and attempts to convert it into a
|
||||
|
|
@ -84,16 +79,18 @@ func (s *Secret) Decode(encodedDescription, path string) (string, error) {
|
|||
// It returns a map where the keys are the secret data keys and the values are
|
||||
// the corresponding secret data values.
|
||||
// If the conversion fails, it returns an error.
|
||||
func ExtractSecrets(o *unstructured.Unstructured) (map[string]string, error) {
|
||||
func ExtractSecrets(o runtime.Object) (map[string]string, error) {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting *unstructured.Unstructured but got %T", o)
|
||||
}
|
||||
var secret v1.Secret
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.Object, &secret)
|
||||
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secretData := make(map[string]string, len(secret.Data))
|
||||
|
||||
for k, val := range secret.Data {
|
||||
secretData[k] = string(val)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,10 @@ import (
|
|||
)
|
||||
|
||||
func TestEncodedSecretDescribe(t *testing.T) {
|
||||
s := dao.Secret{}
|
||||
var s dao.Secret
|
||||
s.Init(makeFactory(), client.NewGVR("v1/secrets"))
|
||||
|
||||
encodedString :=
|
||||
`
|
||||
encodedString := `
|
||||
Name: bootstrap-token-abcdef
|
||||
Namespace: kube-system
|
||||
Labels: <none>
|
||||
|
|
@ -37,8 +36,9 @@ token-secret: 24 bytes`
|
|||
"\n" +
|
||||
"Data\n" +
|
||||
"====\n" +
|
||||
"token-secret:\t0123456789abcdef"
|
||||
"token-secret: 0123456789abcdef"
|
||||
|
||||
decodedDescription, _ := s.Decode(encodedString, "kube-system/bootstrap-token-abcdef")
|
||||
decodedDescription, err := s.Decode(encodedString, "kube-system/bootstrap-token-abcdef")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, decodedDescription)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,14 @@ import (
|
|||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
)
|
||||
|
||||
// ResourceMetas represents a collection of resource metadata.
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func (w *Workload) Delete(ctx context.Context, path string, propagation *metav1.
|
|||
}
|
||||
|
||||
func (a *Workload) fetch(ctx context.Context, gvr client.GVR, ns string) (*metav1.Table, error) {
|
||||
a.Table.gvr = gvr
|
||||
a.gvr = gvr
|
||||
oo, err := a.Table.List(ctx, ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -113,14 +113,12 @@ func (a *Workload) List(ctx context.Context, ns string) ([]runtime.Object, error
|
|||
for _, r := range table.Rows {
|
||||
if obj := r.Object.Object; obj != nil {
|
||||
if m, err := meta.Accessor(obj); err == nil {
|
||||
ns = m.GetNamespace()
|
||||
ts = m.GetCreationTimestamp()
|
||||
ns, ts = m.GetNamespace(), m.GetCreationTimestamp()
|
||||
}
|
||||
} else {
|
||||
var m metav1.PartialObjectMetadata
|
||||
if err := json.Unmarshal(r.Object.Raw, &m); err == nil {
|
||||
ns = m.GetNamespace()
|
||||
ts = m.CreationTimestamp
|
||||
ns, ts = m.GetNamespace(), m.CreationTimestamp
|
||||
}
|
||||
}
|
||||
stat := status(gvr, r, table.ColumnDefinitions)
|
||||
|
|
|
|||
|
|
@ -13,11 +13,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
)
|
||||
|
||||
|
|
@ -239,5 +238,5 @@ func fetchLatestRev() (string, error) {
|
|||
return v.(string), nil
|
||||
}
|
||||
|
||||
return "", errors.New("No version found")
|
||||
return "", errors.New("no version found")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ func (d *Describe) describe(ctx context.Context, gvr client.GVR, path string) (s
|
|||
}
|
||||
|
||||
if desc, ok := meta.DAO.(*dao.Secret); ok {
|
||||
desc.SetDecode(d.decode)
|
||||
desc.SetDecodeData(d.decode)
|
||||
}
|
||||
|
||||
return desc.Describe(path)
|
||||
|
|
|
|||
|
|
@ -262,14 +262,17 @@ func newTestView() *testView {
|
|||
func (t *testView) LogCanceled() {}
|
||||
func (t *testView) LogStop() {}
|
||||
func (t *testView) LogResume() {}
|
||||
|
||||
func (t *testView) LogChanged(ll [][]byte) {
|
||||
t.data = ll
|
||||
t.dataCalled++
|
||||
}
|
||||
|
||||
func (t *testView) LogCleared() {
|
||||
t.clearCalled++
|
||||
t.data = nil
|
||||
}
|
||||
|
||||
func (t *testView) LogFailed(err error) {
|
||||
fmt.Println("LogErr", err)
|
||||
t.errCalled++
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ func (p *Pulse) reconcile(ctx context.Context) error {
|
|||
for _, o := range oo {
|
||||
c, ok := o.(*health.Check)
|
||||
if !ok {
|
||||
return fmt.Errorf("Expecting health check but got %T", o)
|
||||
return fmt.Errorf("expecting health check but got %T", o)
|
||||
}
|
||||
p.data = append(p.data, c)
|
||||
p.firePulseChanged(c)
|
||||
|
|
|
|||
|
|
@ -113,10 +113,6 @@ var Registry = map[string]ResourceMeta{
|
|||
Renderer: &render.Service{},
|
||||
TreeRenderer: &xray.Service{},
|
||||
},
|
||||
"v1/events": {
|
||||
DAO: &dao.Table{},
|
||||
Renderer: &render.Event{},
|
||||
},
|
||||
"v1/serviceaccounts": {
|
||||
Renderer: &render.ServiceAccount{},
|
||||
},
|
||||
|
|
@ -193,14 +189,4 @@ var Registry = map[string]ResourceMeta{
|
|||
"rbac.authorization.k8s.io/v1/rolebindings": {
|
||||
Renderer: &render.RoleBinding{},
|
||||
},
|
||||
|
||||
// Autoscaling...
|
||||
"autoscaling/v1/horizontalpodautoscalers": {
|
||||
Renderer: &render.HorizontalPodAutoscaler{},
|
||||
DAO: &dao.Table{},
|
||||
},
|
||||
"autoscaling/v2/horizontalpodautoscalers": {
|
||||
Renderer: &render.HorizontalPodAutoscaler{},
|
||||
DAO: &dao.Table{},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,11 +81,6 @@ func TestTableMeta(t *testing.T) {
|
|||
accessor: &dao.Node{},
|
||||
renderer: &render.Node{},
|
||||
},
|
||||
"table": {
|
||||
gvr: "v1/events",
|
||||
accessor: &dao.Table{},
|
||||
renderer: &render.Event{},
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ func (t *Text) RemoveListener(listener TextListener) {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
if victim >= 0 {
|
||||
t.listeners = append(t.listeners[:victim], t.listeners[victim+1:]...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func (v *Values) getValues() ([]string, error) {
|
|||
|
||||
valuer, ok := accessor.(dao.Valuer)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Resource %s is not Valuer", v.gvr)
|
||||
return nil, fmt.Errorf("resource %s is not Valuer", v.gvr)
|
||||
}
|
||||
|
||||
values, err := valuer.GetValues(v.path, v.allValues)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ func lessCapacity(s1, s2 string) bool {
|
|||
}
|
||||
|
||||
func lessNumber(s1, s2 string) bool {
|
||||
v1, v2 := strings.Replace(s1, ",", "", -1), strings.Replace(s2, ",", "", -1)
|
||||
v1, v2 := strings.ReplaceAll(s1, ",", ""), strings.ReplaceAll(s2, ",", "")
|
||||
|
||||
return sortorder.NaturalLess(v1, v2)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ func TestLabelize(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIsValid(t *testing.T) {
|
||||
|
||||
uu := map[string]struct {
|
||||
ns string
|
||||
h Header
|
||||
|
|
|
|||
|
|
@ -299,7 +299,6 @@ func (r RowEventSorter) Len() int {
|
|||
}
|
||||
|
||||
func (r RowEventSorter) Swap(i, j int) {
|
||||
|
||||
r.Events.events[i], r.Events.events[j] = r.Events.events[j], r.Events.events[i]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,11 +16,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/rakyll/hey/requester"
|
||||
)
|
||||
|
||||
|
|
@ -127,8 +126,8 @@ func (b *Benchmark) Run(cluster, context string, done func()) {
|
|||
|
||||
func (b *Benchmark) save(cluster, context string, r io.Reader) error {
|
||||
ns, n := client.Namespaced(b.config.Name)
|
||||
n = strings.Replace(n, "|", "_", -1)
|
||||
n = strings.Replace(n, ":", "_", -1)
|
||||
n = strings.ReplaceAll(n, "|", "_")
|
||||
n = strings.ReplaceAll(n, ":", "_")
|
||||
dir, err := config.EnsureBenchmarksDir(cluster, context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ func ParsePlainPF(ann string) (*PFAnn, error) {
|
|||
var pf PFAnn
|
||||
mm := pfPlainRX.FindStringSubmatch(strings.TrimSpace(ann))
|
||||
if len(mm) < 3 {
|
||||
return nil, fmt.Errorf("Invalid plain port-forward %s", ann)
|
||||
return nil, fmt.Errorf("invalid plain port-forward %s", ann)
|
||||
}
|
||||
if len(mm[2]) == 0 {
|
||||
pf.ContainerPort = intstr.Parse(mm[1])
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ func (m ConfigMap) Header(_ string) model1.Header {
|
|||
return m.doHeader(m.defaultHeader())
|
||||
}
|
||||
|
||||
// Header returns a header rbw.
|
||||
func (ConfigMap) defaultHeader() model1.Header {
|
||||
return model1.Header{
|
||||
model1.HeaderColumn{Name: "NAMESPACE"},
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ func (ClusterRole) defaultRow(raw *unstructured.Unstructured, r *model1.Row) err
|
|||
return err
|
||||
}
|
||||
|
||||
r.ID = client.FQN("-", cr.ObjectMeta.Name)
|
||||
r.ID = client.FQN("-", cr.Name)
|
||||
r.Fields = model1.Fields{
|
||||
cr.Name,
|
||||
mapToStr(cr.Labels),
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func (ClusterRoleBinding) defaultRow(raw *unstructured.Unstructured, r *model1.R
|
|||
|
||||
kind, ss := renderSubjects(crb.Subjects)
|
||||
|
||||
r.ID = client.FQN("-", crb.ObjectMeta.Name)
|
||||
r.ID = client.FQN("-", crb.Name)
|
||||
r.Fields = model1.Fields{
|
||||
crb.Name,
|
||||
crb.RoleRef.Name,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func (cc ColumnSpecs) Header(rh model1.Header) model1.Header {
|
|||
|
||||
for _, h := range rh {
|
||||
if idx, ok := hh.IndexOf(h.Name, true); ok {
|
||||
hh[idx].Attrs = hh[idx].Attrs.Merge(h.Attrs)
|
||||
hh[idx].Attrs = hh[idx].Merge(h.Attrs)
|
||||
continue
|
||||
}
|
||||
hh = append(hh, h)
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Authors of K9s
|
||||
|
||||
package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/derailed/tcell/v2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// Event renders a K8s Event to screen.
|
||||
type Event struct {
|
||||
Table
|
||||
}
|
||||
|
||||
func (*Event) IsGeneric() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ColorerFunc colors a resource row.
|
||||
func (e *Event) ColorerFunc() model1.ColorerFunc {
|
||||
return func(ns string, h model1.Header, re *model1.RowEvent) tcell.Color {
|
||||
idx, ok := h.IndexOf("REASON", true)
|
||||
if ok && strings.TrimSpace(re.Row.Fields[idx]) == "Killing" {
|
||||
return model1.KillColor
|
||||
}
|
||||
|
||||
return model1.DefaultColorer(ns, h, re)
|
||||
}
|
||||
}
|
||||
|
||||
var ageCols = map[string]struct{}{
|
||||
"FIRST SEEN": {},
|
||||
"LAST SEEN": {},
|
||||
}
|
||||
|
||||
var wideCols = map[string]struct{}{
|
||||
"SUBOBJECT": {},
|
||||
"COUNT": {},
|
||||
"SOURCE": {},
|
||||
"FIRST SEEN": {},
|
||||
"NAME": {},
|
||||
"MESSAGE": {},
|
||||
}
|
||||
|
||||
// Header returns a header row.
|
||||
func (e *Event) Header(_ string) model1.Header {
|
||||
if e.table == nil {
|
||||
return model1.Header{}
|
||||
}
|
||||
hh := make(model1.Header, 0, len(e.table.ColumnDefinitions))
|
||||
hh = append(hh, model1.HeaderColumn{Name: "NAMESPACE"})
|
||||
for _, h := range e.table.ColumnDefinitions {
|
||||
header := model1.HeaderColumn{Name: strings.ToUpper(h.Name)}
|
||||
if _, ok := ageCols[header.Name]; ok {
|
||||
header.Time = true
|
||||
}
|
||||
if _, ok := wideCols[header.Name]; ok {
|
||||
header.Wide = true
|
||||
}
|
||||
hh = append(hh, header)
|
||||
}
|
||||
|
||||
return hh
|
||||
}
|
||||
|
||||
// Render renders a K8s resource to screen.
|
||||
func (e *Event) Render(o interface{}, ns string, r *model1.Row) error {
|
||||
row, ok := o.(metav1.TableRow)
|
||||
if !ok {
|
||||
return fmt.Errorf("expecting a TableRow but got %T", o)
|
||||
}
|
||||
nns, name, err := resourceNS(row.Object.Raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.ID = client.FQN(nns, name)
|
||||
r.Fields = make(model1.Fields, 0, len(e.Header(ns)))
|
||||
r.Fields = append(r.Fields, nns)
|
||||
for _, o := range row.Cells {
|
||||
if o == nil {
|
||||
r.Fields = append(r.Fields, Blank)
|
||||
continue
|
||||
}
|
||||
if s, ok := o.(fmt.Stringer); ok {
|
||||
r.Fields = append(r.Fields, s.String())
|
||||
continue
|
||||
}
|
||||
if s, ok := o.(string); ok {
|
||||
r.Fields = append(r.Fields, s)
|
||||
continue
|
||||
}
|
||||
r.Fields = append(r.Fields, fmt.Sprintf("%v", o))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Authors of K9s
|
||||
|
||||
package render_test
|
||||
|
||||
// BOZO!!
|
||||
// func TestEventRender(t *testing.T) {
|
||||
// c := render.Event{}
|
||||
// r := model1.NewRow(7)
|
||||
// c.Render(load(t, "ev"), "", &r)
|
||||
|
||||
// assert.Equal(t, "default/hello-1567197780-mn4mv.15bfce150bd764dd", r.ID)
|
||||
// assert.Equal(t, model1.Fields{"default", "pod:hello-1567197780-mn4mv", "Normal", "Pulled", "kubelet", "1", `Successfully pulled image "blang/busybox-bash"`}, r.Fields[:7])
|
||||
// }
|
||||
|
||||
// func BenchmarkEventRender(b *testing.B) {
|
||||
// ev := load(b, "ev")
|
||||
// var re render.Event
|
||||
// r := model1.NewRow(7)
|
||||
|
||||
// b.ResetTimer()
|
||||
// b.ReportAllocs()
|
||||
// for i := 0; i < b.N; i++ {
|
||||
// _ = re.Render(&ev, "", &r)
|
||||
// }
|
||||
// }
|
||||
|
|
@ -51,7 +51,6 @@ func (c ImageScan) ColorerFunc() model1.ColorerFunc {
|
|||
|
||||
return c
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Header returns a header row.
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func (p PersistentVolume) defaultRow(raw *unstructured.Unstructured, r *model1.R
|
|||
}
|
||||
|
||||
phase := pv.Status.Phase
|
||||
if pv.ObjectMeta.DeletionTimestamp != nil {
|
||||
if pv.DeletionTimestamp != nil {
|
||||
phase = terminatingPhase
|
||||
}
|
||||
var claim string
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func (p PersistentVolumeClaim) defaultRow(raw *unstructured.Unstructured, r *mod
|
|||
}
|
||||
|
||||
phase := pvc.Status.Phase
|
||||
if pvc.ObjectMeta.DeletionTimestamp != nil {
|
||||
if pvc.DeletionTimestamp != nil {
|
||||
phase = "Terminating"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func (s StorageClass) defaultRow(raw *unstructured.Unstructured, r *model1.Row)
|
|||
return err
|
||||
}
|
||||
|
||||
r.ID = client.FQN(client.ClusterScope, sc.ObjectMeta.Name)
|
||||
r.ID = client.FQN(client.ClusterScope, sc.Name)
|
||||
r.Fields = model1.Fields{
|
||||
s.nameWithDefault(sc.ObjectMeta),
|
||||
sc.Provisioner,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,10 @@ var _ os.FileInfo = fileInfo{}
|
|||
|
||||
func (f fileInfo) Name() string { return "bob" }
|
||||
func (f fileInfo) Size() int64 { return 100 }
|
||||
func (f fileInfo) Mode() os.FileMode { return os.FileMode(0644) }
|
||||
func (f fileInfo) ModTime() time.Time { return testTime() }
|
||||
func (f fileInfo) IsDir() bool { return false }
|
||||
func (f fileInfo) Sys() interface{} { return nil }
|
||||
|
||||
func (f fileInfo) Mode() os.FileMode {
|
||||
return os.FileMode(0644)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,11 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Secret renders a K8s Secret to screen.
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func (s Service) defaultRow(raw *unstructured.Unstructured, r *model1.Row) error
|
|||
r.ID = client.MetaFQN(svc.ObjectMeta)
|
||||
r.Fields = model1.Fields{
|
||||
svc.Namespace,
|
||||
svc.ObjectMeta.Name,
|
||||
svc.Name,
|
||||
string(svc.Spec.Type),
|
||||
toIP(svc.Spec.ClusterIP),
|
||||
toIPs(svc.Spec.Type, getSvcExtIPS(&svc)),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ package render
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
|
@ -138,39 +137,3 @@ func (t *Table) defaultRow(row *metav1.TableRow, ns string, r *model1.Row) error
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func resourceNS(raw []byte) (string, string, error) {
|
||||
var obj map[string]interface{}
|
||||
var ns, name string
|
||||
err := json.Unmarshal(raw, &obj)
|
||||
if err != nil {
|
||||
return ns, name, err
|
||||
}
|
||||
|
||||
meta, ok := obj["metadata"].(map[string]interface{})
|
||||
if !ok {
|
||||
return ns, name, errors.New("no metadata found on generic resource")
|
||||
}
|
||||
ina, ok := meta["name"]
|
||||
if !ok {
|
||||
return ns, name, errors.New("unable to extract resource name")
|
||||
}
|
||||
name, ok = ina.(string)
|
||||
if !ok {
|
||||
return ns, name, fmt.Errorf("expecting name string type but got %T", ns)
|
||||
}
|
||||
|
||||
ins, ok := meta["namespace"]
|
||||
if !ok {
|
||||
return client.ClusterScope, name, nil
|
||||
}
|
||||
|
||||
ns, ok = ins.(string)
|
||||
if !ok {
|
||||
return ns, name, fmt.Errorf("expecting namespace string type but got %T", ns)
|
||||
}
|
||||
return ns, name, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,10 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
)
|
||||
|
||||
func Test_activeConfig(t *testing.T) {
|
||||
os.Setenv(config.K9sEnvConfigDir, "/tmp/test-config")
|
||||
assert.NoError(t, os.Setenv(config.K9sEnvConfigDir, "/tmp/test-config"))
|
||||
assert.NoError(t, config.InitLocs())
|
||||
|
||||
cl, ct := "cl-1", "ct-1-1"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
func TestSkinnedContext(t *testing.T) {
|
||||
os.Setenv(config.K9sEnvConfigDir, "/tmp/k9s-test")
|
||||
assert.NoError(t, os.Setenv(config.K9sEnvConfigDir, "/tmp/k9s-test"))
|
||||
assert.NoError(t, config.InitLocs())
|
||||
defer assert.NoError(t, os.RemoveAll(config.K9sEnvConfigDir))
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ func TestSkinnedContext(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBenchConfig(t *testing.T) {
|
||||
os.Setenv(config.K9sEnvConfigDir, "/tmp/test-config")
|
||||
assert.NoError(t, os.Setenv(config.K9sEnvConfigDir, "/tmp/test-config"))
|
||||
assert.NoError(t, config.InitLocs())
|
||||
defer assert.NoError(t, os.RemoveAll(config.K9sEnvConfigDir))
|
||||
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ func (c *Crumbs) refresh(crumbs []string) {
|
|||
if i == last {
|
||||
bgColor = c.styles.Frame().Crumb.ActiveColor
|
||||
}
|
||||
fmt.Fprintf(c, "[%s:%s:b] <%s> [-:%s:-] ",
|
||||
_, _ = fmt.Fprintf(c, "[%s:%s:b] <%s> [-:%s:-] ",
|
||||
c.styles.Frame().Crumb.FgColor,
|
||||
bgColor, strings.Replace(strings.ToLower(crumb), " ", "", -1),
|
||||
bgColor, strings.ReplaceAll(strings.ToLower(crumb), " ", ""),
|
||||
c.styles.Body().BgColor)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ const (
|
|||
KeySlash = 47
|
||||
KeyColon = 58
|
||||
KeySpace = 32
|
||||
KeyDash = 45 //or minus for those searching in the code
|
||||
KeyDash = 45
|
||||
KeyLeftBracket = 91
|
||||
KeyRightBracket = 93
|
||||
)
|
||||
|
|
|
|||
|
|
@ -105,9 +105,9 @@ func (l *Logo) refreshLogo(c config.Color) {
|
|||
defer l.mx.Unlock()
|
||||
l.logo.Clear()
|
||||
for i, s := range LogoSmall {
|
||||
fmt.Fprintf(l.logo, "[%s::b]%s", c, s)
|
||||
_, _ = fmt.Fprintf(l.logo, "[%s::b]%s", c, s)
|
||||
if i+1 < len(LogoSmall) {
|
||||
fmt.Fprintf(l.logo, "\n")
|
||||
_, _ = fmt.Fprintf(l.logo, "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ func ToMnemonic(s string) string {
|
|||
|
||||
func formatNSMenu(i int, name string, styles config.Frame) string {
|
||||
fmat := strings.Replace(menuIndexFmt, "[key", "["+styles.Menu.NumKeyColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, ":bg:", ":"+styles.Title.BgColor.String()+":", -1)
|
||||
fmat = strings.ReplaceAll(fmat, ":bg:", ":"+styles.Title.BgColor.String()+":")
|
||||
fmat = strings.Replace(fmat, "[fg", "["+styles.Menu.FgColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, "fgstyle]", styles.Menu.FgStyle.ToShortString()+"]", 1)
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ func formatPlainMenu(h model.MenuHint, size int, styles config.Frame) string {
|
|||
menuFmt := " [key:-:b]%-" + strconv.Itoa(size+2) + "s [fg:-:fgstyle]%s "
|
||||
fmat := strings.Replace(menuFmt, "[key", "["+styles.Menu.KeyColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, "[fg", "["+styles.Menu.FgColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, ":bg:", ":"+styles.Title.BgColor.String()+":", -1)
|
||||
fmat = strings.ReplaceAll(fmat, ":bg:", ":"+styles.Title.BgColor.String()+":")
|
||||
fmat = strings.Replace(fmat, "fgstyle]", styles.Menu.FgStyle.ToShortString()+"]", 1)
|
||||
|
||||
return fmt.Sprintf(fmat, ToMnemonic(h.Mnemonic), h.Description)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func NewPages() *Pages {
|
|||
Pages: tview.NewPages(),
|
||||
Stack: model.NewStack(),
|
||||
}
|
||||
p.Stack.AddListener(&p)
|
||||
p.AddListener(&p)
|
||||
|
||||
return &p
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ func (p *Pages) delete(c model.Component) {
|
|||
// Dump for debug.
|
||||
func (p *Pages) Dump() {
|
||||
slog.Debug("Dumping Pages", slogs.Page, p)
|
||||
for i, c := range p.Stack.Peek() {
|
||||
for i, c := range p.Peek() {
|
||||
slog.Debug(fmt.Sprintf("%d -- %s -- %#v", i, componentID(c), p.GetPrimitive(componentID(c))))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ func (p *Prompt) write(text, suggest string) {
|
|||
txt += fmt.Sprintf("[%s::-]%s", p.styles.Prompt().SuggestColor, suggest)
|
||||
}
|
||||
p.StylesChanged(p.styles)
|
||||
fmt.Fprintf(p, defaultPrompt, p.icon, txt)
|
||||
_, _ = fmt.Fprintf(p, defaultPrompt, p.icon, txt)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ package ui_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/tcell/v2"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/derailed/tcell/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -60,12 +60,12 @@ func NewSplash(styles *config.Styles, version string) *Splash {
|
|||
|
||||
func (s *Splash) layoutLogo(t *tview.TextView, styles *config.Styles) {
|
||||
logo := strings.Join(LogoBig, fmt.Sprintf("\n[%s::b]", styles.Body().LogoColor))
|
||||
fmt.Fprintf(t, "%s[%s::b]%s\n",
|
||||
_, _ = fmt.Fprintf(t, "%s[%s::b]%s\n",
|
||||
strings.Repeat("\n", 2),
|
||||
styles.Body().LogoColor,
|
||||
logo)
|
||||
}
|
||||
|
||||
func (s *Splash) layoutRev(t *tview.TextView, rev string, styles *config.Styles) {
|
||||
fmt.Fprintf(t, "[%s::b]Revision [red::b]%s", styles.Body().FgColor, rev)
|
||||
_, _ = fmt.Fprintf(t, "[%s::b]Revision [red::b]%s", styles.Body().FgColor, rev)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ type Table struct {
|
|||
mx sync.RWMutex
|
||||
readOnly bool
|
||||
noIcon bool
|
||||
fullGVR bool
|
||||
}
|
||||
|
||||
// NewTable returns a new table view.
|
||||
|
|
@ -73,6 +74,14 @@ func NewTable(gvr client.GVR) *Table {
|
|||
}
|
||||
}
|
||||
|
||||
// SetFullGVR toggles full GVR title display.
|
||||
func (t *Table) SetFullGVR(b bool) {
|
||||
t.mx.Lock()
|
||||
defer t.mx.Unlock()
|
||||
|
||||
t.fullGVR = b
|
||||
}
|
||||
|
||||
// SetNoIcon toggles no icon mode.
|
||||
func (t *Table) SetNoIcon(b bool) {
|
||||
t.mx.Lock()
|
||||
|
|
@ -547,11 +556,16 @@ func (t *Table) styleTitle() string {
|
|||
ns = t.Extras
|
||||
}
|
||||
|
||||
resource := t.gvr.R()
|
||||
if t.fullGVR {
|
||||
resource = t.gvr.String()
|
||||
}
|
||||
|
||||
var title string
|
||||
if ns == client.ClusterScope {
|
||||
title = SkinTitle(fmt.Sprintf(TitleFmt, t.gvr, render.AsThousands(rc)), t.styles.Frame())
|
||||
title = SkinTitle(fmt.Sprintf(TitleFmt, resource, render.AsThousands(rc)), t.styles.Frame())
|
||||
} else {
|
||||
title = SkinTitle(fmt.Sprintf(NSTitleFmt, t.gvr, ns, render.AsThousands(rc)), t.styles.Frame())
|
||||
title = SkinTitle(fmt.Sprintf(NSTitleFmt, resource, ns, render.AsThousands(rc)), t.styles.Frame())
|
||||
}
|
||||
if ic := ROIndicator(t.readOnly, t.noIcon); ic != "" {
|
||||
title = " " + ic + title
|
||||
|
|
@ -573,13 +587,12 @@ func (t *Table) styleTitle() string {
|
|||
|
||||
// ROIndicator returns an icon showing whether the session is in readonly mode or not.
|
||||
func ROIndicator(ro, noIC bool) string {
|
||||
if noIC {
|
||||
switch {
|
||||
case noIC:
|
||||
return ""
|
||||
}
|
||||
|
||||
if ro {
|
||||
case ro:
|
||||
return lockedIC
|
||||
default:
|
||||
return unlockedIC
|
||||
}
|
||||
|
||||
return unlockedIC
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,12 +72,12 @@ func SkinTitle(fmat string, style config.Frame) string {
|
|||
if bgColor == config.DefaultColor {
|
||||
bgColor = config.TransparentColor
|
||||
}
|
||||
fmat = strings.Replace(fmat, "[fg:bg", "["+style.Title.FgColor.String()+":"+bgColor.String(), -1)
|
||||
fmat = strings.ReplaceAll(fmat, "[fg:bg", "["+style.Title.FgColor.String()+":"+bgColor.String())
|
||||
fmat = strings.Replace(fmat, "[hilite", "["+style.Title.HighlightColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, "[key", "["+style.Menu.NumKeyColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, "[filter", "["+style.Title.FilterColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, "[count", "["+style.Title.CounterColor.String(), 1)
|
||||
fmat = strings.Replace(fmat, ":bg:", ":"+bgColor.String()+":", -1)
|
||||
fmat = strings.ReplaceAll(fmat, ":bg:", ":"+bgColor.String()+":")
|
||||
|
||||
return fmat
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,36 +70,37 @@ type mockModel struct{}
|
|||
|
||||
var _ ui.Tabular = &mockModel{}
|
||||
|
||||
func (t *mockModel) SetViewSetting(context.Context, *config.ViewSetting) {}
|
||||
func (t *mockModel) SetInstance(string) {}
|
||||
func (t *mockModel) SetLabelFilter(string) {}
|
||||
func (t *mockModel) GetLabelFilter() string { return "" }
|
||||
func (t *mockModel) Empty() bool { return false }
|
||||
func (t *mockModel) RowCount() int { return 1 }
|
||||
func (t *mockModel) HasMetrics() bool { return true }
|
||||
func (t *mockModel) Peek() *model1.TableData { return makeTableData() }
|
||||
func (t *mockModel) Refresh(context.Context) error { return nil }
|
||||
func (t *mockModel) ClusterWide() bool { return false }
|
||||
func (t *mockModel) GetNamespace() string { return "blee" }
|
||||
func (t *mockModel) SetNamespace(string) {}
|
||||
func (t *mockModel) ToggleToast() {}
|
||||
func (t *mockModel) AddListener(model.TableListener) {}
|
||||
func (t *mockModel) RemoveListener(model.TableListener) {}
|
||||
func (t *mockModel) Watch(context.Context) error { return nil }
|
||||
func (t *mockModel) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (t *mockModel) SetViewSetting(context.Context, *config.ViewSetting) {}
|
||||
func (t *mockModel) SetInstance(string) {}
|
||||
func (t *mockModel) SetLabelFilter(string) {}
|
||||
func (t *mockModel) GetLabelFilter() string { return "" }
|
||||
func (t *mockModel) Empty() bool { return false }
|
||||
func (t *mockModel) RowCount() int { return 1 }
|
||||
func (t *mockModel) HasMetrics() bool { return true }
|
||||
func (t *mockModel) Peek() *model1.TableData { return makeTableData() }
|
||||
func (t *mockModel) Refresh(context.Context) error { return nil }
|
||||
func (t *mockModel) ClusterWide() bool { return false }
|
||||
func (t *mockModel) GetNamespace() string { return "blee" }
|
||||
func (t *mockModel) SetNamespace(string) {}
|
||||
func (t *mockModel) ToggleToast() {}
|
||||
func (t *mockModel) AddListener(model.TableListener) {}
|
||||
func (t *mockModel) RemoveListener(model.TableListener) {}
|
||||
func (t *mockModel) Watch(context.Context) error { return nil }
|
||||
func (t *mockModel) Get(ctx context.Context, path string) (runtime.Object, error) { return nil, nil }
|
||||
func (t *mockModel) InNamespace(string) bool { return true }
|
||||
func (t *mockModel) SetRefreshRate(time.Duration) {}
|
||||
|
||||
func (t *mockModel) Delete(context.Context, string, *metav1.DeletionPropagation, dao.Grace) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *mockModel) Describe(context.Context, string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (t *mockModel) ToYAML(ctx context.Context, path string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
func (t *mockModel) InNamespace(string) bool { return true }
|
||||
func (t *mockModel) SetRefreshRate(time.Duration) {}
|
||||
|
||||
func makeTableData() *model1.TableData {
|
||||
return model1.NewTableDataWithRows(
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
unlockedIC = "✍️ "
|
||||
lockedIC = "🔒"
|
||||
unlockedIC = "🖍"
|
||||
lockedIC = "🔑"
|
||||
)
|
||||
|
||||
// Namespaceable tracks namespaces.
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ func (a *App) Init(version string, rate int) error {
|
|||
if err := a.Content.Init(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
a.Content.Stack.AddListener(a.Crumbs())
|
||||
a.Content.Stack.AddListener(a.Menu())
|
||||
a.Content.AddListener(a.Crumbs())
|
||||
a.Content.AddListener(a.Menu())
|
||||
|
||||
a.App.Init()
|
||||
a.SetInputCapture(a.keyboard)
|
||||
|
|
@ -198,7 +198,7 @@ func (a *App) suggestCommand() model.SuggestionFunc {
|
|||
}
|
||||
|
||||
ls := strings.ToLower(s)
|
||||
for _, k := range a.command.alias.Aliases.Keys() {
|
||||
for _, k := range a.command.alias.Keys() {
|
||||
if suggest, ok := cmd.ShouldAddSuggest(ls, k); ok {
|
||||
entries = append(entries, suggest)
|
||||
}
|
||||
|
|
@ -776,7 +776,7 @@ func (a *App) inject(c model.Component, clearStack bool) error {
|
|||
return err
|
||||
}
|
||||
if clearStack {
|
||||
a.Content.Stack.Clear()
|
||||
a.Content.Clear()
|
||||
}
|
||||
a.Content.Push(c)
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,9 @@ func (b *Browser) Init(ctx context.Context) error {
|
|||
if b.App().IsRunning() {
|
||||
b.app.CmdBuff().Reset()
|
||||
}
|
||||
b.Table.SetReadOnly(b.app.Config.IsReadOnly())
|
||||
b.Table.SetNoIcon(b.app.Config.K9s.UI.NoIcons)
|
||||
b.SetReadOnly(b.app.Config.IsReadOnly())
|
||||
b.SetNoIcon(b.app.Config.K9s.UI.NoIcons)
|
||||
b.SetFullGVR(b.app.Config.K9s.UI.UseFullGVRTitle)
|
||||
|
||||
b.bindKeys(b.Actions())
|
||||
for _, f := range b.bindKeysFn {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,8 @@ func TestFlagsNew(t *testing.T) {
|
|||
fuzzyKey: "blee",
|
||||
labelKey: "app=fred",
|
||||
nsKey: "ns1",
|
||||
contextKey: "Dev"},
|
||||
contextKey: "Dev",
|
||||
},
|
||||
},
|
||||
"ctx": {
|
||||
i: NewInterpreter("ctx"),
|
||||
|
|
|
|||
|
|
@ -85,16 +85,16 @@ func (c *Context) showRenameModal(name string, ok func(form *tview.Form, context
|
|||
app.Content.Pages.RemovePage(renamePage)
|
||||
}).
|
||||
AddButton("Cancel", func() {
|
||||
app.Content.Pages.RemovePage(renamePage)
|
||||
app.Content.RemovePage(renamePage)
|
||||
})
|
||||
|
||||
m := tview.NewModalForm("<Rename>", f)
|
||||
m.SetText(fmt.Sprintf("Rename context %q?", name))
|
||||
m.SetDoneFunc(func(int, string) {
|
||||
app.Content.Pages.RemovePage(renamePage)
|
||||
app.Content.RemovePage(renamePage)
|
||||
})
|
||||
app.Content.Pages.AddPage(renamePage, m, false, false)
|
||||
app.Content.Pages.ShowPage(renamePage)
|
||||
app.Content.AddPage(renamePage, m, false, false)
|
||||
app.Content.ShowPage(renamePage)
|
||||
|
||||
for i := 0; i < f.GetButtonCount(); i++ {
|
||||
f.GetButton(i).
|
||||
|
|
|
|||
|
|
@ -238,11 +238,11 @@ func (d *Details) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
func (d *Details) setFullScreen(isFullScreen bool) {
|
||||
d.fullScreen = isFullScreen
|
||||
d.SetFullScreen(isFullScreen)
|
||||
d.Box.SetBorder(!isFullScreen)
|
||||
d.SetBorder(!isFullScreen)
|
||||
if isFullScreen {
|
||||
d.Box.SetBorderPadding(0, 0, 0, 0)
|
||||
d.SetBorderPadding(0, 0, 0, 0)
|
||||
} else {
|
||||
d.Box.SetBorderPadding(0, 0, 1, 1)
|
||||
d.SetBorderPadding(0, 0, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@ package view_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/view"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeploy(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ func (e Env) Substitute(arg string) (string, error) {
|
|||
}
|
||||
v = fmt.Sprintf("%t", b)
|
||||
}
|
||||
arg = strings.Replace(arg, m[0], v, -1)
|
||||
arg = strings.ReplaceAll(arg, m[0], v)
|
||||
}
|
||||
|
||||
return arg, nil
|
||||
|
|
|
|||
|
|
@ -17,12 +17,11 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/ui/dialog"
|
||||
"github.com/fatih/color"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
|
@ -447,7 +446,7 @@ func k9sShellPodName() string {
|
|||
|
||||
func k9sShellPod(node string, cfg config.ShellPod) *v1.Pod {
|
||||
var grace int64
|
||||
var priv bool = true
|
||||
var priv = true
|
||||
|
||||
slog.Debug("Shell pod config", slogs.ShellPodCfg, cfg)
|
||||
c := v1.Container{
|
||||
|
|
|
|||
|
|
@ -292,11 +292,11 @@ func (v *LiveView) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
func (v *LiveView) setFullScreen(isFullScreen bool) {
|
||||
v.fullScreen = isFullScreen
|
||||
v.SetFullScreen(isFullScreen)
|
||||
v.Box.SetBorder(!isFullScreen)
|
||||
v.SetBorder(!isFullScreen)
|
||||
if isFullScreen {
|
||||
v.Box.SetBorderPadding(0, 0, 0, 0)
|
||||
v.SetBorderPadding(0, 0, 0, 0)
|
||||
} else {
|
||||
v.Box.SetBorderPadding(0, 0, 1, 1)
|
||||
v.SetBorderPadding(0, 0, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ func (l *Log) toggleAllContainers(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
func (l *Log) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !l.logs.cmdBuff.IsActive() {
|
||||
fmt.Fprintln(l.ansiWriter)
|
||||
_, _ = fmt.Fprintln(l.ansiWriter)
|
||||
return evt
|
||||
}
|
||||
|
||||
|
|
@ -460,7 +460,7 @@ func (l *Log) clearCmd(*tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
func (l *Log) markCmd(*tcell.EventKey) *tcell.EventKey {
|
||||
_, _, w, _ := l.GetRect()
|
||||
fmt.Fprintf(l.ansiWriter, "\n[%s:-:b]%s[-:-:-]", l.app.Styles.Views().Log.FgColor.String(), strings.Repeat("-", w-4))
|
||||
_, _ = fmt.Fprintf(l.ansiWriter, "\n[%s:-:b]%s[-:-:-]", l.app.Styles.Views().Log.FgColor.String(), strings.Repeat("-", w-4))
|
||||
l.follow = true
|
||||
|
||||
return nil
|
||||
|
|
@ -516,7 +516,7 @@ func (l *Log) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
func (l *Log) toggleFullScreen() {
|
||||
l.SetFullScreen(l.indicator.FullScreen())
|
||||
l.Box.SetBorder(!l.indicator.FullScreen())
|
||||
l.SetBorder(!l.indicator.FullScreen())
|
||||
if l.indicator.FullScreen() {
|
||||
l.logs.SetBorderPadding(0, 0, 0, 0)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -85,14 +85,14 @@ func BenchmarkLogFlush(b *testing.B) {
|
|||
func TestLogAnsi(t *testing.T) {
|
||||
buff := bytes.NewBufferString("")
|
||||
w := tview.ANSIWriter(buff, "white", "black")
|
||||
fmt.Fprintf(w, "[YELLOW] ok")
|
||||
_, _ = fmt.Fprintf(w, "[YELLOW] ok")
|
||||
assert.Equal(t, "[YELLOW] ok", buff.String())
|
||||
|
||||
v := tview.NewTextView()
|
||||
v.SetDynamicColors(true)
|
||||
aw := tview.ANSIWriter(v, "white", "black")
|
||||
s := "[2019-03-27T15:05:15,246][INFO ][o.e.c.r.a.AllocationService] [es-0] Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[.monitoring-es-6-2019.03.27][0]]"
|
||||
fmt.Fprintf(aw, "%s", s)
|
||||
_, _ = fmt.Fprintf(aw, "%s", s)
|
||||
assert.Equal(t, s+"\n", v.GetText(false))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ func (p *PageStack) Init(ctx context.Context) (err error) {
|
|||
if p.app, err = extractApp(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Stack.AddListener(p)
|
||||
p.AddListener(p)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,16 +7,15 @@ import (
|
|||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
)
|
||||
|
||||
func TestEnsurePodPortFwdAllowed(t *testing.T) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue