Skip to content

Commit

Permalink
health: Introduces health and version endpoints
Browse files Browse the repository at this point in the history
Signed-off-by: arekkas <[email protected]>
  • Loading branch information
arekkas authored and arekkas committed Jul 21, 2018
1 parent f14c8ed commit 6a9da74
Show file tree
Hide file tree
Showing 86 changed files with 2,969 additions and 226 deletions.
3 changes: 3 additions & 0 deletions cmd/server/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/ory/graceful"
"github.com/ory/herodot"
"github.com/ory/keto/authentication"
"github.com/ory/keto/health"
"github.com/ory/keto/policy"
"github.com/ory/keto/role"
"github.com/ory/keto/warden"
Expand Down Expand Up @@ -98,10 +99,12 @@ func RunServe(
roleHandler := role.NewHandler(m.roleManager, writer)
policyHandler := policy.NewHandler(m.policyManager, writer)
wardenHandler := warden.NewHandler(writer, firewall, authenticators)
healthHandler := health.NewHandler(writer, buildVersion, m.readyCheckers)

roleHandler.SetRoutes(router)
policyHandler.SetRoutes(router)
wardenHandler.SetRoutes(router)
healthHandler.SetRoutes(router)

n := negroni.New()
n.Use(negronilogrus.NewMiddlewareFromLogger(logger, "keto"))
Expand Down
12 changes: 12 additions & 0 deletions cmd/server/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
"github.com/ory/keto/health"
"github.com/ory/keto/role"
"github.com/ory/ladon"
"github.com/ory/ladon/manager/memory"
Expand All @@ -39,11 +40,17 @@ import (
type managers struct {
roleManager role.Manager
policyManager ladon.Manager
readyCheckers map[string]health.ReadyChecker
}

func newManagers(db string, logger logrus.FieldLogger) (*managers, error) {
if db == "memory" {
return &managers{
readyCheckers: map[string]health.ReadyChecker{
"database": func() error {
return nil
},
},
roleManager: role.NewMemoryManager(),
policyManager: memory.NewMemoryManager(),
}, nil
Expand All @@ -66,6 +73,11 @@ func newManagers(db string, logger logrus.FieldLogger) (*managers, error) {
}

return &managers{
readyCheckers: map[string]health.ReadyChecker{
"database": func() error {
return sdb.GetDatabase().Ping()
},
},
roleManager: role.NewSQLManager(sdb.GetDatabase()),
policyManager: sql.NewSQLManager(sdb.GetDatabase(), nil),
}, nil
Expand Down
115 changes: 101 additions & 14 deletions docs/api.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,51 @@
},
"basePath": "/",
"paths": {
"/health/alive": {
"get": {
"description": "This endpoint returns a 200 status code when the HTTP server is up running.\nThis status does currently not include checks whether the database connection is working.\nThis endpoint does not require the `X-Forwarded-Proto` header when TLS termination is set.\n\nBe aware that if you are running multiple nodes of ORY Keto, the health status will never refer to the cluster state, only to a single instance.",
"tags": [
"health"
],
"summary": "Check the Alive Status",
"operationId": "isInstanceAlive",
"responses": {
"200": {
"description": "healthStatus",
"schema": {
"$ref": "#/definitions/healthStatus"
}
},
"500": {
"$ref": "#/responses/genericError"
}
}
}
},
"/health/ready": {
"get": {
"description": "This endpoint returns a 200 status code when the HTTP server is up running and the environment dependencies (e.g.\nthe database) are responsive as well.\n\nThis status does currently not include checks whether the database connection is working.\nThis endpoint does not require the `X-Forwarded-Proto` header when TLS termination is set.\n\nBe aware that if you are running multiple nodes of ORY Keto, the health status will never refer to the cluster state, only to a single instance.",
"tags": [
"health"
],
"summary": "Check the Readiness Status",
"operationId": "isInstanceReady",
"responses": {
"200": {
"description": "healthStatus",
"schema": {
"$ref": "#/definitions/healthStatus"
}
},
"503": {
"description": "healthNotReadyStatus",
"schema": {
"$ref": "#/definitions/healthNotReadyStatus"
}
}
}
}
},
"/policies": {
"get": {
"description": "List Access Control Policies",
Expand Down Expand Up @@ -165,13 +210,6 @@
}
},
"put": {
"security": [
{
"oauth2": [
"hydra.policies"
]
}
],
"description": "Update an Access Control Policy",
"consumes": [
"application/json"
Expand Down Expand Up @@ -223,13 +261,6 @@
}
},
"delete": {
"security": [
{
"oauth2": [
"hydra.policies"
]
}
],
"description": "Delete an Access Control Policy",
"consumes": [
"application/json"
Expand Down Expand Up @@ -595,6 +626,24 @@
}
}
},
"/version": {
"get": {
"description": "This endpoint returns the version as `{ \"version\": \"VERSION\" }`. The version is only correct with the prebuilt binary and not custom builds.",
"tags": [
"version"
],
"summary": "Get the version of Keto",
"operationId": "getVersion",
"responses": {
"200": {
"description": "version",
"schema": {
"$ref": "#/definitions/version"
}
}
}
}
},
"/warden/oauth2/access-tokens/authorize": {
"post": {
"description": "Checks if a token is valid and if the token subject is allowed to perform an action on a resource.\nThis endpoint requires a token, a scope, a resource name, an action name and a context.\n\n\nIf a token is expired/invalid, has not been granted the requested scope or the subject is not allowed to\nperform the action on the resource, this endpoint returns a 200 response with `{ \"allowed\": false }`.\n\n\nThis endpoint passes all data from the upstream OAuth 2.0 token introspection endpoint. If you use ORY Hydra as an\nupstream OAuth 2.0 provider, data set through the `accessTokenExtra` field in the consent flow will be included in this\nresponse as well.",
Expand Down Expand Up @@ -1022,6 +1071,33 @@
"x-go-name": "OAuth2Session",
"x-go-package": "github.com/ory/keto/authentication"
},
"healthNotReadyStatus": {
"type": "object",
"properties": {
"errors": {
"description": "Errors contains a list of errors that caused the not ready status.",
"type": "object",
"additionalProperties": {
"type": "string"
},
"x-go-name": "Errors"
}
},
"x-go-name": "swaggerNotReadyStatus",
"x-go-package": "github.com/ory/keto/health"
},
"healthStatus": {
"type": "object",
"properties": {
"status": {
"description": "Status always contains \"ok\".",
"type": "string",
"x-go-name": "Status"
}
},
"x-go-name": "swaggerHealthStatus",
"x-go-package": "github.com/ory/keto/health"
},
"policy": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -1242,6 +1318,17 @@
},
"x-go-package": "github.com/ory/keto/warden"
},
"version": {
"type": "object",
"properties": {
"version": {
"type": "string",
"x-go-name": "Version"
}
},
"x-go-name": "swaggerVersion",
"x-go-package": "github.com/ory/keto/health"
},
"wardenOAuth2AccessTokenAuthorizationRequest": {
"type": "object",
"properties": {
Expand Down
38 changes: 38 additions & 0 deletions health/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <[email protected]>
* @copyright 2015-2018 Aeneas Rekkas <[email protected]>
* @license Apache-2.0
*/

package health

// swagger:model healthStatus
type swaggerHealthStatus struct {
// Status always contains "ok".
Status string `json:"status"`
}

// swagger:model healthNotReadyStatus
type swaggerNotReadyStatus struct {
// Errors contains a list of errors that caused the not ready status.
Errors map[string]string `json:"errors"`
}

// swagger:model version
type swaggerVersion struct {
Version string `json:"version"`
}
129 changes: 129 additions & 0 deletions health/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <[email protected]>
* @copyright 2015-2018 Aeneas Rekkas <[email protected]>
* @license Apache-2.0
*/

package health

import (
"net/http"

"github.com/julienschmidt/httprouter"
"github.com/ory/herodot"
)

const (
AliveCheckPath = "/health/alive"
ReadyCheckPath = "/health/ready"
VersionPath = "/version"
)

type ReadyChecker func() error

type Handler struct {
H *herodot.JSONWriter
VersionString string
ReadyChecks map[string]ReadyChecker
}

func NewHandler(
h *herodot.JSONWriter,
version string,
readyChecks map[string]ReadyChecker,
) *Handler {
return &Handler{
H: h,
VersionString: version,
ReadyChecks: readyChecks,
}
}

func (h *Handler) SetRoutes(r *httprouter.Router) {
r.GET(AliveCheckPath, h.Alive)
r.GET(ReadyCheckPath, h.Ready)
r.GET(VersionPath, h.Version)
}

// swagger:route GET /health/alive health isInstanceAlive
//
// Check the Alive Status
//
// This endpoint returns a 200 status code when the HTTP server is up running.
// This status does currently not include checks whether the database connection is working.
// This endpoint does not require the `X-Forwarded-Proto` header when TLS termination is set.
//
// Be aware that if you are running multiple nodes of ORY Keto, the health status will never refer to the cluster state, only to a single instance.
//
// Responses:
// 200: healthStatus
// 500: genericError
func (h *Handler) Alive(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
h.H.Write(rw, r, &swaggerHealthStatus{
Status: "ok",
})
}

// swagger:route GET /health/ready health isInstanceReady
//
// Check the Readiness Status
//
// This endpoint returns a 200 status code when the HTTP server is up running and the environment dependencies (e.g.
// the database) are responsive as well.
//
// This status does currently not include checks whether the database connection is working.
// This endpoint does not require the `X-Forwarded-Proto` header when TLS termination is set.
//
// Be aware that if you are running multiple nodes of ORY Keto, the health status will never refer to the cluster state, only to a single instance.
//
// Responses:
// 200: healthStatus
// 503: healthNotReadyStatus
func (h *Handler) Ready(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
var notReady = swaggerNotReadyStatus{
Errors: map[string]string{},
}

for n, c := range h.ReadyChecks {
if err := c(); err != nil {
notReady.Errors[n] = err.Error()
}
}

if len(notReady.Errors) > 0 {
h.H.WriteCode(rw, r, http.StatusServiceUnavailable, notReady)
return
}

h.H.Write(rw, r, &swaggerHealthStatus{
Status: "ok",
})
}

// swagger:route GET /version version getVersion
//
// Get the version of Keto
//
// This endpoint returns the version as `{ "version": "VERSION" }`. The version is only correct with the prebuilt binary and not custom builds.
//
// Responses:
// 200: version
func (h *Handler) Version(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
h.H.Write(rw, r, &swaggerVersion{
Version: h.VersionString,
})
}
Loading

0 comments on commit 6a9da74

Please sign in to comment.