@@ -18,13 +18,36 @@ limitations under the License.
1818package controllers
1919
2020import (
21+ "context"
2122 "testing"
23+ "time"
2224
25+ "github.com/aws/aws-sdk-go/aws"
26+ sts "github.com/aws/aws-sdk-go/service/sts"
27+ "github.com/aws/aws-sdk-go/service/sts/stsiface"
28+ "github.com/golang/mock/gomock"
2329 . "github.com/onsi/gomega"
24- cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
30+ v1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
31+ rosaaws "github.com/openshift/rosa/pkg/aws"
2532 "github.com/openshift/rosa/pkg/ocm"
33+ corev1 "k8s.io/api/core/v1"
34+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35+ "k8s.io/apimachinery/pkg/runtime"
36+ "k8s.io/apimachinery/pkg/types"
37+ ctrl "sigs.k8s.io/controller-runtime"
38+ "sigs.k8s.io/controller-runtime/pkg/client"
2639
40+ infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
2741 rosacontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/rosa/api/v1beta2"
42+ "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud"
43+ "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
44+ "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/s3/mock_stsiface"
45+ "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/logger"
46+ "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/rosa"
47+ "sigs.k8s.io/cluster-api-provider-aws/v2/test/mocks"
48+ clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
49+ "sigs.k8s.io/cluster-api/util/conditions"
50+ "sigs.k8s.io/cluster-api/util/patch"
2851)
2952
3053func TestUpdateOCMClusterSpec (t * testing.T ) {
@@ -45,12 +68,12 @@ func TestUpdateOCMClusterSpec(t *testing.T) {
4568 }
4669
4770 // Mock Cluster input
48- mockCluster , _ := cmv1 .NewCluster ().
49- AWS (cmv1 .NewAWS ().
50- AuditLog (cmv1 .NewAuditLog ().RoleArn ("arn:aws:iam::123456789012:role/AuditLogRole" ))).
51- RegistryConfig (cmv1 .NewClusterRegistryConfig ().
71+ mockCluster , _ := v1 .NewCluster ().
72+ AWS (v1 .NewAWS ().
73+ AuditLog (v1 .NewAuditLog ().RoleArn ("arn:aws:iam::123456789012:role/AuditLogRole" ))).
74+ RegistryConfig (v1 .NewClusterRegistryConfig ().
5275 AdditionalTrustedCa (map [string ]string {"trusted-ca" : "-----BEGIN CERTIFICATE----- testcert -----END CERTIFICATE-----" }).
53- AllowedRegistriesForImport (cmv1 .NewRegistryLocation ().
76+ AllowedRegistriesForImport (v1 .NewRegistryLocation ().
5477 DomainName ("registry1.com" ).
5578 Insecure (false ))).Build ()
5679
@@ -71,9 +94,9 @@ func TestUpdateOCMClusterSpec(t *testing.T) {
7194 },
7295 }
7396
74- mockCluster , _ := cmv1 .NewCluster ().
75- AWS (cmv1 .NewAWS ().
76- AuditLog (cmv1 .NewAuditLog ().RoleArn ("arn:aws:iam::123456789012:role/OldAuditLogRole" ))).Build ()
97+ mockCluster , _ := v1 .NewCluster ().
98+ AWS (v1 .NewAWS ().
99+ AuditLog (v1 .NewAuditLog ().RoleArn ("arn:aws:iam::123456789012:role/OldAuditLogRole" ))).Build ()
77100
78101 expectedOCMSpec := ocm.Spec {
79102 AuditLogRoleARN : & rosaControlPlane .Spec .AuditLogRoleARN ,
@@ -102,12 +125,12 @@ func TestUpdateOCMClusterSpec(t *testing.T) {
102125 },
103126 }
104127
105- mockCluster , _ := cmv1 .NewCluster ().
106- RegistryConfig (cmv1 .NewClusterRegistryConfig ().
128+ mockCluster , _ := v1 .NewCluster ().
129+ RegistryConfig (v1 .NewClusterRegistryConfig ().
107130 AdditionalTrustedCa (map [string ]string {"old-trusted-ca" : "-----BEGIN CERTIFICATE----- testcert -----END CERTIFICATE-----" }).
108- AllowedRegistriesForImport (cmv1 .NewRegistryLocation ().
131+ AllowedRegistriesForImport (v1 .NewRegistryLocation ().
109132 DomainName ("old-registry.com" ).
110- Insecure (false )).RegistrySources (cmv1 .NewRegistrySources ().BlockedRegistries ([]string {"blocked.io" , "blocked.org" }... ))).
133+ Insecure (false )).RegistrySources (v1 .NewRegistrySources ().BlockedRegistries ([]string {"blocked.io" , "blocked.org" }... ))).
111134 Build ()
112135
113136 expectedOCMSpec := ocm.Spec {
@@ -132,9 +155,9 @@ func TestUpdateOCMClusterSpec(t *testing.T) {
132155 },
133156 }
134157
135- mockCluster , _ := cmv1 .NewCluster ().
136- RegistryConfig (cmv1 .NewClusterRegistryConfig ().
137- AllowedRegistriesForImport (cmv1 .NewRegistryLocation ().
158+ mockCluster , _ := v1 .NewCluster ().
159+ RegistryConfig (v1 .NewClusterRegistryConfig ().
160+ AllowedRegistriesForImport (v1 .NewRegistryLocation ().
138161 DomainName ("old-registry.com" ).
139162 Insecure (false ))).
140163 Build ()
@@ -150,3 +173,204 @@ func TestUpdateOCMClusterSpec(t *testing.T) {
150173 g .Expect (ocmSpec ).To (Equal (expectedOCMSpec ))
151174 })
152175}
176+
177+ func TestRosaControlPlaneReconcileStatusVersion (t * testing.T ) {
178+ g := NewWithT (t )
179+ ns , err := testEnv .CreateNamespace (ctx , "test-namespace" )
180+ g .Expect (err ).ToNot (HaveOccurred ())
181+
182+ secret := & corev1.Secret {
183+ ObjectMeta : metav1.ObjectMeta {
184+ Name : "rosa-secret" ,
185+ Namespace : ns .Name ,
186+ },
187+ Data : map [string ][]byte {
188+ "ocmToken" : []byte ("secret-ocm-token-string" ),
189+ },
190+ }
191+ identity := & infrav1.AWSClusterControllerIdentity {
192+ ObjectMeta : metav1.ObjectMeta {
193+ Name : "default" ,
194+ },
195+ Spec : infrav1.AWSClusterControllerIdentitySpec {
196+ AWSClusterIdentitySpec : infrav1.AWSClusterIdentitySpec {
197+ AllowedNamespaces : & infrav1.AllowedNamespaces {},
198+ },
199+ },
200+ }
201+ identity .SetGroupVersionKind (infrav1 .GroupVersion .WithKind ("AWSClusterStaticIdentity" ))
202+
203+ rosaControlPlane := & rosacontrolplanev1.ROSAControlPlane {
204+ ObjectMeta : metav1.ObjectMeta {
205+ Name : "rosa-control-plane-1" ,
206+ Namespace : ns .Name ,
207+ UID : types .UID ("rosa-control-plane-1" )},
208+ TypeMeta : metav1.TypeMeta {
209+ Kind : "ROSAControlPlane" ,
210+ APIVersion : rosacontrolplanev1 .GroupVersion .String (),
211+ },
212+ Spec : rosacontrolplanev1.RosaControlPlaneSpec {
213+ RosaClusterName : "rosa-control-plane-1" ,
214+ Subnets : []string {"subnet-0ac99a6230b408813" , "subnet-1ac99a6230b408811" },
215+ AvailabilityZones : []string {"az-1" , "az-2" },
216+ Network : & rosacontrolplanev1.NetworkSpec {
217+ MachineCIDR : "10.0.0.0/16" ,
218+ PodCIDR : "10.128.0.0/14" ,
219+ ServiceCIDR : "172.30.0.0/16" ,
220+ },
221+ Region : "us-east-1" ,
222+ Version : "4.15.20" ,
223+ ChannelGroup : "stable" ,
224+ RolesRef : rosacontrolplanev1.AWSRolesRef {},
225+ OIDCID : "iodcid1" ,
226+ InstallerRoleARN : "arn1" ,
227+ WorkerRoleARN : "arn2" ,
228+ SupportRoleARN : "arn3" ,
229+ CredentialsSecretRef : & corev1.LocalObjectReference {
230+ Name : secret .Name ,
231+ },
232+ VersionGate : "Acknowledge" ,
233+ IdentityRef : & infrav1.AWSIdentityReference {
234+ Name : identity .Name ,
235+ Kind : infrav1 .ControllerIdentityKind ,
236+ },
237+ },
238+ Status : rosacontrolplanev1.RosaControlPlaneStatus {
239+ Ready : true ,
240+ ID : "rosa-control-plane-1" ,
241+ // Version: "4.15.20",
242+ Conditions : clusterv1.Conditions {clusterv1.Condition {
243+ Type : "Paused" ,
244+ Status : "False" ,
245+ Severity : "" ,
246+ Reason : "NotPaused" ,
247+ Message : "" ,
248+ }},
249+ },
250+ }
251+
252+ ownerCluster := & clusterv1.Cluster {
253+ ObjectMeta : metav1.ObjectMeta {
254+ Name : "owner-cluster-1" ,
255+ Namespace : ns .Name ,
256+ UID : types .UID ("owner-cluster-1" ),
257+ },
258+ Spec : clusterv1.ClusterSpec {
259+ ControlPlaneRef : & corev1.ObjectReference {
260+ Name : rosaControlPlane .Name ,
261+ Kind : "ROSAControlPlane" ,
262+ APIVersion : rosacontrolplanev1 .GroupVersion .String (),
263+ },
264+ },
265+ }
266+
267+ rosaControlPlane .OwnerReferences = []metav1.OwnerReference {
268+ {
269+ Name : ownerCluster .Name ,
270+ UID : ownerCluster .UID ,
271+ Kind : "Cluster" ,
272+ APIVersion : clusterv1 .GroupVersion .String (),
273+ },
274+ }
275+
276+ mockCtrl := gomock .NewController (t )
277+ ctx := context .TODO ()
278+ ocmMock := mocks .NewMockOCMClient (mockCtrl )
279+ stsMock := mock_stsiface .NewMockSTSAPI (mockCtrl )
280+
281+ getCallerIdentityResult := & sts.GetCallerIdentityOutput {Account : aws .String ("foo" ), Arn : aws .String ("arn:aws:iam::123456789012:rosa/foo" )}
282+ stsMock .EXPECT ().GetCallerIdentity (gomock .Any ()).Return (getCallerIdentityResult , nil ).Times (1 )
283+
284+ expect := func (m * mocks.MockOCMClientMockRecorder ) {
285+ m .ValidateHypershiftVersion (gomock .Any (), gomock .Any ()).DoAndReturn (func (clusterId string , nodePoolID string ) (bool , error ) {
286+ return true , nil
287+ }).Times (1 )
288+ m .GetCluster (gomock .Any (), gomock .Any ()).DoAndReturn (func (clusterKey string , creator * rosaaws.Creator ) (* v1.Cluster , error ) {
289+ sts := (& v1.STSBuilder {}).OIDCEndpointURL ("oidc.com/oidc1" )
290+ aws := v1 .NewAWS ().AuditLog (v1 .NewAuditLog ().RoleArn ("arn:aws:iam::123456789012:role/AuditLogRole" )).STS (sts )
291+ console := (& v1.ClusterConsoleBuilder {}).URL ("console.redhat.com/cluster-123" )
292+ status := (& v1.ClusterStatusBuilder {}).State (v1 .ClusterStateError )
293+ version := (& v1.VersionBuilder {}).RawID (rosaControlPlane .Spec .Version )
294+ mockCluster , _ := v1 .NewCluster ().AWS (aws ).ID ("cluster-1" ).Version (version ).Status (status ).Console (console ).
295+ RegistryConfig (v1 .NewClusterRegistryConfig ().
296+ AdditionalTrustedCa (map [string ]string {"trusted-ca" : "-----BEGIN CERTIFICATE----- testcert -----END CERTIFICATE-----" }).
297+ AllowedRegistriesForImport (v1 .NewRegistryLocation ().
298+ DomainName ("registry1.com" ).
299+ Insecure (false ))).
300+ Build ()
301+ return mockCluster , nil
302+ }).Times (1 )
303+ }
304+
305+ expect (ocmMock .EXPECT ())
306+
307+ objects := []client.Object {ownerCluster , rosaControlPlane , secret , identity }
308+ for _ , obj := range objects {
309+ createObject (g , obj , ns .Name )
310+ }
311+
312+ // Add conditions, can't do this duirng creation
313+ cpPh , err := patch .NewHelper (rosaControlPlane , testEnv )
314+ g .Expect (err ).ShouldNot (HaveOccurred ())
315+ rosaControlPlane .Status = rosacontrolplanev1.RosaControlPlaneStatus {
316+ Ready : true ,
317+ ID : "rosa-control-plane-1" ,
318+ Version : "4.15.1" ,
319+ Conditions : clusterv1.Conditions {clusterv1.Condition {
320+ Type : "Paused" ,
321+ Status : "False" ,
322+ Severity : "" ,
323+ Reason : "NotPaused" ,
324+ Message : "" ,
325+ }},
326+ }
327+
328+ g .Expect (cpPh .Patch (ctx , rosaControlPlane )).To (Succeed ())
329+
330+ time .Sleep (50 * time .Millisecond )
331+
332+ cp := & rosacontrolplanev1.ROSAControlPlane {}
333+ key := client.ObjectKey {Name : rosaControlPlane .Name , Namespace : rosaControlPlane .Namespace }
334+ errGet := testEnv .Get (ctx , key , cp )
335+ g .Expect (errGet ).NotTo (HaveOccurred ())
336+ oldCondition := conditions .Get (cp , clusterv1 .PausedV1Beta2Condition )
337+ g .Expect (oldCondition ).NotTo (BeNil ())
338+
339+ r := ROSAControlPlaneReconciler {
340+ WatchFilterValue : "" ,
341+ Endpoints : []scope.ServiceEndpoint {},
342+ Client : testEnv ,
343+ NewStsClient : func (cloud.ScopeUsage , cloud.Session , logger.Wrapper , runtime.Object ) stsiface.STSAPI { return stsMock },
344+ NewOCMClient : func (ctx context.Context , rosaScope * scope.ROSAControlPlaneScope ) (rosa.OCMClient , error ) {
345+ return ocmMock , nil
346+ },
347+ }
348+
349+ req := ctrl.Request {}
350+ req .NamespacedName = types.NamespacedName {Name : rosaControlPlane .Name , Namespace : rosaControlPlane .Namespace }
351+ _ , errReconcile := r .Reconcile (ctx , req )
352+ g .Expect (errReconcile ).ToNot (HaveOccurred ())
353+ time .Sleep (50 * time .Millisecond )
354+
355+ errGet2 := testEnv .Get (ctx , key , cp )
356+ g .Expect (errGet2 ).NotTo (HaveOccurred ())
357+ g .Expect (cp .Status .Version ).To (Equal ("4.15.20" ))
358+
359+ // cleanup
360+ for _ , obj := range objects {
361+ cleanupObject (g , obj )
362+ }
363+ }
364+
365+ func createObject (g * WithT , obj client.Object , namespace string ) {
366+ if obj .DeepCopyObject () != nil {
367+ obj .SetNamespace (namespace )
368+ g .Expect (testEnv .Create (ctx , obj )).To (Succeed ())
369+ }
370+ }
371+
372+ func cleanupObject (g * WithT , obj client.Object ) {
373+ if obj .DeepCopyObject () != nil {
374+ g .Expect (testEnv .Cleanup (ctx , obj )).To (Succeed ())
375+ }
376+ }
0 commit comments