-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
165 lines (139 loc) · 4.88 KB
/
main.go
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
package main
import (
"encoding/json"
"fmt"
"os"
"sync"
flags "github.com/jessevdk/go-flags"
"github.com/verdel/squid-auth-healthcheck/pkg/checker"
"github.com/verdel/squid-auth-healthcheck/pkg/slice"
)
const (
version = "0.0.4"
)
var opts struct {
URL []string `short:"u" long:"url" description:"url to check for availability (required)" required:"true"`
AuthType []string `long:"auth-type" description:"type of used proxy authentication mechanism. [ntlm, kerberos, no, all] (required)" required:"true"`
ProxyAddr string `long:"proxy-addr" description:"proxy server address (required)" required:"true"`
ProxyPort int `long:"proxy-port" description:"proxy server port (default: 3128)" default:"3128"`
ProxyUsername string `long:"proxy-username" description:"proxy user login"`
ProxyPassword string `long:"proxy-password" description:"proxy user password"`
ConnectionTimeout int `long:"timeout" description:"healthcheck connection timeout in seconds (default: 2)" default:"2"`
StrictURL bool `long:"strict-url" description:"the check returns a positive result only if all URLs are available"`
StrictAuth bool `long:"strict-auth" description:"the check returns a positive result only if url are available with all auth method"`
ClusterCheck bool `long:"cluster-check" description:"check through proxy cluster node instead standalone proxy server"`
IngressProxyAddr string `long:"ingress-proxy-addr" description:"ingress proxy address. It will be used for kerberos verification. This FQDN will be used when forming the request, but the IP address of the node of the proxy server cluster will be used as the IP address" required:"false"`
Verbose bool `short:"v" long:"verbose" description:"output verbose healthcheck information"`
}
var allowAuthType = []string{"ntlm", "kerberos", "no", "all"}
func exitOK(verbose bool) {
if !verbose {
fmt.Println(1)
}
os.Exit(0)
}
func exitErr(verbose bool) {
if !verbose {
fmt.Println(0)
}
os.Exit(1)
}
func main() {
parser := flags.NewParser(&opts, flags.Default)
parser.Usage = fmt.Sprintf("\n\nVersion: %s", version)
if len(os.Args) == 1 {
parser.WriteHelp(os.Stderr)
os.Exit(0)
}
_, err := parser.Parse()
if err != nil {
os.Exit(1)
}
if len(opts.AuthType) > 1 || (len(opts.AuthType) == 1 && !slice.StringInSlice("no", opts.AuthType)) {
if opts.ProxyPassword == "" || opts.ProxyUsername == "" {
fmt.Println("the required flags `--proxy-username' and `--proxy-password' were not specified")
os.Exit(1)
}
}
if opts.ClusterCheck && opts.IngressProxyAddr == "" {
fmt.Println("the required flags `--ingress-proxy-addr' were not specified")
os.Exit(1)
}
var authType []string
if slice.StringInSlice("all", opts.AuthType) {
for _, v := range allowAuthType {
if v != "all" {
authType = append(authType, v)
}
}
} else {
authType = make([]string, len(opts.AuthType))
copy(authType, opts.AuthType)
}
if len(authType) > len(allowAuthType) {
fmt.Println("Too many authentication type")
os.Exit(1)
}
for _, item := range authType {
if !slice.StringInSlice(item, allowAuthType) {
fmt.Printf("Authentication type %s is not allowed", item)
os.Exit(1)
}
}
var wg sync.WaitGroup
ch := make(chan checker.HealthResponse, len(authType)*len(opts.URL))
wg.Add(len(authType))
if slice.StringInSlice("ntlm", authType) {
var ntlm checker.Interface = checker.NewAuthNTLM(opts.ProxyAddr, opts.ProxyPort, opts.ProxyUsername, opts.ProxyPassword, opts.ConnectionTimeout)
go ntlm.Check(opts.URL, ch, &wg)
}
if slice.StringInSlice("kerberos", authType) {
var IngressProxyAddr string
if opts.ClusterCheck {
IngressProxyAddr = opts.IngressProxyAddr
} else {
IngressProxyAddr = opts.ProxyAddr
}
kerberos, err := checker.NewAuthKerberos(IngressProxyAddr, opts.ProxyAddr, opts.ProxyPort, opts.ProxyUsername, opts.ProxyPassword, opts.ConnectionTimeout)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
go kerberos.Check(opts.URL, ch, &wg)
}
if slice.StringInSlice("no", authType) {
var no checker.Interface = checker.NewAuthNo(opts.ProxyAddr, opts.ProxyPort, opts.ConnectionTimeout)
go no.Check(opts.URL, ch, &wg)
}
wg.Wait()
close(ch)
var result []checker.HealthResponse
var okURLResult []string
var okAuthResult []string
for response := range ch {
if response.Status == 1 {
okURLResult = slice.AppendIfMissing(okURLResult, response.URL)
okAuthResult = slice.AppendIfMissing(okAuthResult, response.AuthType)
}
result = append(result, response)
}
if opts.Verbose {
enc := json.NewEncoder(os.Stdout)
enc.Encode(result)
}
if opts.StrictAuth {
if len(okAuthResult) < len(authType) {
exitErr(opts.Verbose)
}
}
if opts.StrictURL {
if len(okURLResult) < len(opts.URL) {
exitErr(opts.Verbose)
}
} else {
if len(okURLResult) == 0 {
exitErr(opts.Verbose)
}
}
exitOK(opts.Verbose)
}