Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add customizable workload GVRs #3028

92 changes: 92 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,98 @@ k9s:

---

## Custom Workload View

You can customize the workload view with CRDs or any resources you want to see on this view.

To do so, you will need to update your config to add a new field `workloadGVRs` following this pattern:
```
k9s:
workloadGVRs:
- name: "v1/pods"
- name: "test.com/v1alpha1/myCRD"
status:
cellName: "State"
readiness:
cellName: "Current"
# The cellExtraName will be added as `cellName/cellExtraName`
cellExtraName: "Desired"
validity:
replicas:
cellCurrentName: "Current"
cellDesiredName: "Desired"
matchs:
- cellName: "State"
cellValue: "Ready"
- name: "external-secrets.io/v1beta1/externalsecrets"
status:
na: true
validity:
matchs:
- cellName: Ready
cellValue: True
- cellName: Status
cellValue: SecretSynced
```
The first one (`v1/pods`) will be recognized by k9s and will set it's default values for the readiness, validity and status.

The second one (`test.com/v1alpha1/myCRD`) will be an unknown GVR, it will use this configuration to be shown on the workload view.

The third one (`external-secrets.io/v1beta1/externalsecrets`) will be an unknown GVR, it will use this configuration to be shown on the workload view, but as the readiness is not set, it will use the default values it. About the status, it's set as `na: true` not applicable (for example the secrets does not need a status).

The default values applied for an unknown GVR are if they are not set and if they are not flagged as not applicable are:
```
status:
cellName: "Status"
validity:
matchs:
- cellName: "Ready"
cellValue: "True"
readiness:
cellName: "Ready"
```

The known GVRs from k9s are:
```
- v1/pods
- apps/v1/replicasets
- v1/serviceaccounts
- v1/persistentvolumeclaims
- scheduling.k8s.io/v1/priorityclasses
- v1/configmaps
- v1/secrets
- v1/services
- apps/v1/daemonsets
- apps/v1/statefulSets
```

The full structure about the configuration is:
```
workloadGVRs:
- name: string
status:
cellName: string
na: bool
readiness:
cellName: string
cellExtraName: string
na: bool
validity:
matchs:
- cellName: string
cellValue: string
- cellName: string
cellValue: string
...
replicas:
cellCurrentName: string
cellDesiredName: string
cellAllName: string
na: bool
```

---

## Contributors

Without the contributions from these fine folks, this project would be a total dud!
Expand Down
48 changes: 48 additions & 0 deletions internal/config/json/schemas/k9s.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,54 @@
}
}
}
},
"workloadGVRs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"status": {
"type":"object",
"properties": {
"cellName": {"type": "string"},
"na": {"type": "boolean"}
}
},
"readiness": {
"type": "object",
"properties": {
"cellName": {"type": "string"},
"cellExtraName": {"type": "string"},
"na": {"type": "boolean"}
}
},
"validity": {
"type": "object",
"properties": {
"matchs": {
"type": "array",
"items": {
"type" :"object",
"properties": {
"cellName": {"type": "string"},
"cellValue": {"type": "string"}
}
}
},
"replicas": {
"type": "object",
"properties": {
"cellCurrentName": {"type":"string"},
"cellDesiredName": {"type":"string"},
"cellAllName": {"type":"string"}
}
},
"na": {"type": "boolean"}
}
}
}
}
}
}
}
Expand Down
31 changes: 18 additions & 13 deletions internal/config/k9s.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@ import (

// K9s tracks K9s configuration options.
type K9s struct {
LiveViewAutoRefresh bool `json:"liveViewAutoRefresh" yaml:"liveViewAutoRefresh"`
ScreenDumpDir string `json:"screenDumpDir" yaml:"screenDumpDir,omitempty"`
RefreshRate int `json:"refreshRate" yaml:"refreshRate"`
MaxConnRetry int `json:"maxConnRetry" yaml:"maxConnRetry"`
ReadOnly bool `json:"readOnly" yaml:"readOnly"`
NoExitOnCtrlC bool `json:"noExitOnCtrlC" yaml:"noExitOnCtrlC"`
UI UI `json:"ui" yaml:"ui"`
SkipLatestRevCheck bool `json:"skipLatestRevCheck" yaml:"skipLatestRevCheck"`
DisablePodCounting bool `json:"disablePodCounting" yaml:"disablePodCounting"`
ShellPod ShellPod `json:"shellPod" yaml:"shellPod"`
ImageScans ImageScans `json:"imageScans" yaml:"imageScans"`
Logger Logger `json:"logger" yaml:"logger"`
Thresholds Threshold `json:"thresholds" yaml:"thresholds"`
LiveViewAutoRefresh bool `json:"liveViewAutoRefresh" yaml:"liveViewAutoRefresh"`
ScreenDumpDir string `json:"screenDumpDir" yaml:"screenDumpDir,omitempty"`
RefreshRate int `json:"refreshRate" yaml:"refreshRate"`
MaxConnRetry int `json:"maxConnRetry" yaml:"maxConnRetry"`
ReadOnly bool `json:"readOnly" yaml:"readOnly"`
NoExitOnCtrlC bool `json:"noExitOnCtrlC" yaml:"noExitOnCtrlC"`
UI UI `json:"ui" yaml:"ui"`
SkipLatestRevCheck bool `json:"skipLatestRevCheck" yaml:"skipLatestRevCheck"`
DisablePodCounting bool `json:"disablePodCounting" yaml:"disablePodCounting"`
ShellPod ShellPod `json:"shellPod" yaml:"shellPod"`
ImageScans ImageScans `json:"imageScans" yaml:"imageScans"`
Logger Logger `json:"logger" yaml:"logger"`
Thresholds Threshold `json:"thresholds" yaml:"thresholds"`
WorkloadGVRs []WorkloadGVR `json:"workloadGVRs,omitempty" yaml:"workloadGVRs,omitempty"`
manualRefreshRate int
manualHeadless *bool
manualLogoless *bool
Expand All @@ -56,6 +57,7 @@ func NewK9s(conn client.Connection, ks data.KubeSettings) *K9s {
Thresholds: NewThreshold(),
ShellPod: NewShellPod(),
ImageScans: NewImageScans(),
WorkloadGVRs: NewWorkloadGVRs(),
dir: data.NewDir(AppContextsDir),
conn: conn,
ks: ks,
Expand Down Expand Up @@ -108,6 +110,9 @@ func (k *K9s) Merge(k1 *K9s) {
if k1.Thresholds != nil {
k.Thresholds = k1.Thresholds
}
if k1.WorkloadGVRs != nil {
k.WorkloadGVRs = k1.WorkloadGVRs
}
}

// AppScreenDumpDir fetch screen dumps dir.
Expand Down
3 changes: 3 additions & 0 deletions internal/config/k9s_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ func TestK9sMerge(t *testing.T) {
ImageScans: config.ImageScans{},
Logger: config.Logger{},
Thresholds: nil,
WorkloadGVRs: nil,
},
k2: &config.K9s{
LiveViewAutoRefresh: true,
MaxConnRetry: 100,
ShellPod: config.NewShellPod(),
WorkloadGVRs: nil,
},
ek: &config.K9s{
LiveViewAutoRefresh: true,
Expand All @@ -118,6 +120,7 @@ func TestK9sMerge(t *testing.T) {
ImageScans: config.ImageScans{},
Logger: config.Logger{},
Thresholds: nil,
WorkloadGVRs: nil,
},
},
}
Expand Down
71 changes: 71 additions & 0 deletions internal/config/testdata/configs/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,74 @@ k9s:
memory:
critical: 90
warn: 70
workloadGVRs:
- name: apps/v1/daemonsets
readiness:
na: false
cellName: Ready
cellExtraName: Desired
validity:
na: false
replicas:
cellCurrentName: Ready
cellDesiredName: Desired
cellAllName: ""
- name: apps/v1/deployments
readiness:
na: false
cellName: Ready
cellExtraName: ""
validity:
na: false
replicas:
cellCurrentName: ""
cellDesiredName: ""
cellAllName: Ready
- name: apps/v1/replicasets
readiness:
na: false
cellName: Current
cellExtraName: Desired
validity:
na: false
replicas:
cellCurrentName: Current
cellDesiredName: Desired
cellAllName: ""
- name: apps/v1/statefulSets
status:
na: false
cellName: Ready
readiness:
na: false
cellName: Ready
cellExtraName: ""
validity:
na: false
replicas:
cellCurrentName: ""
cellDesiredName: ""
cellAllName: Ready
- name: scheduling.k8s.io/v1/priorityclasses
- name: v1/configmaps
- name: v1/persistentvolumeclaims
- name: v1/pods
status:
na: false
cellName: Status
readiness:
na: false
cellName: Ready
cellExtraName: ""
validity:
na: false
matchs:
- cellName: Status
cellValue: Running
replicas:
cellCurrentName: ""
cellDesiredName: ""
cellAllName: Ready
- name: v1/secrets
- name: v1/serviceaccounts
- name: v1/services
71 changes: 71 additions & 0 deletions internal/config/testdata/configs/expected.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,74 @@ k9s:
memory:
critical: 90
warn: 70
workloadGVRs:
- name: apps/v1/daemonsets
readiness:
na: false
cellName: Ready
cellExtraName: Desired
validity:
na: false
replicas:
cellCurrentName: Ready
cellDesiredName: Desired
cellAllName: ""
- name: apps/v1/deployments
readiness:
na: false
cellName: Ready
cellExtraName: ""
validity:
na: false
replicas:
cellCurrentName: ""
cellDesiredName: ""
cellAllName: Ready
- name: apps/v1/replicasets
readiness:
na: false
cellName: Current
cellExtraName: Desired
validity:
na: false
replicas:
cellCurrentName: Current
cellDesiredName: Desired
cellAllName: ""
- name: apps/v1/statefulSets
status:
na: false
cellName: Ready
readiness:
na: false
cellName: Ready
cellExtraName: ""
validity:
na: false
replicas:
cellCurrentName: ""
cellDesiredName: ""
cellAllName: Ready
- name: scheduling.k8s.io/v1/priorityclasses
- name: v1/configmaps
- name: v1/persistentvolumeclaims
- name: v1/pods
status:
na: false
cellName: Status
readiness:
na: false
cellName: Ready
cellExtraName: ""
validity:
na: false
matchs:
- cellName: Status
cellValue: Running
replicas:
cellCurrentName: ""
cellDesiredName: ""
cellAllName: Ready
- name: v1/secrets
- name: v1/serviceaccounts
- name: v1/services
Loading