Add tomswall agent (control-plane pull mode)
Add `tomswall agent`: it pulls this device's compiled config from tomswallapi, differentially applies it, and reports the applied generation. It caches the last known-good config and, when the control plane is unreachable, keeps applying that cache — it never fails closed. - internal/agent: rendered-config types, HTTP client (fetch + status report), on-disk cache, on-device DNS resolver for dns sets (honors the device's configured resolver, fail-safe on lookup failure), and the pull-apply-report loop behind a mockable Applier. - Translate the interface-agnostic, address-matched rendered model into native tomswall config using the "all:<cidr>" any-interface source/dest form, reusing the existing differential engine. Named-set members are inlined as concrete addresses (native nft set references are a tracked follow-up). - cmd/tomswall: wire the `agent` subcommand (flags + TOMSWALL_* env, --once). - Unit tests: translation, cache, and the don't-fail-closed fallback loop. - Add DESIGN.md documenting the control-plane architecture.
This commit is contained in:
@@ -215,7 +215,7 @@ func TestValidateRoutingRules(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "missing providers",
|
||||
name: "missing providers",
|
||||
setup: baseConfig,
|
||||
rules: []RoutingRule{
|
||||
{Source: "10.0.0.0/8", Provider: "isp1", Priority: 1000},
|
||||
@@ -1174,9 +1174,9 @@ func TestResolveNesting(t *testing.T) {
|
||||
t.Run("simple parent-child hierarchy", func(t *testing.T) {
|
||||
cfg := Config{
|
||||
Zones: map[string]Zone{
|
||||
"fw": {Type: ZoneFirewall},
|
||||
"net": {Type: ZoneIP},
|
||||
"dmz": {Type: ZoneIP, Parents: []string{"net"}},
|
||||
"fw": {Type: ZoneFirewall},
|
||||
"net": {Type: ZoneIP},
|
||||
"dmz": {Type: ZoneIP, Parents: []string{"net"}},
|
||||
},
|
||||
}
|
||||
order, err := cfg.ResolveNesting()
|
||||
@@ -1259,9 +1259,9 @@ func TestIsSubZone(t *testing.T) {
|
||||
}{
|
||||
{"dmz", "net", true},
|
||||
{"web", "dmz", true},
|
||||
{"web", "net", true}, // transitive
|
||||
{"net", "dmz", false}, // reverse
|
||||
{"net", "net", false}, // self
|
||||
{"web", "net", true}, // transitive
|
||||
{"net", "dmz", false}, // reverse
|
||||
{"net", "net", false}, // self
|
||||
{"nosuch", "net", false}, // non-existent
|
||||
}
|
||||
|
||||
@@ -1305,10 +1305,10 @@ func TestValidateName(t *testing.T) {
|
||||
|
||||
func TestSubstituteVars(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
vars map[string]string
|
||||
want string
|
||||
name string
|
||||
input string
|
||||
vars map[string]string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "braced substitution",
|
||||
@@ -1441,4 +1441,3 @@ func TestValidateSettings(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user