[Logs onboarding] Refactors the install elastic agent steps to own component (#162600)

This commit is contained in:
Oliver Gupte 2023-07-27 04:28:48 -07:00 committed by GitHub
parent 698ff714de
commit 7277dba30f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 570 additions and 428 deletions

View file

@ -8,28 +8,25 @@
import { import {
EuiButton, EuiButton,
EuiButtonEmpty, EuiButtonEmpty,
EuiButtonGroup,
EuiCallOut,
EuiCodeBlock,
EuiFlexGroup, EuiFlexGroup,
EuiFlexItem, EuiFlexItem,
EuiIconTip,
EuiLink,
EuiSkeletonRectangle,
EuiSpacer, EuiSpacer,
EuiSteps,
EuiStepsProps,
EuiSwitch,
EuiText, EuiText,
} from '@elastic/eui'; } from '@elastic/eui';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { Buffer } from 'buffer';
import { flatten, zip } from 'lodash';
import { default as React, useCallback, useEffect, useState } from 'react'; import { default as React, useCallback, useEffect, useState } from 'react';
import { useWizard } from '.'; import { useWizard } from '.';
import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
import { useKibanaNavigation } from '../../../../hooks/use_kibana_navigation'; import { useKibanaNavigation } from '../../../../hooks/use_kibana_navigation';
import {
ElasticAgentPlatform,
getElasticAgentSetupCommand,
} from '../../../shared/get_elastic_agent_setup_command';
import {
InstallElasticAgentSteps,
ProgressStepId,
EuiStepStatus,
} from '../../../shared/install_elastic_agent_steps';
import { import {
StepPanel, StepPanel,
StepPanelContent, StepPanelContent,
@ -37,9 +34,7 @@ import {
} from '../../../shared/step_panel'; } from '../../../shared/step_panel';
import { ApiKeyBanner } from './api_key_banner'; import { ApiKeyBanner } from './api_key_banner';
import { BackButton } from './back_button'; import { BackButton } from './back_button';
import { StepStatus } from './step_status';
type ElasticAgentPlatform = 'linux-tar' | 'macos' | 'windows';
export function InstallElasticAgent() { export function InstallElasticAgent() {
const { navigateToKibanaUrl } = useKibanaNavigation(); const { navigateToKibanaUrl } = useKibanaNavigation();
const { goBack, goToStep, getState, setState } = useWizard(); const { goBack, goToStep, getState, setState } = useWizard();
@ -196,56 +191,29 @@ export function InstallElasticAgent() {
} }
}, [progressSucceded, refetchProgress]); }, [progressSucceded, refetchProgress]);
const getStep = useCallback( const getCheckLogsStep = useCallback(() => {
({ id, incompleteTitle, loadingTitle, completedTitle }) => { const progress = progressData?.progress;
const progress = progressData?.progress; if (progress) {
if (progress) { const stepStatus = progress?.['logs-ingest']?.status as EuiStepStatus;
const stepStatus = progress?.[id] const title =
?.status as EuiStepsProps['steps'][number]['status']; stepStatus === 'loading'
const title = ? CHECK_LOGS_LABELS.loading
stepStatus === 'loading' : stepStatus === 'complete'
? loadingTitle ? CHECK_LOGS_LABELS.completed
: stepStatus === 'complete' : CHECK_LOGS_LABELS.incomplete;
? completedTitle return { title, status: stepStatus };
: incompleteTitle; }
return { return {
title, title: CHECK_LOGS_LABELS.incomplete,
children: null, status: 'incomplete' as const,
status: stepStatus ?? ('incomplete' as const), };
message: progress?.[id]?.message, }, [progressData?.progress]);
};
}
return {
title: incompleteTitle,
children: null,
status: 'incomplete' as const,
};
},
[progressData?.progress]
);
const isInstallStarted = progressData?.progress['ea-download'] !== undefined; const isInstallStarted = progressData?.progress['ea-download'] !== undefined;
const isInstallCompleted = const isInstallCompleted =
progressData?.progress?.['ea-status']?.status === 'complete'; progressData?.progress?.['ea-status']?.status === 'complete';
const autoDownloadConfigStatus = (progressData?.progress?.['ea-config']
const autoDownloadConfigStep = getStep({ ?.status ?? 'incomplete') as EuiStepStatus;
id: 'ea-config',
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaConfig.incompleteTitle',
{ defaultMessage: 'Configure the agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaConfig.loadingTitle',
{ defaultMessage: 'Downloading Elastic Agent config' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaConfig.completedTitle',
{
defaultMessage: 'Elastic Agent config written to {configPath}',
values: { configPath: '/opt/Elastic/Agent/elastic-agent.yml' },
}
),
});
return ( return (
<StepPanel <StepPanel
@ -311,389 +279,89 @@ export function InstallElasticAgent() {
) )
)} )}
<EuiSpacer size="m" /> <EuiSpacer size="m" />
<EuiSteps <InstallElasticAgentSteps
steps={[ installAgentPlatformOptions={[
{ {
title: i18n.translate( label: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.title', 'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform.linux',
{ defaultMessage: 'Install the Elastic Agent' } { defaultMessage: 'Linux' }
),
status:
installShipperSetupStatus === FETCH_STATUS.LOADING
? 'loading'
: isInstallCompleted
? 'complete'
: 'current',
children: (
<>
<EuiText color="subdued">
<p>
<FormattedMessage
id="xpack.observability_onboarding.installElasticAgent.installStep.description"
defaultMessage="Select your platform, and run the install command in your terminal to enroll and start the Elastic Agent. Do this for each host. Review {hostRequirementsLink} before installing."
values={{
hostRequirementsLink: (
<EuiLink
external
href="https://www.elastic.co/guide/en/fleet/8.7/elastic-agent-installation.html"
>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.hostRequirements',
{
defaultMessage:
'host requirements and other installation options',
}
)}
</EuiLink>
),
}}
/>
</p>
</EuiText>
<EuiSpacer size="l" />
<EuiSwitch
label={
<EuiFlexGroup
alignItems="center"
gutterSize="xs"
responsive={false}
>
<EuiFlexItem grow={false}>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig',
{
defaultMessage:
"Automatically download the agent's config",
}
)}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip
content={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig.tooltip',
{
defaultMessage:
"Turn on to add a string to the following code block that downloads the agent's standard configuration to your host during installation. Turn off to manually configure the agent in the next step.",
}
)}
position="right"
/>
</EuiFlexItem>
</EuiFlexGroup>
}
checked={wizardState.autoDownloadConfig}
onChange={onAutoDownloadConfig}
disabled={
isInstallStarted ||
(monitoringRole && !monitoringRole?.hasPrivileges)
}
/>
<EuiSpacer size="l" />
{wizardState.autoDownloadConfig && (
<>
<EuiCallOut
title={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig.overwriteWarning',
{
defaultMessage:
'Automatically downloading the agent config will overwrite any existing agent config on your host.',
}
)}
color="warning"
iconType="warning"
/>
<EuiSpacer size="l" />
</>
)}
<EuiButtonGroup
isFullWidth
legend={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform',
{ defaultMessage: 'Choose platform' }
)}
options={[
{
id: 'linux-tar',
label: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform.linux',
{ defaultMessage: 'Linux' }
),
},
{
id: 'macos',
label: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform.macOS',
{ defaultMessage: 'MacOS' }
),
isDisabled: true,
},
{
id: 'windows',
label: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform.windows',
{ defaultMessage: 'Windows' }
),
isDisabled: true,
},
]}
type="single"
idSelected={elasticAgentPlatform}
onChange={(id: string) =>
setElasticAgentPlatform(id as typeof elasticAgentPlatform)
}
/>
<EuiSpacer size="m" />
<EuiCodeBlock language="bash" isCopyable>
{getInstallShipperCommand({
elasticAgentPlatform,
apiKeyEncoded,
apiEndpoint: setup?.apiEndpoint,
scriptDownloadUrl: setup?.scriptDownloadUrl,
elasticAgentVersion: setup?.elasticAgentVersion,
autoDownloadConfig: wizardState.autoDownloadConfig,
onboardingId,
})}
</EuiCodeBlock>
<EuiSpacer size="m" />
{isInstallStarted && (
<>
<EuiSpacer size="m" />
<EuiFlexGroup direction="column" gutterSize="m">
{[
{
id: 'ea-download',
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaDownload.incompleteTitle',
{ defaultMessage: 'Download Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaDownload.loadingTitle',
{ defaultMessage: 'Downloading Elastic Agent' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaDownload.completedTitle',
{ defaultMessage: 'Elastic Agent downloaded' }
),
},
{
id: 'ea-extract',
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaExtract.incompleteTitle',
{ defaultMessage: 'Extract Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaExtract.loadingTitle',
{ defaultMessage: 'Extracting Elastic Agent' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaExtract.completedTitle',
{ defaultMessage: 'Elastic Agent extracted' }
),
},
{
id: 'ea-install',
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaInstall.incompleteTitle',
{ defaultMessage: 'Install Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaInstall.loadingTitle',
{ defaultMessage: 'Installing Elastic Agent' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaInstall.completedTitle',
{ defaultMessage: 'Elastic Agent installed' }
),
},
{
id: 'ea-status',
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaStatus.incompleteTitle',
{ defaultMessage: 'Connect to the Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaStatus.loadingTitle',
{
defaultMessage:
'Connecting to the Elastic Agent',
}
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaStatus.completedTitle',
{
defaultMessage:
'Connected to the Elastic Agent',
}
),
},
].map((step, index) => {
const { title, status, message } = getStep(step);
return (
<StepStatus
status={status}
title={title}
message={message}
/>
);
})}
</EuiFlexGroup>
</>
)}
</>
), ),
id: 'linux-tar',
}, },
{ {
title: i18n.translate( label: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configureStep.title', 'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform.macOS',
{ defaultMessage: 'Configure the Elastic agent' } { defaultMessage: 'MacOS' }
),
status:
yamlConfigStatus === FETCH_STATUS.LOADING
? 'loading'
: autoDownloadConfigStep.status,
children: (
<>
<EuiText color="subdued">
<p>
{wizardState.autoDownloadConfig
? i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.auto.description',
{
defaultMessage:
'The agent config below will be downloaded by the install script and written to ({configPath}). This will overwrite any existing agent configuration.',
values: {
configPath:
'/opt/Elastic/Agent/elastic-agent.yml',
},
}
)
: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.manual.description',
{
defaultMessage:
'Add the following configuration to {configPath} on the host where you installed the Elastic agent.',
values: {
configPath:
'/opt/Elastic/Agent/elastic-agent.yml',
},
}
)}
</p>
</EuiText>
<EuiSpacer size="m" />
<EuiSkeletonRectangle
isLoading={yamlConfigStatus === FETCH_STATUS.NOT_INITIATED}
contentAriaLabel={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.yamlCodeBlockdescription',
{ defaultMessage: 'Elastic agent yaml configuration' }
)}
width="100%"
height={300}
borderRadius="s"
>
<EuiCodeBlock
language="yaml"
isCopyable
style={{
opacity: wizardState.autoDownloadConfig ? '.5' : '1',
}}
>
{yamlConfig}
</EuiCodeBlock>
</EuiSkeletonRectangle>
<EuiSpacer size="m" />
<EuiButton
iconType="download"
color="primary"
href={`data:application/yaml;base64,${Buffer.from(
yamlConfig,
'utf8'
).toString('base64')}`}
download="elastic-agent.yml"
target="_blank"
isDisabled={wizardState.autoDownloadConfig}
>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.downloadConfigButton',
{ defaultMessage: 'Download config file' }
)}
</EuiButton>
<EuiSpacer size="m" />
<EuiFlexGroup direction="column">
<StepStatus
status={autoDownloadConfigStep.status}
title={autoDownloadConfigStep.title}
message={autoDownloadConfigStep.message}
/>
</EuiFlexGroup>
</>
), ),
id: 'macos',
}, },
getStep({ {
id: 'logs-ingest', label: i18n.translate(
incompleteTitle: i18n.translate( 'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform.windows',
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.incompleteTitle', { defaultMessage: 'Windows' }
{ defaultMessage: 'Ship logs to Elastic Observability' }
), ),
loadingTitle: i18n.translate( id: 'windows',
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.loadingTitle', isDisabled: true,
{ defaultMessage: 'Waiting for Logs to be shipped...' } },
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.completedTitle',
{ defaultMessage: 'Logs are being shipped!' }
),
}),
]} ]}
onSelectPlatform={(id) => setElasticAgentPlatform(id)}
selectedPlatform={elasticAgentPlatform}
installAgentCommand={getElasticAgentSetupCommand({
elasticAgentPlatform,
apiKeyEncoded,
apiEndpoint: setup?.apiEndpoint,
scriptDownloadUrl: setup?.scriptDownloadUrl,
elasticAgentVersion: setup?.elasticAgentVersion,
autoDownloadConfig: wizardState.autoDownloadConfig,
onboardingId,
})}
autoDownloadConfig={wizardState.autoDownloadConfig}
onToggleAutoDownloadConfig={onAutoDownloadConfig}
installAgentStatus={
installShipperSetupStatus === FETCH_STATUS.LOADING
? 'loading'
: isInstallCompleted
? 'complete'
: 'current'
}
showInstallProgressSteps={isInstallStarted}
installProgressSteps={
(progressData?.progress ?? {}) as Partial<
Record<
ProgressStepId,
{ status: EuiStepStatus; message?: string }
>
>
}
configureAgentStatus={
yamlConfigStatus === FETCH_STATUS.LOADING
? 'loading'
: autoDownloadConfigStatus
}
configureAgentYaml={yamlConfig}
appendedSteps={[getCheckLogsStep()]}
/> />
</StepPanelContent> </StepPanelContent>
</StepPanel> </StepPanel>
); );
} }
function getInstallShipperCommand({
elasticAgentPlatform,
apiKeyEncoded = '$API_KEY',
apiEndpoint = '$API_ENDPOINT',
scriptDownloadUrl = '$SCRIPT_DOWNLOAD_URL',
elasticAgentVersion = '$ELASTIC_AGENT_VERSION',
autoDownloadConfig = false,
onboardingId = '$ONBOARDING_ID',
}: {
elasticAgentPlatform: ElasticAgentPlatform;
apiKeyEncoded: string | undefined;
apiEndpoint: string | undefined;
scriptDownloadUrl: string | undefined;
elasticAgentVersion: string | undefined;
autoDownloadConfig: boolean;
onboardingId: string | undefined;
}) {
const setupScriptFilename = 'standalone_agent_setup.sh';
const PLATFORM_COMMAND: Record<ElasticAgentPlatform, string> = {
'linux-tar': oneLine`
curl ${scriptDownloadUrl} -o ${setupScriptFilename} &&
sudo bash ${setupScriptFilename} ${apiKeyEncoded} ${apiEndpoint} ${elasticAgentVersion} ${onboardingId} ${
autoDownloadConfig ? 'autoDownloadConfig=1' : ''
}
`,
macos: oneLine`
curl -O https://elastic.co/agent-setup.sh &&
sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==
`,
windows: oneLine`
curl -O https://elastic.co/agent-setup.sh &&
sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==
`,
};
return PLATFORM_COMMAND[elasticAgentPlatform];
}
function oneLine(parts: TemplateStringsArray, ...args: string[]) {
const str = flatten(zip(parts, args)).join('');
return str.replace(/\s+/g, ' ').trim();
}
type WizardState = ReturnType<ReturnType<typeof useWizard>['getState']>; type WizardState = ReturnType<ReturnType<typeof useWizard>['getState']>;
function hasAlreadySavedFlow({ apiKeyEncoded, onboardingId }: WizardState) { function hasAlreadySavedFlow({ apiKeyEncoded, onboardingId }: WizardState) {
return Boolean(apiKeyEncoded && onboardingId); return Boolean(apiKeyEncoded && onboardingId);
} }
const CHECK_LOGS_LABELS = {
incomplete: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.incompleteTitle',
{ defaultMessage: 'Ship logs to Elastic Observability' }
),
loading: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.loadingTitle',
{ defaultMessage: 'Waiting for Logs to be shipped...' }
),
completed: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.completedTitle',
{ defaultMessage: 'Logs are being shipped!' }
),
};

View file

@ -0,0 +1,49 @@
/*
* 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 { flatten, zip } from 'lodash';
export type ElasticAgentPlatform = 'linux-tar' | 'macos' | 'windows';
export function getElasticAgentSetupCommand({
elasticAgentPlatform,
apiKeyEncoded = '$API_KEY',
apiEndpoint = '$API_ENDPOINT',
scriptDownloadUrl = '$SCRIPT_DOWNLOAD_URL',
elasticAgentVersion = '$ELASTIC_AGENT_VERSION',
autoDownloadConfig = false,
onboardingId = '$ONBOARDING_ID',
}: {
elasticAgentPlatform: ElasticAgentPlatform;
apiKeyEncoded: string | undefined;
apiEndpoint: string | undefined;
scriptDownloadUrl: string | undefined;
elasticAgentVersion: string | undefined;
autoDownloadConfig: boolean;
onboardingId: string | undefined;
}) {
const setupScriptFilename = 'standalone_agent_setup.sh';
const LINUX_MACOS_COMMAND = oneLine`
curl ${scriptDownloadUrl} -o ${setupScriptFilename} &&
sudo bash ${setupScriptFilename} ${apiKeyEncoded} ${apiEndpoint} ${elasticAgentVersion} ${onboardingId} ${
autoDownloadConfig ? `autoDownloadConfig=1` : ''
}
`;
const PLATFORM_COMMAND: Record<ElasticAgentPlatform, string> = {
'linux-tar': LINUX_MACOS_COMMAND,
macos: LINUX_MACOS_COMMAND,
windows: oneLine`
curl -O https://elastic.co/agent-setup.sh &&
sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==
`,
};
return PLATFORM_COMMAND[elasticAgentPlatform];
}
function oneLine(parts: TemplateStringsArray, ...args: string[]) {
const str = flatten(zip(parts, args)).join('');
return str.replace(/\s+/g, ' ').trim();
}

View file

@ -0,0 +1,425 @@
/*
* 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 {
EuiButton,
EuiButtonGroup,
EuiCallOut,
EuiCodeBlock,
EuiFlexGroup,
EuiFlexItem,
EuiIconTip,
EuiLink,
EuiSkeletonRectangle,
EuiSpacer,
EuiSteps,
EuiStepsProps,
EuiSwitch,
EuiText,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { Buffer } from 'buffer';
import React from 'react';
import { intersection } from 'lodash';
import { FormattedMessage } from '@kbn/i18n-react';
import { StepStatus } from './step_status';
export type EuiStepStatus = EuiStepsProps['steps'][number]['status'];
export type ProgressStepId =
| 'ea-download'
| 'ea-extract'
| 'ea-install'
| 'ea-status'
| 'ea-config';
interface Props<PlatformId extends string> {
installAgentPlatformOptions: Array<{
label: string;
id: PlatformId;
isDisabled?: boolean;
}>;
onSelectPlatform: (id: PlatformId) => void;
selectedPlatform: PlatformId;
installAgentCommand: string;
autoDownloadConfig: boolean;
onToggleAutoDownloadConfig: () => void;
installAgentStatus: EuiStepStatus;
showInstallProgressSteps: boolean;
installProgressSteps: Partial<
Record<ProgressStepId, { status: EuiStepStatus; message?: string }>
>;
configureAgentStatus: EuiStepStatus;
configureAgentYaml: string;
appendedSteps?: Array<Omit<EuiStepsProps['steps'][number], 'children'>>;
}
export function InstallElasticAgentSteps<PlatformId extends string>({
installAgentPlatformOptions,
onSelectPlatform,
selectedPlatform,
installAgentCommand,
autoDownloadConfig,
onToggleAutoDownloadConfig,
installAgentStatus,
showInstallProgressSteps,
installProgressSteps,
configureAgentStatus,
configureAgentYaml,
appendedSteps = [],
}: Props<PlatformId>) {
const isInstallStarted =
intersection(
Object.keys(installProgressSteps),
Object.keys(PROGRESS_STEP_TITLES)
).length > 0;
const autoDownloadConfigStep = getStep('ea-config', installProgressSteps);
return (
<EuiSteps
steps={[
{
title: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.title',
{ defaultMessage: 'Install the Elastic Agent' }
),
status: installAgentStatus,
children: (
<>
<EuiText color="subdued">
<p>
<FormattedMessage
id="xpack.observability_onboarding.installElasticAgent.installStep.description"
defaultMessage="Select your platform, and run the install command in your terminal to enroll and start the Elastic Agent. Do this for each host. Review {hostRequirementsLink} before installing."
values={{
hostRequirementsLink: (
<EuiLink
external
href="https://www.elastic.co/guide/en/fleet/8.7/elastic-agent-installation.html"
>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.hostRequirements',
{
defaultMessage:
'host requirements and other installation options',
}
)}
</EuiLink>
),
}}
/>
</p>
</EuiText>
<EuiSpacer size="l" />
<EuiSwitch
label={
<EuiFlexGroup
alignItems="center"
gutterSize="xs"
responsive={false}
>
<EuiFlexItem grow={false}>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig',
{
defaultMessage:
"Automatically download the agent's config",
}
)}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip
content={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig.tooltip',
{
defaultMessage:
"Turn on to add a string to the following code block that downloads the agent's standard configuration to your host during installation. Turn off to manually configure the agent in the next step.",
}
)}
position="right"
/>
</EuiFlexItem>
</EuiFlexGroup>
}
checked={autoDownloadConfig}
onChange={onToggleAutoDownloadConfig}
disabled={isInstallStarted}
/>
<EuiSpacer size="l" />
{autoDownloadConfig && (
<>
<EuiCallOut
title={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig.overwriteWarning',
{
defaultMessage:
'Automatically downloading the agent config will overwrite any existing agent config on your host.',
}
)}
color="warning"
iconType="warning"
/>
<EuiSpacer size="l" />
</>
)}
<EuiButtonGroup
isFullWidth
legend={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.choosePlatform',
{ defaultMessage: 'Choose platform' }
)}
options={installAgentPlatformOptions.map(
({ id, label, isDisabled }) => ({
id,
label,
isDisabled,
})
)}
type="single"
idSelected={selectedPlatform}
onChange={(id: string) => {
onSelectPlatform(id as PlatformId);
}}
isDisabled={isInstallStarted}
/>
<EuiSpacer size="m" />
<EuiCodeBlock language="bash" isCopyable>
{installAgentCommand}
</EuiCodeBlock>
<EuiSpacer size="m" />
{showInstallProgressSteps && (
<>
<EuiSpacer size="m" />
<EuiFlexGroup direction="column" gutterSize="m">
{(
[
'ea-download',
'ea-extract',
'ea-install',
'ea-status',
] as const
).map((stepId) => {
const { title, status, message } = getStep(
stepId,
installProgressSteps
);
return (
<StepStatus
key={stepId}
status={status}
title={title}
message={message}
/>
);
})}
</EuiFlexGroup>
</>
)}
</>
),
},
{
title: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configureStep.title',
{ defaultMessage: 'Configure the Elastic agent' }
),
status: configureAgentStatus,
children: (
<>
<EuiText color="subdued">
<p>
{autoDownloadConfig
? i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.auto.description',
{
defaultMessage:
'The agent config below will be downloaded by the install script and written to ({configPath}). This will overwrite any existing agent configuration.',
values: {
configPath: '/opt/Elastic/Agent/elastic-agent.yml',
},
}
)
: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.manual.description',
{
defaultMessage:
'Add the following configuration to {configPath} on the host where you installed the Elastic agent.',
values: {
configPath: '/opt/Elastic/Agent/elastic-agent.yml',
},
}
)}
</p>
</EuiText>
<EuiSpacer size="m" />
<EuiSkeletonRectangle
isLoading={false}
contentAriaLabel={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.yamlCodeBlockdescription',
{ defaultMessage: 'Elastic agent yaml configuration' }
)}
width="100%"
height={300}
borderRadius="s"
>
<EuiCodeBlock
language="yaml"
isCopyable
style={{
opacity: autoDownloadConfig ? '.5' : '1',
}}
>
{configureAgentYaml}
</EuiCodeBlock>
</EuiSkeletonRectangle>
<EuiSpacer size="m" />
<EuiButton
iconType="download"
color="primary"
href={`data:application/yaml;base64,${Buffer.from(
configureAgentYaml,
'utf8'
).toString('base64')}`}
download="elastic-agent.yml"
target="_blank"
isDisabled={autoDownloadConfig}
>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.configStep.downloadConfigButton',
{ defaultMessage: 'Download config file' }
)}
</EuiButton>
{showInstallProgressSteps && autoDownloadConfig ? (
<>
<EuiSpacer size="m" />
<EuiFlexGroup direction="column">
<StepStatus
status={autoDownloadConfigStep.status}
title={autoDownloadConfigStep.title}
message={autoDownloadConfigStep.message}
/>
</EuiFlexGroup>
</>
) : null}
</>
),
},
...appendedSteps.map((euiStep) => ({ children: null, ...euiStep })),
]}
/>
);
}
function getStep(
id: ProgressStepId,
installProgressSteps: Props<string>['installProgressSteps']
): { title: string; status: EuiStepStatus; message?: string } {
const { loadingTitle, completedTitle, incompleteTitle } =
PROGRESS_STEP_TITLES[id];
const stepProgress = installProgressSteps[id];
if (stepProgress) {
const { status, message } = stepProgress;
const title =
status === 'loading'
? loadingTitle
: status === 'complete'
? completedTitle
: incompleteTitle;
return {
title,
status: status ?? ('incomplete' as const),
message,
};
}
return {
title: incompleteTitle,
status: 'incomplete' as const,
};
}
const PROGRESS_STEP_TITLES: Record<
ProgressStepId,
Record<'incompleteTitle' | 'loadingTitle' | 'completedTitle', string>
> = {
'ea-download': {
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaDownload.incompleteTitle',
{ defaultMessage: 'Download Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaDownload.loadingTitle',
{ defaultMessage: 'Downloading Elastic Agent' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaDownload.completedTitle',
{ defaultMessage: 'Elastic Agent downloaded' }
),
},
'ea-extract': {
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaExtract.incompleteTitle',
{ defaultMessage: 'Extract Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaExtract.loadingTitle',
{ defaultMessage: 'Extracting Elastic Agent' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaExtract.completedTitle',
{ defaultMessage: 'Elastic Agent extracted' }
),
},
'ea-install': {
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaInstall.incompleteTitle',
{ defaultMessage: 'Install Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaInstall.loadingTitle',
{ defaultMessage: 'Installing Elastic Agent' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaInstall.completedTitle',
{ defaultMessage: 'Elastic Agent installed' }
),
},
'ea-status': {
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaStatus.incompleteTitle',
{ defaultMessage: 'Connect to the Elastic Agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaStatus.loadingTitle',
{
defaultMessage: 'Connecting to the Elastic Agent',
}
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaStatus.completedTitle',
{
defaultMessage: 'Connected to the Elastic Agent',
}
),
},
'ea-config': {
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaConfig.incompleteTitle',
{ defaultMessage: 'Configure the agent' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaConfig.loadingTitle',
{ defaultMessage: 'Downloading Elastic Agent config' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.eaConfig.completedTitle',
{
defaultMessage: 'Elastic Agent config written to {configPath}',
values: { configPath: '/opt/Elastic/Agent/elastic-agent.yml' },
}
),
},
};