From 1347df814de0d603ef844d53b2c8d54fc760b75e Mon Sep 17 00:00:00 2001 From: pingcap-github-bot Date: Fri, 10 Apr 2020 18:16:06 +0800 Subject: [PATCH] server: if status address already in use, return an error (#15177) (#16291) --- server/http_status.go | 57 +++++++++++++++++++++++-------------------- server/server.go | 5 ++++ server/tidb_test.go | 13 ++++++++++ 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/server/http_status.go b/server/http_status.go index 32f81a15d8729..ac5fed8a544e4 100644 --- a/server/http_status.go +++ b/server/http_status.go @@ -68,6 +68,34 @@ func sleepWithCtx(ctx context.Context, d time.Duration) { } } +func (s *Server) listenStatusHTTPServer() error { + s.statusAddr = fmt.Sprintf("%s:%d", s.cfg.Status.StatusHost, s.cfg.Status.StatusPort) + if s.cfg.Status.StatusPort == 0 { + s.statusAddr = fmt.Sprintf("%s:%d", s.cfg.Status.StatusHost, defaultStatusPort) + } + + var err error + logutil.Logger(context.Background()).Info("for status and metrics report", zap.String("listening on addr", s.statusAddr)) + s.statusListener, err = net.Listen("tcp", s.statusAddr) + if err != nil { + logutil.Logger(context.Background()).Info("listen failed", zap.Error(err)) + return errors.Trace(err) + } + + if len(s.cfg.Security.ClusterSSLCA) != 0 { + tlsConfig, err := s.cfg.Security.ToTLSConfig() + if err != nil { + logutil.Logger(context.Background()).Error("invalid TLS config", zap.Error(err)) + return errors.Trace(err) + } + tlsConfig = s.setCNChecker(tlsConfig) + logutil.Logger(context.Background()).Info("HTTP/gRPC status server secure connection is enabled", zap.Bool("CN verification enabled", tlsConfig.VerifyPeerCertificate != nil)) + s.statusListener = tls.NewListener(s.statusListener, tlsConfig) + } + + return nil +} + func (s *Server) startHTTPServer() { router := mux.NewRouter() @@ -113,13 +141,9 @@ func (s *Server) startHTTPServer() { router.Handle("/mvcc/hex/{hexKey}", mvccTxnHandler{tikvHandlerTool, opMvccGetByHex}) router.Handle("/mvcc/index/{db}/{table}/{index}/{handle}", mvccTxnHandler{tikvHandlerTool, opMvccGetByIdx}) } - addr := fmt.Sprintf("%s:%d", s.cfg.Status.StatusHost, s.cfg.Status.StatusPort) - if s.cfg.Status.StatusPort == 0 { - addr = fmt.Sprintf("%s:%d", s.cfg.Status.StatusHost, defaultStatusPort) - } // HTTP path for web UI. - if host, port, err := net.SplitHostPort(addr); err == nil { + if host, port, err := net.SplitHostPort(s.statusAddr); err == nil { if host == "" { host = "localhost" } @@ -255,27 +279,8 @@ func (s *Server) startHTTPServer() { } }) - logutil.Logger(context.Background()).Info("for status and metrics report", zap.String("listening on addr", addr)) - s.statusServer = &http.Server{Addr: addr, Handler: CorsHandler{handler: serverMux, cfg: s.cfg}} - - ln, err := net.Listen("tcp", addr) - if err != nil { - logutil.Logger(context.Background()).Info("listen failed", zap.Error(err)) - return - } - - if len(s.cfg.Security.ClusterSSLCA) != 0 { - tlsConfig, err := s.cfg.Security.ToTLSConfig() - if err != nil { - logutil.Logger(context.Background()).Error("invalid TLS config", zap.Error(err)) - return - } - tlsConfig = s.setCNChecker(tlsConfig) - logutil.Logger(context.Background()).Info("HTTP/gRPC status server secure connection is enabled", zap.Bool("CN verification enabled", tlsConfig.VerifyPeerCertificate != nil)) - ln = tls.NewListener(ln, tlsConfig) - } - - err = s.statusServer.Serve(ln) + s.statusServer = &http.Server{Addr: s.statusAddr, Handler: CorsHandler{handler: serverMux, cfg: s.cfg}} + err = s.statusServer.Serve(s.statusListener) if err != nil { logutil.Logger(context.Background()).Info("serve status port failed", zap.Error(err)) } diff --git a/server/server.go b/server/server.go index 7ef8d39f9c5df..1f51d1998043a 100644 --- a/server/server.go +++ b/server/server.go @@ -112,6 +112,8 @@ type Server struct { concurrentLimiter *TokenLimiter clients map[uint32]*clientConn capability uint32 + statusAddr string + statusListener net.Listener statusServer *http.Server } @@ -247,6 +249,9 @@ func NewServer(cfg *config.Config, driver IDriver) (*Server, error) { s.listener = pplistener } + if s.cfg.Status.ReportStatus && err == nil { + err = s.listenStatusHTTPServer() + } if err != nil { return nil, errors.Trace(err) } diff --git a/server/tidb_test.go b/server/tidb_test.go index 2441bab9dfd02..0b0b37ff6ecef 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -160,6 +160,19 @@ func (ts *TidbTestSuite) TestStatusAPI(c *C) { runTestStatusAPI(c) } +func (ts *TidbTestSuite) TestStatusPort(c *C) { + cfg := config.NewConfig() + cfg.Port = 4008 + cfg.Status.ReportStatus = true + cfg.Status.StatusPort = 10090 + + server, err := NewServer(cfg, ts.tidbdrv) + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, + fmt.Sprintf("listen tcp 0.0.0.0:%d: bind: address already in use", cfg.Status.StatusPort)) + c.Assert(server, IsNil) +} + func (ts *TidbTestSuite) TestStatusAPIWithTLSCNCheck(c *C) { caPath := filepath.Join(os.TempDir(), "ca-cert-cn.pem") serverKeyPath := filepath.Join(os.TempDir(), "server-key-cn.pem")