@@ -12,6 +12,7 @@ import (
12
12
"github.com/stretchr/testify/require"
13
13
14
14
configv1 "github.com/openshift/api/config/v1"
15
+ configinformers "github.com/openshift/client-go/config/informers/externalversions"
15
16
"github.com/openshift/library-go/pkg/operator/certrotation"
16
17
corev1 "k8s.io/api/core/v1"
17
18
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -43,12 +44,14 @@ type fixture struct {
43
44
maoSecretLister []* corev1.Secret
44
45
mcoSecretLister []* corev1.Secret
45
46
mcoConfigMapLister []* corev1.ConfigMap
47
+ infraLister []* configv1.Infrastructure
46
48
47
49
objects []runtime.Object
48
50
configObjects []runtime.Object
49
51
machineObjects []runtime.Object
50
52
aroObjects []runtime.Object
51
53
k8sI kubeinformers.SharedInformerFactory
54
+ infraInformer configinformers.SharedInformerFactory
52
55
53
56
controller * CertRotationController
54
57
}
@@ -80,14 +83,15 @@ func (f *fixture) newController() *CertRotationController {
80
83
Status : configv1.InfrastructureStatus {
81
84
ControlPlaneTopology : configv1 .HighlyAvailableTopologyMode ,
82
85
PlatformStatus : platformStatus ,
83
- APIServerInternalURL : "test-url " },
86
+ APIServerInternalURL : "https://10.0.0.1:6443 " },
84
87
})
85
88
86
89
f .kubeClient = fake .NewSimpleClientset (f .objects ... )
87
90
f .configClient = fakeconfigv1client .NewSimpleClientset (f .configObjects ... )
88
91
f .machineClient = fakemachineclientset .NewSimpleClientset (f .machineObjects ... )
89
92
f .aroClient = fakearoclientset .NewSimpleClientset (f .aroObjects ... )
90
93
f .k8sI = kubeinformers .NewSharedInformerFactory (f .kubeClient , noResyncPeriodFunc ())
94
+ f .infraInformer = configinformers .NewSharedInformerFactory (f .configClient , noResyncPeriodFunc ())
91
95
92
96
for _ , secret := range f .maoSecretLister {
93
97
f .k8sI .Core ().V1 ().Secrets ().Informer ().GetIndexer ().Add (secret )
@@ -101,7 +105,12 @@ func (f *fixture) newController() *CertRotationController {
101
105
f .k8sI .Core ().V1 ().ConfigMaps ().Informer ().GetIndexer ().Add (configMap )
102
106
}
103
107
104
- c , err := New (f .kubeClient , f .configClient , f .machineClient , f .aroClient , f .k8sI .Core ().V1 ().Secrets (), f .k8sI .Core ().V1 ().Secrets (), f .k8sI .Core ().V1 ().ConfigMaps ())
108
+ for _ , infra := range f .configObjects {
109
+ f .infraInformer .Config ().V1 ().Infrastructures ().Informer ().GetIndexer ().Add (infra )
110
+ f .infraLister = append (f .infraLister , infra .(* configv1.Infrastructure ))
111
+ }
112
+
113
+ c , err := New (f .kubeClient , f .configClient , f .machineClient , f .aroClient , f .k8sI .Core ().V1 ().Secrets (), f .k8sI .Core ().V1 ().Secrets (), f .k8sI .Core ().V1 ().ConfigMaps (), f .infraInformer .Config ().V1 ().Infrastructures ())
105
114
require .NoError (f .t , err )
106
115
107
116
c .StartInformers ()
@@ -164,6 +173,72 @@ func (f *fixture) verifyAROIPInTLSCertificate(t *testing.T, expectedIP string) {
164
173
t .Logf ("Successfully verified ARO IP %s is present in TLS certificate" , expectedIP )
165
174
}
166
175
176
+ func TestInfraUpdateTriggersCertResync (t * testing.T ) {
177
+ f := newFixture (t )
178
+ f .objects = append (f .objects , getGoodMAOSecret ("test-user-data" ))
179
+ f .maoSecretLister = append (f .maoSecretLister , getGoodMAOSecret ("test-user-data" ))
180
+ f .machineObjects = append (f .machineObjects , getMachineSet ("test-machine" ))
181
+
182
+ f .controller = f .newController ()
183
+
184
+ // Perform initial sync to create initial certificates
185
+ f .runController ()
186
+
187
+ // Update the Infrastructure object with a new APIServerInternalURL
188
+ infraObj := & configv1.Infrastructure {
189
+ ObjectMeta : metav1.ObjectMeta {
190
+ Name : "cluster" ,
191
+ },
192
+ Status : configv1.InfrastructureStatus {
193
+ ControlPlaneTopology : configv1 .HighlyAvailableTopologyMode ,
194
+ APIServerInternalURL : "https://10.0.0.2:6443" , // Changed from 10.0.0.1 to 10.0.0.2
195
+ },
196
+ }
197
+
198
+ // Update the Infrastructure object
199
+ _ , err := f .configClient .ConfigV1 ().Infrastructures ().Update (context .TODO (), infraObj , metav1.UpdateOptions {})
200
+ require .NoError (t , err )
201
+
202
+ // Update the informer with the new Infrastructure object
203
+ f .infraInformer .Config ().V1 ().Infrastructures ().Informer ().GetIndexer ().Update (infraObj )
204
+
205
+ // Trigger the sync after Infrastructure update
206
+ f .syncListers (t )
207
+ f .runController ()
208
+
209
+ // Verify that the TLS certificate was regenerated with the new hostname
210
+ tlsSecret , err := f .kubeClient .CoreV1 ().Secrets (ctrlcommon .MCONamespace ).Get (context .TODO (), ctrlcommon .MachineConfigServerTLSSecretName , metav1.GetOptions {})
211
+ require .NoError (t , err )
212
+ require .NotNil (t , tlsSecret )
213
+
214
+ // Verify certificate contains new hostname
215
+ certData , exists := tlsSecret .Data ["tls.crt" ]
216
+ require .True (t , exists , "TLS certificate should exist in secret" )
217
+ require .NotEmpty (t , certData , "TLS certificate data should not be empty" )
218
+
219
+ // Decode and parse certificate
220
+ block , _ := pem .Decode (certData )
221
+ require .NotNil (t , block , "Should be able to decode PEM certificate" )
222
+
223
+ cert , err := x509 .ParseCertificate (block .Bytes )
224
+ require .NoError (t , err , "Should be able to parse TLS certificate" )
225
+
226
+ // Verify the new hostname is in the certificate's DNS names
227
+ expectedHostname := "10.0.0.2"
228
+ found := false
229
+ for _ , dnsName := range cert .DNSNames {
230
+ if dnsName == expectedHostname {
231
+ found = true
232
+ break
233
+ }
234
+ }
235
+ require .True (t , found , "New hostname %s should be present in certificate DNS names" , expectedHostname )
236
+ t .Logf ("Successfully verified hostname %s is present in TLS certificate after Infrastructure update" , expectedHostname )
237
+
238
+ // Verify that user data secrets were updated (should be 1 total update)
239
+ f .verifyUserDataSecretUpdateCount (1 )
240
+ }
241
+
167
242
func TestMCSCARotation (t * testing.T ) {
168
243
tests := []struct {
169
244
name string
0 commit comments