Files
EvoBGP/internal/birdfmt/birdctl.go
T

72 lines
1.8 KiB
Go

package birdfmt
import (
"bytes"
"context"
"fmt"
"os/exec"
"strings"
)
// BirdCtl runs bird(8) and birdc(8) for parse checks and configure reload.
type BirdCtl struct {
// Bird is the bird binary path (default "bird").
Bird string
// Birdc is the birdc binary path (default "birdc").
Birdc string
// Socket is optional birdc control socket (-s); empty uses birdc default.
Socket string
}
func (c *BirdCtl) birdBin() string {
if strings.TrimSpace(c.Bird) != "" {
return c.Bird
}
return "bird"
}
func (c *BirdCtl) birdcBin() string {
if strings.TrimSpace(c.Birdc) != "" {
return c.Birdc
}
return "birdc"
}
// ParseCheck runs `bird -c <mainConfigPath> -p` to validate syntax without starting the daemon.
func (c *BirdCtl) ParseCheck(ctx context.Context, mainConfigPath string) error {
mainConfigPath = strings.TrimSpace(mainConfigPath)
if mainConfigPath == "" {
return fmt.Errorf("birdfmt: main config path is required for parse check")
}
cmd := exec.CommandContext(ctx, c.birdBin(), "-c", mainConfigPath, "-p")
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
msg := strings.TrimSpace(stderr.String())
if msg != "" {
return fmt.Errorf("bird -p: %w: %s", err, msg)
}
return fmt.Errorf("bird -p: %w", err)
}
return nil
}
// Configure runs `birdc configure` to load the current config from disk (BIRD 2).
func (c *BirdCtl) Configure(ctx context.Context) error {
args := []string{"configure"}
if s := strings.TrimSpace(c.Socket); s != "" {
args = append([]string{"-s", s}, args...)
}
cmd := exec.CommandContext(ctx, c.birdcBin(), args...)
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
msg := strings.TrimSpace(stderr.String())
if msg != "" {
return fmt.Errorf("birdc configure: %w: %s", err, msg)
}
return fmt.Errorf("birdc configure: %w", err)
}
return nil
}