diff --git a/app.go b/app.go index 32abe71..25e1ee0 100644 --- a/app.go +++ b/app.go @@ -540,104 +540,106 @@ func (a AppConfig) SendSnapshots() (err error) { for _, src := range a.Sources { for _, dest := range a.Destinations { - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Sending snapshots from %s to %s", a.Name, string(src), string(dest)) - } - - var dLastSnapshot Snapshot - dLastSnapshot, err = cfg.Box[dest.Box()].ZFSGetLastSnapshot(dest.Path() + "/" + src.Box() + "/" + src.Path()) - if err != nil && err.Error() == "no snapshot" { + if cfg.Box[dest.Box()].online { if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s on %s", a.Name, string(src), dest.Box()) + log.Printf("AppConfig.SendSnapshots : %s : Sending snapshots from %s to %s", a.Name, string(src), string(dest)) } - var sFirstSnapshot Snapshot - sFirstSnapshot, err = cfg.Box[src.Box()].ZFSGetFirstSnapshot(src.Path()) - if err != nil { + var dLastSnapshot Snapshot + dLastSnapshot, err = cfg.Box[dest.Box()].ZFSGetLastSnapshot(dest.Path() + "/" + src.Box() + "/" + src.Path()) + if err != nil && err.Error() == "no snapshot" { if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s", a.Name, string(src)) + log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s on %s", a.Name, string(src), dest.Box()) } - return - } - if !cfg.Box[dest.Box()].ZFSIsZFS(dest.Path() + "/" + src.Box() + "/" + src.Path()) { - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Creating on %s path %s", a.Name, dest.Box(), dest.Path()+"/"+src.Box()+"/"+src.Path()) - } - if err = cfg.Box[dest.Box()].ZFSCreateZFS(dest.Path() + "/" + src.Box() + "/" + src.Path()); err != nil { - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Creating on %s path %s failed (%s)", a.Name, dest.Box(), dest.Path()+"/"+src.Box()+"/"+src.Path(), err) - } - return - } - } - - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s", a.Name, dest.Box(), string(sFirstSnapshot)) - } - _, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send " + string(sFirstSnapshot) + " | zfs recv -F " + dest.Path() + "/" + src.Box() + "/" + src.Path()) - if err != nil { - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sFirstSnapshot), err) - } - return - } - - var ( - sCurrSnapshot, sNextSnapshot Snapshot - isLastSnapshot bool - ) - sNextSnapshot = sFirstSnapshot - isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) - for !isLastSnapshot { - sCurrSnapshot = sNextSnapshot - sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot) - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) - } - if err != nil && err.Error() != "no snapshot" { - return - } - _, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) + var sFirstSnapshot Snapshot + sFirstSnapshot, err = cfg.Box[src.Box()].ZFSGetFirstSnapshot(src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) + log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s", a.Name, string(src)) } return } - isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) - } - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : All snapshots sent for %s", a.Name, string(src)) - } - } else { - if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Last snapshot on %s is %s", a.Name, dest.Box(), string(dLastSnapshot)) - } - var ( - sCurrSnapshot, sNextSnapshot Snapshot - isLastSnapshot bool - ) - sNextSnapshot = Snapshot(string(dLastSnapshot)[len(dest.Path())+len(src.Box())+2:]) - isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) - for !isLastSnapshot { - sCurrSnapshot = sNextSnapshot - sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot) + if !cfg.Box[dest.Box()].ZFSIsZFS(dest.Path() + "/" + src.Box() + "/" + src.Path()) { + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Creating on %s path %s", a.Name, dest.Box(), dest.Path()+"/"+src.Box()+"/"+src.Path()) + } + if err = cfg.Box[dest.Box()].ZFSCreateZFS(dest.Path() + "/" + src.Box() + "/" + src.Path()); err != nil { + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Creating on %s path %s failed (%s)", a.Name, dest.Box(), dest.Path()+"/"+src.Box()+"/"+src.Path(), err) + } + return + } + } + if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) + log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s", a.Name, dest.Box(), string(sFirstSnapshot)) } - if err != nil && err.Error() != "no snapshot" { - return - } - _, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) + _, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send " + string(sFirstSnapshot) + " | zfs recv -F " + dest.Path() + "/" + src.Box() + "/" + src.Path()) if err != nil { if *debugFlag { - log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) + log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sFirstSnapshot), err) } return } + + var ( + sCurrSnapshot, sNextSnapshot Snapshot + isLastSnapshot bool + ) + sNextSnapshot = sFirstSnapshot isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) + for !isLastSnapshot { + sCurrSnapshot = sNextSnapshot + sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot) + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) + } + if err != nil && err.Error() != "no snapshot" { + return + } + _, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) + if err != nil { + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) + } + return + } + isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) + } + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : All snapshots sent for %s", a.Name, string(src)) + } + + } else { + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Last snapshot on %s is %s", a.Name, dest.Box(), string(dLastSnapshot)) + } + var ( + sCurrSnapshot, sNextSnapshot Snapshot + isLastSnapshot bool + ) + sNextSnapshot = Snapshot(string(dLastSnapshot)[len(dest.Path())+len(src.Box())+2:]) + isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) + for !isLastSnapshot { + sCurrSnapshot = sNextSnapshot + sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot) + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box()) + } + if err != nil && err.Error() != "no snapshot" { + return + } + _, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path()) + if err != nil { + if *debugFlag { + log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err) + } + return + } + isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) + } } } } diff --git a/box.go b/box.go index ca9f606..b132993 100644 --- a/box.go +++ b/box.go @@ -9,12 +9,13 @@ import ( ) type Box struct { - Addr string `json:"addr"` - User string `json:"user"` - Key string `json:"key"` - Name string `json:"-"` - ssh *SSHConfig - zfs *ZFSConfig + Addr string `json:"addr"` + User string `json:"user"` + Key string `json:"key"` + Name string `json:"-"` + ssh *SSHConfig + zfs *ZFSConfig + online bool } func (b *Box) ZFSTakeSnapshot(schedule, path string) (err error) { @@ -22,6 +23,11 @@ func (b *Box) ZFSTakeSnapshot(schedule, path string) (err error) { log.Printf("Box.ZFSTakeSnapshot : %s : Taking snapshot on %s for %s", b.Name, path, schedule) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + err = b.SnapshotInitialize() if err != nil { return @@ -49,9 +55,14 @@ func (b *Box) ZFSGetLastSnapshot(path string) (last Snapshot, err error) { log.Printf("Box.ZFSGetLastSnapshot : %s : Start %s (%d snapshots)", b.Name, path, len(b.zfs.SnapshotList)) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + err = b.SnapshotInitialize() if err != nil { - return + return last, err } b.zfs.M.Lock() @@ -73,6 +84,11 @@ func (b *Box) ZFSIsLastSnapshot(src Snapshot) (is bool, err error) { log.Printf("Box.ZFSIsLastSnapshot : %s : Start %s", b.Name, string(src)) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + err = b.SnapshotInitialize() if err != nil { return @@ -95,6 +111,11 @@ func (b *Box) ZFSGetFirstSnapshot(path string) (first Snapshot, err error) { log.Printf("Box.ZFSGetFirstSnapshot : %s : Start %s", b.Name, path) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + err = b.SnapshotInitialize() if err != nil { return @@ -118,6 +139,11 @@ func (b *Box) ZFSGetNextSnapshot(src Snapshot) (next Snapshot, err error) { log.Printf("Box.ZFSGetNextSnapshot : %s : Start %s", b.Name, string(src)) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + err = b.SnapshotInitialize() if err != nil { return @@ -151,6 +177,11 @@ func (b *Box) ZFSUpdateSnapshotList() (err error) { log.Printf("Box.ZFSUpdateSnapshotList : %s : Start", b.Name) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + b.zfs.M.Lock() if b.zfs.SnapshotDeleted || b.zfs.SnapshotAdded { b.zfs.SnapshotInitialized = false @@ -166,6 +197,11 @@ func (b *Box) ZFSGetSnapshotList() (snaps []Snapshot, err error) { log.Printf("Box.ZFSGetSnapshotList : %s : Start", b.Name) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + err = b.SnapshotInitialize() if err != nil { return @@ -179,6 +215,15 @@ func (b *Box) ZFSGetSnapshotList() (snaps []Snapshot, err error) { } func (b *Box) SnapshotInitialize() (err error) { + if *debugFlag { + log.Printf("Box.SnapshotInitialize : %s : Start", b.Name) + } + + if !b.online { + err = fmt.Errorf("box offline") + return + } + b.zfs.M.Lock() defer b.zfs.M.Unlock() @@ -227,6 +272,11 @@ func (b *Box) ZFSUpdateList() (err error) { log.Printf("Box.ZFSUpdateList : %s : Start", b.Name) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + b.zfs.M.Lock() if b.zfs.ZFSDeleted || b.zfs.ZFSAdded { b.zfs.ZFSInitialized = false @@ -242,6 +292,10 @@ func (b *Box) ZFSIsZFS(path string) bool { log.Printf("Box.ZFSIsZFS : %s : Start %s", b.Name, path) } + if !b.online { + return false + } + err := b.ZFSInitialize() if err != nil { return false @@ -262,6 +316,11 @@ func (b *Box) ZFSCreateZFS(path string) (err error) { log.Printf("Box.ZFSCreateZFS : %s : Start %s", b.Name, path) } + if !b.online { + err = fmt.Errorf("box offline") + return + } + err = b.ZFSInitialize() if err != nil { return @@ -303,6 +362,14 @@ func (b *Box) ZFSCreateZFS(path string) (err error) { func (b *Box) ZFSInitialize() (err error) { b.zfs.M.Lock() defer b.zfs.M.Unlock() + if *debugFlag { + log.Printf("Box.ZFSInitialize : %s : Start", b.Name) + } + + if !b.online { + err = fmt.Errorf("box offline") + return + } if b.zfs.ZFSInitialized { return nil @@ -341,6 +408,11 @@ func (b *Box) ZFSInitialize() (err error) { } func (b *Box) SSHExec(cmd string) (buf *bytes.Buffer, err error) { + if !b.online { + err = fmt.Errorf("box offline") + return + } + buf, err = b.ssh.exec(cmd) return } diff --git a/config.go b/config.go index 6a94009..f15bf01 100644 --- a/config.go +++ b/config.go @@ -53,6 +53,7 @@ func (c *Config) Load() error { for k, v := range c.Box { v.Name = k + v.online = false v.zfs = NewZFSConfig() s := &SSHConfig{ logged: false, @@ -97,31 +98,32 @@ func (c *Config) Load() error { log.Printf("Config.Load : ssh.Dial(%s) : %s", k, err) } return err - } - - session, err := s.client.NewSession() - if err != nil { - if *debugFlag { - log.Printf("Config.Load : client.NewSession(%s) : %s", k, err) + } else { + v.online = true + session, err := s.client.NewSession() + if err != nil { + if *debugFlag { + log.Printf("Config.Load : client.NewSession(%s) : %s", k, err) + } + return err } - return err - } - var b bytes.Buffer - session.Stdout = &b + var b bytes.Buffer + session.Stdout = &b - err = session.Run("TZ=\"" + cfg.Timezone + "\" zfsnap --version") - if err != nil { - if *debugFlag { - log.Printf("Config.Load : client.NewSession(%s) : %s", k, err) + err = session.Run("TZ=\"" + cfg.Timezone + "\" zfsnap --version") + if err != nil { + if *debugFlag { + log.Printf("Config.Load : client.NewSession(%s) : %s", k, err) + } + return err } - return err + if *debugFlag { + log.Printf("Config.Load : logged into %s : %s", k, b.String()) + } + session.Close() + s.logged = true } - if *debugFlag { - log.Printf("Config.Load : logged into %s : %s", k, b.String()) - } - session.Close() - s.logged = true } for _, app := range c.Apps { @@ -132,7 +134,11 @@ func (c *Config) Load() error { if _, ok := cfg.Box[src.Box()]; !ok { return fmt.Errorf("No box defined for source : %s", string(src)) } + if !cfg.Box[src.Box()].online { + return fmt.Errorf("Source box offline for app : %s", app.Name) + } } + var allOffline bool = true for _, dest := range app.Destinations { if !dest.Valid() { return fmt.Errorf("Destination not valid : %s", string(dest)) @@ -140,7 +146,14 @@ func (c *Config) Load() error { if _, ok := cfg.Box[dest.Box()]; !ok { return fmt.Errorf("No box defined for destination : %s", string(dest)) } + if cfg.Box[dest.Box()].online { + allOffline = false + } } + if allOffline { + return fmt.Errorf("No online destination box for app : %s", app.Name) + } + for val, before := range app.Before { _, err = regexp.Compile(val) if err != nil { diff --git a/version.go b/version.go index ab46b22..6b7bf1b 100644 --- a/version.go +++ b/version.go @@ -1,6 +1,6 @@ // Code generated by version.sh (@generated) DO NOT EDIT. package main -var githash = "0083ab6" -var buildstamp = "2022-04-16_07:16:27" -var commits = "28" -var version = "0083ab6-b28 - 2022-04-16_07:16:27" +var githash = "762c538" +var buildstamp = "2022-04-16_12:55:05" +var commits = "29" +var version = "762c538-b29 - 2022-04-16_12:55:05"