package render import ( "encoding/json" "errors" "fmt" "strings" "github.com/derailed/k9s/internal/client" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" ) const ageTableCol = "Age" // Generic renders a generic resource to screen. type Generic struct { table *metav1beta1.Table ageIndex int } // Happy returns true if resource is happy, false otherwise. func (Generic) Happy(ns string, r Row) bool { return true } // SetTable sets the tabular resource. func (g *Generic) SetTable(t *metav1beta1.Table) { g.table = t } // ColorerFunc colors a resource row. func (Generic) ColorerFunc() ColorerFunc { return DefaultColorer } // Header returns a header row. func (g *Generic) Header(ns string) Header { if g.table == nil { return Header{} } h := make(Header, 0, len(g.table.ColumnDefinitions)) h = append(h, HeaderColumn{Name: "NAMESPACE"}) for i, c := range g.table.ColumnDefinitions { if c.Name == ageTableCol { g.ageIndex = i continue } h = append(h, HeaderColumn{Name: strings.ToUpper(c.Name)}) } if g.ageIndex > 0 { h = append(h, HeaderColumn{Name: "AGE", Time: true}) } return h } // Render renders a K8s resource to screen. func (g *Generic) Render(o interface{}, ns string, r *Row) error { row, ok := o.(metav1beta1.TableRow) if !ok { return fmt.Errorf("expecting a TableRow but got %T", o) } nns, name, err := resourceNS(row.Object.Raw) if err != nil { return err } if !ok { return fmt.Errorf("expecting row 0 to be a string but got %T", row.Cells[0]) } r.ID = client.FQN(nns, name) r.Fields = make(Fields, 0, len(g.Header(ns))) r.Fields = append(r.Fields, nns) var ageCell interface{} for i, c := range row.Cells { if g.ageIndex > 0 && i == g.ageIndex { ageCell = c continue } if c == nil { r.Fields = append(r.Fields, Blank) continue } r.Fields = append(r.Fields, fmt.Sprintf("%v", c)) } if ageCell != nil { r.Fields = append(r.Fields, fmt.Sprintf("%v", ageCell)) } return nil } // ---------------------------------------------------------------------------- // Helpers... func resourceNS(raw []byte) (string, string, error) { var obj map[string]interface{} var ns, name string err := json.Unmarshal(raw, &obj) if err != nil { return ns, name, err } meta, ok := obj["metadata"].(map[string]interface{}) if !ok { return ns, name, errors.New("no metadata found on generic resource") } ina, ok := meta["name"] if !ok { return ns, name, errors.New("unable to extract resource name") } name, ok = ina.(string) if !ok { return ns, name, fmt.Errorf("expecting name string type but got %T", ns) } ins, ok := meta["namespace"] if !ok { return client.ClusterScope, name, nil } ns, ok = ins.(string) if !ok { return ns, name, fmt.Errorf("expecting namespace string type but got %T", ns) } return ns, name, nil }