diff --git a/pkg/backup.go b/pkg/backup.go index 7a5bba942..1ec7219fa 100644 --- a/pkg/backup.go +++ b/pkg/backup.go @@ -331,7 +331,12 @@ func (opt *mongoOptions) backupMongoDB(targetRef api_v1beta1.TargetRef) (*restic } } + var tlsEnable bool if appBinding.Spec.ClientConfig.CABundle != nil { + tlsEnable = true + } + + if tlsEnable { if tlsSecret == nil { return nil, errors.Wrap(err, "spec.tlsSecret needs to be set in appbinding for TLS secured database.") } @@ -346,8 +351,8 @@ func (opt *mongoOptions) backupMongoDB(targetRef api_v1beta1.TargetRef) (*restic } dumpCreds = []interface{}{ "--ssl", - "--sslCAFile", filepath.Join(opt.setupOptions.ScratchDir, MongoTLSCertFileName), - "--sslPEMKeyFile", filepath.Join(opt.setupOptions.ScratchDir, MongoClientPemFileName), + fmt.Sprintf("--sslCAFile=%s", filepath.Join(opt.setupOptions.ScratchDir, MongoTLSCertFileName)), + fmt.Sprintf("--sslPEMKeyFile=%s", filepath.Join(opt.setupOptions.ScratchDir, MongoClientPemFileName)), } // get certificate secret to get client certificate @@ -374,9 +379,9 @@ func (opt *mongoOptions) backupMongoDB(targetRef api_v1beta1.TargetRef) (*restic return nil, errors.Wrap(err, "unable to get user from ssl.") } userAuth := []interface{}{ - "-u", user, - "--authenticationMechanism", "MONGODB-X509", - "--authenticationDatabase", "$external", + fmt.Sprintf("--username=%s", user), + "--authenticationMechanism=MONGODB-X509", + "--authenticationDatabase=$external", } mongoCreds = append(mongoCreds, userAuth...) dumpCreds = append(dumpCreds, userAuth...) @@ -400,7 +405,7 @@ func (opt *mongoOptions) backupMongoDB(targetRef api_v1beta1.TargetRef) (*restic BackupPaths: opt.defaultBackupOptions.BackupPaths, } - uri := opt.buildMongoURI(mongoDSN, port, isStandalone, isSrv) + uri := opt.buildMongoURI(mongoDSN, port, isStandalone, isSrv, tlsEnable) // setup pipe command backupCmd := restic.Command{ @@ -410,6 +415,13 @@ func (opt *mongoOptions) backupMongoDB(targetRef api_v1beta1.TargetRef) (*restic "--archive", }, } + + if tlsEnable { + backupCmd.Args = append(backupCmd.Args, + fmt.Sprintf("--sslCAFile=%s", getOptionValue(dumpCreds, "--sslCAFile")), + fmt.Sprintf("--sslPEMKeyFile=%s", getOptionValue(dumpCreds, "--sslPEMKeyFile"))) + } + userArgs := strings.Fields(opt.mongoArgs) if !isStandalone { @@ -571,25 +583,6 @@ func cleanup() { } } -func (opt *mongoOptions) buildMongoURI(mongoDSN string, port int32, isStandalone, isSrv bool) string { - userName := getOptionValue(dumpCreds, "--username") - password := getOptionValue(dumpCreds, "--password") - authDbName := getOptionValue(dumpCreds, "--authenticationDatabase") - - prefix := "mongodb" - portStr := fmt.Sprintf(":%d", port) - if isSrv { - prefix += "+srv" - portStr = "" - } - if !isStandalone { - portStr = "" - } - - return fmt.Sprintf("%s://%s:%s@%s%s/%s?authSource=%s", - prefix, userName, password, mongoDSN, portStr, authDbName, authDbName) -} - func getOptionValue(args []interface{}, option string) string { for _, arg := range args { strArg, ok := arg.(string) diff --git a/pkg/restore.go b/pkg/restore.go index 85a01c1b6..a1f8d2841 100644 --- a/pkg/restore.go +++ b/pkg/restore.go @@ -204,9 +204,23 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti return nil, err } - port, err := appBinding.Port() - if err != nil { - return nil, err + var isSrv bool + port := int32(27017) + if appBinding.Spec.ClientConfig.URL != nil { + isSrv, err = isSrvConnection(*appBinding.Spec.ClientConfig.URL) + if err != nil { + return nil, err + } + } + + // Checked for Altlas and DigitalOcean srv format connection string don't give port. + // mongodump --uri format not support port. + + if !isSrv { + port, err = appBinding.Port() + if err != nil { + return nil, err + } } // unmarshal parameter is the field has value @@ -249,8 +263,12 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti return nil, err } } - + var tlsEnable bool if appBinding.Spec.ClientConfig.CABundle != nil { + tlsEnable = true + } + + if tlsEnable { if err := os.WriteFile(filepath.Join(opt.setupOptions.ScratchDir, MongoTLSCertFileName), appBinding.Spec.ClientConfig.CABundle, os.ModePerm); err != nil { return nil, errors.Wrap(err, "failed to write key for CA certificate") } @@ -261,8 +279,8 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti } dumpCreds = []interface{}{ "--ssl", - "--sslCAFile", filepath.Join(opt.setupOptions.ScratchDir, MongoTLSCertFileName), - "--sslPEMKeyFile", filepath.Join(opt.setupOptions.ScratchDir, MongoClientPemFileName), + fmt.Sprintf("--sslCAFile=%s", filepath.Join(opt.setupOptions.ScratchDir, MongoTLSCertFileName)), + fmt.Sprintf("--sslPEMKeyFile=%s", filepath.Join(opt.setupOptions.ScratchDir, MongoClientPemFileName)), } // get certificate secret to get client certificate @@ -289,9 +307,9 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti return nil, errors.Wrap(err, "unable to get user from ssl.") } userAuth := []interface{}{ - "-u", user, - "--authenticationMechanism", "MONGODB-X509", - "--authenticationDatabase", "$external", + fmt.Sprintf("--username=%s", user), + "--authenticationMechanism=MONGODB-X509", + "--authenticationDatabase=$external", } mongoCreds = append(mongoCreds, userAuth...) dumpCreds = append(dumpCreds, userAuth...) @@ -300,7 +318,7 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti userAuth := []interface{}{ fmt.Sprintf("--username=%s", authSecret.Data[MongoUserKey]), fmt.Sprintf("--password=%s", authSecret.Data[MongoPasswordKey]), - "--authenticationDatabase", opt.authenticationDatabase, + fmt.Sprintf("--authenticationDatabase=%s", opt.authenticationDatabase), } mongoCreds = append(mongoCreds, userAuth...) dumpCreds = append(dumpCreds, userAuth...) @@ -314,19 +332,24 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti FileName: opt.defaultDumpOptions.FileName, Snapshot: opt.getSnapshotForHost(hostKey, restoreSession.Spec.Target.Rules), } + + uri := opt.buildMongoURI(mongoDSN, port, isStandalone, isSrv, tlsEnable) // setup pipe command restoreCmd := restic.Command{ Name: MongoRestoreCMD, - Args: append([]interface{}{ - "--host", mongoDSN, + Args: []interface{}{ + "--uri", fmt.Sprintf("\"%s\"", uri), "--archive", - }, dumpCreds...), + }, + } + if tlsEnable { + restoreCmd.Args = append(restoreCmd.Args, + fmt.Sprintf("--sslCAFile=%s", getOptionValue(dumpCreds, "--sslCAFile")), + fmt.Sprintf("--sslPEMKeyFile=%s", getOptionValue(dumpCreds, "--sslPEMKeyFile"))) } userArgs := strings.Fields(opt.mongoArgs) - if isStandalone { - restoreCmd.Args = append(restoreCmd.Args, fmt.Sprintf("--port=%d", port)) - } else { + if !isStandalone { // - port is already added in mongoDSN with replicasetName/host:port format. // - oplog is enabled automatically for replicasets. // Don't use --oplogReplay if user specify any of these arguments through opt.mongoArgs diff --git a/pkg/utils.go b/pkg/utils.go index 5f8cbb8ef..6f057c3ec 100644 --- a/pkg/utils.go +++ b/pkg/utils.go @@ -125,3 +125,27 @@ func isSrvConnection(connectionString string) (bool, error) { // Check if the scheme is "mongodb+srv" return parsedURL.Scheme == "mongodb+srv", nil } + +func (opt *mongoOptions) buildMongoURI(mongoDSN string, port int32, isStandalone, isSrv, tlsEnable bool) string { + prefix := "mongodb" + portStr := fmt.Sprintf(":%d", port) + if isSrv { + prefix += "+srv" + portStr = "" + } + if !isStandalone { + portStr = "" + } + + authDbName := getOptionValue(dumpCreds, "--authenticationDatabase") + userName := getOptionValue(dumpCreds, "--username") + if !tlsEnable { + password := getOptionValue(dumpCreds, "--password") + return fmt.Sprintf("%s://%s:%s@%s%s/dbnew?authSource=%s", + prefix, userName, password, mongoDSN, portStr, authDbName) + } + + authMechanism := getOptionValue(dumpCreds, "--authenticationMechanism") + return fmt.Sprintf("%s://%s@%s%s/dbnew?authSource=%s&authMechanism=%s&ssl=true", + prefix, userName, mongoDSN, portStr, authDbName, authMechanism) +}