github.com/stakater/IngressMonitorController@v1.0.103/pkg/monitors/pingdom/pingdom-monitor.go (about) 1 package pingdom 2 3 import ( 4 "encoding/json" 5 "fmt" 6 log "github.com/sirupsen/logrus" 7 "net/url" 8 "os" 9 "strconv" 10 "strings" 11 12 "github.com/russellcardullo/go-pingdom/pingdom" 13 "github.com/stakater/IngressMonitorController/pkg/config" 14 "github.com/stakater/IngressMonitorController/pkg/models" 15 "github.com/stakater/IngressMonitorController/pkg/util" 16 ) 17 18 const ( 19 PingdomResolutionAnnotation = "pingdom.monitor.stakater.com/resolution" 20 PingdomSendNotificationWhenDownAnnotation = "pingdom.monitor.stakater.com/send-notification-when-down" 21 PingdomPausedAnnotation = "pingdom.monitor.stakater.com/paused" 22 PingdomNotifyWhenBackUpAnnotation = "pingdom.monitor.stakater.com/notify-when-back-up" 23 PingdomRequestHeadersAnnotation = "pingdom.monitor.stakater.com/request-headers" 24 PingdomBasicAuthUser = "pingdom.monitor.stakater.com/basic-auth-user" 25 PingdomShouldContainString = "pingdom.monitor.stakater.com/should-contain" 26 PingdomTags = "pingdom.monitor.stakater.com/tags" 27 PingdomAlertIntegrations = "pingdom.monitor.stakater.com/alert-integrations" 28 PingdomAlertContacts = "pingdom.monitor.stakater.com/alert-contacts" 29 ) 30 31 // PingdomMonitorService interfaces with MonitorService 32 type PingdomMonitorService struct { 33 apiToken string 34 url string 35 alertContacts string 36 alertIntegrations string 37 client *pingdom.Client 38 } 39 40 func (service *PingdomMonitorService) Setup(p config.Provider) { 41 service.apiToken = p.ApiToken 42 service.alertContacts = p.AlertContacts 43 service.alertIntegrations = p.AlertIntegrations 44 45 var err error 46 service.client, err = pingdom.NewClientWithConfig(pingdom.ClientConfig{ 47 APIToken: service.apiToken, 48 }) 49 if err != nil { 50 log.Println("Failed to authenticate with error: ", err.Error()) 51 } 52 } 53 54 func (service *PingdomMonitorService) GetByName(name string) (*models.Monitor, error) { 55 var match *models.Monitor 56 57 monitors := service.GetAll() 58 for _, mon := range monitors { 59 if mon.Name == name { 60 return &mon, nil 61 } 62 } 63 64 return match, fmt.Errorf("Unable to locate monitor with name %v", name) 65 } 66 67 func (service *PingdomMonitorService) GetAll() []models.Monitor { 68 var monitors []models.Monitor 69 70 checks, err := service.client.Checks.List() 71 if err != nil { 72 log.Println("Error received while listing checks: ", err.Error()) 73 return nil 74 } 75 for _, mon := range checks { 76 newMon := models.Monitor{ 77 URL: mon.Hostname, 78 ID: fmt.Sprintf("%v", mon.ID), 79 Name: mon.Name, 80 } 81 monitors = append(monitors, newMon) 82 } 83 84 return monitors 85 } 86 87 func (service *PingdomMonitorService) Add(m models.Monitor) { 88 httpCheck := service.createHttpCheck(m) 89 90 _, err := service.client.Checks.Create(&httpCheck) 91 if err != nil { 92 log.Println("Error Adding Monitor: ", err.Error()) 93 } else { 94 log.Println("Added monitor for: ", m.Name) 95 } 96 } 97 98 func (service *PingdomMonitorService) Update(m models.Monitor) { 99 httpCheck := service.createHttpCheck(m) 100 monitorID, _ := strconv.Atoi(m.ID) 101 102 resp, err := service.client.Checks.Update(monitorID, &httpCheck) 103 if err != nil { 104 log.Println("Error updating Monitor: ", err.Error()) 105 } else { 106 log.Println("Updated Monitor: ", resp) 107 } 108 } 109 110 func (service *PingdomMonitorService) Remove(m models.Monitor) { 111 monitorID, _ := strconv.Atoi(m.ID) 112 113 resp, err := service.client.Checks.Delete(monitorID) 114 if err != nil { 115 log.Println("Error deleting Monitor: ", err.Error()) 116 } else { 117 log.Println("Delete Monitor: ", resp) 118 } 119 } 120 121 func (service *PingdomMonitorService) createHttpCheck(monitor models.Monitor) pingdom.HttpCheck { 122 httpCheck := pingdom.HttpCheck{} 123 url, err := url.Parse(monitor.URL) 124 if err != nil { 125 log.Println("Unable to parse the URL: ", service.url) 126 } 127 128 if url.Scheme == "https" { 129 httpCheck.Encryption = true 130 } else { 131 httpCheck.Encryption = false 132 } 133 134 httpCheck.Hostname = url.Host 135 httpCheck.Url = url.Path 136 httpCheck.Name = monitor.Name 137 138 if service.alertContacts != "" { 139 userIdsStringArray := strings.Split(service.alertContacts, "-") 140 141 if userIds, err := util.SliceAtoi(userIdsStringArray); err != nil { 142 log.Println(err.Error()) 143 } else { 144 httpCheck.UserIds = userIds 145 } 146 } 147 148 if service.alertIntegrations != "" { 149 integrationIdsStringArray := strings.Split(service.alertIntegrations, "-") 150 151 if integrationIds, err := util.SliceAtoi(integrationIdsStringArray); err != nil { 152 log.Println(err.Error()) 153 } else { 154 httpCheck.IntegrationIds = integrationIds 155 } 156 } 157 service.addAnnotationConfigToHttpCheck(&httpCheck, monitor.Annotations) 158 159 return httpCheck 160 } 161 162 func (service *PingdomMonitorService) addAnnotationConfigToHttpCheck(httpCheck *pingdom.HttpCheck, annotations map[string]string) { 163 // Read known annotations, try to map them to pingdom configs 164 // set some default values if we can't find them 165 166 if value, ok := annotations[PingdomAlertContacts]; ok { 167 userIdsStringArray := strings.Split(value, "-") 168 169 if userIds, err := util.SliceAtoi(userIdsStringArray); err != nil { 170 log.Println("Error decoding user ids annotation", err.Error()) 171 } else { 172 httpCheck.UserIds = userIds 173 } 174 } 175 176 if value, ok := annotations[PingdomAlertIntegrations]; ok { 177 integrationIdsStringArray := strings.Split(value, "-") 178 179 if integrationIds, err := util.SliceAtoi(integrationIdsStringArray); err != nil { 180 log.Println("Error decoding integration ids annotation into integers", err.Error()) 181 } else { 182 httpCheck.IntegrationIds = integrationIds 183 } 184 } 185 186 if value, ok := annotations[PingdomNotifyWhenBackUpAnnotation]; ok { 187 boolValue, err := strconv.ParseBool(value) 188 if err == nil { 189 httpCheck.NotifyWhenBackup = boolValue 190 } 191 } 192 193 if value, ok := annotations[PingdomPausedAnnotation]; ok { 194 boolValue, err := strconv.ParseBool(value) 195 if err == nil { 196 httpCheck.Paused = boolValue 197 } 198 } 199 200 if value, ok := annotations[PingdomResolutionAnnotation]; ok { 201 intValue, err := strconv.Atoi(value) 202 if err == nil { 203 httpCheck.Resolution = intValue 204 } else { 205 log.Println("Error decoding input into an integer") 206 httpCheck.Resolution = 1 207 } 208 } else { 209 httpCheck.Resolution = 1 210 } 211 212 if value, ok := annotations[PingdomSendNotificationWhenDownAnnotation]; ok { 213 intValue, err := strconv.Atoi(value) 214 if err == nil { 215 httpCheck.SendNotificationWhenDown = intValue 216 } else { 217 log.Println("Error decoding input into an integer") 218 httpCheck.SendNotificationWhenDown = 3 219 } 220 } else { 221 httpCheck.SendNotificationWhenDown = 3 222 } 223 224 if value, ok := annotations[PingdomRequestHeadersAnnotation]; ok { 225 226 httpCheck.RequestHeaders = make(map[string]string) 227 err := json.Unmarshal([]byte(value), &httpCheck.RequestHeaders) 228 if err != nil { 229 log.Println("Error Converting from string to JSON object") 230 } 231 } 232 233 // Does an annotation want to use basic auth 234 if userValue, ok := annotations[PingdomBasicAuthUser]; ok { 235 // Annotation should be set to the username to set on the httpCheck 236 // Environment variable should define the password 237 // Mounted via a secret; key is the username, value the password 238 passwordValue := os.Getenv(userValue) 239 if passwordValue != "" { 240 // Env variable set, pass user/pass to httpCheck 241 httpCheck.Username = userValue 242 httpCheck.Password = passwordValue 243 log.Println("Basic auth requirement detected. Setting username and password for httpCheck") 244 } else { 245 log.Println("Error reading basic auth password from environment variable") 246 } 247 } 248 249 // Does an annotation want to set a "should contain" string 250 if containValue, ok := annotations[PingdomShouldContainString]; ok { 251 if containValue != "" { 252 httpCheck.ShouldContain = containValue 253 log.Println("Should contain annotation detected. Setting Should Contain string: ", containValue) 254 } 255 } 256 257 // Does an annotation want to set any "tags" 258 // Tags should be a single word or multiple comma-seperated words 259 if tagValue, ok := annotations[PingdomTags]; ok { 260 if tagValue != "" && !strings.Contains(tagValue, " ") { 261 httpCheck.Tags = tagValue 262 log.Println("Tags annotation detected. Setting Tags as: ", tagValue) 263 } else { 264 log.Println("Tag string should not contain spaces. Not applying tags.") 265 } 266 } 267 }