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
|
cache-dependency-path: go.sum
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
uses: golangci/golangci-lint-action@v6.5.2
|
uses: golangci/golangci-lint-action@v7.0.0
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
reporter: github-pr-check
|
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 }}
|
||||||
237
.golangci.yml
237
.golangci.yml
|
|
@ -1,6 +1,5 @@
|
||||||
# options for analysis running
|
version: "2"
|
||||||
run:
|
run:
|
||||||
# default concurrency is an available CPU number
|
|
||||||
concurrency: 8
|
concurrency: 8
|
||||||
|
|
||||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
# 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
|
# exit code when at least one issue was found, default is 1
|
||||||
issues-exit-code: 1
|
issues-exit-code: 1
|
||||||
|
|
||||||
# include test files or not, default is true
|
|
||||||
tests: true
|
tests: true
|
||||||
|
|
||||||
# which dirs to skip: they won't be analyzed;
|
formatters:
|
||||||
# can use regexp here: generated.*, regexp is applied on full path;
|
enable:
|
||||||
# default value is empty list, but next dirs are always skipped independently
|
- gci
|
||||||
# from this option's value:
|
- gofmt
|
||||||
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
|
# - gofumpt
|
||||||
# skip-dirs:
|
- goimports
|
||||||
# - ^test.*
|
# - golines
|
||||||
|
|
||||||
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
|
linters:
|
||||||
# If invoked with -mod=readonly, the go command is disallowed from the implicit
|
disable-all: true
|
||||||
# automatic updating of go.mod described above. Instead, it fails when any changes
|
enable:
|
||||||
# to go.mod are needed. This setting is most useful to check that go.mod does
|
- sloglint
|
||||||
# not need updates, such as in a continuous integration and testing system.
|
exclusions:
|
||||||
# If invoked with -mod=vendor, the go command assumes that the vendor
|
generated: lax
|
||||||
# directory holds the correct copies of dependencies and ignores
|
paths:
|
||||||
# the dependency descriptions in go.mod.
|
- third_party$
|
||||||
modules-download-mode: readonly
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
- \\.(generated\\.deepcopy|pb)\\.go$
|
||||||
|
|
||||||
# which files to skip: they will be analyzed, but issues from them
|
settings:
|
||||||
# won't be reported. Default value is empty list, but there is
|
gocyclo:
|
||||||
# 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)
|
|
||||||
min-complexity: 35
|
min-complexity: 35
|
||||||
|
|
||||||
govet:
|
govet:
|
||||||
enable:
|
enable:
|
||||||
- nilness
|
- nilness
|
||||||
goimports:
|
|
||||||
local-prefixes: github.com/cilium/cilium
|
goimports:
|
||||||
unused:
|
local-prefixes: github.com/derailed/k9s
|
||||||
parameters-are-used: true
|
|
||||||
local-variables-are-used: true
|
unused:
|
||||||
field-writes-are-uses: true
|
parameters-are-used: true
|
||||||
post-statements-are-reads: true
|
local-variables-are-used: true
|
||||||
exported-fields-are-used: true
|
field-writes-are-uses: true
|
||||||
generated-is-used: true
|
post-statements-are-reads: true
|
||||||
goheader:
|
exported-fields-are-used: true
|
||||||
values:
|
generated-is-used: true
|
||||||
regexp:
|
|
||||||
PROJECT: 'K9s'
|
goheader:
|
||||||
template: |-
|
values:
|
||||||
SPDX-License-Identifier: Apache-2.0
|
regexp:
|
||||||
Copyright Authors of {{ PROJECT }}
|
PROJECT: 'K9s'
|
||||||
gosec:
|
template: |-
|
||||||
includes:
|
SPDX-License-Identifier: Apache-2.0
|
||||||
- G402
|
Copyright Authors of {{ PROJECT }}
|
||||||
sloglint:
|
|
||||||
# Enforce not mixing key-value pairs and attributes.
|
gosec:
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-mixed-arguments
|
includes:
|
||||||
# Default: true
|
- G402
|
||||||
no-mixed-args: true
|
|
||||||
# Enforce using key-value pairs only (overrides no-mixed-args, incompatible with attr-only).
|
sloglint:
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-value-pairs-only
|
# Enforce not mixing key-value pairs and attributes.
|
||||||
# Default: false
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-mixed-arguments
|
||||||
kv-only: true
|
# Default: true
|
||||||
# Enforce using attributes only (overrides no-mixed-args, incompatible with kv-only).
|
no-mixed-args: true
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#attributes-only
|
# Enforce using key-value pairs only (overrides no-mixed-args, incompatible with attr-only).
|
||||||
# Default: false
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-value-pairs-only
|
||||||
attr-only: false
|
# Default: false
|
||||||
# Enforce not using global loggers.
|
kv-only: true
|
||||||
# Values:
|
# Enforce using attributes only (overrides no-mixed-args, incompatible with kv-only).
|
||||||
# - "": disabled
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#attributes-only
|
||||||
# - "all": report all global loggers
|
# Default: false
|
||||||
# - "default": report only the default slog logger
|
attr-only: false
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global
|
# Enforce not using global loggers.
|
||||||
# Default: ""
|
# Values:
|
||||||
no-global: ""
|
# - "": disabled
|
||||||
# Enforce using methods that accept a context.
|
# - "all": report all global loggers
|
||||||
# Values:
|
# - "default": report only the default slog logger
|
||||||
# - "": disabled
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global
|
||||||
# - "all": report all contextless calls
|
# Default: ""
|
||||||
# - "scope": report only if a context exists in the scope of the outermost function
|
no-global: ""
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only
|
# Enforce using methods that accept a context.
|
||||||
# Default: ""
|
# Values:
|
||||||
context: ""
|
# - "": disabled
|
||||||
# Enforce using static values for log messages.
|
# - "all": report all contextless calls
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages
|
# - "scope": report only if a context exists in the scope of the outermost function
|
||||||
# Default: false
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only
|
||||||
static-msg: false
|
# Default: ""
|
||||||
# Enforce using constants instead of raw keys.
|
context: ""
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-raw-keys
|
# Enforce using static values for log messages.
|
||||||
# Default: false
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages
|
||||||
no-raw-keys: true
|
# Default: false
|
||||||
# Enforce a single key naming convention.
|
static-msg: false
|
||||||
# Values: snake, kebab, camel, pascal
|
# Enforce using constants instead of raw keys.
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-raw-keys
|
||||||
# Default: ""
|
# Default: false
|
||||||
key-naming-case: camel
|
no-raw-keys: true
|
||||||
# Enforce not using specific keys.
|
# Enforce a single key naming convention.
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#forbidden-keys
|
# Values: snake, kebab, camel, pascal
|
||||||
# Default: []
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention
|
||||||
forbidden-keys:
|
# Default: ""
|
||||||
- time
|
key-naming-case: camel
|
||||||
- level
|
# Enforce not using specific keys.
|
||||||
- msg
|
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#forbidden-keys
|
||||||
- source
|
# Default: []
|
||||||
# Enforce putting arguments on separate lines.
|
forbidden-keys:
|
||||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#arguments-on-separate-lines
|
- time
|
||||||
# Default: false
|
- level
|
||||||
args-on-sep-lines: false
|
- 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:
|
issues:
|
||||||
|
|
@ -132,10 +126,13 @@ issues:
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
- linters: [staticcheck]
|
- linters: [staticcheck]
|
||||||
text: "SA1019" # this is rule for deprecated method
|
text: "SA1019" # this is rule for deprecated method
|
||||||
|
|
||||||
- linters: [staticcheck]
|
- linters: [staticcheck]
|
||||||
text: "SA9003: empty branch"
|
text: "SA9003: empty branch"
|
||||||
|
|
||||||
- linters: [staticcheck]
|
- linters: [staticcheck]
|
||||||
text: "SA2001: empty critical section"
|
text: "SA2001: empty critical section"
|
||||||
|
|
||||||
- linters: [err113]
|
- linters: [err113]
|
||||||
text: "do not define dynamic errors, use wrapped static errors instead" # This rule to avoid opinionated check fmt.Errorf("text")
|
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
|
# Skip goimports check on generated files
|
||||||
|
|
@ -146,27 +143,3 @@ issues:
|
||||||
- path: "pkg/ipam/(cidrset|service)/.+\\.go"
|
- path: "pkg/ipam/(cidrset|service)/.+\\.go"
|
||||||
linters:
|
linters:
|
||||||
- goheader
|
- 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
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
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
|
# Allows to set certain views default fullscreen mode. (yaml, helm history, describe, value_extender, details, logs) Default false
|
||||||
defaultsToFullScreen: 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.
|
# Toggles icons display as not all terminal support these chars.
|
||||||
noIcons: false
|
noIcons: false
|
||||||
# Toggles whether k9s should check for the latest revision from the GitHub repository releases. Default is 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) {
|
func printLogo(c color.Paint) {
|
||||||
for _, l := range ui.LogoSmall {
|
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.
|
// 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/config/data"
|
||||||
"github.com/derailed/k9s/internal/slogs"
|
"github.com/derailed/k9s/internal/slogs"
|
||||||
"github.com/derailed/k9s/internal/view"
|
"github.com/derailed/k9s/internal/view"
|
||||||
|
|
||||||
"github.com/lmittmann/tint"
|
"github.com/lmittmann/tint"
|
||||||
"github.com/mattn/go-colorable"
|
"github.com/mattn/go-colorable"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@ func printVersion(short bool) {
|
||||||
|
|
||||||
func printTuple(fmat, section, value string, outputColor color.Paint) {
|
func printTuple(fmat, section, value string, outputColor color.Paint) {
|
||||||
if outputColor != -1 {
|
if outputColor != -1 {
|
||||||
fmt.Fprintf(out, fmat, color.Colorize(section+":", outputColor), value)
|
_, _ = fmt.Fprintf(out, fmat, color.Colorize(section+":", outputColor), value)
|
||||||
return
|
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
|
module github.com/derailed/k9s
|
||||||
|
|
||||||
go 1.24.0
|
go 1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/adrg/xdg v0.5.3
|
github.com/adrg/xdg v0.5.3
|
||||||
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837
|
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837
|
||||||
github.com/anchore/grype v0.86.1
|
github.com/anchore/grype v0.87.0
|
||||||
github.com/anchore/syft v1.20.0
|
github.com/anchore/syft v1.21.0
|
||||||
github.com/atotto/clipboard v0.1.4
|
github.com/atotto/clipboard v0.1.4
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0
|
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/derailed/tview v0.8.5
|
||||||
github.com/fatih/color v1.18.0
|
github.com/fatih/color v1.18.0
|
||||||
github.com/fsnotify/fsnotify v1.8.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-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||||
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // 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/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/andybalholm/brotli v1.1.1 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // 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-pep440-version v0.0.1 // indirect
|
||||||
github.com/aquasecurity/go-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/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.44.288 // indirect
|
github.com/aws/aws-sdk-go v1.44.288 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // 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/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||||
github.com/charmbracelet/lipgloss v1.0.0 // indirect
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.8 // 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/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
|
||||||
github.com/containerd/cgroups v1.1.0 // indirect
|
github.com/containerd/cgroups v1.1.0 // indirect
|
||||||
github.com/containerd/containerd v1.7.27 // 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/stargz-snapshotter/estargz v0.16.3 // indirect
|
||||||
github.com/containerd/ttrpc v1.2.7 // indirect
|
github.com/containerd/ttrpc v1.2.7 // indirect
|
||||||
github.com/containerd/typeurl/v2 v2.1.1 // 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect
|
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect
|
||||||
github.com/distribution/reference v0.6.0 // 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/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/docker-credential-helpers v0.8.2 // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // 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/glebarez/sqlite v1.11.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // 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-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-gorp/gorp/v3 v3.1.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.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/go-test/deep v1.1.1 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // 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/protobuf v1.5.4 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/btree v1.0.1 // indirect
|
github.com/google/btree v1.0.1 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // 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/go-containerregistry v0.20.3 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/licensecheck v0.3.1 // 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/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // 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-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-version v1.7.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/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect
|
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // 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/klauspost/pgzip v1.2.6 // indirect
|
||||||
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // 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
|
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/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // 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/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 // 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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // 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/ginkgo v1.16.5 // indirect
|
||||||
github.com/onsi/gomega v1.35.1 // indirect
|
github.com/onsi/gomega v1.35.1 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // 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/runtime-spec v1.1.0 // indirect
|
||||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||||
github.com/openvex/go-vex v0.2.5 // 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 v1.9.5 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible // 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/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pkg/profile v1.7.0 // indirect
|
github.com/pkg/profile v1.7.0 // indirect
|
||||||
|
|
@ -266,6 +269,7 @@ require (
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rubenv/sql-migrate v1.7.1 // indirect
|
github.com/rubenv/sql-migrate v1.7.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // 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/saferwall/pe v1.5.6 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
github.com/sagikazarmark/slog-shim v0.1.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/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // 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/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/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/cast v1.7.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
github.com/spf13/viper v1.19.0 // indirect
|
github.com/spf13/viper v1.19.0 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/sylabs/sif/v2 v2.20.2 // 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/therootcompany/xz v1.0.1 // indirect
|
||||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||||
github.com/vbatts/go-mtree v0.5.4 // indirect
|
github.com/vbatts/go-mtree v0.5.4 // indirect
|
||||||
|
|
@ -315,7 +320,7 @@ require (
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // 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/net v0.37.0 // indirect
|
||||||
golang.org/x/oauth2 v0.25.0 // indirect
|
golang.org/x/oauth2 v0.25.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
|
|
@ -342,7 +347,7 @@ require (
|
||||||
modernc.org/libc v1.61.13 // indirect
|
modernc.org/libc v1.61.13 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.8.2 // 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
|
oras.land/oras-go v1.2.5 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||||
sigs.k8s.io/kustomize/api v0.18.0 // indirect
|
sigs.k8s.io/kustomize/api v0.18.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,7 @@ const (
|
||||||
cacheNSKey = "validNamespaces"
|
cacheNSKey = "validNamespaces"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var supportedMetricsAPIVersions = []string{"v1beta1"}
|
||||||
supportedMetricsAPIVersions = []string{"v1beta1"}
|
|
||||||
)
|
|
||||||
|
|
||||||
// NamespaceNames tracks a collection of namespace names.
|
// NamespaceNames tracks a collection of namespace names.
|
||||||
type NamespaceNames map[string]struct{}
|
type NamespaceNames map[string]struct{}
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,6 @@ func (c *Config) CurrentClusterName() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ct.Cluster, nil
|
return ct.Cluster, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentContextName returns the currently active config context.
|
// CurrentContextName returns the currently active config context.
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func TestCallTimeout(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigCurrentContext(t *testing.T) {
|
func TestConfigCurrentContext(t *testing.T) {
|
||||||
var kubeConfig = "./testdata/config"
|
kubeConfig := "./testdata/config"
|
||||||
|
|
||||||
uu := map[string]struct {
|
uu := map[string]struct {
|
||||||
context string
|
context string
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,6 @@ func TestClusterLoad(t *testing.T) {
|
||||||
eSize: 0,
|
eSize: 0,
|
||||||
},
|
},
|
||||||
"ok": {
|
"ok": {
|
||||||
|
|
||||||
nodes: &v1.NodeList{
|
nodes: &v1.NodeList{
|
||||||
Items: []v1.Node{
|
Items: []v1.Node{
|
||||||
makeNode("n1", "100m", "4Mi", "50m", "2Mi"),
|
makeNode("n1", "100m", "4Mi", "50m", "2Mi"),
|
||||||
|
|
|
||||||
|
|
@ -556,6 +556,7 @@ func TestConfigSaveFile(t *testing.T) {
|
||||||
cfg.K9s.ReadOnly = true
|
cfg.K9s.ReadOnly = true
|
||||||
cfg.K9s.Logger.TailCount = 500
|
cfg.K9s.Logger.TailCount = 500
|
||||||
cfg.K9s.Logger.BufferSize = 800
|
cfg.K9s.Logger.BufferSize = 800
|
||||||
|
cfg.K9s.UI.UseFullGVRTitle = true
|
||||||
cfg.Validate("ct-1-1", "cl-1")
|
cfg.Validate("ct-1-1", "cl-1")
|
||||||
|
|
||||||
path := filepath.Join("/tmp", "k9s.yaml")
|
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) {
|
func (c *Config) Dump(w io.Writer) {
|
||||||
bb, _ := yaml.Marshal(&c)
|
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
|
ct.Namespace, ct.ClusterName = NewActiveNamespace(cfg.Namespace), cfg.Cluster
|
||||||
|
|
||||||
return ct
|
return ct
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContextFromKubeConfig returns a new instance based on kubesettings or an error.
|
// 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) {
|
func TestEnsureDirPathNone(t *testing.T) {
|
||||||
var mod os.FileMode = 0744
|
const mod = 0744
|
||||||
|
|
||||||
dir := filepath.Join("/tmp", "k9s-test")
|
dir := filepath.Join("/tmp", "k9s-test")
|
||||||
os.Remove(dir)
|
_ = os.Remove(dir)
|
||||||
|
|
||||||
path := filepath.Join(dir, "duh.yaml")
|
path := filepath.Join(dir, "duh.yaml")
|
||||||
assert.NoError(t, data.EnsureDirPath(path, mod))
|
assert.NoError(t, data.EnsureDirPath(path, mod))
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg"
|
||||||
"github.com/derailed/k9s/internal/config/data"
|
"github.com/derailed/k9s/internal/config/data"
|
||||||
"github.com/derailed/k9s/internal/slogs"
|
"github.com/derailed/k9s/internal/slogs"
|
||||||
|
|
||||||
"github.com/adrg/xdg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -127,10 +126,7 @@ func initK9sEnvLocs() error {
|
||||||
|
|
||||||
AppDumpsDir = filepath.Join(AppConfigDir, "screen-dumps")
|
AppDumpsDir = filepath.Join(AppConfigDir, "screen-dumps")
|
||||||
if err := data.EnsureFullPath(AppDumpsDir, data.DefaultDirMod); err != nil {
|
if err := data.EnsureFullPath(AppDumpsDir, data.DefaultDirMod); err != nil {
|
||||||
slog.Warn("Unable to create screen-dumps dir",
|
slog.Warn("Unable to create screen-dumps dir", slogs.Dir, AppDumpsDir, slogs.Error, err)
|
||||||
slogs.Dir, AppDumpsDir,
|
|
||||||
slogs.Error, err,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
AppBenchmarksDir = filepath.Join(AppConfigDir, "benchmarks")
|
AppBenchmarksDir = filepath.Join(AppConfigDir, "benchmarks")
|
||||||
if err := data.EnsureFullPath(AppBenchmarksDir, data.DefaultDirMod); err != nil {
|
if err := data.EnsureFullPath(AppBenchmarksDir, data.DefaultDirMod); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,15 @@ func Test_initXDGLocs(t *testing.T) {
|
||||||
tmp, err := UserTmpDir()
|
tmp, err := UserTmpDir()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
os.Unsetenv("XDG_CONFIG_HOME")
|
assert.NoError(t, os.Unsetenv("XDG_CONFIG_HOME"))
|
||||||
os.Unsetenv("XDG_CACHE_HOME")
|
assert.NoError(t, os.Unsetenv("XDG_CACHE_HOME"))
|
||||||
os.Unsetenv("XDG_STATE_HOME")
|
assert.NoError(t, os.Unsetenv("XDG_STATE_HOME"))
|
||||||
os.Unsetenv("XDG_DATA_HOME")
|
assert.NoError(t, os.Unsetenv("XDG_DATA_HOME"))
|
||||||
|
|
||||||
os.Setenv("XDG_CONFIG_HOME", filepath.Join(tmp, "k9s-xdg", "config"))
|
assert.NoError(t, os.Setenv("XDG_CONFIG_HOME", filepath.Join(tmp, "k9s-xdg", "config")))
|
||||||
os.Setenv("XDG_CACHE_HOME", filepath.Join(tmp, "k9s-xdg", "cache"))
|
assert.NoError(t, os.Setenv("XDG_CACHE_HOME", filepath.Join(tmp, "k9s-xdg", "cache")))
|
||||||
os.Setenv("XDG_STATE_HOME", filepath.Join(tmp, "k9s-xdg", "state"))
|
assert.NoError(t, 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_DATA_HOME", filepath.Join(tmp, "k9s-xdg", "data")))
|
||||||
xdg.Reload()
|
xdg.Reload()
|
||||||
|
|
||||||
uu := map[string]struct {
|
uu := map[string]struct {
|
||||||
|
|
|
||||||
|
|
@ -39,17 +39,17 @@ func TestInitLogLoc(t *testing.T) {
|
||||||
for k := range uu {
|
for k := range uu {
|
||||||
u := uu[k]
|
u := uu[k]
|
||||||
t.Run(k, func(t *testing.T) {
|
t.Run(k, func(t *testing.T) {
|
||||||
os.Unsetenv(config.K9sEnvLogsDir)
|
assert.NoError(t, os.Unsetenv(config.K9sEnvLogsDir))
|
||||||
os.Unsetenv("XDG_STATE_HOME")
|
assert.NoError(t, os.Unsetenv("XDG_STATE_HOME"))
|
||||||
os.Unsetenv(config.K9sEnvConfigDir)
|
assert.NoError(t, os.Unsetenv(config.K9sEnvConfigDir))
|
||||||
switch k {
|
switch k {
|
||||||
case "log-env":
|
case "log-env":
|
||||||
os.Setenv(config.K9sEnvLogsDir, u.dir)
|
assert.NoError(t, os.Setenv(config.K9sEnvLogsDir, u.dir))
|
||||||
case "xdg-env":
|
case "xdg-env":
|
||||||
os.Setenv("XDG_STATE_HOME", u.dir)
|
assert.NoError(t, os.Setenv("XDG_STATE_HOME", u.dir))
|
||||||
xdg.Reload()
|
xdg.Reload()
|
||||||
case "cfg-env":
|
case "cfg-env":
|
||||||
os.Setenv(config.K9sEnvConfigDir, u.dir)
|
assert.NoError(t, os.Setenv(config.K9sEnvConfigDir, u.dir))
|
||||||
}
|
}
|
||||||
err := config.InitLogLoc()
|
err := config.InitLogLoc()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -60,7 +60,7 @@ func TestInitLogLoc(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnsureBenchmarkCfg(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())
|
assert.NoError(t, config.InitLocs())
|
||||||
defer assert.NoError(t, os.RemoveAll("/tmp/test-config"))
|
defer assert.NoError(t, os.RemoveAll("/tmp/test-config"))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@
|
||||||
"noIcons": {"type": "boolean"},
|
"noIcons": {"type": "boolean"},
|
||||||
"reactive": {"type": "boolean"},
|
"reactive": {"type": "boolean"},
|
||||||
"skin": {"type": "string"},
|
"skin": {"type": "string"},
|
||||||
"defaultsToFullScreen": {"type": "boolean"}
|
"defaultsToFullScreen": {"type": "boolean"},
|
||||||
|
"useFullGVRTitle": {"type": "boolean"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shellPod": {
|
"shellPod": {
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,6 @@ func Test_k9sOverrides(t *testing.T) {
|
||||||
assert.Equal(t, u.sl, u.k.IsSplashless())
|
assert.Equal(t, u.sl, u.k.IsSplashless())
|
||||||
assert.Equal(t, u.hl, u.k.IsHeadless())
|
assert.Equal(t, u.hl, u.k.IsHeadless())
|
||||||
assert.Equal(t, u.ll, u.k.IsLogoless())
|
assert.Equal(t, u.ll, u.k.IsLogoless())
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ func EnsureDir(d string) error {
|
||||||
|
|
||||||
func NewMockConfig() *config.Config {
|
func NewMockConfig() *config.Config {
|
||||||
if _, err := os.Stat("/tmp/test"); errors.Is(err, os.ErrExist) {
|
if _, err := os.Stat("/tmp/test"); errors.Is(err, os.ErrExist) {
|
||||||
os.RemoveAll("/tmp/test")
|
_ = os.RemoveAll("/tmp/test")
|
||||||
}
|
}
|
||||||
config.AppContextsDir = "/tmp/test"
|
config.AppContextsDir = "/tmp/test"
|
||||||
cl, ct := "cl-1", "ct-1-1"
|
cl, ct := "cl-1", "ct-1-1"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ k9s:
|
||||||
reactive: false
|
reactive: false
|
||||||
noIcons: false
|
noIcons: false
|
||||||
defaultsToFullScreen: false
|
defaultsToFullScreen: false
|
||||||
|
useFullGVRTitle: false
|
||||||
skipLatestRevCheck: false
|
skipLatestRevCheck: false
|
||||||
disablePodCounting: false
|
disablePodCounting: false
|
||||||
shellPod:
|
shellPod:
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ k9s:
|
||||||
reactive: false
|
reactive: false
|
||||||
noIcons: false
|
noIcons: false
|
||||||
defaultsToFullScreen: false
|
defaultsToFullScreen: false
|
||||||
|
useFullGVRTitle: true
|
||||||
skipLatestRevCheck: false
|
skipLatestRevCheck: false
|
||||||
disablePodCounting: false
|
disablePodCounting: false
|
||||||
shellPod:
|
shellPod:
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ k9s:
|
||||||
reactive: false
|
reactive: false
|
||||||
noIcons: false
|
noIcons: false
|
||||||
defaultsToFullScreen: false
|
defaultsToFullScreen: false
|
||||||
|
useFullGVRTitle: false
|
||||||
skipLatestRevCheck: false
|
skipLatestRevCheck: false
|
||||||
disablePodCounting: false
|
disablePodCounting: false
|
||||||
shellPod:
|
shellPod:
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ type UI struct {
|
||||||
// DefaultsToFullScreen toggles fullscreen on views like logs, yaml, details.
|
// DefaultsToFullScreen toggles fullscreen on views like logs, yaml, details.
|
||||||
DefaultsToFullScreen bool `json:"defaultsToFullScreen" yaml:"defaultsToFullScreen"`
|
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
|
manualHeadless *bool
|
||||||
manualLogoless *bool
|
manualLogoless *bool
|
||||||
manualCrumbsless *bool
|
manualCrumbsless *bool
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ import (
|
||||||
|
|
||||||
func TestAsGVR(t *testing.T) {
|
func TestAsGVR(t *testing.T) {
|
||||||
a := dao.NewAlias(makeFactory())
|
a := dao.NewAlias(makeFactory())
|
||||||
a.Aliases.Define("v1/pods", "po", "pod", "pods")
|
a.Define("v1/pods", "po", "pod", "pods")
|
||||||
a.Aliases.Define("workloads", "workloads", "workload", "wkl")
|
a.Define("workloads", "workloads", "workload", "wkl")
|
||||||
|
|
||||||
uu := map[string]struct {
|
uu := map[string]struct {
|
||||||
cmd string
|
cmd string
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,7 @@
|
||||||
|
|
||||||
package dao
|
package dao
|
||||||
|
|
||||||
var (
|
var _ Accessor = (*ConfigMap)(nil)
|
||||||
_ Accessor = (*ConfigMap)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// ConfigMap represents a configmap resource.
|
// ConfigMap represents a configmap resource.
|
||||||
type ConfigMap struct {
|
type ConfigMap struct {
|
||||||
|
|
|
||||||
|
|
@ -321,8 +321,8 @@ func hasConfigMap(spec *v1.PodSpec, name string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range spec.Volumes {
|
for _, v := range spec.Volumes {
|
||||||
if cm := v.VolumeSource.ConfigMap; cm != nil {
|
if cm := v.ConfigMap; cm != nil {
|
||||||
if cm.LocalObjectReference.Name == name {
|
if cm.Name == name {
|
||||||
return true
|
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 {
|
for _, v := range spec.Volumes {
|
||||||
if sec := v.VolumeSource.Secret; sec != nil {
|
if sec := v.Secret; sec != nil {
|
||||||
if sec.SecretName == name {
|
if sec.SecretName == name {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,13 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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"
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/config/data"
|
"github.com/derailed/k9s/internal/config/data"
|
||||||
"github.com/derailed/k9s/internal/render/helm"
|
"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 (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultServiceAccount = "default"
|
defaultServiceAccount = "default"
|
||||||
defaultContainerAnnotation = "kubectl.kubernetes.io/default-container"
|
|
||||||
|
// 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.
|
// GetDefaultContainer returns a container name if specified in an annotation.
|
||||||
func GetDefaultContainer(m metav1.ObjectMeta, spec v1.PodSpec) (string, bool) {
|
func GetDefaultContainer(m metav1.ObjectMeta, spec v1.PodSpec) (string, bool) {
|
||||||
defaultContainer, ok := m.Annotations[defaultContainerAnnotation]
|
defaultContainer, ok := m.Annotations[DefaultContainerAnnotation]
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +40,7 @@ func GetDefaultContainer(m metav1.ObjectMeta, spec v1.PodSpec) (string, bool) {
|
||||||
}
|
}
|
||||||
slog.Warn("Container not found. Annotation ignored",
|
slog.Warn("Container not found. Annotation ignored",
|
||||||
slogs.CO, defaultContainer,
|
slogs.CO, defaultContainer,
|
||||||
slogs.Annotation, defaultContainerAnnotation,
|
slogs.Annotation, DefaultContainerAnnotation,
|
||||||
)
|
)
|
||||||
|
|
||||||
return "", false
|
return "", false
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var _ Accessor = (*ImageScan)(nil)
|
||||||
_ Accessor = (*ImageScan)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// ImageScan represents vulnerability scans.
|
// ImageScan represents vulnerability scans.
|
||||||
type ImageScan struct {
|
type ImageScan struct {
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func (j *Job) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range j.ObjectMeta.OwnerReferences {
|
for _, r := range j.OwnerReferences {
|
||||||
if r.Name == n {
|
if r.Name == n {
|
||||||
ll = append(ll, o)
|
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)
|
dd, errs := h.GetPodsForDeletion(path)
|
||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
for _, e := range errs {
|
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
|
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 {
|
if err := h.DeleteOrEvictPods(dd.Pods()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(h.Out, "Node %s drained!", path)
|
_, _ = fmt.Fprintf(h.Out, "Node %s drained!", path)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,7 @@
|
||||||
|
|
||||||
package dao
|
package dao
|
||||||
|
|
||||||
var (
|
var _ Accessor = (*Namespace)(nil)
|
||||||
_ Accessor = (*Namespace)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Namespace represents a namespace resource.
|
// Namespace represents a namespace resource.
|
||||||
type Namespace struct {
|
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")
|
return nil, errors.New("expecting Deployment resource")
|
||||||
}
|
}
|
||||||
// Just pick controller less pods...
|
// Just pick controller less pods...
|
||||||
if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
if len(pod.OwnerReferences) > 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if serviceAccountMatches(pod.Spec.ServiceAccountName, n) {
|
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")
|
return nil, errors.New("expecting Pod resource")
|
||||||
}
|
}
|
||||||
// Just pick controller less pods...
|
// Just pick controller less pods...
|
||||||
if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
if len(pod.OwnerReferences) > 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch gvr {
|
switch gvr {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ func TestGetDefaultContainer(t *testing.T) {
|
||||||
"container_not_present": {
|
"container_not_present": {
|
||||||
po: &v1.Pod{
|
po: &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Annotations: map[string]string{"kubectl.kubernetes.io/default-container": "container1"},
|
Annotations: map[string]string{DefaultContainerAnnotation: "container1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantContainer: "",
|
wantContainer: "",
|
||||||
|
|
@ -38,7 +38,7 @@ func TestGetDefaultContainer(t *testing.T) {
|
||||||
"container_found": {
|
"container_found": {
|
||||||
po: &v1.Pod{
|
po: &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Annotations: map[string]string{"kubectl.kubernetes.io/default-container": "container1"},
|
Annotations: map[string]string{DefaultContainerAnnotation: "container1"},
|
||||||
},
|
},
|
||||||
Spec: v1.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
Containers: []v1.Container{{Name: "container1"}},
|
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) {
|
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 {
|
if rs.Status.Replicas != 0 {
|
||||||
return 0, errors.New("can not rollback current replica")
|
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) {
|
func controllerInfo(rs *appsv1.ReplicaSet) (string, string, string, error) {
|
||||||
for _, ref := range rs.ObjectMeta.OwnerReferences {
|
for _, ref := range rs.OwnerReferences {
|
||||||
if ref.Controller == nil {
|
if ref.Controller == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ func controllerInfo(rs *appsv1.ReplicaSet) (string, string, string, error) {
|
||||||
}
|
}
|
||||||
return ref.Name, ref.Kind, group, nil
|
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.
|
// Rollback reverses the last deployment.
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,10 @@ import (
|
||||||
"k8s.io/client-go/scale"
|
"k8s.io/client-go/scale"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Scalable = (*Scaler)(nil)
|
var (
|
||||||
var _ ReplicasGetter = (*Scaler)(nil)
|
_ Scalable = (*Scaler)(nil)
|
||||||
|
_ ReplicasGetter = (*Scaler)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// Scaler represents a generic resource with scaling.
|
// Scaler represents a generic resource with scaling.
|
||||||
type Scaler struct {
|
type Scaler struct {
|
||||||
|
|
|
||||||
|
|
@ -16,46 +16,41 @@ import (
|
||||||
// Secret represents a secret K8s resource.
|
// Secret represents a secret K8s resource.
|
||||||
type Secret struct {
|
type Secret struct {
|
||||||
Resource
|
Resource
|
||||||
decode bool
|
decodeData bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe describes a secret that can be encoded or decoded.
|
// Describe describes a secret that can be encoded or decoded.
|
||||||
func (s *Secret) Describe(path string) (string, error) {
|
func (s *Secret) Describe(path string) (string, error) {
|
||||||
encodedDescription, err := s.Generic.Describe(path)
|
encodedDescription, err := s.Generic.Describe(path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
if !s.decodeData {
|
||||||
if !s.decode {
|
|
||||||
return encodedDescription, nil
|
return encodedDescription, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.Decode(encodedDescription, path)
|
return s.Decode(encodedDescription, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDecode sets the decode flag.
|
// SetDecodeData toggles decode mode.
|
||||||
func (s *Secret) SetDecode(flag bool) {
|
func (s *Secret) SetDecodeData(b bool) {
|
||||||
s.decode = flag
|
s.decodeData = b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode removes the encoded part from the secret's description and appends the
|
// Decode removes the encoded part from the secret's description and appends the
|
||||||
// secret's decoded data.
|
// secret's decoded data.
|
||||||
func (s *Secret) Decode(encodedDescription, path string) (string, error) {
|
func (s *Secret) Decode(encodedDescription, path string) (string, error) {
|
||||||
o, err := s.getFactory().Get(s.GVR(), path, true, labels.Everything())
|
o, err := s.getFactory().Get(s.GVR(), path, true, labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
dataEndIndex := strings.Index(encodedDescription, "====")
|
dataEndIndex := strings.Index(encodedDescription, "====")
|
||||||
|
|
||||||
if dataEndIndex == -1 {
|
if dataEndIndex == -1 {
|
||||||
return "", fmt.Errorf("unable to find data section in secret description")
|
return "", fmt.Errorf("unable to find data section in secret description")
|
||||||
}
|
}
|
||||||
|
|
||||||
dataEndIndex += 4
|
dataEndIndex += 4
|
||||||
|
|
||||||
if dataEndIndex >= len(encodedDescription) {
|
if dataEndIndex >= len(encodedDescription) {
|
||||||
return "", fmt.Errorf("data section in secret description is invalid")
|
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
|
// 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]
|
body := encodedDescription[0:dataEndIndex]
|
||||||
|
|
||||||
d, err := ExtractSecrets(o.(*unstructured.Unstructured))
|
data, err := ExtractSecrets(o)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedSecrets := []string{}
|
decodedSecrets := make([]string, 0, len(data))
|
||||||
|
for k, v := range data {
|
||||||
for k, v := range d {
|
line := fmt.Sprintf("%s: %s", k, v)
|
||||||
decodedSecrets = append(decodedSecrets, "\n", k, ":\t", 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
|
// 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
|
// It returns a map where the keys are the secret data keys and the values are
|
||||||
// the corresponding secret data values.
|
// the corresponding secret data values.
|
||||||
// If the conversion fails, it returns an error.
|
// 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
|
var secret v1.Secret
|
||||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.Object, &secret)
|
err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &secret)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
secretData := make(map[string]string, len(secret.Data))
|
secretData := make(map[string]string, len(secret.Data))
|
||||||
|
|
||||||
for k, val := range secret.Data {
|
for k, val := range secret.Data {
|
||||||
secretData[k] = string(val)
|
secretData[k] = string(val)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodedSecretDescribe(t *testing.T) {
|
func TestEncodedSecretDescribe(t *testing.T) {
|
||||||
s := dao.Secret{}
|
var s dao.Secret
|
||||||
s.Init(makeFactory(), client.NewGVR("v1/secrets"))
|
s.Init(makeFactory(), client.NewGVR("v1/secrets"))
|
||||||
|
|
||||||
encodedString :=
|
encodedString := `
|
||||||
`
|
|
||||||
Name: bootstrap-token-abcdef
|
Name: bootstrap-token-abcdef
|
||||||
Namespace: kube-system
|
Namespace: kube-system
|
||||||
Labels: <none>
|
Labels: <none>
|
||||||
|
|
@ -37,8 +36,9 @@ token-secret: 24 bytes`
|
||||||
"\n" +
|
"\n" +
|
||||||
"Data\n" +
|
"Data\n" +
|
||||||
"====\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)
|
assert.Equal(t, expected, decodedDescription)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,14 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal/client"
|
||||||
|
"github.com/derailed/k9s/internal/watch"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
restclient "k8s.io/client-go/rest"
|
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.
|
// 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) {
|
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)
|
oo, err := a.Table.List(ctx, ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -113,14 +113,12 @@ func (a *Workload) List(ctx context.Context, ns string) ([]runtime.Object, error
|
||||||
for _, r := range table.Rows {
|
for _, r := range table.Rows {
|
||||||
if obj := r.Object.Object; obj != nil {
|
if obj := r.Object.Object; obj != nil {
|
||||||
if m, err := meta.Accessor(obj); err == nil {
|
if m, err := meta.Accessor(obj); err == nil {
|
||||||
ns = m.GetNamespace()
|
ns, ts = m.GetNamespace(), m.GetCreationTimestamp()
|
||||||
ts = m.GetCreationTimestamp()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var m metav1.PartialObjectMetadata
|
var m metav1.PartialObjectMetadata
|
||||||
if err := json.Unmarshal(r.Object.Raw, &m); err == nil {
|
if err := json.Unmarshal(r.Object.Raw, &m); err == nil {
|
||||||
ns = m.GetNamespace()
|
ns, ts = m.GetNamespace(), m.CreationTimestamp
|
||||||
ts = m.CreationTimestamp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stat := status(gvr, r, table.ColumnDefinitions)
|
stat := status(gvr, r, table.ColumnDefinitions)
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/config"
|
|
||||||
"github.com/derailed/k9s/internal/slogs"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
|
"github.com/derailed/k9s/internal/config"
|
||||||
"github.com/derailed/k9s/internal/dao"
|
"github.com/derailed/k9s/internal/dao"
|
||||||
|
"github.com/derailed/k9s/internal/slogs"
|
||||||
"k8s.io/apimachinery/pkg/util/cache"
|
"k8s.io/apimachinery/pkg/util/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -239,5 +238,5 @@ func fetchLatestRev() (string, error) {
|
||||||
return v.(string), nil
|
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 {
|
if desc, ok := meta.DAO.(*dao.Secret); ok {
|
||||||
desc.SetDecode(d.decode)
|
desc.SetDecodeData(d.decode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return desc.Describe(path)
|
return desc.Describe(path)
|
||||||
|
|
|
||||||
|
|
@ -262,14 +262,17 @@ func newTestView() *testView {
|
||||||
func (t *testView) LogCanceled() {}
|
func (t *testView) LogCanceled() {}
|
||||||
func (t *testView) LogStop() {}
|
func (t *testView) LogStop() {}
|
||||||
func (t *testView) LogResume() {}
|
func (t *testView) LogResume() {}
|
||||||
|
|
||||||
func (t *testView) LogChanged(ll [][]byte) {
|
func (t *testView) LogChanged(ll [][]byte) {
|
||||||
t.data = ll
|
t.data = ll
|
||||||
t.dataCalled++
|
t.dataCalled++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testView) LogCleared() {
|
func (t *testView) LogCleared() {
|
||||||
t.clearCalled++
|
t.clearCalled++
|
||||||
t.data = nil
|
t.data = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testView) LogFailed(err error) {
|
func (t *testView) LogFailed(err error) {
|
||||||
fmt.Println("LogErr", err)
|
fmt.Println("LogErr", err)
|
||||||
t.errCalled++
|
t.errCalled++
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ func (p *Pulse) reconcile(ctx context.Context) error {
|
||||||
for _, o := range oo {
|
for _, o := range oo {
|
||||||
c, ok := o.(*health.Check)
|
c, ok := o.(*health.Check)
|
||||||
if !ok {
|
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.data = append(p.data, c)
|
||||||
p.firePulseChanged(c)
|
p.firePulseChanged(c)
|
||||||
|
|
|
||||||
|
|
@ -113,10 +113,6 @@ var Registry = map[string]ResourceMeta{
|
||||||
Renderer: &render.Service{},
|
Renderer: &render.Service{},
|
||||||
TreeRenderer: &xray.Service{},
|
TreeRenderer: &xray.Service{},
|
||||||
},
|
},
|
||||||
"v1/events": {
|
|
||||||
DAO: &dao.Table{},
|
|
||||||
Renderer: &render.Event{},
|
|
||||||
},
|
|
||||||
"v1/serviceaccounts": {
|
"v1/serviceaccounts": {
|
||||||
Renderer: &render.ServiceAccount{},
|
Renderer: &render.ServiceAccount{},
|
||||||
},
|
},
|
||||||
|
|
@ -193,14 +189,4 @@ var Registry = map[string]ResourceMeta{
|
||||||
"rbac.authorization.k8s.io/v1/rolebindings": {
|
"rbac.authorization.k8s.io/v1/rolebindings": {
|
||||||
Renderer: &render.RoleBinding{},
|
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{},
|
accessor: &dao.Node{},
|
||||||
renderer: &render.Node{},
|
renderer: &render.Node{},
|
||||||
},
|
},
|
||||||
"table": {
|
|
||||||
gvr: "v1/events",
|
|
||||||
accessor: &dao.Table{},
|
|
||||||
renderer: &render.Event{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range uu {
|
for k := range uu {
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ func (t *Text) RemoveListener(listener TextListener) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if victim >= 0 {
|
if victim >= 0 {
|
||||||
t.listeners = append(t.listeners[:victim], t.listeners[victim+1:]...)
|
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)
|
valuer, ok := accessor.(dao.Valuer)
|
||||||
if !ok {
|
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)
|
values, err := valuer.GetValues(v.path, v.allValues)
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ func lessCapacity(s1, s2 string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func lessNumber(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)
|
return sortorder.NaturalLess(v1, v2)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@ func TestLabelize(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsValid(t *testing.T) {
|
func TestIsValid(t *testing.T) {
|
||||||
|
|
||||||
uu := map[string]struct {
|
uu := map[string]struct {
|
||||||
ns string
|
ns string
|
||||||
h Header
|
h Header
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,6 @@ func (r RowEventSorter) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RowEventSorter) Swap(i, j int) {
|
func (r RowEventSorter) Swap(i, j int) {
|
||||||
|
|
||||||
r.Events.events[i], r.Events.events[j] = r.Events.events[j], r.Events.events[i]
|
r.Events.events[i], r.Events.events[j] = r.Events.events[j], r.Events.events[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"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/client"
|
||||||
"github.com/derailed/k9s/internal/config"
|
"github.com/derailed/k9s/internal/config"
|
||||||
|
"github.com/derailed/k9s/internal/config/data"
|
||||||
|
"github.com/derailed/k9s/internal/slogs"
|
||||||
"github.com/rakyll/hey/requester"
|
"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 {
|
func (b *Benchmark) save(cluster, context string, r io.Reader) error {
|
||||||
ns, n := client.Namespaced(b.config.Name)
|
ns, n := client.Namespaced(b.config.Name)
|
||||||
n = strings.Replace(n, "|", "_", -1)
|
n = strings.ReplaceAll(n, "|", "_")
|
||||||
n = strings.Replace(n, ":", "_", -1)
|
n = strings.ReplaceAll(n, ":", "_")
|
||||||
dir, err := config.EnsureBenchmarksDir(cluster, context)
|
dir, err := config.EnsureBenchmarksDir(cluster, context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func ParsePlainPF(ann string) (*PFAnn, error) {
|
||||||
var pf PFAnn
|
var pf PFAnn
|
||||||
mm := pfPlainRX.FindStringSubmatch(strings.TrimSpace(ann))
|
mm := pfPlainRX.FindStringSubmatch(strings.TrimSpace(ann))
|
||||||
if len(mm) < 3 {
|
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 {
|
if len(mm[2]) == 0 {
|
||||||
pf.ContainerPort = intstr.Parse(mm[1])
|
pf.ContainerPort = intstr.Parse(mm[1])
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ func (m ConfigMap) Header(_ string) model1.Header {
|
||||||
return m.doHeader(m.defaultHeader())
|
return m.doHeader(m.defaultHeader())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header returns a header rbw.
|
|
||||||
func (ConfigMap) defaultHeader() model1.Header {
|
func (ConfigMap) defaultHeader() model1.Header {
|
||||||
return model1.Header{
|
return model1.Header{
|
||||||
model1.HeaderColumn{Name: "NAMESPACE"},
|
model1.HeaderColumn{Name: "NAMESPACE"},
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func (ClusterRole) defaultRow(raw *unstructured.Unstructured, r *model1.Row) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.ID = client.FQN("-", cr.ObjectMeta.Name)
|
r.ID = client.FQN("-", cr.Name)
|
||||||
r.Fields = model1.Fields{
|
r.Fields = model1.Fields{
|
||||||
cr.Name,
|
cr.Name,
|
||||||
mapToStr(cr.Labels),
|
mapToStr(cr.Labels),
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ func (ClusterRoleBinding) defaultRow(raw *unstructured.Unstructured, r *model1.R
|
||||||
|
|
||||||
kind, ss := renderSubjects(crb.Subjects)
|
kind, ss := renderSubjects(crb.Subjects)
|
||||||
|
|
||||||
r.ID = client.FQN("-", crb.ObjectMeta.Name)
|
r.ID = client.FQN("-", crb.Name)
|
||||||
r.Fields = model1.Fields{
|
r.Fields = model1.Fields{
|
||||||
crb.Name,
|
crb.Name,
|
||||||
crb.RoleRef.Name,
|
crb.RoleRef.Name,
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ func (cc ColumnSpecs) Header(rh model1.Header) model1.Header {
|
||||||
|
|
||||||
for _, h := range rh {
|
for _, h := range rh {
|
||||||
if idx, ok := hh.IndexOf(h.Name, true); ok {
|
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
|
continue
|
||||||
}
|
}
|
||||||
hh = append(hh, h)
|
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
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header returns a header row.
|
// Header returns a header row.
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func (p PersistentVolume) defaultRow(raw *unstructured.Unstructured, r *model1.R
|
||||||
}
|
}
|
||||||
|
|
||||||
phase := pv.Status.Phase
|
phase := pv.Status.Phase
|
||||||
if pv.ObjectMeta.DeletionTimestamp != nil {
|
if pv.DeletionTimestamp != nil {
|
||||||
phase = terminatingPhase
|
phase = terminatingPhase
|
||||||
}
|
}
|
||||||
var claim string
|
var claim string
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func (p PersistentVolumeClaim) defaultRow(raw *unstructured.Unstructured, r *mod
|
||||||
}
|
}
|
||||||
|
|
||||||
phase := pvc.Status.Phase
|
phase := pvc.Status.Phase
|
||||||
if pvc.ObjectMeta.DeletionTimestamp != nil {
|
if pvc.DeletionTimestamp != nil {
|
||||||
phase = "Terminating"
|
phase = "Terminating"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ func (s StorageClass) defaultRow(raw *unstructured.Unstructured, r *model1.Row)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.ID = client.FQN(client.ClusterScope, sc.ObjectMeta.Name)
|
r.ID = client.FQN(client.ClusterScope, sc.Name)
|
||||||
r.Fields = model1.Fields{
|
r.Fields = model1.Fields{
|
||||||
s.nameWithDefault(sc.ObjectMeta),
|
s.nameWithDefault(sc.ObjectMeta),
|
||||||
sc.Provisioner,
|
sc.Provisioner,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,10 @@ var _ os.FileInfo = fileInfo{}
|
||||||
|
|
||||||
func (f fileInfo) Name() string { return "bob" }
|
func (f fileInfo) Name() string { return "bob" }
|
||||||
func (f fileInfo) Size() int64 { return 100 }
|
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) ModTime() time.Time { return testTime() }
|
||||||
func (f fileInfo) IsDir() bool { return false }
|
func (f fileInfo) IsDir() bool { return false }
|
||||||
func (f fileInfo) Sys() interface{} { return nil }
|
func (f fileInfo) Sys() interface{} { return nil }
|
||||||
|
|
||||||
|
func (f fileInfo) Mode() os.FileMode {
|
||||||
|
return os.FileMode(0644)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/model1"
|
"github.com/derailed/k9s/internal/model1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Secret renders a K8s Secret to screen.
|
// 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.ID = client.MetaFQN(svc.ObjectMeta)
|
||||||
r.Fields = model1.Fields{
|
r.Fields = model1.Fields{
|
||||||
svc.Namespace,
|
svc.Namespace,
|
||||||
svc.ObjectMeta.Name,
|
svc.Name,
|
||||||
string(svc.Spec.Type),
|
string(svc.Spec.Type),
|
||||||
toIP(svc.Spec.ClusterIP),
|
toIP(svc.Spec.ClusterIP),
|
||||||
toIPs(svc.Spec.Type, getSvcExtIPS(&svc)),
|
toIPs(svc.Spec.Type, getSvcExtIPS(&svc)),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ package render
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -138,39 +137,3 @@ func (t *Table) defaultRow(row *metav1.TableRow, ns string, r *model1.Row) error
|
||||||
|
|
||||||
return nil
|
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"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal/config"
|
||||||
"github.com/derailed/k9s/internal/model"
|
"github.com/derailed/k9s/internal/model"
|
||||||
"github.com/derailed/k9s/internal/model1"
|
"github.com/derailed/k9s/internal/model1"
|
||||||
"github.com/derailed/k9s/internal/slogs"
|
"github.com/derailed/k9s/internal/slogs"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/config"
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_activeConfig(t *testing.T) {
|
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())
|
assert.NoError(t, config.InitLocs())
|
||||||
|
|
||||||
cl, ct := "cl-1", "ct-1-1"
|
cl, ct := "cl-1", "ct-1-1"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSkinnedContext(t *testing.T) {
|
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())
|
assert.NoError(t, config.InitLocs())
|
||||||
defer assert.NoError(t, os.RemoveAll(config.K9sEnvConfigDir))
|
defer assert.NoError(t, os.RemoveAll(config.K9sEnvConfigDir))
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ func TestSkinnedContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBenchConfig(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())
|
assert.NoError(t, config.InitLocs())
|
||||||
defer assert.NoError(t, os.RemoveAll(config.K9sEnvConfigDir))
|
defer assert.NoError(t, os.RemoveAll(config.K9sEnvConfigDir))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,9 @@ func (c *Crumbs) refresh(crumbs []string) {
|
||||||
if i == last {
|
if i == last {
|
||||||
bgColor = c.styles.Frame().Crumb.ActiveColor
|
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,
|
c.styles.Frame().Crumb.FgColor,
|
||||||
bgColor, strings.Replace(strings.ToLower(crumb), " ", "", -1),
|
bgColor, strings.ReplaceAll(strings.ToLower(crumb), " ", ""),
|
||||||
c.styles.Body().BgColor)
|
c.styles.Body().BgColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ const (
|
||||||
KeySlash = 47
|
KeySlash = 47
|
||||||
KeyColon = 58
|
KeyColon = 58
|
||||||
KeySpace = 32
|
KeySpace = 32
|
||||||
KeyDash = 45 //or minus for those searching in the code
|
KeyDash = 45
|
||||||
KeyLeftBracket = 91
|
KeyLeftBracket = 91
|
||||||
KeyRightBracket = 93
|
KeyRightBracket = 93
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -105,9 +105,9 @@ func (l *Logo) refreshLogo(c config.Color) {
|
||||||
defer l.mx.Unlock()
|
defer l.mx.Unlock()
|
||||||
l.logo.Clear()
|
l.logo.Clear()
|
||||||
for i, s := range LogoSmall {
|
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) {
|
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 {
|
func formatNSMenu(i int, name string, styles config.Frame) string {
|
||||||
fmat := strings.Replace(menuIndexFmt, "[key", "["+styles.Menu.NumKeyColor.String(), 1)
|
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, "[fg", "["+styles.Menu.FgColor.String(), 1)
|
||||||
fmat = strings.Replace(fmat, "fgstyle]", styles.Menu.FgStyle.ToShortString()+"]", 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 "
|
menuFmt := " [key:-:b]%-" + strconv.Itoa(size+2) + "s [fg:-:fgstyle]%s "
|
||||||
fmat := strings.Replace(menuFmt, "[key", "["+styles.Menu.KeyColor.String(), 1)
|
fmat := strings.Replace(menuFmt, "[key", "["+styles.Menu.KeyColor.String(), 1)
|
||||||
fmat = strings.Replace(fmat, "[fg", "["+styles.Menu.FgColor.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)
|
fmat = strings.Replace(fmat, "fgstyle]", styles.Menu.FgStyle.ToShortString()+"]", 1)
|
||||||
|
|
||||||
return fmt.Sprintf(fmat, ToMnemonic(h.Mnemonic), h.Description)
|
return fmt.Sprintf(fmat, ToMnemonic(h.Mnemonic), h.Description)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ func NewPages() *Pages {
|
||||||
Pages: tview.NewPages(),
|
Pages: tview.NewPages(),
|
||||||
Stack: model.NewStack(),
|
Stack: model.NewStack(),
|
||||||
}
|
}
|
||||||
p.Stack.AddListener(&p)
|
p.AddListener(&p)
|
||||||
|
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +74,7 @@ func (p *Pages) delete(c model.Component) {
|
||||||
// Dump for debug.
|
// Dump for debug.
|
||||||
func (p *Pages) Dump() {
|
func (p *Pages) Dump() {
|
||||||
slog.Debug("Dumping Pages", slogs.Page, p)
|
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))))
|
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)
|
txt += fmt.Sprintf("[%s::-]%s", p.styles.Prompt().SuggestColor, suggest)
|
||||||
}
|
}
|
||||||
p.StylesChanged(p.styles)
|
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 (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/derailed/tcell/v2"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/config"
|
"github.com/derailed/k9s/internal/config"
|
||||||
"github.com/derailed/k9s/internal/model"
|
"github.com/derailed/k9s/internal/model"
|
||||||
"github.com/derailed/k9s/internal/ui"
|
"github.com/derailed/k9s/internal/ui"
|
||||||
|
"github.com/derailed/tcell/v2"
|
||||||
"github.com/stretchr/testify/assert"
|
"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) {
|
func (s *Splash) layoutLogo(t *tview.TextView, styles *config.Styles) {
|
||||||
logo := strings.Join(LogoBig, fmt.Sprintf("\n[%s::b]", styles.Body().LogoColor))
|
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),
|
strings.Repeat("\n", 2),
|
||||||
styles.Body().LogoColor,
|
styles.Body().LogoColor,
|
||||||
logo)
|
logo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Splash) layoutRev(t *tview.TextView, rev string, styles *config.Styles) {
|
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
|
mx sync.RWMutex
|
||||||
readOnly bool
|
readOnly bool
|
||||||
noIcon bool
|
noIcon bool
|
||||||
|
fullGVR bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTable returns a new table view.
|
// 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.
|
// SetNoIcon toggles no icon mode.
|
||||||
func (t *Table) SetNoIcon(b bool) {
|
func (t *Table) SetNoIcon(b bool) {
|
||||||
t.mx.Lock()
|
t.mx.Lock()
|
||||||
|
|
@ -547,11 +556,16 @@ func (t *Table) styleTitle() string {
|
||||||
ns = t.Extras
|
ns = t.Extras
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource := t.gvr.R()
|
||||||
|
if t.fullGVR {
|
||||||
|
resource = t.gvr.String()
|
||||||
|
}
|
||||||
|
|
||||||
var title string
|
var title string
|
||||||
if ns == client.ClusterScope {
|
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 {
|
} 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 != "" {
|
if ic := ROIndicator(t.readOnly, t.noIcon); ic != "" {
|
||||||
title = " " + ic + title
|
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.
|
// ROIndicator returns an icon showing whether the session is in readonly mode or not.
|
||||||
func ROIndicator(ro, noIC bool) string {
|
func ROIndicator(ro, noIC bool) string {
|
||||||
if noIC {
|
switch {
|
||||||
|
case noIC:
|
||||||
return ""
|
return ""
|
||||||
}
|
case ro:
|
||||||
|
|
||||||
if ro {
|
|
||||||
return lockedIC
|
return lockedIC
|
||||||
|
default:
|
||||||
|
return unlockedIC
|
||||||
}
|
}
|
||||||
|
|
||||||
return unlockedIC
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,12 @@ func SkinTitle(fmat string, style config.Frame) string {
|
||||||
if bgColor == config.DefaultColor {
|
if bgColor == config.DefaultColor {
|
||||||
bgColor = config.TransparentColor
|
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, "[hilite", "["+style.Title.HighlightColor.String(), 1)
|
||||||
fmat = strings.Replace(fmat, "[key", "["+style.Menu.NumKeyColor.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, "[filter", "["+style.Title.FilterColor.String(), 1)
|
||||||
fmat = strings.Replace(fmat, "[count", "["+style.Title.CounterColor.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
|
return fmat
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,36 +70,37 @@ type mockModel struct{}
|
||||||
|
|
||||||
var _ ui.Tabular = &mockModel{}
|
var _ ui.Tabular = &mockModel{}
|
||||||
|
|
||||||
func (t *mockModel) SetViewSetting(context.Context, *config.ViewSetting) {}
|
func (t *mockModel) SetViewSetting(context.Context, *config.ViewSetting) {}
|
||||||
func (t *mockModel) SetInstance(string) {}
|
func (t *mockModel) SetInstance(string) {}
|
||||||
func (t *mockModel) SetLabelFilter(string) {}
|
func (t *mockModel) SetLabelFilter(string) {}
|
||||||
func (t *mockModel) GetLabelFilter() string { return "" }
|
func (t *mockModel) GetLabelFilter() string { return "" }
|
||||||
func (t *mockModel) Empty() bool { return false }
|
func (t *mockModel) Empty() bool { return false }
|
||||||
func (t *mockModel) RowCount() int { return 1 }
|
func (t *mockModel) RowCount() int { return 1 }
|
||||||
func (t *mockModel) HasMetrics() bool { return true }
|
func (t *mockModel) HasMetrics() bool { return true }
|
||||||
func (t *mockModel) Peek() *model1.TableData { return makeTableData() }
|
func (t *mockModel) Peek() *model1.TableData { return makeTableData() }
|
||||||
func (t *mockModel) Refresh(context.Context) error { return nil }
|
func (t *mockModel) Refresh(context.Context) error { return nil }
|
||||||
func (t *mockModel) ClusterWide() bool { return false }
|
func (t *mockModel) ClusterWide() bool { return false }
|
||||||
func (t *mockModel) GetNamespace() string { return "blee" }
|
func (t *mockModel) GetNamespace() string { return "blee" }
|
||||||
func (t *mockModel) SetNamespace(string) {}
|
func (t *mockModel) SetNamespace(string) {}
|
||||||
func (t *mockModel) ToggleToast() {}
|
func (t *mockModel) ToggleToast() {}
|
||||||
func (t *mockModel) AddListener(model.TableListener) {}
|
func (t *mockModel) AddListener(model.TableListener) {}
|
||||||
func (t *mockModel) RemoveListener(model.TableListener) {}
|
func (t *mockModel) RemoveListener(model.TableListener) {}
|
||||||
func (t *mockModel) Watch(context.Context) error { return nil }
|
func (t *mockModel) Watch(context.Context) error { return nil }
|
||||||
func (t *mockModel) Get(ctx context.Context, path string) (runtime.Object, error) {
|
func (t *mockModel) Get(ctx context.Context, path string) (runtime.Object, error) { return nil, nil }
|
||||||
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 {
|
func (t *mockModel) Delete(context.Context, string, *metav1.DeletionPropagation, dao.Grace) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mockModel) Describe(context.Context, string) (string, error) {
|
func (t *mockModel) Describe(context.Context, string) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mockModel) ToYAML(ctx context.Context, path string) (string, error) {
|
func (t *mockModel) ToYAML(ctx context.Context, path string) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
func (t *mockModel) InNamespace(string) bool { return true }
|
|
||||||
func (t *mockModel) SetRefreshRate(time.Duration) {}
|
|
||||||
|
|
||||||
func makeTableData() *model1.TableData {
|
func makeTableData() *model1.TableData {
|
||||||
return model1.NewTableDataWithRows(
|
return model1.NewTableDataWithRows(
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
unlockedIC = "✍️ "
|
unlockedIC = "🖍"
|
||||||
lockedIC = "🔒"
|
lockedIC = "🔑"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Namespaceable tracks namespaces.
|
// Namespaceable tracks namespaces.
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,8 @@ func (a *App) Init(version string, rate int) error {
|
||||||
if err := a.Content.Init(ctx); err != nil {
|
if err := a.Content.Init(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.Content.Stack.AddListener(a.Crumbs())
|
a.Content.AddListener(a.Crumbs())
|
||||||
a.Content.Stack.AddListener(a.Menu())
|
a.Content.AddListener(a.Menu())
|
||||||
|
|
||||||
a.App.Init()
|
a.App.Init()
|
||||||
a.SetInputCapture(a.keyboard)
|
a.SetInputCapture(a.keyboard)
|
||||||
|
|
@ -198,7 +198,7 @@ func (a *App) suggestCommand() model.SuggestionFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := strings.ToLower(s)
|
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 {
|
if suggest, ok := cmd.ShouldAddSuggest(ls, k); ok {
|
||||||
entries = append(entries, suggest)
|
entries = append(entries, suggest)
|
||||||
}
|
}
|
||||||
|
|
@ -776,7 +776,7 @@ func (a *App) inject(c model.Component, clearStack bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if clearStack {
|
if clearStack {
|
||||||
a.Content.Stack.Clear()
|
a.Content.Clear()
|
||||||
}
|
}
|
||||||
a.Content.Push(c)
|
a.Content.Push(c)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,9 @@ func (b *Browser) Init(ctx context.Context) error {
|
||||||
if b.App().IsRunning() {
|
if b.App().IsRunning() {
|
||||||
b.app.CmdBuff().Reset()
|
b.app.CmdBuff().Reset()
|
||||||
}
|
}
|
||||||
b.Table.SetReadOnly(b.app.Config.IsReadOnly())
|
b.SetReadOnly(b.app.Config.IsReadOnly())
|
||||||
b.Table.SetNoIcon(b.app.Config.K9s.UI.NoIcons)
|
b.SetNoIcon(b.app.Config.K9s.UI.NoIcons)
|
||||||
|
b.SetFullGVR(b.app.Config.K9s.UI.UseFullGVRTitle)
|
||||||
|
|
||||||
b.bindKeys(b.Actions())
|
b.bindKeys(b.Actions())
|
||||||
for _, f := range b.bindKeysFn {
|
for _, f := range b.bindKeysFn {
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,8 @@ func TestFlagsNew(t *testing.T) {
|
||||||
fuzzyKey: "blee",
|
fuzzyKey: "blee",
|
||||||
labelKey: "app=fred",
|
labelKey: "app=fred",
|
||||||
nsKey: "ns1",
|
nsKey: "ns1",
|
||||||
contextKey: "Dev"},
|
contextKey: "Dev",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"ctx": {
|
"ctx": {
|
||||||
i: NewInterpreter("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)
|
app.Content.Pages.RemovePage(renamePage)
|
||||||
}).
|
}).
|
||||||
AddButton("Cancel", func() {
|
AddButton("Cancel", func() {
|
||||||
app.Content.Pages.RemovePage(renamePage)
|
app.Content.RemovePage(renamePage)
|
||||||
})
|
})
|
||||||
|
|
||||||
m := tview.NewModalForm("<Rename>", f)
|
m := tview.NewModalForm("<Rename>", f)
|
||||||
m.SetText(fmt.Sprintf("Rename context %q?", name))
|
m.SetText(fmt.Sprintf("Rename context %q?", name))
|
||||||
m.SetDoneFunc(func(int, string) {
|
m.SetDoneFunc(func(int, string) {
|
||||||
app.Content.Pages.RemovePage(renamePage)
|
app.Content.RemovePage(renamePage)
|
||||||
})
|
})
|
||||||
app.Content.Pages.AddPage(renamePage, m, false, false)
|
app.Content.AddPage(renamePage, m, false, false)
|
||||||
app.Content.Pages.ShowPage(renamePage)
|
app.Content.ShowPage(renamePage)
|
||||||
|
|
||||||
for i := 0; i < f.GetButtonCount(); i++ {
|
for i := 0; i < f.GetButtonCount(); i++ {
|
||||||
f.GetButton(i).
|
f.GetButton(i).
|
||||||
|
|
|
||||||
|
|
@ -238,11 +238,11 @@ func (d *Details) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
func (d *Details) setFullScreen(isFullScreen bool) {
|
func (d *Details) setFullScreen(isFullScreen bool) {
|
||||||
d.fullScreen = isFullScreen
|
d.fullScreen = isFullScreen
|
||||||
d.SetFullScreen(isFullScreen)
|
d.SetFullScreen(isFullScreen)
|
||||||
d.Box.SetBorder(!isFullScreen)
|
d.SetBorder(!isFullScreen)
|
||||||
if isFullScreen {
|
if isFullScreen {
|
||||||
d.Box.SetBorderPadding(0, 0, 0, 0)
|
d.SetBorderPadding(0, 0, 0, 0)
|
||||||
} else {
|
} else {
|
||||||
d.Box.SetBorderPadding(0, 0, 1, 1)
|
d.SetBorderPadding(0, 0, 1, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,9 @@ package view_test
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/view"
|
"github.com/derailed/k9s/internal/view"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDeploy(t *testing.T) {
|
func TestDeploy(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ func (e Env) Substitute(arg string) (string, error) {
|
||||||
}
|
}
|
||||||
v = fmt.Sprintf("%t", b)
|
v = fmt.Sprintf("%t", b)
|
||||||
}
|
}
|
||||||
arg = strings.Replace(arg, m[0], v, -1)
|
arg = strings.ReplaceAll(arg, m[0], v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return arg, nil
|
return arg, nil
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,11 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/render"
|
|
||||||
"github.com/derailed/k9s/internal/slogs"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/config"
|
"github.com/derailed/k9s/internal/config"
|
||||||
"github.com/derailed/k9s/internal/model"
|
"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/derailed/k9s/internal/ui/dialog"
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
|
@ -447,7 +446,7 @@ func k9sShellPodName() string {
|
||||||
|
|
||||||
func k9sShellPod(node string, cfg config.ShellPod) *v1.Pod {
|
func k9sShellPod(node string, cfg config.ShellPod) *v1.Pod {
|
||||||
var grace int64
|
var grace int64
|
||||||
var priv bool = true
|
var priv = true
|
||||||
|
|
||||||
slog.Debug("Shell pod config", slogs.ShellPodCfg, cfg)
|
slog.Debug("Shell pod config", slogs.ShellPodCfg, cfg)
|
||||||
c := v1.Container{
|
c := v1.Container{
|
||||||
|
|
|
||||||
|
|
@ -292,11 +292,11 @@ func (v *LiveView) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
func (v *LiveView) setFullScreen(isFullScreen bool) {
|
func (v *LiveView) setFullScreen(isFullScreen bool) {
|
||||||
v.fullScreen = isFullScreen
|
v.fullScreen = isFullScreen
|
||||||
v.SetFullScreen(isFullScreen)
|
v.SetFullScreen(isFullScreen)
|
||||||
v.Box.SetBorder(!isFullScreen)
|
v.SetBorder(!isFullScreen)
|
||||||
if isFullScreen {
|
if isFullScreen {
|
||||||
v.Box.SetBorderPadding(0, 0, 0, 0)
|
v.SetBorderPadding(0, 0, 0, 0)
|
||||||
} else {
|
} 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 {
|
func (l *Log) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
if !l.logs.cmdBuff.IsActive() {
|
if !l.logs.cmdBuff.IsActive() {
|
||||||
fmt.Fprintln(l.ansiWriter)
|
_, _ = fmt.Fprintln(l.ansiWriter)
|
||||||
return evt
|
return evt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -460,7 +460,7 @@ func (l *Log) clearCmd(*tcell.EventKey) *tcell.EventKey {
|
||||||
|
|
||||||
func (l *Log) markCmd(*tcell.EventKey) *tcell.EventKey {
|
func (l *Log) markCmd(*tcell.EventKey) *tcell.EventKey {
|
||||||
_, _, w, _ := l.GetRect()
|
_, _, 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
|
l.follow = true
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -516,7 +516,7 @@ func (l *Log) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
|
|
||||||
func (l *Log) toggleFullScreen() {
|
func (l *Log) toggleFullScreen() {
|
||||||
l.SetFullScreen(l.indicator.FullScreen())
|
l.SetFullScreen(l.indicator.FullScreen())
|
||||||
l.Box.SetBorder(!l.indicator.FullScreen())
|
l.SetBorder(!l.indicator.FullScreen())
|
||||||
if l.indicator.FullScreen() {
|
if l.indicator.FullScreen() {
|
||||||
l.logs.SetBorderPadding(0, 0, 0, 0)
|
l.logs.SetBorderPadding(0, 0, 0, 0)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -85,14 +85,14 @@ func BenchmarkLogFlush(b *testing.B) {
|
||||||
func TestLogAnsi(t *testing.T) {
|
func TestLogAnsi(t *testing.T) {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
w := tview.ANSIWriter(buff, "white", "black")
|
w := tview.ANSIWriter(buff, "white", "black")
|
||||||
fmt.Fprintf(w, "[YELLOW] ok")
|
_, _ = fmt.Fprintf(w, "[YELLOW] ok")
|
||||||
assert.Equal(t, "[YELLOW] ok", buff.String())
|
assert.Equal(t, "[YELLOW] ok", buff.String())
|
||||||
|
|
||||||
v := tview.NewTextView()
|
v := tview.NewTextView()
|
||||||
v.SetDynamicColors(true)
|
v.SetDynamicColors(true)
|
||||||
aw := tview.ANSIWriter(v, "white", "black")
|
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]]"
|
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))
|
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 {
|
if p.app, err = extractApp(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.Stack.AddListener(p)
|
p.AddListener(p)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,15 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal/client"
|
||||||
|
"github.com/derailed/k9s/internal/dao"
|
||||||
|
"github.com/derailed/k9s/internal/watch"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/informers"
|
"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) {
|
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