From 8aae1502f0632d6de8c73fe0b7747eda57234d86 Mon Sep 17 00:00:00 2001 From: Tomas Knappek Date: Mon, 21 May 2018 10:41:27 -0700 Subject: [PATCH] Admin server for paths which are not part of API (#1011) * admin server added * test fixed, ping moved out of admin server * keeping admin/web port in sync --- api/server/runner_async_test.go | 13 ++++---- api/server/server.go | 57 +++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/api/server/runner_async_test.go b/api/server/runner_async_test.go index 05920e88b..5b72ea23a 100644 --- a/api/server/runner_async_test.go +++ b/api/server/runner_async_test.go @@ -15,13 +15,14 @@ import ( func testRouterAsync(ds models.Datastore, mq models.MessageQueue, rnr agent.Agent) *gin.Engine { ctx := context.Background() - + engine := gin.New() s := &Server{ - agent: rnr, - Router: gin.New(), - datastore: ds, - mq: mq, - nodeType: ServerTypeFull, + agent: rnr, + Router: engine, + AdminRouter: engine, + datastore: ds, + mq: mq, + nodeType: ServerTypeFull, } r := s.Router diff --git a/api/server/server.go b/api/server/server.go index e13c26a0e..9b7a9d367 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -100,9 +100,11 @@ func (s ServerNodeType) String() string { type Server struct { // TODO this one maybe we have `AddRoute` in extensions? - Router *gin.Engine + Router *gin.Engine + AdminRouter *gin.Engine webListenPort int + adminListenPort int grpcListenPort int agent agent.Agent datastore models.Datastore @@ -187,6 +189,9 @@ func pwd() string { func WithWebPort(port int) ServerOption { return func(ctx context.Context, s *Server) error { + if s.adminListenPort == s.webListenPort { + s.adminListenPort = port + } s.webListenPort = port return nil } @@ -480,6 +485,15 @@ func WithExtraCtx(extraCtx context.Context) ServerOption { } } +// WithAdminServer starts the admin server on the specified port. +func WithAdminServer(port int) ServerOption { + return func(ctx context.Context, s *Server) error { + s.AdminRouter = gin.New() + s.adminListenPort = port + return nil + } +} + // New creates a new Functions server with the opts given. For convenience, users may // prefer to use NewFromEnv but New is more flexible if needed. func New(ctx context.Context, opts ...ServerOption) *Server { @@ -487,11 +501,14 @@ func New(ctx context.Context, opts ...ServerOption) *Server { defer span.End() log := common.Logger(ctx) + engine := gin.New() s := &Server{ - Router: gin.New(), + Router: engine, + AdminRouter: engine, // Add default ports - webListenPort: DefaultPort, - grpcListenPort: DefaultGRPCPort, + webListenPort: DefaultPort, + adminListenPort: DefaultPort, + grpcListenPort: DefaultGRPCPort, // Almost everything else is configured through opts (see NewFromEnv for ex.) or below } @@ -779,6 +796,31 @@ func (s *Server) startGears(ctx context.Context, cancel context.CancelFunc) { } }() + if s.webListenPort != s.adminListenPort { + adminListen := fmt.Sprintf(":%d", s.adminListenPort) + logrus.WithField("type", s.nodeType).Infof("Fn Admin serving on `%v`", adminListen) + adminServer := http.Server{ + Addr: adminListen, + Handler: &ochttp.Handler{Handler: s.AdminRouter}, + } + + go func() { + err := adminServer.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + logrus.WithError(err).Error("server error") + cancel() + } else { + logrus.Info("server stopped") + } + }() + + defer func() { + if err := adminServer.Shutdown(context.Background()); err != nil { + logrus.WithError(err).Error("admin server shutdown error") + } + }() + } + // listening for signals or listener errors or cancellations on all registered contexts. s.extraCtxs = append(s.extraCtxs, ctx) cases := make([]reflect.SelectCase, len(s.extraCtxs)) @@ -812,18 +854,19 @@ func (s *Server) startGears(ctx context.Context, cancel context.CancelFunc) { func (s *Server) bindHandlers(ctx context.Context) { engine := s.Router + admin := s.AdminRouter // now for extensible middleware engine.Use(s.rootMiddlewareWrapper()) engine.GET("/", handlePing) - engine.GET("/version", handleVersion) + admin.GET("/version", handleVersion) // TODO: move under v1 ? if s.promExporter != nil { - engine.GET("/metrics", gin.WrapH(s.promExporter)) + admin.GET("/metrics", gin.WrapH(s.promExporter)) } - profilerSetup(engine, "/debug") + profilerSetup(admin, "/debug") // Pure runners don't have any route, they have grpc if s.nodeType != ServerTypePureRunner {