diff --git a/client/fingerprint/consul.go b/client/fingerprint/consul.go index adfbe4c4e16..f562672332b 100644 --- a/client/fingerprint/consul.go +++ b/client/fingerprint/consul.go @@ -189,5 +189,5 @@ func (f *ConsulFingerprint) grpc(info agentconsul.Self) (string, bool) { } func (f *ConsulFingerprint) namespaces(info agentconsul.Self) (string, bool) { - return agentconsul.Namespaces(info) + return strconv.FormatBool(agentconsul.Namespaces(info)), true } diff --git a/client/fingerprint/consul_test.go b/client/fingerprint/consul_test.go index ae373209eb5..fb7ff3ca8c0 100644 --- a/client/fingerprint/consul_test.go +++ b/client/fingerprint/consul_test.go @@ -326,33 +326,38 @@ func TestConsulFingerprint_namespaces(t *testing.T) { fp := newConsulFingerPrint(t) t.Run("supports namespaces", func(t *testing.T) { - s, ok := fp.namespaces(agentconsul.Self{ + value, ok := fp.namespaces(agentconsul.Self{ "Stats": {"license": map[string]interface{}{"features": "Automated Backups, Automated Upgrades, Enhanced Read Scalability, Network Segments, Redundancy Zone, Advanced Network Federation, Namespaces, SSO, Audit Logging"}}, }) require.True(t, ok) - require.Equal(t, "true", s) + require.Equal(t, "true", value) }) t.Run("no namespaces", func(t *testing.T) { - _, ok := fp.namespaces(agentconsul.Self{ + value, ok := fp.namespaces(agentconsul.Self{ "Stats": {"license": map[string]interface{}{"features": "Automated Backups, Automated Upgrades, Enhanced Read Scalability, Network Segments, Redundancy Zone, Advanced Network Federation, SSO, Audit Logging"}}, }) - require.False(t, ok) + require.True(t, ok) + require.Equal(t, "false", value) + }) t.Run("stats missing", func(t *testing.T) { - _, ok := fp.namespaces(agentconsul.Self{}) - require.False(t, ok) + value, ok := fp.namespaces(agentconsul.Self{}) + require.True(t, ok) + require.Equal(t, "false", value) }) t.Run("license missing", func(t *testing.T) { - _, ok := fp.namespaces(agentconsul.Self{"Stats": {}}) - require.False(t, ok) + value, ok := fp.namespaces(agentconsul.Self{"Stats": {}}) + require.True(t, ok) + require.Equal(t, "false", value) }) t.Run("features missing", func(t *testing.T) { - _, ok := fp.namespaces(agentconsul.Self{"Stats": {"license": map[string]interface{}{}}}) - require.False(t, ok) + value, ok := fp.namespaces(agentconsul.Self{"Stats": {"license": map[string]interface{}{}}}) + require.True(t, ok) + require.Equal(t, "false", value) }) } @@ -372,15 +377,16 @@ func TestConsulFingerprint_Fingerprint_oss(t *testing.T) { err := cf.Fingerprint(&FingerprintRequest{Config: cfg, Node: node}, &resp) require.NoError(t, err) require.Equal(t, map[string]string{ - "consul.datacenter": "dc1", - "consul.revision": "3c1c22679", - "consul.segment": "seg1", - "consul.server": "true", - "consul.sku": "oss", - "consul.version": "1.9.5", - "consul.connect": "true", - "consul.grpc": "8502", - "unique.consul.name": "HAL9000", + "consul.datacenter": "dc1", + "consul.revision": "3c1c22679", + "consul.segment": "seg1", + "consul.server": "true", + "consul.sku": "oss", + "consul.version": "1.9.5", + "consul.connect": "true", + "consul.grpc": "8502", + "consul.ft.namespaces": "false", + "unique.consul.name": "HAL9000", }, resp.Attributes) require.True(t, resp.Detected) @@ -425,15 +431,16 @@ func TestConsulFingerprint_Fingerprint_oss(t *testing.T) { err3 := cf.Fingerprint(&FingerprintRequest{Config: cfg, Node: node}, &resp3) require.NoError(t, err3) require.Equal(t, map[string]string{ - "consul.datacenter": "dc1", - "consul.revision": "3c1c22679", - "consul.segment": "seg1", - "consul.server": "true", - "consul.sku": "oss", - "consul.version": "1.9.5", - "consul.connect": "true", - "consul.grpc": "8502", - "unique.consul.name": "HAL9000", + "consul.datacenter": "dc1", + "consul.revision": "3c1c22679", + "consul.segment": "seg1", + "consul.server": "true", + "consul.sku": "oss", + "consul.version": "1.9.5", + "consul.connect": "true", + "consul.grpc": "8502", + "consul.ft.namespaces": "false", + "unique.consul.name": "HAL9000", }, resp3.Attributes) // consul now available again diff --git a/command/agent/consul/namespaces_client.go b/command/agent/consul/namespaces_client.go index 5d5f6a5a62e..974b2e705a3 100644 --- a/command/agent/consul/namespaces_client.go +++ b/command/agent/consul/namespaces_client.go @@ -60,12 +60,7 @@ func (ns *NamespacesClient) allowable(now time.Time) bool { return ns.enabled } - enabledStr, ok := Namespaces(self) - if !ok { - return ns.enabled - } - - ns.enabled = enabledStr == "true" + ns.enabled = Namespaces(self) ns.updated = now return ns.enabled } diff --git a/command/agent/consul/self.go b/command/agent/consul/self.go index 1cdd48045af..d0edee2758c 100644 --- a/command/agent/consul/self.go +++ b/command/agent/consul/self.go @@ -27,30 +27,29 @@ func SKU(info Self) (string, bool) { return "oss", true } -func Namespaces(info Self) (string, bool) { +// Namespaces returns true if the "Namespaces" feature is enabled in Consul, and +// false otherwise. Consul OSS will always return false, and Consul ENT will return +// false if the license file does not contain the necessary feature. +func Namespaces(info Self) bool { return feature("Namespaces", info) } -// Feature returns whether the indicated feature is enabled by Consul and the +// feature returns whether the indicated feature is enabled by Consul and the // associated License. // possible values as of v1.9.5+ent: // Automated Backups, Automated Upgrades, Enhanced Read Scalability, // Network Segments, Redundancy Zone, Advanced Network Federation, // Namespaces, SSO, Audit Logging -func feature(name string, info Self) (string, bool) { +func feature(name string, info Self) bool { lic, licOK := info["Stats"]["license"].(map[string]interface{}) if !licOK { - return "", false + return false } features, exists := lic["features"].(string) if !exists { - return "", false - } - - if !strings.Contains(features, name) { - return "", false + return false } - return "true", true + return strings.Contains(features, name) } diff --git a/command/agent/consul/self_test.go b/command/agent/consul/self_test.go index a9620fd3077..3089c242204 100644 --- a/command/agent/consul/self_test.go +++ b/command/agent/consul/self_test.go @@ -67,32 +67,31 @@ func TestSelf_Namespaces(t *testing.T) { t.Parallel() t.Run("supports namespaces", func(t *testing.T) { - s, ok := Namespaces(Self{ + enabled := Namespaces(Self{ "Stats": {"license": map[string]interface{}{"features": "Automated Backups, Automated Upgrades, Enhanced Read Scalability, Network Segments, Redundancy Zone, Advanced Network Federation, Namespaces, SSO, Audit Logging"}}, }) - require.True(t, ok) - require.Equal(t, "true", s) + require.True(t, enabled) }) t.Run("no namespaces", func(t *testing.T) { - _, ok := Namespaces(Self{ + enabled := Namespaces(Self{ "Stats": {"license": map[string]interface{}{"features": "Automated Backups, Automated Upgrades, Enhanced Read Scalability, Network Segments, Redundancy Zone, Advanced Network Federation, SSO, Audit Logging"}}, }) - require.False(t, ok) + require.False(t, enabled) }) t.Run("stats missing", func(t *testing.T) { - _, ok := Namespaces(Self{}) - require.False(t, ok) + enabled := Namespaces(Self{}) + require.False(t, enabled) }) t.Run("license missing", func(t *testing.T) { - _, ok := Namespaces(Self{"Stats": {}}) - require.False(t, ok) + enabled := Namespaces(Self{"Stats": {}}) + require.False(t, enabled) }) t.Run("features missing", func(t *testing.T) { - _, ok := Namespaces(Self{"Stats": {"license": map[string]interface{}{}}}) - require.False(t, ok) + enabled := Namespaces(Self{"Stats": {"license": map[string]interface{}{}}}) + require.False(t, enabled) }) }