commit de307873b2f65a59f88679f30fa206645329b6ba Author: Samuel Pua Date: Thu Aug 22 00:33:52 2019 +0800 First commit diff --git a/backup-manager b/backup-manager new file mode 100755 index 0000000..8db1fc8 Binary files /dev/null and b/backup-manager differ diff --git a/config.json b/config.json new file mode 100644 index 0000000..f1e7fcd --- /dev/null +++ b/config.json @@ -0,0 +1,69 @@ +{ + "TimeHour": 2, + "TimeMinute": 0, + "WorkingDir": "/mnt/seagate-backup/backups/", + "BackupPeriods": [ + { + "Interval": 1, + "Count": 3 + }, + { + "Interval": 30, + "Count": 2 + }, + { + "Interval": 180, + "Count": 1 + } + ], + "Hosts": [ + { + "Name": "taskus", + "IPAddr": "192.168.2.102", + "Port": 777, + "Username": "root", + "PrivKey": "/mnt/seagate-backup/backup-manager/id_rsa", + "RemoteDir": "/home/samuel/taskus" + }, + { + "Name": "samuelpua-mail", + "IPAddr": "samuelpua.com", + "Port": 777, + "Username": "root", + "PrivKey": "/mnt/seagate-backup/backup-manager/id_rsa", + "RemoteDir": "/docker/poste" + }, + { + "Name": "samuelpua-owncloud", + "IPAddr": "samuelpua.com", + "Port": 777, + "Username": "root", + "PrivKey": "/mnt/seagate-backup/backup-manager/id_rsa", + "RemoteDir": "/docker/owncloud" + }, + { + "Name": "samuelpua-docker-run", + "IPAddr": "samuelpua.com", + "Port": 777, + "Username": "root", + "PrivKey": "/mnt/seagate-backup/backup-manager/id_rsa", + "RemoteDir": "/docker/run" + }, + { + "Name": "gitea-data", + "IPAddr": "192.168.2.102", + "Port": 777, + "Username": "root", + "PrivKey": "/mnt/seagate-backup/backup-manager/id_rsa", + "RemoteDir": "/docker/persistent-data/gitea" + }, + { + "Name": "athena-docker-run", + "IPAddr": "192.168.2.102", + "Port": 777, + "Username": "root", + "PrivKey": "/mnt/seagate-backup/backup-manager/id_rsa", + "RemoteDir": "/docker/run" + } + ] +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..df0316b --- /dev/null +++ b/main.go @@ -0,0 +1,205 @@ +package main + +import ( + "os" + "os/exec" + "encoding/json" + "io/ioutil" + "log" + "bytes" + "time" + "fmt" + "path/filepath" + "strings" +) + +var ( + configFile = "config.json" +) + +// Config -- General config +type Config struct { + TimeHour int + TimeMinute int + WorkingDir string + BackupPeriods []BackupPeriod + Hosts []Host +} + +// Host -- Struct for each host in the config +type Host struct { + Name string + IPAddr string + Port int + Username string + PrivKey string + RemoteDir string +} + +// BackupPeriod -- Struct for individual backup period +type BackupPeriod struct { + Interval int + Count int +} + +func loadConfig(configFile string) Config { + var config Config + + fileBytes, err := ioutil.ReadFile(configFile) + if err != nil { + log.Println(err) + } + + err = json.Unmarshal(fileBytes, &config) + if err != nil { + log.Println(err) + } + + return config +} + +func runCommand(cmdline string) { + var errBuff bytes.Buffer + var outBuff bytes.Buffer + cmd := exec.Command("/bin/bash", "-c", cmdline) + cmd.Stderr = &errBuff + cmd.Stdout = &outBuff + log.Printf("Executing: " + cmdline) + err := cmd.Run() + log.Printf("Command finished with error: %v", err) + log.Printf("Std Out: %s", outBuff.String()) + log.Printf("Std Err: %s", errBuff.String()) +} + +func getNDay(hour int, min int, offset int) time.Time { + today := time.Now() + location := time.FixedZone("UTC+8", 8*60*60) + nextDate := time.Date(today.Year(), today.Month(), today.Day() + offset, hour, min, 0, 0, location) + return nextDate +} + +func getDir(path string, filter string) ([]string, []time.Time) { + var names []string + var dates []time.Time + + files, err := ioutil.ReadDir(path) + if err != nil { + log.Fatal(err) + } + + for _, file := range files { + if strings.Contains(file.Name(), filter) { + name := file.Name() + workingDateStr := name[len(filter)+1:len(name)] + workingDate, err := time.Parse("2006-01-02", workingDateStr) + if err!= nil { + log.Println(err) + } else { + names = append(names, name) + dates = append(dates, workingDate) + } + } + } + + return names, dates +} + +func backupToday(timeToday time.Time, config Config, host Host) { + dirDateStr := fmt.Sprintf("%04d-%02d-%02d", timeToday.Year(), timeToday.Month(), timeToday.Day()) + dirCommand := fmt.Sprintf("mkdir \"%s/%s-%s\"", config.WorkingDir, host.Name, dirDateStr) + runCommand(dirCommand) + + log.Printf("Current Host: %s", host.Name) + dateStr := fmt.Sprintf("%04d-%02d-%02d", timeToday.Year(), timeToday.Month(), timeToday.Day()) + command := fmt.Sprintf("rsync -azvhe \"ssh -i %s -p %d\" %s@%s:\"%s\" \"%s/%s-%s/\"", + host.PrivKey, host.Port, host.Username, host.IPAddr, host.RemoteDir, config.WorkingDir, host.Name, dateStr) + runCommand(command) +} + +func findBackupDate(dates []time.Time, findDate time.Time) int { + for i, date := range(dates) { + if date == findDate { + log.Printf("%v found", date) + return i + } + } + log.Printf("%v not found", findDate) + return 0 +} + +func enumerateDates(dates []time.Time, currDate time.Time, searchDayNum int) bool { + for i:=0; i