Skip to content
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
5 changes: 3 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ jobs:
go-version-file: go.mod

- name: Lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v8
with:
version: v1.64
# v1 cannot lint a go 1.25 module, it is built with go 1.24
version: v2.14.0
only-new-issues: false
args: --timeout 10m

Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ jobs:
go-version-file: go.mod

- name: Lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v8
with:
version: v1.64
# v1 cannot lint a go 1.25 module, it is built with go 1.24
version: v2.14.0
only-new-issues: false
args: --timeout 10m

Expand Down
29 changes: 29 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
version: "2"

# golangci-lint v2 is required to lint a go 1.25 module (v1 was built with go 1.24
# and refuses to run on a newer go directive). The settings below keep the checks
# that were enabled by default in v1, so the migration does not turn on a new set
# of checks for existing code.
linters:
settings:
staticcheck:
checks:
- all
# quickfix checks (QF*) are suggestions, they were not part of the v1
# default linter set
- -QF*
# checks stylecheck skipped by default in v1
- -ST1000
- -ST1003
- -ST1016
- -ST1020
- -ST1021
- -ST1022
- -ST1023
exclusions:
# the v1 `issues.exclude-use-default` defaults
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ providers:
apiKey: <your-api-key>
apiURL: https://api.uptimerobot.com/v2/
alertContacts: <your-alert-contacts>
- name: UptimeKuma
apiURL: http://uptime-kuma.uptime-kuma.svc:3001
username: <your-uptime-kuma-username>
password: <your-uptime-kuma-password>
- name: StatusCake
apiKey: <your-api-key>
apiURL: https://app.statuscake.com/API/
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.24 AS builder
FROM golang:1.25 AS builder

WORKDIR /workspace
# Copy the Go Modules manifests
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ IMG ?= stakater/ingressmonitorcontroller:v2.2.4
# GOLANGCI_LINT env
GOLANGCI_LINT = _output/tools/golangci-lint
GOLANGCI_LINT_CACHE = $(PWD)/_output/golangci-lint-cache
GOLANGCI_LINT_VERSION = v1.64.0
GOLANGCI_LINT_VERSION = v2.14.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand Down Expand Up @@ -181,7 +181,7 @@ GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
KUSTOMIZE_VERSION ?= 5.4.3
CONTROLLER_TOOLS_VERSION ?= v0.16.1
ENVTEST_VERSION ?= release-0.19
GOLANGCI_LINT_VERSION ?= v1.59.1
GOLANGCI_LINT_VERSION ?= v2.14.0

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
Expand All @@ -201,7 +201,7 @@ $(ENVTEST): $(LOCALBIN)
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary (ideally with version)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Currently we support the following monitors:
- [Application Insights](https://docs.microsoft.com/en-us/azure/azure-monitor/app/monitor-web-app-availability) ([Additional Config](docs/appinsights-configuration.md))
- [gcloud](https://cloud.google.com/monitoring/uptime-checks) ([Additional Config](docs/gcloud-configuration.md))
- [Grafana](https://grafana.com/grafana/plugins/grafana-synthetic-monitoring-app/) ([Additional Config](docs/grafana-configuration.md))
- [Uptime Kuma](https://uptime.kuma.pet) ([Additional Config](docs/uptimekuma-configuration.md))

## Usage

Expand Down
33 changes: 33 additions & 0 deletions api/v1alpha1/endpointmonitor_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ type EndpointMonitorSpec struct {
// Configuration for Grafana Cloud Monitor Provider
// +optional
GrafanaConfig *GrafanaConfig `json:"grafanaConfig,omitempty"`

// Configuration for Uptime Kuma Monitor Provider
// +optional
UptimeKumaConfig *UptimeKumaConfig `json:"uptimeKumaConfig,omitempty"`
}

// UptimeRobotConfig defines the configuration for UptimeRobot Monitor Provider
Expand Down Expand Up @@ -430,6 +434,35 @@ type GrafanaConfig struct {
AlertSensitivity string `json:"alertSensitivity,omitempty"`
}

// UptimeKumaConfig defines the configuration for UptimeKuma Monitor Provider
type UptimeKumaConfig struct {
// The uptime kuma check interval in seconds (Uptime Kuma minimum is 20)
// +kubebuilder:validation:Minimum=20
// +optional
Interval int `json:"interval,omitempty"`

// The uptime kuma monitor type (http or keyword)
// +kubebuilder:validation:Enum=http;keyword
// +optional
MonitorType string `json:"monitorType,omitempty"`

// keyword to check on URL (Only if monitor-type is keyword)
// +optional
KeywordValue string `json:"keywordValue,omitempty"`

// The monitor stays up while the keyword is present in the response (yes) or
// while it is absent (no), so `no` with a keyword like "404" alerts as soon
// as the endpoint starts answering with a 404 page (Only if monitor-type is
// keyword)
// +kubebuilder:validation:Enum=yes;no
// +optional
KeywordExists string `json:"keywordExists,omitempty"`

// Comma-separated uptime kuma notification IDs to attach to this monitor
// +optional
Notifications string `json:"notifications,omitempty"`
}

// URLSource represents the set of resources to fetch the URL from
type URLSource struct {
// +optional
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,39 @@ spec:
description: Add one or more tags for the check separated by `,`
type: string
type: object
uptimeKumaConfig:
description: Configuration for Uptime Kuma Monitor Provider
properties:
interval:
description: The uptime kuma check interval in seconds (Uptime
Kuma minimum is 20)
minimum: 20
type: integer
keywordExists:
description: |-
The monitor stays up while the keyword is present in the response (yes) or
while it is absent (no), so `no` with a keyword like "404" alerts as soon
as the endpoint starts answering with a 404 page (Only if monitor-type is
keyword)
enum:
- "yes"
- "no"
type: string
keywordValue:
description: keyword to check on URL (Only if monitor-type is
keyword)
type: string
monitorType:
description: The uptime kuma monitor type (http or keyword)
enum:
- http
- keyword
type: string
notifications:
description: Comma-separated uptime kuma notification IDs to attach
to this monitor
type: string
type: object
uptimeRobotConfig:
description: Configuration for UptimeRobot Monitor Provider
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,39 @@ spec:
description: Add one or more tags for the check separated by `,`
type: string
type: object
uptimeKumaConfig:
description: Configuration for Uptime Kuma Monitor Provider
properties:
interval:
description: The uptime kuma check interval in seconds (Uptime
Kuma minimum is 20)
minimum: 20
type: integer
keywordExists:
description: |-
The monitor stays up while the keyword is present in the response (yes) or
while it is absent (no), so `no` with a keyword like "404" alerts as soon
as the endpoint starts answering with a 404 page (Only if monitor-type is
keyword)
enum:
- "yes"
- "no"
type: string
keywordValue:
description: keyword to check on URL (Only if monitor-type is
keyword)
type: string
monitorType:
description: The uptime kuma monitor type (http or keyword)
enum:
- http
- keyword
type: string
notifications:
description: Comma-separated uptime kuma notification IDs to attach
to this monitor
type: string
type: object
uptimeRobotConfig:
description: Configuration for UptimeRobot Monitor Provider
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,39 @@ spec:
description: Add one or more tags for the check separated by `,`
type: string
type: object
uptimeKumaConfig:
description: Configuration for Uptime Kuma Monitor Provider
properties:
interval:
description: The uptime kuma check interval in seconds (Uptime
Kuma minimum is 20)
minimum: 20
type: integer
keywordExists:
description: |-
The monitor stays up while the keyword is present in the response (yes) or
while it is absent (no), so `no` with a keyword like "404" alerts as soon
as the endpoint starts answering with a 404 page (Only if monitor-type is
keyword)
enum:
- "yes"
- "no"
type: string
keywordValue:
description: keyword to check on URL (Only if monitor-type is
keyword)
type: string
monitorType:
description: The uptime kuma monitor type (http or keyword)
enum:
- http
- keyword
type: string
notifications:
description: Comma-separated uptime kuma notification IDs to attach
to this monitor
type: string
type: object
uptimeRobotConfig:
description: Configuration for UptimeRobot Monitor Provider
properties:
Expand Down
79 changes: 79 additions & 0 deletions docs/uptimekuma-configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Uptime Kuma Configuration

Uptime Kuma support speaks the Uptime Kuma **2.x** socket.io API via [go-uptime-kuma-client](https://github.com/breml/go-uptime-kuma-client). Older Uptime Kuma versions (1.x) are not supported.

Notes:

- Uptime Kuma API keys do **not** work for creating, updating or deleting monitors, so the controller authenticates with **username and password**.
- **2FA must be disabled** for the account the controller uses — create a dedicated service account in Uptime Kuma without two-factor authentication.
- Uptime Kuma allows only 20 logins per minute for all clients together. The controller therefore keeps one connection for its lifetime and backs off for up to 5 minutes after a failed login, so a wrong password cannot lock out the Uptime Kuma UI.
- Point `apiURL` at the internal HTTP service (e.g. `http://uptime-kuma.uptime-kuma.svc:3001`) rather than an ingress to avoid self-signed certificate issues.

## Configuration

Add a provider entry to the controller's config:

```yaml
providers:
- name: UptimeKuma
apiURL: http://uptime-kuma.uptime-kuma.svc:3001
username: <your-username>
password: <your-password>
```

Additional uptime kuma configurations can be added to the EndpointMonitor through these fields:

| Fields | Description |
|:--------------:|:--------------------------------------------------------------------------------------------------------:|
| Interval | The uptime kuma check interval in seconds (minimum 20, defaults to 60) |
| MonitorType | The uptime kuma monitor type (http or keyword) |
| KeywordExists | `yes` keeps the monitor up while the keyword is present in the response, `no` keeps it up while the keyword is absent (Only if monitor-type is keyword) |
| KeywordValue | keyword to check on URL (e.g.'search' or '404') (Only if monitor-type is keyword) |
| Notifications | Comma-separated uptime kuma notification IDs to attach to this monitor |

### Keyword monitors

A keyword monitor compares the response body against `keywordValue`:

- `keywordExists: "yes"` (the default) — the monitor is **up** while the keyword is in the response and goes **down** when it disappears, for example `keywordValue: "search"` for a search page that is expected to render.
- `keywordExists: "no"` — the monitor is **up** only while the keyword is *absent*, so it goes **down** (and alerts) as soon as the keyword shows up, for example `keywordValue: "404"` to be alerted when the endpoint starts answering with a 404 page.

This matches the `UptimeRobot` provider, where `keywordExists` selects between `keyword_type` 1 (contains) and 2 (does not contain).

> **Note**
> `keywordExists` and `keywordValue` are strings. Quote them, otherwise YAML turns `no` into a boolean and `404` into a number and the API server rejects the resource.

### Checking fields

The controller sets the remaining Uptime Kuma check fields to the values the Kuma UI uses by default, since Uptime Kuma has no default for them and rejects a monitor without them:

| Field | Value |
|:---------------:|:--------------------------|
| Retry interval | the same as the interval |
| Max redirects | 10 |
| Timeout | 80% of the interval |
| Accepted status | 200-299 |

### Fetching notification IDs from Uptime Kuma

Notification IDs are the identifiers of notification targets (e.g. a Slack or ntfy integration) configured in Uptime Kuma. You can find the ID of a notification in **Settings > Notifications** — it is shown in the URL when editing a notification, or in the notification list API.

The controller checks the configured IDs against the notifications of the account it logs in with and refuses to create or update a monitor if one of them does not exist. Uptime Kuma itself accepts such a monitor but silently drops the notifications, which made the controller retry a failing update on every reconcile.

## Example

```yaml
apiVersion: endpointmonitor.stakater.com/v1alpha1
kind: EndpointMonitor
metadata:
name: stakater
spec:
forceHttps: true
url: https://stakater.com/
uptimeKumaConfig:
interval: 120
monitorType: keyword
keywordExists: "no"
keywordValue: "404"
notifications: "1,2"
```
Loading
Loading