Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New way to resolve namespaces from MetaData #37

Merged
merged 2 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions configs/aerospike_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ client_config:
### Probe discovery configuration ###
# The key to discover Aerospike's namespaces through service discovery
# Set it to "" to instead discover namespaces automatically via the info command
# DEPRECATED since 02/19/2024
namespace_meta_key: "aerospike-namespaces"
# The key prefix to discover Aerospike's namespaces through service discovery
# old "namespace_meta_key" has been DEPRECATED because of 512 bytes limitation of the value in consul.
namespace_meta_key_prefix: "aerospike-monitoring-"
### Probe configuration ###
monitoring_set: monitoring
latency_key_prefix: monitoring_latency_
Expand Down
2 changes: 2 additions & 0 deletions pkg/aerospike/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type AerospikeEndpointConfig struct {
TLSHostnameMetaKey string `yaml:"tls_hostname_meta_key,omitempty"`
// Probe configuration
NamespaceMetaKey string `yaml:"namespace_meta_key,omitempty"`
NamespaceMetaKeyPrefix string `yaml:"namespace_meta_key_prefix,omitempty"`
MonitoringSet string `yaml:"monitoring_set,omitempty"`
LatencyKeyPrefix string `yaml:"latency_key_prefix,omitempty"`
DurabilityKeyPrefix string `yaml:"durability_key_prefix,omitempty"`
Expand All @@ -63,6 +64,7 @@ var (
TLSTag: "tls",
TLSHostnameMetaKey: "tls-hostname",
NamespaceMetaKey: "",
NamespaceMetaKeyPrefix: "",
MonitoringSet: "monitoring",
LatencyKeyPrefix: "monitoring_latency_",
DurabilityKeyPrefix: "monitoring_durability_",
Expand Down
45 changes: 38 additions & 7 deletions pkg/aerospike/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package aerospike
import (
"fmt"
"os"
"strconv"
"strings"

as "github.com/aerospike/aerospike-client-go/v5"
Expand Down Expand Up @@ -47,7 +48,7 @@ func (conf *AerospikeProbeConfig) generateNamespacedEndpointsFromEntry(logger lo
clusterName = entry.Address
}

namespaces := conf.getNamespacesFromEntry(entry)
namespaces := conf.getNamespacesFromEntry(logger, entry)

var endpoints []*AerospikeEndpoint
for namespace := range namespaces {
Expand Down Expand Up @@ -75,15 +76,45 @@ func (conf *AerospikeProbeConfig) generateNamespacedEndpointsFromEntry(logger lo
return endpoints, nil
}

func (conf AerospikeProbeConfig) getNamespacesFromEntry(entry discovery.ServiceEntry) map[string]struct{} {
func (conf AerospikeProbeConfig) getNamespacesFromEntry(logger log.Logger, entry discovery.ServiceEntry) map[string]struct{} {
namespaces := make(map[string]struct{})
nsString, ok := entry.Meta[conf.AerospikeEndpointConfig.NamespaceMetaKey]
if ok {
nsFromDiscovery := strings.Split(nsString, ";")
for _, ns := range nsFromDiscovery {
namespaces[ns] = struct{}{}
fallback := false

// Correct way to get namespaces.
for metaKey, metaValue := range entry.Meta {
if !strings.HasPrefix(metaKey, conf.AerospikeEndpointConfig.NamespaceMetaKeyPrefix) {
continue
}
ready, err := strconv.ParseBool(metaValue)
// if the value of the NamespaceMetaKeyPrefix MetaData is not a boolean then fallback to the old method
if err != nil {
level.Error(logger).Log("msg", fmt.Sprintf("Fail to parse boolean value from MetaData %s. Fallbacking to deprecated method.", metaKey), "err", err)
fallback = true
break
}
// if ready is at false, then iterate to the next MetaData and try to resolve other namespaces
if !ready {
continue
}
ns := strings.Split(metaKey, "-")[2] // MetaKey is like : "aerospike-monitoring-closeststore"
namespaces[ns] = struct{}{}
}

// DEPRECATED way to get namespaces in case of fallback required or empty namespaces with the new method
if fallback || len(namespaces) == 0 {
nsString, ok := entry.Meta[conf.AerospikeEndpointConfig.NamespaceMetaKey]
if ok {
// Clear namespaces for any previously found entry from the old method
for k := range namespaces {
delete(namespaces, k)
}
nsFromDiscovery := strings.Split(nsString, ";")
for _, ns := range nsFromDiscovery {
namespaces[ns] = struct{}{}
}
}
}

return namespaces
}

Expand Down
110 changes: 110 additions & 0 deletions pkg/aerospike/discovery_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package aerospike

import (
"errors"
"reflect"
"testing"
"time"

"github.com/criteo/blackbox-prober/pkg/discovery"
"github.com/criteo/blackbox-prober/pkg/topology"
"github.com/go-kit/log"
)

type testEndpoint struct {
topology.DummyEndpoint
deadline time.Time
CheckCallCount int
RefreshCallCount int
}

func (te *testEndpoint) Refresh() error {
te.RefreshCallCount += 1
if te.RefreshCallCount%2 == 0 {
return errors.New("fake err")
}
return nil
}

func TestGetNamespacesFromEntry(t *testing.T) {
entry_newValid := discovery.ServiceEntry{
Meta: map[string]string{
"aerospike-monitoring-test1": "true",
"aerospike-monitoring-test2": "true",
"aerospike-monitoring-test3": "false",
},
}
expected_newValid := map[string]struct{}{
"test1": struct{}{},
"test2": struct{}{},
}

entry_oldValid := discovery.ServiceEntry{
Meta: map[string]string{
"aerospike-namespaces": "test1;test2;test3",
},
}
expected_oldValid := map[string]struct{}{
"test1": struct{}{},
"test2": struct{}{},
"test3": struct{}{},
}

entry_noFallback := discovery.ServiceEntry{
Meta: map[string]string{
"aerospike-namespaces": "test3",
"aerospike-monitoring-test1": "true",
"aerospike-monitoring-test2": "false",
"aerospike-monitoring-test3": "true",
},
}
expected_noFallback := map[string]struct{}{
"test1": struct{}{},
"test3": struct{}{},
}

entry_fallback := discovery.ServiceEntry{
Meta: map[string]string{
"aerospike-namespaces": "test3",
"aerospike-monitoring-test1": "true",
"aerospike-monitoring-test2": "foo",
"aerospike-monitoring-test3": "false",
},
}
expected_fallback := map[string]struct{}{
"test3": struct{}{},
}

entry_empty := discovery.ServiceEntry{
Meta: map[string]string{},
}
expected_empty := map[string]struct{}{}

// Minimum config for getNamespacesFromEntry tests
config := AerospikeProbeConfig{}
config.AerospikeEndpointConfig = AerospikeEndpointConfig{
NamespaceMetaKey: "aerospike-namespaces",
NamespaceMetaKeyPrefix: "aerospike-monitoring-",
}

namespaces := config.getNamespacesFromEntry(log.NewNopLogger(), entry_newValid)
if !reflect.DeepEqual(namespaces, expected_newValid) {
t.Errorf("getNamespacesFromEntry didn't return expected value for entry 'entry_newValid'.")
}
namespaces = config.getNamespacesFromEntry(log.NewNopLogger(), entry_oldValid)
if !reflect.DeepEqual(namespaces, expected_oldValid) {
t.Errorf("getNamespacesFromEntry didn't return expected value for entry 'entry_oldValid'.")
}
namespaces = config.getNamespacesFromEntry(log.NewNopLogger(), entry_noFallback)
if !reflect.DeepEqual(namespaces, expected_noFallback) {
t.Errorf("getNamespacesFromEntry didn't return expected value for entry 'entry_noFallback'.")
}
namespaces = config.getNamespacesFromEntry(log.NewNopLogger(), entry_fallback)
if !reflect.DeepEqual(namespaces, expected_fallback) {
t.Errorf("getNamespacesFromEntry didn't return expected value for entry 'entry_fallback'.")
}
namespaces = config.getNamespacesFromEntry(log.NewNopLogger(), entry_empty)
if !reflect.DeepEqual(namespaces, expected_empty) {
t.Errorf("getNamespacesFromEntry didn't return expected value for entry 'entry_empty'.")
}
}
20 changes: 15 additions & 5 deletions probes/aerospike/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,28 @@

## Namespace discovery

The probe is not discovering namespaces automatically. The `namespace_meta_key`
The probe is not discovering namespaces automatically. The `namespace_meta_key_prefix`
needs to be defined on the cluster's consul services for the probe to discover them
The probe will not do any checking without at least one namespace specified.

Example:
`namespace_meta_key` per default is set to `aerospike-namespaces`. The value
is a set of namespace name separated by a semicolon `;`.
`namespace_meta_key_prefix` per default is set to `aerospike-monitoring-`.

Example: advertising "foo" and "bar" namespace
For advertising "foo" and "bar" namespace

`aerospike-namespaces: "foo;bar"`
`aerospike-monitoring-foo: true`
`aerospike-monitoring-bar: true`

If any of these MetaData entries are not present of does not define a bool value
then it will fallback to the old method of namespace discovery:
`namespace_meta_key` which contains namespaces separated by `;`

Example:
`namespace_meta_key` per default is set to `aerospike-namespaces`.

For advertising "foo" and "bar" namespace

`aerospike-namespaces: foo;bar`

## Latency checks executed at cluster level

Expand Down
Loading