@@ -2,6 +2,7 @@ package rest
2
2
3
3
import (
4
4
"context"
5
+ "time"
5
6
6
7
"github.com/grafana/grafana/pkg/services/apiserver/utils"
7
8
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -22,6 +23,8 @@ type DualWriterMode2 struct {
22
23
Log klog.Logger
23
24
}
24
25
26
+ const mode2Str = "2"
27
+
25
28
// NewDualWriterMode2 returns a new DualWriter in mode 2.
26
29
// Mode 2 represents writing to LegacyStorage and Storage and reading from LegacyStorage.
27
30
func NewDualWriterMode2 (legacy LegacyStorage , storage Storage ) * DualWriterMode2 {
@@ -39,52 +42,78 @@ func (d *DualWriterMode2) Mode() DualWriterMode {
39
42
func (d * DualWriterMode2 ) Create (ctx context.Context , original runtime.Object , createValidation rest.ValidateObjectFunc , options * metav1.CreateOptions ) (runtime.Object , error ) {
40
43
log := d .Log .WithValues ("kind" , options .Kind )
41
44
ctx = klog .NewContext (ctx , log )
45
+ var method = "create"
42
46
47
+ startLegacy := time .Now ()
43
48
created , err := d .Legacy .Create (ctx , original , createValidation , options )
44
49
if err != nil {
45
50
log .Error (err , "unable to create object in legacy storage" )
51
+ d .recordLegacyDuration (true , mode2Str , options .Kind , method , startLegacy )
46
52
return created , err
47
53
}
54
+ d .recordLegacyDuration (false , mode2Str , options .Kind , method , startLegacy )
48
55
49
56
createdLegacy , err := enrichLegacyObject (original , created , true )
50
57
if err != nil {
51
58
return createdLegacy , err
52
59
}
53
60
61
+ startStorage := time .Now ()
54
62
rsp , err := d .Storage .Create (ctx , created , createValidation , options )
55
63
if err != nil {
56
64
log .WithValues ("name" ).Error (err , "unable to create object in storage" )
57
- return rsp , err
65
+ d . recordStorageDuration ( true , mode2Str , options . Kind , method , startStorage )
58
66
}
59
- return rsp , nil
67
+ d .recordStorageDuration (false , mode2Str , options .Kind , method , startStorage )
68
+ return rsp , err
60
69
}
61
70
62
71
// It retrieves an object from Storage if possible, and if not it falls back to LegacyStorage.
63
72
func (d * DualWriterMode2 ) Get (ctx context.Context , name string , options * metav1.GetOptions ) (runtime.Object , error ) {
64
73
log := d .Log .WithValues ("name" , name , "resourceVersion" , options .ResourceVersion , "kind" , options .Kind )
65
74
ctx = klog .NewContext (ctx , log )
66
- s , err := d .Storage .Get (ctx , name , & metav1.GetOptions {})
75
+ var method = "get"
76
+
77
+ startStorage := time .Now ()
78
+ res , err := d .Storage .Get (ctx , name , options )
67
79
if err != nil {
80
+ // if it errors because it's not found, we try to fetch it from the legacy storage
68
81
if apierrors .IsNotFound (err ) {
69
- log .Info ("object not found in storage" )
70
- return d .Legacy .Get (ctx , name , & metav1.GetOptions {})
82
+ d .recordStorageDuration (false , mode2Str , options .Kind , method , startStorage )
83
+
84
+ log .Info ("object not found in storage, fetching from legacy" )
85
+ startLegacy := time .Now ()
86
+ res , err = d .Legacy .Get (ctx , name , options )
87
+ if err != nil {
88
+ log .Error (err , "unable to fetch object from legacy" )
89
+ d .recordLegacyDuration (true , mode2Str , options .Kind , method , startLegacy )
90
+ }
91
+ d .recordLegacyDuration (false , mode2Str , options .Kind , method , startLegacy )
92
+ return res , err
71
93
}
94
+ d .recordStorageDuration (true , mode2Str , options .Kind , method , startStorage )
72
95
log .Error (err , "unable to fetch object from storage" )
73
- return d . Legacy . Get ( ctx , name , & metav1. GetOptions {})
96
+ return res , err
74
97
}
75
- return s , nil
98
+ return res , err
76
99
}
77
100
78
101
// List overrides the behavior of the generic DualWriter.
79
102
// It returns Storage entries if possible and falls back to LegacyStorage entries if not.
80
103
func (d * DualWriterMode2 ) List (ctx context.Context , options * metainternalversion.ListOptions ) (runtime.Object , error ) {
81
104
log := d .Log .WithValues ("kind" , options .Kind , "resourceVersion" , options .ResourceVersion , "kind" , options .Kind )
82
105
ctx = klog .NewContext (ctx , log )
106
+ var method = "list"
107
+
108
+ startLegacy := time .Now ()
83
109
ll , err := d .Legacy .List (ctx , options )
84
110
if err != nil {
85
111
log .Error (err , "unable to list objects from legacy storage" )
86
- return nil , err
112
+ d .recordLegacyDuration (true , mode2Str , options .Kind , method , startLegacy )
113
+ return ll , err
87
114
}
115
+ d .recordLegacyDuration (false , mode2Str , options .Kind , method , startLegacy )
116
+
88
117
legacyList , err := meta .ExtractList (ll )
89
118
if err != nil {
90
119
log .Error (err , "unable to extract list from legacy storage" )
@@ -98,15 +127,20 @@ func (d *DualWriterMode2) List(ctx context.Context, options *metainternalversion
98
127
return nil , err
99
128
}
100
129
130
+ // TODO: why do we need this?
101
131
if optionsStorage .LabelSelector == nil {
102
132
return ll , nil
103
133
}
104
134
135
+ startStorage := time .Now ()
105
136
sl , err := d .Storage .List (ctx , & optionsStorage )
106
137
if err != nil {
107
138
log .Error (err , "unable to list objects from storage" )
108
- return nil , err
139
+ d .recordStorageDuration (true , mode2Str , options .Kind , method , startStorage )
140
+ return sl , err
109
141
}
142
+ d .recordStorageDuration (false , mode2Str , options .Kind , method , startStorage )
143
+
110
144
storageList , err := meta .ExtractList (sl )
111
145
if err != nil {
112
146
log .Error (err , "unable to extract list from storage" )
@@ -133,11 +167,17 @@ func (d *DualWriterMode2) List(ctx context.Context, options *metainternalversion
133
167
func (d * DualWriterMode2 ) DeleteCollection (ctx context.Context , deleteValidation rest.ValidateObjectFunc , options * metav1.DeleteOptions , listOptions * metainternalversion.ListOptions ) (runtime.Object , error ) {
134
168
log := d .Log .WithValues ("kind" , options .Kind , "resourceVersion" , listOptions .ResourceVersion )
135
169
ctx = klog .NewContext (ctx , log )
170
+ var method = "delete-collection"
171
+
172
+ startLegacy := time .Now ()
136
173
deleted , err := d .Legacy .DeleteCollection (ctx , deleteValidation , options , listOptions )
137
174
if err != nil {
138
175
log .WithValues ("deleted" , deleted ).Error (err , "failed to delete collection successfully from legacy storage" )
139
- return nil , err
176
+ d .recordLegacyDuration (true , mode2Str , options .Kind , method , startLegacy )
177
+ return deleted , err
140
178
}
179
+ d .recordLegacyDuration (false , mode2Str , options .Kind , method , startLegacy )
180
+
141
181
legacyList , err := meta .ExtractList (deleted )
142
182
if err != nil {
143
183
log .Error (err , "unable to extract list from legacy storage" )
@@ -153,33 +193,42 @@ func (d *DualWriterMode2) DeleteCollection(ctx context.Context, deleteValidation
153
193
return deleted , nil
154
194
}
155
195
196
+ startStorage := time .Now ()
156
197
res , err := d .Storage .DeleteCollection (ctx , deleteValidation , options , & optionsStorage )
157
198
if err != nil {
158
199
log .WithValues ("deleted" , res ).Error (err , "failed to delete collection successfully from Storage" )
200
+ d .recordStorageDuration (true , mode2Str , options .Kind , method , startStorage )
159
201
}
202
+ d .recordStorageDuration (false , mode2Str , options .Kind , method , startStorage )
160
203
161
204
return res , err
162
205
}
163
206
164
207
func (d * DualWriterMode2 ) Delete (ctx context.Context , name string , deleteValidation rest.ValidateObjectFunc , options * metav1.DeleteOptions ) (runtime.Object , bool , error ) {
165
208
log := d .Log .WithValues ("name" , name , "kind" , options .Kind )
166
209
ctx = klog .NewContext (ctx , log )
210
+ var method = "delete"
167
211
212
+ startLegacy := time .Now ()
168
213
deletedLS , async , err := d .Legacy .Delete (ctx , name , deleteValidation , options )
169
214
if err != nil {
170
215
if ! apierrors .IsNotFound (err ) {
171
216
log .WithValues ("objectList" , deletedLS ).Error (err , "could not delete from legacy store" )
217
+ d .recordLegacyDuration (true , mode2Str , options .Kind , method , startLegacy )
172
218
return deletedLS , async , err
173
219
}
174
220
}
221
+ d .recordLegacyDuration (false , mode2Str , options .Kind , method , startLegacy )
175
222
176
- deletedS , _ , errUS := d .Storage .Delete (ctx , name , deleteValidation , options )
177
- if errUS != nil {
178
- if ! apierrors .IsNotFound (errUS ) {
179
- log .WithValues ("objectList" , deletedS ).Error (errUS , "could not delete from duplicate storage" )
223
+ startStorage := time .Now ()
224
+ deletedS , _ , err := d .Storage .Delete (ctx , name , deleteValidation , options )
225
+ if err != nil {
226
+ if ! apierrors .IsNotFound (err ) {
227
+ log .WithValues ("objectList" , deletedS ).Error (err , "could not delete from duplicate storage" )
228
+ d .recordStorageDuration (true , mode2Str , options .Kind , method , startStorage )
180
229
}
181
230
}
182
-
231
+ d . recordStorageDuration ( false , mode2Str , options . Kind , method , startStorage )
183
232
return deletedLS , async , err
184
233
}
185
234
@@ -205,12 +254,16 @@ func (d *DualWriterMode2) Update(ctx context.Context, name string, objInfo rest.
205
254
return nil , false , err
206
255
}
207
256
257
+ startLegacy := time .Now ()
208
258
obj , created , err := d .Legacy .Update (ctx , name , & updateWrapper {upstream : objInfo , updated : updated }, createValidation , updateValidation , forceAllowCreate , options )
209
259
if err != nil {
210
260
log .WithValues ("object" , obj ).Error (err , "could not update in legacy storage" )
261
+ d .recordLegacyDuration (true , mode2Str , options .Kind , "update" , startLegacy )
211
262
return obj , created , err
212
263
}
264
+ d .recordLegacyDuration (false , mode2Str , options .Kind , "update" , startLegacy )
213
265
266
+ // if the object is found, create a new updateWrapper with the object found
214
267
if foundObj != nil {
215
268
obj , err = enrichLegacyObject (foundObj , obj , false )
216
269
if err != nil {
@@ -223,7 +276,13 @@ func (d *DualWriterMode2) Update(ctx context.Context, name string, objInfo rest.
223
276
}
224
277
}
225
278
226
- return d .Storage .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
279
+ startStorage := time .Now ()
280
+ res , created , err := d .Storage .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
281
+ if err != nil {
282
+ log .WithValues ("object" , res ).Error (err , "could not update in storage" )
283
+ }
284
+ d .recordStorageDuration (err != nil , mode2Str , options .Kind , "update" , startStorage )
285
+ return res , created , err
227
286
}
228
287
229
288
func (d * DualWriterMode2 ) Destroy () {
0 commit comments