github.com/argoproj/argo-cd/v3@v3.2.1/cmpserver/server.go (about) 1 package cmpserver 2 3 import ( 4 "fmt" 5 "net" 6 "os" 7 "os/signal" 8 "syscall" 9 10 grpc_prometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" 11 "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" 12 "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery" 13 "github.com/prometheus/client_golang/prometheus" 14 log "github.com/sirupsen/logrus" 15 "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" 16 "google.golang.org/grpc" 17 "google.golang.org/grpc/health" 18 "google.golang.org/grpc/health/grpc_health_v1" 19 "google.golang.org/grpc/keepalive" 20 "google.golang.org/grpc/reflection" 21 22 "github.com/argoproj/argo-cd/v3/cmpserver/apiclient" 23 "github.com/argoproj/argo-cd/v3/cmpserver/plugin" 24 "github.com/argoproj/argo-cd/v3/common" 25 versionpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/version" 26 "github.com/argoproj/argo-cd/v3/server/version" 27 "github.com/argoproj/argo-cd/v3/util/errors" 28 grpc_util "github.com/argoproj/argo-cd/v3/util/grpc" 29 ) 30 31 // ArgoCDCMPServer is the config management plugin server implementation 32 type ArgoCDCMPServer struct { 33 opts []grpc.ServerOption 34 initConstants plugin.CMPServerInitConstants 35 stopCh chan os.Signal 36 doneCh chan any 37 sig os.Signal 38 } 39 40 // NewServer returns a new instance of the Argo CD config management plugin server 41 func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, error) { 42 var serverMetricsOptions []grpc_prometheus.ServerMetricsOption 43 if os.Getenv(common.EnvEnableGRPCTimeHistogramEnv) == "true" { 44 serverMetricsOptions = append(serverMetricsOptions, grpc_prometheus.WithServerHandlingTimeHistogram()) 45 } 46 serverMetrics := grpc_prometheus.NewServerMetrics(serverMetricsOptions...) 47 reg := prometheus.NewRegistry() 48 reg.MustRegister(serverMetrics) 49 50 serverLog := log.NewEntry(log.StandardLogger()) 51 streamInterceptors := []grpc.StreamServerInterceptor{ 52 logging.StreamServerInterceptor(grpc_util.InterceptorLogger(serverLog)), 53 serverMetrics.StreamServerInterceptor(), 54 recovery.StreamServerInterceptor(recovery.WithRecoveryHandler(grpc_util.LoggerRecoveryHandler(serverLog))), 55 } 56 unaryInterceptors := []grpc.UnaryServerInterceptor{ 57 logging.UnaryServerInterceptor(grpc_util.InterceptorLogger(serverLog)), 58 serverMetrics.UnaryServerInterceptor(), 59 recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(grpc_util.LoggerRecoveryHandler(serverLog))), 60 } 61 62 serverOpts := []grpc.ServerOption{ 63 grpc.ChainUnaryInterceptor(unaryInterceptors...), 64 grpc.ChainStreamInterceptor(streamInterceptors...), 65 grpc.MaxRecvMsgSize(apiclient.MaxGRPCMessageSize), 66 grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize), 67 grpc.KeepaliveEnforcementPolicy( 68 keepalive.EnforcementPolicy{ 69 MinTime: common.GetGRPCKeepAliveEnforcementMinimum(), 70 }, 71 ), 72 grpc.StatsHandler(otelgrpc.NewServerHandler()), 73 } 74 75 return &ArgoCDCMPServer{ 76 opts: serverOpts, 77 stopCh: make(chan os.Signal), 78 doneCh: make(chan any), 79 initConstants: initConstants, 80 }, nil 81 } 82 83 func (a *ArgoCDCMPServer) Run() { 84 config := a.initConstants.PluginConfig 85 86 // Listen on the socket address 87 _ = os.Remove(config.Address()) 88 listener, err := net.Listen("unix", config.Address()) 89 errors.CheckError(err) 90 log.Infof("argocd-cmp-server %s serving on %s", common.GetVersion(), listener.Addr()) 91 92 signal.Notify(a.stopCh, syscall.SIGINT, syscall.SIGTERM) 93 go a.Shutdown(config.Address()) 94 95 grpcServer, err := a.CreateGRPC() 96 errors.CheckError(err) 97 err = grpcServer.Serve(listener) 98 errors.CheckError(err) 99 100 if a.sig != nil { 101 <-a.doneCh 102 } 103 } 104 105 // CreateGRPC creates new configured grpc server 106 func (a *ArgoCDCMPServer) CreateGRPC() (*grpc.Server, error) { 107 server := grpc.NewServer(a.opts...) 108 versionpkg.RegisterVersionServiceServer(server, version.NewServer(nil, func() (bool, error) { 109 return true, nil 110 })) 111 pluginService := plugin.NewService(a.initConstants) 112 err := pluginService.Init(common.GetCMPWorkDir()) 113 if err != nil { 114 return nil, fmt.Errorf("error initializing plugin service: %w", err) 115 } 116 apiclient.RegisterConfigManagementPluginServiceServer(server, pluginService) 117 118 healthService := health.NewServer() 119 grpc_health_v1.RegisterHealthServer(server, healthService) 120 121 // Register reflection service on gRPC server. 122 reflection.Register(server) 123 124 return server, nil 125 } 126 127 func (a *ArgoCDCMPServer) Shutdown(address string) { 128 defer signal.Stop(a.stopCh) 129 a.sig = <-a.stopCh 130 _ = os.Remove(address) 131 close(a.doneCh) 132 }