// configureSession takes in a session and modifies it with properly configured // settings. It does the following configurations: // // 1. Sets the session to not timeout // 2. Sets the write concern on the session // // returns an error if it's unable to set the write concern func (imp *MongoImport) configureSession(session *mgo.Session) error { // sockets to the database will never be forcibly closed session.SetSocketTimeout(0) sessionSafety, err := db.BuildWriteConcern(imp.IngestOptions.WriteConcern, imp.nodeType) if err != nil { return fmt.Errorf("write concern error: %v", err) } session.SetSafe(sessionSafety) return nil }
// ParseAndValidateOptions returns a non-nil error if user-supplied options are invalid. func (restore *MongoRestore) ParseAndValidateOptions() error { // Can't use option pkg defaults for --objcheck because it's two separate flags, // and we need to be able to see if they're both being used. We default to // true here and then see if noobjcheck is enabled. log.Logv(log.DebugHigh, "checking options") if restore.InputOptions.Objcheck { restore.objCheck = true log.Logv(log.DebugHigh, "\tdumping with object check enabled") } else { log.Logv(log.DebugHigh, "\tdumping with object check disabled") } if restore.NSOptions.DB == "" && restore.NSOptions.Collection != "" { return fmt.Errorf("cannot restore a collection without a specified database") } if restore.NSOptions.DB != "" { if err := util.ValidateDBName(restore.NSOptions.DB); err != nil { return fmt.Errorf("invalid db name: %v", err) } } if restore.NSOptions.Collection != "" { if err := util.ValidateCollectionGrammar(restore.NSOptions.Collection); err != nil { return fmt.Errorf("invalid collection name: %v", err) } } if restore.InputOptions.RestoreDBUsersAndRoles && restore.NSOptions.DB == "" { return fmt.Errorf("cannot use --restoreDbUsersAndRoles without a specified database") } if restore.InputOptions.RestoreDBUsersAndRoles && restore.NSOptions.DB == "admin" { return fmt.Errorf("cannot use --restoreDbUsersAndRoles with the admin database") } var err error restore.isMongos, err = restore.SessionProvider.IsMongos() if err != nil { return err } if restore.isMongos { log.Logv(log.DebugLow, "restoring to a sharded system") } if restore.InputOptions.OplogLimit != "" { if !restore.InputOptions.OplogReplay { return fmt.Errorf("cannot use --oplogLimit without --oplogReplay enabled") } restore.oplogLimit, err = ParseTimestampFlag(restore.InputOptions.OplogLimit) if err != nil { return fmt.Errorf("error parsing timestamp argument to --oplogLimit: %v", err) } } if restore.InputOptions.OplogFile != "" { if !restore.InputOptions.OplogReplay { return fmt.Errorf("cannot use --oplogFile without --oplogReplay enabled") } if restore.InputOptions.Archive != "" { return fmt.Errorf("cannot use --oplogFile with --archive specified") } } // check if we are using a replica set and fall back to w=1 if we aren't (for <= 2.4) nodeType, err := restore.SessionProvider.GetNodeType() if err != nil { return fmt.Errorf("error determining type of connected node: %v", err) } log.Logvf(log.DebugLow, "connected to node type: %v", nodeType) restore.safety, err = db.BuildWriteConcern(restore.OutputOptions.WriteConcern, nodeType) if err != nil { return fmt.Errorf("error parsing write concern: %v", err) } // deprecations with --nsInclude --nsExclude if restore.NSOptions.DB != "" || restore.NSOptions.Collection != "" { // these are only okay if restoring from a bson file _, fileType := restore.getInfoFromFilename(restore.TargetDirectory) if fileType != BSONFileType { log.Logvf(log.Always, "the --db and --collection args should only be used when "+ "restoring from a BSON file. Other uses are deprecated and will not exist "+ "in the future; use --nsInclude instead") } } if len(restore.NSOptions.ExcludedCollections) > 0 || len(restore.NSOptions.ExcludedCollectionPrefixes) > 0 { log.Logvf(log.Always, "the --excludeCollections and --excludeCollectionPrefixes options "+ "are deprecated and will not exist in the future; use --nsExclude instead") } if restore.InputOptions.OplogReplay { if len(restore.NSOptions.NSInclude) > 0 || restore.NSOptions.DB != "" { return fmt.Errorf("cannot use --oplogReplay with includes specified") } if len(restore.NSOptions.NSExclude) > 0 || len(restore.NSOptions.ExcludedCollections) > 0 || len(restore.NSOptions.ExcludedCollectionPrefixes) > 0 { return fmt.Errorf("cannot use --oplogReplay with excludes specified") } if len(restore.NSOptions.NSFrom) > 0 { return fmt.Errorf("cannot use --oplogReplay with namespace renames specified") } } includes := restore.NSOptions.NSInclude if restore.NSOptions.DB != "" && restore.NSOptions.Collection != "" { includes = append(includes, ns.Escape(restore.NSOptions.DB)+"."+ restore.NSOptions.Collection) } else if restore.NSOptions.DB != "" { includes = append(includes, ns.Escape(restore.NSOptions.DB)+".*") } if len(includes) == 0 { includes = []string{"*"} } restore.includer, err = ns.NewMatcher(includes) if err != nil { return fmt.Errorf("invalid includes: %v", err) } if len(restore.NSOptions.ExcludedCollections) > 0 && restore.NSOptions.Collection != "" { return fmt.Errorf("--collection is not allowed when --excludeCollection is specified") } if len(restore.NSOptions.ExcludedCollectionPrefixes) > 0 && restore.NSOptions.Collection != "" { return fmt.Errorf("--collection is not allowed when --excludeCollectionsWithPrefix is specified") } excludes := restore.NSOptions.NSExclude for _, col := range restore.NSOptions.ExcludedCollections { excludes = append(excludes, "*."+ns.Escape(col)) } for _, colPrefix := range restore.NSOptions.ExcludedCollectionPrefixes { excludes = append(excludes, "*."+ns.Escape(colPrefix)+"*") } restore.excluder, err = ns.NewMatcher(excludes) if err != nil { return fmt.Errorf("invalid excludes: %v", err) } if len(restore.NSOptions.NSFrom) != len(restore.NSOptions.NSTo) { return fmt.Errorf("--nsFrom and --nsTo arguments must be specified an equal number of times") } restore.renamer, err = ns.NewRenamer(restore.NSOptions.NSFrom, restore.NSOptions.NSTo) if err != nil { return fmt.Errorf("invalid renames: %v", err) } if restore.OutputOptions.NumInsertionWorkers < 0 { return fmt.Errorf( "cannot specify a negative number of insertion workers per collection") } // a single dash signals reading from stdin if restore.TargetDirectory == "-" { if restore.InputOptions.Archive != "" { return fmt.Errorf( "cannot restore from \"-\" when --archive is specified") } if restore.NSOptions.Collection == "" { return fmt.Errorf("cannot restore from stdin without a specified collection") } } if restore.stdin == nil { restore.stdin = os.Stdin } return nil }
// ParseAndValidateOptions returns a non-nil error if user-supplied options are invalid. func (restore *MongoRestore) ParseAndValidateOptions() error { // Can't use option pkg defaults for --objcheck because it's two separate flags, // and we need to be able to see if they're both being used. We default to // true here and then see if noobjcheck is enabled. log.Log(log.DebugHigh, "checking options") if restore.InputOptions.Objcheck { restore.objCheck = true log.Log(log.DebugHigh, "\tdumping with object check enabled") } else { log.Log(log.DebugHigh, "\tdumping with object check disabled") } if restore.ToolOptions.DB == "" && restore.ToolOptions.Collection != "" { return fmt.Errorf("cannot dump a collection without a specified database") } if restore.ToolOptions.DB != "" { if err := util.ValidateDBName(restore.ToolOptions.DB); err != nil { return fmt.Errorf("invalid db name: %v", err) } } if restore.ToolOptions.Collection != "" { if err := util.ValidateCollectionGrammar(restore.ToolOptions.Collection); err != nil { return fmt.Errorf("invalid collection name: %v", err) } } if restore.InputOptions.RestoreDBUsersAndRoles && restore.ToolOptions.DB == "" { return fmt.Errorf("cannot use --restoreDbUsersAndRoles without a specified database") } if restore.InputOptions.RestoreDBUsersAndRoles && restore.ToolOptions.DB == "admin" { return fmt.Errorf("cannot use --restoreDbUsersAndRoles with the admin database") } var err error restore.isMongos, err = restore.SessionProvider.IsMongos() if err != nil { return err } if restore.isMongos { log.Log(log.DebugLow, "restoring to a sharded system") } if restore.InputOptions.OplogLimit != "" { if !restore.InputOptions.OplogReplay { return fmt.Errorf("cannot use --oplogLimit without --oplogReplay enabled") } restore.oplogLimit, err = ParseTimestampFlag(restore.InputOptions.OplogLimit) if err != nil { return fmt.Errorf("error parsing timestamp argument to --oplogLimit: %v", err) } } // check if we are using a replica set and fall back to w=1 if we aren't (for <= 2.4) nodeType, err := restore.SessionProvider.GetNodeType() if err != nil { return fmt.Errorf("error determining type of connected node: %v", err) } log.Logf(log.DebugLow, "connected to node type: %v", nodeType) restore.safety, err = db.BuildWriteConcern(restore.OutputOptions.WriteConcern, nodeType) if err != nil { return fmt.Errorf("error parsing write concern: %v", err) } // handle the hidden auth collection flags if restore.ToolOptions.HiddenOptions.TempUsersColl == nil { restore.tempUsersCol = "tempusers" } else { restore.tempUsersCol = *restore.ToolOptions.HiddenOptions.TempUsersColl } if restore.ToolOptions.HiddenOptions.TempRolesColl == nil { restore.tempRolesCol = "temproles" } else { restore.tempRolesCol = *restore.ToolOptions.HiddenOptions.TempRolesColl } if restore.OutputOptions.NumInsertionWorkers < 0 { return fmt.Errorf( "cannot specify a negative number of insertion workers per collection") } // a single dash signals reading from stdin if restore.TargetDirectory == "-" { restore.useStdin = true if restore.InputOptions.Archive != "" { return fmt.Errorf( "cannot restore from \"-\" when --archive is specified") } if restore.ToolOptions.Collection == "" { return fmt.Errorf("cannot restore from stdin without a specified collection") } } return nil }
// Run the mongofiles utility. If displayHost is true, the connected host/port is // displayed. func (mf *MongoFiles) Run(displayHost bool) (string, error) { connUrl := mf.ToolOptions.Host if connUrl == "" { connUrl = util.DefaultHost } if mf.ToolOptions.Port != "" { connUrl = fmt.Sprintf("%s:%s", connUrl, mf.ToolOptions.Port) } var mode = mgo.Nearest var tags bson.D if mf.InputOptions.ReadPreference != "" { var err error mode, tags, err = db.ParseReadPreference(mf.InputOptions.ReadPreference) if err != nil { return "", fmt.Errorf("error parsing --readPreference : %v", err) } if len(tags) > 0 { mf.SessionProvider.SetTags(tags) } } mf.SessionProvider.SetReadPreference(mode) mf.SessionProvider.SetTags(tags) mf.SessionProvider.SetFlags(db.DisableSocketTimeout) // get session session, err := mf.SessionProvider.GetSession() if err != nil { return "", err } defer session.Close() // check type of node we're connected to, and fall back to w=1 if standalone (for <= 2.4) nodeType, err := mf.SessionProvider.GetNodeType() if err != nil { return "", fmt.Errorf("error determining type of node connected: %v", err) } log.Logvf(log.DebugLow, "connected to node type: %v", nodeType) safety, err := db.BuildWriteConcern(mf.StorageOptions.WriteConcern, nodeType) if err != nil { return "", fmt.Errorf("error parsing write concern: %v", err) } // configure the session with the appropriate write concern and ensure the // socket does not timeout session.SetSafe(safety) if displayHost { log.Logvf(log.Always, "connected to: %v", connUrl) } // first validate the namespaces we'll be using: <db>.<prefix>.files and <db>.<prefix>.chunks // it's ok to validate only <db>.<prefix>.chunks (the longer one) err = util.ValidateFullNamespace(fmt.Sprintf("%s.%s.chunks", mf.StorageOptions.DB, mf.StorageOptions.GridFSPrefix)) if err != nil { return "", err } // get GridFS handle gfs := session.DB(mf.StorageOptions.DB).GridFS(mf.StorageOptions.GridFSPrefix) var output string log.Logvf(log.Info, "handling mongofiles '%v' command...", mf.Command) switch mf.Command { case List: query := bson.M{} if mf.FileName != "" { regex := bson.M{"$regex": "^" + regexp.QuoteMeta(mf.FileName)} query = bson.M{"filename": regex} } output, err = mf.findAndDisplay(gfs, query) if err != nil { return "", err } case Search: regex := bson.M{"$regex": mf.FileName} query := bson.M{"filename": regex} output, err = mf.findAndDisplay(gfs, query) if err != nil { return "", err } case Get: output, err = mf.handleGet(gfs) if err != nil { return "", err } case GetID: output, err = mf.handleGetID(gfs) if err != nil { return "", err } case Put: output, err = mf.handlePut(gfs) if err != nil { return "", err } case Delete: err = gfs.Remove(mf.FileName) if err != nil { return "", fmt.Errorf("error while removing '%v' from GridFS: %v\n", mf.FileName, err) } output = fmt.Sprintf("successfully deleted all instances of '%v' from GridFS\n", mf.FileName) case DeleteID: output, err = mf.handleDeleteID(gfs) if err != nil { return "", err } } return output, nil }