CI / changes (push) Successful in 8s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 25s
CI / web (push) Failing after 34s
CI / go (push) Failing after 19s
CI / bird2 (push) Has been skipped
CI / release (push) Has been skipped
- Added support for remote speaker configuration in the README and documentation. - Implemented a new endpoint for retrieving the bundle signing public key. - Updated the `evobgp-agent` to include a `serve` command for Panel→Node sync API. - Enhanced CI workflow to validate remote speaker compose files. - Introduced new fields in the API and UI for managing speaker metadata, including dispatch status and sync status. - Improved error handling and response formatting in speaker-related API endpoints. - Updated documentation to reflect changes in remote speaker functionality and usage guidelines.
130 lines
3.5 KiB
Go
130 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"evobgp/internal/agentserver"
|
|
"evobgp/internal/birdfmt"
|
|
)
|
|
|
|
func main() {
|
|
bird := flag.String("bird", "", "path to bird binary (default: bird from PATH)")
|
|
birdc := flag.String("birdc", "", "path to birdc binary (default: birdc from PATH)")
|
|
socket := flag.String("socket", "", "optional birdc control socket (-s)")
|
|
timeout := flag.Duration("timeout", 30*time.Second, "timeout for bird/birdc")
|
|
watchEvery := flag.Duration("watch-interval", 30*time.Second, "for watch: interval between birdc configure")
|
|
listen := flag.String("listen", "", "for serve: listen address (default :8443 or EVOBGP_AGENT_LISTEN)")
|
|
flag.Usage = func() {
|
|
fmt.Fprintf(os.Stderr, "Usage: %s [flags] <command>\n", os.Args[0])
|
|
fmt.Fprintf(os.Stderr, "Commands:\n")
|
|
fmt.Fprintf(os.Stderr, " parse-check <path/to/bird.conf> run bird -c <path> -p (syntax check)\n")
|
|
fmt.Fprintf(os.Stderr, " configure run birdc configure (reload running BIRD)\n")
|
|
fmt.Fprintf(os.Stderr, " watch periodically run birdc configure (compose sidecar)\n")
|
|
fmt.Fprintf(os.Stderr, " serve Panel→Node HTTP API (POST /v1/agent/sync)\n")
|
|
flag.PrintDefaults()
|
|
}
|
|
flag.Parse()
|
|
args := flag.Args()
|
|
if len(args) < 1 {
|
|
flag.Usage()
|
|
os.Exit(2)
|
|
}
|
|
|
|
ctl := &birdfmt.BirdCtl{Socket: *socket}
|
|
if *bird != "" {
|
|
ctl.Bird = *bird
|
|
}
|
|
if *birdc != "" {
|
|
ctl.Birdc = *birdc
|
|
}
|
|
|
|
switch args[0] {
|
|
case "serve":
|
|
runServe(*listen, *timeout)
|
|
case "parse-check", "configure", "watch":
|
|
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
|
|
defer cancel()
|
|
runBirdCommand(ctx, args, ctl, *watchEvery, *timeout)
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "unknown command: %s\n", args[0])
|
|
flag.Usage()
|
|
os.Exit(2)
|
|
}
|
|
}
|
|
|
|
func runBirdCommand(ctx context.Context, args []string, ctl *birdfmt.BirdCtl, watchEvery, timeout time.Duration) {
|
|
switch args[0] {
|
|
case "parse-check":
|
|
if len(args) != 2 {
|
|
fmt.Fprintln(os.Stderr, "parse-check requires exactly one argument: path to bird.conf")
|
|
os.Exit(2)
|
|
}
|
|
if err := ctl.ParseCheck(ctx, args[1]); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
case "configure":
|
|
if len(args) != 1 {
|
|
fmt.Fprintln(os.Stderr, "configure takes no extra arguments")
|
|
os.Exit(2)
|
|
}
|
|
if err := ctl.Configure(ctx); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
case "watch":
|
|
if watchEvery <= 0 {
|
|
fmt.Fprintln(os.Stderr, "watch-interval must be > 0")
|
|
os.Exit(2)
|
|
}
|
|
log.Printf("evobgp-agent watch: birdc configure every %s (socket=%q)", watchEvery, ctl.Socket)
|
|
for {
|
|
cctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
err := ctl.Configure(cctx)
|
|
cancel()
|
|
if err != nil {
|
|
log.Printf("evobgp-agent watch: configure: %v", err)
|
|
}
|
|
time.Sleep(watchEvery)
|
|
}
|
|
}
|
|
}
|
|
|
|
func runServe(listenFlag string, syncTimeout time.Duration) {
|
|
cfg, err := agentserver.ConfigFromEnv()
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(2)
|
|
}
|
|
if listenFlag != "" {
|
|
cfg.Listen = listenFlag
|
|
}
|
|
if syncTimeout > 0 {
|
|
cfg.SyncTimeout = syncTimeout
|
|
}
|
|
var mu sync.Mutex
|
|
var lastRev string
|
|
var lastAt time.Time
|
|
cfg.LastSync = func() (string, time.Time) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
return lastRev, lastAt
|
|
}
|
|
cfg.OnSyncSuccess = func(rev string) {
|
|
mu.Lock()
|
|
lastRev = rev
|
|
lastAt = time.Now().UTC()
|
|
mu.Unlock()
|
|
}
|
|
if err := agentserver.ListenAndServe(cfg); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|