Complete CRUD: add GET-single and DELETE endpoints
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful

Add GET /{name} and DELETE /{name} for zones, address-groups, portgroups,
fabrics, devices, and bindings, plus GET /rules/{id}, with the matching store
Get/Delete methods (deletes bump the generation and 404 on no-match). This gives
the resources full read/update/delete lifecycle so the Terraform provider can
manage them.
This commit is contained in:
benvin
2026-07-19 22:18:07 +10:00
parent 3afaab7d6c
commit 82c7d9c5f7
2 changed files with 209 additions and 1 deletions
+104 -1
View File
@@ -480,8 +480,16 @@ func (s *Store) CreateRule(ctx context.Context, r model.Rule) (int64, error) {
}
func (s *Store) DeleteRule(ctx context.Context, id int64) error {
return s.deleteOne(ctx, `DELETE FROM rules WHERE id = $1`, id)
}
// ---- Get-single and Delete completion --------------------------------------
// deleteOne runs a single-row delete, returning ErrNotFound when nothing matched
// and bumping the generation on success.
func (s *Store) deleteOne(ctx context.Context, query string, args ...any) error {
return pgx.BeginFunc(ctx, s.pool, func(tx pgx.Tx) error {
tag, err := tx.Exec(ctx, `DELETE FROM rules WHERE id = $1`, id)
tag, err := tx.Exec(ctx, query, args...)
if err != nil {
return err
}
@@ -491,3 +499,98 @@ func (s *Store) DeleteRule(ctx context.Context, id int64) error {
return bump(ctx, tx)
})
}
func (s *Store) DeleteZone(ctx context.Context, name string) error {
return s.deleteOne(ctx, `DELETE FROM zones WHERE name = $1`, name)
}
func (s *Store) DeleteFabric(ctx context.Context, name string) error {
return s.deleteOne(ctx, `DELETE FROM fabrics WHERE name = $1`, name)
}
func (s *Store) DeleteDevice(ctx context.Context, name string) error {
return s.deleteOne(ctx, `DELETE FROM devices WHERE name = $1`, name)
}
func (s *Store) DeletePortGroup(ctx context.Context, name string) error {
return s.deleteOne(ctx, `DELETE FROM portgroups WHERE name = $1`, name)
}
func (s *Store) DeleteAddressGroup(ctx context.Context, name string) error {
return s.deleteOne(ctx, `DELETE FROM address_groups WHERE name = $1`, name)
}
func (s *Store) DeleteBinding(ctx context.Context, device, zone string) error {
return s.deleteOne(ctx, `DELETE FROM bindings WHERE device = $1 AND zone = $2`, device, zone)
}
func (s *Store) GetAddressGroup(ctx context.Context, name string) (model.AddressGroup, error) {
var g model.AddressGroup
var members, resolved []byte
err := s.pool.QueryRow(ctx, `
SELECT name, type, members, refresh, description, resolved, resolved_at
FROM address_groups WHERE name = $1`, name,
).Scan(&g.Name, &g.Type, &members, &g.Refresh, &g.Description, &resolved, &g.ResolvedAt)
if errors.Is(err, pgx.ErrNoRows) {
return g, ErrNotFound
}
if err != nil {
return g, err
}
if err := json.Unmarshal(members, &g.Members); err != nil {
return g, err
}
return g, json.Unmarshal(resolved, &g.Resolved)
}
func (s *Store) GetPortGroup(ctx context.Context, name string) (model.PortGroup, error) {
var p model.PortGroup
var ports []byte
err := s.pool.QueryRow(ctx,
`SELECT name, proto, ports FROM portgroups WHERE name = $1`, name,
).Scan(&p.Name, &p.Proto, &ports)
if errors.Is(err, pgx.ErrNoRows) {
return p, ErrNotFound
}
if err != nil {
return p, err
}
return p, json.Unmarshal(ports, &p.Ports)
}
func (s *Store) GetBinding(ctx context.Context, device, zone string) (model.Binding, error) {
var b model.Binding
var ifaces []byte
err := s.pool.QueryRow(ctx,
`SELECT device, zone, interfaces FROM bindings WHERE device = $1 AND zone = $2`, device, zone,
).Scan(&b.Device, &b.Zone, &ifaces)
if errors.Is(err, pgx.ErrNoRows) {
return b, ErrNotFound
}
if err != nil {
return b, err
}
return b, json.Unmarshal(ifaces, &b.Interfaces)
}
func (s *Store) GetRule(ctx context.Context, id int64) (model.Rule, error) {
var r model.Rule
var source, dest, ports []byte
err := s.pool.QueryRow(ctx, `
SELECT id, priority, action, source, dest, proto, COALESCE(portgroup, ''), ports, log, comment
FROM rules WHERE id = $1`, id,
).Scan(&r.ID, &r.Priority, &r.Action, &source, &dest, &r.Proto, &r.PortGroup, &ports, &r.Log, &r.Comment)
if errors.Is(err, pgx.ErrNoRows) {
return r, ErrNotFound
}
if err != nil {
return r, err
}
if err := json.Unmarshal(source, &r.Source); err != nil {
return r, err
}
if err := json.Unmarshal(dest, &r.Dest); err != nil {
return r, err
}
return r, json.Unmarshal(ports, &r.Ports)
}