mirror of
https://github.com/grafana/grafana.git
synced 2025-01-08 15:13:30 -06:00
history in resource package
This commit is contained in:
parent
37c6b56e4e
commit
b71329a8c3
@ -113,10 +113,9 @@ func (a *dashboardSqlAccess) GetDashboard(ctx context.Context, orgId int64, uid
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
row, err := rows.Next()
|
||||
if err != nil {
|
||||
if err != nil || row == nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return row.Dash, row.Version, nil
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/apistore"
|
||||
)
|
||||
|
||||
var _ builder.APIGroupBuilder = (*DashboardsAPIBuilder)(nil)
|
||||
@ -154,9 +155,10 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo(
|
||||
storage[dash.StoragePath("dto")] = &DTOConnector{
|
||||
builder: b,
|
||||
}
|
||||
storage[dash.StoragePath("versions")] = &VersionsREST{
|
||||
search: b.store.server, // resource.NewLocalResourceSearchClient(b.store.server),
|
||||
}
|
||||
storage[dash.StoragePath("history")] = apistore.NewHistoryConnector(
|
||||
b.store.server, // as client???
|
||||
dashboard.DashboardResourceInfo.GroupResource(),
|
||||
)
|
||||
|
||||
// // Dual writes if a RESTOptionsGetter is provided
|
||||
// if desiredMode != grafanarest.Mode0 && optsGetter != nil {
|
||||
|
@ -1,125 +0,0 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
dashboard "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
)
|
||||
|
||||
type VersionsREST struct {
|
||||
search resource.ResourceSearchServer // should be a client!
|
||||
}
|
||||
|
||||
var _ = rest.Connecter(&VersionsREST{})
|
||||
var _ = rest.StorageMetadata(&VersionsREST{})
|
||||
|
||||
func (r *VersionsREST) New() runtime.Object {
|
||||
return &metav1.PartialObjectMetadataList{}
|
||||
}
|
||||
|
||||
func (r *VersionsREST) Destroy() {
|
||||
}
|
||||
|
||||
func (r *VersionsREST) ConnectMethods() []string {
|
||||
return []string{"GET"}
|
||||
}
|
||||
|
||||
func (r *VersionsREST) ProducesMIMETypes(verb string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *VersionsREST) ProducesObject(verb string) interface{} {
|
||||
return &metav1.PartialObjectMetadataList{}
|
||||
}
|
||||
|
||||
func (r *VersionsREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
return nil, true, ""
|
||||
}
|
||||
|
||||
func (r *VersionsREST) Connect(ctx context.Context, uid string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := &resource.ResourceKey{
|
||||
Namespace: info.Value,
|
||||
Group: dashboard.GROUP,
|
||||
Resource: dashboard.DashboardResourceInfo.GroupResource().Resource,
|
||||
Name: uid,
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
path := req.URL.Path
|
||||
idx := strings.LastIndex(path, "/versions/")
|
||||
if idx > 0 {
|
||||
vkey := path[strings.LastIndex(path, "/")+1:]
|
||||
version, err := strconv.ParseInt(vkey, 10, 64)
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
dashbytes, err := r.search.Read(ctx, &resource.ReadRequest{
|
||||
Key: key,
|
||||
ResourceVersion: version,
|
||||
})
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Convert the version to a regular dashboard
|
||||
dash := &dashboard.Dashboard{}
|
||||
json.Unmarshal(dashbytes.Value, dash)
|
||||
meta, err := utils.MetaAccessor(dash)
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
meta.SetResourceVersionInt64(dashbytes.ResourceVersion)
|
||||
responder.Object(100, dash)
|
||||
return
|
||||
}
|
||||
|
||||
rsp, err := r.search.History(ctx, &resource.HistoryRequest{
|
||||
NextPageToken: "", // TODO!
|
||||
Limit: 100,
|
||||
Key: key,
|
||||
})
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
list := &metav1.PartialObjectMetadataList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
Continue: rsp.NextPageToken,
|
||||
},
|
||||
}
|
||||
if rsp.ResourceVersion > 0 {
|
||||
list.ResourceVersion = strconv.FormatInt(rsp.ResourceVersion, 10)
|
||||
}
|
||||
|
||||
for _, v := range rsp.Items {
|
||||
partial := metav1.PartialObjectMetadata{}
|
||||
err = json.Unmarshal(v.PartialObjectMeta, &partial)
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
list.Items = append(list.Items, partial)
|
||||
}
|
||||
responder.Object(http.StatusOK, list)
|
||||
}), nil
|
||||
}
|
103
pkg/storage/unified/apistore/history.go
Normal file
103
pkg/storage/unified/apistore/history.go
Normal file
@ -0,0 +1,103 @@
|
||||
package apistore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
)
|
||||
|
||||
type HistoryConnector interface {
|
||||
rest.Storage
|
||||
rest.Connecter
|
||||
rest.StorageMetadata
|
||||
}
|
||||
|
||||
func NewHistoryConnector(search resource.ResourceSearchServer, gr schema.GroupResource) HistoryConnector {
|
||||
return &historyREST{
|
||||
search: search,
|
||||
gr: gr,
|
||||
}
|
||||
}
|
||||
|
||||
type historyREST struct {
|
||||
search resource.ResourceSearchServer // should be a client!
|
||||
gr schema.GroupResource
|
||||
}
|
||||
|
||||
func (r *historyREST) New() runtime.Object {
|
||||
return &metav1.PartialObjectMetadataList{}
|
||||
}
|
||||
|
||||
func (r *historyREST) Destroy() {
|
||||
}
|
||||
|
||||
func (r *historyREST) ConnectMethods() []string {
|
||||
return []string{"GET"}
|
||||
}
|
||||
|
||||
func (r *historyREST) ProducesMIMETypes(verb string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *historyREST) ProducesObject(verb string) interface{} {
|
||||
return &metav1.PartialObjectMetadataList{}
|
||||
}
|
||||
|
||||
func (r *historyREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
return nil, false, ""
|
||||
}
|
||||
|
||||
func (r *historyREST) Connect(ctx context.Context, uid string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := &resource.ResourceKey{
|
||||
Namespace: info.Value,
|
||||
Group: r.gr.Group,
|
||||
Resource: r.gr.Resource,
|
||||
Name: uid,
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
query := req.URL.Query()
|
||||
rsp, err := r.search.History(ctx, &resource.HistoryRequest{
|
||||
NextPageToken: query.Get("token"),
|
||||
Limit: 100, // TODO, from query
|
||||
Key: key,
|
||||
})
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
list := &metav1.PartialObjectMetadataList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
Continue: rsp.NextPageToken,
|
||||
},
|
||||
}
|
||||
if rsp.ResourceVersion > 0 {
|
||||
list.ResourceVersion = strconv.FormatInt(rsp.ResourceVersion, 10)
|
||||
}
|
||||
for _, v := range rsp.Items {
|
||||
partial := metav1.PartialObjectMetadata{}
|
||||
err = json.Unmarshal(v.PartialObjectMeta, &partial)
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
list.Items = append(list.Items, partial)
|
||||
}
|
||||
responder.Object(http.StatusOK, list)
|
||||
}), nil
|
||||
}
|
@ -248,12 +248,21 @@ func (s *Storage) Watch(ctx context.Context, _ string, opts storage.ListOptions)
|
||||
// The returned contents may be delayed, but it is guaranteed that they will
|
||||
// match 'opts.ResourceVersion' according 'opts.ResourceVersionMatch'.
|
||||
func (s *Storage) Get(ctx context.Context, _ string, opts storage.GetOptions, objPtr runtime.Object) error {
|
||||
key, err := getKey(ctx)
|
||||
var err error
|
||||
req := &resource.ReadRequest{}
|
||||
req.Key, err = getKey(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rsp, err := s.store.Read(ctx, &resource.ReadRequest{Key: key})
|
||||
if opts.ResourceVersion != "" {
|
||||
req.ResourceVersion, err = strconv.ParseInt(opts.ResourceVersion, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
rsp, err := s.store.Read(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user