Skip to content

Commit

Permalink
move logic into right place
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 committed Nov 13, 2024
1 parent 5a935b4 commit 74cd958
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 40 deletions.
28 changes: 28 additions & 0 deletions x-pack/plugins/fleet/server/services/agents/agent_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,32 @@ function expectApisToCallServicesSuccessfully(
);
expect(mockgetLatestAvailableAgentVersion).toHaveBeenCalledTimes(1);
});

test('client.getLatestAgentAvailableBaseVersion strips away IAR suffix', async () => {
mockgetLatestAvailableAgentVersion.mockResolvedValue('1.2.3+build12345678987654321');
await expect(agentClient.getLatestAgentAvailableBaseVersion()).resolves.toEqual(
'1.2.3'
);
});

test('client.getLatestAgentAvailableBaseVersion does not break on usual version numbers', async () => {
mockgetLatestAvailableAgentVersion.mockResolvedValue('8.17.0');
await expect(agentClient.getLatestAgentAvailableBaseVersion()).resolves.toEqual(
'8.17.0'
);
});

test('client.getLatestAgentAvailableDockerImageVersion transforms IAR suffix', async () => {
mockgetLatestAvailableAgentVersion.mockResolvedValue('1.2.3+build12345678987654321');
await expect(agentClient.getLatestAgentAvailableDockerImageVersion()).resolves.toEqual(
'1.2.3.build12345678987654321'
);
});

test('client.getLatestAgentAvailableDockerImageVersion does not break on usual version numbers', async () => {
mockgetLatestAvailableAgentVersion.mockResolvedValue('8.17.0');
await expect(agentClient.getLatestAgentAvailableDockerImageVersion()).resolves.toEqual(
'8.17.0'
);
});
}
18 changes: 18 additions & 0 deletions x-pack/plugins/fleet/server/services/agents/agent_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ export interface AgentClient {
* Return the latest agent available version
*/
getLatestAgentAvailableVersion(includeCurrentVersion?: boolean): Promise<string>;
/**
* Return the latest agent available version, not taking into account IAR versions
*/
getLatestAgentAvailableBaseVersion(includeCurrentVersion?: boolean): Promise<string>;
/**
* Return the latest agent available version formatted for the docker image
*/
getLatestAgentAvailableDockerImageVersion(includeCurrentVersion?: boolean): Promise<string>;
}

/**
Expand Down Expand Up @@ -163,6 +171,16 @@ class AgentClientImpl implements AgentClient {
);
}

public async getLatestAgentAvailableBaseVersion(includeCurrentVersion?: boolean) {
const fullVersion = await this.getLatestAgentAvailableVersion(includeCurrentVersion);
return fullVersion.split('+')[0];
}

public async getLatestAgentAvailableDockerImageVersion(includeCurrentVersion?: boolean) {
const fullVersion = await this.getLatestAgentAvailableVersion(includeCurrentVersion);
return fullVersion.replace('+', '.');
}

public async getLatestAgentAvailableVersion(includeCurrentVersion?: boolean) {
await this.#runPreflight();
return getLatestAvailableAgentVersion({ includeCurrentVersion });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

export interface ElasticAgentVersionInfo {
agentVersion: string;
agentBaseVersion: string;
agentDockerImageVersion: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function getAutoDetectCommand(
--kibana-url=${options.kibanaUrl}
--install-key=${options.installApiKey}
--ingest-key=${options.ingestApiKey}
--ea-version=${options.elasticAgentVersion}
--ea-version=${options.elasticAgentVersionInfo.agentVersion}
`;
}
function oneLine(parts: TemplateStringsArray, ...args: string[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export function InstallElasticAgent() {
apiKeyEncoded,
apiEndpoint: setup?.apiEndpoint,
scriptDownloadUrl: setup?.scriptDownloadUrl,
elasticAgentVersion: setup?.elasticAgentVersion,
elasticAgentVersion: setup?.elasticAgentVersionInfo.agentVersion,
autoDownloadConfig,
onboardingId,
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
* 2.0.
*/

import { ElasticAgentVersionInfo } from '../../../../common/types';

interface Params {
encodedApiKey: string;
onboardingId: string;
elasticsearchUrl: string;
elasticAgentVersion: string;
elasticAgentVersionInfo: ElasticAgentVersionInfo;
}

const KUSTOMIZE_TEMPLATE_URL =
Expand All @@ -19,18 +21,16 @@ export function buildKubectlCommand({
encodedApiKey,
onboardingId,
elasticsearchUrl,
elasticAgentVersion,
elasticAgentVersionInfo,
}: Params) {
const escapedElasticsearchUrl = elasticsearchUrl.replace(/\//g, '\\/');
// Strip away the build metadata from the version
const versionTag = elasticAgentVersion.split('+')[0];

return `
kubectl kustomize ${KUSTOMIZE_TEMPLATE_URL}\\?ref\\=v${versionTag}
kubectl kustomize ${KUSTOMIZE_TEMPLATE_URL}\\?ref\\=v${elasticAgentVersionInfo.agentBaseVersion}
| sed -e 's/JUFQSV9LRVkl/${encodedApiKey}/g'
-e "s/%ES_HOST%/${escapedElasticsearchUrl}/g"
-e "s/%ONBOARDING_ID%/${onboardingId}/g"
-e "s/\\(docker.elastic.co\\/beats\\/elastic-agent\:\\).*$/\\1${elasticAgentVersion}/g"
-e "s/\\(docker.elastic.co\\/beats\\/elastic-agent\:\\).*$/\\1${elasticAgentVersionInfo.agentDockerImageVersion}/g"
-e "/{CA_TRUSTED}/c\\ "
| kubectl apply -f-
`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,30 @@ import React from 'react';
import { EuiCodeBlock, EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { ElasticAgentVersionInfo } from '../../../../common/types';
import { buildKubectlCommand } from './build_kubectl_command';
import { CopyToClipboardButton } from '../shared/copy_to_clipboard_button';

interface Props {
encodedApiKey: string;
onboardingId: string;
elasticsearchUrl: string;
elasticAgentVersion: string;
elasticAgentVersionInfo: ElasticAgentVersionInfo;
isCopyPrimaryAction: boolean;
}

export function CommandSnippet({
encodedApiKey,
onboardingId,
elasticsearchUrl,
elasticAgentVersion,
elasticAgentVersionInfo,
isCopyPrimaryAction,
}: Props) {
const command = buildKubectlCommand({
encodedApiKey,
onboardingId,
elasticsearchUrl,
elasticAgentVersion,
elasticAgentVersionInfo,
});

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const KubernetesPanel: React.FC = () => {
encodedApiKey={data.apiKeyEncoded}
onboardingId={data.onboardingId}
elasticsearchUrl={data.elasticsearchUrl}
elasticAgentVersion={data.elasticAgentVersion}
elasticAgentVersionInfo={data.elasticAgentVersionInfo}
isCopyPrimaryAction={!isMonitoringStepActive}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,27 @@
*/

import type { FleetStartContract } from '@kbn/fleet-plugin/server';
import { ElasticAgentVersionInfo } from '../../common/types';

export function getAgentVersion(fleetStart: FleetStartContract, kibanaVersion: string) {
export async function getAgentVersionInfo(
fleetStart: FleetStartContract,
kibanaVersion: string
): Promise<ElasticAgentVersionInfo> {
// If undefined, we will follow fleet's strategy to select latest available version:
// for serverless we will use the latest published version, for statefull we will use
// current Kibana version. If false, irrespective of fleet flags and logic, we are
// explicitly deciding to not append the current version.
const includeCurrentVersion = kibanaVersion.endsWith('-SNAPSHOT') ? false : undefined;

const agentClient = fleetStart.agentService.asInternalUser;
return agentClient.getLatestAgentAvailableVersion(includeCurrentVersion);
const [agentVersion, agentBaseVersion, agentDockerImageVersion] = await Promise.all([
agentClient.getLatestAgentAvailableVersion(includeCurrentVersion),
agentClient.getLatestAgentAvailableBaseVersion(includeCurrentVersion),
agentClient.getLatestAgentAvailableDockerImageVersion(includeCurrentVersion),
]);
return {
agentVersion,
agentBaseVersion,
agentDockerImageVersion,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ObservabilityOnboardingFlow } from '../../saved_objects/observability_o
import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route';
import { getHasLogs } from './get_has_logs';
import { getKibanaUrl } from '../../lib/get_fallback_urls';
import { getAgentVersion } from '../../lib/get_agent_version';
import { getAgentVersionInfo } from '../../lib/get_agent_version';
import { getFallbackESUrl } from '../../lib/get_fallback_urls';
import { ElasticAgentStepPayload, InstalledIntegration, StepProgressPayloadRT } from '../types';
import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key';
Expand Down Expand Up @@ -220,21 +220,22 @@ const createFlowRoute = createObservabilityOnboardingServerRoute({

const fleetPluginStart = await plugins.fleet.start();

const [onboardingFlow, ingestApiKey, installApiKey, elasticAgentVersion] = await Promise.all([
saveObservabilityOnboardingFlow({
savedObjectsClient,
observabilityOnboardingState: {
type: 'autoDetect',
state: undefined,
progress: {},
},
}),
createShipperApiKey(client.asCurrentUser, `onboarding_ingest_${name}`),
(
await context.resolve(['core'])
).core.security.authc.apiKeys.create(createInstallApiKey(`onboarding_install_${name}`)),
getAgentVersion(fleetPluginStart, kibanaVersion),
]);
const [onboardingFlow, ingestApiKey, installApiKey, elasticAgentVersionInfo] =
await Promise.all([
saveObservabilityOnboardingFlow({
savedObjectsClient,
observabilityOnboardingState: {
type: 'autoDetect',
state: undefined,
progress: {},
},
}),
createShipperApiKey(client.asCurrentUser, `onboarding_ingest_${name}`),
(
await context.resolve(['core'])
).core.security.authc.apiKeys.create(createInstallApiKey(`onboarding_install_${name}`)),
getAgentVersionInfo(fleetPluginStart, kibanaVersion),
]);

if (!installApiKey) {
throw Boom.notFound('License does not allow API key creation.');
Expand All @@ -250,7 +251,7 @@ const createFlowRoute = createObservabilityOnboardingServerRoute({
onboardingFlow,
ingestApiKey: ingestApiKey.encoded,
installApiKey: installApiKey.encoded,
elasticAgentVersion,
elasticAgentVersionInfo,
kibanaUrl,
scriptDownloadUrl,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ import * as t from 'io-ts';
import Boom from '@hapi/boom';
import { termQuery } from '@kbn/observability-plugin/server';
import type { estypes } from '@elastic/elasticsearch';
import { ElasticAgentVersionInfo } from '../../../common/types';
import { getFallbackESUrl } from '../../lib/get_fallback_urls';
import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route';
import { hasLogMonitoringPrivileges } from '../../lib/api_key/has_log_monitoring_privileges';
import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key';
import { getAgentVersion } from '../../lib/get_agent_version';
import { getAgentVersionInfo } from '../../lib/get_agent_version';

export interface CreateKubernetesOnboardingFlowRouteResponse {
apiKeyEncoded: string;
onboardingId: string;
elasticsearchUrl: string;
elasticAgentVersion: string;
elasticAgentVersionInfo: ElasticAgentVersionInfo;
}

export interface HasKubernetesDataRouteResponse {
Expand Down Expand Up @@ -56,9 +57,9 @@ const createKubernetesOnboardingFlowRoute = createObservabilityOnboardingServerR
const fleetPluginStart = await plugins.fleet.start();
const packageClient = fleetPluginStart.packageService.asScoped(request);

const [{ encoded: apiKeyEncoded }, elasticAgentVersion] = await Promise.all([
const [{ encoded: apiKeyEncoded }, elasticAgentVersionInfo] = await Promise.all([
createShipperApiKey(client.asCurrentUser, `${params.body.pkgName}_onboarding`, true),
getAgentVersion(fleetPluginStart, kibanaVersion),
getAgentVersionInfo(fleetPluginStart, kibanaVersion),
// System package is always required
packageClient.ensureInstalledPackage({ pkgName: 'system' }),
// Kubernetes package is required for both classic kubernetes and otel
Expand All @@ -77,7 +78,7 @@ const createKubernetesOnboardingFlowRoute = createObservabilityOnboardingServerR
onboardingId: uuidv4(),
apiKeyEncoded,
elasticsearchUrl: elasticsearchUrlList.length > 0 ? elasticsearchUrlList[0] : '',
elasticAgentVersion,
elasticAgentVersionInfo,
};
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

import * as t from 'io-ts';
import Boom from '@hapi/boom';
import { ElasticAgentVersionInfo } from '../../../common/types';
import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route';
import { getFallbackESUrl } from '../../lib/get_fallback_urls';
import { getKibanaUrl } from '../../lib/get_fallback_urls';
import { getAgentVersion } from '../../lib/get_agent_version';
import { getAgentVersionInfo } from '../../lib/get_agent_version';
import { saveObservabilityOnboardingFlow } from '../../lib/state';
import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key';
import { ObservabilityOnboardingFlow } from '../../saved_objects/observability_onboarding_status';
Expand Down Expand Up @@ -39,7 +40,7 @@ const installShipperSetupRoute = createObservabilityOnboardingServerRoute({
async handler(resources): Promise<{
apiEndpoint: string;
scriptDownloadUrl: string;
elasticAgentVersion: string;
elasticAgentVersionInfo: ElasticAgentVersionInfo;
elasticsearchUrl: string[];
}> {
const {
Expand All @@ -50,7 +51,7 @@ const installShipperSetupRoute = createObservabilityOnboardingServerRoute({
} = resources;

const fleetPluginStart = await plugins.fleet.start();
const elasticAgentVersion = await getAgentVersion(fleetPluginStart, kibanaVersion);
const elasticAgentVersionInfo = await getAgentVersionInfo(fleetPluginStart, kibanaVersion);
const kibanaUrl = getKibanaUrl(core.setup, plugins.cloud?.setup);
const scriptDownloadUrl = new URL(
core.setup.http.staticAssets.getPluginAssetHref('standalone_agent_setup.sh'),
Expand All @@ -67,7 +68,7 @@ const installShipperSetupRoute = createObservabilityOnboardingServerRoute({
apiEndpoint,
elasticsearchUrl,
scriptDownloadUrl,
elasticAgentVersion,
elasticAgentVersionInfo,
};
},
});
Expand Down

0 comments on commit 74cd958

Please sign in to comment.