4693b7093c
- Add secmarks (id-keyed) and vars (key-keyed) resources: migration 0009, model, store CRUD, REST handlers. - Compiler rendering for the global-compiled tail: blrules, conntrack, secmarks render on enforcing devices; vars render on every device. This closes the rendering gap left by batch 1 (blrules/conntrack were stored but not rendered).
119 lines
3.3 KiB
Go
119 lines
3.3 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
|
|
"git.unkin.net/unkin/tomswallapi/internal/model"
|
|
)
|
|
|
|
// ---- Secmarks --------------------------------------------------------------
|
|
|
|
func (s *Store) ListSecmarks(ctx context.Context) ([]model.SecmarkRule, error) {
|
|
rows, err := s.pool.Query(ctx,
|
|
`SELECT id, secmark, chain, source, dest, proto, dport, sport, comment FROM secmarks ORDER BY id`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var out []model.SecmarkRule
|
|
for rows.Next() {
|
|
r, err := scanSecmark(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
func (s *Store) GetSecmark(ctx context.Context, id int64) (model.SecmarkRule, error) {
|
|
rows, err := s.pool.Query(ctx,
|
|
`SELECT id, secmark, chain, source, dest, proto, dport, sport, comment FROM secmarks WHERE id = $1`, id)
|
|
if err != nil {
|
|
return model.SecmarkRule{}, err
|
|
}
|
|
defer rows.Close()
|
|
if !rows.Next() {
|
|
return model.SecmarkRule{}, ErrNotFound
|
|
}
|
|
return scanSecmark(rows)
|
|
}
|
|
|
|
func scanSecmark(rows pgx.Rows) (model.SecmarkRule, error) {
|
|
var r model.SecmarkRule
|
|
var dport, sport []byte
|
|
if err := rows.Scan(&r.ID, &r.Secmark, &r.Chain, &r.Source, &r.Dest, &r.Proto, &dport, &sport, &r.Comment); err != nil {
|
|
return r, err
|
|
}
|
|
if err := unmarshalStrings(dport, &r.DPort); err != nil {
|
|
return r, err
|
|
}
|
|
return r, unmarshalStrings(sport, &r.SPort)
|
|
}
|
|
|
|
func (s *Store) CreateSecmark(ctx context.Context, r model.SecmarkRule) (int64, error) {
|
|
dport, _ := jsonb(r.DPort)
|
|
sport, _ := jsonb(r.SPort)
|
|
var id int64
|
|
err := pgx.BeginFunc(ctx, s.pool, func(tx pgx.Tx) error {
|
|
if err := tx.QueryRow(ctx, `
|
|
INSERT INTO secmarks (secmark, chain, source, dest, proto, dport, sport, comment)
|
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING id`,
|
|
r.Secmark, r.Chain, r.Source, r.Dest, r.Proto, dport, sport, r.Comment).Scan(&id); err != nil {
|
|
return err
|
|
}
|
|
return bump(ctx, tx)
|
|
})
|
|
return id, err
|
|
}
|
|
|
|
func (s *Store) DeleteSecmark(ctx context.Context, id int64) error {
|
|
return s.deleteOne(ctx, `DELETE FROM secmarks WHERE id = $1`, id)
|
|
}
|
|
|
|
// ---- Vars (key-keyed) ------------------------------------------------------
|
|
|
|
func (s *Store) ListVars(ctx context.Context) ([]model.Var, error) {
|
|
rows, err := s.pool.Query(ctx, `SELECT key, value FROM vars ORDER BY key`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var out []model.Var
|
|
for rows.Next() {
|
|
var v model.Var
|
|
if err := rows.Scan(&v.Key, &v.Value); err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, v)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
func (s *Store) GetVar(ctx context.Context, key string) (model.Var, error) {
|
|
var v model.Var
|
|
err := s.pool.QueryRow(ctx, `SELECT key, value FROM vars WHERE key = $1`, key).Scan(&v.Key, &v.Value)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return v, ErrNotFound
|
|
}
|
|
return v, err
|
|
}
|
|
|
|
func (s *Store) UpsertVar(ctx context.Context, v model.Var) error {
|
|
return pgx.BeginFunc(ctx, s.pool, func(tx pgx.Tx) error {
|
|
if _, err := tx.Exec(ctx,
|
|
`INSERT INTO vars (key, value) VALUES ($1, $2) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`,
|
|
v.Key, v.Value); err != nil {
|
|
return err
|
|
}
|
|
return bump(ctx, tx)
|
|
})
|
|
}
|
|
|
|
func (s *Store) DeleteVar(ctx context.Context, key string) error {
|
|
return s.deleteOne(ctx, `DELETE FROM vars WHERE key = $1`, key)
|
|
}
|