feat: enhance evobgp with new command-line tools for bundle management, including pull, verify, and apply functionalities. Update go.mod to include necessary dependencies and complete todos in architecture plan for improved observability and deployment practices.
This commit is contained in:
@@ -1,3 +1,67 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"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")
|
||||
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")
|
||||
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
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
|
||||
defer cancel()
|
||||
|
||||
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)
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "unknown command: %s\n", args[0])
|
||||
flag.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
+87
-1
@@ -1,3 +1,89 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"evobgp/internal/birdfmt"
|
||||
"evobgp/internal/config"
|
||||
"evobgp/internal/deploy"
|
||||
"evobgp/internal/httpapi"
|
||||
"evobgp/internal/ingest"
|
||||
"evobgp/internal/observability"
|
||||
"evobgp/internal/platform"
|
||||
"evobgp/internal/render"
|
||||
"evobgp/internal/scheduler"
|
||||
)
|
||||
|
||||
// microVPS entrypoint: one process — HTTP API (same as evobgp-api) plus in-process stubs for scheduler/ingest/render/deploy.
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
opts := httpapi.Options{
|
||||
APIKeys: os.Getenv("EVOBGP_API_KEYS"),
|
||||
InsecureDev: os.Getenv("EVOBGP_DEV_INSECURE") == "1",
|
||||
SeedDemo: os.Getenv("EVOBGP_SEED_DEMO") != "0",
|
||||
BundleSeedHex: strings.TrimSpace(os.Getenv("EVOBGP_BUNDLE_SEED_HEX")),
|
||||
CORSAllowedOrigins: strings.TrimSpace(os.Getenv("EVOBGP_CORS_ORIGINS")),
|
||||
}
|
||||
srv, err := httpapi.New(opts)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
observability.SetBuildInfo("0.1.0", strings.TrimSpace(os.Getenv("EVOBGP_GIT_SHA")))
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
go scheduler.Run(ctx)
|
||||
go ingest.Run(ctx)
|
||||
go render.Run(ctx)
|
||||
go deploy.Run(ctx)
|
||||
|
||||
startBirdMetricsPoller()
|
||||
|
||||
httpSrv := &http.Server{
|
||||
Addr: cfg.HTTPAddr,
|
||||
Handler: srv.Handler(),
|
||||
}
|
||||
go func() {
|
||||
svc := platform.ServiceName("evobgp-all")
|
||||
log.Printf("%s (microVPS): HTTP API on %s", svc, cfg.HTTPAddr)
|
||||
log.Printf("bundle public key (base64): %s", srv.BundlePublicKeyBase64())
|
||||
if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
if err := httpSrv.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("HTTP shutdown: %v", err)
|
||||
}
|
||||
log.Printf("%s stopped", platform.ServiceName("evobgp-all"))
|
||||
}
|
||||
|
||||
func startBirdMetricsPoller() {
|
||||
sock := strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_SOCKET"))
|
||||
if sock == "" {
|
||||
return
|
||||
}
|
||||
interval := 30 * time.Second
|
||||
if d, err := time.ParseDuration(strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_INTERVAL"))); err == nil && d > 0 {
|
||||
interval = d
|
||||
}
|
||||
bin := strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_BIN"))
|
||||
observability.StartBirdProtocolsPoller(sock, bin, interval,
|
||||
func(ctx context.Context, socket, birdcBin string) (string, error) {
|
||||
return birdfmt.ShowProtocols(ctx, socket, birdcBin)
|
||||
},
|
||||
birdfmt.CountEstablishedBGPSessions,
|
||||
)
|
||||
log.Printf("birdc protocols poller enabled (socket=%s interval=%s)", sock, interval)
|
||||
}
|
||||
|
||||
+84
-1
@@ -1,3 +1,86 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"evobgp/internal/birdfmt"
|
||||
"evobgp/internal/config"
|
||||
"evobgp/internal/httpapi"
|
||||
"evobgp/internal/observability"
|
||||
"evobgp/internal/platform"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
seedDemo := os.Getenv("EVOBGP_SEED_DEMO") != "0"
|
||||
opts := httpapi.Options{
|
||||
APIKeys: os.Getenv("EVOBGP_API_KEYS"),
|
||||
InsecureDev: os.Getenv("EVOBGP_DEV_INSECURE") == "1",
|
||||
SeedDemo: seedDemo,
|
||||
BundleSeedHex: strings.TrimSpace(os.Getenv("EVOBGP_BUNDLE_SEED_HEX")),
|
||||
CORSAllowedOrigins: strings.TrimSpace(os.Getenv("EVOBGP_CORS_ORIGINS")),
|
||||
}
|
||||
srv, err := httpapi.New(opts)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
observability.SetBuildInfo("0.1.0", strings.TrimSpace(os.Getenv("EVOBGP_GIT_SHA")))
|
||||
startBirdMetricsPoller()
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
httpSrv := &http.Server{
|
||||
Addr: cfg.HTTPAddr,
|
||||
Handler: srv.Handler(),
|
||||
}
|
||||
go func() {
|
||||
svc := platform.ServiceName("evobgp-api")
|
||||
log.Printf("%s listening on %s", svc, cfg.HTTPAddr)
|
||||
log.Printf("bundle signing public key (base64, set on evobgp-node): %s", srv.BundlePublicKeyBase64())
|
||||
if opts.SeedDemo {
|
||||
tid, mCDN, mIP, rev, sp := srv.Store().DemoIDs()
|
||||
log.Printf("demo tenant=%s module_cdn=%s module_ip_ranges=%s revision=%s speaker=%s", tid, mCDN, mIP, rev, sp)
|
||||
log.Printf("example: EVOBGP_API_KEYS=op|%s|operator,node|%s|node", tid, tid)
|
||||
log.Printf("with EVOBGP_DEV_INSECURE=1 use Authorization: Bearer dev (operator, demo tenant only)")
|
||||
}
|
||||
if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
if err := httpSrv.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("HTTP shutdown: %v", err)
|
||||
}
|
||||
log.Printf("%s stopped", platform.ServiceName("evobgp-api"))
|
||||
}
|
||||
|
||||
func startBirdMetricsPoller() {
|
||||
sock := strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_SOCKET"))
|
||||
if sock == "" {
|
||||
return
|
||||
}
|
||||
interval := 30 * time.Second
|
||||
if d, err := time.ParseDuration(strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_INTERVAL"))); err == nil && d > 0 {
|
||||
interval = d
|
||||
}
|
||||
bin := strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_BIN"))
|
||||
observability.StartBirdProtocolsPoller(sock, bin, interval,
|
||||
func(ctx context.Context, socket, birdcBin string) (string, error) {
|
||||
return birdfmt.ShowProtocols(ctx, socket, birdcBin)
|
||||
},
|
||||
birdfmt.CountEstablishedBGPSessions,
|
||||
)
|
||||
log.Printf("birdc protocols poller enabled (socket=%s interval=%s)", sock, interval)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"evobgp/internal/config"
|
||||
"evobgp/internal/deploy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
name := cfg.ServiceName
|
||||
if name == "" {
|
||||
name = "evobgp-deploy"
|
||||
}
|
||||
log.Printf("%s starting (reference profile worker)", name)
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
deploy.Run(ctx)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"evobgp/internal/config"
|
||||
"evobgp/internal/ingest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
name := cfg.ServiceName
|
||||
if name == "" {
|
||||
name = "evobgp-ingest"
|
||||
}
|
||||
log.Printf("%s starting (reference profile worker)", name)
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
ingest.Run(ctx)
|
||||
}
|
||||
|
||||
+238
-1
@@ -1,3 +1,240 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"evobgp/internal/birdfmt"
|
||||
"evobgp/internal/bundle"
|
||||
"evobgp/internal/signing"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
switch os.Args[1] {
|
||||
case "pull-bundle":
|
||||
os.Exit(cmdPullBundle(os.Args[2:]))
|
||||
case "verify-bundle":
|
||||
os.Exit(cmdVerifyBundle(os.Args[2:]))
|
||||
case "apply-bundle":
|
||||
os.Exit(cmdApplyBundle(os.Args[2:]))
|
||||
default:
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, `Usage:
|
||||
%s pull-bundle -base-url URL -token TOKEN -speaker-id ID [-revision-id ID] [-o path]
|
||||
%s verify-bundle -f bundle.tar.gz (-pubkey-base64 B64 | -pubkey-hex HEX)
|
||||
%s apply-bundle -f bundle.tar.gz -extract-dir DIR (-pubkey-base64 B64 | -pubkey-hex HEX)
|
||||
[-bird PATH] [-birdc PATH] [-socket PATH] [-timeout DURATION]
|
||||
|
||||
apply-bundle verifies, extracts, runs bird -p on main bird.conf, then birdc configure.
|
||||
`, os.Args[0], os.Args[0], os.Args[0])
|
||||
}
|
||||
|
||||
func cmdPullBundle(args []string) int {
|
||||
fs := flag.NewFlagSet("pull-bundle", flag.ExitOnError)
|
||||
base := fs.String("base-url", "", "control plane base URL, e.g. http://localhost:8080")
|
||||
token := fs.String("token", "", "Bearer token (node role)")
|
||||
speaker := fs.String("speaker-id", "", "bgp_speaker id")
|
||||
revision := fs.String("revision-id", "", "revision to fetch (empty = latest pointer)")
|
||||
out := fs.String("o", "bundle.tar.gz", "output file")
|
||||
_ = fs.Parse(args)
|
||||
|
||||
if strings.TrimSpace(*base) == "" || *token == "" || *speaker == "" {
|
||||
fmt.Fprintln(os.Stderr, "pull-bundle: -base-url, -token, -speaker-id are required")
|
||||
return 2
|
||||
}
|
||||
rev := strings.TrimSpace(*revision)
|
||||
if rev == "" {
|
||||
var err error
|
||||
rev, err = fetchLatestRevision(*base, *token, *speaker)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
body, err := fetchBundle(*base, *token, *speaker, rev)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
if err := os.WriteFile(*out, body, 0o644); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "wrote %s (revision %s)\n", *out, rev)
|
||||
return 0
|
||||
}
|
||||
|
||||
func fetchLatestRevision(base, token, speaker string) (string, error) {
|
||||
u := strings.TrimRight(base, "/") + "/v1/speakers/" + speaker + "/revisions/latest"
|
||||
req, err := http.NewRequest(http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
return "", fmt.Errorf("latest revision: %s: %s", resp.Status, strings.TrimSpace(string(b)))
|
||||
}
|
||||
var out struct {
|
||||
RevisionID string `json:"revision_id"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if out.RevisionID == "" {
|
||||
return "", fmt.Errorf("empty revision_id in response")
|
||||
}
|
||||
return out.RevisionID, nil
|
||||
}
|
||||
|
||||
func fetchBundle(base, token, speaker, revision string) ([]byte, error) {
|
||||
u := strings.TrimRight(base, "/") + "/v1/speakers/" + speaker + "/bundle/" + revision
|
||||
req, err := http.NewRequest(http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
return nil, fmt.Errorf("bundle: %s: %s", resp.Status, strings.TrimSpace(string(b)))
|
||||
}
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func loadPubKey(pubB64, pubHex string) (ed25519.PublicKey, error) {
|
||||
switch {
|
||||
case strings.TrimSpace(pubB64) != "":
|
||||
raw, err := base64.StdEncoding.DecodeString(strings.TrimSpace(pubB64))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(raw) != ed25519.PublicKeySize {
|
||||
return nil, fmt.Errorf("pubkey-base64 must decode to %d bytes", ed25519.PublicKeySize)
|
||||
}
|
||||
return ed25519.PublicKey(raw), nil
|
||||
case strings.TrimSpace(pubHex) != "":
|
||||
return bundle.ParsePublicKeyHex(pubHex)
|
||||
default:
|
||||
return nil, fmt.Errorf("public key required")
|
||||
}
|
||||
}
|
||||
|
||||
func cmdVerifyBundle(args []string) int {
|
||||
fs := flag.NewFlagSet("verify-bundle", flag.ExitOnError)
|
||||
path := fs.String("f", "", "path to bundle.tar.gz")
|
||||
pubB64 := fs.String("pubkey-base64", "", "Ed25519 public key (base64)")
|
||||
pubHex := fs.String("pubkey-hex", "", "Ed25519 public key (64 hex chars)")
|
||||
_ = fs.Parse(args)
|
||||
|
||||
if *path == "" {
|
||||
fmt.Fprintln(os.Stderr, "verify-bundle: -f required")
|
||||
return 2
|
||||
}
|
||||
pub, err := loadPubKey(*pubB64, *pubHex)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 2
|
||||
}
|
||||
raw, err := os.ReadFile(*path)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
v, err := signing.VerifyGzippedTar(raw, pub)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "ok: revision %s, %d payload files\n", v.Manifest.RevisionID, len(v.Files))
|
||||
return 0
|
||||
}
|
||||
|
||||
func cmdApplyBundle(args []string) int {
|
||||
fs := flag.NewFlagSet("apply-bundle", flag.ExitOnError)
|
||||
path := fs.String("f", "", "path to bundle.tar.gz")
|
||||
dir := fs.String("extract-dir", "", "directory to extract into")
|
||||
pubB64 := fs.String("pubkey-base64", "", "Ed25519 public key (base64)")
|
||||
pubHex := fs.String("pubkey-hex", "", "Ed25519 public key (64 hex chars)")
|
||||
bird := fs.String("bird", "", "bird binary (default PATH)")
|
||||
birdc := fs.String("birdc", "", "birdc binary (default PATH)")
|
||||
socket := fs.String("socket", "", "birdc -s socket path")
|
||||
timeout := fs.Duration("timeout", 30*time.Second, "timeout for bird/birdc")
|
||||
_ = fs.Parse(args)
|
||||
|
||||
if *path == "" || *dir == "" {
|
||||
fmt.Fprintln(os.Stderr, "apply-bundle: -f and -extract-dir required")
|
||||
return 2
|
||||
}
|
||||
pub, err := loadPubKey(*pubB64, *pubHex)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 2
|
||||
}
|
||||
raw, err := os.ReadFile(*path)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
v, err := signing.VerifyGzippedTar(raw, pub)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
root := filepath.Clean(*dir)
|
||||
if err := os.MkdirAll(root, 0o755); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
if err := bundle.WriteExtractedFiles(root, v); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
mainRel := v.FindMainBirdConf()
|
||||
if mainRel == "" {
|
||||
fmt.Fprintln(os.Stderr, "bundle has no bird.conf path in manifest")
|
||||
return 1
|
||||
}
|
||||
mainPath := filepath.Join(root, filepath.FromSlash(strings.TrimPrefix(mainRel, "/")))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
|
||||
defer cancel()
|
||||
ctl := &birdfmt.BirdCtl{Bird: *bird, Birdc: *birdc, Socket: *socket}
|
||||
if err := ctl.ParseCheck(ctx, mainPath); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
if err := ctl.Configure(ctx); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "applied revision %s (main config %s)\n", v.Manifest.RevisionID, mainPath)
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"evobgp/internal/config"
|
||||
"evobgp/internal/render"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
name := cfg.ServiceName
|
||||
if name == "" {
|
||||
name = "evobgp-render"
|
||||
}
|
||||
log.Printf("%s starting (reference profile worker)", name)
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
render.Run(ctx)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"evobgp/internal/config"
|
||||
"evobgp/internal/scheduler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
name := cfg.ServiceName
|
||||
if name == "" {
|
||||
name = "evobgp-scheduler"
|
||||
}
|
||||
log.Printf("%s starting (reference profile worker)", name)
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
scheduler.Run(ctx)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user