-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathip_wrapper.go
More file actions
172 lines (154 loc) · 3.28 KB
/
ip_wrapper.go
File metadata and controls
172 lines (154 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package main
import (
"bytes"
"flag"
"fmt"
"net"
"os"
"os/exec"
"regexp"
"log"
"syscall"
)
var verbose bool
var hostname string
var tail []string
var version string
var printHelp bool
var printVersion bool
func initArgs() {
flag.BoolVar(&printHelp, "help", false, "print help and exit")
flag.BoolVar(&printVersion, "V", false, "print version and exit")
flag.BoolVar(&verbose, "v", false, "be verbose")
flag.StringVar(&hostname, "host", "", "the hostname to check")
flag.Parse()
if printHelp {
flag.PrintDefaults()
os.Exit(0)
}
if printVersion {
fmt.Println("ip_wrapper Version:", version)
os.Exit(0)
}
// this is the command to run
tail = flag.Args()
if len(tail) < 1 {
os.Exit(3)
}
}
func main() {
initArgs()
if verbose {
fmt.Println("host : ", hostname)
fmt.Println("command: ", tail)
}
// get the real path of the executable
// exec.Command() would do LookPath, but this is for error handling
binary, lookErr := exec.LookPath(tail[0])
// this is not syscall.Exec(), so we need to shift the first element off
tail = tail[1:]
if lookErr != nil {
fmt.Println(lookErr)
// executable check command not found
exitWithProperCode(3, []int{3})
} else if verbose {
fmt.Printf("Found binary: %s\n", binary)
}
ipAddrs, err := net.LookupHost(hostname)
if err != nil {
fmt.Println(err)
exitWithProperCode(1, []int{1})
}
exitCode := 0
total := 0
exitCodes := []int{}
for _, ip := range ipAddrs {
exitCode = run(ip, binary, tail)
exitCodes = append(exitCodes, exitCode)
total += exitCode
}
exitWithProperCode(total, exitCodes)
}
func run(ip string, binary string, tail []string) int {
if verbose {
fmt.Printf("Checking IP: %s\n", ip)
}
// replace '%%IP%%' placeholder in the command to be executed
reg, err := regexp.Compile("%%IP%%")
if err != nil {
log.Fatal(err)
return 2
}
for k, v := range tail {
tail[k] = reg.ReplaceAllString(v, ip)
}
// execute a sensu check, we need
// - return value of the executed check
// - stdout + stderr for debugging
cmd := exec.Command(binary, tail...)
var out bytes.Buffer
cmd.Stdout = &out
if err != nil {
log.Fatal(err)
return 2
}
execErr := cmd.Start()
if err != nil {
log.Fatal(err)
return 2
}
execErr = cmd.Wait()
// the exit code was zero
if execErr != nil {
exitCode2 := 0
if exitError, ok := execErr.(*exec.ExitError); ok {
ws := exitError.Sys().(syscall.WaitStatus)
exitCode2 = ws.ExitStatus()
if verbose {
fmt.Printf("Found exit code: %d\n", exitCode2)
}
} else {
exitCode2 = 2
}
return exitCode2
}
// exit code was 0
return 0
}
func exitWithProperCode(total int, exitCodes []int) {
msg := "Check"
status := ""
rest := ""
finalExitCode := 0
if total == 0 {
status = "OK"
rest = "OK"
} else {
if hasOnlyUnknowns(exitCodes) {
status = "UNKNOWN"
rest = "Check not found"
finalExitCode = 3
} else {
if verbose {
fmt.Printf("All exitCodes:")
for _, ex := range exitCodes {
fmt.Printf(" %d", ex)
}
fmt.Printf("\n")
}
status = "CRITICAL"
rest = fmt.Sprintf("%d failed", len(exitCodes))
finalExitCode = 2
}
}
fmt.Printf("%s %s: %s\n", msg, status, rest)
os.Exit(finalExitCode)
}
func hasOnlyUnknowns(exitCodes []int) bool {
for _, v := range exitCodes {
if v != 3 {
return false
}
}
return true
}