Skip to content

Commit

Permalink
fix: add missing TODOs
Browse files Browse the repository at this point in the history
  • Loading branch information
ffforest committed Nov 29, 2023
1 parent 8cde216 commit 0a35940
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 57 deletions.
66 changes: 55 additions & 11 deletions pkg/registry/cluster/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/KusionStack/karbour/pkg/apis/cluster"
"github.com/KusionStack/karbour/pkg/registry/search/relationship"
proxyutil "github.com/KusionStack/karbour/pkg/util/proxy"
"github.com/dominikbraun/graph/draw"
"github.com/pkg/errors"

Expand All @@ -33,7 +34,10 @@ import (
"k8s.io/apiserver/pkg/registry/generic"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/klog/v2"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
)
Expand Down Expand Up @@ -110,13 +114,35 @@ func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOp

func (r *StatusREST) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
rt := &cluster.Cluster{}
client, err := r.BuildDynamicClient(ctx)
dynamicClient, err := r.BuildDynamicClient(ctx)
if err != nil {
return rt, err
}
graph, rg, _ := relationship.BuildRelationshipGraph(ctx, client, true)
discoveryClient, err := r.BuildDiscoveryClient(ctx)
if err != nil {
return rt, err
}

graph, rg, _ := relationship.BuildRelationshipGraph(ctx, dynamicClient)
namespace, ok := proxyutil.NamespaceFrom(ctx)
if !ok {
// Count resources in all namespaces
klog.Infof("Retrieving topology for the entire cluster")
rg, err = rg.CountRelationshipGraph(ctx, dynamicClient, discoveryClient, "")
if err != nil {
return rt, err
}
} else {
// Only count resources that belong to a specific namespace
klog.Infof("Retrieving topology for namespace: %s", namespace)
rg, err = rg.CountRelationshipGraph(ctx, dynamicClient, discoveryClient, namespace)
if err != nil {
return rt, err
}
}

// Draw graph
// TODO: This is drawn on the server side, not needed eventually
file, _ := os.Create("./relationship.gv")
_ = draw.DOT(graph, file)

Expand Down Expand Up @@ -151,6 +177,31 @@ func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object,

// BuildDynamicClient returns a dynamic client based on the cluster name in the request
func (r *StatusREST) BuildDynamicClient(ctx context.Context) (*dynamic.DynamicClient, error) {
config, err := r.GetConfigFromContext(ctx)
if err != nil {
return nil, err
}
// Create the dynamic client
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
return nil, err
}

return dynamicClient, nil
}

func (r *StatusREST) BuildDiscoveryClient(ctx context.Context) (*discovery.DiscoveryInterface, error) {
config, err := r.GetConfigFromContext(ctx)
if err != nil {
return nil, err
}
// Create the discovery client
clientset := kubernetes.NewForConfigOrDie(config)
discoveryClient := clientset.Discovery()
return &discoveryClient, nil
}

func (r *StatusREST) GetConfigFromContext(ctx context.Context) (*restclient.Config, error) {
// Extract the cluster name from context
info, ok := request.RequestInfoFrom(ctx)
if !ok {
Expand All @@ -164,17 +215,10 @@ func (r *StatusREST) BuildDynamicClient(ctx context.Context) (*dynamic.DynamicCl
return nil, err
}
clusterFromContext := obj.(*cluster.Cluster)
klog.Infof("Cluster found: %s", clusterFromContext.Name)
klog.Infof("Cluster found for discovery client: %s", clusterFromContext.Name)
config, err := NewConfigFromCluster(clusterFromContext)
if err != nil {
return nil, errors.Wrapf(err, "failed to create cluster client config %s", clusterFromContext.Name)
}

// Create the dynamic client
client, err := dynamic.NewForConfig(config)
if err != nil {
return nil, err
}

return client, nil
return config, nil
}
8 changes: 4 additions & 4 deletions pkg/registry/search/relationship/children.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ package relationship
import (
"context"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"

topologyutil "github.com/KusionStack/karbour/pkg/util/topology"
"github.com/dominikbraun/graph"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/klog/v2"
)

// GetChildResourcesList returns an *unstructured.UnstructuredList representing all resources that matches the child GVK in the current namespace
Expand Down
9 changes: 4 additions & 5 deletions pkg/registry/search/relationship/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ package relationship
import (
"context"

"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"

topologyutil "github.com/KusionStack/karbour/pkg/util/topology"
"github.com/dominikbraun/graph"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"

topologyutil "github.com/KusionStack/karbour/pkg/util/topology"
"k8s.io/klog/v2"
)

func GetByJSONPath(relatedResList *unstructured.UnstructuredList, relationshipType string, ctx context.Context, client *dynamic.DynamicClient, obj unstructured.Unstructured, relation *Relationship, relatedGVK schema.GroupVersionKind, objResourceNode ResourceGraphNode, relationshipGraph graph.Graph[string, RelationshipGraphNode], resourceGraph graph.Graph[string, ResourceGraphNode]) (graph.Graph[string, ResourceGraphNode], error) {
Expand Down
8 changes: 4 additions & 4 deletions pkg/registry/search/relationship/parents.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ package relationship
import (
"context"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"

topologyutil "github.com/KusionStack/karbour/pkg/util/topology"
"github.com/dominikbraun/graph"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/klog/v2"
)

// GetParentResourcesList returns an *unstructured.UnstructuredList representing all resources that matches the parent GVK in the current namespace
Expand Down
75 changes: 55 additions & 20 deletions pkg/registry/search/relationship/relationship.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ import (
"os"
"reflect"

"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/klog/v2"

topologyutil "github.com/KusionStack/karbour/pkg/util/topology"
"github.com/dominikbraun/graph"
"github.com/dominikbraun/graph/draw"

yaml "gopkg.in/yaml.v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/klog/v2"
)

func (rgn ResourceGraphNode) GetHash() string {
Expand Down Expand Up @@ -93,7 +95,7 @@ func FindNodeOnGraph(g graph.Graph[string, RelationshipGraphNode], group, versio
}

// BuildBuiltinRelationshipGraph returns the relationship graph built from the YAML describing resource relationships
func BuildBuiltinRelationshipGraph(ctx context.Context, client *dynamic.DynamicClient, countResouces bool) (graph.Graph[string, RelationshipGraphNode], *RelationshipGraph, error) {
func BuildBuiltinRelationshipGraph(ctx context.Context, client *dynamic.DynamicClient) (graph.Graph[string, RelationshipGraphNode], *RelationshipGraph, error) {
r := RelationshipGraph{}
yamlFile, err := os.ReadFile("relationship.yaml")
if err != nil {
Expand Down Expand Up @@ -142,19 +144,7 @@ func BuildBuiltinRelationshipGraph(ctx context.Context, client *dynamic.DynamicC
// Add Vertices
for _, node := range r.RelationshipNodes {
klog.Infof("Adding Vertex: %s\n", node.GetHash())
if countResouces {
resGVR, err := topologyutil.GetGVRFromGVK(schema.GroupVersion{Group: node.Group, Version: node.Version}.String(), node.Kind)
if err != nil {
return nil, nil, err
}
resList, _ := client.Resource(resGVR).List(ctx, metav1.ListOptions{})
resCount := len(resList.Items)
klog.Infof("Counted resources for Vertex %s: %d\n", node.GetHash(), resCount)
node.ResourceCount = resCount
_ = g.AddVertex(*node, graph.VertexWeight(resCount))
} else {
_ = g.AddVertex(*node)
}
_ = g.AddVertex(*node)
}
// Add Edges, requires all vertices to be present
for _, node := range r.RelationshipNodes {
Expand All @@ -176,15 +166,16 @@ func BuildBuiltinRelationshipGraph(ctx context.Context, client *dynamic.DynamicC
klog.Infof("Built-in graph completed.")

// Draw graph
// TODO: This is drawn on the server side, not needed eventually
file, _ := os.Create("./relationship.gv")
_ = draw.DOT(g, file)

return g, &r, nil
}

// BuildRelationshipGraph builds the complete relationship graph including the built-in one and customer-specified one
func BuildRelationshipGraph(ctx context.Context, client *dynamic.DynamicClient, countResouces bool) (graph.Graph[string, RelationshipGraphNode], *RelationshipGraph, error) {
res, rg, _ := BuildBuiltinRelationshipGraph(ctx, client, countResouces)
func BuildRelationshipGraph(ctx context.Context, client *dynamic.DynamicClient) (graph.Graph[string, RelationshipGraphNode], *RelationshipGraph, error) {
res, rg, _ := BuildBuiltinRelationshipGraph(ctx, client)
// TODO: Also include customized relationship graph
return res, rg, nil
}
Expand Down Expand Up @@ -225,3 +216,47 @@ func InsertIfNotExist(relationList []*Relationship, relation Relationship, relat
func RelationshipEquals(r, relation *Relationship) bool {
return r.Group == relation.Group && r.Version == relation.Version && r.Kind == relation.Kind && r.Type == relation.Type && reflect.DeepEqual(r.JSONPath, relation.JSONPath)
}

// CountRelationshipGraph returns the same RelationshipGraph with the count for each resource
func (rg *RelationshipGraph) CountRelationshipGraph(ctx context.Context, dynamicClient *dynamic.DynamicClient, discoveryClient *discovery.DiscoveryInterface, countNamespace string) (*RelationshipGraph, error) {
for _, node := range rg.RelationshipNodes {
var resList *unstructured.UnstructuredList
resGVR, err := topologyutil.GetGVRFromGVK(schema.GroupVersion{Group: node.Group, Version: node.Version}.String(), node.Kind)
if err != nil {
return rg, err
}
if countNamespace == "" {
resList, err = dynamicClient.Resource(resGVR).List(ctx, metav1.ListOptions{})
} else if countNamespace != "" && GVRNamespaced(resGVR, *discoveryClient) {
resList, err = dynamicClient.Resource(resGVR).Namespace(countNamespace).List(ctx, metav1.ListOptions{})
} else {
continue
}
if err != nil {
return rg, err
}
resCount := len(resList.Items)
klog.Infof("Counted resources for Vertex %s: %d\n", node.GetHash(), resCount)
node.ResourceCount = resCount
}
return rg, nil
}

// GVRNamespaced returns true if a given GVR is namespaced based on the result of discovery client
func GVRNamespaced(gvr schema.GroupVersionResource, discoveryClient discovery.DiscoveryInterface) bool {
apiResourceList, err := discoveryClient.ServerResourcesForGroupVersion(gvr.GroupVersion().String())
if err != nil {
return false
}
// Iterate over the APIResources to find the one that matches the Resource and determine if it is namespaced
for _, apiResource := range apiResourceList.APIResources {
if apiResource.Name == gvr.Resource {
if apiResource.Namespaced {
return true
} else {
return false
}
}
}
return false
}
4 changes: 2 additions & 2 deletions pkg/registry/search/uniresource/topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (r *TopologyREST) List(ctx context.Context, options *internalversion.ListOp
if err != nil {
return nil, err
}
rg, _, err := relationship.BuildRelationshipGraph(ctx, client, false)
rg, _, err := relationship.BuildRelationshipGraph(ctx, client)
if err != nil {
return nil, err
}
Expand All @@ -103,7 +103,7 @@ func (r *TopologyREST) List(ctx context.Context, options *internalversion.ListOp
}
}
// Draw graph
// TODO: This is drawn on the server side, probably not needed eventually
// TODO: This is drawn on the server side, not needed eventually
file, _ := os.Create("./resource.gv")
_ = draw.DOT(g, file)

Expand Down
18 changes: 9 additions & 9 deletions pkg/util/filters/search_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/KusionStack/karbour/pkg/search/storage"
)

type ctxTyp string
type CtxTyp string

type Resource struct {
Name string
Expand All @@ -42,15 +42,15 @@ const (
)

func SearchQueryFrom(ctx context.Context) (string, bool) {
query, ok := ctx.Value(ctxTyp(searchQueryKey)).(string)
query, ok := ctx.Value(CtxTyp(searchQueryKey)).(string)
if !ok {
return "", false
}
return query, true
}

func PatternTypeFrom(ctx context.Context) (string, bool) {
patternType, ok := ctx.Value(ctxTyp(patternTypeKey)).(string)
patternType, ok := ctx.Value(CtxTyp(patternTypeKey)).(string)
if !ok {
return "", false
}
Expand All @@ -59,23 +59,23 @@ func PatternTypeFrom(ctx context.Context) (string, bool) {

func ResourceDetailFrom(ctx context.Context) (Resource, bool) {
res := Resource{}
resourceName, ok := ctx.Value(ctxTyp(resourceNameQueryKey)).(string)
resourceName, ok := ctx.Value(CtxTyp(resourceNameQueryKey)).(string)
if !ok {
return res, false
}
namespace, ok := ctx.Value(ctxTyp(resourceNamespaceQueryKey)).(string)
namespace, ok := ctx.Value(CtxTyp(resourceNamespaceQueryKey)).(string)
if !ok {
return res, false
}
cluster, ok := ctx.Value(ctxTyp(resourceClusterQueryKey)).(string)
cluster, ok := ctx.Value(CtxTyp(resourceClusterQueryKey)).(string)
if !ok {
return res, false
}
apiVersion, ok := ctx.Value(ctxTyp(resourceAPIVersionQueryKey)).(string)
apiVersion, ok := ctx.Value(CtxTyp(resourceAPIVersionQueryKey)).(string)
if !ok {
return res, false
}
kind, ok := ctx.Value(ctxTyp(resourceKindQueryKey)).(string)
kind, ok := ctx.Value(CtxTyp(resourceKindQueryKey)).(string)
if !ok {
return res, false
}
Expand Down Expand Up @@ -114,5 +114,5 @@ func FromQueryToContext(req *http.Request, key string, defaultVal string) *http.
query.Del(key)
val = queryVal[0]
}
return req.WithContext(context.WithValue(req.Context(), ctxTyp(key), val))
return req.WithContext(context.WithValue(req.Context(), CtxTyp(key), val))
}
Loading

0 comments on commit 0a35940

Please sign in to comment.