Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/advanced error handling #294

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions pkg/controller/endpointmonitor/endpointmonitor_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,17 @@ func (r *ReconcileEndpointMonitor) Reconcile(request reconcile.Request) (reconci
delay := time.Until(createTime.Add(config.GetControllerConfig().CreationDelay))

for index := 0; index < len(r.monitorServices); index++ {
monitor := findMonitorByName(r.monitorServices[index], monitorName)
monitor, err := findMonitorByName(r.monitorServices[index], monitorName)
// if there was some error while getting a monitor, re-queue it to try on the next reconcile iteration
if err != nil {
return reconcile.Result{RequeueAfter: RequeueTime}, err
}
Comment on lines +120 to +124
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's unable to create a monitor this will be an endless re-conciliation loop !

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if it was only the API call error? E.g. API has returned 500 code, and we would be able to add this monitor on the next iteration?

if monitor != nil {
// Monitor already exists, update if required
err = r.handleUpdate(request, instance, *monitor, r.monitorServices[index])
if err != nil {
log.Errorf("Error while handling update: %s", err)
}
} else {
// Monitor doesn't exist, create monitor
if delay.Nanoseconds() > 0 {
Expand All @@ -129,18 +136,16 @@ func (r *ReconcileEndpointMonitor) Reconcile(request reconcile.Request) (reconci
return reconcile.Result{RequeueAfter: delay}, nil
}
err = r.handleCreate(request, instance, monitorName, r.monitorServices[index])
if err != nil {
log.Errorf("Error while handling create: %s", err)
}
}
}

return reconcile.Result{RequeueAfter: RequeueTime}, err
}

func findMonitorByName(monitorService monitors.MonitorServiceProxy, monitorName string) *models.Monitor {

monitor, _ := monitorService.GetByName(monitorName)
// Monitor Exists
if monitor != nil {
return monitor
}
return nil
func findMonitorByName(monitorService monitors.MonitorServiceProxy, monitorName string) (*models.Monitor, error) {
monitor, err := monitorService.GetByName(monitorName)
return monitor, err
}
14 changes: 10 additions & 4 deletions pkg/controller/endpointmonitor/endpointmonitor_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ func TestEndpointMonitorReconcileUpdate(t *testing.T) {

monitorCount = 0
for index := 0; index < len(r.monitorServices); index++ {
monitor := findMonitorByName(r.monitorServices[index], monitorName)
if monitor != nil && monitor.URL == testURLFacebook {
monitor, err := findMonitorByName(r.monitorServices[index], monitorName)
if monitor != nil && err == nil && monitor.URL == testURLFacebook {
log.Info("Found Updated Monitor for Provider: " + r.monitorServices[index].GetType())
monitorCount++
}
Expand Down Expand Up @@ -185,7 +185,10 @@ func TestEndpointMonitorReconcileDelete(t *testing.T) {

monitorCount = 0
for index := 0; index < len(r.monitorServices); index++ {
monitor := findMonitorByName(r.monitorServices[index], monitorName)
monitor, err := findMonitorByName(r.monitorServices[index], monitorName)
if err != nil {
t.Error(err, "Could not findMonitorByName")
}
if monitor == nil {
monitorCount++
}
Expand Down Expand Up @@ -232,7 +235,10 @@ func setupReconcilerAndCreateResource() (client.Client, *ReconcileEndpointMonito
func getMonitorCount(monitorName string, monitorServices []monitors.MonitorServiceProxy) int {
monitorCount := 0
for index := 0; index < len(monitorServices); index++ {
monitor := findMonitorByName(monitorServices[index], monitorName)
monitor, err := findMonitorByName(monitorServices[index], monitorName)
if err != nil {
log.Error(err, "Could not findMonitorByName")
}
if monitor != nil {
log.Info("Found Monitor for Provider: " + monitorServices[index].GetType())
monitorCount++
Expand Down
4 changes: 3 additions & 1 deletion pkg/monitors/appinsights/appinsights-monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,10 @@ func (aiService *AppinsightsMonitorService) GetByName(monitorName string) (*mode
log.Println("AppInsights Monitor's GetByName method has been called")
webtest, err := aiService.insightsClient.Get(aiService.ctx, aiService.resourceGroup, monitorName)
if err != nil {
// if not found let's mark it as non-error
if webtest.Response.StatusCode == http.StatusNotFound {
return nil, fmt.Errorf("Application Insights WebTest %s was not found in Resource Group %s", monitorName, aiService.resourceGroup)
log.Printf("Application Insights WebTest %s was not found in Resource Group %s", monitorName, aiService.resourceGroup)
return nil, nil
Comment on lines +194 to +195
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we removing this error from here ?

}
return nil, fmt.Errorf("Error retrieving Application Insights WebTests %s (Resource Group %s): %v", monitorName, aiService.resourceGroup, err)
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/monitors/gcloud/gcloud-monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ func (service *MonitorService) GetByName(name string) (monitor *models.Monitor,
return &localMonitor, nil
}
}

return nil, fmt.Errorf("Unable to locate monitor with name %v", name)
// monitor not found and no errors raised
log.Printf("There is no gcloud MonitorService with name %s found.", name)
return nil, nil
Comment on lines +64 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we removing this error from here ?

}

func (service *MonitorService) GetAll() (monitors []models.Monitor) {
Expand Down
36 changes: 29 additions & 7 deletions pkg/monitors/pingdom/pingdom-monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type PingdomMonitorService struct {
client *pingdom.Client
}

func (monitor *PingdomMonitorService) Equal(oldMonitor models.Monitor, newMonitor models.Monitor) bool {
func (service *PingdomMonitorService) Equal(oldMonitor models.Monitor, newMonitor models.Monitor) bool {
// TODO: Retrieve oldMonitor config and compare it here
return false
}
Expand All @@ -45,21 +45,23 @@ func (service *PingdomMonitorService) Setup(p config.Provider) {
BaseURL: service.url,
})
if err != nil {
log.Println("Error Seting Up Monitor Service: ", err.Error())
log.Println("Error Setting Up Monitor Service: ", err.Error())
}
}

func (service *PingdomMonitorService) GetByName(name string) (*models.Monitor, error) {
var match *models.Monitor

monitors := service.GetAll()
monitors, err := service.GetAllWithAPIErrorHandler()
if err != nil {
return nil, fmt.Errorf("error received while getting all Pingdom monitors: %s", err.Error())
}
for _, mon := range monitors {
if mon.Name == name {
return &mon, nil
}
}

return match, fmt.Errorf("Unable to locate monitor with name %v", name)
// neither error and any matched monitor
log.Printf("There is no PingdomMonitorService with name %s found.", name)
return nil, nil
Comment on lines +63 to +64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we removing this error from here ?

}

func (service *PingdomMonitorService) GetAll() []models.Monitor {
Expand All @@ -82,6 +84,26 @@ func (service *PingdomMonitorService) GetAll() []models.Monitor {
return monitors
}

// Function that gets all monitors with an error handling to avoid duplicate checks creation
func (service *PingdomMonitorService) GetAllWithAPIErrorHandler() ([]models.Monitor, error) {
Copy link

@namm2 namm2 Aug 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how this function can avoid duplication compared with the existing GetAll() one?

var monitors []models.Monitor

checks, err := service.client.Checks.List()
if err != nil {
return nil, err
}
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, nil
}

func (service *PingdomMonitorService) Add(m models.Monitor) {
httpCheck := service.createHttpCheck(m)

Expand Down
46 changes: 33 additions & 13 deletions pkg/monitors/pingdom/pingdom-monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package pingdom

import (
log "github.com/sirupsen/logrus"
"net/url"
"testing"
"time"

"github.com/stakater/IngressMonitorController/pkg/config"
"github.com/stakater/IngressMonitorController/pkg/models"
Expand All @@ -21,22 +23,33 @@ func TestAddMonitorWithCorrectValues(t *testing.T) {
return
}
service.Setup(*provider)
m := models.Monitor{Name: "google-test", URL: "https://google1.com"}
urlToTest := "https://google1.com"
parsedUrl, err := url.Parse(urlToTest)
if err != nil {
t.Errorf("Error: %s", err)
}
m := models.Monitor{Name: "google-test", URL: urlToTest}
service.Add(m)

//Creation delay
time.Sleep(5 * time.Second)
mRes, err := service.GetByName("google-test")

if err != nil {
t.Error("Error: " + err.Error())
}
if mRes.Name != m.Name || mRes.URL != m.URL {
t.Error("URL and name should be the same")
// mRes.URL is a domain name, without scheme, so we parsed URL previously
if mRes.Name != m.Name || mRes.URL != parsedUrl.Host {
t.Errorf("URL and name should be the same %+v", mRes)
}
service.Remove(*mRes)
//Deletion delay
time.Sleep(5 * time.Second)
monitor, err := service.GetByName(mRes.Name)

if err != nil {
t.Error("Error: " + err.Error())
}
if monitor != nil {
t.Error("Monitor should've been deleted ", monitor, err)
t.Error("Monitor should've been deleted ", monitor)
}
}

Expand All @@ -53,16 +66,21 @@ func TestUpdateMonitorWithCorrectValues(t *testing.T) {
return
}
service.Setup(*provider)

m := models.Monitor{Name: "google-test", URL: "https://google.com"}
urlToTest := "https://google.com"
parsedUrl, err := url.Parse(urlToTest)
if err != nil {
t.Errorf("Error: %s", err)
}
m := models.Monitor{Name: "google-test", URL: urlToTest}
service.Add(m)

//Creation delay
time.Sleep(5 * time.Second)
mRes, err := service.GetByName("google-test")

if err != nil {
t.Error("Error: " + err.Error())
}
if mRes.Name != m.Name || mRes.URL != m.URL {
if mRes.Name != m.Name || mRes.URL != parsedUrl.Host {
t.Error("URL and name should be the same")
}

Expand All @@ -75,15 +93,17 @@ func TestUpdateMonitorWithCorrectValues(t *testing.T) {
if err != nil {
t.Error("Error: " + err.Error())
}
if mRes.URL != "https://facebook.com" {
if mRes.URL != "facebook.com" {
t.Error("URL and name should be the same")
}

service.Remove(*mRes)

monitor, err := service.GetByName(mRes.Name)

if err != nil {
t.Error("Error: " + err.Error())
}
if monitor != nil {
t.Error("Monitor should've been deleted ", monitor, err)
t.Error("Monitor should've been deleted ", monitor)
}
}
5 changes: 2 additions & 3 deletions pkg/monitors/statuscake/statuscake-monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package statuscake
import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"net/url"
Expand Down Expand Up @@ -202,8 +201,8 @@ func (service *StatusCakeMonitorService) GetByName(name string) (*models.Monitor
return &monitor, nil
}
}
errorString := "GetByName Request failed for name: " + name
return nil, errors.New(errorString)
log.Printf("There is no StatusCakeMonitorService with name %s found.", name)
return nil, nil
Comment on lines +204 to +205
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we removing this error from here ?

}

// GetAll function will fetch all monitors
Expand Down
11 changes: 8 additions & 3 deletions pkg/monitors/statuscake/statuscake-monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ func TestAddMonitorWithCorrectValues(t *testing.T) {

monitor, err := service.GetByName(mRes.Name)

if err != nil {
t.Error("Error: " + err.Error())
}
if monitor != nil {
t.Error("Monitor should've been deleted ", monitor, err)
t.Error("Monitor should've been deleted ", monitor)
}
}

Expand Down Expand Up @@ -83,9 +86,11 @@ func TestUpdateMonitorWithCorrectValues(t *testing.T) {
service.Remove(*mRes)

monitor, err := service.GetByName(mRes.Name)

if err != nil {
t.Error("Error: " + err.Error())
}
if monitor != nil {
t.Error("Monitor should've been deleted ", monitor, err)
t.Error("Monitor should've been deleted ", monitor)
}
}

Expand Down
5 changes: 2 additions & 3 deletions pkg/monitors/updown/updown-monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
package updown

import (
"fmt"
"net/http"
"net/url"

Expand Down Expand Up @@ -94,8 +93,8 @@ func (updownService *UpdownMonitorService) GetByName(monitorName string) (*model
return &updownMonitor, nil
}
}

return nil, fmt.Errorf("Unable to locate %v monitor", monitorName)
log.Printf("There is no UpdownMonitorService with name %s found.", monitorName)
return nil, nil
}

// Add function method will add a monitor (updown check)
Expand Down
6 changes: 2 additions & 4 deletions pkg/monitors/uptime/uptime-monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package uptime

import (
"encoding/json"
"errors"
"strconv"
"strings"

Expand Down Expand Up @@ -44,9 +43,8 @@ func (monitor *UpTimeMonitorService) GetByName(name string) (*models.Monitor, er
}
}

errorString := name + " not found"
log.Println(errorString)
return nil, errors.New(errorString)
log.Printf("There is no UpTimeMonitorService with name %s found.", name)
return nil, nil
}

func (monitor *UpTimeMonitorService) GetAll() []models.Monitor {
Expand Down
7 changes: 5 additions & 2 deletions pkg/monitors/uptime/uptime-monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,12 @@ func TestAddMonitorWithIncorrectValues(t *testing.T) {

service.Add(m)

_, err := service.GetByName("google-test")
monitor, err := service.GetByName("google-test")

if err == nil {
if err != nil {
t.Error("Error: " + err.Error())
}
if monitor != nil {
t.Error("google-test should not have existed")
}
}