diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/index.tsx index 34233a00e630ab..bc0a250b9a8092 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/index.tsx @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ShellEnrollmentInstructions } from './shell'; export { ManualInstructions } from './manual'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx index b1da4583b74cc2..5d2938f3e9fa03 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx @@ -4,33 +4,53 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiText, EuiSpacer } from '@elastic/eui'; import React from 'react'; +import { EuiText, EuiSpacer, EuiCode, EuiCodeBlock, EuiCopy, EuiButton } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EnrollmentAPIKey } from '../../../types'; -export const ManualInstructions: React.FunctionComponent = () => { +interface Props { + kibanaUrl: string; + apiKey: EnrollmentAPIKey; + kibanaCASha256?: string; +} + +export const ManualInstructions: React.FunctionComponent = ({ + kibanaUrl, + apiKey, + kibanaCASha256, +}) => { + const command = ` +./elastic-agent enroll ${kibanaUrl} ${apiKey.api_key}${ + kibanaCASha256 ? ` --ca_sha256=${kibanaCASha256}` : '' + } +./elastic-agent run`; return ( <> - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam vestibulum ullamcorper - turpis vitae interdum. Maecenas orci magna, auctor volutpat pellentesque eu, consectetur id - est. Nunc orci lacus, condimentum vel congue ac, fringilla eget tortor. Aliquam blandit, - nisi et congue euismod, leo lectus blandit risus, eu blandit erat metus sit amet leo. Nam - dictum lobortis condimentum. + agent enroll, + }} + /> - - Vivamus sem sapien, dictum eu tellus vel, rutrum aliquam purus. Cras quis cursus nibh. - Aliquam fermentum ipsum nec turpis luctus lobortis. Nulla facilisi. Etiam nec fringilla - urna, sed vehicula ipsum. Quisque vel pellentesque lorem, at egestas enim. Nunc semper elit - lectus, in sollicitudin erat fermentum in. Pellentesque tempus massa eget purus pharetra - blandit. - + +
{command}
+
- - Mauris congue enim nulla, nec semper est posuere non. Donec et eros eu nisi gravida - malesuada eget in velit. Morbi placerat semper euismod. Suspendisse potenti. Morbi quis - porta erat, quis cursus nulla. Aenean mauris lorem, mollis in mattis et, lobortis a lectus. - + + {copy => ( + + + + )} + ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/shell/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/shell/index.tsx deleted file mode 100644 index cb65e31fb74b53..00000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/shell/index.tsx +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 { - EuiButtonEmpty, - EuiContextMenuItem, - EuiContextMenuPanel, - EuiCopy, - EuiFieldText, - EuiPopover, -} from '@elastic/eui'; -import { EnrollmentAPIKey } from '../../../types'; - -// No need for i18n as these are platform names -const PLATFORMS = { - macos: 'macOS', - windows: 'Windows', - linux: 'Linux', -}; - -interface Props { - kibanaUrl: string; - kibanaCASha256?: string; - apiKey: EnrollmentAPIKey; -} - -export const ShellEnrollmentInstructions: React.FunctionComponent = ({ - kibanaUrl, - kibanaCASha256, - apiKey, -}) => { - // Platform state - const [currentPlatform, setCurrentPlatform] = useState('macos'); - const [isPlatformOptionsOpen, setIsPlatformOptionsOpen] = useState(false); - - // Build quick installation command - // const quickInstallInstructions = `${ - // kibanaCASha256 ? `CA_SHA256=${kibanaCASha256} ` : '' - // }API_KEY=${ - // apiKey.api_key - // } sh -c "$(curl ${kibanaUrl}/api/ingest_manager/fleet/install/${currentPlatform})"`; - - const quickInstallInstructions = `./elastic-agent enroll ${kibanaUrl} ${apiKey.api_key}`; - - return ( - <> - setIsPlatformOptionsOpen(true)} - > - {PLATFORMS[currentPlatform]} - - } - isOpen={isPlatformOptionsOpen} - closePopover={() => setIsPlatformOptionsOpen(false)} - > - ( - { - setCurrentPlatform(platform as typeof currentPlatform); - setIsPlatformOptionsOpen(false); - }} - > - {name} - - ))} - /> - - } - append={ - - {copy => } - - } - /> - - ); -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx index 9f2088521ed389..39fa8c6ee87011 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx @@ -6,23 +6,9 @@ import React, { memo } from 'react'; import { dump } from 'js-yaml'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiTitle, - EuiSpacer, - EuiText, - EuiCodeBlock, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; +import { EuiCodeBlock, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { AgentConfig } from '../../../../../types'; -import { - useGetOneAgentConfigFull, - useGetEnrollmentAPIKeys, - useGetOneEnrollmentAPIKey, - useCore, -} from '../../../../../hooks'; -import { ShellEnrollmentInstructions } from '../../../../../components/enrollment_instructions'; +import { useGetOneAgentConfigFull } from '../../../../../hooks'; import { Loading } from '../../../../../components'; const CONFIG_KEYS_ORDER = [ @@ -38,14 +24,7 @@ const CONFIG_KEYS_ORDER = [ ]; export const ConfigYamlView = memo<{ config: AgentConfig }>(({ config }) => { - const core = useCore(); - const fullConfigRequest = useGetOneAgentConfigFull(config.id); - const apiKeysRequest = useGetEnrollmentAPIKeys({ - page: 1, - perPage: 1000, - }); - const apiKeyRequest = useGetOneEnrollmentAPIKey(apiKeysRequest.data?.list?.[0]?.id); if (fullConfigRequest.isLoading && !fullConfigRequest.data) { return ; @@ -72,30 +51,6 @@ export const ConfigYamlView = memo<{ config: AgentConfig }>(({ config }) => { })} - {apiKeyRequest.data && ( - - -

- -

-
- - - - - - -
- )} ); }); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx deleted file mode 100644 index e9347ccd2d6c92..00000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 { - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutHeader, - EuiSpacer, - EuiTitle, - EuiFlexGroup, - EuiFlexItem, - EuiButtonEmpty, - EuiButton, - EuiFlyoutFooter, - EuiLink, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { AgentConfig } from '../../../../../types'; -import { APIKeySelection } from './key_selection'; -import { EnrollmentInstructions } from './instructions'; -import { useFleetStatus } from '../../../../../hooks/use_fleet_status'; -import { useLink } from '../../../../../hooks'; -import { FLEET_PATH } from '../../../../../constants'; - -interface Props { - onClose: () => void; - agentConfigs: AgentConfig[]; -} - -export const AgentEnrollmentFlyout: React.FunctionComponent = ({ - onClose, - agentConfigs = [], -}) => { - const fleetStatus = useFleetStatus(); - const [selectedAPIKeyId, setSelectedAPIKeyId] = useState(); - - const fleetLink = useLink(FLEET_PATH); - - return ( - - - -

- -

-
-
- - {fleetStatus.isReady ? ( - <> - setSelectedAPIKeyId(keyId)} - /> - - - - ) : ( - <> - - - - ), - }} - /> - - )} - - - - - - - - - {fleetStatus.isReady && ( - - - - - - )} - - -
- ); -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx deleted file mode 100644 index 1d2f3bd155622f..00000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 { i18n } from '@kbn/i18n'; -import { EuiSpacer, EuiText, EuiButtonGroup, EuiSteps } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - ShellEnrollmentInstructions, - ManualInstructions, -} from '../../../../../components/enrollment_instructions'; -import { useCore, useGetAgents, useGetOneEnrollmentAPIKey } from '../../../../../hooks'; -import { Loading } from '../../../components'; - -interface Props { - selectedAPIKeyId: string | undefined; -} -function useNewEnrolledAgents() { - // New enrolled agents - const [timestamp] = useState(new Date().toISOString()); - const agentsRequest = useGetAgents( - { - perPage: 100, - page: 1, - showInactive: false, - }, - { - pollIntervalMs: 3000, - } - ); - return React.useMemo(() => { - if (!agentsRequest.data) { - return []; - } - - return agentsRequest.data.list.filter(agent => agent.enrolled_at >= timestamp); - }, [agentsRequest.data, timestamp]); -} - -export const EnrollmentInstructions: React.FunctionComponent = ({ selectedAPIKeyId }) => { - const core = useCore(); - const [installType, setInstallType] = useState<'quickInstall' | 'manual'>('quickInstall'); - - const apiKey = useGetOneEnrollmentAPIKey(selectedAPIKeyId); - - const newAgents = useNewEnrolledAgents(); - if (!apiKey.data) { - return null; - } - - return ( - <> - { - setInstallType(installType === 'manual' ? 'quickInstall' : 'manual'); - }} - buttonSize="m" - isFullWidth - /> - - {installType === 'manual' ? ( - - ) : ( - - ), - }, - { - title: i18n.translate('xpack.ingestManager.agentEnrollment.stepTestAgents', { - defaultMessage: 'Test Agents', - }), - children: ( - - {!newAgents.length ? ( - <> - - - - ) : ( - <> - - - )} - - ), - }, - ]} - /> - )} - - ); -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/key_selection.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/key_selection.tsx deleted file mode 100644 index 67930e51418b0c..00000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/key_selection.tsx +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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 { i18n } from '@kbn/i18n'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiSelect, - EuiSpacer, - EuiText, - EuiLink, - EuiFieldText, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { AgentConfig } from '../../../../../types'; -import { useInput, useCore, sendRequest, useGetEnrollmentAPIKeys } from '../../../../../hooks'; -import { enrollmentAPIKeyRouteService } from '../../../../../services'; - -interface Props { - onKeyChange: (keyId: string | undefined) => void; - agentConfigs: AgentConfig[]; -} - -function useCreateApiKeyForm(configId: string | undefined, onSuccess: (keyId: string) => void) { - const { notifications } = useCore(); - const [isLoading, setIsLoading] = useState(false); - const apiKeyNameInput = useInput(''); - - const onSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - setIsLoading(true); - try { - const res = await sendRequest({ - method: 'post', - path: enrollmentAPIKeyRouteService.getCreatePath(), - body: JSON.stringify({ - name: apiKeyNameInput.value, - config_id: configId, - }), - }); - apiKeyNameInput.clear(); - setIsLoading(false); - onSuccess(res.data.item.id); - } catch (err) { - notifications.toasts.addError(err as Error, { - title: 'Error', - }); - setIsLoading(false); - } - }; - - return { - isLoading, - onSubmit, - apiKeyNameInput, - }; -} - -export const APIKeySelection: React.FunctionComponent = ({ onKeyChange, agentConfigs }) => { - const enrollmentAPIKeysRequest = useGetEnrollmentAPIKeys({ - page: 1, - perPage: 1000, - }); - - 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 []; - } - - return enrollmentAPIKeysRequest.data.list.filter( - key => key.config_id === selectedState.agentConfigId - ); - }, [enrollmentAPIKeysRequest.data, selectedState.agentConfigId]); - - // Select first API key when config change - React.useEffect(() => { - if (!selectedState.enrollmentAPIKeyId && filteredEnrollmentAPIKeys.length > 0) { - const enrollmentAPIKeyId = filteredEnrollmentAPIKeys[0].id; - setSelectedState({ - agentConfigId: selectedState.agentConfigId, - enrollmentAPIKeyId, - }); - onKeyChange(enrollmentAPIKeyId); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [filteredEnrollmentAPIKeys, selectedState.enrollmentAPIKeyId, selectedState.agentConfigId]); - - const [showAPIKeyForm, setShowAPIKeyForm] = useState(false); - const apiKeyForm = useCreateApiKeyForm(selectedState.agentConfigId, async (keyId: string) => { - const res = await enrollmentAPIKeysRequest.sendRequest(); - setSelectedState({ - ...selectedState, - enrollmentAPIKeyId: res.data?.list.find(key => key.id === keyId)?.id, - }); - setShowAPIKeyForm(false); - }); - - return ( - <> - - - - - - - - } - > - ({ - value: agentConfig.id, - text: agentConfig.name, - }))} - value={selectedState.agentConfigId || undefined} - onChange={e => - setSelectedState({ - agentConfigId: e.target.value, - enrollmentAPIKeyId: undefined, - }) - } - /> - - - - - } - labelAppend={ - - setShowAPIKeyForm(!showAPIKeyForm)} color="primary"> - {showAPIKeyForm ? ( - - ) : ( - - )} - - - } - > - {showAPIKeyForm ? ( -
- - - ) : ( - ({ - value: key.id, - text: key.name, - }))} - value={selectedState.enrollmentAPIKeyId || undefined} - onChange={e => { - setSelectedState({ - ...selectedState, - enrollmentAPIKeyId: e.target.value, - }); - onKeyChange(selectedState.enrollmentAPIKeyId); - }} - /> - )} -
-
-
- - ); -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/index.ts deleted file mode 100644 index c82c82db6f7138..00000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * 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. - */ -export { AgentEnrollmentFlyout } from './agent_enrollment_flyout'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx index 5e7fe745a0c4a7..829b0cb69e67bf 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx @@ -25,7 +25,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage, FormattedRelative } from '@kbn/i18n/react'; import { CSSProperties } from 'styled-components'; -import { AgentEnrollmentFlyout } from './components'; +import { AgentEnrollmentFlyout } from '../components'; import { Agent } from '../../../types'; import { usePagination, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_datasource_badges.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_datasource_badges.tsx new file mode 100644 index 00000000000000..30bc9dc7014270 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_datasource_badges.tsx @@ -0,0 +1,59 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { EuiSpacer, EuiText, EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; +import { Datasource } from '../../../types'; +import { useGetOneAgentConfig } from '../../../hooks'; +import { PackageIcon } from '../../../components/package_icon'; + +interface Props { + agentConfigId: string; +} + +export const AgentConfigDatasourceBadges: React.FunctionComponent = ({ agentConfigId }) => { + const agentConfigRequest = useGetOneAgentConfig(agentConfigId); + const agentConfig = agentConfigRequest.data ? agentConfigRequest.data.item : null; + + if (!agentConfig) { + return null; + } + return ( + <> + + {agentConfig.datasources.length}, + }} + /> + + + {(agentConfig.datasources as Datasource[]).map((datasource, idx) => { + if (!datasource.package) { + return null; + } + return ( + + + + + + {datasource.package.title} + + + ); + })} + + ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/config_selection.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/config_selection.tsx new file mode 100644 index 00000000000000..a8cebfdf899a67 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/config_selection.tsx @@ -0,0 +1,129 @@ +/* + * 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 { 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 { AgentConfigDatasourceBadges } from '../agent_config_datasource_badges'; + +interface Props { + agentConfigs: AgentConfig[]; + onKeyChange: (key: string) => void; +} + +export const EnrollmentStepAgentConfig: React.FC = ({ agentConfigs, onKeyChange }) => { + const [isAuthenticationSettingsOpen, setIsAuthenticationSettingsOpen] = useState(false); + const enrollmentAPIKeysRequest = useGetEnrollmentAPIKeys({ + page: 1, + perPage: 1000, + }); + + 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 []; + } + + return enrollmentAPIKeysRequest.data.list.filter( + key => key.config_id === selectedState.agentConfigId + ); + }, [enrollmentAPIKeysRequest.data, selectedState.agentConfigId]); + + // Select first API key when config change + React.useEffect(() => { + if (!selectedState.enrollmentAPIKeyId && filteredEnrollmentAPIKeys.length > 0) { + const enrollmentAPIKeyId = filteredEnrollmentAPIKeys[0].id; + setSelectedState({ + agentConfigId: selectedState.agentConfigId, + enrollmentAPIKeyId, + }); + onKeyChange(enrollmentAPIKeyId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [filteredEnrollmentAPIKeys, selectedState.enrollmentAPIKeyId, selectedState.agentConfigId]); + + return ( + <> + + + + } + options={agentConfigs.map(config => ({ + value: config.id, + text: config.name, + }))} + value={selectedState.agentConfigId || undefined} + onChange={e => + setSelectedState({ + agentConfigId: e.target.value, + enrollmentAPIKeyId: undefined, + }) + } + aria-label={i18n.translate( + 'xpack.ingestManager.enrollmentStepAgentConfig.configSelectAriaLabel', + { defaultMessage: 'Agent configuration' } + )} + /> + + {selectedState.agentConfigId && ( + + )} + + setIsAuthenticationSettingsOpen(!isAuthenticationSettingsOpen)} + > + + + {isAuthenticationSettingsOpen && ( + <> + + ({ + value: key.id, + text: key.name, + }))} + value={selectedState.enrollmentAPIKeyId || undefined} + prepend={ + + + + } + onChange={e => { + setSelectedState({ + ...selectedState, + enrollmentAPIKeyId: e.target.value, + }); + onKeyChange(e.target.value); + }} + /> + + )} + + ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/index.tsx new file mode 100644 index 00000000000000..002b4772d92167 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/index.tsx @@ -0,0 +1,131 @@ +/* + * 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 { + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiButton, + EuiFlyoutFooter, + EuiSteps, + EuiText, + EuiLink, +} 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 } from '../../../../hooks'; +import { ManualInstructions } from '../../../../components/enrollment_instructions'; + +interface Props { + onClose: () => void; + agentConfigs: AgentConfig[]; +} + +export const AgentEnrollmentFlyout: React.FunctionComponent = ({ + onClose, + agentConfigs = [], +}) => { + const core = useCore(); + const [selectedAPIKeyId, setSelectedAPIKeyId] = useState(); + + 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: ( + + + + + ), + }} + /> + + ), + }, + { + title: i18n.translate('xpack.ingestManager.agentEnrollment.stepChooseAgentConfigTitle', { + defaultMessage: 'Choose an agent configuration', + }), + children: ( + + ), + }, + { + title: i18n.translate('xpack.ingestManager.agentEnrollment.stepRunAgentTitle', { + defaultMessage: 'Enroll and run the Elastic Agent', + }), + children: apiKey.data && ( + + ), + }, + ]; + + return ( + + + +

+ +

+
+
+ + + + + + + + + + + + + + + + + +
+ ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_reassign_config_flyout/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_reassign_config_flyout/index.tsx index 692c60cdce38c1..2c103ade31f5b1 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_reassign_config_flyout/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_reassign_config_flyout/index.tsx @@ -19,17 +19,11 @@ import { EuiSelect, EuiFormRow, EuiText, - EuiBadge, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Datasource, Agent } from '../../../../types'; -import { - useGetOneAgentConfig, - sendPutAgentReassign, - useCore, - useGetAgentConfigs, -} from '../../../../hooks'; -import { PackageIcon } from '../../../../components/package_icon'; +import { Agent } from '../../../../types'; +import { sendPutAgentReassign, useCore, useGetAgentConfigs } from '../../../../hooks'; +import { AgentConfigDatasourceBadges } from '../agent_config_datasource_badges'; interface Props { onClose: () => void; @@ -45,9 +39,6 @@ export const AgentReassignConfigFlyout: React.FunctionComponent = ({ onCl const agentConfigsRequest = useGetAgentConfigs(); const agentConfigs = agentConfigsRequest.data ? agentConfigsRequest.data.items : []; - const agentConfigRequest = useGetOneAgentConfig(selectedAgentConfigId); - const agentConfig = agentConfigRequest.data ? agentConfigRequest.data.item : null; - const [isSubmitting, setIsSubmitting] = useState(false); async function onSubmit() { @@ -121,40 +112,9 @@ export const AgentReassignConfigFlyout: React.FunctionComponent = ({ onCl - {agentConfig && ( - - {agentConfig.datasources.length}, - }} - /> - + {selectedAgentConfigId && ( + )} - - {agentConfig && - (agentConfig.datasources as Datasource[]).map((datasource, idx) => { - if (!datasource.package) { - return null; - } - return ( - - - - - - {datasource.package.title} - - - ); - })} @@ -168,7 +128,7 @@ export const AgentReassignConfigFlyout: React.FunctionComponent = ({ onCl ; savedObjects: SavedObjectsServiceStart; isProductionMode: boolean; - serverInfo?: HttpServerInfo; + kibanaVersion: string; cloud?: CloudSetup; + httpSetup?: HttpServiceSetup; } export type IngestManagerSetupContract = void; @@ -108,15 +109,17 @@ export class IngestManagerPlugin private cloud: CloudSetup | undefined; private isProductionMode: boolean; - private serverInfo: HttpServerInfo | undefined; + private kibanaVersion: string; + private httpSetup: HttpServiceSetup | undefined; constructor(private readonly initializerContext: PluginInitializerContext) { this.config$ = this.initializerContext.config.create(); this.isProductionMode = this.initializerContext.env.mode.prod; + this.kibanaVersion = this.initializerContext.env.packageInfo.version; } public async setup(core: CoreSetup, deps: IngestManagerSetupDeps) { - this.serverInfo = core.http.getServerInfo(); + this.httpSetup = core.http; this.licensing$ = deps.licensing.license$; if (deps.security) { this.security = deps.security; @@ -179,7 +182,6 @@ export class IngestManagerPlugin registerEnrollmentApiKeyRoutes(router); registerInstallScriptRoutes({ router, - serverInfo: core.http.getServerInfo(), basePath: core.http.basePath, }); } @@ -197,7 +199,8 @@ export class IngestManagerPlugin config$: this.config$, savedObjects: core.savedObjects, isProductionMode: this.isProductionMode, - serverInfo: this.serverInfo, + kibanaVersion: this.kibanaVersion, + httpSetup: this.httpSetup, cloud: this.cloud, }); licenseService.start(this.licensing$); diff --git a/x-pack/plugins/ingest_manager/server/routes/install_script/index.ts b/x-pack/plugins/ingest_manager/server/routes/install_script/index.ts index b007e61594e9de..2a8d4fdbec4977 100644 --- a/x-pack/plugins/ingest_manager/server/routes/install_script/index.ts +++ b/x-pack/plugins/ingest_manager/server/routes/install_script/index.ts @@ -4,27 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ import url from 'url'; -import { IRouter, BasePath, HttpServerInfo, KibanaRequest } from 'src/core/server'; +import { IRouter, BasePath, KibanaRequest } from 'src/core/server'; import { INSTALL_SCRIPT_API_ROUTES } from '../../constants'; import { getScript } from '../../services/install_script'; import { InstallScriptRequestSchema } from '../../types'; +import { appContextService, settingsService } from '../../services'; + +function getInternalUserSOClient(request: KibanaRequest) { + // soClient as kibana internal users, be carefull on how you use it, security is not enabled + return appContextService.getSavedObjects().getScopedClient(request, { + excludedWrappers: ['security'], + }); +} export const registerRoutes = ({ router, - basePath, - serverInfo, }: { router: IRouter; basePath: Pick; - serverInfo: HttpServerInfo; }) => { - const kibanaUrl = url.format({ - protocol: serverInfo.protocol, - hostname: serverInfo.host, - port: serverInfo.port, - pathname: basePath.serverBasePath, - }); - router.get( { path: INSTALL_SCRIPT_API_ROUTES, @@ -36,6 +34,19 @@ export const registerRoutes = ({ request: KibanaRequest<{ osType: 'macos' }>, response ) { + const soClient = getInternalUserSOClient(request); + const http = appContextService.getHttpSetup(); + const serverInfo = http.getServerInfo(); + const basePath = http.basePath; + const kibanaUrl = + (await settingsService.getSettings(soClient)).kibana_url || + url.format({ + protocol: serverInfo.protocol, + hostname: serverInfo.host, + port: serverInfo.port, + pathname: basePath.serverBasePath, + }); + const script = getScript(request.params.osType, kibanaUrl); return response.ok({ body: script }); diff --git a/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts index 542dfa9cefe8f9..abe5f3620d214e 100644 --- a/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts +++ b/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts @@ -13,7 +13,7 @@ export const getFleetStatusHandler: RequestHandler = async (context, request, re try { const isAdminUserSetup = (await outputService.getAdminUser(soClient)) !== null; const isApiKeysEnabled = await appContextService.getSecurity().authc.areAPIKeysEnabled(); - const isTLSEnabled = appContextService.getServerInfo().protocol === 'https'; + const isTLSEnabled = appContextService.getHttpSetup().getServerInfo().protocol === 'https'; const isProductionMode = appContextService.getIsProductionMode(); const isCloud = appContextService.getCloud()?.isCloudEnabled ?? false; const isTLSCheckDisabled = appContextService.getConfig()?.fleet?.tlsCheckDisabled ?? false; diff --git a/x-pack/plugins/ingest_manager/server/services/app_context.ts b/x-pack/plugins/ingest_manager/server/services/app_context.ts index 5e538ad84b4c21..6da0a137fa087e 100644 --- a/x-pack/plugins/ingest_manager/server/services/app_context.ts +++ b/x-pack/plugins/ingest_manager/server/services/app_context.ts @@ -5,7 +5,7 @@ */ import { BehaviorSubject, Observable } from 'rxjs'; import { first } from 'rxjs/operators'; -import { SavedObjectsServiceStart, HttpServerInfo } from 'src/core/server'; +import { SavedObjectsServiceStart, HttpServiceSetup } from 'src/core/server'; import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server'; import { SecurityPluginSetup } from '../../../security/server'; import { IngestManagerConfigType } from '../../common'; @@ -18,17 +18,19 @@ class AppContextService { private config$?: Observable; private configSubject$?: BehaviorSubject; private savedObjects: SavedObjectsServiceStart | undefined; - private serverInfo: HttpServerInfo | undefined; private isProductionMode: boolean = false; + private kibanaVersion: string | undefined; private cloud?: CloudSetup; + private httpSetup?: HttpServiceSetup; public async start(appContext: IngestManagerAppContext) { this.encryptedSavedObjects = appContext.encryptedSavedObjects; this.security = appContext.security; this.savedObjects = appContext.savedObjects; - this.serverInfo = appContext.serverInfo; this.isProductionMode = appContext.isProductionMode; this.cloud = appContext.cloud; + this.kibanaVersion = appContext.kibanaVersion; + this.httpSetup = appContext.httpSetup; if (appContext.config$) { this.config$ = appContext.config$; @@ -77,11 +79,18 @@ class AppContextService { return this.isProductionMode; } - public getServerInfo() { - if (!this.serverInfo) { - throw new Error('Server info not set.'); + public getHttpSetup() { + if (!this.httpSetup) { + throw new Error('HttpServiceSetup not set.'); } - return this.serverInfo; + return this.httpSetup; + } + + public getKibanaVersion() { + if (!this.kibanaVersion) { + throw new Error('Kibana version is not set.'); + } + return this.kibanaVersion; } } diff --git a/x-pack/plugins/ingest_manager/server/services/install_script/index.ts b/x-pack/plugins/ingest_manager/server/services/install_script/index.ts index 7e7f8d2a3734b0..02386531f5d61b 100644 --- a/x-pack/plugins/ingest_manager/server/services/install_script/index.ts +++ b/x-pack/plugins/ingest_manager/server/services/install_script/index.ts @@ -4,14 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ +import { appContextService } from '../app_context'; import { macosInstallTemplate } from './install_templates/macos'; +import { linuxInstallTemplate } from './install_templates/linux'; -export function getScript(osType: 'macos', kibanaUrl: string): string { - const variables = { kibanaUrl }; +export function getScript(osType: 'macos' | 'linux', kibanaUrl: string): string { + const variables = { kibanaUrl, kibanaVersion: appContextService.getKibanaVersion() }; switch (osType) { case 'macos': return macosInstallTemplate(variables); + case 'linux': + return linuxInstallTemplate(variables); default: throw new Error(`${osType} is not supported.`); } diff --git a/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/linux.ts b/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/linux.ts new file mode 100644 index 00000000000000..0bb68c40bc5809 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/linux.ts @@ -0,0 +1,21 @@ +/* + * 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 { InstallTemplateFunction } from './types'; + +export const linuxInstallTemplate: InstallTemplateFunction = variables => { + const artifact = `elastic-agent-${variables.kibanaVersion}-linux-x86_64`; + + return `#!/bin/sh + +set -e +curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/${artifact}.tar.gz +tar -xzvf ${artifact}.tar.gz +cd ${artifact} +./elastic-agent enroll ${variables.kibanaUrl} $API_KEY --force +./elastic-agent run +`; +}; diff --git a/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/macos.ts b/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/macos.ts index e59dc6174b40ff..11bb58d184d33c 100644 --- a/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/macos.ts +++ b/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/macos.ts @@ -4,12 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { resolve } from 'path'; import { InstallTemplateFunction } from './types'; -const PROJECT_ROOT = resolve(__dirname, '../../../../'); -export const macosInstallTemplate: InstallTemplateFunction = variables => `#!/bin/sh +export const macosInstallTemplate: InstallTemplateFunction = variables => { + const artifact = `elastic-agent-${variables.kibanaVersion}-darwin-x86_64`; -eval "node ${PROJECT_ROOT}/scripts/dev_agent --enrollmentApiKey=$API_KEY --kibanaUrl=${variables.kibanaUrl}" + return `#!/bin/sh +set -e +curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/${artifact}.tar.gz +tar -xzvf ${artifact}.tar.gz +cd ${artifact} +./elastic-agent enroll ${variables.kibanaUrl} $API_KEY --force +./elastic-agent run `; +}; diff --git a/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/types.ts b/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/types.ts index a478beaa96cfca..65d57f8ac7dbfe 100644 --- a/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/types.ts +++ b/x-pack/plugins/ingest_manager/server/services/install_script/install_templates/types.ts @@ -4,4 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -export type InstallTemplateFunction = (variables: { kibanaUrl: string }) => string; +export type InstallTemplateFunction = (variables: { + kibanaUrl: string; + kibanaVersion: string; +}) => string; diff --git a/x-pack/plugins/ingest_manager/server/services/setup.ts b/x-pack/plugins/ingest_manager/server/services/setup.ts index 3619628bd4f8b9..22acce8d4a51c7 100644 --- a/x-pack/plugins/ingest_manager/server/services/setup.ts +++ b/x-pack/plugins/ingest_manager/server/services/setup.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import url from 'url'; import uuid from 'uuid'; import { SavedObjectsClientContract } from 'src/core/server'; import { CallESAsCurrentUser } from '../types'; @@ -38,10 +39,21 @@ export async function setupIngestManager( agentConfigService.ensureDefaultAgentConfig(soClient), settingsService.getSettings(soClient).catch((e: any) => { if (e.isBoom && e.output.statusCode === 404) { + const http = appContextService.getHttpSetup(); + const serverInfo = http.getServerInfo(); + const basePath = http.basePath; + + const defaultKibanaUrl = url.format({ + protocol: serverInfo.protocol, + hostname: serverInfo.host, + port: serverInfo.port, + pathname: basePath.serverBasePath, + }); + return settingsService.saveSettings(soClient, { agent_auto_upgrade: true, package_auto_upgrade: true, - kibana_url: appContextService.getConfig()?.fleet?.kibana?.host, + kibana_url: appContextService.getConfig()?.fleet?.kibana?.host ?? defaultKibanaUrl, }); } diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/install_script.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/install_script.ts index cf676129cce7ad..f872efc006b764 100644 --- a/x-pack/plugins/ingest_manager/server/types/rest_spec/install_script.ts +++ b/x-pack/plugins/ingest_manager/server/types/rest_spec/install_script.ts @@ -8,6 +8,6 @@ import { schema } from '@kbn/config-schema'; export const InstallScriptRequestSchema = { params: schema.object({ - osType: schema.oneOf([schema.literal('macos')]), + osType: schema.oneOf([schema.literal('macos'), schema.literal('linux')]), }), }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index aeb86144635d9a..aab3636e2375b3 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8219,18 +8219,9 @@ "xpack.ingestManager.agentDetails.statusLabel": "ステータス", "xpack.ingestManager.agentDetails.unexceptedErrorTitle": "エージェントを読み込む間にエラーが発生しました", "xpack.ingestManager.agentDetails.userProvidedMetadataSectionSubtitle": "ユーザー提供メタデータ", - "xpack.ingestManager.agentEnrollment.apiKeySelectionDescription": "ご希望のエージェント構成とプラットフォームをすばやく選択できます。次いで、以下の手順に従ってエージェントをセットアップして登録します。", "xpack.ingestManager.agentEnrollment.cancelButtonLabel": "キャンセル", "xpack.ingestManager.agentEnrollment.continueButtonLabel": "続行", "xpack.ingestManager.agentEnrollment.flyoutTitle": "新しいエージェントを登録", - "xpack.ingestManager.agentEnrollment.installManuallyTitle": "手動でインストール", - "xpack.ingestManager.agentEnrollment.newAgentsMessage": "{count, plural, one {# 新規エージェント} other {# 新規エージェント}}。", - "xpack.ingestManager.agentEnrollment.quickInstallTitle": "簡易インストール", - "xpack.ingestManager.agentEnrollment.selectAgentConfig": "エージェント構成", - "xpack.ingestManager.agentEnrollment.selectAPIKeyTitle": "登録 API キー", - "xpack.ingestManager.agentEnrollment.stepSetupAgents": "Beats エージェントのセットアップ", - "xpack.ingestManager.agentEnrollment.stepTestAgents": "エージェントのテスト", - "xpack.ingestManager.agentEnrollment.testAgentLoadingMessage": "新しいエージェントの登録を待っています", "xpack.ingestManager.agentEventsList.messageColumnTitle": "メッセージ", "xpack.ingestManager.agentEventsList.refreshButton": "更新", "xpack.ingestManager.agentEventsList.subtypeColumnTitle": "サブタイプ", @@ -8340,9 +8331,6 @@ "xpack.ingestManager.deleteDatasource.successSingleNotificationTitle": "データソース「{id}」を削除しました", "xpack.ingestManager.disabledSecurityDescription": "Elastic Fleet を使用するには、Kibana と Elasticsearch でセキュリティを有効にする必要があります。", "xpack.ingestManager.disabledSecurityTitle": "セキュリティが有効ではありません", - "xpack.ingestManager.enrollmentApiKeyForm.namePlaceholder": "名前を選択", - "xpack.ingestManager.enrollmentApiKeyList.createNewButton": "新規キーを作成", - "xpack.ingestManager.enrollmentApiKeyList.useExistingsButton": "既存のキーを使用", "xpack.ingestManager.epm.addDatasourceButtonText": "データソースを作成", "xpack.ingestManager.epm.pageSubtitle": "人気のアプリやサービスのパッケージを参照する", "xpack.ingestManager.epm.pageTitle": "Elastic Package Manager", @@ -8371,8 +8359,6 @@ "xpack.ingestManager.unenrollAgents.confirmModal.loadingButtonLabel": "読み込み中...", "xpack.ingestManager.unenrollAgents.fatalErrorNotificationTitle": "エージェントの登録解除エラー", "xpack.ingestManager.unenrollAgents.successSingleNotificationTitle": "エージェント「{id}」の登録を解除しました", - "xpack.ingestManager.yamlConfig.instructionDescription": "この構成でエージェントを登録するには、ホストで次のコマンドをコピーして実行します。", - "xpack.ingestManager.yamlConfig.instructionTittle": "フリートに登録", "xpack.lens.app.docLoadingError": "保存されたドキュメントの保存中にエラーが発生", "xpack.lens.app.docSavingError": "ドキュメントの保存中にエラーが発生", "xpack.lens.app.indexPatternLoadingError": "インデックスパターンの読み込み中にエラーが発生", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 104d53a93088a3..853d56fbdf7a90 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8225,18 +8225,9 @@ "xpack.ingestManager.agentDetails.statusLabel": "状态", "xpack.ingestManager.agentDetails.unexceptedErrorTitle": "加载代理时发生错误", "xpack.ingestManager.agentDetails.userProvidedMetadataSectionSubtitle": "用户提供的元数据", - "xpack.ingestManager.agentEnrollment.apiKeySelectionDescription": "快速选择所需的代理配置和平台。然后,根据下面的说明设置和注册代理。", "xpack.ingestManager.agentEnrollment.cancelButtonLabel": "取消", "xpack.ingestManager.agentEnrollment.continueButtonLabel": "继续", "xpack.ingestManager.agentEnrollment.flyoutTitle": "注册新代理", - "xpack.ingestManager.agentEnrollment.installManuallyTitle": "手动安装", - "xpack.ingestManager.agentEnrollment.newAgentsMessage": "{count, plural, one {# 个新代理} other {# 个新代理}}.", - "xpack.ingestManager.agentEnrollment.quickInstallTitle": "快速安装", - "xpack.ingestManager.agentEnrollment.selectAgentConfig": "代理配置", - "xpack.ingestManager.agentEnrollment.selectAPIKeyTitle": "注册 API 密钥", - "xpack.ingestManager.agentEnrollment.stepSetupAgents": "设置 Beats 代理", - "xpack.ingestManager.agentEnrollment.stepTestAgents": "测试代理", - "xpack.ingestManager.agentEnrollment.testAgentLoadingMessage": "正在等候新代理注册", "xpack.ingestManager.agentEventsList.messageColumnTitle": "消息", "xpack.ingestManager.agentEventsList.refreshButton": "刷新", "xpack.ingestManager.agentEventsList.subtypeColumnTitle": "子类型", @@ -8346,9 +8337,6 @@ "xpack.ingestManager.deleteDatasource.successSingleNotificationTitle": "已删除数据源“{id}”", "xpack.ingestManager.disabledSecurityDescription": "必须在 Kibana 和 Elasticsearch 启用安全性,才能使用 Elastic Fleet。", "xpack.ingestManager.disabledSecurityTitle": "安全性未启用", - "xpack.ingestManager.enrollmentApiKeyForm.namePlaceholder": "选择名称", - "xpack.ingestManager.enrollmentApiKeyList.createNewButton": "创建新密钥", - "xpack.ingestManager.enrollmentApiKeyList.useExistingsButton": "使用现有密钥", "xpack.ingestManager.epm.addDatasourceButtonText": "创建数据源", "xpack.ingestManager.epm.pageSubtitle": "浏览热门应用和服务的软件。", "xpack.ingestManager.epm.pageTitle": "Elastic Package Manager", @@ -8377,8 +8365,6 @@ "xpack.ingestManager.unenrollAgents.confirmModal.loadingButtonLabel": "正在加载……", "xpack.ingestManager.unenrollAgents.fatalErrorNotificationTitle": "取消注册代理时出错", "xpack.ingestManager.unenrollAgents.successSingleNotificationTitle": "已取消注册代理“{id}”", - "xpack.ingestManager.yamlConfig.instructionDescription": "要将代理注册到此配置,请在您的主机上复制并运行以下命令。", - "xpack.ingestManager.yamlConfig.instructionTittle": "注册到 fleet", "xpack.lens.app.docLoadingError": "加载已保存文档时出错", "xpack.lens.app.docSavingError": "保存文档时出错", "xpack.lens.app.indexPatternLoadingError": "加载索引模式时出错",