feat: Extract Wild Central as standalone Go service
Extract the Central networking functionality from wild-cloud/api into a standalone service. Wild Central manages DNS (dnsmasq), gateway (HAProxy), firewall (nftables), VPN (WireGuard), TLS (certbot), security (CrowdSec), and DDNS — all the network appliance concerns. All Cloud-specific code (instances, clusters, nodes, apps, backups, operations, kubectl/talosctl tooling) has been removed. The API struct and route registration contain only Central endpoints. Tests updated to match the new API signature. Builds and all tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
114
internal/config/extraports_test.go
Normal file
114
internal/config/extraports_test.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestExtraPortsJSONDecode_Legacy(t *testing.T) {
|
||||
// Legacy format: plain integer array
|
||||
input := `{"cloud":{"nftables":{"extraPorts":[22]}}}`
|
||||
var cfg GlobalConfig
|
||||
if err := json.Unmarshal([]byte(input), &cfg); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if len(cfg.Cloud.Nftables.ExtraPorts) != 1 || cfg.Cloud.Nftables.ExtraPorts[0].Port != 22 {
|
||||
t.Errorf("after JSON decode: expected [{Port:22}], got %v", cfg.Cloud.Nftables.ExtraPorts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtraPortsJSONDecode_Structured(t *testing.T) {
|
||||
// New structured format
|
||||
input := `{"cloud":{"nftables":{"extraPorts":[{"port":22,"protocol":"tcp","label":"SSH"},{"port":5353,"protocol":"udp"}]}}}`
|
||||
var cfg GlobalConfig
|
||||
if err := json.Unmarshal([]byte(input), &cfg); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if len(cfg.Cloud.Nftables.ExtraPorts) != 2 {
|
||||
t.Fatalf("expected 2 ports, got %d", len(cfg.Cloud.Nftables.ExtraPorts))
|
||||
}
|
||||
if cfg.Cloud.Nftables.ExtraPorts[0].Port != 22 || cfg.Cloud.Nftables.ExtraPorts[0].Protocol != "tcp" || cfg.Cloud.Nftables.ExtraPorts[0].Label != "SSH" {
|
||||
t.Errorf("port 0: expected {22,tcp,SSH}, got %+v", cfg.Cloud.Nftables.ExtraPorts[0])
|
||||
}
|
||||
if cfg.Cloud.Nftables.ExtraPorts[1].Port != 5353 || cfg.Cloud.Nftables.ExtraPorts[1].Protocol != "udp" {
|
||||
t.Errorf("port 1: expected {5353,udp}, got %+v", cfg.Cloud.Nftables.ExtraPorts[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtraPortsJSONEncode(t *testing.T) {
|
||||
var cfg GlobalConfig
|
||||
cfg.Cloud.Nftables.ExtraPorts = []ExtraPort{{Port: 22, Protocol: "tcp", Label: "SSH"}}
|
||||
out, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal: %v", err)
|
||||
}
|
||||
var decoded map[string]any
|
||||
json.Unmarshal(out, &decoded)
|
||||
cloud := decoded["cloud"].(map[string]any)
|
||||
nft := cloud["nftables"].(map[string]any)
|
||||
ports, ok := nft["extraPorts"]
|
||||
if !ok {
|
||||
t.Errorf("extraPorts missing from JSON output: %s", out)
|
||||
}
|
||||
arr := ports.([]any)
|
||||
if len(arr) != 1 {
|
||||
t.Fatalf("expected 1 port, got %d", len(arr))
|
||||
}
|
||||
entry := arr[0].(map[string]any)
|
||||
if entry["port"].(float64) != 22 {
|
||||
t.Errorf("expected port 22, got %v", entry["port"])
|
||||
}
|
||||
if entry["label"].(string) != "SSH" {
|
||||
t.Errorf("expected label SSH, got %v", entry["label"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtraPortsYAML_LegacyRoundTrip(t *testing.T) {
|
||||
// Legacy YAML format with plain integers
|
||||
input := "cloud:\n nftables:\n extraPorts:\n - 22\n - 8080\n"
|
||||
var cfg GlobalConfig
|
||||
if err := yaml.Unmarshal([]byte(input), &cfg); err != nil {
|
||||
t.Fatalf("yaml unmarshal: %v", err)
|
||||
}
|
||||
if len(cfg.Cloud.Nftables.ExtraPorts) != 2 {
|
||||
t.Fatalf("expected 2 ports, got %d", len(cfg.Cloud.Nftables.ExtraPorts))
|
||||
}
|
||||
if cfg.Cloud.Nftables.ExtraPorts[0].Port != 22 || cfg.Cloud.Nftables.ExtraPorts[1].Port != 8080 {
|
||||
t.Errorf("expected [22, 8080], got %v", cfg.Cloud.Nftables.ExtraPorts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtraPortsYAML_StructuredRoundTrip(t *testing.T) {
|
||||
input := "cloud:\n nftables:\n extraPorts:\n - port: 22\n protocol: tcp\n label: SSH\n - port: 5353\n protocol: udp\n"
|
||||
var cfg GlobalConfig
|
||||
if err := yaml.Unmarshal([]byte(input), &cfg); err != nil {
|
||||
t.Fatalf("yaml unmarshal: %v", err)
|
||||
}
|
||||
if len(cfg.Cloud.Nftables.ExtraPorts) != 2 {
|
||||
t.Fatalf("expected 2 ports, got %d", len(cfg.Cloud.Nftables.ExtraPorts))
|
||||
}
|
||||
if cfg.Cloud.Nftables.ExtraPorts[0].Label != "SSH" {
|
||||
t.Errorf("expected label SSH, got %q", cfg.Cloud.Nftables.ExtraPorts[0].Label)
|
||||
}
|
||||
if cfg.Cloud.Nftables.ExtraPorts[1].Protocol != "udp" {
|
||||
t.Errorf("expected protocol udp, got %q", cfg.Cloud.Nftables.ExtraPorts[1].Protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitExtraPorts(t *testing.T) {
|
||||
ports := []ExtraPort{
|
||||
{Port: 22, Protocol: "tcp"},
|
||||
{Port: 80}, // default = tcp
|
||||
{Port: 5353, Protocol: "udp"},
|
||||
{Port: 123, Protocol: "UDP"}, // case-insensitive
|
||||
}
|
||||
tcp, udp := SplitExtraPorts(ports)
|
||||
if len(tcp) != 2 || tcp[0] != 22 || tcp[1] != 80 {
|
||||
t.Errorf("expected tcp=[22,80], got %v", tcp)
|
||||
}
|
||||
if len(udp) != 2 || udp[0] != 5353 || udp[1] != 123 {
|
||||
t.Errorf("expected udp=[5353,123], got %v", udp)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user