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:
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"git.unkin.net/unkin/tomswall/internal/agent"
|
||||
)
|
||||
|
||||
func agentCmd() *cobra.Command {
|
||||
var (
|
||||
apiURL string
|
||||
device string
|
||||
token string
|
||||
cachePath string
|
||||
interval time.Duration
|
||||
once bool
|
||||
)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "agent",
|
||||
Short: "Pull compiled config from tomswallapi and apply it continuously",
|
||||
Long: `Agent runs the control-plane pull loop: it fetches this device's compiled
|
||||
config from tomswallapi, differentially applies it, and reports the applied
|
||||
generation back. It caches the last known-good config and, if the control plane
|
||||
is unreachable, keeps applying that cache — it never fails closed.
|
||||
|
||||
The agent token defaults to the TOMSWALL_AGENT_TOKEN environment variable, and
|
||||
the device name defaults to the system hostname.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if token == "" {
|
||||
token = os.Getenv("TOMSWALL_AGENT_TOKEN")
|
||||
}
|
||||
if device == "" {
|
||||
device, _ = os.Hostname()
|
||||
}
|
||||
if apiURL == "" {
|
||||
return fmt.Errorf("--api-url is required (or set it in the environment)")
|
||||
}
|
||||
if device == "" {
|
||||
return fmt.Errorf("--device is required (could not determine hostname)")
|
||||
}
|
||||
if token == "" {
|
||||
return fmt.Errorf("agent token required: set --token or TOMSWALL_AGENT_TOKEN")
|
||||
}
|
||||
|
||||
a := &agent.Agent{
|
||||
Client: agent.NewClient(apiURL, device, token),
|
||||
Cache: agent.Cache{Path: cachePath},
|
||||
Interval: interval,
|
||||
Applier: agent.EngineApplier{},
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
if once {
|
||||
return a.RunOnce(ctx)
|
||||
}
|
||||
return a.Run(ctx)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&apiURL, "api-url", os.Getenv("TOMSWALL_API_URL"), "tomswallapi base URL (or TOMSWALL_API_URL)")
|
||||
cmd.Flags().StringVar(&device, "device", "", "device name (defaults to hostname)")
|
||||
cmd.Flags().StringVar(&token, "token", "", "agent bearer token (or TOMSWALL_AGENT_TOKEN)")
|
||||
cmd.Flags().StringVar(&cachePath, "cache", "/var/lib/tomswall/rendered.yaml", "path to the last-known-good config cache")
|
||||
cmd.Flags().DurationVar(&interval, "interval", time.Minute, "poll interval")
|
||||
cmd.Flags().BoolVar(&once, "once", false, "run a single apply cycle and exit")
|
||||
return cmd
|
||||
}
|
||||
@@ -39,6 +39,7 @@ Use 'tomswall migrate' to convert a shorewall config to YAML.`,
|
||||
purgeCmd(),
|
||||
flushCmd(),
|
||||
migrateCmd(),
|
||||
agentCmd(),
|
||||
completionCmd(),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user