//DeleteBackupHistory - Responsible for deleting records from backups.file_history //older than the value in rdpg.config.key = defaultDaysToKeepFileHistory func DeleteBackupHistory() (err error) { daysToKeep, err := config.GetValue(`defaultDaysToKeepFileHistory`) log.Trace(fmt.Sprintf("tasks.DeleteBackupHistory() Keeping %s days of file history in backups.file_history", daysToKeep)) address := `127.0.0.1` sq := fmt.Sprintf(`DELETE FROM backups.file_history WHERE created_at < NOW() - '%s days'::interval; `, daysToKeep) err = rdpgpg.ExecQuery(address, sq) if err != nil { log.Error(fmt.Sprintf(`history.DeleteBackupHistory() Error when running query %s ! %s`, sq, err)) } return }
//BackupAllDatabases - Use pg_dumpall on a SOLO cluster to perform a full backup of everything postgres related func (t *Task) BackupAllDatabases() (err error) { b := backupParams{} b.databaseName = "postgres" b.pgDumpPath, err = config.GetValue(`pgDumpBinaryLocation`) if err != nil { return err } b.pgPort, err = config.GetValue(`BackupPort`) if err != nil { return err } b.basePath, err = config.GetValue(`BackupsPath`) if err != nil { return err } b.node, err = rdpgconsul.GetNode() if err != nil { return err } b.baseFileName = getBaseFileName() //Use this to keep schema and data file names the same err = createTargetFolder(b.basePath + `/` + b.databaseName) if err != nil { log.Error(fmt.Sprintf("tasks.BackupAllDatabases() Could not create target folder %s ! %s", b.basePath, err)) return err } createDumpAllFileHistory, err := createDumpAllFile(b) if err != nil { log.Error(fmt.Sprintf("tasks.BackupAllDatabases() Could not create pg_dumpall file for database %s ! %s", b.databaseName, err)) createDumpAllFileHistory.Status = `error` } err = history.InsertBackupHistoryDumpAll(createDumpAllFileHistory) return }
// Restores a database given the name of the database, and the absolute path to // the backup file. func ImportSqlFile(dbname, filepath string) (err error) { log.Trace(fmt.Sprintf("utils/backup.ImportSqlFile ! Beginning restore of database %s", dbname)) start := time.Now() f := history.BackupFileHistory{} f.Status = "error" f.BackupFile = filepath f.BackupPathAndFile = filepath f.DBName = dbname f.Node = globals.MyIP defer func() { f.Duration = int(time.Since(start).Seconds()) insertErr := history.InsertRestoreHistory(f) if insertErr != nil { log.Error(fmt.Sprintf("utils/backup.ImportSqlFile ! Unable to record history for BackupFileHistory: %+v: %s", f, insertErr.Error())) } }() //Make sure database actually exists first. exists, err := DatabaseExists(dbname) if err != nil { log.Error(fmt.Sprintf("utils/backup.ImportSqlFile ! utils/backup.DatabaseExists(%s) erred : %s", dbname, err.Error())) return err } if !exists { errorMessage := fmt.Sprintf("utils/backup.ImportSqlFile ! No database found with name: %s", dbname) log.Error(errorMessage) return errors.New(errorMessage) } pgPort, err := config.GetValue(`BackupPort`) if err != nil { log.Error(fmt.Sprintf("utils/backup.ImportSqlFile ! config.GetValue(`BackupPort`) erred : %s", err.Error())) return err } lockRestore() log.Trace(fmt.Sprintf("utils/backup.RestoreInPlace ! Executing %s -p %s -U vcap -d %s -f %s", globals.PSQL_PATH, pgPort, dbname, filepath)) out, err := exec.Command(globals.PSQL_PATH, "-p", pgPort, "-U", "vcap", "-d", dbname, "-f", filepath).CombinedOutput() unlockRestore() if err != nil { log.Error(fmt.Sprintf(`utils/backup.ImportSqlFile ! Error running pg_dump command for: %s out: %s ! %s`, dbname, out, err)) return err } log.Trace(fmt.Sprintf("utils/backup.ImportSqlFile ! Restored database: %s", dbname)) f.Status = "ok" return }
//BackupDatabase - Perform a schema and database backup of a given database to local disk func (t *Task) BackupDatabase() (err error) { b := backupParams{} //Make sure database actually exists first. b.databaseName = t.Data if b.databaseName != "rdpg" { address := `127.0.0.1` sq := fmt.Sprintf(`SELECT 1 FROM cfsb.instances WHERE effective_at IS NOT NULL AND decommissioned_at IS NULL AND dbname = '%s';`, b.databaseName) databasesWithThatName, err := rdpgpg.GetList(address, sq) if err != nil { log.Error(fmt.Sprintf("Tasks.BackupDatabase() utils/backup.GetList(%s, %s) Error trying to query for database.", address, b.databaseName)) return err } if len(databasesWithThatName) == 0 { log.Error(fmt.Sprintf("Task.BackupDatabase() Attempt to back up non-existant or non-commissioned database with name: %s", b.databaseName)) return errors.New("Database doesn't exist.") } } lockAcquired, sessID := acquireBackupLock(b.databaseName) if !lockAcquired { log.Warn("Aborting Backup: Unable to acquire database lock. Is another backup already in progress?") return errors.New("Unable to acquire database lock") } defer releaseBackupLock(b.databaseName, sessID) b.pgDumpPath, err = config.GetValue(`pgDumpBinaryLocation`) if err != nil { return err } b.pgPort, err = config.GetValue(`BackupPort`) if err != nil { return err } b.basePath, err = config.GetValue(`BackupsPath`) if err != nil { return err } b.node, err = rdpgconsul.GetNode() if err != nil { return err } b.baseFileName = getBaseFileName() //Use this to keep schema and data file names the same err = createTargetFolder(b.basePath + `/` + b.databaseName) if err != nil { log.Error(fmt.Sprintf("tasks.BackupDatabase() Could not create target folder %s ! %s", b.basePath, err)) return err } schemaDataFileHistory, err := createSchemaAndDataFile(b) if err != nil { log.Error(fmt.Sprintf("tasks.BackupDatabase() Could not create schema and data file for database %s ! %s", b.databaseName, err)) schemaDataFileHistory.Status = `error` } err = history.InsertBackupHistory(schemaDataFileHistory) if b.databaseName == `rdpg` { globalsFileHistory, err := createGlobalsFile(b) if err != nil { log.Error(fmt.Sprintf("tasks.BackupDatabase() Could not create globals file for database %s ! %s", b.databaseName, err)) globalsFileHistory.Status = `error` } err = history.InsertBackupHistory(globalsFileHistory) } return }