diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ebb954ebe41430..9300edae64d58c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,7 +6,6 @@ /components/blobserve @gitpod-io/engineering-workspace /components/common-go @gitpod-io/engineering-workspace @gitpod-io/engineering-webapp -/components/common-go/baseserver @gitpod-io/engineering-webapp /components/content-service-api @csweichel @geropl /components/content-service @gitpod-io/engineering-workspace /components/dashboard @gitpod-io/engineering-webapp diff --git a/components/common-go/baseserver/config.go b/components/common-go/baseserver/config.go new file mode 100644 index 00000000000000..6258320b18749a --- /dev/null +++ b/components/common-go/baseserver/config.go @@ -0,0 +1,33 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package baseserver + +type Configuration struct { + Services ServicesConfiguration `json:"services" yaml:"services"` +} + +type ServicesConfiguration struct { + GRPC *ServerConfiguration `json:"grpc,omitempty" yaml:"grpc,omitempty"` + HTTP *ServerConfiguration `json:"http,omitempty" yaml:"http,omitempty"` +} + +type ServerConfiguration struct { + Address string `json:"address" yaml:"address"` + TLS *TLSConfiguration `json:"tls" yaml:"tls"` +} + +// GetAddress returns the configured address or an empty string of s is nil +func (s *ServerConfiguration) GetAddress() string { + if s == nil { + return "" + } + return s.Address +} + +type TLSConfiguration struct { + CAPath string `json:"caPath" yaml:"caPath"` + CertPath string `json:"certPath" yaml:"certPath"` + KeyPath string `json:"keyPath" yaml:"keyPath"` +} diff --git a/components/common-go/baseserver/options.go b/components/common-go/baseserver/options.go index c92c86b51845c7..812c3d32e732a0 100644 --- a/components/common-go/baseserver/options.go +++ b/components/common-go/baseserver/options.go @@ -7,29 +7,25 @@ package baseserver import ( "context" "fmt" + "time" + "github.com/gitpod-io/gitpod/common-go/log" "github.com/heptiolabs/healthcheck" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" "google.golang.org/grpc/health/grpc_health_v1" - "time" ) -type config struct { +type options struct { logger *logrus.Entry - // hostname is the hostname on which our servers will listen. - hostname string - // debugPort is the port we listen on for metrics, pprof, readiness and livenss checks - debugPort int - // grpcPort is the port we listen on for gRPC traffic - grpcPort int - // httpPort is the port we listen on for HTTP traffic - httpPort int + config *Configuration // closeTimeout is the amount we allow for the server to shut down cleanly closeTimeout time.Duration + underTest bool + // metricsRegistry configures the metrics registry to use for exporting metrics. When not set, the default prometheus registry is used. metricsRegistry *prometheus.Registry @@ -38,13 +34,16 @@ type config struct { grpcHealthCheck grpc_health_v1.HealthServer } -func defaultConfig() *config { - return &config{ - logger: log.New(), - hostname: "localhost", - httpPort: -1, // disabled by default - grpcPort: -1, // disabled by default - debugPort: 9500, +func defaultOptions() *options { + return &options{ + logger: log.New(), + config: &Configuration{ + Services: ServicesConfiguration{ + GRPC: nil, // disabled by default + HTTP: nil, // disabled by default + }, + }, + closeTimeout: 5 * time.Second, healthHandler: healthcheck.NewHandler(), metricsRegistry: prometheus.NewRegistry(), @@ -52,97 +51,94 @@ func defaultConfig() *config { } } -type Option func(cfg *config) error +type Option func(opts *options) error -func WithHostname(hostname string) Option { - return func(cfg *config) error { - cfg.hostname = hostname +// WithConfig uses a config struct to initialise the services +func WithConfig(config *Configuration) Option { + return func(opts *options) error { + opts.config = config return nil } } -// WithHTTPPort sets the port to use for an HTTP server. Setting WithHTTPPort also enables an HTTP server on the baseserver. -func WithHTTPPort(port int) Option { - return func(cfg *config) error { - cfg.httpPort = port +func WithUnderTest() Option { + return func(opts *options) error { + opts.underTest = true return nil } } -// WithGRPCPort sets the port to use for an HTTP server. Setting WithGRPCPort also enables a gRPC server on the baseserver. -func WithGRPCPort(port int) Option { - return func(cfg *config) error { - cfg.grpcPort = port +// WithHTTP configures and enables the HTTP server. +func WithHTTP(cfg *ServerConfiguration) Option { + return func(opts *options) error { + opts.config.Services.HTTP = cfg return nil } } -func WithDebugPort(port int) Option { - return func(cfg *config) error { - if port < 0 { - return fmt.Errorf("grpc port must not be negative, got: %d", port) - } - - cfg.debugPort = port +// WithGRPC configures and enables the GRPC server. +func WithGRPC(cfg *ServerConfiguration) Option { + return func(opts *options) error { + opts.config.Services.GRPC = cfg return nil } } func WithLogger(logger *logrus.Entry) Option { - return func(cfg *config) error { + return func(opts *options) error { if logger == nil { return fmt.Errorf("nil logger specified") } - cfg.logger = logger + opts.logger = logger return nil } } func WithCloseTimeout(d time.Duration) Option { - return func(cfg *config) error { - cfg.closeTimeout = d + return func(opts *options) error { + opts.closeTimeout = d return nil } } func WithMetricsRegistry(r *prometheus.Registry) Option { - return func(cfg *config) error { + return func(opts *options) error { if r == nil { return fmt.Errorf("nil prometheus registry received") } - cfg.metricsRegistry = r + opts.metricsRegistry = r return nil } } func WithHealthHandler(handler healthcheck.Handler) Option { - return func(cfg *config) error { + return func(opts *options) error { if handler == nil { return fmt.Errorf("nil healthcheck handler provided") } - cfg.healthHandler = handler + opts.healthHandler = handler return nil } } func WithGRPCHealthService(svc grpc_health_v1.HealthServer) Option { - return func(cfg *config) error { + return func(opts *options) error { if svc == nil { return fmt.Errorf("nil healthcheck handler provided") } - cfg.grpcHealthCheck = svc + opts.grpcHealthCheck = svc return nil } } -func evaluateOptions(cfg *config, opts ...Option) (*config, error) { +func evaluateOptions(cfg *options, opts ...Option) (*options, error) { for _, opt := range opts { if err := opt(cfg); err != nil { - return nil, fmt.Errorf("failed to evaluate config: %w", err) + return nil, fmt.Errorf("failed to evaluate options: %w", err) } } diff --git a/components/common-go/baseserver/options_test.go b/components/common-go/baseserver/options_test.go index b9e52707d12f82..3a63e930f40a25 100644 --- a/components/common-go/baseserver/options_test.go +++ b/components/common-go/baseserver/options_test.go @@ -5,105 +5,55 @@ package baseserver import ( + "testing" + "time" + "github.com/gitpod-io/gitpod/common-go/log" "github.com/heptiolabs/healthcheck" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" "google.golang.org/grpc/health/grpc_health_v1" - "testing" - "time" ) func TestOptions(t *testing.T) { logger := log.New() - httpPort := 8080 - grpcPort := 8081 - debugPort := 8082 timeout := 10 * time.Second - hostname := "another_hostname" registry := prometheus.NewRegistry() health := healthcheck.NewHandler() grpcHealthService := &grpc_health_v1.UnimplementedHealthServer{} + httpCfg := ServerConfiguration{Address: "localhost:8080"} + grpcCfg := ServerConfiguration{Address: "localhost:8081"} var opts = []Option{ - WithHostname(hostname), - WithDebugPort(debugPort), - WithHTTPPort(httpPort), - WithGRPCPort(grpcPort), + WithHTTP(&httpCfg), + WithGRPC(&grpcCfg), WithLogger(logger), WithCloseTimeout(timeout), WithMetricsRegistry(registry), WithHealthHandler(health), WithGRPCHealthService(grpcHealthService), } - cfg, err := evaluateOptions(defaultConfig(), opts...) + actual, err := evaluateOptions(defaultOptions(), opts...) require.NoError(t, err) - require.Equal(t, &config{ - logger: logger, - hostname: hostname, - grpcPort: grpcPort, - httpPort: httpPort, - debugPort: debugPort, + expected := &options{ + logger: logger, + config: &Configuration{ + Services: ServicesConfiguration{ + GRPC: &grpcCfg, + HTTP: &httpCfg, + }, + }, closeTimeout: timeout, metricsRegistry: registry, healthHandler: health, grpcHealthCheck: grpcHealthService, - }, cfg) -} - -func TestWithHTTPPort(t *testing.T) { - for _, scenario := range []struct { - Port int - Expected int - }{ - {Port: -1, Expected: -1}, - {Port: 0, Expected: 0}, - {Port: 9000, Expected: 9000}, - } { - cfg, err := evaluateOptions(defaultConfig(), WithHTTPPort(scenario.Port)) - require.NoError(t, err) - require.Equal(t, scenario.Expected, cfg.httpPort) } -} - -func TestWithGRPCPort(t *testing.T) { - for _, scenario := range []struct { - Port int - Expected int - }{ - {Port: -1, Expected: -1}, - {Port: 0, Expected: 0}, - {Port: 9000, Expected: 9000}, - } { - cfg, err := evaluateOptions(defaultConfig(), WithGRPCPort(scenario.Port)) - require.NoError(t, err) - require.Equal(t, scenario.Expected, cfg.grpcPort) - } -} -func TestWithDebugPort(t *testing.T) { - for _, scenario := range []struct { - Port int - - Errors bool - Expected int - }{ - {Port: -1, Errors: true}, - {Port: 0, Expected: 0}, - {Port: 9000, Expected: 9000}, - } { - cfg, err := evaluateOptions(defaultConfig(), WithDebugPort(scenario.Port)) - if scenario.Errors { - require.Error(t, err) - continue - } - - require.Equal(t, scenario.Expected, cfg.debugPort) - } + require.Equal(t, expected, actual) } func TestLogger_ErrorsWithNilLogger(t *testing.T) { - _, err := evaluateOptions(defaultConfig(), WithLogger(nil)) + _, err := evaluateOptions(defaultOptions(), WithLogger(nil)) require.Error(t, err) } diff --git a/components/common-go/baseserver/server.go b/components/common-go/baseserver/server.go index f8e393455af3b1..ead4077a57e1e2 100644 --- a/components/common-go/baseserver/server.go +++ b/components/common-go/baseserver/server.go @@ -7,49 +7,45 @@ package baseserver import ( "context" "fmt" - gitpod_grpc "github.com/gitpod-io/gitpod/common-go/grpc" + "net" + "net/http" + "os" + "os/signal" + "sync" + "syscall" + + common_grpc "github.com/gitpod-io/gitpod/common-go/grpc" + "github.com/gitpod-io/gitpod/common-go/log" "github.com/gitpod-io/gitpod/common-go/pprof" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/health/grpc_health_v1" - "net" - "net/http" - "os" - "os/signal" - "syscall" ) func New(name string, opts ...Option) (*Server, error) { - cfg, err := evaluateOptions(defaultConfig(), opts...) + options, err := evaluateOptions(defaultOptions(), opts...) if err != nil { return nil, fmt.Errorf("invalid config: %w", err) } server := &Server{ - Name: name, - cfg: cfg, + Name: name, + options: options, } + server.builtinServices = newBuiltinServices(server) - if initErr := server.initializeDebug(); initErr != nil { - return nil, fmt.Errorf("failed to initialize debug server: %w", initErr) - } - - if server.isHTTPEnabled() { - httpErr := server.initializeHTTP() - if httpErr != nil { - return nil, fmt.Errorf("failed to initialize http server: %w", httpErr) - } - } + server.httpMux = http.NewServeMux() + server.http = &http.Server{Handler: server.httpMux} - if server.isGRPCEnabled() { - grpcErr := server.initializeGRPC() - if grpcErr != nil { - return nil, fmt.Errorf("failed to initialize grpc server: %w", grpcErr) - } + err = server.initializeGRPC() + if err != nil { + return nil, fmt.Errorf("failed to initialize gRPC server: %w", err) } return server, nil @@ -75,11 +71,9 @@ type Server struct { // Name is the name of this server, used for logging context Name string - cfg *config + options *options - // debug is an HTTP server for debug endpoints - metrics, pprof, readiness & liveness. - debug *http.Server - debugListener net.Listener + builtinServices *builtinServices // http is an http Server, only used when port is specified in cfg http *http.Server @@ -92,69 +86,64 @@ type Server struct { // listening indicates the server is serving. When closed, the server is in the process of graceful termination. listening chan struct{} + closeOnce sync.Once +} + +func serveHTTP(cfg *ServerConfiguration, srv *http.Server, l net.Listener) (err error) { + if cfg.TLS == nil { + err = srv.Serve(l) + } else { + err = srv.ServeTLS(l, cfg.TLS.CertPath, cfg.TLS.KeyPath) + } + return } func (s *Server) ListenAndServe() error { var err error - s.debugListener, err = net.Listen("tcp", fmt.Sprintf(":%d", s.cfg.debugPort)) - if err != nil { - return fmt.Errorf("failed to acquire port %d", s.cfg.debugPort) - } - - if s.isGRPCEnabled() { - s.grpcListener, err = net.Listen("tcp", fmt.Sprintf(":%d", s.cfg.grpcPort)) + s.listening = make(chan struct{}) + defer func() { + err := s.Close() if err != nil { - return fmt.Errorf("failed to acquire port %d", s.cfg.grpcPort) + s.Logger().WithError(err).Errorf("cannot close gracefully") } - } + }() - if s.isHTTPEnabled() { - s.httpListener, err = net.Listen("tcp", fmt.Sprintf(":%d", s.cfg.httpPort)) + go func() { + err := s.builtinServices.ListenAndServe() if err != nil { - return fmt.Errorf("failed to acquire port %d", s.cfg.httpPort) + s.Logger().WithError(err).Errorf("builtin services encountered an error - closing remaining servers.") + s.Close() } - } - - errors := make(chan error) - defer close(errors) - s.listening = make(chan struct{}) - - // Always start the debug server, we should always have metrics and other debug information. - go func() { - s.Logger().WithField("protocol", "http").Infof("Serving debug server on %s", s.debugListener.Addr().String()) - serveErr := s.debug.Serve(s.debugListener) - if serveErr != nil { - if s.isClosing() { - return - } + }() - errors <- serveErr + if srv := s.options.config.Services.HTTP; srv != nil { + s.httpListener, err = net.Listen("tcp", srv.Address) + if err != nil { + return fmt.Errorf("failed to start HTTP server: %w", err) } - }() + s.http.Addr = srv.Address - if s.isGRPCEnabled() { go func() { - s.Logger().WithField("protocol", "grpc").Infof("Serving gRPC on %s", s.grpcListener.Addr().String()) - if serveErr := s.grpc.Serve(s.grpcListener); serveErr != nil { - if s.isClosing() { - return - } - - errors <- serveErr + err := serveHTTP(srv, s.http, s.httpListener) + if err != nil { + s.Logger().WithError(err).Errorf("HTTP server encountered an error - closing remaining servers.") + s.Close() } }() } - if s.isHTTPEnabled() { - go func() { - s.Logger().WithField("protocol", "http").Infof("Serving http on %s", s.httpListener.Addr().String()) - if serveErr := s.http.Serve(s.httpListener); serveErr != nil { - if s.isClosing() { - return - } + if srv := s.options.config.Services.GRPC; srv != nil { + s.grpcListener, err = net.Listen("tcp", srv.Address) + if err != nil { + return fmt.Errorf("failed to start gRPC server: %w", err) + } - errors <- serveErr + go func() { + err := s.grpc.Serve(s.grpcListener) + if err != nil { + s.Logger().WithError(err).Errorf("gRPC server encountered an error - closing remaining servers.") + s.Close() } }() } @@ -166,61 +155,23 @@ func (s *Server) ListenAndServe() error { select { case sig := <-signals: s.Logger().Infof("Received system signal %s, closing server.", sig.String()) - if closeErr := s.Close(); closeErr != nil { - s.Logger().WithError(closeErr).Error("Failed to close server.") - return closeErr - } - return nil - case serverErr := <-errors: - s.Logger().WithError(serverErr).Errorf("Server encountered an error. Closing remaining servers.") - if closeErr := s.Close(); closeErr != nil { - return fmt.Errorf("failed to close server after one of the servers errored: %w", closeErr) - } - - return serverErr } } func (s *Server) Close() error { - ctx, cancel := context.WithTimeout(context.Background(), s.cfg.closeTimeout) + ctx, cancel := context.WithTimeout(context.Background(), s.options.closeTimeout) defer cancel() - return s.close(ctx) + var err error + s.closeOnce.Do(func() { + err = s.close(ctx) + }) + return err } func (s *Server) Logger() *logrus.Entry { - return s.cfg.logger -} - -// HTTPAddress returns address of the HTTP Server -// HTTPAddress() is only available once the server has been started. -func (s *Server) HTTPAddress() string { - if s.httpListener == nil { - return "" - } - protocol := "http" - addr := s.httpListener.Addr().(*net.TCPAddr) - return fmt.Sprintf("%s://%s:%d", protocol, s.cfg.hostname, addr.Port) -} - -// GRPCAddress returns address of the gRPC Server -// GRPCAddress() is only available once the server has been started. -func (s *Server) GRPCAddress() string { - if s.grpcListener == nil { - return "" - } - addr := s.grpcListener.Addr().(*net.TCPAddr) - return fmt.Sprintf("%s:%d", s.cfg.hostname, addr.Port) -} - -func (s *Server) DebugAddress() string { - if s.debugListener == nil { - return "" - } - protocol := "http" - addr := s.debugListener.Addr().(*net.TCPAddr) - return fmt.Sprintf("%s://%s:%d", protocol, s.cfg.hostname, addr.Port) + return s.options.logger } func (s *Server) HTTPMux() *http.ServeMux { @@ -232,7 +183,7 @@ func (s *Server) GRPC() *grpc.Server { } func (s *Server) MetricsRegistry() *prometheus.Registry { - return s.cfg.metricsRegistry + return s.options.metricsRegistry } func (s *Server) close(ctx context.Context) error { @@ -241,22 +192,23 @@ func (s *Server) close(ctx context.Context) error { } if s.isClosing() { - s.Logger().Info("Server is already closing.") + s.Logger().Debug("Server is already closing.") return nil } s.Logger().Info("Received graceful shutdown request.") close(s.listening) - if s.isGRPCEnabled() { + if s.grpc != nil { s.grpc.GracefulStop() // s.grpc.GracefulStop() also closes the underlying net.Listener, we just release the reference. s.grpcListener = nil s.Logger().Info("GRPC server terminated.") } - if s.isHTTPEnabled() { - if err := s.http.Shutdown(ctx); err != nil { + if s.http != nil { + err := s.http.Shutdown(ctx) + if err != nil { return fmt.Errorf("failed to close http server: %w", err) } // s.http.Shutdown() also closes the underlying net.Listener, we just release the reference. @@ -264,12 +216,11 @@ func (s *Server) close(ctx context.Context) error { s.Logger().Info("HTTP server terminated.") } - // Always terminate debug server last, we want to keep it running for as long as possible - if err := s.debug.Shutdown(ctx); err != nil { + // Always terminate builtin server last, we want to keep it running for as long as possible + err := s.builtinServices.Close() + if err != nil { return fmt.Errorf("failed to close debug server: %w", err) } - // s.http.Shutdown() also closes the underlying net.Listener, we just release the reference. - s.debugListener = nil s.Logger().Info("Debug server terminated.") return nil @@ -285,45 +236,23 @@ func (s *Server) isClosing() bool { } } -func (s *Server) initializeHTTP() error { - s.httpMux = http.NewServeMux() - s.http = &http.Server{ - Addr: fmt.Sprintf(":%d", s.cfg.httpPort), - Handler: s.httpMux, - } - - return nil +func (s *Server) healthEndpoint() http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/ready", s.options.healthHandler.ReadyEndpoint) + mux.HandleFunc("/live", s.options.healthHandler.LiveEndpoint) + return mux } -func (s *Server) initializeDebug() error { - logger := s.Logger().WithField("protocol", "debug") - +func (s *Server) metricsEndpoint() http.Handler { mux := http.NewServeMux() - - mux.HandleFunc("/ready", s.cfg.healthHandler.ReadyEndpoint) - logger.Debug("Serving readiness handler on /ready") - - mux.HandleFunc("/live", s.cfg.healthHandler.LiveEndpoint) - logger.Debug("Serving liveliness handler on /live") - mux.Handle("/metrics", promhttp.InstrumentMetricHandler( - s.cfg.metricsRegistry, promhttp.HandlerFor(s.cfg.metricsRegistry, promhttp.HandlerOpts{}), + s.options.metricsRegistry, promhttp.HandlerFor(s.options.metricsRegistry, promhttp.HandlerOpts{}), )) - s.Logger().WithField("protocol", "http").Debug("Serving metrics on /metrics") - - mux.Handle(pprof.Path, pprof.Handler()) - logger.Debug("Serving profiler on /debug/pprof") - - s.debug = &http.Server{ - Addr: fmt.Sprintf(":%d", s.cfg.debugPort), - Handler: mux, - } - - return nil + return mux } func (s *Server) initializeGRPC() error { - gitpod_grpc.SetupLogging() + common_grpc.SetupLogging() grpcMetrics := grpc_prometheus.NewServerMetrics() grpcMetrics.EnableHandlingTimeHistogram() @@ -340,18 +269,121 @@ func (s *Server) initializeGRPC() error { grpcMetrics.StreamServerInterceptor(), } - s.grpc = grpc.NewServer(gitpod_grpc.ServerOptionsWithInterceptors(stream, unary)...) + opts := common_grpc.ServerOptionsWithInterceptors(stream, unary) + if cfg := s.options.config.Services.GRPC; cfg != nil && cfg.TLS != nil { + tlsConfig, err := common_grpc.ClientAuthTLSConfig( + cfg.TLS.CAPath, cfg.TLS.CertPath, cfg.TLS.KeyPath, + common_grpc.WithSetClientCAs(true), + common_grpc.WithServerName(s.Name), + ) + if err != nil { + log.WithError(err).Fatal("cannot load ws-manager certs") + } + + opts = append(opts, grpc.Creds(credentials.NewTLS(tlsConfig))) + } + + s.grpc = grpc.NewServer(opts...) // Register health service by default - grpc_health_v1.RegisterHealthServer(s.grpc, s.cfg.grpcHealthCheck) + grpc_health_v1.RegisterHealthServer(s.grpc, s.options.grpcHealthCheck) return nil } -func (s *Server) isGRPCEnabled() bool { - return s.cfg.grpcPort >= 0 +func httpAddress(cfg *ServerConfiguration, l net.Listener) string { + if l == nil { + return "" + } + protocol := "http" + if cfg != nil && cfg.TLS != nil { + protocol = "https" + } + return fmt.Sprintf("%s://%s", protocol, l.Addr().String()) +} + +func (s *Server) DebugAddress() string { + if s.builtinServices == nil { + return "" + } + return "http://" + s.builtinServices.Debug.Addr +} +func (s *Server) HealthAddr() string { + if s.builtinServices == nil { + return "" + } + return "http://" + s.builtinServices.Health.Addr +} +func (s *Server) HTTPAddress() string { + return httpAddress(s.options.config.Services.HTTP, s.httpListener) +} +func (s *Server) GRPCAddress() string { return s.options.config.Services.GRPC.GetAddress() } + +const ( + BuiltinDebugPort = 6060 + BuiltinMetricsPort = 9500 + BuiltinHealthPort = 9501 +) + +type builtinServices struct { + underTest bool + + Debug *http.Server + Health *http.Server + Metrics *http.Server +} + +func newBuiltinServices(server *Server) *builtinServices { + healthAddr := fmt.Sprintf(":%d", BuiltinHealthPort) + if server.options.underTest { + healthAddr = "localhost:0" + } + + return &builtinServices{ + underTest: server.options.underTest, + Debug: &http.Server{ + Addr: fmt.Sprintf("localhost:%d", BuiltinDebugPort), + Handler: pprof.Handler(), + }, + Health: &http.Server{ + Addr: healthAddr, + Handler: server.healthEndpoint(), + }, + Metrics: &http.Server{ + Addr: fmt.Sprintf("localhost:%d", BuiltinMetricsPort), + Handler: server.metricsEndpoint(), + }, + } +} + +func (s *builtinServices) ListenAndServe() error { + if s == nil { + return nil + } + + var eg errgroup.Group + if !s.underTest { + eg.Go(func() error { return s.Debug.ListenAndServe() }) + eg.Go(func() error { return s.Metrics.ListenAndServe() }) + } + eg.Go(func() error { + // health is the only service which has a variable address, + // because we need the health service to figure out if the + // server started at all + l, err := net.Listen("tcp", s.Health.Addr) + if err != nil { + return err + } + s.Health.Addr = l.Addr().String() + return s.Health.Serve(l) + }) + return eg.Wait() } -func (s *Server) isHTTPEnabled() bool { - return s.cfg.httpPort >= 0 +func (s *builtinServices) Close() error { + var eg errgroup.Group + eg.Go(func() error { return s.Debug.Close() }) + eg.Go(func() error { return s.Metrics.Close() }) + eg.Go(func() error { return s.Health.Close() }) + return eg.Wait() } diff --git a/components/common-go/baseserver/server_test.go b/components/common-go/baseserver/server_test.go index 33d54e5e901203..d6e07245656e0b 100644 --- a/components/common-go/baseserver/server_test.go +++ b/components/common-go/baseserver/server_test.go @@ -7,69 +7,73 @@ package baseserver_test import ( "context" "fmt" + "testing" + "github.com/gitpod-io/gitpod/common-go/baseserver" - "github.com/gitpod-io/gitpod/common-go/pprof" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/health/grpc_health_v1" - "net/http" - "testing" ) func TestServer_StartStop(t *testing.T) { // We don't use the helper NewForTests, because we want to control stopping ourselves. - srv, err := baseserver.New("server_test", baseserver.WithHTTPPort(8765), baseserver.WithGRPCPort(8766), baseserver.WithDebugPort(8767)) + srv, err := baseserver.New("server_test", + baseserver.WithUnderTest(), + baseserver.WithHTTP(&baseserver.ServerConfiguration{Address: "localhost:8765"}), + baseserver.WithGRPC(&baseserver.ServerConfiguration{Address: "localhost:8766"}), + ) require.NoError(t, err) baseserver.StartServerForTests(t, srv) - require.Equal(t, "http://localhost:8765", srv.HTTPAddress()) + require.Equal(t, "http://127.0.0.1:8765", srv.HTTPAddress()) require.Equal(t, "localhost:8766", srv.GRPCAddress()) - require.Equal(t, "http://localhost:8767", srv.DebugAddress()) require.NoError(t, srv.Close()) } func TestServer_ServerCombinations_StartsAndStops(t *testing.T) { - scenarios := []struct { - startHTTP bool - startGRPC bool + tests := []struct { + StartHTTP bool + StartGRPC bool }{ - {startHTTP: false, startGRPC: false}, - {startHTTP: true, startGRPC: false}, - {startHTTP: true, startGRPC: true}, - {startHTTP: false, startGRPC: true}, + {StartHTTP: false, StartGRPC: false}, + {StartHTTP: true, StartGRPC: false}, + {StartHTTP: true, StartGRPC: true}, + {StartHTTP: false, StartGRPC: true}, } - for _, scenario := range scenarios { - t.Run(fmt.Sprintf("with grpc: %v, http: %v", scenario.startGRPC, scenario.startHTTP), func(t *testing.T) { - opts := []baseserver.Option{baseserver.WithDebugPort(9000)} - - if scenario.startHTTP { - opts = append(opts, baseserver.WithHTTPPort(7000)) - } else { - opts = append(opts, baseserver.WithHTTPPort(-1)) + for _, test := range tests { + t.Run(fmt.Sprintf("with http: %v, grpc: %v", test.StartGRPC, test.StartHTTP), func(t *testing.T) { + var opts []baseserver.Option + opts = append(opts, baseserver.WithUnderTest()) + if test.StartHTTP { + opts = append(opts, baseserver.WithHTTP(&baseserver.ServerConfiguration{ + Address: fmt.Sprintf("localhost:%d", baseserver.MustFindFreePort(t)), + })) } - if scenario.startGRPC { - opts = append(opts, baseserver.WithGRPCPort(8000)) - } else { - opts = append(opts, baseserver.WithGRPCPort(-1)) + if test.StartGRPC { + opts = append(opts, baseserver.WithGRPC(&baseserver.ServerConfiguration{ + Address: fmt.Sprintf("localhost:%d", baseserver.MustFindFreePort(t)), + })) } - srv := baseserver.NewForTests(t, opts...) + srv, err := baseserver.New("test_server", opts...) + if err != nil { + t.Fatal(err) + } baseserver.StartServerForTests(t, srv) - require.Equal(t, "http://localhost:9000", srv.DebugAddress()) - if scenario.startHTTP { - require.Equal(t, "http://localhost:7000", srv.HTTPAddress(), "must serve http on port 7000 because startHTTP was set") + require.NotEmpty(t, srv.DebugAddress(), "must serve debug endpoint") + if test.StartHTTP { + require.NotEmpty(t, srv.HTTPAddress(), "must serve http because startHTTP was set") } else { require.Empty(t, srv.HTTPAddress(), "must not serve http") } - if scenario.startGRPC { - require.Equal(t, "localhost:8000", srv.GRPCAddress(), "must serve grpc on port 8000 because startGRPC was set") + if test.StartGRPC { + require.NotEmpty(t, srv.GRPCAddress(), "must serve grpc because startGRPC was set") } else { require.Empty(t, srv.GRPCAddress(), "must not serve grpc") } @@ -77,71 +81,11 @@ func TestServer_ServerCombinations_StartsAndStops(t *testing.T) { } } -func TestServer_OnlyDebug(t *testing.T) { - srv := baseserver.NewForTests(t, baseserver.WithGRPCPort(-1), baseserver.WithHTTPPort(-1), baseserver.WithDebugPort(7777)) - baseserver.StartServerForTests(t, srv) - - require.Empty(t, srv.HTTPAddress(), "server not started, address must be empty") - require.Empty(t, srv.GRPCAddress(), "server not started, address must be empty") - require.Equal(t, "http://localhost:7777", srv.DebugAddress()) -} - -func TestServer_Debug_HealthEndpoints(t *testing.T) { - for _, scenario := range []struct { - name string - endpoint string - }{ - {name: "ready endpoint", endpoint: "/ready"}, - {name: "live endpoint", endpoint: "/live"}, - } { - t.Run(scenario.name, func(t *testing.T) { - srv := baseserver.NewForTests(t) - baseserver.StartServerForTests(t, srv) - - resp, err := http.Get(srv.DebugAddress() + scenario.endpoint) - require.NoError(t, err) - require.Equal(t, http.StatusOK, resp.StatusCode) - }) - } -} - -func TestServer_Debug_MetricsEndpointWithDefaultConfig(t *testing.T) { - srv := baseserver.NewForTests(t) - - baseserver.StartServerForTests(t, srv) - - readyUR := fmt.Sprintf("%s/metrics", srv.DebugAddress()) - resp, err := http.Get(readyUR) - require.NoError(t, err) - require.Equal(t, http.StatusOK, resp.StatusCode) -} - -func TestServer_ServesMetricsEndpointWithCustomMetricsConfig(t *testing.T) { - registry := prometheus.NewRegistry() - srv := baseserver.NewForTests(t, - baseserver.WithMetricsRegistry(registry), - ) - - baseserver.StartServerForTests(t, srv) - - readyUR := fmt.Sprintf("%s/metrics", srv.DebugAddress()) - resp, err := http.Get(readyUR) - require.NoError(t, err) - require.Equal(t, http.StatusOK, resp.StatusCode) -} - -func TestServer_ServesPprof(t *testing.T) { - srv := baseserver.NewForTests(t) - baseserver.StartServerForTests(t, srv) - - resp, err := http.Get(srv.DebugAddress() + pprof.Path) - require.NoError(t, err) - require.Equalf(t, http.StatusOK, resp.StatusCode, "must serve pprof on %s", pprof.Path) -} - func TestServer_Metrics_gRPC(t *testing.T) { ctx := context.Background() - srv := baseserver.NewForTests(t) + srv := baseserver.NewForTests(t, baseserver.WithGRPC(&baseserver.ServerConfiguration{ + Address: fmt.Sprintf("localhost:%d", baseserver.MustFindFreePort(t)), + })) // At this point, there must be metrics registry available for use require.NotNil(t, srv.MetricsRegistry()) diff --git a/components/common-go/baseserver/testing.go b/components/common-go/baseserver/testing.go index 458dbbb6c68178..9e6dcfdf673e3f 100644 --- a/components/common-go/baseserver/testing.go +++ b/components/common-go/baseserver/testing.go @@ -7,10 +7,12 @@ package baseserver import ( "context" "fmt" - "github.com/stretchr/testify/require" + "net" "net/http" "testing" "time" + + "github.com/stretchr/testify/require" ) // NewForTests constructs a *baseserver.Server which is automatically closed after the test finishes. @@ -18,9 +20,7 @@ func NewForTests(t *testing.T, opts ...Option) *Server { t.Helper() defaultTestOpts := []Option{ - WithGRPCPort(0), - WithHTTPPort(0), - WithDebugPort(0), + WithUnderTest(), WithCloseTimeout(1 * time.Second), } @@ -35,6 +35,33 @@ func NewForTests(t *testing.T, opts ...Option) *Server { return srv } +func MustUseRandomLocalAddress(t *testing.T) *ServerConfiguration { + t.Helper() + + return &ServerConfiguration{ + Address: fmt.Sprintf("localhost:%d", MustFindFreePort(t)), + } +} + +func MustFindFreePort(t *testing.T) int { + t.Helper() + + addr, err := net.ResolveTCPAddr("tcp", "localhost:0") + if err != nil { + t.Fatalf("cannot find free port: %v", err) + return 0 + } + + l, err := net.ListenTCP("tcp", addr) + if err != nil { + t.Fatalf("cannot find free port: %v", err) + return 0 + } + defer l.Close() + + return l.Addr().(*net.TCPAddr).Port +} + // StartServerForTests starts the server for test purposes. // This is a helper which also ensures the server is reachable before returning. func StartServerForTests(t *testing.T, srv *Server) { @@ -61,12 +88,13 @@ func waitForServerToBeReachable(t *testing.T, srv *Server, timeout time.Duration } for { + healthURL := fmt.Sprintf("%s/ready", srv.HealthAddr()) + select { case <-ctx.Done(): - require.Failf(t, "server did not become reachable in %s", timeout.String()) + t.Fatalf("server did not become reachable in %s on %s", timeout.String(), healthURL) case <-ticker.C: // We retrieve the URL on each tick, because the HTTPAddress is only available once the server is listening. - healthURL := fmt.Sprintf("%s/ready", srv.DebugAddress()) _, err := client.Get(healthURL) if err != nil { continue diff --git a/components/common-go/go.mod b/components/common-go/go.mod index f6fb4de037a8ff..228ae27c36e1d9 100644 --- a/components/common-go/go.mod +++ b/components/common-go/go.mod @@ -27,6 +27,7 @@ require ( require ( github.com/hashicorp/golang-lru v0.5.1 github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 diff --git a/components/common-go/go.sum b/components/common-go/go.sum index d452f67702f0f7..6015504922fc1b 100644 --- a/components/common-go/go.sum +++ b/components/common-go/go.sum @@ -399,6 +399,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/components/public-api-server/go.mod b/components/public-api-server/go.mod index 0c7963ddcbf359..270feda1aa373c 100644 --- a/components/public-api-server/go.mod +++ b/components/public-api-server/go.mod @@ -8,6 +8,7 @@ require ( github.com/gitpod-io/gitpod/public-api v0.0.0-00010101000000-000000000000 github.com/google/go-cmp v0.5.7 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 @@ -30,12 +31,12 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/sourcegraph/jsonrpc2 v0.0.0-20200429184054-15c2290dcb37 // indirect golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect diff --git a/components/public-api-server/go.sum b/components/public-api-server/go.sum index 4d30d12bc771b2..89b4d7574035b8 100644 --- a/components/public-api-server/go.sum +++ b/components/public-api-server/go.sum @@ -334,6 +334,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/components/public-api-server/main.go b/components/public-api-server/main.go index 5e01cfa0a47b71..b51cb5b322c525 100644 --- a/components/public-api-server/main.go +++ b/components/public-api-server/main.go @@ -6,12 +6,13 @@ package main import ( "context" + "net/url" + "github.com/gitpod-io/gitpod/common-go/log" "github.com/gitpod-io/gitpod/public-api-server/pkg/server" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" - "net/url" ) const ( @@ -31,9 +32,9 @@ func main() { func command() *cobra.Command { var ( - gitpodAPIURL string - debugPort, grpcPort int - verbose bool + gitpodAPIURL string + grpcPort int + verbose bool ) cmd := &cobra.Command{ @@ -53,7 +54,6 @@ func command() *cobra.Command { if err := server.Start(logger, server.Config{ GitpodAPI: gitpodAPI, - DebugPort: debugPort, GRPCPort: grpcPort, }); err != nil { logger.WithError(err).Fatal("Server errored.") @@ -62,7 +62,6 @@ func command() *cobra.Command { } cmd.Flags().StringVar(&gitpodAPIURL, "gitpod-api-url", "wss://main.preview.gitpod-dev.com/api/v1", "URL for existing Gitpod Websocket API") - cmd.Flags().IntVar(&debugPort, "debug-port", 9500, "Port for serving debug endpoints") cmd.Flags().IntVar(&grpcPort, "grpc-port", 9501, "Port for serving gRPC traffic") cmd.Flags().BoolVar(&verbose, "verbose", false, "Toggle verbose logging (debug level)") diff --git a/components/public-api-server/pkg/apiv1/workspace_test.go b/components/public-api-server/pkg/apiv1/workspace_test.go index 8016408c35e00e..03a5ba04b6afc4 100644 --- a/components/public-api-server/pkg/apiv1/workspace_test.go +++ b/components/public-api-server/pkg/apiv1/workspace_test.go @@ -7,6 +7,8 @@ package apiv1 import ( "context" "errors" + "testing" + "github.com/gitpod-io/gitpod/common-go/baseserver" gitpod "github.com/gitpod-io/gitpod/gitpod-protocol" v1 "github.com/gitpod-io/gitpod/public-api/v1" @@ -18,7 +20,6 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/testing/protocmp" - "testing" ) func TestWorkspaceService_GetWorkspace(t *testing.T) { @@ -30,7 +31,9 @@ func TestWorkspaceService_GetWorkspace(t *testing.T) { description = "This is the description" ) - srv := baseserver.NewForTests(t) + srv := baseserver.NewForTests(t, + baseserver.WithGRPC(baseserver.MustUseRandomLocalAddress(t)), + ) connPool := &FakeServerConnPool{ api: &FakeGitpodAPI{workspaces: map[string]*gitpod.WorkspaceInfo{ @@ -113,7 +116,9 @@ func TestWorkspaceService_GetWorkspace(t *testing.T) { } func TestWorkspaceService_GetOwnerToken(t *testing.T) { - srv := baseserver.NewForTests(t) + srv := baseserver.NewForTests(t, + baseserver.WithGRPC(baseserver.MustUseRandomLocalAddress(t)), + ) var connPool *FakeServerConnPool v1.RegisterWorkspacesServiceServer(srv.GRPC(), NewWorkspaceService(connPool)) diff --git a/components/public-api-server/pkg/proxy/prometheusmetrics_test.go b/components/public-api-server/pkg/proxy/prometheusmetrics_test.go index abf662a9dafa97..e1c6fd35475091 100644 --- a/components/public-api-server/pkg/proxy/prometheusmetrics_test.go +++ b/components/public-api-server/pkg/proxy/prometheusmetrics_test.go @@ -6,6 +6,8 @@ package proxy import ( "context" + "testing" + "github.com/gitpod-io/gitpod/common-go/baseserver" v1 "github.com/gitpod-io/gitpod/public-api/v1" "github.com/prometheus/client_golang/prometheus" @@ -14,12 +16,13 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" - "testing" ) func TestConnectionCreationWasTracked(t *testing.T) { // Set up server - srv := baseserver.NewForTests(t) + srv := baseserver.NewForTests(t, + baseserver.WithGRPC(baseserver.MustUseRandomLocalAddress(t)), + ) baseserver.StartServerForTests(t, srv) // Set up Prometheus registry diff --git a/components/public-api-server/pkg/server/config.go b/components/public-api-server/pkg/server/config.go index 8a5905dc392181..70a6c3f6c44357 100644 --- a/components/public-api-server/pkg/server/config.go +++ b/components/public-api-server/pkg/server/config.go @@ -9,6 +9,5 @@ import "net/url" type Config struct { GitpodAPI *url.URL - GRPCPort int - DebugPort int + GRPCPort int } diff --git a/components/public-api-server/pkg/server/integration_test.go b/components/public-api-server/pkg/server/integration_test.go index afc585d67bc1d4..6d09dfc850bec9 100644 --- a/components/public-api-server/pkg/server/integration_test.go +++ b/components/public-api-server/pkg/server/integration_test.go @@ -6,6 +6,9 @@ package server import ( "context" + "net/url" + "testing" + "github.com/gitpod-io/gitpod/common-go/baseserver" v1 "github.com/gitpod-io/gitpod/public-api/v1" "github.com/prometheus/client_golang/prometheus" @@ -15,13 +18,13 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" - "net/url" - "testing" ) func TestPublicAPIServer_v1_WorkspaceService(t *testing.T) { ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "some-token") - srv := baseserver.NewForTests(t) + srv := baseserver.NewForTests(t, + baseserver.WithGRPC(baseserver.MustUseRandomLocalAddress(t)), + ) registry := prometheus.NewRegistry() gitpodAPI, err := url.Parse("wss://main.preview.gitpod-dev.com/api/v1") @@ -68,7 +71,7 @@ func TestPublicAPIServer_v1_WorkspaceService(t *testing.T) { func TestPublicAPIServer_v1_PrebuildService(t *testing.T) { ctx := context.Background() - srv := baseserver.NewForTests(t) + srv := baseserver.NewForTests(t, baseserver.WithGRPC(baseserver.MustUseRandomLocalAddress(t))) registry := prometheus.NewRegistry() gitpodAPI, err := url.Parse("wss://main.preview.gitpod-dev.com/api/v1") diff --git a/components/public-api-server/pkg/server/server.go b/components/public-api-server/pkg/server/server.go index 6eabf70c8a1a7c..89d6a8de71ad1a 100644 --- a/components/public-api-server/pkg/server/server.go +++ b/components/public-api-server/pkg/server/server.go @@ -6,6 +6,7 @@ package server import ( "fmt" + "github.com/gitpod-io/gitpod/common-go/baseserver" "github.com/gitpod-io/gitpod/public-api-server/pkg/apiv1" "github.com/gitpod-io/gitpod/public-api-server/pkg/proxy" @@ -19,8 +20,7 @@ func Start(logger *logrus.Entry, cfg Config) error { srv, err := baseserver.New("public_api_server", baseserver.WithLogger(logger), - baseserver.WithDebugPort(cfg.DebugPort), - baseserver.WithGRPCPort(cfg.GRPCPort), + baseserver.WithGRPC(&baseserver.ServerConfiguration{Address: fmt.Sprintf("localhost:%d", cfg.GRPCPort)}), baseserver.WithMetricsRegistry(registry), ) if err != nil { diff --git a/install/installer/go.mod b/install/installer/go.mod index ed3863625517a3..29df459321a826 100644 --- a/install/installer/go.mod +++ b/install/installer/go.mod @@ -131,6 +131,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect diff --git a/install/installer/go.sum b/install/installer/go.sum index cf5c8511b3bbec..ea1039aae0b4eb 100644 --- a/install/installer/go.sum +++ b/install/installer/go.sum @@ -843,6 +843,8 @@ github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoI github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb h1:tsEKRC3PU9rMw18w/uAptoijhgG4EvlA5kfJPtwrMDk= +github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb/go.mod h1:NtmN9h8vrTveVQRLHcX2HQ5wIPBDCsZ351TGbZWgg38= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -2638,6 +2640,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= diff --git a/install/installer/pkg/components/public-api-server/constants.go b/install/installer/pkg/components/public-api-server/constants.go index 5d8f0a001d82fb..387ffafc1d2514 100644 --- a/install/installer/pkg/components/public-api-server/constants.go +++ b/install/installer/pkg/components/public-api-server/constants.go @@ -7,10 +7,6 @@ package public_api_server const ( Component = "public-api-server" - DebugPortName = "debug" - DebugContainerPort = 9000 - DebugServicePort = 9000 - GRPCPortName = "grpc" GRPCContainerPort = 9001 GRPCServicePort = 9001 diff --git a/install/installer/pkg/components/public-api-server/deployment.go b/install/installer/pkg/components/public-api-server/deployment.go index 856b610bd0d235..9b0c876bdcc601 100644 --- a/install/installer/pkg/components/public-api-server/deployment.go +++ b/install/installer/pkg/components/public-api-server/deployment.go @@ -5,6 +5,8 @@ package public_api_server import ( "fmt" + + "github.com/gitpod-io/gitpod/common-go/baseserver" "github.com/gitpod-io/gitpod/installer/pkg/cluster" "github.com/gitpod-io/gitpod/installer/pkg/common" appsv1 "k8s.io/api/apps/v1" @@ -47,7 +49,6 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { Name: Component, Image: ctx.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.PublicAPIServer.Version), Args: []string{ - fmt.Sprintf("--debug-port=%d", DebugContainerPort), fmt.Sprintf("--grpc-port=%d", GRPCContainerPort), fmt.Sprintf("--gitpod-api-url=wss://%s/api/v1", ctx.Config.Domain), }, @@ -59,10 +60,6 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, }), Ports: []corev1.ContainerPort{ - { - ContainerPort: DebugContainerPort, - Name: DebugPortName, - }, { ContainerPort: GRPCContainerPort, Name: GRPCPortName, @@ -78,7 +75,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/live", - Port: intstr.IntOrString{IntVal: DebugContainerPort}, + Port: intstr.IntOrString{IntVal: baseserver.BuiltinHealthPort}, Scheme: corev1.URISchemeHTTP, }, }, @@ -90,7 +87,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/ready", - Port: intstr.IntOrString{IntVal: DebugContainerPort}, + Port: intstr.IntOrString{IntVal: baseserver.BuiltinHealthPort}, Scheme: corev1.URISchemeHTTP, }, }, @@ -99,7 +96,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { TimeoutSeconds: 1, }, }, - *common.KubeRBACProxyContainerWithConfig(ctx, 9500, fmt.Sprintf("http://127.0.0.1:%d/", DebugContainerPort)), + *common.KubeRBACProxyContainerWithConfig(ctx, 9500, fmt.Sprintf("http://127.0.0.1:%d/", baseserver.BuiltinDebugPort)), }, }, }, diff --git a/install/installer/pkg/components/public-api-server/deployment_test.go b/install/installer/pkg/components/public-api-server/deployment_test.go index 54ef83cd3b343a..74d5c1c84021b0 100644 --- a/install/installer/pkg/components/public-api-server/deployment_test.go +++ b/install/installer/pkg/components/public-api-server/deployment_test.go @@ -4,9 +4,10 @@ package public_api_server import ( + "testing" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" - "testing" ) func TestDeployment(t *testing.T) { @@ -35,7 +36,6 @@ func TestDeployment_ServerArguments(t *testing.T) { apiContainer := containers[0] require.EqualValues(t, []string{ - "--debug-port=9000", "--grpc-port=9001", `--gitpod-api-url=wss://test.domain.everything.awesome.is/api/v1`, }, apiContainer.Args) diff --git a/install/installer/pkg/components/public-api-server/networkpolicy.go b/install/installer/pkg/components/public-api-server/networkpolicy.go index 6a99c855cd58ab..27ffbc0146d196 100644 --- a/install/installer/pkg/components/public-api-server/networkpolicy.go +++ b/install/installer/pkg/components/public-api-server/networkpolicy.go @@ -29,10 +29,6 @@ func networkpolicy(ctx *common.RenderContext) ([]runtime.Object, error) { Ingress: []networkingv1.NetworkPolicyIngressRule{ { Ports: []networkingv1.NetworkPolicyPort{ - { - Protocol: common.TCPProtocol, - Port: &intstr.IntOrString{IntVal: DebugContainerPort}, - }, { Protocol: common.TCPProtocol, Port: &intstr.IntOrString{IntVal: GRPCContainerPort}, diff --git a/install/installer/pkg/components/public-api-server/networkpolicy_test.go b/install/installer/pkg/components/public-api-server/networkpolicy_test.go index 076c67697b9ddb..cde6e5c78c16b2 100644 --- a/install/installer/pkg/components/public-api-server/networkpolicy_test.go +++ b/install/installer/pkg/components/public-api-server/networkpolicy_test.go @@ -4,12 +4,13 @@ package public_api_server import ( + "testing" + "github.com/gitpod-io/gitpod/installer/pkg/common" "github.com/stretchr/testify/require" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - "testing" ) func TestNetworkPolicy(t *testing.T) { @@ -25,10 +26,6 @@ func TestNetworkPolicy(t *testing.T) { require.Equal(t, networkingv1.NetworkPolicyIngressRule{ Ports: []networkingv1.NetworkPolicyPort{ - { - Protocol: common.TCPProtocol, - Port: &intstr.IntOrString{IntVal: DebugContainerPort}, - }, { Protocol: common.TCPProtocol, Port: &intstr.IntOrString{IntVal: GRPCContainerPort}, diff --git a/install/installer/pkg/components/public-api-server/service.go b/install/installer/pkg/components/public-api-server/service.go index addd915739a011..1372ba62b6bca6 100644 --- a/install/installer/pkg/components/public-api-server/service.go +++ b/install/installer/pkg/components/public-api-server/service.go @@ -10,10 +10,6 @@ import ( func service(ctx *common.RenderContext) ([]runtime.Object, error) { return common.GenerateService(Component, map[string]common.ServicePort{ - DebugPortName: { - ContainerPort: DebugContainerPort, - ServicePort: DebugServicePort, - }, GRPCPortName: { ContainerPort: GRPCContainerPort, ServicePort: GRPCServicePort,