diff --git a/comp/collector/collector/collectorimpl/internal/middleware/check_wrapper.go b/comp/collector/collector/collectorimpl/internal/middleware/check_wrapper.go index e8e777355ea0b..37084af52f3e1 100644 --- a/comp/collector/collector/collectorimpl/internal/middleware/check_wrapper.go +++ b/comp/collector/collector/collectorimpl/internal/middleware/check_wrapper.go @@ -7,6 +7,7 @@ package middleware import ( + "fmt" "sync" "time" @@ -78,7 +79,17 @@ func (c *CheckWrapper) Configure(senderManager sender.SenderManager, integration if c.senderManager == nil { c.senderManager = senderManager } - return c.inner.Configure(c.senderManager, integrationConfigDigest, config, initConfig, source) + err := c.inner.Configure(c.senderManager, integrationConfigDigest, config, initConfig, source) + + if err != nil { + return err + } + + if c.inner.IsHAEnabled() && !c.inner.IsHASupported() { + return fmt.Errorf("High Availability is enabled for check %s but this integration does not support it", string(c.ID())) + } + + return nil } // Interval implements Check#Interval @@ -147,3 +158,8 @@ func (c *CheckWrapper) GetDiagnoses() ([]diagnosis.Diagnosis, error) { func (c *CheckWrapper) IsHAEnabled() bool { return c.inner.IsHAEnabled() } + +// IsHASupported implements Check#IsHASupported +func (c *CheckWrapper) IsHASupported() bool { + return c.inner.IsHASupported() +} diff --git a/pkg/collector/check/check.go b/pkg/collector/check/check.go index a22021f0fe1ba..1b9b1650c5a24 100644 --- a/pkg/collector/check/check.go +++ b/pkg/collector/check/check.go @@ -56,6 +56,8 @@ type Check interface { GetDiagnoses() ([]diagnosis.Diagnosis, error) // IsHAEnabled returns if High Availability is enabled for this check IsHAEnabled() bool + // IsHASupported returns if the check is compatible with High Availability + IsHASupported() bool } // Info is an interface to pull information from types capable to run checks. This is a subsection from the Check diff --git a/pkg/collector/check/stub/stub.go b/pkg/collector/check/stub/stub.go index e616f6450d10a..7b362e32a2610 100644 --- a/pkg/collector/check/stub/stub.go +++ b/pkg/collector/check/stub/stub.go @@ -73,3 +73,6 @@ func (c *StubCheck) GetDiagnoses() ([]diagnosis.Diagnosis, error) { return nil, // IsHAEnabled returns false func (c *StubCheck) IsHAEnabled() bool { return false } + +// IsHASupported returns false +func (c *StubCheck) IsHASupported() bool { return false } diff --git a/pkg/collector/corechecks/checkbase.go b/pkg/collector/corechecks/checkbase.go index e6676051d8396..ad4c5650b3b7e 100644 --- a/pkg/collector/corechecks/checkbase.go +++ b/pkg/collector/corechecks/checkbase.go @@ -295,3 +295,8 @@ func (c *CheckBase) GetDiagnoses() ([]diagnosis.Diagnosis, error) { func (c *CheckBase) IsHAEnabled() bool { return c.haEnabled } + +// IsHASupported returns if the check is compatible with High Availability +func (c *CheckBase) IsHASupported() bool { + return false +} diff --git a/pkg/collector/corechecks/checkbase_test.go b/pkg/collector/corechecks/checkbase_test.go index 0028ff45e2333..a570779e90afa 100644 --- a/pkg/collector/corechecks/checkbase_test.go +++ b/pkg/collector/corechecks/checkbase_test.go @@ -23,6 +23,10 @@ foo_init: bar_init min_collection_interval: 60 empty_default_hostname: true name: foobar +` + haConfig = ` +foo_init: bar_init +ha_enabled: true ` ) diff --git a/pkg/collector/corechecks/embed/apm/apm.go b/pkg/collector/corechecks/embed/apm/apm.go index e8bda38528523..a58e141ecfaf8 100644 --- a/pkg/collector/corechecks/embed/apm/apm.go +++ b/pkg/collector/corechecks/embed/apm/apm.go @@ -259,6 +259,11 @@ func (c *APMCheck) IsHAEnabled() bool { return false } +// IsHASupported returns if the check is compatible with High Availability +func (c *APMCheck) IsHASupported() bool { + return false +} + // Factory creates a new check factory func Factory() option.Option[func() check.Check] { return option.New(newCheck) diff --git a/pkg/collector/corechecks/embed/process/process_agent.go b/pkg/collector/corechecks/embed/process/process_agent.go index 63f700f45efd6..5db0af05c0226 100644 --- a/pkg/collector/corechecks/embed/process/process_agent.go +++ b/pkg/collector/corechecks/embed/process/process_agent.go @@ -253,6 +253,11 @@ func (c *ProcessAgentCheck) IsHAEnabled() bool { return false } +// IsHASupported returns if the check is compatible with High Availability +func (c *ProcessAgentCheck) IsHASupported() bool { + return false +} + // Factory creates a new check factory func Factory() option.Option[func() check.Check] { return option.New(newCheck) diff --git a/pkg/collector/corechecks/longrunning_test.go b/pkg/collector/corechecks/longrunning_test.go index 966324a77a104..a8cfd57cb4c05 100644 --- a/pkg/collector/corechecks/longrunning_test.go +++ b/pkg/collector/corechecks/longrunning_test.go @@ -95,6 +95,11 @@ func (m *mockLongRunningCheck) IsHAEnabled() bool { return args.Bool(0) } +func (m *mockLongRunningCheck) IsHASupported() bool { + args := m.Called() + return args.Bool(0) +} + func (m *mockLongRunningCheck) GetSender() (sender.Sender, error) { args := m.Called() s := args.Get(0) diff --git a/pkg/collector/corechecks/network-devices/cisco-sdwan/sdwan.go b/pkg/collector/corechecks/network-devices/cisco-sdwan/sdwan.go index d1ab6b9ea5835..c86b694f14dee 100644 --- a/pkg/collector/corechecks/network-devices/cisco-sdwan/sdwan.go +++ b/pkg/collector/corechecks/network-devices/cisco-sdwan/sdwan.go @@ -290,6 +290,11 @@ func (c *CiscoSdwanCheck) Interval() time.Duration { return c.interval } +// IsHASupported returns true if the check supports HA +func (c *CiscoSdwanCheck) IsHASupported() bool { + return true +} + func boolPointer(b bool) *bool { return &b } diff --git a/pkg/collector/corechecks/networkpath/networkpath.go b/pkg/collector/corechecks/networkpath/networkpath.go index 6e010fa6eda90..5b3346dfbdc22 100644 --- a/pkg/collector/corechecks/networkpath/networkpath.go +++ b/pkg/collector/corechecks/networkpath/networkpath.go @@ -138,6 +138,11 @@ func (c *Check) Configure(senderManager sender.SenderManager, integrationConfigD return nil } +// IsHASupported returns true if the check supports HA +func (c *Check) IsHASupported() bool { + return true +} + // Factory creates a new check factory func Factory(telemetry telemetryComp.Component) option.Option[func() check.Check] { return option.New(func() check.Check { diff --git a/pkg/collector/corechecks/snmp/snmp.go b/pkg/collector/corechecks/snmp/snmp.go index 630dd25c31848..75a20eda7a388 100644 --- a/pkg/collector/corechecks/snmp/snmp.go +++ b/pkg/collector/corechecks/snmp/snmp.go @@ -196,6 +196,11 @@ func (c *Check) GetDiagnoses() ([]diagnosis.Diagnosis, error) { return c.singleDeviceCk.GetDiagnoses(), nil } +// IsHASupported returns true if the check supports HA +func (c *Check) IsHASupported() bool { + return true +} + // Factory creates a new check factory func Factory(agentConfig config.Component) option.Option[func() check.Check] { return option.New(func() check.Check { diff --git a/pkg/collector/python/check.go b/pkg/collector/python/check.go index e83a5fac1ac30..c15a02be600ac 100644 --- a/pkg/collector/python/check.go +++ b/pkg/collector/python/check.go @@ -64,10 +64,11 @@ type PythonCheck struct { initConfig string instanceConfig string haEnabled bool + haSupported bool } // NewPythonCheck conveniently creates a PythonCheck instance -func NewPythonCheck(senderManager sender.SenderManager, name string, class *C.rtloader_pyobject_t) (*PythonCheck, error) { +func NewPythonCheck(senderManager sender.SenderManager, name string, class *C.rtloader_pyobject_t, haSupported bool) (*PythonCheck, error) { glock, err := newStickyLock() if err != nil { return nil, err @@ -83,6 +84,7 @@ func NewPythonCheck(senderManager sender.SenderManager, name string, class *C.rt interval: defaults.DefaultCheckInterval, lastWarnings: []error{}, telemetry: utils.IsCheckTelemetryEnabled(name, pkgconfigsetup.Datadog()), + haSupported: haSupported, } runtime.SetFinalizer(pyCheck, pythonCheckFinalizer) @@ -419,6 +421,11 @@ func (c *PythonCheck) IsHAEnabled() bool { return c.haEnabled } +// IsHASupported returns the HA_SUPPORTED class attribute defined at Python Check level +func (c *PythonCheck) IsHASupported() bool { + return c.haSupported +} + // pythonCheckFinalizer is a finalizer that decreases the reference count on the PyObject refs owned // by the PythonCheck. func pythonCheckFinalizer(c *PythonCheck) { diff --git a/pkg/collector/python/loader.go b/pkg/collector/python/loader.go index 122229f9b11c3..8ab3c9c9c4f22 100644 --- a/pkg/collector/python/loader.go +++ b/pkg/collector/python/loader.go @@ -208,7 +208,20 @@ func (cl *PythonCheckLoader) Load(senderManager sender.SenderManager, config int go reportPy3Warnings(name, goCheckFilePath) } - c, err := NewPythonCheck(senderManager, moduleName, checkClass) + var goHASupported bool + if pkgconfigsetup.Datadog().GetBool("ha_enabled") { + var haSupported *C.char + + haSupportedAttr := TrackedCString("HA_SUPPORTED") + defer C._free(unsafe.Pointer(haSupportedAttr)) + if res := C.get_attr_string(rtloader, checkModule, haSupportedAttr, &haSupported); res != 0 { + goHASupported = C.GoString(haSupported) == "true" + } else { + log.Debugf("Could not query the HA_SUPPORTED attribute for check %s: %s", name, getRtLoaderError()) + } + } + + c, err := NewPythonCheck(senderManager, moduleName, checkClass, goHASupported) if err != nil { return c, err } diff --git a/pkg/collector/python/test_check.go b/pkg/collector/python/test_check.go index 193dfaddbd907..e960241190172 100644 --- a/pkg/collector/python/test_check.go +++ b/pkg/collector/python/test_check.go @@ -693,7 +693,7 @@ func testConfigureHA(t *testing.T) { defer func() { rtloader = nil }() senderManager := mocksender.CreateDefaultDemultiplexer() - c, err := NewPythonFakeCheck(senderManager) + c, err := NewPythonFakeHACheck(senderManager) if !assert.Nil(t, err) { return } @@ -723,7 +723,19 @@ func testConfigureHA(t *testing.T) { // NewPythonFakeCheck create a fake PythonCheck func NewPythonFakeCheck(senderManager sender.SenderManager) (*PythonCheck, error) { - c, err := NewPythonCheck(senderManager, "fake_check", nil) + c, err := NewPythonCheck(senderManager, "fake_check", nil, false) + + // Remove check finalizer that may trigger race condition while testing + if err == nil { + runtime.SetFinalizer(c, nil) + } + + return c, err +} + +// NewPythonFakeCheck create a fake PythonCheck +func NewPythonFakeHACheck(senderManager sender.SenderManager) (*PythonCheck, error) { + c, err := NewPythonCheck(senderManager, "fake_check", nil, true) // Remove check finalizer that may trigger race condition while testing if err == nil { diff --git a/pkg/jmxfetch/jmxfetch.go b/pkg/jmxfetch/jmxfetch.go index 852ff8ef20a04..a30ddb41cfd9c 100644 --- a/pkg/jmxfetch/jmxfetch.go +++ b/pkg/jmxfetch/jmxfetch.go @@ -112,6 +112,7 @@ type checkInstanceCfg struct { JavaOptions string `yaml:"java_options,omitempty"` ToolsJarPath string `yaml:"tools_jar_path,omitempty"` ProcessNameRegex string `yaml:"process_name_regex,omitempty"` + HAEnabled bool `yaml:"ha_enabled,omitempty"` } type checkInitCfg struct { @@ -119,6 +120,7 @@ type checkInitCfg struct { ToolsJarPath string `yaml:"tools_jar_path,omitempty"` JavaBinPath string `yaml:"java_bin_path,omitempty"` JavaOptions string `yaml:"java_options,omitempty"` + HAEnabled bool `yaml:"ha_enabled,omitempty"` } func NewJMXFetch(logger jmxlogger.Component) *JMXFetch { @@ -478,6 +480,9 @@ func (j *JMXFetch) ConfigureFromInitConfig(initConfig integration.Data) error { j.JavaCustomJarPaths = initConf.CustomJarPaths } } + if initConf.HAEnabled { + return fmt.Errorf("High Availability is not supported in JMX integrations") + } return nil } @@ -508,6 +513,9 @@ func (j *JMXFetch) ConfigureFromInstance(instance integration.Data) error { j.JavaToolsJarPath = instanceConf.ToolsJarPath } } + if instanceConf.HAEnabled { + return fmt.Errorf("High Availability is not supported in JMX integrations") + } return nil } diff --git a/pkg/jmxfetch/jmxfetch_test.go b/pkg/jmxfetch/jmxfetch_test.go index 824923ee943d9..105241a791143 100644 --- a/pkg/jmxfetch/jmxfetch_test.go +++ b/pkg/jmxfetch/jmxfetch_test.go @@ -65,3 +65,18 @@ func TestConflictingInstanceInitJavaOptions(t *testing.T) { require.Contains(t, j.JavaOptions, "Xmx200m") require.NotContains(t, j.JavaOptions, "Xmx444m") } + +func TestCheckHAIsNotSupported(t *testing.T) { + j := NewJMXFetch(nil) + + var configOne integration.Data = integration.Data("{\"ha_enabled\": true}") + var configTwo integration.Data = integration.Data("{\"ha_enabled\": true}") + + err := j.ConfigureFromInitConfig(configOne) + require.Error(t, err) + require.Contains(t, err.Error(), "High Availability is not supported in JMX integrations") + + err = j.ConfigureFromInstance(configTwo) + require.Error(t, err) + require.Contains(t, err.Error(), "High Availability is not supported in JMX integrations") +} diff --git a/release.json b/release.json index fbf16c98808bf..3f61355d8ff60 100644 --- a/release.json +++ b/release.json @@ -22,7 +22,7 @@ "WINDOWS_APMINJECT_MODULE": "release-signed", "WINDOWS_APMINJECT_VERSION": "1.1.3", "WINDOWS_APMINJECT_SHASUM": "5fdd62a84e640204386b9c28dc2e3ac5d9b8adde6427cb9f5914619f94d7b5bd", - "INTEGRATIONS_CORE_VERSION": "6782bb7cf5da2ce9e0ab77d8420ac849d31cb8a6" + "INTEGRATIONS_CORE_VERSION": "80119188f5cd11ee49cf4ec0fa673c8f49af2bf0" }, "nightly-a7": { "OMNIBUS_SOFTWARE_VERSION": "d4a12d8a009e1c497e5e740e1ea5c8d23d6864ca", @@ -41,7 +41,7 @@ "WINDOWS_APMINJECT_MODULE": "release-signed", "WINDOWS_APMINJECT_VERSION": "1.1.3", "WINDOWS_APMINJECT_SHASUM": "5fdd62a84e640204386b9c28dc2e3ac5d9b8adde6427cb9f5914619f94d7b5bd", - "INTEGRATIONS_CORE_VERSION": "6782bb7cf5da2ce9e0ab77d8420ac849d31cb8a6" + "INTEGRATIONS_CORE_VERSION": "80119188f5cd11ee49cf4ec0fa673c8f49af2bf0" }, "release-a6": { "INTEGRATIONS_CORE_VERSION": "7.56.0-rc.2",