From 63ef929a1c45774f3ba8c729babd85b56b758c00 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Thu, 17 Oct 2024 17:40:41 +0200 Subject: [PATCH 01/13] add standard RC client as a "CDN" option --- pkg/fleet/daemon/daemon.go | 7 +- pkg/fleet/env/env.go | 3 + pkg/fleet/internal/cdn/cdn.go | 5 +- pkg/fleet/internal/cdn/cdn_direct.go | 183 +++++++++++++++++++++++++++ pkg/fleet/internal/cdn/cdn_remote.go | 11 +- pkg/fleet/internal/cdn/tags.go | 71 +++++++++++ 6 files changed, 268 insertions(+), 12 deletions(-) create mode 100644 pkg/fleet/internal/cdn/cdn_direct.go create mode 100644 pkg/fleet/internal/cdn/tags.go diff --git a/pkg/fleet/daemon/daemon.go b/pkg/fleet/daemon/daemon.go index 11c5d7e0d76d8..dab1305100748 100644 --- a/pkg/fleet/daemon/daemon.go +++ b/pkg/fleet/daemon/daemon.go @@ -41,7 +41,7 @@ const ( // gcInterval is the interval at which the GC will run gcInterval = 1 * time.Hour // refreshStateInterval is the interval at which the state will be refreshed - refreshStateInterval = 1 * time.Minute + refreshStateInterval = 30 * time.Second ) // Daemon is the fleet daemon in charge of remote install, updates and configuration. @@ -562,7 +562,7 @@ func (d *daemonImpl) resolveRemoteConfigVersion(ctx context.Context, pkg string) } config, err := d.cdn.Get(ctx, pkg) if err != nil { - return "", fmt.Errorf("could not get cdn config: %w", err) + return "", err } return config.Version(), nil } @@ -602,9 +602,6 @@ func (d *daemonImpl) refreshState(ctx context.Context) { } configVersion, err := d.resolveRemoteConfigVersion(ctx, pkg) - if err != nil { - log.Errorf("could not get agent remote config version: %v", err) - } if err == nil { p.RemoteConfigVersion = configVersion } else if err != cdn.ErrProductNotSupported { diff --git a/pkg/fleet/env/env.go b/pkg/fleet/env/env.go index 18cf17ea6ed06..dbdce9c709b68 100644 --- a/pkg/fleet/env/env.go +++ b/pkg/fleet/env/env.go @@ -32,6 +32,7 @@ const ( envAgentMinorVersion = "DD_AGENT_MINOR_VERSION" envApmLanguages = "DD_APM_INSTRUMENTATION_LANGUAGES" envCDNLocalDirPath = "DD_INSTALLER_DEBUG_CDN_LOCAL_DIR_PATH" + envCDNEnabled = "DD_INSTALLER_CDN_ENABLED" ) var defaultEnv = Env{ @@ -88,6 +89,7 @@ type Env struct { InstallScript InstallScriptEnv + CDNEnabled bool CDNLocalDirPath string } @@ -118,6 +120,7 @@ func FromEnv() *Env { InstallScript: installScriptEnvFromEnv(), + CDNEnabled: strings.ToLower(os.Getenv(envCDNEnabled)) == "true", CDNLocalDirPath: getEnvOrDefault(envCDNLocalDirPath, ""), } } diff --git a/pkg/fleet/internal/cdn/cdn.go b/pkg/fleet/internal/cdn/cdn.go index 8bbaa37d02c15..fd4fe16bfb0f4 100644 --- a/pkg/fleet/internal/cdn/cdn.go +++ b/pkg/fleet/internal/cdn/cdn.go @@ -43,5 +43,8 @@ func New(env *env.Env, configDBPath string) (CDN, error) { if env.CDNLocalDirPath != "" { return newLocal(env) } - return newRemote(env, configDBPath) + if env.CDNEnabled { + return newRemote(env, configDBPath) + } + return newDirect(env, configDBPath) } diff --git a/pkg/fleet/internal/cdn/cdn_direct.go b/pkg/fleet/internal/cdn/cdn_direct.go new file mode 100644 index 0000000000000..7e25016d67d03 --- /dev/null +++ b/pkg/fleet/internal/cdn/cdn_direct.go @@ -0,0 +1,183 @@ +// 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 cdn + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "time" + + "github.com/DataDog/datadog-agent/comp/remote-config/rctelemetryreporter/rctelemetryreporterimpl" + remoteconfig "github.com/DataDog/datadog-agent/pkg/config/remote/service" + pkgconfigsetup "github.com/DataDog/datadog-agent/pkg/config/setup" + "github.com/DataDog/datadog-agent/pkg/fleet/env" + pbgo "github.com/DataDog/datadog-agent/pkg/proto/pbgo/core" + pkghostname "github.com/DataDog/datadog-agent/pkg/util/hostname" + "github.com/DataDog/datadog-agent/pkg/version" + "github.com/DataDog/go-tuf/data" + "github.com/google/uuid" + "go.uber.org/multierr" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" +) + +type cdnDirect struct { + rcService *remoteconfig.CoreAgentService + currentRootsVersion uint64 + clientUUID string + configDBPath string +} + +// newDirect creates a new direct CDN: it fetches the configuration from the remote config service instead of cloudfront +// note: naming is a bit misleading, it's not really a cdn, but we're following the convention +func newDirect(env *env.Env, configDBPath string) (CDN, error) { + ctx := context.Background() + ctx, cc := context.WithTimeout(ctx, 10*time.Second) + defer cc() + + ht := newHostTagsGetter() + hostname, err := pkghostname.Get(ctx) + if err != nil { + return nil, err + } + + // Remove previous DB if needed + err = os.Remove(configDBPath) + if err != nil && !os.IsNotExist(err) { + return nil, fmt.Errorf("could not remove previous DB: %v", err) + } + + options := []remoteconfig.Option{ + remoteconfig.WithAPIKey(env.APIKey), + remoteconfig.WithConfigRootOverride(env.Site, ""), + remoteconfig.WithDirectorRootOverride(env.Site, ""), + remoteconfig.WithDatabaseFileName(filepath.Base(configDBPath)), + } + + service, err := remoteconfig.NewService( + pkgconfigsetup.Datadog(), // May not be filled + "Datadog Installer", + fmt.Sprintf("https://config.%s", env.Site), + hostname, + func() []string { return append(ht.get(), "installer:true") }, // Add a tag to identify the installer + &rctelemetryreporterimpl.DdRcTelemetryReporter{}, // No telemetry for this client + version.AgentVersion, + options..., + ) + if err != nil { + return nil, err + } + cdn := &cdnDirect{ + rcService: service, + currentRootsVersion: 1, + clientUUID: uuid.New().String(), + configDBPath: configDBPath, + } + service.Start() + return cdn, nil +} + +func (c *cdnDirect) Get(ctx context.Context, pkg string) (cfg Config, err error) { + span, _ := tracer.StartSpanFromContext(ctx, "cdn_direct.Get") + defer func() { span.Finish(tracer.WithError(err)) }() + + switch pkg { + case "datadog-agent": + orderConfig, layers, err := c.get(ctx, 0) + if err != nil { + return nil, err + } + cfg, err = newAgentConfig(orderConfig, layers...) + if err != nil { + return nil, err + } + default: + return nil, ErrProductNotSupported + } + + return cfg, nil +} + +// get calls the Remote Config service to get the ordered layers. +func (c *cdnDirect) get(ctx context.Context, retry int) (*orderConfig, [][]byte, error) { + agentConfigUpdate, err := c.rcService.ClientGetConfigs(ctx, &pbgo.ClientGetConfigsRequest{ + Client: &pbgo.Client{ + Id: c.clientUUID, + Products: []string{"AGENT_CONFIG"}, + IsUpdater: true, + ClientUpdater: &pbgo.ClientUpdater{}, + State: &pbgo.ClientState{ + RootVersion: c.currentRootsVersion, + TargetsVersion: 1, + }, + }, + }) + if err != nil { + return nil, nil, err + } + + if agentConfigUpdate == nil { + return &orderConfig{}, nil, nil + } + + // Update root versions + for _, root := range agentConfigUpdate.Roots { + var signedRoot data.Signed + err = json.Unmarshal(root, &signedRoot) + if err != nil { + continue + } + var r data.Root + err = json.Unmarshal(signedRoot.Signed, &r) + if err != nil { + continue + } + if uint64(r.Version) > c.currentRootsVersion { + c.currentRootsVersion = uint64(r.Version) + } + } + + // Unmarshal RC results + configLayers := make([][]byte, 0) + var configOrder *orderConfig + var layersErr error + for _, file := range agentConfigUpdate.TargetFiles { + matched := datadogConfigIDRegexp.FindStringSubmatch(file.GetPath()) + if len(matched) != 2 { + layersErr = multierr.Append(layersErr, fmt.Errorf("invalid config path: %s", file.GetPath())) + continue + } + configName := matched[1] + + if configName != configOrderID { + configLayers = append(configLayers, file.GetRaw()) + } else { + configOrder = &orderConfig{} + err = json.Unmarshal(file.GetRaw(), configOrder) + if err != nil { + // Return first - we can't continue without the order + return nil, nil, err + } + } + } + if layersErr != nil { + return nil, nil, layersErr + } + + if configOrder == nil && retry < 10 { + // Retry for up to 10 seconds to get the order config + time.Sleep(1 * time.Second) + return c.get(ctx, retry+1) + + } + return configOrder, configLayers, nil +} + +func (c *cdnDirect) Close() error { + return c.rcService.Stop() +} diff --git a/pkg/fleet/internal/cdn/cdn_remote.go b/pkg/fleet/internal/cdn/cdn_remote.go index 1e4e5f8588f15..d8ee929d0df2d 100644 --- a/pkg/fleet/internal/cdn/cdn_remote.go +++ b/pkg/fleet/internal/cdn/cdn_remote.go @@ -43,16 +43,15 @@ func newRemote(env *env.Env, configDBPath string) (CDN, error) { // Get gets the configuration from the CDN. func (c *cdnRemote) Get(ctx context.Context, pkg string) (cfg Config, err error) { - span, _ := tracer.StartSpanFromContext(ctx, "cdn.Get") + span, _ := tracer.StartSpanFromContext(ctx, "cdn_remote.Get") defer func() { span.Finish(tracer.WithError(err)) }() - orderConfig, layers, err := c.get(ctx) - if err != nil { - return nil, err - } - switch pkg { case "datadog-agent": + orderConfig, layers, err := c.get(ctx) + if err != nil { + return nil, err + } cfg, err = newAgentConfig(orderConfig, layers...) if err != nil { return nil, err diff --git a/pkg/fleet/internal/cdn/tags.go b/pkg/fleet/internal/cdn/tags.go new file mode 100644 index 0000000000000..85f5eb3a931b7 --- /dev/null +++ b/pkg/fleet/internal/cdn/tags.go @@ -0,0 +1,71 @@ +// 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 cdn + +import ( + "context" + "os" + "runtime" + "time" + + "github.com/DataDog/datadog-agent/comp/metadata/host/hostimpl/hosttags" + detectenv "github.com/DataDog/datadog-agent/pkg/config/env" + "github.com/DataDog/datadog-agent/pkg/config/model" + pkgconfigsetup "github.com/DataDog/datadog-agent/pkg/config/setup" + "github.com/DataDog/datadog-agent/pkg/util/log" + "gopkg.in/yaml.v2" +) + +type hostTagsGetter struct { + config model.Config +} + +func newHostTagsGetter() hostTagsGetter { + config := pkgconfigsetup.Datadog() + detectenv.DetectFeatures(config) // For host tags to work + err := populateTags(config) + if err != nil { + log.Warnf("Failed to populate tags from datadog.yaml: %v", err) + } + return hostTagsGetter{ + config: config, + } +} + +type tagsConfigFields struct { + Tags []string `yaml:"tags"` + ExtraTags []string `yaml:"extra_tags"` +} + +// populateTags is a best effort to get the tags from `datadog.yaml`. +func populateTags(config model.Config) error { + configPath := "/etc/datadog-agent/datadog.yaml" + if runtime.GOOS == "windows" { + configPath = "C:\\ProgramData\\Datadog\\datadog.yaml" + } + rawConfig, err := os.ReadFile(configPath) + if err != nil { + return err + } + var cfg tagsConfigFields + err = yaml.Unmarshal(rawConfig, &cfg) + if err != nil { + return err + } + config.Set("tags", cfg.Tags, model.SourceFile) + config.Set("extra_tags", cfg.ExtraTags, model.SourceFile) + return nil +} + +func (h *hostTagsGetter) get() []string { + // Host tags are cached on host, but we add a timeout to avoid blocking the request + // if the host tags are not available yet and need to be fetched + ctx, cc := context.WithTimeout(context.Background(), time.Second) + defer cc() + hostTags := hosttags.Get(ctx, true, h.config) + tags := append(hostTags.System, hostTags.GoogleCloudPlatform...) + return tags +} From 8c3db2f7ce7bb81f56719bbfa6317dc293608d98 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Fri, 18 Oct 2024 10:45:06 +0200 Subject: [PATCH 02/13] remove retries --- pkg/fleet/internal/cdn/cdn.go | 11 ++++-- pkg/fleet/internal/cdn/cdn_direct.go | 34 ++++++++----------- .../cdn/{cdn_remote.go => cdn_regular.go} | 15 ++++---- 3 files changed, 31 insertions(+), 29 deletions(-) rename pkg/fleet/internal/cdn/{cdn_remote.go => cdn_regular.go} (89%) diff --git a/pkg/fleet/internal/cdn/cdn.go b/pkg/fleet/internal/cdn/cdn.go index fd4fe16bfb0f4..93efdd52205e4 100644 --- a/pkg/fleet/internal/cdn/cdn.go +++ b/pkg/fleet/internal/cdn/cdn.go @@ -10,6 +10,7 @@ import ( "context" "errors" "regexp" + "runtime" "github.com/DataDog/datadog-agent/pkg/fleet/env" ) @@ -40,11 +41,15 @@ type CDN interface { // New creates a new CDN. func New(env *env.Env, configDBPath string) (CDN, error) { + if !env.RemotePolicies { + return nil, nil + } if env.CDNLocalDirPath != "" { return newLocal(env) } - if env.CDNEnabled { - return newRemote(env, configDBPath) + if !env.CDNEnabled && runtime.GOOS != "windows" { + // Windows can't use the direct CDN yet as it breaks the static binary build + return newDirect(env, configDBPath) } - return newDirect(env, configDBPath) + return newRegular(env, configDBPath) } diff --git a/pkg/fleet/internal/cdn/cdn_direct.go b/pkg/fleet/internal/cdn/cdn_direct.go index 7e25016d67d03..cf15cb7ecca25 100644 --- a/pkg/fleet/internal/cdn/cdn_direct.go +++ b/pkg/fleet/internal/cdn/cdn_direct.go @@ -43,7 +43,7 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { ht := newHostTagsGetter() hostname, err := pkghostname.Get(ctx) if err != nil { - return nil, err + hostname = "unknown" } // Remove previous DB if needed @@ -60,12 +60,12 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { } service, err := remoteconfig.NewService( - pkgconfigsetup.Datadog(), // May not be filled + pkgconfigsetup.Datadog(), // May not be filled as we don't read the config when we're not in the daemon, in which case we'll use the defaults "Datadog Installer", fmt.Sprintf("https://config.%s", env.Site), hostname, - func() []string { return append(ht.get(), "installer:true") }, // Add a tag to identify the installer - &rctelemetryreporterimpl.DdRcTelemetryReporter{}, // No telemetry for this client + ht.get, + &rctelemetryreporterimpl.DdRcTelemetryReporter{}, // No telemetry for this client version.AgentVersion, options..., ) @@ -83,12 +83,13 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { } func (c *cdnDirect) Get(ctx context.Context, pkg string) (cfg Config, err error) { - span, _ := tracer.StartSpanFromContext(ctx, "cdn_direct.Get") + span, _ := tracer.StartSpanFromContext(ctx, "cdn.Get") + span.SetTag("cdn_type", "remote_config") defer func() { span.Finish(tracer.WithError(err)) }() switch pkg { case "datadog-agent": - orderConfig, layers, err := c.get(ctx, 0) + orderConfig, layers, err := c.get(ctx) if err != nil { return nil, err } @@ -104,16 +105,18 @@ func (c *cdnDirect) Get(ctx context.Context, pkg string) (cfg Config, err error) } // get calls the Remote Config service to get the ordered layers. -func (c *cdnDirect) get(ctx context.Context, retry int) (*orderConfig, [][]byte, error) { +func (c *cdnDirect) get(ctx context.Context) (*orderConfig, [][]byte, error) { agentConfigUpdate, err := c.rcService.ClientGetConfigs(ctx, &pbgo.ClientGetConfigsRequest{ Client: &pbgo.Client{ - Id: c.clientUUID, - Products: []string{"AGENT_CONFIG"}, - IsUpdater: true, - ClientUpdater: &pbgo.ClientUpdater{}, + Id: c.clientUUID, + Products: []string{"AGENT_CONFIG"}, + IsUpdater: true, + ClientUpdater: &pbgo.ClientUpdater{ + Tags: []string{"installer:true"}, + }, State: &pbgo.ClientState{ RootVersion: c.currentRootsVersion, - TargetsVersion: 1, + TargetsVersion: 0, }, }, }) @@ -168,13 +171,6 @@ func (c *cdnDirect) get(ctx context.Context, retry int) (*orderConfig, [][]byte, if layersErr != nil { return nil, nil, layersErr } - - if configOrder == nil && retry < 10 { - // Retry for up to 10 seconds to get the order config - time.Sleep(1 * time.Second) - return c.get(ctx, retry+1) - - } return configOrder, configLayers, nil } diff --git a/pkg/fleet/internal/cdn/cdn_remote.go b/pkg/fleet/internal/cdn/cdn_regular.go similarity index 89% rename from pkg/fleet/internal/cdn/cdn_remote.go rename to pkg/fleet/internal/cdn/cdn_regular.go index d8ee929d0df2d..bd7deec882cbf 100644 --- a/pkg/fleet/internal/cdn/cdn_remote.go +++ b/pkg/fleet/internal/cdn/cdn_regular.go @@ -20,12 +20,12 @@ import ( "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" ) -type cdnRemote struct { +type cdnRegular struct { client *remoteconfig.HTTPClient currentRootsVersion uint64 } -func newRemote(env *env.Env, configDBPath string) (CDN, error) { +func newRegular(env *env.Env, configDBPath string) (CDN, error) { client, err := remoteconfig.NewHTTPClient( configDBPath, env.Site, @@ -35,15 +35,16 @@ func newRemote(env *env.Env, configDBPath string) (CDN, error) { if err != nil { return nil, err } - return &cdnRemote{ + return &cdnRegular{ client: client, currentRootsVersion: 1, }, nil } // Get gets the configuration from the CDN. -func (c *cdnRemote) Get(ctx context.Context, pkg string) (cfg Config, err error) { - span, _ := tracer.StartSpanFromContext(ctx, "cdn_remote.Get") +func (c *cdnRegular) Get(ctx context.Context, pkg string) (cfg Config, err error) { + span, _ := tracer.StartSpanFromContext(ctx, "cdn.Get") + span.SetTag("cdn_type", "cdn") defer func() { span.Finish(tracer.WithError(err)) }() switch pkg { @@ -64,12 +65,12 @@ func (c *cdnRemote) Get(ctx context.Context, pkg string) (cfg Config, err error) } // Close cleans up the CDN's resources -func (c *cdnRemote) Close() error { +func (c *cdnRegular) Close() error { return c.client.Close() } // get calls the Remote Config service to get the ordered layers. -func (c *cdnRemote) get(ctx context.Context) (*orderConfig, [][]byte, error) { +func (c *cdnRegular) get(ctx context.Context) (*orderConfig, [][]byte, error) { agentConfigUpdate, err := c.client.GetCDNConfigUpdate( ctx, []string{"AGENT_CONFIG"}, From 3de4c3d80f63115a1c4071c99829fbab8eeab068 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Tue, 22 Oct 2024 14:01:56 +0200 Subject: [PATCH 03/13] windows cgo --- pkg/fleet/internal/cdn/cdn.go | 6 ++--- pkg/fleet/internal/cdn/cdn_noop.go | 37 ++++++++++++++++++++++++++++++ pkg/util/hostname/fqdn_windows.go | 4 +--- 3 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 pkg/fleet/internal/cdn/cdn_noop.go diff --git a/pkg/fleet/internal/cdn/cdn.go b/pkg/fleet/internal/cdn/cdn.go index 93efdd52205e4..a1047c85e5974 100644 --- a/pkg/fleet/internal/cdn/cdn.go +++ b/pkg/fleet/internal/cdn/cdn.go @@ -10,7 +10,6 @@ import ( "context" "errors" "regexp" - "runtime" "github.com/DataDog/datadog-agent/pkg/fleet/env" ) @@ -42,13 +41,12 @@ type CDN interface { // New creates a new CDN. func New(env *env.Env, configDBPath string) (CDN, error) { if !env.RemotePolicies { - return nil, nil + return newNoop() } if env.CDNLocalDirPath != "" { return newLocal(env) } - if !env.CDNEnabled && runtime.GOOS != "windows" { - // Windows can't use the direct CDN yet as it breaks the static binary build + if !env.CDNEnabled { return newDirect(env, configDBPath) } return newRegular(env, configDBPath) diff --git a/pkg/fleet/internal/cdn/cdn_noop.go b/pkg/fleet/internal/cdn/cdn_noop.go new file mode 100644 index 0000000000000..8c4377bb97d14 --- /dev/null +++ b/pkg/fleet/internal/cdn/cdn_noop.go @@ -0,0 +1,37 @@ +// 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 cdn + +import ( + "context" +) + +type cdnNoop struct { +} + +type configNoop struct{} + +// newNoop creates a new noop CDN. +func newNoop() (CDN, error) { + return &cdnNoop{}, nil +} + +// Get gets the configuration from the CDN. +func (c *cdnNoop) Get(_ context.Context, _ string) (Config, error) { + return &configNoop{}, nil +} + +func (c *cdnNoop) Close() error { + return nil +} + +func (c *configNoop) Version() string { + return "" +} + +func (c *configNoop) Write(_ string) error { + return nil +} diff --git a/pkg/util/hostname/fqdn_windows.go b/pkg/util/hostname/fqdn_windows.go index c9e47ad7924f8..3df8050a2b2c7 100644 --- a/pkg/util/hostname/fqdn_windows.go +++ b/pkg/util/hostname/fqdn_windows.go @@ -6,9 +6,7 @@ package hostname import ( - "C" "os" - "unsafe" "golang.org/x/sys/windows" ) @@ -23,7 +21,7 @@ func getSystemFQDN() (string, error) { if err != nil { return "", err } - namestring := C.GoString((*C.char)(unsafe.Pointer(he.Name))) + namestring := windows.BytePtrToString(he.Name) return namestring, nil } From c0105d573a0d62f9faa659c5489885238e4a8f60 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Thu, 24 Oct 2024 13:16:42 +0200 Subject: [PATCH 04/13] fix test --- pkg/fleet/internal/cdn/cdn_direct.go | 2 +- test/new-e2e/tests/installer/unix/upgrade_scenario_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/fleet/internal/cdn/cdn_direct.go b/pkg/fleet/internal/cdn/cdn_direct.go index cf15cb7ecca25..b41375862531e 100644 --- a/pkg/fleet/internal/cdn/cdn_direct.go +++ b/pkg/fleet/internal/cdn/cdn_direct.go @@ -56,7 +56,7 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { remoteconfig.WithAPIKey(env.APIKey), remoteconfig.WithConfigRootOverride(env.Site, ""), remoteconfig.WithDirectorRootOverride(env.Site, ""), - remoteconfig.WithDatabaseFileName(filepath.Base(configDBPath)), + remoteconfig.WithDatabaseFileName(filepath.Join(filepath.Base(configDBPath), "remote-config.db")), } service, err := remoteconfig.NewService( diff --git a/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go b/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go index 62da6d6ffda4c..aebee47a4488f 100644 --- a/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go +++ b/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go @@ -624,7 +624,7 @@ func (s *upgradeScenarioSuite) assertSuccessfulAgentStopExperiment(timestamp hos func (s *upgradeScenarioSuite) startConfigExperiment(localCDNPath string, pkg packageName, hash string) (string, error) { cmd := fmt.Sprintf("sudo -E datadog-installer install-config-experiment %s %s > /tmp/start_config_experiment.log 2>&1", pkg, hash) s.T().Logf("Running start command: %s", cmd) - return s.Env().RemoteHost.Execute(cmd, client.WithEnvVariables(map[string]string{"DD_INSTALLER_DEBUG_CDN_LOCAL_DIR_PATH": localCDNPath})) + return s.Env().RemoteHost.Execute(cmd, client.WithEnvVariables(map[string]string{"DD_INSTALLER_DEBUG_CDN_LOCAL_DIR_PATH": localCDNPath, "DD_REMOTE_POLICIES": "true"})) } func (s *upgradeScenarioSuite) mustStartConfigExperiment(localCDNPath string, pkg packageName, version string) string { @@ -640,7 +640,7 @@ func (s *upgradeScenarioSuite) mustStartConfigExperiment(localCDNPath string, pk func (s *upgradeScenarioSuite) promoteConfigExperiment(localCDNPath string, pkg packageName) (string, error) { cmd := fmt.Sprintf("sudo -E datadog-installer promote-config-experiment %s > /tmp/promote_config_experiment.log 2>&1", pkg) s.T().Logf("Running promote command: %s", cmd) - return s.Env().RemoteHost.Execute(cmd, client.WithEnvVariables(map[string]string{"DD_INSTALLER_DEBUG_CDN_LOCAL_DIR_PATH": localCDNPath})) + return s.Env().RemoteHost.Execute(cmd, client.WithEnvVariables(map[string]string{"DD_INSTALLER_DEBUG_CDN_LOCAL_DIR_PATH": localCDNPath, "DD_REMOTE_POLICIES": "true"})) } func (s *upgradeScenarioSuite) mustPromoteConfigExperiment(localCDNPath string, pkg packageName) string { @@ -656,7 +656,7 @@ func (s *upgradeScenarioSuite) mustPromoteConfigExperiment(localCDNPath string, func (s *upgradeScenarioSuite) stopConfigExperiment(localCDNPath string, pkg packageName) (string, error) { cmd := fmt.Sprintf("sudo -E datadog-installer remove-config-experiment %s > /tmp/stop_config_experiment.log 2>&1", pkg) s.T().Logf("Running stop command: %s", cmd) - return s.Env().RemoteHost.Execute(cmd, client.WithEnvVariables(map[string]string{"DD_INSTALLER_DEBUG_CDN_LOCAL_DIR_PATH": localCDNPath})) + return s.Env().RemoteHost.Execute(cmd, client.WithEnvVariables(map[string]string{"DD_INSTALLER_DEBUG_CDN_LOCAL_DIR_PATH": localCDNPath, "DD_REMOTE_POLICIES": "true"})) } func (s *upgradeScenarioSuite) mustStopConfigExperiment(localCDNPath string, pkg packageName) string { From 1a4fd85a1f34265fc13afa2539b331e5595631de Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Mon, 28 Oct 2024 16:47:33 +0100 Subject: [PATCH 05/13] fix --- pkg/fleet/internal/cdn/cdn_direct.go | 2 +- test/new-e2e/tests/installer/host/host.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/fleet/internal/cdn/cdn_direct.go b/pkg/fleet/internal/cdn/cdn_direct.go index b41375862531e..26fc5d09d4727 100644 --- a/pkg/fleet/internal/cdn/cdn_direct.go +++ b/pkg/fleet/internal/cdn/cdn_direct.go @@ -47,7 +47,7 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { } // Remove previous DB if needed - err = os.Remove(configDBPath) + err = os.RemoveAll(configDBPath) if err != nil && !os.IsNotExist(err) { return nil, fmt.Errorf("could not remove previous DB: %v", err) } diff --git a/test/new-e2e/tests/installer/host/host.go b/test/new-e2e/tests/installer/host/host.go index 0488a72130557..7f6f07a40ae79 100644 --- a/test/new-e2e/tests/installer/host/host.go +++ b/test/new-e2e/tests/installer/host/host.go @@ -143,7 +143,7 @@ func (h *Host) DeletePath(path string) { func (h *Host) WaitForUnitActive(units ...string) { for _, unit := range units { _, err := h.remote.Execute(fmt.Sprintf("timeout=30; unit=%s; while ! systemctl is-active --quiet $unit && [ $timeout -gt 0 ]; do sleep 1; ((timeout--)); done; [ $timeout -ne 0 ]", unit)) - require.NoError(h.t, err, "unit %s did not become active", unit) + require.NoError(h.t, err, "unit %s did not become active. logs: %s", unit, h.remote.MustExecute("journalctl -xeu "+unit)) } } @@ -151,7 +151,8 @@ func (h *Host) WaitForUnitActive(units ...string) { func (h *Host) WaitForUnitActivating(units ...string) { for _, unit := range units { _, err := h.remote.Execute(fmt.Sprintf("timeout=30; unit=%s; while ! grep -q \"Active: activating\" <(sudo systemctl status $unit) && [ $timeout -gt 0 ]; do sleep 1; ((timeout--)); done; [ $timeout -ne 0 ]", unit)) - require.NoError(h.t, err, "unit %s did not become active", unit) + require.NoError(h.t, err, "unit %s did not become activating. logs: %s", unit, h.remote.MustExecute("journalctl -xeu "+unit)) + } } From 37509562defee6bcdbf9e976a58f0e0042127bd0 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Tue, 29 Oct 2024 10:31:12 +0100 Subject: [PATCH 06/13] fix test --- test/new-e2e/tests/installer/host/host.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/new-e2e/tests/installer/host/host.go b/test/new-e2e/tests/installer/host/host.go index 7f6f07a40ae79..b736809965ee8 100644 --- a/test/new-e2e/tests/installer/host/host.go +++ b/test/new-e2e/tests/installer/host/host.go @@ -143,7 +143,7 @@ func (h *Host) DeletePath(path string) { func (h *Host) WaitForUnitActive(units ...string) { for _, unit := range units { _, err := h.remote.Execute(fmt.Sprintf("timeout=30; unit=%s; while ! systemctl is-active --quiet $unit && [ $timeout -gt 0 ]; do sleep 1; ((timeout--)); done; [ $timeout -ne 0 ]", unit)) - require.NoError(h.t, err, "unit %s did not become active. logs: %s", unit, h.remote.MustExecute("journalctl -xeu "+unit)) + require.NoError(h.t, err, "unit %s did not become active. logs: %s", unit, h.remote.MustExecute("sudo journalctl -xeu "+unit)) } } @@ -151,7 +151,7 @@ func (h *Host) WaitForUnitActive(units ...string) { func (h *Host) WaitForUnitActivating(units ...string) { for _, unit := range units { _, err := h.remote.Execute(fmt.Sprintf("timeout=30; unit=%s; while ! grep -q \"Active: activating\" <(sudo systemctl status $unit) && [ $timeout -gt 0 ]; do sleep 1; ((timeout--)); done; [ $timeout -ne 0 ]", unit)) - require.NoError(h.t, err, "unit %s did not become activating. logs: %s", unit, h.remote.MustExecute("journalctl -xeu "+unit)) + require.NoError(h.t, err, "unit %s did not become activating. logs: %s", unit, h.remote.MustExecute("sudo journalctl -xeu "+unit)) } } From 6b643db439fea797cde006e5561a249b511845c6 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Tue, 29 Oct 2024 13:16:01 +0100 Subject: [PATCH 07/13] fix(fleet): tmp rc db --- pkg/config/remote/service/service.go | 18 +++++++++++++++--- pkg/fleet/internal/cdn/cdn_direct.go | 23 ++++++++++++++++------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/pkg/config/remote/service/service.go b/pkg/config/remote/service/service.go index f09c59df87d88..8994a60933f26 100644 --- a/pkg/config/remote/service/service.go +++ b/pkg/config/remote/service/service.go @@ -17,14 +17,15 @@ import ( "errors" "expvar" "fmt" - "github.com/DataDog/datadog-agent/pkg/remoteconfig/state" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" "net/url" "path" "strconv" "sync" "time" + "github.com/DataDog/datadog-agent/pkg/remoteconfig/state" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" + "github.com/DataDog/go-tuf/data" tufutil "github.com/DataDog/go-tuf/util" "github.com/benbjohnson/clock" @@ -247,6 +248,7 @@ type options struct { apiKey string traceAgentEnv string databaseFileName string + databaseFilePath string configRootOverride string directorRootOverride string clientCacheBypassLimit int @@ -261,6 +263,7 @@ var defaultOptions = options{ apiKey: "", traceAgentEnv: "", databaseFileName: "remote-config.db", + databaseFilePath: "", configRootOverride: "", directorRootOverride: "", clientCacheBypassLimit: defaultCacheBypassLimit, @@ -283,6 +286,11 @@ func WithDatabaseFileName(fileName string) func(s *options) { return func(s *options) { s.databaseFileName = fileName } } +// WithDatabasePath sets the service database path +func WithDatabasePath(path string) func(s *options) { + return func(s *options) { s.databaseFilePath = path } +} + // WithConfigRootOverride sets the service config root override func WithConfigRootOverride(site string, override string) func(s *options) { return func(opts *options) { @@ -410,7 +418,11 @@ func NewService(cfg model.Reader, rcType, baseRawURL, hostname string, tagsGette return nil, err } - dbPath := path.Join(cfg.GetString("run_path"), options.databaseFileName) + databaseFilePath := cfg.GetString("run_path") + if options.databaseFilePath != "" { + databaseFilePath = options.databaseFilePath + } + dbPath := path.Join(databaseFilePath, options.databaseFileName) db, err := openCacheDB(dbPath, agentVersion, authKeys.apiKey) if err != nil { return nil, err diff --git a/pkg/fleet/internal/cdn/cdn_direct.go b/pkg/fleet/internal/cdn/cdn_direct.go index 26fc5d09d4727..2f154d7f83b2d 100644 --- a/pkg/fleet/internal/cdn/cdn_direct.go +++ b/pkg/fleet/internal/cdn/cdn_direct.go @@ -10,7 +10,6 @@ import ( "encoding/json" "fmt" "os" - "path/filepath" "time" "github.com/DataDog/datadog-agent/comp/remote-config/rctelemetryreporter/rctelemetryreporterimpl" @@ -46,17 +45,23 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { hostname = "unknown" } - // Remove previous DB if needed - err = os.RemoveAll(configDBPath) - if err != nil && !os.IsNotExist(err) { - return nil, fmt.Errorf("could not remove previous DB: %v", err) + // ensures the config db path exists + err = os.MkdirAll(configDBPath, 0755) + if err != nil { + return nil, err + } + + configDBPathTemp, err := os.MkdirTemp(configDBPath, "direct-*") + if err != nil { + return nil, err } options := []remoteconfig.Option{ remoteconfig.WithAPIKey(env.APIKey), remoteconfig.WithConfigRootOverride(env.Site, ""), remoteconfig.WithDirectorRootOverride(env.Site, ""), - remoteconfig.WithDatabaseFileName(filepath.Join(filepath.Base(configDBPath), "remote-config.db")), + remoteconfig.WithDatabaseFileName("remote-config.db"), + remoteconfig.WithDatabasePath(configDBPathTemp), } service, err := remoteconfig.NewService( @@ -76,7 +81,7 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { rcService: service, currentRootsVersion: 1, clientUUID: uuid.New().String(), - configDBPath: configDBPath, + configDBPath: configDBPathTemp, } service.Start() return cdn, nil @@ -175,5 +180,9 @@ func (c *cdnDirect) get(ctx context.Context) (*orderConfig, [][]byte, error) { } func (c *cdnDirect) Close() error { + err := os.RemoveAll(c.configDBPath) + if err != nil { + return err + } return c.rcService.Stop() } From 5396181d25130797e5695cc58e2584c8689c065a Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Tue, 29 Oct 2024 16:54:00 +0100 Subject: [PATCH 08/13] fix --- .../subcommands/installer/command.go | 22 +++++++++---------- .../installer/unix/upgrade_scenario_test.go | 8 +++++-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/cmd/installer/subcommands/installer/command.go b/cmd/installer/subcommands/installer/command.go index 2a612cfe1750c..bb380cbfd79ab 100644 --- a/cmd/installer/subcommands/installer/command.go +++ b/cmd/installer/subcommands/installer/command.go @@ -293,7 +293,7 @@ func installCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() i.span.SetTag("params.url", args[0]) return i.Install(i.ctx, args[0], installArgs) }, @@ -313,7 +313,7 @@ func removeCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() i.span.SetTag("params.package", args[0]) return i.Remove(i.ctx, args[0]) }, @@ -332,7 +332,7 @@ func purgeCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() i.Purge(i.ctx) return nil }, @@ -351,7 +351,7 @@ func installExperimentCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() i.span.SetTag("params.url", args[0]) return i.InstallExperiment(i.ctx, args[0]) }, @@ -370,7 +370,7 @@ func removeExperimentCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() i.span.SetTag("params.package", args[0]) return i.RemoveExperiment(i.ctx, args[0]) }, @@ -389,7 +389,7 @@ func promoteExperimentCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() i.span.SetTag("params.package", args[0]) return i.PromoteExperiment(i.ctx, args[0]) }, @@ -408,7 +408,7 @@ func installConfigExperimentCommand() *cobra.Command { if err != nil { return err } - defer func() { i.Stop(err) }() + defer func() { i.stop(err) }() i.span.SetTag("params.package", args[0]) i.span.SetTag("params.version", args[1]) return i.InstallConfigExperiment(i.ctx, args[0], args[1]) @@ -428,7 +428,7 @@ func removeConfigExperimentCommand() *cobra.Command { if err != nil { return err } - defer func() { i.Stop(err) }() + defer func() { i.stop(err) }() i.span.SetTag("params.package", args[0]) return i.RemoveConfigExperiment(i.ctx, args[0]) }, @@ -447,7 +447,7 @@ func promoteConfigExperimentCommand() *cobra.Command { if err != nil { return err } - defer func() { i.Stop(err) }() + defer func() { i.stop(err) }() i.span.SetTag("params.package", args[0]) return i.PromoteConfigExperiment(i.ctx, args[0]) }, @@ -466,7 +466,7 @@ func garbageCollectCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() return i.GarbageCollect(i.ctx) }, } @@ -489,7 +489,7 @@ func isInstalledCommand() *cobra.Command { if err != nil { return err } - defer i.stop(err) + defer func() { i.stop(err) }() installed, err := i.IsInstalled(i.ctx, args[0]) if err != nil { return err diff --git a/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go b/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go index aebee47a4488f..dffa24e1f54e6 100644 --- a/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go +++ b/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go @@ -734,19 +734,23 @@ func (s *upgradeScenarioSuite) assertSuccessfulConfigStopExperiment(timestamp ho func (s *upgradeScenarioSuite) getInstallerStatus() installerStatus { socketPath := "/opt/datadog-packages/run/installer.sock" + s.host.WaitForFileExists(true, socketPath) requestHeader := " -H 'Content-Type: application/json' -H 'Accept: application/json' " - response := s.Env().RemoteHost.MustExecute(fmt.Sprintf( + response, err := s.Env().RemoteHost.Execute(fmt.Sprintf( "sudo curl -s --unix-socket %s %s http://daemon/status", socketPath, requestHeader, )) + require.NoError(s.T(), err, "Failed to get installer status: %s", + s.Env().RemoteHost.MustExecute("sudo journalctl -xeu datadog-installer --no-pager"), + ) // {"version":"7.56.0-devel+git.446.acf2836","packages":{ // "datadog-agent":{"Stable":"7.56.0-devel.git.446.acf2836.pipeline.37567760-1","Experiment":"7.54.1-1"}, // "datadog-installer":{"Stable":"7.56.0-devel.git.446.acf2836.pipeline.37567760-1","Experiment":""}}} var status installerStatus - err := json.Unmarshal([]byte(response), &status) + err = json.Unmarshal([]byte(response), &status) if err != nil { s.T().Fatal(err) } From 3a9b76b2197db40416a6ab0de6b7bf2a4ccee01e Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Wed, 30 Oct 2024 10:59:24 +0100 Subject: [PATCH 09/13] fix --- pkg/fleet/internal/cdn/cdn_direct.go | 16 ++++++++++-- .../installer/unix/upgrade_scenario_test.go | 26 +++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/pkg/fleet/internal/cdn/cdn_direct.go b/pkg/fleet/internal/cdn/cdn_direct.go index 2f154d7f83b2d..4f8a1be155f10 100644 --- a/pkg/fleet/internal/cdn/cdn_direct.go +++ b/pkg/fleet/internal/cdn/cdn_direct.go @@ -30,6 +30,7 @@ type cdnDirect struct { currentRootsVersion uint64 clientUUID string configDBPath string + firstRequest bool } // newDirect creates a new direct CDN: it fetches the configuration from the remote config service instead of cloudfront @@ -82,6 +83,7 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { currentRootsVersion: 1, clientUUID: uuid.New().String(), configDBPath: configDBPathTemp, + firstRequest: true, } service.Start() return cdn, nil @@ -111,6 +113,16 @@ func (c *cdnDirect) Get(ctx context.Context, pkg string) (cfg Config, err error) // get calls the Remote Config service to get the ordered layers. func (c *cdnDirect) get(ctx context.Context) (*orderConfig, [][]byte, error) { + if c.firstRequest { + // A first request is made to the remote config service at service startup, + // so if we do another request too close to the first one (in the same second) + // we'll get the same director version (== timestamp) with different contents, + // which will cause the response to be rejected silently and we won't get + // the configurations + time.Sleep(1 * time.Second) + c.firstRequest = false + } + agentConfigUpdate, err := c.rcService.ClientGetConfigs(ctx, &pbgo.ClientGetConfigsRequest{ Client: &pbgo.Client{ Id: c.clientUUID, @@ -180,9 +192,9 @@ func (c *cdnDirect) get(ctx context.Context) (*orderConfig, [][]byte, error) { } func (c *cdnDirect) Close() error { - err := os.RemoveAll(c.configDBPath) + err := c.rcService.Stop() if err != nil { return err } - return c.rcService.Stop() + return os.RemoveAll(c.configDBPath) } diff --git a/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go b/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go index dffa24e1f54e6..eece340b956a8 100644 --- a/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go +++ b/test/new-e2e/tests/installer/unix/upgrade_scenario_test.go @@ -734,23 +734,27 @@ func (s *upgradeScenarioSuite) assertSuccessfulConfigStopExperiment(timestamp ho func (s *upgradeScenarioSuite) getInstallerStatus() installerStatus { socketPath := "/opt/datadog-packages/run/installer.sock" - s.host.WaitForFileExists(true, socketPath) - - requestHeader := " -H 'Content-Type: application/json' -H 'Accept: application/json' " - response, err := s.Env().RemoteHost.Execute(fmt.Sprintf( - "sudo curl -s --unix-socket %s %s http://daemon/status", - socketPath, - requestHeader, - )) - require.NoError(s.T(), err, "Failed to get installer status: %s", - s.Env().RemoteHost.MustExecute("sudo journalctl -xeu datadog-installer --no-pager"), + + var response string + assert.Eventually(s.T(), func() bool { + var err error + requestHeader := " -H 'Content-Type: application/json' -H 'Accept: application/json' " + response, err = s.Env().RemoteHost.Execute(fmt.Sprintf( + "sudo curl -s --unix-socket %s %s http://daemon/status", + socketPath, + requestHeader, + )) + return err == nil + }, time.Second*30, time.Second*1, "Failed to get installer status: %s\n\n%s", + s.Env().RemoteHost.MustExecute("sudo journalctl -xeu datadog-installer"), + s.Env().RemoteHost.MustExecute("sudo journalctl -xeu datadog-installer-exp"), ) // {"version":"7.56.0-devel+git.446.acf2836","packages":{ // "datadog-agent":{"Stable":"7.56.0-devel.git.446.acf2836.pipeline.37567760-1","Experiment":"7.54.1-1"}, // "datadog-installer":{"Stable":"7.56.0-devel.git.446.acf2836.pipeline.37567760-1","Experiment":""}}} var status installerStatus - err = json.Unmarshal([]byte(response), &status) + err := json.Unmarshal([]byte(response), &status) if err != nil { s.T().Fatal(err) } From fd50c3fb9d025b0f5952bfd7b376c6efac40ece2 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Wed, 30 Oct 2024 13:52:50 +0100 Subject: [PATCH 10/13] test magic --- pkg/fleet/internal/cdn/cdn.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/fleet/internal/cdn/cdn.go b/pkg/fleet/internal/cdn/cdn.go index a1047c85e5974..0bdd15d126ea3 100644 --- a/pkg/fleet/internal/cdn/cdn.go +++ b/pkg/fleet/internal/cdn/cdn.go @@ -10,6 +10,7 @@ import ( "context" "errors" "regexp" + "runtime" "github.com/DataDog/datadog-agent/pkg/fleet/env" ) @@ -40,6 +41,9 @@ type CDN interface { // New creates a new CDN. func New(env *env.Env, configDBPath string) (CDN, error) { + if runtime.GOOS == "windows" { + return newRegular(env, configDBPath) + } if !env.RemotePolicies { return newNoop() } From 734559ce1e4e030266a94dd756d9e4951a1a48c4 Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Thu, 31 Oct 2024 12:42:32 +0100 Subject: [PATCH 11/13] comments --- pkg/fleet/internal/cdn/cdn.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/fleet/internal/cdn/cdn.go b/pkg/fleet/internal/cdn/cdn.go index 0bdd15d126ea3..776690baee32e 100644 --- a/pkg/fleet/internal/cdn/cdn.go +++ b/pkg/fleet/internal/cdn/cdn.go @@ -39,9 +39,13 @@ type CDN interface { Close() error } -// New creates a new CDN. +// New creates a new CDN and chooses the implementation depending +// on the environment func New(env *env.Env, configDBPath string) (CDN, error) { if runtime.GOOS == "windows" { + // There's an assumption on windows that some directories are already there + // but they are in fact created by the regular CDN implementation. Until + // there is a fix on windows we keep the previous CDN behaviour for them return newRegular(env, configDBPath) } if !env.RemotePolicies { From 35b277b62903f27194bbf3f40b8f903d3dbbc09d Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Mon, 4 Nov 2024 13:08:34 +0100 Subject: [PATCH 12/13] more comments --- pkg/fleet/internal/cdn/cdn.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pkg/fleet/internal/cdn/cdn.go b/pkg/fleet/internal/cdn/cdn.go index 776690baee32e..c658a216cab7c 100644 --- a/pkg/fleet/internal/cdn/cdn.go +++ b/pkg/fleet/internal/cdn/cdn.go @@ -48,14 +48,27 @@ func New(env *env.Env, configDBPath string) (CDN, error) { // there is a fix on windows we keep the previous CDN behaviour for them return newRegular(env, configDBPath) } + if !env.RemotePolicies { + // Remote policies are not enabled -- we don't need the CDN + // and we don't want to create the directories that the CDN + // implementation would create. We return a no-op CDN to avoid + // nil pointer dereference. return newNoop() } + if env.CDNLocalDirPath != "" { + // Mock the CDN for local development or testing return newLocal(env) } + if !env.CDNEnabled { + // Remote policies are enabled but we don't want to use the CDN + // as it's still in development. We use standard remote config calls + // instead (dubbed "direct" CDN). return newDirect(env, configDBPath) } + + // Regular CDN with the cloudfront distribution return newRegular(env, configDBPath) } From 65055a58be1c564020787e82bc140bcf2c8df94d Mon Sep 17 00:00:00 2001 From: Baptiste Foy Date: Tue, 5 Nov 2024 10:12:48 +0100 Subject: [PATCH 13/13] review --- pkg/fleet/internal/cdn/cdn.go | 10 +++++----- .../internal/cdn/{cdn_regular.go => cdn_http.go} | 12 ++++++------ pkg/fleet/internal/cdn/cdn_local.go | 4 ++-- pkg/fleet/internal/cdn/cdn_noop.go | 10 ++++++++-- .../internal/cdn/{cdn_direct.go => cdn_rc.go} | 14 +++++++------- 5 files changed, 28 insertions(+), 22 deletions(-) rename pkg/fleet/internal/cdn/{cdn_regular.go => cdn_http.go} (92%) rename pkg/fleet/internal/cdn/{cdn_direct.go => cdn_rc.go} (93%) diff --git a/pkg/fleet/internal/cdn/cdn.go b/pkg/fleet/internal/cdn/cdn.go index c658a216cab7c..7891c7b697904 100644 --- a/pkg/fleet/internal/cdn/cdn.go +++ b/pkg/fleet/internal/cdn/cdn.go @@ -46,7 +46,7 @@ func New(env *env.Env, configDBPath string) (CDN, error) { // There's an assumption on windows that some directories are already there // but they are in fact created by the regular CDN implementation. Until // there is a fix on windows we keep the previous CDN behaviour for them - return newRegular(env, configDBPath) + return newCDNHTTP(env, configDBPath) } if !env.RemotePolicies { @@ -54,21 +54,21 @@ func New(env *env.Env, configDBPath string) (CDN, error) { // and we don't want to create the directories that the CDN // implementation would create. We return a no-op CDN to avoid // nil pointer dereference. - return newNoop() + return newCDNNoop() } if env.CDNLocalDirPath != "" { // Mock the CDN for local development or testing - return newLocal(env) + return newCDNLocal(env) } if !env.CDNEnabled { // Remote policies are enabled but we don't want to use the CDN // as it's still in development. We use standard remote config calls // instead (dubbed "direct" CDN). - return newDirect(env, configDBPath) + return newCDNRC(env, configDBPath) } // Regular CDN with the cloudfront distribution - return newRegular(env, configDBPath) + return newCDNHTTP(env, configDBPath) } diff --git a/pkg/fleet/internal/cdn/cdn_regular.go b/pkg/fleet/internal/cdn/cdn_http.go similarity index 92% rename from pkg/fleet/internal/cdn/cdn_regular.go rename to pkg/fleet/internal/cdn/cdn_http.go index bd7deec882cbf..1bcc8124112f3 100644 --- a/pkg/fleet/internal/cdn/cdn_regular.go +++ b/pkg/fleet/internal/cdn/cdn_http.go @@ -20,12 +20,12 @@ import ( "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" ) -type cdnRegular struct { +type cdnHTTP struct { client *remoteconfig.HTTPClient currentRootsVersion uint64 } -func newRegular(env *env.Env, configDBPath string) (CDN, error) { +func newCDNHTTP(env *env.Env, configDBPath string) (CDN, error) { client, err := remoteconfig.NewHTTPClient( configDBPath, env.Site, @@ -35,14 +35,14 @@ func newRegular(env *env.Env, configDBPath string) (CDN, error) { if err != nil { return nil, err } - return &cdnRegular{ + return &cdnHTTP{ client: client, currentRootsVersion: 1, }, nil } // Get gets the configuration from the CDN. -func (c *cdnRegular) Get(ctx context.Context, pkg string) (cfg Config, err error) { +func (c *cdnHTTP) Get(ctx context.Context, pkg string) (cfg Config, err error) { span, _ := tracer.StartSpanFromContext(ctx, "cdn.Get") span.SetTag("cdn_type", "cdn") defer func() { span.Finish(tracer.WithError(err)) }() @@ -65,12 +65,12 @@ func (c *cdnRegular) Get(ctx context.Context, pkg string) (cfg Config, err error } // Close cleans up the CDN's resources -func (c *cdnRegular) Close() error { +func (c *cdnHTTP) Close() error { return c.client.Close() } // get calls the Remote Config service to get the ordered layers. -func (c *cdnRegular) get(ctx context.Context) (*orderConfig, [][]byte, error) { +func (c *cdnHTTP) get(ctx context.Context) (*orderConfig, [][]byte, error) { agentConfigUpdate, err := c.client.GetCDNConfigUpdate( ctx, []string{"AGENT_CONFIG"}, diff --git a/pkg/fleet/internal/cdn/cdn_local.go b/pkg/fleet/internal/cdn/cdn_local.go index b6fc898bca66d..b70e0c4499dd8 100644 --- a/pkg/fleet/internal/cdn/cdn_local.go +++ b/pkg/fleet/internal/cdn/cdn_local.go @@ -19,8 +19,8 @@ type cdnLocal struct { dirPath string } -// newLocal creates a new local CDN. -func newLocal(env *env.Env) (CDN, error) { +// newCDNLocal creates a new local CDN. +func newCDNLocal(env *env.Env) (CDN, error) { return &cdnLocal{ dirPath: env.CDNLocalDirPath, }, nil diff --git a/pkg/fleet/internal/cdn/cdn_noop.go b/pkg/fleet/internal/cdn/cdn_noop.go index 8c4377bb97d14..b18e0e788c011 100644 --- a/pkg/fleet/internal/cdn/cdn_noop.go +++ b/pkg/fleet/internal/cdn/cdn_noop.go @@ -7,6 +7,8 @@ package cdn import ( "context" + + "github.com/DataDog/datadog-agent/pkg/util/log" ) type cdnNoop struct { @@ -14,24 +16,28 @@ type cdnNoop struct { type configNoop struct{} -// newNoop creates a new noop CDN. -func newNoop() (CDN, error) { +// newCDNNoop creates a new noop CDN. +func newCDNNoop() (CDN, error) { return &cdnNoop{}, nil } // Get gets the configuration from the CDN. func (c *cdnNoop) Get(_ context.Context, _ string) (Config, error) { + log.Debug("Noop CDN get") return &configNoop{}, nil } func (c *cdnNoop) Close() error { + log.Debug("Noop CDN close") return nil } func (c *configNoop) Version() string { + log.Debug("Noop CDN version") return "" } func (c *configNoop) Write(_ string) error { + log.Debug("Noop CDN write") return nil } diff --git a/pkg/fleet/internal/cdn/cdn_direct.go b/pkg/fleet/internal/cdn/cdn_rc.go similarity index 93% rename from pkg/fleet/internal/cdn/cdn_direct.go rename to pkg/fleet/internal/cdn/cdn_rc.go index 4f8a1be155f10..de3d21c1f11a7 100644 --- a/pkg/fleet/internal/cdn/cdn_direct.go +++ b/pkg/fleet/internal/cdn/cdn_rc.go @@ -25,7 +25,7 @@ import ( "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" ) -type cdnDirect struct { +type cdnRC struct { rcService *remoteconfig.CoreAgentService currentRootsVersion uint64 clientUUID string @@ -33,9 +33,9 @@ type cdnDirect struct { firstRequest bool } -// newDirect creates a new direct CDN: it fetches the configuration from the remote config service instead of cloudfront +// newCDNRC creates a new CDN with RC: it fetches the configuration from the remote config service instead of cloudfront // note: naming is a bit misleading, it's not really a cdn, but we're following the convention -func newDirect(env *env.Env, configDBPath string) (CDN, error) { +func newCDNRC(env *env.Env, configDBPath string) (CDN, error) { ctx := context.Background() ctx, cc := context.WithTimeout(ctx, 10*time.Second) defer cc() @@ -78,7 +78,7 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { if err != nil { return nil, err } - cdn := &cdnDirect{ + cdn := &cdnRC{ rcService: service, currentRootsVersion: 1, clientUUID: uuid.New().String(), @@ -89,7 +89,7 @@ func newDirect(env *env.Env, configDBPath string) (CDN, error) { return cdn, nil } -func (c *cdnDirect) Get(ctx context.Context, pkg string) (cfg Config, err error) { +func (c *cdnRC) Get(ctx context.Context, pkg string) (cfg Config, err error) { span, _ := tracer.StartSpanFromContext(ctx, "cdn.Get") span.SetTag("cdn_type", "remote_config") defer func() { span.Finish(tracer.WithError(err)) }() @@ -112,7 +112,7 @@ func (c *cdnDirect) Get(ctx context.Context, pkg string) (cfg Config, err error) } // get calls the Remote Config service to get the ordered layers. -func (c *cdnDirect) get(ctx context.Context) (*orderConfig, [][]byte, error) { +func (c *cdnRC) get(ctx context.Context) (*orderConfig, [][]byte, error) { if c.firstRequest { // A first request is made to the remote config service at service startup, // so if we do another request too close to the first one (in the same second) @@ -191,7 +191,7 @@ func (c *cdnDirect) get(ctx context.Context) (*orderConfig, [][]byte, error) { return configOrder, configLayers, nil } -func (c *cdnDirect) Close() error { +func (c *cdnRC) Close() error { err := c.rcService.Stop() if err != nil { return err