forked from stakater/IngressMonitorController
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpingdom-monitor.go
292 lines (249 loc) · 9.17 KB
/
pingdom-monitor.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
package pingdom
import (
"encoding/json"
"errors"
"fmt"
"net/url"
"os"
"strconv"
"strings"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"github.com/russellcardullo/go-pingdom/pingdom"
endpointmonitorv1alpha1 "github.com/stakater/IngressMonitorController/v2/api/v1alpha1"
"github.com/stakater/IngressMonitorController/v2/pkg/config"
"github.com/stakater/IngressMonitorController/v2/pkg/models"
"github.com/stakater/IngressMonitorController/v2/pkg/util"
)
var log = logf.Log.WithName("pingdom")
// PingdomMonitorService interfaces with MonitorService
type PingdomMonitorService struct {
apiToken string
url string
alertContacts string
alertIntegrations string
teamAlertContacts string
client *pingdom.Client
}
func (monitor *PingdomMonitorService) Equal(oldMonitor models.Monitor, newMonitor models.Monitor) bool {
// TODO: Retrieve oldMonitor config and compare it here
return false
}
func (service *PingdomMonitorService) Setup(p config.Provider) {
service.apiToken = p.ApiToken
service.url = p.ApiURL
service.alertContacts = p.AlertContacts
service.alertIntegrations = p.AlertIntegrations
service.teamAlertContacts = p.TeamAlertContacts
var err error
service.client, err = pingdom.NewClientWithConfig(pingdom.ClientConfig{
APIToken: service.apiToken,
BaseURL: service.url,
})
if err != nil {
log.Info("Error Seting Up Monitor Service: " + err.Error())
}
}
func (service *PingdomMonitorService) GetByName(name string) (*models.Monitor, error) {
var match *models.Monitor
monitors := service.GetAll()
for _, mon := range monitors {
if mon.Name == name {
return &mon, nil
}
}
return match, fmt.Errorf("Unable to locate monitor with name %v", name)
}
func (service *PingdomMonitorService) GetAll() []models.Monitor {
var monitors []models.Monitor
checks, err := service.client.Checks.List()
if err != nil {
log.Info("Error received while listing checks: " + err.Error())
return nil
}
for _, mon := range checks {
newMon := models.Monitor{
URL: mon.Hostname,
ID: fmt.Sprintf("%v", mon.ID),
Name: mon.Name,
}
monitors = append(monitors, newMon)
}
return monitors
}
func (service *PingdomMonitorService) Add(m models.Monitor) {
httpCheck := service.createHttpCheck(m)
_, err := service.client.Checks.Create(&httpCheck)
if err != nil {
log.Info("Error Adding Monitor: " + err.Error())
} else {
log.Info("Added monitor for: " + m.Name)
}
}
func (service *PingdomMonitorService) Update(m models.Monitor) {
httpCheck := service.createHttpCheck(m)
monitorID, _ := strconv.Atoi(m.ID)
resp, err := service.client.Checks.Update(monitorID, &httpCheck)
if err != nil {
log.Info("Error updating Monitor: " + err.Error())
} else {
log.Info(fmt.Sprintf("Updated Monitor: %v", resp))
}
}
func (service *PingdomMonitorService) Remove(m models.Monitor) {
monitorID, _ := strconv.Atoi(m.ID)
resp, err := service.client.Checks.Delete(monitorID)
if err != nil {
log.Info("Error deleting Monitor: " + err.Error())
} else {
log.Info(fmt.Sprintf("Delete Monitor: %v", resp))
}
}
func (service *PingdomMonitorService) createHttpCheck(monitor models.Monitor) pingdom.HttpCheck {
httpCheck := pingdom.HttpCheck{}
url, err := url.Parse(monitor.URL)
if err != nil {
log.Info("Unable to parse the URL: " + service.url)
}
if url.Scheme == "https" {
httpCheck.Encryption = true
} else {
httpCheck.Encryption = false
}
httpCheck.Hostname = url.Host
httpCheck.Url = url.Path
httpCheck.Name = monitor.Name
// Set the default values if they are present in provider config
// all of them can be overridden via EndpointMonitor specific options
// Default alert contacts
if len(service.alertContacts) > 0 {
userIdsStringArray := strings.Split(service.alertContacts, "-")
if userIds, err := util.SliceAtoi(userIdsStringArray); err != nil {
log.Info(err.Error())
} else {
httpCheck.UserIds = userIds
}
}
// Default alert integrations
if len(service.alertIntegrations) > 0 {
integrationIdsStringArray := strings.Split(service.alertIntegrations, "-")
if integrationIds, err := util.SliceAtoi(integrationIdsStringArray); err != nil {
log.Info(err.Error())
} else {
httpCheck.IntegrationIds = integrationIds
}
}
// Default team alert contacts
if len(service.teamAlertContacts) > 0 {
teamAlertContactsStringArray := strings.Split(service.teamAlertContacts, "-")
if teamAlertsIds, err := util.SliceAtoi(teamAlertContactsStringArray); err != nil {
log.Info(err.Error())
} else {
httpCheck.TeamIds = teamAlertsIds
}
}
// Generate check itself
service.addConfigToHttpCheck(&httpCheck, monitor.Config)
return httpCheck
}
func (service *PingdomMonitorService) addConfigToHttpCheck(httpCheck *pingdom.HttpCheck, config interface{}) {
// Read config, try to map them to pingdom configs
// set some default values if we can't find them
// Retrieve provider configuration
providerConfig, _ := config.(*endpointmonitorv1alpha1.PingdomConfig)
if providerConfig != nil && len(providerConfig.AlertContacts) != 0 {
userIdsStringArray := strings.Split(providerConfig.AlertContacts, "-")
if userIds, err := util.SliceAtoi(userIdsStringArray); err != nil {
log.Info("Error decoding user alert contact IDs from config" + err.Error())
} else {
httpCheck.UserIds = userIds
}
}
if providerConfig != nil && len(providerConfig.AlertIntegrations) != 0 {
integrationIdsStringArray := strings.Split(providerConfig.AlertIntegrations, "-")
if integrationIds, err := util.SliceAtoi(integrationIdsStringArray); err != nil {
log.Info("Error decoding integration ids into integers" + err.Error())
} else {
httpCheck.IntegrationIds = integrationIds
}
}
if providerConfig != nil && len(providerConfig.TeamAlertContacts) != 0 {
integrationTeamIdsStringArray := strings.Split(providerConfig.TeamAlertContacts, "-")
if integrationTeamIdsStringArray, err := util.SliceAtoi(integrationTeamIdsStringArray); err != nil {
log.Info("Error decoding integration ids into integers" + err.Error())
} else {
httpCheck.TeamIds = integrationTeamIdsStringArray
}
}
if providerConfig != nil && providerConfig.Resolution > 0 {
httpCheck.Resolution = providerConfig.Resolution
} else {
httpCheck.Resolution = 1
}
if providerConfig != nil && providerConfig.SendNotificationWhenDown > 0 {
httpCheck.SendNotificationWhenDown = providerConfig.SendNotificationWhenDown
} else {
httpCheck.SendNotificationWhenDown = 3
}
if providerConfig != nil && len(providerConfig.RequestHeaders) > 0 {
httpCheck.RequestHeaders = make(map[string]string)
err := json.Unmarshal([]byte(providerConfig.RequestHeaders), &httpCheck.RequestHeaders)
if err != nil {
log.Info("Error Converting from string to JSON object")
}
}
if providerConfig != nil && len(providerConfig.BasicAuthUser) > 0 {
// This should be set to the username to set on the httpCheck
// Environment variable should define the password
// Mounted via a secret; key is the username, value the password
passwordValue := os.Getenv(providerConfig.BasicAuthUser)
if passwordValue != "" {
// Env variable set, pass user/pass to httpCheck
httpCheck.Username = providerConfig.BasicAuthUser
httpCheck.Password = passwordValue
log.Info("Basic auth requirement detected. Setting username and password for httpCheck")
} else {
log.Info("Error reading basic auth password from environment variable")
}
}
if providerConfig != nil && len(providerConfig.ShouldContain) > 0 {
httpCheck.ShouldContain = providerConfig.ShouldContain
log.Info("Should contain detected. Setting Should Contain string: " + providerConfig.ShouldContain)
}
// Tags should be a single word or multiple comma-separated words
if providerConfig != nil && len(providerConfig.Tags) > 0 {
if !strings.Contains(providerConfig.Tags, " ") {
httpCheck.Tags = providerConfig.Tags
log.Info("Tags detected. Setting Tags as: " + providerConfig.Tags)
} else {
log.Info("Tag string should not contain spaces. Not applying tags.")
}
}
if providerConfig != nil {
// Enable SSL validation
httpCheck.VerifyCertificate = &providerConfig.VerifyCertificate
// Add post data if exists
if len(providerConfig.PostDataEnvVar) > 0 {
postDataValue := os.Getenv(providerConfig.PostDataEnvVar)
if postDataValue != "" {
httpCheck.PostData = postDataValue
log.Info("Post data detected. Setting post data for httpCheck to value of environment variable: " + providerConfig.PostDataEnvVar)
} else {
log.Error(errors.New("Error reading post data from environment variable"), "Environment Variable %s does not exist", providerConfig.PostDataEnvVar)
}
}
}
// Set certificate not valid before, default to 28 days to accommodate Let's Encrypt 30 day renewals + 2 days grace period.
defaultSSLDownDaysBefore := 28
// Pingdom doesn't allow SSLDownDaysBefore to be set if VerifyCertificate isn't set to true
if providerConfig != nil && providerConfig.VerifyCertificate {
if providerConfig.SSLDownDaysBefore > 0 {
httpCheck.SSLDownDaysBefore = &providerConfig.SSLDownDaysBefore
} else {
httpCheck.SSLDownDaysBefore = &defaultSSLDownDaysBefore
}
}
if providerConfig != nil {
httpCheck.Paused = providerConfig.Paused
httpCheck.NotifyWhenBackup = providerConfig.NotifyWhenBackUp
}
}