diff --git a/controllers/cinder_common.go b/controllers/cinder_common.go new file mode 100644 index 00000000..ea8446ee --- /dev/null +++ b/controllers/cinder_common.go @@ -0,0 +1,114 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "fmt" + "github.com/openstack-k8s-operators/lib-common/modules/common/condition" + "github.com/openstack-k8s-operators/lib-common/modules/common/secret" + "k8s.io/apimachinery/pkg/types" + "time" + + "github.com/openstack-k8s-operators/cinder-operator/pkg/cinder" + "github.com/openstack-k8s-operators/lib-common/modules/common/env" + "github.com/openstack-k8s-operators/lib-common/modules/common/helper" + k8s_errors "k8s.io/apimachinery/pkg/api/errors" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +type conditionUpdater interface { + Set(c *condition.Condition) + MarkTrue(t condition.Type, messageFormat string, messageArgs ...interface{}) +} + +// verifyServiceSecret - ensures that the Secret object exists and the expected +// fields are in the Secret. It also sets a hash of the values of the expected +// fields passed as input. +func verifyServiceSecret( + ctx context.Context, + secretName types.NamespacedName, + expectedFields []string, + reader client.Reader, + conditionUpdater conditionUpdater, + requeueTimeout time.Duration, + envVars *map[string]env.Setter, +) (ctrl.Result, error) { + + hash, res, err := secret.VerifySecret(ctx, secretName, expectedFields, reader, requeueTimeout) + if err != nil { + conditionUpdater.Set(condition.FalseCondition( + condition.InputReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.InputReadyErrorMessage, + err.Error())) + return res, err + } else if (res != ctrl.Result{}) { + log.FromContext(ctx).Info(fmt.Sprintf("OpenStack secret %s not found", secretName)) + conditionUpdater.Set(condition.FalseCondition( + condition.InputReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.InputReadyWaitingMessage)) + return res, nil + } + (*envVars)[secretName.Name] = env.SetValue(hash) + return ctrl.Result{}, nil +} + +// verifyConfigSecrets - It iterates over the secretNames passed as input and +// sets the hash of values in the envVars map. +func verifyConfigSecrets( + ctx context.Context, + h *helper.Helper, + conditionUpdater conditionUpdater, + secretNames []string, + namespace string, + envVars *map[string]env.Setter, +) (ctrl.Result, error) { + var hash string + var err error + for _, secretName := range secretNames { + _, hash, err = secret.GetSecret(ctx, h, secretName, namespace) + if err != nil { + if k8s_errors.IsNotFound(err) { + log.FromContext(ctx).Info(fmt.Sprintf("Secret %s not found", secretName)) + conditionUpdater.Set(condition.FalseCondition( + condition.InputReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.InputReadyWaitingMessage)) + return cinder.ResultRequeue, nil + } + conditionUpdater.Set(condition.FalseCondition( + condition.InputReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.InputReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } + // Add a prefix to the var name to avoid accidental collision with other non-secret + // vars. The secret names themselves will be unique. + (*envVars)["secret-"+secretName] = env.SetValue(hash) + } + + return ctrl.Result{}, nil +} diff --git a/controllers/cinder_controller.go b/controllers/cinder_controller.go index 1f5748e6..5dfe21b6 100644 --- a/controllers/cinder_controller.go +++ b/controllers/cinder_controller.go @@ -23,6 +23,7 @@ import ( k8s_errors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -396,7 +397,7 @@ func (r *CinderReconciler) reconcileInit( jobDef, cinderv1beta1.DbSyncHash, instance.Spec.PreserveJobs, - time.Duration(5)*time.Second, + cinder.ShortDuration, dbSyncHash, ) ctrlResult, err := dbSyncjob.DoJob( @@ -492,7 +493,7 @@ func (r *CinderReconciler) reconcileNormal(ctx context.Context, instance *cinder condition.RequestedReason, condition.SeverityInfo, condition.RabbitMqTransportURLReadyRunningMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil + return cinder.ResultRequeue, nil } instance.Status.Conditions.MarkTrue(condition.RabbitMqTransportURLReadyCondition, condition.RabbitMqTransportURLReadyMessage) @@ -504,6 +505,7 @@ func (r *CinderReconciler) reconcileNormal(ctx context.Context, instance *cinder // memcached, err := memcachedv1.GetMemcachedByName(ctx, helper, instance.Spec.MemcachedInstance, instance.Namespace) if err != nil { + Log.Info(fmt.Sprintf("%s... requeueing", condition.MemcachedReadyWaitingMessage)) if k8s_errors.IsNotFound(err) { Log.Info(fmt.Sprintf("memcached %s not found", instance.Spec.MemcachedInstance)) instance.Status.Conditions.Set(condition.FalseCondition( @@ -511,7 +513,7 @@ func (r *CinderReconciler) reconcileNormal(ctx context.Context, instance *cinder condition.RequestedReason, condition.SeverityInfo, condition.MemcachedReadyWaitingMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil + return cinder.ResultRequeue, nil } instance.Status.Conditions.Set(condition.FalseCondition( condition.MemcachedReadyCondition, @@ -523,13 +525,13 @@ func (r *CinderReconciler) reconcileNormal(ctx context.Context, instance *cinder } if !memcached.IsReady() { - Log.Info(fmt.Sprintf("memcached %s is not ready", memcached.Name)) + Log.Info(fmt.Sprintf("%s... requeueing", condition.MemcachedReadyWaitingMessage)) instance.Status.Conditions.Set(condition.FalseCondition( condition.MemcachedReadyCondition, condition.RequestedReason, condition.SeverityInfo, condition.MemcachedReadyWaitingMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil + return cinder.ResultRequeue, nil } // Mark the Memcached Service as Ready if we get to this point with no errors instance.Status.Conditions.MarkTrue( @@ -539,28 +541,23 @@ func (r *CinderReconciler) reconcileNormal(ctx context.Context, instance *cinder // // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map // - ospSecret, hash, err := secret.GetSecret(ctx, helper, instance.Spec.Secret, instance.Namespace) + + result, err := verifyServiceSecret( + ctx, + types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret}, + []string{ + instance.Spec.PasswordSelectors.Service, + }, + helper.GetClient(), + &instance.Status.Conditions, + cinder.NormalDuration, + &configVars, + ) if err != nil { - if k8s_errors.IsNotFound(err) { - Log.Info(fmt.Sprintf("OpenStack secret %s not found", instance.Spec.Secret)) - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.RequestedReason, - condition.SeverityInfo, - condition.InputReadyWaitingMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil - } - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.ErrorReason, - condition.SeverityWarning, - condition.InputReadyErrorMessage, - err.Error())) - return ctrl.Result{}, err + return result, err + } else if (result != ctrl.Result{}) { + return result, nil } - // Add a prefix to the var name to avoid accidental collision with other non-secret vars. - configVars["secret-"+ospSecret.Name] = env.SetValue(hash) - instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) // run check OpenStack secret - end @@ -629,7 +626,7 @@ func (r *CinderReconciler) reconcileNormal(ctx context.Context, instance *cinder condition.SeverityInfo, condition.NetworkAttachmentsReadyWaitingMessage, netAtt)) - return ctrl.Result{RequeueAfter: time.Second * 10}, nil + return cinder.ResultRequeue, fmt.Errorf(condition.NetworkAttachmentsReadyWaitingMessage, netAtt) } instance.Status.Conditions.Set(condition.FalseCondition( condition.NetworkAttachmentsReadyCondition, diff --git a/controllers/cinderapi_controller.go b/controllers/cinderapi_controller.go index eb8be6cb..1cce54a5 100644 --- a/controllers/cinderapi_controller.go +++ b/controllers/cinderapi_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -569,7 +568,7 @@ func (r *CinderAPIReconciler) reconcileInit( PasswordSelector: instance.Spec.PasswordSelectors.Service, } - ksSvcObj := keystonev1.NewKeystoneService(ksSvcSpec, instance.Namespace, serviceLabels, time.Duration(10)*time.Second) + ksSvcObj := keystonev1.NewKeystoneService(ksSvcSpec, instance.Namespace, serviceLabels, cinder.NormalDuration) ctrlResult, err := ksSvcObj.CreateOrPatch(ctx, helper) if err != nil { instance.Status.Conditions.MarkFalse( @@ -604,7 +603,7 @@ func (r *CinderAPIReconciler) reconcileInit( instance.Namespace, ksEndptSpec, serviceLabels, - time.Duration(10)*time.Second) + cinder.NormalDuration) ctrlResult, err = ksEndptObj.CreateOrPatch(ctx, helper) if err != nil { instance.Status.Conditions.MarkFalse( @@ -642,43 +641,49 @@ func (r *CinderAPIReconciler) reconcileNormal(ctx context.Context, instance *cin // // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map // - ctrlResult, err := r.getSecret(ctx, helper, instance, instance.Spec.Secret, &configVars) - if err != nil { - return ctrlResult, err - } - // - // check for required TransportURL secret holding transport URL string - // - ctrlResult, err = r.getSecret(ctx, helper, instance, instance.Spec.TransportURLSecret, &configVars) + ctrlResult, err := verifyServiceSecret( + ctx, + types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret}, + []string{ + instance.Spec.PasswordSelectors.Service, + }, + helper.GetClient(), + &instance.Status.Conditions, + cinder.NormalDuration, + &configVars, + ) if err != nil { return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } // - // check for required service secrets + // check for required Transport URL and config secrets // - for _, secretName := range instance.Spec.CustomServiceConfigSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, secretName, &configVars) - if err != nil { - return ctrlResult, err - } - } - // - // check for required Cinder secrets that should have been created by parent Cinder CR - // parentCinderName := cinder.GetOwningCinderName(instance) - parentSecrets := []string{ - fmt.Sprintf("%s-scripts", parentCinderName), - fmt.Sprintf("%s-config-data", parentCinderName), + secretNames := []string{ + instance.Spec.TransportURLSecret, // TransportURLSecret + fmt.Sprintf("%s-scripts", parentCinderName), // ScriptsSecret + fmt.Sprintf("%s-config-data", parentCinderName), // ConfigSecret } - - for _, parentSecret := range parentSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, parentSecret, &configVars) - if err != nil { - return ctrlResult, err - } + // Append CustomServiceConfigSecrets that should be checked + secretNames = append(secretNames, instance.Spec.CustomServiceConfigSecrets...) + + ctrlResult, err = verifyConfigSecrets( + ctx, + helper, + &instance.Status.Conditions, + secretNames, + instance.Namespace, + &configVars, + ) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) @@ -783,7 +788,7 @@ func (r *CinderAPIReconciler) reconcileNormal(ctx context.Context, instance *cin condition.SeverityInfo, condition.NetworkAttachmentsReadyWaitingMessage, netAtt)) - return ctrl.Result{RequeueAfter: time.Second * 10}, nil + return cinder.ResultRequeue, fmt.Errorf("network-attachment-definition %s not found", netAtt) } instance.Status.Conditions.Set(condition.FalseCondition( condition.NetworkAttachmentsReadyCondition, @@ -871,10 +876,7 @@ func (r *CinderAPIReconciler) reconcileNormal(ctx context.Context, instance *cin err.Error())) return ctrl.Result{}, err } - ss := statefulset.NewStatefulSet( - ssDef, - time.Duration(5)*time.Second, - ) + ss := statefulset.NewStatefulSet(ssDef, cinder.ShortDuration) var ssData appsv1.StatefulSet ctrlResult, err = ss.CreateOrPatch(ctx, helper) @@ -891,9 +893,8 @@ func (r *CinderAPIReconciler) reconcileNormal(ctx context.Context, instance *cin // Wait until the data in the StatefulSet is for the current generation ssData = ss.GetStatefulSet() if ssData.Generation != ssData.Status.ObservedGeneration { - ctrlResult = ctrl.Result{RequeueAfter: time.Duration(10) * time.Second} - Log.Info(fmt.Sprintf("waiting for Statefulset %s to start reconciling", ssData.Name)) - err = nil + ctrlResult = cinder.ResultRequeue + err = fmt.Errorf("waiting for Statefulset %s to start reconciling", ssData.Name) } } @@ -1006,41 +1007,6 @@ func (r *CinderAPIReconciler) reconcileUpgrade(ctx context.Context, instance *ci return ctrl.Result{}, nil } -// getSecret - get the specified secret, and add its hash to envVars -func (r *CinderAPIReconciler) getSecret( - ctx context.Context, - h *helper.Helper, - instance *cinderv1beta1.CinderAPI, - secretName string, - envVars *map[string]env.Setter, -) (ctrl.Result, error) { - secret, hash, err := secret.GetSecret(ctx, h, secretName, instance.Namespace) - if err != nil { - if k8s_errors.IsNotFound(err) { - h.GetLogger().Info(fmt.Sprintf("Secret %s not found", secretName)) - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.RequestedReason, - condition.SeverityInfo, - condition.InputReadyWaitingMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil - } - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.ErrorReason, - condition.SeverityWarning, - condition.InputReadyErrorMessage, - err.Error())) - return ctrl.Result{}, err - } - - // Add a prefix to the var name to avoid accidental collision with other non-secret - // vars. The secret names themselves will be unique. - (*envVars)["secret-"+secret.Name] = env.SetValue(hash) - - return ctrl.Result{}, nil -} - // generateServiceConfigs - create Secret which holds the service configuration func (r *CinderAPIReconciler) generateServiceConfigs( ctx context.Context, diff --git a/controllers/cinderbackup_controller.go b/controllers/cinderbackup_controller.go index 04d7b904..f7132017 100644 --- a/controllers/cinderbackup_controller.go +++ b/controllers/cinderbackup_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -343,43 +342,49 @@ func (r *CinderBackupReconciler) reconcileNormal(ctx context.Context, instance * // // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map // - ctrlResult, err := r.getSecret(ctx, helper, instance, instance.Spec.Secret, &configVars) - if err != nil { - return ctrlResult, err - } - // - // check for required TransportURL secret holding transport URL string - // - ctrlResult, err = r.getSecret(ctx, helper, instance, instance.Spec.TransportURLSecret, &configVars) + ctrlResult, err := verifyServiceSecret( + ctx, + types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret}, + []string{ + instance.Spec.PasswordSelectors.Service, + }, + helper.GetClient(), + &instance.Status.Conditions, + cinder.NormalDuration, + &configVars, + ) if err != nil { return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } // - // check for required service secrets + // check for required Transport URL and config secrets // - for _, secretName := range instance.Spec.CustomServiceConfigSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, secretName, &configVars) - if err != nil { - return ctrlResult, err - } - } - // - // check for required Cinder secrets that should have been created by parent Cinder CR - // parentCinderName := cinder.GetOwningCinderName(instance) - parentSecrets := []string{ - fmt.Sprintf("%s-scripts", parentCinderName), - fmt.Sprintf("%s-config-data", parentCinderName), - } - - for _, parentSecret := range parentSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, parentSecret, &configVars) - if err != nil { - return ctrlResult, err - } + secretNames := []string{ + instance.Spec.TransportURLSecret, // TransportURLSecret + fmt.Sprintf("%s-scripts", parentCinderName), // ScriptsSecret + fmt.Sprintf("%s-config-data", parentCinderName), // ConfigSecret + } + // Append CustomServiceConfigSecrets that should be checked + secretNames = append(secretNames, instance.Spec.CustomServiceConfigSecrets...) + + ctrlResult, err = verifyConfigSecrets( + ctx, + helper, + &instance.Status.Conditions, + secretNames, + instance.Namespace, + &configVars, + ) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) @@ -486,7 +491,7 @@ func (r *CinderBackupReconciler) reconcileNormal(ctx context.Context, instance * condition.SeverityInfo, condition.NetworkAttachmentsReadyWaitingMessage, netAtt)) - return ctrl.Result{RequeueAfter: time.Second * 10}, nil + return cinder.ResultRequeue, fmt.Errorf("network-attachment-definition %s not found", netAtt) } instance.Status.Conditions.Set(condition.FalseCondition( condition.NetworkAttachmentsReadyCondition, @@ -540,10 +545,7 @@ func (r *CinderBackupReconciler) reconcileNormal(ctx context.Context, instance * // Deploy a statefulset ssDef := cinderbackup.StatefulSet(instance, inputHash, serviceLabels, serviceAnnotations) - ss := statefulset.NewStatefulSet( - ssDef, - time.Duration(5)*time.Second, - ) + ss := statefulset.NewStatefulSet(ssDef, cinder.ShortDuration) var ssData appsv1.StatefulSet ctrlResult, err = ss.CreateOrPatch(ctx, helper) @@ -560,9 +562,8 @@ func (r *CinderBackupReconciler) reconcileNormal(ctx context.Context, instance * // Wait until the data in the StatefulSet is for the current generation ssData = ss.GetStatefulSet() if ssData.Generation != ssData.Status.ObservedGeneration { - ctrlResult = ctrl.Result{RequeueAfter: time.Duration(10) * time.Second} - Log.Info(fmt.Sprintf("waiting for Statefulset %s to start reconciling", ssData.Name)) - err = nil + ctrlResult = cinder.ResultRequeue + err = fmt.Errorf("waiting for Statefulset %s to start reconciling", ssData.Name) } } @@ -674,41 +675,6 @@ func (r *CinderBackupReconciler) reconcileUpgrade(ctx context.Context, instance return ctrl.Result{}, nil } -// getSecret - get the specified secret, and add its hash to envVars -func (r *CinderBackupReconciler) getSecret( - ctx context.Context, - h *helper.Helper, - instance *cinderv1beta1.CinderBackup, - secretName string, - envVars *map[string]env.Setter, -) (ctrl.Result, error) { - secret, hash, err := secret.GetSecret(ctx, h, secretName, instance.Namespace) - if err != nil { - if k8s_errors.IsNotFound(err) { - h.GetLogger().Info(fmt.Sprintf("Secret %s not found", secretName)) - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.RequestedReason, - condition.SeverityInfo, - condition.InputReadyWaitingMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil - } - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.ErrorReason, - condition.SeverityWarning, - condition.InputReadyErrorMessage, - err.Error())) - return ctrl.Result{}, err - } - - // Add a prefix to the var name to avoid accidental collision with other non-secret - // vars. The secret names themselves will be unique. - (*envVars)["secret-"+secret.Name] = env.SetValue(hash) - - return ctrl.Result{}, nil -} - // generateServiceConfigs - create Secret which holds the service configuration func (r *CinderBackupReconciler) generateServiceConfigs( ctx context.Context, diff --git a/controllers/cinderscheduler_controller.go b/controllers/cinderscheduler_controller.go index 49f35444..2d0a2eec 100644 --- a/controllers/cinderscheduler_controller.go +++ b/controllers/cinderscheduler_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -342,43 +341,49 @@ func (r *CinderSchedulerReconciler) reconcileNormal(ctx context.Context, instanc // // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map // - ctrlResult, err := r.getSecret(ctx, helper, instance, instance.Spec.Secret, &configVars) - if err != nil { - return ctrlResult, err - } - // - // check for required TransportURL secret holding transport URL string - // - ctrlResult, err = r.getSecret(ctx, helper, instance, instance.Spec.TransportURLSecret, &configVars) + ctrlResult, err := verifyServiceSecret( + ctx, + types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret}, + []string{ + instance.Spec.PasswordSelectors.Service, + }, + helper.GetClient(), + &instance.Status.Conditions, + cinder.NormalDuration, + &configVars, + ) if err != nil { return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } // - // check for required service secrets + // check for required Transport URL and config secrets // - for _, secretName := range instance.Spec.CustomServiceConfigSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, secretName, &configVars) - if err != nil { - return ctrlResult, err - } - } - // - // check for required Cinder secrets that should have been created by parent Cinder CR - // parentCinderName := cinder.GetOwningCinderName(instance) - parentSecrets := []string{ - fmt.Sprintf("%s-scripts", parentCinderName), - fmt.Sprintf("%s-config-data", parentCinderName), - } - - for _, parentSecret := range parentSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, parentSecret, &configVars) - if err != nil { - return ctrlResult, err - } + secretNames := []string{ + instance.Spec.TransportURLSecret, // TransportURLSecret + fmt.Sprintf("%s-scripts", parentCinderName), // ScriptsSecret + fmt.Sprintf("%s-config-data", parentCinderName), // ConfigSecret + } + // Append CustomServiceConfigSecrets that should be checked + secretNames = append(secretNames, instance.Spec.CustomServiceConfigSecrets...) + + ctrlResult, err = verifyConfigSecrets( + ctx, + helper, + &instance.Status.Conditions, + secretNames, + instance.Namespace, + &configVars, + ) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) @@ -485,7 +490,7 @@ func (r *CinderSchedulerReconciler) reconcileNormal(ctx context.Context, instanc condition.SeverityInfo, condition.NetworkAttachmentsReadyWaitingMessage, netAtt)) - return ctrl.Result{RequeueAfter: time.Second * 10}, nil + return cinder.ResultRequeue, fmt.Errorf("network-attachment-definition %s not found", netAtt) } instance.Status.Conditions.Set(condition.FalseCondition( condition.NetworkAttachmentsReadyCondition, @@ -539,10 +544,7 @@ func (r *CinderSchedulerReconciler) reconcileNormal(ctx context.Context, instanc // Deploy a statefulset ssDef := cinderscheduler.StatefulSet(instance, inputHash, serviceLabels, serviceAnnotations) - ss := statefulset.NewStatefulSet( - ssDef, - time.Duration(5)*time.Second, - ) + ss := statefulset.NewStatefulSet(ssDef, cinder.ShortDuration) var ssData appsv1.StatefulSet ctrlResult, err = ss.CreateOrPatch(ctx, helper) @@ -559,9 +561,8 @@ func (r *CinderSchedulerReconciler) reconcileNormal(ctx context.Context, instanc // Wait until the data in the StatefulSet is for the current generation ssData = ss.GetStatefulSet() if ssData.Generation != ssData.Status.ObservedGeneration { - ctrlResult = ctrl.Result{RequeueAfter: time.Duration(10) * time.Second} - Log.Info(fmt.Sprintf("waiting for Statefulset %s to start reconciling", ssData.Name)) - err = nil + ctrlResult = cinder.ResultRequeue + err = fmt.Errorf("waiting for Statefulset %s to start reconciling", ssData.Name) } } @@ -673,41 +674,6 @@ func (r *CinderSchedulerReconciler) reconcileUpgrade(ctx context.Context, instan return ctrl.Result{}, nil } -// getSecret - get the specified secret, and add its hash to envVars -func (r *CinderSchedulerReconciler) getSecret( - ctx context.Context, - h *helper.Helper, - instance *cinderv1beta1.CinderScheduler, - secretName string, - envVars *map[string]env.Setter, -) (ctrl.Result, error) { - secret, hash, err := secret.GetSecret(ctx, h, secretName, instance.Namespace) - if err != nil { - if k8s_errors.IsNotFound(err) { - h.GetLogger().Info(fmt.Sprintf("Secret %s not found", secretName)) - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.RequestedReason, - condition.SeverityInfo, - condition.InputReadyWaitingMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil - } - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.ErrorReason, - condition.SeverityWarning, - condition.InputReadyErrorMessage, - err.Error())) - return ctrl.Result{}, err - } - - // Add a prefix to the var name to avoid accidental collision with other non-secret - // vars. The secret names themselves will be unique. - (*envVars)["secret-"+secret.Name] = env.SetValue(hash) - - return ctrl.Result{}, nil -} - // generateServiceConfigs - create Secret which holds the service configuration func (r *CinderSchedulerReconciler) generateServiceConfigs( ctx context.Context, diff --git a/controllers/cindervolume_controller.go b/controllers/cindervolume_controller.go index 64076d7a..0e996a13 100644 --- a/controllers/cindervolume_controller.go +++ b/controllers/cindervolume_controller.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "strings" - "time" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -344,43 +343,49 @@ func (r *CinderVolumeReconciler) reconcileNormal(ctx context.Context, instance * // // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map // - ctrlResult, err := r.getSecret(ctx, helper, instance, instance.Spec.Secret, &configVars) - if err != nil { - return ctrlResult, err - } - // - // check for required TransportURL secret holding transport URL string - // - ctrlResult, err = r.getSecret(ctx, helper, instance, instance.Spec.TransportURLSecret, &configVars) + ctrlResult, err := verifyServiceSecret( + ctx, + types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret}, + []string{ + instance.Spec.PasswordSelectors.Service, + }, + helper.GetClient(), + &instance.Status.Conditions, + cinder.NormalDuration, + &configVars, + ) if err != nil { return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } // - // check for required service secrets + // check for required Transport URL and config secrets // - for _, secretName := range instance.Spec.CustomServiceConfigSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, secretName, &configVars) - if err != nil { - return ctrlResult, err - } - } - // - // check for required Cinder secrets that should have been created by parent Cinder CR - // parentCinderName := cinder.GetOwningCinderName(instance) - parentSecrets := []string{ - fmt.Sprintf("%s-scripts", parentCinderName), - fmt.Sprintf("%s-config-data", parentCinderName), - } - - for _, parentSecret := range parentSecrets { - ctrlResult, err = r.getSecret(ctx, helper, instance, parentSecret, &configVars) - if err != nil { - return ctrlResult, err - } + secretNames := []string{ + instance.Spec.TransportURLSecret, // TransportURLSecret + fmt.Sprintf("%s-scripts", parentCinderName), // ScriptsSecret + fmt.Sprintf("%s-config-data", parentCinderName), // ConfigSecret + } + // Append CustomServiceConfigSecrets that should be checked + secretNames = append(secretNames, instance.Spec.CustomServiceConfigSecrets...) + + ctrlResult, err = verifyConfigSecrets( + ctx, + helper, + &instance.Status.Conditions, + secretNames, + instance.Namespace, + &configVars, + ) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) @@ -488,7 +493,7 @@ func (r *CinderVolumeReconciler) reconcileNormal(ctx context.Context, instance * condition.SeverityInfo, condition.NetworkAttachmentsReadyWaitingMessage, netAtt)) - return ctrl.Result{RequeueAfter: time.Second * 10}, nil + return cinder.ResultRequeue, fmt.Errorf("network-attachment-definition %s not found", netAtt) } instance.Status.Conditions.Set(condition.FalseCondition( condition.NetworkAttachmentsReadyCondition, @@ -542,10 +547,7 @@ func (r *CinderVolumeReconciler) reconcileNormal(ctx context.Context, instance * // Deploy a statefulset ssDef := cindervolume.StatefulSet(instance, inputHash, serviceLabels, serviceAnnotations, usesLVM) - ss := statefulset.NewStatefulSet( - ssDef, - time.Duration(5)*time.Second, - ) + ss := statefulset.NewStatefulSet(ssDef, cinder.ShortDuration) var ssData appsv1.StatefulSet ctrlResult, err = ss.CreateOrPatch(ctx, helper) @@ -562,9 +564,8 @@ func (r *CinderVolumeReconciler) reconcileNormal(ctx context.Context, instance * // Wait until the data in the StatefulSet is for the current generation ssData = ss.GetStatefulSet() if ssData.Generation != ssData.Status.ObservedGeneration { - ctrlResult = ctrl.Result{RequeueAfter: time.Duration(10) * time.Second} - Log.Info(fmt.Sprintf("waiting for Statefulset %s to start reconciling", ssData.Name)) - err = nil + ctrlResult = cinder.ResultRequeue + err = fmt.Errorf("waiting for Statefulset %s to start reconciling", ssData.Name) } } @@ -676,41 +677,6 @@ func (r *CinderVolumeReconciler) reconcileUpgrade(ctx context.Context, instance return ctrl.Result{}, nil } -// getSecret - get the specified secret, and add its hash to envVars -func (r *CinderVolumeReconciler) getSecret( - ctx context.Context, - h *helper.Helper, - instance *cinderv1beta1.CinderVolume, - secretName string, - envVars *map[string]env.Setter, -) (ctrl.Result, error) { - secret, hash, err := secret.GetSecret(ctx, h, secretName, instance.Namespace) - if err != nil { - if k8s_errors.IsNotFound(err) { - h.GetLogger().Info(fmt.Sprintf("Secret %s not found", secretName)) - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.RequestedReason, - condition.SeverityInfo, - condition.InputReadyWaitingMessage)) - return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil - } - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.ErrorReason, - condition.SeverityWarning, - condition.InputReadyErrorMessage, - err.Error())) - return ctrl.Result{}, err - } - - // Add a prefix to the var name to avoid accidental collision with other non-secret - // vars. The secret names themselves will be unique. - (*envVars)["secret-"+secret.Name] = env.SetValue(hash) - - return ctrl.Result{}, nil -} - // generateServiceConfigs - create Secret which holds the service configuration and check if it's using LVM func (r *CinderVolumeReconciler) generateServiceConfigs( ctx context.Context, diff --git a/pkg/cinder/const.go b/pkg/cinder/const.go index 560b39d1..3ac5a2c8 100644 --- a/pkg/cinder/const.go +++ b/pkg/cinder/const.go @@ -16,6 +16,10 @@ limitations under the License. package cinder import ( + "time" + + ctrl "sigs.k8s.io/controller-runtime" + "github.com/openstack-k8s-operators/lib-common/modules/storage" ) @@ -66,8 +70,13 @@ const ( // Cinder is the global ServiceType that refers to all the components deployed // by the cinder operator Cinder storage.PropagationType = "Cinder" + + ShortDuration = time.Duration(5) * time.Second + NormalDuration = time.Duration(10) * time.Second ) +var ResultRequeue = ctrl.Result{RequeueAfter: NormalDuration} + // DbsyncPropagation keeps track of the DBSync Service Propagation Type var DbsyncPropagation = []storage.PropagationType{storage.DBSync}