...

Source file src/github.com/prometheus/alertmanager/api/v2/restapi/server.go

Documentation: github.com/prometheus/alertmanager/api/v2/restapi

     1  // Code generated by go-swagger; DO NOT EDIT.
     2  
     3  // Copyright Prometheus Team
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  // http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package restapi
    18  
    19  import (
    20  	"context"
    21  	"crypto/tls"
    22  	"crypto/x509"
    23  	"errors"
    24  	"fmt"
    25  	"log"
    26  	"net"
    27  	"net/http"
    28  	"os"
    29  	"os/signal"
    30  	"strconv"
    31  	"sync"
    32  	"sync/atomic"
    33  	"syscall"
    34  	"time"
    35  
    36  	"github.com/go-openapi/runtime/flagext"
    37  	"github.com/go-openapi/swag"
    38  	flags "github.com/jessevdk/go-flags"
    39  	"golang.org/x/net/netutil"
    40  
    41  	"github.com/prometheus/alertmanager/api/v2/restapi/operations"
    42  )
    43  
    44  const (
    45  	schemeHTTP  = "http"
    46  	schemeHTTPS = "https"
    47  	schemeUnix  = "unix"
    48  )
    49  
    50  var defaultSchemes []string
    51  
    52  func init() {
    53  	defaultSchemes = []string{
    54  		schemeHTTP,
    55  	}
    56  }
    57  
    58  // NewServer creates a new api alertmanager server but does not configure it
    59  func NewServer(api *operations.AlertmanagerAPI) *Server {
    60  	s := new(Server)
    61  
    62  	s.shutdown = make(chan struct{})
    63  	s.api = api
    64  	s.interrupt = make(chan os.Signal, 1)
    65  	return s
    66  }
    67  
    68  // ConfigureAPI configures the API and handlers.
    69  func (s *Server) ConfigureAPI() {
    70  	if s.api != nil {
    71  		s.handler = configureAPI(s.api)
    72  	}
    73  }
    74  
    75  // ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
    76  func (s *Server) ConfigureFlags() {
    77  	if s.api != nil {
    78  		configureFlags(s.api)
    79  	}
    80  }
    81  
    82  // Server for the alertmanager API
    83  type Server struct {
    84  	EnabledListeners []string         `long:"scheme" description:"the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec"`
    85  	CleanupTimeout   time.Duration    `long:"cleanup-timeout" description:"grace period for which to wait before killing idle connections" default:"10s"`
    86  	GracefulTimeout  time.Duration    `long:"graceful-timeout" description:"grace period for which to wait before shutting down the server" default:"15s"`
    87  	MaxHeaderSize    flagext.ByteSize `long:"max-header-size" description:"controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body." default:"1MiB"`
    88  
    89  	SocketPath    flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/alertmanager.sock"`
    90  	domainSocketL net.Listener
    91  
    92  	Host         string        `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`
    93  	Port         int           `long:"port" description:"the port to listen on for insecure connections, defaults to a random value" env:"PORT"`
    94  	ListenLimit  int           `long:"listen-limit" description:"limit the number of outstanding requests"`
    95  	KeepAlive    time.Duration `long:"keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)" default:"3m"`
    96  	ReadTimeout  time.Duration `long:"read-timeout" description:"maximum duration before timing out read of the request" default:"30s"`
    97  	WriteTimeout time.Duration `long:"write-timeout" description:"maximum duration before timing out write of the response" default:"60s"`
    98  	httpServerL  net.Listener
    99  
   100  	TLSHost           string         `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`
   101  	TLSPort           int            `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`
   102  	TLSCertificate    flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`
   103  	TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`
   104  	TLSCACertificate  flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`
   105  	TLSListenLimit    int            `long:"tls-listen-limit" description:"limit the number of outstanding requests"`
   106  	TLSKeepAlive      time.Duration  `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"`
   107  	TLSReadTimeout    time.Duration  `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`
   108  	TLSWriteTimeout   time.Duration  `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`
   109  	httpsServerL      net.Listener
   110  
   111  	api          *operations.AlertmanagerAPI
   112  	handler      http.Handler
   113  	hasListeners bool
   114  	shutdown     chan struct{}
   115  	shuttingDown int32
   116  	interrupted  bool
   117  	interrupt    chan os.Signal
   118  }
   119  
   120  // Logf logs message either via defined user logger or via system one if no user logger is defined.
   121  func (s *Server) Logf(f string, args ...interface{}) {
   122  	if s.api != nil && s.api.Logger != nil {
   123  		s.api.Logger(f, args...)
   124  	} else {
   125  		log.Printf(f, args...)
   126  	}
   127  }
   128  
   129  // Fatalf logs message either via defined user logger or via system one if no user logger is defined.
   130  // Exits with non-zero status after printing
   131  func (s *Server) Fatalf(f string, args ...interface{}) {
   132  	if s.api != nil && s.api.Logger != nil {
   133  		s.api.Logger(f, args...)
   134  		os.Exit(1)
   135  	} else {
   136  		log.Fatalf(f, args...)
   137  	}
   138  }
   139  
   140  // SetAPI configures the server with the specified API. Needs to be called before Serve
   141  func (s *Server) SetAPI(api *operations.AlertmanagerAPI) {
   142  	if api == nil {
   143  		s.api = nil
   144  		s.handler = nil
   145  		return
   146  	}
   147  
   148  	s.api = api
   149  	s.handler = configureAPI(api)
   150  }
   151  
   152  func (s *Server) hasScheme(scheme string) bool {
   153  	schemes := s.EnabledListeners
   154  	if len(schemes) == 0 {
   155  		schemes = defaultSchemes
   156  	}
   157  
   158  	for _, v := range schemes {
   159  		if v == scheme {
   160  			return true
   161  		}
   162  	}
   163  	return false
   164  }
   165  
   166  // Serve the api
   167  func (s *Server) Serve() (err error) {
   168  	if !s.hasListeners {
   169  		if err = s.Listen(); err != nil {
   170  			return err
   171  		}
   172  	}
   173  
   174  	// set default handler, if none is set
   175  	if s.handler == nil {
   176  		if s.api == nil {
   177  			return errors.New("can't create the default handler, as no api is set")
   178  		}
   179  
   180  		s.SetHandler(s.api.Serve(nil))
   181  	}
   182  
   183  	wg := new(sync.WaitGroup)
   184  	once := new(sync.Once)
   185  	signalNotify(s.interrupt)
   186  	go handleInterrupt(once, s)
   187  
   188  	servers := []*http.Server{}
   189  
   190  	if s.hasScheme(schemeUnix) {
   191  		domainSocket := new(http.Server)
   192  		domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
   193  		domainSocket.Handler = s.handler
   194  		if int64(s.CleanupTimeout) > 0 {
   195  			domainSocket.IdleTimeout = s.CleanupTimeout
   196  		}
   197  
   198  		configureServer(domainSocket, "unix", string(s.SocketPath))
   199  
   200  		servers = append(servers, domainSocket)
   201  		wg.Add(1)
   202  		s.Logf("Serving alertmanager at unix://%s", s.SocketPath)
   203  		go func(l net.Listener) {
   204  			defer wg.Done()
   205  			if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
   206  				s.Fatalf("%v", err)
   207  			}
   208  			s.Logf("Stopped serving alertmanager at unix://%s", s.SocketPath)
   209  		}(s.domainSocketL)
   210  	}
   211  
   212  	if s.hasScheme(schemeHTTP) {
   213  		httpServer := new(http.Server)
   214  		httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
   215  		httpServer.ReadTimeout = s.ReadTimeout
   216  		httpServer.WriteTimeout = s.WriteTimeout
   217  		httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
   218  		if s.ListenLimit > 0 {
   219  			s.httpServerL = netutil.LimitListener(s.httpServerL, s.ListenLimit)
   220  		}
   221  
   222  		if int64(s.CleanupTimeout) > 0 {
   223  			httpServer.IdleTimeout = s.CleanupTimeout
   224  		}
   225  
   226  		httpServer.Handler = s.handler
   227  
   228  		configureServer(httpServer, "http", s.httpServerL.Addr().String())
   229  
   230  		servers = append(servers, httpServer)
   231  		wg.Add(1)
   232  		s.Logf("Serving alertmanager at http://%s", s.httpServerL.Addr())
   233  		go func(l net.Listener) {
   234  			defer wg.Done()
   235  			if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
   236  				s.Fatalf("%v", err)
   237  			}
   238  			s.Logf("Stopped serving alertmanager at http://%s", l.Addr())
   239  		}(s.httpServerL)
   240  	}
   241  
   242  	if s.hasScheme(schemeHTTPS) {
   243  		httpsServer := new(http.Server)
   244  		httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
   245  		httpsServer.ReadTimeout = s.TLSReadTimeout
   246  		httpsServer.WriteTimeout = s.TLSWriteTimeout
   247  		httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
   248  		if s.TLSListenLimit > 0 {
   249  			s.httpsServerL = netutil.LimitListener(s.httpsServerL, s.TLSListenLimit)
   250  		}
   251  		if int64(s.CleanupTimeout) > 0 {
   252  			httpsServer.IdleTimeout = s.CleanupTimeout
   253  		}
   254  		httpsServer.Handler = s.handler
   255  
   256  		// Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
   257  		httpsServer.TLSConfig = &tls.Config{
   258  			// Causes servers to use Go's default ciphersuite preferences,
   259  			// which are tuned to avoid attacks. Does nothing on clients.
   260  			PreferServerCipherSuites: true,
   261  			// Only use curves which have assembly implementations
   262  			// https://github.com/golang/go/tree/master/src/crypto/elliptic
   263  			CurvePreferences: []tls.CurveID{tls.CurveP256},
   264  			// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
   265  			NextProtos: []string{"h2", "http/1.1"},
   266  			// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
   267  			MinVersion: tls.VersionTLS12,
   268  			// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
   269  			CipherSuites: []uint16{
   270  				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   271  				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   272  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   273  				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   274  				tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   275  				tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
   276  			},
   277  		}
   278  
   279  		// build standard config from server options
   280  		if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
   281  			httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
   282  			httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(string(s.TLSCertificate), string(s.TLSCertificateKey))
   283  			if err != nil {
   284  				return err
   285  			}
   286  		}
   287  
   288  		if s.TLSCACertificate != "" {
   289  			// include specified CA certificate
   290  			caCert, caCertErr := os.ReadFile(string(s.TLSCACertificate))
   291  			if caCertErr != nil {
   292  				return caCertErr
   293  			}
   294  			caCertPool := x509.NewCertPool()
   295  			ok := caCertPool.AppendCertsFromPEM(caCert)
   296  			if !ok {
   297  				return fmt.Errorf("cannot parse CA certificate")
   298  			}
   299  			httpsServer.TLSConfig.ClientCAs = caCertPool
   300  			httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
   301  		}
   302  
   303  		// call custom TLS configurator
   304  		configureTLS(httpsServer.TLSConfig)
   305  
   306  		if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
   307  			// after standard and custom config are passed, this ends up with no certificate
   308  			if s.TLSCertificate == "" {
   309  				if s.TLSCertificateKey == "" {
   310  					s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
   311  				}
   312  				s.Fatalf("the required flag `--tls-certificate` was not specified")
   313  			}
   314  			if s.TLSCertificateKey == "" {
   315  				s.Fatalf("the required flag `--tls-key` was not specified")
   316  			}
   317  			// this happens with a wrong custom TLS configurator
   318  			s.Fatalf("no certificate was configured for TLS")
   319  		}
   320  
   321  		configureServer(httpsServer, "https", s.httpsServerL.Addr().String())
   322  
   323  		servers = append(servers, httpsServer)
   324  		wg.Add(1)
   325  		s.Logf("Serving alertmanager at https://%s", s.httpsServerL.Addr())
   326  		go func(l net.Listener) {
   327  			defer wg.Done()
   328  			if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
   329  				s.Fatalf("%v", err)
   330  			}
   331  			s.Logf("Stopped serving alertmanager at https://%s", l.Addr())
   332  		}(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig))
   333  	}
   334  
   335  	wg.Add(1)
   336  	go s.handleShutdown(wg, &servers)
   337  
   338  	wg.Wait()
   339  	return nil
   340  }
   341  
   342  // Listen creates the listeners for the server
   343  func (s *Server) Listen() error {
   344  	if s.hasListeners { // already done this
   345  		return nil
   346  	}
   347  
   348  	if s.hasScheme(schemeHTTPS) {
   349  		// Use http host if https host wasn't defined
   350  		if s.TLSHost == "" {
   351  			s.TLSHost = s.Host
   352  		}
   353  		// Use http listen limit if https listen limit wasn't defined
   354  		if s.TLSListenLimit == 0 {
   355  			s.TLSListenLimit = s.ListenLimit
   356  		}
   357  		// Use http tcp keep alive if https tcp keep alive wasn't defined
   358  		if int64(s.TLSKeepAlive) == 0 {
   359  			s.TLSKeepAlive = s.KeepAlive
   360  		}
   361  		// Use http read timeout if https read timeout wasn't defined
   362  		if int64(s.TLSReadTimeout) == 0 {
   363  			s.TLSReadTimeout = s.ReadTimeout
   364  		}
   365  		// Use http write timeout if https write timeout wasn't defined
   366  		if int64(s.TLSWriteTimeout) == 0 {
   367  			s.TLSWriteTimeout = s.WriteTimeout
   368  		}
   369  	}
   370  
   371  	if s.hasScheme(schemeUnix) {
   372  		domSockListener, err := net.Listen("unix", string(s.SocketPath))
   373  		if err != nil {
   374  			return err
   375  		}
   376  		s.domainSocketL = domSockListener
   377  	}
   378  
   379  	if s.hasScheme(schemeHTTP) {
   380  		listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
   381  		if err != nil {
   382  			return err
   383  		}
   384  
   385  		h, p, err := swag.SplitHostPort(listener.Addr().String())
   386  		if err != nil {
   387  			return err
   388  		}
   389  		s.Host = h
   390  		s.Port = p
   391  		s.httpServerL = listener
   392  	}
   393  
   394  	if s.hasScheme(schemeHTTPS) {
   395  		tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort)))
   396  		if err != nil {
   397  			return err
   398  		}
   399  
   400  		sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
   401  		if err != nil {
   402  			return err
   403  		}
   404  		s.TLSHost = sh
   405  		s.TLSPort = sp
   406  		s.httpsServerL = tlsListener
   407  	}
   408  
   409  	s.hasListeners = true
   410  	return nil
   411  }
   412  
   413  // Shutdown server and clean up resources
   414  func (s *Server) Shutdown() error {
   415  	if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) {
   416  		close(s.shutdown)
   417  	}
   418  	return nil
   419  }
   420  
   421  func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) {
   422  	// wg.Done must occur last, after s.api.ServerShutdown()
   423  	// (to preserve old behaviour)
   424  	defer wg.Done()
   425  
   426  	<-s.shutdown
   427  
   428  	servers := *serversPtr
   429  
   430  	ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
   431  	defer cancel()
   432  
   433  	// first execute the pre-shutdown hook
   434  	s.api.PreServerShutdown()
   435  
   436  	shutdownChan := make(chan bool)
   437  	for i := range servers {
   438  		server := servers[i]
   439  		go func() {
   440  			var success bool
   441  			defer func() {
   442  				shutdownChan <- success
   443  			}()
   444  			if err := server.Shutdown(ctx); err != nil {
   445  				// Error from closing listeners, or context timeout:
   446  				s.Logf("HTTP server Shutdown: %v", err)
   447  			} else {
   448  				success = true
   449  			}
   450  		}()
   451  	}
   452  
   453  	// Wait until all listeners have successfully shut down before calling ServerShutdown
   454  	success := true
   455  	for range servers {
   456  		success = success && <-shutdownChan
   457  	}
   458  	if success {
   459  		s.api.ServerShutdown()
   460  	}
   461  }
   462  
   463  // GetHandler returns a handler useful for testing
   464  func (s *Server) GetHandler() http.Handler {
   465  	return s.handler
   466  }
   467  
   468  // SetHandler allows for setting a http handler on this server
   469  func (s *Server) SetHandler(handler http.Handler) {
   470  	s.handler = handler
   471  }
   472  
   473  // UnixListener returns the domain socket listener
   474  func (s *Server) UnixListener() (net.Listener, error) {
   475  	if !s.hasListeners {
   476  		if err := s.Listen(); err != nil {
   477  			return nil, err
   478  		}
   479  	}
   480  	return s.domainSocketL, nil
   481  }
   482  
   483  // HTTPListener returns the http listener
   484  func (s *Server) HTTPListener() (net.Listener, error) {
   485  	if !s.hasListeners {
   486  		if err := s.Listen(); err != nil {
   487  			return nil, err
   488  		}
   489  	}
   490  	return s.httpServerL, nil
   491  }
   492  
   493  // TLSListener returns the https listener
   494  func (s *Server) TLSListener() (net.Listener, error) {
   495  	if !s.hasListeners {
   496  		if err := s.Listen(); err != nil {
   497  			return nil, err
   498  		}
   499  	}
   500  	return s.httpsServerL, nil
   501  }
   502  
   503  func handleInterrupt(once *sync.Once, s *Server) {
   504  	once.Do(func() {
   505  		for range s.interrupt {
   506  			if s.interrupted {
   507  				s.Logf("Server already shutting down")
   508  				continue
   509  			}
   510  			s.interrupted = true
   511  			s.Logf("Shutting down... ")
   512  			if err := s.Shutdown(); err != nil {
   513  				s.Logf("HTTP server Shutdown: %v", err)
   514  			}
   515  		}
   516  	})
   517  }
   518  
   519  func signalNotify(interrupt chan<- os.Signal) {
   520  	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
   521  }
   522  

View as plain text