162 lines
4.2 KiB
Go
162 lines
4.2 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright Authors of K9s
|
|
package dao
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/derailed/k9s/internal"
|
|
"github.com/derailed/k9s/internal/client"
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/client-go/rest"
|
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
)
|
|
|
|
type Dynamic struct {
|
|
Generic
|
|
}
|
|
|
|
// Get returns a given resource as a table object.
|
|
func (d *Dynamic) Get(ctx context.Context, path string) (runtime.Object, error) {
|
|
oo, err := d.toTable(ctx, path)
|
|
if err != nil || len(oo) == 0 {
|
|
return nil, err
|
|
}
|
|
|
|
return oo[0], nil
|
|
}
|
|
|
|
// List returns a collection of resources as one or more table objects.
|
|
func (d *Dynamic) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
|
return d.toTable(ctx, ns+"/")
|
|
}
|
|
|
|
func (d *Dynamic) toTable(ctx context.Context, fqn string) ([]runtime.Object, error) {
|
|
strLabel, _ := ctx.Value(internal.KeyLabels).(string)
|
|
|
|
opts := []string{d.gvr.AsResourceName()}
|
|
ns, n := client.Namespaced(fqn)
|
|
if n != "" {
|
|
opts = append(opts, n)
|
|
}
|
|
|
|
allNS := client.IsAllNamespaces(ns)
|
|
flags := cmdutil.NewMatchVersionFlags(d.getFactory().Client().Config().Flags())
|
|
f := cmdutil.NewFactory(flags)
|
|
b := f.NewBuilder().
|
|
Unstructured().
|
|
NamespaceParam(ns).DefaultNamespace().AllNamespaces(allNS).
|
|
LabelSelectorParam(strLabel).
|
|
FieldSelectorParam("").
|
|
RequestChunksOf(0).
|
|
ResourceTypeOrNameArgs(true, opts...).
|
|
ContinueOnError().
|
|
Latest().
|
|
Flatten().
|
|
TransformRequests(d.transformRequests).
|
|
Do()
|
|
if err := b.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
infos, err := b.Infos()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
oo := make([]runtime.Object, 0, len(infos))
|
|
for _, info := range infos {
|
|
o, err := decodeIntoTable(info.Object, allNS)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
oo = append(oo, o.(*metav1.Table))
|
|
}
|
|
|
|
return oo, nil
|
|
}
|
|
|
|
var recognizedTableVersions = map[schema.GroupVersionKind]bool{
|
|
metav1beta1.SchemeGroupVersion.WithKind("Table"): true,
|
|
metav1.SchemeGroupVersion.WithKind("Table"): true,
|
|
}
|
|
|
|
func decodeIntoTable(obj runtime.Object, allNs bool) (runtime.Object, error) {
|
|
event, isEvent := obj.(*metav1.WatchEvent)
|
|
if isEvent {
|
|
obj = event.Object.Object
|
|
}
|
|
|
|
if !recognizedTableVersions[obj.GetObjectKind().GroupVersionKind()] {
|
|
return nil, fmt.Errorf("attempt to decode non-Table object: %v", obj.GetObjectKind().GroupVersionKind())
|
|
}
|
|
|
|
u, ok := obj.(*unstructured.Unstructured)
|
|
if !ok {
|
|
return nil, fmt.Errorf("attempt to decode non-Unstructured object")
|
|
}
|
|
var table metav1.Table
|
|
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &table); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if allNs {
|
|
defs := make([]metav1.TableColumnDefinition, 0, len(table.ColumnDefinitions)+1)
|
|
defs = append(defs, metav1.TableColumnDefinition{Name: "Namespace", Type: "string"})
|
|
defs = append(defs, table.ColumnDefinitions...)
|
|
table.ColumnDefinitions = defs
|
|
}
|
|
|
|
for i := range table.Rows {
|
|
row := &table.Rows[i]
|
|
if row.Object.Raw == nil || row.Object.Object != nil {
|
|
continue
|
|
}
|
|
converted, err := runtime.Decode(unstructured.UnstructuredJSONScheme, row.Object.Raw)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
row.Object.Object = converted
|
|
var m metav1.Object
|
|
if obj := row.Object.Object; obj != nil {
|
|
m, _ = meta.Accessor(obj)
|
|
}
|
|
var ns string
|
|
if m != nil {
|
|
ns = m.GetNamespace()
|
|
}
|
|
if allNs {
|
|
cells := make([]interface{}, 0, len(row.Cells)+1)
|
|
cells = append(cells, ns)
|
|
cells = append(cells, row.Cells...)
|
|
row.Cells = cells
|
|
}
|
|
}
|
|
|
|
if isEvent {
|
|
event.Object.Object = &table
|
|
return event, nil
|
|
}
|
|
|
|
return &table, nil
|
|
}
|
|
|
|
func (d *Dynamic) transformRequests(req *rest.Request) {
|
|
req.SetHeader("Accept", strings.Join([]string{
|
|
fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1.SchemeGroupVersion.Version, metav1.GroupName),
|
|
fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName),
|
|
"application/json",
|
|
}, ","))
|
|
|
|
if d.includeObj {
|
|
req.Param("includeObject", "Object")
|
|
}
|
|
}
|