Skip to content

Commit 1d5cd3b

Browse files
committed
wip
1 parent 863185f commit 1d5cd3b

File tree

2 files changed

+68
-7
lines changed

2 files changed

+68
-7
lines changed

cmd/cluster-agent/subcommands/start/command.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ func start(log log.Component,
430430
products = append(products, state.ProductGradualRollout)
431431
}
432432
// Add private action runner product if enabled
433-
if config.GetBool("privateactionrunner.enabled") {
433+
if config.GetBool("private_action_runner.enabled") {
434434
products = append(products, state.ProductActionPlatformRunnerKeys)
435435
}
436436

@@ -550,7 +550,7 @@ func start(log log.Component,
550550
appsec.Cleanup(mainCtx, log, config, le.Subscribe)
551551
}
552552

553-
if config.GetBool("privateactionrunner.enabled") {
553+
if config.GetBool("private_action_runner.enabled") {
554554
drain, err := startPrivateActionRunner(mainCtx, config, hostnameGetter, rcClient, log)
555555
if err != nil {
556556
log.Errorf("Cannot start private action runner: %v", err)

pkg/privateactionrunner/enrollment/k8s_secret.go

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ import (
1212
"encoding/base64"
1313
"errors"
1414
"fmt"
15+
"time"
1516

1617
configModel "github.com/DataDog/datadog-agent/pkg/config/model"
1718
"github.com/DataDog/datadog-agent/pkg/config/setup"
1819
log "github.com/DataDog/datadog-agent/pkg/privateactionrunner/adapters/logging"
1920
"github.com/DataDog/datadog-agent/pkg/privateactionrunner/util"
2021
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/apiserver"
2122
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/apiserver/common/namespace"
23+
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/apiserver/leaderelection"
2224

2325
corev1 "k8s.io/api/core/v1"
2426
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -27,9 +29,11 @@ import (
2729
)
2830

2931
const (
30-
defaultSecretName = "private-action-runner-identity"
31-
privateKeyField = "private_key"
32-
urnField = "urn"
32+
defaultSecretName = "private-action-runner-identity"
33+
privateKeyField = "private_key"
34+
urnField = "urn"
35+
secretWaitTimeout = 5 * time.Minute
36+
secretWaitPollInterval = 5 * time.Second
3337
)
3438

3539
// getIdentityFromK8sSecret retrieves PAR identity from a Kubernetes secret
@@ -42,12 +46,28 @@ func getIdentityFromK8sSecret(ctx context.Context, cfg configModel.Reader) (*Per
4246
ns := namespace.GetResourcesNamespace()
4347
secretName := getSecretName(cfg)
4448

49+
// Check if we're a follower - if so, we may need to wait for leader to create the secret
50+
le, err := leaderelection.GetLeaderEngine()
51+
isFollower := err == nil && !le.IsLeader()
52+
4553
secret, err := client.CoreV1().Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
4654
if err != nil {
4755
if k8serrors.IsNotFound(err) {
48-
return nil, nil
56+
// If we're a follower and secret doesn't exist, wait for leader to create it
57+
if isFollower {
58+
log.Info("Follower replica: waiting for leader to create PAR identity secret")
59+
secret, err = waitForSecretCreation(ctx, client, ns, secretName)
60+
if err != nil {
61+
return nil, err
62+
}
63+
// Continue to parse the secret below
64+
} else {
65+
// Leader or no leader election - return nil to trigger self-enrollment
66+
return nil, nil
67+
}
68+
} else {
69+
return nil, fmt.Errorf("failed to get identity secret: %w", err)
4970
}
50-
return nil, fmt.Errorf("failed to get identity secret: %w", err)
5171
}
5272

5373
privateKey, ok := secret.Data[privateKeyField]
@@ -70,6 +90,18 @@ func getIdentityFromK8sSecret(ctx context.Context, cfg configModel.Reader) (*Per
7090

7191
// persistIdentityToK8sSecret saves the enrollment result to a Kubernetes secret
7292
func persistIdentityToK8sSecret(ctx context.Context, cfg configModel.Reader, result *Result) error {
93+
// Check if this replica is the leader before creating the secret
94+
le, err := leaderelection.GetLeaderEngine()
95+
if err != nil {
96+
log.Warnf("Failed to get leader engine, proceeding without leader check: %v", err)
97+
// Fall through to create secret anyway if leader election is not available
98+
} else if !le.IsLeader() {
99+
log.Info("Not leader, skipping PAR identity secret creation (leader will handle it)")
100+
return nil
101+
}
102+
103+
log.Info("Leader replica: persisting PAR identity to K8s secret")
104+
73105
client, err := getKubeClient()
74106
if err != nil {
75107
return err
@@ -139,3 +171,32 @@ func getSecretName(cfg configModel.Reader) string {
139171
}
140172
return defaultSecretName
141173
}
174+
175+
// waitForSecretCreation waits for the leader to create the PAR identity secret
176+
func waitForSecretCreation(ctx context.Context, client kubernetes.Interface, ns, secretName string) (*corev1.Secret, error) {
177+
deadline := time.Now().Add(secretWaitTimeout)
178+
ticker := time.NewTicker(secretWaitPollInterval)
179+
defer ticker.Stop()
180+
181+
for {
182+
select {
183+
case <-ctx.Done():
184+
return nil, fmt.Errorf("context cancelled while waiting for secret: %w", ctx.Err())
185+
case <-ticker.C:
186+
if time.Now().After(deadline) {
187+
return nil, fmt.Errorf("timeout waiting for leader to create secret %s/%s after %v", ns, secretName, secretWaitTimeout)
188+
}
189+
190+
secret, err := client.CoreV1().Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
191+
if err == nil {
192+
log.Infof("Follower replica: found PAR identity secret created by leader: %s/%s", ns, secretName)
193+
return secret, nil
194+
}
195+
196+
if !k8serrors.IsNotFound(err) {
197+
return nil, fmt.Errorf("error checking for secret: %w", err)
198+
}
199+
// Secret still not found, continue waiting
200+
}
201+
}
202+
}

0 commit comments

Comments
 (0)