Add per-device config compiler and agent config endpoint
Project the fleet-global model through a device's bindings into a rendered,
interface-agnostic config: rules compile to saddr/daddr forward matches with no
iif/oif so they are correct under FRR/ECMP. Firewalls always enforce; routers
enforce only when their fabric opts into defense-in-depth. Referenced address
groups are emitted as named sets carrying their source (static CIDRs, dns FQDNs,
or asn numbers) so membership churns out-of-band without a rule reload. Wire
GET /devices/{name}/config to compile and serve YAML, generation-stamped. Add
portgroups/policies/settings store methods and portgroup CRUD. Pure Render is
unit-tested for enforcement gating, ASN set emission, and resolver precedence.
This commit is contained in:
@@ -262,6 +262,94 @@ func (s *Store) RecordDeviceStatus(ctx context.Context, name string, generation
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) GetDevice(ctx context.Context, name string) (model.Device, error) {
|
||||
var d model.Device
|
||||
var resolver, settings []byte
|
||||
err := s.pool.QueryRow(ctx,
|
||||
`SELECT name, class, COALESCE(fabric, ''), resolver, settings FROM devices WHERE name = $1`, name,
|
||||
).Scan(&d.Name, &d.Class, &d.Fabric, &resolver, &settings)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return d, ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
if err := json.Unmarshal(resolver, &d.Resolver); err != nil {
|
||||
return d, err
|
||||
}
|
||||
return d, json.Unmarshal(settings, &d.Settings)
|
||||
}
|
||||
|
||||
// ---- Settings, portgroups, policies ----------------------------------------
|
||||
|
||||
func (s *Store) GetSettings(ctx context.Context) (model.Settings, error) {
|
||||
var st model.Settings
|
||||
var resolver []byte
|
||||
err := s.pool.QueryRow(ctx, `
|
||||
SELECT address_family, log_level, ip_forwarding, table_name, default_resolver
|
||||
FROM settings WHERE id = true`,
|
||||
).Scan(&st.AddressFamily, &st.LogLevel, &st.IPForwarding, &st.TableName, &resolver)
|
||||
if err != nil {
|
||||
return st, err
|
||||
}
|
||||
return st, json.Unmarshal(resolver, &st.DefaultResolver)
|
||||
}
|
||||
|
||||
func (s *Store) ListPortGroups(ctx context.Context) ([]model.PortGroup, error) {
|
||||
rows, err := s.pool.Query(ctx, `SELECT name, proto, ports FROM portgroups ORDER BY name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []model.PortGroup
|
||||
for rows.Next() {
|
||||
var p model.PortGroup
|
||||
var ports []byte
|
||||
if err := rows.Scan(&p.Name, &p.Proto, &ports); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(ports, &p.Ports); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (s *Store) UpsertPortGroup(ctx context.Context, p model.PortGroup) error {
|
||||
ports, err := jsonb(p.Ports)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pgx.BeginFunc(ctx, s.pool, func(tx pgx.Tx) error {
|
||||
if _, err := tx.Exec(ctx, `
|
||||
INSERT INTO portgroups (name, proto, ports) VALUES ($1, $2, $3)
|
||||
ON CONFLICT (name) DO UPDATE SET proto = EXCLUDED.proto, ports = EXCLUDED.ports`,
|
||||
p.Name, p.Proto, ports); err != nil {
|
||||
return err
|
||||
}
|
||||
return bump(ctx, tx)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) ListPolicies(ctx context.Context) ([]model.Policy, error) {
|
||||
rows, err := s.pool.Query(ctx,
|
||||
`SELECT id, priority, source, dest, action, log FROM policies ORDER BY priority, id`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []model.Policy
|
||||
for rows.Next() {
|
||||
var p model.Policy
|
||||
if err := rows.Scan(&p.ID, &p.Priority, &p.Source, &p.Dest, &p.Action, &p.Log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// ---- Bindings --------------------------------------------------------------
|
||||
|
||||
func (s *Store) ListBindings(ctx context.Context, device string) ([]model.Binding, error) {
|
||||
|
||||
Reference in New Issue
Block a user