...

Source file src/github.com/ory/x/healthx/handler.go

Documentation: github.com/ory/x/healthx

     1  /*
     2   * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
     3   *
     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   * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
    17   * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
    18   * @license 	Apache-2.0
    19   */
    20  
    21  package healthx
    22  
    23  import (
    24  	"net/http"
    25  
    26  	"github.com/julienschmidt/httprouter"
    27  
    28  	"github.com/ory/herodot"
    29  )
    30  
    31  const (
    32  	// AliveCheckPath is the path where information about the life state of the instance is provided.
    33  	AliveCheckPath = "/health/alive"
    34  	// ReadyCheckPath is the path where information about the rady state of the instance is provided.
    35  	ReadyCheckPath = "/health/ready"
    36  	// VersionPath is the path where information about the software version of the instance is provided.
    37  	VersionPath = "/version"
    38  )
    39  
    40  // RoutesToObserve returns a string of all the available routes of this module.
    41  func RoutesToObserve() []string {
    42  	return []string{
    43  		AliveCheckPath,
    44  		ReadyCheckPath,
    45  		VersionPath,
    46  	}
    47  }
    48  
    49  // ReadyChecker should return an error if the component is not ready yet.
    50  type ReadyChecker func(r *http.Request) error
    51  
    52  // ReadyCheckers is a map of ReadyCheckers.
    53  type ReadyCheckers map[string]ReadyChecker
    54  
    55  // NoopReadyChecker is always ready.
    56  func NoopReadyChecker() error {
    57  	return nil
    58  }
    59  
    60  // Handler handles HTTP requests to health and version endpoints.
    61  type Handler struct {
    62  	H             herodot.Writer
    63  	VersionString string
    64  	ReadyChecks   ReadyCheckers
    65  }
    66  
    67  // NewHandler instantiates a handler.
    68  func NewHandler(
    69  	h herodot.Writer,
    70  	version string,
    71  	readyChecks ReadyCheckers,
    72  ) *Handler {
    73  	return &Handler{
    74  		H:             h,
    75  		VersionString: version,
    76  		ReadyChecks:   readyChecks,
    77  	}
    78  }
    79  
    80  // SetHealthRoutes registers this handler's routes for health checking.
    81  func (h *Handler) SetHealthRoutes(r *httprouter.Router, shareErrors bool) {
    82  	r.GET(AliveCheckPath, h.Alive)
    83  	r.GET(ReadyCheckPath, h.Ready(shareErrors))
    84  }
    85  
    86  // SetHealthRoutes registers this handler's routes for health checking.
    87  func (h *Handler) SetVersionRoutes(r *httprouter.Router) {
    88  	r.GET(VersionPath, h.Version)
    89  }
    90  
    91  // Alive returns an ok status if the instance is ready to handle HTTP requests.
    92  //
    93  // swagger:route GET /health/alive health isInstanceAlive
    94  //
    95  // Check alive status
    96  //
    97  // This endpoint returns a 200 status code when the HTTP server is up running.
    98  // This status does currently not include checks whether the database connection is working.
    99  //
   100  // If the service supports TLS Edge Termination, this endpoint does not require the
   101  // `X-Forwarded-Proto` header to be set.
   102  //
   103  // Be aware that if you are running multiple nodes of this service, the health status will never
   104  // refer to the cluster state, only to a single instance.
   105  //
   106  //     Produces:
   107  //     - application/json
   108  //
   109  //     Responses:
   110  //       200: healthStatus
   111  //       500: genericError
   112  func (h *Handler) Alive(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
   113  	h.H.Write(rw, r, &swaggerHealthStatus{
   114  		Status: "ok",
   115  	})
   116  }
   117  
   118  // Ready returns an ok status if the instance is ready to handle HTTP requests and all ReadyCheckers are ok.
   119  //
   120  // swagger:route GET /health/ready health isInstanceReady
   121  //
   122  // Check readiness status
   123  //
   124  // This endpoint returns a 200 status code when the HTTP server is up running and the environment dependencies (e.g.
   125  // the database) are responsive as well.
   126  //
   127  // If the service supports TLS Edge Termination, this endpoint does not require the
   128  // `X-Forwarded-Proto` header to be set.
   129  //
   130  // Be aware that if you are running multiple nodes of this service, the health status will never
   131  // refer to the cluster state, only to a single instance.
   132  //
   133  //     Produces:
   134  //     - application/json
   135  //
   136  //     Responses:
   137  //       200: healthStatus
   138  //       503: healthNotReadyStatus
   139  func (h *Handler) Ready(shareErrors bool) httprouter.Handle {
   140  	return func(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
   141  		var notReady = swaggerNotReadyStatus{
   142  			Errors: map[string]string{},
   143  		}
   144  
   145  		for n, c := range h.ReadyChecks {
   146  			if err := c(r); err != nil {
   147  				if shareErrors {
   148  					notReady.Errors[n] = err.Error()
   149  				} else {
   150  					notReady.Errors[n] = "error may contain sensitive information and was obfuscated"
   151  				}
   152  			}
   153  		}
   154  
   155  		if len(notReady.Errors) > 0 {
   156  			h.H.WriteCode(rw, r, http.StatusServiceUnavailable, notReady)
   157  			return
   158  		}
   159  
   160  		h.H.Write(rw, r, &swaggerHealthStatus{
   161  			Status: "ok",
   162  		})
   163  	}
   164  }
   165  
   166  // Version returns this service's versions.
   167  //
   168  // swagger:route GET /version version getVersion
   169  //
   170  // Get service version
   171  //
   172  // This endpoint returns the service version typically notated using semantic versioning.
   173  //
   174  // If the service supports TLS Edge Termination, this endpoint does not require the
   175  // `X-Forwarded-Proto` header to be set.
   176  //
   177  // Be aware that if you are running multiple nodes of this service, the health status will never
   178  // refer to the cluster state, only to a single instance.
   179  //
   180  //     Produces:
   181  //     - application/json
   182  //
   183  //	   Responses:
   184  // 			200: version
   185  func (h *Handler) Version(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
   186  	h.H.Write(rw, r, &swaggerVersion{
   187  		Version: h.VersionString,
   188  	})
   189  }
   190  

View as plain text