Repository: m3db/m3db-operator
Pull request #257 (2020-12-16 21:14:21)

Use /health endpoint for boostrapped check
This returns a 200 instead of an error when not bootstrapped. This makes
it easier to differentiate between transient errors and not
bootstrapped.

Thanks for contributing to the M3DB Operator! We'd love to accept your contribution, but we require that most issues
outside of trivial changes such as typo corrections have an issue associated with the pull request. So please [open an
issue](https://github.com/m3db/m3db-operator/issues/new) first!


codecov[bot]: # [Codecov](https://codecov.io/gh/m3db/m3db-operator/pull/257?src=pr&el=h1) Report
> Merging [#257](https://codecov.io/gh/m3db/m3db-operator/pull/257?src=pr&el=desc) (e8ea0bf) into [master](https://codecov.io/gh/m3db/m3db-operator/commit/d49daa25b3ef0a9803626da6b848ddb2aa23bd17?el=desc) (d49daa2) will **decrease** coverage by `0.10%`.
> The diff coverage is `55.55%`.


[![Impacted file tree graph](https://codecov.io/gh/m3db/m3db-operator/pull/257/graphs/tree.svg?width=650&height=150&src=pr&token=jtHDyWhsto)](https://codecov.io/gh/m3db/m3db-operator/pull/257?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #257      +/-   ##
==========================================
- Coverage   76.45%   76.35%   -0.11%     
==========================================
  Files          31       31              
  Lines        2285     2292       +7     
==========================================
+ Hits         1747     1750       +3     
- Misses        395      397       +2     
- Partials      143      145       +2     
```


------

[Continue to review full report at Codecov](https://codecov.io/gh/m3db/m3db-operator/pull/257?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/m3db/m3db-operator/pull/257?src=pr&el=footer). Last update [d49daa2...e8ea0bf](https://codecov.io/gh/m3db/m3db-operator/pull/257?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/pkg/m3admin/health/client.go b/pkg/m3admin/health/client.go
index 91818b9..7a79477 100644
--- a/pkg/m3admin/health/client.go
+++ b/pkg/m3admin/health/client.go
@@ -21,7 +21,9 @@
 package health
 
 import (
+	"encoding/json"
 	"fmt"
+	"io/ioutil"
 	"net/http"
 	"net/url"
 
@@ -30,8 +32,8 @@ import (
 )
 
 const (
-	bootstrappedPath = "/bootstrapped"
-	m3dbServiceName  = "m3dbnode-m3-cluster-short"
+	healthPath      = "/health"
+	m3dbServiceName = "m3dbnode-m3-cluster-short"
 )
 
 type healthClient struct {
@@ -104,14 +106,33 @@ func (h *healthClient) Bootstrapped(namespace string, podName string) (bool, err
 		url = getPodURL(namespace, podName, port)
 	}
 
-	_, err := h.client.DoHTTPRequest(http.MethodGet, url+bootstrappedPath, nil)
+	// The /health endpoint is used since it returns a 200 even if not bootstrapped. The /bootstrapped endpoint returns
+	// an error if not bootstrapped. This makes it difficult to differentiate transient errors from not bootstrapped.
+	resp, err := h.client.DoHTTPRequest(http.MethodGet, url+healthPath, nil)
 	if err != nil {
 		return false, err
 	}
 
-	return true, nil
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return false, err
+	}
+	resp.Body.Close()
+	var result healthResult
+	if err := json.Unmarshal(body, &result); err != nil {
+		return false, err
+	}
+
+	return result.Bootstrapped && result.Ok, nil
 }
 
 func getPodURL(namespace string, podName string, port int) string {
 	return fmt.Sprintf("http://%s.%s.%s:%d", podName, m3dbServiceName, namespace, port)
 }
+
+type healthResult struct {
+	Ok bool `json:"ok"`
+	Status string `json:"status"`
+	Bootstrapped bool `json:"bootstrapped"`
+}
+


Test patch:
diff --git a/pkg/m3admin/health/client_test.go b/pkg/m3admin/health/client_test.go
index d69d0ac..8faa888 100644
--- a/pkg/m3admin/health/client_test.go
+++ b/pkg/m3admin/health/client_test.go
@@ -24,6 +24,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"strings"
 	"testing"
 
 	"github.com/m3db/m3db-operator/pkg/m3admin"
@@ -39,7 +40,7 @@ func TestBootstrapped(t *testing.T) {
 		require.NoError(t, err)
 
 		w.WriteHeader(200)
-		w.Write([]byte("{}"))
+		w.Write([]byte(`{"ok":true, "bootstrapped":true}`))
 	}))
 
 	defer s.Close()
@@ -56,9 +57,12 @@ func TestBootstrapped_ValidateURL(t *testing.T) {
 	defer ctrl.Finish()
 
 	adminClient := m3admin.NewMockClient(ctrl)
-	adminClient.EXPECT().DoHTTPRequest("GET", "http://bar.m3dbnode-m3-cluster-short.foo:9002/bootstrapped",
+
+	adminClient.EXPECT().DoHTTPRequest("GET", "http://bar.m3dbnode-m3-cluster-short.foo:9002/health",
 		nil).
-		Return(&http.Response{}, nil)
+		Return(&http.Response{
+			Body: ioutil.NopCloser(strings.NewReader(`{"ok":true, "bootstrapped":true}`)),
+		}, nil)
 
 	client := newHealthClient(t, adminClient)
 
@@ -73,9 +77,11 @@ func TestBootstrapped_WithPort(t *testing.T) {
 	defer ctrl.Finish()
 
 	adminClient := m3admin.NewMockClient(ctrl)
-	adminClient.EXPECT().DoHTTPRequest("GET", "http://bar.m3dbnode-m3-cluster-short.foo:8088/bootstrapped",
+	adminClient.EXPECT().DoHTTPRequest("GET", "http://bar.m3dbnode-m3-cluster-short.foo:8088/health",
 		nil).
-		Return(&http.Response{}, nil)
+		Return(&http.Response{
+			Body: ioutil.NopCloser(strings.NewReader(`{"ok":true, "bootstrapped":true}`)),
+		}, nil)
 
 	client, err := NewClient(
 		WithClient(adminClient),