diff --git a/controllers/che/checluster_controller.go b/controllers/che/checluster_controller.go index 6c8cd865fd..1cb521a945 100644 --- a/controllers/che/checluster_controller.go +++ b/controllers/che/checluster_controller.go @@ -102,8 +102,8 @@ func NewReconciler( reconcileManager := deploy.NewReconcileManager() // order does matter - reconcileManager.RegisterReconciler(migration.NewMigrator()) if !util.IsTestMode() { + reconcileManager.RegisterReconciler(migration.NewMigrator()) reconcileManager.RegisterReconciler(NewCheClusterValidator()) } reconcileManager.RegisterReconciler(imagepuller.NewImagePuller()) diff --git a/pkg/deploy/migration/on-reconcile-one-time-migration.go b/pkg/deploy/migration/on-reconcile-one-time-migration.go index bf6f49b103..ceb3f22aa7 100644 --- a/pkg/deploy/migration/on-reconcile-one-time-migration.go +++ b/pkg/deploy/migration/on-reconcile-one-time-migration.go @@ -16,9 +16,10 @@ import ( "time" "github.com/eclipse-che/che-operator/pkg/deploy" - corev1 "k8s.io/api/core/v1" + "github.com/eclipse-che/che-operator/pkg/util" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -44,9 +45,7 @@ func (m *Migrator) Reconcile(ctx *deploy.DeployContext) (reconcile.Result, bool, } result, done, err := m.migrate(ctx) - if done && err == nil { - m.migrationDone = true - } + m.migrationDone = done && err == nil return result, done, err } @@ -55,41 +54,138 @@ func (m *Migrator) Finalize(ctx *deploy.DeployContext) error { } func (m *Migrator) migrate(ctx *deploy.DeployContext) (reconcile.Result, bool, error) { - // Add required labels for the config map with additional CA certificates + if err := addRequiredLabelsForConfigMaps(ctx); err != nil { + return reconcile.Result{}, false, err + } + + if err := addRequiredLabelsForSecrets(ctx); err != nil { + return reconcile.Result{}, false, err + } + + // Give some time for the migration resources to be flushed + return reconcile.Result{RequeueAfter: 5 * time.Second}, true, nil +} + +// addRequiredLabelsForConfigMaps processes the following cofig maps: +// - 'che-git-self-signed-cert' if spec.server.gitSelfSignedCert is set to true +// - spec.server.serverTrustStoreConfigMapName (legacy way to add trusted CA certificates) +func addRequiredLabelsForConfigMaps(ctx *deploy.DeployContext) error { + // Legacy config map with additional CA certificates if ctx.CheCluster.Spec.Server.ServerTrustStoreConfigMapName != "" { - if err := addRequiredLabelsForConfigMap(ctx, ctx.CheCluster.Spec.Server.ServerTrustStoreConfigMapName, deploy.CheCACertsConfigMapLabelValue); err != nil { - return reconcile.Result{}, false, err + if err := addRequiredLabelsForObject(ctx, ctx.CheCluster.Spec.Server.ServerTrustStoreConfigMapName, deploy.CheCACertsConfigMapLabelValue); err != nil { + return err } } - // Add required labels for the config map with CA certificates for git + // Config map with CA certificates for git if ctx.CheCluster.Spec.Server.GitSelfSignedCert { - if err := addRequiredLabelsForConfigMap(ctx, gitSelfSignedCertsConfigMapName, deploy.CheCACertsConfigMapLabelValue); err != nil { - return reconcile.Result{}, false, err + if err := addRequiredLabelsForObject(ctx, gitSelfSignedCertsConfigMapName, deploy.CheCACertsConfigMapLabelValue); err != nil { + return err } } - // Give some time for the migration resources to be flushed - return reconcile.Result{RequeueAfter: 5 * time.Second}, true, nil + return nil +} + +// addRequiredLabelsForSecrets processes the following secrets: +// - spec.k8s.tlsSecretName +// - 'self-signed-certificate' secret +// - spec.server.cheHostTLSSecret +// - spec.server.proxySecret +// - spec.database.chePostgresSecret +// - spec.auth.identityProviderSecret +// - spec.auth.identityProviderPostgresSecret +// - spec.auth.oAuthSecret +// Note, most of the secrets above are autogenerated and do not require any migraation, +// but to handle the case when some were created manually, the check is done here. +func addRequiredLabelsForSecrets(ctx *deploy.DeployContext) error { + if !util.IsOpenShift { + // Kubernetes only + + tlsSecretName := "che-tls" + if ctx.CheCluster.Spec.K8s.TlsSecretName != "" { + tlsSecretName = ctx.CheCluster.Spec.K8s.TlsSecretName + } + if err := addRequiredLabelsForObject(ctx, tlsSecretName, cheFlavor); err != nil { + return err + } + } + + // TLS + if err := addRequiredLabelsForObject(ctx, deploy.CheTLSSelfSignedCertificateSecretName, cheFlavor); err != nil { + return err + } + + if ctx.CheCluster.Spec.Server.CheHostTLSSecret != "" { + if err := addRequiredLabelsForObject(ctx, ctx.CheCluster.Spec.Server.CheHostTLSSecret, cheFlavor); err != nil { + return err + } + } + + // Proxy credentials + if ctx.CheCluster.Spec.Server.ProxySecret != "" { + if err := addRequiredLabelsForObject(ctx, ctx.CheCluster.Spec.Server.ProxySecret, cheFlavor); err != nil { + return err + } + } + + // Database credentials + if ctx.CheCluster.Spec.Database.ChePostgresSecret != "" { + if err := addRequiredLabelsForObject(ctx, ctx.CheCluster.Spec.Database.ChePostgresSecret, cheFlavor); err != nil { + return err + } + } + + // Keycloak related secrets + if ctx.CheCluster.Spec.Auth.IdentityProviderSecret != "" { + if err := addRequiredLabelsForObject(ctx, ctx.CheCluster.Spec.Auth.IdentityProviderSecret, cheFlavor); err != nil { + return err + } + } + + if ctx.CheCluster.Spec.Auth.IdentityProviderPostgresSecret != "" { + if err := addRequiredLabelsForObject(ctx, ctx.CheCluster.Spec.Auth.IdentityProviderPostgresSecret, cheFlavor); err != nil { + return err + } + } + + // OAuth + if ctx.CheCluster.Spec.Auth.OAuthSecret != "" { + if err := addRequiredLabelsForObject(ctx, ctx.CheCluster.Spec.Auth.OAuthSecret, cheFlavor); err != nil { + return err + } + } + + return nil } -func addRequiredLabelsForConfigMap(ctx *deploy.DeployContext, configMapName string, componentName string) error { - configMap := &corev1.ConfigMap{} - err := ctx.ClusterAPI.NonCachingClient.Get(context.TODO(), types.NamespacedName{Namespace: ctx.CheCluster.Namespace, Name: configMapName}, configMap) +func addRequiredLabelsForObject(ctx *deploy.DeployContext, objectName string, componentName string) error { + // Check if the object is already migrated + var obj client.Object + if exists, _ := deploy.GetNamespacedObject(ctx, objectName, obj); exists { + // Default client sees the object in cache, no need in adding labels + return nil + } + + err := ctx.ClusterAPI.NonCachingClient.Get(context.TODO(), types.NamespacedName{Namespace: ctx.CheCluster.Namespace, Name: objectName}, obj) if err != nil { if errors.IsNotFound(err) { + // The object doesn't exist in cluster, nothing to do return nil } return err } - if configMap.ObjectMeta.Labels == nil { - configMap.ObjectMeta.Labels = make(map[string]string) + // Add required labels to the object + labels := obj.GetLabels() + if labels == nil { + labels = make(map[string]string) } for labelName, labelValue := range deploy.GetLabels(ctx.CheCluster, componentName) { - configMap.ObjectMeta.Labels[labelName] = labelValue + labels[labelName] = labelValue } - if err := ctx.ClusterAPI.NonCachingClient.Update(context.TODO(), configMap); err != nil { + obj.SetLabels(labels) + if err := ctx.ClusterAPI.NonCachingClient.Update(context.TODO(), obj); err != nil { return err } diff --git a/pkg/deploy/tls.go b/pkg/deploy/tls.go index 3be2d28be3..dc65c62869 100644 --- a/pkg/deploy/tls.go +++ b/pkg/deploy/tls.go @@ -328,8 +328,6 @@ func K8sHandleCheTLSSecrets(deployContext *DeployContext) (reconcile.Result, err return reconcile.Result{RequeueAfter: time.Second}, err } - requiredLabels := GetLabels(deployContext.CheCluster, cheTLSSecretName) - // Check if a job is already running for TLS secrets creation if jobExists { if job.Status.Succeeded == 0 && job.Status.Failed == 0 { @@ -339,39 +337,6 @@ func K8sHandleCheTLSSecrets(deployContext *DeployContext) (reconcile.Result, err // Secrets are ready, restart reconcilation loop return reconcile.Result{}, nil } - } else { - // Handle case when the secret(s) exists, but miss the required labels - err = deployContext.ClusterAPI.NonCachingClient.Get(context.TODO(), cheTLSSecretNamespacedName, cheTLSSecret) - if err == nil { - // Che TLS secret exists, add required labels - addLabelsToSecret(requiredLabels, cheTLSSecret) - err := deployContext.ClusterAPI.NonCachingClient.Update(context.TODO(), cheTLSSecret) - if err == nil { - // Try to do the same for CA certifaicete if any - cheTLSSelfSignedCertificateSecret := &corev1.Secret{} - err = deployContext.ClusterAPI.NonCachingClient.Get(context.TODO(), CheTLSSelfSignedCertificateSecretNamespacedName, cheTLSSelfSignedCertificateSecret) - if err == nil { - // CA certifaicete secret exists, add required labels - addLabelsToSecret(requiredLabels, cheTLSSelfSignedCertificateSecret) - err = deployContext.ClusterAPI.NonCachingClient.Update(context.TODO(), cheTLSSelfSignedCertificateSecret) - return reconcile.Result{RequeueAfter: time.Second}, err - } else if !errors.IsNotFound(err) { - // Error reading CA certificate secret - logrus.Errorf("Error getting Che self-signed certificate secert \"%s\": %v", CheTLSSelfSignedCertificateSecretName, err) - return reconcile.Result{RequeueAfter: time.Second}, err - } - // Che self-signed CA certificate secert doesn't exists. - // Consider, that a commonly trusted TLS certificate is used. - return reconcile.Result{}, nil - } else { - // Failed to update Che TLS secret with the required labels - return reconcile.Result{RequeueAfter: time.Second}, err - } - } else if !errors.IsNotFound(err) { - // Error reading Che TLS secret info - logrus.Errorf("Error getting Che TLS secert \"%s\": %v", cheTLSSecretName, err) - return reconcile.Result{RequeueAfter: time.Second}, err - } } // Che TLS secret doesn't exist, generate a new one @@ -416,7 +381,7 @@ func K8sHandleCheTLSSecrets(deployContext *DeployContext) (reconcile.Result, err } labels := "" - for labelName, labelValue := range requiredLabels { + for labelName, labelValue := range GetLabels(deployContext.CheCluster, cheTLSSecretName) { labels += fmt.Sprintf("%s=%s ", labelName, labelValue) }