"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports._buildStatusRuntimeField = _buildStatusRuntimeField; exports.buildAgentStatusRuntimeField = buildAgentStatusRuntimeField; var _constants = require("../../../common/constants"); var _constants2 = require("../../constants"); var _agent_policy = require("../agent_policy"); var _app_context = require("../app_context"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ const MISSED_INTERVALS_BEFORE_OFFLINE = 10; const MS_BEFORE_OFFLINE = MISSED_INTERVALS_BEFORE_OFFLINE * _constants2.AGENT_POLLING_THRESHOLD_MS; let inactivityTimeoutsDisabled = false; const _buildInactiveCondition = opts => { const { now, inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout, field, logger } = opts; // if there are no policies with inactivity timeouts, then no agents are inactive if (inactivityTimeouts.length === 0) { return null; } const totalAgentPoliciesWithInactivityTimeouts = inactivityTimeouts.reduce((total, { policyIds }) => total + policyIds.length, 0); // if too many agent policies have inactivity timeouts, then we can't use the inactivity timeout // as the query becomes too large see github.com/elastic/kibana/issues/150577 if (totalAgentPoliciesWithInactivityTimeouts > maxAgentPoliciesWithInactivityTimeout) { if (!inactivityTimeoutsDisabled) { // only log this once as this function is executed a lot logger === null || logger === void 0 ? void 0 : logger.warn(`There are ${totalAgentPoliciesWithInactivityTimeouts} agent policies with an inactivity timeout set but the maximum allowed is ${maxAgentPoliciesWithInactivityTimeout}. Agents will not be marked as inactive.`); inactivityTimeoutsDisabled = true; } return null; } if (inactivityTimeoutsDisabled) { logger === null || logger === void 0 ? void 0 : logger.info(`There are ${totalAgentPoliciesWithInactivityTimeouts} agent policies which is now below the maximum allowed of ${maxAgentPoliciesWithInactivityTimeout}. Agents will now be marked as inactive again.`); inactivityTimeoutsDisabled = false; } const policyClauses = inactivityTimeouts.map(({ inactivityTimeout, policyIds }) => { const inactivityTimeoutMs = inactivityTimeout * 1000; const policyIdMatches = `[${policyIds.map(id => `'${id}'`).join(',')}].contains(${field('policy_id')}.value)`; return `${policyIdMatches} && lastCheckinMillis < ${now - inactivityTimeoutMs}L`; }).join(' || '); return `lastCheckinMillis > 0 && ${field('policy_id')}.size() > 0 && ${policyClauses}`; }; function _buildSource(inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout, pathPrefix, logger) { const normalizedPrefix = pathPrefix ? `${pathPrefix}${pathPrefix.endsWith('.') ? '' : '.'}` : ''; const field = path => `doc['${normalizedPrefix + path}']`; const now = Date.now(); const agentIsInactiveCondition = _buildInactiveCondition({ now, inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout, field, logger }); return ` long lastCheckinMillis = ${field('last_checkin')}.size() > 0 ? ${field('last_checkin')}.value.toInstant().toEpochMilli() : ( ${field('enrolled_at')}.size() > 0 ? ${field('enrolled_at')}.value.toInstant().toEpochMilli() : -1 ); if (${field('active')}.size() > 0 && ${field('active')}.value == false) { emit('unenrolled'); } ${agentIsInactiveCondition ? `else if (${agentIsInactiveCondition}) {emit('inactive');}` : ''} else if ( lastCheckinMillis > 0 && lastCheckinMillis < ${now - MS_BEFORE_OFFLINE}L ) { emit('offline'); } else if ( ${field('policy_revision_idx')}.size() == 0 || ( ${field('upgrade_started_at')}.size() > 0 && ${field('upgraded_at')}.size() == 0 ) ) { emit('updating'); } else if (${field('last_checkin')}.size() == 0) { emit('enrolling'); } else if (${field('unenrollment_started_at')}.size() > 0) { emit('unenrolling'); } else if ( ${field('last_checkin_status')}.size() > 0 && ${field('last_checkin_status')}.value.toLowerCase() == 'error' ) { emit('error'); } else if ( ${field('last_checkin_status')}.size() > 0 && ${field('last_checkin_status')}.value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }`.replace(/\s{2,}/g, ' '); // replace newlines and double spaces to save characters } // exported for testing function _buildStatusRuntimeField(opts) { const { inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout = _constants.DEFAULT_MAX_AGENT_POLICIES_WITH_INACTIVITY_TIMEOUT, pathPrefix, logger } = opts; const source = _buildSource(inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout, pathPrefix, logger); return { status: { type: 'keyword', script: { lang: 'painless', source } } }; } // Build the runtime field to return the agent status // pathPrefix is used to prefix the field path in the source // pathPrefix is used by the endpoint team currently to run // agent queries against the endpoint metadata index async function buildAgentStatusRuntimeField(soClient, pathPrefix) { var _config$developer; const config = _app_context.appContextService.getConfig(); let logger; try { logger = _app_context.appContextService.getLogger(); } catch (e) { // ignore, logger is optional // this code can be used and tested without an app context } const maxAgentPoliciesWithInactivityTimeout = config === null || config === void 0 ? void 0 : (_config$developer = config.developer) === null || _config$developer === void 0 ? void 0 : _config$developer.maxAgentPoliciesWithInactivityTimeout; const inactivityTimeouts = await _agent_policy.agentPolicyService.getInactivityTimeouts(soClient); return _buildStatusRuntimeField({ inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout, pathPrefix, logger }); }