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  }