diff --git a/pkg/apis/scope/v0alpha1/register.go b/pkg/apis/scope/v0alpha1/register.go index 7cb83f8c831..6c7cdf434f1 100644 --- a/pkg/apis/scope/v0alpha1/register.go +++ b/pkg/apis/scope/v0alpha1/register.go @@ -57,7 +57,8 @@ func AddKnownTypes(gv schema.GroupVersion, scheme *runtime.Scheme) error { &ScopeDashboardBindingList{}, &ScopeNode{}, &ScopeNodeList{}, - &TreeResults{}, + &FindScopeNodeChildrenResults{}, + &FindScopeDashboardBindingsResults{}, ) //metav1.AddToGroupVersion(scheme, gv) return nil diff --git a/pkg/apis/scope/v0alpha1/types.go b/pkg/apis/scope/v0alpha1/types.go index 35e6aca97aa..2683368d148 100644 --- a/pkg/apis/scope/v0alpha1/types.go +++ b/pkg/apis/scope/v0alpha1/types.go @@ -74,6 +74,14 @@ type ScopeDashboardBindingList struct { Items []ScopeDashboardBinding `json:"items,omitempty"` } +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type FindScopeDashboardBindingsResults struct { + metav1.TypeMeta `json:",inline"` + + Items []ScopeDashboardBinding `json:"items,omitempty"` + Message string `json:"message,omitempty"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type ScopeNode struct { metav1.TypeMeta `json:",inline"` @@ -125,20 +133,9 @@ type ScopeNodeList struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type TreeResults struct { +type FindScopeNodeChildrenResults struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []TreeItem `json:"items,omitempty"` -} - -type TreeItem struct { - NodeID string `json:"nodeId,omitempty"` - NodeType NodeType `json:"nodeType"` // container | leaf - - Title string `json:"title"` - Description string `json:"description,omitempty"` - - LinkType LinkType `json:"linkType,omitempty"` // scope (later more things) - LinkID string `json:"linkId,omitempty"` // the k8s name + Items []ScopeNode `json:"items,omitempty"` } diff --git a/pkg/apis/scope/v0alpha1/zz_generated.deepcopy.go b/pkg/apis/scope/v0alpha1/zz_generated.deepcopy.go index 9f9d40daad5..dcf457e6cef 100644 --- a/pkg/apis/scope/v0alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/scope/v0alpha1/zz_generated.deepcopy.go @@ -11,6 +11,71 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FindScopeDashboardBindingsResults) DeepCopyInto(out *FindScopeDashboardBindingsResults) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ScopeDashboardBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FindScopeDashboardBindingsResults. +func (in *FindScopeDashboardBindingsResults) DeepCopy() *FindScopeDashboardBindingsResults { + if in == nil { + return nil + } + out := new(FindScopeDashboardBindingsResults) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FindScopeDashboardBindingsResults) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FindScopeNodeChildrenResults) DeepCopyInto(out *FindScopeNodeChildrenResults) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ScopeNode, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FindScopeNodeChildrenResults. +func (in *FindScopeNodeChildrenResults) DeepCopy() *FindScopeNodeChildrenResults { + if in == nil { + return nil + } + out := new(FindScopeNodeChildrenResults) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FindScopeNodeChildrenResults) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Scope) DeepCopyInto(out *Scope) { *out = *in @@ -259,50 +324,3 @@ func (in *ScopeSpec) DeepCopy() *ScopeSpec { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TreeItem) DeepCopyInto(out *TreeItem) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TreeItem. -func (in *TreeItem) DeepCopy() *TreeItem { - if in == nil { - return nil - } - out := new(TreeItem) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TreeResults) DeepCopyInto(out *TreeResults) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TreeItem, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TreeResults. -func (in *TreeResults) DeepCopy() *TreeResults { - if in == nil { - return nil - } - out := new(TreeResults) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TreeResults) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} diff --git a/pkg/apis/scope/v0alpha1/zz_generated.openapi.go b/pkg/apis/scope/v0alpha1/zz_generated.openapi.go index 771f7645573..4f081df925e 100644 --- a/pkg/apis/scope/v0alpha1/zz_generated.openapi.go +++ b/pkg/apis/scope/v0alpha1/zz_generated.openapi.go @@ -16,18 +16,112 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.Scope": schema_pkg_apis_scope_v0alpha1_Scope(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBinding": schema_pkg_apis_scope_v0alpha1_ScopeDashboardBinding(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBindingList": schema_pkg_apis_scope_v0alpha1_ScopeDashboardBindingList(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBindingSpec": schema_pkg_apis_scope_v0alpha1_ScopeDashboardBindingSpec(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeFilter": schema_pkg_apis_scope_v0alpha1_ScopeFilter(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeList": schema_pkg_apis_scope_v0alpha1_ScopeList(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNode": schema_pkg_apis_scope_v0alpha1_ScopeNode(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNodeList": schema_pkg_apis_scope_v0alpha1_ScopeNodeList(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNodeSpec": schema_pkg_apis_scope_v0alpha1_ScopeNodeSpec(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeSpec": schema_pkg_apis_scope_v0alpha1_ScopeSpec(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.TreeItem": schema_pkg_apis_scope_v0alpha1_TreeItem(ref), - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.TreeResults": schema_pkg_apis_scope_v0alpha1_TreeResults(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.FindScopeDashboardBindingsResults": schema_pkg_apis_scope_v0alpha1_FindScopeDashboardBindingsResults(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.FindScopeNodeChildrenResults": schema_pkg_apis_scope_v0alpha1_FindScopeNodeChildrenResults(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.Scope": schema_pkg_apis_scope_v0alpha1_Scope(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBinding": schema_pkg_apis_scope_v0alpha1_ScopeDashboardBinding(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBindingList": schema_pkg_apis_scope_v0alpha1_ScopeDashboardBindingList(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBindingSpec": schema_pkg_apis_scope_v0alpha1_ScopeDashboardBindingSpec(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeFilter": schema_pkg_apis_scope_v0alpha1_ScopeFilter(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeList": schema_pkg_apis_scope_v0alpha1_ScopeList(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNode": schema_pkg_apis_scope_v0alpha1_ScopeNode(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNodeList": schema_pkg_apis_scope_v0alpha1_ScopeNodeList(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNodeSpec": schema_pkg_apis_scope_v0alpha1_ScopeNodeSpec(ref), + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeSpec": schema_pkg_apis_scope_v0alpha1_ScopeSpec(ref), + } +} + +func schema_pkg_apis_scope_v0alpha1_FindScopeDashboardBindingsResults(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBinding"), + }, + }, + }, + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeDashboardBinding"}, + } +} + +func schema_pkg_apis_scope_v0alpha1_FindScopeNodeChildrenResults(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNode"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeNode", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } @@ -471,106 +565,3 @@ func schema_pkg_apis_scope_v0alpha1_ScopeSpec(ref common.ReferenceCallback) comm "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.ScopeFilter"}, } } - -func schema_pkg_apis_scope_v0alpha1_TreeItem(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "nodeId": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "nodeType": { - SchemaProps: spec.SchemaProps{ - Description: "Possible enum values:\n - `\"container\"`\n - `\"leaf\"`", - Default: "", - Type: []string{"string"}, - Format: "", - Enum: []interface{}{"container", "leaf"}, - }, - }, - "title": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "linkType": { - SchemaProps: spec.SchemaProps{ - Description: "Possible enum values:\n - `\"scope\"`", - Type: []string{"string"}, - Format: "", - Enum: []interface{}{"scope"}, - }, - }, - "linkId": { - SchemaProps: spec.SchemaProps{ - Description: "scope (later more things)", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"nodeType", "title"}, - }, - }, - } -} - -func schema_pkg_apis_scope_v0alpha1_TreeResults(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/pkg/apis/scope/v0alpha1.TreeItem"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/pkg/apis/scope/v0alpha1.TreeItem", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} diff --git a/pkg/apis/scope/v0alpha1/zz_generated.openapi_violation_exceptions.list b/pkg/apis/scope/v0alpha1/zz_generated.openapi_violation_exceptions.list index a295544ba5f..e0fabd106cb 100644 --- a/pkg/apis/scope/v0alpha1/zz_generated.openapi_violation_exceptions.list +++ b/pkg/apis/scope/v0alpha1/zz_generated.openapi_violation_exceptions.list @@ -1,3 +1,2 @@ +API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/scope/v0alpha1,FindScopeDashboardBindingsResults,Items API rule violation: names_match,github.com/grafana/grafana/pkg/apis/scope/v0alpha1,ScopeNodeSpec,LinkID -API rule violation: names_match,github.com/grafana/grafana/pkg/apis/scope/v0alpha1,TreeItem,LinkID -API rule violation: names_match,github.com/grafana/grafana/pkg/apis/scope/v0alpha1,TreeItem,NodeID diff --git a/pkg/apiserver/builder/helper.go b/pkg/apiserver/builder/helper.go index 496983a7292..ed223a7667e 100644 --- a/pkg/apiserver/builder/helper.go +++ b/pkg/apiserver/builder/helper.go @@ -30,9 +30,9 @@ import ( // TODO: this is a temporary hack to make rest.Connecter work with resource level routes var pathRewriters = []filters.PathRewriter{ { - Pattern: regexp.MustCompile(`(/apis/scope.grafana.app/v0alpha1/namespaces/.*/find$)`), + Pattern: regexp.MustCompile(`(/apis/scope.grafana.app/v0alpha1/namespaces/.*/)find/(.*)$`), ReplaceFunc: func(matches []string) string { - return matches[1] + "/name" // connector requires a name + return matches[1] + matches[2] + "/name" // connector requires a name }, }, { diff --git a/pkg/registry/apis/scope/find.go b/pkg/registry/apis/scope/find.go index b4b4213d1b3..b82c8c03dc6 100644 --- a/pkg/registry/apis/scope/find.go +++ b/pkg/registry/apis/scope/find.go @@ -29,7 +29,7 @@ var ( func (r *findREST) New() runtime.Object { // This is added as the "ResponseType" regarless what ProducesObject() says :) - return &scope.TreeResults{} + return &scope.FindScopeNodeChildrenResults{} } func (r *findREST) Destroy() {} @@ -39,7 +39,7 @@ func (r *findREST) NamespaceScoped() bool { } func (r *findREST) GetSingularName() string { - return "TreeResult" // Used for the + return "FindScopeNodeChildrenResults" // Used for the } func (r *findREST) ProducesMIMETypes(verb string) []string { @@ -47,7 +47,7 @@ func (r *findREST) ProducesMIMETypes(verb string) []string { } func (r *findREST) ProducesObject(verb string) interface{} { - return &scope.TreeResults{} + return &scope.FindScopeNodeChildrenResults{} } func (r *findREST) ConnectMethods() []string { @@ -68,7 +68,7 @@ func (r *findREST) Connect(ctx context.Context, name string, opts runtime.Object return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { parent := req.URL.Query().Get("parent") query := req.URL.Query().Get("query") - results := &scope.TreeResults{} + results := &scope.FindScopeNodeChildrenResults{} raw, err := r.scopeNodeStorage.List(ctx, &internalversion.ListOptions{ Limit: 1000, @@ -93,7 +93,7 @@ func (r *findREST) Connect(ctx context.Context, name string, opts runtime.Object }), nil } -func filterAndAppendItem(item scope.ScopeNode, parent string, query string, results *scope.TreeResults) { +func filterAndAppendItem(item scope.ScopeNode, parent string, query string, results *scope.FindScopeNodeChildrenResults) { if parent != item.Spec.ParentName { return // Someday this will have an index in raw storage on parentName } @@ -104,12 +104,5 @@ func filterAndAppendItem(item scope.ScopeNode, parent string, query string, resu return } - results.Items = append(results.Items, scope.TreeItem{ - NodeID: item.Name, - NodeType: item.Spec.NodeType, - Title: item.Spec.Title, - Description: item.Spec.Description, - LinkType: item.Spec.LinkType, - LinkID: item.Spec.LinkID, - }) + results.Items = append(results.Items, item) } diff --git a/pkg/registry/apis/scope/find_scope_dashboards.go b/pkg/registry/apis/scope/find_scope_dashboards.go new file mode 100644 index 00000000000..98994c6e6ef --- /dev/null +++ b/pkg/registry/apis/scope/find_scope_dashboards.go @@ -0,0 +1,96 @@ +package scope + +import ( + "context" + "fmt" + "net/http" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/internalversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/registry/rest" + + scope "github.com/grafana/grafana/pkg/apis/scope/v0alpha1" +) + +type findScopeDashboardsREST struct { + scopeDashboardStorage *storage +} + +var ( + _ rest.Storage = (*findScopeDashboardsREST)(nil) + _ rest.SingularNameProvider = (*findScopeDashboardsREST)(nil) + _ rest.Connecter = (*findScopeDashboardsREST)(nil) + _ rest.Scoper = (*findScopeDashboardsREST)(nil) + _ rest.StorageMetadata = (*findScopeDashboardsREST)(nil) +) + +func (f *findScopeDashboardsREST) New() runtime.Object { + return &scope.FindScopeDashboardBindingsResults{} +} + +func (f *findScopeDashboardsREST) Destroy() {} + +func (f *findScopeDashboardsREST) NamespaceScoped() bool { + return true +} + +func (f *findScopeDashboardsREST) GetSingularName() string { + return "FindScopeDashboardsResult" // not sure if this is actually used, but it is required to exist +} + +func (f *findScopeDashboardsREST) ProducesMIMETypes(verb string) []string { + return []string{"application/json"} // and parquet! +} + +func (f *findScopeDashboardsREST) ProducesObject(verb string) interface{} { + return &scope.FindScopeDashboardBindingsResults{} +} + +func (f *findScopeDashboardsREST) ConnectMethods() []string { + return []string{"GET"} +} + +func (f *findScopeDashboardsREST) NewConnectOptions() (runtime.Object, bool, string) { + return nil, false, "" // true means you can use the trailing path as a variable +} + +func (f *findScopeDashboardsREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) { + // See: /pkg/apiserver/builder/helper.go#L34 + // The name is set with a rewriter hack + if name != "name" { + return nil, errors.NewNotFound(schema.GroupResource{}, name) + } + + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + raw, err := f.scopeDashboardStorage.List(ctx, &internalversion.ListOptions{}) + if err != nil { + w.WriteHeader(500) + return + } + all, ok := raw.(*scope.ScopeDashboardBindingList) + if !ok { + w.WriteHeader(500) + return + } + + scopes := req.URL.Query()["scope"] + results := &scope.FindScopeDashboardBindingsResults{ + Message: fmt.Sprintf("Find: %s", scopes), + Items: make([]scope.ScopeDashboardBinding, 0), + } + + // we can improve the performance by calling .List once per scope if they are index by labels. + // The API stays the same thou. + for _, item := range all.Items { + for _, s := range scopes { + if item.Spec.Scope == s { + results.Items = append(results.Items, item) + } + } + } + + responder.Object(200, results) + }), nil +} diff --git a/pkg/registry/apis/scope/find_test.go b/pkg/registry/apis/scope/find_test.go index caea3e604fb..0f9ce99b6e4 100644 --- a/pkg/registry/apis/scope/find_test.go +++ b/pkg/registry/apis/scope/find_test.go @@ -54,7 +54,7 @@ func TestFilterAndAppendItem(t *testing.T) { } for _, tc := range tcs { - results := &scope.TreeResults{} + results := &scope.FindScopeNodeChildrenResults{} item := scope.ScopeNode{ Spec: scope.ScopeNodeSpec{ ParentName: tc.ParentName, diff --git a/pkg/registry/apis/scope/register.go b/pkg/registry/apis/scope/register.go index 243dd978967..91215ce7a7e 100644 --- a/pkg/registry/apis/scope/register.go +++ b/pkg/registry/apis/scope/register.go @@ -151,7 +151,12 @@ func (b *ScopeAPIBuilder) GetAPIGroupInfo( // Adds a rest.Connector // NOTE! the server has a hardcoded rewrite filter that fills in a name // so the standard k8s plumbing continues to work - storage["find"] = &findREST{scopeNodeStorage: scopeNodeStorage} + storage["scope_node_children"] = &findREST{scopeNodeStorage: scopeNodeStorage} + + // Adds a rest.Connector + // NOTE! the server has a hardcoded rewrite filter that fills in a name + // so the standard k8s plumbing continues to work + storage["scope_dashboard_bindings"] = &findScopeDashboardsREST{scopeDashboardStorage: scopeDashboardStorage} apiGroupInfo.VersionedResourcesStorageMap[scope.VERSION] = storage return &apiGroupInfo, nil @@ -174,7 +179,7 @@ func (b *ScopeAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI root := "/apis/" + b.GetGroupVersion().String() + "/" // Add query parameters to the rest.Connector - sub := oas.Paths.Paths[root+"namespaces/{namespace}/find/{name}"] + sub := oas.Paths.Paths[root+"namespaces/{namespace}/scope_node_children/{name}"] if sub != nil && sub.Get != nil { sub.Parameters = []*spec3.Parameter{ { @@ -198,8 +203,35 @@ func (b *ScopeAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI }, }, } - delete(oas.Paths.Paths, root+"namespaces/{namespace}/find/{name}") - oas.Paths.Paths[root+"namespaces/{namespace}/find"] = sub + delete(oas.Paths.Paths, root+"namespaces/{namespace}/scope_node_children/{name}") + oas.Paths.Paths[root+"namespaces/{namespace}/find/scope_node_children"] = sub + } + + findDashboardPath := oas.Paths.Paths[root+"namespaces/{namespace}/scope_dashboard_bindings/{name}"] + if findDashboardPath != nil && sub.Get != nil { + sub.Parameters = []*spec3.Parameter{ + { + ParameterProps: spec3.ParameterProps{ + Name: "namespace", + In: "path", + Description: "object name and auth scope, such as for teams and projects", + Example: "default", + Required: true, + }, + }, + } + findDashboardPath.Get.Description = "find scope dashboard bindings that match any of the given scopes." + findDashboardPath.Get.Parameters = []*spec3.Parameter{ + { + ParameterProps: spec3.ParameterProps{ + Name: "scope", + In: "query", + Description: "A scope name (id) to match against, this parameter may be repeated", + }, + }, + } + delete(oas.Paths.Paths, root+"namespaces/{namespace}/scope_dashboard_bindings/{name}") + oas.Paths.Paths[root+"namespaces/{namespace}/find/scope_dashboard_bindings"] = findDashboardPath } // The root API discovery list diff --git a/pkg/registry/apis/scope/storage.go b/pkg/registry/apis/scope/storage.go index 7107ee00ada..bbda3223993 100644 --- a/pkg/registry/apis/scope/storage.go +++ b/pkg/registry/apis/scope/storage.go @@ -39,6 +39,8 @@ func newScopeStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGette []metav1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name"}, {Name: "Created At", Type: "date"}, + {Name: "Title", Type: "string"}, + {Name: "Filters", Type: "array"}, }, func(obj any) ([]interface{}, error) { m, ok := obj.(*scope.Scope) @@ -48,6 +50,8 @@ func newScopeStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGette return []interface{}{ m.Name, m.CreationTimestamp.UTC().Format(time.RFC3339), + m.Spec.Title, + m.Spec.Filters, }, nil }, ), @@ -77,15 +81,19 @@ func newScopeDashboardBindingStorage(scheme *runtime.Scheme, optsGetter generic. []metav1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name"}, {Name: "Created At", Type: "date"}, + {Name: "Dashboard", Type: "string"}, + {Name: "Scope", Type: "string"}, }, func(obj any) ([]interface{}, error) { - m, ok := obj.(*scope.Scope) + m, ok := obj.(*scope.ScopeDashboardBinding) if !ok { - return nil, fmt.Errorf("expected scope") + return nil, fmt.Errorf("expected scope dashboard binding") } return []interface{}{ m.Name, m.CreationTimestamp.UTC().Format(time.RFC3339), + m.Spec.Dashboard, + m.Spec.Scope, }, nil }, ), @@ -115,6 +123,11 @@ func newScopeNodeStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsG []metav1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name"}, {Name: "Created At", Type: "date"}, + {Name: "Title", Type: "string"}, + {Name: "Parent Name", Type: "string"}, + {Name: "Node Type", Type: "string"}, + {Name: "Link Type", Type: "string"}, + {Name: "Link ID", Type: "string"}, }, func(obj any) ([]interface{}, error) { m, ok := obj.(*scope.ScopeNode) @@ -124,6 +137,11 @@ func newScopeNodeStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsG return []interface{}{ m.Name, m.CreationTimestamp.UTC().Format(time.RFC3339), + m.Spec.Title, + m.Spec.ParentName, + m.Spec.NodeType, + m.Spec.LinkType, + m.Spec.LinkID, }, nil }, ), diff --git a/pkg/tests/apis/scopes/scopes_test.go b/pkg/tests/apis/scopes/scopes_test.go index b5f85e65609..b775fca020c 100644 --- a/pkg/tests/apis/scopes/scopes_test.go +++ b/pkg/tests/apis/scopes/scopes_test.go @@ -48,10 +48,19 @@ func TestIntegrationScopes(t *testing.T) { "groupVersion": "scope.grafana.app/v0alpha1", "resources": [ { - "name": "find", - "singularName": "TreeResult", + "name": "scope_dashboard_bindings", + "singularName": "FindScopeDashboardsResult", "namespaced": true, - "kind": "TreeResults", + "kind": "FindScopeDashboardBindingsResults", + "verbs": [ + "get" + ] + }, + { + "name": "scope_node_children", + "singularName": "FindScopeNodeChildrenResults", + "namespaced": true, + "kind": "FindScopeNodeChildrenResults", "verbs": [ "get" ]