@@ -2,7 +2,10 @@ package rest
2
2
3
3
import (
4
4
"context"
5
+ "errors"
6
+ "time"
5
7
8
+ "k8s.io/apimachinery/pkg/api/meta"
6
9
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
7
10
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8
11
"k8s.io/apimachinery/pkg/runtime"
@@ -17,6 +20,10 @@ type DualWriterMode1 struct {
17
20
* dualWriterMetrics
18
21
}
19
22
23
+ const (
24
+ mode1Str = "1"
25
+ )
26
+
20
27
// NewDualWriterMode1 returns a new DualWriter in mode 1.
21
28
// Mode 1 represents writing to and reading from LegacyStorage.
22
29
func NewDualWriterMode1 (legacy LegacyStorage , storage Storage ) * DualWriterMode1 {
@@ -27,36 +34,195 @@ func NewDualWriterMode1(legacy LegacyStorage, storage Storage) *DualWriterMode1
27
34
28
35
// Create overrides the behavior of the generic DualWriter and writes only to LegacyStorage.
29
36
func (d * DualWriterMode1 ) Create (ctx context.Context , obj runtime.Object , createValidation rest.ValidateObjectFunc , options * metav1.CreateOptions ) (runtime.Object , error ) {
30
- ctx = klog .NewContext (ctx , d .Log )
31
- return d .Legacy .Create (ctx , obj , createValidation , options )
37
+ log := d .Log .WithValues ("kind" , options .Kind )
38
+ ctx = klog .NewContext (ctx , log )
39
+ var method = "create"
40
+
41
+ startLegacy := time .Now ()
42
+ res , err := d .Legacy .Create (ctx , obj , createValidation , options )
43
+ if err != nil {
44
+ log .Error (err , "unable to create object in legacy storage" )
45
+ d .recordLegacyDuration (true , mode1Str , options .Kind , method , startLegacy )
46
+ return res , err
47
+ }
48
+ d .recordLegacyDuration (false , mode1Str , options .Kind , method , startLegacy )
49
+
50
+ go func () {
51
+ accessorCreated , err := meta .Accessor (res )
52
+ if err != nil {
53
+ log .Error (err , "unable to get accessor for created object" )
54
+ }
55
+
56
+ accessorOld , err := meta .Accessor (obj )
57
+ if err != nil {
58
+ log .Error (err , "unable to get accessor for old object" )
59
+ }
60
+
61
+ enrichObject (accessorOld , accessorCreated )
62
+ startStorage := time .Now ()
63
+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("storage create timeout" ))
64
+ defer cancel ()
65
+ _ , errObjectSt := d .Storage .Create (ctx , obj , createValidation , options )
66
+ d .recordStorageDuration (errObjectSt != nil , mode1Str , options .Kind , method , startStorage )
67
+ }()
68
+
69
+ return res , nil
32
70
}
33
71
34
72
// Get overrides the behavior of the generic DualWriter and reads only from LegacyStorage.
35
73
func (d * DualWriterMode1 ) Get (ctx context.Context , name string , options * metav1.GetOptions ) (runtime.Object , error ) {
36
- ctx = klog .NewContext (ctx , d .Log )
37
- return d .Legacy .Get (ctx , name , options )
74
+ log := d .Log .WithValues ("name" , name , "resourceVersion" , options .ResourceVersion , "kind" , options .Kind )
75
+ ctx = klog .NewContext (ctx , log )
76
+ var method = "get"
77
+
78
+ startLegacy := time .Now ()
79
+ res , errLegacy := d .Legacy .Get (ctx , name , options )
80
+ if errLegacy != nil {
81
+ log .Error (errLegacy , "unable to get object in legacy storage" )
82
+ }
83
+ d .recordLegacyDuration (errLegacy != nil , mode1Str , options .Kind , method , startLegacy )
84
+
85
+ go func () {
86
+ startStorage := time .Now ()
87
+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("storage get timeout" ))
88
+ defer cancel ()
89
+ _ , err := d .Storage .Get (ctx , name , options )
90
+ d .recordStorageDuration (err != nil , mode1Str , options .Kind , method , startStorage )
91
+ }()
92
+
93
+ return res , errLegacy
38
94
}
39
95
40
96
// List overrides the behavior of the generic DualWriter and reads only from LegacyStorage.
41
97
func (d * DualWriterMode1 ) List (ctx context.Context , options * metainternalversion.ListOptions ) (runtime.Object , error ) {
42
- ctx = klog .NewContext (ctx , d .Log )
43
- return d .Legacy .List (ctx , options )
98
+ log := d .Log .WithValues ("kind" , options .Kind , "resourceVersion" , options .ResourceVersion , "kind" , options .Kind )
99
+ ctx = klog .NewContext (ctx , log )
100
+ var method = "list"
101
+
102
+ startLegacy := time .Now ()
103
+ res , errLegacy := d .Legacy .List (ctx , options )
104
+ if errLegacy != nil {
105
+ log .Error (errLegacy , "unable to list object in legacy storage" )
106
+ }
107
+ d .recordLegacyDuration (errLegacy != nil , mode1Str , options .Kind , method , startLegacy )
108
+
109
+ go func () {
110
+ startStorage := time .Now ()
111
+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("storage list timeout" ))
112
+ defer cancel ()
113
+ _ , err := d .Storage .List (ctx , options )
114
+ d .recordStorageDuration (err != nil , mode1Str , options .Kind , method , startStorage )
115
+ }()
116
+
117
+ return res , errLegacy
44
118
}
45
119
46
120
func (d * DualWriterMode1 ) Delete (ctx context.Context , name string , deleteValidation rest.ValidateObjectFunc , options * metav1.DeleteOptions ) (runtime.Object , bool , error ) {
121
+ log := d .Log .WithValues ("name" , name , "kind" , options .Kind )
47
122
ctx = klog .NewContext (ctx , d .Log )
48
- return d .Legacy .Delete (ctx , name , deleteValidation , options )
123
+ var method = "delete"
124
+
125
+ startLegacy := time .Now ()
126
+ res , async , err := d .Legacy .Delete (ctx , name , deleteValidation , options )
127
+ if err != nil {
128
+ log .Error (err , "unable to delete object in legacy storage" )
129
+ d .recordLegacyDuration (true , mode1Str , options .Kind , method , startLegacy )
130
+ return res , async , err
131
+ }
132
+ d .recordLegacyDuration (false , mode1Str , options .Kind , method , startLegacy )
133
+
134
+ go func () {
135
+ startStorage := time .Now ()
136
+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("storage delete timeout" ))
137
+ defer cancel ()
138
+ _ , _ , err := d .Storage .Delete (ctx , name , deleteValidation , options )
139
+ d .recordStorageDuration (err != nil , mode1Str , options .Kind , method , startStorage )
140
+ }()
141
+
142
+ return res , async , nil
49
143
}
50
144
51
145
// DeleteCollection overrides the behavior of the generic DualWriter and deletes only from LegacyStorage.
52
146
func (d * DualWriterMode1 ) DeleteCollection (ctx context.Context , deleteValidation rest.ValidateObjectFunc , options * metav1.DeleteOptions , listOptions * metainternalversion.ListOptions ) (runtime.Object , error ) {
53
- ctx = klog .NewContext (ctx , d .Log )
54
- return d .Legacy .DeleteCollection (ctx , deleteValidation , options , listOptions )
147
+ log := d .Log .WithValues ("kind" , options .Kind , "resourceVersion" , listOptions .ResourceVersion )
148
+ ctx = klog .NewContext (ctx , log )
149
+ var method = "delete-collection"
150
+
151
+ startLegacy := time .Now ()
152
+ res , err := d .Legacy .DeleteCollection (ctx , deleteValidation , options , listOptions )
153
+ if err != nil {
154
+ log .Error (err , "unable to delete collection in legacy storage" )
155
+ d .recordLegacyDuration (true , mode1Str , options .Kind , method , startLegacy )
156
+ return res , err
157
+ }
158
+ d .recordLegacyDuration (false , mode1Str , options .Kind , method , startLegacy )
159
+
160
+ go func () {
161
+ startStorage := time .Now ()
162
+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("storage deletecollection timeout" ))
163
+ defer cancel ()
164
+ _ , err := d .Storage .DeleteCollection (ctx , deleteValidation , options , listOptions )
165
+ d .recordStorageDuration (err != nil , mode1Str , options .Kind , method , startStorage )
166
+ }()
167
+
168
+ return res , nil
55
169
}
56
170
57
171
func (d * DualWriterMode1 ) Update (ctx context.Context , name string , objInfo rest.UpdatedObjectInfo , createValidation rest.ValidateObjectFunc , updateValidation rest.ValidateObjectUpdateFunc , forceAllowCreate bool , options * metav1.UpdateOptions ) (runtime.Object , bool , error ) {
58
- ctx = klog .NewContext (ctx , d .Log )
59
- return d .Legacy .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
172
+ log := d .Log .WithValues ("name" , name , "kind" , options .Kind )
173
+ ctx = klog .NewContext (ctx , log )
174
+ var method = "update"
175
+
176
+ startLegacy := time .Now ()
177
+ res , async , err := d .Legacy .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
178
+ if err != nil {
179
+ log .Error (err , "unable to update in legacy storage" )
180
+ d .recordLegacyDuration (true , mode1Str , options .Kind , method , startLegacy )
181
+ return res , async , err
182
+ }
183
+ d .recordLegacyDuration (false , mode1Str , options .Kind , method , startLegacy )
184
+
185
+ go func () {
186
+ updated , err := objInfo .UpdatedObject (ctx , res )
187
+ if err != nil {
188
+ log .WithValues ("object" , updated ).Error (err , "could not update or create object" )
189
+ }
190
+
191
+ // get the object to be updated
192
+ foundObj , err := d .Storage .Get (ctx , name , & metav1.GetOptions {})
193
+ if err != nil {
194
+ log .WithValues ("object" , foundObj ).Error (err , "could not get object to update" )
195
+ }
196
+
197
+ // if the object is found, create a new updateWrapper with the object found
198
+ if foundObj != nil {
199
+ accessorOld , err := meta .Accessor (foundObj )
200
+ if err != nil {
201
+ log .Error (err , "unable to get accessor for original updated object" )
202
+ }
203
+
204
+ accessor , err := meta .Accessor (res )
205
+ if err != nil {
206
+ log .Error (err , "unable to get accessor for updated object" )
207
+ }
208
+
209
+ accessor .SetResourceVersion (accessorOld .GetResourceVersion ())
210
+ accessor .SetUID (accessorOld .GetUID ())
211
+
212
+ enrichObject (accessorOld , accessor )
213
+ objInfo = & updateWrapper {
214
+ upstream : objInfo ,
215
+ updated : res ,
216
+ }
217
+ }
218
+ startStorage := time .Now ()
219
+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("storage update timeout" ))
220
+ defer cancel ()
221
+ _ , _ , errObjectSt := d .Storage .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
222
+ d .recordStorageDuration (errObjectSt != nil , mode1Str , options .Kind , method , startStorage )
223
+ }()
224
+
225
+ return res , async , nil
60
226
}
61
227
62
228
func (d * DualWriterMode1 ) Destroy () {
0 commit comments