Skip to content

Commit

Permalink
Merge pull request mendersoftware#64 from alfrunes/MEN-3030
Browse files Browse the repository at this point in the history
MEN-3030: Add health check endpoint GET /health
  • Loading branch information
alfrunes authored Aug 3, 2020
2 parents 79c2239 + 5c809e4 commit 8f0d619
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 6 deletions.
3 changes: 3 additions & 0 deletions api/http/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
const (
APIURLStatus = "/status"

APIURLHealth = "/api/v1/health"
APIURLWorkflow = "/api/v1/workflow/:name"
APIURLWorkflowID = "/api/v1/workflow/:name/:id"

Expand All @@ -49,6 +50,8 @@ func NewRouter(dataStore store.DataStore) *gin.Engine {
router.GET(APIURLStatus, status.Status)

workflow := NewWorkflowController(dataStore)
router.GET(APIURLHealth, workflow.HealthCheck)

router.POST(APIURLWorkflow, workflow.StartWorkflow)
router.GET(APIURLWorkflowID, workflow.GetWorkflowByNameAndID)

Expand Down
21 changes: 21 additions & 0 deletions api/http/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,25 @@
package http

import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"

"github.com/gin-gonic/gin"

"github.com/mendersoftware/go-lib-micro/log"
"github.com/mendersoftware/workflows/app/worker"
"github.com/mendersoftware/workflows/model"
"github.com/mendersoftware/workflows/store"
)

const (
defaultTimeout = time.Second * 5
)

// WorkflowController container for end-points
type WorkflowController struct {
// dataStore provides an interface to the database
Expand All @@ -40,6 +47,20 @@ func NewWorkflowController(dataStore store.DataStore) *WorkflowController {
}
}

func (h WorkflowController) HealthCheck(c *gin.Context) {
ctx := c.Request.Context()
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
err := h.dataStore.Ping(ctx)
if err != nil {
c.JSON(http.StatusServiceUnavailable, gin.H{
"error": "error reaching MongoDB: " + err.Error(),
})
return
}
c.Status(http.StatusOK)
}

// RegisterWorkflow responds to POST /api/v1/metadata/workflows
func (h WorkflowController) RegisterWorkflow(c *gin.Context) {
var workflow model.Workflow
Expand Down
48 changes: 48 additions & 0 deletions api/http/workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,54 @@ import (
"github.com/mendersoftware/workflows/store/mock"
)

func TestHealthCheck(t *testing.T) {
testCases := []struct {
Name string

DataStoreErr error
HTTPStatus int
HTTPBody map[string]interface{}
}{{
Name: "ok",
HTTPStatus: http.StatusOK,
}, {
Name: "error, MongoDB not reachable",
DataStoreErr: errors.New("connection refused"),
HTTPStatus: http.StatusServiceUnavailable,
HTTPBody: map[string]interface{}{
"error": "error reaching MongoDB: connection refused",
},
}}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
dataStore := mock.NewDataStore()
router := NewRouter(dataStore)
dataStore.On("Ping", mocklib.Anything).
Return(tc.DataStoreErr)

req, err := http.NewRequest("GET", "http://localhost"+APIURLHealth, nil)
if !assert.NoError(t, err) {
t.FailNow()
}

w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, tc.HTTPStatus, w.Code)
if tc.HTTPStatus >= 400 {
var bodyJSON map[string]interface{}
decoder := json.NewDecoder(w.Body)
err := decoder.Decode(&bodyJSON)
if assert.NoError(t, err) {
assert.Equal(t, tc.HTTPBody, bodyJSON)
}
} else {
assert.Nil(t, w.Body.Bytes())
}
})
}
}

func TestWorkflowNotFound(t *testing.T) {
dataStore := mock.NewDataStore()
router := NewRouter(dataStore)
Expand Down
1 change: 1 addition & 0 deletions store/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var (

// DataStore interface for DataStore services
type DataStore interface {
Ping(ctx context.Context) error
InsertWorkflows(ctx context.Context, workflow ...model.Workflow) (int, error)
GetWorkflowByName(ctx context.Context, workflowName string) (*model.Workflow, error)
GetWorkflows(ctx context.Context) []model.Workflow
Expand Down
24 changes: 18 additions & 6 deletions store/mock/datastore_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,27 @@ func NewDataStore() *DataStore {
return &DataStore{}
}

func (db *DataStore) Ping(ctx context.Context) error {
ret := db.Called(ctx)

var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}

// LoadWorkflows from filesystem if the workflowsPath setting is provided
func (db *DataStore) LoadWorkflows(ctx context.Context, l *log.Logger) error {
ret := db.Called(ctx, l)

var r0 error
if rf, ok := ret.Get(1).(func(context.Context, *log.Logger) error); ok {
if rf, ok := ret.Get(0).(func(context.Context, *log.Logger) error); ok {
r0 = rf(ctx, l)
} else {
r0 = ret.Error(1)
r0 = ret.Error(0)
}
return r0
}
Expand Down Expand Up @@ -252,16 +264,16 @@ func (db *DataStore) GetAllJobs(ctx context.Context, page int64, perPage int64)

var r1 int64
if rf, ok := ret.Get(1).(func(
context.Context,int64,int64) int64); ok {
r1 = rf(ctx,page,perPage)
context.Context, int64, int64) int64); ok {
r1 = rf(ctx, page, perPage)
} else {
r1 = ret.Get(1).(int64)
}

var r2 error
if rf, ok := ret.Get(2).(func(
context.Context,int64,int64) error); ok {
r2 = rf(ctx,page,perPage)
context.Context, int64, int64) error); ok {
r2 = rf(ctx, page, perPage)
} else {
r2 = ret.Error(2)
}
Expand Down
4 changes: 4 additions & 0 deletions store/mongo/datastore_mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ func NewDataStoreWithClient(client *Client, c config.Reader) *DataStoreMongo {
}
}

func (db *DataStoreMongo) Ping(ctx context.Context) error {
return db.client.Ping(ctx, nil)
}

// LoadWorkflows from filesystem if the workflowsPath setting is provided
func (db *DataStoreMongo) LoadWorkflows(ctx context.Context, l *log.Logger) error {
workflowsPath := config.Config.GetString(dconfig.SettingWorkflowsPath)
Expand Down
7 changes: 7 additions & 0 deletions store/mongo/datastore_mongo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -899,3 +899,10 @@ func TestGetAllJobs(t *testing.T) {
assert.Equal(t, job.InputParameters, jobs[0].InputParameters)
assert.Equal(t, model.StatusPending, jobs[0].Status)
}

func TestPing(t *testing.T) {
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
defer cancel()
err := testDataStore.Ping(ctx)
assert.NoError(t, err)
}

0 comments on commit 8f0d619

Please sign in to comment.