Rel v0.40.6 (#3185)
* update deps * docs * fix#3161 - add V attr * add alias sort * fix#3139 - cpu/mem with rx * fix#3147 - prompt styles * fix#3138 - rbac subres * update deps * mv pfAddress to main config + relax validation * fix#3179 - gvr title * fix#3178 - jobs in wrong ns * fix#3163 - cust views with ns * fix#3162 - ctx switch save in wrong context * switch over to slog logger * add exit code * update default timeout * rel notes * update docs * rel notesmine
parent
4867f5361d
commit
a8b75ef1e5
|
|
@ -78,6 +78,62 @@ linters-settings:
|
|||
- errors
|
||||
reason: "Go 1.20+ has support for combining multiple errors, see https://go.dev/doc/go1.20#errors"
|
||||
|
||||
sloglint:
|
||||
# Enforce not mixing key-value pairs and attributes.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-mixed-arguments
|
||||
# Default: true
|
||||
no-mixed-args: true
|
||||
# Enforce using key-value pairs only (overrides no-mixed-args, incompatible with attr-only).
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-value-pairs-only
|
||||
# Default: false
|
||||
kv-only: true
|
||||
# Enforce using attributes only (overrides no-mixed-args, incompatible with kv-only).
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#attributes-only
|
||||
# Default: false
|
||||
attr-only: false
|
||||
# Enforce not using global loggers.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all global loggers
|
||||
# - "default": report only the default slog logger
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global
|
||||
# Default: ""
|
||||
no-global: ""
|
||||
# Enforce using methods that accept a context.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all contextless calls
|
||||
# - "scope": report only if a context exists in the scope of the outermost function
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only
|
||||
# Default: ""
|
||||
context: ""
|
||||
# Enforce using static values for log messages.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages
|
||||
# Default: false
|
||||
static-msg: false
|
||||
# Enforce using constants instead of raw keys.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-raw-keys
|
||||
# Default: false
|
||||
no-raw-keys: true
|
||||
# Enforce a single key naming convention.
|
||||
# Values: snake, kebab, camel, pascal
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention
|
||||
# Default: ""
|
||||
key-naming-case: camel
|
||||
# Enforce not using specific keys.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#forbidden-keys
|
||||
# Default: []
|
||||
forbidden-keys:
|
||||
- time
|
||||
- level
|
||||
- msg
|
||||
- source
|
||||
# Enforce putting arguments on separate lines.
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#arguments-on-separate-lines
|
||||
# Default: false
|
||||
args-on-sep-lines: false
|
||||
|
||||
|
||||
issues:
|
||||
|
||||
# default is true. Enables skipping of directories:
|
||||
|
|
@ -124,3 +180,5 @@ linters:
|
|||
- misspell
|
||||
- prealloc
|
||||
- typecheck
|
||||
- sloglint
|
||||
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:
|
|||
else
|
||||
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
||||
endif
|
||||
VERSION ?= v0.40.5
|
||||
VERSION ?= v0.40.6
|
||||
IMG_NAME := derailed/k9s
|
||||
IMAGE := ${IMG_NAME}:${VERSION}
|
||||
|
||||
|
|
|
|||
28
README.md
28
README.md
|
|
@ -66,6 +66,8 @@ Your donations will go a long way in keeping our servers lights on and beers in
|
|||
|
||||
Please refer to our [K9s documentation](https://k9scli.io) site for installation, usage, customization and tips.
|
||||
|
||||
---
|
||||
|
||||
## Slack Channel
|
||||
|
||||
Wanna discuss K9s features with your fellow `K9sers` or simply show your support for this tool?
|
||||
|
|
@ -73,6 +75,21 @@ Wanna discuss K9s features with your fellow `K9sers` or simply show your support
|
|||
* Channel: [K9sersSlack](https://k9sers.slack.com/)
|
||||
* Invite: [K9slackers Invite](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
|
||||
|
||||
---
|
||||
|
||||
## 🥳 A Word From Our Rhodium Sponsors...
|
||||
|
||||
Below are organizations that have opted to show their support and sponsor K9s.
|
||||
|
||||
<br/>
|
||||
<a href="https://panfactum.com"><img src="assets/sponsors/panfactum.png" alt="panfactum"></a>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
> NOTE! K9s neither vouches for nor endorses these companies or products.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
K9s is available on Linux, macOS and Windows platforms.
|
||||
|
|
@ -627,7 +644,7 @@ The annotation value must specify a container to forward to as well as a local p
|
|||
|
||||
---
|
||||
|
||||
## Resource Custom Columns
|
||||
## Custom Views
|
||||
|
||||
[SneakCast v0.17.0 on The Beach! - Yup! sound is sucking but what a setting!](https://youtu.be/7S33CNLAofk)
|
||||
|
||||
|
|
@ -654,6 +671,7 @@ You can have one or more of the following attributes:
|
|||
* `T` -> time column indicator
|
||||
* `N` -> number column indicator
|
||||
* `W` -> turns on wide column aka only shows while in wide mode. Defaults to the standard resource definition when present.
|
||||
* `S` -> Ensures a column is visible and not wide. Overrides `wide` std resource definition if present.
|
||||
* `H` -> Hides the column
|
||||
* `L` -> Left align (default)
|
||||
* `R` -> Right align
|
||||
|
|
@ -674,6 +692,14 @@ views:
|
|||
- NODE
|
||||
- STATUS
|
||||
- READY
|
||||
- MEM/RL|S # => 🌚 Overrides std resource default wide attribute via `S` for `Show`
|
||||
- '%MEM/R|' # => NOTE! column names with non alpha names need to be quoted as columns must be strings!
|
||||
|
||||
v1/pods@fred: # => 🌚 New v0.40.6! Customize columns for a given resource and namespace!
|
||||
columns:
|
||||
- AGE
|
||||
- NAMESPACE|WR
|
||||
|
||||
v1/services:
|
||||
columns:
|
||||
- AGE
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1,99 @@
|
|||
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
|
||||
|
||||
# Release v0.40.6
|
||||
|
||||
## 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!
|
||||
|
||||
### Breaking change
|
||||
|
||||
Moved `portForwardAddress` out of clusterXXX/contextYYY/config.yaml and into the main K9s config file.
|
||||
This is a global preference based on your setup vs a cluster/context specific attribute.
|
||||
K9s will nag you in the logs if a specific context config still contains this attribute but should not prevent the configuration load.
|
||||
|
||||
### Column Blow Reloaded!
|
||||
|
||||
We've added another property to the custom view. You can now also specify namespace specific column definition for a given resource.
|
||||
For instance, view pods in any namespace using one configuration and view pods in `fred` namespace using an alternate configuration.
|
||||
|
||||
```yaml
|
||||
# views.yaml
|
||||
views:
|
||||
# Using this for all pods...
|
||||
v1/pods:
|
||||
columns:
|
||||
- AGE
|
||||
- NAMESPACE|WR # => 🌚 Specifies the NAMESPACE column to be right aligned and only visible while in wide mode
|
||||
- ZORG:.metadata.labels.fred\.io\.kubernetes\.blee # => 🌚 extract fred.io.kubernetes.blee label into it's own column
|
||||
- BLEE:.metadata.annotations.blee|R # => 🌚 extract annotation blee into it's own column and right align it
|
||||
- NAME
|
||||
- IP
|
||||
- NODE
|
||||
- STATUS
|
||||
- READY
|
||||
- MEM/RL|S # => 🌚 Overrides std resource default wide attribute via `S` for `Show`
|
||||
- '%MEM/R|' # => NOTE! column names with non alpha names need to be quoted as columns must be strings!
|
||||
|
||||
# Use this instead for pods in namespace `fred`
|
||||
v1/pods@fred: # => 🌚 New v0.40.6! Customize columns for a given resource and namespace!
|
||||
columns:
|
||||
- AGE
|
||||
- NAMESPACE|WR
|
||||
```
|
||||
|
||||
Additionally, we've added a new column attribute aka `Show` -> `S`. This allows you to now override the default resource column `wide` attribute when set.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
* [#3179](https://github.com/derailed/k9s/issues/3179) Resource name with full api or group displayed (somewhere and sometimes)
|
||||
* [#3178](https://github.com/derailed/k9s/issues/3178) Cronjobs with the same name in different namespaces appear together
|
||||
* [#3176](https://github.com/derailed/k9s/issues/3176) Trigger all marked cronjobs
|
||||
* [#3162](https://github.com/derailed/k9s/issues/3162) Context configs: context directory created under wrong cluster after context switch
|
||||
* [#3161](https://github.com/derailed/k9s/issues/3161) Force wide-only columns to appear outside of wide view
|
||||
* [#3147](https://github.com/derailed/k9s/issues/3147) Prompt style is overriden by body
|
||||
* [#3139](https://github.com/derailed/k9s/issues/3139) CPU/R:L and MEM/R:L columns invalid in views.yaml
|
||||
* [#3138](https://github.com/derailed/k9s/issues/3138) Subresources are not shown correctly in the RBAC view
|
||||
|
||||
---
|
||||
|
||||
## 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!!
|
||||
|
||||
* [#3182](https://github.com/derailed/k9s/pull/3182) fix: Use the latest version when downloading the Ubuntu deb file
|
||||
* [#3168](https://github.com/derailed/k9s/pull/3168) fix(history): handle cases where special commands add their command their command to the history
|
||||
* [#3159](https://github.com/derailed/k9s/pull/3159) Added hard contrast gruvbox skins
|
||||
* [#3149](https://github.com/derailed/k9s/pull/3149) fix: Pass grv on gotoResource as a String to fix non-default apiGroup list
|
||||
* [#3149](https://github.com/derailed/k9s/pull/3149) Add externalsecrets plugin
|
||||
* [#3140](https://github.com/derailed/k9s/pull/3140) fix: Avoid false positive matches in enableRegion (#3093)
|
||||
|
||||
|
||||
<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)
|
||||
|
|
@ -5,12 +5,13 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal/color"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
|
@ -60,13 +61,13 @@ func getScreenDumpDirForInfo() string {
|
|||
|
||||
f, err := os.ReadFile(config.AppConfigFile)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Reads k9s config file %v", err)
|
||||
slog.Error("Unable to reads k9s config file", slogs.Error, err)
|
||||
return config.AppDumpsDir
|
||||
}
|
||||
|
||||
var cfg config.Config
|
||||
if err := yaml.Unmarshal(f, &cfg); err != nil {
|
||||
log.Error().Err(err).Msgf("Unmarshal k9s config %v", err)
|
||||
slog.Error("Unable to unmarshal k9s config file", slogs.Error, err)
|
||||
return config.AppDumpsDir
|
||||
}
|
||||
if cfg.K9s == nil {
|
||||
|
|
|
|||
72
cmd/root.go
72
cmd/root.go
|
|
@ -6,22 +6,25 @@ package cmd
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/color"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/view"
|
||||
|
||||
"github.com/lmittmann/tint"
|
||||
// "github.com/MatusOllah/slogcolor"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -78,35 +81,37 @@ func run(cmd *cobra.Command, args []string) error {
|
|||
if err := config.InitLocs(); err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.OpenFile(
|
||||
logFile, err := os.OpenFile(
|
||||
*k9sFlags.LogFile,
|
||||
os.O_CREATE|os.O_APPEND|os.O_WRONLY,
|
||||
data.DefaultFileMod,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Log file %q init failed: %w", *k9sFlags.LogFile, err)
|
||||
return fmt.Errorf("log file %q init failed: %w", *k9sFlags.LogFile, err)
|
||||
}
|
||||
defer func() {
|
||||
if file != nil {
|
||||
_ = file.Close()
|
||||
if logFile != nil {
|
||||
_ = logFile.Close()
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Error().Msgf("Boom! %v", err)
|
||||
log.Error().Msg(string(debug.Stack()))
|
||||
slog.Error("Boom!! k9s init failed", slogs.Error, err)
|
||||
slog.Error("", slogs.Stack, string(debug.Stack()))
|
||||
printLogo(color.Red)
|
||||
fmt.Printf("%s", color.Colorize("Boom!! ", color.Red))
|
||||
fmt.Printf("%v.\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: file})
|
||||
zerolog.SetGlobalLevel(parseLevel(*k9sFlags.LogLevel))
|
||||
slog.SetDefault(slog.New(tint.NewHandler(logFile, &tint.Options{
|
||||
Level: parseLevel(*k9sFlags.LogLevel),
|
||||
TimeFormat: time.Kitchen,
|
||||
})))
|
||||
|
||||
cfg, err := loadConfiguration()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Fail to load global/context configuration")
|
||||
slog.Warn("Fail to load global/context configuration", slogs.Error, err)
|
||||
}
|
||||
app := view.NewApp(cfg)
|
||||
if err := app.Init(version, *k9sFlags.RefreshRate); err != nil {
|
||||
|
|
@ -123,7 +128,7 @@ func run(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
|
||||
func loadConfiguration() (*config.Config, error) {
|
||||
log.Info().Msg("🐶 K9s starting up...")
|
||||
slog.Info("🐶 K9s starting up...")
|
||||
|
||||
k8sCfg := client.NewConfig(k8sFlags)
|
||||
k9sCfg := config.NewConfig(k8sCfg)
|
||||
|
|
@ -134,50 +139,43 @@ func loadConfiguration() (*config.Config, error) {
|
|||
}
|
||||
k9sCfg.K9s.Override(k9sFlags)
|
||||
if err := k9sCfg.Refine(k8sFlags, k9sFlags, k8sCfg); err != nil {
|
||||
log.Error().Err(err).Msgf("config refine failed")
|
||||
slog.Error("Fail to refine k9s config", slogs.Error, err)
|
||||
errs = errors.Join(errs, err)
|
||||
}
|
||||
|
||||
conn, err := client.InitConnection(k8sCfg)
|
||||
|
||||
conn, err := client.InitConnection(k8sCfg, slog.Default())
|
||||
if err != nil {
|
||||
errs = errors.Join(errs, err)
|
||||
}
|
||||
|
||||
// Try to access server version if that fail. Connectivity issue?
|
||||
if !conn.CheckConnectivity() {
|
||||
errs = errors.Join(errs, fmt.Errorf("cannot connect to context: %s", k9sCfg.K9s.ActiveContextName()))
|
||||
}
|
||||
|
||||
if !conn.ConnectionOK() {
|
||||
slog.Warn("💣 Kubernetes connectivity toast!")
|
||||
errs = errors.Join(errs, fmt.Errorf("k8s connection failed for context: %s", k9sCfg.K9s.ActiveContextName()))
|
||||
} else {
|
||||
slog.Info("✅ Kubernetes connectivity OK")
|
||||
}
|
||||
|
||||
k9sCfg.SetConnection(conn)
|
||||
|
||||
log.Info().Msg("✅ Kubernetes connectivity")
|
||||
if err := k9sCfg.Save(false); err != nil {
|
||||
log.Error().Err(err).Msg("Config save")
|
||||
slog.Error("K9s config save failed", slogs.Error, err)
|
||||
errs = errors.Join(errs, err)
|
||||
}
|
||||
|
||||
return k9sCfg, errs
|
||||
}
|
||||
|
||||
func parseLevel(level string) zerolog.Level {
|
||||
func parseLevel(level string) slog.Level {
|
||||
switch level {
|
||||
case "trace":
|
||||
return zerolog.TraceLevel
|
||||
case "debug":
|
||||
return zerolog.DebugLevel
|
||||
return slog.LevelDebug
|
||||
case "warn":
|
||||
return zerolog.WarnLevel
|
||||
return slog.LevelWarn
|
||||
case "error":
|
||||
return zerolog.ErrorLevel
|
||||
case "fatal":
|
||||
return zerolog.FatalLevel
|
||||
return slog.LevelError
|
||||
default:
|
||||
return zerolog.InfoLevel
|
||||
return slog.LevelInfo
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +191,7 @@ func initK9sFlags() {
|
|||
k9sFlags.LogLevel,
|
||||
"logLevel", "l",
|
||||
config.DefaultLogLevel,
|
||||
"Specify a log level (error, warn, info, debug, trace)",
|
||||
"Specify a log level (error, warn, info, debug)",
|
||||
)
|
||||
rootCmd.Flags().StringVarP(
|
||||
k9sFlags.LogFile,
|
||||
|
|
@ -265,7 +263,7 @@ func initK8sFlags() {
|
|||
rootCmd.Flags().StringVar(
|
||||
k8sFlags.Timeout,
|
||||
"request-timeout",
|
||||
"",
|
||||
"5s",
|
||||
"The length of time to wait before giving up on a single server request",
|
||||
)
|
||||
|
||||
|
|
@ -376,7 +374,7 @@ func initK8sFlagCompletion() {
|
|||
|
||||
_ = rootCmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, s string) ([]string, cobra.ShellCompDirective) {
|
||||
conn := client.NewConfig(k8sFlags)
|
||||
if c, err := client.InitConnection(conn); err == nil {
|
||||
if c, err := client.InitConnection(conn, slog.Default()); err == nil {
|
||||
if nss, err := c.ValidNamespaceNames(); err == nil {
|
||||
return filterFlagCompletions(nss, s)
|
||||
}
|
||||
|
|
@ -391,7 +389,7 @@ func k8sFlagCompletion[T any](picker k8sPickerFn[T]) completeFn {
|
|||
conn := client.NewConfig(k8sFlags)
|
||||
cfg, err := conn.RawConfig()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("k8s config getter failed")
|
||||
slog.Error("K8s raw config getter failed", slogs.Error, err)
|
||||
}
|
||||
|
||||
return filterFlagCompletions(picker(&cfg), toComplete)
|
||||
|
|
|
|||
40
go.mod
40
go.mod
|
|
@ -1,12 +1,12 @@
|
|||
module github.com/derailed/k9s
|
||||
|
||||
go 1.23.2
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/adrg/xdg v0.5.3
|
||||
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837
|
||||
github.com/anchore/grype v0.86.1
|
||||
github.com/anchore/syft v1.19.0
|
||||
github.com/anchore/syft v1.20.0
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/cenkalti/backoff/v4 v4.3.0
|
||||
github.com/derailed/popeye v0.11.3
|
||||
|
|
@ -16,12 +16,12 @@ require (
|
|||
github.com/fsnotify/fsnotify v1.8.0
|
||||
github.com/fvbommel/sortorder v1.1.0
|
||||
github.com/go-errors/errors v1.5.1
|
||||
github.com/lmittmann/tint v1.0.7
|
||||
github.com/mattn/go-colorable v0.1.14
|
||||
github.com/mattn/go-runewidth v0.0.16
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/petergtz/pegomock v2.9.0+incompatible
|
||||
github.com/rakyll/hey v0.1.4
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/sahilm/fuzzy v0.1.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
|
|
@ -69,7 +69,7 @@ require (
|
|||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.7 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
||||
github.com/acobaugh/osrelease v0.1.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51 // indirect
|
||||
|
|
@ -79,7 +79,7 @@ require (
|
|||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // 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/packageurl-go v0.1.1-0.20250117185454-edf36a908b10 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 // indirect
|
||||
github.com/anchore/stereoscope v0.0.13 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
|
|
@ -91,9 +91,10 @@ require (
|
|||
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.0 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
|
|
@ -118,7 +119,7 @@ require (
|
|||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/cli v27.5.0+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v27.5.0+incompatible // indirect
|
||||
github.com/docker/docker v28.0.0+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
|
|
@ -136,7 +137,7 @@ require (
|
|||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/facebookincubator/nvdtools v0.1.5 // indirect
|
||||
github.com/fatih/camelcase v1.0.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
|
|
@ -146,7 +147,7 @@ require (
|
|||
github.com/glebarez/sqlite v1.11.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.1 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.2 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
|
|
@ -254,7 +255,7 @@ require (
|
|||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/profile v1.7.0 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
|
|
@ -265,6 +266,7 @@ require (
|
|||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
github.com/rubenv/sql-migrate v1.7.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/saferwall/pe v1.5.6 // indirect
|
||||
|
|
@ -314,14 +316,14 @@ require (
|
|||
go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/oauth2 v0.25.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/term v0.29.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
|
|
@ -340,10 +342,10 @@ require (
|
|||
k8s.io/component-base v0.32.2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
modernc.org/libc v1.55.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/sqlite v1.34.5 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.35.0 // indirect
|
||||
oras.land/oras-go v1.2.5 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.18.0 // indirect
|
||||
|
|
|
|||
121
go.sum
121
go.sum
|
|
@ -249,8 +249,8 @@ github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA
|
|||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
|
||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
|
||||
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
||||
|
|
@ -283,12 +283,12 @@ github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 h1:rmZG77uXgE
|
|||
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/grype v0.86.1 h1:HWpzCOCwjKkwkIEEC5lcKI4yl6GhTF3+Z12tXWYtMoI=
|
||||
github.com/anchore/grype v0.86.1/go.mod h1:k3VnXfi+e/OGx1mTUL733gy3fyB4W/AdHP8fSyQML9w=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250117185454-edf36a908b10 h1:zBedM9ZGYbs/61QC4ZOKxtChx5njXKHgHqDeHuUxrTw=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250117185454-edf36a908b10/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 h1:ZyRCmiEjnoGJZ1+Ah0ZZ/mKKqNhGcUZBl0s7PTTDzvY=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=
|
||||
github.com/anchore/stereoscope v0.0.13 h1:9Ivkh7k+vOeG3JHrt44jOg/8UdZrCvMsSjLQ7trHBig=
|
||||
github.com/anchore/stereoscope v0.0.13/go.mod h1:QfhhFc2pezp5aX/dVJ5qnBFpBUv5+KUTphwaQLxMUig=
|
||||
github.com/anchore/syft v1.19.0 h1:cUVVdbOHtYCz+581Aq2hhaEbR1MRowbwXyo+Xw+oW20=
|
||||
github.com/anchore/syft v1.19.0/go.mod h1:QyTWjG0LzowbJVNQj5ZX8UVx17eTkU73Xl7jAf6upE8=
|
||||
github.com/anchore/syft v1.20.0 h1:4nVM/eiqrb2GJCkW+d1xv8M5mxply8vVblpWOvVCgN8=
|
||||
github.com/anchore/syft v1.20.0/go.mod h1:h8U0q+Fk7f1d9ay4oa+gDb//AJYFuQftrBLOuS6llz4=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
|
|
@ -326,12 +326,14 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef h1:TSFnfbbu2oAOuWbeDDTtwXWE6z+PmpgbSsMBeV7l0ww=
|
||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bmatcuk/doublestar/v2 v2.0.4 h1:6I6oUiT/sU27eE2OFcWqBhL1SwjyvQuOssxT4a1yidI=
|
||||
github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw=
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.0 h1:DSXtrypQddoug1459viM9X9D3dp1Z7993fw36I2kNcQ=
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
|
||||
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
|
||||
|
|
@ -366,9 +368,15 @@ github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoC
|
|||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
|
|
@ -439,8 +447,8 @@ github.com/docker/cli v27.5.0+incompatible h1:aMphQkcGtpHixwwhAXJT1rrK/detk2JIvD
|
|||
github.com/docker/cli v27.5.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U=
|
||||
github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.0.0+incompatible h1:Olh0KS820sJ7nPsBKChVhk5pzqcwDR15fumfAd/p9hM=
|
||||
github.com/docker/docker v28.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
|
|
@ -460,8 +468,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
|||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
|
||||
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
|
||||
github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ=
|
||||
github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
|
||||
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
|
||||
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
|
||||
github.com/elliotchance/phpserialize v1.4.0 h1:cAp/9+KSnEbUC8oYCE32n2n84BeW8HOY3HMDI8hG2OY=
|
||||
github.com/elliotchance/phpserialize v1.4.0/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
|
|
@ -502,8 +510,9 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
|||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA=
|
||||
github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=
|
||||
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
|
||||
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
|
||||
|
|
@ -530,8 +539,8 @@ github.com/gkampitakis/ciinfo v0.3.1 h1:lzjbemlGI4Q+XimPg64ss89x8Mf3xihJqy/0Mgag
|
|||
github.com/gkampitakis/ciinfo v0.3.1/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
|
||||
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
|
||||
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
|
||||
github.com/gkampitakis/go-snaps v0.5.8 h1:BB4ihcyXgJEVO/Pj/P+4bs7pFzsLcEjsfU2+mFdJh1c=
|
||||
github.com/gkampitakis/go-snaps v0.5.8/go.mod h1:PcKmy8q5Se7p48ywpogN5Td13reipz1Iivah4wrTIvY=
|
||||
github.com/gkampitakis/go-snaps v0.5.11 h1:LFG0ggUKR+KEiiaOvFCmLgJ5NO2zf93AxxddkBn3LdQ=
|
||||
github.com/gkampitakis/go-snaps v0.5.11/go.mod h1:PcKmy8q5Se7p48ywpogN5Td13reipz1Iivah4wrTIvY=
|
||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||
|
|
@ -546,8 +555,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
|
|||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
|
||||
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
|
||||
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
|
|
@ -584,6 +593,9 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
|||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/goccy/go-yaml v1.15.13 h1:Xd87Yddmr2rC1SLLTm2MNDcTjeO/GYo0JGiww6gSTDg=
|
||||
github.com/goccy/go-yaml v1.15.13/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
|
@ -681,6 +693,7 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
|
|
@ -783,6 +796,7 @@ github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47
|
|||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
|
|
@ -848,12 +862,15 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq
|
|||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
|
||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||
github.com/lmittmann/tint v1.0.7 h1:D/0OqWZ0YOGZ6AyC+5Y2kD8PBEzBk6rFHVSfOqCkF9Y=
|
||||
github.com/lmittmann/tint v1.0.7/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
|
|
@ -993,6 +1010,7 @@ github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaL
|
|||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/openvex/go-vex v0.2.5 h1:41utdp2rHgAGCsG+UbjmfMG5CWQxs15nGqir1eRgSrQ=
|
||||
github.com/openvex/go-vex v0.2.5/go.mod h1:j+oadBxSUELkrKh4NfNb+BPo77U3q7gdKME88IO/0Wo=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 h1:FvA4bwjKpPqik5WsQ8+4z4DKWgA1tO1RTTtNKr5oYNA=
|
||||
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554/go.mod h1:n73K/hcuJ50MiVznXyN4rde6fZY7naGKWBXOLFTyc94=
|
||||
github.com/package-url/packageurl-go v0.1.1 h1:KTRE0bK3sKbFKAk3yy63DpeskU7Cvs/x/Da5l+RtzyU=
|
||||
|
|
@ -1014,8 +1032,8 @@ github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1H
|
|||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
|
|
@ -1085,8 +1103,8 @@ github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
|||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||
github.com/sanity-io/litter v1.5.6 h1:hCFycYzhRnW4niFbbmR7QKdmds69PbVa/sNmEN5euSU=
|
||||
github.com/sanity-io/litter v1.5.6/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
|
||||
github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg=
|
||||
github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ=
|
||||
|
|
@ -1282,8 +1300,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
|
@ -1324,8 +1342,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -1384,8 +1402,8 @@ golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfS
|
|||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
|
@ -1509,6 +1527,7 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
@ -1525,14 +1544,14 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
@ -1918,28 +1937,28 @@ k8s.io/metrics v0.32.2 h1:7t/rZzTHFrGa9f94XcgLlm3ToAuJtdlHANcJEHlYl9g=
|
|||
k8s.io/metrics v0.32.2/go.mod h1:VL3nJpzcgB6L5nSljkkzoE0nilZhVgcjCfNRgoylaIQ=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
|
||||
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
|
||||
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
|
||||
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
|
||||
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
|
||||
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
|
||||
modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
|
||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
|
||||
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
|
||||
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
|
||||
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.35.0 h1:yQps4fegMnZFdphtzlfQTCNBWtS0CZv48pRpW3RFHRw=
|
||||
modernc.org/sqlite v1.35.0/go.mod h1:9cr2sicr7jIaWTBKQmAxQLfBv9LL0su4ZTEV+utt3ic=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo=
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
|
|
@ -34,7 +35,9 @@ const (
|
|||
cacheNSKey = "validNamespaces"
|
||||
)
|
||||
|
||||
var supportedMetricsAPIVersions = []string{"v1beta1"}
|
||||
var (
|
||||
supportedMetricsAPIVersions = []string{"v1beta1"}
|
||||
)
|
||||
|
||||
// NamespaceNames tracks a collection of namespace names.
|
||||
type NamespaceNames map[string]struct{}
|
||||
|
|
@ -50,6 +53,7 @@ type APIClient struct {
|
|||
mx sync.RWMutex
|
||||
cache *cache.LRUExpireCache
|
||||
connOK bool
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
// NewTestAPIClient for testing ONLY!!
|
||||
|
|
@ -62,15 +66,16 @@ func NewTestAPIClient() *APIClient {
|
|||
|
||||
// InitConnection initialize connection from command line args.
|
||||
// Checks for connectivity with the api server.
|
||||
func InitConnection(config *Config) (*APIClient, error) {
|
||||
func InitConnection(config *Config, log *slog.Logger) (*APIClient, error) {
|
||||
a := APIClient{
|
||||
config: config,
|
||||
cache: cache.NewLRUExpireCache(cacheSize),
|
||||
connOK: true,
|
||||
log: log.With(slogs.Subsys, "client"),
|
||||
}
|
||||
err := a.supportsMetricsResources()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Fail to locate metrics-server")
|
||||
slog.Warn("Fail to locate metrics-server", slogs.Error, err)
|
||||
}
|
||||
if err == nil || errors.Is(err, noMetricServerErr) || errors.Is(err, metricsUnsupportedErr) {
|
||||
return &a, nil
|
||||
|
|
@ -113,7 +118,7 @@ func makeCacheKey(ns, gvr, n string, vv []string) string {
|
|||
func (a *APIClient) ActiveContext() string {
|
||||
c, err := a.config.CurrentContextName()
|
||||
if err != nil {
|
||||
log.Error().Msgf("Unable to located active cluster")
|
||||
slog.Error("unable to located active cluster", slogs.Error, err)
|
||||
return ""
|
||||
}
|
||||
return c
|
||||
|
|
@ -158,6 +163,8 @@ func (a *APIClient) CanI(ns, gvr, name string, verbs []string) (auth bool, err e
|
|||
}
|
||||
}
|
||||
|
||||
clog := a.log.With(slogs.Subsys, "can")
|
||||
|
||||
dial, err := a.Dial()
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
@ -169,14 +176,20 @@ func (a *APIClient) CanI(ns, gvr, name string, verbs []string) (auth bool, err e
|
|||
for _, v := range verbs {
|
||||
sar.Spec.ResourceAttributes.Verb = v
|
||||
resp, err := client.Create(ctx, sar, metav1.CreateOptions{})
|
||||
log.Trace().Msgf("[CAN] %s(%q/%q) <%v>", gvr, ns, name, verbs)
|
||||
clog.Debug("[CAN] access",
|
||||
slogs.GVR, gvr,
|
||||
slogs.Namespace, ns,
|
||||
slogs.ResName, name,
|
||||
slogs.Verb, verbs,
|
||||
)
|
||||
if resp != nil {
|
||||
log.Trace().Msgf(" Spec: %#v", resp.Spec)
|
||||
log.Trace().Msgf(" Auth: %t [%q]", resp.Status.Allowed, resp.Status.Reason)
|
||||
clog.Debug("[CAN] reps",
|
||||
slogs.AuthStatus, resp.Status.Allowed,
|
||||
slogs.AuthReason, resp.Status.Reason,
|
||||
)
|
||||
}
|
||||
log.Trace().Msgf(" <<%v>>", err)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf(" Dial Failed!")
|
||||
clog.Warn("Auth request failed", slogs.Error, err)
|
||||
a.cache.Add(key, false, cacheExpiry)
|
||||
return auth, err
|
||||
}
|
||||
|
|
@ -220,7 +233,10 @@ func (a *APIClient) ServerVersion() (*version.Info, error) {
|
|||
func (a *APIClient) IsValidNamespace(ns string) bool {
|
||||
ok, err := a.isValidNamespace(ns)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("namespace validation failed for: %q", ns)
|
||||
slog.Warn("Namespace validation failed",
|
||||
slogs.Namespace, ns,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
|
||||
return ok
|
||||
|
|
@ -287,16 +303,15 @@ func (a *APIClient) CheckConnectivity() bool {
|
|||
}()
|
||||
|
||||
cfg, err := a.config.RESTConfig()
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("restConfig load failed")
|
||||
slog.Error("RestConfig load failed", slogs.Error, err)
|
||||
a.connOK = false
|
||||
return a.connOK
|
||||
}
|
||||
cfg.Timeout = a.config.CallTimeout()
|
||||
client, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to connect to api server")
|
||||
slog.Error("Unable to connect to api server", slogs.Error, err)
|
||||
a.setConnOK(false)
|
||||
return a.getConnOK()
|
||||
}
|
||||
|
|
@ -307,7 +322,7 @@ func (a *APIClient) CheckConnectivity() bool {
|
|||
a.reset()
|
||||
}
|
||||
} else {
|
||||
log.Error().Err(err).Msgf("can't connect to cluster")
|
||||
slog.Error("Unable to fetch server version", slogs.Error, err)
|
||||
a.setConnOK(false)
|
||||
}
|
||||
|
||||
|
|
@ -541,13 +556,13 @@ func (a *APIClient) invalidateCache() error {
|
|||
|
||||
// SwitchContext handles kubeconfig context switches.
|
||||
func (a *APIClient) SwitchContext(name string) error {
|
||||
log.Debug().Msgf("Switching context %q", name)
|
||||
slog.Debug("Switching context", slogs.Context, name)
|
||||
if err := a.config.SwitchContext(name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !a.CheckConnectivity() {
|
||||
log.Debug().Msg("No connectivity, skipping cache invalidation")
|
||||
slog.Debug("No connectivity, skipping cache invalidation")
|
||||
} else if err := a.invalidateCache(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -597,7 +612,7 @@ func (a *APIClient) supportsMetricsResources() error {
|
|||
|
||||
dial, err := a.Dial()
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("Unable to dial discovery API")
|
||||
slog.Warn("Unable to dial API client for metrics", slogs.Error, err)
|
||||
return err
|
||||
}
|
||||
apiGroups, err := dial.Discovery().ServerGroups()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultCallTimeoutDuration time.Duration = 15 * time.Second
|
||||
defaultCallTimeoutDuration time.Duration = 10 * time.Second
|
||||
|
||||
// UsePersistentConfig caches client config to avoid reloads.
|
||||
UsePersistentConfig = true
|
||||
|
|
|
|||
|
|
@ -5,18 +5,18 @@ package client_test
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestCallTimeout(t *testing.T) {
|
||||
|
|
@ -29,7 +29,7 @@ func TestCallTimeout(t *testing.T) {
|
|||
e: 1 * time.Minute,
|
||||
},
|
||||
"default": {
|
||||
e: 15 * time.Second,
|
||||
e: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ package client
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/fvbommel/sortorder"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
|
@ -40,7 +41,7 @@ func NewGVR(gvr string) GVR {
|
|||
case 1:
|
||||
r = tokens[0]
|
||||
default:
|
||||
log.Error().Err(fmt.Errorf("can't parse GVR %q", gvr)).Msg("GVR init failed!")
|
||||
slog.Error("GVR init failed!", slogs.Error, fmt.Errorf("can't parse GVR %q", gvr))
|
||||
}
|
||||
|
||||
return GVR{raw: gvr, g: g, v: v, r: r, sr: sr}
|
||||
|
|
@ -186,7 +187,7 @@ func Can(verbs []string, v string) bool {
|
|||
for _, verb := range verbs {
|
||||
candidates, err := mapVerb(v)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("verb mapping failed")
|
||||
slog.Error("Access verb mapping failed", slogs.Error, err)
|
||||
return false
|
||||
}
|
||||
for _, c := range candidates {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
|
|
@ -81,7 +83,8 @@ func MetaFQN(m metav1.ObjectMeta) string {
|
|||
func mustHomeDir() string {
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Die getting user home directory")
|
||||
slog.Error("Die getting user home directory", slogs.Error, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return usr.HomeDir
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ package config
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/config/json"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ func (a *Aliases) Load(path string) error {
|
|||
|
||||
f, err := EnsureAliasesCfgFile()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to gen config aliases")
|
||||
slog.Error("Unable to gen config aliases", slogs.Error, err)
|
||||
}
|
||||
|
||||
// load global alias file
|
||||
|
|
@ -146,7 +146,7 @@ func (a *Aliases) LoadFile(path string) error {
|
|||
return err
|
||||
}
|
||||
if err := data.JSONValidator.Validate(json.AliasesSchema, bb); err != nil {
|
||||
return fmt.Errorf("validation failed for %q: %w", path, err)
|
||||
slog.Warn("Aliases validation failed", slogs.Error, err)
|
||||
}
|
||||
|
||||
var aa Aliases
|
||||
|
|
@ -193,7 +193,7 @@ func (a *Aliases) loadDefaultAliases() {
|
|||
|
||||
// Save alias to disk.
|
||||
func (a *Aliases) Save() error {
|
||||
log.Debug().Msg("[Config] Saving Aliases...")
|
||||
slog.Debug("Saving Aliases...")
|
||||
return a.SaveAliases(AppAliasesFile)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/config/json"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/view/cmd"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v2"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
|
@ -33,6 +34,16 @@ func NewConfig(ks data.KubeSettings) *Config {
|
|||
}
|
||||
}
|
||||
|
||||
// ActiveClusterName returns the corresponding cluster name.
|
||||
func (c *Config) ActiveClusterName(contextName string) (string, error) {
|
||||
ct, err := c.settings.GetContext(contextName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ct.Cluster, nil
|
||||
}
|
||||
|
||||
// ContextHotkeysPath returns a context specific hotkeys file spec.
|
||||
func (c *Config) ContextHotkeysPath() string {
|
||||
ct, err := c.K9s.ActiveContext()
|
||||
|
|
@ -82,7 +93,7 @@ func (c *Config) Refine(flags *genericclioptions.ConfigFlags, k9sFlags *Flags, c
|
|||
return fmt.Errorf("unable to activate context %q: %w", n, err)
|
||||
}
|
||||
}
|
||||
log.Debug().Msgf("Active Context %q", c.K9s.ActiveContextName())
|
||||
slog.Debug("Using active context", slogs.Context, c.K9s.ActiveContextName())
|
||||
|
||||
var ns string
|
||||
switch {
|
||||
|
|
@ -113,7 +124,7 @@ func (c *Config) Reset() {
|
|||
c.K9s.Reset()
|
||||
}
|
||||
|
||||
func (c *Config) SetCurrentContext(n string) (*data.Context, error) {
|
||||
func (c *Config) ActivateContext(n string) (*data.Context, error) {
|
||||
ct, err := c.K9s.ActivateContext(n)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("set current context failed. %w", err)
|
||||
|
|
@ -132,7 +143,7 @@ func (c *Config) CurrentContext() (*data.Context, error) {
|
|||
func (c *Config) ActiveNamespace() string {
|
||||
ns, err := c.K9s.ActiveContextNamespace()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to assert active namespace. Using default")
|
||||
slog.Error("Unable to assert active namespace. Using default", slogs.Error, err)
|
||||
ns = client.DefaultNamespace
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +156,7 @@ func (c *Config) FavNamespaces() []string {
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
ct.Validate(c.conn, c.settings)
|
||||
ct.Validate(c.conn, c.K9s.getActiveContextName(), ct.ClusterName)
|
||||
|
||||
return ct.Namespace.Favorites
|
||||
}
|
||||
|
|
@ -153,7 +164,7 @@ func (c *Config) FavNamespaces() []string {
|
|||
// SetActiveNamespace set the active namespace in the current context.
|
||||
func (c *Config) SetActiveNamespace(ns string) error {
|
||||
if ns == client.NotNamespaced {
|
||||
log.Debug().Msgf("[SetNS] No namespace given. skipping!")
|
||||
slog.Debug("No namespace given. skipping!", slogs.Namespace, ns)
|
||||
return nil
|
||||
}
|
||||
ct, err := c.K9s.ActiveContext()
|
||||
|
|
@ -251,8 +262,13 @@ func (c *Config) Load(path string, force bool) error {
|
|||
|
||||
// Save configuration to disk.
|
||||
func (c *Config) Save(force bool) error {
|
||||
c.Validate()
|
||||
if err := c.K9s.Save(force); err != nil {
|
||||
contextName := c.K9s.ActiveContextName()
|
||||
clusterName, err := c.ActiveClusterName(contextName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to locate associated cluster for context %q: %w", contextName, err)
|
||||
}
|
||||
c.Validate(contextName, clusterName)
|
||||
if err := c.K9s.Save(contextName, clusterName, force); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(AppConfigFile); errors.Is(err, fs.ErrNotExist) {
|
||||
|
|
@ -267,21 +283,23 @@ func (c *Config) SaveFile(path string) error {
|
|||
if err := data.EnsureDirPath(path, data.DefaultDirMod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg, err := yaml.Marshal(c)
|
||||
if err != nil {
|
||||
log.Error().Msgf("[Config] Unable to save K9s config file: %v", err)
|
||||
slog.Error("Unable to save K9s config file", slogs.Error, err)
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("[CONFIG] Saving K9s config to disk", slogs.Path, path)
|
||||
return os.WriteFile(path, cfg, data.DefaultFileMod)
|
||||
}
|
||||
|
||||
// Validate the configuration.
|
||||
func (c *Config) Validate() {
|
||||
func (c *Config) Validate(contextName, clusterName string) {
|
||||
if c.K9s == nil {
|
||||
c.K9s = NewK9s(c.conn, c.settings)
|
||||
}
|
||||
c.K9s.Validate(c.conn, c.settings)
|
||||
c.K9s.Validate(c.conn, contextName, clusterName)
|
||||
}
|
||||
|
||||
// Dump for debug...
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package config_test
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
|
@ -16,13 +17,12 @@ import (
|
|||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/config/mock"
|
||||
m "github.com/petergtz/pegomock"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestConfigSave(t *testing.T) {
|
||||
|
|
@ -324,7 +324,7 @@ Invalid type. Expected: boolean, given: string`,
|
|||
}
|
||||
}
|
||||
|
||||
func TestConfigSetCurrentContext(t *testing.T) {
|
||||
func TestConfigActivateContext(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
cl, ct string
|
||||
err string
|
||||
|
|
@ -344,7 +344,7 @@ func TestConfigSetCurrentContext(t *testing.T) {
|
|||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
cfg := mock.NewMockConfig()
|
||||
ct, err := cfg.SetCurrentContext(u.ct)
|
||||
ct, err := cfg.ActivateContext(u.ct)
|
||||
if err != nil {
|
||||
assert.Equal(t, u.err, err.Error())
|
||||
return
|
||||
|
|
@ -529,7 +529,7 @@ func TestConfigValidate(t *testing.T) {
|
|||
cfg.SetConnection(mock.NewMockConnection())
|
||||
|
||||
assert.Nil(t, cfg.Load("testdata/configs/k9s.yaml", true))
|
||||
cfg.Validate()
|
||||
cfg.Validate("ct-1-1", "cl-1")
|
||||
}
|
||||
|
||||
func TestConfigLoad(t *testing.T) {
|
||||
|
|
@ -556,7 +556,7 @@ func TestConfigSaveFile(t *testing.T) {
|
|||
cfg.K9s.ReadOnly = true
|
||||
cfg.K9s.Logger.TailCount = 500
|
||||
cfg.K9s.Logger.BufferSize = 800
|
||||
cfg.Validate()
|
||||
cfg.Validate("ct-1-1", "cl-1")
|
||||
|
||||
path := filepath.Join("/tmp", "k9s.yaml")
|
||||
assert.NoError(t, cfg.SaveFile(path))
|
||||
|
|
@ -571,7 +571,7 @@ func TestConfigReset(t *testing.T) {
|
|||
cfg := mock.NewMockConfig()
|
||||
assert.Nil(t, cfg.Load("testdata/configs/k9s.yaml", true))
|
||||
cfg.Reset()
|
||||
cfg.Validate()
|
||||
cfg.Validate("ct-1-1", "cl-1")
|
||||
|
||||
path := filepath.Join("/tmp", "k9s.yaml")
|
||||
assert.NoError(t, cfg.SaveFile(path))
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ func NewConfig(ct *api.Context) *Config {
|
|||
}
|
||||
}
|
||||
|
||||
// Merge merges configs and updates receiver.
|
||||
func (c *Config) Merge(c1 *Config) {
|
||||
if c1 == nil {
|
||||
return
|
||||
|
|
@ -36,14 +37,14 @@ func (c *Config) Merge(c1 *Config) {
|
|||
}
|
||||
|
||||
// Validate ensures config is in norms.
|
||||
func (c *Config) Validate(conn client.Connection, ks KubeSettings) {
|
||||
func (c *Config) Validate(conn client.Connection, contextName, clusterName string) {
|
||||
c.mx.Lock()
|
||||
defer c.mx.Unlock()
|
||||
|
||||
if c.Context == nil {
|
||||
c.Context = NewContext()
|
||||
}
|
||||
c.Context.Validate(conn, ks)
|
||||
c.Context.Validate(conn, contextName, clusterName)
|
||||
}
|
||||
|
||||
// Dump used for debugging.
|
||||
|
|
|
|||
|
|
@ -13,24 +13,22 @@ import (
|
|||
|
||||
// Context tracks K9s context configuration.
|
||||
type Context struct {
|
||||
ClusterName string `yaml:"cluster,omitempty"`
|
||||
ReadOnly *bool `yaml:"readOnly,omitempty"`
|
||||
Skin string `yaml:"skin,omitempty"`
|
||||
Namespace *Namespace `yaml:"namespace"`
|
||||
View *View `yaml:"view"`
|
||||
FeatureGates FeatureGates `yaml:"featureGates"`
|
||||
PortForwardAddress string `yaml:"portForwardAddress"`
|
||||
Proxy *Proxy `yaml:"proxy"`
|
||||
mx sync.RWMutex
|
||||
ClusterName string `yaml:"cluster,omitempty"`
|
||||
ReadOnly *bool `yaml:"readOnly,omitempty"`
|
||||
Skin string `yaml:"skin,omitempty"`
|
||||
Namespace *Namespace `yaml:"namespace"`
|
||||
View *View `yaml:"view"`
|
||||
FeatureGates FeatureGates `yaml:"featureGates"`
|
||||
Proxy *Proxy `yaml:"proxy"`
|
||||
mx sync.RWMutex
|
||||
}
|
||||
|
||||
// NewContext creates a new cluster configuration.
|
||||
func NewContext() *Context {
|
||||
return &Context{
|
||||
Namespace: NewNamespace(),
|
||||
View: NewView(),
|
||||
PortForwardAddress: defaultPFAddress(),
|
||||
FeatureGates: NewFeatureGates(),
|
||||
Namespace: NewNamespace(),
|
||||
View: NewView(),
|
||||
FeatureGates: NewFeatureGates(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,19 +69,11 @@ func (c *Context) GetClusterName() string {
|
|||
}
|
||||
|
||||
// Validate ensures a context config is tip top.
|
||||
func (c *Context) Validate(conn client.Connection, ks KubeSettings) {
|
||||
func (c *Context) Validate(conn client.Connection, contextName, clusterName string) {
|
||||
c.mx.Lock()
|
||||
defer c.mx.Unlock()
|
||||
|
||||
if a := os.Getenv(envPFAddress); a != "" {
|
||||
c.PortForwardAddress = a
|
||||
}
|
||||
if c.PortForwardAddress == "" {
|
||||
c.PortForwardAddress = defaultPFAddress()
|
||||
}
|
||||
if cl, err := ks.CurrentClusterName(); err == nil {
|
||||
c.ClusterName = cl
|
||||
}
|
||||
c.ClusterName = clusterName
|
||||
if b := os.Getenv(envFGNodeShell); b != "" {
|
||||
c.FeatureGates.NodeShell = defaultFGNodeShell()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
func TestClusterValidate(t *testing.T) {
|
||||
c := data.NewContext()
|
||||
c.Validate(mock.NewMockConnection(), mock.NewMockKubeSettings(makeFlags("cl-1", "ct-1")))
|
||||
c.Validate(mock.NewMockConnection(), "ct-1", "cl-1")
|
||||
|
||||
assert.Equal(t, "po", c.View.Active)
|
||||
assert.Equal(t, "default", c.Namespace.Active)
|
||||
|
|
@ -23,7 +23,7 @@ func TestClusterValidate(t *testing.T) {
|
|||
|
||||
func TestClusterValidateEmpty(t *testing.T) {
|
||||
c := data.NewContext()
|
||||
c.Validate(mock.NewMockConnection(), mock.NewMockKubeSettings(makeFlags("cl-1", "ct-1")))
|
||||
c.Validate(mock.NewMockConnection(), "ct-1", "cl-1")
|
||||
|
||||
assert.Equal(t, "po", c.View.Active)
|
||||
assert.Equal(t, "default", c.Namespace.Active)
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/json"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"gopkg.in/yaml.v2"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
|
@ -31,18 +32,19 @@ func NewDir(root string) *Dir {
|
|||
}
|
||||
|
||||
// Load loads context configuration.
|
||||
func (d *Dir) Load(n string, ct *api.Context) (*Config, error) {
|
||||
func (d *Dir) Load(contextName string, ct *api.Context) (*Config, error) {
|
||||
if ct == nil {
|
||||
return nil, errors.New("api.Context must not be nil")
|
||||
}
|
||||
var path = filepath.Join(d.root, SanitizeContextSubpath(ct.Cluster, n), MainConfigFile)
|
||||
|
||||
path := filepath.Join(d.root, SanitizeContextSubpath(ct.Cluster, contextName), MainConfigFile)
|
||||
slog.Debug("[CONFIG] Loading context config from disk", slogs.Path, path, slogs.Cluster, ct.Cluster, slogs.Context, contextName)
|
||||
f, err := os.Stat(path)
|
||||
if errors.Is(err, fs.ErrPermission) {
|
||||
return nil, err
|
||||
}
|
||||
if errors.Is(err, fs.ErrNotExist) || (f != nil && f.Size() == 0) {
|
||||
log.Debug().Msgf("Context config not found! Generating... %q", path)
|
||||
slog.Debug("Context config not found! Generating..", slogs.Path, path)
|
||||
return d.genConfig(path, ct)
|
||||
}
|
||||
if err != nil {
|
||||
|
|
@ -89,7 +91,10 @@ func (d *Dir) loadConfig(path string) (*Config, error) {
|
|||
return nil, err
|
||||
}
|
||||
if err := JSONValidator.Validate(json.ContextSchema, bb); err != nil {
|
||||
return nil, fmt.Errorf("validation failed for %q: %w", path, err)
|
||||
slog.Warn("Validation failed. Please update your config and restart!",
|
||||
slogs.Path, path,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
|
|
|
|||
|
|
@ -4,20 +4,20 @@
|
|||
package data_test
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/config/mock"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestDirLoad(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -11,11 +11,7 @@ import (
|
|||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
envPFAddress = "K9S_DEFAULT_PF_ADDRESS"
|
||||
envFGNodeShell = "K9S_FEATURE_GATE_NODE_SHELL"
|
||||
defaultPortFwdAddress = "localhost"
|
||||
)
|
||||
const envFGNodeShell = "K9S_FEATURE_GATE_NODE_SHELL"
|
||||
|
||||
var invalidPathCharsRX = regexp.MustCompile(`[:/]+`)
|
||||
|
||||
|
|
@ -29,14 +25,6 @@ func SanitizeFileName(name string) string {
|
|||
return invalidPathCharsRX.ReplaceAllString(name, "-")
|
||||
}
|
||||
|
||||
func defaultPFAddress() string {
|
||||
if a := os.Getenv(envPFAddress); a != "" {
|
||||
return a
|
||||
}
|
||||
|
||||
return defaultPortFwdAddress
|
||||
}
|
||||
|
||||
func defaultFGNodeShell() bool {
|
||||
if a := os.Getenv(envFGNodeShell); a != "" {
|
||||
return a == "true"
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -67,7 +68,10 @@ func (n *Namespace) Validate(c client.Connection) {
|
|||
}
|
||||
for _, ns := range n.Favorites {
|
||||
if !c.IsValidNamespace(ns) {
|
||||
log.Debug().Msgf("[Namespace] Invalid favorite found '%s' - %t", ns, n.isAllNamespaces())
|
||||
slog.Debug("Invalid favorite found",
|
||||
slogs.Namespace, ns,
|
||||
slogs.AllNS, n.isAllNamespaces(),
|
||||
)
|
||||
n.rmFavNS(ns)
|
||||
}
|
||||
}
|
||||
|
|
@ -136,7 +140,7 @@ func (n *Namespace) rmFavNS(ns string) {
|
|||
|
||||
func (n *Namespace) trimFavNs() {
|
||||
if len(n.Favorites) > MaxFavoritesNS {
|
||||
log.Debug().Msgf("[Namespace] Number of favorite exceeds hard limit of %v. Trimming.", MaxFavoritesNS)
|
||||
slog.Debug("Number of favorite exceeds hard limit. Trimming.", slogs.Max, MaxFavoritesNS)
|
||||
n.Favorites = n.Favorites[:MaxFavoritesNS]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,4 +9,3 @@ k9s:
|
|||
active: po
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -13,4 +13,3 @@ k9s:
|
|||
active: dp
|
||||
featureGates:
|
||||
nodeShell: true
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -11,4 +11,3 @@ k9s:
|
|||
active: po
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ k9s:
|
|||
active: svc
|
||||
featureGates:
|
||||
nodeShell: true
|
||||
portForwardAddress: fred
|
||||
|
|
|
|||
|
|
@ -9,4 +9,3 @@ k9s:
|
|||
active: po
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -13,4 +13,3 @@ k9s:
|
|||
active: dp
|
||||
featureGates:
|
||||
nodeShell: true
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -11,4 +11,3 @@ k9s:
|
|||
active: po
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ k9s:
|
|||
active: svc
|
||||
featureGates:
|
||||
nodeShell: true
|
||||
portForwardAddress: fred
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import (
|
|||
_ "embed"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -126,19 +127,31 @@ func initK9sEnvLocs() error {
|
|||
|
||||
AppDumpsDir = filepath.Join(AppConfigDir, "screen-dumps")
|
||||
if err := data.EnsureFullPath(AppDumpsDir, data.DefaultDirMod); err != nil {
|
||||
log.Warn().Err(err).Msgf("Unable to create screen-dumps dir: %s", AppDumpsDir)
|
||||
slog.Warn("Unable to create screen-dumps dir",
|
||||
slogs.Dir, AppDumpsDir,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
AppBenchmarksDir = filepath.Join(AppConfigDir, "benchmarks")
|
||||
if err := data.EnsureFullPath(AppBenchmarksDir, data.DefaultDirMod); err != nil {
|
||||
log.Warn().Err(err).Msgf("Unable to create benchmarks dir: %s", AppBenchmarksDir)
|
||||
slog.Warn("Unable to create benchmarks dir",
|
||||
slogs.Dir, AppBenchmarksDir,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
AppSkinsDir = filepath.Join(AppConfigDir, "skins")
|
||||
if err := data.EnsureFullPath(AppSkinsDir, data.DefaultDirMod); err != nil {
|
||||
log.Warn().Err(err).Msgf("Unable to create skins dir: %s", AppSkinsDir)
|
||||
slog.Warn("Unable to create skins dir",
|
||||
slogs.Dir, AppSkinsDir,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
AppContextsDir = filepath.Join(AppConfigDir, "clusters")
|
||||
if err := data.EnsureFullPath(AppContextsDir, data.DefaultDirMod); err != nil {
|
||||
log.Warn().Err(err).Msgf("Unable to create clusters dir: %s", AppContextsDir)
|
||||
slog.Warn("Unable to create clusters dir",
|
||||
slogs.Dir, AppContextsDir,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
|
||||
AppConfigFile = filepath.Join(AppConfigDir, data.MainConfigFile)
|
||||
|
|
@ -170,7 +183,7 @@ func initXDGLocs() error {
|
|||
|
||||
AppSkinsDir = filepath.Join(AppConfigDir, "skins")
|
||||
if err := data.EnsureFullPath(AppSkinsDir, data.DefaultDirMod); err != nil {
|
||||
log.Warn().Err(err).Msgf("No skins dir detected")
|
||||
slog.Warn("No skins dir detected", slogs.Error, err)
|
||||
}
|
||||
|
||||
AppDumpsDir, err = xdg.StateFile(filepath.Join(AppName, "screen-dumps"))
|
||||
|
|
@ -180,7 +193,10 @@ func initXDGLocs() error {
|
|||
|
||||
AppBenchmarksDir, err = xdg.StateFile(filepath.Join(AppName, "benchmarks"))
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("No benchmarks dir detected")
|
||||
slog.Warn("No benchmarks dir detected",
|
||||
slogs.Dir, AppBenchmarksDir,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
|
||||
dataDir, err := xdg.DataFile(AppName)
|
||||
|
|
@ -189,7 +205,10 @@ func initXDGLocs() error {
|
|||
}
|
||||
AppContextsDir = filepath.Join(dataDir, "clusters")
|
||||
if err := data.EnsureFullPath(AppContextsDir, data.DefaultDirMod); err != nil {
|
||||
log.Warn().Err(err).Msgf("No context dir detected")
|
||||
slog.Warn("No context dir detected",
|
||||
slogs.Dir, AppContextsDir,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -4,11 +4,17 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
const (
|
||||
envPFAddress = "K9S_DEFAULT_PF_ADDRESS"
|
||||
defaultPortFwdAddress = "localhost"
|
||||
)
|
||||
|
||||
// IsBoolSet checks if a bool ptr is set.
|
||||
|
|
@ -54,7 +60,16 @@ func MustK9sUser() string {
|
|||
if envUsr != "" {
|
||||
return envUsr
|
||||
}
|
||||
log.Fatal().Err(err).Msg("Die on retrieving user info")
|
||||
slog.Error("Die on retrieving user info", slogs.Error, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return usr.Username
|
||||
}
|
||||
|
||||
func defaultPFAddress() string {
|
||||
if a := os.Getenv(envPFAddress); a != "" {
|
||||
return a
|
||||
}
|
||||
|
||||
return defaultPortFwdAddress
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ package config
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/config/json"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
|
|
@ -57,7 +58,10 @@ func (h HotKeys) LoadHotKeys(path string) error {
|
|||
return err
|
||||
}
|
||||
if err := data.JSONValidator.Validate(json.HotkeysSchema, bb); err != nil {
|
||||
return fmt.Errorf("validation failed for %q: %w", path, err)
|
||||
slog.Warn("Validation failed. Please update your config and restart.",
|
||||
slogs.Path, path,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
|
||||
var hh HotKeys
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
"cluster": { "type": "string" },
|
||||
"readOnly": {"type": "boolean"},
|
||||
"skin": { "type": "string" },
|
||||
"portForwardAddress": { "type": "string" },
|
||||
"proxy": {
|
||||
"oneOf": [
|
||||
{ "type": "null" },
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"noExitOnCtrlC": { "type": "boolean" },
|
||||
"skipLatestRevCheck": { "type": "boolean" },
|
||||
"disablePodCounting": { "type": "boolean" },
|
||||
"portForwardAddress": { "type": "string" },
|
||||
"ui": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ k9s:
|
|||
active: pod
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -13,4 +13,3 @@ k9s:
|
|||
fred: blee
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
portForwardAddress: localhost
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ import (
|
|||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
|
@ -89,9 +90,15 @@ func NewValidator() *Validator {
|
|||
func (v *Validator) register() {
|
||||
v.loader = gojsonschema.NewSchemaLoader()
|
||||
v.loader.Validate = true
|
||||
|
||||
clog := slog.With(slogs.Subsys, "schema")
|
||||
|
||||
for k, s := range v.schemas {
|
||||
if err := v.loader.AddSchema(k, s); err != nil {
|
||||
log.Error().Err(err).Msgf("schema initialization failed: %q", k)
|
||||
clog.Error("Schema initialization failed",
|
||||
slogs.SchemaFile, k,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
// K9s tracks K9s configuration options.
|
||||
|
|
@ -26,6 +27,7 @@ type K9s struct {
|
|||
MaxConnRetry int `json:"maxConnRetry" yaml:"maxConnRetry"`
|
||||
ReadOnly bool `json:"readOnly" yaml:"readOnly"`
|
||||
NoExitOnCtrlC bool `json:"noExitOnCtrlC" yaml:"noExitOnCtrlC"`
|
||||
PortForwardAddress string `yaml:"portForwardAddress"`
|
||||
UI UI `json:"ui" yaml:"ui"`
|
||||
SkipLatestRevCheck bool `json:"skipLatestRevCheck" yaml:"skipLatestRevCheck"`
|
||||
DisablePodCounting bool `json:"disablePodCounting" yaml:"disablePodCounting"`
|
||||
|
|
@ -46,24 +48,40 @@ type K9s struct {
|
|||
conn client.Connection
|
||||
ks data.KubeSettings
|
||||
mx sync.RWMutex
|
||||
contextSwitch bool
|
||||
}
|
||||
|
||||
// NewK9s create a new K9s configuration.
|
||||
func NewK9s(conn client.Connection, ks data.KubeSettings) *K9s {
|
||||
return &K9s{
|
||||
RefreshRate: defaultRefreshRate,
|
||||
MaxConnRetry: defaultMaxConnRetry,
|
||||
ScreenDumpDir: AppDumpsDir,
|
||||
Logger: NewLogger(),
|
||||
Thresholds: NewThreshold(),
|
||||
ShellPod: NewShellPod(),
|
||||
ImageScans: NewImageScans(),
|
||||
dir: data.NewDir(AppContextsDir),
|
||||
conn: conn,
|
||||
ks: ks,
|
||||
RefreshRate: defaultRefreshRate,
|
||||
MaxConnRetry: defaultMaxConnRetry,
|
||||
ScreenDumpDir: AppDumpsDir,
|
||||
Logger: NewLogger(),
|
||||
Thresholds: NewThreshold(),
|
||||
PortForwardAddress: defaultPFAddress(),
|
||||
ShellPod: NewShellPod(),
|
||||
ImageScans: NewImageScans(),
|
||||
dir: data.NewDir(AppContextsDir),
|
||||
conn: conn,
|
||||
ks: ks,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *K9s) ToggleContextSwitch(b bool) {
|
||||
k.mx.Lock()
|
||||
defer k.mx.Unlock()
|
||||
|
||||
k.contextSwitch = b
|
||||
}
|
||||
|
||||
func (k *K9s) getContextSwitch() bool {
|
||||
k.mx.Lock()
|
||||
defer k.mx.Unlock()
|
||||
|
||||
return k.contextSwitch
|
||||
}
|
||||
|
||||
func (k *K9s) resetConnection(conn client.Connection) {
|
||||
k.mx.Lock()
|
||||
defer k.mx.Unlock()
|
||||
|
|
@ -72,17 +90,15 @@ func (k *K9s) resetConnection(conn client.Connection) {
|
|||
}
|
||||
|
||||
// Save saves the k9s config to disk.
|
||||
func (k *K9s) Save(force bool) error {
|
||||
if k.getActiveConfig() == nil {
|
||||
log.Warn().Msgf("Save failed. no active config detected")
|
||||
return nil
|
||||
}
|
||||
func (k *K9s) Save(contextName, clusterName string, force bool) error {
|
||||
path := filepath.Join(
|
||||
AppContextsDir,
|
||||
data.SanitizeContextSubpath(k.activeConfig.Context.GetClusterName(), k.getActiveContextName()),
|
||||
data.SanitizeContextSubpath(clusterName, contextName),
|
||||
data.MainConfigFile,
|
||||
)
|
||||
|
||||
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) || force {
|
||||
slog.Debug("[CONFIG] Saving context config to disk", slogs.Path, path, slogs.Cluster, k.getActiveConfig().Context.GetClusterName(), slogs.Context, k.getActiveContextName())
|
||||
return k.dir.Save(path, k.getActiveConfig())
|
||||
}
|
||||
|
||||
|
|
@ -168,12 +184,9 @@ func (k *K9s) ActiveContext() (*data.Context, error) {
|
|||
if cfg := k.getActiveConfig(); cfg != nil && cfg.Context != nil {
|
||||
return cfg.Context, nil
|
||||
}
|
||||
ct, err := k.ActivateContext(k.getActiveContextName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ct, err := k.ActivateContext(k.ActiveContextName())
|
||||
|
||||
return ct, nil
|
||||
return ct, err
|
||||
}
|
||||
|
||||
func (k *K9s) setActiveConfig(c *data.Config) {
|
||||
|
|
@ -205,14 +218,14 @@ func (k *K9s) getActiveContextName() string {
|
|||
}
|
||||
|
||||
// ActivateContext initializes the active context if not present.
|
||||
func (k *K9s) ActivateContext(n string) (*data.Context, error) {
|
||||
k.setActiveContextName(n)
|
||||
ct, err := k.ks.GetContext(n)
|
||||
func (k *K9s) ActivateContext(contextName string) (*data.Context, error) {
|
||||
k.setActiveContextName(contextName)
|
||||
ct, err := k.ks.GetContext(contextName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg, err := k.dir.Load(n, ct)
|
||||
cfg, err := k.dir.Load(contextName, ct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -220,7 +233,7 @@ func (k *K9s) ActivateContext(n string) (*data.Context, error) {
|
|||
|
||||
if cfg.Context.Proxy != nil {
|
||||
k.ks.SetProxy(func(*http.Request) (*url.URL, error) {
|
||||
log.Debug().Msgf("[Proxy]: %s", cfg.Context.Proxy.Address)
|
||||
slog.Debug("Using proxy address", slogs.Address, cfg.Context.Proxy.Address)
|
||||
return url.Parse(cfg.Context.Proxy.Address)
|
||||
})
|
||||
|
||||
|
|
@ -229,25 +242,25 @@ func (k *K9s) ActivateContext(n string) (*data.Context, error) {
|
|||
// already has an API connection object so we just set the proxy to
|
||||
// avoid recreation using client.InitConnection
|
||||
k.conn.Config().SetProxy(func(*http.Request) (*url.URL, error) {
|
||||
log.Debug().Msgf("[Proxy]: %s", cfg.Context.Proxy.Address)
|
||||
slog.Debug("Setting proxy address", slogs.Address, cfg.Context.Proxy.Address)
|
||||
return url.Parse(cfg.Context.Proxy.Address)
|
||||
})
|
||||
|
||||
if !k.conn.CheckConnectivity() {
|
||||
return nil, fmt.Errorf("unable to connect to context %q", n)
|
||||
return nil, fmt.Errorf("unable to connect to context %q", contextName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k.Validate(k.conn, k.ks)
|
||||
k.Validate(k.conn, contextName, ct.Cluster)
|
||||
// If the context specifies a namespace, use it!
|
||||
if ns := ct.Namespace; ns != client.BlankNamespace {
|
||||
k.getActiveConfig().Context.Namespace.Active = ns
|
||||
} else if k.activeConfig.Context.Namespace.Active == "" {
|
||||
} else if k.getActiveConfig().Context.Namespace.Active == "" {
|
||||
k.getActiveConfig().Context.Namespace.Active = client.DefaultNamespace
|
||||
}
|
||||
if k.getActiveConfig().Context == nil {
|
||||
return nil, fmt.Errorf("context activation failed for: %s", n)
|
||||
return nil, fmt.Errorf("context activation failed for: %s", contextName)
|
||||
}
|
||||
|
||||
return k.getActiveConfig().Context, nil
|
||||
|
|
@ -255,6 +268,10 @@ func (k *K9s) ActivateContext(n string) (*data.Context, error) {
|
|||
|
||||
// Reload reloads the context config from disk.
|
||||
func (k *K9s) Reload() error {
|
||||
// Switching context skipping reload...
|
||||
if k.getContextSwitch() {
|
||||
return nil
|
||||
}
|
||||
ct, err := k.ks.GetContext(k.getActiveContextName())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -265,7 +282,7 @@ func (k *K9s) Reload() error {
|
|||
return err
|
||||
}
|
||||
k.setActiveConfig(cfg)
|
||||
k.getActiveConfig().Validate(k.conn, k.ks)
|
||||
k.getActiveConfig().Validate(k.conn, k.getActiveContextName(), ct.Cluster)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -340,7 +357,7 @@ func (k *K9s) IsReadOnly() bool {
|
|||
}
|
||||
|
||||
// Validate the current configuration.
|
||||
func (k *K9s) Validate(c client.Connection, ks data.KubeSettings) {
|
||||
func (k *K9s) Validate(c client.Connection, contextName, clusterName string) {
|
||||
if k.RefreshRate <= 0 {
|
||||
k.RefreshRate = defaultRefreshRate
|
||||
}
|
||||
|
|
@ -348,16 +365,21 @@ func (k *K9s) Validate(c client.Connection, ks data.KubeSettings) {
|
|||
k.MaxConnRetry = defaultMaxConnRetry
|
||||
}
|
||||
|
||||
if a := os.Getenv(envPFAddress); a != "" {
|
||||
k.PortForwardAddress = a
|
||||
}
|
||||
if k.PortForwardAddress == "" {
|
||||
k.PortForwardAddress = defaultPFAddress()
|
||||
}
|
||||
|
||||
if k.getActiveConfig() == nil {
|
||||
if n, err := ks.CurrentContextName(); err == nil {
|
||||
_, _ = k.ActivateContext(n)
|
||||
}
|
||||
_, _ = k.ActivateContext(contextName)
|
||||
}
|
||||
k.ShellPod = k.ShellPod.Validate()
|
||||
k.Logger = k.Logger.Validate()
|
||||
k.Thresholds = k.Thresholds.Validate()
|
||||
|
||||
if cfg := k.getActiveConfig(); cfg != nil {
|
||||
cfg.Validate(c, ks)
|
||||
cfg.Validate(c, contextName, clusterName)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ func EnsureDir(d string) error {
|
|||
}
|
||||
|
||||
func NewMockConfig() *config.Config {
|
||||
if _, err := os.Stat("/tmp/test"); errors.Is(err, os.ErrExist) {
|
||||
os.RemoveAll("/tmp/test")
|
||||
}
|
||||
config.AppContextsDir = "/tmp/test"
|
||||
cl, ct := "cl-1", "ct-1-1"
|
||||
flags := genericclioptions.ConfigFlags{
|
||||
|
|
|
|||
|
|
@ -7,14 +7,15 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/config/json"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
|
|
@ -113,7 +114,10 @@ func (p *Plugins) load(path string) error {
|
|||
return err
|
||||
}
|
||||
if err := data.JSONValidator.Validate(json.PluginsSchema, bb); err != nil {
|
||||
return fmt.Errorf("validation failed for %q: %w", path, err)
|
||||
slog.Warn("Validation failed. Please update your config and restart!",
|
||||
slogs.Path, path,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
var pp Plugins
|
||||
if err := yaml.Unmarshal(bb, &pp); err != nil {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ k9s:
|
|||
maxConnRetry: 5
|
||||
readOnly: false
|
||||
noExitOnCtrlC: false
|
||||
portForwardAddress: localhost
|
||||
ui:
|
||||
enableMouse: false
|
||||
headless: false
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ k9s:
|
|||
maxConnRetry: 5
|
||||
readOnly: true
|
||||
noExitOnCtrlC: false
|
||||
portForwardAddress: localhost
|
||||
ui:
|
||||
enableMouse: false
|
||||
headless: false
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ k9s:
|
|||
maxConnRetry: 5
|
||||
readOnly: false
|
||||
noExitOnCtrlC: false
|
||||
portForwardAddress: localhost
|
||||
ui:
|
||||
enableMouse: false
|
||||
headless: false
|
||||
|
|
|
|||
|
|
@ -5,3 +5,15 @@ views:
|
|||
- NAME
|
||||
- AGE
|
||||
- IP
|
||||
|
||||
v1/pods@default:
|
||||
columns:
|
||||
- NAME
|
||||
- IP
|
||||
- AGE
|
||||
|
||||
v1/pods@ns*:
|
||||
columns:
|
||||
- AGE
|
||||
- NAME
|
||||
- IP
|
||||
|
|
|
|||
|
|
@ -8,13 +8,16 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/config/json"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
|
|
@ -22,6 +25,9 @@ import (
|
|||
type ViewConfigListener interface {
|
||||
// ViewSettingsChanged notifies listener the view configuration changed.
|
||||
ViewSettingsChanged(*ViewSetting)
|
||||
|
||||
// GetNamespace return the view namespace
|
||||
GetNamespace() string
|
||||
}
|
||||
|
||||
// ViewSetting represents a view configuration.
|
||||
|
|
@ -50,13 +56,19 @@ func (v *ViewSetting) SortCol() (string, bool, error) {
|
|||
return tt[0], tt[1] == "asc", nil
|
||||
}
|
||||
|
||||
// Equals checks if two view settings are equal.
|
||||
func (v *ViewSetting) Equals(vs *ViewSetting) bool {
|
||||
if v == nil && vs == nil {
|
||||
return true
|
||||
}
|
||||
if v == nil || vs == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if c := slices.Compare(v.Columns, vs.Columns); c != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return cmp.Compare(v.SortColumn, vs.SortColumn) == 0
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +103,10 @@ func (v *CustomView) Load(path string) error {
|
|||
return err
|
||||
}
|
||||
if err := data.JSONValidator.Validate(json.ViewsSchema, bb); err != nil {
|
||||
return fmt.Errorf("validation failed for %q: %w", path, err)
|
||||
slog.Warn("Validation failed. Please update your config and restart!",
|
||||
slogs.Path, path,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
var in CustomView
|
||||
if err := yaml.Unmarshal(bb, &in); err != nil {
|
||||
|
|
@ -116,11 +131,41 @@ func (v *CustomView) RemoveListener(gvr string) {
|
|||
|
||||
func (v *CustomView) fireConfigChanged() {
|
||||
for gvr, list := range v.listeners {
|
||||
if vs, ok := v.Views[gvr]; ok {
|
||||
log.Debug().Msgf("Reloading custom view settings for %s", gvr)
|
||||
list.ViewSettingsChanged(&vs)
|
||||
} else {
|
||||
if vs := v.getVS(gvr, list.GetNamespace()); vs == nil {
|
||||
list.ViewSettingsChanged(nil)
|
||||
} else {
|
||||
slog.Debug("Reloading custom view settings", slogs.GVR, gvr)
|
||||
list.ViewSettingsChanged(vs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *CustomView) getVS(gvr, ns string) *ViewSetting {
|
||||
k := gvr
|
||||
if ns != "" {
|
||||
k += "@" + ns
|
||||
}
|
||||
|
||||
for key := range maps.Keys(v.Views) {
|
||||
if !strings.HasPrefix(key, gvr) {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case key == k:
|
||||
vs := v.Views[key]
|
||||
return &vs
|
||||
case strings.Contains(key, "@"):
|
||||
tt := strings.Split(key, "@")
|
||||
if len(tt) != 2 {
|
||||
break
|
||||
}
|
||||
if rx, err := regexp.Compile(tt[1]); err == nil && rx.MatchString(k) {
|
||||
vs := v.Views[key]
|
||||
return &vs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Authors of K9s
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCustomView_getVS(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
cv *CustomView
|
||||
gvr, ns string
|
||||
e *ViewSetting
|
||||
}{
|
||||
"empty": {},
|
||||
|
||||
"gvr": {
|
||||
gvr: "v1/pods",
|
||||
e: &ViewSetting{
|
||||
Columns: []string{"NAMESPACE", "NAME", "AGE", "IP"},
|
||||
},
|
||||
},
|
||||
|
||||
"gvr+ns": {
|
||||
gvr: "v1/pods",
|
||||
ns: "default",
|
||||
e: &ViewSetting{
|
||||
Columns: []string{"NAME", "IP", "AGE"},
|
||||
},
|
||||
},
|
||||
|
||||
"rx": {
|
||||
gvr: "v1/pods",
|
||||
ns: "ns-fred",
|
||||
e: &ViewSetting{
|
||||
Columns: []string{"AGE", "NAME", "IP"},
|
||||
},
|
||||
},
|
||||
|
||||
"toast-no-ns": {
|
||||
gvr: "v1/pods",
|
||||
ns: "zorg",
|
||||
},
|
||||
|
||||
"toast-no-res": {
|
||||
gvr: "v1/services",
|
||||
ns: "zorg",
|
||||
},
|
||||
}
|
||||
|
||||
v := NewCustomView()
|
||||
assert.NoError(t, v.Load("testdata/views/views.yaml"))
|
||||
for k, u := range uu {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equal(t, u.e, v.getVS(u.gvr, u.ns))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -4,37 +4,117 @@
|
|||
package config_test
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestViewSettingsLoad(t *testing.T) {
|
||||
cfg := config.NewCustomView()
|
||||
|
||||
assert.Nil(t, cfg.Load("testdata/views/views.yaml"))
|
||||
assert.Equal(t, 1, len(cfg.Views))
|
||||
assert.Equal(t, 4, len(cfg.Views["v1/pods"].Columns))
|
||||
func init() {
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestViewSetting_Equals(t *testing.T) {
|
||||
tests := []struct {
|
||||
v1, v2 *config.ViewSetting
|
||||
equals bool
|
||||
func TestCustomViewLoad(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
cv *config.CustomView
|
||||
path string
|
||||
key string
|
||||
e []string
|
||||
}{
|
||||
{nil, nil, false},
|
||||
{&config.ViewSetting{}, nil, false},
|
||||
{nil, &config.ViewSetting{}, false},
|
||||
{&config.ViewSetting{}, &config.ViewSetting{}, true},
|
||||
{&config.ViewSetting{Columns: []string{"A"}}, &config.ViewSetting{}, false},
|
||||
{&config.ViewSetting{Columns: []string{"A"}}, &config.ViewSetting{Columns: []string{"A"}}, true},
|
||||
{&config.ViewSetting{Columns: []string{"A"}}, &config.ViewSetting{Columns: []string{"B"}}, false},
|
||||
{&config.ViewSetting{SortColumn: "A"}, &config.ViewSetting{SortColumn: "B"}, false},
|
||||
{&config.ViewSetting{SortColumn: "A"}, &config.ViewSetting{SortColumn: "A"}, true},
|
||||
"empty": {},
|
||||
|
||||
"gvr": {
|
||||
path: "testdata/views/views.yaml",
|
||||
key: "v1/pods",
|
||||
e: []string{"NAMESPACE", "NAME", "AGE", "IP"},
|
||||
},
|
||||
|
||||
"gvr+ns": {
|
||||
path: "testdata/views/views.yaml",
|
||||
key: "v1/pods@default",
|
||||
e: []string{"NAME", "IP", "AGE"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equalf(t, tt.equals, tt.v1.Equals(tt.v2), "%#v and %#v", tt.v1, tt.v2)
|
||||
for k, u := range uu {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
cfg := config.NewCustomView()
|
||||
|
||||
assert.NoError(t, cfg.Load(u.path))
|
||||
assert.Equal(t, u.e, cfg.Views[u.key].Columns)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewSettingEquals(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
v1, v2 *config.ViewSetting
|
||||
e bool
|
||||
}{
|
||||
"v1-nil-v2-nil": {
|
||||
e: true,
|
||||
},
|
||||
|
||||
"v1-v2-empty": {
|
||||
v1: new(config.ViewSetting),
|
||||
v2: new(config.ViewSetting),
|
||||
e: true,
|
||||
},
|
||||
|
||||
"v1-nil": {
|
||||
v1: new(config.ViewSetting),
|
||||
},
|
||||
|
||||
"nil-v2": {
|
||||
v2: new(config.ViewSetting),
|
||||
},
|
||||
|
||||
"v1-v2-blank": {
|
||||
v1: &config.ViewSetting{
|
||||
Columns: []string{"A"},
|
||||
},
|
||||
v2: new(config.ViewSetting),
|
||||
},
|
||||
|
||||
"v1-v2-nil": {
|
||||
v1: &config.ViewSetting{
|
||||
Columns: []string{"A"},
|
||||
},
|
||||
},
|
||||
|
||||
"same": {
|
||||
v1: &config.ViewSetting{
|
||||
Columns: []string{"A", "B", "C"},
|
||||
},
|
||||
v2: &config.ViewSetting{
|
||||
Columns: []string{"A", "B", "C"},
|
||||
},
|
||||
e: true,
|
||||
},
|
||||
|
||||
"order": {
|
||||
v1: &config.ViewSetting{
|
||||
Columns: []string{"C", "A", "B"},
|
||||
},
|
||||
v2: &config.ViewSetting{
|
||||
Columns: []string{"A", "B", "C"},
|
||||
},
|
||||
},
|
||||
|
||||
"delta": {
|
||||
v1: &config.ViewSetting{
|
||||
Columns: []string{"A", "B", "C"},
|
||||
},
|
||||
v2: &config.ViewSetting{
|
||||
Columns: []string{"B"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for k, u := range uu {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equalf(t, u.e, u.v1.Equals(u.v2), "%#v and %#v", u.v1, u.v2)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ package dao
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
// RefScanner represents a resource reference scanner.
|
||||
|
|
@ -55,7 +57,7 @@ func scanners() map[string]RefScanner {
|
|||
// ScanForRefs scans cluster resources for resource references.
|
||||
func ScanForRefs(ctx context.Context, f Factory) (Refs, error) {
|
||||
defer func(t time.Time) {
|
||||
log.Debug().Msgf("Cluster Scan %v", time.Since(t))
|
||||
slog.Debug("Cluster Scan", slogs.Elapsed, time.Since(t))
|
||||
}(time.Now())
|
||||
|
||||
gvr, ok := ctx.Value(internal.KeyGVR).(client.GVR)
|
||||
|
|
@ -68,7 +70,7 @@ func ScanForRefs(ctx context.Context, f Factory) (Refs, error) {
|
|||
}
|
||||
wait, ok := ctx.Value(internal.KeyWait).(bool)
|
||||
if !ok {
|
||||
log.Error().Msgf("expecting Context Wait Key")
|
||||
slog.Warn("Expecting context Wait key. Using default")
|
||||
}
|
||||
|
||||
ss := scanners()
|
||||
|
|
@ -81,7 +83,10 @@ func ScanForRefs(ctx context.Context, f Factory) (Refs, error) {
|
|||
s.Init(f, client.NewGVR(kind))
|
||||
refs, err := s.Scan(ctx, gvr, fqn, wait)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("scan failed for %T", s)
|
||||
slog.Error("Reference scan failed for",
|
||||
slogs.RefType, fmt.Sprintf("%T", s),
|
||||
slogs.Error, err,
|
||||
)
|
||||
return
|
||||
}
|
||||
select {
|
||||
|
|
@ -108,7 +113,7 @@ func ScanForRefs(ctx context.Context, f Factory) (Refs, error) {
|
|||
// ScanForSARefs scans cluster resources for serviceaccount refs.
|
||||
func ScanForSARefs(ctx context.Context, f Factory) (Refs, error) {
|
||||
defer func(t time.Time) {
|
||||
log.Debug().Msgf("SA Cluster Scan %v", time.Since(t))
|
||||
slog.Debug("Time to scan Cluster SA", slogs.Elapsed, time.Since(t))
|
||||
}(time.Now())
|
||||
|
||||
fqn, ok := ctx.Value(internal.KeyPath).(string)
|
||||
|
|
@ -130,7 +135,10 @@ func ScanForSARefs(ctx context.Context, f Factory) (Refs, error) {
|
|||
s.Init(f, client.NewGVR(kind))
|
||||
refs, err := s.ScanSA(ctx, fqn, wait)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("scan failed for %T", s)
|
||||
slog.Error("ServiceAccount scan failed",
|
||||
slogs.RefType, fmt.Sprintf("%T", s),
|
||||
slogs.Error, err,
|
||||
)
|
||||
return
|
||||
}
|
||||
select {
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ package dao
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ func (c *Context) List(_ context.Context, _ string) ([]runtime.Object, error) {
|
|||
func (c *Context) MustCurrentContextName() string {
|
||||
cl, err := c.config().CurrentContextName()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Fetching current context")
|
||||
slog.Error("Fetching current context", slogs.Error, err)
|
||||
}
|
||||
return cl
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -200,7 +201,10 @@ func (c *CronJob) Scan(ctx context.Context, gvr client.GVR, fqn string, wait boo
|
|||
case SecGVR:
|
||||
found, err := hasSecret(c.Factory, &cj.Spec.JobTemplate.Spec.Template.Spec, cj.Namespace, n, wait)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("locate secret %q", fqn)
|
||||
slog.Warn("Failed to locate secret",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Error, err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if !found {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"k8s.io/kubectl/pkg/describe"
|
||||
)
|
||||
|
||||
|
|
@ -14,13 +16,19 @@ func Describe(c client.Connection, gvr client.GVR, path string) (string, error)
|
|||
mapper := RestMapper{Connection: c}
|
||||
m, err := mapper.ToRESTMapper()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("No REST mapper for resource %s", gvr)
|
||||
slog.Error("No REST mapper for resource",
|
||||
slogs.GVR, gvr,
|
||||
slogs.Error, err,
|
||||
)
|
||||
return "", err
|
||||
}
|
||||
|
||||
gvk, err := m.KindFor(gvr.GVR())
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("No GVK for resource %s", gvr)
|
||||
slog.Error("No GVK for resource %s",
|
||||
slogs.GVR, gvr,
|
||||
slogs.Error, err,
|
||||
)
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
@ -30,12 +38,19 @@ func Describe(c client.Connection, gvr client.GVR, path string) (string, error)
|
|||
}
|
||||
mapping, err := mapper.ResourceFor(gvr.AsResourceName(), gvk.Kind)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to find mapper for %s %s", gvr, n)
|
||||
slog.Error("Unable to find mapper",
|
||||
slogs.GVR, gvr,
|
||||
slogs.ResName, n,
|
||||
slogs.Error, err,
|
||||
)
|
||||
return "", err
|
||||
}
|
||||
d, err := describe.Describer(c.Config().Flags(), mapping)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to find describer for %#v", mapping)
|
||||
slog.Error("Unable to find describer",
|
||||
slogs.GVR, gvr.AsResourceName(),
|
||||
slogs.Error, err,
|
||||
)
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -215,7 +216,10 @@ func (d *Deployment) Scan(ctx context.Context, gvr client.GVR, fqn string, wait
|
|||
case SecGVR:
|
||||
found, err := hasSecret(d.Factory, &dp.Spec.Template.Spec, dp.Namespace, n, wait)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("scanning secret %q", fqn)
|
||||
slog.Warn("Fail to locate secret",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Error, err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if !found {
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
"github.com/rs/zerolog/log"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -235,7 +236,10 @@ func (d *DaemonSet) Scan(ctx context.Context, gvr client.GVR, fqn string, wait b
|
|||
case SecGVR:
|
||||
found, err := hasSecret(d.Factory, &ds.Spec.Template.Spec, ds.Namespace, n, wait)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("locate secret %q", fqn)
|
||||
slog.Warn("Unable to locate secret",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Error, err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if !found {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ package dao
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render/helm"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"gopkg.in/yaml.v2"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -163,6 +164,9 @@ func ensureHelmConfig(flags *genericclioptions.ConfigFlags, ns string) (*action.
|
|||
return cfg, err
|
||||
}
|
||||
|
||||
func helmLogger(fmt string, args ...interface{}) {
|
||||
log.Debug().Msgf("[Helm] "+fmt, args...)
|
||||
func helmLogger(fmat string, args ...interface{}) {
|
||||
slog.Debug("Log",
|
||||
slogs.Log, fmt.Sprintf(fmat, args...),
|
||||
slogs.Subsys, "helm",
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -35,7 +36,10 @@ func GetDefaultContainer(m metav1.ObjectMeta, spec v1.PodSpec) (string, bool) {
|
|||
return defaultContainer, true
|
||||
}
|
||||
}
|
||||
log.Warn().Msg(defaultContainer + " container not found. " + defaultContainerAnnotation + " annotation will be ignored")
|
||||
slog.Warn("Container not found. Annotation ignored",
|
||||
slogs.CO, defaultContainer,
|
||||
slogs.Annotation, defaultContainerAnnotation,
|
||||
)
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
|
@ -43,7 +47,7 @@ func GetDefaultContainer(m metav1.ObjectMeta, spec v1.PodSpec) (string, bool) {
|
|||
func extractFQN(o runtime.Object) string {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
log.Error().Err(fmt.Errorf("expecting unstructured but got %T", o))
|
||||
slog.Error("Expecting unstructured", slogs.ResType, fmt.Sprintf("%T", o))
|
||||
return client.NA
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +97,7 @@ func ToYAML(o runtime.Object, showManaged bool) (string, error) {
|
|||
}
|
||||
err := p.PrintObj(o, &buff)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Marshal Error %v", err)
|
||||
slog.Error("Marshal failed", slogs.Error, err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
|
@ -159,7 +160,10 @@ func (j *Job) Scan(ctx context.Context, gvr client.GVR, fqn string, wait bool) (
|
|||
case SecGVR:
|
||||
found, err := hasSecret(j.Factory, &job.Spec.Template.Spec, job.Namespace, n, wait)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("locate secret %q", fqn)
|
||||
slog.Warn("Locate secret failed",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Error, err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if !found {
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ package dao_test
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestLogItemsFilter(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,12 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
|
@ -37,16 +38,23 @@ type Node struct {
|
|||
}
|
||||
|
||||
// ToggleCordon toggles cordon/uncordon a node.
|
||||
func (n *Node) ToggleCordon(path string, cordon bool) error {
|
||||
log.Debug().Msgf("CORDON %q::%t -- %q", path, cordon, n.gvr.GVK())
|
||||
o, err := FetchNode(context.Background(), n.Factory, path)
|
||||
func (n *Node) ToggleCordon(fqn string, cordon bool) error {
|
||||
slog.Debug("Toggle cordon on node",
|
||||
slogs.GVR, n.GVR(),
|
||||
slogs.FQN, fqn,
|
||||
slogs.Bool, cordon,
|
||||
)
|
||||
o, err := FetchNode(context.Background(), n.Factory, fqn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h, err := drain.NewCordonHelperFromRuntimeObject(o, scheme.Scheme, n.gvr.GVK())
|
||||
if err != nil {
|
||||
log.Debug().Msgf("BOOM %v", err)
|
||||
slog.Debug("Fail to toggle cordon on node",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Error, err,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +182,10 @@ func (n *Node) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
|||
if shouldCountPods {
|
||||
podCount, err = n.CountPods(name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("unable to get pods count for %s", name)
|
||||
slog.Error("Unable to get pods count",
|
||||
slogs.ResName, name,
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
}
|
||||
res = append(res, &render.NodeWithMetrics{
|
||||
|
|
|
|||
|
|
@ -1,221 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Authors of K9s
|
||||
|
||||
package dao
|
||||
|
||||
// BOZO!! Revamp with latest
|
||||
|
||||
// import (
|
||||
// "bytes"
|
||||
// "context"
|
||||
// "encoding/json"
|
||||
// "errors"
|
||||
// "fmt"
|
||||
// "io"
|
||||
// "net/http"
|
||||
// "net/url"
|
||||
// "os"
|
||||
// "path"
|
||||
// "strings"
|
||||
// "time"
|
||||
|
||||
// "github.com/derailed/k9s/internal/client"
|
||||
// "github.com/derailed/k9s/internal/render"
|
||||
// "github.com/openfaas/faas-cli/proxy"
|
||||
// "github.com/openfaas/faas/gateway/requests"
|
||||
// "github.com/rs/zerolog/log"
|
||||
// "k8s.io/apimachinery/pkg/runtime"
|
||||
// "sigs.k8s.io/yaml"
|
||||
// )
|
||||
|
||||
// const (
|
||||
// oFaasGatewayEnv = "OPENFAAS_GATEWAY"
|
||||
// oFaasJWTTokenEnv = "OPENFAAS_JWT_TOKEN"
|
||||
// oFaasTLSInsecure = "OPENFAAS_TLS_INSECURE"
|
||||
// )
|
||||
|
||||
// var (
|
||||
// _ Accessor = (*OpenFaas)(nil)
|
||||
// _ Nuker = (*OpenFaas)(nil)
|
||||
// _ Describer = (*OpenFaas)(nil)
|
||||
// )
|
||||
|
||||
// // OpenFaas represents a faas gateway connection.
|
||||
// type OpenFaas struct {
|
||||
// NonResource
|
||||
// }
|
||||
|
||||
// // IsOpenFaasEnabled returns true if a gateway url is set in the environment.
|
||||
// func IsOpenFaasEnabled() bool {
|
||||
// return os.Getenv(oFaasGatewayEnv) != ""
|
||||
// }
|
||||
|
||||
// func getOpenFAASFlags() (string, string, bool) {
|
||||
// gw, token := os.Getenv(oFaasGatewayEnv), os.Getenv(oFaasJWTTokenEnv)
|
||||
// tlsInsecure := false
|
||||
// if os.Getenv(oFaasTLSInsecure) == "true" {
|
||||
// tlsInsecure = true
|
||||
// }
|
||||
|
||||
// return gw, token, tlsInsecure
|
||||
// }
|
||||
|
||||
// // Get returns a function by name.
|
||||
// func (f *OpenFaas) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
// ns, n := client.Namespaced(path)
|
||||
|
||||
// oo, err := f.List(ctx, ns)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// var found runtime.Object
|
||||
// for _, o := range oo {
|
||||
// r, ok := o.(render.OpenFaasRes)
|
||||
// if !ok {
|
||||
// continue
|
||||
// }
|
||||
// if r.Function.Name == n {
|
||||
// found = o
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
|
||||
// if found == nil {
|
||||
// return nil, fmt.Errorf("unable to locate function %q", path)
|
||||
// }
|
||||
|
||||
// return found, nil
|
||||
// }
|
||||
|
||||
// // List returns a collection of functions.
|
||||
// func (f *OpenFaas) List(_ context.Context, ns string) ([]runtime.Object, error) {
|
||||
// if !IsOpenFaasEnabled() {
|
||||
// return nil, errors.New("OpenFAAS is not enabled on this cluster")
|
||||
// }
|
||||
|
||||
// gw, token, tls := getOpenFAASFlags()
|
||||
// ff, err := proxy.ListFunctionsToken(gw, tls, token, ns)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// oo := make([]runtime.Object, 0, len(ff))
|
||||
// for _, f := range ff {
|
||||
// oo = append(oo, render.OpenFaasRes{Function: f})
|
||||
// }
|
||||
|
||||
// return oo, nil
|
||||
// }
|
||||
|
||||
// // Delete removes a function.
|
||||
// func (f *OpenFaas) Delete(path string, _, _ bool) error {
|
||||
// gw, token, tls := getOpenFAASFlags()
|
||||
// ns, n := client.Namespaced(path)
|
||||
|
||||
// // BOZO!! openfaas spews to stdout. Not good for us...
|
||||
// return deleteFunctionToken(gw, n, tls, token, ns)
|
||||
// }
|
||||
|
||||
// // ToYAML dumps a function to yaml.
|
||||
// func (f *OpenFaas) ToYAML(path string, _ bool) (string, error) {
|
||||
// return f.Describe(path)
|
||||
// }
|
||||
|
||||
// // Describe describes a function.
|
||||
// func (f *OpenFaas) Describe(path string) (string, error) {
|
||||
// o, err := f.Get(context.Background(), path)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// fn, ok := o.(render.OpenFaasRes)
|
||||
// if !ok {
|
||||
// return "", fmt.Errorf("expecting OpenFaasRes but got %T", o)
|
||||
// }
|
||||
|
||||
// raw, err := json.Marshal(fn)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// bytes, err := yaml.JSONToYAML(raw)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// return string(bytes), nil
|
||||
// }
|
||||
|
||||
// // BOZO!! Meow! openfaas fn prints to stdout have to dup ;(.
|
||||
// func deleteFunctionToken(gateway string, functionName string, tlsInsecure bool, token string, namespace string) error {
|
||||
// defaultCommandTimeout := 60 * time.Second
|
||||
|
||||
// gateway = strings.TrimRight(gateway, "/")
|
||||
// delReq := requests.DeleteFunctionRequest{FunctionName: functionName}
|
||||
// reqBytes, _ := json.Marshal(&delReq)
|
||||
// reader := bytes.NewReader(reqBytes)
|
||||
|
||||
// c := proxy.MakeHTTPClient(&defaultCommandTimeout, tlsInsecure)
|
||||
|
||||
// deleteEndpoint, err := createSystemEndpoint(gateway, namespace)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// req, err := http.NewRequestWithContext(context.Background(), "DELETE", deleteEndpoint, reader)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// if len(token) > 0 {
|
||||
// proxy.SetToken(req, token)
|
||||
// } else {
|
||||
// proxy.SetAuth(req, gateway)
|
||||
// }
|
||||
|
||||
// delRes, delErr := c.Do(req)
|
||||
// if delErr != nil {
|
||||
// return delErr
|
||||
// }
|
||||
|
||||
// if delRes.Body != nil {
|
||||
// defer func() {
|
||||
// if err := delRes.Body.Close(); err != nil {
|
||||
// log.Error().Err(err).Msgf("closing delete-gtw body")
|
||||
// }
|
||||
// }()
|
||||
// }
|
||||
|
||||
// switch delRes.StatusCode {
|
||||
// case http.StatusOK, http.StatusCreated, http.StatusAccepted:
|
||||
// return nil
|
||||
// case http.StatusNotFound:
|
||||
// return fmt.Errorf("no function named %s found", functionName)
|
||||
// case http.StatusUnauthorized:
|
||||
// return fmt.Errorf("unauthorized access, run \"faas-cli login\" to setup authentication for this server")
|
||||
// default:
|
||||
// bytesOut, err := io.ReadAll(delRes.Body)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// return fmt.Errorf("server returned unexpected status code %d %s", delRes.StatusCode, string(bytesOut))
|
||||
// }
|
||||
// }
|
||||
|
||||
// func createSystemEndpoint(gateway, namespace string) (string, error) {
|
||||
// const systemPath = "/system/functions"
|
||||
|
||||
// gatewayURL, err := url.Parse(gateway)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("invalid gateway URL: %w", err)
|
||||
// }
|
||||
// gatewayURL.Path = path.Join(gatewayURL.Path, systemPath)
|
||||
// if len(namespace) > 0 {
|
||||
// q := gatewayURL.Query()
|
||||
// q.Set("namespace", namespace)
|
||||
// gatewayURL.RawQuery = q.Encode()
|
||||
// }
|
||||
// return gatewayURL.String(), nil
|
||||
// }
|
||||
|
|
@ -9,15 +9,16 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -287,7 +288,10 @@ func (p *Pod) Scan(ctx context.Context, gvr client.GVR, fqn string, wait bool) (
|
|||
case SecGVR:
|
||||
found, err := hasSecret(p.Factory, &pod.Spec, pod.Namespace, n, wait)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("locate secret %q", fqn)
|
||||
slog.Warn("Locate secret failed",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Error, err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if !found {
|
||||
|
|
@ -332,30 +336,33 @@ func tailLogs(ctx context.Context, logger Logger, opts *LogOptions) LogChan {
|
|||
go func() {
|
||||
defer wg.Done()
|
||||
podOpts := opts.ToPodLogOptions()
|
||||
var stream io.ReadCloser
|
||||
for r := 0; r < logRetryCount; r++ {
|
||||
var e error
|
||||
req, err := logger.Logs(opts.Path, podOpts)
|
||||
if err == nil {
|
||||
// This call will block if nothing is in the stream!!
|
||||
if stream, err = req.Stream(ctx); err == nil {
|
||||
if stream, e := req.Stream(ctx); e == nil {
|
||||
wg.Add(1)
|
||||
go readLogs(ctx, &wg, stream, out, opts)
|
||||
return
|
||||
} else {
|
||||
slog.Error("Stream logs failed",
|
||||
slogs.Error, e,
|
||||
slogs.Container, opts.Info(),
|
||||
)
|
||||
}
|
||||
e = fmt.Errorf("stream logs failed %w for %s", err, opts.Info())
|
||||
log.Error().Err(e).Msg("logs-stream")
|
||||
} else {
|
||||
e = fmt.Errorf("stream logs failed %w for %s", err, opts.Info())
|
||||
log.Error().Err(e).Msg("log-request")
|
||||
slog.Error("Log request failed",
|
||||
slogs.Container, opts.Info(),
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
if e != nil {
|
||||
out <- opts.ToErrLogItem(e)
|
||||
if err != nil {
|
||||
out <- opts.ToErrLogItem(err)
|
||||
}
|
||||
time.Sleep(logRetryWait)
|
||||
}
|
||||
|
|
@ -372,12 +379,15 @@ func tailLogs(ctx context.Context, logger Logger, opts *LogOptions) LogChan {
|
|||
func readLogs(ctx context.Context, wg *sync.WaitGroup, stream io.ReadCloser, out chan<- *LogItem, opts *LogOptions) {
|
||||
defer func() {
|
||||
if err := stream.Close(); err != nil {
|
||||
log.Error().Err(err).Msgf("Fail to close stream %s", opts.Info())
|
||||
slog.Error("Fail to close stream",
|
||||
slogs.Container, opts.Info(),
|
||||
slogs.Error, err,
|
||||
)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
log.Debug().Msgf(">>> LOG-READER PROCESSING %#v", opts)
|
||||
slog.Debug("Processing logs", slogs.Options, opts.Info())
|
||||
r := bufio.NewReader(stream)
|
||||
for {
|
||||
var item *LogItem
|
||||
|
|
@ -387,11 +397,14 @@ func readLogs(ctx context.Context, wg *sync.WaitGroup, stream io.ReadCloser, out
|
|||
if errors.Is(err, io.EOF) {
|
||||
e := fmt.Errorf("stream closed %w for %s", err, opts.Info())
|
||||
item = opts.ToErrLogItem(e)
|
||||
log.Warn().Err(e).Msg("log-reader EOF")
|
||||
slog.Warn("Log reader EOF",
|
||||
slogs.Container, opts.Info(),
|
||||
slogs.Error, e,
|
||||
)
|
||||
} else {
|
||||
e := fmt.Errorf("stream canceled %w for %s", err, opts.Info())
|
||||
item = opts.ToErrLogItem(e)
|
||||
log.Warn().Err(e).Msg("log-reader canceled")
|
||||
slog.Warn("Log stream canceled")
|
||||
}
|
||||
}
|
||||
select {
|
||||
|
|
@ -488,7 +501,6 @@ func (p *Pod) Sanitize(ctx context.Context, ns string) (int, error) {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
log.Debug().Msgf("Pod status: %q", render.PodStatus(&pod))
|
||||
switch render.PodStatus(&pod) {
|
||||
case render.PhaseCompleted:
|
||||
fallthrough
|
||||
|
|
@ -506,16 +518,20 @@ func (p *Pod) Sanitize(ctx context.Context, ns string) (int, error) {
|
|||
fallthrough
|
||||
case render.PhaseOOMKilled:
|
||||
// !!BOZO!! Might need to bump timeout otherwise rev limit if too many??
|
||||
log.Debug().Msgf("Sanitizing %s:%s", pod.Namespace, pod.Name)
|
||||
fqn := client.FQN(pod.Namespace, pod.Name)
|
||||
slog.Debug("Sanitizing resource", slogs.FQN, fqn)
|
||||
if err := p.Delete(ctx, fqn, nil, 0); err != nil {
|
||||
log.Debug().Msgf("Aborted! Sanitizer deleted %d pods", count)
|
||||
slog.Debug("Aborted! Sanitizer delete failed",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Count, count,
|
||||
slogs.Error, err,
|
||||
)
|
||||
return count, err
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
log.Debug().Msgf("Sanitizer deleted %d pods", count)
|
||||
slog.Debug("Sanitizer deleted pods", slogs.Count, count)
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ package dao
|
|||
// "github.com/derailed/popeye/pkg"
|
||||
// "github.com/derailed/popeye/pkg/config"
|
||||
// "github.com/derailed/popeye/types"
|
||||
// "github.com/rs/zerolog/log"
|
||||
// "k8s.io/apimachinery/pkg/runtime"
|
||||
// )
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package dao
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ import (
|
|||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
|
@ -45,7 +46,7 @@ func (p *PortForward) List(ctx context.Context, _ string) ([]runtime.Object, err
|
|||
|
||||
config, err := config.NewBench(benchFile)
|
||||
if err != nil {
|
||||
log.Debug().Msgf("No custom benchmark config file found: %q", benchFile)
|
||||
slog.Debug("No custom benchmark config file found", slogs.FileName, benchFile)
|
||||
}
|
||||
|
||||
ff, cc := p.getFactory().Forwarders(), config.Benchmarks.Containers
|
||||
|
|
@ -92,7 +93,10 @@ func BenchConfigFor(benchFile, path string) config.BenchConfig {
|
|||
def := config.DefaultBenchSpec()
|
||||
cust, err := config.NewBench(benchFile)
|
||||
if err != nil {
|
||||
log.Debug().Msgf("No custom benchmark config file found. Using default: %q", benchFile)
|
||||
slog.Debug("No custom benchmark config file found. Using default",
|
||||
slogs.FileName, benchFile,
|
||||
slogs.Error, err,
|
||||
)
|
||||
return def
|
||||
}
|
||||
if b, ok := cust.Benchmarks.Containers[PodToKey(path)]; ok {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/port"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -101,7 +100,6 @@ func (p *PortForwarder) Container() string {
|
|||
|
||||
// Stop terminates a port forward.
|
||||
func (p *PortForwarder) Stop() {
|
||||
log.Debug().Msgf("<<< Stopping PortForward %s", p.ID())
|
||||
p.active = false
|
||||
if p.stopChan != nil {
|
||||
close(p.stopChan)
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ package dao
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
|
@ -121,9 +122,9 @@ func (r *Rbac) loadRoleBinding(path string) ([]runtime.Object, error) {
|
|||
return asRuntimeObjects(parseRules(client.ClusterScope, "-", role.Rules)), nil
|
||||
}
|
||||
|
||||
func (r *Rbac) loadClusterRole(path string) ([]runtime.Object, error) {
|
||||
log.Debug().Msgf("LOAD-CR %q", path)
|
||||
o, err := r.getFactory().Get(crGVR, path, true, labels.Everything())
|
||||
func (r *Rbac) loadClusterRole(fqn string) ([]runtime.Object, error) {
|
||||
slog.Debug("LOAD-CR", slogs.FQN, fqn)
|
||||
o, err := r.getFactory().Get(crGVR, fqn, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -165,6 +166,9 @@ func parseRules(ns, binding string, rules []rbacv1.PolicyRule) render.Policies {
|
|||
pp := make(render.Policies, 0, len(rules))
|
||||
for _, rule := range rules {
|
||||
for _, grp := range rule.APIGroups {
|
||||
if grp == "" {
|
||||
grp = "core"
|
||||
}
|
||||
for _, res := range rule.Resources {
|
||||
for _, na := range rule.ResourceNames {
|
||||
pp = pp.Upsert(render.NewPolicyRes(ns, binding, FQN(res, na), grp, rule.Verbs))
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ package dao
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
|
@ -102,7 +103,10 @@ func (p *Policy) loadRoleBinding(kind, name string) (render.Policies, error) {
|
|||
rows := make(render.Policies, 0, len(crs))
|
||||
for _, cr := range crs {
|
||||
if rbNs, ok := rbsMap["ClusterRole:"+cr.Name]; ok {
|
||||
log.Debug().Msgf("Loading rules for clusterrole %q:%q", rbNs, cr.Name)
|
||||
slog.Debug("Loading rules for clusterrole",
|
||||
slogs.Namespace, rbNs,
|
||||
slogs.ResName, cr.Name,
|
||||
)
|
||||
rows = append(rows, parseRules(rbNs, "CR:"+cr.Name, cr.Rules)...)
|
||||
}
|
||||
}
|
||||
|
|
@ -115,7 +119,10 @@ func (p *Policy) loadRoleBinding(kind, name string) (render.Policies, error) {
|
|||
if _, ok := rbsMap["Role:"+ro.Name]; !ok {
|
||||
continue
|
||||
}
|
||||
log.Debug().Msgf("Loading rules for role %q:%q", ro.Namespace, ro.Name)
|
||||
slog.Debug("Loading rules for role",
|
||||
slogs.Namespace, ro.Namespace,
|
||||
slogs.ResName, ro.Name,
|
||||
)
|
||||
rows = append(rows, parseRules(ro.Namespace, "RO:"+ro.Name, ro.Rules)...)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ package dao
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -97,7 +98,7 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) {
|
|||
r, ok := m[gvr]
|
||||
if !ok {
|
||||
r = new(Scaler)
|
||||
log.Debug().Msgf("No DAO registry entry for %q. Using generics!", gvr)
|
||||
slog.Debug("No DAO registry entry. Using generics!", slogs.GVR, gvr)
|
||||
}
|
||||
r.Init(f, gvr)
|
||||
|
||||
|
|
@ -348,7 +349,7 @@ func loadRBAC(m ResourceMetas) {
|
|||
|
||||
func loadPreferred(f Factory, m ResourceMetas) error {
|
||||
if f.Client() == nil || !f.Client().ConnectionOK() {
|
||||
log.Error().Msgf("Load cluster resources - No API server connection")
|
||||
slog.Error("Load cluster resources - No API server connection")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -358,7 +359,7 @@ func loadPreferred(f Factory, m ResourceMetas) error {
|
|||
}
|
||||
rr, err := dial.ServerPreferredResources()
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msgf("Failed to load preferred resources")
|
||||
slog.Debug("Failed to load preferred resources", slogs.Error, err)
|
||||
}
|
||||
for _, r := range rr {
|
||||
for _, res := range r.APIResources {
|
||||
|
|
@ -400,7 +401,7 @@ func loadCRDs(f Factory, m ResourceMetas) {
|
|||
|
||||
oo, err := f.List(crdGVR, client.ClusterScope, true, labels.Everything())
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("Fail CRDs load")
|
||||
slog.Warn("CRDs load Fail", slogs.Error, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -408,7 +409,7 @@ func loadCRDs(f Factory, m ResourceMetas) {
|
|||
var crd apiext.CustomResourceDefinition
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &crd)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("boom")
|
||||
slog.Error("CRD conversion failed", slogs.Error, err)
|
||||
continue
|
||||
}
|
||||
gvr, version, ok := newGVRFromCRD(&crd)
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ package dao
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/client-go/scale"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
)
|
||||
|
||||
var _ Scalable = (*Scaler)(nil)
|
||||
|
|
@ -59,7 +59,10 @@ func (s *Scaler) Scale(ctx context.Context, path string, replicas int32) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("%s scaled to %d", path, updatedScale.Spec.Replicas)
|
||||
slog.Debug("Scaled resource",
|
||||
slogs.FQN, path,
|
||||
slogs.Replicas, updatedScale.Spec.Replicas,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -236,7 +237,10 @@ func (s *StatefulSet) Scan(ctx context.Context, gvr client.GVR, fqn string, wait
|
|||
case SecGVR:
|
||||
found, err := hasSecret(s.Factory, &sts.Spec.Template.Spec, sts.Namespace, n, wait)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("locate secret %q", fqn)
|
||||
slog.Warn("Locate secret failed",
|
||||
slogs.FQN, fqn,
|
||||
slogs.Error, err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if !found {
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -206,12 +207,18 @@ func isReady(s string) bool {
|
|||
}
|
||||
r, err := strconv.Atoi(tt[0])
|
||||
if err != nil {
|
||||
log.Error().Msgf("invalid ready count: %q", tt[0])
|
||||
slog.Error("Invalid ready count",
|
||||
slogs.Error, err,
|
||||
slogs.Count, tt[0],
|
||||
)
|
||||
return false
|
||||
}
|
||||
c, err := strconv.Atoi(tt[1])
|
||||
if err != nil {
|
||||
log.Error().Msgf("invalid expected count: %q", tt[1])
|
||||
slog.Error("invalid expected count: %q",
|
||||
slogs.Error, err,
|
||||
slogs.Count, tt[1],
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,15 +8,16 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/rs/zerolog/log"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
)
|
||||
|
||||
|
|
@ -107,7 +108,7 @@ func (c *ClusterInfo) fetchK9sLatestRev() string {
|
|||
|
||||
latestRev, err := fetchLatestRev()
|
||||
if err != nil {
|
||||
log.Warn().Msgf("k9s latest rev fetch failed %s", err)
|
||||
slog.Warn("k9s latest rev fetch failed", slogs.Error, err)
|
||||
} else {
|
||||
c.cache.Add(k9sLatestRevKey, latestRev, cacheExpiry)
|
||||
}
|
||||
|
|
@ -206,7 +207,7 @@ func (c *ClusterInfo) fireNoMetaChanged(data ClusterMeta) {
|
|||
// Helpers...
|
||||
|
||||
func fetchLatestRev() (string, error) {
|
||||
log.Debug().Msgf("Fetching latest k9s rev...")
|
||||
slog.Debug("Fetching latest k9s rev...")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
|
|
@ -234,7 +235,7 @@ func fetchLatestRev() (string, error) {
|
|||
}
|
||||
|
||||
if v, ok := m["name"]; ok {
|
||||
log.Debug().Msgf("K9s latest rev: %q", v.(string))
|
||||
slog.Debug("K9s latest rev", slogs.Revision, v.(string))
|
||||
return v.(string), nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestClusterMetaDelta(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/sahilm/fuzzy"
|
||||
)
|
||||
|
||||
|
|
@ -113,7 +114,7 @@ func (d *Describe) Watch(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (d *Describe) updater(ctx context.Context) {
|
||||
defer log.Debug().Msgf("Describe canceled -- %q", d.gvr)
|
||||
defer slog.Debug("Describe canceled", slogs.GVR, d.gvr)
|
||||
|
||||
backOff := NewExpBackOff(ctx, defaultReaderRefreshRate, maxReaderRetryInterval)
|
||||
delay := defaultReaderRefreshRate
|
||||
|
|
@ -125,7 +126,7 @@ func (d *Describe) updater(ctx context.Context) {
|
|||
if err := d.refresh(ctx); err != nil {
|
||||
d.fireResourceFailed(err)
|
||||
if delay = backOff.NextBackOff(); delay == backoff.Stop {
|
||||
log.Error().Err(err).Msgf("Describe gave up!")
|
||||
slog.Error("Describe gave up!", slogs.Error, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
|
@ -138,13 +139,16 @@ func (d *Describe) updater(ctx context.Context) {
|
|||
|
||||
func (d *Describe) refresh(ctx context.Context) error {
|
||||
if !atomic.CompareAndSwapInt32(&d.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
slog.Debug("Dropping update...")
|
||||
return nil
|
||||
}
|
||||
defer atomic.StoreInt32(&d.inUpdate, 0)
|
||||
|
||||
if err := d.reconcile(ctx); err != nil {
|
||||
log.Error().Err(err).Msgf("reconcile failed %q", d.gvr)
|
||||
slog.Error("reconcile failed",
|
||||
slogs.GVR, d.gvr,
|
||||
slogs.Error, err,
|
||||
)
|
||||
d.fireResourceFailed(err)
|
||||
return err
|
||||
}
|
||||
|
|
@ -170,7 +174,7 @@ func (d *Describe) reconcile(ctx context.Context) error {
|
|||
// Describe describes a given resource.
|
||||
func (d *Describe) describe(ctx context.Context, gvr client.GVR, path string) (string, error) {
|
||||
defer func(t time.Time) {
|
||||
log.Debug().Msgf("Describe model elapsed: %v", time.Since(t))
|
||||
slog.Debug("Describe model elapsed", slogs.Elapsed, time.Since(t))
|
||||
}(time.Now())
|
||||
|
||||
meta, err := getMeta(ctx, gvr)
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -86,7 +87,7 @@ func (f *Flash) Infof(fmat string, args ...interface{}) {
|
|||
|
||||
// Warn displays a warning flash message.
|
||||
func (f *Flash) Warn(msg string) {
|
||||
log.Warn().Msg(msg)
|
||||
slog.Warn(msg)
|
||||
f.SetMessage(FlashWarn, msg)
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +98,7 @@ func (f *Flash) Warnf(fmat string, args ...interface{}) {
|
|||
|
||||
// Err displays an error flash message.
|
||||
func (f *Flash) Err(err error) {
|
||||
log.Error().Msg(err.Error())
|
||||
slog.Error("Flash failed", slogs.Error, err)
|
||||
f.SetMessage(FlashErr, err.Error())
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +111,10 @@ func (f *Flash) Errf(fmat string, args ...interface{}) {
|
|||
err = e
|
||||
}
|
||||
}
|
||||
log.Error().Err(err).Msgf(fmat, args...)
|
||||
slog.Error("Flashing error",
|
||||
slogs.Error, err,
|
||||
slogs.Message, fmt.Sprintf(fmat, args...),
|
||||
)
|
||||
f.SetMessage(FlashErr, fmt.Sprintf(fmat, args...))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ import (
|
|||
"github.com/derailed/k9s/internal/color"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
// LogsListener represents a log model listener.
|
||||
|
|
@ -164,7 +165,7 @@ func (l *Log) Restart(ctx context.Context) {
|
|||
// Start starts logging.
|
||||
func (l *Log) Start(ctx context.Context) {
|
||||
if err := l.load(ctx); err != nil {
|
||||
log.Error().Err(err).Msgf("Tail logs failed!")
|
||||
slog.Error("Tail logs failed!", slogs.Error, err)
|
||||
l.fireLogError(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -219,7 +220,6 @@ func (l *Log) cancel() {
|
|||
defer l.mx.Unlock()
|
||||
if l.cancelFn != nil {
|
||||
l.cancelFn()
|
||||
log.Debug().Msgf("!!! LOG-MODEL CANCELED !!!")
|
||||
l.cancelFn = nil
|
||||
}
|
||||
}
|
||||
|
|
@ -231,7 +231,7 @@ func (l *Log) load(ctx context.Context) error {
|
|||
}
|
||||
loggable, ok := accessor.(dao.Loggable)
|
||||
if !ok {
|
||||
return fmt.Errorf("Resource %s is not Loggable", l.gvr)
|
||||
return fmt.Errorf("resource %s is not Loggable", l.gvr)
|
||||
}
|
||||
|
||||
l.cancel()
|
||||
|
|
@ -240,7 +240,7 @@ func (l *Log) load(ctx context.Context) error {
|
|||
|
||||
cc, err := loggable.TailLogs(ctx, l.logOptions)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Tail logs failed")
|
||||
slog.Error("Tail logs failed", slogs.Error, err)
|
||||
l.cancel()
|
||||
l.fireLogError(err)
|
||||
}
|
||||
|
|
@ -288,8 +288,6 @@ func (l *Log) ToggleAllContainers(ctx context.Context) {
|
|||
}
|
||||
|
||||
func (l *Log) updateLogs(ctx context.Context, c dao.LogChan) {
|
||||
defer log.Debug().Msgf("<<< LOG-MODEL UPDATER DONE %s!!!!", l.logOptions.Info())
|
||||
log.Debug().Msgf(">>> START LOG-MODEL UPDATER %s", l.logOptions.Info())
|
||||
for {
|
||||
select {
|
||||
case item, ok := <-c:
|
||||
|
|
|
|||
|
|
@ -6,13 +6,14 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/health"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ func (p *Pulse) Watch(ctx context.Context) {
|
|||
}
|
||||
|
||||
func (p *Pulse) updater(ctx context.Context) {
|
||||
defer log.Debug().Msgf("Pulse canceled -- %q", p.gvr)
|
||||
defer slog.Debug("Pulse canceled", slogs.GVR, p.gvr)
|
||||
|
||||
rate := initRefreshRate
|
||||
for {
|
||||
|
|
@ -77,13 +78,13 @@ func (p *Pulse) Refresh(ctx context.Context) {
|
|||
|
||||
func (p *Pulse) refresh(ctx context.Context) {
|
||||
if !atomic.CompareAndSwapInt32(&p.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
slog.Debug("Dropping update...")
|
||||
return
|
||||
}
|
||||
defer atomic.StoreInt32(&p.inUpdate, 0)
|
||||
|
||||
if err := p.reconcile(ctx); err != nil {
|
||||
log.Error().Err(err).Msg("Reconcile failed")
|
||||
slog.Error("Reconcile failed", slogs.Error, err)
|
||||
p.firePulseFailed(err)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,14 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/health"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
|
@ -72,7 +73,7 @@ func (h *PulseHealth) checkMetrics(ctx context.Context) (health.Checks, error) {
|
|||
|
||||
nmx, err := dial.FetchNodesMetrics(ctx)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Fetching metrics")
|
||||
slog.Error("Fetching metrics", slogs.Error, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ package model
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -13,7 +14,7 @@ import (
|
|||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/sahilm/fuzzy"
|
||||
)
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ func getHelmHistDao() *dao.HelmHistory {
|
|||
func getRevValues(path, rev string) []string {
|
||||
vals, err := getHelmHistDao().GetValues(path, true)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Failed to get Helm values")
|
||||
slog.Error("Failed to get Helm values", slogs.Error, err)
|
||||
}
|
||||
return strings.Split(string(vals), "\n")
|
||||
}
|
||||
|
|
@ -133,7 +134,7 @@ func (v *RevValues) Watch(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (v *RevValues) updater(ctx context.Context) {
|
||||
defer log.Debug().Msgf("YAML canceled -- %q", v.gvr)
|
||||
defer slog.Debug("YAML canceled", slogs.GVR, v.gvr)
|
||||
|
||||
backOff := NewExpBackOff(ctx, defaultReaderRefreshRate, maxReaderRetryInterval)
|
||||
delay := defaultReaderRefreshRate
|
||||
|
|
@ -145,7 +146,7 @@ func (v *RevValues) updater(ctx context.Context) {
|
|||
if err := v.refresh(ctx); err != nil {
|
||||
v.fireResourceFailed(err)
|
||||
if delay = backOff.NextBackOff(); delay == backoff.Stop {
|
||||
log.Error().Err(err).Msgf("giving up retrieving chart values")
|
||||
slog.Error("Giving up retrieving chart values", slogs.Error, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
|
@ -158,7 +159,7 @@ func (v *RevValues) updater(ctx context.Context) {
|
|||
|
||||
func (v *RevValues) refresh(ctx context.Context) error {
|
||||
if !atomic.CompareAndSwapInt32(&v.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
slog.Debug("Dropping update...")
|
||||
return nil
|
||||
}
|
||||
defer atomic.StoreInt32(&v.inUpdate, 0)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -188,9 +190,9 @@ func (s *Stack) notify(a StackAction, c Component) {
|
|||
|
||||
// Dump prints out the stack.
|
||||
func (s *Stack) Dump() {
|
||||
log.Debug().Msgf("--- Stack Dump %p---", s)
|
||||
slog.Debug("Stack Dump", slogs.Stack, fmt.Sprintf("%p", s))
|
||||
for i, c := range s.components {
|
||||
log.Debug().Msgf("%d -- %s -- %#v", i, c.Name(), c)
|
||||
slog.Debug(fmt.Sprintf("%d -- %s -- %#v", i, c.Name(), c))
|
||||
}
|
||||
log.Debug().Msg("------------------")
|
||||
slog.Debug("------------------")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,17 +5,17 @@ package model_test
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/tcell/v2"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestStackClear(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -16,7 +17,7 @@ import (
|
|||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
|
@ -63,7 +64,7 @@ func (t *Table) SetViewSetting(ctx context.Context, vs *config.ViewSetting) {
|
|||
|
||||
if ctx != context.Background() {
|
||||
if err := t.reconcile(ctx); err != nil {
|
||||
log.Err(err).Msgf("refresh failed for gvr: %s", t.gvr)
|
||||
slog.Error("Refresh failed", slogs.GVR, t.gvr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -209,13 +210,13 @@ func (t *Table) updater(ctx context.Context) {
|
|||
rate = t.refreshRate
|
||||
err := backoff.Retry(func() error {
|
||||
if err := t.refresh(ctx); err != nil {
|
||||
log.Err(err).Msgf("refresh failed for gvr: %s", t.gvr)
|
||||
slog.Error("Refresh failed", slogs.GVR, t.gvr)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, backoff.WithContext(bf, ctx))
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("reconciler exited")
|
||||
slog.Warn("Reconciler exited", slogs.Error, err)
|
||||
t.fireTableLoadFailed(err)
|
||||
return
|
||||
}
|
||||
|
|
@ -224,12 +225,8 @@ func (t *Table) updater(ctx context.Context) {
|
|||
}
|
||||
|
||||
func (t *Table) refresh(ctx context.Context) error {
|
||||
defer func(ti time.Time) {
|
||||
log.Trace().Msgf("Refresh [%s](%d) %s ", t.gvr, t.data.RowCount(), time.Since(ti))
|
||||
}(time.Now())
|
||||
|
||||
if !atomic.CompareAndSwapInt32(&t.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
slog.Debug("Dropping update...")
|
||||
return nil
|
||||
}
|
||||
defer atomic.StoreInt32(&t.inUpdate, 0)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
|
@ -15,8 +16,8 @@ import (
|
|||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/k9s/internal/xray"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
|
@ -162,7 +163,7 @@ func (t *Tree) ToYAML(ctx context.Context, gvr, path string) (string, error) {
|
|||
}
|
||||
|
||||
func (t *Tree) updater(ctx context.Context) {
|
||||
defer log.Debug().Msgf("Tree-model canceled -- %q", t.gvr)
|
||||
defer slog.Debug("Tree-model canceled", slogs.GVR, t.gvr)
|
||||
|
||||
rate := initTreeRefreshRate
|
||||
for {
|
||||
|
|
@ -179,13 +180,13 @@ func (t *Tree) updater(ctx context.Context) {
|
|||
|
||||
func (t *Tree) refresh(ctx context.Context) {
|
||||
if !atomic.CompareAndSwapInt32(&t.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
slog.Debug("Dropping update...")
|
||||
return
|
||||
}
|
||||
defer atomic.StoreInt32(&t.inUpdate, 0)
|
||||
|
||||
if err := t.reconcile(ctx); err != nil {
|
||||
log.Error().Err(err).Msg("Reconcile failed")
|
||||
slog.Error("Reconcile failed", slogs.Error, err)
|
||||
t.fireTreeLoadFailed(err)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -14,7 +15,7 @@ import (
|
|||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/sahilm/fuzzy"
|
||||
)
|
||||
|
||||
|
|
@ -162,7 +163,7 @@ func (v *Values) Watch(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (v *Values) updater(ctx context.Context) {
|
||||
defer log.Debug().Msgf("YAML canceled -- %q", v.gvr)
|
||||
defer slog.Debug("YAML canceled", slogs.GVR, v.gvr)
|
||||
|
||||
backOff := NewExpBackOff(ctx, defaultReaderRefreshRate, maxReaderRetryInterval)
|
||||
delay := defaultReaderRefreshRate
|
||||
|
|
@ -174,7 +175,7 @@ func (v *Values) updater(ctx context.Context) {
|
|||
if err := v.refresh(ctx); err != nil {
|
||||
v.fireResourceFailed(err)
|
||||
if delay = backOff.NextBackOff(); delay == backoff.Stop {
|
||||
log.Error().Err(err).Msgf("giving up retrieving chart values")
|
||||
slog.Error("Giving up retrieving chart values", slogs.Error, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
|
@ -187,7 +188,7 @@ func (v *Values) updater(ctx context.Context) {
|
|||
|
||||
func (v *Values) refresh(ctx context.Context) error {
|
||||
if !atomic.CompareAndSwapInt32(&v.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
slog.Debug("Dropping update...")
|
||||
return nil
|
||||
}
|
||||
defer atomic.StoreInt32(&v.inUpdate, 0)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/sahilm/fuzzy"
|
||||
)
|
||||
|
||||
|
|
@ -121,7 +122,7 @@ func (y *YAML) Watch(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (y *YAML) updater(ctx context.Context) {
|
||||
defer log.Debug().Msgf("YAML canceled -- %q", y.gvr)
|
||||
defer slog.Debug("YAML canceled", slogs.GVR, y.gvr)
|
||||
|
||||
backOff := NewExpBackOff(ctx, defaultReaderRefreshRate, maxReaderRetryInterval)
|
||||
delay := defaultReaderRefreshRate
|
||||
|
|
@ -133,7 +134,7 @@ func (y *YAML) updater(ctx context.Context) {
|
|||
if err := y.refresh(ctx); err != nil {
|
||||
y.fireResourceFailed(err)
|
||||
if delay = backOff.NextBackOff(); delay == backoff.Stop {
|
||||
log.Error().Err(err).Msgf("YAML gave up!")
|
||||
slog.Error("YAML gave up!", slogs.Error, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
|
@ -146,7 +147,7 @@ func (y *YAML) updater(ctx context.Context) {
|
|||
|
||||
func (y *YAML) refresh(ctx context.Context) error {
|
||||
if !atomic.CompareAndSwapInt32(&y.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
slog.Debug("Dropping update...", slogs.GVR, y.gvr)
|
||||
return nil
|
||||
}
|
||||
defer atomic.StoreInt32(&y.inUpdate, 0)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ package model1
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
const ageCol = "AGE"
|
||||
|
|
@ -16,6 +17,7 @@ type Attrs struct {
|
|||
Align int
|
||||
Decorator DecoratorFunc
|
||||
Wide bool
|
||||
Show bool
|
||||
MX bool
|
||||
MXC, MXM bool
|
||||
Time bool
|
||||
|
|
@ -34,18 +36,20 @@ func (a Attrs) Merge(b Attrs) Attrs {
|
|||
if a.Align == 0 {
|
||||
a.Align = b.Align
|
||||
}
|
||||
if !a.Wide {
|
||||
|
||||
if !a.Hide {
|
||||
a.Hide = b.Hide
|
||||
}
|
||||
if !a.Show && !a.Wide {
|
||||
a.Wide = b.Wide
|
||||
}
|
||||
|
||||
if !a.Time {
|
||||
a.Time = b.Time
|
||||
}
|
||||
if !a.Capacity {
|
||||
a.Capacity = b.Capacity
|
||||
}
|
||||
if !a.Hide {
|
||||
a.Hide = b.Hide
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
|
@ -107,7 +111,7 @@ func (h Header) MapIndices(cols []string, wide bool) []int {
|
|||
for _, col := range cols {
|
||||
idx, ok := h.IndexOf(col, true)
|
||||
if !ok {
|
||||
log.Warn().Msgf("Column %q not found on resource", col)
|
||||
slog.Warn("Column not found on resource", slogs.ColName, col)
|
||||
}
|
||||
ii, cc[idx] = append(ii, idx), struct{}{}
|
||||
}
|
||||
|
|
@ -134,7 +138,7 @@ func (h Header) Customize(cols []string, wide bool) Header {
|
|||
for _, c := range cols {
|
||||
idx, ok := h.IndexOf(c, true)
|
||||
if !ok {
|
||||
log.Warn().Msgf("Column %s is not available on this resource", c)
|
||||
slog.Warn("Column is not available on this resource", slogs.ColName, c)
|
||||
cc = append(cc, HeaderColumn{Name: c})
|
||||
continue
|
||||
}
|
||||
|
|
@ -232,8 +236,8 @@ func (h Header) IndexOf(colName string, includeWide bool) (int, bool) {
|
|||
|
||||
// Dump for debugging.
|
||||
func (h Header) Dump() {
|
||||
log.Debug().Msgf("HEADER")
|
||||
slog.Debug("HEADER")
|
||||
for i, c := range h {
|
||||
log.Debug().Msgf("%d %q -- %t", i, c.Name, c.Wide)
|
||||
slog.Debug(fmt.Sprintf("%d %q -- %t", i, c.Name, c.Wide))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ package model1
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sort"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type ReRangeFn func(int, RowEvent) bool
|
||||
|
|
@ -274,11 +273,11 @@ func (r *RowEvents) Sort(ns string, sortCol int, isDuration, numCol, isCapacity,
|
|||
r.reindex()
|
||||
}
|
||||
|
||||
// For debguging...
|
||||
// For debugging...
|
||||
func (re RowEvents) Dump(msg string) {
|
||||
log.Debug().Msg(msg)
|
||||
slog.Debug("[DEBUG] RowEvents" + msg)
|
||||
for _, r := range re.events {
|
||||
log.Debug().Msgf("!!YO!! %#v", r)
|
||||
slog.Debug(fmt.Sprintf(" %#v", r))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -14,7 +15,7 @@ import (
|
|||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/sahilm/fuzzy"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -155,7 +156,7 @@ func (t *TableData) Filter(f FilterOpts) *TableData {
|
|||
if err == nil {
|
||||
td.rowEvents = rr
|
||||
} else {
|
||||
log.Error().Err(err).Msg("rx filter failed")
|
||||
slog.Error("RX filter failed", slogs.Error, err)
|
||||
}
|
||||
|
||||
return td
|
||||
|
|
@ -206,12 +207,11 @@ func (t *TableData) fuzzyFilter(q string) *RowEvents {
|
|||
mm := fuzzy.Find(q, ss)
|
||||
rr := NewRowEvents(t.RowCount() / 2)
|
||||
for _, m := range mm {
|
||||
re, ok := t.rowEvents.At(m.Index)
|
||||
if !ok {
|
||||
log.Error().Msgf("unable to find event for index in fuzzfilter: %d", m.Index)
|
||||
continue
|
||||
if re, ok := t.rowEvents.At(m.Index); !ok {
|
||||
slog.Error("Unable to find event for index in fuzzfilter", slogs.Index, m.Index)
|
||||
} else {
|
||||
rr.Add(re)
|
||||
}
|
||||
rr.Add(re)
|
||||
}
|
||||
|
||||
return rr
|
||||
|
|
@ -474,7 +474,10 @@ func (t *TableData) Delete(newKeys map[string]struct{}) {
|
|||
})
|
||||
for _, id := range victims {
|
||||
if err := t.rowEvents.Delete(id); err != nil {
|
||||
log.Error().Err(err).Msgf("table delete failed: %q", id)
|
||||
slog.Error("Table delete failed",
|
||||
slogs.Error, err,
|
||||
slogs.Message, id,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@
|
|||
package model1
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestTableDataComputeSortCol(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -16,11 +17,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/data"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/rakyll/hey/requester"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -59,7 +60,7 @@ func (b *Benchmark) init(base, version string) error {
|
|||
req.SetBasicAuth(b.config.Auth.User, b.config.Auth.Password)
|
||||
}
|
||||
req.Header = b.config.HTTP.Headers
|
||||
log.Debug().Msgf("Benchmarking Request %s", req.URL.String())
|
||||
slog.Debug("Benchmarking Request", slogs.URL, req.URL.String())
|
||||
|
||||
ua := req.UserAgent()
|
||||
if ua == "" {
|
||||
|
|
@ -73,8 +74,7 @@ func (b *Benchmark) init(base, version string) error {
|
|||
}
|
||||
req.Header.Set("User-Agent", ua)
|
||||
|
||||
log.Debug().Msgf("Using bench config N:%d--C:%d", b.config.N, b.config.C)
|
||||
|
||||
slog.Debug(fmt.Sprintf("Using bench config N:%d--C:%d", b.config.N, b.config.C))
|
||||
b.worker = &requester.Work{
|
||||
Request: req,
|
||||
RequestBody: []byte(b.config.HTTP.Body),
|
||||
|
|
@ -108,7 +108,10 @@ func (b *Benchmark) Canceled() bool {
|
|||
|
||||
// Run starts a benchmark.
|
||||
func (b *Benchmark) Run(cluster, context string, done func()) {
|
||||
log.Debug().Msgf("Running benchmark on context %s", cluster)
|
||||
slog.Debug("Running benchmark",
|
||||
slogs.Cluster, cluster,
|
||||
slogs.Context, context,
|
||||
)
|
||||
buff := new(bytes.Buffer)
|
||||
b.worker.Writer = buff
|
||||
// this call will block until the benchmark is complete or times out.
|
||||
|
|
@ -116,7 +119,7 @@ func (b *Benchmark) Run(cluster, context string, done func()) {
|
|||
b.worker.Stop()
|
||||
if buff.Len() > 0 {
|
||||
if err := b.save(cluster, context, buff); err != nil {
|
||||
log.Error().Err(err).Msg("Saving Benchmark")
|
||||
slog.Error("Saving Benchmark", slogs.Error, err)
|
||||
}
|
||||
}
|
||||
done()
|
||||
|
|
@ -141,7 +144,10 @@ func (b *Benchmark) save(cluster, context string, r io.Reader) error {
|
|||
}
|
||||
defer func() {
|
||||
if e := f.Close(); e != nil {
|
||||
log.Error().Err(e).Msgf("Benchmark file close failed: %q", bf)
|
||||
slog.Error("Benchmark file close failed",
|
||||
slogs.Error, e,
|
||||
slogs.Path, bf,
|
||||
)
|
||||
}
|
||||
}()
|
||||
if _, err = io.Copy(f, r); err != nil {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,16 @@ package port
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
// PortTunnels represents a collection of tunnels.
|
||||
type PortTunnels []PortTunnel
|
||||
|
||||
// CheckAvailable checks if all port tunnels are available.
|
||||
func (t PortTunnels) CheckAvailable() error {
|
||||
for _, pt := range t {
|
||||
if !IsPortFree(pt) {
|
||||
|
|
@ -26,6 +30,7 @@ type PortTunnel struct {
|
|||
Address, Container, LocalPort, ContainerPort string
|
||||
}
|
||||
|
||||
// NewPortTunnel returns a new instance.
|
||||
func NewPortTunnel(a, co, lp, cp string) PortTunnel {
|
||||
return PortTunnel{
|
||||
Address: a,
|
||||
|
|
@ -45,13 +50,17 @@ func (t PortTunnel) PortMap() string {
|
|||
if t.LocalPort == "" {
|
||||
t.LocalPort = t.ContainerPort
|
||||
}
|
||||
|
||||
return t.LocalPort + ":" + t.ContainerPort
|
||||
}
|
||||
|
||||
// IsPortFree checks if a address/port pair is available on host.
|
||||
func IsPortFree(t PortTunnel) bool {
|
||||
s, err := net.Listen("tcp", fmt.Sprintf("%s:%s", t.Address, t.LocalPort))
|
||||
if err != nil {
|
||||
slog.Warn("Port is not available", slogs.Port, t.LocalPort, slogs.Address, t.Address)
|
||||
return false
|
||||
}
|
||||
|
||||
return s.Close() == nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ package render
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
|
|
@ -36,13 +37,14 @@ func (Alias) Render(o interface{}, ns string, r *model1.Row) error {
|
|||
return fmt.Errorf("expected AliasRes, but got %T", o)
|
||||
}
|
||||
|
||||
slices.Sort(a.Aliases)
|
||||
gvr := client.NewGVR(a.GVR)
|
||||
r.ID = gvr.String()
|
||||
r.Fields = append(r.Fields,
|
||||
gvr.R(),
|
||||
gvr.G(),
|
||||
gvr.V(),
|
||||
strings.Join(a.Aliases, ","),
|
||||
strings.Join(a.Aliases, " "),
|
||||
)
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func TestAliasRender(t *testing.T) {
|
|||
assert.Nil(t, a.Render(o, "fred/v1/blee", &r))
|
||||
assert.Equal(t, model1.Row{
|
||||
ID: "fred/v1/blee",
|
||||
Fields: model1.Fields{"blee", "fred", "v1", "a,b,c"},
|
||||
Fields: model1.Fields{"blee", "fred", "v1", "a b c"},
|
||||
}, r)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
package render
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
)
|
||||
|
||||
// DecoratorFunc decorates a string.
|
||||
|
|
@ -48,7 +50,7 @@ func (b *Base) SetViewSetting(vs *config.ViewSetting) {
|
|||
}
|
||||
specs, err := NewColsSpecs(cols...).parseSpecs()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("unable to grok custom columns")
|
||||
slog.Error("Unable to grok custom columns", slogs.Error, err)
|
||||
return
|
||||
}
|
||||
b.specs = specs
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@
|
|||
package render
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
slog.SetDefault(slog.New(slog.DiscardHandler))
|
||||
}
|
||||
|
||||
func TestAugmentRow(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ func (Container) defaultHeader() model1.Header {
|
|||
model1.HeaderColumn{Name: "PROBES(L:R:S)"},
|
||||
model1.HeaderColumn{Name: "CPU", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "MEM", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "CPU/R:L", Attrs: model1.Attrs{Align: tview.AlignRight}},
|
||||
model1.HeaderColumn{Name: "MEM/R:L", Attrs: model1.Attrs{Align: tview.AlignRight}},
|
||||
model1.HeaderColumn{Name: "CPU/RL", Attrs: model1.Attrs{Align: tview.AlignRight}},
|
||||
model1.HeaderColumn{Name: "MEM/RL", Attrs: model1.Attrs{Align: tview.AlignRight}},
|
||||
model1.HeaderColumn{Name: "%CPU/R", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "%CPU/L", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
model1.HeaderColumn{Name: "%MEM/R", Attrs: model1.Attrs{Align: tview.AlignRight, MX: true}},
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ package render
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/derailed/tcell/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
|
|
@ -88,8 +89,8 @@ func NewNamedContext(c ContextNamer, n string, ctx *api.Context) *NamedContext {
|
|||
func (c *NamedContext) IsCurrentContext(n string) bool {
|
||||
cl, err := c.Config.CurrentContextName()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Fetching current context")
|
||||
return false
|
||||
slog.Error("Fail to retrieve current context. Exiting!")
|
||||
os.Exit(1)
|
||||
}
|
||||
return cl == n
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ package render
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -84,7 +85,7 @@ func (c CustomResourceDefinition) defaultRow(raw *unstructured.Unstructured, r *
|
|||
}
|
||||
}
|
||||
if len(versions) == 0 {
|
||||
log.Warn().Msgf("unable to assert CRD versions for %s", crd.Name)
|
||||
slog.Warn("Unable to assert CRD versions", slogs.FQN, crd.Name)
|
||||
}
|
||||
|
||||
r.ID = client.MetaFQN(crd.ObjectMeta)
|
||||
|
|
|
|||
|
|
@ -5,14 +5,16 @@ package render
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
|
||||
"github.com/derailed/k9s/internal/model1"
|
||||
"github.com/derailed/k9s/internal/slogs"
|
||||
"github.com/derailed/tview"
|
||||
"k8s.io/kubectl/pkg/cmd/get"
|
||||
)
|
||||
|
||||
var fullRX = regexp.MustCompile(`^([\w\s%\/-]+)\:?([\w\d\S\W]*?)\|?([N|T|W|R|L|H]{0,3})$`)
|
||||
var fullRX = regexp.MustCompile(`^([\w\s%\/-]+)\:?([\w\d\S\W]*?)\|?([N|T|W|V|R|L|H]{0,3})$`)
|
||||
|
||||
type colAttr byte
|
||||
|
||||
|
|
@ -20,6 +22,7 @@ const (
|
|||
number colAttr = 'N'
|
||||
age colAttr = 'T'
|
||||
wide colAttr = 'W'
|
||||
show colAttr = 'V'
|
||||
alignLeft colAttr = 'L'
|
||||
alignRight colAttr = 'R'
|
||||
hide colAttr = 'H'
|
||||
|
|
@ -32,6 +35,7 @@ type colAttrs struct {
|
|||
mxm bool
|
||||
time bool
|
||||
wide bool
|
||||
show bool
|
||||
hide bool
|
||||
capacity bool
|
||||
}
|
||||
|
|
@ -46,7 +50,9 @@ func newColFlags(flags string) colAttrs {
|
|||
case hide:
|
||||
c.hide = true
|
||||
case wide:
|
||||
c.wide = true
|
||||
c.wide, c.show = true, false
|
||||
case show:
|
||||
c.show, c.wide = true, false
|
||||
case alignLeft:
|
||||
c.align = tview.AlignLeft
|
||||
case alignRight:
|
||||
|
|
@ -55,6 +61,8 @@ func newColFlags(flags string) colAttrs {
|
|||
c.time = true
|
||||
case number:
|
||||
c.capacity, c.align = true, tview.AlignRight
|
||||
default:
|
||||
slog.Warn("Unknown column attribute", slogs.Attr, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,8 +77,6 @@ type colDef struct {
|
|||
spec string
|
||||
}
|
||||
|
||||
// TAG:.spec.containers[0].image|split(":")|.[-1]|TW
|
||||
|
||||
func parse(s string) (colDef, error) {
|
||||
mm := fullRX.FindStringSubmatch(s)
|
||||
if len(mm) == 4 {
|
||||
|
|
@ -95,6 +101,7 @@ func (c colDef) toHeaderCol() model1.HeaderColumn {
|
|||
Attrs: model1.Attrs{
|
||||
Align: c.align,
|
||||
Wide: c.wide,
|
||||
Show: c.show,
|
||||
Time: c.time,
|
||||
MX: c.mx,
|
||||
MXC: c.mxc,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue