feat: Docker Compose E2E test env, agent fixes, TAP MAC config, testclient binary
- Add docker-compose.yml with server + init + 3 clients + tester - Add Dockerfile.server (CGO multi-stage) and Dockerfile.client - Add .dockerignore for efficient builds - Add cmd/testclient/main.go: full E2E test binary using SDK - Fix agent handshake loop: only respond to new handshakes - Add tapInterface.SetMAC() to match agent's generated MAC - Call SetMAC() in agent SetTAPIP to fix ARP resolution - Add data-plane debug logging for troubleshooting - Change config database path to /tmp/data/ for container use - Add SetMAC stub for non-Linux builds
This commit is contained in:
192
cmd/testclient/main.go
Normal file
192
cmd/testclient/main.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"zeromesh/sdk"
|
||||
)
|
||||
|
||||
var (
|
||||
serverURL = flag.String("server", "http://server:10001", "Controller HTTP URL")
|
||||
name = flag.String("name", "client", "Node name")
|
||||
udpPort = flag.Int("udp", 7001, "Agent UDP listen port")
|
||||
tapName = flag.String("tap", "ztmesh0", "TAP device name")
|
||||
identityPath = flag.String("identity", "", "Identity file path")
|
||||
adminUser = flag.String("admin", "admin", "Admin username")
|
||||
adminPass = flag.String("pass", "admin123456", "Admin password")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
slog.SetLogLoggerLevel(slog.LevelInfo)
|
||||
|
||||
cfg := sdk.DefaultConfig()
|
||||
cfg.ControllerURL = *serverURL
|
||||
cfg.ListenPort = *udpPort
|
||||
cfg.TapName = *tapName
|
||||
cfg.PSK = "default-psk-change-me"
|
||||
if *identityPath != "" {
|
||||
cfg.IdentityPath = *identityPath
|
||||
}
|
||||
cli := sdk.New(cfg)
|
||||
|
||||
var token string
|
||||
for i := 0; i < 30; i++ {
|
||||
if err := cli.Login(*adminUser, *adminPass); err == nil {
|
||||
token = cli.Token()
|
||||
break
|
||||
}
|
||||
if _, err := cli.InitAdmin(*adminUser, *adminPass); err == nil {
|
||||
token = cli.Token()
|
||||
log.Print("initialized admin")
|
||||
break
|
||||
}
|
||||
log.Printf("waiting for server (attempt %d)...", i+1)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
if token == "" {
|
||||
log.Fatal("could not login or init admin after 30 attempts")
|
||||
}
|
||||
log.Printf("logged in as %s", *adminUser)
|
||||
|
||||
idPath := *identityPath
|
||||
if idPath == "" {
|
||||
idPath = fmt.Sprintf("/tmp/%s.id", *name)
|
||||
}
|
||||
id, err := sdk.LoadOrGenerateIdentity(idPath)
|
||||
if err != nil {
|
||||
log.Fatalf("identity: %v", err)
|
||||
}
|
||||
log.Printf("identity: %s pub=%s", id.Address, id.PublicKeyHex())
|
||||
|
||||
myIP := sdk.GetPreferredIP()
|
||||
node, err := cli.RegisterNode(id.Address.String(), id.PublicKeyHex(), *name, myIP, *udpPort, "1.0.0")
|
||||
if err != nil {
|
||||
log.Fatalf("register node: %v", err)
|
||||
}
|
||||
log.Printf("registered node: %s", node.NodeID)
|
||||
|
||||
findNetwork := func() *sdk.Network {
|
||||
networks, err := cli.ListNetworks()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for i := range networks {
|
||||
if !strings.HasPrefix(networks[i].IPRange, "10.7.") && !strings.HasPrefix(networks[i].IPRange, "172.") && !strings.HasPrefix(networks[i].IPRange, "192.") {
|
||||
continue
|
||||
}
|
||||
return &networks[i]
|
||||
}
|
||||
if len(networks) > 0 {
|
||||
return &networks[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
myNet := findNetwork()
|
||||
if myNet == nil {
|
||||
created, err := cli.CreateNetwork(fmt.Sprintf("testnet-%s", *name), "")
|
||||
if err != nil {
|
||||
log.Fatalf("create network: %v", err)
|
||||
}
|
||||
myNet = created
|
||||
log.Printf("created network: %s (%s) id=%d", myNet.Name, myNet.IPRange, myNet.NetworkID)
|
||||
} else {
|
||||
log.Printf("using network: %s (%s) id=%d", myNet.Name, myNet.IPRange, myNet.NetworkID)
|
||||
}
|
||||
|
||||
var myIPAddr string
|
||||
for i := 0; i < 10; i++ {
|
||||
members, err := cli.NetworkMembers(myNet.NetworkID)
|
||||
if err == nil {
|
||||
for _, m := range members {
|
||||
if m.NodeID == id.Address.String() {
|
||||
myIPAddr = m.IPAddress
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if myIPAddr != "" {
|
||||
break
|
||||
}
|
||||
log.Printf("authorizing self on network %d...", myNet.NetworkID)
|
||||
cli.AuthorizeMember(myNet.NetworkID, id.Address.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
if myIPAddr == "" {
|
||||
log.Fatalf("could not get virtual IP after authorization")
|
||||
}
|
||||
log.Printf("my virtual IP: %s", myIPAddr)
|
||||
|
||||
agent := sdk.NewAgent(cli)
|
||||
agent.SetIdentity(id)
|
||||
|
||||
if err := agent.Start(); err != nil {
|
||||
log.Fatalf("agent start: %v", err)
|
||||
}
|
||||
defer agent.Stop()
|
||||
log.Printf("agent started: tap=%s udp=%d", agent.TAPName(), agent.LocalPort())
|
||||
|
||||
agent.ControllerHello()
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
agent.SyncPeers()
|
||||
time.Sleep(3 * time.Second)
|
||||
c := agent.PeerCount()
|
||||
if c > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
cidrFull := myIPAddr + "/24"
|
||||
if err := agent.SetTAPIP(cidrFull); err != nil {
|
||||
log.Printf("set tap ip warning: %v", err)
|
||||
} else {
|
||||
log.Printf("tap ip set: %s", cidrFull)
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf("%s:7777", myIPAddr))
|
||||
if err != nil {
|
||||
log.Printf("echo server listen error (expected if TAP not ready): %v", err)
|
||||
} else {
|
||||
defer listener.Close()
|
||||
log.Printf("echo server listening on %s:7777", myIPAddr)
|
||||
go func() {
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go func(c net.Conn) {
|
||||
defer c.Close()
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, err := c.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.Write(buf[:n])
|
||||
}
|
||||
}(conn)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
peerCount := agent.PeerCount()
|
||||
log.Printf("%s ready: ip=%s tap=%s peers=%d", *name, myIPAddr, agent.TAPName(), peerCount)
|
||||
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sc
|
||||
log.Printf("shutting down %s", *name)
|
||||
}
|
||||
Reference in New Issue
Block a user