mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-24 13:48:49 +08:00
MF-1308 - Use IETF Health Check standard (#1541)
* MF-1308 - Use IETF Health Check standard Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add nginx health endpoint Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Rm github.com/nelkinda dependency Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Check error Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Replace Version by Health in the CLI and SDK Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Use new build flag go:build Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Revert wrong renaming Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * sdk health test Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add /health endpoint to openapi doc Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Use const for description message Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add version and build time during build Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Time format Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add version and commit using git and build args Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add comments Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add tests Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add missing api properties Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix api Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Use ./schemas/HealthInfo.yml as Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix example Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Use content type application/health+json Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Set Makefile variables only if empty Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
This commit is contained in:
parent
bcc8cf7119
commit
42dd813521
13
Makefile
13
Makefile
@ -10,9 +10,17 @@ DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
CGO_ENABLED ?= 0
|
||||
GOARCH ?= amd64
|
||||
VERSION ?= $(shell git describe --abbrev=0 --tags)
|
||||
COMMIT ?= $(shell git rev-parse HEAD)
|
||||
TIME ?= $(shell date +%F_%T)
|
||||
|
||||
define compile_service
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) go build -mod=vendor -ldflags "-s -w" -o ${BUILD_DIR}/mainflux-$(1) cmd/$(1)/main.go
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
|
||||
go build -mod=vendor -ldflags "-s -w \
|
||||
-X 'github.com/mainflux/mainflux.BuildTime=$(TIME)' \
|
||||
-X 'github.com/mainflux/mainflux.Version=$(VERSION)' \
|
||||
-X 'github.com/mainflux/mainflux.Commit=$(COMMIT)'" \
|
||||
-o ${BUILD_DIR}/mainflux-$(1) cmd/$(1)/main.go
|
||||
endef
|
||||
|
||||
define make_docker
|
||||
@ -23,6 +31,9 @@ define make_docker
|
||||
--build-arg SVC=$(svc) \
|
||||
--build-arg GOARCH=$(GOARCH) \
|
||||
--build-arg GOARM=$(GOARM) \
|
||||
--build-arg VERSION=$(VERSION) \
|
||||
--build-arg COMMIT=$(COMMIT) \
|
||||
--build-arg TIME=$(TIME) \
|
||||
--tag=$(MF_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
-f docker/Dockerfile .
|
||||
endef
|
||||
|
21
api/auth.yml
21
api/auth.yml
@ -87,7 +87,7 @@ paths:
|
||||
summary: Gets all groups.
|
||||
description: |
|
||||
Gets all groups up to a max level of hierarchy that can be fetched in one
|
||||
request ( max level = 5). Result can be filtered by metadata. Groups will
|
||||
request ( max level = 5). Result can be filtered by metadata. Groups will
|
||||
be returned as JSON array or JSON tree.
|
||||
tags:
|
||||
- auth
|
||||
@ -154,7 +154,7 @@ paths:
|
||||
summary: Deletes group.
|
||||
description: |
|
||||
Deletes group. If group is parent and descendant groups do not have any members
|
||||
child groups will be deleted. Group cannot be deleted if has members or if
|
||||
child groups will be deleted. Group cannot be deleted if has members or if
|
||||
any descendant group has members.
|
||||
tags:
|
||||
- auth
|
||||
@ -354,6 +354,17 @@ paths:
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Key:
|
||||
@ -736,3 +747,9 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MembershipPage"
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -224,6 +224,16 @@ paths:
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
@ -514,3 +524,9 @@ components:
|
||||
$ref: "#/components/schemas/BootstrapConfig"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -10,7 +10,7 @@ paths:
|
||||
summary: Creates a certificate for thing
|
||||
description: Creates a certificate for thing
|
||||
tags:
|
||||
- Thing to proxy
|
||||
- certs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Authorization"
|
||||
requestBody:
|
||||
@ -28,7 +28,7 @@ paths:
|
||||
description: |
|
||||
Retrieves a certificate for a given cert ID.
|
||||
tags:
|
||||
- configs
|
||||
- certs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Authorization"
|
||||
- $ref: "#/components/parameters/CertID"
|
||||
@ -45,7 +45,7 @@ paths:
|
||||
description: |
|
||||
Revokes a certificate for a given cert ID.
|
||||
tags:
|
||||
- configs
|
||||
- certs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Authorization"
|
||||
- $ref: "#/components/parameters/CertID"
|
||||
@ -63,7 +63,7 @@ paths:
|
||||
description: |
|
||||
Retrieves a list of certificates' serial IDs for a given thing ID.
|
||||
tags:
|
||||
- configs
|
||||
- certs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Authorization"
|
||||
- $ref: "#/components/parameters/ThingID"
|
||||
@ -75,6 +75,16 @@ paths:
|
||||
Failed to retrieve corresponding certificates.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
parameters:
|
||||
@ -228,3 +238,9 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Revoke"
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -79,6 +79,16 @@ paths:
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
@ -204,3 +214,9 @@ components:
|
||||
$ref: "#/components/schemas/Page"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
25
api/http.yml
25
api/http.yml
@ -30,8 +30,18 @@ paths:
|
||||
description: Message discarded due to invalid channel id.
|
||||
"415":
|
||||
description: Message discarded due to invalid or missing content type.
|
||||
"500":
|
||||
description: Unexpected server-side error occurred.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
@ -104,6 +114,7 @@ components:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: Authorization
|
||||
|
||||
parameters:
|
||||
ID:
|
||||
name: id
|
||||
@ -127,3 +138,13 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/SenMLArray"
|
||||
|
||||
responses:
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -40,9 +40,18 @@ paths:
|
||||
description: Unauthorized.
|
||||
'500':
|
||||
description: Unexpected server-side error ocurred.
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
|
||||
parameters:
|
||||
Authorization:
|
||||
name: Authorization
|
||||
@ -78,3 +87,9 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -37,6 +37,16 @@ paths:
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
@ -210,6 +220,11 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MessagesPage"
|
||||
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
23
api/schemas/HealthInfo.yml
Normal file
23
api/schemas/HealthInfo.yml
Normal file
@ -0,0 +1,23 @@
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
description: Service status.
|
||||
enum:
|
||||
- pass
|
||||
version:
|
||||
type: string
|
||||
description: Service version.
|
||||
example: 0.0.1
|
||||
commit:
|
||||
type: string
|
||||
description: Service commit hash.
|
||||
example: 7d6f4dc4f7f0c1fa3dc24eddfb18bb5073ff4f62
|
||||
description:
|
||||
type: string
|
||||
description: Service description.
|
||||
example: <service_name> service
|
||||
build_time:
|
||||
type: string
|
||||
description: Service build time.
|
||||
example: 1970-01-01_00:00:00
|
@ -621,6 +621,17 @@ paths:
|
||||
description: Database can't process request.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Key:
|
||||
@ -1096,3 +1107,9 @@ components:
|
||||
schema:
|
||||
type: string
|
||||
format: byte
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -140,6 +140,16 @@ paths:
|
||||
description: Twin does not exist.
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
parameters:
|
||||
@ -365,3 +375,9 @@ components:
|
||||
$ref: '#/components/schemas/StatesPage'
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -25,7 +25,7 @@ paths:
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
summary: Retrieves users
|
||||
description: |
|
||||
@ -221,6 +221,16 @@ paths:
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
@ -303,6 +313,7 @@ components:
|
||||
error:
|
||||
type: string
|
||||
description: Error message
|
||||
|
||||
parameters:
|
||||
Authorization:
|
||||
name: Authorization
|
||||
@ -454,3 +465,9 @@ components:
|
||||
$ref: "#/components/schemas/UsersPage"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
@ -15,12 +15,13 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler(svc auth.Service, tracer opentracing.Tracer) http.Handler {
|
||||
mux := bone.New()
|
||||
mux = keys.MakeHandler(svc, mux, tracer)
|
||||
mux = groups.MakeHandler(svc, mux, tracer)
|
||||
mux = policies.MakeHandler(svc, mux, tracer)
|
||||
mux.GetFunc("/version", mainflux.Version("auth"))
|
||||
mux.GetFunc("/health", mainflux.Health("auth"))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
return mux
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -100,7 +100,7 @@ func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader) http.Hand
|
||||
encodeResponse,
|
||||
opts...))
|
||||
|
||||
r.GetFunc("/version", mainflux.Version("bootstrap"))
|
||||
r.GetFunc("/health", mainflux.Health("bootstrap"))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -68,7 +68,7 @@ func MakeHandler(svc certs.Service) http.Handler {
|
||||
))
|
||||
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
r.GetFunc("/version", mainflux.Version("certs"))
|
||||
r.GetFunc("/health", mainflux.Health("certs"))
|
||||
|
||||
return r
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ make cli
|
||||
|
||||
## Usage
|
||||
### Service
|
||||
#### Get the version of Mainflux services
|
||||
#### Get Mainflux Things services Health Check
|
||||
```bash
|
||||
mainflux-cli version
|
||||
mainflux-cli health
|
||||
```
|
||||
|
||||
### Users management
|
||||
@ -239,4 +239,4 @@ mainflux-cli groups members <group_id> <user_auth_token>
|
||||
#### List groups that user belongs to
|
||||
```bash
|
||||
mainflux-cli groups membership <user_id> <user_auth_token>
|
||||
```
|
||||
```
|
||||
|
@ -5,14 +5,14 @@ package cli
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// NewVersionCmd returns version command.
|
||||
func NewVersionCmd() *cobra.Command {
|
||||
// NewHealthCmd returns health check command.
|
||||
func NewHealthCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Mainflux services version",
|
||||
Long: `Mainflux services version: get version of Mainflux Things Service`,
|
||||
Use: "health",
|
||||
Short: "Health Check",
|
||||
Long: `Mainflux Things service Health Check`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
v, err := sdk.Version()
|
||||
v, err := sdk.Health()
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
@ -41,7 +41,7 @@ func main() {
|
||||
}
|
||||
|
||||
// API commands
|
||||
versionCmd := cli.NewVersionCmd()
|
||||
healthCmd := cli.NewHealthCmd()
|
||||
usersCmd := cli.NewUsersCmd()
|
||||
thingsCmd := cli.NewThingsCmd()
|
||||
groupsCmd := cli.NewGroupsCmd()
|
||||
@ -52,7 +52,7 @@ func main() {
|
||||
certsCmd := cli.NewCertsCmd()
|
||||
|
||||
// Root Commands
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
rootCmd.AddCommand(healthCmd)
|
||||
rootCmd.AddCommand(usersCmd)
|
||||
rootCmd.AddCommand(groupsCmd)
|
||||
rootCmd.AddCommand(thingsCmd)
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -40,10 +40,10 @@ var (
|
||||
service coap.Service
|
||||
)
|
||||
|
||||
//MakeHTTPHandler creates handler for version endpoint.
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHTTPHandler() http.Handler {
|
||||
b := bone.New()
|
||||
b.GetFunc("/version", mainflux.Version(protocol))
|
||||
b.GetFunc("/health", mainflux.Health(protocol))
|
||||
b.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return b
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -59,7 +59,7 @@ func MakeHandler(svc notifiers.Service, tracer opentracing.Tracer) http.Handler
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.GetFunc("/version", mainflux.Version("notifier"))
|
||||
mux.GetFunc("/health", mainflux.Health("notifier"))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return mux
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -13,10 +11,10 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP API handler with version and metrics.
|
||||
// MakeHandler returns a HTTP API handler with health check and metrics.
|
||||
func MakeHandler(svcName string) http.Handler {
|
||||
r := bone.New()
|
||||
r.GetFunc("/version", mainflux.Version(svcName))
|
||||
r.GetFunc("/health", mainflux.Health(svcName))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
|
@ -2,6 +2,9 @@ FROM golang:1.17-alpine AS builder
|
||||
ARG SVC
|
||||
ARG GOARCH
|
||||
ARG GOARM
|
||||
ARG VERSION
|
||||
ARG COMMIT
|
||||
ARG TIME
|
||||
|
||||
WORKDIR /go/src/github.com/mainflux/mainflux
|
||||
COPY . .
|
||||
|
@ -89,7 +89,7 @@ http {
|
||||
proxy_pass http://auth:${MF_AUTH_HTTP_PORT};
|
||||
}
|
||||
|
||||
location /version {
|
||||
location /health {
|
||||
include snippets/proxy-headers.conf;
|
||||
proxy_pass http://things:${MF_THINGS_HTTP_PORT};
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ http {
|
||||
proxy_pass http://auth:${MF_AUTH_HTTP_PORT};
|
||||
}
|
||||
|
||||
location /version {
|
||||
location /health {
|
||||
include snippets/proxy-headers.conf;
|
||||
proxy_pass http://things:${MF_THINGS_HTTP_PORT};
|
||||
}
|
||||
|
74
health.go
Normal file
74
health.go
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mainflux
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
contentType = "Content-Type"
|
||||
contentTypeJSON = "application/health+json"
|
||||
svcStatus = "pass"
|
||||
description = " service"
|
||||
)
|
||||
|
||||
var (
|
||||
// Version represents the last service git tag in git history.
|
||||
// It's meant to be set using go build ldflags:
|
||||
// -ldflags "-X 'github.com/mainflux/mainflux.Version=0.0.0'"
|
||||
Version = "0.0.0"
|
||||
// Commit represents the service git commit hash.
|
||||
// It's meant to be set using go build ldflags:
|
||||
// -ldflags "-X 'github.com/mainflux/mainflux.Commit=ffffffff'"
|
||||
Commit = "ffffffff"
|
||||
// BuildTime represetns the service build time.
|
||||
// It's meant to be set using go build ldflags:
|
||||
// -ldflags "-X 'github.com/mainflux/mainflux.BuildTime=1970-01-01_00:00:00'"
|
||||
BuildTime = "1970-01-01_00:00:00"
|
||||
)
|
||||
|
||||
// HealthInfo contains version endpoint response.
|
||||
type HealthInfo struct {
|
||||
// Status contains service status.
|
||||
Status string `json:"status"`
|
||||
|
||||
// Version contains current service version.
|
||||
Version string `json:"version"`
|
||||
|
||||
// Commit represents the git hash commit.
|
||||
Commit string `json:"commit"`
|
||||
|
||||
// Description contains service description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// BuildTime contains service build time.
|
||||
BuildTime string `json:"build_time"`
|
||||
}
|
||||
|
||||
// Health exposes an HTTP handler for retrieving service health.
|
||||
func Health(service string) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add(contentType, contentTypeJSON)
|
||||
if r.Method != http.MethodGet && r.Method != http.MethodHead {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
res := HealthInfo{
|
||||
Status: svcStatus,
|
||||
Version: Version,
|
||||
Commit: Commit,
|
||||
Description: service + description,
|
||||
BuildTime: BuildTime,
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
if err := json.NewEncoder(w).Encode(res); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -57,7 +57,7 @@ func MakeHandler(svc adapter.Service, tracer opentracing.Tracer) http.Handler {
|
||||
opts...,
|
||||
))
|
||||
|
||||
r.GetFunc("/version", mainflux.Version("http"))
|
||||
r.GetFunc("/health", mainflux.Health("http"))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler() http.Handler {
|
||||
r := bone.New()
|
||||
r.GetFunc("/version", mainflux.Version("lora-adapter"))
|
||||
r.GetFunc("/health", mainflux.Health("lora-adapter"))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -43,7 +43,7 @@ func MakeHandler(svc opcua.Service) http.Handler {
|
||||
opts...,
|
||||
))
|
||||
|
||||
r.GetFunc("/version", mainflux.Version("opcua-adapter"))
|
||||
r.GetFunc("/health", mainflux.Health("opcua-adapter"))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
|
@ -77,6 +77,6 @@ func (sdk mfSDK) UpdateChannel(channel Channel, token string) error
|
||||
func (sdk mfSDK) UpdateThing(thing Thing, token string) error
|
||||
UpdateThing - updates thing by ID
|
||||
|
||||
func (sdk mfSDK) Version() (string, error)
|
||||
Version - server health check
|
||||
func (sdk mfSDK) Health() (mainflux.Health, error)
|
||||
Health - things service health check
|
||||
```
|
||||
|
40
pkg/sdk/go/health.go
Normal file
40
pkg/sdk/go/health.go
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
)
|
||||
|
||||
func (sdk mfSDK) Health() (mainflux.HealthInfo, error) {
|
||||
url := fmt.Sprintf("%s/health", sdk.thingsURL)
|
||||
|
||||
resp, err := sdk.client.Get(url)
|
||||
if err != nil {
|
||||
return mainflux.HealthInfo{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return mainflux.HealthInfo{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return mainflux.HealthInfo{}, errors.Wrap(ErrFetchHealth, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var h mainflux.HealthInfo
|
||||
if err := json.Unmarshal(body, &h); err != nil {
|
||||
return mainflux.HealthInfo{}, err
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
47
pkg/sdk/go/health_test.go
Normal file
47
pkg/sdk/go/health_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
thingsDescription = "things service"
|
||||
thingsStatus = "pass"
|
||||
)
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
svc := newThingsService(map[string]string{token: email})
|
||||
ts := newThingsServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
sdkConf := sdk.Config{
|
||||
ThingsURL: ts.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mainfluxSDK := sdk.NewSDK(sdkConf)
|
||||
cases := map[string]struct {
|
||||
empty bool
|
||||
err error
|
||||
}{
|
||||
"get things service health check": {
|
||||
empty: false,
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
for desc, tc := range cases {
|
||||
h, err := mainfluxSDK.Health()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", desc, tc.err, err))
|
||||
assert.Equal(t, thingsStatus, h.Status, fmt.Sprintf("%s: expected %s status, got %s", desc, thingsStatus, h.Status))
|
||||
assert.Equal(t, tc.empty, h.Version == "", fmt.Sprintf("%s: expected non-empty version", desc))
|
||||
assert.Equal(t, mainflux.Commit, h.Commit, fmt.Sprintf("%s: expected non-empty commit", desc))
|
||||
assert.Equal(t, thingsDescription, h.Description, fmt.Sprintf("%s: expected proper description, got %s", desc, h.Description))
|
||||
assert.Equal(t, mainflux.BuildTime, h.BuildTime, fmt.Sprintf("%s: expected default epoch date, got %s", desc, h.BuildTime))
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -53,8 +55,8 @@ var (
|
||||
// was passed.
|
||||
ErrInvalidContentType = errors.New("Unknown Content Type")
|
||||
|
||||
// ErrFetchVersion indicates that fetching of version failed.
|
||||
ErrFetchVersion = errors.New("failed to fetch version")
|
||||
// ErrFetchHealth indicates that fetching of health check failed.
|
||||
ErrFetchHealth = errors.New("failed to fetch health check")
|
||||
|
||||
// ErrFailedWhitelist failed to whitelist configs
|
||||
ErrFailedWhitelist = errors.New("failed to whitelist")
|
||||
@ -234,8 +236,8 @@ type SDK interface {
|
||||
// SetContentType sets message content type.
|
||||
SetContentType(ct ContentType) error
|
||||
|
||||
// Version returns used mainflux version.
|
||||
Version() (string, error)
|
||||
// Health returns things service health check.
|
||||
Health() (mainflux.HealthInfo, error)
|
||||
|
||||
// AddBootstrap add bootstrap configuration
|
||||
AddBootstrap(token string, cfg BootstrapConfig) (string, error)
|
||||
|
@ -1,43 +0,0 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
)
|
||||
|
||||
type version struct {
|
||||
Value string `json:"version"`
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Version() (string, error) {
|
||||
url := fmt.Sprintf("%s/version", sdk.thingsURL)
|
||||
|
||||
resp, err := sdk.client.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", errors.Wrap(ErrFetchVersion, errors.New(resp.Status))
|
||||
}
|
||||
|
||||
var ver version
|
||||
if err := json.Unmarshal(body, &ver); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ver.Value, nil
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
svc := newThingsService(map[string]string{token: email})
|
||||
ts := newThingsServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
sdkConf := sdk.Config{
|
||||
ThingsURL: ts.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mainfluxSDK := sdk.NewSDK(sdkConf)
|
||||
cases := map[string]struct {
|
||||
empty bool
|
||||
err error
|
||||
}{
|
||||
"get version": {
|
||||
empty: false,
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
for desc, tc := range cases {
|
||||
ver, err := mainfluxSDK.Version()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", desc, tc.err, err))
|
||||
assert.Equal(t, tc.empty, ver == "", fmt.Sprintf("%s: expected non-empty result version, got %s", desc, ver))
|
||||
}
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -47,7 +47,7 @@ func MakeHandler(svc provision.Service) http.Handler {
|
||||
))
|
||||
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
r.GetFunc("/version", mainflux.Version("provision"))
|
||||
r.GetFunc("/health", mainflux.Health("provision"))
|
||||
|
||||
return r
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -62,7 +62,7 @@ func MakeHandler(svc readers.MessageRepository, tc mainflux.ThingsServiceClient,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.GetFunc("/version", mainflux.Version(svcName))
|
||||
mux.GetFunc("/health", mainflux.Health(svcName))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return mux
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -198,7 +198,7 @@ func MakeHandler(tracer opentracing.Tracer, svc things.Service) http.Handler {
|
||||
opts...,
|
||||
))
|
||||
|
||||
r.GetFunc("/version", mainflux.Version("things"))
|
||||
r.GetFunc("/health", mainflux.Health("things"))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
|
@ -81,7 +81,7 @@ func MakeHandler(tracer opentracing.Tracer, svc twins.Service) http.Handler {
|
||||
opts...,
|
||||
))
|
||||
|
||||
r.GetFunc("/version", mainflux.Version("twins"))
|
||||
r.GetFunc("/health", mainflux.Health("twins"))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// +build !test
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -109,7 +109,7 @@ func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.GetFunc("/version", mainflux.Version("users"))
|
||||
mux.GetFunc("/health", mainflux.Health("users"))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return mux
|
||||
|
31
version.go
31
version.go
@ -1,31 +0,0 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mainflux
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const version string = "0.12.1"
|
||||
|
||||
// VersionInfo contains version endpoint response.
|
||||
type VersionInfo struct {
|
||||
// Service contains service name.
|
||||
Service string `json:"service"`
|
||||
|
||||
// Version contains service current version value.
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// Version exposes an HTTP handler for retrieving service version.
|
||||
func Version(service string) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
|
||||
res := VersionInfo{service, version}
|
||||
|
||||
data, _ := json.Marshal(res)
|
||||
|
||||
rw.Write(data)
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user