github.com/stakater/IngressMonitorController@v1.0.103/pkg/monitors/gcloud/gcloud-monitor.go (about)

     1  package gcloud
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"net/url"
     8  	"strconv"
     9  
    10  	monitoring "cloud.google.com/go/monitoring/apiv3"
    11  	"google.golang.org/api/iterator"
    12  	"google.golang.org/api/option"
    13  	monitoredres "google.golang.org/genproto/googleapis/api/monitoredres"
    14  	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
    15  
    16  	"github.com/stakater/IngressMonitorController/pkg/config"
    17  	"github.com/stakater/IngressMonitorController/pkg/models"
    18  )
    19  
    20  const (
    21  	ProjectIDAnnotation = "gcloud.monitor.stakater.com/project-id"
    22  )
    23  
    24  type MonitorService struct {
    25  	client    *monitoring.UptimeCheckClient
    26  	projectID string
    27  	ctx       context.Context
    28  }
    29  
    30  func (service *MonitorService) Setup(provider config.Provider) {
    31  	service.ctx = context.Background()
    32  
    33  	client, err := monitoring.NewUptimeCheckClient(service.ctx, option.WithCredentialsJSON([]byte(provider.ApiKey)))
    34  
    35  	if err != nil {
    36  		log.Println("Error Seting Up Monitor Service: ", err.Error())
    37  	} else {
    38  		service.client = client
    39  	}
    40  
    41  	service.projectID = provider.GcloudConfig.ProjectID
    42  }
    43  
    44  func (service *MonitorService) GetByName(name string) (monitor *models.Monitor, err error) {
    45  	uptimeCheckConfigsIterator := service.client.ListUptimeCheckConfigs(service.ctx, &monitoringpb.ListUptimeCheckConfigsRequest{
    46  		Parent: "projects/" + service.projectID,
    47  	})
    48  
    49  	for {
    50  		uptimeCheckConfig, err := uptimeCheckConfigsIterator.Next()
    51  		if err == iterator.Done {
    52  			break
    53  		}
    54  		if err != nil {
    55  			return nil, fmt.Errorf("Error Locating Monitor: %s", err.Error())
    56  		}
    57  		if uptimeCheckConfig.DisplayName == name {
    58  			localMonitor := transformToMonitor(uptimeCheckConfig)
    59  			return &localMonitor, nil
    60  		}
    61  	}
    62  
    63  	return nil, fmt.Errorf("Unable to locate monitor with name %v", name)
    64  }
    65  
    66  func (service *MonitorService) GetAll() (monitors []models.Monitor) {
    67  	uptimeCheckConfigsIterator := service.client.ListUptimeCheckConfigs(service.ctx, &monitoringpb.ListUptimeCheckConfigsRequest{
    68  		Parent: "projects/" + service.projectID,
    69  	})
    70  
    71  	monitors = []models.Monitor{}
    72  	for {
    73  		uptimeCheckConfig, err := uptimeCheckConfigsIterator.Next()
    74  		if err == iterator.Done {
    75  			break
    76  		}
    77  		if err != nil {
    78  			log.Println("Error received while listing checks: ", err.Error())
    79  			return nil
    80  		}
    81  		monitors = append(monitors, transformToMonitor(uptimeCheckConfig))
    82  	}
    83  
    84  	return monitors
    85  }
    86  
    87  func (service *MonitorService) Add(monitor models.Monitor) {
    88  	url, err := url.Parse(monitor.URL)
    89  	if err != nil {
    90  		log.Println("Error Adding Monitor: ", err.Error())
    91  		return
    92  	}
    93  
    94  	portString := url.Port()
    95  	var port int
    96  	if portString == "" {
    97  		if url.Scheme == "http" {
    98  			port = 80
    99  		} else if url.Scheme == "https" {
   100  			port = 443
   101  		} else {
   102  			log.Println("Error Adding Monitor: unknown protocol ", url.Scheme)
   103  			return
   104  		}
   105  	} else {
   106  		port, err = strconv.Atoi(portString)
   107  		if err != nil {
   108  			log.Println("Error Adding Monitor: ", err.Error())
   109  			return
   110  		}
   111  	}
   112  
   113  	_, err = service.client.CreateUptimeCheckConfig(service.ctx, &monitoringpb.CreateUptimeCheckConfigRequest{
   114  		Parent: "projects/" + service.projectID,
   115  		UptimeCheckConfig: &monitoringpb.UptimeCheckConfig{
   116  			DisplayName: monitor.Name,
   117  			Resource: &monitoringpb.UptimeCheckConfig_MonitoredResource{
   118  				MonitoredResource: &monitoredres.MonitoredResource{
   119  					Type: "uptime_url",
   120  					Labels: map[string]string{
   121  						"host": url.Hostname(),
   122  					},
   123  				},
   124  			},
   125  			CheckRequestType: &monitoringpb.UptimeCheckConfig_HttpCheck_{
   126  				HttpCheck: &monitoringpb.UptimeCheckConfig_HttpCheck{
   127  					Path:   url.Path,
   128  					Port:   int32(port),
   129  					UseSsl: url.Scheme == "https",
   130  				},
   131  			},
   132  		},
   133  	})
   134  	if err != nil {
   135  		log.Println("Error Adding Monitor: ", err.Error())
   136  		return
   137  	}
   138  
   139  	log.Println("Added monitor for: ", monitor.Name)
   140  }
   141  
   142  func (service *MonitorService) Update(monitor models.Monitor) {
   143  	uptimeCheckConfig, err := service.client.GetUptimeCheckConfig(service.ctx, &monitoringpb.GetUptimeCheckConfigRequest{Name: monitor.ID})
   144  	if err != nil {
   145  		log.Println("Error updating Monitor: ", err.Error())
   146  	}
   147  
   148  	url, err := url.Parse(monitor.URL)
   149  	if err != nil {
   150  		log.Println("Error Adding Monitor: ", err.Error())
   151  		return
   152  	}
   153  
   154  	if uptimeCheckConfig.GetMonitoredResource().Labels["host"] != url.Hostname() {
   155  		log.Println("Error Adding Monitor: URL Host is immutable")
   156  		return
   157  	}
   158  
   159  	portString := url.Port()
   160  	var port int
   161  	if portString == "" {
   162  		if url.Scheme == "http" {
   163  			port = 80
   164  		} else if url.Scheme == "https" {
   165  			port = 443
   166  		} else {
   167  			log.Println("Error Adding Monitor: unknown protocol ", url.Scheme)
   168  			return
   169  		}
   170  	} else {
   171  		port, err = strconv.Atoi(portString)
   172  		if err != nil {
   173  			log.Println("Error Adding Monitor: ", err.Error())
   174  			return
   175  		}
   176  	}
   177  
   178  	uptimeCheckConfig.DisplayName = monitor.Name
   179  	uptimeCheckConfig.GetHttpCheck().Port = int32(port)
   180  	uptimeCheckConfig.GetHttpCheck().Path = url.Path
   181  
   182  	uptimeCheckConfig, err = service.client.UpdateUptimeCheckConfig(service.ctx, &monitoringpb.UpdateUptimeCheckConfigRequest{
   183  		UptimeCheckConfig: uptimeCheckConfig,
   184  	})
   185  	if err != nil {
   186  		log.Println("Error Adding Monitor: ", err.Error())
   187  		return
   188  	}
   189  
   190  	log.Println("Updated Monitor: ", uptimeCheckConfig)
   191  }
   192  
   193  func (service *MonitorService) Remove(monitor models.Monitor) {
   194  	err := service.client.DeleteUptimeCheckConfig(service.ctx, &monitoringpb.DeleteUptimeCheckConfigRequest{
   195  		Name: monitor.ID,
   196  	})
   197  	if err != nil {
   198  		log.Println("Error deleting Monitor: ", err.Error())
   199  		return
   200  	}
   201  	log.Println("Deleted Monitor: ", monitor.Name)
   202  }
   203  
   204  func transformToMonitor(uptimeCheckConfig *monitoringpb.UptimeCheckConfig) (monitor models.Monitor) {
   205  	isSsl := uptimeCheckConfig.GetHttpCheck().UseSsl
   206  	path := uptimeCheckConfig.GetHttpCheck().Path
   207  	port := uptimeCheckConfig.GetHttpCheck().Port
   208  	host := uptimeCheckConfig.GetMonitoredResource().Labels["host"]
   209  
   210  	var scheme string
   211  	if isSsl {
   212  		scheme = "https"
   213  	} else {
   214  		scheme = "http"
   215  	}
   216  
   217  	if (isSsl && port != 443) || (!isSsl && port != 80) {
   218  		host = host + ":" + strconv.FormatInt(int64(port), 10)
   219  	}
   220  
   221  	url := url.URL{
   222  		Scheme: scheme,
   223  		Host:   host,
   224  		Path:   path,
   225  	}
   226  
   227  	return models.Monitor{
   228  		URL:         url.String(),
   229  		Name:        uptimeCheckConfig.DisplayName,
   230  		ID:          uptimeCheckConfig.Name,
   231  		Annotations: map[string]string{},
   232  	}
   233  }