diff --git a/Makefile b/Makefile index 9832ce014b5..a5143c886df 100644 --- a/Makefile +++ b/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 diff --git a/api/auth.yml b/api/auth.yml index b3c14b82aef..0b8882a2a44 100644 --- a/api/auth.yml +++ b/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" diff --git a/api/bootstrap.yml b/api/bootstrap.yml index 0cb9cae36dc..81173834b7a 100644 --- a/api/bootstrap.yml +++ b/api/bootstrap.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" diff --git a/api/certs.yml b/api/certs.yml index 8e20d31bab0..a7e2fedcc87 100644 --- a/api/certs.yml +++ b/api/certs.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" diff --git a/api/consumers-notifiers.yml b/api/consumers-notifiers.yml index 209351ae50e..2afc750fcff 100644 --- a/api/consumers-notifiers.yml +++ b/api/consumers-notifiers.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" diff --git a/api/http.yml b/api/http.yml index a511d14972d..88f3294522e 100644 --- a/api/http.yml +++ b/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" diff --git a/api/provision.yml b/api/provision.yml index ce02b818d3d..8097c3f579e 100644 --- a/api/provision.yml +++ b/api/provision.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" diff --git a/api/readers.yml b/api/readers.yml index 8c6cacf1c7b..7e6bd4b86c2 100644 --- a/api/readers.yml +++ b/api/readers.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" diff --git a/api/schemas/HealthInfo.yml b/api/schemas/HealthInfo.yml new file mode 100644 index 00000000000..4d4c062c4eb --- /dev/null +++ b/api/schemas/HealthInfo.yml @@ -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 + build_time: + type: string + description: Service build time. + example: 1970-01-01_00:00:00 diff --git a/api/things.yml b/api/things.yml index e36088a6689..89ceb1859cc 100644 --- a/api/things.yml +++ b/api/things.yml @@ -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" diff --git a/api/twins.yml b/api/twins.yml index ebe5bdd3493..4233e169604 100644 --- a/api/twins.yml +++ b/api/twins.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" diff --git a/api/users.yml b/api/users.yml index 2ed294697bd..9960de33db3 100644 --- a/api/users.yml +++ b/api/users.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" diff --git a/auth/api/http/transport.go b/auth/api/http/transport.go index 046988895ad..ed87ee6fbbe 100644 --- a/auth/api/http/transport.go +++ b/auth/api/http/transport.go @@ -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 } diff --git a/auth/api/metrics.go b/auth/api/metrics.go index 25e602fcefe..c07bd94289f 100644 --- a/auth/api/metrics.go +++ b/auth/api/metrics.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/bootstrap/api/logging.go b/bootstrap/api/logging.go index b99028ef89b..49c903b736c 100644 --- a/bootstrap/api/logging.go +++ b/bootstrap/api/logging.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/bootstrap/api/metrics.go b/bootstrap/api/metrics.go index 79c47c1fb1c..49398d41f77 100644 --- a/bootstrap/api/metrics.go +++ b/bootstrap/api/metrics.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/bootstrap/api/transport.go b/bootstrap/api/transport.go index 4eaec888e3b..480c2a5d743 100644 --- a/bootstrap/api/transport.go +++ b/bootstrap/api/transport.go @@ -101,7 +101,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 diff --git a/certs/api/logging.go b/certs/api/logging.go index c86b9794ef5..2f4ed7040cb 100644 --- a/certs/api/logging.go +++ b/certs/api/logging.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/certs/api/metrics.go b/certs/api/metrics.go index 16491982119..09668e394ba 100644 --- a/certs/api/metrics.go +++ b/certs/api/metrics.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/certs/api/transport.go b/certs/api/transport.go index 84a57955396..e7970da6e9d 100644 --- a/certs/api/transport.go +++ b/certs/api/transport.go @@ -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 } diff --git a/cli/README.md b/cli/README.md index 8fdaf69db71..19832909cbb 100644 --- a/cli/README.md +++ b/cli/README.md @@ -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 #### List groups that user belongs to ```bash mainflux-cli groups membership -``` \ No newline at end of file +``` diff --git a/cli/version.go b/cli/health.go similarity index 51% rename from cli/version.go rename to cli/health.go index eafce28c6dd..419c1a5e2fa 100644 --- a/cli/version.go +++ b/cli/health.go @@ -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 diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 6ca4843fd57..ff6ecc7ae67 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -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) diff --git a/coap/api/logging.go b/coap/api/logging.go index 3ba3b1c469d..6bad55c305a 100644 --- a/coap/api/logging.go +++ b/coap/api/logging.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/coap/api/metrics.go b/coap/api/metrics.go index 47dae727c31..69526b3cd8b 100644 --- a/coap/api/metrics.go +++ b/coap/api/metrics.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/coap/api/transport.go b/coap/api/transport.go index 25a1454713d..301a13ebaf5 100644 --- a/coap/api/transport.go +++ b/coap/api/transport.go @@ -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 diff --git a/consumers/notifiers/api/logging.go b/consumers/notifiers/api/logging.go index a459ac86f1e..2ced56f7a62 100644 --- a/consumers/notifiers/api/logging.go +++ b/consumers/notifiers/api/logging.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/consumers/notifiers/api/metrics.go b/consumers/notifiers/api/metrics.go index 1d3052b6dd1..0462bca4023 100644 --- a/consumers/notifiers/api/metrics.go +++ b/consumers/notifiers/api/metrics.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/consumers/notifiers/api/transport.go b/consumers/notifiers/api/transport.go index bbce4b2a0b3..a2be131c52a 100644 --- a/consumers/notifiers/api/transport.go +++ b/consumers/notifiers/api/transport.go @@ -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 diff --git a/consumers/writers/api/logging.go b/consumers/writers/api/logging.go index 7c2e5eb25f5..39bddb07f8c 100644 --- a/consumers/writers/api/logging.go +++ b/consumers/writers/api/logging.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/consumers/writers/api/metrics.go b/consumers/writers/api/metrics.go index 8021f1734c9..cbc09c5d08c 100644 --- a/consumers/writers/api/metrics.go +++ b/consumers/writers/api/metrics.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/consumers/writers/api/transport.go b/consumers/writers/api/transport.go index df5915e5a89..1230726a784 100644 --- a/consumers/writers/api/transport.go +++ b/consumers/writers/api/transport.go @@ -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 diff --git a/docker/Dockerfile b/docker/Dockerfile index 08f32fc6ab5..1cc06b87e10 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -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 . . diff --git a/docker/nginx/nginx-key.conf b/docker/nginx/nginx-key.conf index 2238c3afeb5..61d6f897c5f 100644 --- a/docker/nginx/nginx-key.conf +++ b/docker/nginx/nginx-key.conf @@ -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}; } diff --git a/docker/nginx/nginx-x509.conf b/docker/nginx/nginx-x509.conf index e3e4ea3dca3..89e95a60cc2 100644 --- a/docker/nginx/nginx-x509.conf +++ b/docker/nginx/nginx-x509.conf @@ -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}; } diff --git a/health.go b/health.go new file mode 100644 index 00000000000..a142440f23c --- /dev/null +++ b/health.go @@ -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) + } + }) +} diff --git a/http/api/logging.go b/http/api/logging.go index fa0587a4b34..b4e5957a754 100644 --- a/http/api/logging.go +++ b/http/api/logging.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/http/api/metrics.go b/http/api/metrics.go index 1aa25320b3b..46ef9ef6a0a 100644 --- a/http/api/metrics.go +++ b/http/api/metrics.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/http/api/transport.go b/http/api/transport.go index bd92b9a3d51..f778c01a143 100644 --- a/http/api/transport.go +++ b/http/api/transport.go @@ -58,7 +58,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 diff --git a/lora/api/api.go b/lora/api/api.go index 297b1bfdb35..c6082677df3 100644 --- a/lora/api/api.go +++ b/lora/api/api.go @@ -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 diff --git a/lora/api/logging.go b/lora/api/logging.go index 6db7ab5b8a4..f17894203bf 100644 --- a/lora/api/logging.go +++ b/lora/api/logging.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/lora/api/metrics.go b/lora/api/metrics.go index 7f65f73c3da..7e703ad36ac 100644 --- a/lora/api/metrics.go +++ b/lora/api/metrics.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/opcua/api/logging.go b/opcua/api/logging.go index fe82d18d4e0..ba32a7f8485 100644 --- a/opcua/api/logging.go +++ b/opcua/api/logging.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/opcua/api/metrics.go b/opcua/api/metrics.go index 4222cbc363f..1061932d4d9 100644 --- a/opcua/api/metrics.go +++ b/opcua/api/metrics.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/opcua/api/transport.go b/opcua/api/transport.go index 733a7cfd87b..724afdd437f 100644 --- a/opcua/api/transport.go +++ b/opcua/api/transport.go @@ -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 diff --git a/pkg/sdk/go/README.md b/pkg/sdk/go/README.md index 7f5ff1a64c9..4924b8985b6 100644 --- a/pkg/sdk/go/README.md +++ b/pkg/sdk/go/README.md @@ -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 ``` diff --git a/pkg/sdk/go/health.go b/pkg/sdk/go/health.go new file mode 100644 index 00000000000..ef64c894dd1 --- /dev/null +++ b/pkg/sdk/go/health.go @@ -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 +} diff --git a/pkg/sdk/go/health_test.go b/pkg/sdk/go/health_test.go new file mode 100644 index 00000000000..31e16696d91 --- /dev/null +++ b/pkg/sdk/go/health_test.go @@ -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)) + } +} diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index 3175753e59a..eb14c62c80e 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -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) diff --git a/pkg/sdk/go/version.go b/pkg/sdk/go/version.go deleted file mode 100644 index fcf1c3d45d7..00000000000 --- a/pkg/sdk/go/version.go +++ /dev/null @@ -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 -} diff --git a/pkg/sdk/go/version_test.go b/pkg/sdk/go/version_test.go deleted file mode 100644 index 87886593223..00000000000 --- a/pkg/sdk/go/version_test.go +++ /dev/null @@ -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)) - } -} diff --git a/provision/api/logging.go b/provision/api/logging.go index e20893d49c9..bc63a7ac7a3 100644 --- a/provision/api/logging.go +++ b/provision/api/logging.go @@ -1,3 +1,8 @@ +// Copyright (c) Mainflux +// SPDX-License-Identifier: Apache-2.0 + +//go:build !test + package api import ( diff --git a/provision/api/transport.go b/provision/api/transport.go index 3fe5aeef380..948ad16cdee 100644 --- a/provision/api/transport.go +++ b/provision/api/transport.go @@ -48,7 +48,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 } diff --git a/readers/api/logging.go b/readers/api/logging.go index 43154686b66..185383c8cb7 100644 --- a/readers/api/logging.go +++ b/readers/api/logging.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/readers/api/metrics.go b/readers/api/metrics.go index 1ce4684a570..e6b8b6fa377 100644 --- a/readers/api/metrics.go +++ b/readers/api/metrics.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/readers/api/transport.go b/readers/api/transport.go index 3bcbe0cafee..c4d0f584750 100644 --- a/readers/api/transport.go +++ b/readers/api/transport.go @@ -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 diff --git a/things/api/logging.go b/things/api/logging.go index b1ed7d6f00c..cf0ddb1c072 100644 --- a/things/api/logging.go +++ b/things/api/logging.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/things/api/metrics.go b/things/api/metrics.go index d5da0d5972d..5aad2998fd6 100644 --- a/things/api/metrics.go +++ b/things/api/metrics.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/things/api/things/http/transport.go b/things/api/things/http/transport.go index 65833f11e70..3f299cad4f3 100644 --- a/things/api/things/http/transport.go +++ b/things/api/things/http/transport.go @@ -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 diff --git a/twins/api/http/transport.go b/twins/api/http/transport.go index f54a811624b..4c38f60a74e 100644 --- a/twins/api/http/transport.go +++ b/twins/api/http/transport.go @@ -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 diff --git a/twins/api/logging.go b/twins/api/logging.go index 497e2327739..dafe88d1f2e 100644 --- a/twins/api/logging.go +++ b/twins/api/logging.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/twins/api/metrics.go b/twins/api/metrics.go index cf2b739690c..d58fafda77b 100644 --- a/twins/api/metrics.go +++ b/twins/api/metrics.go @@ -1,7 +1,7 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 -// +build !test +//go:build !test package api diff --git a/users/api/logging.go b/users/api/logging.go index e6c6e50eb49..8fdd62515ed 100644 --- a/users/api/logging.go +++ b/users/api/logging.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/users/api/metrics.go b/users/api/metrics.go index 028d168a815..8865e68d145 100644 --- a/users/api/metrics.go +++ b/users/api/metrics.go @@ -1,6 +1,8 @@ // Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 +//go:build !test + package api import ( diff --git a/users/api/transport.go b/users/api/transport.go index 4fe89cf222f..f086c1d452f 100644 --- a/users/api/transport.go +++ b/users/api/transport.go @@ -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 diff --git a/version.go b/version.go deleted file mode 100644 index 3f16d520662..00000000000 --- a/version.go +++ /dev/null @@ -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) - }) -}