Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b70edaace5 | |||
| 9d12e3ecf1 |
+2
-5
@@ -26,8 +26,8 @@ go.work
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/go
|
||||
|
||||
/goupkeep
|
||||
upkeep.db
|
||||
/uptop
|
||||
uptop.db
|
||||
|
||||
.ssh
|
||||
|
||||
@@ -35,8 +35,5 @@ authorized_keys
|
||||
|
||||
tmp
|
||||
|
||||
# Old repo
|
||||
/go-upkeep/
|
||||
|
||||
*.local.json
|
||||
*.local.md
|
||||
+7
-7
@@ -9,7 +9,7 @@ ENV CGO_ENABLED=1
|
||||
ARG VERSION=dev
|
||||
ARG COMMIT=none
|
||||
ARG BUILD_DATE=unknown
|
||||
RUN go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.date=${BUILD_DATE}" -o go-upkeep ./cmd/goupkeep/main.go
|
||||
RUN go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.date=${BUILD_DATE}" -o uptop ./cmd/uptop/main.go
|
||||
|
||||
# --- Stage 2: Runner ---
|
||||
FROM alpine:latest
|
||||
@@ -17,15 +17,15 @@ WORKDIR /app
|
||||
RUN apk add --no-cache ca-certificates openssh-client
|
||||
RUN mkdir /data
|
||||
|
||||
COPY --from=builder /app/go-upkeep .
|
||||
COPY --from=builder /app/uptop .
|
||||
|
||||
# Set Default Configuration via ENV
|
||||
# Docker users can override these in docker-compose.yml
|
||||
ENV LIPGLOSS_RENDERER_HAS_DARK_BACKGROUND=true
|
||||
ENV UPKEEP_DB_TYPE=sqlite
|
||||
ENV UPKEEP_DB_DSN=/data/upkeep.db
|
||||
ENV UPKEEP_KEYS=/data/authorized_keys
|
||||
ENV UPKEEP_PORT=23234
|
||||
ENV UPTOP_DB_TYPE=sqlite
|
||||
ENV UPTOP_DB_DSN=/data/uptop.db
|
||||
ENV UPTOP_KEYS=/data/authorized_keys
|
||||
ENV UPTOP_PORT=23234
|
||||
|
||||
EXPOSE 23234
|
||||
CMD ["./go-upkeep"]
|
||||
CMD ["./uptop"]
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Self-hosted uptime monitor with a TUI you can access over SSH. No browser, no install on the client — just `ssh -p 23234 your-server`.
|
||||
|
||||
Built on the foundation of [RDGames/uptop](https://github.com/RDGames/uptop).
|
||||
Built on the foundation of [RDGames/go-upkeep](https://github.com/RDGames/go-upkeep).
|
||||
|
||||
## What it does
|
||||
|
||||
@@ -33,7 +33,7 @@ go run cmd/uptop/main.go -demo
|
||||
### From source
|
||||
|
||||
```bash
|
||||
go install gitea.lerkolabs.com/lerko/uptime/cmd/uptop@latest
|
||||
go install gitea.lerkolabs.com/lerko/uptop/cmd/uptop@latest
|
||||
```
|
||||
|
||||
### Docker
|
||||
@@ -45,7 +45,7 @@ docker run -p 23234:23234 -p 8080:8080 -v ./data:/data lerko/uptop
|
||||
|
||||
### Binary
|
||||
|
||||
Download from [Releases](https://gitea.lerkolabs.com/lerko/uptime/releases).
|
||||
Download from [Releases](https://gitea.lerkolabs.com/lerko/uptop/releases).
|
||||
|
||||
## Config as code
|
||||
|
||||
@@ -81,10 +81,10 @@ services:
|
||||
- ./data:/data
|
||||
- ./ssh_keys:/app/.ssh
|
||||
environment:
|
||||
- UPKEEP_DB_TYPE=sqlite
|
||||
- UPKEEP_DB_DSN=/data/upkeep.db
|
||||
- UPKEEP_STATUS_ENABLED=true
|
||||
- UPKEEP_CLUSTER_SECRET=change-me
|
||||
- UPTOP_DB_TYPE=sqlite
|
||||
- UPTOP_DB_DSN=/data/uptop.db
|
||||
- UPTOP_STATUS_ENABLED=true
|
||||
- UPTOP_CLUSTER_SECRET=change-me
|
||||
```
|
||||
|
||||
First run: attach to the container (`docker attach uptop`), go to the Users tab, add your SSH public key. Then detach with `Ctrl+P, Ctrl+Q` and connect normally over SSH.
|
||||
@@ -93,16 +93,16 @@ First run: attach to the container (`docker attach uptop`), go to the Users tab,
|
||||
|
||||
| Variable | Default | What it does |
|
||||
|---|---|---|
|
||||
| `UPKEEP_PORT` | `23234` | SSH server port |
|
||||
| `UPKEEP_HTTP_PORT` | `8080` | HTTP server port (status page, push, metrics) |
|
||||
| `UPKEEP_DB_TYPE` | `sqlite` | `sqlite` or `postgres` |
|
||||
| `UPKEEP_DB_DSN` | `upkeep.db` | Database path or connection string |
|
||||
| `UPKEEP_STATUS_ENABLED` | `false` | Enable public status page |
|
||||
| `UPKEEP_STATUS_TITLE` | `System Status` | Status page title |
|
||||
| `UPKEEP_CLUSTER_MODE` | `leader` | `leader` or `follower` |
|
||||
| `UPKEEP_PEER_URL` | | Leader URL for follower nodes |
|
||||
| `UPKEEP_CLUSTER_SECRET` | | Shared key for cluster + API auth |
|
||||
| `UPKEEP_INSECURE_SKIP_VERIFY` | `false` | Skip TLS verification for checks |
|
||||
| `UPTOP_PORT` | `23234` | SSH server port |
|
||||
| `UPTOP_HTTP_PORT` | `8080` | HTTP server port (status page, push, metrics) |
|
||||
| `UPTOP_DB_TYPE` | `sqlite` | `sqlite` or `postgres` |
|
||||
| `UPTOP_DB_DSN` | `uptop.db` | Database path or connection string |
|
||||
| `UPTOP_STATUS_ENABLED` | `false` | Enable public status page |
|
||||
| `UPTOP_STATUS_TITLE` | `System Status` | Status page title |
|
||||
| `UPTOP_CLUSTER_MODE` | `leader` | `leader` or `follower` |
|
||||
| `UPTOP_PEER_URL` | | Leader URL for follower nodes |
|
||||
| `UPTOP_CLUSTER_SECRET` | | Shared key for cluster + API auth |
|
||||
| `UPTOP_INSECURE_SKIP_VERIFY` | `false` | Skip TLS verification for checks |
|
||||
|
||||
## Migrating from Uptime Kuma
|
||||
|
||||
|
||||
+21
-21
@@ -91,8 +91,8 @@ func runApply(args []string) {
|
||||
filePath := fs.String("f", "", "Path to YAML config file (required)")
|
||||
dryRun := fs.Bool("dry-run", false, "Show planned changes without applying")
|
||||
prune := fs.Bool("prune", false, "Delete monitors/alerts not in YAML")
|
||||
dbType := fs.String("db-type", envOrDefault("UPKEEP_DB_TYPE", "sqlite"), "Database type")
|
||||
dsn := fs.String("dsn", envOrDefault("UPKEEP_DB_DSN", "upkeep.db"), "Database DSN")
|
||||
dbType := fs.String("db-type", envOrDefault("UPTOP_DB_TYPE", "sqlite"), "Database type")
|
||||
dsn := fs.String("dsn", envOrDefault("UPTOP_DB_DSN", "uptop.db"), "Database DSN")
|
||||
_ = fs.Parse(args) // ExitOnError: parse errors exit before returning
|
||||
|
||||
if *filePath == "" {
|
||||
@@ -124,8 +124,8 @@ func runApply(args []string) {
|
||||
func runExport(args []string) {
|
||||
fs := flag.NewFlagSet("export", flag.ExitOnError)
|
||||
outPath := fs.String("o", "-", "Output file path (- for stdout)")
|
||||
dbType := fs.String("db-type", envOrDefault("UPKEEP_DB_TYPE", "sqlite"), "Database type")
|
||||
dsn := fs.String("dsn", envOrDefault("UPKEEP_DB_DSN", "upkeep.db"), "Database DSN")
|
||||
dbType := fs.String("db-type", envOrDefault("UPTOP_DB_TYPE", "sqlite"), "Database type")
|
||||
dsn := fs.String("dsn", envOrDefault("UPTOP_DB_DSN", "uptop.db"), "Database DSN")
|
||||
_ = fs.Parse(args) // ExitOnError: parse errors exit before returning
|
||||
|
||||
s := openStore(*dbType, *dsn)
|
||||
@@ -145,7 +145,7 @@ func runExport(args []string) {
|
||||
func runServe(args []string) {
|
||||
portVal := 23234
|
||||
dbType := "sqlite"
|
||||
dbDSN := "upkeep.db"
|
||||
dbDSN := "uptop.db"
|
||||
httpPort := 8080
|
||||
enableStatus := false
|
||||
statusTitle := "System Status"
|
||||
@@ -153,50 +153,50 @@ func runServe(args []string) {
|
||||
clusterPeer := ""
|
||||
clusterKey := ""
|
||||
|
||||
if v := os.Getenv("UPKEEP_PORT"); v != "" {
|
||||
if v := os.Getenv("UPTOP_PORT"); v != "" {
|
||||
if p, err := strconv.Atoi(v); err == nil {
|
||||
portVal = p
|
||||
}
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_DB_TYPE"); v != "" {
|
||||
if v := os.Getenv("UPTOP_DB_TYPE"); v != "" {
|
||||
dbType = v
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_DB_DSN"); v != "" {
|
||||
if v := os.Getenv("UPTOP_DB_DSN"); v != "" {
|
||||
dbDSN = v
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_HTTP_PORT"); v != "" {
|
||||
if v := os.Getenv("UPTOP_HTTP_PORT"); v != "" {
|
||||
if p, err := strconv.Atoi(v); err == nil {
|
||||
httpPort = p
|
||||
}
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_STATUS_ENABLED"); v == "true" {
|
||||
if v := os.Getenv("UPTOP_STATUS_ENABLED"); v == "true" {
|
||||
enableStatus = true
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_STATUS_TITLE"); v != "" {
|
||||
if v := os.Getenv("UPTOP_STATUS_TITLE"); v != "" {
|
||||
statusTitle = v
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_CLUSTER_MODE"); v != "" {
|
||||
if v := os.Getenv("UPTOP_CLUSTER_MODE"); v != "" {
|
||||
clusterMode = v
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_PEER_URL"); v != "" {
|
||||
if v := os.Getenv("UPTOP_PEER_URL"); v != "" {
|
||||
clusterPeer = v
|
||||
}
|
||||
if v := os.Getenv("UPKEEP_CLUSTER_SECRET"); v != "" {
|
||||
if v := os.Getenv("UPTOP_CLUSTER_SECRET"); v != "" {
|
||||
clusterKey = v
|
||||
}
|
||||
|
||||
nodeID := os.Getenv("UPKEEP_NODE_ID")
|
||||
nodeName := os.Getenv("UPKEEP_NODE_NAME")
|
||||
nodeRegion := os.Getenv("UPKEEP_NODE_REGION")
|
||||
aggStrategy := os.Getenv("UPKEEP_AGG_STRATEGY")
|
||||
nodeID := os.Getenv("UPTOP_NODE_ID")
|
||||
nodeName := os.Getenv("UPTOP_NODE_NAME")
|
||||
nodeRegion := os.Getenv("UPTOP_NODE_REGION")
|
||||
aggStrategy := os.Getenv("UPTOP_AGG_STRATEGY")
|
||||
|
||||
if clusterMode == "probe" {
|
||||
if nodeID == "" {
|
||||
fmt.Fprintln(os.Stderr, "UPKEEP_NODE_ID is required for probe mode")
|
||||
fmt.Fprintln(os.Stderr, "UPTOP_NODE_ID is required for probe mode")
|
||||
os.Exit(1)
|
||||
}
|
||||
if clusterPeer == "" {
|
||||
fmt.Fprintln(os.Stderr, "UPKEEP_PEER_URL is required for probe mode")
|
||||
fmt.Fprintln(os.Stderr, "UPTOP_PEER_URL is required for probe mode")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ func runServe(args []string) {
|
||||
}
|
||||
|
||||
eng := monitor.NewEngine(s)
|
||||
if os.Getenv("UPKEEP_INSECURE_SKIP_VERIFY") == "true" {
|
||||
if os.Getenv("UPTOP_INSECURE_SKIP_VERIFY") == "true" {
|
||||
eng.SetInsecureSkipVerify(true)
|
||||
}
|
||||
if aggStrategy != "" {
|
||||
|
||||
+21
-21
@@ -4,21 +4,21 @@ services:
|
||||
# -------------------------
|
||||
leader:
|
||||
build: .
|
||||
container_name: upkeep-leader
|
||||
container_name: uptop-leader
|
||||
ports:
|
||||
- "23234:23234" # SSH
|
||||
- "8080:8080" # HTTP
|
||||
environment:
|
||||
- UPKEEP_DB_TYPE=postgres
|
||||
- UPTOP_DB_TYPE=postgres
|
||||
# Note: Port 5432 is correct here because we are talking INSIDE the network
|
||||
- UPKEEP_DB_DSN=postgres://devuser:devpass@leader-db:5432/upkeep_dev?sslmode=disable
|
||||
- UPKEEP_HTTP_PORT=8080
|
||||
- UPKEEP_STATUS_ENABLED=true
|
||||
- UPKEEP_STATUS_TITLE=Leader Node
|
||||
- UPTOP_DB_DSN=postgres://devuser:devpass@leader-db:5432/uptop_dev?sslmode=disable
|
||||
- UPTOP_HTTP_PORT=8080
|
||||
- UPTOP_STATUS_ENABLED=true
|
||||
- UPTOP_STATUS_TITLE=Leader Node
|
||||
|
||||
# Cluster Config
|
||||
- UPKEEP_CLUSTER_MODE=leader
|
||||
- UPKEEP_CLUSTER_SECRET=mysecret
|
||||
- UPTOP_CLUSTER_MODE=leader
|
||||
- UPTOP_CLUSTER_SECRET=mysecret
|
||||
depends_on:
|
||||
- leader-db
|
||||
stdin_open: true
|
||||
@@ -26,11 +26,11 @@ services:
|
||||
|
||||
leader-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: upkeep-leader-db
|
||||
container_name: uptop-leader-db
|
||||
environment:
|
||||
POSTGRES_USER: devuser
|
||||
POSTGRES_PASSWORD: devpass
|
||||
POSTGRES_DB: upkeep_dev
|
||||
POSTGRES_DB: uptop_dev
|
||||
volumes:
|
||||
- ./tmp/leader-data:/var/lib/postgresql/data
|
||||
|
||||
@@ -39,23 +39,23 @@ services:
|
||||
# -------------------------
|
||||
follower:
|
||||
build: .
|
||||
container_name: upkeep-follower
|
||||
container_name: uptop-follower
|
||||
ports:
|
||||
- "23233:23234" # SSH (Mapped to different host port)
|
||||
- "8081:8080" # HTTP (Mapped to different host port)
|
||||
environment:
|
||||
- UPKEEP_DB_TYPE=postgres
|
||||
- UPTOP_DB_TYPE=postgres
|
||||
# Connects to its OWN database
|
||||
- UPKEEP_DB_DSN=postgres://devuser:devpass@follower-db:5432/upkeep_dev?sslmode=disable
|
||||
- UPKEEP_HTTP_PORT=8080
|
||||
- UPKEEP_STATUS_ENABLED=true
|
||||
- UPKEEP_STATUS_TITLE=Follower Node
|
||||
- UPTOP_DB_DSN=postgres://devuser:devpass@follower-db:5432/uptop_dev?sslmode=disable
|
||||
- UPTOP_HTTP_PORT=8080
|
||||
- UPTOP_STATUS_ENABLED=true
|
||||
- UPTOP_STATUS_TITLE=Follower Node
|
||||
|
||||
# Cluster Config
|
||||
- UPKEEP_CLUSTER_MODE=follower
|
||||
- UPKEEP_CLUSTER_SECRET=mysecret
|
||||
- UPTOP_CLUSTER_MODE=follower
|
||||
- UPTOP_CLUSTER_SECRET=mysecret
|
||||
# IMPORTANT: Uses the Service Name "leader" to connect internally
|
||||
- UPKEEP_PEER_URL=http://leader:8080
|
||||
- UPTOP_PEER_URL=http://leader:8080
|
||||
depends_on:
|
||||
- follower-db
|
||||
stdin_open: true
|
||||
@@ -63,10 +63,10 @@ services:
|
||||
|
||||
follower-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: upkeep-follower-db
|
||||
container_name: uptop-follower-db
|
||||
environment:
|
||||
POSTGRES_USER: devuser
|
||||
POSTGRES_PASSWORD: devpass
|
||||
POSTGRES_DB: upkeep_dev
|
||||
POSTGRES_DB: uptop_dev
|
||||
volumes:
|
||||
- ./tmp/follower-data:/var/lib/postgresql/data
|
||||
@@ -4,19 +4,19 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: upkeep-dev
|
||||
container_name: uptop-dev
|
||||
ports:
|
||||
- "23234:23234" # SSH Access
|
||||
- "8080:8080" # HTTP (Push Monitors + Status Page)
|
||||
environment:
|
||||
# --- Database Configuration (Postgres) ---
|
||||
- UPKEEP_DB_TYPE=postgres
|
||||
- UPKEEP_DB_DSN=postgres://devuser:devpass@postgres:5432/upkeep_dev?sslmode=disable
|
||||
- UPTOP_DB_TYPE=postgres
|
||||
- UPTOP_DB_DSN=postgres://devuser:devpass@postgres:5432/uptop_dev?sslmode=disable
|
||||
|
||||
# --- Web Server Configuration (Phase 4) ---
|
||||
- UPKEEP_HTTP_PORT=8080
|
||||
- UPKEEP_STATUS_ENABLED=true
|
||||
- UPKEEP_STATUS_TITLE=Dev Infrastructure Status
|
||||
- UPTOP_HTTP_PORT=8080
|
||||
- UPTOP_STATUS_ENABLED=true
|
||||
- UPTOP_STATUS_TITLE=Dev Infrastructure Status
|
||||
depends_on:
|
||||
- postgres
|
||||
stdin_open: true # Required for 'docker attach' (Local Admin Console)
|
||||
@@ -25,11 +25,11 @@ services:
|
||||
# The Database
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: upkeep-postgres
|
||||
container_name: uptop-postgres
|
||||
environment:
|
||||
POSTGRES_USER: devuser
|
||||
POSTGRES_PASSWORD: devpass
|
||||
POSTGRES_DB: upkeep_dev
|
||||
POSTGRES_DB: uptop_dev
|
||||
ports:
|
||||
- "5432:5432" # Expose for external DB tools (DBeaver, etc.)
|
||||
volumes:
|
||||
|
||||
+16
-16
@@ -2,10 +2,10 @@ services:
|
||||
leader:
|
||||
build: .
|
||||
environment:
|
||||
- UPKEEP_CLUSTER_MODE=leader
|
||||
- UPKEEP_CLUSTER_SECRET=changeme
|
||||
- UPKEEP_AGG_STRATEGY=any-down
|
||||
- UPKEEP_STATUS_ENABLED=true
|
||||
- UPTOP_CLUSTER_MODE=leader
|
||||
- UPTOP_CLUSTER_SECRET=changeme
|
||||
- UPTOP_AGG_STRATEGY=any-down
|
||||
- UPTOP_STATUS_ENABLED=true
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "23234:23234"
|
||||
@@ -13,23 +13,23 @@ services:
|
||||
probe-us-east:
|
||||
build: .
|
||||
environment:
|
||||
- UPKEEP_CLUSTER_MODE=probe
|
||||
- UPKEEP_NODE_ID=us-east-1
|
||||
- UPKEEP_NODE_NAME=US East Probe
|
||||
- UPKEEP_NODE_REGION=us-east
|
||||
- UPKEEP_PEER_URL=http://leader:8080
|
||||
- UPKEEP_CLUSTER_SECRET=changeme
|
||||
- UPTOP_CLUSTER_MODE=probe
|
||||
- UPTOP_NODE_ID=us-east-1
|
||||
- UPTOP_NODE_NAME=US East Probe
|
||||
- UPTOP_NODE_REGION=us-east
|
||||
- UPTOP_PEER_URL=http://leader:8080
|
||||
- UPTOP_CLUSTER_SECRET=changeme
|
||||
depends_on:
|
||||
- leader
|
||||
|
||||
probe-eu-west:
|
||||
build: .
|
||||
environment:
|
||||
- UPKEEP_CLUSTER_MODE=probe
|
||||
- UPKEEP_NODE_ID=eu-west-1
|
||||
- UPKEEP_NODE_NAME=EU West Probe
|
||||
- UPKEEP_NODE_REGION=eu-west
|
||||
- UPKEEP_PEER_URL=http://leader:8080
|
||||
- UPKEEP_CLUSTER_SECRET=changeme
|
||||
- UPTOP_CLUSTER_MODE=probe
|
||||
- UPTOP_NODE_ID=eu-west-1
|
||||
- UPTOP_NODE_NAME=EU West Probe
|
||||
- UPTOP_NODE_REGION=eu-west
|
||||
- UPTOP_PEER_URL=http://leader:8080
|
||||
- UPTOP_CLUSTER_SECRET=changeme
|
||||
depends_on:
|
||||
- leader
|
||||
|
||||
+6
-6
@@ -3,16 +3,16 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: upkeep
|
||||
container_name: uptop
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "23234:23234"
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- UPKEEP_DB_TYPE=sqlite
|
||||
- UPKEEP_DB_DSN=/data/upkeep.db
|
||||
- UPKEEP_HTTP_PORT=8080
|
||||
- UPKEEP_STATUS_ENABLED=true
|
||||
- UPKEEP_STATUS_TITLE=System Status
|
||||
- UPTOP_DB_TYPE=sqlite
|
||||
- UPTOP_DB_DSN=/data/uptop.db
|
||||
- UPTOP_HTTP_PORT=8080
|
||||
- UPTOP_STATUS_ENABLED=true
|
||||
- UPTOP_STATUS_TITLE=System Status
|
||||
volumes:
|
||||
- ./data:/data
|
||||
|
||||
@@ -207,11 +207,11 @@ Without `--prune`, apply never deletes anything. It only creates and updates.
|
||||
|
||||
**Pointing at a different database:**
|
||||
```bash
|
||||
uptop export -db-type postgres -dsn "host=localhost dbname=upkeep sslmode=disable"
|
||||
uptop export -db-type postgres -dsn "host=localhost dbname=uptop sslmode=disable"
|
||||
uptop apply -f monitors.yaml -db-type postgres -dsn "..."
|
||||
```
|
||||
|
||||
Both commands respect the `UPKEEP_DB_TYPE` and `UPKEEP_DB_DSN` environment variables too.
|
||||
Both commands respect the `UPTOP_DB_TYPE` and `UPTOP_DB_DSN` environment variables too.
|
||||
|
||||
## How apply works
|
||||
|
||||
|
||||
@@ -16,74 +16,74 @@ func Handler(eng *monitor.Engine) http.HandlerFunc {
|
||||
|
||||
var b strings.Builder
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_up", "gauge", "Whether the monitor is up (1) or down (0).")
|
||||
writeHelp(&b, "uptop_monitor_up", "gauge", "Whether the monitor is up (1) or down (0).")
|
||||
for _, s := range sites {
|
||||
val := 0
|
||||
if s.Status == "UP" {
|
||||
val = 1
|
||||
}
|
||||
writeGauge(&b, "upkeep_monitor_up", labels(s), float64(val))
|
||||
writeGauge(&b, "uptop_monitor_up", labels(s), float64(val))
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_latency_seconds", "gauge", "Last check latency in seconds.")
|
||||
writeHelp(&b, "uptop_monitor_latency_seconds", "gauge", "Last check latency in seconds.")
|
||||
for _, s := range sites {
|
||||
writeGauge(&b, "upkeep_monitor_latency_seconds", labels(s), s.Latency.Seconds())
|
||||
writeGauge(&b, "uptop_monitor_latency_seconds", labels(s), s.Latency.Seconds())
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_status_code", "gauge", "HTTP response status code of the last check.")
|
||||
writeHelp(&b, "uptop_monitor_status_code", "gauge", "HTTP response status code of the last check.")
|
||||
for _, s := range sites {
|
||||
if s.Type != "http" {
|
||||
continue
|
||||
}
|
||||
writeGauge(&b, "upkeep_monitor_status_code", labels(s), float64(s.StatusCode))
|
||||
writeGauge(&b, "uptop_monitor_status_code", labels(s), float64(s.StatusCode))
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_check_timestamp_seconds", "gauge", "Unix timestamp of the last check.")
|
||||
writeHelp(&b, "uptop_monitor_check_timestamp_seconds", "gauge", "Unix timestamp of the last check.")
|
||||
for _, s := range sites {
|
||||
if s.LastCheck.IsZero() {
|
||||
continue
|
||||
}
|
||||
writeGauge(&b, "upkeep_monitor_check_timestamp_seconds", labels(s), float64(s.LastCheck.Unix()))
|
||||
writeGauge(&b, "uptop_monitor_check_timestamp_seconds", labels(s), float64(s.LastCheck.Unix()))
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_paused", "gauge", "Whether the monitor is paused (1) or active (0).")
|
||||
writeHelp(&b, "uptop_monitor_paused", "gauge", "Whether the monitor is paused (1) or active (0).")
|
||||
for _, s := range sites {
|
||||
val := 0
|
||||
if s.Paused {
|
||||
val = 1
|
||||
}
|
||||
writeGauge(&b, "upkeep_monitor_paused", labels(s), float64(val))
|
||||
writeGauge(&b, "uptop_monitor_paused", labels(s), float64(val))
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_maintenance", "gauge", "Whether the monitor is in a maintenance window (1) or not (0).")
|
||||
writeHelp(&b, "uptop_monitor_maintenance", "gauge", "Whether the monitor is in a maintenance window (1) or not (0).")
|
||||
for _, s := range sites {
|
||||
val := 0
|
||||
if eng.GetDisplayStatus(s) == "MAINT" {
|
||||
val = 1
|
||||
}
|
||||
writeGauge(&b, "upkeep_monitor_maintenance", labels(s), float64(val))
|
||||
writeGauge(&b, "uptop_monitor_maintenance", labels(s), float64(val))
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_cert_expiry_timestamp_seconds", "gauge", "Unix timestamp when the SSL certificate expires.")
|
||||
writeHelp(&b, "uptop_monitor_cert_expiry_timestamp_seconds", "gauge", "Unix timestamp when the SSL certificate expires.")
|
||||
for _, s := range sites {
|
||||
if !s.HasSSL || s.CertExpiry.IsZero() {
|
||||
continue
|
||||
}
|
||||
writeGauge(&b, "upkeep_monitor_cert_expiry_timestamp_seconds", labels(s), float64(s.CertExpiry.Unix()))
|
||||
writeGauge(&b, "uptop_monitor_cert_expiry_timestamp_seconds", labels(s), float64(s.CertExpiry.Unix()))
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_monitor_checks_total", "counter", "Total number of checks performed.")
|
||||
writeHelp(&b, "upkeep_monitor_checks_up_total", "counter", "Total number of successful checks.")
|
||||
writeHelp(&b, "uptop_monitor_checks_total", "counter", "Total number of checks performed.")
|
||||
writeHelp(&b, "uptop_monitor_checks_up_total", "counter", "Total number of successful checks.")
|
||||
for _, s := range sites {
|
||||
h, ok := eng.GetHistory(s.ID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
writeGauge(&b, "upkeep_monitor_checks_total", labels(s), float64(h.TotalChecks))
|
||||
writeGauge(&b, "upkeep_monitor_checks_up_total", labels(s), float64(h.UpChecks))
|
||||
writeGauge(&b, "uptop_monitor_checks_total", labels(s), float64(h.TotalChecks))
|
||||
writeGauge(&b, "uptop_monitor_checks_up_total", labels(s), float64(h.UpChecks))
|
||||
}
|
||||
|
||||
writeHelp(&b, "upkeep_probe_up", "gauge", "Whether a probe node is online (1) or offline (0) based on last-seen time.")
|
||||
writeHelp(&b, "uptop_probe_up", "gauge", "Whether a probe node is online (1) or offline (0) based on last-seen time.")
|
||||
for _, site := range sites {
|
||||
probeResults := eng.GetProbeResults(site.ID)
|
||||
for nodeID, result := range probeResults {
|
||||
@@ -92,7 +92,7 @@ func Handler(eng *monitor.Engine) http.HandlerFunc {
|
||||
val = 1
|
||||
}
|
||||
nodeLabels := fmt.Sprintf(`id="%d",name="%s",node="%s"`, site.ID, escapeLabelValue(site.Name), escapeLabelValue(nodeID))
|
||||
writeGauge(&b, "upkeep_probe_up", nodeLabels, float64(val))
|
||||
writeGauge(&b, "uptop_probe_up", nodeLabels, float64(val))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,13 +94,13 @@ func TestMetricsHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"# HELP upkeep_monitor_up",
|
||||
"# TYPE upkeep_monitor_up gauge",
|
||||
`upkeep_monitor_up{id="1",name="Example",type="http"}`,
|
||||
`upkeep_monitor_up{id="2",name="DNS Check",type="dns"}`,
|
||||
"# HELP upkeep_monitor_latency_seconds",
|
||||
"# HELP upkeep_monitor_paused",
|
||||
"# HELP upkeep_monitor_checks_total",
|
||||
"# HELP uptop_monitor_up",
|
||||
"# TYPE uptop_monitor_up gauge",
|
||||
`uptop_monitor_up{id="1",name="Example",type="http"}`,
|
||||
`uptop_monitor_up{id="2",name="DNS Check",type="dns"}`,
|
||||
"# HELP uptop_monitor_latency_seconds",
|
||||
"# HELP uptop_monitor_paused",
|
||||
"# HELP uptop_monitor_checks_total",
|
||||
}
|
||||
for _, s := range expected {
|
||||
if !strings.Contains(body, s) {
|
||||
|
||||
@@ -161,7 +161,7 @@ type ServerConfig struct {
|
||||
|
||||
func Start(cfg ServerConfig, s store.Store, eng *monitor.Engine) *http.Server {
|
||||
if cfg.ClusterKey == "" {
|
||||
fmt.Println("WARNING: No UPKEEP_CLUSTER_SECRET set. Cluster API endpoints are unauthenticated.")
|
||||
fmt.Println("WARNING: No UPTOP_CLUSTER_SECRET set. Cluster API endpoints are unauthenticated.")
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
|
||||
@@ -193,7 +193,7 @@ func Start(cfg ServerConfig, s store.Store, eng *monitor.Engine) *http.Server {
|
||||
// 3. Config Export
|
||||
mux.HandleFunc("/api/backup/export", func(w http.ResponseWriter, r *http.Request) {
|
||||
if cfg.ClusterKey == "" || !checkSecret(r.Header.Get("X-Upkeep-Secret"), cfg.ClusterKey) {
|
||||
http.Error(w, "Unauthorized: UPKEEP_CLUSTER_SECRET required", http.StatusUnauthorized)
|
||||
http.Error(w, "Unauthorized: UPTOP_CLUSTER_SECRET required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
data, err := s.ExportData()
|
||||
|
||||
@@ -2,12 +2,13 @@ package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/huh"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
|
||||
Reference in New Issue
Block a user