Skip to content

Commit 8bbe15c

Browse files
Add agent_policy_id and policy_revision_idx to checkin requests
Add the agent_policy_id and policy_revision_idx attributes to checkin requests.
1 parent 7c3157b commit 8bbe15c

File tree

4 files changed

+163
-12
lines changed

4 files changed

+163
-12
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: feature
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: Add agent_policy_id and policy_revision_idx to checkin requests
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
description: |
20+
Add agent_policy_id and policy_revision_idx attributes to checkin requests.
21+
These attributes are used to inform fleet-server of the policy id and revision that the agent is currently running.
22+
Agents that use these policies no longer need to send acks for POLICY_CHANGE actions.
23+
24+
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
25+
component: elastic-agent
26+
27+
# PR URL; optional; the PR number that added the changeset.
28+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
29+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
30+
# Please provide it if you are adding a fragment for a different PR.
31+
#pr: https://github.com/owner/repo/1234
32+
33+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
34+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
35+
issue: https://github.com/elastic/elastic-agent/issues/6446

internal/pkg/agent/application/gateway/fleet/fleet_gateway.go

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ type stateStore interface {
7171
AckToken() string
7272
SetAckToken(ackToken string)
7373
Save() error
74+
Action() fleetapi.Action
7475
}
7576

7677
type FleetGateway struct {
@@ -356,15 +357,20 @@ func (f *FleetGateway) execute(ctx context.Context) (*fleetapi.CheckinResponse,
356357
// Fix loglevel with the current log level used by coordinator
357358
ecsMeta.Elastic.Agent.LogLevel = state.LogLevel.String()
358359

360+
agentPolicyID := getPolicyID(f.stateStore.Action())
361+
policyRevisionIDX := getPolicyRevisionIDX(f.stateStore.Action())
362+
359363
// checkin
360364
cmd := fleetapi.NewCheckinCmd(f.agentInfo, f.client)
361365
req := &fleetapi.CheckinRequest{
362-
AckToken: ackToken,
363-
Metadata: ecsMeta,
364-
Status: agentStateToString(state.State),
365-
Message: state.Message,
366-
Components: components,
367-
UpgradeDetails: state.UpgradeDetails,
366+
AckToken: ackToken,
367+
Metadata: ecsMeta,
368+
Status: agentStateToString(state.State),
369+
Message: state.Message,
370+
Components: components,
371+
UpgradeDetails: state.UpgradeDetails,
372+
AgentPolicyID: agentPolicyID,
373+
PolicyRevisionIDX: policyRevisionIDX,
368374
}
369375

370376
resp, took, err := cmd.Execute(ctx, req)
@@ -447,3 +453,43 @@ func RequestBackoff(done <-chan struct{}) backoff.Backoff {
447453
defaultFleetBackoffSettings.Max,
448454
)
449455
}
456+
457+
// getPolicyID will check that the passed action is a POLICY_CHANGE action and return the policy_id attribute of the policy as a string.
458+
func getPolicyID(action fleetapi.Action) string {
459+
policyChange, ok := action.(*fleetapi.ActionPolicyChange)
460+
if !ok {
461+
return ""
462+
}
463+
v, ok := policyChange.Data.Policy["policy_id"]
464+
if !ok {
465+
return ""
466+
}
467+
vv, ok := v.(string)
468+
if !ok {
469+
return ""
470+
}
471+
return vv
472+
}
473+
474+
// getPolicyRevisionIDX will check that the passed action is a POLICY_CHANGE action and return the policy_revision_idx attribute of the policy as an int64.
475+
// The function will attempt to convert the attribute to int64 if int or float64 is used in order to prevent issues from serialization.
476+
func getPolicyRevisionIDX(action fleetapi.Action) int64 {
477+
policyChange, ok := action.(*fleetapi.ActionPolicyChange)
478+
if !ok {
479+
return 0
480+
}
481+
v, ok := policyChange.Data.Policy["policy_revision_idx"]
482+
if !ok {
483+
return 0
484+
}
485+
switch vv := v.(type) {
486+
case int64:
487+
return vv
488+
case int:
489+
return int64(vv)
490+
case float64:
491+
return int64(vv)
492+
default:
493+
return 0
494+
}
495+
}

internal/pkg/agent/application/gateway/fleet/fleet_gateway_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,74 @@ func TestFleetGateway(t *testing.T) {
377377
default:
378378
}
379379
})
380+
381+
t.Run("sends agent_policy_id and policy_revision_idx", func(t *testing.T) {
382+
ctx, cancel := context.WithCancel(t.Context())
383+
defer cancel()
384+
385+
scheduler := scheduler.NewStepper()
386+
client := newTestingClient()
387+
388+
log, _ := loggertest.New("fleet_gateway")
389+
390+
stateStore := newStateStore(t, log)
391+
stateStore.SetAction(&fleetapi.ActionPolicyChange{
392+
ActionID: "test-action-id",
393+
ActionType: fleetapi.ActionTypePolicyChange,
394+
Data: fleetapi.ActionPolicyChangeData{
395+
Policy: map[string]interface{}{
396+
"policy_id": "test-policy-id",
397+
"policy_revision_idx": 1,
398+
},
399+
},
400+
})
401+
err := stateStore.Save()
402+
require.NoError(t, err)
403+
404+
gateway, err := newFleetGatewayWithScheduler(
405+
log,
406+
settings,
407+
agentInfo,
408+
client,
409+
scheduler,
410+
noop.New(),
411+
emptyStateFetcher,
412+
stateStore,
413+
)
414+
require.NoError(t, err)
415+
416+
waitFn := ackSeq(
417+
client.Answer(func(headers http.Header, body io.Reader) (*http.Response, error) {
418+
data, err := io.ReadAll(body)
419+
require.NoError(t, err)
420+
421+
var checkinRequest fleetapi.CheckinRequest
422+
err = json.Unmarshal(data, &checkinRequest)
423+
require.NoError(t, err)
424+
425+
require.Equal(t, "test-policy-id", checkinRequest.AgentPolicyID)
426+
require.Equal(t, int64(1), checkinRequest.PolicyRevisionIDX)
427+
428+
resp := wrapStrToResp(http.StatusOK, `{ "actions": [] }`)
429+
return resp, nil
430+
}),
431+
)
432+
433+
errCh := runFleetGateway(ctx, gateway)
434+
435+
// Synchronize scheduler and acking of calls from the worker go routine.
436+
scheduler.Next()
437+
waitFn()
438+
439+
cancel()
440+
err = <-errCh
441+
require.NoError(t, err)
442+
select {
443+
case actions := <-gateway.Actions():
444+
t.Errorf("Expected no actions, got %v", actions)
445+
default:
446+
}
447+
})
380448
}
381449

382450
func TestRetriesOnFailures(t *testing.T) {

internal/pkg/fleetapi/checkin_cmd.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,14 @@ type CheckinComponent struct {
4141

4242
// CheckinRequest consists of multiple events reported to fleet ui.
4343
type CheckinRequest struct {
44-
Status string `json:"status"`
45-
AckToken string `json:"ack_token,omitempty"`
46-
Metadata *info.ECSMeta `json:"local_metadata,omitempty"`
47-
Message string `json:"message"` // V2 Agent message
48-
Components []CheckinComponent `json:"components"` // V2 Agent components
49-
UpgradeDetails *details.Details `json:"upgrade_details,omitempty"`
44+
Status string `json:"status"`
45+
AckToken string `json:"ack_token,omitempty"`
46+
Metadata *info.ECSMeta `json:"local_metadata,omitempty"`
47+
Message string `json:"message"` // V2 Agent message
48+
Components []CheckinComponent `json:"components"` // V2 Agent components
49+
UpgradeDetails *details.Details `json:"upgrade_details,omitempty"`
50+
AgentPolicyID string `json:"agent_policy_id,omitempty"`
51+
PolicyRevisionIDX int64 `json:"policy_revision_idx,omitempty"`
5052
}
5153

5254
// SerializableEvent is a representation of the event to be send to the Fleet Server API via the checkin

0 commit comments

Comments
 (0)