func nestedBsonMapGet(m bson.M, arg string, moreArgs ...string) (interface{}, error) { strata.Log("Call to nestedBsonMapGet()") value, found := m[arg] if !found { return nil, errors.New("Key not found") } if len(moreArgs) == 0 { return value, nil } nextNest, ok := value.(bson.M) if !ok { return nil, errors.New("Nested value is not a bson map") } return nestedBsonMapGet(nextNest, moreArgs[0], moreArgs[1:]...) }
// PrepareToRestoreSnapshot checks that the necessary directories exist and are not being used func (r *LocalReplica) PrepareToRestoreSnapshot(replicaID string, targetPath string, s *strata.Snapshot) (string, error) { if targetPath == "" { targetPath = s.Metadata.Path } dbpath := targetPath + "/db/" syscall.Umask(0) if err := os.MkdirAll(dbpath, 0777); err != nil { return dbpath, err } // Check that database is not in use strata.Log("Checking that database is not in use") lockfile, err := GetDBLock(targetPath) if lockfile != nil { defer lockfile.Close() } if err != nil && !os.IsNotExist(err) { return dbpath, err } return dbpath, nil }
// CreateSnapshot is called to trigger snapshot creation on the target source. // It should run on the host that corresponds to replicaID unless you know what you're doing. // CreateSnapshot replaces DBPATH/backup/latest with the snapshot that it creates. No other snapshots are kept locally. // TODO(agf): Have a way to pass in tags func (r *LocalReplica) CreateSnapshot(replicaID, snapshotID string) (*strata.Snapshot, error) { strata.Log("Getting session for CreateSnapshot()") session, err := r.sessionGetter.get(r.port, r.username, r.password) if err != nil { return nil, err } defer session.Close() session.SetMode(mgo.Eventual, false) result := bson.M{} strata.Log("Getting dbpath") // determine dbpath cmd := bson.D{{"getCmdLineOpts", 1}} if err := session.DB("admin").Run(cmd, &result); err != nil { return nil, err } dbpathInterface, err := nestedBsonMapGet(result, "parsed", "storage", "dbPath") if err != nil { return nil, err } dbpath, ok := dbpathInterface.(string) if !ok { return nil, errors.New("Nested bson map do not end in a string") } if !strings.HasPrefix(dbpath, "/") { return nil, fmt.Errorf( "Found relative database path %s. Database path must be absolute.", dbpath) } strata.Log("Got dbpath: " + dbpath) strata.Log("Preparing backup directory") // The backup's parent directory should exist syscall.Umask(0) if err := os.MkdirAll(getParentOfBackupPath(dbpath, replicaID), 0777); err != nil { return nil, err } // The actual backup directory shouldn't exist yet backupPath := getBackupPath(dbpath, replicaID) if err := os.RemoveAll(backupPath); err != nil { return nil, err } strata.Log("Getting new snapshot metadata") metadata := strata.SnapshotMetadata{ ID: snapshotID, ReplicaID: replicaID, Time: time.Now(), Path: dbpath} cmd = bson.D{{"setParameter", 1}, {"rocksdbBackup", backupPath}} strata.Log("Performing command for local backup") if err := session.DB("admin").Run(cmd, &result); err != nil { strata.Log("Error performing local backup....") return nil, err } strata.Log("Building metadata.Files") // Build metadata.Files files, err := ioutil.ReadDir(backupPath) if err != nil { return nil, err } for _, file := range files { fullpath := backupPath + "/" + file.Name() csum, err := partialChecksum(fullpath) if err != nil { return nil, err } metadata.Files = append( metadata.Files, strata.File{ Name: file.Name(), Size: file.Size(), Checksum: csum}) } strata.Log("Finished building metadata.Files.") return r.GetSnapshot(metadata) }