mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[EDR Workflows] Initialize agent with latest fleet supported version (#189174)
This PR introduces a call to `/agents/available_versions` to fetch the latest available agent version in Serverless environment. This version is then used to create agents throughout our tests.
This commit is contained in:
parent
40d1a91bac
commit
4106cac4ed
27 changed files with 210 additions and 113 deletions
|
@ -36,7 +36,7 @@ export class EndpointRuleAlertGenerator extends BaseDataGenerator {
|
|||
generate(overrides: DeepPartial<EndpointRuleAlert> = {}): EndpointRuleAlert {
|
||||
const endpointMetadataGenerator = new EndpointMetadataGenerator();
|
||||
const endpointMetadata = endpointMetadataGenerator.generate({
|
||||
agent: { version: kibanaPackageJson.version },
|
||||
agent: { version: overrides?.agent?.version ?? kibanaPackageJson.version },
|
||||
host: { hostname: overrides?.host?.hostname },
|
||||
Endpoint: { state: { isolation: overrides?.Endpoint?.state?.isolation } },
|
||||
});
|
||||
|
@ -50,7 +50,7 @@ export class EndpointRuleAlertGenerator extends BaseDataGenerator {
|
|||
agent: {
|
||||
id: endpointAgentId,
|
||||
type: 'endpoint',
|
||||
version: kibanaPackageJson.version,
|
||||
version: endpointMetadata.agent.version,
|
||||
},
|
||||
elastic: endpointMetadata.elastic,
|
||||
host: endpointMetadata.host,
|
||||
|
|
|
@ -15,6 +15,9 @@ import type {
|
|||
MappingTypeMapping,
|
||||
Name,
|
||||
} from '@elastic/elasticsearch/lib/api/types';
|
||||
import type { KbnClient } from '@kbn/test';
|
||||
import { isServerlessKibanaFlavor } from '../utils/kibana_status';
|
||||
import { fetchFleetLatestAvailableAgentVersion } from '../utils/fetch_fleet_version';
|
||||
import { createToolingLogger, wrapErrorIfNeeded } from './utils';
|
||||
import { DEFAULT_ALERTS_INDEX } from '../../constants';
|
||||
import { EndpointRuleAlertGenerator } from '../data_generators/endpoint_rule_alert_generator';
|
||||
|
@ -26,6 +29,7 @@ export interface IndexEndpointRuleAlertsOptions {
|
|||
endpointIsolated?: boolean;
|
||||
count?: number;
|
||||
log?: ToolingLog;
|
||||
kbnClient?: KbnClient;
|
||||
}
|
||||
|
||||
export interface IndexedEndpointRuleAlerts {
|
||||
|
@ -41,6 +45,7 @@ export interface DeletedIndexedEndpointRuleAlerts {
|
|||
* Loads alerts for Endpoint directly into the internal index that the Endpoint Rule would have
|
||||
* written them to for a given endpoint
|
||||
* @param esClient
|
||||
* @param kbnClient
|
||||
* @param endpointAgentId
|
||||
* @param endpointHostname
|
||||
* @param endpointIsolated
|
||||
|
@ -49,6 +54,7 @@ export interface DeletedIndexedEndpointRuleAlerts {
|
|||
*/
|
||||
export const indexEndpointRuleAlerts = async ({
|
||||
esClient,
|
||||
kbnClient,
|
||||
endpointAgentId,
|
||||
endpointHostname,
|
||||
endpointIsolated,
|
||||
|
@ -59,12 +65,20 @@ export const indexEndpointRuleAlerts = async ({
|
|||
|
||||
await ensureEndpointRuleAlertsIndexExists(esClient);
|
||||
|
||||
let version = kibanaPackageJson.version;
|
||||
if (kbnClient) {
|
||||
const isServerless = await isServerlessKibanaFlavor(kbnClient);
|
||||
if (isServerless) {
|
||||
version = await fetchFleetLatestAvailableAgentVersion(kbnClient);
|
||||
}
|
||||
}
|
||||
|
||||
const alertsGenerator = new EndpointRuleAlertGenerator();
|
||||
const indexedAlerts: estypes.IndexResponse[] = [];
|
||||
|
||||
for (let n = 0; n < count; n++) {
|
||||
const alert = alertsGenerator.generate({
|
||||
agent: { id: endpointAgentId },
|
||||
agent: { id: endpointAgentId, version },
|
||||
host: { hostname: endpointHostname },
|
||||
...(endpointIsolated ? { Endpoint: { state: { isolation: endpointIsolated } } } : {}),
|
||||
});
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
packagePolicyRouteService,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import { fetchFleetLatestAvailableAgentVersion } from '../utils/fetch_fleet_version';
|
||||
import { indexFleetServerAgent } from './index_fleet_agent';
|
||||
import { catchAxiosErrorFormatAndThrow } from '../format_axios_error';
|
||||
import { usageTracker } from './usage_tracker';
|
||||
|
@ -47,6 +48,12 @@ export const enableFleetServerIfNecessary = usageTracker.track(
|
|||
log: ToolingLog = createToolingLogger(),
|
||||
version: string = kibanaPackageJson.version
|
||||
) => {
|
||||
let agentVersion = version;
|
||||
|
||||
if (isServerless) {
|
||||
agentVersion = await fetchFleetLatestAvailableAgentVersion(kbnClient);
|
||||
}
|
||||
|
||||
const agentPolicy = await getOrCreateFleetServerAgentPolicy(kbnClient, log);
|
||||
|
||||
if (!isServerless && !(await hasFleetServerAgent(esClient, agentPolicy.id))) {
|
||||
|
@ -56,7 +63,7 @@ export const enableFleetServerIfNecessary = usageTracker.track(
|
|||
|
||||
const indexedAgent = await indexFleetServerAgent(esClient, log, {
|
||||
policy_id: agentPolicy.id,
|
||||
agent: { version },
|
||||
agent: { version: agentVersion },
|
||||
last_checkin_status: 'online',
|
||||
last_checkin: lastCheckin.toISOString(),
|
||||
});
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches the latest version of the Elastic Agent available for download
|
||||
* @param kbnClient
|
||||
*/
|
||||
import type { KbnClient } from '@kbn/test';
|
||||
import { AGENT_API_ROUTES } from '@kbn/fleet-plugin/common';
|
||||
import type { GetAvailableVersionsResponse } from '@kbn/fleet-plugin/common/types';
|
||||
import { catchAxiosErrorFormatAndThrow } from '../format_axios_error';
|
||||
|
||||
export const fetchFleetLatestAvailableAgentVersion = async (
|
||||
kbnClient: KbnClient
|
||||
): Promise<string> => {
|
||||
return kbnClient
|
||||
.request<GetAvailableVersionsResponse>({
|
||||
method: 'GET',
|
||||
path: AGENT_API_ROUTES.AVAILABLE_VERSIONS_PATTERN,
|
||||
headers: {
|
||||
'elastic-api-version': '2023-10-31',
|
||||
},
|
||||
})
|
||||
.then((response) => response.data.items[0])
|
||||
.catch(catchAxiosErrorFormatAndThrow);
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import type { StatusResponse } from '@kbn/core-status-common-internal';
|
||||
import { catchAxiosErrorFormatAndThrow } from '../format_axios_error';
|
||||
|
||||
export const fetchKibanaStatus = async (kbnClient: KbnClient): Promise<StatusResponse> => {
|
||||
return (await kbnClient.status.get().catch(catchAxiosErrorFormatAndThrow)) as StatusResponse;
|
||||
};
|
||||
/**
|
||||
* Checks to see if Kibana/ES is running in serverless mode
|
||||
* @param client
|
||||
*/
|
||||
export const isServerlessKibanaFlavor = async (client: KbnClient | Client): Promise<boolean> => {
|
||||
if (client instanceof KbnClient) {
|
||||
const kbnStatus = await fetchKibanaStatus(client);
|
||||
|
||||
// If we don't have status for plugins, then error
|
||||
// the Status API will always return something (its an open API), but if auth was successful,
|
||||
// it will also return more data.
|
||||
if (!kbnStatus?.status?.plugins) {
|
||||
throw new Error(
|
||||
`Unable to retrieve Kibana plugins status (likely an auth issue with the username being used for kibana)`
|
||||
);
|
||||
}
|
||||
|
||||
return kbnStatus.status.plugins?.serverless?.level === 'available';
|
||||
} else {
|
||||
return (await client.info()).version.build_flavor === 'serverless';
|
||||
}
|
||||
};
|
|
@ -56,8 +56,8 @@ describe(
|
|||
policy = indexedPolicy.integrationPolicies[0];
|
||||
|
||||
return enableAllPolicyProtections(policy.id).then(() => {
|
||||
// Create and enroll a new Endpoint host
|
||||
return createEndpointHost(policy.policy_ids[0]).then((host) => {
|
||||
// At this point 8.14.2 is GA and this functionality is not available until 8.15.0
|
||||
return createEndpointHost(policy.policy_ids[0], '8.15.0').then((host) => {
|
||||
createdHost = host as CreateAndEnrollEndpointHostResponse;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,13 +10,14 @@ import type { Client } from '@elastic/elasticsearch';
|
|||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import type { KbnClient } from '@kbn/test/src/kbn_client';
|
||||
import { kibanaPackageJson } from '@kbn/repo-info';
|
||||
import { isServerlessKibanaFlavor } from '../../../../common/endpoint/utils/kibana_status';
|
||||
import { fetchFleetLatestAvailableAgentVersion } from '../../../../common/endpoint/utils/fetch_fleet_version';
|
||||
import { isFleetServerRunning } from '../../../../scripts/endpoint/common/fleet_server/fleet_server_services';
|
||||
import type { HostVm } from '../../../../scripts/endpoint/common/types';
|
||||
import type { BaseVmCreateOptions } from '../../../../scripts/endpoint/common/vm_services';
|
||||
import { createVm } from '../../../../scripts/endpoint/common/vm_services';
|
||||
import {
|
||||
fetchAgentPolicyEnrollmentKey,
|
||||
fetchFleetAvailableVersions,
|
||||
fetchFleetServerUrl,
|
||||
getAgentDownloadUrl,
|
||||
getAgentFileName,
|
||||
|
@ -38,12 +39,12 @@ export interface CreateAndEnrollEndpointHostCIOptions
|
|||
agentPolicyId: string;
|
||||
/** version of the Agent to install. Defaults to stack version */
|
||||
version?: string;
|
||||
/** skip all checks and use provided version */
|
||||
forceVersion?: boolean;
|
||||
/** The name for the host. Will also be the name of the VM */
|
||||
hostname?: string;
|
||||
/** If `version` should be exact, or if this is `true`, then the closest version will be used. Defaults to `false` */
|
||||
useClosestVersionMatch?: boolean;
|
||||
/** If the environment is MKI */
|
||||
isMkiEnvironment?: boolean;
|
||||
}
|
||||
|
||||
export interface CreateAndEnrollEndpointHostCIResponse {
|
||||
|
@ -66,14 +67,16 @@ export const createAndEnrollEndpointHostCI = async ({
|
|||
hostname,
|
||||
version = kibanaPackageJson.version,
|
||||
useClosestVersionMatch = true,
|
||||
isMkiEnvironment = false,
|
||||
forceVersion = false,
|
||||
}: CreateAndEnrollEndpointHostCIOptions): Promise<CreateAndEnrollEndpointHostCIResponse> => {
|
||||
let agentVersion = version;
|
||||
const vmName = hostname ?? `test-host-${Math.random().toString().substring(2, 6)}`;
|
||||
let agentVersion = version;
|
||||
|
||||
if (isMkiEnvironment) {
|
||||
// MKI env provides own fleet server. We must be sure that currently deployed FS is compatible with agent version we want to deploy.
|
||||
agentVersion = await fetchFleetAvailableVersions(kbnClient);
|
||||
if (!forceVersion) {
|
||||
const isServerless = await isServerlessKibanaFlavor(kbnClient);
|
||||
if (isServerless) {
|
||||
agentVersion = await fetchFleetLatestAvailableAgentVersion(kbnClient);
|
||||
}
|
||||
}
|
||||
|
||||
const fileNameNoExtension = getAgentFileName(agentVersion);
|
||||
|
|
|
@ -246,11 +246,12 @@ export const dataLoaders = (
|
|||
},
|
||||
|
||||
indexEndpointRuleAlerts: async (options: { endpointAgentId: string; count?: number }) => {
|
||||
const { esClient, log } = await stackServicesPromise;
|
||||
const { esClient, log, kbnClient } = await stackServicesPromise;
|
||||
return (
|
||||
await indexEndpointRuleAlerts({
|
||||
...options,
|
||||
esClient,
|
||||
kbnClient,
|
||||
log,
|
||||
})
|
||||
).alerts;
|
||||
|
@ -326,8 +327,6 @@ export const dataLoadersForRealEndpoints = (
|
|||
config: Cypress.PluginConfigOptions
|
||||
): void => {
|
||||
const stackServicesPromise = setupStackServicesUsingCypressConfig(config);
|
||||
const isServerless = Boolean(config.env.IS_SERVERLESS);
|
||||
const isCloudServerless = Boolean(config.env.CLOUD_SERVERLESS);
|
||||
|
||||
on('task', {
|
||||
createSentinelOneHost: async () => {
|
||||
|
@ -415,7 +414,6 @@ ${s1Info.status}
|
|||
options: Omit<CreateAndEnrollEndpointHostCIOptions, 'log' | 'kbnClient'>
|
||||
): Promise<CreateAndEnrollEndpointHostCIResponse> => {
|
||||
const { kbnClient, log, esClient } = await stackServicesPromise;
|
||||
const isMkiEnvironment = isServerless && isCloudServerless;
|
||||
let retryAttempt = 0;
|
||||
const attemptCreateEndpointHost =
|
||||
async (): Promise<CreateAndEnrollEndpointHostCIResponse> => {
|
||||
|
@ -424,7 +422,6 @@ ${s1Info.status}
|
|||
const newHost = process.env.CI
|
||||
? await createAndEnrollEndpointHostCI({
|
||||
useClosestVersionMatch: true,
|
||||
isMkiEnvironment,
|
||||
...options,
|
||||
log,
|
||||
kbnClient,
|
||||
|
|
|
@ -10,6 +10,7 @@ import type { KbnClient } from '@kbn/test';
|
|||
import pRetry from 'p-retry';
|
||||
import { kibanaPackageJson } from '@kbn/repo-info';
|
||||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import { fetchFleetLatestAvailableAgentVersion } from '../../../../../common/endpoint/utils/fetch_fleet_version';
|
||||
import { dump } from '../../../../../scripts/endpoint/common/utils';
|
||||
import { STARTED_TRANSFORM_STATES } from '../../../../../common/constants';
|
||||
import {
|
||||
|
@ -77,8 +78,18 @@ export const cyLoadEndpointDataHandler = async (
|
|||
isServerless = false,
|
||||
} = options;
|
||||
|
||||
let agentVersion = version;
|
||||
|
||||
if (isServerless) {
|
||||
agentVersion = await fetchFleetLatestAvailableAgentVersion(kbnClient);
|
||||
}
|
||||
|
||||
const DocGenerator = EndpointDocGenerator.custom({
|
||||
CustomMetadataGenerator: EndpointMetadataGenerator.custom({ version, os, isolation }),
|
||||
CustomMetadataGenerator: EndpointMetadataGenerator.custom({
|
||||
version: agentVersion,
|
||||
os,
|
||||
isolation,
|
||||
}),
|
||||
});
|
||||
|
||||
if (waitUntilTransformed) {
|
||||
|
@ -192,6 +203,7 @@ const startTransform = async (
|
|||
* the united metadata index
|
||||
*
|
||||
* @param esClient
|
||||
* @param log
|
||||
* @param location
|
||||
* @param ids
|
||||
*/
|
||||
|
|
|
@ -10,12 +10,14 @@ import type { CreateAndEnrollEndpointHostResponse } from '../../../../scripts/en
|
|||
// only used in "real" endpoint tests not in mocked ones
|
||||
export const createEndpointHost = (
|
||||
agentPolicyId: string,
|
||||
version?: string,
|
||||
timeout?: number
|
||||
): Cypress.Chainable<CreateAndEnrollEndpointHostResponse> => {
|
||||
return cy.task(
|
||||
'createEndpointHost',
|
||||
{
|
||||
agentPolicyId,
|
||||
...(version ? { version, forceVersion: true } : {}),
|
||||
},
|
||||
{ timeout: timeout ?? 30 * 60 * 1000 }
|
||||
);
|
||||
|
|
|
@ -11,6 +11,8 @@ import pMap from 'p-map';
|
|||
import type { CreatePackagePolicyResponse } from '@kbn/fleet-plugin/common';
|
||||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import { kibanaPackageJson } from '@kbn/repo-info';
|
||||
import { isServerlessKibanaFlavor } from '../../../../common/endpoint/utils/kibana_status';
|
||||
import { fetchFleetLatestAvailableAgentVersion } from '../../../../common/endpoint/utils/fetch_fleet_version';
|
||||
import { indexAlerts } from '../../../../common/endpoint/data_loaders/index_alerts';
|
||||
import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data';
|
||||
import { fetchEndpointMetadataList } from '../../common/endpoint_metadata_services';
|
||||
|
@ -21,16 +23,9 @@ import { METADATA_DATASTREAM } from '../../../../common/endpoint/constants';
|
|||
import { EndpointMetadataGenerator } from '../../../../common/endpoint/data_generators/endpoint_metadata_generator';
|
||||
import { getEndpointPackageInfo } from '../../../../common/endpoint/utils/package';
|
||||
import { ENDPOINT_ALERTS_INDEX, ENDPOINT_EVENTS_INDEX } from '../../common/constants';
|
||||
import { isServerlessKibanaFlavor } from '../../common/stack_services';
|
||||
|
||||
let WAS_FLEET_SETUP_DONE = false;
|
||||
|
||||
const CurrentKibanaVersionDocGenerator = EndpointDocGenerator.custom({
|
||||
CustomMetadataGenerator: EndpointMetadataGenerator.custom({
|
||||
version: kibanaPackageJson.version,
|
||||
}),
|
||||
});
|
||||
|
||||
export const loadEndpointsIfNoneExist = async (
|
||||
esClient: Client,
|
||||
kbnClient: KbnClient,
|
||||
|
@ -84,14 +79,20 @@ export const loadEndpoints = async ({
|
|||
log,
|
||||
onProgress,
|
||||
count = 2,
|
||||
DocGeneratorClass = CurrentKibanaVersionDocGenerator,
|
||||
DocGeneratorClass,
|
||||
}: LoadEndpointsOptions): Promise<void> => {
|
||||
if (log) {
|
||||
log.verbose(`loadEndpoints(): Loading ${count} endpoints...`);
|
||||
}
|
||||
|
||||
const isServerless = await isServerlessKibanaFlavor(kbnClient);
|
||||
let version = kibanaPackageJson.version;
|
||||
|
||||
if (isServerless) {
|
||||
version = await fetchFleetLatestAvailableAgentVersion(kbnClient);
|
||||
}
|
||||
|
||||
if (!WAS_FLEET_SETUP_DONE) {
|
||||
const isServerless = await isServerlessKibanaFlavor(kbnClient);
|
||||
await setupFleetForEndpoint(kbnClient);
|
||||
await enableFleetServerIfNecessary(esClient, isServerless, kbnClient, log);
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
|
@ -120,10 +121,16 @@ export const loadEndpoints = async ({
|
|||
}
|
||||
};
|
||||
|
||||
const CurrentKibanaVersionDocGenerator = EndpointDocGenerator.custom({
|
||||
CustomMetadataGenerator: EndpointMetadataGenerator.custom({
|
||||
version,
|
||||
}),
|
||||
});
|
||||
|
||||
await pMap(
|
||||
Array.from({ length: count }),
|
||||
async () => {
|
||||
const endpointGenerator = new DocGeneratorClass();
|
||||
const endpointGenerator = new (DocGeneratorClass ?? CurrentKibanaVersionDocGenerator)();
|
||||
|
||||
await indexEndpointHostDocs({
|
||||
numDocs: 1,
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
import type { Client, estypes } from '@elastic/elasticsearch';
|
||||
import assert from 'assert';
|
||||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import { createEsClient, isServerlessKibanaFlavor } from './stack_services';
|
||||
import { isServerlessKibanaFlavor } from '../../../common/endpoint/utils/kibana_status';
|
||||
import { createEsClient } from './stack_services';
|
||||
import type { CreatedSecuritySuperuser } from './security_user_services';
|
||||
import { createSecuritySuperuser } from './security_user_services';
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
import { kibanaPackageJson } from '@kbn/repo-info';
|
||||
import type { KbnClient } from '@kbn/test';
|
||||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import { isServerlessKibanaFlavor } from '../../../common/endpoint/utils/kibana_status';
|
||||
import { fetchFleetLatestAvailableAgentVersion } from '../../../common/endpoint/utils/fetch_fleet_version';
|
||||
import { prefixedOutputLogger } from './utils';
|
||||
import type { HostVm } from './types';
|
||||
import type { BaseVmCreateOptions } from './vm_services';
|
||||
|
@ -23,6 +25,8 @@ export interface CreateAndEnrollEndpointHostOptions
|
|||
agentPolicyId: string;
|
||||
/** version of the Agent to install. Defaults to stack version */
|
||||
version?: string;
|
||||
/** skip all checks and use provided version */
|
||||
forceVersion?: boolean;
|
||||
/** The name for the host. Will also be the name of the VM */
|
||||
hostname?: string;
|
||||
/** If `version` should be exact, or if this is `true`, then the closest version will be used. Defaults to `false` */
|
||||
|
@ -49,13 +53,22 @@ export const createAndEnrollEndpointHost = async ({
|
|||
memory,
|
||||
hostname,
|
||||
version = kibanaPackageJson.version,
|
||||
forceVersion = false,
|
||||
useClosestVersionMatch = false,
|
||||
useCache = true,
|
||||
}: CreateAndEnrollEndpointHostOptions): Promise<CreateAndEnrollEndpointHostResponse> => {
|
||||
const log = prefixedOutputLogger('createAndEnrollEndpointHost()', _log);
|
||||
let agentVersion = version;
|
||||
|
||||
if (!forceVersion) {
|
||||
const isServerless = await isServerlessKibanaFlavor(kbnClient);
|
||||
if (isServerless) {
|
||||
agentVersion = await fetchFleetLatestAvailableAgentVersion(kbnClient);
|
||||
}
|
||||
}
|
||||
const isRunningInCI = Boolean(process.env.CI);
|
||||
const vmName = hostname ?? `test-host-${Math.random().toString().substring(2, 6)}`;
|
||||
const { url: agentUrl } = await getAgentDownloadUrl(version, useClosestVersionMatch, log);
|
||||
const { url: agentUrl } = await getAgentDownloadUrl(agentVersion, useClosestVersionMatch, log);
|
||||
const agentDownload = isRunningInCI ? await downloadAndStoreAgent(agentUrl) : undefined;
|
||||
|
||||
// TODO: remove dependency on env. var and keep function pure
|
||||
|
@ -84,7 +97,7 @@ export const createAndEnrollEndpointHost = async ({
|
|||
log,
|
||||
hostVm,
|
||||
agentPolicyId,
|
||||
version,
|
||||
version: agentVersion,
|
||||
closestVersionMatch: useClosestVersionMatch,
|
||||
useAgentCache: useCache,
|
||||
});
|
||||
|
|
|
@ -41,9 +41,9 @@ import {
|
|||
} from '@kbn/dev-utils';
|
||||
import { maybeCreateDockerNetwork, SERVERLESS_NODES, verifyDockerInstalled } from '@kbn/es';
|
||||
import { resolve } from 'path';
|
||||
import { isServerlessKibanaFlavor } from '../../../../common/endpoint/utils/kibana_status';
|
||||
import { captureCallingStack, dump, prefixedOutputLogger } from '../utils';
|
||||
import { createToolingLogger } from '../../../../common/endpoint/data_loaders/utils';
|
||||
import { isServerlessKibanaFlavor } from '../stack_services';
|
||||
import type { FormattedAxiosError } from '../../../../common/endpoint/format_axios_error';
|
||||
import { catchAxiosErrorFormatAndThrow } from '../../../../common/endpoint/format_axios_error';
|
||||
import {
|
||||
|
|
|
@ -11,6 +11,7 @@ import type {
|
|||
Agent,
|
||||
AgentPolicy,
|
||||
AgentStatus,
|
||||
CopyAgentPolicyResponse,
|
||||
CreateAgentPolicyRequest,
|
||||
CreateAgentPolicyResponse,
|
||||
CreatePackagePolicyRequest,
|
||||
|
@ -24,7 +25,6 @@ import type {
|
|||
GetPackagePoliciesResponse,
|
||||
PackagePolicy,
|
||||
PostFleetSetupResponse,
|
||||
CopyAgentPolicyResponse,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
AGENT_API_ROUTES,
|
||||
|
@ -37,8 +37,8 @@ import {
|
|||
APP_API_ROUTES,
|
||||
epmRouteService,
|
||||
PACKAGE_POLICY_API_ROUTES,
|
||||
SETUP_API_ROUTE,
|
||||
PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
SETUP_API_ROUTE,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import type { KbnClient } from '@kbn/test';
|
||||
|
@ -49,6 +49,7 @@ import {
|
|||
outputRoutesService,
|
||||
} from '@kbn/fleet-plugin/common/services';
|
||||
import type {
|
||||
CopyAgentPolicyRequest,
|
||||
DeleteAgentPolicyResponse,
|
||||
EnrollmentAPIKey,
|
||||
GenerateServiceTokenResponse,
|
||||
|
@ -56,12 +57,12 @@ import type {
|
|||
GetEnrollmentAPIKeysResponse,
|
||||
GetOutputsResponse,
|
||||
PostAgentUnenrollResponse,
|
||||
CopyAgentPolicyRequest,
|
||||
} from '@kbn/fleet-plugin/common/types';
|
||||
import semver from 'semver';
|
||||
import axios from 'axios';
|
||||
import { userInfo } from 'os';
|
||||
import pRetry from 'p-retry';
|
||||
import { fetchKibanaStatus } from '../../../common/endpoint/utils/kibana_status';
|
||||
import { isFleetServerRunning } from './fleet_server/fleet_server_services';
|
||||
import { getEndpointPackageInfo } from '../../../common/endpoint/utils/package';
|
||||
import type { DownloadAndStoreAgentResponse } from './agent_downloads_service';
|
||||
|
@ -72,7 +73,6 @@ import {
|
|||
RETRYABLE_TRANSIENT_ERRORS,
|
||||
retryOnError,
|
||||
} from '../../../common/endpoint/data_loaders/utils';
|
||||
import { fetchKibanaStatus } from './stack_services';
|
||||
import { catchAxiosErrorFormatAndThrow } from '../../../common/endpoint/format_axios_error';
|
||||
import { FleetAgentGenerator } from '../../../common/endpoint/data_generators/fleet_agent_generator';
|
||||
|
||||
|
@ -524,24 +524,6 @@ export const getAgentDownloadUrl = async (
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches the latest version of the Elastic Agent available for download
|
||||
* @param kbnClient
|
||||
*/
|
||||
|
||||
export const fetchFleetAvailableVersions = async (kbnClient: KbnClient): Promise<string> => {
|
||||
return kbnClient
|
||||
.request<{ items: string[] }>({
|
||||
method: 'GET',
|
||||
path: AGENT_API_ROUTES.AVAILABLE_VERSIONS_PATTERN,
|
||||
headers: {
|
||||
'elastic-api-version': '2023-10-31',
|
||||
},
|
||||
})
|
||||
.then((response) => response.data.items[0])
|
||||
.catch(catchAxiosErrorFormatAndThrow);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a stack version number, function will return the closest Agent download version available
|
||||
* for download. THis could be the actual version passed in or lower.
|
||||
|
|
|
@ -9,7 +9,6 @@ import { Client } from '@elastic/elasticsearch';
|
|||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import type { KbnClientOptions } from '@kbn/test';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import type { StatusResponse } from '@kbn/core-status-common-internal';
|
||||
import pRetry from 'p-retry';
|
||||
import type { ReqOptions } from '@kbn/test/src/kbn_client/kbn_client_requester';
|
||||
import { type AxiosResponse } from 'axios';
|
||||
|
@ -17,8 +16,11 @@ import type { ClientOptions } from '@elastic/elasticsearch/lib/client';
|
|||
import fs from 'fs';
|
||||
import { CA_CERT_PATH } from '@kbn/dev-utils';
|
||||
import { omit } from 'lodash';
|
||||
import {
|
||||
fetchKibanaStatus,
|
||||
isServerlessKibanaFlavor,
|
||||
} from '../../../common/endpoint/utils/kibana_status';
|
||||
import { createToolingLogger } from '../../../common/endpoint/data_loaders/utils';
|
||||
import { catchAxiosErrorFormatAndThrow } from '../../../common/endpoint/format_axios_error';
|
||||
import { isLocalhost } from './is_localhost';
|
||||
import { getLocalhostRealIp } from './network_services';
|
||||
import { createSecuritySuperuser } from './security_user_services';
|
||||
|
@ -313,10 +315,6 @@ export const fetchStackVersion = async (kbnClient: KbnClient): Promise<string> =
|
|||
return status.version.number;
|
||||
};
|
||||
|
||||
export const fetchKibanaStatus = async (kbnClient: KbnClient): Promise<StatusResponse> => {
|
||||
return (await kbnClient.status.get().catch(catchAxiosErrorFormatAndThrow)) as StatusResponse;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks to ensure Kibana is up and running
|
||||
* @param kbnClient
|
||||
|
@ -335,26 +333,3 @@ export const waitForKibana = async (kbnClient: KbnClient): Promise<void> => {
|
|||
{ maxTimeout: 10000 }
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks to see if Kibana/ES is running in serverless mode
|
||||
* @param client
|
||||
*/
|
||||
export const isServerlessKibanaFlavor = async (client: KbnClient | Client): Promise<boolean> => {
|
||||
if (client instanceof KbnClient) {
|
||||
const kbnStatus = await fetchKibanaStatus(client);
|
||||
|
||||
// If we don't have status for plugins, then error
|
||||
// the Status API will always return something (its an open API), but if auth was successful,
|
||||
// it will also return more data.
|
||||
if (!kbnStatus?.status?.plugins) {
|
||||
throw new Error(
|
||||
`Unable to retrieve Kibana plugins status (likely an auth issue with the username being used for kibana)`
|
||||
);
|
||||
}
|
||||
|
||||
return kbnStatus.status.plugins?.serverless?.level === 'available';
|
||||
} else {
|
||||
return (await client.info()).version.build_flavor === 'serverless';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,13 +14,14 @@ import { CA_CERT_PATH } from '@kbn/dev-utils';
|
|||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import type { KbnClientOptions } from '@kbn/test';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import { isServerlessKibanaFlavor } from '../../common/endpoint/utils/kibana_status';
|
||||
import { createToolingLogger } from '../../common/endpoint/data_loaders/utils';
|
||||
import { EndpointSecurityTestRolesLoader } from './common/role_and_user_loader';
|
||||
import { METADATA_DATASTREAM } from '../../common/endpoint/constants';
|
||||
import { EndpointMetadataGenerator } from '../../common/endpoint/data_generators/endpoint_metadata_generator';
|
||||
import { indexHostsAndAlerts } from '../../common/endpoint/index_data';
|
||||
import { ANCESTRY_LIMIT, EndpointDocGenerator } from '../../common/endpoint/generate_data';
|
||||
import { fetchStackVersion, isServerlessKibanaFlavor } from './common/stack_services';
|
||||
import { fetchStackVersion } from './common/stack_services';
|
||||
import { ENDPOINT_ALERTS_INDEX, ENDPOINT_EVENTS_INDEX } from './common/constants';
|
||||
|
||||
main();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context_edr_workflows';
|
||||
import { ROLE } from '../../../../config/services/security_solution_edr_workflows_roles_users';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context_edr_workflows';
|
||||
import { ROLE } from '../../../../config/services/security_solution_edr_workflows_roles_users';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context_edr_workflows';
|
||||
import { ROLE } from '../../../../config/services/security_solution_edr_workflows_roles_users';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context_edr_workflows';
|
||||
import { ROLE } from '../../../../config/services/security_solution_edr_workflows_roles_users';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context_edr_workflows';
|
||||
import { ROLE } from '../../../../config/services/security_solution_edr_workflows_roles_users';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context_edr_workflows';
|
||||
import { ROLE } from '../../../../config/services/security_solution_edr_workflows_roles_users';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context_edr_workflows';
|
||||
import { ROLE } from '../../../../config/services/security_solution_edr_workflows_roles_users';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../configs/ftr_provider_context';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { getRegistryUrl as getRegistryUrlFromIngest } from '@kbn/fleet-plugin/server';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/scripts/endpoint/common/stack_services';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrProviderContext } from '../../configs/ftr_provider_context';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
|
|
|
@ -7,18 +7,17 @@
|
|||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { errors } from '@elastic/elasticsearch';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import { Client, errors } from '@elastic/elasticsearch';
|
||||
import { AGENTS_INDEX } from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
metadataCurrentIndexPattern,
|
||||
metadataTransformPrefix,
|
||||
HOST_METADATA_GET_ROUTE,
|
||||
METADATA_CURRENT_TRANSFORM_V2,
|
||||
METADATA_DATASTREAM,
|
||||
METADATA_UNITED_INDEX,
|
||||
METADATA_UNITED_TRANSFORM,
|
||||
METADATA_UNITED_TRANSFORM_V2,
|
||||
HOST_METADATA_GET_ROUTE,
|
||||
METADATA_DATASTREAM,
|
||||
metadataCurrentIndexPattern,
|
||||
metadataTransformPrefix,
|
||||
} from '@kbn/security-solution-plugin/common/endpoint/constants';
|
||||
import {
|
||||
deleteIndexedHostsAndAlerts,
|
||||
|
@ -38,20 +37,33 @@ import { merge } from 'lodash';
|
|||
// @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail
|
||||
import { kibanaPackageJson } from '@kbn/repo-info';
|
||||
import seedrandom from 'seedrandom';
|
||||
import { fetchFleetLatestAvailableAgentVersion } from '@kbn/security-solution-plugin/common/endpoint/utils/fetch_fleet_version';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import { isServerlessKibanaFlavor } from '@kbn/security-solution-plugin/common/endpoint/utils/kibana_status';
|
||||
import { FtrService } from '../../functional/ftr_provider_context';
|
||||
|
||||
// Document Generator override that uses a custom Endpoint Metadata generator and sets the
|
||||
// `agent.version` to the current version
|
||||
const CurrentKibanaVersionDocGenerator = class extends EndpointDocGenerator {
|
||||
constructor(seedValue: string | seedrandom.prng) {
|
||||
const MetadataGenerator = class extends EndpointMetadataGenerator {
|
||||
protected randomVersion(): string {
|
||||
return kibanaPackageJson.version;
|
||||
}
|
||||
};
|
||||
|
||||
super(seedValue, MetadataGenerator);
|
||||
const createDocGeneratorClass = async (kbnClient: KbnClient, isServerless: boolean) => {
|
||||
let version = kibanaPackageJson.version;
|
||||
if (isServerless) {
|
||||
version = await fetchFleetLatestAvailableAgentVersion(kbnClient);
|
||||
}
|
||||
// TS doesn't like the `version` let being used in the class definition
|
||||
const capturedVersion = version;
|
||||
|
||||
return class extends EndpointDocGenerator {
|
||||
constructor(seedValue: string | seedrandom.prng) {
|
||||
const MetadataGenerator = class extends EndpointMetadataGenerator {
|
||||
protected randomVersion(): string {
|
||||
return capturedVersion;
|
||||
}
|
||||
};
|
||||
|
||||
super(seedValue, MetadataGenerator);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export class EndpointTestResources extends FtrService {
|
||||
|
@ -93,7 +105,7 @@ export class EndpointTestResources extends FtrService {
|
|||
* @param [options.numHostDocs=1] Number of Document to be loaded per Endpoint Host (Endpoint hosts index uses a append-only index)
|
||||
* @param [options.alertsPerHost=1] Number of Alerts and Events to be loaded per Endpoint Host
|
||||
* @param [options.enableFleetIntegration=true] When set to `true`, Fleet data will also be loaded (ex. Integration Policies, Agent Policies, "fake" Agents)
|
||||
* @param [options.generatorSeed='seed`] The seed to be used by the data generator. Important in order to ensure the same data is generated on very run.
|
||||
* @param [options.generatorSeed='seed'] The seed to be used by the data generator. Important in order to ensure the same data is generated on very run.
|
||||
* @param [options.waitUntilTransformed=true] If set to `true`, the data loading process will wait until the endpoint hosts metadata is processed by the transform
|
||||
* @param [options.waitTimeout=120000] If waitUntilTransformed=true, number of ms to wait until timeout
|
||||
* @param [options.customIndexFn] If provided, will use this function to generate and index data instead
|
||||
|
@ -140,6 +152,12 @@ export class EndpointTestResources extends FtrService {
|
|||
await this.stopTransform(unitedTransformName);
|
||||
}
|
||||
|
||||
const isServerless = await isServerlessKibanaFlavor(this.kbnClient);
|
||||
const CurrentKibanaVersionDocGenerator = await createDocGeneratorClass(
|
||||
this.kbnClient,
|
||||
isServerless
|
||||
);
|
||||
|
||||
// load data into the system
|
||||
const indexedData = customIndexFn
|
||||
? await customIndexFn()
|
||||
|
@ -308,15 +326,13 @@ export class EndpointTestResources extends FtrService {
|
|||
* @param endpointAgentId
|
||||
*/
|
||||
async fetchEndpointMetadata(endpointAgentId: string): Promise<HostInfo> {
|
||||
const metadata = this.supertest
|
||||
return this.supertest
|
||||
.get(HOST_METADATA_GET_ROUTE.replace('{id}', endpointAgentId))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('Elastic-Api-Version', '2023-10-31')
|
||||
.send()
|
||||
.expect(200)
|
||||
.then((response) => response.body as HostInfo);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue