Skip to content
This repository has been archived by the owner on Jun 11, 2019. It is now read-only.

Commit

Permalink
Merge pull request #7 from meltwater/status_endpoint
Browse files Browse the repository at this point in the history
Added a /v1/status endpoint for use with load balancer health checks
  • Loading branch information
alexandernilsson committed Feb 10, 2016
2 parents ce7b3e6 + e2c2a71 commit bf5b917
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ coverage.txt
.vscode
vendor/
.aws
keys/
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ load balancer in front of them to ensure high availability. The daemon defaults
bind to 5070/tcp. The `secretary daemon` is completely stateless and can be load balanced
easily.

The daemon has an HTTP health check endpoint at `/v1/status` that will respond with
`HTTP 200 OK` if all is well. This can be useful to point a load balancers health check
mechanism at.

### Systemd and CoreOS/Fleet
Create a [Systemd unit](http://www.freedesktop.org/software/systemd/man/systemd.unit.html) file
in **/etc/systemd/system/secretary.service** with contents like below. Using CoreOS and
Expand Down
23 changes: 21 additions & 2 deletions daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,24 @@ import (
"strings"
)

// DaemonRequest TODO
// DaemonRequest is the request expected by the /v1/decrypt endpoint
type DaemonRequest struct {
AppID, AppVersion, TaskID string

// Secret encrypted with master key
RequestedSecret string
}

// DaemonResponse TODO
// DaemonResponse is the response returned by the /v1/decrypt endpoint
type DaemonResponse struct {
PlaintextSecret string
}

// DaemonStatusResponse is the response returned by the /v1/status endpoint
type DaemonStatusResponse struct {
Status string
}

func errorResponse(w http.ResponseWriter, r *http.Request, err interface{}, statusCode int) {
log.Printf("HTTP %d from %s: %s", statusCode, r.RemoteAddr, err)
http.Error(w, fmt.Sprintf("%s", err), statusCode)
Expand Down Expand Up @@ -155,8 +160,22 @@ func decryptEndpointHandler(marathonURL string, masterKey *[32]byte, strategy De
}
}

func statusEndpointHandler() func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
message := DaemonStatusResponse{Status: "OK"}
encoded, err := json.Marshal(message)
if err != nil {
errorResponse(w, r, fmt.Errorf("Failed to serialize json response", err), http.StatusInternalServerError)
return
}

w.Write(encoded)
}
}

func daemonCommand(listenAddress string, marathonURL string, masterKey *[32]byte, strategy DecryptionStrategy) {
http.HandleFunc("/v1/decrypt", decryptEndpointHandler(marathonURL, masterKey, strategy))
http.HandleFunc("/v1/status", statusEndpointHandler())
log.Printf("Daemon listening on %s", listenAddress)
log.Fatal(http.ListenAndServe(listenAddress, nil))
}
36 changes: 36 additions & 0 deletions daemon_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/assert"
)

func TestDaemonStatus(t *testing.T) {
// Start secretary daemon
handler := statusEndpointHandler()

daemon := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch r.URL.Path {
case "/v1/status":
handler(w, r)
default:
http.Error(w, fmt.Sprintf("Bad URL %s", r.URL.Path), http.StatusNotFound)
}
}))

defer daemon.Close()

response, err := httpGet(daemon.URL + "/v1/status")
assert.Nil(t, err)

var parsedResponse DaemonStatusResponse
err = json.Unmarshal(response, &parsedResponse)
assert.Nil(t, err)
assert.Equal(t, "OK", parsedResponse.Status)
}

0 comments on commit bf5b917

Please sign in to comment.