The mesh says what filters a converged machine: filters kept per node, shown by node show, named by status, and previewed with their fates (hq ADR 0168)
A host reports every table and chain that refuses traffic with its owner, and a converged machine's found firewall's state. The controller keeps both on the node's record (migration 0054), shows them on node show, names every converged machine something other than the mesh filters in status — text and JSON, and such a machine is not well — and the converge preview lists what filters the machine with the fate of each: retired with the front end, left as the runtime's, left as a ban, or left in force and not the mesh's. What was invisible for eleven hours (issues 144, 145) is said by name.
This commit is contained in:
@@ -178,6 +178,103 @@ type Stray struct {
|
||||
Detail string `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
// A Filter is one place on a machine that refuses traffic, with its owner (novox/hq ADR 0168).
|
||||
type Filter struct {
|
||||
Where string `json:"where"`
|
||||
Owner string `json:"owner"`
|
||||
Refuses string `json:"refuses"`
|
||||
}
|
||||
|
||||
// Owners of a filter, as the host names them (ADR 0168).
|
||||
const (
|
||||
FilterMesh = "mesh"
|
||||
FilterFoundFirewall = "found-firewall"
|
||||
FilterRuntime = "runtime"
|
||||
FilterBan = "ban"
|
||||
FilterOther = "other"
|
||||
)
|
||||
|
||||
// FoundFirewall is the state of a converged machine's found firewall (ADR 0168): in force now or
|
||||
// not, and how it came to be inactive.
|
||||
type FoundFirewall struct {
|
||||
Kind string `json:"kind"`
|
||||
Active bool `json:"active"`
|
||||
RetiredBy string `json:"retired_by,omitempty"`
|
||||
}
|
||||
|
||||
// Filtering is what a machine last said filters it (ADR 0168).
|
||||
type Filtering struct {
|
||||
Filters []Filter
|
||||
FoundFirewall *FoundFirewall
|
||||
}
|
||||
|
||||
// Alone is whether the machine is filtered by the mesh alone: nothing in its list but the mesh's
|
||||
// own, the runtime's plumbing and bans, and no found firewall in force.
|
||||
func (f Filtering) Alone() bool {
|
||||
for _, x := range f.Filters {
|
||||
if x.Owner == FilterOther || x.Owner == FilterFoundFirewall {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return f.FoundFirewall == nil || !f.FoundFirewall.Active
|
||||
}
|
||||
|
||||
// Others is every filter that is neither the mesh's, the runtime's nor a ban.
|
||||
func (f Filtering) Others() []Filter {
|
||||
var out []Filter
|
||||
for _, x := range f.Filters {
|
||||
if x.Owner == FilterOther || x.Owner == FilterFoundFirewall {
|
||||
out = append(out, x)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// RecordFiltering keeps what a machine last said filters it, replacing what was there (ADR 0168).
|
||||
func (i *Inventory) RecordFiltering(ctx context.Context, nodeID string, filters []Filter, found *FoundFirewall) error {
|
||||
raw, err := json.Marshal(nonNil(filters))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var foundRaw any
|
||||
if found != nil {
|
||||
b, err := json.Marshal(found)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
foundRaw = string(b)
|
||||
}
|
||||
_, err = i.store.Pool().Exec(ctx,
|
||||
`update node set filters = $2, found_firewall = $3 where id = $1`, nodeID, raw, foundRaw)
|
||||
return err
|
||||
}
|
||||
|
||||
// FilteringOf is what a machine last said filters it; empty for a machine that never said.
|
||||
func (i *Inventory) FilteringOf(ctx context.Context, name string) (Filtering, error) {
|
||||
var filtersRaw, foundRaw []byte
|
||||
err := i.store.Pool().QueryRow(ctx,
|
||||
`select filters, found_firewall from node where name = $1`, name).Scan(&filtersRaw, &foundRaw)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return Filtering{}, fmt.Errorf("%w: %s", ErrNoSuchNode, name)
|
||||
}
|
||||
if err != nil {
|
||||
return Filtering{}, err
|
||||
}
|
||||
var out Filtering
|
||||
if len(filtersRaw) > 0 {
|
||||
if err := json.Unmarshal(filtersRaw, &out.Filters); err != nil {
|
||||
return Filtering{}, err
|
||||
}
|
||||
}
|
||||
if len(foundRaw) > 0 {
|
||||
out.FoundFirewall = &FoundFirewall{}
|
||||
if err := json.Unmarshal(foundRaw, out.FoundFirewall); err != nil {
|
||||
return Filtering{}, err
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Reach is one thing reachable on an adopted node: a listening socket or a published port.
|
||||
type Reach struct {
|
||||
Protocol string `json:"protocol"`
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- What filters a machine, with owners, as the host reports it with every apply (novox/hq ADR 0168):
|
||||
-- every table and chain that refuses traffic — the mesh's, the found firewall's, the runtime's own,
|
||||
-- a ban, or other — so the mesh says truthfully what filters a converged machine and names what it
|
||||
-- did not write. And the state of the firewall a converged machine was found with: in force now or
|
||||
-- not, and who retired it.
|
||||
alter table node add column filters jsonb;
|
||||
alter table node add column found_firewall jsonb;
|
||||
Reference in New Issue
Block a user