Files
compute-blade-agent/cmd/agent/main.go
Cedric Kienzler 631ddfedd4 chore: update repository references from uptime-industries to computeblade-community (#70)
* chore: update repository references from uptime-industries to compute-blade-community

chore: update repository references from uptime-industries to compute-blade-community for consistency and clarity across all files
fix: update links in CHANGELOG.md and README.md to point to the new repository location for accurate documentation
fix: update Dockerfile and systemd service file to reflect the new repository URL for proper source tracking
refactor: change import paths in Go files to use the new repository name for correct package referencing

* chore: Add CODEOWNERS

* feat: add auto-labeling

---------

Co-authored-by: Cedric Kienzler <cedric@specht-labs.de>
2025-06-06 14:40:06 +02:00

182 lines
4.8 KiB
Go

package main
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/pprof"
"os"
"os/signal"
"strings"
"sync"
"syscall"
"time"
"github.com/compute-blade-community/compute-blade-agent/internal/agent"
"github.com/compute-blade-community/compute-blade-agent/internal/api"
"github.com/compute-blade-community/compute-blade-agent/pkg/log"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"go.uber.org/zap"
)
var (
Version string
Commit string
Date string
)
var debug = pflag.BoolP("debug", "v", false, "enable verbose logging")
func main() {
pflag.Parse()
// Setup configuration
viper.SetEnvPrefix("BLADE")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("/etc/compute-blade-agent")
// Load potential file configs
if err := viper.ReadInConfig(); err != nil {
panic(err)
}
// setup logger
var baseLogger *zap.Logger
if debug != nil && *debug {
baseLogger = zap.Must(zap.NewDevelopment())
} else {
baseLogger = zap.Must(zap.NewProduction())
}
zapLogger := baseLogger.With(zap.String("app", "compute-blade-agent"))
defer func() {
_ = zapLogger.Sync()
}()
_ = zap.ReplaceGlobals(zapLogger.With(zap.String("scope", "global")))
baseCtx := log.IntoContext(context.Background(), zapLogger)
ctx, cancelCtx := context.WithCancelCause(baseCtx)
defer cancelCtx(context.Canceled)
// load configuration
var cbAgentConfig agent.ComputeBladeAgentConfig
if err := viper.Unmarshal(&cbAgentConfig); err != nil {
cancelCtx(err)
log.FromContext(ctx).Fatal("Failed to load configuration", zap.Error(err))
}
// setup stop signal handlers
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
select {
// Wait for context cancel
case <-ctx.Done():
// Wait for signal
case sig := <-sigs:
switch sig {
case syscall.SIGTERM:
fallthrough
case syscall.SIGINT:
fallthrough
case syscall.SIGQUIT:
// On terminate signal, cancel context causing the program to terminate
cancelCtx(fmt.Errorf("signal %s received", sig))
default:
log.FromContext(ctx).Warn("Received unknown signal", zap.String("signal", sig.String()))
}
}
}()
log.FromContext(ctx).Info("Bootstrapping compute-blade-agent", zap.String("version", Version), zap.String("commit", Commit), zap.String("date", Date))
computebladeAgent, err := agent.NewComputeBladeAgent(ctx, cbAgentConfig)
if err != nil {
cancelCtx(err)
log.FromContext(ctx).Fatal("Failed to create agent", zap.Error(err))
}
// Run agent
computebladeAgent.RunAsync(ctx, cancelCtx)
// Setup GRPC server
grpcServer := api.NewGrpcApiServer(ctx,
api.WithComputeBladeAgent(computebladeAgent),
api.WithAuthentication(cbAgentConfig.Listen.GrpcAuthenticated),
api.WithListenAddr(cbAgentConfig.Listen.Grpc),
api.WithListenMode(cbAgentConfig.Listen.GrpcListenMode),
)
// Run gRPC API
grpcServer.ServeAsync(ctx, cancelCtx)
// setup prometheus endpoint
promServer := runPrometheusEndpoint(ctx, cancelCtx, &cbAgentConfig.Listen)
// Wait for done
<-ctx.Done()
var wg sync.WaitGroup
// Shut-Down GRPC Server
wg.Add(1)
go func() {
defer wg.Done()
log.FromContext(ctx).Info("Shutting down grpc server")
grpcServer.GracefulStop()
}()
// Shut-Down Prometheus Endpoint
wg.Add(1)
go func() {
defer wg.Done()
shutdownCtx, shutdownCtxCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdownCtxCancel()
if err := promServer.Shutdown(shutdownCtx); err != nil {
log.FromContext(ctx).Error("Failed to shutdown prometheus/pprof server", zap.Error(err))
}
}()
wg.Wait()
// Wait for context cancel
if err := ctx.Err(); !errors.Is(err, context.Canceled) {
log.FromContext(ctx).Fatal("Exiting", zap.Error(err))
} else {
log.FromContext(ctx).Info("Exiting")
}
}
func runPrometheusEndpoint(ctx context.Context, cancel context.CancelCauseFunc, apiConfig *api.Config) *http.Server {
instrumentationHandler := http.NewServeMux()
instrumentationHandler.Handle("/metrics", promhttp.Handler())
instrumentationHandler.HandleFunc("/debug/pprof/", pprof.Index)
instrumentationHandler.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
instrumentationHandler.HandleFunc("/debug/pprof/profile", pprof.Profile)
instrumentationHandler.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
instrumentationHandler.HandleFunc("/debug/pprof/trace", pprof.Trace)
server := &http.Server{Addr: apiConfig.Metrics, Handler: instrumentationHandler}
// Run Prometheus Endpoint
go func() {
err := server.ListenAndServe()
if err != nil && !errors.Is(err, http.ErrServerClosed) {
log.FromContext(ctx).Error("Failed to start prometheus/pprof server", zap.Error(err))
cancel(err)
}
}()
return server
}