Skip to content
This repository has been archived by the owner on Jan 19, 2023. It is now read-only.

Handle mutliple CRD versions #490

Merged
merged 1 commit into from Dec 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelogs/unreleased/405-bryanl
@@ -0,0 +1 @@
Support v1 and v1beta1 CRD API
4 changes: 4 additions & 0 deletions internal/api/content_manager.go
Expand Up @@ -97,6 +97,10 @@ func (cm *ContentManager) runUpdate(state octant.State, s OctantClient) PollerFu

contentResponse, _, err := cm.contentGenerateFunc(ctx, state)
if err != nil {
cm.logger.
WithErr(err).
With("content-path", contentPath).
Errorf("generate content")
return false
}

Expand Down
31 changes: 21 additions & 10 deletions internal/describer/crd.go
Expand Up @@ -7,16 +7,17 @@ package describer

import (
"context"
"fmt"

"github.com/pkg/errors"
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"

"github.com/vmware-tanzu/octant/internal/config"
"github.com/vmware-tanzu/octant/internal/gvk"
"github.com/vmware-tanzu/octant/internal/link"
"github.com/vmware-tanzu/octant/internal/modules/overview/yamlviewer"
"github.com/vmware-tanzu/octant/internal/octant"
"github.com/vmware-tanzu/octant/internal/printer"
"github.com/vmware-tanzu/octant/internal/queryer"
"github.com/vmware-tanzu/octant/internal/resourceviewer"
Expand All @@ -25,7 +26,7 @@ import (
"github.com/vmware-tanzu/octant/pkg/view/component"
)

type crdPrinter func(ctx context.Context, crd *apiextv1beta1.CustomResourceDefinition, object *unstructured.Unstructured, options printer.Options) (component.Component, error)
type crdPrinter func(ctx context.Context, crd, object *unstructured.Unstructured, options printer.Options) (component.Component, error)
type resourceViewerPrinter func(ctx context.Context, object *unstructured.Unstructured, dashConfig config.Dash, q queryer.Queryer) (component.Component, error)
type yamlPrinter func(runtime.Object) (*component.YAML, error)

Expand Down Expand Up @@ -66,14 +67,24 @@ func (c *crd) Describe(ctx context.Context, namespace string, options Options) (
return component.EmptyContentResponse, err
}

// TODO: crd.Spec.Version is incorrect. Use crd.Spec.Version instead.
gvk := schema.GroupVersionKind{
Group: crd.Spec.Group,
Version: crd.Spec.Version,
Kind: crd.Spec.Names.Kind,
octantCRD, err := octant.NewCustomResourceDefinition(crd)
if err != nil {
return component.EmptyContentResponse, err
}

crdVersions, err := octantCRD.Versions()
if err != nil {
return component.EmptyContentResponse, fmt.Errorf("get versions for crd %s: %w", crd.GetName(), err)
} else if len(crdVersions) == 0 {
return component.EmptyContentResponse, fmt.Errorf("crd %s has no no versions", crd.GetName())
}

crGVK, err := gvk.CustomResource(crd, crdVersions[0])
if err != nil {
return component.EmptyContentResponse, fmt.Errorf("get gvk for custom resource")
}

apiVersion, kind := gvk.ToAPIVersionAndKind()
apiVersion, kind := crGVK.ToAPIVersionAndKind()

key := store.Key{
Namespace: namespace,
Expand All @@ -93,7 +104,7 @@ func (c *crd) Describe(ctx context.Context, namespace string, options Options) (

title := component.Title(
component.NewText("Custom Resources"),
component.NewText(crd.Name),
component.NewText(crd.GetName()),
component.NewText(object.GetName()))

iconName, iconSource := loadIcon(icon.CustomResourceDefinition)
Expand Down
73 changes: 19 additions & 54 deletions internal/describer/crd_list.go
Expand Up @@ -7,27 +7,16 @@ package describer

import (
"context"
"fmt"

"github.com/pkg/errors"
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"

"github.com/vmware-tanzu/octant/internal/link"
"github.com/vmware-tanzu/octant/internal/modules/overview/yamlviewer"
"github.com/vmware-tanzu/octant/internal/printer"
"github.com/vmware-tanzu/octant/pkg/icon"
"github.com/vmware-tanzu/octant/pkg/store"
"github.com/vmware-tanzu/octant/pkg/view/component"
)

type crdListPrinter func(
crdName string,
crd *apiextv1beta1.CustomResourceDefinition,
objects *unstructured.UnstructuredList,
linkGenerator link.Interface,
isLoading bool) (component.Component, error)
type crdListPrinter func(crdObject *unstructured.Unstructured, resources *unstructured.UnstructuredList, version string, linkGenerator link.Interface) (component.Component, error)

type crdListDescriptionOption func(*crdList)

Expand Down Expand Up @@ -57,63 +46,39 @@ func newCRDList(name, path string, options ...crdListDescriptionOption) *crdList

func (cld *crdList) Describe(ctx context.Context, namespace string, options Options) (component.ContentResponse, error) {
objectStore := options.ObjectStore()

crd, err := CustomResourceDefinition(ctx, cld.name, objectStore)
if err != nil {
return component.EmptyContentResponse, err
}

objects, isLoading, err := ListCustomResources(ctx, crd, namespace, objectStore, options.LabelSet)
if err != nil {
return component.EmptyContentResponse, err
printOptions := printer.Options{
DashConfig: options.Dash,
Link: options.Link,
}

table, err := cld.printer(cld.name, crd, objects, options.Link, isLoading)
view, err := printer.CustomResourceDefinitionHandler(ctx, crd, namespace, printOptions)
if err != nil {
return component.EmptyContentResponse, err
}
view.SetAccessor("summary")

list := component.NewList(fmt.Sprintf("Custom Resources / %s", cld.name), []component.Component{
table,
})
title := component.Title(
component.NewText("Custom Resources"),
component.NewText(crd.GetName()))

iconName, iconSource := loadIcon(icon.CustomResourceDefinition)
list.SetIcon(iconName, iconSource)
contentResponse := component.NewContentResponse(title)
contentResponse.Add(view)

return component.ContentResponse{
Components: []component.Component{list},
}, nil
}

func ListCustomResources(
ctx context.Context,
crd *apiextv1beta1.CustomResourceDefinition,
namespace string,
o store.Store,
selector *labels.Set) (*unstructured.UnstructuredList, bool, error) {
if crd == nil {
return nil, false, errors.New("crd is nil")
}
gvk := schema.GroupVersionKind{
Group: crd.Spec.Group,
Version: crd.Spec.Version,
Kind: crd.Spec.Names.Kind,
}

apiVersion, kind := gvk.ToAPIVersionAndKind()

key := store.Key{
Namespace: namespace,
APIVersion: apiVersion,
Kind: kind,
Selector: selector,
}

objects, isLoading, err := o.List(ctx, key)
yamlView, err := yamlviewer.ToComponent(crd)
if err != nil {
return nil, false, errors.Wrapf(err, "listing custom resources for %q", crd.Name)
return component.EmptyContentResponse, err
}
yamlView.SetAccessor("yaml")

contentResponse.Add(yamlView)

return objects, isLoading, nil
return *contentResponse, nil
}

func (cld *crdList) PathFilters() []PathFilter {
Expand Down
82 changes: 0 additions & 82 deletions internal/describer/crd_list_test.go

This file was deleted.

66 changes: 53 additions & 13 deletions internal/describer/crd_section.go
Expand Up @@ -7,10 +7,14 @@ package describer

import (
"context"
"path"
"sort"
"sync"

"github.com/vmware-tanzu/octant/internal/gvk"
"github.com/vmware-tanzu/octant/internal/log"
"github.com/vmware-tanzu/octant/internal/octant"
"github.com/vmware-tanzu/octant/pkg/store"
"github.com/vmware-tanzu/octant/pkg/view/component"
)

Expand Down Expand Up @@ -57,28 +61,64 @@ func (csd *CRDSection) Describe(ctx context.Context, namespace string, options O

sort.Strings(names)

list := component.NewList("Custom Resources", nil)
tableCols := component.NewTableCols("Name", "Labels", "Age")
table := component.NewTable("Custom Resources", "", tableCols)

for _, name := range names {
resp, err := csd.describers[name].Describe(ctx, namespace, options)
if err != nil {
return component.EmptyContentResponse, err
}
switch d := csd.describers[name].(type) {
case *crdList:
key := store.KeyFromGroupVersionKind(gvk.CustomResourceDefinition)
key.Name = d.name
crd, _, err := options.ObjectStore().Get(ctx, key)
if err != nil {
return component.EmptyContentResponse, err
}

crdObject, err := octant.NewCustomResourceDefinition(crd)
if err != nil {
return component.EmptyContentResponse, err
}

versions, err := crdObject.Versions()
if err != nil {
return component.EmptyContentResponse, err
}

count := 0
for _, version := range versions {
crGVK, err := gvk.CustomResource(crd, version)
if err != nil {
return component.EmptyContentResponse, err
}
key2 := store.KeyFromGroupVersionKind(crGVK)
key2.Namespace = namespace
list, _, err := options.ObjectStore().List(ctx, key2)
if err != nil {
return component.EmptyContentResponse, err
}
count += len(list.Items)
}

if count > 0 {
row := component.TableRow{}

for i := range resp.Components {
if nestedList, ok := resp.Components[i].(*component.List); ok {
for i := range nestedList.Config.Items {
item := nestedList.Config.Items[i]
if !item.IsEmpty() {
list.Add(item)
}
ref := path.Join("/overview/namespace", namespace, "custom-resources", crd.GetName())
if namespace == "" {
ref = path.Join("/cluster-overview/custom-resources", crd.GetName())
}

row["Name"] = component.NewLink("", crd.GetName(), ref)
row["Labels"] = component.NewLabels(crd.GetLabels())
row["Age"] = component.NewTimestamp(crd.GetCreationTimestamp().Time)

table.Add(row)
}

}
}

cr := component.ContentResponse{
Components: []component.Component{list},
Components: []component.Component{table},
Title: component.TitleFromString(csd.title),
}

Expand Down