diff --git a/app.go b/app.go index e476a4d..ff96e51 100644 --- a/app.go +++ b/app.go @@ -385,19 +385,9 @@ func (a AppConfig) needHourlySnapshot() bool { return true } -func (a AppConfig) RunAppBackup() error { +func (a AppConfig) CheckZFS() error { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Start", a.Name) - } - schedule, err := a.getSchedule() - if err != nil { - if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error getting schedule : %s", a.Name, err) - } - return err - } - if schedule == "" { - return nil + log.Printf("AppConfig.CheckZFS : %s : Start", a.Name) } for _, src := range a.Sources { @@ -409,87 +399,142 @@ func (a AppConfig) RunAppBackup() error { err := cfg.Box[dest.Box()].ssh.createZFS(dest.Path() + "/" + src.Box() + "/" + src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error creating %s on %s", a.Name, dest.Path()+"/"+src.Box()+"/"+src.Path(), dest.Box()) + log.Printf("AppConfig.CheckZFS : %s : Error creating %s on %s", a.Name, dest.Path()+"/"+src.Box()+"/"+src.Path(), dest.Box()) } return err } } } } + return nil +} + +func (a AppConfig) ExecBefore(schedule string) error { + if *debugFlag { + log.Printf("AppConfig.ExecBefore : %s : Start %s", a.Name, schedule) + } + for k, v := range a.Before { re := regexp.MustCompile(k) if re.MatchString(schedule) { err := cfg.Box[v.Box()].ssh.exec(v.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error executing %s", a.Name, string(v)) + log.Printf("AppConfig.ExecBefore : %s : Error executing %s", a.Name, string(v)) + } + return err + } + } + } + return nil +} + +func (a AppConfig) ExecAfter(schedule string) error { + if *debugFlag { + log.Printf("AppConfig.ExecAfter : %s : Start %s", a.Name, schedule) + } + + for k, v := range a.After { + re := regexp.MustCompile(k) + if re.MatchString(schedule) { + err := cfg.Box[v.Box()].ssh.exec(v.Path()) + if err != nil { + if *debugFlag { + log.Printf("AppConfig.ExecAfter : %s : Error executing %s on %s", a.Name, v.Path(), v.Box()) } return err } } } - refreshSnapshot := make(map[string]bool) + return nil +} + +func (a AppConfig) TakeSnapshot(schedule string) error { + if *debugFlag { + log.Printf("AppConfig.TakeSnapshot : %s : Start %s", a.Name, schedule) + } + takeSnapshot := make(map[string]string) delSnapshot := make(map[string]string) for _, v := range a.Sources { takeSnapshot[v.Box()] = takeSnapshot[v.Box()] + " " + v.Path() - refreshSnapshot[v.Box()] = true for _, v2 := range a.Destinations { delSnapshot[v2.Box()] = delSnapshot[v2.Box()] + " " + v2.Path() + "/" + v.Box() + "/" + v.Path() } } for k, v := range takeSnapshot { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : taking snapshot on %s for %s", a.Name, k, v) + log.Printf("AppConfig.TakeSnapshot : %s : taking snapshot on %s for %s", a.Name, k, v) } err := cfg.Box[k].ssh.exec("/usr/sbin/zfsnap snapshot -p " + schedule + "- -a " + cfg.Zfsnap[schedule] + v) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error executing zfsnap on %s", a.Name, k) + log.Printf("AppConfig.TakeSnapshot : %s : Error executing zfsnap on %s", a.Name, k) } return err } } + + return nil +} + +func (a AppConfig) RefreshSnapshot() error { + if *debugFlag { + log.Printf("AppConfig.RefreshSnapshot : %s : Start", a.Name) + } + + refreshSnapshot := make(map[string]struct{}) + for _, v := range a.Sources { + refreshSnapshot[v.Box()] = struct{}{} + } for _, v := range a.Destinations { - refreshSnapshot[v.Box()] = true + refreshSnapshot[v.Box()] = struct{}{} } for k, _ := range refreshSnapshot { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : refreshing snapshots for source %s", a.Name, k) + log.Printf("AppConfig.RefreshSnapshot : %s : refreshing snapshots for source %s", a.Name, k) } err := cfg.Box[k].ssh.getSnapshotList() if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error getting snapshots on %s", a.Name, k) + log.Printf("AppConfig.RefreshSnapshot : %s : Error getting snapshots on %s", a.Name, k) } return err } } + return nil +} + +func (a AppConfig) SendSnapshots() error { + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Start", a.Name) + } + for _, src := range a.Sources { for _, dest := range a.Destinations { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Sending snapshots from %s to %s", a.Name, string(src), string(dest)) + log.Printf("AppConfig.SendSnapshots : %s : Sending snapshots from %s to %s", a.Name, string(src), string(dest)) } dLastSnapshot, err := cfg.Box[dest.Box()].ssh.getLastSnapshot(dest.Path() + "/" + src.Box() + "/" + src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : No snapshot for %s on %s", a.Name, string(src), dest.Box()) + log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s on %s", a.Name, string(src), dest.Box()) } sFirstSnapshot, err := cfg.Box[src.Box()].ssh.getFirstSnapshot(src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : No snapshot for %s", a.Name, string(src)) + log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s", a.Name, string(src)) } return err } if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Initializing snapshot on %s from %s", a.Name, dest.Box(), string(sFirstSnapshot)) + log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s", a.Name, dest.Box(), string(sFirstSnapshot)) } - err = cfg.Box[dest.Box()].ssh.exec("/usr/bin/ssh root@" + src.Box() + " /sbin/zfs send " + string(sFirstSnapshot) + " | /sbin/zfs recv -F " + dest.Path() + "/" + src.Box() + "/" + src.Path()) + err = cfg.Box[dest.Box()].ssh.exec("/usr/bin/ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " /sbin/zfs send " + string(sFirstSnapshot) + " | /sbin/zfs recv -F " + dest.Path() + "/" + src.Box() + "/" + src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Initializing snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sFirstSnapshot), err) + log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sFirstSnapshot), err) } return err } @@ -499,23 +544,23 @@ func (a AppConfig) RunAppBackup() error { sCurrSnapshot = sNextSnapshot sNextSnapshot, err = cfg.Box[src.Box()].ssh.getNextSnapshot(sNextSnapshot) if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) + log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) } - err = cfg.Box[dest.Box()].ssh.exec("/usr/bin/ssh root@" + src.Box() + " /sbin/zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | /sbin/zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) + err = cfg.Box[dest.Box()].ssh.exec("/usr/bin/ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " /sbin/zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | /sbin/zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) + log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) } return err } } if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : All snapshots sent for %s", a.Name, string(src)) + log.Printf("AppConfig.SendSnapshots : %s : All snapshots sent for %s", a.Name, string(src)) } } else { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Last snapshot on %s is %s", a.Name, dest.Box(), string(dLastSnapshot)) + log.Printf("AppConfig.SendSnapshots : %s : Last snapshot on %s is %s", a.Name, dest.Box(), string(dLastSnapshot)) } var sCurrSnapshot Snapshot sNextSnapshot := Snapshot(string(dLastSnapshot)[len(string(dest))+2:]) @@ -523,12 +568,12 @@ func (a AppConfig) RunAppBackup() error { sCurrSnapshot = sNextSnapshot sNextSnapshot, err = cfg.Box[src.Box()].ssh.getNextSnapshot(sNextSnapshot) if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) + log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) } - err = cfg.Box[dest.Box()].ssh.exec("/usr/bin/ssh root@" + src.Box() + " /sbin/zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | /sbin/zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) + err = cfg.Box[dest.Box()].ssh.exec("/usr/bin/ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " /sbin/zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | /sbin/zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) + log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) } return err } @@ -536,41 +581,102 @@ func (a AppConfig) RunAppBackup() error { } } } - for k, v := range takeSnapshot { - if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : cleaning snapshot on %s for %s", a.Name, k, v) - } - err := cfg.Box[k].ssh.exec("/usr/sbin/zfsnap destroy -p hourly- -p daily- -p weekly- -p monthly- -p yearly- " + v) - if err != nil { - if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error executing zfsnap on %s", a.Name, k) - } - return err - } - } - for k, v := range delSnapshot { - if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : cleaning snapshot on %s for %s", a.Name, k, v) - } - err := cfg.Box[k].ssh.exec("/usr/sbin/zfsnap destroy -p hourly- -p daily- -p weekly- -p monthly- -p yearly- " + v) - if err != nil { - if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error executing zfsnap on %s", a.Name, k) - } - return err - } - } - for k, v := range a.After { - re := regexp.MustCompile(k) - if re.MatchString(schedule) { - err := cfg.Box[v.Box()].ssh.exec(v.Path()) - if err != nil { - if *debugFlag { - log.Printf("AppConfig.RunAppBackup : %s : Error executing %s on %s", a.Name, v.Path(), v.Box()) - } - return err - } - } - } + return nil +} + +func (a AppConfig) CleanupSnapshot() error { + if *debugFlag { + log.Printf("AppConfig.CleanupSnapshot : %s : Start]", a.Name) + } + + cleanupSnapshot := make(map[string]string) + + for _, dest := range a.Destinations { + for _, src := range a.Sources { + cleanupSnapshot[src.Box()] = cleanupSnapshot[src.Box()] + " " + src.Path() + cleanupSnapshot[dest.Box()] = cleanupSnapshot[dest.Box()] + " " + dest.Path() + "/" + src.Box() + "/" + src.Path() + } + } + + for k, v := range cleanupSnapshot { + if *debugFlag { + log.Printf("AppConfig.CleanupSnapshot : %s : cleaning snapshots on %s for%s", a.Name, k, v) + } + err := cfg.Box[k].ssh.exec("/usr/sbin/zfsnap destroy -p hourly- -p daily- -p weekly- -p monthly- -p yearly-" + v) + if err != nil { + if *debugFlag { + log.Printf("AppConfig.CleanupSnapshot : %s : Error executing zfsnap on %s", a.Name, k) + } + return err + } + } + + return nil +} + +func (a AppConfig) RunAppBackup() error { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : Start", a.Name) + } + schedule, err := a.getSchedule() + if err != nil { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : Error getting schedule : %s", a.Name, err) + } + return err + } + + if schedule != "" { + err = a.CheckZFS() + if err != nil { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : CheckZFS : %s", a.Name, err) + } + return err + } + + err = a.ExecBefore(schedule) + if err != nil { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : ExecBefore : %s", a.Name, err) + } + return err + } + } + + err = a.RefreshSnapshot() + if err != nil { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : RefreshSnapshot : %s", a.Name, err) + } + return err + } + + err = a.SendSnapshots() + if err != nil { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : SendSnapshots : %s", a.Name, err) + } + return err + } + + if schedule != "" { + err = a.ExecAfter(schedule) + if err != nil { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : ExecAfter : %s", a.Name, err) + } + return err + } + } + + err = a.CleanupSnapshot() + if err != nil { + if *debugFlag { + log.Printf("AppConfig.RunAppBackup : %s : RefreshSnapshot : %s", a.Name, err) + } + return err + } + return nil }