[Ingest Manager] Add UI to enroll standalone agent (#71288)

This commit is contained in:
Nicolas Chaulet 2020-07-13 11:33:51 -04:00 committed by GitHub
parent 24edc804c9
commit 17dc0439e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 517 additions and 164 deletions

View file

@ -11,8 +11,8 @@ const CONFIG_KEYS_ORDER = [
'name',
'revision',
'type',
'settings',
'outputs',
'settings',
'inputs',
'enabled',
'use_output',

View file

@ -48,6 +48,17 @@ export const useGetOneAgentConfigFull = (agentConfigId: string) => {
});
};
export const sendGetOneAgentConfigFull = (
agentConfigId: string,
query: { standalone?: boolean } = {}
) => {
return sendRequest<GetFullAgentConfigResponse>({
path: agentConfigRouteService.getInfoFullPath(agentConfigId),
method: 'get',
query,
});
};
export const sendGetOneAgentConfig = (agentConfigId: string) => {
return sendRequest<GetOneAgentConfigResponse>({
path: agentConfigRouteService.getInfoPath(agentConfigId),

View file

@ -44,6 +44,18 @@ export function sendDeleteOneEnrollmentAPIKey(keyId: string, options?: RequestOp
});
}
export function sendGetEnrollmentAPIKeys(
query: GetEnrollmentAPIKeysRequest['query'],
options?: RequestOptions
) {
return sendRequest<GetEnrollmentAPIKeysResponse>({
method: 'get',
path: enrollmentAPIKeyRouteService.getListPath(),
query,
...options,
});
}
export function useGetEnrollmentAPIKeys(
query: GetEnrollmentAPIKeysRequest['query'],
options?: RequestOptions

View file

@ -4,46 +4,91 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSelect, EuiSpacer, EuiText, EuiButtonEmpty } from '@elastic/eui';
import { AgentConfig } from '../../../../types';
import { useGetEnrollmentAPIKeys } from '../../../../hooks';
import { AgentConfig, GetEnrollmentAPIKeysResponse } from '../../../../types';
import { sendGetEnrollmentAPIKeys, useCore } from '../../../../hooks';
import { AgentConfigPackageBadges } from '../agent_config_package_badges';
interface Props {
type Props = {
agentConfigs: AgentConfig[];
onKeyChange: (key: string) => void;
}
onConfigChange?: (key: string) => void;
} & (
| {
withKeySelection: true;
onKeyChange?: (key: string) => void;
}
| {
withKeySelection: false;
}
);
export const EnrollmentStepAgentConfig: React.FC<Props> = (props) => {
const { notifications } = useCore();
const { withKeySelection, agentConfigs, onConfigChange } = props;
const onKeyChange = props.withKeySelection && props.onKeyChange;
export const EnrollmentStepAgentConfig: React.FC<Props> = ({ agentConfigs, onKeyChange }) => {
const [isAuthenticationSettingsOpen, setIsAuthenticationSettingsOpen] = useState(false);
const enrollmentAPIKeysRequest = useGetEnrollmentAPIKeys({
page: 1,
perPage: 1000,
});
const [enrollmentAPIKeys, setEnrollmentAPIKeys] = useState<GetEnrollmentAPIKeysResponse['list']>(
[]
);
const [selectedState, setSelectedState] = useState<{
agentConfigId?: string;
enrollmentAPIKeyId?: string;
}>({
agentConfigId: agentConfigs.length ? agentConfigs[0].id : undefined,
});
const filteredEnrollmentAPIKeys = React.useMemo(() => {
if (!selectedState.agentConfigId || !enrollmentAPIKeysRequest.data) {
return [];
useEffect(() => {
if (onConfigChange && selectedState.agentConfigId) {
onConfigChange(selectedState.agentConfigId);
}
}, [selectedState.agentConfigId, onConfigChange]);
useEffect(() => {
if (!withKeySelection) {
return;
}
if (!selectedState.agentConfigId) {
setEnrollmentAPIKeys([]);
return;
}
return enrollmentAPIKeysRequest.data.list.filter(
(key) => key.config_id === selectedState.agentConfigId
);
}, [enrollmentAPIKeysRequest.data, selectedState.agentConfigId]);
async function fetchEnrollmentAPIKeys() {
try {
const res = await sendGetEnrollmentAPIKeys({
page: 1,
perPage: 10000,
});
if (res.error) {
throw res.error;
}
if (!res.data) {
throw new Error('No data while fetching enrollment API keys');
}
setEnrollmentAPIKeys(
res.data.list.filter((key) => key.config_id === selectedState.agentConfigId)
);
} catch (error) {
notifications.toasts.addError(error, {
title: 'Error',
});
}
}
fetchEnrollmentAPIKeys();
}, [withKeySelection, selectedState.agentConfigId, notifications.toasts]);
// Select first API key when config change
React.useEffect(() => {
if (!selectedState.enrollmentAPIKeyId && filteredEnrollmentAPIKeys.length > 0) {
const enrollmentAPIKeyId = filteredEnrollmentAPIKeys[0].id;
if (!withKeySelection || !onKeyChange) {
return;
}
if (!selectedState.enrollmentAPIKeyId && enrollmentAPIKeys.length > 0) {
const enrollmentAPIKeyId = enrollmentAPIKeys[0].id;
setSelectedState({
agentConfigId: selectedState.agentConfigId,
enrollmentAPIKeyId,
@ -51,7 +96,7 @@ export const EnrollmentStepAgentConfig: React.FC<Props> = ({ agentConfigs, onKey
onKeyChange(enrollmentAPIKeyId);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [filteredEnrollmentAPIKeys, selectedState.enrollmentAPIKeyId, selectedState.agentConfigId]);
}, [enrollmentAPIKeys, selectedState.enrollmentAPIKeyId, selectedState.agentConfigId]);
return (
<>
@ -85,43 +130,47 @@ export const EnrollmentStepAgentConfig: React.FC<Props> = ({ agentConfigs, onKey
{selectedState.agentConfigId && (
<AgentConfigPackageBadges agentConfigId={selectedState.agentConfigId} />
)}
<EuiSpacer size="m" />
<EuiButtonEmpty
flush="left"
iconType={isAuthenticationSettingsOpen ? 'arrowDown' : 'arrowRight'}
onClick={() => setIsAuthenticationSettingsOpen(!isAuthenticationSettingsOpen)}
>
<FormattedMessage
id="xpack.ingestManager.enrollmentStepAgentConfig.showAuthenticationSettingsButton"
defaultMessage="Authentication settings"
/>
</EuiButtonEmpty>
{isAuthenticationSettingsOpen && (
{withKeySelection && onKeyChange && (
<>
<EuiSpacer size="m" />
<EuiSelect
fullWidth
options={filteredEnrollmentAPIKeys.map((key) => ({
value: key.id,
text: key.name,
}))}
value={selectedState.enrollmentAPIKeyId || undefined}
prepend={
<EuiText>
<FormattedMessage
id="xpack.ingestManager.enrollmentStepAgentConfig.enrollmentTokenSelectLabel"
defaultMessage="Enrollment token"
/>
</EuiText>
}
onChange={(e) => {
setSelectedState({
...selectedState,
enrollmentAPIKeyId: e.target.value,
});
onKeyChange(e.target.value);
}}
/>
<EuiButtonEmpty
flush="left"
iconType={isAuthenticationSettingsOpen ? 'arrowDown' : 'arrowRight'}
onClick={() => setIsAuthenticationSettingsOpen(!isAuthenticationSettingsOpen)}
>
<FormattedMessage
id="xpack.ingestManager.enrollmentStepAgentConfig.showAuthenticationSettingsButton"
defaultMessage="Authentication settings"
/>
</EuiButtonEmpty>
{isAuthenticationSettingsOpen && (
<>
<EuiSpacer size="m" />
<EuiSelect
fullWidth
options={enrollmentAPIKeys.map((key) => ({
value: key.id,
text: key.name,
}))}
value={selectedState.enrollmentAPIKeyId || undefined}
prepend={
<EuiText>
<FormattedMessage
id="xpack.ingestManager.enrollmentStepAgentConfig.enrollmentTokenSelectLabel"
defaultMessage="Enrollment token"
/>
</EuiText>
}
onChange={(e) => {
setSelectedState({
...selectedState,
enrollmentAPIKeyId: e.target.value,
});
onKeyChange(e.target.value);
}}
/>
</>
)}
</>
)}
</>

View file

@ -14,23 +14,13 @@ import {
EuiButtonEmpty,
EuiButton,
EuiFlyoutFooter,
EuiSteps,
EuiText,
EuiLink,
EuiTab,
EuiTabs,
} from '@elastic/eui';
import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { AgentConfig } from '../../../../types';
import { EnrollmentStepAgentConfig } from './config_selection';
import {
useGetOneEnrollmentAPIKey,
useCore,
useGetSettings,
useLink,
useFleetStatus,
} from '../../../../hooks';
import { ManualInstructions } from '../../../../components/enrollment_instructions';
import { ManagedInstructions } from './managed_instructions';
import { StandaloneInstructions } from './standalone_instructions';
interface Props {
onClose: () => void;
@ -41,99 +31,40 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<Props> = ({
onClose,
agentConfigs = [],
}) => {
const { getHref } = useLink();
const core = useCore();
const fleetStatus = useFleetStatus();
const [selectedAPIKeyId, setSelectedAPIKeyId] = useState<string | undefined>();
const settings = useGetSettings();
const apiKey = useGetOneEnrollmentAPIKey(selectedAPIKeyId);
const kibanaUrl =
settings.data?.item?.kibana_url ?? `${window.location.origin}${core.http.basePath.get()}`;
const kibanaCASha256 = settings.data?.item?.kibana_ca_sha256;
const steps: EuiContainedStepProps[] = [
{
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepDownloadAgentTitle', {
defaultMessage: 'Download the Elastic Agent',
}),
children: (
<EuiText>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.downloadDescription"
defaultMessage="Download the Elastic agent on your hosts machine. You can download the agent binary and its verification signature from Elastics {downloadLink}."
values={{
downloadLink: (
<EuiLink href="https://ela.st/download-elastic-agent" target="_blank">
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.downloadLink"
defaultMessage="download page"
/>
</EuiLink>
),
}}
/>
</EuiText>
),
},
{
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepChooseAgentConfigTitle', {
defaultMessage: 'Choose an agent configuration',
}),
children: (
<EnrollmentStepAgentConfig agentConfigs={agentConfigs} onKeyChange={setSelectedAPIKeyId} />
),
},
{
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepRunAgentTitle', {
defaultMessage: 'Enroll and run the Elastic Agent',
}),
children: apiKey.data && (
<ManualInstructions
apiKey={apiKey.data.item}
kibanaUrl={kibanaUrl}
kibanaCASha256={kibanaCASha256}
/>
),
},
];
const [mode, setMode] = useState<'managed' | 'standalone'>('managed');
return (
<EuiFlyout onClose={onClose} size="l" maxWidth={860}>
<EuiFlyout onClose={onClose} size="l" maxWidth={880}>
<EuiFlyoutHeader hasBorder aria-labelledby="FleetAgentEnrollmentFlyoutTitle">
<EuiTitle size="m">
<h2 id="FleetAgentEnrollmentFlyoutTitle">
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.flyoutTitle"
defaultMessage="Enroll new agent"
defaultMessage="Add agent"
/>
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
{fleetStatus.isReady ? (
<>
<EuiSteps steps={steps} />
</>
) : (
<>
<EuiTabs style={{ marginBottom: '-25px' }}>
<EuiTab isSelected={mode === 'managed'} onClick={() => setMode('managed')}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.fleetNotInitializedText"
defaultMessage="Fleet needs to be set up before agents can be enrolled. {link}"
values={{
link: (
<EuiLink href={getHref('fleet')}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.goToFleetButton"
defaultMessage="Go to Fleet."
/>
</EuiLink>
),
}}
id="xpack.ingestManager.agentEnrollment.enrollFleetTabLabel"
defaultMessage="Enroll with Fleet"
/>
</>
</EuiTab>
<EuiTab isSelected={mode === 'standalone'} onClick={() => setMode('standalone')}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.enrollStandaloneTabLabel"
defaultMessage="Standalone mode"
/>
</EuiTab>
</EuiTabs>
</EuiFlyoutHeader>
<EuiFlyoutBody>
{mode === 'managed' ? (
<ManagedInstructions agentConfigs={agentConfigs} />
) : (
<StandaloneInstructions agentConfigs={agentConfigs} />
)}
</EuiFlyoutBody>
<EuiFlyoutFooter>

View file

@ -0,0 +1,91 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useState } from 'react';
import { EuiSteps, EuiLink, EuiText, EuiSpacer } from '@elastic/eui';
import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { AgentConfig } from '../../../../types';
import {
useGetOneEnrollmentAPIKey,
useCore,
useGetSettings,
useLink,
useFleetStatus,
} from '../../../../hooks';
import { ManualInstructions } from '../../../../components/enrollment_instructions';
import { DownloadStep, AgentConfigSelectionStep } from './steps';
interface Props {
agentConfigs: AgentConfig[];
}
export const ManagedInstructions: React.FunctionComponent<Props> = ({ agentConfigs = [] }) => {
const { getHref } = useLink();
const core = useCore();
const fleetStatus = useFleetStatus();
const [selectedAPIKeyId, setSelectedAPIKeyId] = useState<string | undefined>();
const settings = useGetSettings();
const apiKey = useGetOneEnrollmentAPIKey(selectedAPIKeyId);
const kibanaUrl =
settings.data?.item?.kibana_url ?? `${window.location.origin}${core.http.basePath.get()}`;
const kibanaCASha256 = settings.data?.item?.kibana_ca_sha256;
const steps: EuiContainedStepProps[] = [
DownloadStep(),
AgentConfigSelectionStep({ agentConfigs, setSelectedAPIKeyId }),
{
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepEnrollAndRunAgentTitle', {
defaultMessage: 'Enroll and start the Elastic Agent',
}),
children: apiKey.data && (
<ManualInstructions
apiKey={apiKey.data.item}
kibanaUrl={kibanaUrl}
kibanaCASha256={kibanaCASha256}
/>
),
},
];
return (
<>
<EuiText>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.managedDescription"
defaultMessage="Whether you need one agent or thousands, Fleet makes it easy to centrally manage and deploy updates to your agents. Follow the instructions below to download and enroll an Elastic Agent with Fleet."
/>
</EuiText>
<EuiSpacer size="l" />
{fleetStatus.isReady ? (
<>
<EuiSteps steps={steps} />
</>
) : (
<>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.fleetNotInitializedText"
defaultMessage="Fleet needs to be set up before agents can be enrolled. {link}"
values={{
link: (
<EuiLink href={getHref('fleet')}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.goToFleetButton"
defaultMessage="Go to Fleet."
/>
</EuiLink>
),
}}
/>
</>
)}{' '}
</>
);
};

View file

@ -0,0 +1,181 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useState, useEffect, useMemo } from 'react';
import {
EuiSteps,
EuiText,
EuiSpacer,
EuiButton,
EuiCode,
EuiFlexItem,
EuiFlexGroup,
EuiCodeBlock,
EuiCopy,
} from '@elastic/eui';
import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { AgentConfig } from '../../../../types';
import { useCore, sendGetOneAgentConfigFull } from '../../../../hooks';
import { DownloadStep, AgentConfigSelectionStep } from './steps';
import { configToYaml, agentConfigRouteService } from '../../../../services';
interface Props {
agentConfigs: AgentConfig[];
}
const RUN_INSTRUCTIONS = './elastic-agent run';
export const StandaloneInstructions: React.FunctionComponent<Props> = ({ agentConfigs = [] }) => {
const core = useCore();
const { notifications } = core;
const [selectedConfigId, setSelectedConfigId] = useState<string | undefined>();
const [fullAgentConfig, setFullAgentConfig] = useState<any | undefined>();
const downloadLink = selectedConfigId
? core.http.basePath.prepend(
`${agentConfigRouteService.getInfoFullDownloadPath(selectedConfigId)}?standalone=true`
)
: undefined;
useEffect(() => {
async function fetchFullConfig() {
try {
if (!selectedConfigId) {
return;
}
const res = await sendGetOneAgentConfigFull(selectedConfigId, { standalone: true });
if (res.error) {
throw res.error;
}
if (!res.data) {
throw new Error('No data while fetching full agent config');
}
setFullAgentConfig(res.data.item);
} catch (error) {
notifications.toasts.addError(error, {
title: 'Error',
});
}
}
fetchFullConfig();
}, [selectedConfigId, notifications.toasts]);
const yaml = useMemo(() => configToYaml(fullAgentConfig), [fullAgentConfig]);
const steps: EuiContainedStepProps[] = [
DownloadStep(),
AgentConfigSelectionStep({ agentConfigs, setSelectedConfigId }),
{
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepConfigureAgentTitle', {
defaultMessage: 'Configure the agent',
}),
children: (
<>
<EuiText>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.stepConfigureAgentDescription"
defaultMessage="Copy this configuration and put it into a file named {fileName} on the system where the Elastic Agent is installed. Dont forget to modify {ESUsernameVariable} and {ESPasswordVariable} in the {outputSection} section of the configuration file so that it uses your actual Elasticsearch credentials."
values={{
fileName: <EuiCode>elastic-agent.yml</EuiCode>,
ESUsernameVariable: <EuiCode>ES_USERNAME</EuiCode>,
ESPasswordVariable: <EuiCode>ES_PASSWORD</EuiCode>,
outputSection: <EuiCode>outputs</EuiCode>,
}}
/>
<EuiSpacer size="m" />
<EuiFlexGroup gutterSize="m">
<EuiFlexItem grow={false}>
<EuiCopy textToCopy={yaml}>
{(copy) => (
<EuiButton onClick={copy} iconType="copyClipboard">
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.copyConfigurationButton"
defaultMessage="Copy to clipboard"
/>
</EuiButton>
)}
</EuiCopy>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton iconType="download" href={downloadLink} isDisabled={!downloadLink}>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.downloadConfigurationButton"
defaultMessage="Download configuration"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
<EuiCodeBlock language="yaml" style={{ maxHeight: 300 }} fontSize="m">
{yaml}
</EuiCodeBlock>
</EuiText>
</>
),
},
{
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepRunAgentTitle', {
defaultMessage: 'Start the agent',
}),
children: (
<>
<EuiText>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.stepRunAgentDescription"
defaultMessage="From the agents directory, run the following command to start the agent."
/>
<EuiSpacer size="m" />
<EuiCodeBlock fontSize="m">{RUN_INSTRUCTIONS}</EuiCodeBlock>
<EuiSpacer size="m" />
<EuiCopy textToCopy={RUN_INSTRUCTIONS}>
{(copy) => (
<EuiButton onClick={copy} iconType="copyClipboard">
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.copyRunInstructionsButton"
defaultMessage="Copy to clipboard"
/>
</EuiButton>
)}
</EuiCopy>
</EuiText>
</>
),
},
{
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepCheckForDataTitle', {
defaultMessage: 'Check for data',
}),
status: 'incomplete',
children: (
<>
<EuiText>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.stepCheckForDataDescription"
defaultMessage="After starting the agent, the agent should begin sending data. You can view this data on Ingest Managers datasets page."
/>
</EuiText>
</>
),
},
];
return (
<>
<EuiText>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.standaloneDescription"
defaultMessage="Agents running in standalone mode need to be updated manually if you ever wish to make changes to their configuration. Follow the instructions below to download and setup an Elastic Agent in standalone mode."
/>
</EuiText>
<EuiSpacer size="l" />
<EuiSteps steps={steps} />
</>
);
};

View file

@ -0,0 +1,66 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { EuiText, EuiButton, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { EnrollmentStepAgentConfig } from './config_selection';
import { AgentConfig } from '../../../../types';
export const DownloadStep = () => {
return {
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepDownloadAgentTitle', {
defaultMessage: 'Download the Elastic Agent',
}),
children: (
<>
<EuiText>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.downloadDescription"
defaultMessage="Download the Elastic Agent on your hosts machine. You can access the agent binaries and their verification signatures from the Elastic Agent download page."
/>
</EuiText>
<EuiSpacer size="l" />
<EuiButton
href="https://ela.st/download-elastic-agent"
target="_blank"
iconSide="right"
iconType="popout"
>
<FormattedMessage
id="xpack.ingestManager.agentEnrollment.downloadLink"
defaultMessage="Go to elastic.co/downloads"
/>
</EuiButton>
</>
),
};
};
export const AgentConfigSelectionStep = ({
agentConfigs,
setSelectedAPIKeyId,
setSelectedConfigId,
}: {
agentConfigs: AgentConfig[];
setSelectedAPIKeyId?: (key: string) => void;
setSelectedConfigId?: (configId: string) => void;
}) => {
return {
title: i18n.translate('xpack.ingestManager.agentEnrollment.stepChooseAgentConfigTitle', {
defaultMessage: 'Choose an agent configuration',
}),
children: (
<EnrollmentStepAgentConfig
agentConfigs={agentConfigs}
withKeySelection={setSelectedAPIKeyId ? true : false}
onKeyChange={setSelectedAPIKeyId}
onConfigChange={setSelectedConfigId}
/>
),
};
};

View file

@ -232,15 +232,17 @@ export const deleteAgentConfigsHandler: RequestHandler<
}
};
export const getFullAgentConfig: RequestHandler<TypeOf<
typeof GetFullAgentConfigRequestSchema.params
>> = async (context, request, response) => {
export const getFullAgentConfig: RequestHandler<
TypeOf<typeof GetFullAgentConfigRequestSchema.params>,
TypeOf<typeof GetFullAgentConfigRequestSchema.query>
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
try {
const fullAgentConfig = await agentConfigService.getFullConfig(
soClient,
request.params.agentConfigId
request.params.agentConfigId,
{ standalone: request.query.standalone === true }
);
if (fullAgentConfig) {
const body: GetFullAgentConfigResponse = {
@ -264,16 +266,19 @@ export const getFullAgentConfig: RequestHandler<TypeOf<
}
};
export const downloadFullAgentConfig: RequestHandler<TypeOf<
typeof GetFullAgentConfigRequestSchema.params
>> = async (context, request, response) => {
export const downloadFullAgentConfig: RequestHandler<
TypeOf<typeof GetFullAgentConfigRequestSchema.params>,
TypeOf<typeof GetFullAgentConfigRequestSchema.query>
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
const {
params: { agentConfigId },
} = request;
try {
const fullAgentConfig = await agentConfigService.getFullConfig(soClient, agentConfigId);
const fullAgentConfig = await agentConfigService.getFullConfig(soClient, agentConfigId, {
standalone: request.query.standalone === true,
});
if (fullAgentConfig) {
const body = configToYaml(fullAgentConfig);
const headers: ResponseHeaders = {

View file

@ -365,7 +365,8 @@ class AgentConfigService {
public async getFullConfig(
soClient: SavedObjectsClientContract,
id: string
id: string,
options?: { standalone: boolean }
): Promise<FullAgentConfig | null> {
let config;
@ -400,6 +401,13 @@ class AgentConfigService {
api_key,
...outputConfig,
};
if (options?.standalone) {
delete outputs[name].api_key;
outputs[name].username = 'ES_USERNAME';
outputs[name].password = 'ES_PASSWORD';
}
return outputs;
},
{} as FullAgentConfig['outputs']

View file

@ -51,5 +51,6 @@ export const GetFullAgentConfigRequestSchema = {
}),
query: schema.object({
download: schema.maybe(schema.boolean()),
standalone: schema.maybe(schema.boolean()),
}),
};

View file

@ -8042,7 +8042,6 @@
"xpack.ingestManager.agentDetails.viewAgentListTitle": "すべてのエージェント構成を表示",
"xpack.ingestManager.agentEnrollment.cancelButtonLabel": "キャンセル",
"xpack.ingestManager.agentEnrollment.continueButtonLabel": "続行",
"xpack.ingestManager.agentEnrollment.downloadDescription": "ホストのコンピューターでElasticエージェントをダウンロードします。エージェントバイナリをダウンロードできます。検証署名はElasticの{downloadLink}にあります。",
"xpack.ingestManager.agentEnrollment.downloadLink": "ダウンロードページ",
"xpack.ingestManager.agentEnrollment.fleetNotInitializedText": "エージェントを登録する前に、フリートを設定する必要があります。{link}",
"xpack.ingestManager.agentEnrollment.flyoutTitle": "新しいエージェントを登録",

View file

@ -8047,7 +8047,6 @@
"xpack.ingestManager.agentDetails.viewAgentListTitle": "查看所有代理配置",
"xpack.ingestManager.agentEnrollment.cancelButtonLabel": "取消",
"xpack.ingestManager.agentEnrollment.continueButtonLabel": "继续",
"xpack.ingestManager.agentEnrollment.downloadDescription": "在主机计算机上下载 Elastic 代理。可以从 Elastic 的{downloadLink}下载代理二进制文件及其验证签名。",
"xpack.ingestManager.agentEnrollment.downloadLink": "下载页面",
"xpack.ingestManager.agentEnrollment.fleetNotInitializedText": "注册代理前需要设置 Fleet。{link}",
"xpack.ingestManager.agentEnrollment.flyoutTitle": "注册新代理",