diff --git a/cluster-agent/controllers/argoproj.io/namespace_reconciler.go b/cluster-agent/controllers/argoproj.io/namespace_reconciler.go index df85d60d63..0c0409a38f 100644 --- a/cluster-agent/controllers/argoproj.io/namespace_reconciler.go +++ b/cluster-agent/controllers/argoproj.io/namespace_reconciler.go @@ -71,7 +71,7 @@ func (r *ApplicationReconciler) startTimerForNextCycle(ctx context.Context, name // Clean orphaned and purposeless Operation CRs from Cluster. cleanOrphanedCRsfromCluster_Operation(ctx, r.DB, r.Client, log) - // Recreate Secrets that are required by Applications, but missing from cluster. + // Recreate Secrets that are required by Applications and RepositoryCredentials, but missing from cluster. recreateClusterSecrets(ctx, r.DB, r.Client, log) log.Info(fmt.Sprintf("Namespace Reconciler finished an iteration at %s. "+ @@ -499,15 +499,16 @@ func cleanOrphanedCRsfromCluster_Operation(ctx context.Context, dbQueries db.Dat } } -// recreateClusterSecrets goes through list of ManagedEnvironments created in cluster and recreates Secrets that are missing from cluster. +// recreateClusterSecrets goes through list of ManagedEnvironments & RepositoryCredentials created in cluster and recreates Secrets that are missing from cluster. func recreateClusterSecrets(ctx context.Context, dbQueries db.DatabaseQueries, k8sClient client.Client, logger logr.Logger) { log := logger.WithValues(sharedutil.Log_JobKey, sharedutil.Log_JobKeyValue). WithValues(sharedutil.Log_JobTypeKey, "CR_Secret_recreate") - // First get list of ClusterAccess and Application entries from DB. + // First get list of ClusterAccess, Application and RepositoryCredentials entries from DB. listOfClusterAccessFromDB := getListOfClusterAccessFromTable(ctx, dbQueries, false, log) listOfApplicationFromDB := getListOfApplicationsFromTable(ctx, dbQueries, false, log) + listOfRepoCredFromDB := getListOfRepositoryCredentialsFromTable(ctx, dbQueries, false, log) // Now get list of GitopsEngineInstances from DB for the cluster service is running on. listOfGitopsEngineInstanceFromCluster, err := getListOfGitopsEngineInstancesForCurrentCluster(ctx, dbQueries, k8sClient, log) @@ -534,83 +535,150 @@ func recreateClusterSecrets(ctx context.Context, dbQueries db.DatabaseQueries, k } namespacesProcessed[instance.Namespace_uid] = nil - // Iterate through list of ClusterAccess entries from DB and find entry using current GitOpsEngineInstance. - for clusterAccessIndex := range listOfClusterAccessFromDB { + recreateClusterSecrets_ManagedEnvironments(ctx, dbQueries, k8sClient, listOfClusterAccessFromDB, listOfApplicationFromDB, instance, log) + recreateClusterSecrets_RepositoryCredentials(ctx, dbQueries, k8sClient, listOfRepoCredFromDB, instance, log) + } +} - clusterAccess := listOfClusterAccessFromDB[clusterAccessIndex] // To avoid "Implicit memory aliasing in for loop." error. +// recreateClusterSecrets_ManagedEnvironments goes through list of ManagedEnvironments created in cluster and recreates Secrets that are missing from cluster. +func recreateClusterSecrets_ManagedEnvironments(ctx context.Context, dbQueries db.DatabaseQueries, k8sClient client.Client, listOfClusterAccessFromDB []db.ClusterAccess, listOfApplicationFromDB []db.Application, instance db.GitopsEngineInstance, logger logr.Logger) { - if clusterAccess.Clusteraccess_gitops_engine_instance_id == instance.Gitopsengineinstance_id { + log := logger.WithValues(sharedutil.Log_JobKey, sharedutil.Log_JobKeyValue). + WithValues(sharedutil.Log_JobTypeKey, "CR_Secret_recreate_managedEnv") - // This ClusterAccess is using current GitOpsEngineInstance, - // now find the ManagedEnvironment using this ClusterAccess. - managedEnvironment := db.ManagedEnvironment{ - Managedenvironment_id: clusterAccess.Clusteraccess_managed_environment_id, - } + // Iterate through list of ClusterAccess entries from DB and find entry using current GitOpsEngineInstance. + for clusterAccessIndex := range listOfClusterAccessFromDB { - if err := dbQueries.GetManagedEnvironmentById(ctx, &managedEnvironment); err != nil { - log.Error(err, "Error occurred in recreateClusterSecrets while fetching ManagedEnvironment from DB.:"+managedEnvironment.Managedenvironment_id) - continue - } + clusterAccess := listOfClusterAccessFromDB[clusterAccessIndex] // To avoid "Implicit memory aliasing in for loop." error. - // Skip if ManagedEnvironment is created recently - if time.Since(managedEnvironment.Created_on) < 30*time.Minute { - continue - } + if clusterAccess.Clusteraccess_gitops_engine_instance_id == instance.Gitopsengineinstance_id { - clusterCreds := db.ClusterCredentials{ - Clustercredentials_cred_id: managedEnvironment.Clustercredentials_id, - } - if err := dbQueries.GetClusterCredentialsById(ctx, &clusterCreds); err != nil { - log.Error(err, "Error occurred in recreateClusterSecrets while retrieving ClusterCredentials:"+managedEnvironment.Clustercredentials_id) - continue - } + // This ClusterAccess is using current GitOpsEngineInstance, + // now find the ManagedEnvironment using this ClusterAccess. + managedEnvironment := db.ManagedEnvironment{ + Managedenvironment_id: clusterAccess.Clusteraccess_managed_environment_id, + } - // Skip if the cluster credentials do not have a token - // - this usually indicates that the ManagedEnvironment is on the local cluster, and thus does not require an Argo CD Cluster Secret in order to deploy - if clusterCreds.Serviceaccount_bearer_token == db.DefaultServiceaccount_bearer_token { - continue - } + if err := dbQueries.GetManagedEnvironmentById(ctx, &managedEnvironment); err != nil { + log.Error(err, "Error occurred in recreateClusterSecrets_ManagedEnvironments while fetching ManagedEnvironment from DB.:"+managedEnvironment.Managedenvironment_id) + continue + } + + // Skip if ManagedEnvironment is created recently + if time.Since(managedEnvironment.Created_on) < 30*time.Minute { + continue + } + + clusterCreds := db.ClusterCredentials{ + Clustercredentials_cred_id: managedEnvironment.Clustercredentials_id, + } + if err := dbQueries.GetClusterCredentialsById(ctx, &clusterCreds); err != nil { + log.Error(err, "Error occurred in recreateClusterSecrets while retrieving ClusterCredentials:"+managedEnvironment.Clustercredentials_id) + continue + } - // Check if Secret used for this ManagedEnvironment is present in GitOpsEngineInstance namespace. - secretName := argosharedutil.GenerateArgoCDClusterSecretName(managedEnvironment) + // Skip if the cluster credentials do not have a token + // - this usually indicates that the ManagedEnvironment is on the local cluster, and thus does not require an Argo CD Cluster Secret in order to deploy + if clusterCreds.Serviceaccount_bearer_token == db.DefaultServiceaccount_bearer_token { + continue + } - argoSecret := corev1.Secret{} - if err := k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: instance.Namespace_name}, &argoSecret); err != nil { + // Check if Secret used for this ManagedEnvironment is present in GitOpsEngineInstance namespace. + secretName := argosharedutil.GenerateArgoCDClusterSecretName(managedEnvironment) - // If Secret is not present, then create Operation to recreate the Secret. - if apierr.IsNotFound(err) { + argoSecret := corev1.Secret{} + if err := k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: instance.Namespace_name}, &argoSecret); err != nil { - log.Info("Secret: " + secretName + " not found in Namespace:" + instance.Namespace_name + ", recreating it.") + // If Secret is not present, then create Operation to recreate the Secret. + if apierr.IsNotFound(err) { - // Get Special user from DB because we need ClusterUser for creating Operation and we don't have one. - // Hence created a dummy Cluster User for internal purpose. - var specialClusterUser db.ClusterUser - if err := dbQueries.GetOrCreateSpecialClusterUser(ctx, &specialClusterUser); err != nil { - log.Error(err, "Error occurred in recreateClusterSecrets while fetching clusterUser.") - return - } + log.Info("Secret: " + secretName + " not found in Namespace:" + instance.Namespace_name + ", recreating it.") - // We need to create an Operation to recreate the Secret, which requires Application details running in current ManagedEnvironment - // hence we iterate through list of Application entries from DB to find that Application. - if ok, application := getApplicationRunningInManagedEnvironment(listOfApplicationFromDB, managedEnvironment.Managedenvironment_id); ok { + // Get Special user from DB because we need ClusterUser for creating Operation and we don't have one. + // Hence created a dummy Cluster User for internal purpose. + var specialClusterUser db.ClusterUser + if err := dbQueries.GetOrCreateSpecialClusterUser(ctx, &specialClusterUser); err != nil { + log.Error(err, "Error occurred in recreateClusterSecrets_ManagedEnvironments while fetching clusterUser.") + return + } - // We need to recreate Secret, to do that create Operation to inform Argo CD about it. - dbOperationInput := db.Operation{ - Instance_id: application.Engine_instance_inst_id, - Resource_id: application.Application_id, - Resource_type: db.OperationResourceType_Application, - } + // We need to create an Operation to recreate the Secret, which requires Application details running in current ManagedEnvironment + // hence we iterate through list of Application entries from DB to find that Application. + if ok, application := getApplicationRunningInManagedEnvironment(listOfApplicationFromDB, managedEnvironment.Managedenvironment_id); ok { - if _, _, err := operations.CreateOperation(ctx, false, dbOperationInput, specialClusterUser.Clusteruser_id, instance.Namespace_name, dbQueries, k8sClient, log); err != nil { - log.Error(err, "Error occurred in recreateClusterSecrets while creating Operation.") - continue - } + // We need to recreate Secret, to do that create Operation to inform Argo CD about it. + dbOperationInput := db.Operation{ + Instance_id: application.Engine_instance_inst_id, + Resource_id: application.Application_id, + Resource_type: db.OperationResourceType_Application, + } - log.Info("Operation " + dbOperationInput.Operation_id + " is created to create Secret: managed-env-" + managedEnvironment.Managedenvironment_id) + if _, _, err := operations.CreateOperation(ctx, false, dbOperationInput, specialClusterUser.Clusteruser_id, instance.Namespace_name, dbQueries, k8sClient, log); err != nil { + log.Error(err, "Error occurred in recreateClusterSecrets_ManagedEnvironments while creating Operation.") + continue } - } else { - log.Error(err, "Error occurred in recreateClusterSecrets while fetching Secret:"+secretName+" from Namespace: "+instance.Namespace_name) + + log.Info("Operation " + dbOperationInput.Operation_id + " is created to create Secret: managed-env-" + managedEnvironment.Managedenvironment_id) } + } else { + log.Error(err, "Error occurred in recreateClusterSecrets_ManagedEnvironments while fetching Secret:"+secretName+" from Namespace: "+instance.Namespace_name) + } + } + } + } + +} + +// recreateClusterSecrets_RepositoryCredentials goes through list of RepositoryCredentials created in cluster and recreates Secrets that are missing from cluster. +func recreateClusterSecrets_RepositoryCredentials(ctx context.Context, dbQueries db.DatabaseQueries, k8sClient client.Client, listOfRepoCredFromDB []db.RepositoryCredentials, instance db.GitopsEngineInstance, logger logr.Logger) { + + log := logger.WithValues(sharedutil.Log_JobKey, sharedutil.Log_JobKeyValue). + WithValues(sharedutil.Log_JobTypeKey, "CR_Secret_recreate_repoCred") + + // Iterate through list of RepositoryCredentials entries from DB and find entry using current GitOpsEngineInstance. + for repositoryCredentialsIndex := range listOfRepoCredFromDB { + + repositoryCredentials := listOfRepoCredFromDB[repositoryCredentialsIndex] // To avoid "Implicit memory aliasing in for loop." error. + + if repositoryCredentials.EngineClusterID == instance.Gitopsengineinstance_id { + // Skip if RepositoryCredentials is created recently + if time.Since(repositoryCredentials.Created_on) < 30*time.Minute { + continue + } + + // Check if Secret used for this RepositoryCredentials is present in GitOpsEngineInstance namespace. + argoSecret := corev1.Secret{} + + if err := k8sClient.Get(ctx, types.NamespacedName{Name: argosharedutil.GenerateArgoCDRepoCredSecretName(repositoryCredentials), Namespace: instance.Namespace_name}, &argoSecret); err != nil { + + // If Secret is not present, then create Operation to recreate the Secret. + if apierr.IsNotFound(err) { + + log.Info("Secret: " + repositoryCredentials.SecretObj + " not found in Namespace:" + instance.Namespace_name + ", recreating it.") + + // Get Special user from DB because we need ClusterUser for creating Operation and we don't have one. + // Hence created a dummy Cluster User for internal purpose. + var specialClusterUser db.ClusterUser + if err := dbQueries.GetOrCreateSpecialClusterUser(ctx, &specialClusterUser); err != nil { + log.Error(err, "Error occurred in recreateClusterSecrets_RepositoryCredentials while fetching clusterUser.") + return + } + + // We need to recreate Secret, to do that create Operation to inform Argo CD about it. + dbOperationInput := db.Operation{ + Instance_id: instance.Gitopsengineinstance_id, + Resource_id: repositoryCredentials.RepositoryCredentialsID, + Resource_type: db.OperationResourceType_RepositoryCredentials, + } + + if _, _, err := operations.CreateOperation(ctx, false, dbOperationInput, specialClusterUser.Clusteruser_id, instance.Namespace_name, dbQueries, k8sClient, log); err != nil { + log.Error(err, "Error occurred in recreateClusterSecrets_RepositoryCredentials while creating Operation.") + continue + } + + log.Info("Operation " + dbOperationInput.Operation_id + " is created to create Secret: " + repositoryCredentials.SecretObj) + } else { + log.Error(err, "Error occurred in recreateClusterSecrets_RepositoryCredentials while fetching Secret:"+repositoryCredentials.SecretObj+" from Namespace: "+instance.Namespace_name) } } } @@ -728,3 +796,38 @@ func getApplicationRunningInManagedEnvironment(applicationList []db.Application, return false, db.Application{} } + +// getListOfRepositoryCredentialsFromTable loops through RepositoryCredentials in database and returns list of user IDs. +func getListOfRepositoryCredentialsFromTable(ctx context.Context, dbQueries db.DatabaseQueries, skipDelay bool, log logr.Logger) []db.RepositoryCredentials { + + offSet := 0 + var listOfRepositoryCredentialsFromDB []db.RepositoryCredentials + + // Continuously iterate and fetch batches until all entries of table processed. + for { + if offSet != 0 && !skipDelay { + time.Sleep(sleepIntervalsOfBatches) + } + + var tempList []db.RepositoryCredentials + + // Fetch ClusterAccess table entries in batch size as configured above.​ + if err := dbQueries.GetRepositoryCredentialsBatch(ctx, &tempList, appRowBatchSize, offSet); err != nil { + log.Error(err, fmt.Sprintf("Error occurred in cleanOrphanedEntriesfromTable_ClusterUser while fetching batch from Offset: %d to %d: ", + offSet, offSet+appRowBatchSize)) + break + } + + // Break the loop if no entries are left in table to be processed. + if len(tempList) == 0 { + break + } + + listOfRepositoryCredentialsFromDB = append(listOfRepositoryCredentialsFromDB, tempList...) + + // Skip processed entries in next iteration + offSet += appRowBatchSize + } + + return listOfRepositoryCredentialsFromDB +} diff --git a/cluster-agent/controllers/argoproj.io/namespace_reconciler_test.go b/cluster-agent/controllers/argoproj.io/namespace_reconciler_test.go index 0ae48fe274..5bc6814175 100644 --- a/cluster-agent/controllers/argoproj.io/namespace_reconciler_test.go +++ b/cluster-agent/controllers/argoproj.io/namespace_reconciler_test.go @@ -750,17 +750,17 @@ var _ = Describe("Namespace Reconciler Tests.", func() { }) }) - Context("Testing for recreateClusterSecrets function.", func() { + Context("Testing for recreateClusterSecrets function for ManagedEnvironments.", func() { var log logr.Logger var ctx context.Context var secret corev1.Secret + var operation []db.Operation var application db.Application var dbq db.AllDatabaseQueries var k8sClient client.WithWatch var kubeSystemNamepace corev1.Namespace var managedEnvironment db.ManagedEnvironment - var clusterAccess db.ClusterAccess BeforeEach(func() { @@ -776,8 +776,7 @@ var _ = Describe("Namespace Reconciler Tests.", func() { scheme, _, _, _, err := tests.GenericTestSetup() Expect(err).ToNot(HaveOccurred()) - err = appv1.AddToScheme(scheme) - Expect(err).ToNot(HaveOccurred()) + Expect(appv1.AddToScheme(scheme)).To(Succeed()) By("Create fake kube client.") @@ -791,8 +790,7 @@ var _ = Describe("Namespace Reconciler Tests.", func() { UID: "test-" + uuid.NewUUID(), }, } - err = k8sClient.Create(ctx, &kubeSystemNamepace) - Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient.Create(ctx, &kubeSystemNamepace)).To(Succeed()) By("Create GitopsEngineCluster.") @@ -811,8 +809,7 @@ var _ = Describe("Namespace Reconciler Tests.", func() { Serviceaccount_bearer_token: "fake service account bearer token", Serviceaccount_ns: "Serviceaccount_ns", } - err = dbq.CreateClusterCredentials(ctx, &clusterCredentials) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.CreateClusterCredentials(ctx, &clusterCredentials)).To(Succeed()) By("Create ManagedEnvironment entry in DB.") @@ -821,8 +818,7 @@ var _ = Describe("Namespace Reconciler Tests.", func() { Clustercredentials_id: clusterCredentials.Clustercredentials_cred_id, Name: "my env", } - err = dbq.CreateManagedEnvironment(ctx, &managedEnvironment) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.CreateManagedEnvironment(ctx, &managedEnvironment)).To(Succeed()) By("Create GitopsEngineInstance entry in DB.") @@ -832,8 +828,7 @@ var _ = Describe("Namespace Reconciler Tests.", func() { Namespace_uid: "test-ns-" + string(uuid.NewUUID()), EngineCluster_id: gitopsEngineCluster.Gitopsenginecluster_id, } - err = dbq.CreateGitopsEngineInstance(ctx, &gitopsEngineInstance) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.CreateGitopsEngineInstance(ctx, &gitopsEngineInstance)).To(Succeed()) By("Create Application entry in DB.") @@ -844,8 +839,7 @@ var _ = Describe("Namespace Reconciler Tests.", func() { Engine_instance_inst_id: gitopsEngineInstance.Gitopsengineinstance_id, Managed_environment_id: managedEnvironment.Managedenvironment_id, } - err = dbq.CreateApplication(ctx, &application) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.CreateApplication(ctx, &application)).To(Succeed()) By("Create ClusterAccess entry in DB.") @@ -854,8 +848,7 @@ var _ = Describe("Namespace Reconciler Tests.", func() { Clusteraccess_managed_environment_id: managedEnvironment.Managedenvironment_id, Clusteraccess_gitops_engine_instance_id: gitopsEngineInstance.Gitopsengineinstance_id, } - err = dbq.CreateClusterAccess(ctx, &clusterAccess) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.CreateClusterAccess(ctx, &clusterAccess)).To(Succeed()) By("Create Secret CR definition.") @@ -865,19 +858,18 @@ var _ = Describe("Namespace Reconciler Tests.", func() { Namespace: gitopsEngineInstance.Namespace_name, }, } - }) - - It("Should not create Operation for Secret, even if it is missing in Cluster, since ManagedEnvironment is created recently.", func() { - - defer dbq.CloseDatabase() By("Get list of Operations before calling function.") - var operation []db.Operation - - err := dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName)).To(Succeed()) Expect(operation).To(BeEmpty()) + }) + + AfterEach(func() { + defer dbq.CloseDatabase() + }) + + It("Should not create Operation for Secret, even if it is missing in Cluster, since ManagedEnvironment is created recently.", func() { By("Call function to recreate Secret if missing from cluster.") @@ -885,33 +877,20 @@ var _ = Describe("Namespace Reconciler Tests.", func() { By("Get list of Operations after calling function.") - err = dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName)).To(Succeed()) Expect(operation).To(BeEmpty()) }) It("Should not create Operation for Secret, since it is already present in Cluster.", func() { - defer dbq.CloseDatabase() - By("Set 'Created_on' field more than 30 Minutes.") managedEnvironment.Created_on = time.Now().Add(time.Duration(-(31 * time.Minute))) - err := dbq.UpdateManagedEnvironment(ctx, &managedEnvironment) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.UpdateManagedEnvironment(ctx, &managedEnvironment)).To(Succeed()) By("Create Secret CR in cluster.") - err = k8sClient.Create(ctx, &secret) - Expect(err).ToNot(HaveOccurred()) - - By("Get list of Operations before calling function.") - - var operation []db.Operation - - err = dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName) - Expect(err).ToNot(HaveOccurred()) - Expect(operation).To(BeEmpty()) + Expect(k8sClient.Create(ctx, &secret)).To(Succeed()) By("Call function to recreate Secret if missing from cluster.") @@ -919,27 +898,17 @@ var _ = Describe("Namespace Reconciler Tests.", func() { By("Get list of Operations after calling function.") - err = dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName) - Expect(err).ToNot(HaveOccurred()) + Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName)).To(Succeed()) Expect(operation).To(BeEmpty()) }) It("Should create Operation to recreate Secret, since it is not present in Cluster.", func() { - defer dbq.CloseDatabase() - By("Set 'Created_on' field more than 30 Minutes.") managedEnvironment.Created_on = time.Now().Add(time.Duration(-(31 * time.Minute))) Expect(dbq.UpdateManagedEnvironment(ctx, &managedEnvironment)).To(Succeed()) - By("Get list of Operations before calling function.") - - var operation []db.Operation - - Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName)).To(Succeed()) - Expect(operation).To(BeEmpty()) - By("Call function to recreate Secret if missing from cluster.") recreateClusterSecrets(ctx, dbq, k8sClient, log) @@ -974,12 +943,120 @@ var _ = Describe("Namespace Reconciler Tests.", func() { managedEnvironment.Created_on = time.Now().Add(time.Duration(-(31 * time.Minute))) Expect(dbq.UpdateManagedEnvironment(ctx, &managedEnvironment)).To(Succeed()) - By("Get list of Operations before calling function.") + By("Call function to recreate Secret if missing from cluster.") + + recreateClusterSecrets(ctx, dbq, k8sClient, log) - var operation []db.Operation + By("Get list of Operations after calling function.") Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName)).To(Succeed()) + Expect(operation).To(BeEmpty(), "no operations should have been created, because the managed environment's cluster credential has a default value in the Serviceaccount_bearer_token field. In this case, an Argo CD Cluster Secret does not need to exist, because Argo CD always has the ability to deploy to the local cluster.") + }) + }) + + Context("Testing for recreateClusterSecrets function for RepositoryCredentials.", func() { + + var log logr.Logger + var ctx context.Context + var secret corev1.Secret + var operation []db.Operation + var dbq db.AllDatabaseQueries + var k8sClient client.WithWatch + var kubeSystemNamepace corev1.Namespace + var repositoryCredentials db.RepositoryCredentials + + BeforeEach(func() { + err := db.SetupForTestingDBGinkgo() + Expect(err).ToNot(HaveOccurred()) + + ctx = context.Background() + log = logger.FromContext(ctx) + + dbq, err = db.NewUnsafePostgresDBQueries(true, true) + Expect(err).ToNot(HaveOccurred()) + + scheme, _, _, _, err := tests.GenericTestSetup() + Expect(err).ToNot(HaveOccurred()) + + Expect(appv1.AddToScheme(scheme)).To(Succeed()) + + By("Create fake kube client.") + + k8sClient = fake.NewClientBuilder().WithScheme(scheme).Build() + + By("Create kube-system namespace.") + + kubeSystemNamepace = corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-system", + UID: "test-" + uuid.NewUUID(), + }, + } + Expect(k8sClient.Create(ctx, &kubeSystemNamepace)).To(Succeed()) + + By("Create GitopsEngineCluster.") + + gitopsEngineCluster, created, err := dbutil.GetOrCreateGitopsEngineClusterByKubeSystemNamespaceUID(ctx, string(kubeSystemNamepace.UID), dbq, log) + Expect(err).ToNot(HaveOccurred()) + Expect(gitopsEngineCluster).ToNot(BeNil()) + Expect(created).To(BeTrue()) + + By("Create ClusterCredentials entry in DB.") + + clusterCredentials := db.ClusterCredentials{ + Clustercredentials_cred_id: "test-creds-" + string(uuid.NewUUID()), + Host: "host", + Kube_config: "kube-config", + Kube_config_context: "kube-config-context", + Serviceaccount_bearer_token: "serviceaccount_bearer_token", + Serviceaccount_ns: "Serviceaccount_ns", + } + Expect(dbq.CreateClusterCredentials(ctx, &clusterCredentials)).To(Succeed()) + + By("Create GitopsEngineInstance entry in DB.") + + gitopsEngineInstance := db.GitopsEngineInstance{ + Gitopsengineinstance_id: "test-id" + string(uuid.NewUUID()), + Namespace_name: "test-ns-" + string(uuid.NewUUID()), + Namespace_uid: "test-ns-" + string(uuid.NewUUID()), + EngineCluster_id: gitopsEngineCluster.Gitopsenginecluster_id, + } + Expect(dbq.CreateGitopsEngineInstance(ctx, &gitopsEngineInstance)).To(Succeed()) + + By("Create RepositoryCredentials entry in DB.") + + repositoryCredentials = db.RepositoryCredentials{ + RepositoryCredentialsID: "test-repo-" + string(uuid.NewUUID()), + UserID: "test-user", + PrivateURL: "https://test-private-url", + AuthUsername: "test-auth-username", + AuthPassword: "test-auth-password", + AuthSSHKey: "test-auth-ssh-key", + SecretObj: "test-secret-obj", + EngineClusterID: gitopsEngineInstance.Gitopsengineinstance_id, + } + Expect(dbq.CreateRepositoryCredentials(ctx, &repositoryCredentials)).To(Succeed()) + + By("Create Secret CR definition.") + + secret = corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: argosharedutil.GenerateArgoCDRepoCredSecretName(repositoryCredentials), + Namespace: gitopsEngineInstance.Namespace_name, + }, + } + + By("Get list of Operations before calling function.") + + Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, repositoryCredentials.RepositoryCredentialsID, db.OperationResourceType_RepositoryCredentials, &operation, db.SpecialClusterUserName)).To(Succeed()) Expect(operation).To(BeEmpty()) + }) + + AfterEach(func() { + defer dbq.CloseDatabase() + }) + + It("Should not create Operation for Secret, even if it is missing in Cluster, since RepositoryCredentials is created recently.", func() { By("Call function to recreate Secret if missing from cluster.") @@ -987,8 +1064,46 @@ var _ = Describe("Namespace Reconciler Tests.", func() { By("Get list of Operations after calling function.") - Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, application.Application_id, db.OperationResourceType_Application, &operation, db.SpecialClusterUserName)).To(Succeed()) - Expect(operation).To(BeEmpty(), "no operations should have been created, because the managed environment's cluster credential has a default value in the Serviceaccount_bearer_token field. In this case, an Argo CD Cluster Secret does not need to exist, because Argo CD always has the ability to deploy to the local cluster.") + Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, repositoryCredentials.RepositoryCredentialsID, db.OperationResourceType_RepositoryCredentials, &operation, db.SpecialClusterUserName)).To(Succeed()) + Expect(operation).To(BeEmpty()) + }) + + It("Should not create Operation for Secret, since it is already present in Cluster.", func() { + + By("Set 'Created_on' field more than 30 Minutes.") + + repositoryCredentials.Created_on = time.Now().Add(time.Duration(-(31 * time.Minute))) + Expect(dbq.UpdateRepositoryCredentials(ctx, &repositoryCredentials)).To(Succeed()) + + By("Create Secret CR in cluster.") + + Expect(k8sClient.Create(ctx, &secret)).To(Succeed()) + + By("Call function to recreate Secret if missing from cluster.") + + recreateClusterSecrets(ctx, dbq, k8sClient, log) + + By("Get list of Operations after calling function.") + + Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, repositoryCredentials.RepositoryCredentialsID, db.OperationResourceType_RepositoryCredentials, &operation, db.SpecialClusterUserName)).To(Succeed()) + Expect(operation).To(BeEmpty()) + }) + + It("Should create Operation to recreate Secret, since it is not present in Cluster.", func() { + + By("Set 'Created_on' field more than 30 Minutes.") + + repositoryCredentials.Created_on = time.Now().Add(time.Duration(-(31 * time.Minute))) + Expect(dbq.UpdateRepositoryCredentials(ctx, &repositoryCredentials)).To(Succeed()) + + By("Call function to recreate Secret if missing from cluster.") + + recreateClusterSecrets(ctx, dbq, k8sClient, log) + + By("Get list of Operations after calling function.") + + Expect(dbq.ListOperationsByResourceIdAndTypeAndOwnerId(ctx, repositoryCredentials.RepositoryCredentialsID, db.OperationResourceType_RepositoryCredentials, &operation, db.SpecialClusterUserName)).To(Succeed()) + Expect(operation).To(HaveLen(1)) }) }) })