Initial commit
This commit is contained in:
commit
c15d4128e3
3 changed files with 169 additions and 0 deletions
11
go.mod
Normal file
11
go.mod
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
module check_restic
|
||||||
|
|
||||||
|
go 1.17
|
||||||
|
|
||||||
|
require github.com/pkg/sftp v1.13.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
|
||||||
|
)
|
||||||
21
go.sum
Normal file
21
go.sum
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
github.com/pkg/sftp v1.13.4 h1:Lb0RYJCmgUcBgZosfoi9Y9sbl6+LJgOIgk/2Y4YjMFg=
|
||||||
|
github.com/pkg/sftp v1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
|
||||||
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
|
||||||
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
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