Skip to content

Commit 845c6f7

Browse files
Merge pull request #396 from kstrenkova/add-input-condition
Validate openstack inputs and add input condition
2 parents 9e2ade5 + 4056721 commit 845c6f7

8 files changed

Lines changed: 167 additions & 11 deletions

internal/controller/ansibletest_controller.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func (r *AnsibleTestReconciler) Reconcile(ctx context.Context, req ctrl.Request)
115115
// Initialize conditions used later as Status=Unknown
116116
cl := condition.CreateList(
117117
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
118-
condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyMessage),
118+
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
119119
condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage),
120120
)
121121
instance.Status.Conditions.Init(&cl)
@@ -207,7 +207,17 @@ func (r *AnsibleTestReconciler) Reconcile(ctx context.Context, req ctrl.Request)
207207
}
208208
// Create PersistentVolumeClaim - end
209209

210-
instance.Status.Conditions.MarkTrue(condition.ServiceConfigReadyCondition, condition.ServiceConfigReadyMessage)
210+
err = r.ValidateOpenstackInputs(ctx, instance, instance.Spec.OpenStackConfigMap, instance.Spec.OpenStackConfigSecret)
211+
if err != nil {
212+
instance.Status.Conditions.Set(condition.FalseCondition(
213+
condition.InputReadyCondition,
214+
condition.ErrorReason,
215+
condition.SeverityError,
216+
condition.InputReadyErrorMessage,
217+
err.Error()))
218+
return ctrl.Result{RequeueAfter: RequeueAfterValue}, err
219+
}
220+
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)
211221

212222
// Create a new pod
213223
mountCerts := r.CheckSecretExists(ctx, instance, "combined-ca-bundle")

internal/controller/common.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ var (
9494

9595
// ErrFieldNotFound indicates a field name does not exist on the struct.
9696
ErrFieldNotFound = errors.New("field not found")
97+
98+
// ErrMissingRequiredKey indicates that a required key is missing in a resource.
99+
ErrMissingRequiredKey = errors.New("missing required key")
97100
)
98101

99102
// Reconciler provides common functionality for all test framework reconcilers
@@ -350,6 +353,82 @@ func (r *Reconciler) CheckSecretExists(ctx context.Context, instance client.Obje
350353
return true
351354
}
352355

356+
// ValidateSecretWithKeys validates that a Secret exists and contains required keys
357+
func (r *Reconciler) ValidateSecretWithKeys(
358+
ctx context.Context,
359+
instance client.Object,
360+
secretName string,
361+
requiredKeys []string,
362+
) error {
363+
// When secret is not specified, skip it
364+
if secretName == "" {
365+
return nil
366+
}
367+
368+
secret := &corev1.Secret{}
369+
err := r.Client.Get(ctx, client.ObjectKey{Namespace: instance.GetNamespace(), Name: secretName}, secret)
370+
if err != nil {
371+
return err
372+
}
373+
374+
// Validate required keys
375+
for _, key := range requiredKeys {
376+
if _, ok := secret.Data[key]; !ok {
377+
return fmt.Errorf("%w '%s' in secret %s", ErrMissingRequiredKey, key, secretName)
378+
}
379+
}
380+
381+
return nil
382+
}
383+
384+
// ValidateConfigMapWithKeys validates that a ConfigMap exists and contains required keys
385+
func (r *Reconciler) ValidateConfigMapWithKeys(
386+
ctx context.Context,
387+
instance client.Object,
388+
configMapName string,
389+
requiredKeys []string,
390+
) error {
391+
// When config map is not specified, skip it
392+
if configMapName == "" {
393+
return nil
394+
}
395+
396+
cm := &corev1.ConfigMap{}
397+
err := r.Client.Get(ctx, client.ObjectKey{Namespace: instance.GetNamespace(), Name: configMapName}, cm)
398+
if err != nil {
399+
return err
400+
}
401+
402+
// Validate required keys
403+
for _, key := range requiredKeys {
404+
if _, ok := cm.Data[key]; !ok {
405+
return fmt.Errorf("%w '%s' in config map %s", ErrMissingRequiredKey, key, configMapName)
406+
}
407+
}
408+
409+
return nil
410+
}
411+
412+
// ValidateOpenstackInputs validates OpenStack configuration inputs
413+
func (r *Reconciler) ValidateOpenstackInputs(
414+
ctx context.Context,
415+
instance client.Object,
416+
openstackConfigMapName string,
417+
openstackConfigSecretName string,
418+
) error {
419+
err := r.ValidateConfigMapWithKeys(ctx, instance, openstackConfigMapName, []string{"clouds.yaml"})
420+
if err != nil {
421+
return err
422+
}
423+
424+
err = r.ValidateSecretWithKeys(ctx, instance, openstackConfigSecretName, []string{"secure.yaml"})
425+
if err != nil {
426+
return err
427+
}
428+
429+
return nil
430+
}
431+
353432
// GetStringHash returns a hash of the given string with the specified length
354433
func GetStringHash(str string, hashLength int) string {
355434
hash := sha256.New()

internal/controller/horizontest_controller.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ func (r *HorizonTestReconciler) Reconcile(ctx context.Context, req ctrl.Request)
110110
// Initialize conditions used later as Status=Unknown
111111
cl := condition.CreateList(
112112
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
113+
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
113114
condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage),
114115
)
115116
instance.Status.Conditions.Init(&cl)
@@ -214,9 +215,32 @@ func (r *HorizonTestReconciler) Reconcile(ctx context.Context, req ctrl.Request)
214215
}
215216
// Create PersistentVolumeClaim - end
216217

218+
err = r.ValidateOpenstackInputs(ctx, instance, instance.Spec.OpenStackConfigMap, instance.Spec.OpenStackConfigSecret)
219+
if err != nil {
220+
instance.Status.Conditions.Set(condition.FalseCondition(
221+
condition.InputReadyCondition,
222+
condition.ErrorReason,
223+
condition.SeverityError,
224+
condition.InputReadyErrorMessage,
225+
err.Error()))
226+
return ctrl.Result{RequeueAfter: RequeueAfterValue}, err
227+
}
228+
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)
229+
230+
err = r.ValidateSecretWithKeys(ctx, instance, instance.Spec.KubeconfigSecretName, []string{})
231+
if err != nil {
232+
instance.Status.Conditions.Set(condition.FalseCondition(
233+
condition.InputReadyCondition,
234+
condition.ErrorReason,
235+
condition.SeverityWarning,
236+
condition.InputReadyErrorMessage,
237+
err.Error()))
238+
return ctrl.Result{}, err
239+
}
240+
mountKubeconfig := len(instance.Spec.KubeconfigSecretName) != 0
241+
217242
// Create Pod
218243
mountCerts := r.CheckSecretExists(ctx, instance, "combined-ca-bundle")
219-
mountKubeconfig := len(instance.Spec.KubeconfigSecretName) != 0
220244

221245
// Prepare HorizonTest env vars
222246
envVars := r.PrepareHorizonTestEnvVars(instance)

internal/controller/tempest_controller.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ func (r *TempestReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re
117117
// Initialize conditions used later as Status=Unknown
118118
cl := condition.CreateList(
119119
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
120+
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
120121
condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage),
121122
condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage),
122123
condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage),
@@ -232,10 +233,29 @@ func (r *TempestReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re
232233
}
233234
// Create PersistentVolumeClaim - end
234235

235-
mountSSHKey := false
236-
if instance.Spec.SSHKeySecretName != "" {
237-
mountSSHKey = r.CheckSecretExists(ctx, instance, instance.Spec.SSHKeySecretName)
236+
err = r.ValidateOpenstackInputs(ctx, instance, instance.Spec.OpenStackConfigMap, instance.Spec.OpenStackConfigSecret)
237+
if err != nil {
238+
instance.Status.Conditions.Set(condition.FalseCondition(
239+
condition.InputReadyCondition,
240+
condition.ErrorReason,
241+
condition.SeverityError,
242+
condition.InputReadyErrorMessage,
243+
err.Error()))
244+
return ctrl.Result{RequeueAfter: RequeueAfterValue}, err
245+
}
246+
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)
247+
248+
err = r.ValidateSecretWithKeys(ctx, instance, instance.Spec.SSHKeySecretName, []string{})
249+
if err != nil {
250+
instance.Status.Conditions.Set(condition.FalseCondition(
251+
condition.InputReadyCondition,
252+
condition.ErrorReason,
253+
condition.SeverityWarning,
254+
condition.InputReadyErrorMessage,
255+
err.Error()))
256+
return ctrl.Result{}, err
238257
}
258+
mountSSHKey := len(instance.Spec.SSHKeySecretName) != 0
239259

240260
// Generate ConfigMaps
241261
err = r.generateServiceConfigMaps(ctx, helper, instance, nextWorkflowStep)

internal/controller/tobiko_controller.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ func (r *TobikoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
114114
// Initialize conditions used later as Status=Unknown
115115
cl := condition.CreateList(
116116
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
117+
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
117118
condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage),
118119
condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage),
119120
)
@@ -229,6 +230,30 @@ func (r *TobikoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
229230
}
230231
// Create PersistentVolumeClaim - end
231232

233+
err = r.ValidateOpenstackInputs(ctx, instance, instance.Spec.OpenStackConfigMap, instance.Spec.OpenStackConfigSecret)
234+
if err != nil {
235+
instance.Status.Conditions.Set(condition.FalseCondition(
236+
condition.InputReadyCondition,
237+
condition.ErrorReason,
238+
condition.SeverityError,
239+
condition.InputReadyErrorMessage,
240+
err.Error()))
241+
return ctrl.Result{RequeueAfter: RequeueAfterValue}, err
242+
}
243+
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)
244+
245+
err = r.ValidateSecretWithKeys(ctx, instance, instance.Spec.KubeconfigSecretName, []string{})
246+
if err != nil {
247+
instance.Status.Conditions.Set(condition.FalseCondition(
248+
condition.InputReadyCondition,
249+
condition.ErrorReason,
250+
condition.SeverityWarning,
251+
condition.InputReadyErrorMessage,
252+
err.Error()))
253+
return ctrl.Result{}, err
254+
}
255+
mountKubeconfig := len(instance.Spec.KubeconfigSecretName) != 0
256+
232257
serviceAnnotations, ctrlResult, err := r.EnsureNetworkAttachments(
233258
ctx,
234259
Log,
@@ -266,8 +291,6 @@ func (r *TobikoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
266291
mountKeys = true
267292
}
268293

269-
mountKubeconfig := len(instance.Spec.KubeconfigSecretName) != 0
270-
271294
// Prepare Tobiko env vars
272295
envVars := r.PrepareTobikoEnvVars(ctx, serviceLabels, instance, helper, nextWorkflowStep)
273296
podName := r.GetPodName(instance, nextWorkflowStep)

test/functional/horizontest_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ var _ = Describe("HorizonTest controller", func() {
4848
It("initializes the status fields", func() {
4949
Eventually(func(g Gomega) {
5050
horizonTest := GetHorizonTest(horizonTestName)
51-
g.Expect(horizonTest.Status.Conditions).To(HaveLen(2))
51+
g.Expect(horizonTest.Status.Conditions).To(HaveLen(3))
5252
}, timeout*2, interval).Should(Succeed())
5353
})
5454

test/functional/tempest_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ var _ = Describe("Tempest controller", func() {
4848
It("initializes the status fields", func() {
4949
Eventually(func(g Gomega) {
5050
tempest := GetTempest(tempestName)
51-
g.Expect(tempest.Status.Conditions).To(HaveLen(4))
51+
g.Expect(tempest.Status.Conditions).To(HaveLen(5))
5252
}, timeout*2, interval).Should(Succeed())
5353
})
5454

test/functional/tobiko_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ var _ = Describe("Tobiko controller", func() {
4848
It("initializes the status fields", func() {
4949
Eventually(func(g Gomega) {
5050
tobiko := GetTobiko(tobikoName)
51-
g.Expect(tobiko.Status.Conditions).To(HaveLen(3))
51+
g.Expect(tobiko.Status.Conditions).To(HaveLen(4))
5252
}, timeout*2, interval).Should(Succeed())
5353
})
5454

0 commit comments

Comments
 (0)