argo-cd/cmpserver/server.go

135 lines
4.4 KiB
Go
Raw Normal View History

package cmpserver
import (
"context"
"fmt"
"net"
"os"
"os/signal"
"syscall"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/reflection"
"github.com/argoproj/argo-cd/v3/cmpserver/apiclient"
"github.com/argoproj/argo-cd/v3/cmpserver/plugin"
"github.com/argoproj/argo-cd/v3/common"
versionpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/version"
"github.com/argoproj/argo-cd/v3/server/version"
"github.com/argoproj/argo-cd/v3/util/errors"
grpc_util "github.com/argoproj/argo-cd/v3/util/grpc"
)
// ArgoCDCMPServer is the config management plugin server implementation
type ArgoCDCMPServer struct {
opts []grpc.ServerOption
initConstants plugin.CMPServerInitConstants
stopCh chan os.Signal
doneCh chan any
sig os.Signal
}
// NewServer returns a new instance of the Argo CD config management plugin server
func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, error) {
var serverMetricsOptions []grpc_prometheus.ServerMetricsOption
if os.Getenv(common.EnvEnableGRPCTimeHistogramEnv) == "true" {
serverMetricsOptions = append(serverMetricsOptions, grpc_prometheus.WithServerHandlingTimeHistogram())
}
serverMetrics := grpc_prometheus.NewServerMetrics(serverMetricsOptions...)
reg := prometheus.NewRegistry()
reg.MustRegister(serverMetrics)
serverLog := log.NewEntry(log.StandardLogger())
streamInterceptors := []grpc.StreamServerInterceptor{
logging.StreamServerInterceptor(grpc_util.InterceptorLogger(serverLog)),
serverMetrics.StreamServerInterceptor(),
recovery.StreamServerInterceptor(recovery.WithRecoveryHandler(grpc_util.LoggerRecoveryHandler(serverLog))),
}
unaryInterceptors := []grpc.UnaryServerInterceptor{
logging.UnaryServerInterceptor(grpc_util.InterceptorLogger(serverLog)),
serverMetrics.UnaryServerInterceptor(),
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(grpc_util.LoggerRecoveryHandler(serverLog))),
}
serverOpts := []grpc.ServerOption{
grpc.ChainUnaryInterceptor(unaryInterceptors...),
grpc.ChainStreamInterceptor(streamInterceptors...),
grpc.MaxRecvMsgSize(apiclient.MaxGRPCMessageSize),
grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize),
grpc.KeepaliveEnforcementPolicy(
keepalive.EnforcementPolicy{
MinTime: common.GetGRPCKeepAliveEnforcementMinimum(),
},
),
grpc.StatsHandler(otelgrpc.NewServerHandler()),
}
return &ArgoCDCMPServer{
opts: serverOpts,
stopCh: make(chan os.Signal),
doneCh: make(chan any),
initConstants: initConstants,
}, nil
}
func (a *ArgoCDCMPServer) Run() {
config := a.initConstants.PluginConfig
// Listen on the socket address
_ = os.Remove(config.Address())
lc := &net.ListenConfig{}
listener, err := lc.Listen(context.Background(), "unix", config.Address())
errors.CheckError(err)
log.Infof("argocd-cmp-server %s serving on %s", common.GetVersion(), listener.Addr())
signal.Notify(a.stopCh, syscall.SIGINT, syscall.SIGTERM)
go a.Shutdown(config.Address())
grpcServer, err := a.CreateGRPC()
errors.CheckError(err)
err = grpcServer.Serve(listener)
errors.CheckError(err)
if a.sig != nil {
<-a.doneCh
}
}
// CreateGRPC creates new configured grpc server
func (a *ArgoCDCMPServer) CreateGRPC() (*grpc.Server, error) {
server := grpc.NewServer(a.opts...)
versionpkg.RegisterVersionServiceServer(server, version.NewServer(nil, func() (bool, error) {
return true, nil
}))
pluginService := plugin.NewService(a.initConstants)
feat: parameterized config management plugins (#9135) (#9216) * feat: parameterized CMPs Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * values types for parameters Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Add types for CMP announcement Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Reorg Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * finish type Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * First pass at working GetParametersAnnouncement Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Typos Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Make all fields optional Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Make sure response makes it to repo server Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Refactor for testing Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * lint Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * send build env to param announcement gen Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * test parameter announcement Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * environ tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Rename workdir to app dir Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * handle empty command, start ui work (#11) * Add types for CMP announcement Signed-off-by: zachaller <zachaller@hotmail.com> * Reorg Signed-off-by: zachaller <zachaller@hotmail.com> * finish type Signed-off-by: zachaller <zachaller@hotmail.com> * First pass at working GetParametersAnnouncement Signed-off-by: zachaller <zachaller@hotmail.com> * Typos Signed-off-by: zachaller <zachaller@hotmail.com> * Make all fields optional Signed-off-by: zachaller <zachaller@hotmail.com> * Make sure response makes it to repo server Signed-off-by: zachaller <zachaller@hotmail.com> * Refactor for testing Signed-off-by: zachaller <zachaller@hotmail.com> * values types for parameters Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * lint Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * send build env to param announcement gen Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * test parameter announcement * tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * environ tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Rename workdir to app dir Signed-off-by: zachaller <zachaller@hotmail.com> * handle empty command, start ui work Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix order Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix map merging, make params read-only Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> Co-authored-by: zachaller <zachaller@hotmail.com> * Add helm PoC example plugin Signed-off-by: zachaller <zachaller@hotmail.com> * example as kustomize overlay Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * Parameterized cmps docs (#12) * use printf instead of echo Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * docs Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * test for temp dir cleanup Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * handle empty params Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * handle empty values Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * consolidate types Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * docs Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * docs Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * remove duplicate info Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * add warning about param announcements vs param values Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * tests (#13) Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix types Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix test Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix codegen Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix codegen Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * revert test hack Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * docs correction Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix indentation Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix spacing Signed-off-by: CI <michael@crenshaw.dev> * move util function to util file and add test Signed-off-by: CI <michael@crenshaw.dev> * wrap error Signed-off-by: CI <michael@crenshaw.dev> * correct version number Signed-off-by: CI <michael@crenshaw.dev> * document necessity of collectionType param Signed-off-by: CI <michael@crenshaw.dev> * remove part of error message that's not useful (dir name is now randomized) Signed-off-by: CI <michael@crenshaw.dev> * fix things so that they are not broken Signed-off-by: CI <michael@crenshaw.dev> * don't close file before caller gets a chance to use it Signed-off-by: CI <michael@crenshaw.dev> * codegen Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * fix test Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * comments Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * fix test Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * DON'T PANIC Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> Signed-off-by: zachaller <zachaller@hotmail.com> Signed-off-by: CI <michael@crenshaw.dev> Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> Co-authored-by: zachaller <zachaller@hotmail.com>
2022-11-29 18:08:32 +00:00
err := pluginService.Init(common.GetCMPWorkDir())
if err != nil {
return nil, fmt.Errorf("error initializing plugin service: %w", err)
}
apiclient.RegisterConfigManagementPluginServiceServer(server, pluginService)
healthService := health.NewServer()
grpc_health_v1.RegisterHealthServer(server, healthService)
// Register reflection service on gRPC server.
reflection.Register(server)
return server, nil
}
func (a *ArgoCDCMPServer) Shutdown(address string) {
defer signal.Stop(a.stopCh)
a.sig = <-a.stopCh
_ = os.Remove(address)
close(a.doneCh)
}