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

[HA Agent][NDMII-3313] Add ha_agent_metadata #33546

Merged
merged 27 commits into from
Feb 3, 2025
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bfd81b6
[HA Agent] Add ha_agent_metadata
AlexandreYang Jan 29, 2025
339bb9e
clean up
AlexandreYang Jan 30, 2025
fdb4a55
remove unused auth token
AlexandreYang Jan 30, 2025
a5ed2fd
clean up
AlexandreYang Jan 30, 2025
9d75820
fix comp
AlexandreYang Jan 30, 2025
37e0e88
fix cmd/agent/subcommands/diagnose/command.go
AlexandreYang Jan 31, 2025
12f0098
rename inventory-ha-agent -> ha-agent
AlexandreYang Jan 31, 2025
c68ad3b
remove refresh
AlexandreYang Jan 31, 2025
078b81a
remove scrub
AlexandreYang Jan 31, 2025
ce46b53
fix copy
AlexandreYang Jan 31, 2025
0c8e438
remove mock
AlexandreYang Jan 31, 2025
ea92905
Revert "remove mock"
AlexandreYang Jan 31, 2025
75f68b0
remove module from mock
AlexandreYang Jan 31, 2025
351f766
remove mock
AlexandreYang Jan 31, 2025
b33fa75
clean up def/component.go
AlexandreYang Jan 31, 2025
1b86d23
rename comp
AlexandreYang Jan 31, 2025
663c96a
rename inventoryhaagent to haagent
AlexandreYang Jan 31, 2025
26cb4f0
rename
AlexandreYang Jan 31, 2025
bf47962
fix test
AlexandreYang Jan 31, 2025
fa58605
remove uuid
AlexandreYang Jan 31, 2025
824d9df
Merge branch 'main' into NDMII-3313-ha-agent-metadata3
AlexandreYang Feb 1, 2025
fbfe797
move haagent dep to cmd/agent/subcommands/run/command.go
AlexandreYang Feb 1, 2025
b623fbd
sort import
AlexandreYang Feb 1, 2025
a4ac683
newline
AlexandreYang Feb 1, 2025
843412a
rename import
AlexandreYang Feb 1, 2025
ae5d840
fix TestBundleDependencies
AlexandreYang Feb 1, 2025
d1e127f
remove exception tasks/components.py
AlexandreYang Feb 3, 2025
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -327,6 +327,7 @@
/comp/forwarder/eventplatform @DataDog/agent-logs
/comp/forwarder/eventplatformreceiver @DataDog/agent-logs
/comp/forwarder/orchestrator @DataDog/agent-logs
/comp/metadata/haagent @DataDog/ndm-core
/comp/metadata/packagesigning @DataDog/agent-delivery
/comp/trace/etwtracer @DataDog/windows-agent
/comp/autoscaling/datadogclient @DataDog/container-integrations
15 changes: 15 additions & 0 deletions cmd/agent/subcommands/diagnose/command.go
Original file line number Diff line number Diff line change
@@ -216,6 +216,20 @@ This command print the inventory-otel metadata payload. This payload is used by
},
}

payloadInventoriesHaAgentCmd := &cobra.Command{
Use: "ha-agent",
Short: "Print the HA Agent metadata payload.",
Long: `
This command print the ha-agent metadata payload. This payload is used by the 'HA Agent' feature.`,
RunE: func(_ *cobra.Command, _ []string) error {
return fxutil.OneShot(printPayload,
fx.Supply(payloadName("ha-agent")),
fx.Supply(command.GetDefaultCoreBundleParams(cliParams.GlobalParams)),
core.Bundle(),
)
},
}

payloadInventoriesChecksCmd := &cobra.Command{
Use: "inventory-checks",
Short: "[internal] Print the Inventory checks metadata payload.",
@@ -290,6 +304,7 @@ This command print the security-agent metadata payload. This payload is used by
showPayloadCommand.AddCommand(payloadInventoriesAgentCmd)
showPayloadCommand.AddCommand(payloadInventoriesHostCmd)
showPayloadCommand.AddCommand(payloadInventoriesOtelCmd)
showPayloadCommand.AddCommand(payloadInventoriesHaAgentCmd)
showPayloadCommand.AddCommand(payloadInventoriesChecksCmd)
showPayloadCommand.AddCommand(payloadInventoriesPkgSigningCmd)
showPayloadCommand.AddCommand(payloadSystemProbeCmd)
10 changes: 10 additions & 0 deletions cmd/agent/subcommands/diagnose/command_test.go
Original file line number Diff line number Diff line change
@@ -86,6 +86,16 @@ func TestShowMetadataInventoryOtelCommand(t *testing.T) {
})
}

func TestShowMetadataHaAgentCommand(t *testing.T) {
fxutil.TestOneShotSubcommand(t,
Commands(&command.GlobalParams{}),
[]string{"diagnose", "show-metadata", "ha-agent"},
printPayload,
func(_ core.BundleParams, secretParams secrets.Params) {
require.Equal(t, false, secretParams.Enabled)
})
}

func TestShowMetadataPkgSigningCommand(t *testing.T) {
fxutil.TestOneShotSubcommand(t,
Commands(&command.GlobalParams{}),
2 changes: 2 additions & 0 deletions cmd/agent/subcommands/flare/command.go
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ import (
workloadmeta "github.com/DataDog/datadog-agent/comp/core/workloadmeta/def"
workloadmetafx "github.com/DataDog/datadog-agent/comp/core/workloadmeta/fx"
haagentfx "github.com/DataDog/datadog-agent/comp/haagent/fx"
haagentmetadatafx "github.com/DataDog/datadog-agent/comp/metadata/haagent/fx"
"github.com/DataDog/datadog-agent/comp/metadata/host/hostimpl"
"github.com/DataDog/datadog-agent/comp/metadata/inventoryagent/inventoryagentimpl"
"github.com/DataDog/datadog-agent/comp/metadata/inventoryhost/inventoryhostimpl"
@@ -138,6 +139,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command {
hostimpl.Module(),
inventoryhostimpl.Module(),
inventoryotelimpl.Module(),
haagentmetadatafx.Module(),
resourcesimpl.Module(),
authtokenimpl.Module(),
// inventoryagent require a serializer. Since we're not actually sending the payload to
2 changes: 2 additions & 0 deletions cmd/agent/subcommands/run/command.go
Original file line number Diff line number Diff line change
@@ -98,6 +98,7 @@ import (
logsAgent "github.com/DataDog/datadog-agent/comp/logs/agent"
integrations "github.com/DataDog/datadog-agent/comp/logs/integrations/def"
"github.com/DataDog/datadog-agent/comp/metadata"
haagentmetadata "github.com/DataDog/datadog-agent/comp/metadata/haagent/def"
"github.com/DataDog/datadog-agent/comp/metadata/host"
"github.com/DataDog/datadog-agent/comp/metadata/inventoryagent"
"github.com/DataDog/datadog-agent/comp/metadata/inventorychecks"
@@ -239,6 +240,7 @@ func run(log log.Component,
_ inventoryagent.Component,
_ inventoryhost.Component,
_ inventoryotel.Component,
_ haagentmetadata.Component,
_ secrets.Component,
invChecks inventorychecks.Component,
logReceiver option.Option[integrations.Component],
2 changes: 2 additions & 0 deletions cmd/agent/subcommands/run/command_windows.go
Original file line number Diff line number Diff line change
@@ -61,6 +61,7 @@ import (
"github.com/DataDog/datadog-agent/comp/forwarder/defaultforwarder"
logsAgent "github.com/DataDog/datadog-agent/comp/logs/agent"
integrations "github.com/DataDog/datadog-agent/comp/logs/integrations/def"
haagentmetadata "github.com/DataDog/datadog-agent/comp/metadata/haagent/def"
"github.com/DataDog/datadog-agent/comp/metadata/host"
"github.com/DataDog/datadog-agent/comp/metadata/inventoryagent"
"github.com/DataDog/datadog-agent/comp/metadata/inventorychecks"
@@ -116,6 +117,7 @@ func StartAgentWithDefaults(ctxChan <-chan context.Context) (<-chan error, error
_ inventoryagent.Component,
_ inventoryhost.Component,
_ inventoryotel.Component,
_ haagentmetadata.Component,
_ secrets.Component,
invChecks inventorychecks.Component,
logsReceiver option.Option[integrations.Component],
6 changes: 6 additions & 0 deletions comp/README.md
Original file line number Diff line number Diff line change
@@ -301,6 +301,12 @@ send logs.
Package metadata implements the "metadata" bundle, providing services and support for all the metadata payload sent
by the Agent.

### [comp/metadata/haagent](https://pkg.go.dev/github.com/DataDog/datadog-agent/comp/metadata/haagent)

*Datadog Team*: ndm-core

Package haagent implements a component to generate the 'ha_agent_metadata' metadata payload for inventory.

### [comp/metadata/host](https://pkg.go.dev/github.com/DataDog/datadog-agent/comp/metadata/host)

Package host implements a component to generate the 'host' metadata payload (also known as "v5").
2 changes: 2 additions & 0 deletions comp/metadata/bundle.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
package metadata

import (
haagentmetadatafx "github.com/DataDog/datadog-agent/comp/metadata/haagent/fx"
"github.com/DataDog/datadog-agent/comp/metadata/host/hostimpl"
"github.com/DataDog/datadog-agent/comp/metadata/inventoryagent/inventoryagentimpl"
"github.com/DataDog/datadog-agent/comp/metadata/inventorychecks/inventorychecksimpl"
@@ -36,6 +37,7 @@ func Bundle() fxutil.BundleOptions {
packagesigningimpl.Module(),
systemprobe.Module(),
securityagent.Module(),
haagentmetadatafx.Module(),
)
}

2 changes: 2 additions & 0 deletions comp/metadata/bundle_test.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ package metadata
import (
"testing"

haagentmock "github.com/DataDog/datadog-agent/comp/haagent/mock"
"go.uber.org/fx"

authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/fetchonlyimpl"
@@ -29,6 +30,7 @@ func TestBundleDependencies(t *testing.T) {
return option.None[agent.Component]()
}),
authtokenimpl.Module(),
haagentmock.Module(),
)
}

44 changes: 44 additions & 0 deletions comp/metadata/haagent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Inventory Agent Payload

This package populates some of the ha-agent related fields in the `inventories` product in DataDog. More specifically the
`datadog_agent_ha_agent` table.

This is enabled by default if `ha_agent.enabled` is set to true, and can be turned off using `inventories_enabled` config.

The payload is sent every 10min (see `inventories_max_interval` in the config) or whenever it's updated with at most 1
update every minute (see `inventories_min_interval`).

# Content

## Agent Configuration

Sending Agent configuration can be disabled using `inventories_configuration_enabled`.

# Format

The payload is a JSON dict with the following fields

- `hostname` - **string**: the hostname of the ha-agent as shown on the status page.
- `timestamp` - **int**: the timestamp when the payload was created.
- `ha_agent_metadata` - **dict of string to JSON type**:
- `enabled` - **boolean**: describes if the HA Agent has been enabled in the Agent configuration.
- `state` - **string**: HA Agent state (active or standby).

("scrubbed" indicates that secrets are removed from the field value just as they are in logs)

As the environment configuration and override only affect scalar values (as opposed to slices & maps), combining configurations should be straight-forward to do. Environment variables take precendence over the provided configuration, and runtime overrides take precendence over that.

## Example Payload

Here an example of an inventory payload:

```
{
"hostname": "COMP-GQ7WQN6HYC",
"ha_agent_metadata": {
"enabled": true,
"state": "active"
},
"timestamp": 1716985696922603000
}
```
12 changes: 12 additions & 0 deletions comp/metadata/haagent/def/component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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 2025-present Datadog, Inc.

// Package haagent implements a component to generate the 'ha_agent_metadata' metadata payload for inventory.
package haagent

// team: ndm-core

// Component is the component type.
type Component interface{}
23 changes: 23 additions & 0 deletions comp/metadata/haagent/fx/fx.go
Original file line number Diff line number Diff line change
@@ -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 2025-present Datadog, Inc.

// Package fx provides the fx module for the haagent component
package fx

import (
haagent "github.com/DataDog/datadog-agent/comp/metadata/haagent/def"
haagentimpl "github.com/DataDog/datadog-agent/comp/metadata/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](),
)
}
62 changes: 62 additions & 0 deletions comp/metadata/haagent/impl/haagent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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 2025-present Datadog, Inc.

// Package haagentimpl implements the haagentimpl component interface
package haagentimpl

import (
"context"

api "github.com/DataDog/datadog-agent/comp/api/api/def"
"github.com/DataDog/datadog-agent/comp/core/config"
flaretypes "github.com/DataDog/datadog-agent/comp/core/flare/types"
log "github.com/DataDog/datadog-agent/comp/core/log/def"
"github.com/DataDog/datadog-agent/comp/core/status"
haagentcomp "github.com/DataDog/datadog-agent/comp/haagent/def"
haagent "github.com/DataDog/datadog-agent/comp/metadata/haagent/def"
"github.com/DataDog/datadog-agent/comp/metadata/internal/util"
"github.com/DataDog/datadog-agent/comp/metadata/runner/runnerimpl"
"github.com/DataDog/datadog-agent/pkg/serializer"
"github.com/DataDog/datadog-agent/pkg/util/hostname"
)

// Requires defines the dependencies for the haagentimpl component
type Requires struct {
Log log.Component
Config config.Component
Serializer serializer.MetricSerializer
HaAgent haagentcomp.Component
}

// Provides defines the output of the haagentimpl component
type Provides struct {
Comp haagent.Component
Provider runnerimpl.Provider
FlareProvider flaretypes.Provider
StatusHeaderProvider status.HeaderInformationProvider
Endpoint api.AgentEndpointProvider
}

// NewComponent creates a new haagentimpl component
func NewComponent(reqs Requires) (Provides, error) {
hname, _ := hostname.Get(context.Background())
i := &haagentimpl{
conf: reqs.Config,
log: reqs.Log,
hostname: hname,
data: make(haAgentMetadata),
haAgent: reqs.HaAgent,
}

i.InventoryPayload = util.CreateInventoryPayload(reqs.Config, reqs.Log, reqs.Serializer, i.getPayload, "ha-agent.json")

return Provides{
Comp: i,
Provider: i.MetadataProvider(),
FlareProvider: i.FlareProvider(),
StatusHeaderProvider: status.NewHeaderInformationProvider(i),
Endpoint: api.NewAgentEndpointProvider(i.writePayloadAsJSON, "/metadata/ha-agent", "GET"),
}, nil
}
105 changes: 105 additions & 0 deletions comp/metadata/haagent/impl/haagentimpl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// 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 2016-present Datadog, Inc.

// Package haagentimpl implements a component to generate the 'ha_agent_metadata' metadata payload for inventory.
package haagentimpl

import (
"encoding/json"
"fmt"
"maps"
"net/http"
"sync"
"time"

"github.com/DataDog/datadog-agent/comp/core/config"
log "github.com/DataDog/datadog-agent/comp/core/log/def"
haagentcomp "github.com/DataDog/datadog-agent/comp/haagent/def"
"github.com/DataDog/datadog-agent/comp/metadata/internal/util"
"github.com/DataDog/datadog-agent/pkg/serializer/marshaler"
httputils "github.com/DataDog/datadog-agent/pkg/util/http"
)

type haAgentMetadata = map[string]interface{}

// Payload handles the JSON unmarshalling of the metadata payload
type Payload struct {
Hostname string `json:"hostname"`
Timestamp int64 `json:"timestamp"`
Metadata haAgentMetadata `json:"ha_agent_metadata"`
}

// MarshalJSON serialization a Payload to JSON
func (p *Payload) MarshalJSON() ([]byte, error) {
type PayloadAlias Payload
return json.Marshal((*PayloadAlias)(p))
}

// SplitPayload implements marshaler.AbstractMarshaler#SplitPayload.
//
// In this case, the payload can't be split any further.
func (p *Payload) SplitPayload(_ int) ([]marshaler.AbstractMarshaler, error) {
return nil, fmt.Errorf("could not split inventories agent payload any more, payload is too big for intake")
}

type haagentimpl struct {
util.InventoryPayload

conf config.Component
log log.Component
m sync.Mutex
data haAgentMetadata
hostname string
haAgent haagentcomp.Component
}

func (i *haagentimpl) refreshMetadata() {
isEnabled := i.haAgent.Enabled()

if !isEnabled {
i.log.Infof("HA Agent Metadata unavailable as HA Agent is disabled")
i.data = nil
return
}

i.data["enabled"] = isEnabled
i.data["state"] = string(i.haAgent.GetState())
}

func (i *haagentimpl) getPayload() marshaler.JSONMarshaler {
i.m.Lock()
defer i.m.Unlock()

i.refreshMetadata()

return &Payload{
Hostname: i.hostname,
Timestamp: time.Now().UnixNano(),
Metadata: i.getDataCopy(),
}
}

func (i *haagentimpl) writePayloadAsJSON(w http.ResponseWriter, _ *http.Request) {
// GetAsJSON already return scrubbed data
scrubbed, err := i.GetAsJSON()
if err != nil {
httputils.SetJSONError(w, err, 500)
return
}
w.Write(scrubbed)
}

// Get returns a copy of the agent metadata. Useful to be incorporated in the status page.
func (i *haagentimpl) Get() haAgentMetadata {
i.m.Lock()
defer i.m.Unlock()
return i.getDataCopy()
}

func (i *haagentimpl) getDataCopy() haAgentMetadata {
data := haAgentMetadata{}
maps.Copy(data, i.data)
return data
}
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.