notif(elasticsearch): switch to address field and validate

This commit is contained in:
CrazyMax
2025-08-10 00:56:03 +02:00
parent f245869582
commit d6f79800e2
6 changed files with 27 additions and 38 deletions

View File

@@ -8,9 +8,7 @@ Send notifications to your Elasticsearch cluster as structured documents.
```yaml ```yaml
notif: notif:
elasticsearch: elasticsearch:
scheme: https address: http://localhost:9200
host: localhost
port: 9200
username: elastic username: elastic
password: password password: password
client: diun client: diun
@@ -19,24 +17,20 @@ Send notifications to your Elasticsearch cluster as structured documents.
insecureSkipVerify: false insecureSkipVerify: false
``` ```
| Name | Default | Description | | Name | Default | Description |
| -------------------- | -------------------- | ------------------------------------------------------------------- | |----------------------|-------------------------|---------------------------------------------------------------------|
| `scheme`[^1] | `http` | Elasticsearch scheme (`http` or `https`) | | `address`[^1] | `http://localhost:9200` | Elasticsearch base URL |
| `host`[^1] | `localhost` | Elasticsearch host | | `username` | | Elasticsearch username for authentication |
| `port`[^1] | `9200` | Elasticsearch port | | `usernameFile` | | Use content of secret file as username if `username` is not defined |
| `username` | | Elasticsearch username for authentication | | `password` | | Elasticsearch password for authentication |
| `usernameFile` | | Use content of secret file as username if `username` is not defined | | `passwordFile` | | Use content of secret file as password if `password` is not defined |
| `password` | | Elasticsearch password for authentication | | `client`[^1] | `diun` | Client name to identify the source of notifications |
| `passwordFile` | | Use content of secret file as password if `password` is not defined | | `index`[^1] | `diun-notifications` | Elasticsearch index name where notifications will be stored |
| `client`[^1] | `diun` | Client name to identify the source of notifications | | `timeout`[^1] | `10s` | Timeout specifies a time limit for the request to be made |
| `index`[^1] | `diun-notifications` | Elasticsearch index name where notifications will be stored | | `insecureSkipVerify` | `false` | Skip TLS certificate verification |
| `timeout`[^1] | `10s` | Timeout specifies a time limit for the request to be made |
| `insecureSkipVerify` | `false` | Skip TLS certificate verification |
!!! abstract "Environment variables" !!! abstract "Environment variables"
* `DIUN_NOTIF_ELASTICSEARCH_SCHEME` * `DIUN_NOTIF_ELASTICSEARCH_ADDRESS`
* `DIUN_NOTIF_ELASTICSEARCH_HOST`
* `DIUN_NOTIF_ELASTICSEARCH_PORT`
* `DIUN_NOTIF_ELASTICSEARCH_USERNAME` * `DIUN_NOTIF_ELASTICSEARCH_USERNAME`
* `DIUN_NOTIF_ELASTICSEARCH_USERNAMEFILE` * `DIUN_NOTIF_ELASTICSEARCH_USERNAMEFILE`
* `DIUN_NOTIF_ELASTICSEARCH_PASSWORD` * `DIUN_NOTIF_ELASTICSEARCH_PASSWORD`
@@ -48,7 +42,7 @@ Send notifications to your Elasticsearch cluster as structured documents.
## Document Structure ## Document Structure
Each notification is stored as a JSON document with following structure: Each notification is stored as a JSON document with the following structure:
```json ```json
{ {

View File

@@ -95,9 +95,7 @@ func TestLoadFile(t *testing.T) {
TemplateBody: model.NotifDefaultTemplateBody, TemplateBody: model.NotifDefaultTemplateBody,
}, },
Elasticsearch: &model.NotifElasticsearch{ Elasticsearch: &model.NotifElasticsearch{
Scheme: "https", Address: "https://elastic.foo.com",
Host: "localhost",
Port: 9200,
Username: "elastic", Username: "elastic",
Password: "password", Password: "password",
Client: "diun", Client: "diun",

View File

@@ -40,9 +40,7 @@ notif:
renderFields: true renderFields: true
timeout: 10s timeout: 10s
elasticsearch: elasticsearch:
scheme: https address: https://elastic.foo.com
host: localhost
port: 9200
username: elastic username: elastic
password: password password: password
client: diun client: diun

View File

@@ -29,9 +29,7 @@ notif:
renderFields: true renderFields: true
timeout: 10s timeout: 10s
elasticsearch: elasticsearch:
scheme: https address: https://elastic.foo.com
host: localhost
port: 9200
username: elastic username: elastic
password: password password: password
client: diun client: diun

View File

@@ -7,9 +7,7 @@ import (
) )
type NotifElasticsearch struct { type NotifElasticsearch struct {
Scheme string `yaml:"scheme,omitempty" json:"scheme,omitempty" validate:"required,oneof=http https"` Address string `yaml:"address,omitempty" json:"address,omitempty" validate:"required"`
Host string `yaml:"host,omitempty" json:"host,omitempty" validate:"required"`
Port int `yaml:"port,omitempty" json:"port,omitempty" validate:"required,min=1"`
Username string `yaml:"username,omitempty" json:"username,omitempty" validate:"omitempty"` Username string `yaml:"username,omitempty" json:"username,omitempty" validate:"omitempty"`
UsernameFile string `yaml:"usernameFile,omitempty" json:"usernameFile,omitempty" validate:"omitempty,file"` UsernameFile string `yaml:"usernameFile,omitempty" json:"usernameFile,omitempty" validate:"omitempty,file"`
Password string `yaml:"password,omitempty" json:"password,omitempty" validate:"omitempty"` Password string `yaml:"password,omitempty" json:"password,omitempty" validate:"omitempty"`
@@ -29,9 +27,7 @@ func (s *NotifElasticsearch) GetDefaults() *NotifElasticsearch {
// SetDefaults sets the default values // SetDefaults sets the default values
func (s *NotifElasticsearch) SetDefaults() { func (s *NotifElasticsearch) SetDefaults() {
s.Scheme = "http" s.Address = "http://localhost:9200"
s.Host = "localhost"
s.Port = 9200
s.Client = "diun" s.Client = "diun"
s.Index = "diun-notifications" s.Index = "diun-notifications"
s.Timeout = utl.NewDuration(10 * time.Second) s.Timeout = utl.NewDuration(10 * time.Second)

View File

@@ -5,8 +5,9 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"net/url"
"path"
"time" "time"
"github.com/crazy-max/diun/v4/internal/model" "github.com/crazy-max/diun/v4/internal/model"
@@ -85,7 +86,11 @@ func (c *Client) Send(entry model.NotifEntry) error {
// Build the Elasticsearch indexing URL // Build the Elasticsearch indexing URL
// This uses the Index API (POST /{index}/_doc) to create a document with an auto-generated _id: // This uses the Index API (POST /{index}/_doc) to create a document with an auto-generated _id:
// https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-create // https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-create
url := fmt.Sprintf("%s://%s:%d/%s/_doc", c.cfg.Scheme, c.cfg.Host, c.cfg.Port, c.cfg.Index) u, err := url.Parse(c.cfg.Address)
if err != nil {
return err
}
u.Path = path.Join(u.Path, c.cfg.Index, "_doc")
cancelCtx, cancel := context.WithCancelCause(context.Background()) cancelCtx, cancel := context.WithCancelCause(context.Background())
timeoutCtx, _ := context.WithTimeoutCause(cancelCtx, *c.cfg.Timeout, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent timeoutCtx, _ := context.WithTimeoutCause(cancelCtx, *c.cfg.Timeout, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent
@@ -99,7 +104,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
}, },
} }
req, err := http.NewRequestWithContext(timeoutCtx, "POST", url, bytes.NewBuffer(body)) req, err := http.NewRequestWithContext(timeoutCtx, "POST", u.String(), bytes.NewBuffer(body))
if err != nil { if err != nil {
return err return err
} }