Initial commit
This commit is contained in:
commit
c15d4128e3
3 changed files with 169 additions and 0 deletions
137
main.go
Normal file
137
main.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/sftp"
|
||||
)
|
||||
|
||||
const (
|
||||
OK = 0
|
||||
WARNING = 1
|
||||
CRITICAL = 2
|
||||
UNKNOWN = 3
|
||||
)
|
||||
|
||||
var (
|
||||
warning = flag.Duration("warning", -1, "return WARNING if the lastest snapshot is older than the specified number of hours")
|
||||
critical = flag.Duration("critical", -1, "return CRITICAL if the lastest snapshot is older than the specified number of hours")
|
||||
repoPath = flag.String("repository", "", "path to restic repository on sftp target")
|
||||
sftpHost = flag.String("host", "", "ssh host to be used for sftp connection")
|
||||
sftpUser = flag.String("user", "", "ssh user to be used for sftp connection")
|
||||
sftpPort = flag.String("port", "22", "ssh port to be used for sftp connection")
|
||||
)
|
||||
|
||||
func parseArgs() error {
|
||||
flag.Parse()
|
||||
if *warning < 0 {
|
||||
return fmt.Errorf("The option 'warning' needs to be set and greater than 0.")
|
||||
}
|
||||
if *critical < 0 {
|
||||
return fmt.Errorf("The option 'critical' needs to be set and greater than 0.")
|
||||
}
|
||||
if *repoPath == "" {
|
||||
return fmt.Errorf("The option 'repository' needs to be set.")
|
||||
}
|
||||
if *sftpHost == "" {
|
||||
return fmt.Errorf("The option 'host' needs to be set.")
|
||||
}
|
||||
if *sftpUser == "" {
|
||||
return fmt.Errorf("The option 'user' needs to be set.")
|
||||
}
|
||||
if *sftpPort == "" {
|
||||
return fmt.Errorf("The option 'port' needs to be a valid port.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStatusStr(status int) string {
|
||||
switch status {
|
||||
case OK:
|
||||
return "OK"
|
||||
case WARNING:
|
||||
return "WARNING"
|
||||
case CRITICAL:
|
||||
return "CRITICAL"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
rc, msg := mainReturnWithStatus()
|
||||
fmt.Printf("%s: %s\n", getStatusStr(rc), msg)
|
||||
os.Exit(rc)
|
||||
}
|
||||
|
||||
func mainReturnWithStatus() (int, string) {
|
||||
err := parseArgs()
|
||||
if err != nil {
|
||||
return UNKNOWN, err.Error()
|
||||
}
|
||||
|
||||
// Connect to a remote host and request the sftp subsystem via the 'ssh'
|
||||
// command. This assumes that passwordless login is correctly configured.
|
||||
cmd := exec.Command("ssh", *sftpHost, "-l", *sftpUser, "-p", *sftpPort, "-s", "sftp")
|
||||
|
||||
// send errors from ssh to stderr
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
// get stdin and stdout
|
||||
wr, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return UNKNOWN, err.Error()
|
||||
}
|
||||
rd, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return UNKNOWN, err.Error()
|
||||
}
|
||||
|
||||
// start the process
|
||||
if err := cmd.Start(); err != nil {
|
||||
return UNKNOWN, err.Error()
|
||||
}
|
||||
defer cmd.Wait()
|
||||
|
||||
// open the SFTP session
|
||||
client, err := sftp.NewClientPipe(rd, wr)
|
||||
if err != nil {
|
||||
return UNKNOWN, err.Error()
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// get a list of all snapshots in the restic repository
|
||||
files, err := client.ReadDir(*repoPath + "/snapshots")
|
||||
if err != nil {
|
||||
return UNKNOWN, err.Error()
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return CRITICAL, "no snapshots found"
|
||||
}
|
||||
|
||||
// sort snapshots by modtime
|
||||
sort.Slice(files, func(a, b int) bool {
|
||||
return files[b].ModTime().Before(files[a].ModTime())
|
||||
})
|
||||
|
||||
age := time.Now().Sub(files[0].ModTime())
|
||||
|
||||
// sanity check
|
||||
if age < 0 {
|
||||
return CRITICAL, "latest snapshot is in the future"
|
||||
}
|
||||
msg := fmt.Sprintf("latest snapshot created %s ago", age.Round(time.Second))
|
||||
if age > *critical {
|
||||
return CRITICAL, msg
|
||||
} else if age > *warning {
|
||||
return WARNING, msg
|
||||
} else {
|
||||
return OK, msg
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue