-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'release/1.0.0' into production
- Loading branch information
Showing
7 changed files
with
530 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# IDE and build system artifacts | ||
*.dll | ||
*.dylib | ||
*.exe | ||
*.iml | ||
*.so | ||
*.test | ||
.idea/ | ||
.protoc | ||
gprobe | ||
release/ | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Changelog | ||
|
||
## 1.0.0 - 2017-12-13 | ||
|
||
### Added | ||
|
||
- Probing servers and services via gRPC health-checking protocol |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
BINARY=gprobe | ||
VERSION=$(shell git describe 2>/dev/null || echo "0.0.0") | ||
RELEASE=release | ||
RELEASE_FORMAT=${BINARY}-${GOOS}-${GOARCH}-${VERSION}.tar.gz | ||
|
||
default: bin | ||
.PHONY: bin | ||
bin: deps ${BINARY} | ||
|
||
.PHONY: release | ||
release: release/gprobe-linux-amd64-${VERSION}.tar.gz | ||
release: release/gprobe-linux-386-${VERSION}.tar.gz | ||
release: release/gprobe-darwin-amd64-${VERSION}.tar.gz | ||
|
||
.PHONY: release-dir | ||
release-dir: | ||
mkdir -p ${RELEASE} | ||
|
||
${RELEASE}/%-${VERSION}.tar.gz: | release-dir | ||
GOOS=$(shell echo $* | cut -d '-' -f 2) GOARCH=$(shell echo $* | cut -d '-' -f 3) \ | ||
go build -ldflags="-s -w -X main.version=${VERSION} -v" -o ${RELEASE}/${BINARY} | ||
tar -C ${RELEASE} -czf $@ ${BINARY} | ||
rm ${RELEASE}/${BINARY} | ||
|
||
${BINARY}: | ||
go build -ldflags="-s -w -X main.version=${VERSION} -v" -o $@ | ||
|
||
.PHONY: lint | ||
lint: | ||
go get -u github.com/golang/lint/golint | ||
golint -set_exit_status ./... | ||
|
||
.PHONY: test | ||
test: | ||
go test -v $(go list ./... | grep -v /acctest/) | ||
|
||
.PHONY: acctest | ||
acctest: ${BINARY} | ||
go test -v ./acctest/... -args -gprobe `pwd`/${BINARY} | ||
|
||
.PHONY: deps | ||
deps: | ||
go get -u ./... | ||
|
||
.PHONY: test-deps | ||
test-deps: | ||
go get -t -u ./... | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -f ${BINARY} | ||
rm -rf ${RELEASE} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,89 @@ | ||
``` | ||
____ ____ | ||
/ \/ \ | | ||
| | ,--. ,--. .-- .--. |,--. ,---. | ||
\::::::::::; | | | | | | | | | |---' | ||
`:::::::;' '--| |--' | '--' '---' `--- | ||
`:::;' / | | ||
`' | ||
``` | ||
|
||
_gprobe_ is a CLI client for the | ||
[gRPC health-checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). | ||
|
||
## Usage | ||
|
||
Assuming server is listening on `localhost:1234` | ||
|
||
Check server health (it is considered healthy if it has `grpc.health.v1.Health` service and is able to serve requests) | ||
|
||
```bash | ||
gprobe localhost:1234 | ||
``` | ||
|
||
Check specific service health | ||
|
||
```bash | ||
gprobe localhost:1234 my.package.MyService | ||
``` | ||
|
||
Get help | ||
|
||
| | ||
,--. ,--. .-- .--. |,--. ,---. | ||
| | | | | | | | | |---' | ||
'--| |--' | '--' '---' `--- | ||
/ | | ||
```bash | ||
gprobe -h | ||
``` | ||
|
||
## Building | ||
|
||
Valid _go_ environment is required to build `gprobe` (`go` is in `PATH`, `GOPATH` is set, etc.). | ||
|
||
Build distributable tarballs for all OSes | ||
|
||
```bash | ||
make release | ||
``` | ||
|
||
Build binary for current OS | ||
|
||
```bash | ||
make bin | ||
``` | ||
|
||
## Development | ||
|
||
This project follows git-flow branching model. All development is done off of the `develop` branch. `HEAD` in | ||
`production` branch should always point to a tagged release. There's no `master` branch to avoid possible confusion. | ||
|
||
To contribute: | ||
|
||
1. Create a feature branch from the latest `develop`, commit your work there | ||
```bash | ||
git checkout develop | ||
git pull | ||
git checkout -b feature/<feature_description> | ||
``` | ||
2. Run `go fmt` and all the checks before committing any code | ||
```bash | ||
go fmt ./... | ||
make lint test acctest | ||
``` | ||
3. When the change is ready in a separate commit update `CHANGELOG.md` describing the change. Follow | ||
[keepachangelog](http://keepachangelog.com/en/1.0.0/) guidelines | ||
4. Create PR to develop | ||
|
||
To release: | ||
|
||
1. Create a release branch from the latest `develop` and update `CHANGELOG.md` there, setting version and date | ||
```bash | ||
git checkout -b release/1.2.3 | ||
``` | ||
2. Create PR to `production` | ||
3. Once PR is merged, tag `HEAD` commit using annotated tag | ||
```bash | ||
git tag -a 1.2.3 -m "1.2.3" | ||
``` | ||
4. Merge `production` back to `develop`. Do not use `fast-forward` merges | ||
```bash | ||
git checkout develop | ||
git merge --no-ff production | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// PUBLIC DOMAIN NOTICE | ||
// National Center for Biotechnology Information | ||
// | ||
// This software/database is a "United States Government Work" under the | ||
// terms of the United States Copyright Act. It was written as part of | ||
// the author's official duties as a United States Government employee and | ||
// thus cannot be copyrighted. This software/database is freely available | ||
// to the public for use. The National Library of Medicine and the U.S. | ||
// Government have not placed any restriction on its use or reproduction. | ||
// | ||
// Although all reasonable efforts have been taken to ensure the accuracy | ||
// and reliability of the software and data, the NLM and the U.S. | ||
// Government do not and cannot warrant the performance or results that | ||
// may be obtained by using this software or data. The NLM and the U.S. | ||
// Government disclaim all warranties, express or implied, including | ||
// warranties of performance, merchantability or fitness for any particular | ||
// purpose. | ||
// | ||
// Please cite the author in any work or product based on this material. | ||
|
||
package acctest | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"github.com/stretchr/testify/assert" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/health" | ||
hv1 "google.golang.org/grpc/health/grpc_health_v1" | ||
"io" | ||
"log" | ||
"net" | ||
"os" | ||
"os/exec" | ||
"syscall" | ||
"testing" | ||
"flag" | ||
) | ||
|
||
var ( | ||
port int | ||
listenAddr string | ||
bin string | ||
) | ||
|
||
func startServer() net.Listener { | ||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) | ||
if err != nil { | ||
log.Fatalf("failed to listen: %v", err) | ||
} | ||
|
||
grpcServer := grpc.NewServer() | ||
server := health.NewServer() | ||
hv1.RegisterHealthServer(grpcServer, server) | ||
|
||
server.SetServingStatus("foo", hv1.HealthCheckResponse_SERVING) | ||
server.SetServingStatus("bar", hv1.HealthCheckResponse_NOT_SERVING) | ||
go grpcServer.Serve(listener) | ||
return listener | ||
} | ||
|
||
func init() { | ||
flag.IntVar(&port, "stub-port", 54321, "port for the stub server") | ||
flag.StringVar(&bin, "gprobe", "", "path to the gprobe binary") | ||
} | ||
|
||
func TestMain(m *testing.M) { | ||
flag.Parse() | ||
listenAddr = fmt.Sprintf("%s:%d", "localhost", port) | ||
|
||
lis := startServer() | ||
result := 0 | ||
defer func() { | ||
lis.Close() | ||
os.Exit(result) | ||
}() | ||
|
||
result = m.Run() | ||
} | ||
|
||
func TestShouldReturnServingForRunningServer(t *testing.T) { | ||
stdout, stderr, exitcode := runBin(t, listenAddr) | ||
|
||
assert.Equal(t, 0, exitcode) | ||
assert.Equal(t, "SERVING\n", stdout) | ||
assert.Empty(t, stderr) | ||
} | ||
|
||
func TestShouldFailIfServerIsNotListening(t *testing.T) { | ||
stdout, stderr, exitcode := runBin(t, "nosuchhost:1234") | ||
|
||
assert.Equal(t, 127, exitcode) | ||
assert.Empty(t, stdout) | ||
assert.Contains(t, stderr, "error", "should print status to STDOUT") | ||
} | ||
|
||
func TestShouldReturnServingForHealthyService(t *testing.T) { | ||
stdout, stderr, exitcode := runBin(t, listenAddr, "foo") | ||
|
||
assert.Equal(t, 0, exitcode) | ||
assert.Equal(t, "SERVING\n", stdout) | ||
assert.Empty(t, stderr) | ||
} | ||
|
||
func TestShouldReturnNotServingForUnhealthyService(t *testing.T) { | ||
stdout, stderr, exitcode := runBin(t, listenAddr, "bar") | ||
|
||
assert.Equal(t, 2, exitcode) | ||
assert.Equal(t, "NOT_SERVING\n", stdout) | ||
assert.Contains(t, stderr, "health-check failed") | ||
} | ||
|
||
func TestShouldNotFailForUnhealthyServiceIfNoFailIsSet(t *testing.T) { | ||
stdout, stderr, exitcode := runBin(t, "--no-fail", listenAddr, "bar") | ||
|
||
assert.Equal(t, 0, exitcode) | ||
assert.Equal(t, "NOT_SERVING\n", stdout) | ||
assert.Empty(t, stderr) | ||
} | ||
|
||
func TestShouldFailIfServiceHealthCheckIsNotRegistered(t *testing.T) { | ||
stdout, stderr, exitcode := runBin(t, listenAddr, "non_registered_service") | ||
|
||
assert.Equal(t, 127, exitcode) | ||
assert.Empty(t, stdout) | ||
assert.Contains(t, stderr, "NotFound") | ||
} | ||
|
||
func runBin(t *testing.T, args ...string) (stdout string, stderr string, exitcode int) { | ||
gprobe := exec.Command(bin, args...) | ||
stdoutPipe, _ := gprobe.StdoutPipe() | ||
stderrPipe, _ := gprobe.StderrPipe() | ||
|
||
err := gprobe.Start() | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
stdout = readPipe(t, stdoutPipe) | ||
stderr = readPipe(t, stderrPipe) | ||
exitcode = waitForExitCode(t, gprobe) | ||
|
||
return | ||
} | ||
|
||
func readPipe(t *testing.T, reader io.Reader) string { | ||
buf := new(bytes.Buffer) | ||
_, err := io.Copy(buf, reader) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
return buf.String() | ||
} | ||
|
||
func waitForExitCode(t *testing.T, cmd *exec.Cmd) (exitcode int) { | ||
err := cmd.Wait() | ||
if err != nil { | ||
if exiterr, ok := err.(*exec.ExitError); ok { | ||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { | ||
exitcode = status.ExitStatus() | ||
} | ||
} else { | ||
exitcode = -1 | ||
t.Error(err) | ||
} | ||
} | ||
return | ||
} | ||
|
||
|
Oops, something went wrong.