mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s/Folder: Show parent folder information (#97938)
This commit is contained in:
parent
00b51c0422
commit
eb38a63559
@ -45,14 +45,20 @@ type FolderInfoList struct {
|
|||||||
// FolderInfo briefly describes a folder -- unlike a folder resource,
|
// FolderInfo briefly describes a folder -- unlike a folder resource,
|
||||||
// this is a partial record of the folder metadata used for navigating parents and children
|
// this is a partial record of the folder metadata used for navigating parents and children
|
||||||
type FolderInfo struct {
|
type FolderInfo struct {
|
||||||
// UID is the unique identifier for a folder (and the k8s name)
|
// Name is the k8s name (eg, the unique identifier) for a folder
|
||||||
UID string `json:"uid"`
|
Name string `json:"name"`
|
||||||
|
|
||||||
// Title is the display value
|
// Title is the display value
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
|
||||||
|
// The folder description
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
|
||||||
// The parent folder UID
|
// The parent folder UID
|
||||||
Parent string `json:"parent,omitempty"`
|
Parent string `json:"parent,omitempty"`
|
||||||
|
|
||||||
|
// This folder does not resolve
|
||||||
|
Detached bool `json:"detached,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access control information for the current user
|
// Access control information for the current user
|
||||||
|
@ -170,9 +170,9 @@ func schema_pkg_apis_folder_v0alpha1_FolderInfo(ref common.ReferenceCallback) co
|
|||||||
Description: "FolderInfo briefly describes a folder -- unlike a folder resource, this is a partial record of the folder metadata used for navigating parents and children",
|
Description: "FolderInfo briefly describes a folder -- unlike a folder resource, this is a partial record of the folder metadata used for navigating parents and children",
|
||||||
Type: []string{"object"},
|
Type: []string{"object"},
|
||||||
Properties: map[string]spec.Schema{
|
Properties: map[string]spec.Schema{
|
||||||
"uid": {
|
"name": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "UID is the unique identifier for a folder (and the k8s name)",
|
Description: "Name is the k8s name (eg, the unique identifier) for a folder",
|
||||||
Default: "",
|
Default: "",
|
||||||
Type: []string{"string"},
|
Type: []string{"string"},
|
||||||
Format: "",
|
Format: "",
|
||||||
@ -186,6 +186,13 @@ func schema_pkg_apis_folder_v0alpha1_FolderInfo(ref common.ReferenceCallback) co
|
|||||||
Format: "",
|
Format: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"description": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Description: "The folder description",
|
||||||
|
Type: []string{"string"},
|
||||||
|
Format: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
"parent": {
|
"parent": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "The parent folder UID",
|
Description: "The parent folder UID",
|
||||||
@ -193,8 +200,15 @@ func schema_pkg_apis_folder_v0alpha1_FolderInfo(ref common.ReferenceCallback) co
|
|||||||
Format: "",
|
Format: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"detached": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Description: "This folder does not resolve",
|
||||||
|
Type: []string{"boolean"},
|
||||||
|
Format: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Required: []string{"uid", "title"},
|
Required: []string{"name", "title"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -126,11 +126,6 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API
|
|||||||
|
|
||||||
storage := map[string]rest.Storage{}
|
storage := map[string]rest.Storage{}
|
||||||
storage[resourceInfo.StoragePath()] = legacyStore
|
storage[resourceInfo.StoragePath()] = legacyStore
|
||||||
storage[resourceInfo.StoragePath("parents")] = &subParentsREST{b.folderSvc}
|
|
||||||
storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc}
|
|
||||||
storage[resourceInfo.StoragePath("counts")] = &subCountREST{searcher: b.searcher}
|
|
||||||
|
|
||||||
// enable dual writer
|
|
||||||
if optsGetter != nil && dualWriteBuilder != nil {
|
if optsGetter != nil && dualWriteBuilder != nil {
|
||||||
store, err := grafanaregistry.NewRegistryStore(scheme, resourceInfo, optsGetter)
|
store, err := grafanaregistry.NewRegistryStore(scheme, resourceInfo, optsGetter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -141,6 +136,11 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
storage[resourceInfo.StoragePath("parents")] = &subParentsREST{
|
||||||
|
getter: storage[resourceInfo.StoragePath()].(rest.Getter), // Get the parents
|
||||||
|
}
|
||||||
|
storage[resourceInfo.StoragePath("counts")] = &subCountREST{searcher: b.searcher}
|
||||||
|
storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc}
|
||||||
|
|
||||||
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage
|
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage
|
||||||
b.storage = storage[resourceInfo.StoragePath()].(grafanarest.Storage)
|
b.storage = storage[resourceInfo.StoragePath()].(grafanarest.Storage)
|
||||||
|
@ -2,18 +2,20 @@ package folders
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||||
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
|
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type subParentsREST struct {
|
type subParentsREST struct {
|
||||||
service folder.Service
|
getter rest.Getter
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = rest.Connecter(&subParentsREST{})
|
var _ = rest.Connecter(&subParentsREST{})
|
||||||
@ -43,32 +45,58 @@ func (r *subParentsREST) NewConnectOptions() (runtime.Object, bool, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *subParentsREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
func (r *subParentsREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||||
|
obj, err := r.getter.Get(ctx, name, &metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
folder, ok := obj.(*v0alpha1.Folder)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("expecting folder, found: %T", folder)
|
||||||
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
ns, err := request.NamespaceInfoFrom(ctx, true)
|
|
||||||
if err != nil {
|
|
||||||
responder.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
parents, err := r.service.GetParents(ctx, folder.GetParentsQuery{
|
|
||||||
UID: name,
|
|
||||||
OrgID: ns.OrgID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
responder.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
info := &v0alpha1.FolderInfoList{
|
info := &v0alpha1.FolderInfoList{
|
||||||
Items: make([]v0alpha1.FolderInfo, 0),
|
Items: []v0alpha1.FolderInfo{},
|
||||||
}
|
}
|
||||||
for _, parent := range parents {
|
for folder != nil {
|
||||||
|
parent := ""
|
||||||
|
meta, _ := utils.MetaAccessor(folder)
|
||||||
|
if meta != nil {
|
||||||
|
parent = meta.GetFolder()
|
||||||
|
}
|
||||||
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||||
UID: parent.UID,
|
Name: folder.Name,
|
||||||
Title: parent.Title,
|
Title: folder.Spec.Title,
|
||||||
Parent: parent.ParentUID,
|
Description: folder.Spec.Description,
|
||||||
|
Parent: parent,
|
||||||
})
|
})
|
||||||
|
if parent == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, err = r.getter.Get(ctx, parent, &metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||||
|
Name: parent,
|
||||||
|
Detached: true,
|
||||||
|
Description: err.Error(),
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
folder, ok = obj.(*v0alpha1.Folder)
|
||||||
|
if !ok {
|
||||||
|
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||||
|
Name: parent,
|
||||||
|
Detached: true,
|
||||||
|
Description: fmt.Sprintf("expected folder, found: %T", obj),
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start from the root
|
||||||
|
slices.Reverse(info.Items)
|
||||||
responder.Object(http.StatusOK, info)
|
responder.Object(http.StatusOK, info)
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user