@@ -25,6 +25,8 @@ import (
25
25
storagev1 "k8s.io/api/storage/v1"
26
26
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
27
"k8s.io/apimachinery/pkg/labels"
28
+ "k8s.io/apimachinery/pkg/runtime"
29
+ "k8s.io/apimachinery/pkg/runtime/schema"
28
30
"k8s.io/apimachinery/pkg/types"
29
31
utilrand "k8s.io/apimachinery/pkg/util/rand"
30
32
"k8s.io/client-go/util/retry"
@@ -164,6 +166,98 @@ var _ = utils.SIGDescribe("VolumeAttachment", func() {
164
166
}))
165
167
framework .ExpectNoError (err , "Timeout while waiting to confirm deletion of all VolumeAttachments" )
166
168
})
169
+
170
+ ginkgo .It ("should apply changes to a volumeattachment status" , func (ctx context.Context ) {
171
+
172
+ vaClient := f .ClientSet .StorageV1 ().VolumeAttachments ()
173
+
174
+ randUID := "e2e-" + utilrand .String (5 )
175
+ vaName := "va-" + randUID
176
+ pvName := "pv-" + randUID
177
+
178
+ nodes , err := f .ClientSet .CoreV1 ().Nodes ().List (ctx , metav1.ListOptions {})
179
+ framework .ExpectNoError (err , "failed to list nodes" )
180
+ randNode := rand .Intn (len (nodes .Items ))
181
+ vaNodeName := nodes .Items [randNode ].Name
182
+ vaAttachStatus := false
183
+
184
+ ginkgo .By (fmt .Sprintf ("Create VolumeAttachment %q on node %q" , vaName , vaNodeName ))
185
+ initialVA := NewVolumeAttachment (vaName , pvName , vaNodeName , vaAttachStatus )
186
+
187
+ createdVA , err := vaClient .Create (ctx , initialVA , metav1.CreateOptions {})
188
+ framework .ExpectNoError (err , "failed to create VolumeAttachment %q" , vaName )
189
+ gomega .Expect (createdVA .Name ).To (gomega .Equal (vaName ), "Checking that the created VolumeAttachment has the correct name" )
190
+
191
+ ginkgo .By (fmt .Sprintf ("Patch VolumeAttachment %q on node %q" , vaName , vaNodeName ))
192
+ payload := "{\" metadata\" :{\" labels\" :{\" " + createdVA .Name + "\" :\" patched\" }}}"
193
+ patchedVA , err := vaClient .Patch (ctx , createdVA .Name , types .MergePatchType , []byte (payload ), metav1.PatchOptions {})
194
+ framework .ExpectNoError (err , "failed to patch PV %q" , vaName )
195
+ gomega .Expect (patchedVA .Labels ).To (gomega .HaveKeyWithValue (patchedVA .Name , "patched" ), "Checking that patched label has been applied" )
196
+ patchedSelector := labels.Set {patchedVA .Name : "patched" }.AsSelector ().String ()
197
+
198
+ ginkgo .By (fmt .Sprintf ("Reading %q Status" , patchedVA .Name ))
199
+ vaResource := schema.GroupVersionResource {Group : "storage.k8s.io" , Version : "v1" , Resource : "volumeattachments" }
200
+ vaUnstructured , err := f .DynamicClient .Resource (vaResource ).Get (ctx , patchedVA .Name , metav1.GetOptions {}, "status" )
201
+ framework .ExpectNoError (err , "Failed to fetch the status of %q VolumeAttachment" , patchedVA .Name )
202
+
203
+ retrievedVA := & storagev1.VolumeAttachment {}
204
+ err = runtime .DefaultUnstructuredConverter .FromUnstructured (vaUnstructured .UnstructuredContent (), & retrievedVA )
205
+ framework .ExpectNoError (err , "Failed to retrieve %q status." , patchedVA .Name )
206
+ gomega .Expect (retrievedVA .Status .Attached ).To (gomega .BeFalseBecause ("Checking that the VolumeAttachment status has been read" ))
207
+
208
+ ginkgo .By (fmt .Sprintf ("Patching %q Status" , patchedVA .Name ))
209
+ statusPayload := []byte (`{"status":{"attached":true}}` )
210
+
211
+ vaPatched , err := vaClient .Patch (ctx , patchedVA .Name , types .MergePatchType , statusPayload , metav1.PatchOptions {}, "status" )
212
+ framework .ExpectNoError (err , "Failed to patch status." )
213
+ gomega .Expect (vaPatched .Status .Attached ).To (gomega .BeTrueBecause ("Checking that the VolumeAttachment status has been patched" ))
214
+ framework .Logf ("%q Status.Attached: %v" , vaPatched .Name , vaPatched .Status .Attached )
215
+
216
+ ginkgo .By (fmt .Sprintf ("Updating %q Status" , vaPatched .Name ))
217
+ var statusToUpdate , updatedVA * storagev1.VolumeAttachment
218
+
219
+ err = retry .RetryOnConflict (retry .DefaultRetry , func () error {
220
+ statusToUpdate , err = vaClient .Get (ctx , vaPatched .Name , metav1.GetOptions {})
221
+ framework .ExpectNoError (err , "Unable to retrieve VolumeAttachment %q" , vaPatched .Name )
222
+
223
+ statusToUpdate .Status .Attached = false
224
+
225
+ updatedVA , err = vaClient .UpdateStatus (ctx , statusToUpdate , metav1.UpdateOptions {})
226
+ return err
227
+ })
228
+ framework .ExpectNoError (err , "Failed to update status." )
229
+ gomega .Expect (updatedVA .Status .Attached ).To (gomega .BeFalseBecause ("Checking that the VolumeAttachment status has been updated" ))
230
+ framework .Logf ("%q Status.Attached: %v" , updatedVA .Name , updatedVA .Status .Attached )
231
+
232
+ ginkgo .By (fmt .Sprintf ("Delete VolumeAttachment %q on node %q" , vaName , vaNodeName ))
233
+ err = vaClient .Delete (ctx , vaName , metav1.DeleteOptions {})
234
+ framework .ExpectNoError (err , "failed to delete VolumeAttachment %q" , vaName )
235
+
236
+ ginkgo .By (fmt .Sprintf ("Confirm deletion of VolumeAttachment %q on node %q" , vaName , vaNodeName ))
237
+
238
+ type state struct {
239
+ VolumeAttachments []storagev1.VolumeAttachment
240
+ }
241
+
242
+ err = framework .Gomega ().Eventually (ctx , framework .HandleRetry (func (ctx context.Context ) (* state , error ) {
243
+ vaList , err := vaClient .List (ctx , metav1.ListOptions {LabelSelector : patchedSelector })
244
+ if err != nil {
245
+ return nil , fmt .Errorf ("failed to list VolumeAttachment: %w" , err )
246
+ }
247
+ return & state {
248
+ VolumeAttachments : vaList .Items ,
249
+ }, nil
250
+ })).WithTimeout (30 * time .Second ).Should (framework .MakeMatcher (func (s * state ) (func () string , error ) {
251
+ if len (s .VolumeAttachments ) == 0 {
252
+ return nil , nil
253
+ }
254
+ return func () string {
255
+ return fmt .Sprintf ("Expected VolumeAttachment to be deleted, found %q" , s .VolumeAttachments [0 ].Name )
256
+ }, nil
257
+ }))
258
+ framework .ExpectNoError (err , "Timeout while waiting to confirm VolumeAttachment %q deletion" , vaName )
259
+ })
260
+
167
261
})
168
262
})
169
263
0 commit comments