Skip to content

Commit 0c47747

Browse files
authored
[Ingest Manager] Use long polling for agent checkin (#68922)
1 parent 550b95f commit 0c47747

File tree

23 files changed

+534
-353
lines changed

23 files changed

+534
-353
lines changed

x-pack/plugins/ingest_manager/common/constants/agent.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ export const AGENT_TYPE_TEMPORARY = 'TEMPORARY';
1414

1515
export const AGENT_POLLING_THRESHOLD_MS = 30000;
1616
export const AGENT_POLLING_INTERVAL = 1000;
17+
export const AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS = 30000;
18+
export const AGENT_UPDATE_ACTIONS_INTERVAL_MS = 5000;

x-pack/plugins/ingest_manager/common/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface IngestManagerConfigType {
1515
fleet: {
1616
enabled: boolean;
1717
tlsCheckDisabled: boolean;
18+
pollingRequestTimeout: number;
1819
kibana: {
1920
host?: string;
2021
ca_sha256?: string;

x-pack/plugins/ingest_manager/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
"name": "ingest-manager",
44
"version": "8.0.0",
55
"private": true,
6-
"license": "Elastic-License"
6+
"license": "Elastic-License",
7+
"dependencies": {
8+
"abort-controller": "^3.0.0"
9+
}
710
}

x-pack/plugins/ingest_manager/server/constants/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export {
99
AGENT_TYPE_TEMPORARY,
1010
AGENT_POLLING_THRESHOLD_MS,
1111
AGENT_POLLING_INTERVAL,
12+
AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS,
13+
AGENT_UPDATE_ACTIONS_INTERVAL_MS,
1214
INDEX_PATTERN_PLACEHOLDER_SUFFIX,
1315
// Routes
1416
PLUGIN_ID,

x-pack/plugins/ingest_manager/server/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const config = {
2727
fleet: schema.object({
2828
enabled: schema.boolean({ defaultValue: true }),
2929
tlsCheckDisabled: schema.boolean({ defaultValue: false }),
30+
pollingRequestTimeout: schema.number({ defaultValue: 60000 }),
3031
kibana: schema.object({
3132
host: schema.maybe(schema.string()),
3233
ca_sha256: schema.maybe(schema.string()),

x-pack/plugins/ingest_manager/server/plugin.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
} from './services';
5656
import { getAgentStatusById } from './services/agents';
5757
import { CloudSetup } from '../../cloud/server';
58+
import { agentCheckinState } from './services/agents/checkin/state';
5859

5960
export interface IngestManagerSetupDeps {
6061
licensing: LicensingPluginSetup;
@@ -229,6 +230,8 @@ export class IngestManagerPlugin
229230
logger: this.logger,
230231
});
231232
licenseService.start(this.licensing$);
233+
agentCheckinState.start();
234+
232235
return {
233236
esIndexPatternService: new ESIndexPatternSavedObjectService(),
234237
agentService: {
@@ -240,5 +243,6 @@ export class IngestManagerPlugin
240243
public async stop() {
241244
appContextService.stop();
242245
licenseService.stop();
246+
agentCheckinState.stop();
243247
}
244248
}

x-pack/plugins/ingest_manager/server/routes/agent/handlers.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { RequestHandler, KibanaRequest } from 'src/core/server';
7+
import { RequestHandler } from 'src/core/server';
88
import { TypeOf } from '@kbn/config-schema';
9+
import { AbortController } from 'abort-controller';
910
import {
1011
GetAgentsResponse,
1112
GetOneAgentResponse,
@@ -32,13 +33,6 @@ import * as AgentService from '../../services/agents';
3233
import * as APIKeyService from '../../services/api_keys';
3334
import { appContextService } from '../../services/app_context';
3435

35-
export function getInternalUserSOClient(request: KibanaRequest) {
36-
// soClient as kibana internal users, be carefull on how you use it, security is not enabled
37-
return appContextService.getSavedObjects().getScopedClient(request, {
38-
excludedWrappers: ['security'],
39-
});
40-
}
41-
4236
export const getAgentHandler: RequestHandler<TypeOf<
4337
typeof GetOneAgentRequestSchema.params
4438
>> = async (context, request, response) => {
@@ -176,14 +170,20 @@ export const postAgentCheckinHandler: RequestHandler<
176170
TypeOf<typeof PostAgentCheckinRequestSchema.body>
177171
> = async (context, request, response) => {
178172
try {
179-
const soClient = getInternalUserSOClient(request);
173+
const soClient = appContextService.getInternalUserSOClient(request);
180174
const res = APIKeyService.parseApiKeyFromHeaders(request.headers);
181175
const agent = await AgentService.getAgentByAccessAPIKeyId(soClient, res.apiKeyId);
176+
const abortController = new AbortController();
177+
request.events.aborted$.subscribe(() => {
178+
abortController.abort();
179+
});
180+
const signal = abortController.signal;
182181
const { actions } = await AgentService.agentCheckin(
183182
soClient,
184183
agent,
185184
request.body.events || [],
186-
request.body.local_metadata
185+
request.body.local_metadata,
186+
{ signal }
187187
);
188188
const body: PostAgentCheckinResponse = {
189189
action: 'checkin',
@@ -198,16 +198,24 @@ export const postAgentCheckinHandler: RequestHandler<
198198
};
199199

200200
return response.ok({ body });
201-
} catch (e) {
202-
if (e.isBoom && e.output.statusCode === 404) {
203-
return response.notFound({
204-
body: { message: `Agent ${request.params.agentId} not found` },
201+
} catch (err) {
202+
const logger = appContextService.getLogger();
203+
if (err.isBoom) {
204+
if (err.output.statusCode >= 500) {
205+
logger.error(err);
206+
}
207+
208+
return response.customError({
209+
statusCode: err.output.statusCode,
210+
body: { message: err.output.payload.message },
205211
});
206212
}
207213

214+
logger.error(err);
215+
208216
return response.customError({
209217
statusCode: 500,
210-
body: { message: e.message },
218+
body: { message: err.message },
211219
});
212220
}
213221
};
@@ -218,7 +226,7 @@ export const postAgentEnrollHandler: RequestHandler<
218226
TypeOf<typeof PostAgentEnrollRequestSchema.body>
219227
> = async (context, request, response) => {
220228
try {
221-
const soClient = getInternalUserSOClient(request);
229+
const soClient = appContextService.getInternalUserSOClient(request);
222230
const { apiKeyId } = APIKeyService.parseApiKeyFromHeaders(request.headers);
223231
const enrollmentAPIKey = await APIKeyService.getEnrollmentAPIKeyById(soClient, apiKeyId);
224232

x-pack/plugins/ingest_manager/server/routes/agent/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ import {
3535
postAgentEnrollHandler,
3636
postAgentsUnenrollHandler,
3737
getAgentStatusForConfigHandler,
38-
getInternalUserSOClient,
3938
putAgentsReassignHandler,
4039
} from './handlers';
4140
import { postAgentAcksHandlerBuilder } from './acks_handlers';
4241
import * as AgentService from '../../services/agents';
4342
import { postNewAgentActionHandlerBuilder } from './actions_handlers';
43+
import { appContextService } from '../../services';
4444

4545
export const registerRoutes = (router: IRouter) => {
4646
// Get one
@@ -110,7 +110,9 @@ export const registerRoutes = (router: IRouter) => {
110110
postAgentAcksHandlerBuilder({
111111
acknowledgeAgentActions: AgentService.acknowledgeAgentActions,
112112
getAgentByAccessAPIKeyId: AgentService.getAgentByAccessAPIKeyId,
113-
getSavedObjectsClientContract: getInternalUserSOClient,
113+
getSavedObjectsClientContract: appContextService.getInternalUserSOClient.bind(
114+
appContextService
115+
),
114116
saveAgentEvents: AgentService.saveAgentEvents,
115117
})
116118
);

x-pack/plugins/ingest_manager/server/services/agent_config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ class AgentConfigService {
6565
updated_by: user ? user.username : 'system',
6666
});
6767

68-
await this.triggerAgentConfigUpdatedEvent(soClient, 'updated', id);
69-
7068
return (await this.get(soClient, id)) as AgentConfig;
7169
}
7270

x-pack/plugins/ingest_manager/server/services/agents/actions.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ export async function getAgentActionByIds(
7777
);
7878
}
7979

80+
export async function getNewActionsSince(soClient: SavedObjectsClientContract, timestamp: string) {
81+
const res = await soClient.find<AgentActionSOAttributes>({
82+
type: AGENT_ACTION_SAVED_OBJECT_TYPE,
83+
filter: `not ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.sent_at: * AND ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.created_at >= "${timestamp}"`,
84+
});
85+
86+
return res.saved_objects.map(savedObjectToAgentAction);
87+
}
88+
8089
export interface ActionsService {
8190
getAgent: (soClient: SavedObjectsClientContract, agentId: string) => Promise<Agent>;
8291

0 commit comments

Comments
 (0)