k9s/internal/render/rbac.go

179 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package render
import (
"fmt"
"strings"
"github.com/gdamore/tcell/v2"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const allVerbs = "*"
var (
k8sVerbs = []string{
"get",
"list",
"watch",
"create",
"patch",
"update",
"delete",
"deletecollection",
}
httpTok8sVerbs = map[string]string{
"post": "create",
"put": "update",
}
)
// Rbac renders a rbac to screen.
type Rbac struct {
Base
}
// ColorerFunc colors a resource row.
func (Rbac) ColorerFunc() ColorerFunc {
return func(_ string, _ Header, _re RowEvent) tcell.Color {
return tcell.ColorMediumSpringGreen
}
}
// Header returns a header row.
func (Rbac) Header(ns string) Header {
h := make(Header, 0, 10)
h = append(h,
HeaderColumn{Name: "NAME"},
HeaderColumn{Name: "APIGROUP"},
)
h = append(h, rbacVerbHeader()...)
return append(h, HeaderColumn{Name: "VALID", Wide: true})
}
// Render renders a K8s resource to screen.
func (r Rbac) Render(o interface{}, ns string, ro *Row) error {
p, ok := o.(PolicyRes)
if !ok {
return fmt.Errorf("expecting RuleRes but got %T", o)
}
ro.ID = p.Resource
ro.Fields = make(Fields, 0, len(r.Header(ns)))
ro.Fields = append(ro.Fields,
cleanseResource(p.Resource),
p.Group,
)
ro.Fields = append(ro.Fields, asVerbs(p.Verbs)...)
ro.Fields = append(ro.Fields, "")
return nil
}
// ----------------------------------------------------------------------------
// Helpers...
func asVerbs(verbs []string) []string {
const (
verbLen = 4
unknownLen = 30
)
r := make([]string, 0, len(k8sVerbs)+1)
for _, v := range k8sVerbs {
r = append(r, toVerbIcon(hasVerb(verbs, v)))
}
var unknowns []string
for _, v := range verbs {
if hv, ok := httpTok8sVerbs[v]; ok {
v = hv
}
if !hasVerb(k8sVerbs, v) && v != allVerbs {
unknowns = append(unknowns, v)
}
}
return append(r, Truncate(strings.Join(unknowns, ","), unknownLen))
}
func toVerbIcon(ok bool) string {
if ok {
return "[green::b] ✓ [::]"
}
return "[orangered::b] × [::]"
}
func hasVerb(verbs []string, verb string) bool {
if len(verbs) == 1 && verbs[0] == allVerbs {
return true
}
for _, v := range verbs {
if hv, ok := httpTok8sVerbs[v]; ok {
if hv == verb {
return true
}
}
if v == verb {
return true
}
}
return false
}
// RuleRes represents an rbac rule.
type RuleRes struct {
Resource, Group string
ResourceName string
NonResourceURL string
Verbs []string
}
// NewRuleRes returns a new rule.
func NewRuleRes(res, grp string, vv []string) RuleRes {
return RuleRes{
Resource: res,
Group: grp,
Verbs: vv,
}
}
// GetObjectKind returns a schema object.
func (r RuleRes) GetObjectKind() schema.ObjectKind {
return nil
}
// DeepCopyObject returns a container copy.
func (r RuleRes) DeepCopyObject() runtime.Object {
return r
}
// Rules represents a collection of rules.
type Rules []RuleRes
// Upsert adds a new rule.
func (rr Rules) Upsert(r RuleRes) Rules {
idx, ok := rr.find(r.Resource)
if !ok {
return append(rr, r)
}
rr[idx] = r
return rr
}
// Find locates a row by id. Returns false is not found.
func (rr Rules) find(res string) (int, bool) {
for i, r := range rr {
if r.Resource == res {
return i, true
}
}
return 0, false
}