Skip to content

Commit e9908f2

Browse files
jillguyonnetkibanamachineelasticmachine
authored andcommitted
[Fleet] Add task for automatic agent upgrades (elastic#211019)
Closes elastic/ingest-dev#4722 - [x] Handle fetching agent policies and agents at scale - [x] Only consider active agents for upgrade - [x] Agents already on or upgrading to target version are included in the count but not considered for upgrade - [x] Agents stuck in updating are considered for upgrade - [x] Bulk upgrade actions triggered by the task have an added `isAutomatic:true` flag - [x] Use rollout duration to spread bulk upgrade in time (1h or longer depending on agent count) - This should be tested with real Elastic Agents (that will upgrade and have `upgrade_details`). - Edit the task interval in order to test how the task logic handles agents already upgrading. - Edit the agents batch size in order to test how the task logic handles agents at scale. - We should also check that space awareness is respected if enabled. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) Risk of incorrectly triggering agent upgrades. Probability should be very low if the agent policy does not have `required_versions` set. --------- Co-authored-by: kibanamachine <[email protected]> Co-authored-by: Elastic Machine <[email protected]>
1 parent 16a0eb3 commit e9908f2

File tree

18 files changed

+983
-14
lines changed

18 files changed

+983
-14
lines changed

packages/kbn-check-mappings-update-cli/current_fields.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@
500500
"name",
501501
"namespace",
502502
"overrides",
503+
"required_versions",
503504
"revision",
504505
"schema_version",
505506
"status",
@@ -624,6 +625,7 @@
624625
"name",
625626
"namespace",
626627
"overrides",
628+
"required_versions",
627629
"revision",
628630
"schema_version",
629631
"status",

packages/kbn-check-mappings-update-cli/current_mappings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,10 @@
16851685
"index": false,
16861686
"type": "flattened"
16871687
},
1688+
"required_versions": {
1689+
"index": false,
1690+
"type": "flattened"
1691+
},
16881692
"revision": {
16891693
"type": "integer"
16901694
},
@@ -2071,6 +2075,10 @@
20712075
"index": false,
20722076
"type": "flattened"
20732077
},
2078+
"required_versions": {
2079+
"index": false,
2080+
"type": "flattened"
2081+
},
20742082
"revision": {
20752083
"type": "integer"
20762084
},

src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
105105
"file": "6b65ae5899b60ebe08656fd163ea532e557d3c98",
106106
"file-upload-usage-collection-telemetry": "06e0a8c04f991e744e09d03ab2bd7f86b2088200",
107107
"fileShare": "5be52de1747d249a221b5241af2838264e19aaa1",
108-
"fleet-agent-policies": "4a5c6477d2a61121e95ea9865ed1403a28c38706",
108+
"fleet-agent-policies": "f69f7c5639f4cf9e85077c904e161f3574ac3ca2",
109109
"fleet-fleet-server-host": "69be15f6b6f2a2875ad3c7050ddea7a87f505417",
110110
"fleet-message-signing-keys": "93421f43fed2526b59092a4e3c65d64bc2266c0f",
111111
"fleet-package-policies": "8173220091e28ff4afa8238bb37749599378f9e5",
@@ -121,7 +121,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
121121
"infra-custom-dashboards": "1a5994f2e05bb8a1609825ddbf5012f77c5c67f3",
122122
"infrastructure-monitoring-log-view": "5f86709d3c27aed7a8379153b08ee5d3d90d77f5",
123123
"infrastructure-ui-source": "113182d6895764378dfe7fa9fa027244f3a457c4",
124-
"ingest-agent-policies": "57ebfb047cf0b81c6fa0ceed8586fa7199c7c5e2",
124+
"ingest-agent-policies": "cfe66f4aeca8f53b26bd4ddb0e956de1637d774e",
125125
"ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d",
126126
"ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91",
127127
"ingest-package-policies": "870f8c21fe3602f31075430a1fdfb052c62d4a14",

x-pack/platform/plugins/shared/fleet/common/constants/agent.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ export const AgentStatuses = [
4848
'degraded',
4949
] as const;
5050

51+
export const ActiveAgentStatuses = [
52+
'online',
53+
'offline',
54+
'enrolling',
55+
'updating',
56+
'degraded',
57+
'error',
58+
'orphaned',
59+
]; // excluded: unenrolling, unenrolled, inactive, uninstalled
60+
5161
// Kueries for finding unprivileged and privileged agents
5262
// Privileged is `not` because the metadata field can be undefined
5363
export const UNPRIVILEGED_AGENT_KUERY = `${AGENTS_PREFIX}.local_metadata.elastic.agent.unprivileged: true`;

x-pack/platform/plugins/shared/fleet/common/services/agent_status.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* 2.0.
66
*/
77

8+
import { ActiveAgentStatuses } from '../constants';
89
import type { Agent, AgentStatus, FleetServerAgent } from '../types';
910

1011
export function getPreviousAgentStatusForOfflineAgents(
@@ -57,6 +58,10 @@ export function buildKueryForInactiveAgents() {
5758
return 'status:inactive';
5859
}
5960

61+
export function buildKueryForActiveAgents() {
62+
return `(${ActiveAgentStatuses.map((s) => `status:${s}`).join(' or ')})`;
63+
}
64+
6065
export const AGENT_UPDATING_TIMEOUT_HOURS = 2;
6166

6267
export function isStuckInUpdating(agent: Agent): boolean {

x-pack/platform/plugins/shared/fleet/common/types/models/agent.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export interface NewAgentAction {
7070
rollout_duration_seconds?: number;
7171
source_uri?: string;
7272
total?: number;
73+
is_automatic?: boolean;
7374
}
7475

7576
export interface AgentAction extends NewAgentAction {
@@ -444,6 +445,11 @@ export interface FleetServerAgentAction {
444445
signature: string;
445446
};
446447

448+
/**
449+
* True if action was generated by an automated task.
450+
*/
451+
is_automatic?: boolean;
452+
447453
[k: string]: unknown;
448454
}
449455

x-pack/platform/plugins/shared/fleet/server/mocks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ export const createAppContextStartContractMock = (
143143
unenrollInactiveAgentsTask: {} as any,
144144
deleteUnenrolledAgentsTask: {} as any,
145145
updateAgentlessDeploymentsTask: {} as any,
146+
automaticAgentUpgradeTask: {} as any,
146147
};
147148
};
148149

x-pack/platform/plugins/shared/fleet/server/plugin.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ import { registerDeployAgentPoliciesTask } from './services/agent_policies/deplo
147147
import { DeleteUnenrolledAgentsTask } from './tasks/delete_unenrolled_agents_task';
148148
import { registerBumpAgentPoliciesTask } from './services/agent_policies/bump_agent_policies_task';
149149
import { UpgradeAgentlessDeploymentsTask } from './tasks/upgrade_agentless_deployment';
150+
import { AutomaticAgentUpgradeTask } from './tasks/automatic_agent_upgrade_task';
150151

151152
export interface FleetSetupDeps {
152153
security: SecurityPluginSetup;
@@ -199,6 +200,7 @@ export interface FleetAppContext {
199200
unenrollInactiveAgentsTask: UnenrollInactiveAgentsTask;
200201
deleteUnenrolledAgentsTask: DeleteUnenrolledAgentsTask;
201202
updateAgentlessDeploymentsTask: UpgradeAgentlessDeploymentsTask;
203+
automaticAgentUpgradeTask: AutomaticAgentUpgradeTask;
202204
taskManagerStart?: TaskManagerStartContract;
203205
}
204206

@@ -299,6 +301,7 @@ export class FleetPlugin
299301
private unenrollInactiveAgentsTask?: UnenrollInactiveAgentsTask;
300302
private deleteUnenrolledAgentsTask?: DeleteUnenrolledAgentsTask;
301303
private updateAgentlessDeploymentsTask?: UpgradeAgentlessDeploymentsTask;
304+
private automaticAgentUpgradeTask?: AutomaticAgentUpgradeTask;
302305

303306
private agentService?: AgentService;
304307
private packageService?: PackageService;
@@ -628,7 +631,7 @@ export class FleetPlugin
628631
registerRoutes(fleetAuthzRouter, config);
629632

630633
this.telemetryEventsSender.setup(deps.telemetry);
631-
// Register task
634+
// Register tasks
632635
registerUpgradeManagedPackagePoliciesTask(deps.taskManager);
633636
registerDeployAgentPoliciesTask(deps.taskManager);
634637
registerBumpAgentPoliciesTask(deps.taskManager);
@@ -654,6 +657,11 @@ export class FleetPlugin
654657
taskManager: deps.taskManager,
655658
logFactory: this.initializerContext.logger,
656659
});
660+
this.automaticAgentUpgradeTask = new AutomaticAgentUpgradeTask({
661+
core,
662+
taskManager: deps.taskManager,
663+
logFactory: this.initializerContext.logger,
664+
});
657665

658666
// Register fields metadata extractors
659667
registerFieldsMetadataExtractors({ core, fieldsMetadata: deps.fieldsMetadata });
@@ -702,6 +710,7 @@ export class FleetPlugin
702710
unenrollInactiveAgentsTask: this.unenrollInactiveAgentsTask!,
703711
deleteUnenrolledAgentsTask: this.deleteUnenrolledAgentsTask!,
704712
updateAgentlessDeploymentsTask: this.updateAgentlessDeploymentsTask!,
713+
automaticAgentUpgradeTask: this.automaticAgentUpgradeTask!,
705714
taskManagerStart: plugins.taskManager,
706715
});
707716
licenseService.start(plugins.licensing.license$);
@@ -714,7 +723,7 @@ export class FleetPlugin
714723
this.updateAgentlessDeploymentsTask
715724
?.start({ taskManager: plugins.taskManager })
716725
.catch(() => {});
717-
726+
this.automaticAgentUpgradeTask?.start({ taskManager: plugins.taskManager }).catch(() => {});
718727
startFleetUsageLogger(plugins.taskManager).catch(() => {});
719728
this.fleetMetricsTask
720729
?.start(plugins.taskManager, core.elasticsearch.client.asInternalUser)

x-pack/platform/plugins/shared/fleet/server/saved_objects/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ export const getSavedObjectTypes = (
254254
monitoring_pprof_enabled: { type: 'boolean', index: false },
255255
monitoring_http: { type: 'flattened', index: false },
256256
monitoring_diagnostics: { type: 'flattened', index: false },
257+
required_versions: { type: 'flattened', index: false },
257258
},
258259
},
259260
migrations: {
@@ -331,6 +332,16 @@ export const getSavedObjectTypes = (
331332
},
332333
],
333334
},
335+
'7': {
336+
changes: [
337+
{
338+
type: 'mappings_addition',
339+
addedMappings: {
340+
required_versions: { type: 'flattened', index: false },
341+
},
342+
},
343+
],
344+
},
334345
},
335346
},
336347
[AGENT_POLICY_SAVED_OBJECT_TYPE]: {
@@ -379,6 +390,7 @@ export const getSavedObjectTypes = (
379390
dynamic: false,
380391
properties: {},
381392
},
393+
required_versions: { type: 'flattened', index: false },
382394
},
383395
},
384396
modelVersions: {
@@ -390,6 +402,16 @@ export const getSavedObjectTypes = (
390402
},
391403
],
392404
},
405+
'2': {
406+
changes: [
407+
{
408+
type: 'mappings_addition',
409+
addedMappings: {
410+
required_versions: { type: 'flattened', index: false },
411+
},
412+
},
413+
],
414+
},
393415
},
394416
},
395417
[OUTPUT_SAVED_OBJECT_TYPE]: {

x-pack/platform/plugins/shared/fleet/server/services/agents/actions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export async function createAgentAction(
6464
rollout_duration_seconds: newAgentAction.rollout_duration_seconds,
6565
total: newAgentAction.total,
6666
traceparent: apm.currentTraceparent,
67+
is_automatic: newAgentAction.is_automatic,
6768
};
6869

6970
const messageSigningService = appContextService.getMessageSigningService();

0 commit comments

Comments
 (0)