Skip to content

Commit d2bc4f3

Browse files
authored
DualWrite: Cleanup and centralize the dual write creation (grafana#90013)
1 parent 4b5b599 commit d2bc4f3

File tree

22 files changed

+125
-150
lines changed

22 files changed

+125
-150
lines changed

pkg/apiserver/rest/dualwriter.go

+15-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"k8s.io/apimachinery/pkg/api/meta"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
"k8s.io/apimachinery/pkg/runtime"
14+
"k8s.io/apimachinery/pkg/runtime/schema"
1415
"k8s.io/apiserver/pkg/registry/rest"
1516
"k8s.io/klog/v2"
1617
)
@@ -25,6 +26,9 @@ var (
2526
_ rest.SingularNameProvider = (DualWriter)(nil)
2627
)
2728

29+
// Function that will create a dual writer
30+
type DualWriteBuilder func(gr schema.GroupResource, legacy LegacyStorage, storage Storage) (Storage, error)
31+
2832
// Storage is a storage implementation that satisfies the same interfaces as genericregistry.Store.
2933
type Storage interface {
3034
rest.Storage
@@ -152,7 +156,12 @@ func SetDualWritingMode(
152156
entity string,
153157
desiredMode DualWriterMode,
154158
reg prometheus.Registerer,
155-
) (DualWriter, error) {
159+
) (DualWriterMode, error) {
160+
// Mode0 means no DualWriter
161+
if desiredMode == Mode0 {
162+
return Mode0, nil
163+
}
164+
156165
toMode := map[string]DualWriterMode{
157166
// It is not possible to initialize a mode 0 dual writer. Mode 0 represents
158167
// writing to legacy storage without `unifiedStorage` enabled.
@@ -166,7 +175,7 @@ func SetDualWritingMode(
166175
// Use entity name as key
167176
m, ok, err := kvs.Get(ctx, entity)
168177
if err != nil {
169-
return nil, errors.New("failed to fetch current dual writing mode")
178+
return Mode0, errors.New("failed to fetch current dual writing mode")
170179
}
171180

172181
currentMode, valid := toMode[m]
@@ -182,7 +191,7 @@ func SetDualWritingMode(
182191

183192
err := kvs.Set(ctx, entity, fmt.Sprint(currentMode))
184193
if err != nil {
185-
return nil, errDualWriterSetCurrentMode
194+
return Mode0, errDualWriterSetCurrentMode
186195
}
187196
}
188197

@@ -194,7 +203,7 @@ func SetDualWritingMode(
194203

195204
err := kvs.Set(ctx, entity, fmt.Sprint(currentMode))
196205
if err != nil {
197-
return nil, errDualWriterSetCurrentMode
206+
return Mode0, errDualWriterSetCurrentMode
198207
}
199208
}
200209
if (desiredMode == Mode1) && (currentMode == Mode2) {
@@ -204,13 +213,13 @@ func SetDualWritingMode(
204213

205214
err := kvs.Set(ctx, entity, fmt.Sprint(currentMode))
206215
if err != nil {
207-
return nil, errDualWriterSetCurrentMode
216+
return Mode0, errDualWriterSetCurrentMode
208217
}
209218
}
210219

211220
// #TODO add support for other combinations of desired and current modes
212221

213-
return NewDualWriter(currentMode, legacy, storage, reg), nil
222+
return currentMode, nil
214223
}
215224

216225
var defaultConverter = runtime.UnstructuredConverter(runtime.DefaultUnstructuredConverter)

pkg/apiserver/rest/dualwriter_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ func TestSetDualWritingMode(t *testing.T) {
4646
kvStore := &fakeNamespacedKV{data: make(map[string]string), namespace: "storage.dualwriting." + tt.stackID}
4747

4848
p := prometheus.NewRegistry()
49-
dw, err := SetDualWritingMode(context.Background(), kvStore, ls, us, "playlist.grafana.app/v0alpha1", tt.desiredMode, p)
49+
dwMode, err := SetDualWritingMode(context.Background(), kvStore, ls, us, "playlist.grafana.app/v0alpha1", tt.desiredMode, p)
5050
assert.NoError(t, err)
51-
assert.Equal(t, tt.expectedMode, dw.Mode())
51+
assert.Equal(t, tt.expectedMode, dwMode)
5252

5353
// check kv store
5454
val, ok, err := kvStore.Get(context.Background(), "playlist.grafana.app/v0alpha1")

pkg/cmd/grafana/apiserver/server.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ func (o *APIServerOptions) RunAPIServer(config *genericapiserver.RecommendedConf
166166

167167
// Install the API Group+version
168168
// #TODO figure out how to configure storage type in o.Options.StorageOptions
169-
err = builder.InstallAPIs(grafanaAPIServer.Scheme, grafanaAPIServer.Codecs, server, config.RESTOptionsGetter, o.builders, o.Options.StorageOptions, o.Options.MetricsOptions.MetricsRegisterer)
169+
err = builder.InstallAPIs(grafanaAPIServer.Scheme, grafanaAPIServer.Codecs, server, config.RESTOptionsGetter, o.builders, o.Options.StorageOptions,
170+
o.Options.MetricsOptions.MetricsRegisterer, nil, nil, // no need for server lock in standalone
171+
)
170172
if err != nil {
171173
return err
172174
}

pkg/registry/apis/alerting/notifications/receiver/storage.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import (
99
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
1010
"k8s.io/apiserver/pkg/registry/rest"
1111

12-
"github.com/prometheus/client_golang/prometheus"
13-
1412
model "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
1513
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
1614
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
@@ -33,9 +31,9 @@ func NewStorage(
3331
legacySvc ReceiverService,
3432
namespacer request.NamespaceMapper,
3533
scheme *runtime.Scheme,
36-
desiredMode grafanarest.DualWriterMode,
3734
optsGetter generic.RESTOptionsGetter,
38-
reg prometheus.Registerer) (rest.Storage, error) {
35+
dualWriteBuilder grafanarest.DualWriteBuilder,
36+
) (rest.Storage, error) {
3937
legacyStore := &legacyStorage{
4038
service: legacySvc,
4139
namespacer: namespacer,
@@ -57,7 +55,7 @@ func NewStorage(
5755
return nil, fmt.Errorf("expected resource or info")
5856
}),
5957
}
60-
if optsGetter != nil && desiredMode != grafanarest.Mode0 {
58+
if optsGetter != nil && dualWriteBuilder != nil {
6159
strategy := grafanaregistry.NewStrategy(scheme)
6260
s := &genericregistry.Store{
6361
NewFunc: resourceInfo.NewFunc,
@@ -74,7 +72,7 @@ func NewStorage(
7472
if err := s.CompleteWithOptions(options); err != nil {
7573
return nil, err
7674
}
77-
return grafanarest.NewDualWriter(desiredMode, legacyStore, storage{Store: s}, reg), nil
75+
return dualWriteBuilder(resourceInfo.GroupResource(), legacyStore, storage{Store: s})
7876
}
7977
return legacyStore, nil
8078
}

pkg/registry/apis/alerting/notifications/register.go

+3-10
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66

7-
"github.com/prometheus/client_golang/prometheus"
87
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
98
"k8s.io/apimachinery/pkg/runtime"
109
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -37,11 +36,6 @@ type NotificationsAPIBuilder struct {
3736
gv schema.GroupVersion
3837
}
3938

40-
func (t NotificationsAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, toMode map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode {
41-
// Add required configuration support in order to enable other modes. For an example, see pkg/registry/apis/playlist/register.go
42-
return grafanarest.Mode0
43-
}
44-
4539
func RegisterAPIService(
4640
features featuremgmt.FeatureToggles,
4741
apiregistration builder.APIRegistrar,
@@ -77,17 +71,16 @@ func (t NotificationsAPIBuilder) GetAPIGroupInfo(
7771
scheme *runtime.Scheme,
7872
codecs serializer.CodecFactory,
7973
optsGetter generic.RESTOptionsGetter,
80-
desiredMode grafanarest.DualWriterMode,
81-
reg prometheus.Registerer,
74+
dualWriteBuilder grafanarest.DualWriteBuilder,
8275
) (*genericapiserver.APIGroupInfo, error) {
8376
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(notificationsModels.GROUP, scheme, metav1.ParameterCodec, codecs)
8477

85-
intervals, err := timeInterval.NewStorage(t.ng.Api.MuteTimings, t.namespacer, scheme, desiredMode, optsGetter, reg)
78+
intervals, err := timeInterval.NewStorage(t.ng.Api.MuteTimings, t.namespacer, scheme, optsGetter, dualWriteBuilder)
8679
if err != nil {
8780
return nil, fmt.Errorf("failed to initialize time-interval storage: %w", err)
8881
}
8982

90-
recvStorage, err := receiver.NewStorage(nil, t.namespacer, scheme, desiredMode, optsGetter, reg) // TODO: add receiver service
83+
recvStorage, err := receiver.NewStorage(nil, t.namespacer, scheme, optsGetter, dualWriteBuilder) // TODO: add receiver service
9184
if err != nil {
9285
return nil, fmt.Errorf("failed to initialize receiver storage: %w", err)
9386
}

pkg/registry/apis/alerting/notifications/timeinterval/storage.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
"k8s.io/apiserver/pkg/registry/rest"
1313
apistore "k8s.io/apiserver/pkg/storage"
1414

15-
"github.com/prometheus/client_golang/prometheus"
16-
1715
model "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
1816
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
1917
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
@@ -36,9 +34,9 @@ func NewStorage(
3634
legacySvc TimeIntervalService,
3735
namespacer request.NamespaceMapper,
3836
scheme *runtime.Scheme,
39-
desiredMode grafanarest.DualWriterMode,
4037
optsGetter generic.RESTOptionsGetter,
41-
reg prometheus.Registerer) (rest.Storage, error) {
38+
dualWriteBuilder grafanarest.DualWriteBuilder,
39+
) (rest.Storage, error) {
4240
legacyStore := &legacyStorage{
4341
service: legacySvc,
4442
namespacer: namespacer,
@@ -59,7 +57,7 @@ func NewStorage(
5957
return nil, fmt.Errorf("expected resource or info")
6058
}),
6159
}
62-
if optsGetter != nil && desiredMode != grafanarest.Mode0 {
60+
if optsGetter != nil && dualWriteBuilder != nil {
6361
strategy := grafanaregistry.NewStrategy(scheme)
6462
s := &genericregistry.Store{
6563
NewFunc: resourceInfo.NewFunc,
@@ -78,7 +76,7 @@ func NewStorage(
7876
if err := s.CompleteWithOptions(options); err != nil {
7977
return nil, err
8078
}
81-
return grafanarest.NewDualWriter(desiredMode, legacyStore, storage{Store: s}, reg), nil
79+
return dualWriteBuilder(resourceInfo.GroupResource(), legacyStore, storage{Store: s})
8280
}
8381
return legacyStore, nil
8482
}

pkg/registry/apis/dashboard/register.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,6 @@ func (b *DashboardsAPIBuilder) GetGroupVersion() schema.GroupVersion {
7676
return v0alpha1.DashboardResourceInfo.GroupVersion()
7777
}
7878

79-
func (b *DashboardsAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode {
80-
// Add required configuration support in order to enable other modes. For an example, see pkg/registry/apis/playlist/register.go
81-
return grafanarest.Mode0
82-
}
83-
8479
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
8580
scheme.AddKnownTypes(gv,
8681
&v0alpha1.Dashboard{},
@@ -115,8 +110,7 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo(
115110
scheme *runtime.Scheme,
116111
codecs serializer.CodecFactory, // pointer?
117112
optsGetter generic.RESTOptionsGetter,
118-
desiredMode grafanarest.DualWriterMode,
119-
reg prometheus.Registerer,
113+
dualWriteBuilder grafanarest.DualWriteBuilder,
120114
) (*genericapiserver.APIGroupInfo, error) {
121115
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v0alpha1.GROUP, scheme, metav1.ParameterCodec, codecs)
122116

@@ -142,12 +136,15 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo(
142136
}
143137

144138
// Dual writes if a RESTOptionsGetter is provided
145-
if desiredMode != grafanarest.Mode0 && optsGetter != nil {
139+
if optsGetter != nil && dualWriteBuilder != nil {
146140
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: grafanaregistry.GetAttrs}
147141
if err := store.CompleteWithOptions(options); err != nil {
148142
return nil, err
149143
}
150-
storage[resourceInfo.StoragePath()] = grafanarest.NewDualWriter(grafanarest.Mode1, legacyStore, store, reg)
144+
storage[resourceInfo.StoragePath()], err = dualWriteBuilder(resourceInfo.GroupResource(), legacyStore, store)
145+
if err != nil {
146+
return nil, err
147+
}
151148
}
152149

153150
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage

pkg/registry/apis/dashboardsnapshot/register.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,6 @@ func (b *SnapshotsAPIBuilder) GetGroupVersion() schema.GroupVersion {
8989
return resourceInfo.GroupVersion()
9090
}
9191

92-
func (b *SnapshotsAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode {
93-
// Add required configuration support in order to enable other modes. For an example, see pkg/registry/apis/playlist/register.go
94-
return grafanarest.Mode0
95-
}
96-
9792
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
9893
scheme.AddKnownTypes(gv,
9994
&dashboardsnapshot.DashboardSnapshot{},
@@ -130,8 +125,7 @@ func (b *SnapshotsAPIBuilder) GetAPIGroupInfo(
130125
scheme *runtime.Scheme,
131126
codecs serializer.CodecFactory, // pointer?
132127
optsGetter generic.RESTOptionsGetter,
133-
_ grafanarest.DualWriterMode,
134-
_ prometheus.Registerer,
128+
_ grafanarest.DualWriteBuilder,
135129
) (*genericapiserver.APIGroupInfo, error) {
136130
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(dashboardsnapshot.GROUP, scheme, metav1.ParameterCodec, codecs)
137131
storage := map[string]rest.Storage{}

pkg/registry/apis/datasource/register.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,6 @@ func (b *DataSourceAPIBuilder) GetGroupVersion() schema.GroupVersion {
156156
return b.connectionResourceInfo.GroupVersion()
157157
}
158158

159-
func (b *DataSourceAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode {
160-
// Add required configuration support in order to enable other modes. For an example, see pkg/registry/apis/playlist/register.go
161-
return grafanarest.Mode0
162-
}
163-
164159
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
165160
scheme.AddKnownTypes(gv,
166161
&datasource.DataSourceConnection{},
@@ -208,8 +203,7 @@ func (b *DataSourceAPIBuilder) GetAPIGroupInfo(
208203
scheme *runtime.Scheme,
209204
codecs serializer.CodecFactory, // pointer?
210205
_ generic.RESTOptionsGetter,
211-
_ grafanarest.DualWriterMode,
212-
_ prometheus.Registerer,
206+
_ grafanarest.DualWriteBuilder,
213207
) (*genericapiserver.APIGroupInfo, error) {
214208
storage := map[string]rest.Storage{}
215209

pkg/registry/apis/featuretoggle/register.go

+3-8
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ import (
1313
"k8s.io/kube-openapi/pkg/spec3"
1414
"k8s.io/kube-openapi/pkg/validation/spec"
1515

16+
"github.com/prometheus/client_golang/prometheus"
17+
1618
"github.com/grafana/grafana/pkg/apis/featuretoggle/v0alpha1"
1719
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
1820
"github.com/grafana/grafana/pkg/services/accesscontrol"
1921
"github.com/grafana/grafana/pkg/services/apiserver/builder"
2022
"github.com/grafana/grafana/pkg/services/featuremgmt"
2123
"github.com/grafana/grafana/pkg/setting"
22-
"github.com/prometheus/client_golang/prometheus"
2324
)
2425

2526
var _ builder.APIGroupBuilder = (*FeatureFlagAPIBuilder)(nil)
@@ -52,11 +53,6 @@ func (b *FeatureFlagAPIBuilder) GetGroupVersion() schema.GroupVersion {
5253
return gv
5354
}
5455

55-
func (b *FeatureFlagAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode {
56-
// Add required configuration support in order to enable other modes. For an example, see pkg/registry/apis/playlist/register.go
57-
return grafanarest.Mode0
58-
}
59-
6056
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
6157
scheme.AddKnownTypes(gv,
6258
&v0alpha1.Feature{},
@@ -90,8 +86,7 @@ func (b *FeatureFlagAPIBuilder) GetAPIGroupInfo(
9086
scheme *runtime.Scheme,
9187
codecs serializer.CodecFactory, // pointer?
9288
_ generic.RESTOptionsGetter,
93-
_ grafanarest.DualWriterMode,
94-
_ prometheus.Registerer,
89+
_ grafanarest.DualWriteBuilder,
9590
) (*genericapiserver.APIGroupInfo, error) {
9691
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v0alpha1.GROUP, scheme, metav1.ParameterCodec, codecs)
9792

pkg/registry/apis/folders/register.go

+7-10
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,6 @@ func (b *FolderAPIBuilder) GetGroupVersion() schema.GroupVersion {
6969
return b.gv
7070
}
7171

72-
func (b *FolderAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, modeMap map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode {
73-
// Add required configuration support in order to enable other modes. For an example, see pkg/registry/apis/playlist/register.go
74-
return grafanarest.Mode0
75-
}
76-
7772
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
7873
scheme.AddKnownTypes(gv,
7974
&v0alpha1.Folder{},
@@ -107,8 +102,7 @@ func (b *FolderAPIBuilder) GetAPIGroupInfo(
107102
scheme *runtime.Scheme,
108103
codecs serializer.CodecFactory, // pointer?
109104
optsGetter generic.RESTOptionsGetter,
110-
desiredMode grafanarest.DualWriterMode,
111-
reg prometheus.Registerer,
105+
dualWriteBuilder grafanarest.DualWriteBuilder,
112106
) (*genericapiserver.APIGroupInfo, error) {
113107
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v0alpha1.GROUP, scheme, metav1.ParameterCodec, codecs)
114108

@@ -142,13 +136,16 @@ func (b *FolderAPIBuilder) GetAPIGroupInfo(
142136
storage[resourceInfo.StoragePath("count")] = &subCountREST{b.folderSvc}
143137
storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc}
144138

145-
// enable dual writes if a RESTOptionsGetter is provided
146-
if optsGetter != nil && desiredMode != grafanarest.Mode0 {
139+
// enable dual writer
140+
if optsGetter != nil && dualWriteBuilder != nil {
147141
store, err := newStorage(scheme, optsGetter, legacyStore)
148142
if err != nil {
149143
return nil, err
150144
}
151-
storage[resourceInfo.StoragePath()] = grafanarest.NewDualWriter(grafanarest.Mode1, legacyStore, store, reg)
145+
storage[resourceInfo.StoragePath()], err = dualWriteBuilder(resourceInfo.GroupResource(), legacyStore, store)
146+
if err != nil {
147+
return nil, err
148+
}
152149
}
153150

154151
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage

0 commit comments

Comments
 (0)