history from SQL query

This commit is contained in:
Ryan McKinley 2024-06-27 08:49:24 +03:00
parent 4d49cc3118
commit 80fa46b225
5 changed files with 156 additions and 80 deletions

View File

@ -0,0 +1,15 @@
This implements a ResourceServer backed by the existing dashboard SQL tables.
There are a few oddities worth noting. This is not a totally accurate implementation,
but it is good enough to drive the UI needs and let kubectl list work!
1. The resourceVersion is the dashboard version
- each resource starts at 1 and increases
- there are duplicate resourceVersions!
- the resourceVersion is never set on the list commands
1. Results are always sorted by internal id ascending
- this ensures everything is returned
1. The history objects have createdTimestamp == updatedTimestamp
- not real, but good enough

View File

@ -19,7 +19,6 @@ import (
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils" gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/provisioning" "github.com/grafana/grafana/pkg/services/provisioning"
"github.com/grafana/grafana/pkg/services/sqlstore/session" "github.com/grafana/grafana/pkg/services/sqlstore/session"
"github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resource"
@ -30,15 +29,12 @@ var (
) )
type dashboardRow struct { type dashboardRow struct {
// The numeric resource version for this dashboard // The numeric version for this dashboard
ResourceVersion int64 Version int64
// Dashboard resource // Dashboard resource
Dash *dashboardsV0.Dashboard Dash *dashboardsV0.Dashboard
// Title -- this may come from saved metadata rather than the body
Title string
// The folder UID (needed for access control checks) // The folder UID (needed for access control checks)
FolderUID string FolderUID string
@ -56,7 +52,6 @@ type dashboardSqlAccess struct {
namespacer request.NamespaceMapper namespacer request.NamespaceMapper
dashStore dashboards.Store dashStore dashboards.Store
provisioning provisioning.ProvisioningService provisioning provisioning.ProvisioningService
versions dashver.Service
// Typically one... the server wrapper // Typically one... the server wrapper
subscribers []chan *resource.WrittenEvent subscribers []chan *resource.WrittenEvent
@ -67,21 +62,19 @@ func NewDashboardAccess(sql db.DB,
namespacer request.NamespaceMapper, namespacer request.NamespaceMapper,
dashStore dashboards.Store, dashStore dashboards.Store,
provisioning provisioning.ProvisioningService, provisioning provisioning.ProvisioningService,
versions dashver.Service) DashboardAccess { ) DashboardAccess {
return &dashboardSqlAccess{ return &dashboardSqlAccess{
sql: sql, sql: sql,
sess: sql.GetSqlxSession(), sess: sql.GetSqlxSession(),
namespacer: namespacer, namespacer: namespacer,
dashStore: dashStore, dashStore: dashStore,
provisioning: provisioning, provisioning: provisioning,
versions: versions,
} }
} }
const selector = `SELECT const selector = `SELECT
dashboard.org_id, dashboard.id, dashboard.org_id, dashboard.id,
dashboard.uid,slug, dashboard.uid, dashboard.folder_uid,
dashboard.folder_uid,
dashboard.created,dashboard.created_by,CreatedUSER.uid as created_uid, dashboard.created,dashboard.created_by,CreatedUSER.uid as created_uid,
dashboard.updated,dashboard.updated_by,UpdatedUSER.uid as updated_uid, dashboard.updated,dashboard.updated_by,UpdatedUSER.uid as updated_uid,
plugin_id, plugin_id,
@ -89,14 +82,29 @@ const selector = `SELECT
dashboard_provisioning.external_id as origin_path, dashboard_provisioning.external_id as origin_path,
dashboard_provisioning.check_sum as origin_key, dashboard_provisioning.check_sum as origin_key,
dashboard_provisioning.updated as origin_ts, dashboard_provisioning.updated as origin_ts,
dashboard.version, dashboard.version, '', dashboard.data
title,
dashboard.data
FROM dashboard FROM dashboard
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
LEFT OUTER JOIN user AS CreatedUSER ON dashboard.created_by = CreatedUSER.id LEFT OUTER JOIN user AS CreatedUSER ON dashboard.created_by = CreatedUSER.id
LEFT OUTER JOIN user AS UpdatedUSER ON dashboard.created_by = UpdatedUSER.id LEFT OUTER JOIN user AS UpdatedUSER ON dashboard.created_by = UpdatedUSER.id
WHERE is_folder = false` WHERE dashboard.is_folder = false`
const history = `SELECT
dashboard.org_id, dashboard.id,
dashboard.uid, dashboard.folder_uid,
dashboard_version.created,dashboard_version.created_by,CreatedUSER.uid as created_uid,
dashboard_version.created,dashboard_version.created_by,CreatedUSER.uid as updated_uid,
plugin_id,
dashboard_provisioning.name as origin_name,
dashboard_provisioning.external_id as origin_path,
dashboard_provisioning.check_sum as origin_key,
dashboard_provisioning.updated as origin_ts,
dashboard_version.version, dashboard_version.message, dashboard_version.data
FROM dashboard
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
LEFT OUTER JOIN dashboard_version ON dashboard.id = dashboard_version.dashboard_id
LEFT OUTER JOIN user AS CreatedUSER ON dashboard_version.created_by = CreatedUSER.id
WHERE dashboard.is_folder = false`
func (a *dashboardSqlAccess) getRows(ctx context.Context, query *DashboardQuery) (*rowsWrapper, int, error) { func (a *dashboardSqlAccess) getRows(ctx context.Context, query *DashboardQuery) (*rowsWrapper, int, error) {
if len(query.Labels) > 0 { if len(query.Labels) > 0 {
@ -107,24 +115,50 @@ func (a *dashboardSqlAccess) getRows(ctx context.Context, query *DashboardQuery)
// } // }
} }
sqlcmd := selector
args := []any{query.OrgID} args := []any{query.OrgID}
sqlcmd := fmt.Sprintf("%s AND dashboard.org_id=$%d", selector, len(args))
limit := query.Limit limit := query.Limit
if limit < 1 { if limit < 1 {
limit = 15 // limit = 15 //
} }
if query.UID != "" { if query.FromHistory {
sqlcmd = fmt.Sprintf("%s AND dashboard.org_id=$%d\n ", history, len(args))
if query.UID == "" {
return nil, 0, fmt.Errorf("history query must have a UID")
}
args = append(args, query.UID) args = append(args, query.UID)
sqlcmd = fmt.Sprintf("%s AND dashboard.uid=$%d", sqlcmd, len(args)) sqlcmd = fmt.Sprintf("%s AND dashboard.uid=$%d", sqlcmd, len(args))
} else if query.MinID > 0 {
args = append(args, query.MinID) if query.Version > 0 {
sqlcmd = fmt.Sprintf("%s AND dashboard.id>=$%d", sqlcmd, len(args)) args = append(args, query.Version)
sqlcmd = fmt.Sprintf("%s AND dashboard_version.version=$%d", sqlcmd, len(args))
} else if query.MinID > 0 {
args = append(args, query.MinID)
sqlcmd = fmt.Sprintf("%s AND dashboard_version.version<$%d", sqlcmd, len(args))
}
args = append(args, (limit + 2)) // add more so we can include a next token
sqlcmd = fmt.Sprintf("%s\n ORDER BY dashboard_version.version desc LIMIT $%d", sqlcmd, len(args))
} else {
sqlcmd = fmt.Sprintf("%s AND dashboard.org_id=$%d\n ", selector, len(args))
if query.UID != "" {
args = append(args, query.UID)
sqlcmd = fmt.Sprintf("%s AND dashboard.uid=$%d", sqlcmd, len(args))
} else if query.MinID > 0 {
args = append(args, query.MinID)
sqlcmd = fmt.Sprintf("%s AND dashboard.id>=$%d", sqlcmd, len(args))
}
args = append(args, (limit + 2)) // add more so we can include a next token
sqlcmd = fmt.Sprintf("%s\n ORDER BY dashboard.id asc LIMIT $%d", sqlcmd, len(args))
} }
args = append(args, (limit + 2)) // add more so we can include a next token fmt.Printf("%s // %v\n", sqlcmd, args)
sqlcmd = fmt.Sprintf("%s ORDER BY dashboard.id asc LIMIT $%d", sqlcmd, len(args))
rows, err := a.doQuery(ctx, sqlcmd, args...) rows, err := a.doQuery(ctx, sqlcmd, args...)
if err != nil { if err != nil {
@ -199,7 +233,6 @@ func (a *dashboardSqlAccess) scanRow(rows *sql.Rows) (*dashboardRow, error) {
var dashboard_id int64 var dashboard_id int64
var orgId int64 var orgId int64
var slug string
var folder_uid sql.NullString var folder_uid sql.NullString
var updated time.Time var updated time.Time
var updatedByID int64 var updatedByID int64
@ -208,6 +241,7 @@ func (a *dashboardSqlAccess) scanRow(rows *sql.Rows) (*dashboardRow, error) {
var created time.Time var created time.Time
var createdByID int64 var createdByID int64
var createdByUID sql.NullString var createdByUID sql.NullString
var message sql.NullString
var plugin_id string var plugin_id string
var origin_name sql.NullString var origin_name sql.NullString
@ -217,20 +251,18 @@ func (a *dashboardSqlAccess) scanRow(rows *sql.Rows) (*dashboardRow, error) {
var data []byte // the dashboard JSON var data []byte // the dashboard JSON
var version int64 var version int64
err := rows.Scan(&orgId, &dashboard_id, &dash.Name, err := rows.Scan(&orgId, &dashboard_id, &dash.Name, &folder_uid,
&slug, &folder_uid,
&created, &createdByID, &createdByUID, &created, &createdByID, &createdByUID,
&updated, &updatedByID, &updatedByUID, &updated, &updatedByID, &updatedByUID,
&plugin_id, &plugin_id,
&origin_name, &origin_path, &origin_hash, &origin_ts, &origin_name, &origin_path, &origin_hash, &origin_ts,
&version, &version, &message, &data,
&row.Title, &data,
) )
row.token = &continueToken{orgId: orgId, id: dashboard_id} row.token = &continueToken{orgId: orgId, id: dashboard_id}
if err == nil { if err == nil {
row.ResourceVersion = updated.UnixNano() + version row.Version = version
dash.ResourceVersion = fmt.Sprintf("%d", row.ResourceVersion) dash.ResourceVersion = fmt.Sprintf("%d", version)
dash.Namespace = a.namespacer(orgId) dash.Namespace = a.namespacer(orgId)
dash.UID = gapiutil.CalculateClusterWideUID(dash) dash.UID = gapiutil.CalculateClusterWideUID(dash)
dash.SetCreationTimestamp(metav1.NewTime(created)) dash.SetCreationTimestamp(metav1.NewTime(created))
@ -239,7 +271,6 @@ func (a *dashboardSqlAccess) scanRow(rows *sql.Rows) (*dashboardRow, error) {
return nil, err return nil, err
} }
meta.SetUpdatedTimestamp(&updated) meta.SetUpdatedTimestamp(&updated)
meta.SetSlug(slug)
if createdByID > 0 { if createdByID > 0 {
meta.SetCreatedBy(identity.NewNamespaceID(identity.NamespaceUser, createdByID).String()) meta.SetCreatedBy(identity.NewNamespaceID(identity.NamespaceUser, createdByID).String())
} else if createdByID < 0 { } else if createdByID < 0 {
@ -250,6 +281,9 @@ func (a *dashboardSqlAccess) scanRow(rows *sql.Rows) (*dashboardRow, error) {
} else if updatedByID < 0 { } else if updatedByID < 0 {
meta.SetCreatedBy(identity.NewNamespaceID(identity.NamespaceProvisioning, 0).String()) meta.SetCreatedBy(identity.NewNamespaceID(identity.NamespaceProvisioning, 0).String())
} }
if message.Valid && message.String != "" {
meta.SetMessage(message.String)
}
if folder_uid.Valid { if folder_uid.Valid {
meta.SetFolder(folder_uid.String) meta.SetFolder(folder_uid.String)
row.FolderUID = folder_uid.String row.FolderUID = folder_uid.String
@ -287,7 +321,6 @@ func (a *dashboardSqlAccess) scanRow(rows *sql.Rows) (*dashboardRow, error) {
return row, err return row, err
} }
dash.Spec.Set("id", dashboard_id) // add it so we can get it from the body later dash.Spec.Set("id", dashboard_id) // add it so we can get it from the body later
row.Title = dash.Spec.GetNestedString("title")
} }
} }
return row, err return row, err

View File

@ -11,11 +11,10 @@ import (
"github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/apimachinery/utils"
dashboard "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1" dashboard "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resource"
) )
func getDashbaordFromEvent(event resource.WriteEvent) (*dashboard.Dashboard, error) { func getDashboardFromEvent(event resource.WriteEvent) (*dashboard.Dashboard, error) {
obj, ok := event.Object.GetRuntimeObject() obj, ok := event.Object.GetRuntimeObject()
if ok && obj != nil { if ok && obj != nil {
dash, ok := obj.(*dashboard.Dashboard) dash, ok := obj.(*dashboard.Dashboard)
@ -60,7 +59,7 @@ func (a *dashboardSqlAccess) WriteEvent(ctx context.Context, event resource.Writ
// The difference depends on embedded internal ID // The difference depends on embedded internal ID
case resource.WatchEvent_ADDED, resource.WatchEvent_MODIFIED: case resource.WatchEvent_ADDED, resource.WatchEvent_MODIFIED:
{ {
dash, err := getDashbaordFromEvent(event) dash, err := getDashboardFromEvent(event)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -118,7 +117,7 @@ func (a *dashboardSqlAccess) GetDashboard(ctx context.Context, orgId int64, uid
return nil, 0, err return nil, 0, err
} }
return row.Dash, row.ResourceVersion, nil return row.Dash, row.Version, nil
} }
// Read implements ResourceStoreServer. // Read implements ResourceStoreServer.
@ -201,7 +200,7 @@ func (a *dashboardSqlAccess) List(ctx context.Context, req *resource.ListRequest
return list, err return list, err
} }
list.Items = append(list.Items, &resource.ResourceWrapper{ list.Items = append(list.Items, &resource.ResourceWrapper{
ResourceVersion: row.ResourceVersion, ResourceVersion: row.Version,
Value: val, Value: val,
}) })
} }
@ -267,46 +266,75 @@ func (a *dashboardSqlAccess) GetBlob(ctx context.Context, key *resource.Resource
} }
func (a *dashboardSqlAccess) History(ctx context.Context, req *resource.HistoryRequest) (*resource.HistoryResponse, error) { func (a *dashboardSqlAccess) History(ctx context.Context, req *resource.HistoryRequest) (*resource.HistoryResponse, error) {
ns, err := request.ParseNamespace(req.Key.Namespace) info, err := request.ParseNamespace(req.Key.Namespace)
if err == nil { if err == nil {
err = isDashboardKey(req.Key, true) err = isDashboardKey(req.Key, false)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
versions, err := a.versions.List(ctx, &dashver.ListDashboardVersionsQuery{
OrgID: ns.OrgID, token, err := readContinueToken(req.NextPageToken)
DashboardUID: req.Key.Name,
Limit: 100,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
if token.orgId > 0 && token.orgId != info.OrgID {
return nil, fmt.Errorf("token and orgID mismatch")
}
rsp := &resource.HistoryResponse{} query := &DashboardQuery{
for _, version := range versions { OrgID: info.OrgID,
partial := &metav1.PartialObjectMetadata{} Limit: int(req.Limit),
meta, err := utils.MetaAccessor(partial) MaxBytes: 2 * 1024 * 1024, // 2MB,
if err != nil { MinID: token.id,
return nil, err FromHistory: true,
} UID: req.Key.Name,
meta.SetName(version.DashboardUID) }
meta.SetCreationTimestamp(metav1.NewTime(version.Created)) // ???
meta.SetUpdatedTimestampMillis(version.Created.UnixMilli())
meta.SetMessage(version.Message)
meta.SetResourceVersionInt64(version.Created.UnixMilli())
bytes, err := json.Marshal(partial) rows, limit, err := a.getRows(ctx, query)
if err != nil { if err != nil {
return nil, err return nil, err
}
defer func() { _ = rows.Close() }()
totalSize := 0
list := &resource.HistoryResponse{}
for {
row, err := rows.Next()
if err != nil || row == nil {
return list, err
} }
rsp.Items = append(rsp.Items, &resource.ResourceMeta{
ResourceVersion: version.Created.UnixMilli(), totalSize += row.Bytes
PartialObjectMeta: bytes, if len(list.Items) > 0 && (totalSize > query.MaxBytes || len(list.Items) >= limit) {
// if query.Requirements.Folder != nil {
// row.token.folder = *query.Requirements.Folder
// }
row.token.id = row.Version // Use the version as the increment
list.NextPageToken = row.token.String() // will skip this one but start here next time
return list, err
}
partial := &metav1.PartialObjectMetadata{
ObjectMeta: row.Dash.ObjectMeta,
}
partial.UID = "" // it is not useful/helpful/accurate and just confusing now
val, err := json.Marshal(partial)
if err != nil {
return list, err
}
full, err := json.Marshal(row.Dash.Spec)
if err != nil {
return list, err
}
list.Items = append(list.Items, &resource.ResourceMeta{
ResourceVersion: row.Version,
PartialObjectMeta: val,
Size: int32(len(full)),
Hash: "??", // hash the full?
}) })
} }
return rsp, err
} }
// Used for efficient provisioning // Used for efficient provisioning

View File

@ -16,6 +16,9 @@ type DashboardQuery struct {
MaxBytes int MaxBytes int
MinID int64 // from continue token MinID int64 // from continue token
FromHistory bool
Version int64
// The label requirements // The label requirements
Labels []*resource.Requirement Labels []*resource.Requirement
} }

View File

@ -15,7 +15,6 @@ import (
common "k8s.io/kube-openapi/pkg/common" common "k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/spec3" "k8s.io/kube-openapi/pkg/spec3"
"github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1"
dashboard "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1" dashboard "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1"
"github.com/grafana/grafana/pkg/apiserver/builder" "github.com/grafana/grafana/pkg/apiserver/builder"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
@ -27,7 +26,6 @@ import (
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils" gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/provisioning" "github.com/grafana/grafana/pkg/services/provisioning"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@ -48,7 +46,6 @@ type DashboardsAPIBuilder struct {
func RegisterAPIService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, func RegisterAPIService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
apiregistration builder.APIRegistrar, apiregistration builder.APIRegistrar,
dashboardService dashboards.DashboardService, dashboardService dashboards.DashboardService,
dashboardVersionService dashver.Service,
accessControl accesscontrol.AccessControl, accessControl accesscontrol.AccessControl,
provisioning provisioning.ProvisioningService, provisioning provisioning.ProvisioningService,
dashStore dashboards.Store, dashStore dashboards.Store,
@ -69,7 +66,7 @@ func RegisterAPIService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
store: &dashboardStorage{ store: &dashboardStorage{
resource: dashboard.DashboardResourceInfo, resource: dashboard.DashboardResourceInfo,
access: access.NewDashboardAccess(sql, namespacer, dashStore, provisioning, dashboardVersionService), access: access.NewDashboardAccess(sql, namespacer, dashStore, provisioning),
tableConverter: gapiutil.NewTableConverter( tableConverter: gapiutil.NewTableConverter(
dashboard.DashboardResourceInfo.GroupResource(), dashboard.DashboardResourceInfo.GroupResource(),
[]metav1.TableColumnDefinition{ []metav1.TableColumnDefinition{
@ -78,7 +75,7 @@ func RegisterAPIService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
{Name: "Created At", Type: "date"}, {Name: "Created At", Type: "date"},
}, },
func(obj any) ([]interface{}, error) { func(obj any) ([]interface{}, error) {
dash, ok := obj.(*v0alpha1.Dashboard) dash, ok := obj.(*dashboard.Dashboard)
if ok { if ok {
if dash != nil { if dash != nil {
return []interface{}{ return []interface{}{
@ -97,7 +94,7 @@ func RegisterAPIService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
} }
func (b *DashboardsAPIBuilder) GetGroupVersion() schema.GroupVersion { func (b *DashboardsAPIBuilder) GetGroupVersion() schema.GroupVersion {
return v0alpha1.DashboardResourceInfo.GroupVersion() return dashboard.DashboardResourceInfo.GroupVersion()
} }
func (b *DashboardsAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode { func (b *DashboardsAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode {
@ -107,18 +104,18 @@ func (b *DashboardsAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) { func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
scheme.AddKnownTypes(gv, scheme.AddKnownTypes(gv,
&v0alpha1.Dashboard{}, &dashboard.Dashboard{},
&v0alpha1.DashboardList{}, &dashboard.DashboardList{},
&v0alpha1.DashboardWithAccessInfo{}, &dashboard.DashboardWithAccessInfo{},
&v0alpha1.DashboardVersionList{}, &dashboard.DashboardVersionList{},
&v0alpha1.VersionsQueryOptions{}, &dashboard.VersionsQueryOptions{},
&metav1.PartialObjectMetadata{}, &metav1.PartialObjectMetadata{},
&metav1.PartialObjectMetadataList{}, &metav1.PartialObjectMetadataList{},
) )
} }
func (b *DashboardsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { func (b *DashboardsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
resourceInfo := v0alpha1.DashboardResourceInfo resourceInfo := dashboard.DashboardResourceInfo
addKnownTypes(scheme, resourceInfo.GroupVersion()) addKnownTypes(scheme, resourceInfo.GroupVersion())
// Link this version to the internal representation. // Link this version to the internal representation.
@ -144,7 +141,7 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo(
desiredMode grafanarest.DualWriterMode, desiredMode grafanarest.DualWriterMode,
reg prometheus.Registerer, reg prometheus.Registerer,
) (*genericapiserver.APIGroupInfo, error) { ) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v0alpha1.GROUP, scheme, metav1.ParameterCodec, codecs) apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(dashboard.GROUP, scheme, metav1.ParameterCodec, codecs)
dash := b.store.resource dash := b.store.resource
legacyStore, err := b.store.newStore(scheme, optsGetter) legacyStore, err := b.store.newStore(scheme, optsGetter)
@ -174,12 +171,12 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo(
// reg) // reg)
// } // }
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[dashboard.VERSION] = storage
return &apiGroupInfo, nil return &apiGroupInfo, nil
} }
func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {
return v0alpha1.GetOpenAPIDefinitions return dashboard.GetOpenAPIDefinitions
} }
func (b *DashboardsAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) { func (b *DashboardsAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
@ -190,8 +187,8 @@ func (b *DashboardsAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
root := "/apis/" + b.GetGroupVersion().String() + "/" root := "/apis/" + b.GetGroupVersion().String() + "/"
// Hide the ability to list or watch across all tenants // Hide the ability to list or watch across all tenants
delete(oas.Paths.Paths, root+v0alpha1.DashboardResourceInfo.GroupResource().Resource) delete(oas.Paths.Paths, root+dashboard.DashboardResourceInfo.GroupResource().Resource)
delete(oas.Paths.Paths, root+"watch/"+v0alpha1.DashboardResourceInfo.GroupResource().Resource) delete(oas.Paths.Paths, root+"watch/"+dashboard.DashboardResourceInfo.GroupResource().Resource)
// The root API discovery list // The root API discovery list
sub := oas.Paths.Paths[root] sub := oas.Paths.Paths[root]