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

[CONTP-390] Allow user to set the cardinality of a check in the check configuration #29984

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/autodiscoveryimpl/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ func (s *dummyService) GetTags() ([]string, error) {
return nil, nil
}

// GetTagsWithCardinality returns the tags for this service
func (s *dummyService) GetTagsWithCardinality(_ string) ([]string, error) {
return s.GetTags()
}

// GetPid return a dummy pid
func (s *dummyService) GetPid(context.Context) (int, error) {
return s.Pid, nil
Expand Down
11 changes: 8 additions & 3 deletions comp/core/autodiscovery/common/utils/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
logsConfigPath = "logs"
checksPath = "checks"
checkIDPath = "check.id"
checkTagCardinality = "check_tag_cardinality"
)

// ExtractTemplatesFromMap looks for autodiscovery configurations in a given
Expand Down Expand Up @@ -76,7 +77,10 @@ func extractCheckTemplatesFromMap(key string, input map[string]string, prefix st
}
// ParseBool returns `true` only on success cases
ignoreAdTags, _ := strconv.ParseBool(input[prefix+ignoreAutodiscoveryTags])
return BuildTemplates(key, checkNames, initConfigs, instances, ignoreAdTags), nil

cardinality := input[prefix+checkTagCardinality]

return BuildTemplates(key, checkNames, initConfigs, instances, ignoreAdTags, cardinality), nil
}

// extractLogsTemplatesFromMap returns the logs configuration from a given map,
Expand Down Expand Up @@ -166,8 +170,8 @@ func ParseJSONValue(value string) ([][]integration.Data, error) {

// BuildTemplates returns check configurations configured according to the
// passed in AD identifier, check names, init, instance configs and their
// `ignoreAutoDiscoveryTags` field.
func BuildTemplates(adID string, checkNames []string, initConfigs, instances [][]integration.Data, ignoreAutodiscoveryTags bool) []integration.Config {
// `ignoreAutoDiscoveryTags`, `CheckTagCardinality` fields.
func BuildTemplates(adID string, checkNames []string, initConfigs, instances [][]integration.Data, ignoreAutodiscoveryTags bool, checkCard string) []integration.Config {
templates := make([]integration.Config, 0)

// sanity checks
Expand All @@ -192,6 +196,7 @@ func BuildTemplates(adID string, checkNames []string, initConfigs, instances [][
Instances: []integration.Data{instance},
ADIdentifiers: []string{adID},
IgnoreAutodiscoveryTags: ignoreAutodiscoveryTags,
CheckTagCardinality: checkCard,
})
}
}
Expand Down
45 changes: 38 additions & 7 deletions comp/core/autodiscovery/common/utils/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,13 @@ func TestParseCheckNames(t *testing.T) {
func TestBuildTemplates(t *testing.T) {
key := "id"
tests := []struct {
name string
inputCheckNames []string
inputInitConfig [][]integration.Data
inputInstances [][]integration.Data
expectedConfigs []integration.Config
ignoreAdTags bool
name string
inputCheckNames []string
inputInitConfig [][]integration.Data
inputInstances [][]integration.Data
expectedConfigs []integration.Config
ignoreAdTags bool
checkTagCardinality string
}{
{
name: "wrong number of checkNames",
Expand Down Expand Up @@ -434,10 +435,40 @@ func TestBuildTemplates(t *testing.T) {
},
},
},
{
name: "valid inputs with list and checkCardinality",
inputCheckNames: []string{"a", "b"},
inputInitConfig: [][]integration.Data{{integration.Data("{\"test\": 1}")}, {integration.Data("{}")}},
inputInstances: [][]integration.Data{{integration.Data("{\"foo\": 1}"), integration.Data("{\"foo\": 2}")}, {integration.Data("{1:2}")}},
checkTagCardinality: "low",
expectedConfigs: []integration.Config{
{
Name: "a",
ADIdentifiers: []string{key},
InitConfig: integration.Data("{\"test\": 1}"),
Instances: []integration.Data{integration.Data("{\"foo\": 1}")},
CheckTagCardinality: "low",
},
{
Name: "a",
ADIdentifiers: []string{key},
InitConfig: integration.Data("{\"test\": 1}"),
Instances: []integration.Data{integration.Data("{\"foo\": 2}")},
CheckTagCardinality: "low",
},
{
Name: "b",
ADIdentifiers: []string{key},
InitConfig: integration.Data("{}"),
Instances: []integration.Data{integration.Data("{1:2}")},
CheckTagCardinality: "low",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expectedConfigs, BuildTemplates(key, tt.inputCheckNames, tt.inputInitConfig, tt.inputInstances, tt.ignoreAdTags))
assert.Equal(t, tt.expectedConfigs, BuildTemplates(key, tt.inputCheckNames, tt.inputInitConfig, tt.inputInstances, tt.ignoreAdTags, tt.checkTagCardinality))
})
}
}
3 changes: 3 additions & 0 deletions comp/core/autodiscovery/common/utils/pod_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func parseChecksJSON(adIdentifier string, checksJSON string) ([]integration.Conf
Instances []interface{} `json:"instances"`
Logs json.RawMessage `json:"logs"`
IgnoreAutodiscoveryTags bool `json:"ignore_autodiscovery_tags"`
CheckTagCardinality string `json:"check_tag_cardinality"`
}

err := json.Unmarshal([]byte(checksJSON), &namedChecks)
Expand All @@ -84,6 +85,8 @@ func parseChecksJSON(adIdentifier string, checksJSON string) ([]integration.Conf
IgnoreAutodiscoveryTags: config.IgnoreAutodiscoveryTags,
}

c.CheckTagCardinality = config.CheckTagCardinality

if len(config.Logs) > 0 {
c.LogsConfig = integration.Data(config.Logs)
}
Expand Down
26 changes: 26 additions & 0 deletions comp/core/autodiscovery/common/utils/pod_annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,32 @@ func TestExtractTemplatesFromAnnotations(t *testing.T) {
},
},
},
{
name: "Nominal case with two templates and check tag cardinality",
annotations: map[string]string{
"ad.datadoghq.com/foobar.check_names": "[\"apache\",\"http_check\"]",
"ad.datadoghq.com/foobar.init_configs": "[{},{}]",
"ad.datadoghq.com/foobar.instances": "[{\"apache_status_url\":\"http://%%host%%/server-status?auto\"},{\"name\":\"My service\",\"timeout\":1,\"url\":\"http://%%host%%\"}]",
"ad.datadoghq.com/foobar.check_tag_cardinality": "low",
},
adIdentifier: "foobar",
output: []integration.Config{
{
Name: "apache",
Instances: []integration.Data{integration.Data("{\"apache_status_url\":\"http://%%host%%/server-status?auto\"}")},
InitConfig: integration.Data("{}"),
ADIdentifiers: []string{adID},
CheckTagCardinality: "low",
},
{
Name: "http_check",
Instances: []integration.Data{integration.Data("{\"name\":\"My service\",\"timeout\":1,\"url\":\"http://%%host%%\"}")},
InitConfig: integration.Data("{}"),
ADIdentifiers: []string{adID},
CheckTagCardinality: "low",
},
},
},
{
name: "Take one, ignore one",
annotations: map[string]string{
Expand Down
8 changes: 7 additions & 1 deletion comp/core/autodiscovery/configresolver/configresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,13 @@ func Resolve(tpl integration.Config, svc listeners.Service) (integration.Config,
return resolvedConfig, errors.New("unable to resolve, service not ready")
}

tags, err := svc.GetTags()
var tags []string
var err error
if tpl.CheckTagCardinality != "" {
tags, err = svc.GetTagsWithCardinality(tpl.CheckTagCardinality)
} else {
tags, err = svc.GetTags()
}
if err != nil {
return resolvedConfig, fmt.Errorf("couldn't get tags for service '%s', err: %w", svc.GetServiceID(), err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ func (s *dummyService) GetTags() ([]string, error) {
return []string{"foo:bar"}, nil
}

// GetTagsWithCardinality returns the tags for this service
func (s *dummyService) GetTagsWithCardinality(_ string) ([]string, error) {
return s.GetTags()
}

// GetPid return a dummy pid
func (s *dummyService) GetPid(context.Context) (int, error) {
return s.Pid, nil
Expand Down
3 changes: 3 additions & 0 deletions comp/core/autodiscovery/integration/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ type Config struct {
// IgnoreAutodiscoveryTags is used to ignore tags coming from autodiscovery
IgnoreAutodiscoveryTags bool `json:"ignore_autodiscovery_tags"` // (include in digest: true)

// CheckTagCardinality is used to override the default tag cardinality in the agent configuration
CheckTagCardinality string `json:"check_tag_cardinality"` // (include in digest: false)

// MetricsExcluded is whether metrics collection is disabled (set by
// container listeners only)
MetricsExcluded bool `json:"metrics_excluded"` // (include in digest: false)
Expand Down
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/listeners/cloudfoundry.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,11 @@ func (s *CloudFoundryService) GetTags() ([]string, error) {
return s.tags, nil
}

// GetTagsWithCardinality returns the tags with given cardinality. Not supported in CF
func (s *CloudFoundryService) GetTagsWithCardinality(cardinality string) ([]string, error) {
return s.GetTags()
}

// GetPid returns nil and an error because pids are currently not supported in CF
func (s *CloudFoundryService) GetPid(context.Context) (int, error) {
return -1, ErrNotSupported
Expand Down
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/listeners/dbm_aurora.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ func (d *DBMAuroraService) GetTags() ([]string, error) {
return []string{}, nil
}

// GetTagsWithCardinality returns the tags with given cardinality. Not supported in DBMAuroraService
func (d *DBMAuroraService) GetTagsWithCardinality(_ string) ([]string, error) {
return d.GetTags()
}

// GetPid returns nil and an error because pids are currently not supported
func (d *DBMAuroraService) GetPid(context.Context) (int, error) {
return -1, ErrNotSupported
Expand Down
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/listeners/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ func (s *EnvironmentService) GetTags() ([]string, error) {
return nil, nil
}

// GetTagsWithCardinality returns the tags with given cardinality. Not supported in EnvironmentService
func (s *EnvironmentService) GetTagsWithCardinality(_ string) ([]string, error) {
return s.GetTags()
}

// GetPid inspect the container and return its pid
// Not relevant in this listener
func (s *EnvironmentService) GetPid(context.Context) (int, error) {
Expand Down
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/listeners/kube_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,11 @@ func (s *KubeEndpointService) GetTags() ([]string, error) {
return s.tags, nil
}

// GetTagsWithCardinality returns the tags with given cardinality.
func (s *KubeEndpointService) GetTagsWithCardinality(_ string) ([]string, error) {
return s.GetTags()
}

// GetHostname returns nil and an error because port is not supported in Kubelet
func (s *KubeEndpointService) GetHostname(context.Context) (string, error) {
return "", ErrNotSupported
Expand Down
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/listeners/kube_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ func (s *KubeServiceService) GetTags() ([]string, error) {
return s.tags, nil
}

// GetTagsWithCardinality returns the tags with given cardinality.
func (s *KubeServiceService) GetTagsWithCardinality(_ string) ([]string, error) {
return s.GetTags()
}

// GetHostname returns nil and an error because port is not supported in Kubelet
func (s *KubeServiceService) GetHostname(context.Context) (string, error) {
return "", ErrNotSupported
Expand Down
11 changes: 11 additions & 0 deletions comp/core/autodiscovery/listeners/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/DataDog/datadog-agent/comp/core/autodiscovery/providers/names"
"github.com/DataDog/datadog-agent/comp/core/tagger"
taggercommon "github.com/DataDog/datadog-agent/comp/core/tagger/common"
"github.com/DataDog/datadog-agent/comp/core/tagger/types"
workloadmeta "github.com/DataDog/datadog-agent/comp/core/workloadmeta/def"
pkgconfigsetup "github.com/DataDog/datadog-agent/pkg/config/setup"
"github.com/DataDog/datadog-agent/pkg/util/containers"
Expand Down Expand Up @@ -92,6 +93,16 @@ func (s *service) GetTags() ([]string, error) {
return tagger.Tag(taggercommon.BuildTaggerEntityID(s.entity.GetID()).String(), tagger.ChecksCardinality())
}

// GetTagsWithCardinality returns the tags with given cardinality.
func (s *service) GetTagsWithCardinality(cardinality string) ([]string, error) {
checkCard, err := types.StringToTagCardinality(cardinality)
if err == nil {
return tagger.Tag(taggercommon.BuildTaggerEntityID(s.entity.GetID()).String(), checkCard)
}
log.Warnf("error converting cardinality %s to TagCardinality: %v", cardinality, err)
return s.GetTags()
}

// GetPid returns the process ID of the service.
func (s *service) GetPid(_ context.Context) (int, error) {
return s.pid, nil
Expand Down
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/listeners/snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,11 @@ func (s *SNMPService) GetTags() ([]string, error) {
return []string{}, nil
}

// GetTagsWithCardinality returns the tags with given cardinality.
func (s *SNMPService) GetTagsWithCardinality(_ string) ([]string, error) {
return s.GetTags()
}

// GetPid returns nil and an error because pids are currently not supported
func (s *SNMPService) GetPid(context.Context) (int, error) {
return -1, ErrNotSupported
Expand Down
5 changes: 5 additions & 0 deletions comp/core/autodiscovery/listeners/staticconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ func (s *StaticConfigService) GetTags() ([]string, error) {
return nil, nil
}

// GetTagsWithCardinality returns the tags with given cardinality.
func (s *StaticConfigService) GetTagsWithCardinality(_ string) ([]string, error) {
return s.GetTags()
}

// GetPid inspect the container and return its pid
// Not relevant in this listener
func (s *StaticConfigService) GetPid(context.Context) (int, error) {
Expand Down
23 changes: 12 additions & 11 deletions comp/core/autodiscovery/listeners/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ type ContainerPort struct {
// It should be matched with a check template by the ConfigResolver using the
// ADIdentifiers field.
type Service interface {
Equal(Service) bool // compare two services
GetServiceID() string // unique service name
GetADIdentifiers(context.Context) ([]string, error) // identifiers on which templates will be matched
GetHosts(context.Context) (map[string]string, error) // network --> IP address
GetPorts(context.Context) ([]ContainerPort, error) // network ports
GetTags() ([]string, error) // tags
GetPid(context.Context) (int, error) // process identifier
GetHostname(context.Context) (string, error) // hostname.domainname for the entity
IsReady(context.Context) bool // is the service ready
HasFilter(containers.FilterType) bool // whether the service is excluded by metrics or logs exclusion config
GetExtraConfig(string) (string, error) // Extra configuration values
Equal(Service) bool // compare two services
GetServiceID() string // unique service name
GetADIdentifiers(context.Context) ([]string, error) // identifiers on which templates will be matched
GetHosts(context.Context) (map[string]string, error) // network --> IP address
GetPorts(context.Context) ([]ContainerPort, error) // network ports
GetTags() ([]string, error) // tags
GetTagsWithCardinality(cardinality string) ([]string, error) // tags with given cardinality
zhuminyi marked this conversation as resolved.
Show resolved Hide resolved
GetPid(context.Context) (int, error) // process identifier
GetHostname(context.Context) (string, error) // hostname.domainname for the entity
IsReady(context.Context) bool // is the service ready
HasFilter(containers.FilterType) bool // whether the service is excluded by metrics or logs exclusion config
GetExtraConfig(string) (string, error) // Extra configuration values

// FilterTemplates filters the templates which will be resolved against
// this service, in a map keyed by template digest.
Expand Down
4 changes: 4 additions & 0 deletions comp/core/autodiscovery/providers/config_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type configFormat struct {
Instances []integration.RawMap
DockerImages []string `yaml:"docker_images"` // Only imported for deprecation warning
IgnoreAutodiscoveryTags bool `yaml:"ignore_autodiscovery_tags"` // Use to ignore tags coming from autodiscovery
CheckTagCardinality string `yaml:"check_tag_cardinality"` // Use to set the tag cardinality override for the check
}

type configPkg struct {
Expand Down Expand Up @@ -430,6 +431,9 @@ func GetIntegrationConfigFromFile(name, fpath string) (integration.Config, error
// Copy ignore_autodiscovery_tags parameter
conf.IgnoreAutodiscoveryTags = cf.IgnoreAutodiscoveryTags

// Copy check_tag_cardinality parameter
conf.CheckTagCardinality = cf.CheckTagCardinality

// DockerImages entry was found: we ignore it if no ADIdentifiers has been found
if len(cf.DockerImages) > 0 && len(cf.ADIdentifiers) == 0 {
return conf, errors.New("the 'docker_images' section is deprecated, please use 'ad_identifiers' instead")
Expand Down
2 changes: 1 addition & 1 deletion comp/core/autodiscovery/providers/consul.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func (p *ConsulConfigProvider) getTemplates(ctx context.Context, key string) []i
log.Errorf("Failed to retrieve instances at %s. Error: %s", instanceKey, err)
return templates
}
return utils.BuildTemplates(key, checkNames, initConfigs, instances, false)
return utils.BuildTemplates(key, checkNames, initConfigs, instances, false, "")
}

// getValue returns value, error
Expand Down
2 changes: 1 addition & 1 deletion comp/core/autodiscovery/providers/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (p *EtcdConfigProvider) getTemplates(ctx context.Context, key string) []int
return nil
}

return utils.BuildTemplates(key, checkNames, initConfigs, instances, false)
return utils.BuildTemplates(key, checkNames, initConfigs, instances, false, "")
}

// getEtcdValue retrieves content from etcd
Expand Down
1 change: 1 addition & 0 deletions comp/core/autodiscovery/providers/kube_endpoints_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ func endpointChecksFromTemplate(tpl integration.Config, ep *v1.Endpoints) []inte
Provider: names.KubeEndpointsFile,
Source: tpl.Source,
IgnoreAutodiscoveryTags: tpl.IgnoreAutodiscoveryTags,
CheckTagCardinality: tpl.CheckTagCardinality,
}

utils.ResolveEndpointConfigAuto(config, ep.Subsets[i].Addresses[j])
Expand Down
2 changes: 1 addition & 1 deletion comp/core/autodiscovery/providers/zookeeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func (z *ZookeeperConfigProvider) getTemplates(key string) []integration.Config
return nil
}

return utils.BuildTemplates(key, checkNames, initConfigs, instances, false)
return utils.BuildTemplates(key, checkNames, initConfigs, instances, false, "")
}

func (z *ZookeeperConfigProvider) getJSONValue(key string) ([][]integration.Data, error) {
Expand Down
Loading
Loading