1
0
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:
Manuel Imperiale 2022-01-24 21:18:53 +01:00 committed by GitHub
parent bcc8cf7119
commit 42dd813521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 456 additions and 173 deletions

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View 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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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
}

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -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

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -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
}

View File

@ -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>
```
```

View File

@ -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

View File

@ -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)

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -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

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -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

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -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

View File

@ -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 . .

View File

@ -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};
}

View File

@ -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
View 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)
}
})
}

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -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

View File

@ -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

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -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

View File

@ -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
View 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
View 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))
}
}

View File

@ -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)

View File

@ -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
}

View File

@ -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))
}
}

View File

@ -1,3 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -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
}

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -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

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// +build !test
//go:build !test
package api

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -1,6 +1,8 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
//go:build !test
package api
import (

View File

@ -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

View File

@ -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)
})
}