110 lines
3.0 KiB
Go
110 lines
3.0 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// ListTargetGroups returns all configured target groups, ordered by name.
|
|
func (d *DB) ListTargetGroups(ctx context.Context) ([]TargetGroup, error) {
|
|
rows, err := d.QueryContext(ctx, `
|
|
SELECT group_name, targets, created_at, updated_at FROM target_groups ORDER BY group_name
|
|
`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var out []TargetGroup
|
|
for rows.Next() {
|
|
g, err := scanTargetGroup(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, *g)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
// GetTargetGroup returns a single target group by name.
|
|
func (d *DB) GetTargetGroup(ctx context.Context, name string) (*TargetGroup, error) {
|
|
row := d.QueryRowContext(ctx, `
|
|
SELECT group_name, targets, created_at, updated_at FROM target_groups WHERE group_name=?
|
|
`, name)
|
|
g, err := scanTargetGroup(row)
|
|
if err == sql.ErrNoRows {
|
|
return nil, fmt.Errorf("target group %q: %w", name, ErrNotFound)
|
|
}
|
|
return g, err
|
|
}
|
|
|
|
// UpsertTargetGroup creates or replaces a target group's target list.
|
|
func (d *DB) UpsertTargetGroup(ctx context.Context, name string, targets []string) error {
|
|
if name == "" {
|
|
return fmt.Errorf("group name must not be empty: %w", ErrValidation)
|
|
}
|
|
if len(targets) == 0 {
|
|
return fmt.Errorf("target group %q must have at least one target: %w", name, ErrValidation)
|
|
}
|
|
payload, err := json.Marshal(targets)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
now := timeToDB(Now())
|
|
_, err = d.ExecContext(ctx, `
|
|
INSERT INTO target_groups (group_name, targets, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?)
|
|
ON CONFLICT(group_name) DO UPDATE SET targets=excluded.targets, updated_at=excluded.updated_at
|
|
`, name, string(payload), now, now)
|
|
if err != nil {
|
|
return fmt.Errorf("upsert target group: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteTargetGroup removes a target group, refusing if any check type
|
|
// still references it.
|
|
func (d *DB) DeleteTargetGroup(ctx context.Context, name string) error {
|
|
checkTypes, err := d.ListCheckTypes(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, ct := range checkTypes {
|
|
for _, g := range ct.TargetGroups {
|
|
if g == name {
|
|
return fmt.Errorf("target group %q is used by check type %q: %w", name, ct.Name, ErrInUse)
|
|
}
|
|
}
|
|
}
|
|
|
|
res, err := d.ExecContext(ctx, `DELETE FROM target_groups WHERE group_name=?`, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n, _ := res.RowsAffected(); n == 0 {
|
|
return fmt.Errorf("target group %q: %w", name, ErrNotFound)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func scanTargetGroup(row rowScanner) (*TargetGroup, error) {
|
|
var g TargetGroup
|
|
var targetsJSON, createdAt, updatedAt string
|
|
if err := row.Scan(&g.Name, &targetsJSON, &createdAt, &updatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := json.Unmarshal([]byte(targetsJSON), &g.Targets); err != nil {
|
|
return nil, fmt.Errorf("decode targets for group %q: %w", g.Name, err)
|
|
}
|
|
var err error
|
|
if g.CreatedAt, err = dbToTime(createdAt); err != nil {
|
|
return nil, err
|
|
}
|
|
if g.UpdatedAt, err = dbToTime(updatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
return &g, nil
|
|
}
|