mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Scopes: Add Handler for returning dashboards related to a list of scopes. (#87758)
- Adds a find endpoint to return dashboard bindings that match any of the scopes. For example /apis/scope.grafana.app/v0alpha1/namespaces/default/find/scope_dashboard_bindings?scope=s1&scope=s2 - Updates the ScopeNode find endpoint to a new path, /find/scope_node_children , makes the key "items" for all find endpoints (instead of mix of "found" and "items"), and makes the list item type a ScopeNode instead of its own type. - Updates kubectl get commands to return more information about scopes, scopenodes, and scopedashboard bindings to display more fields in table output --------- Signed-off-by: bergquist <carl.bergquist@gmail.com> Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: Todd Treece <todd.treece@grafana.com>
This commit is contained in:
parent
023857625a
commit
16cc75b02c
@ -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
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"},
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -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)
|
||||
}
|
||||
|
96
pkg/registry/apis/scope/find_scope_dashboards.go
Normal file
96
pkg/registry/apis/scope/find_scope_dashboards.go
Normal file
@ -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
|
||||
}
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
},
|
||||
),
|
||||
|
@ -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"
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user