From af96a9414d7bdf58027e5aedb654756306495209 Mon Sep 17 00:00:00 2001 From: Alexandre Yang Date: Mon, 18 Nov 2024 12:24:30 +0100 Subject: [PATCH] [haagent] Add haagent component --- .github/CODEOWNERS | 1 + cmd/agent/subcommands/run/command.go | 2 + comp/haagent/def/component.go | 25 +++++++++ comp/haagent/fx/fx.go | 23 +++++++++ comp/haagent/impl/config.go | 22 ++++++++ comp/haagent/impl/haagent.go | 44 ++++++++++++++++ comp/haagent/impl/haagent_comp.go | 33 ++++++++++++ comp/haagent/impl/haagent_test.go | 57 +++++++++++++++++++++ comp/haagent/impl/haagent_testutils_test.go | 32 ++++++++++++ comp/haagent/mock/mock.go | 45 ++++++++++++++++ pkg/config/setup/config.go | 4 ++ 11 files changed, 288 insertions(+) create mode 100644 comp/haagent/def/component.go create mode 100644 comp/haagent/fx/fx.go create mode 100644 comp/haagent/impl/config.go create mode 100644 comp/haagent/impl/haagent.go create mode 100644 comp/haagent/impl/haagent_comp.go create mode 100644 comp/haagent/impl/haagent_test.go create mode 100644 comp/haagent/impl/haagent_testutils_test.go create mode 100644 comp/haagent/mock/mock.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cd9cafea971f8..86aeb529e652f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -320,6 +320,7 @@ /comp/rdnsquerier @DataDog/ndm-integrations /comp/serializer/compression @DataDog/agent-metrics-logs /comp/snmpscan @DataDog/ndm-core +/comp/haagent @DataDog/network-device-monitoring @DataDog/remote-config @DataDog/fleet # END COMPONENTS # Additional notification to @iglendd about Agent Telemetry changes for optional approval and governance acknowledgement diff --git a/cmd/agent/subcommands/run/command.go b/cmd/agent/subcommands/run/command.go index 986ff25c5349f..e23e94d67a3f7 100644 --- a/cmd/agent/subcommands/run/command.go +++ b/cmd/agent/subcommands/run/command.go @@ -30,6 +30,7 @@ import ( internalsettings "github.com/DataDog/datadog-agent/cmd/agent/subcommands/run/internal/settings" agenttelemetry "github.com/DataDog/datadog-agent/comp/core/agenttelemetry/def" agenttelemetryfx "github.com/DataDog/datadog-agent/comp/core/agenttelemetry/fx" + haagentfx "github.com/DataDog/datadog-agent/comp/haagent/fx" // checks implemented as components @@ -472,6 +473,7 @@ func getSharedFxOption() fx.Option { agenttelemetryfx.Module(), networkpath.Bundle(), remoteagentregistryfx.Module(), + haagentfx.Module(), ) } diff --git a/comp/haagent/def/component.go b/comp/haagent/def/component.go new file mode 100644 index 0000000000000..e20be4b3d0c81 --- /dev/null +++ b/comp/haagent/def/component.go @@ -0,0 +1,25 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +// Package haagent handles states for HA Agent feature. +package haagent + +// team: network-device-monitoring + +// Component is the component type. +type Component interface { + // Enabled returns true if ha_agent.enabled is set to true + Enabled() bool + + // GetGroup returns the value of ha_agent.group + GetGroup() string + + // IsLeader returns true if the current Agent is leader + IsLeader() bool + + // SetLeader takes the leader agent hostname as input, if it matches the current agent hostname, + // the isLeader state is set to true, otherwise false. + SetLeader(leaderAgentHostname string) +} diff --git a/comp/haagent/fx/fx.go b/comp/haagent/fx/fx.go new file mode 100644 index 0000000000000..a60f314250169 --- /dev/null +++ b/comp/haagent/fx/fx.go @@ -0,0 +1,23 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +// Package fx provides the fx module for the haagent component +package fx + +import ( + haagent "github.com/DataDog/datadog-agent/comp/haagent/def" + haagentimpl "github.com/DataDog/datadog-agent/comp/haagent/impl" + "github.com/DataDog/datadog-agent/pkg/util/fxutil" +) + +// Module defines the fx options for this component +func Module() fxutil.Module { + return fxutil.Component( + fxutil.ProvideComponentConstructor( + haagentimpl.NewComponent, + ), + fxutil.ProvideOptional[haagent.Component](), + ) +} diff --git a/comp/haagent/impl/config.go b/comp/haagent/impl/config.go new file mode 100644 index 0000000000000..2417106455a7d --- /dev/null +++ b/comp/haagent/impl/config.go @@ -0,0 +1,22 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +package haagentimpl + +import ( + "github.com/DataDog/datadog-agent/comp/core/config" +) + +type haAgentConfigs struct { + enabled bool + group string +} + +func newHaAgentConfigs(agentConfig config.Component) *haAgentConfigs { + return &haAgentConfigs{ + enabled: agentConfig.GetBool("ha_agent.enabled"), + group: agentConfig.GetString("ha_agent.group"), + } +} diff --git a/comp/haagent/impl/haagent.go b/comp/haagent/impl/haagent.go new file mode 100644 index 0000000000000..4b51f09d69fe1 --- /dev/null +++ b/comp/haagent/impl/haagent.go @@ -0,0 +1,44 @@ +package haagentimpl + +import ( + "context" + + log "github.com/DataDog/datadog-agent/comp/core/log/def" + "github.com/DataDog/datadog-agent/pkg/util/hostname" + "go.uber.org/atomic" +) + +type haAgentImpl struct { + log log.Component + haAgentConfigs *haAgentConfigs + isLeader *atomic.Bool +} + +func newHaAgentImpl(log log.Component, haAgentConfigs *haAgentConfigs) *haAgentImpl { + return &haAgentImpl{ + log: log, + haAgentConfigs: haAgentConfigs, + isLeader: atomic.NewBool(false), + } +} + +func (h *haAgentImpl) Enabled() bool { + return h.haAgentConfigs.enabled +} + +func (h *haAgentImpl) GetGroup() string { + return h.haAgentConfigs.group +} + +func (h *haAgentImpl) IsLeader() bool { + return h.isLeader.Load() +} + +func (h *haAgentImpl) SetLeader(leaderAgentHostname string) { + agentHostname, err := hostname.Get(context.TODO()) + if err != nil { + h.log.Warnf("Error getting the hostname: %v", err) + return + } + h.isLeader.Store(agentHostname == leaderAgentHostname) +} diff --git a/comp/haagent/impl/haagent_comp.go b/comp/haagent/impl/haagent_comp.go new file mode 100644 index 0000000000000..24f591741fa0d --- /dev/null +++ b/comp/haagent/impl/haagent_comp.go @@ -0,0 +1,33 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +// Package haagentimpl implements the haagent component interface +package haagentimpl + +import ( + "github.com/DataDog/datadog-agent/comp/core/config" + log "github.com/DataDog/datadog-agent/comp/core/log/def" + haagent "github.com/DataDog/datadog-agent/comp/haagent/def" +) + +// Requires defines the dependencies for the haagent component +type Requires struct { + Logger log.Component + AgentConfig config.Component +} + +// Provides defines the output of the haagent component +type Provides struct { + Comp haagent.Component +} + +// NewComponent creates a new haagent component +func NewComponent(reqs Requires) (Provides, error) { + haAgentConfigs := newHaAgentConfigs(reqs.AgentConfig) + provides := Provides{ + Comp: newHaAgentImpl(reqs.Logger, haAgentConfigs), + } + return provides, nil +} diff --git a/comp/haagent/impl/haagent_test.go b/comp/haagent/impl/haagent_test.go new file mode 100644 index 0000000000000..63011aa645e44 --- /dev/null +++ b/comp/haagent/impl/haagent_test.go @@ -0,0 +1,57 @@ +package haagentimpl + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Enabled(t *testing.T) { + tests := []struct { + name string + configs map[string]interface{} + expectedEnabled bool + }{ + { + name: "enabled", + configs: map[string]interface{}{ + "ha_agent.enabled": true, + }, + expectedEnabled: true, + }, + { + name: "disabled", + configs: map[string]interface{}{ + "ha_agent.enabled": false, + }, + expectedEnabled: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + haAgent := newTestHaAgentComponent(t, tt.configs) + assert.Equal(t, tt.expectedEnabled, haAgent.Enabled()) + }) + } +} + +func Test_GetGroup(t *testing.T) { + agentConfigs := map[string]interface{}{ + "ha_agent.group": "my-group-01", + } + haAgent := newTestHaAgentComponent(t, agentConfigs) + assert.Equal(t, "my-group-01", haAgent.GetGroup()) +} + +func Test_IsLeader_SetLeader(t *testing.T) { + agentConfigs := map[string]interface{}{ + "hostname": "my-agent-hostname", + } + haAgent := newTestHaAgentComponent(t, agentConfigs) + + haAgent.SetLeader("another-agent") + assert.False(t, haAgent.IsLeader()) + + haAgent.SetLeader("my-agent-hostname") + assert.True(t, haAgent.IsLeader()) +} diff --git a/comp/haagent/impl/haagent_testutils_test.go b/comp/haagent/impl/haagent_testutils_test.go new file mode 100644 index 0000000000000..bdeb90cee7155 --- /dev/null +++ b/comp/haagent/impl/haagent_testutils_test.go @@ -0,0 +1,32 @@ +package haagentimpl + +import ( + "testing" + + "github.com/DataDog/datadog-agent/comp/core/config" + logmock "github.com/DataDog/datadog-agent/comp/core/log/mock" + haagent "github.com/DataDog/datadog-agent/comp/haagent/def" + "github.com/DataDog/datadog-agent/pkg/util/fxutil" + "github.com/stretchr/testify/require" + "go.uber.org/fx" +) + +func newTestHaAgentComponent(t *testing.T, agentConfigs map[string]interface{}) haagent.Component { + logComponent := logmock.New(t) + agentConfigComponent := fxutil.Test[config.Component](t, fx.Options( + config.MockModule(), + fx.Replace(config.MockParams{Overrides: agentConfigs}), + )) + + requires := Requires{ + Logger: logComponent, + AgentConfig: agentConfigComponent, + } + + provides, err := NewComponent(requires) + require.NoError(t, err) + + comp := provides.Comp + require.NotNil(t, comp) + return comp +} diff --git a/comp/haagent/mock/mock.go b/comp/haagent/mock/mock.go new file mode 100644 index 0000000000000..6ee0c733361f7 --- /dev/null +++ b/comp/haagent/mock/mock.go @@ -0,0 +1,45 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +//go:build test + +// Package mock provides a mock for the haagent component +package mock + +import ( + "testing" + + log "github.com/DataDog/datadog-agent/comp/core/log/def" + haagent "github.com/DataDog/datadog-agent/comp/haagent/def" +) + +type mock struct { + Logger log.Component +} + +func (m *mock) GetGroup() string { + return "mockGroup01" +} + +func (m *mock) Enabled() bool { + return true +} + +func (m *mock) SetLeader(_ string) { +} + +func (m *mock) IsLeader() bool { return false } + +// Provides that defines the output of mocked snmpscan component +type Provides struct { + comp haagent.Component +} + +// Mock returns a mock for haagent component. +func Mock(_ *testing.T) Provides { + return Provides{ + comp: &mock{}, + } +} diff --git a/pkg/config/setup/config.go b/pkg/config/setup/config.go index 27215e0975243..9a790ca22e3fe 100644 --- a/pkg/config/setup/config.go +++ b/pkg/config/setup/config.go @@ -474,6 +474,10 @@ func InitConfig(config pkgconfigmodel.Setup) { config.BindEnvAndSetDefault("network_path.collector.reverse_dns_enrichment.timeout", 5000) bindEnvAndSetLogsConfigKeys(config, "network_path.forwarder.") + // HA Agent + config.BindEnvAndSetDefault("ha_agent.enabled", false) + config.BindEnv("ha_agent.group") + // Kube ApiServer config.BindEnvAndSetDefault("kubernetes_kubeconfig_path", "") config.BindEnvAndSetDefault("kubernetes_apiserver_ca_path", "")