From 702eb682fcbc91bec71f4262d831963e2cc05087 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Tue, 24 Sep 2024 17:32:38 +0200 Subject: [PATCH 01/20] WIP add config option --- api/v1alpha1/endpointmonitor_types.go | 5 ++++- pkg/monitors/statuscake/statuscake-monitor.go | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/v1alpha1/endpointmonitor_types.go b/api/v1alpha1/endpointmonitor_types.go index c8a2f70b..07f1338b 100644 --- a/api/v1alpha1/endpointmonitor_types.go +++ b/api/v1alpha1/endpointmonitor_types.go @@ -163,6 +163,10 @@ type StatusCakeConfig struct { // +optional BasicAuthUser string `json:"basicAuthUser,omitempty"` + // Basic Auth String + // +optional + BasicAuthSecret string `json:"basicAuthSecret,omitempty"` + // Set Check Rate for the monitor // +optional CheckRate int `json:"checkRate,omitempty"` @@ -299,7 +303,6 @@ type PingdomConfig struct { // PingdomTransactionConfig defines the configuration for Pingdom Transaction Monitor Provider type PingdomTransactionConfig struct { - // Check status: active or inactive // +optional Paused bool `json:"paused,omitempty"` diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 0ed9b13e..13a181af 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -100,9 +100,12 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { } } + if providerConfig != nil && len(providerConfig.BasicAuthSecret) > 0 { + log.Info("The secret name is: %s", providerConfig.BasicAuthSecret) + } + if providerConfig != nil && len(providerConfig.StatusCodes) > 0 { f.Add("status_codes_csv", providerConfig.StatusCodes) - } else { statusCodes := []string{ "204", // No content @@ -243,7 +246,6 @@ func (service *StatusCakeMonitorService) GetByName(name string) (*models.Monitor } errorString := "GetByName Request failed for name: " + name return nil, errors.New(errorString) - } // GetByID function will Get a monitor by it's ID @@ -445,7 +447,6 @@ func (service *StatusCakeMonitorService) Remove(m models.Monitor) { } if resp.StatusCode != http.StatusNoContent { log.Error(nil, fmt.Sprintf("Delete Request failed for Monitor: %s with id: %s", m.Name, m.ID)) - } else { _, err = service.GetByID(m.ID) if strings.Contains(err.Error(), "Request failed") { From c1af02311704c6da6d8407bc7055304e32f8a5d6 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Thu, 26 Sep 2024 14:08:07 +0200 Subject: [PATCH 02/20] Update controller-gen version Fixes the broken v0.9 of controller-gen because it causes a segfault when running `make install` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 43ef1c52..0465d4a3 100644 --- a/Makefile +++ b/Makefile @@ -154,7 +154,7 @@ ENVTEST ?= $(LOCALBIN)/setup-envtest ## Tool Versions KUSTOMIZE_VERSION ?= v3.8.7 -CONTROLLER_TOOLS_VERSION ?= v0.9.0 +CONTROLLER_TOOLS_VERSION ?= v0.14.0 KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" .PHONY: kustomize From ce4156b51557dd785892c96b6cadddaf973e5a10 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Thu, 26 Sep 2024 14:09:25 +0200 Subject: [PATCH 03/20] Update formatting for base CRDS --- ...monitor.stakater.com_endpointmonitors.yaml | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index 0f984d44..b38412b3 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.9.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: endpointmonitors.endpointmonitor.stakater.com spec: group: endpointmonitor.stakater.com @@ -21,14 +20,19 @@ spec: description: EndpointMonitor is the Schema for the endpointmonitors API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -65,9 +69,9 @@ spec: properties: alertSensitivity: default: none - description: The alertSensitivity value defaults to none if there - are no alerts or can be set to low, medium, or high to correspond - to the check alert levels. + description: |- + The alertSensitivity value defaults to none if there are no alerts or can be set to low, medium, + or high to correspond to the check alert levels. enum: - none - low @@ -80,11 +84,10 @@ spec: format: int64 type: integer probes: - description: Probes are the monitoring agents responsible for - simulating user interactions with your web applications or services. - These agents periodically send requests to predefined URLs and - record the responses, checking for expected outcomes and measuring - performance. + description: |- + Probes are the monitoring agents responsible for simulating user interactions with your web applications + or services. These agents periodically send requests to predefined URLs and record the responses, + checking for expected outcomes and measuring performance. items: type: string type: array @@ -114,18 +117,17 @@ spec: description: Set to "true" to pause checks type: boolean postDataEnvVar: - description: Data that should be posted to the web page, for example - submission data for a sign-up or login form. The data needs - to be formatted in the same way as a web browser would send - it to the web server. Because post data contains sensitive secret - this field is only a reference to an environment variable. + description: |- + Data that should be posted to the web page, for example submission data for a sign-up or login form. + The data needs to be formatted in the same way as a web browser would send it to the web server. + Because post data contains sensitive secret this field is only a reference to an environment variable. type: string requestHeaders: description: Custom request headers type: string requestHeadersEnvVar: - description: Custom request headers that should be read from an - environment variable as it possibly contains sensitive data. + description: |- + Custom request headers that should be read from an environment variable as it possibly contains sensitive data. An example would be an API token. type: string resolution: @@ -139,11 +141,10 @@ spec: HTML code of the page type: string sslDownDaysBefore: - description: Consider down prior to certificate expiring Select - the number of days prior to your certificate expiry date that - you want to consider the check down. At this day your check - will be considered down and if applicable a down alert will - be sent. + description: |- + Consider down prior to certificate expiring + Select the number of days prior to your certificate expiry date that you want to consider the check down. + At this day your check will be considered down and if applicable a down alert will be sent. type: integer tags: description: Comma separated set of tags to apply to check (e.g. @@ -153,11 +154,11 @@ spec: description: '`-` separated team id''s (e.g. "1234567_8_9-9876543_2_1")' type: string verifyCertificate: - description: Monitor SSL/TLS certificate Monitor the validity - of your SSL/TLS certificate. With this enabled Uptime checks - will be considered DOWN when the certificate becomes invalid - or expires. SSL/TLS certificate monitoring is available for - HTTP checks. + description: |- + Monitor SSL/TLS certificate + Monitor the validity of your SSL/TLS certificate. With this enabled Uptime checks will be considered DOWN when + the certificate becomes invalid or expires. + SSL/TLS certificate monitoring is available for HTTP checks. type: boolean type: object pingdomTransactionConfig: @@ -218,18 +219,17 @@ spec: args: additionalProperties: type: string - description: 'contains the html element with assigned value - the key element is always lowercase for example {"url": - "https://www.pingdom.com"} see available values at https://pkg.go.dev/github.com/karlderkaefer/pingdom-golang-client@latest/pkg/pingdom/client/tmschecks#StepArg' + description: |- + contains the html element with assigned value + the key element is always lowercase for example {"url": "https://www.pingdom.com"} + see available values at https://pkg.go.dev/github.com/karlderkaefer/pingdom-golang-client@latest/pkg/pingdom/client/tmschecks#StepArg type: object function: - description: 'contains the function that is executed as - part of the step commands: go_to, click, fill, check, - uncheck, sleep, select_radio, basic_auth, submit, wait_for_element, - wait_for_contains validations: url, exists, not_exists, - contains, not_contains, field_contains, field_not_contains, - is_checked, is_not_checked, radio_selected, dropdown_selected, - dropdown_not_selected see updated list https://docs.pingdom.com/api/#section/TMS-Steps-Vocabulary/Script-transaction-checks' + description: |- + contains the function that is executed as part of the step + commands: go_to, click, fill, check, uncheck, sleep, select_radio, basic_auth, submit, wait_for_element, wait_for_contains + validations: url, exists, not_exists, contains, not_contains, field_contains, field_not_contains, is_checked, is_not_checked, radio_selected, dropdown_selected, dropdown_not_selected + see updated list https://docs.pingdom.com/api/#section/TMS-Steps-Vocabulary/Script-transaction-checks type: string required: - args @@ -351,9 +351,9 @@ spec: this monitor type: string customHTTPStatuses: - description: 'Defines which http status codes are treated as up - or down For ex: 200:0_401:1_503:1 (to accept 200 as down and - 401 and 503 as up)' + description: |- + Defines which http status codes are treated as up or down + For ex: 200:0_401:1_503:1 (to accept 200 as down and 401 and 503 as up) type: string interval: description: The uptimerobot check interval in seconds From 5c69fd4d5a280f62b52eeb62dfba0a3920e79067 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Tue, 1 Oct 2024 14:14:14 +0200 Subject: [PATCH 04/20] Working read secret --- pkg/monitors/statuscake/statuscake-monitor.go | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 13a181af..728ce715 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -12,12 +12,21 @@ import ( "strconv" "strings" + "gopkg.in/yaml.v2" + "k8s.io/client-go/rest" + + // ctrlConfig "sigs.k8s.io/controller-runtime/pkg/client/config" logf "sigs.k8s.io/controller-runtime/pkg/log" + //"sigs.k8s.io/controller-runtime/pkg/manager" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" statuscake "github.com/StatusCakeDev/statuscake-go" 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/secret" ) var log = logf.Log.WithName("statuscake-monitor") @@ -86,7 +95,7 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { } } - if providerConfig != nil && len(providerConfig.BasicAuthUser) > 0 { + if providerConfig != nil && len(providerConfig.BasicAuthUser) > 0 && len(providerConfig.BasicAuthSecret) == 0 { // This value is mandatory // Environment variable should define the password // Mounted via a secret; key is the username, value is the password @@ -101,7 +110,39 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { } if providerConfig != nil && len(providerConfig.BasicAuthSecret) > 0 { - log.Info("The secret name is: %s", providerConfig.BasicAuthSecret) + var basicPass string + clusterConfig, err := rest.InClusterConfig() + if err != nil { + panic(err) + } + + s := runtime.NewScheme() + if err := scheme.AddToScheme(s); err != nil { + panic(err) + } + + // Create a new client + k8sClient, err := client.New(clusterConfig, client.Options{Scheme: s}) + if err != nil { + panic(err) + } + + log.Info(fmt.Sprintf("The secret name is: %s", providerConfig.BasicAuthSecret)) + secretKey, err := secret.LoadSecretData(k8sClient, providerConfig.BasicAuthSecret, "test", providerConfig.BasicAuthUser) + if err != nil { + panic(err) + } + + err = yaml.Unmarshal([]byte(secretKey), &basicPass) + if err != nil { + panic(err) + } + var log_str string = fmt.Sprintf("Secret content -- BasicAuthUser: %s | BasicAuthPass: %s", providerConfig.BasicAuthUser, basicPass) + log.Info(log_str) + + f.Add("basic_username", providerConfig.BasicAuthUser) + f.Add("basic_password", basicPass) + log.Info("Basic auth requirement detected. Setting username and password") } if providerConfig != nil && len(providerConfig.StatusCodes) > 0 { From 6b2bb1dc04b61b88906bd6b233d59518d283f642 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Tue, 1 Oct 2024 15:25:50 +0200 Subject: [PATCH 05/20] Fixed read secret --- ...monitor.stakater.com_endpointmonitors.yaml | 3 ++ docs/statuscake-configuration.md | 11 +++-- pkg/kube/kube.go | 26 ++++++++++- pkg/monitors/statuscake/statuscake-monitor.go | 43 ++++++------------- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index b38412b3..2cce1dcb 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -255,6 +255,9 @@ spec: statusCakeConfig: description: Configuration for StatusCake Monitor Provider properties: + basicAuthSecret: + description: Basic Auth String + type: string basicAuthUser: description: Basic Auth User type: string diff --git a/docs/statuscake-configuration.md b/docs/statuscake-configuration.md index bd0c62bf..200ce72f 100644 --- a/docs/statuscake-configuration.md +++ b/docs/statuscake-configuration.md @@ -16,15 +16,16 @@ Currently additional Statuscake configurations can be added through these fields |:--------------------------------------------------------:|:------------------------------------------------:| | CheckRate | Set Check Rate for the monitor (default: 300) | | TestType | Set Test type - HTTP, TCP, PING (default: HTTP) | -| Paused | Pause the service | +| Paused | Pause the service | | PingURL | Webhook for alerts | | FollowRedirect | Enable ingress redirects | -| Port | TCP Port | +| Port | TCP Port | | TriggerRate | Minutes to wait before sending an alert | | ContactGroup | Contact Group to be alerted. | | TestTags | Comma separated list of tags | | FindString | String to look for within the response | -| BasicAuthUser | Required for [basic-authenticationchecks](#basic-auth-checks) | +| BasicAuthUser | Required for [basic-authenticationchecks](#basic-auth-checks) | +| BasicAuthSecret | Allows for an alternate method of adding basic-auth to checks | | Regions | Regions to execute the check from | @@ -34,6 +35,10 @@ Statuscake supports checks completing basic auth requirements. In `EndpointMonit For example; setting the field like `basic-auth-user: 'my-service-username'` will set the username field to the value `my-service-username` and will retrieve the password via `os.Getenv('my-service-username')` and set this appropriately. +In addition to the previous method, you can use the `basicAuthSecret` field to define a secret that should be read by the monitor which contains the basic-auth data. This should be a generic kubernetes secret with the secret containing only `username: password`. This setting expects the `basicAuthUser` field to be filled in, so that we know what key to read from the secret. Furthermore, the secret must be present in the same namespace as the monitor. This ensures that we can keep the permissions of the monitor to be as small as possible. + +So for example, if you have a generic secret called `my-deployment-secret` containing the data `user: MyPassword1!` you should set `basicAuthUser: user` and `BasicAuthSecret: my-deployment-secret`. This will ensure that the monitor can read the basic-auth data correctly. + ## Example: ```yaml diff --git a/pkg/kube/kube.go b/pkg/kube/kube.go index fc0bdc58..9560946d 100644 --- a/pkg/kube/kube.go +++ b/pkg/kube/kube.go @@ -12,6 +12,10 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" ) var ( @@ -26,14 +30,14 @@ func getConfig() (*rest.Config, error) { if kubeconfigPath == "" { kubeconfigPath = os.Getenv("HOME") + "/.kube/config" } - //If file exists so use that config settings + // If file exists so use that config settings if _, err := os.Stat(kubeconfigPath); err == nil { config, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath) if err != nil { return nil, err } } else { - //Use Incluster Configuration + // Use Incluster Configuration config, err = rest.InClusterConfig() if err != nil { return nil, err @@ -55,6 +59,24 @@ func GetClient() (*kubernetes.Clientset, error) { return kubernetes.NewForConfig(config) } +func CreateSingleClient() (client.Client, error) { + config, err := getConfig() + if err != nil { + return nil, err + } + + s := runtime.NewScheme() + if err := scheme.AddToScheme(s); err != nil { + return nil, err + } + + k8sClient, err := client.New(config, client.Options{Scheme: s}) + if err != nil { + return nil, err + } + return k8sClient, err +} + // IsRoute returns true if given resource is a route func IsRoute(resource interface{}) bool { if _, ok := resource.(*routev1.Route); ok { diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 728ce715..4b038d59 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -13,18 +13,13 @@ import ( "strings" "gopkg.in/yaml.v2" - "k8s.io/client-go/rest" - // ctrlConfig "sigs.k8s.io/controller-runtime/pkg/client/config" logf "sigs.k8s.io/controller-runtime/pkg/log" - //"sigs.k8s.io/controller-runtime/pkg/manager" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" statuscake "github.com/StatusCakeDev/statuscake-go" endpointmonitorv1alpha1 "github.com/stakater/IngressMonitorController/v2/api/v1alpha1" "github.com/stakater/IngressMonitorController/v2/pkg/config" + "github.com/stakater/IngressMonitorController/v2/pkg/kube" "github.com/stakater/IngressMonitorController/v2/pkg/models" "github.com/stakater/IngressMonitorController/v2/pkg/secret" ) @@ -111,38 +106,26 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { if providerConfig != nil && len(providerConfig.BasicAuthSecret) > 0 { var basicPass string - clusterConfig, err := rest.InClusterConfig() - if err != nil { - panic(err) - } - - s := runtime.NewScheme() - if err := scheme.AddToScheme(s); err != nil { - panic(err) - } - // Create a new client - k8sClient, err := client.New(clusterConfig, client.Options{Scheme: s}) + k8sClient, err := kube.CreateSingleClient() if err != nil { panic(err) } - log.Info(fmt.Sprintf("The secret name is: %s", providerConfig.BasicAuthSecret)) - secretKey, err := secret.LoadSecretData(k8sClient, providerConfig.BasicAuthSecret, "test", providerConfig.BasicAuthUser) + namespace := kube.GetCurrentKubernetesNamespace() + secretKey, err := secret.LoadSecretData(k8sClient, providerConfig.BasicAuthSecret, namespace, providerConfig.BasicAuthUser) if err != nil { - panic(err) - } + log.Error(err, "Could not read the secret") + } else { + err = yaml.Unmarshal([]byte(secretKey), &basicPass) + if err != nil { + panic(err) + } - err = yaml.Unmarshal([]byte(secretKey), &basicPass) - if err != nil { - panic(err) + f.Add("basic_username", providerConfig.BasicAuthUser) + f.Add("basic_password", basicPass) + log.Info("Basic auth requirement detected. Setting username and password") } - var log_str string = fmt.Sprintf("Secret content -- BasicAuthUser: %s | BasicAuthPass: %s", providerConfig.BasicAuthUser, basicPass) - log.Info(log_str) - - f.Add("basic_username", providerConfig.BasicAuthUser) - f.Add("basic_password", basicPass) - log.Info("Basic auth requirement detected. Setting username and password") } if providerConfig != nil && len(providerConfig.StatusCodes) > 0 { From bd43d94bd38df37ef258fce33f345e18054f7be8 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 13:27:12 +0200 Subject: [PATCH 06/20] Use new secret function not client function --- api/v1alpha1/endpointmonitor_types.go | 2 +- ...monitor.stakater.com_endpointmonitors.yaml | 2 +- pkg/kube/kube.go | 26 ++----------------- pkg/monitors/statuscake/statuscake-monitor.go | 18 ++++--------- pkg/secret/secrets.go | 23 ++++++++++++++++ 5 files changed, 32 insertions(+), 39 deletions(-) diff --git a/api/v1alpha1/endpointmonitor_types.go b/api/v1alpha1/endpointmonitor_types.go index 07f1338b..424806d3 100644 --- a/api/v1alpha1/endpointmonitor_types.go +++ b/api/v1alpha1/endpointmonitor_types.go @@ -163,7 +163,7 @@ type StatusCakeConfig struct { // +optional BasicAuthUser string `json:"basicAuthUser,omitempty"` - // Basic Auth String + // Basic Auth Secret Name // +optional BasicAuthSecret string `json:"basicAuthSecret,omitempty"` diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index 2cce1dcb..992d4e10 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -256,7 +256,7 @@ spec: description: Configuration for StatusCake Monitor Provider properties: basicAuthSecret: - description: Basic Auth String + description: Basic Auth Secret Name type: string basicAuthUser: description: Basic Auth User diff --git a/pkg/kube/kube.go b/pkg/kube/kube.go index 9560946d..fc0bdc58 100644 --- a/pkg/kube/kube.go +++ b/pkg/kube/kube.go @@ -12,10 +12,6 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" ) var ( @@ -30,14 +26,14 @@ func getConfig() (*rest.Config, error) { if kubeconfigPath == "" { kubeconfigPath = os.Getenv("HOME") + "/.kube/config" } - // If file exists so use that config settings + //If file exists so use that config settings if _, err := os.Stat(kubeconfigPath); err == nil { config, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath) if err != nil { return nil, err } } else { - // Use Incluster Configuration + //Use Incluster Configuration config, err = rest.InClusterConfig() if err != nil { return nil, err @@ -59,24 +55,6 @@ func GetClient() (*kubernetes.Clientset, error) { return kubernetes.NewForConfig(config) } -func CreateSingleClient() (client.Client, error) { - config, err := getConfig() - if err != nil { - return nil, err - } - - s := runtime.NewScheme() - if err := scheme.AddToScheme(s); err != nil { - return nil, err - } - - k8sClient, err := client.New(config, client.Options{Scheme: s}) - if err != nil { - return nil, err - } - return k8sClient, err -} - // IsRoute returns true if given resource is a route func IsRoute(resource interface{}) bool { if _, ok := resource.(*routev1.Route); ok { diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 4b038d59..78fe54d1 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -12,8 +12,6 @@ import ( "strconv" "strings" - "gopkg.in/yaml.v2" - logf "sigs.k8s.io/controller-runtime/pkg/log" statuscake "github.com/StatusCakeDev/statuscake-go" @@ -105,25 +103,19 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { } if providerConfig != nil && len(providerConfig.BasicAuthSecret) > 0 { - var basicPass string - - k8sClient, err := kube.CreateSingleClient() + k8sClient, err := kube.GetClient() if err != nil { panic(err) } namespace := kube.GetCurrentKubernetesNamespace() - secretKey, err := secret.LoadSecretData(k8sClient, providerConfig.BasicAuthSecret, namespace, providerConfig.BasicAuthUser) + username, password, err := secret.ReadBasicAuthSecret(k8sClient.CoreV1().Secrets(namespace), providerConfig.BasicAuthSecret) + if err != nil { log.Error(err, "Could not read the secret") } else { - err = yaml.Unmarshal([]byte(secretKey), &basicPass) - if err != nil { - panic(err) - } - - f.Add("basic_username", providerConfig.BasicAuthUser) - f.Add("basic_password", basicPass) + f.Add("basic_username", username) + f.Add("basic_password", password) log.Info("Basic auth requirement detected. Setting username and password") } } diff --git a/pkg/secret/secrets.go b/pkg/secret/secrets.go index 704a7167..0d679050 100644 --- a/pkg/secret/secrets.go +++ b/pkg/secret/secrets.go @@ -5,7 +5,9 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + clientv1 "k8s.io/client-go/kubernetes/typed/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -23,3 +25,24 @@ func LoadSecretData(apiReader client.Reader, secretName, namespace, dataKey stri } return string(retStr), nil } + +func ReadBasicAuthSecret(apiReader clientv1.SecretInterface, secretName string) (string, string, error) { + secret, err := apiReader.Get(context.TODO(), secretName, metav1.GetOptions{}) + var username, password string + if err != nil { + return "", "", err + } + + for key, value := range secret.Data { + switch key { + case "username": + username = string(value) + case "password": + password = string(value) + default: + return "", "", fmt.Errorf("secret %s contained unkown key %s", secretName, key) + } + } + + return username, password, err +} From 92649217f80c817a0b26fc795d97f499646b2dce Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 13:36:52 +0200 Subject: [PATCH 07/20] Revert random formatting changes --- api/v1alpha1/endpointmonitor_types.go | 1 + ...monitor.stakater.com_endpointmonitors.yaml | 46 ++++++++----------- pkg/monitors/statuscake/statuscake-monitor.go | 3 ++ 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/api/v1alpha1/endpointmonitor_types.go b/api/v1alpha1/endpointmonitor_types.go index 424806d3..fde33e28 100644 --- a/api/v1alpha1/endpointmonitor_types.go +++ b/api/v1alpha1/endpointmonitor_types.go @@ -232,6 +232,7 @@ type StatusCakeConfig struct { // PingdomConfig defines the configuration for Pingdom Monitor Provider type PingdomConfig struct { + // The pingdom check interval in minutes // +optional Resolution int `json:"resolution,omitempty"` diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index 992d4e10..b448f935 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -4,6 +4,7 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 + creationTimestamp: null name: endpointmonitors.endpointmonitor.stakater.com spec: group: endpointmonitor.stakater.com @@ -20,19 +21,17 @@ spec: description: EndpointMonitor is the Schema for the endpointmonitors API properties: apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: |- - Kind is a string value representing the REST resource this object represents. + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -69,9 +68,8 @@ spec: properties: alertSensitivity: default: none - description: |- - The alertSensitivity value defaults to none if there are no alerts or can be set to low, medium, - or high to correspond to the check alert levels. + description: 'The alertSensitivity value defaults to none if there are no alerts or can be set to low, medium, + or high to correspond to the check alert levels.' enum: - none - low @@ -84,8 +82,7 @@ spec: format: int64 type: integer probes: - description: |- - Probes are the monitoring agents responsible for simulating user interactions with your web applications + description: Probes are the monitoring agents responsible for simulating user interactions with your web applications or services. These agents periodically send requests to predefined URLs and record the responses, checking for expected outcomes and measuring performance. items: @@ -117,8 +114,7 @@ spec: description: Set to "true" to pause checks type: boolean postDataEnvVar: - description: |- - Data that should be posted to the web page, for example submission data for a sign-up or login form. + description: Data that should be posted to the web page, for example submission data for a sign-up or login form. The data needs to be formatted in the same way as a web browser would send it to the web server. Because post data contains sensitive secret this field is only a reference to an environment variable. type: string @@ -126,8 +122,7 @@ spec: description: Custom request headers type: string requestHeadersEnvVar: - description: |- - Custom request headers that should be read from an environment variable as it possibly contains sensitive data. + description: Custom request headers that should be read from an environment variable as it possibly contains sensitive data. An example would be an API token. type: string resolution: @@ -141,8 +136,7 @@ spec: HTML code of the page type: string sslDownDaysBefore: - description: |- - Consider down prior to certificate expiring + description: Consider down prior to certificate expiring Select the number of days prior to your certificate expiry date that you want to consider the check down. At this day your check will be considered down and if applicable a down alert will be sent. type: integer @@ -154,8 +148,7 @@ spec: description: '`-` separated team id''s (e.g. "1234567_8_9-9876543_2_1")' type: string verifyCertificate: - description: |- - Monitor SSL/TLS certificate + description: Monitor SSL/TLS certificate Monitor the validity of your SSL/TLS certificate. With this enabled Uptime checks will be considered DOWN when the certificate becomes invalid or expires. SSL/TLS certificate monitoring is available for HTTP checks. @@ -219,17 +212,15 @@ spec: args: additionalProperties: type: string - description: |- - contains the html element with assigned value + description: 'contains the html element with assigned value the key element is always lowercase for example {"url": "https://www.pingdom.com"} - see available values at https://pkg.go.dev/github.com/karlderkaefer/pingdom-golang-client@latest/pkg/pingdom/client/tmschecks#StepArg + see available values at https://pkg.go.dev/github.com/karlderkaefer/pingdom-golang-client@latest/pkg/pingdom/client/tmschecks#StepArg' type: object function: - description: |- - contains the function that is executed as part of the step + description: 'contains the function that is executed as part of the step commands: go_to, click, fill, check, uncheck, sleep, select_radio, basic_auth, submit, wait_for_element, wait_for_contains validations: url, exists, not_exists, contains, not_contains, field_contains, field_not_contains, is_checked, is_not_checked, radio_selected, dropdown_selected, dropdown_not_selected - see updated list https://docs.pingdom.com/api/#section/TMS-Steps-Vocabulary/Script-transaction-checks + see updated list https://docs.pingdom.com/api/#section/TMS-Steps-Vocabulary/Script-transaction-checks' type: string required: - args @@ -354,9 +345,8 @@ spec: this monitor type: string customHTTPStatuses: - description: |- - Defines which http status codes are treated as up or down - For ex: 200:0_401:1_503:1 (to accept 200 as down and 401 and 503 as up) + description: 'Defines which http status codes are treated as up or down + For ex: 200:0_401:1_503:1 (to accept 200 as down and 401 and 503 as up)' type: string interval: description: The uptimerobot check interval in seconds diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 78fe54d1..2b5ace9b 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -122,6 +122,7 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { if providerConfig != nil && len(providerConfig.StatusCodes) > 0 { f.Add("status_codes_csv", providerConfig.StatusCodes) + } else { statusCodes := []string{ "204", // No content @@ -262,6 +263,7 @@ func (service *StatusCakeMonitorService) GetByName(name string) (*models.Monitor } errorString := "GetByName Request failed for name: " + name return nil, errors.New(errorString) + } // GetByID function will Get a monitor by it's ID @@ -463,6 +465,7 @@ func (service *StatusCakeMonitorService) Remove(m models.Monitor) { } if resp.StatusCode != http.StatusNoContent { log.Error(nil, fmt.Sprintf("Delete Request failed for Monitor: %s with id: %s", m.Name, m.ID)) + } else { _, err = service.GetByID(m.ID) if strings.Contains(err.Error(), "Request failed") { From eab5ea336cd54c8b0834f1c4271e68728dcb2cd1 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 13:53:25 +0200 Subject: [PATCH 08/20] More stupid formatting fixes --- api/v1alpha1/endpointmonitor_types.go | 2 +- ...monitor.stakater.com_endpointmonitors.yaml | 75 +++++++++++-------- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/api/v1alpha1/endpointmonitor_types.go b/api/v1alpha1/endpointmonitor_types.go index fde33e28..9fbda8cf 100644 --- a/api/v1alpha1/endpointmonitor_types.go +++ b/api/v1alpha1/endpointmonitor_types.go @@ -232,7 +232,6 @@ type StatusCakeConfig struct { // PingdomConfig defines the configuration for Pingdom Monitor Provider type PingdomConfig struct { - // The pingdom check interval in minutes // +optional Resolution int `json:"resolution,omitempty"` @@ -304,6 +303,7 @@ type PingdomConfig struct { // PingdomTransactionConfig defines the configuration for Pingdom Transaction Monitor Provider type PingdomTransactionConfig struct { + // Check status: active or inactive // +optional Paused bool `json:"paused,omitempty"` diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index b448f935..aa1f57ed 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -21,17 +21,15 @@ spec: description: EndpointMonitor is the Schema for the endpointmonitors API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: 'Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the clients + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -68,8 +66,9 @@ spec: properties: alertSensitivity: default: none - description: 'The alertSensitivity value defaults to none if there are no alerts or can be set to low, medium, - or high to correspond to the check alert levels.' + description: 'The alertSensitivity value defaults to none if there + are no alerts or can be set to low, medium, or high to correspond + to the check alert levels.' enum: - none - low @@ -82,9 +81,11 @@ spec: format: int64 type: integer probes: - description: Probes are the monitoring agents responsible for simulating user interactions with your web applications - or services. These agents periodically send requests to predefined URLs and record the responses, - checking for expected outcomes and measuring performance. + description: Probes are the monitoring agents responsible for + simulating user interactions with your web applications or services. + These agents periodically send requests to predefined URLs and + record the responses, checking for expected outcomes and measuring + performance. items: type: string type: array @@ -114,15 +115,18 @@ spec: description: Set to "true" to pause checks type: boolean postDataEnvVar: - description: Data that should be posted to the web page, for example submission data for a sign-up or login form. - The data needs to be formatted in the same way as a web browser would send it to the web server. - Because post data contains sensitive secret this field is only a reference to an environment variable. + description: Data that should be posted to the web page, for example + submission data for a sign-up or login form. The data needs + to be formatted in the same way as a web browser would send + it to the web server. Because post data contains sensitive secret + this field is only a reference to an environment variable. type: string requestHeaders: description: Custom request headers type: string requestHeadersEnvVar: - description: Custom request headers that should be read from an environment variable as it possibly contains sensitive data. + description: Custom request headers that should be read from an + environment variable as it possibly contains sensitive data. An example would be an API token. type: string resolution: @@ -136,9 +140,11 @@ spec: HTML code of the page type: string sslDownDaysBefore: - description: Consider down prior to certificate expiring - Select the number of days prior to your certificate expiry date that you want to consider the check down. - At this day your check will be considered down and if applicable a down alert will be sent. + description: Consider down prior to certificate expiring Select + the number of days prior to your certificate expiry date that + you want to consider the check down. At this day your check + will be considered down and if applicable a down alert will + be sent. type: integer tags: description: Comma separated set of tags to apply to check (e.g. @@ -148,10 +154,11 @@ spec: description: '`-` separated team id''s (e.g. "1234567_8_9-9876543_2_1")' type: string verifyCertificate: - description: Monitor SSL/TLS certificate - Monitor the validity of your SSL/TLS certificate. With this enabled Uptime checks will be considered DOWN when - the certificate becomes invalid or expires. - SSL/TLS certificate monitoring is available for HTTP checks. + description: Monitor SSL/TLS certificate Monitor the validity + of your SSL/TLS certificate. With this enabled Uptime checks + will be considered DOWN when the certificate becomes invalid + or expires. SSL/TLS certificate monitoring is available for + HTTP checks. type: boolean type: object pingdomTransactionConfig: @@ -213,14 +220,17 @@ spec: additionalProperties: type: string description: 'contains the html element with assigned value - the key element is always lowercase for example {"url": "https://www.pingdom.com"} - see available values at https://pkg.go.dev/github.com/karlderkaefer/pingdom-golang-client@latest/pkg/pingdom/client/tmschecks#StepArg' + the key element is always lowercase for example {"url": + "https://www.pingdom.com"} see available values at https://pkg.go.dev/github.com/karlderkaefer/pingdom-golang-client@latest/pkg/pingdom/client/tmschecks#StepArg' type: object function: - description: 'contains the function that is executed as part of the step - commands: go_to, click, fill, check, uncheck, sleep, select_radio, basic_auth, submit, wait_for_element, wait_for_contains - validations: url, exists, not_exists, contains, not_contains, field_contains, field_not_contains, is_checked, is_not_checked, radio_selected, dropdown_selected, dropdown_not_selected - see updated list https://docs.pingdom.com/api/#section/TMS-Steps-Vocabulary/Script-transaction-checks' + description: 'contains the function that is executed as + part of the step commands: go_to, click, fill, check, + uncheck, sleep, select_radio, basic_auth, submit, wait_for_element, + wait_for_contains validations: url, exists, not_exists, + contains, not_contains, field_contains, field_not_contains, + is_checked, is_not_checked, radio_selected, dropdown_selected, + dropdown_not_selected see updated list https://docs.pingdom.com/api/#section/TMS-Steps-Vocabulary/Script-transaction-checks' type: string required: - args @@ -345,8 +355,9 @@ spec: this monitor type: string customHTTPStatuses: - description: 'Defines which http status codes are treated as up or down - For ex: 200:0_401:1_503:1 (to accept 200 as down and 401 and 503 as up)' + description: 'Defines which http status codes are treated as up + or down For ex: 200:0_401:1_503:1 (to accept 200 as down + and 401 and 503 as up)' type: string interval: description: The uptimerobot check interval in seconds From b09b83c65fc288cc27cdad4d8ad00d00cb8e882f Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 13:56:36 +0200 Subject: [PATCH 09/20] Final formatting fixes I don't like formatting :( --- ...dpointmonitor.stakater.com_endpointmonitors.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index aa1f57ed..8ba49a54 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -23,12 +23,11 @@ spec: apiVersion: description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the clients + object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: @@ -66,9 +65,9 @@ spec: properties: alertSensitivity: default: none - description: 'The alertSensitivity value defaults to none if there + description: The alertSensitivity value defaults to none if there are no alerts or can be set to low, medium, or high to correspond - to the check alert levels.' + to the check alert levels. enum: - none - low @@ -356,8 +355,8 @@ spec: type: string customHTTPStatuses: description: 'Defines which http status codes are treated as up - or down For ex: 200:0_401:1_503:1 (to accept 200 as down - and 401 and 503 as up)' + or down For ex: 200:0_401:1_503:1 (to accept 200 as down and + 401 and 503 as up)' type: string interval: description: The uptimerobot check interval in seconds From b85d4a758fcb86f07a0a72b6607c509136b5b2f0 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:03:53 +0200 Subject: [PATCH 10/20] Small fixes and docs update --- docs/statuscake-configuration.md | 4 ++-- pkg/monitors/statuscake/statuscake-monitor.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/statuscake-configuration.md b/docs/statuscake-configuration.md index 200ce72f..93490aba 100644 --- a/docs/statuscake-configuration.md +++ b/docs/statuscake-configuration.md @@ -35,9 +35,9 @@ Statuscake supports checks completing basic auth requirements. In `EndpointMonit For example; setting the field like `basic-auth-user: 'my-service-username'` will set the username field to the value `my-service-username` and will retrieve the password via `os.Getenv('my-service-username')` and set this appropriately. -In addition to the previous method, you can use the `basicAuthSecret` field to define a secret that should be read by the monitor which contains the basic-auth data. This should be a generic kubernetes secret with the secret containing only `username: password`. This setting expects the `basicAuthUser` field to be filled in, so that we know what key to read from the secret. Furthermore, the secret must be present in the same namespace as the monitor. This ensures that we can keep the permissions of the monitor to be as small as possible. +In addition to the previous method, you can use the `basicAuthSecret` field to define a secret that should be read by the monitor which contains the basic-auth data. This secret should only contain the keys `username` and `password`. It expects the values for those keys to be strings. NOT base64 encoded strings. Furthermore, the secret must be present in the same namespace as the IngressMonitorController operator. This ensures that we can keep the permissions of the operator to be as small as possible. -So for example, if you have a generic secret called `my-deployment-secret` containing the data `user: MyPassword1!` you should set `basicAuthUser: user` and `BasicAuthSecret: my-deployment-secret`. This will ensure that the monitor can read the basic-auth data correctly. +So for example, if you have a secret called `my-deployment-secret` it should contain the data `username: my-user` and `password: MyPassword1!` and you should set to `basicAuthSecret: my-deployment-secret`. This will ensure that the monitor can read the basic-auth data correctly. ## Example: diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 2b5ace9b..88f6d071 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -88,7 +88,7 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { } } - if providerConfig != nil && len(providerConfig.BasicAuthUser) > 0 && len(providerConfig.BasicAuthSecret) == 0 { + if providerConfig != nil && len(providerConfig.BasicAuthUser) > 0 { // This value is mandatory // Environment variable should define the password // Mounted via a secret; key is the username, value is the password From 89375dace0c19bcc8d24531e2e0b0a797b2a369a Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:34:45 +0200 Subject: [PATCH 11/20] Update example --- examples/endpointMonitor/statuscake-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/endpointMonitor/statuscake-config.yaml b/examples/endpointMonitor/statuscake-config.yaml index bf4f64eb..54ab4994 100644 --- a/examples/endpointMonitor/statuscake-config.yaml +++ b/examples/endpointMonitor/statuscake-config.yaml @@ -7,6 +7,7 @@ spec: statusCakeConfig: port: 123 basicAuthUser: my-service-username + basicAuthSecret: my-basicauth-secret checkRate: 300 realBrowser: true testTags: 'abc,def' From ce3811a7a73da84f7254710f40ce895a4cd806cb Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Thu, 3 Oct 2024 17:02:46 +0200 Subject: [PATCH 12/20] Update CRDs --- .../crds/endpointmonitor.stakater.com_endpointmonitors.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml b/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml index 0f984d44..1d6b0dec 100644 --- a/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.9.0 creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: endpointmonitors.endpointmonitor.stakater.com spec: group: endpointmonitor.stakater.com @@ -255,6 +255,9 @@ spec: statusCakeConfig: description: Configuration for StatusCake Monitor Provider properties: + basicAuthSecret: + description: Basic Auth Secret Name + type: string basicAuthUser: description: Basic Auth User type: string From df4e885f1e65a96432b6dfcf85dc1d7a18266953 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:05:31 +0200 Subject: [PATCH 13/20] Add raw_post_data var to statuscake --- api/v1alpha1/endpointmonitor_types.go | 4 ++++ .../bases/endpointmonitor.stakater.com_endpointmonitors.yaml | 4 ++++ pkg/monitors/statuscake/statuscake-monitor.go | 3 +++ 3 files changed, 11 insertions(+) diff --git a/api/v1alpha1/endpointmonitor_types.go b/api/v1alpha1/endpointmonitor_types.go index 9fbda8cf..79b18f69 100644 --- a/api/v1alpha1/endpointmonitor_types.go +++ b/api/v1alpha1/endpointmonitor_types.go @@ -228,6 +228,10 @@ type StatusCakeConfig struct { // String to look for within the response. Considered down if not found // +optional FindString string `json:"findString,omitempty"` + + // RawPostData can be used to send parameters within the URL. Changes the request from a GET to a POST + // +optional + RawPostData string `json:"rawPostData,omitempty"` } // PingdomConfig defines the configuration for Pingdom Monitor Provider diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index 8ba49a54..2ef7629c 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -291,6 +291,10 @@ spec: port: description: TCP Port type: integer + rawPostData: + description: RawPostData can be used to send parameters within + the URL. Changes the request from a GET to a POST + type: string realBrowser: description: Enable Real Browser type: boolean diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 88f6d071..4b13a50a 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -222,6 +222,9 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { if providerConfig != nil { f.Add("find_string", providerConfig.FindString) } + if providerConfig != nil && len(providerConfig.RawPostData) > 0 { + f.Add("post_raw", providerConfig.RawPostData) + } return f } From 7107f26a57eac727e3dbd8e6601868d914d827d1 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:16:52 +0200 Subject: [PATCH 14/20] Add user_agent var to statuscake --- api/v1alpha1/endpointmonitor_types.go | 4 ++++ pkg/monitors/statuscake/statuscake-monitor.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/api/v1alpha1/endpointmonitor_types.go b/api/v1alpha1/endpointmonitor_types.go index 79b18f69..c3ac40bc 100644 --- a/api/v1alpha1/endpointmonitor_types.go +++ b/api/v1alpha1/endpointmonitor_types.go @@ -232,6 +232,10 @@ type StatusCakeConfig struct { // RawPostData can be used to send parameters within the URL. Changes the request from a GET to a POST // +optional RawPostData string `json:"rawPostData,omitempty"` + + // UserAgent is used to set a user agent string. + // +optional + UserAgent string `json:"userAgent,omitempty"` } // PingdomConfig defines the configuration for Pingdom Monitor Provider diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index 4b13a50a..f73f2715 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -225,6 +225,9 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { if providerConfig != nil && len(providerConfig.RawPostData) > 0 { f.Add("post_raw", providerConfig.RawPostData) } + if providerConfig != nil && len(providerConfig.UserAgent) > 0 { + f.Add("user_agent", providerConfig.UserAgent) + } return f } From ba83b4bb15c010f5f668c67ba52cbacebdea35dd Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:19:45 +0200 Subject: [PATCH 15/20] Update formatting for user_agent --- api/v1alpha1/endpointmonitor_types.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/v1alpha1/endpointmonitor_types.go b/api/v1alpha1/endpointmonitor_types.go index c3ac40bc..321127bd 100644 --- a/api/v1alpha1/endpointmonitor_types.go +++ b/api/v1alpha1/endpointmonitor_types.go @@ -233,9 +233,9 @@ type StatusCakeConfig struct { // +optional RawPostData string `json:"rawPostData,omitempty"` - // UserAgent is used to set a user agent string. - // +optional - UserAgent string `json:"userAgent,omitempty"` + // UserAgent is used to set a user agent string. + // +optional + UserAgent string `json:"userAgent,omitempty"` } // PingdomConfig defines the configuration for Pingdom Monitor Provider From eb5bcde1d2633c6ce8927652eee74d24abc27afc Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:24:26 +0200 Subject: [PATCH 16/20] Fix tabs in statuscake-monitor.go --- pkg/monitors/statuscake/statuscake-monitor.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index f73f2715..ac3f4331 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -225,9 +225,9 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { if providerConfig != nil && len(providerConfig.RawPostData) > 0 { f.Add("post_raw", providerConfig.RawPostData) } - if providerConfig != nil && len(providerConfig.UserAgent) > 0 { - f.Add("user_agent", providerConfig.UserAgent) - } + if providerConfig != nil && len(providerConfig.UserAgent) > 0 { + f.Add("user_agent", providerConfig.UserAgent) + } return f } From 68f525c3ad70b0d958e2c25b03b1faebd94ad666 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:31:04 +0200 Subject: [PATCH 17/20] Update base crds --- .../bases/endpointmonitor.stakater.com_endpointmonitors.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml index 2ef7629c..8882cc43 100644 --- a/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/config/crd/bases/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -314,6 +314,9 @@ spec: triggerRate: description: Minutes to wait before sending an alert type: integer + userAgent: + description: UserAgent is used to set a user agent string. + type: string type: object updownConfig: description: Configuration for Updown Monitor Provider From 65ae6450b0a283e8421decbaca4067c3685d74bf Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Wed, 2 Oct 2024 14:37:57 +0200 Subject: [PATCH 18/20] Docs and example update --- docs/statuscake-configuration.md | 2 ++ examples/endpointMonitor/statuscake-config.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/statuscake-configuration.md b/docs/statuscake-configuration.md index 93490aba..47c70c24 100644 --- a/docs/statuscake-configuration.md +++ b/docs/statuscake-configuration.md @@ -27,6 +27,8 @@ Currently additional Statuscake configurations can be added through these fields | BasicAuthUser | Required for [basic-authenticationchecks](#basic-auth-checks) | | BasicAuthSecret | Allows for an alternate method of adding basic-auth to checks | | Regions | Regions to execute the check from | +| RawPostData | Add data to change the request to a POST | +| UserAgent | Add a user agent string to the request | ### Basic Auth checks diff --git a/examples/endpointMonitor/statuscake-config.yaml b/examples/endpointMonitor/statuscake-config.yaml index 54ab4994..165d53b4 100644 --- a/examples/endpointMonitor/statuscake-config.yaml +++ b/examples/endpointMonitor/statuscake-config.yaml @@ -21,4 +21,6 @@ spec: pingUrl: 'https://stakater2.com/' contactGroup: '123456,654321' regions: amsterdam, stockholm + rawPostData: '{"test": "data"}' + userAgent: test-user url: 'https://stakater1.com/' From 2eff906bc6cd304dcfff9c29a0cf5de559fd1b7a Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Thu, 3 Oct 2024 17:05:39 +0200 Subject: [PATCH 19/20] Update CRDs --- .../endpointmonitor.stakater.com_endpointmonitors.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml b/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml index 1d6b0dec..24717806 100644 --- a/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml +++ b/charts/ingressmonitorcontroller/crds/endpointmonitor.stakater.com_endpointmonitors.yaml @@ -291,6 +291,10 @@ spec: port: description: TCP Port type: integer + rawPostData: + description: RawPostData can be used to send parameters within + the URL. Changes the request from a GET to a POST + type: string realBrowser: description: Enable Real Browser type: boolean @@ -310,6 +314,9 @@ spec: triggerRate: description: Minutes to wait before sending an alert type: integer + userAgent: + description: UserAgent is used to set a user agent string. + type: string type: object updownConfig: description: Configuration for Updown Monitor Provider From 28c025a29145bdb5a69e0eb9fea6581da4ce9193 Mon Sep 17 00:00:00 2001 From: Matthijs Wolters Date: Thu, 3 Oct 2024 11:41:40 +0200 Subject: [PATCH 20/20] Implement Equals function using TestTags It is mentioned in a comment in the code itself but because of the discrepency between the fields in the EndpointMonitor CR and the Statuscake API it is not immediately clear how to compare an old monitor with an updated monitor. The way I have elected to check this is to use the TestTags field to include some kind of identifier that should be updated on any change. So if the tags have changed then the monitor should be updated. --- pkg/monitors/statuscake/statuscake-mappers.go | 11 ++++++++++ pkg/monitors/statuscake/statuscake-monitor.go | 21 +++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/pkg/monitors/statuscake/statuscake-mappers.go b/pkg/monitors/statuscake/statuscake-mappers.go index a5b8715a..5eed6537 100644 --- a/pkg/monitors/statuscake/statuscake-mappers.go +++ b/pkg/monitors/statuscake/statuscake-mappers.go @@ -1,7 +1,10 @@ package statuscake import ( + "strings" + statuscake "github.com/StatusCakeDev/statuscake-go" + endpointmonitorv1alpha1 "github.com/stakater/IngressMonitorController/v2/api/v1alpha1" "github.com/stakater/IngressMonitorController/v2/pkg/models" ) @@ -11,6 +14,10 @@ func StatusCakeMonitorMonitorToBaseMonitorMapper(statuscakeData StatusCakeMonito m.Name = statuscakeData.WebsiteName m.URL = statuscakeData.WebsiteURL m.ID = statuscakeData.TestID + + var providerConfig endpointmonitorv1alpha1.StatusCakeConfig + providerConfig.TestTags = strings.Join(statuscakeData.Tags, ",") + m.Config = &providerConfig return &m } @@ -20,6 +27,10 @@ func StatusCakeApiResponseDataToBaseMonitorMapper(statuscakeData statuscake.Upti m.Name = statuscakeData.Data.Name m.URL = statuscakeData.Data.WebsiteURL m.ID = statuscakeData.Data.ID + + var providerConfig endpointmonitorv1alpha1.StatusCakeConfig + providerConfig.TestTags = strings.Join(statuscakeData.Data.Tags, ",") + m.Config = &providerConfig return &m } diff --git a/pkg/monitors/statuscake/statuscake-monitor.go b/pkg/monitors/statuscake/statuscake-monitor.go index ac3f4331..3cdcd35f 100644 --- a/pkg/monitors/statuscake/statuscake-monitor.go +++ b/pkg/monitors/statuscake/statuscake-monitor.go @@ -34,8 +34,17 @@ type StatusCakeMonitorService struct { } func (monitor *StatusCakeMonitorService) Equal(oldMonitor models.Monitor, newMonitor models.Monitor) bool { - // TODO: Retrieve oldMonitor config and compare it here - return false + // Since there is a discrepency between the fields in the endpointmonitor CR and the statuscake API + // use the tags to define a last updated by tags. This ensures we are not ratelimited by statuscake. + oldConf := oldMonitor.Config.(*endpointmonitorv1alpha1.StatusCakeConfig) + newConf := newMonitor.Config.(*endpointmonitorv1alpha1.StatusCakeConfig) + if oldConf.TestTags != newConf.TestTags { + msg := "Found a difference between the old TestTags and new TestTags. Updating the UptimeCheck..." + log.Info(msg, "Old Tags", oldConf.TestTags, "New Tags", newConf.TestTags) + return false + } else { + return true + } } // buildUpsertForm function is used to create the form needed to Add or update a monitor @@ -219,15 +228,15 @@ func buildUpsertForm(m models.Monitor, cgroup string) url.Values { if providerConfig != nil && providerConfig.Confirmation > 0 { f.Add("confirmation", strconv.Itoa(providerConfig.Confirmation)) } - if providerConfig != nil { + if providerConfig != nil && len(providerConfig.FindString) > 0 { f.Add("find_string", providerConfig.FindString) } if providerConfig != nil && len(providerConfig.RawPostData) > 0 { f.Add("post_raw", providerConfig.RawPostData) } - if providerConfig != nil && len(providerConfig.UserAgent) > 0 { - f.Add("user_agent", providerConfig.UserAgent) - } + if providerConfig != nil && len(providerConfig.UserAgent) > 0 { + f.Add("user_agent", providerConfig.UserAgent) + } return f }