adding test containers
Some checks failed
Check scripts syntax / check-scripts-syntax (push) Successful in 3s
Test automated-nfs-backup / test-automated-nfs-backup (push) Successful in 4s
Haven Notify Build and Deploy / Build Haven Notify Image (pull_request) Has been cancelled
Haven Notify Build and Deploy / Build Haven Notify Image (PR) (pull_request) Has been cancelled
Haven Notify Build and Deploy / Deploy Haven Notify (internal) (pull_request) Has been cancelled
Haven Notify Build and Deploy / Test Haven Notify (pull_request) Has been cancelled
Some checks failed
Check scripts syntax / check-scripts-syntax (push) Successful in 3s
Test automated-nfs-backup / test-automated-nfs-backup (push) Successful in 4s
Haven Notify Build and Deploy / Build Haven Notify Image (pull_request) Has been cancelled
Haven Notify Build and Deploy / Build Haven Notify Image (PR) (pull_request) Has been cancelled
Haven Notify Build and Deploy / Deploy Haven Notify (internal) (pull_request) Has been cancelled
Haven Notify Build and Deploy / Test Haven Notify (pull_request) Has been cancelled
This commit is contained in:
@@ -3,21 +3,28 @@
|
||||
</div>
|
||||
|
||||
## Overview
|
||||
Haven Notify is an internal service designed to send notifications to a specified Discord channel.
|
||||
|
||||
It's built in Go and can be deployed as a container or managed service.
|
||||
Haven Notify is an internal Go service that validates notification requests, renders Discord-compatible payloads, and delivers them to a configured Discord webhook.
|
||||
|
||||
It runs as a standalone binary or container. Templates are embedded in the binary and validated at startup.
|
||||
|
||||
## Prerequisites
|
||||
- Go 1.18 or newer
|
||||
- Docker
|
||||
- A Discord Webhook URL
|
||||
|
||||
## API Specification
|
||||
- Go 1.25.10
|
||||
- A Docker API compatible with Testcontainers for the end-to-end suite
|
||||
- A Discord webhook URL for normal service operation
|
||||
|
||||
`WEBHOOK_URL` is required and must be an absolute HTTP or HTTPS URL. The process exits before becoming ready when the configuration or embedded templates are invalid.
|
||||
|
||||
## API
|
||||
|
||||
All notification endpoints require `POST` and `Content-Type: application/json`. Request bodies are limited to 64 KiB, documented fields are required, and unknown fields are accepted for forward compatibility.
|
||||
|
||||
### Send Notification
|
||||
|
||||
- **Endpoint**: `/notify`
|
||||
- **Method**: `POST`
|
||||
- **Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Notification Title",
|
||||
@@ -26,71 +33,128 @@ It's built in Go and can be deployed as a container or managed service.
|
||||
```
|
||||
|
||||
### Send Backup Notification
|
||||
|
||||
- **Endpoint**: `/template/notify/backup`
|
||||
- **Method**: `POST`
|
||||
- **Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Notification Title",
|
||||
"asset": "Notification Asset Name",
|
||||
"backupSizeInMB": 500,
|
||||
"title": "Nightly backup",
|
||||
"asset": "Photos",
|
||||
"backupSizeInMB": 1536,
|
||||
"extra": [
|
||||
{
|
||||
"name": "Additional Info",
|
||||
"value": "Some extra information"
|
||||
"name": "Host",
|
||||
"value": "nebula"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Send Update Notification
|
||||
|
||||
- **Endpoint**: `/template/notify/update`
|
||||
- **Method**: `POST`
|
||||
- **Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"host": "Notification Title",
|
||||
"asset": "Notification Message",
|
||||
"time": 500 // in seconds
|
||||
"host": "nexus",
|
||||
"asset": "k3s",
|
||||
"time": 42
|
||||
}
|
||||
```
|
||||
|
||||
`time` is expressed in seconds.
|
||||
|
||||
### Send Error Notification
|
||||
|
||||
- **Endpoint**: `/template/notify/error`
|
||||
- **Method**: `POST`
|
||||
- **Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"caller": "Who triggered the error",
|
||||
"caller": "backup-job",
|
||||
"message": "Error while moving file",
|
||||
"critical": true,
|
||||
"extra": [
|
||||
{
|
||||
"name": "Additional Info",
|
||||
"value": "Some extra information"
|
||||
"name": "Path",
|
||||
"value": "/mnt/backups"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Setup & Usage
|
||||
### Health Probes
|
||||
|
||||
- `GET` or `HEAD /ready` returns `200 Ready` after configuration and templates initialize.
|
||||
- `GET` or `HEAD /live` returns `200 Alive` while the process can serve HTTP.
|
||||
|
||||
### Response Statuses
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| `200` | Notification delivered |
|
||||
| `400` | Invalid or missing request data |
|
||||
| `404` | Unknown route or template |
|
||||
| `405` | Unsupported method |
|
||||
| `415` | Content type is not JSON |
|
||||
| `502` | Discord rejected the request or delivery retries failed |
|
||||
| `504` | Discord delivery exceeded its timeout |
|
||||
|
||||
Haven Notify suppresses Discord mention parsing and safely truncates content to Discord's message and embed limits. Transport errors, rate limits, and server errors receive at most two retries within a ten-second total delivery budget.
|
||||
|
||||
## Run
|
||||
|
||||
### Go
|
||||
|
||||
```sh
|
||||
WEBHOOK_URL=https://discord.com/api/webhooks/... go run .
|
||||
```
|
||||
|
||||
### Docker
|
||||
1. Build the Docker image:
|
||||
```sh
|
||||
docker build -t haven-notify .
|
||||
```
|
||||
2. Run the container:
|
||||
```sh
|
||||
docker run -e WEBHOOK_URL=your_webhook_url haven-notify
|
||||
```
|
||||
|
||||
### Kubernetes
|
||||
The Deployment/Service/Ingress manifest lives in the **`haven`** homelab repo at `infra/haven-notify.yaml` (this repo only holds the Go source + Dockerfile + CI).
|
||||
1. Edit the manifest to set your environment variables.
|
||||
2. Create a generic secret named `discord-webhook` with `HAVEN_WEBHOOK_URL=your_webhook_url`:
|
||||
- `kubectl create secret generic discord-webhook --from-literal=HAVEN_WEBHOOK_URL=<your_webhook_url> -n <namespace>`
|
||||
3. Apply deployment (from the `haven` repo):
|
||||
```sh
|
||||
kubectl apply -f infra/haven-notify.yaml
|
||||
```
|
||||
```sh
|
||||
docker build -t haven-notify .
|
||||
docker run --rm -p 8080:8080 \
|
||||
-e WEBHOOK_URL=https://discord.com/api/webhooks/... \
|
||||
haven-notify
|
||||
```
|
||||
|
||||
The runtime container uses a non-root `haven-notify` user and contains only the binary, Alpine runtime files, and CA certificates.
|
||||
|
||||
## Tests
|
||||
|
||||
Run unit and HTTP contract tests:
|
||||
|
||||
```sh
|
||||
go test ./...
|
||||
```
|
||||
|
||||
Run static analysis, the race detector, and coverage (the race detector requires CGO support):
|
||||
|
||||
```sh
|
||||
go vet ./...
|
||||
go test -race -shuffle=on -count=1 -covermode=atomic -coverprofile=coverage.out ./...
|
||||
go tool cover -func=coverage.out
|
||||
```
|
||||
|
||||
Run the seeded fuzz target:
|
||||
|
||||
```sh
|
||||
go test -run=^$ -fuzz=FuzzErrorNotificationHandler -fuzztime=10s .
|
||||
```
|
||||
|
||||
Run the black-box container suite:
|
||||
|
||||
```sh
|
||||
go test -tags=e2e -run '^TestContainerE2E$' -count=1 -timeout=5m -v .
|
||||
```
|
||||
|
||||
The end-to-end suite builds the production Dockerfile, starts Haven Notify and a disposable MockServer on an isolated network, and verifies the complete HTTP-to-Discord payload flow. It never calls a real Discord webhook. Configure `DOCKER_HOST` or the Testcontainers host settings when the Docker daemon is not available through the platform's default socket.
|
||||
|
||||
## Deployment
|
||||
|
||||
The Kubernetes Deployment, Service, and Ingress manifest lives in the `haven` homelab repository at `infra/haven-notify.yaml`. This repository holds the service source, Dockerfile, tests, and Gitea Actions pipeline.
|
||||
|
||||
The production manifest maps the `HAVEN_WEBHOOK_URL` key from the `discord-webhook` secret into the container's `WEBHOOK_URL` environment variable.
|
||||
|
||||
Reference in New Issue
Block a user