Skip to content

Commit

Permalink
[query] Ensure calls to /namespace/ready endpoint return true for sta…
Browse files Browse the repository at this point in the history
…tic config (#3290)
  • Loading branch information
nbroyles committed Feb 26, 2021
1 parent a3853ee commit a8f366e
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 4 deletions.
10 changes: 10 additions & 0 deletions src/query/api/v1/handler/namespace/ready.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ func (h *ReadyHandler) parseRequest(r *http.Request) (*admin.NamespaceReadyReque
}

func (h *ReadyHandler) Ready(req *admin.NamespaceReadyRequest, opts handleroptions.ServiceOptions) (bool, error) {
// NB(nate): Readying a namespace only applies to namespaces created dynamically. As such,
// ensure that any calls to the ready endpoint simply return true when using static configuration
// as namespaces are ready by default in this case.
if h.clusters != nil && h.clusters.ConfigType() == m3.ClusterConfigTypeStatic {
h.instrumentOpts.Logger().Debug(
"/namespace/ready endpoint not supported for statically configured namespaces.",
)
return true, nil
}

// Fetch existing namespace metadata.
store, err := h.client.Store(opts.KVOverrideOptions())
if err != nil {
Expand Down
45 changes: 45 additions & 0 deletions src/query/api/v1/handler/namespace/ready_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func TestNamespaceReadyHandler(t *testing.T) {
options: m3.ClusterNamespaceOptions{},
}
testClusters := testClusters{
configType: m3.ClusterConfigTypeDynamic,
nonReadyNamespaces: []m3.ClusterNamespace{&testClusterNs},
}
mockSession.EXPECT().FetchTaggedIDs(testClusterNs.NamespaceID(), index.Query{Query: idx.NewAllQuery()},
Expand Down Expand Up @@ -173,6 +174,45 @@ func TestNamespaceReadyFailIfNamespaceMissing(t *testing.T) {
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
}

func TestNamespaceReadyHandlerStaticConf(t *testing.T) {
ctrl := xtest.NewController(t)
defer ctrl.Finish()

mockClient := clusterclient.NewMockClient(ctrl)
require.NotNil(t, mockClient)

tc := testClusters{
configType: m3.ClusterConfigTypeStatic,
}

readyHandler := NewReadyHandler(mockClient, &tc, instrument.NewOptions())

jsonInput := xjson.Map{
"name": "testNamespace",
}

req := httptest.NewRequest("POST", "/namespace/ready",
xjson.MustNewTestReader(t, jsonInput))
require.NotNil(t, req)

w := httptest.NewRecorder()
readyHandler.ServeHTTP(svcDefaults, w, req)

resp := w.Result()
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)

expected := xtest.MustPrettyJSONMap(t,
xjson.Map{
"ready": true,
})
actual := xtest.MustPrettyJSONString(t, string(body))
require.Equal(t, expected, actual, xtest.Diff(expected, actual))
}

func testSetup(t *testing.T, ctrl *gomock.Controller) (*clusterclient.MockClient, *kv.MockStore, ident.ID) {
mockClient, mockKV := setupNamespaceTest(t, ctrl)
mockClient.EXPECT().Store(gomock.Any()).Return(mockKV, nil)
Expand Down Expand Up @@ -220,6 +260,7 @@ func (t *testClusterNamespace) Session() client.Session {
}

type testClusters struct {
configType m3.ClusterConfigType
nonReadyNamespaces m3.ClusterNamespaces
}

Expand All @@ -242,3 +283,7 @@ func (t *testClusters) UnaggregatedClusterNamespace() m3.ClusterNamespace {
func (t *testClusters) AggregatedClusterNamespace(attrs m3.RetentionResolution) (m3.ClusterNamespace, bool) {
panic("implement me")
}

func (t *testClusters) ConfigType() m3.ClusterConfigType {
return t.configType
}
19 changes: 19 additions & 0 deletions src/query/storage/m3/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ var (
}
)

// ClusterConfigType is an enum representing the configuration used
// to create a Clusters interface
type ClusterConfigType int

const (
// ClusterConfigTypeStatic is for static configuration.
ClusterConfigTypeStatic = iota
// ClusterConfigTypeDynamic is for dynamic configuration.
ClusterConfigTypeDynamic
)

// Clusters is a flattened collection of local storage clusters and namespaces.
type Clusters interface {
io.Closer
Expand All @@ -61,6 +72,10 @@ type Clusters interface {
// AggregatedClusterNamespace returns an aggregated cluster namespace
// at a specific retention and resolution.
AggregatedClusterNamespace(attrs RetentionResolution) (ClusterNamespace, bool)

// ConfigType returns the type of configuration used to create this Clusters
// object.
ConfigType() ClusterConfigType
}

// RetentionResolution is a tuple of retention and resolution that describes
Expand Down Expand Up @@ -269,6 +284,10 @@ func (c *clusters) AggregatedClusterNamespace(
return namespace, ok
}

func (c *clusters) ConfigType() ClusterConfigType {
return ClusterConfigTypeStatic
}

func (c *clusters) Close() error {
var (
wg sync.WaitGroup
Expand Down
12 changes: 8 additions & 4 deletions src/query/storage/m3/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func TestNewClustersFromConfig(t *testing.T) {
ClusterStaticConfiguration{
NewClientFromConfig: newClient1,
Namespaces: []ClusterStaticNamespaceConfiguration{
ClusterStaticNamespaceConfiguration{
{
Namespace: "unaggregated",
Type: storagemetadata.UnaggregatedMetricsType,
Retention: 7 * 24 * time.Hour,
Expand All @@ -84,13 +84,13 @@ func TestNewClustersFromConfig(t *testing.T) {
ClusterStaticConfiguration{
NewClientFromConfig: newClient2,
Namespaces: []ClusterStaticNamespaceConfiguration{
ClusterStaticNamespaceConfiguration{
{
Namespace: "aggregated0",
Type: storagemetadata.AggregatedMetricsType,
Retention: 30 * 24 * time.Hour,
Resolution: time.Minute,
},
ClusterStaticNamespaceConfiguration{
{
Namespace: "aggregated1",
Type: storagemetadata.AggregatedMetricsType,
Retention: 365 * 24 * time.Hour,
Expand Down Expand Up @@ -213,7 +213,11 @@ func (n *noopCluster) UnaggregatedClusterNamespace() ClusterNamespace {
panic("implement me")
}

func (n *noopCluster) AggregatedClusterNamespace(attrs RetentionResolution) (ClusterNamespace, bool) {
func (n *noopCluster) AggregatedClusterNamespace(RetentionResolution) (ClusterNamespace, bool) {
panic("implement me")
}

func (n *noopCluster) ConfigType() ClusterConfigType {
panic("implement me")
}

Expand Down
4 changes: 4 additions & 0 deletions src/query/storage/m3/dynamic_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,10 @@ func (d *dynamicCluster) AggregatedClusterNamespace(attrs RetentionResolution) (
return namespace, ok
}

func (d *dynamicCluster) ConfigType() ClusterConfigType {
return ClusterConfigTypeDynamic
}

// clusterNamespaceLookup is a helper to track namespace changes. Two maps are necessary
// to handle the update case which causes the metadata for a previously seen namespaces to change.
// idToMetadata map allows us to find the previous metadata to detect changes. metadataToClusterNamespaces
Expand Down

0 comments on commit a8f366e

Please sign in to comment.