From bbc275c6b1d639c944180898a5c6921ef8d0b573 Mon Sep 17 00:00:00 2001 From: diptiranjan Date: Thu, 7 Sep 2023 23:16:22 +0530 Subject: [PATCH 1/3] PWX-33569: Creating backuplocation in dest namespace while creating unidirectional clusterpair. --- pkg/migration/controllers/clusterpair.go | 8 +-- pkg/storkctl/clusterpair.go | 69 ++++++++++++------------ 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/pkg/migration/controllers/clusterpair.go b/pkg/migration/controllers/clusterpair.go index cf48474e1d..ccaeb19767 100644 --- a/pkg/migration/controllers/clusterpair.go +++ b/pkg/migration/controllers/clusterpair.go @@ -229,9 +229,6 @@ func (c *ClusterPairController) cleanup(clusterPair *stork_api.ClusterPair) erro } } } - if !skipDelete && clusterPair.Status.RemoteStorageID != "" { - return c.volDriver.DeletePair(clusterPair) - } // Delete the backuplocation and secret associated with clusterpair as part of the delete if backuplocationName, ok := clusterPair.Spec.Options["backuplocation"]; ok { @@ -259,6 +256,11 @@ func (c *ClusterPairController) cleanup(clusterPair *stork_api.ClusterPair) erro } } } + + if !skipDelete && clusterPair.Status.RemoteStorageID != "" { + return c.volDriver.DeletePair(clusterPair) + } + return nil } diff --git a/pkg/storkctl/clusterpair.go b/pkg/storkctl/clusterpair.go index b45c1e36fd..125eca4e66 100644 --- a/pkg/storkctl/clusterpair.go +++ b/pkg/storkctl/clusterpair.go @@ -550,34 +550,6 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions return } printMsg(fmt.Sprintf("ClusterPair %s created successfully. Direction Source -> Destination\n", clusterPairName), ioStreams.Out) - - if unidirectional { - return - } - - sIP, sPort := getHostPortFromEndPoint(sEP, ioStreams) - - if len(srcToken) == 0 { - pxAuthTokenSrc, pxAuthSecretNamespaceSrc, err = getPXAuthToken(sFile) - if err != nil { - printMsg(fmt.Sprintf("Got error while fetching px auth token in source cluster: %v", err), ioStreams.Out) - } - if len(pxAuthTokenSrc) > 0 { - printMsg("Fetching px token with auth token in source cluster", ioStreams.Out) - } - token, err := getPXToken(sEP, pxAuthTokenSrc) - if err != nil { - err := fmt.Errorf("got error while fetching px token in source cluster %s. Err: %v", sEP, err) - util.CheckErr(err) - return - } - srcToken = token - } - destClusterPair, err := generateClusterPair(clusterPairName, cmdFactory.GetNamespace(), sIP, sPort, srcToken, sFile, projectMappingsStr, pxAuthSecretNamespaceSrc, true, false) - if err != nil { - util.CheckErr(err) - return - } // Create cluster-pair on dest cluster conf, err = getConfig(dFile).ClientConfig() if err != nil { @@ -586,7 +558,6 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions } storkops.Instance().SetConfig(conf) core.Instance().SetConfig(conf) - if len(cmdFactory.GetNamespace()) > 0 { err = createNamespace(dFile, cmdFactory.GetNamespace()) if err != nil { @@ -608,14 +579,40 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions } printMsg(fmt.Sprintf("ObjectstoreLocation %v created on destination cluster in namespace %v\n", clusterPairName, cmdFactory.GetNamespace()), ioStreams.Out) - printMsg("Creating a cluster pair. Direction: Destination -> Source", ioStreams.Out) - destClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = backupLocation.Name - _, err = storkops.Instance().CreateClusterPair(destClusterPair) - if err != nil { - util.CheckErr(err) - return + if !unidirectional { + sIP, sPort := getHostPortFromEndPoint(sEP, ioStreams) + + if len(srcToken) == 0 { + pxAuthTokenSrc, pxAuthSecretNamespaceSrc, err = getPXAuthToken(sFile) + if err != nil { + printMsg(fmt.Sprintf("Got error while fetching px auth token in source cluster: %v", err), ioStreams.Out) + } + if len(pxAuthTokenSrc) > 0 { + printMsg("Fetching px token with auth token in source cluster", ioStreams.Out) + } + token, err := getPXToken(sEP, pxAuthTokenSrc) + if err != nil { + err := fmt.Errorf("got error while fetching px token in source cluster %s. Err: %v", sEP, err) + util.CheckErr(err) + return + } + srcToken = token + } + destClusterPair, err := generateClusterPair(clusterPairName, cmdFactory.GetNamespace(), sIP, sPort, srcToken, sFile, projectMappingsStr, pxAuthSecretNamespaceSrc, true, false) + if err != nil { + util.CheckErr(err) + return + } + + printMsg("Creating a cluster pair. Direction: Destination -> Source", ioStreams.Out) + destClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = backupLocation.Name + _, err = storkops.Instance().CreateClusterPair(destClusterPair) + if err != nil { + util.CheckErr(err) + return + } + printMsg(fmt.Sprintf("Cluster pair %s created successfully. Direction: Destination -> Source", clusterPairName), ioStreams.Out) } - printMsg(fmt.Sprintf("Cluster pair %s created successfully. Direction: Destination -> Source", clusterPairName), ioStreams.Out) }, } From 3133788a56c228eb0d380de762efdbc0dc3d7b1c Mon Sep 17 00:00:00 2001 From: diptiranjan Date: Mon, 11 Sep 2023 13:10:45 +0530 Subject: [PATCH 2/3] Additional changes for supporting "--use-existing-backuplocation". --- pkg/storkctl/clusterpair.go | 296 +++++++++++++++++++++--------------- 1 file changed, 171 insertions(+), 125 deletions(-) diff --git a/pkg/storkctl/clusterpair.go b/pkg/storkctl/clusterpair.go index 125eca4e66..600e08e79a 100644 --- a/pkg/storkctl/clusterpair.go +++ b/pkg/storkctl/clusterpair.go @@ -254,6 +254,7 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions var syncDR bool var pxAuthTokenSrc, pxAuthSecretNamespaceSrc string var pxAuthTokenDest, pxAuthSecretNamespaceDest string + var backupLocationName string var unidirectional bool createClusterPairCommand := &cobra.Command{ @@ -370,84 +371,20 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions } //Handling the asyncDR cases here onwards - // create backuplocation in source - backupLocation := &storkv1.BackupLocation{ - ObjectMeta: meta.ObjectMeta{ - Name: clusterPairName, - Namespace: cmdFactory.GetNamespace(), - Annotations: map[string]string{ - skipResourceAnnotation: "true", - storkCreatedAnnotation: "true", - }, - }, - Location: storkv1.BackupLocationItem{}, - } - // create backuplocation secrets in both source and destination - credentialData := make(map[string][]byte) - switch provider { - case "s3": - if s3AccessKey == "" { - util.CheckErr(getMissingParameterError("s3-access-key", "Access Key missing for S3")) - return - } - if s3SecretKey == "" { - util.CheckErr(getMissingParameterError("s3-secret-key", "Secret Key missing for S3")) - return - } - if len(s3EndPoint) == 0 { - util.CheckErr(getMissingParameterError("s3-endpoint", "Endpoint missing for S3")) - return - } - if len(s3Region) == 0 { - util.CheckErr(getMissingParameterError("s3-region", "Region missing for S3")) - return - } - credentialData["endpoint"] = []byte(s3EndPoint) - credentialData["accessKeyID"] = []byte(s3AccessKey) - credentialData["secretAccessKey"] = []byte(s3SecretKey) - credentialData["region"] = []byte(s3Region) - credentialData["disableSSL"] = []byte(strconv.FormatBool(disableSSL)) - backupLocation.Location.Type = storkv1.BackupLocationS3 - case "azure": - if azureAccountName == "" { - util.CheckErr(getMissingParameterError("azure-account-name", "Account Name missing for Azure")) - return - } - if azureAccountKey == "" { - util.CheckErr(getMissingParameterError("azure-account-key", "Account Key missing for Azure")) - return - } - credentialData["storageAccountName"] = []byte(azureAccountName) - credentialData["storageAccountKey"] = []byte(azureAccountKey) - backupLocation.Location.Type = storkv1.BackupLocationAzure - case "google": - if len(googleProjectID) == 0 { - util.CheckErr(getMissingParameterError("google-project-id", "Project ID missing for Google")) - return - } - if len(googleJSONKey) == 0 { - util.CheckErr(getMissingParameterError("google-key-file-path", "Json key file path missing for Google")) + if len(cmdFactory.GetNamespace()) > 0 { + err = createNamespace(sFile, cmdFactory.GetNamespace()) + if err != nil { + util.CheckErr(fmt.Errorf("error in creating namespace %s in source cluster: %v", cmdFactory.GetNamespace(), err)) return } - // Read the jsonkey file - keyData, err := os.ReadFile(googleJSONKey) + err = createNamespace(dFile, cmdFactory.GetNamespace()) if err != nil { - util.CheckErr(fmt.Errorf("failed to read json key file: %v", err)) + util.CheckErr(fmt.Errorf("error in creating namespace %s in destination cluster: %v", cmdFactory.GetNamespace(), err)) return } - credentialData["accountKey"] = keyData - credentialData["projectID"] = []byte(googleProjectID) - backupLocation.Location.Type = storkv1.BackupLocationGoogle - default: - util.CheckErr(getMissingParameterError("provider", "External objectstore provider needs to be either of azure, google, s3")) - return } - credentialData["path"] = []byte(bucket) - credentialData["type"] = []byte(provider) - credentialData["encryptionKey"] = []byte(encryptionKey) - // Bail out if portworx-api service type is not loadbalancer type and the endpoints are not provided. if !unidirectional && len(sEP) == 0 { srcPXEndpoint, err := getPXEndPointDetails(sFile) @@ -490,30 +427,20 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions destToken = token } - srcClusterPair, err := generateClusterPair(clusterPairName, cmdFactory.GetNamespace(), dIP, dPort, destToken, dFile, projectMappingsStr, pxAuthSecretNamespaceDest, false, false) + sconf, err := getConfig(sFile).ClientConfig() if err != nil { util.CheckErr(err) return } - - // Create cluster-pair on source cluster - conf, err := getConfig(sFile).ClientConfig() + dconf, err := getConfig(dFile).ClientConfig() if err != nil { util.CheckErr(err) return } - if len(cmdFactory.GetNamespace()) > 0 { - err = createNamespace(sFile, cmdFactory.GetNamespace()) - if err != nil { - util.CheckErr(err) - return - } - } - printMsg(fmt.Sprintf("\nCreating Secret and ObjectstoreLocation in source cluster in namespace %v...", cmdFactory.GetNamespace()), ioStreams.Out) - storkops.Instance().SetConfig(conf) - core.Instance().SetConfig(conf) - secret := &v1.Secret{ + finalBackupLocationName := backupLocationName + // backuplocation object init as it is used in different if blocks + backupLocation := &storkv1.BackupLocation{ ObjectMeta: meta.ObjectMeta{ Name: clusterPairName, Namespace: cmdFactory.GetNamespace(), @@ -522,63 +449,153 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions storkCreatedAnnotation: "true", }, }, - Data: credentialData, - Type: v1.SecretTypeOpaque, - } - _, err = core.Instance().CreateSecret(secret) - if err != nil { - util.CheckErr(err) - return + Location: storkv1.BackupLocationItem{}, } - backupLocation.Location.SecretConfig = clusterPairName - var annotations = make(map[string]string) - annotations[skipResourceAnnotation] = "true" - _, err = storkops.Instance().CreateBackupLocation(backupLocation) - if err != nil { - err := fmt.Errorf("unable to create ObjectstoreLocation in source. Err: %v", err) - util.CheckErr(err) - return - } - printMsg(fmt.Sprintf("ObjectstoreLocation %v created on source cluster in namespace %v\n", clusterPairName, cmdFactory.GetNamespace()), ioStreams.Out) + if len(backupLocationName) > 0 { + err = verifyBackupLocationExistence(sFile, backupLocationName, cmdFactory.GetNamespace()) + if err != nil { + util.CheckErr(fmt.Errorf("input backuplocation %s existence check failed with error in source cluster: %v", backupLocationName, err)) + return + } + err = verifyBackupLocationExistence(dFile, backupLocationName, cmdFactory.GetNamespace()) + if err != nil { + util.CheckErr(fmt.Errorf("input backuplocation %s existence check failed with error in destination cluster: %v", backupLocationName, err)) + return + } + } else { + // create backuplocation secrets in both source and destination + credentialData := make(map[string][]byte) + switch provider { + case "s3": + if s3AccessKey == "" { + util.CheckErr(getMissingParameterError("s3-access-key", "Access Key missing for S3")) + return + } + if s3SecretKey == "" { + util.CheckErr(getMissingParameterError("s3-secret-key", "Secret Key missing for S3")) + return + } + if len(s3EndPoint) == 0 { + util.CheckErr(getMissingParameterError("s3-endpoint", "Endpoint missing for S3")) + return + } + if len(s3Region) == 0 { + util.CheckErr(getMissingParameterError("s3-region", "Region missing for S3")) + return + } + credentialData["endpoint"] = []byte(s3EndPoint) + credentialData["accessKeyID"] = []byte(s3AccessKey) + credentialData["secretAccessKey"] = []byte(s3SecretKey) + credentialData["region"] = []byte(s3Region) + credentialData["disableSSL"] = []byte(strconv.FormatBool(disableSSL)) + backupLocation.Location.Type = storkv1.BackupLocationS3 + case "azure": + if azureAccountName == "" { + util.CheckErr(getMissingParameterError("azure-account-name", "Account Name missing for Azure")) + return + } + if azureAccountKey == "" { + util.CheckErr(getMissingParameterError("azure-account-key", "Account Key missing for Azure")) + return + } + credentialData["storageAccountName"] = []byte(azureAccountName) + credentialData["storageAccountKey"] = []byte(azureAccountKey) + backupLocation.Location.Type = storkv1.BackupLocationAzure + case "google": + if len(googleProjectID) == 0 { + util.CheckErr(getMissingParameterError("google-project-id", "Project ID missing for Google")) + return + } + if len(googleJSONKey) == 0 { + util.CheckErr(getMissingParameterError("google-key-file-path", "Json key file path missing for Google")) + return + } + // Read the jsonkey file + keyData, err := os.ReadFile(googleJSONKey) + if err != nil { + util.CheckErr(fmt.Errorf("failed to read json key file: %v", err)) + return + } + credentialData["accountKey"] = keyData + credentialData["projectID"] = []byte(googleProjectID) + backupLocation.Location.Type = storkv1.BackupLocationGoogle + default: + util.CheckErr(getMissingParameterError("provider", "External objectstore provider needs to be either of azure, google, s3")) + return + } - printMsg("Creating a cluster pair. Direction: Source -> Destination", ioStreams.Out) - srcClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = backupLocation.Name - _, err = storkops.Instance().CreateClusterPair(srcClusterPair) - if err != nil { - util.CheckErr(err) - return - } - printMsg(fmt.Sprintf("ClusterPair %s created successfully. Direction Source -> Destination\n", clusterPairName), ioStreams.Out) - // Create cluster-pair on dest cluster - conf, err = getConfig(dFile).ClientConfig() - if err != nil { - util.CheckErr(err) - return - } - storkops.Instance().SetConfig(conf) - core.Instance().SetConfig(conf) - if len(cmdFactory.GetNamespace()) > 0 { - err = createNamespace(dFile, cmdFactory.GetNamespace()) + credentialData["path"] = []byte(bucket) + credentialData["type"] = []byte(provider) + credentialData["encryptionKey"] = []byte(encryptionKey) + finalBackupLocationName = backupLocation.Name + + printMsg(fmt.Sprintf("\nCreating Secret and ObjectstoreLocation in source cluster in namespace %v...", cmdFactory.GetNamespace()), ioStreams.Out) + storkops.Instance().SetConfig(sconf) + core.Instance().SetConfig(sconf) + secret := &v1.Secret{ + ObjectMeta: meta.ObjectMeta{ + Name: clusterPairName, + Namespace: cmdFactory.GetNamespace(), + Annotations: map[string]string{ + skipResourceAnnotation: "true", + storkCreatedAnnotation: "true", + }, + }, + Data: credentialData, + Type: v1.SecretTypeOpaque, + } + _, err = core.Instance().CreateSecret(secret) + if err != nil { + util.CheckErr(err) + return + } + + backupLocation.Location.SecretConfig = clusterPairName + var annotations = make(map[string]string) + annotations[skipResourceAnnotation] = "true" + _, err = storkops.Instance().CreateBackupLocation(backupLocation) if err != nil { + err := fmt.Errorf("unable to create ObjectstoreLocation in source. Err: %v", err) util.CheckErr(err) return } + printMsg(fmt.Sprintf("ObjectstoreLocation %v created on source cluster in namespace %v\n", clusterPairName, cmdFactory.GetNamespace()), ioStreams.Out) + + storkops.Instance().SetConfig(dconf) + core.Instance().SetConfig(dconf) + printMsg(fmt.Sprintf("Creating Secret and ObjectstoreLocation in destination cluster in namespace %v...", cmdFactory.GetNamespace()), ioStreams.Out) + _, err = core.Instance().CreateSecret(secret) + if err != nil { + util.CheckErr(err) + return + } + _, err = storkops.Instance().CreateBackupLocation(backupLocation) + if err != nil { + err := fmt.Errorf("unable to create ObjectstoreLocation in destination. Err: %v", err) + util.CheckErr(err) + return + } + printMsg(fmt.Sprintf("ObjectstoreLocation %v created on destination cluster in namespace %v\n", clusterPairName, cmdFactory.GetNamespace()), ioStreams.Out) } - printMsg(fmt.Sprintf("Creating Secret and ObjectstoreLocation in destination cluster in namespace %v...", cmdFactory.GetNamespace()), ioStreams.Out) - _, err = core.Instance().CreateSecret(secret) + + printMsg("Creating a cluster pair. Direction: Source -> Destination", ioStreams.Out) + srcClusterPair, err := generateClusterPair(clusterPairName, cmdFactory.GetNamespace(), dIP, dPort, destToken, dFile, projectMappingsStr, pxAuthSecretNamespaceDest, false, false) if err != nil { util.CheckErr(err) return } - _, err = storkops.Instance().CreateBackupLocation(backupLocation) + storkops.Instance().SetConfig(sconf) + core.Instance().SetConfig(sconf) + srcClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = finalBackupLocationName + _, err = storkops.Instance().CreateClusterPair(srcClusterPair) if err != nil { - err := fmt.Errorf("unable to create ObjectstoreLocation in destination. Err: %v", err) util.CheckErr(err) return } - printMsg(fmt.Sprintf("ObjectstoreLocation %v created on destination cluster in namespace %v\n", clusterPairName, cmdFactory.GetNamespace()), ioStreams.Out) + printMsg(fmt.Sprintf("ClusterPair %s created successfully. Direction Source -> Destination\n", clusterPairName), ioStreams.Out) + // Create clusterpair in destination only if unidirectional flag is not set if !unidirectional { sIP, sPort := getHostPortFromEndPoint(sEP, ioStreams) @@ -605,6 +622,8 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions } printMsg("Creating a cluster pair. Direction: Destination -> Source", ioStreams.Out) + storkops.Instance().SetConfig(dconf) + core.Instance().SetConfig(dconf) destClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = backupLocation.Name _, err = storkops.Instance().CreateClusterPair(destClusterPair) if err != nil { @@ -633,6 +652,7 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions createClusterPairCommand.Flags().StringVarP(&projectMappingsStr, "project-mappings", "", "", projectMappingHelpString) createClusterPairCommand.Flags().StringVarP(&mode, "mode", "", "async-dr", "Mode of DR. [async-dr, sync-dr]") createClusterPairCommand.Flags().BoolVarP(&unidirectional, "unidirectional", "u", false, "(Optional) to create Clusterpair from source -> dest only") + createClusterPairCommand.Flags().StringVarP(&backupLocationName, "use-existing-backuplocation", "", "", "(Optional) Backuplocation with the provided name should be present in both source and destination cluster") // New parameters for creating backuplocation secret createClusterPairCommand.Flags().StringVarP(&provider, "provider", "p", "", "External objectstore provider name. [s3, azure, google]") createClusterPairCommand.Flags().StringVar(&bucket, "bucket", "", "Bucket name") @@ -933,3 +953,29 @@ func createNamespace(config string, namespace string) error { } return nil } + +func verifyBackupLocationExistence(config string, blName string, namespace string) error { + conf, err := getConfig(config).ClientConfig() + if err != nil { + return err + } + storkOps, err := storkops.NewForConfig(conf) + if err != nil { + return err + } + bl, err := storkOps.GetBackupLocation(blName, namespace) + if err != nil { + return err + } + if len(bl.Location.SecretConfig) > 0 { + coreOps, err := core.NewForConfig(conf) + if err != nil { + return err + } + _, err = coreOps.GetSecret(bl.Location.SecretConfig, namespace) + if err != nil { + return err + } + } + return nil +} From 00454180b73680b3fa870067c9a59ade4ecebe79 Mon Sep 17 00:00:00 2001 From: diptiranjan Date: Tue, 12 Sep 2023 17:41:54 +0530 Subject: [PATCH 3/3] Addressed the review comments. --- pkg/storkctl/clusterpair.go | 61 ++++++++++++++++---------------- pkg/storkctl/clusterpair_test.go | 12 +++---- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/pkg/storkctl/clusterpair.go b/pkg/storkctl/clusterpair.go index 600e08e79a..073c0ed699 100644 --- a/pkg/storkctl/clusterpair.go +++ b/pkg/storkctl/clusterpair.go @@ -298,14 +298,17 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions if sFile == dFile { util.CheckErr(fmt.Errorf("source kubeconfig file and destination kubeconfig file should be different")) + return } sameFiles, err := utils.CompareFiles(sFile, dFile) if err != nil { util.CheckErr(err) + return } if sameFiles { util.CheckErr(fmt.Errorf("source kubeconfig and destination kubeconfig file should be different")) + return } // Handling the syncDR cases here if syncDR { @@ -371,20 +374,6 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions } //Handling the asyncDR cases here onwards - - if len(cmdFactory.GetNamespace()) > 0 { - err = createNamespace(sFile, cmdFactory.GetNamespace()) - if err != nil { - util.CheckErr(fmt.Errorf("error in creating namespace %s in source cluster: %v", cmdFactory.GetNamespace(), err)) - return - } - err = createNamespace(dFile, cmdFactory.GetNamespace()) - if err != nil { - util.CheckErr(fmt.Errorf("error in creating namespace %s in destination cluster: %v", cmdFactory.GetNamespace(), err)) - return - } - } - // Bail out if portworx-api service type is not loadbalancer type and the endpoints are not provided. if !unidirectional && len(sEP) == 0 { srcPXEndpoint, err := getPXEndPointDetails(sFile) @@ -427,18 +416,30 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions destToken = token } - sconf, err := getConfig(sFile).ClientConfig() + sConf, err := getConfig(sFile).ClientConfig() if err != nil { util.CheckErr(err) return } - dconf, err := getConfig(dFile).ClientConfig() + dConf, err := getConfig(dFile).ClientConfig() if err != nil { util.CheckErr(err) return } - finalBackupLocationName := backupLocationName + if len(cmdFactory.GetNamespace()) > 0 { + err = createNamespace(sFile, cmdFactory.GetNamespace()) + if err != nil { + util.CheckErr(fmt.Errorf("error in creating namespace %s in source cluster: %v", cmdFactory.GetNamespace(), err)) + return + } + err = createNamespace(dFile, cmdFactory.GetNamespace()) + if err != nil { + util.CheckErr(fmt.Errorf("error in creating namespace %s in destination cluster: %v", cmdFactory.GetNamespace(), err)) + return + } + } + // backuplocation object init as it is used in different if blocks backupLocation := &storkv1.BackupLocation{ ObjectMeta: meta.ObjectMeta{ @@ -455,12 +456,12 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions if len(backupLocationName) > 0 { err = verifyBackupLocationExistence(sFile, backupLocationName, cmdFactory.GetNamespace()) if err != nil { - util.CheckErr(fmt.Errorf("input backuplocation %s existence check failed with error in source cluster: %v", backupLocationName, err)) + util.CheckErr(fmt.Errorf("input objectstoreLocation %s existence check failed with error in source cluster: %v", backupLocationName, err)) return } err = verifyBackupLocationExistence(dFile, backupLocationName, cmdFactory.GetNamespace()) if err != nil { - util.CheckErr(fmt.Errorf("input backuplocation %s existence check failed with error in destination cluster: %v", backupLocationName, err)) + util.CheckErr(fmt.Errorf("input objectstoreLocation %s existence check failed with error in destination cluster: %v", backupLocationName, err)) return } } else { @@ -528,11 +529,11 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions credentialData["path"] = []byte(bucket) credentialData["type"] = []byte(provider) credentialData["encryptionKey"] = []byte(encryptionKey) - finalBackupLocationName = backupLocation.Name + backupLocationName = backupLocation.Name printMsg(fmt.Sprintf("\nCreating Secret and ObjectstoreLocation in source cluster in namespace %v...", cmdFactory.GetNamespace()), ioStreams.Out) - storkops.Instance().SetConfig(sconf) - core.Instance().SetConfig(sconf) + storkops.Instance().SetConfig(sConf) + core.Instance().SetConfig(sConf) secret := &v1.Secret{ ObjectMeta: meta.ObjectMeta{ Name: clusterPairName, @@ -562,8 +563,8 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions } printMsg(fmt.Sprintf("ObjectstoreLocation %v created on source cluster in namespace %v\n", clusterPairName, cmdFactory.GetNamespace()), ioStreams.Out) - storkops.Instance().SetConfig(dconf) - core.Instance().SetConfig(dconf) + storkops.Instance().SetConfig(dConf) + core.Instance().SetConfig(dConf) printMsg(fmt.Sprintf("Creating Secret and ObjectstoreLocation in destination cluster in namespace %v...", cmdFactory.GetNamespace()), ioStreams.Out) _, err = core.Instance().CreateSecret(secret) if err != nil { @@ -585,9 +586,9 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions util.CheckErr(err) return } - storkops.Instance().SetConfig(sconf) - core.Instance().SetConfig(sconf) - srcClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = finalBackupLocationName + storkops.Instance().SetConfig(sConf) + core.Instance().SetConfig(sConf) + srcClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = backupLocationName _, err = storkops.Instance().CreateClusterPair(srcClusterPair) if err != nil { util.CheckErr(err) @@ -622,8 +623,8 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions } printMsg("Creating a cluster pair. Direction: Destination -> Source", ioStreams.Out) - storkops.Instance().SetConfig(dconf) - core.Instance().SetConfig(dconf) + storkops.Instance().SetConfig(dConf) + core.Instance().SetConfig(dConf) destClusterPair.Spec.Options[storkv1.BackupLocationResourceName] = backupLocation.Name _, err = storkops.Instance().CreateClusterPair(destClusterPair) if err != nil { @@ -652,7 +653,7 @@ func newCreateClusterPairCommand(cmdFactory Factory, ioStreams genericclioptions createClusterPairCommand.Flags().StringVarP(&projectMappingsStr, "project-mappings", "", "", projectMappingHelpString) createClusterPairCommand.Flags().StringVarP(&mode, "mode", "", "async-dr", "Mode of DR. [async-dr, sync-dr]") createClusterPairCommand.Flags().BoolVarP(&unidirectional, "unidirectional", "u", false, "(Optional) to create Clusterpair from source -> dest only") - createClusterPairCommand.Flags().StringVarP(&backupLocationName, "use-existing-backuplocation", "", "", "(Optional) Backuplocation with the provided name should be present in both source and destination cluster") + createClusterPairCommand.Flags().StringVarP(&backupLocationName, "use-existing-objectstorelocation", "", "", "(Optional) Objectstorelocation with the provided name should be present in both source and destination cluster") // New parameters for creating backuplocation secret createClusterPairCommand.Flags().StringVarP(&provider, "provider", "p", "", "External objectstore provider name. [s3, azure, google]") createClusterPairCommand.Flags().StringVar(&bucket, "bucket", "", "Bucket name") diff --git a/pkg/storkctl/clusterpair_test.go b/pkg/storkctl/clusterpair_test.go index 22c5539c74..f9697adf36 100644 --- a/pkg/storkctl/clusterpair_test.go +++ b/pkg/storkctl/clusterpair_test.go @@ -133,24 +133,22 @@ func TestCreateUniDirectionalClusterPairMissingParameters(t *testing.T) { expected := "error: missing parameter \"src-kube-file\" - Kubeconfig file missing for source cluster" testCommon(t, cmdArgs, nil, expected, true) - srcConfig := createTempFile(t, "src.config", "source configuration") - destConfig := createTempFile(t, "dest.config", "destination configuration") + srcConfig := createTempFile(t, "src.config", "source") + destConfig := createTempFile(t, "dest.config", "destination") defer os.Remove(srcConfig.Name()) defer os.Remove(destConfig.Name()) + cmdArgs = []string{"create", "clusterpair", "uni-pair1", "-n", "test", "--src-kube-file", srcConfig.Name(), "--unidirectional"} expected = "error: missing parameter \"dest-kube-file\" - Kubeconfig file missing for destination cluster" testCommon(t, cmdArgs, nil, expected, true) - cmdArgs = []string{"create", "clusterpair", "uni-pair1", "-n", "test", "--src-kube-file", srcConfig.Name(), "--dest-kube-file", destConfig.Name(), "-u"} - expected = "error: missing parameter \"provider\" - External objectstore provider needs to be either of azure, google, s3" - testCommon(t, cmdArgs, nil, expected, true) - cmdArgs = []string{"create", "clusterpair", "uni-pair1", "-n", "test", "--src-kube-file", srcConfig.Name(), "--dest-kube-file", srcConfig.Name(), "-u"} expected = "error: source kubeconfig file and destination kubeconfig file should be different" testCommon(t, cmdArgs, nil, expected, true) - srcConfigDuplicate := createTempFile(t, "srcDup.config", "source configuration") + srcConfigDuplicate := createTempFile(t, "srcDup.config", "source") defer os.Remove(srcConfigDuplicate.Name()) + cmdArgs = []string{"create", "clusterpair", "uni-pair1", "-n", "test", "--src-kube-file", srcConfig.Name(), "--dest-kube-file", srcConfigDuplicate.Name(), "-u"} expected = "error: source kubeconfig and destination kubeconfig file should be different" testCommon(t, cmdArgs, nil, expected, true)