@@ -12,11 +12,12 @@ import (
1212
1313 "github.com/stretchr/testify/require"
1414 corev1 "k8s.io/api/core/v1"
15- apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1 "
16- "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1 "
15+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 "
16+ "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1 "
1717 "k8s.io/apimachinery/pkg/api/errors"
1818 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1919 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
20+ "k8s.io/apimachinery/pkg/runtime"
2021 "k8s.io/apimachinery/pkg/runtime/schema"
2122 "k8s.io/apimachinery/pkg/types"
2223 "k8s.io/apimachinery/pkg/util/wait"
@@ -25,7 +26,6 @@ import (
2526 "k8s.io/client-go/kubernetes"
2627 corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
2728 "k8s.io/client-go/tools/cache"
28- "k8s.io/client-go/util/retry"
2929 "k8s.io/utils/clock"
3030 "sigs.k8s.io/yaml"
3131
@@ -67,11 +67,11 @@ func TestEncryptionIntegration(tt *testing.T) {
6767 kubeClient , err := kubernetes .NewForConfig (kubeConfig )
6868 require .NoError (t , err )
6969 kubeInformers := v1helpers .NewKubeInformersForNamespaces (kubeClient , "openshift-config-managed" )
70- apiextensionsClient , err := v1beta1 .NewForConfig (kubeConfig )
70+ apiextensionsClient , err := v1 .NewForConfig (kubeConfig )
7171 require .NoError (t , err )
7272
7373 // create ExtensionTest operator CRD
74- var operatorCRD apiextensionsv1beta1 .CustomResourceDefinition
74+ var operatorCRD apiextensionsv1 .CustomResourceDefinition
7575 require .NoError (t , yaml .Unmarshal ([]byte (encryptionTestOperatorCRD ), & operatorCRD ))
7676 crd , err := apiextensionsClient .CustomResourceDefinitions ().Create (ctx , & operatorCRD , metav1.CreateOptions {})
7777 if errors .IsAlreadyExists (err ) {
@@ -81,6 +81,26 @@ func TestEncryptionIntegration(tt *testing.T) {
8181 }
8282 defer apiextensionsClient .CustomResourceDefinitions ().Delete (ctx , crd .Name , metav1.DeleteOptions {})
8383
84+ t .Logf ("Waiting for CRD to be ready" )
85+ err = wait .PollUntilContextTimeout (ctx , 100 * time .Millisecond , wait .ForeverTestTimeout , true , func (ctx context.Context ) (bool , error ) {
86+ oCRD , crdErr := apiextensionsClient .CustomResourceDefinitions ().Get (ctx , operatorCRD .Name , metav1.GetOptions {})
87+ if crdErr != nil {
88+ if errors .IsNotFound (crdErr ) {
89+ return false , nil
90+ }
91+ return false , crdErr
92+ }
93+
94+ for _ , condition := range oCRD .Status .Conditions {
95+ if condition .Type == apiextensionsv1 .Established {
96+ operatorCRD = * oCRD
97+ return condition .Status == apiextensionsv1 .ConditionTrue , nil
98+ }
99+ }
100+ return false , nil
101+ })
102+ require .NoError (t , err )
103+
84104 // create operator client and create instance with ManagementState="Managed"
85105 operatorGVR := schema.GroupVersionResource {Group : operatorCRD .Spec .Group , Version : "v1" , Resource : operatorCRD .Spec .Names .Plural }
86106 operatorGVK := schema.GroupVersionKind {Group : operatorCRD .Spec .Group , Version : "v1" , Kind : operatorCRD .Spec .Names .Kind }
@@ -99,7 +119,7 @@ func TestEncryptionIntegration(tt *testing.T) {
99119 require .NoError (t , err )
100120 dynamicClient , err := dynamic .NewForConfig (kubeConfig )
101121 require .NoError (t , err )
102- err = wait .PollImmediate ( time .Second , wait .ForeverTestTimeout , func () (bool , error ) {
122+ err = wait .PollUntilContextTimeout ( ctx , time .Second , wait .ForeverTestTimeout , true , func (ctx context. Context ) (bool , error ) {
103123 _ , err := dynamicClient .Resource (operatorGVR ).Create (ctx , & unstructured.Unstructured {
104124 Object : map [string ]interface {}{
105125 "apiVersion" : "operator.openshift.io/v1" ,
@@ -121,7 +141,7 @@ func TestEncryptionIntegration(tt *testing.T) {
121141 require .NoError (t , err )
122142
123143 // create APIServer clients
124- fakeConfigClient := configv1clientfake .NewSimpleClientset (& configv1.APIServer {ObjectMeta : metav1.ObjectMeta {Name : "cluster" }})
144+ fakeConfigClient := configv1clientfake .NewClientset (& configv1.APIServer {ObjectMeta : metav1.ObjectMeta {Name : "cluster" }})
125145 fakeConfigInformer := configv1informers .NewSharedInformerFactory (fakeConfigClient , 10 * time .Minute )
126146 fakeApiServerClient := fakeConfigClient .ConfigV1 ().APIServers ()
127147
@@ -159,6 +179,20 @@ func TestEncryptionIntegration(tt *testing.T) {
159179 operatorInformer .Start (stopCh )
160180 go controllers .Run (ctx , 1 )
161181
182+ t .Logf ("Waiting for operator informer to sync" )
183+ if ! cache .WaitForCacheSync (stopCh , operatorClient .Informer ().HasSynced ) {
184+ t .Fatalf ("failed to sync operator informer" )
185+ }
186+ kubeInformers .WaitForCacheSync (stopCh )
187+ err = wait .PollUntilContextTimeout (ctx , 100 * time .Millisecond , wait .ForeverTestTimeout , true , func (ctx context.Context ) (bool , error ) {
188+ _ , _ , _ , err := operatorClient .GetOperatorState ()
189+ if errors .IsNotFound (err ) {
190+ return false , nil
191+ }
192+ return err == nil , err
193+ })
194+ require .NoError (t , err )
195+
162196 waitForConfigEventuallyCond := func (cond func (s string ) bool ) {
163197 t .Helper ()
164198 stopCh := time .After (wait .ForeverTestTimeout )
@@ -208,22 +242,16 @@ func TestEncryptionIntegration(tt *testing.T) {
208242 }
209243 return operatorv1 .ConditionUnknown
210244 }
211- requireConditionStatus := func (condType string , expected operatorv1.ConditionStatus ) {
212- t .Helper ()
213- if status := conditionStatus (condType ); status != expected {
214- t .Errorf ("expected condition %s of status %s, found: %q" , condType , expected , status )
215- }
216- }
217245 waitForConditionStatus := func (condType string , expected operatorv1.ConditionStatus ) {
218246 t .Helper ()
219- err := wait .PollImmediate ( time .Millisecond * 100 , wait .ForeverTestTimeout , func () (bool , error ) {
247+ err := wait .PollUntilContextTimeout ( ctx , time .Millisecond * 100 , wait .ForeverTestTimeout , true , func (ctx context. Context ) (bool , error ) {
220248 return conditionStatus (condType ) == expected , nil
221249 })
222250 require .NoError (t , err )
223251 }
224252 waitForMigration := func (key string ) {
225253 t .Helper ()
226- err := wait .PollImmediate ( time .Millisecond * 100 , wait .ForeverTestTimeout , func () (bool , error ) {
254+ err := wait .PollUntilContextTimeout ( ctx , time .Millisecond * 100 , wait .ForeverTestTimeout , true , func (ctx context. Context ) (bool , error ) {
227255 s , err := kubeClient .CoreV1 ().Secrets ("openshift-config-managed" ).Get (ctx , fmt .Sprintf ("encryption-key-%s-%s" , component , key ), metav1.GetOptions {})
228256 require .NoError (t , err )
229257
@@ -245,7 +273,7 @@ func TestEncryptionIntegration(tt *testing.T) {
245273 keySecretsLabel := fmt .Sprintf ("%s=%s" , secrets .EncryptionKeySecretsLabel , component )
246274 waitForKeys := func (n int ) {
247275 t .Helper ()
248- err := wait .PollImmediate ( time .Second , wait .ForeverTestTimeout , func () (bool , error ) {
276+ err := wait .PollUntilContextTimeout ( ctx , time .Second , wait .ForeverTestTimeout , true , func (ctx context. Context ) (bool , error ) {
249277 l , err := kubeClient .CoreV1 ().Secrets ("openshift-config-managed" ).List (ctx , metav1.ListOptions {LabelSelector : keySecretsLabel })
250278 if err != nil {
251279 return false , err
@@ -264,7 +292,7 @@ func TestEncryptionIntegration(tt *testing.T) {
264292 "kubeapiservers.operator.openshift.io=aescbc:1,identity;kubeschedulers.operator.openshift.io=aescbc:1,identity" ,
265293 )
266294 waitForMigration ("1" )
267- requireConditionStatus ("Encrypted" , operatorv1 .ConditionTrue )
295+ waitForConditionStatus ("Encrypted" , operatorv1 .ConditionTrue )
268296
269297 t .Logf ("Switch to identity" )
270298 _ , err = fakeApiServerClient .Patch (ctx , "cluster" , types .MergePatchType , []byte (`{"spec":{"encryption":{"type":"identity"}}}` ), metav1.PatchOptions {})
@@ -274,14 +302,14 @@ func TestEncryptionIntegration(tt *testing.T) {
274302 "kubeapiservers.operator.openshift.io=aescbc:1,identity,aesgcm:2;kubeschedulers.operator.openshift.io=aescbc:1,identity,aesgcm:2" ,
275303 "kubeapiservers.operator.openshift.io=identity,aescbc:1,aesgcm:2;kubeschedulers.operator.openshift.io=identity,aescbc:1,aesgcm:2" ,
276304 )
277- requireConditionStatus ("Encrypted" , operatorv1 .ConditionFalse )
305+ waitForConditionStatus ("Encrypted" , operatorv1 .ConditionFalse )
278306
279307 t .Logf ("Switch to empty mode" )
280308 _ , err = fakeApiServerClient .Patch (ctx , "cluster" , types .MergePatchType , []byte (`{"spec":{"encryption":{"type":""}}}` ), metav1.PatchOptions {})
281309 require .NoError (t , err )
282310 time .Sleep (5 * time .Second ) // give controller time to create keys (it shouldn't)
283311 waitForKeys (2 )
284- requireConditionStatus ("Encrypted" , operatorv1 .ConditionFalse )
312+ waitForConditionStatus ("Encrypted" , operatorv1 .ConditionFalse )
285313
286314 t .Logf ("Switch to aescbc again" )
287315 _ , err = fakeApiServerClient .Patch (ctx , "cluster" , types .MergePatchType , []byte (`{"spec":{"encryption":{"type":"aescbc"}}}` ), metav1.PatchOptions {})
@@ -297,15 +325,11 @@ func TestEncryptionIntegration(tt *testing.T) {
297325 t .Logf ("Setting external reason" )
298326 setExternalReason := func (reason string ) {
299327 t .Helper ()
300- err = retry .RetryOnConflict (retry .DefaultBackoff , func () error {
301- spec , _ , rv , err := operatorClient .GetOperatorState ()
302- if err != nil {
303- return err
304- }
305- spec .UnsupportedConfigOverrides .Raw = []byte (fmt .Sprintf (`{"encryption":{"reason":%q}}` , reason ))
306- _ , _ , err = operatorClient .UpdateOperatorSpec (context .TODO (), rv , spec )
307- return err
308- })
328+ applyConfig := applyoperatorv1 .OperatorSpec ().
329+ WithUnsupportedConfigOverrides (runtime.RawExtension {
330+ Raw : []byte (fmt .Sprintf (`{"encryption":{"reason":%q}}` , reason )),
331+ })
332+ err = operatorClient .ApplyOperatorSpec (ctx , "encryption-test" , applyConfig )
309333 require .NoError (t , err )
310334 }
311335 setExternalReason ("a" )
@@ -341,7 +365,7 @@ func TestEncryptionIntegration(tt *testing.T) {
341365 require .NoError (t , err )
342366 err = kubeClient .CoreV1 ().Secrets ("openshift-config-managed" ).Delete (ctx , fmt .Sprintf ("encryption-key-%s-6" , component ), metav1.DeleteOptions {})
343367 require .NoError (t , err )
344- err = wait .PollImmediate ( time .Second , wait .ForeverTestTimeout , func () (bool , error ) {
368+ err = wait .PollUntilContextTimeout ( ctx , time .Second , wait .ForeverTestTimeout , true , func (ctx context. Context ) (bool , error ) {
345369 _ , err := kubeClient .CoreV1 ().Secrets ("openshift-config-managed" ).Get (ctx , fmt .Sprintf ("encryption-key-%s-7" , component ), metav1.GetOptions {})
346370 if errors .IsNotFound (err ) {
347371 return false , nil
@@ -378,16 +402,16 @@ func TestEncryptionIntegration(tt *testing.T) {
378402 t .Logf ("Delete the openshift-config-managed config" )
379403 deployer .DeleteOperandConfig ()
380404 waitForConfigs (
381- // 7 is migrated and hence only one needed, but we rotate through identity
382- "kubeapiservers.operator.openshift.io=identity,aescbc:7;kubeschedulers.operator.openshift.io=identity,aescbc:7" ,
383- // 7 is migrated, plus one backed key (5). 6 is deleted, and therefore is not preserved (would be if the operand config was not deleted)
405+ // 7 is migrated, backed key (5) is immediately included when rotating through identity. 6 is deleted, not preserved (would be if operand config was not deleted)
406+ "kubeapiservers.operator.openshift.io=identity,aescbc:7,aescbc:5 ;kubeschedulers.operator.openshift.io=identity,aescbc:7,aescbc:5 " ,
407+ // promote aescbc:7 back to write position
384408 "kubeapiservers.operator.openshift.io=aescbc:7,aescbc:5,identity;kubeschedulers.operator.openshift.io=aescbc:7,aescbc:5,identity" ,
385409 )
386410 waitForConditionStatus ("Encrypted" , operatorv1 .ConditionTrue )
387411}
388412
389413const encryptionTestOperatorCRD = `
390- apiVersion: apiextensions.k8s.io/v1beta1
414+ apiVersion: apiextensions.k8s.io/v1
391415kind: CustomResourceDefinition
392416metadata:
393417 name: encryptiontests.operator.openshift.io
@@ -399,12 +423,62 @@ spec:
399423 plural: encryptiontests
400424 singular: encryptiontest
401425 scope: Cluster
402- subresources:
403- status: {}
404426 versions:
405427 - name: v1
406428 served: true
407429 storage: true
430+ subresources:
431+ status: {}
432+ schema:
433+ openAPIV3Schema:
434+ type: object
435+ required:
436+ - spec
437+ properties:
438+ spec:
439+ type: object
440+ required:
441+ - managementState
442+ properties:
443+ managementState:
444+ type: string
445+ enum:
446+ - Managed
447+ - Unmanaged
448+ - Removed
449+ observedConfig:
450+ type: object
451+ nullable: true
452+ x-kubernetes-preserve-unknown-fields: true
453+ unsupportedConfigOverrides:
454+ type: object
455+ nullable: true
456+ x-kubernetes-preserve-unknown-fields: true
457+ status:
458+ type: object
459+ properties:
460+ conditions:
461+ type: array
462+ items:
463+ type: object
464+ required:
465+ - type
466+ - status
467+ properties:
468+ type:
469+ type: string
470+ status:
471+ type: string
472+ lastTransitionTime:
473+ type: string
474+ format: date-time
475+ reason:
476+ type: string
477+ message:
478+ type: string
479+ observedGeneration:
480+ type: integer
481+ format: int64
408482`
409483
410484func toString (c * apiserverv1.EncryptionConfiguration ) string {
0 commit comments