Fix .gitignore excluding cmd/provisioning directory
The pattern `provisioning` matched both the binary and the directory. Use `/provisioning` to only match at the repo root. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# Binary
|
# Binary
|
||||||
provisioning
|
/provisioning
|
||||||
provisioning.exe
|
/provisioning.exe
|
||||||
|
|
||||||
# Runtime data
|
# Runtime data
|
||||||
data/
|
data/
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"provisioning/internal/api"
|
||||||
|
"provisioning/internal/config"
|
||||||
|
"provisioning/internal/db"
|
||||||
|
"provisioning/internal/events"
|
||||||
|
"provisioning/internal/httpserver"
|
||||||
|
"provisioning/internal/infra"
|
||||||
|
"provisioning/internal/orchestrator"
|
||||||
|
"provisioning/internal/pxe"
|
||||||
|
"provisioning/internal/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfgPath := flag.String("config", "provisioning.yaml", "path to config file")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
cfg, err := config.Load(*cfgPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
serverTypes, err := config.LoadServerTypes(cfg.ServerTypePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("server types: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(cfg.Database.Path), 0o755); err != nil {
|
||||||
|
log.Fatalf("create db dir: %v", err)
|
||||||
|
}
|
||||||
|
database, err := db.Open(cfg.Database.Path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("database: %v", err)
|
||||||
|
}
|
||||||
|
defer database.Close()
|
||||||
|
|
||||||
|
hosts := &store.Hosts{DB: database}
|
||||||
|
ops := &store.Operations{DB: database}
|
||||||
|
locks := &store.Locks{DB: database, TTLMinutes: cfg.Locks.TTLMinutes}
|
||||||
|
images := &store.Images{DB: database}
|
||||||
|
|
||||||
|
hub := events.NewHub()
|
||||||
|
|
||||||
|
runner := &orchestrator.Runner{
|
||||||
|
Hosts: hosts,
|
||||||
|
Ops: ops,
|
||||||
|
Locks: locks,
|
||||||
|
Hub: hub,
|
||||||
|
}
|
||||||
|
|
||||||
|
pxeSupervisor := pxe.NewSupervisor(pxe.SupervisorConfig{
|
||||||
|
Enabled: cfg.PXE.Enabled,
|
||||||
|
Interface: cfg.PXE.Interface,
|
||||||
|
Subnet: cfg.PXE.Subnet,
|
||||||
|
RuntimeDir: cfg.PXE.RuntimeDir,
|
||||||
|
TFTPRoot: cfg.PXE.TFTPRoot,
|
||||||
|
DnsmasqBin: cfg.PXE.DnsmasqBin,
|
||||||
|
PublicURL: cfg.Server.PublicURL,
|
||||||
|
})
|
||||||
|
|
||||||
|
var infraClient *infra.Client
|
||||||
|
if cfg.Infrastructure.BaseURL != "" {
|
||||||
|
infraClient = infra.NewClient(cfg.Infrastructure.BaseURL, time.Duration(cfg.Infrastructure.TimeoutSec)*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterJoiner := &orchestrator.ClusterJoiner{
|
||||||
|
ExistingNode: cfg.Proxmox.ExistingNode,
|
||||||
|
ClusterName: cfg.Proxmox.ClusterName,
|
||||||
|
JoinFingerprint: cfg.Proxmox.JoinFingerprint,
|
||||||
|
}
|
||||||
|
|
||||||
|
hostOrch := &orchestrator.HostOrchestrator{
|
||||||
|
Runner: runner,
|
||||||
|
Hosts: hosts,
|
||||||
|
Ops: ops,
|
||||||
|
Locks: locks,
|
||||||
|
Cluster: clusterJoiner,
|
||||||
|
InfraClient: infraClient,
|
||||||
|
Config: cfg,
|
||||||
|
ServerTypes: serverTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
hostAPI := &api.HostAPI{
|
||||||
|
Hosts: hosts,
|
||||||
|
Ops: ops,
|
||||||
|
Locks: locks,
|
||||||
|
Images: images,
|
||||||
|
Runner: runner,
|
||||||
|
Orchestrator: hostOrch,
|
||||||
|
PXE: pxeSupervisor,
|
||||||
|
Config: cfg,
|
||||||
|
ServerTypes: serverTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
bootAPI := &api.BootAPI{
|
||||||
|
Hosts: hosts,
|
||||||
|
Images: images,
|
||||||
|
Runner: runner,
|
||||||
|
Orchestrator: hostOrch,
|
||||||
|
Config: cfg,
|
||||||
|
ServerTypes: serverTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
ui := &api.UI{
|
||||||
|
Hosts: hosts,
|
||||||
|
Ops: ops,
|
||||||
|
Locks: locks,
|
||||||
|
Images: images,
|
||||||
|
Runner: runner,
|
||||||
|
Orchestrator: hostOrch,
|
||||||
|
Hub: hub,
|
||||||
|
PXE: pxeSupervisor,
|
||||||
|
Config: cfg,
|
||||||
|
ServerTypes: serverTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
router := httpserver.NewRouter(httpserver.Deps{
|
||||||
|
HostAPI: hostAPI,
|
||||||
|
BootAPI: bootAPI,
|
||||||
|
UI: ui,
|
||||||
|
Hub: hub,
|
||||||
|
})
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: cfg.Server.Bind,
|
||||||
|
Handler: router,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start PXE
|
||||||
|
allHosts, _ := hosts.List(context.Background())
|
||||||
|
if err := pxeSupervisor.Start(context.Background(), allHosts); err != nil {
|
||||||
|
log.Printf("pxe: failed to start: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch server types for hot reload
|
||||||
|
stop := make(chan struct{})
|
||||||
|
serverTypes.Watch(stop)
|
||||||
|
|
||||||
|
// Start HTTP server
|
||||||
|
go func() {
|
||||||
|
log.Printf("listening on %s", cfg.Server.Bind)
|
||||||
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
log.Fatalf("http: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Graceful shutdown
|
||||||
|
shutdown := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)
|
||||||
|
<-shutdown
|
||||||
|
|
||||||
|
log.Printf("shutting down")
|
||||||
|
close(stop)
|
||||||
|
_ = pxeSupervisor.Shutdown()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := srv.Shutdown(ctx); err != nil {
|
||||||
|
log.Printf("http shutdown: %v", err)
|
||||||
|
}
|
||||||
|
_ = hub.Shutdown(ctx)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user