mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Observability Onboarding] Auto-detect flow (#186106)
Resolves #183362 ## Summary Implements auto-detect based onboarding flow. The new flow can only be accessed behind a hidden URL: `/app/observabilityOnboarding/auto-detect?category=logs` ## Screenshots ### Kibana <img width="1243" alt="Screenshot 2024-06-12 at 16 05 54" src="ab4d01a4
-431b-425e-acc1-80cb7adadb35"> ### Terminal <img width="1188" alt="Screenshot 2024-06-12 at 16 07 32" src="e5924156
-d2c5-487d-af2f-163c3d114e93"> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Joe Reuter <johannes.reuter@elastic.co>
This commit is contained in:
parent
8bd7124ca1
commit
f015066fcf
29 changed files with 1443 additions and 265 deletions
|
@ -1,22 +1,37 @@
|
|||
{
|
||||
"type": "plugin",
|
||||
"id": "@kbn/observability-onboarding-plugin",
|
||||
"owner": ["@elastic/obs-ux-logs-team", "@elastic/obs-ux-onboarding-team"],
|
||||
"owner": [
|
||||
"@elastic/obs-ux-logs-team",
|
||||
"@elastic/obs-ux-onboarding-team"
|
||||
],
|
||||
"plugin": {
|
||||
"id": "observabilityOnboarding",
|
||||
"server": true,
|
||||
"browser": true,
|
||||
"configPath": ["xpack", "observability_onboarding"],
|
||||
"configPath": [
|
||||
"xpack",
|
||||
"observability_onboarding"
|
||||
],
|
||||
"requiredPlugins": [
|
||||
"data",
|
||||
"observability",
|
||||
"observabilityShared",
|
||||
"discover",
|
||||
"share",
|
||||
"fleet"
|
||||
"fleet",
|
||||
"security"
|
||||
],
|
||||
"optionalPlugins": ["cloud", "cloudExperiments", "usageCollection"],
|
||||
"requiredBundles": ["kibanaReact"],
|
||||
"extraPublicDirs": ["common"]
|
||||
"optionalPlugins": [
|
||||
"cloud",
|
||||
"cloudExperiments",
|
||||
"usageCollection"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact"
|
||||
],
|
||||
"extraPublicDirs": [
|
||||
"common"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import { ObservabilityOnboardingHeaderActionMenu } from './shared/header_action_
|
|||
import {
|
||||
ObservabilityOnboardingPluginSetupDeps,
|
||||
ObservabilityOnboardingPluginStartDeps,
|
||||
ObservabilityOnboardingContextValue,
|
||||
} from '../plugin';
|
||||
import { ObservabilityOnboardingFlow } from './observability_onboarding_flow';
|
||||
|
||||
|
@ -40,14 +41,13 @@ export const breadcrumbsApp = {
|
|||
export function ObservabilityOnboardingAppRoot({
|
||||
appMountParameters,
|
||||
core,
|
||||
deps,
|
||||
corePlugins: { observability, data },
|
||||
corePlugins,
|
||||
config,
|
||||
}: {
|
||||
appMountParameters: AppMountParameters;
|
||||
} & RenderAppProps) {
|
||||
const { history, setHeaderActionMenu, theme$ } = appMountParameters;
|
||||
const plugins = { ...deps };
|
||||
const services: ObservabilityOnboardingContextValue = { ...core, ...corePlugins, config };
|
||||
|
||||
const renderFeedbackLinkAsPortal = !config.serverless.enabled;
|
||||
|
||||
|
@ -63,15 +63,7 @@ export function ObservabilityOnboardingAppRoot({
|
|||
application: core.application,
|
||||
}}
|
||||
>
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
...core,
|
||||
...plugins,
|
||||
observability,
|
||||
data,
|
||||
config,
|
||||
}}
|
||||
>
|
||||
<KibanaContextProvider services={services}>
|
||||
<KibanaThemeProvider
|
||||
theme={{ theme$ }}
|
||||
modify={{
|
||||
|
|
|
@ -17,6 +17,7 @@ import { OnboardingFlowForm } from './onboarding_flow_form/onboarding_flow_form'
|
|||
import { Header } from './header/header';
|
||||
import { SystemLogsPanel } from './quickstart_flows/system_logs';
|
||||
import { CustomLogsPanel } from './quickstart_flows/custom_logs';
|
||||
import { AutoDetectPanel } from './quickstart_flows/auto_detect';
|
||||
import { BackButton } from './shared/back_button';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
@ -52,6 +53,10 @@ export function ObservabilityOnboardingFlow() {
|
|||
</EuiPageTemplate.Section>
|
||||
<EuiPageTemplate.Section paddingSize="xl" color="subdued" restrictWidth>
|
||||
<Routes>
|
||||
<Route path="/auto-detect">
|
||||
<BackButton />
|
||||
<AutoDetectPanel />
|
||||
</Route>
|
||||
<Route path="/systemLogs">
|
||||
<BackButton />
|
||||
<SystemLogsPanel />
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* 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 React, { type FunctionComponent } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
EuiPanel,
|
||||
EuiSteps,
|
||||
EuiCodeBlock,
|
||||
EuiSpacer,
|
||||
EuiSkeletonText,
|
||||
EuiBadge,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiImage,
|
||||
EuiSkeletonRectangle,
|
||||
useGeneratedHtmlId,
|
||||
} from '@elastic/eui';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import {
|
||||
type SingleDatasetLocatorParams,
|
||||
SINGLE_DATASET_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { type DashboardLocatorParams } from '@kbn/dashboard-plugin/public';
|
||||
import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics';
|
||||
import { getAutoDetectCommand } from './get_auto_detect_command';
|
||||
import { useOnboardingFlow } from './use_onboarding_flow';
|
||||
import { ProgressIndicator } from '../shared/progress_indicator';
|
||||
import { AccordionWithIcon } from '../shared/accordion_with_icon';
|
||||
import { type ObservabilityOnboardingContextValue } from '../../../plugin';
|
||||
import { EmptyPrompt } from '../shared/empty_prompt';
|
||||
import { CopyToClipboardButton } from '../shared/copy_to_clipboard_button';
|
||||
import { LocatorButtonEmpty } from '../shared/locator_button_empty';
|
||||
|
||||
export const AutoDetectPanel: FunctionComponent = () => {
|
||||
const {
|
||||
services: { http },
|
||||
} = useKibana<ObservabilityOnboardingContextValue>();
|
||||
const { status, data, error, refetch, installedIntegrations } = useOnboardingFlow();
|
||||
const command = data ? getAutoDetectCommand(data) : undefined;
|
||||
const accordionId = useGeneratedHtmlId({ prefix: 'accordion' });
|
||||
|
||||
if (error) {
|
||||
return <EmptyPrompt error={error} onRetryClick={refetch} />;
|
||||
}
|
||||
|
||||
const registryIntegrations = installedIntegrations.filter(
|
||||
(integration) => integration.installSource === 'registry'
|
||||
);
|
||||
const customIntegrations = installedIntegrations.filter(
|
||||
(integration) => integration.installSource === 'custom'
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiPanel hasBorder paddingSize="xl">
|
||||
<EuiSteps
|
||||
steps={[
|
||||
{
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.runTheCommandOnLabel',
|
||||
{ defaultMessage: 'Run the command on your host' }
|
||||
),
|
||||
status: status === 'notStarted' ? 'current' : 'complete',
|
||||
children: command ? (
|
||||
<>
|
||||
<EuiText>
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.p.wellScanYourHostLabel',
|
||||
{
|
||||
defaultMessage: "We'll scan your host for logs and metrics, including:",
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
{['Apache', 'Docker', 'Nginx', 'System', 'Custom .log files'].map((item) => (
|
||||
<EuiFlexItem key={item} grow={false}>
|
||||
<EuiBadge color="hollow">{item}</EuiBadge>
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer />
|
||||
{/* Bash syntax highlighting only highlights a few random numbers (badly) so it looks less messy to go with plain text */}
|
||||
<EuiCodeBlock paddingSize="m" language="text">
|
||||
{command}
|
||||
</EuiCodeBlock>
|
||||
<EuiSpacer />
|
||||
<CopyToClipboardButton textToCopy={command} fill={status === 'notStarted'} />
|
||||
</>
|
||||
) : (
|
||||
<EuiSkeletonText lines={6} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.visualizeYourDataLabel',
|
||||
{ defaultMessage: 'Visualize your data' }
|
||||
),
|
||||
status:
|
||||
status === 'dataReceived'
|
||||
? 'complete'
|
||||
: status === 'awaitingData' || status === 'inProgress'
|
||||
? 'current'
|
||||
: 'incomplete',
|
||||
children: (
|
||||
<>
|
||||
{status === 'dataReceived' ? (
|
||||
<ProgressIndicator
|
||||
iconType="cheer"
|
||||
title={i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.yourDataIsReadyToExploreLabel',
|
||||
{ defaultMessage: 'Your data is ready to explore!' }
|
||||
)}
|
||||
isLoading={false}
|
||||
/>
|
||||
) : status === 'awaitingData' ? (
|
||||
<ProgressIndicator
|
||||
title={i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.installingElasticAgentFlexItemLabel',
|
||||
{ defaultMessage: 'Waiting for data to arrive...' }
|
||||
)}
|
||||
/>
|
||||
) : status === 'inProgress' ? (
|
||||
<ProgressIndicator
|
||||
title={i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.lookingForLogFilesFlexItemLabel',
|
||||
{ defaultMessage: 'Waiting for installation to complete...' }
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
{(status === 'awaitingData' || status === 'dataReceived') &&
|
||||
installedIntegrations.length > 0 ? (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
{registryIntegrations.map((integration) => (
|
||||
<AccordionWithIcon
|
||||
key={integration.pkgName}
|
||||
id={`${accordionId}_${integration.pkgName}`}
|
||||
iconType="desktop"
|
||||
title={i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.h3.getStartedWithNginxLabel',
|
||||
{
|
||||
defaultMessage: 'Get started with {title} logs',
|
||||
values: { title: integration.title },
|
||||
}
|
||||
)}
|
||||
isDisabled={status !== 'dataReceived'}
|
||||
initialIsOpen
|
||||
>
|
||||
<EuiFlexGroup responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
{status === 'dataReceived' ? (
|
||||
<EuiImage
|
||||
src={http.staticAssets.getPluginAssetHref('charts_screen.svg')}
|
||||
width={162}
|
||||
height={117}
|
||||
alt=""
|
||||
hasShadow
|
||||
/>
|
||||
) : (
|
||||
<EuiSkeletonRectangle width={162} height={117} />
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<ul>
|
||||
{integration.kibanaAssets
|
||||
.filter((asset) => asset.type === 'dashboard')
|
||||
.map((dashboard) => (
|
||||
<li key={dashboard.id}>
|
||||
<LocatorButtonEmpty<DashboardLocatorParams>
|
||||
locator={DASHBOARD_APP_LOCATOR}
|
||||
params={{ dashboardId: dashboard.id }}
|
||||
target="_blank"
|
||||
iconType="dashboardApp"
|
||||
isDisabled={status !== 'dataReceived'}
|
||||
flush="left"
|
||||
size="s"
|
||||
>
|
||||
{dashboard.attributes.title}
|
||||
</LocatorButtonEmpty>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</AccordionWithIcon>
|
||||
))}
|
||||
{customIntegrations.length > 0 && (
|
||||
<AccordionWithIcon
|
||||
id={`${accordionId}_custom`}
|
||||
iconType="documents"
|
||||
title={i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.h3.getStartedWithlogLabel',
|
||||
{ defaultMessage: 'Get started with custom .log files' }
|
||||
)}
|
||||
isDisabled={status !== 'dataReceived'}
|
||||
initialIsOpen
|
||||
>
|
||||
<ul>
|
||||
{customIntegrations.map((integration) =>
|
||||
integration.dataStreams.map((datastream) => (
|
||||
<li key={`${integration.pkgName}/${datastream.dataset}`}>
|
||||
<LocatorButtonEmpty<SingleDatasetLocatorParams>
|
||||
locator={SINGLE_DATASET_LOCATOR_ID}
|
||||
params={{
|
||||
integration: integration.pkgName,
|
||||
dataset: datastream.dataset,
|
||||
}}
|
||||
target="_blank"
|
||||
iconType="document"
|
||||
isDisabled={status !== 'dataReceived'}
|
||||
flush="left"
|
||||
size="s"
|
||||
>
|
||||
{integration.pkgName}
|
||||
</LocatorButtonEmpty>
|
||||
</li>
|
||||
))
|
||||
)}
|
||||
</ul>
|
||||
</AccordionWithIcon>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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';
|
||||
import { useOnboardingFlow } from './use_onboarding_flow';
|
||||
|
||||
export function getAutoDetectCommand(
|
||||
options: NonNullable<ReturnType<typeof useOnboardingFlow>['data']>
|
||||
) {
|
||||
const scriptName = 'auto_detect.sh';
|
||||
return oneLine`
|
||||
curl ${options.scriptDownloadUrl} -so ${scriptName} &&
|
||||
sudo bash ${scriptName}
|
||||
--id=${options.onboardingFlow.id}
|
||||
--kibana-url=${options.kibanaUrl}
|
||||
--install-key=${options.installApiKey}
|
||||
--ingest-key=${options.ingestApiKey}
|
||||
--ea-version=${options.elasticAgentVersion}
|
||||
`;
|
||||
}
|
||||
function oneLine(parts: TemplateStringsArray, ...args: string[]) {
|
||||
const str = flatten(zip(parts, args)).join('');
|
||||
return str.replace(/\s+/g, ' ').trim();
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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 type { InstallIntegrationsStepPayload } from '../../../../server/routes/types';
|
||||
import type { ObservabilityOnboardingFlow } from '../../../../server/saved_objects/observability_onboarding_status';
|
||||
import type { InstalledIntegration } from '../../../../server/routes/types';
|
||||
|
||||
export function getInstalledIntegrations(
|
||||
data: Pick<ObservabilityOnboardingFlow, 'progress'> | undefined
|
||||
): InstalledIntegration[] {
|
||||
return (data?.progress['install-integrations']?.payload as InstallIntegrationsStepPayload) ?? [];
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { ObservabilityOnboardingFlow } from '../../../../server/saved_objects/observability_onboarding_status';
|
||||
|
||||
export type ObservabilityOnboardingFlowStatus =
|
||||
| 'notStarted'
|
||||
| 'inProgress'
|
||||
| 'awaitingData'
|
||||
| 'dataReceived';
|
||||
|
||||
/**
|
||||
* Returns the current status of the onboarding flow:
|
||||
*
|
||||
* - `notStarted`: No progress has been made.
|
||||
* - `inProgress`: The user is running the installation command on the host.
|
||||
* - `awaitingData`: The installation has completed and we are waiting for data to be ingested.
|
||||
* - `dataReceived`: Data has been ingested - The Agent is up and running.
|
||||
*/
|
||||
export function getOnboardingStatus(
|
||||
data: Pick<ObservabilityOnboardingFlow, 'progress'> | undefined
|
||||
): ObservabilityOnboardingFlowStatus {
|
||||
if (!data) {
|
||||
return 'notStarted';
|
||||
}
|
||||
return data.progress['logs-ingest']?.status === 'complete'
|
||||
? 'dataReceived'
|
||||
: data.progress['logs-ingest']?.status === 'loading'
|
||||
? 'awaitingData'
|
||||
: Object.values(data.progress).some((step) => step.status !== 'incomplete')
|
||||
? 'inProgress'
|
||||
: 'notStarted';
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { AutoDetectPanel } from './auto_detect_panel';
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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 useInterval from 'react-use/lib/useInterval';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { type AssetSOObject, type GetBulkAssetsResponse } from '@kbn/fleet-plugin/common';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { getOnboardingStatus } from './get_onboarding_status';
|
||||
import { getInstalledIntegrations } from './get_installed_integrations';
|
||||
import { type ObservabilityOnboardingContextValue } from '../../../plugin';
|
||||
|
||||
export function useOnboardingFlow() {
|
||||
const {
|
||||
services: { fleet },
|
||||
} = useKibana<ObservabilityOnboardingContextValue>();
|
||||
|
||||
// Create onboarding session
|
||||
const { data, error, refetch } = useFetcher(
|
||||
(callApi) =>
|
||||
callApi('POST /internal/observability_onboarding/flow', {
|
||||
params: {
|
||||
body: {
|
||||
name: 'auto-detect',
|
||||
},
|
||||
},
|
||||
}),
|
||||
[],
|
||||
{ showToastOnError: false }
|
||||
);
|
||||
|
||||
const onboardingId = data?.onboardingFlow.id;
|
||||
|
||||
// Fetch onboarding progress
|
||||
const {
|
||||
data: progressData,
|
||||
status: progressStatus,
|
||||
refetch: refetchProgress,
|
||||
} = useFetcher(
|
||||
(callApi) => {
|
||||
if (onboardingId) {
|
||||
return callApi('GET /internal/observability_onboarding/flow/{onboardingId}/progress', {
|
||||
params: { path: { onboardingId } },
|
||||
});
|
||||
}
|
||||
},
|
||||
[onboardingId]
|
||||
);
|
||||
|
||||
const status = getOnboardingStatus(progressData);
|
||||
const installedIntegrations = getInstalledIntegrations(progressData);
|
||||
|
||||
// Fetch metadata for installed Kibana assets
|
||||
const assetsState = useAsync(async () => {
|
||||
if (installedIntegrations.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const assetsMetadata = await fleet.hooks.epm.getBulkAssets({
|
||||
assetIds: installedIntegrations
|
||||
.map((integration) => integration.kibanaAssets)
|
||||
.flat() as AssetSOObject[],
|
||||
});
|
||||
return installedIntegrations.map((integration) => {
|
||||
return {
|
||||
...integration,
|
||||
// Enrich installed Kibana assets with metadata from Fleet API (e.g. title, description, etc.)
|
||||
kibanaAssets: integration.kibanaAssets.reduce<GetBulkAssetsResponse['items']>(
|
||||
(acc, asset) => {
|
||||
const assetWithMetadata = assetsMetadata.data?.items.find(({ id }) => id === asset.id);
|
||||
if (assetWithMetadata) {
|
||||
acc.push(assetWithMetadata);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [installedIntegrations.length]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useInterval(
|
||||
refetchProgress,
|
||||
progressStatus === FETCH_STATUS.SUCCESS && status !== 'dataReceived' ? 3000 : null
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
error,
|
||||
refetch,
|
||||
status,
|
||||
installedIntegrations: assetsState.value ?? [],
|
||||
};
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 React, { type FunctionComponent } from 'react';
|
||||
import {
|
||||
EuiAccordion,
|
||||
EuiIcon,
|
||||
EuiTitle,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
type EuiAccordionProps,
|
||||
} from '@elastic/eui';
|
||||
|
||||
interface AccordionWithIconProps
|
||||
extends Omit<EuiAccordionProps, 'buttonContent' | 'buttonProps' | 'borders' | 'paddingSize'> {
|
||||
title: string;
|
||||
iconType: string;
|
||||
}
|
||||
export const AccordionWithIcon: FunctionComponent<AccordionWithIconProps> = ({
|
||||
title,
|
||||
iconType,
|
||||
children,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<EuiAccordion
|
||||
{...rest}
|
||||
buttonContent={
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false} css={{ marginLeft: 8 }}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type={iconType} size="l" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs" css={rest.isDisabled ? { color: 'inherit' } : undefined}>
|
||||
<h3>{title}</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
buttonProps={{ paddingSize: 'l' }}
|
||||
borders="horizontal"
|
||||
paddingSize="none"
|
||||
>
|
||||
<div css={{ paddingLeft: 36, paddingBottom: 24 }}>{children}</div>
|
||||
</EuiAccordion>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 React, { type FunctionComponent } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiCopy, EuiButton, type EuiButtonProps } from '@elastic/eui';
|
||||
|
||||
interface CopyToClipboardButtonProps extends Omit<EuiButtonProps, 'onClick'> {
|
||||
textToCopy: string;
|
||||
}
|
||||
|
||||
export const CopyToClipboardButton: FunctionComponent<CopyToClipboardButtonProps> = ({
|
||||
textToCopy,
|
||||
children,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<EuiCopy textToCopy={textToCopy}>
|
||||
{(copyToClipboard) => (
|
||||
<EuiButton
|
||||
data-test-subj="observabilityOnboardingCopyToClipboardButton"
|
||||
iconType="copyClipboard"
|
||||
onClick={copyToClipboard}
|
||||
{...rest}
|
||||
>
|
||||
{children ??
|
||||
i18n.translate(
|
||||
'xpack.observability_onboarding.copyToClipboardButton.copyToClipboardButtonLabel',
|
||||
{ defaultMessage: 'Copy to clipboard' }
|
||||
)}
|
||||
</EuiButton>
|
||||
)}
|
||||
</EuiCopy>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 React, { type FunctionComponent } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';
|
||||
import type { IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser';
|
||||
|
||||
interface EmptyPromptProps {
|
||||
error: IHttpFetchError<ResponseErrorBody>;
|
||||
onRetryClick(): void;
|
||||
}
|
||||
export const EmptyPrompt: FunctionComponent<EmptyPromptProps> = ({ error, onRetryClick }) => {
|
||||
if (error.response?.status === 403) {
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
color="plain"
|
||||
iconType="lock"
|
||||
title={
|
||||
<h2>
|
||||
{i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.h2.contactYourAdministratorForLabel',
|
||||
{ defaultMessage: 'Contact your administrator for access' }
|
||||
)}
|
||||
</h2>
|
||||
}
|
||||
body={
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.p.toInstallIntegrationsAndLabel',
|
||||
{
|
||||
defaultMessage:
|
||||
'To install integrations and ingest data, you need additional privileges.',
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
color="danger"
|
||||
iconType="error"
|
||||
title={
|
||||
<h2>
|
||||
{i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.h2.unableToInitiateDataLabel',
|
||||
{ defaultMessage: 'Unable to load content' }
|
||||
)}
|
||||
</h2>
|
||||
}
|
||||
body={
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.p.thereWasAProblemLabel',
|
||||
{
|
||||
defaultMessage:
|
||||
'There was a problem loading the application. Retry or contact your administrator for help.',
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
}
|
||||
actions={
|
||||
<EuiButton
|
||||
color="danger"
|
||||
iconType="refresh"
|
||||
fill
|
||||
data-test-subj="observabilityOnboardingAutoDetectPanelGoBackButton"
|
||||
onClick={onRetryClick}
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.observability_onboarding.autoDetectPanel.backToSelectionButtonLabel',
|
||||
{ defaultMessage: 'Retry' }
|
||||
)}
|
||||
</EuiButton>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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 React, { type AnchorHTMLAttributes } from 'react';
|
||||
import { EuiButtonEmpty, type EuiButtonEmptyProps } from '@elastic/eui';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import { type LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { type ObservabilityOnboardingContextValue } from '../../../plugin';
|
||||
|
||||
type EuiButtonEmptyPropsForAnchor = Extract<
|
||||
EuiButtonEmptyProps,
|
||||
AnchorHTMLAttributes<HTMLAnchorElement>
|
||||
>;
|
||||
|
||||
export interface LocatorButtonEmptyProps<Params extends SerializableRecord>
|
||||
extends Omit<EuiButtonEmptyPropsForAnchor, 'href'> {
|
||||
locator: string | LocatorPublic<Params>;
|
||||
params: Params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `EuiButtonEmpty` but uses locators to navigate instead of URLs.
|
||||
*
|
||||
* Accepts the following props instead of an `href`:
|
||||
* - `locator`: Either the URL locator public contract or the ID of the locator if previously registered.
|
||||
* - `params`: The params to pass to the locator.
|
||||
*
|
||||
* Get type safety for `params` by passing the correct type to the generic component.
|
||||
*
|
||||
* Example 1:
|
||||
*
|
||||
* ```ts
|
||||
* <LocatorButtonEmpty locator={dashboardStart.locator} params={{ dashboardId: 'abc' }}>
|
||||
* View dashboard
|
||||
* </LocatorButtonEmpty>
|
||||
* ```
|
||||
*
|
||||
* Example 2:
|
||||
*
|
||||
* ```ts
|
||||
* import { type SingleDatasetLocatorParams, SINGLE_DATASET_LOCATOR_ID } from '@kbn/deeplinks-observability/locators';
|
||||
*
|
||||
* <LocatorButtonEmpty<SingleDatasetLocatorParams>
|
||||
* locator={SINGLE_DATASET_LOCATOR_ID}
|
||||
* params={{
|
||||
* integration: 'system',
|
||||
* dataset: 'system.syslog',
|
||||
* }}
|
||||
* >
|
||||
* View in Logs Explorer
|
||||
* </LocatorButtonEmpty>
|
||||
* ```
|
||||
*/
|
||||
export const LocatorButtonEmpty = <Params extends SerializableRecord>({
|
||||
locator,
|
||||
params,
|
||||
...rest
|
||||
}: LocatorButtonEmptyProps<Params>) => {
|
||||
const {
|
||||
services: { share },
|
||||
} = useKibana<ObservabilityOnboardingContextValue>();
|
||||
|
||||
const locatorObj =
|
||||
typeof locator === 'string' ? share.url.locators.get<Params>(locator) : locator;
|
||||
|
||||
return (
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="observabilityOnboardingLocatorButtonEmptyButton"
|
||||
href={locatorObj?.useUrl(params)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -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 React, { type FunctionComponent } from 'react';
|
||||
import {
|
||||
EuiIcon,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
type EuiCallOutProps,
|
||||
EuiCallOut,
|
||||
EuiLoadingSpinner,
|
||||
} from '@elastic/eui';
|
||||
|
||||
interface ProgressIndicatorProps extends EuiCallOutProps {
|
||||
iconType?: string;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
export const ProgressIndicator: FunctionComponent<ProgressIndicatorProps> = ({
|
||||
iconType,
|
||||
isLoading = true,
|
||||
title,
|
||||
color = isLoading ? 'primary' : 'success',
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
|
||||
{isLoading ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size={rest.size} />
|
||||
</EuiFlexItem>
|
||||
) : iconType ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type={iconType} color={color} size={rest.size} />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
<EuiFlexItem>{title}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
color={color}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -87,9 +87,9 @@ selected_unknown_log_file_pattern_array=()
|
|||
excluded_options_string=""
|
||||
selected_unknown_log_file_pattern_tsv_string=""
|
||||
custom_log_file_path_list_tsv_string=""
|
||||
install_integrations_api_body_string=""
|
||||
elastic_agent_artifact_name=""
|
||||
elastic_agent_config_path="/opt/Elastic/Agent/elastic-agent.yml"
|
||||
elastic_agent_tmp_config_path="/tmp/elastic-agent-config-template.yml"
|
||||
|
||||
OS="$(uname)"
|
||||
ARCH="$(uname -m)"
|
||||
|
@ -130,14 +130,16 @@ update_step_progress() {
|
|||
--header "x-elastic-internal-origin: Kibana" \
|
||||
--data "$data" \
|
||||
--output /dev/null \
|
||||
--no-progress-meter
|
||||
--no-progress-meter \
|
||||
--fail
|
||||
}
|
||||
|
||||
download_elastic_agent() {
|
||||
local download_url="https://artifacts.elastic.co/downloads/beats/elastic-agent/${elastic_agent_artifact_name}.tar.gz"
|
||||
curl -L -O $download_url --fail
|
||||
curl -L -O $download_url --silent --fail
|
||||
|
||||
if [ "$?" -eq 0 ]; then
|
||||
printf "\e[1;32m✓\e[0m %s\n" "Elastic Agent downloaded to $(pwd)/$elastic_agent_artifact_name.tar.gz"
|
||||
update_step_progress "ea-download" "complete"
|
||||
else
|
||||
update_step_progress "ea-download" "danger" "Failed to download Elastic Agent, see script output for error."
|
||||
|
@ -149,6 +151,7 @@ extract_elastic_agent() {
|
|||
tar -xzf "${elastic_agent_artifact_name}.tar.gz"
|
||||
|
||||
if [ "$?" -eq 0 ]; then
|
||||
printf "\e[1;32m✓\e[0m %s\n" "Archive extracted"
|
||||
update_step_progress "ea-extract" "complete"
|
||||
else
|
||||
update_step_progress "ea-extract" "danger" "Failed to extract Elastic Agent, see script output for error."
|
||||
|
@ -157,9 +160,10 @@ extract_elastic_agent() {
|
|||
}
|
||||
|
||||
install_elastic_agent() {
|
||||
"./${elastic_agent_artifact_name}/elastic-agent" install -f
|
||||
"./${elastic_agent_artifact_name}/elastic-agent" install -f -n > /dev/null
|
||||
|
||||
if [ "$?" -eq 0 ]; then
|
||||
printf "\e[1;32m✓\e[0m %s\n" "Elastic Agent installed to $(dirname $elastic_agent_config_path)"
|
||||
update_step_progress "ea-install" "complete"
|
||||
else
|
||||
update_step_progress "ea-install" "danger" "Failed to install Elastic Agent, see script output for error."
|
||||
|
@ -170,17 +174,14 @@ install_elastic_agent() {
|
|||
wait_for_elastic_agent_status() {
|
||||
local MAX_RETRIES=10
|
||||
local i=0
|
||||
echo -n "."
|
||||
elastic-agent status > /dev/null 2>&1
|
||||
local ELASTIC_AGENT_STATUS_EXIT_CODE="$?"
|
||||
while [ "$ELASTIC_AGENT_STATUS_EXIT_CODE" -ne 0 ] && [ $i -le $MAX_RETRIES ]; do
|
||||
sleep 1
|
||||
echo -n "."
|
||||
elastic-agent status > /dev/null 2>&1
|
||||
ELASTIC_AGENT_STATUS_EXIT_CODE="$?"
|
||||
((i++))
|
||||
done
|
||||
echo ""
|
||||
|
||||
if [ "$ELASTIC_AGENT_STATUS_EXIT_CODE" -ne 0 ]; then
|
||||
update_step_progress "ea-status" "warning" "Unable to determine agent status"
|
||||
|
@ -214,11 +215,11 @@ backup_elastic_agent_config() {
|
|||
confirmation_reply="${confirmation_reply:-Y}"
|
||||
|
||||
if [[ "$confirmation_reply" =~ ^[Yy](es)?$ ]]; then
|
||||
local backup_path="${elastic_agent_config_path%.yml}.$(date +%s).yml" # e.g. /opt/Elastic/Agent/elastic-agent.1712267614.yml
|
||||
local backup_path="$(pwd)/$(basename "${elastic_agent_config_path%.yml}.$(date +%s).yml")" # e.g. /opt/Elastic/Agent/elastic-agent.1712267614.yml
|
||||
cp $elastic_agent_config_path $backup_path
|
||||
|
||||
if [ "$?" -eq 0 ]; then
|
||||
printf "\n\e[1;32m✓\e[0m \e[1m%s\e[0m\n" "Backup saved to $backup_path"
|
||||
printf "\n\e[1;32m✓\e[0m %s\n" "Backup saved to $backup_path"
|
||||
else
|
||||
update_step_progress "ea-config" "warning" "Failed to backup existing configuration"
|
||||
fail "Failed to backup existing config file - Try manually creating a backup or delete your existing config file before re-running this script"
|
||||
|
@ -229,31 +230,56 @@ backup_elastic_agent_config() {
|
|||
fi
|
||||
}
|
||||
|
||||
download_elastic_agent_config() {
|
||||
local decoded_ingest_api_key=$(echo "$ingest_api_key_encoded" | base64 -d)
|
||||
local tmp_path="/tmp/elastic-agent-config-template.yml"
|
||||
install_integrations() {
|
||||
local install_integrations_api_body_string=""
|
||||
|
||||
update_step_progress "ea-config" "loading"
|
||||
for item in "${selected_known_integrations_array[@]}"; do
|
||||
install_integrations_api_body_string+="$item\tregistry\n"
|
||||
done
|
||||
|
||||
for item in "${selected_unknown_log_file_pattern_array[@]}" "${custom_log_file_path_list_array[@]}"; do
|
||||
local integration_name=$(generate_custom_integration_name "$item")
|
||||
|
||||
install_integrations_api_body_string+="$integration_name\tcustom\t$item\n"
|
||||
done
|
||||
|
||||
curl --request POST \
|
||||
-o $tmp_path \
|
||||
-o $elastic_agent_tmp_config_path \
|
||||
--url "$kibana_api_endpoint/internal/observability_onboarding/flow/$onboarding_flow_id/integrations/install" \
|
||||
--header "Authorization: ApiKey $install_api_key_encoded" \
|
||||
--header "Content-Type: text/tab-separated-values" \
|
||||
--header "kbn-xsrf: true" \
|
||||
--header "x-elastic-internal-origin: Kibana" \
|
||||
--data "$(echo -e "$install_integrations_api_body_string")" \
|
||||
--no-progress-meter
|
||||
--no-progress-meter \
|
||||
--fail
|
||||
|
||||
if [ "$?" -ne 0 ]; then
|
||||
update_step_progress "ea-config" "warning" "Failed to install integrations."
|
||||
fail "Failed to install integrations."
|
||||
if [ "$?" -eq 0 ]; then
|
||||
printf "\n\e[1;32m✓\e[0m %s\n" "Integrations installed"
|
||||
else
|
||||
update_step_progress "ea-config" "warning" "Failed to install integrations"
|
||||
fail "Failed to install integrations"
|
||||
fi
|
||||
}
|
||||
|
||||
sed "s/'\${API_KEY}'/$decoded_ingest_api_key/g" $tmp_path > $elastic_agent_config_path
|
||||
apply_elastic_agent_config() {
|
||||
local decoded_ingest_api_key=$(echo "$ingest_api_key_encoded" | base64 -d)
|
||||
|
||||
sed "s/'\${API_KEY}'/$decoded_ingest_api_key/g" $elastic_agent_tmp_config_path > $elastic_agent_config_path
|
||||
if [ "$?" -eq 0 ]; then
|
||||
printf "\e[1;32m✓\e[0m %s\n" "Config written to $elastic_agent_config_path"
|
||||
update_step_progress "ea-config" "complete"
|
||||
else
|
||||
update_step_progress "ea-config" "warning" "Failed to configure Elastic Agent"
|
||||
fail "Failed to configure Elastic Agent"
|
||||
fi
|
||||
}
|
||||
|
||||
read_open_log_file_list() {
|
||||
local exclude_patterns=(
|
||||
"^\/Users\/.+?\/Library\/Application Support"
|
||||
"^\/Users\/.+?\/Library\/Group Containers"
|
||||
"^\/Users\/.+?\/Library\/Containers"
|
||||
"^\/Users\/.+?\/Library\/Caches"
|
||||
"^\/private"
|
||||
# Excluding all patterns that correspond to known integrations
|
||||
|
@ -269,7 +295,7 @@ read_open_log_file_list() {
|
|||
"^\/var\/log\/secure"
|
||||
)
|
||||
|
||||
local list=$(lsof -Fn | grep "\.log$" | awk '/^n/ {print substr($0, 2)}' | sort | uniq)
|
||||
local list=$(lsof -Fn / | grep "^n.*\.log$" | cut -c2- | sort -u)
|
||||
|
||||
# Filtering by the exclude patterns
|
||||
while IFS= read -r line; do
|
||||
|
@ -385,12 +411,12 @@ function select_list() {
|
|||
fi
|
||||
done
|
||||
|
||||
printf "\n\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m" "Ingest all detected logs?" "[Y/n] (default: Yes): "
|
||||
printf "\n\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m" "Continue installation with detected logs?" "[Y/n] (default: Yes): "
|
||||
read confirmation_reply
|
||||
confirmation_reply="${confirmation_reply:-Y}"
|
||||
|
||||
if [[ ! "$confirmation_reply" =~ ^[Yy](es)?$ ]]; then
|
||||
printf "\n\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m" "Exclude logs by listing their index numbers" "(e.g. 1, 2, 3): "
|
||||
printf "\n\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m\n" "Exclude logs by listing their index numbers" "(e.g. 1, 2, 3). Press Enter to skip."
|
||||
read exclude_index_list_string
|
||||
|
||||
IFS=', ' read -r -a exclude_index_list_array <<< "$exclude_index_list_string"
|
||||
|
@ -417,6 +443,33 @@ function select_list() {
|
|||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "$excluded_options_string" ]]; then
|
||||
echo -e "\nThese logs will not be ingested:"
|
||||
echo -e "$excluded_options_string"
|
||||
fi
|
||||
|
||||
printf "\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m\n" "List any additional logs you'd like to ingest" "(e.g. /path1/*.log, /path2/*.log). Press Enter to skip."
|
||||
read custom_log_file_path_list_string
|
||||
|
||||
IFS=', ' read -r -a custom_log_file_path_list_array <<< "$custom_log_file_path_list_string"
|
||||
|
||||
echo -e "\nYou've selected these logs for ingestion:"
|
||||
for item in "${selected_known_integrations_array[@]}"; do
|
||||
printf "\e[32m•\e[0m %s\n" "$(known_integration_title "${item}")"
|
||||
done
|
||||
for item in "${selected_unknown_log_file_pattern_array[@]}" "${custom_log_file_path_list_array[@]}"; do
|
||||
printf "\e[32m•\e[0m %s\n" "$item"
|
||||
done
|
||||
|
||||
printf "\n\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m" "Continue installation with selected logs?" "[Y/n] (default: Yes): "
|
||||
read confirmation_reply
|
||||
confirmation_reply="${confirmation_reply:-Y}"
|
||||
|
||||
if [[ ! "$confirmation_reply" =~ ^[Yy](es)?$ ]]; then
|
||||
echo -e "Rerun the script again to select different logs."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
selected_known_integrations_array=("${known_integrations_options[@]}")
|
||||
selected_unknown_log_file_pattern_array=("${unknown_logs_options[@]}")
|
||||
|
@ -450,70 +503,26 @@ generate_custom_integration_name() {
|
|||
echo "$name"
|
||||
}
|
||||
|
||||
build_install_integrations_api_body_string() {
|
||||
for item in "${selected_known_integrations_array[@]}"; do
|
||||
install_integrations_api_body_string+="$item\tregistry\n"
|
||||
done
|
||||
|
||||
for item in "${selected_unknown_log_file_pattern_array[@]}" "${custom_log_file_path_list_array[@]}"; do
|
||||
local integration_name=$(generate_custom_integration_name "$item")
|
||||
|
||||
install_integrations_api_body_string+="$integration_name\tcustom\t$item\n"
|
||||
done
|
||||
}
|
||||
|
||||
echo "Looking for log files..."
|
||||
printf "\e[1m%s\e[0m\n" "Looking for log files..."
|
||||
update_step_progress "logs-detect" "loading"
|
||||
detect_known_integrations
|
||||
read_open_log_file_list
|
||||
build_unknown_log_file_patterns
|
||||
|
||||
update_step_progress "logs-detect" "complete"
|
||||
echo -e "\nWe found these logs on your system:"
|
||||
select_list
|
||||
|
||||
if [[ -n "$excluded_options_string" ]]; then
|
||||
echo -e "\nThese logs will not be ingested:"
|
||||
echo -e "$excluded_options_string"
|
||||
fi
|
||||
|
||||
|
||||
printf "\n\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m\n" "Add paths to any custom logs we've missed" "(e.g. /path1/*.log, /path2/*.log). Press Enter to skip."
|
||||
read custom_log_file_path_list_string
|
||||
|
||||
IFS=', ' read -r -a custom_log_file_path_list_array <<< "$custom_log_file_path_list_string"
|
||||
|
||||
echo -e "\nYou've selected these logs to ingest:"
|
||||
for item in "${selected_known_integrations_array[@]}"; do
|
||||
printf "• %s\n" "$(known_integration_title "${item}")"
|
||||
done
|
||||
for item in "${selected_unknown_log_file_pattern_array[@]}" "${custom_log_file_path_list_array[@]}"; do
|
||||
printf "• %s\n" "$item"
|
||||
done
|
||||
|
||||
|
||||
printf "\n\e[1;36m?\e[0m \e[1m%s\e[0m \e[2m%s\e[0m" "Continue installation with selected logs?" "[Y/n] (default: Yes): "
|
||||
read confirmation_reply
|
||||
confirmation_reply="${confirmation_reply:-Y}"
|
||||
|
||||
if [[ ! "$confirmation_reply" =~ ^[Yy](es)?$ ]]; then
|
||||
echo -e "Rerun the script again to select different logs."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
build_install_integrations_api_body_string
|
||||
|
||||
backup_elastic_agent_config
|
||||
|
||||
echo -e "\nDownloading Elastic Agent...\n"
|
||||
printf "\n\e[1m%s\e[0m\n" "Installing Elastic Agent..."
|
||||
install_integrations
|
||||
download_elastic_agent
|
||||
extract_elastic_agent
|
||||
|
||||
echo -e "\nInstalling Elastic Agent...\n"
|
||||
install_elastic_agent
|
||||
apply_elastic_agent_config
|
||||
|
||||
printf "\n\e[1m%s\e[0m\n" "Waiting for healthy status..."
|
||||
wait_for_elastic_agent_status
|
||||
ensure_elastic_agent_healthy
|
||||
|
||||
echo -e "\nInstalling integrations...\n"
|
||||
download_elastic_agent_config
|
||||
|
||||
update_step_progress "ea-config" "complete"
|
||||
printf "\n\e[32m%s\e[0m\n" "🎉 Elastic Agent is configured and running. You can now go back to Kibana and check for incoming logs."
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
<svg width="162" height="117" viewBox="0 0 162 117" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6_66533)">
|
||||
<rect width="162" height="117" rx="3.6" fill="#F7F8FC"/>
|
||||
<g filter="url(#filter0_dddd_6_66533)">
|
||||
<rect width="135" height="99" transform="translate(27 18)" fill="white"/>
|
||||
<rect x="37.6387" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="52.9395" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="68.2383" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="83.5391" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="98.8379" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="114.139" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="129.439" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="144.738" y="105.891" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="37.6387" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="52.9395" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="68.2383" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="83.5391" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="98.8379" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="114.139" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="129.439" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="144.738" y="62.6907" width="6.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<path d="M38.25 48.0639L55.243 33.6119L63.8969 40.9717L70.9773 34.95L86.3969 48.0639L113.302 25.1815L134.386 43.1127L140.995 37.4925L150.75 45.7891" stroke="#F1F4FA" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M38.25 40.8918L49.677 50.6101L59.4945 42.2606L67.8635 49.3782L85.8892 34.048L109.87 54.4427L117.112 48.2832L127.252 56.9065C135.138 50.2907 150.878 37.0319 150.749 36.9224" stroke="#F1F4FA" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M150.75 78.5426L129.091 100.201L115.847 86.9567L109.458 93.3452L94.6558 78.5426L75.3345 97.8639L69.4134 91.9429L63.4924 97.8639L46.8199 81.1915L38.25 89.7614" stroke="#F1F4FA" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M150.75 74.079L131.455 93.3736L124.92 86.8383L116.829 94.9296L104.225 82.3259L93.1774 93.3736L72.3268 72.5229L49.9201 94.9296L46.0301 91.0395L38.25 98.8196" stroke="#F1F4FA" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<mask id="mask0_6_66533" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="37" y="18" width="115" height="99">
|
||||
<rect x="37.1875" y="18" width="114.75" height="99" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_6_66533)">
|
||||
<path d="M38.25 48.0639L55.243 33.6119L63.8969 40.9717L70.9773 34.95L86.3969 48.0639L113.302 25.1815L134.386 43.1127L140.995 37.4925L150.75 45.7891" stroke="#6092C0" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M150.75 78.5426L129.091 100.201L115.847 86.9567L109.458 93.3452L94.6558 78.5426L75.3345 97.8639L69.4134 91.9429L63.4924 97.8639L46.8199 81.1915L38.25 89.7614" stroke="#6092C0" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<mask id="mask1_6_66533" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="27" y="18" width="125" height="99">
|
||||
<rect x="27" y="18" width="124.489" height="99" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask1_6_66533)">
|
||||
<path d="M38.25 40.8918L49.677 50.6101L59.4945 42.2606L67.8635 49.3782L85.8892 34.048L109.87 54.4427L117.112 48.2832L127.252 56.9065C135.138 50.2907 150.878 37.0319 150.749 36.9224" stroke="#D36086" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M150.75 74.0781L131.455 93.3727L124.92 86.8374L116.829 94.9287L104.225 82.325L93.1774 93.3727L72.3268 72.5221L49.9201 94.9287L46.0301 91.0387L38.25 98.8188" stroke="#D36086" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect x="3.15039" y="27" width="13.5" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="31.05" width="5.4" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="35.1" width="14.85" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="39.15" width="13.5" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="43.2" width="15.75" height="1.8" rx="0.9" fill="#98A2B3"/>
|
||||
<rect x="3.15039" y="47.25" width="10.8" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="51.3" width="13.5" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="55.35" width="7.2" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="59.4" width="12.15" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="21.15" width="16.65" height="2.7" rx="1.35" fill="#98A2B3"/>
|
||||
<g filter="url(#filter1_ddd_6_66533)">
|
||||
<rect width="162" height="9" transform="translate(0 9)" fill="white"/>
|
||||
<path d="M26.0996 11.25H35.0996C35.5967 11.25 35.9996 11.6529 35.9996 12.15V14.85C35.9996 15.3471 35.5967 15.75 35.0996 15.75H26.0996V11.25Z" fill="#69707D" fill-opacity="0.2"/>
|
||||
<path d="M15.75 12.15C15.75 11.6529 16.1529 11.25 16.65 11.25H25.65V15.75H16.65C16.1529 15.75 15.75 15.3471 15.75 14.85V12.15Z" fill="#006DE4" fill-opacity="0.2"/>
|
||||
<rect x="9" y="11.25" width="4.5" height="4.5" rx="0.9" fill="#00BFB3"/>
|
||||
<rect x="2.25" y="11.25" width="4.5" height="4.5" rx="0.9" fill="#D3DAE6"/>
|
||||
</g>
|
||||
<rect width="162" height="9" fill="#26282F"/>
|
||||
<circle cx="157.501" cy="4.50005" r="2.7" fill="#0077CC"/>
|
||||
<circle cx="150.3" cy="4.50005" r="2.7" fill="#69707D"/>
|
||||
<rect x="62.0996" y="1.80005" width="38.25" height="5.4" rx="1.35" fill="#69707D"/>
|
||||
<rect x="9.45117" y="3.15002" width="13.05" height="2.7" rx="1.35" fill="#69707D"/>
|
||||
<g clip-path="url(#clip1_6_66533)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.00841 4.01557C7.13416 4.19573 7.20134 4.41027 7.20079 4.62999C7.1997 4.85059 7.13129 5.0656 7.0047 5.24626C6.87836 5.42659 6.6998 5.56387 6.49305 5.63962C6.55327 5.80507 6.55834 5.98557 6.50748 6.15414C6.45662 6.32271 6.35258 6.47029 6.2109 6.57483C6.06931 6.67888 5.89766 6.73396 5.72197 6.7317C5.54627 6.72945 5.37609 6.66999 5.23721 6.56234C5.04992 6.82498 4.78399 7.02129 4.47784 7.12293C4.17197 7.22442 3.84172 7.22578 3.53503 7.12681C3.22807 7.02759 2.9606 6.83334 2.77127 6.57213C2.58151 6.31046 2.47948 5.99542 2.47984 5.67218C2.4798 5.57453 2.48883 5.47708 2.50684 5.38109C2.29947 5.30677 2.12028 5.16992 1.99401 4.98942C1.86746 4.80852 1.79997 4.5929 1.80079 4.37214C1.80193 4.15152 1.8704 3.93651 1.99704 3.75586C2.12355 3.57552 2.3023 3.43829 2.5092 3.36267C2.44812 3.19714 2.44238 3.01626 2.49282 2.84718C2.54327 2.67809 2.64719 2.52993 2.78899 2.42493C2.93066 2.32037 3.1026 2.26495 3.27866 2.26708C3.45472 2.26921 3.62527 2.32879 3.76436 2.43674C3.96714 2.15359 4.26072 1.94838 4.5963 1.85523C4.93162 1.76233 5.28866 1.78728 5.60779 1.92594C5.92731 2.06487 6.18972 2.30888 6.35147 2.61747C6.51354 2.92651 6.56551 3.28154 6.49879 3.62407C6.70499 3.69885 6.88301 3.8356 7.00841 4.01557ZM3.92366 4.1266L5.10525 4.66846L6.29764 3.62002C6.31491 3.53351 6.3235 3.44549 6.32329 3.35727C6.32341 3.07175 6.23236 2.79365 6.06341 2.56347C5.89487 2.33371 5.65711 2.16403 5.38504 2.07933C5.11323 1.99485 4.82147 1.99994 4.55276 2.09384C4.28368 2.18791 4.05184 2.36576 3.89126 2.60127L3.69315 3.63369L3.92383 4.12644L3.92366 4.1266ZM2.70073 5.38227C2.66339 5.56605 2.66492 5.75562 2.70523 5.93877C2.74554 6.12193 2.82373 6.29462 2.93479 6.44574C3.10426 6.67621 3.34323 6.84621 3.61654 6.93072C3.88952 7.01503 4.18238 7.00929 4.45185 6.91435C4.72173 6.81922 4.95395 6.64 5.11436 6.40304L5.31113 5.37333L5.04872 4.86961L3.86241 4.32775L2.70056 5.3821L2.70073 5.38227ZM3.50314 3.52197L2.69314 3.3301L2.69348 3.32977C2.64661 3.19965 2.64283 3.05792 2.6827 2.92549C2.72257 2.79306 2.80397 2.67697 2.91488 2.59435C3.02579 2.51215 3.16036 2.4681 3.29842 2.4688C3.43647 2.4695 3.57058 2.51491 3.68066 2.59824L3.50314 3.52197ZM2.62294 3.52366C2.44766 3.58172 2.29467 3.69267 2.18503 3.84125C2.07512 3.99007 2.01383 4.1692 2.00954 4.35417C2.00525 4.53913 2.05817 4.72091 2.16107 4.87467C2.26384 5.02823 2.41149 5.14636 2.58379 5.21217L3.71998 4.18263L3.51158 3.73544L2.62294 3.52366ZM5.7087 6.53551C5.56905 6.53527 5.43342 6.48868 5.32311 6.40304L5.4981 5.48268L6.3081 5.67252C6.34348 5.76944 6.35504 5.87345 6.34179 5.97577C6.32855 6.07809 6.29089 6.17573 6.232 6.26045C6.17341 6.34509 6.09523 6.41431 6.00411 6.4622C5.91299 6.5101 5.81164 6.53525 5.7087 6.53551ZM5.48764 5.27005L6.37864 5.47897C6.55661 5.41875 6.71131 5.3044 6.8211 5.15193C6.93113 4.99921 6.99088 4.81602 6.99204 4.62779C6.992 4.4464 6.93692 4.26929 6.83409 4.11985C6.73144 3.97061 6.58575 3.85618 6.41644 3.7918L5.25139 4.81612L5.48764 5.27005Z" fill="white"/>
|
||||
<path d="M3.92387 4.12664L5.10546 4.6685L6.29785 3.62006C6.31512 3.53355 6.32371 3.44553 6.3235 3.35731C6.32362 3.07179 6.23257 2.79368 6.06362 2.56351C5.89507 2.33375 5.65732 2.16407 5.38525 2.07937C5.11343 1.99489 4.82167 1.99998 4.55297 2.09388C4.28389 2.18795 4.05205 2.3658 3.89147 2.60131L3.69336 3.63372L3.92404 4.12647L3.92387 4.12664Z" fill="#FEC514"/>
|
||||
<path d="M2.70075 5.38228C2.6634 5.56606 2.66493 5.75562 2.70524 5.93878C2.74555 6.12193 2.82375 6.29462 2.9348 6.44574C3.10427 6.67622 3.34324 6.84622 3.61655 6.93073C3.88953 7.01503 4.18239 7.0093 4.45186 6.91436C4.72174 6.81923 4.95396 6.64 5.11438 6.40305L5.31114 5.37333L5.04873 4.86962L3.86242 4.32776L2.70058 5.38211L2.70075 5.38228Z" fill="#00BFB3"/>
|
||||
<path d="M2.6921 3.33006L3.5021 3.52193L3.67963 2.59819C3.56955 2.51487 3.43543 2.46946 3.29738 2.46876C3.15932 2.46806 3.02476 2.51211 2.91384 2.59431C2.80293 2.67693 2.72153 2.79302 2.68166 2.92545C2.6418 3.05787 2.64557 3.19961 2.69244 3.32972" fill="#F04E98"/>
|
||||
<path d="M2.62341 3.52368C2.44812 3.58174 2.29514 3.6927 2.1855 3.84127C2.07558 3.99009 2.0143 4.16923 2.01001 4.35419C2.00572 4.53916 2.05864 4.72093 2.16154 4.87469C2.26431 5.02826 2.41196 5.14638 2.58426 5.21219L3.72045 4.18265L3.51204 3.73546L2.62341 3.52368V3.52368Z" fill="#1BA9F5"/>
|
||||
<path d="M5.32422 6.40303C5.43454 6.48866 5.57016 6.53526 5.70981 6.5355C5.81275 6.53524 5.9141 6.51009 6.00522 6.46219C6.09634 6.4143 6.17452 6.34508 6.23311 6.26043C6.292 6.17572 6.32966 6.07808 6.3429 5.97576C6.35615 5.87344 6.34459 5.76943 6.30921 5.67251L5.49921 5.48267L5.32422 6.40303Z" fill="#93C90E"/>
|
||||
<path d="M5.4882 5.27012L6.3792 5.47903C6.55718 5.41881 6.71188 5.30447 6.82167 5.152C6.9317 4.99928 6.99145 4.81608 6.99261 4.62786C6.99256 4.44646 6.93749 4.26935 6.83466 4.11992C6.732 3.97068 6.58632 3.85625 6.417 3.79187L5.25195 4.81618L5.4882 5.27012V5.27012Z" fill="#0077CC"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_dddd_6_66533" x="20.7" y="15.615" width="147.6" height="114.435" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect1_dropShadow_6_66533"/>
|
||||
<feOffset dy="6.75"/>
|
||||
<feGaussianBlur stdDeviation="3.375"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6_66533"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect2_dropShadow_6_66533"/>
|
||||
<feOffset dy="2.565"/>
|
||||
<feGaussianBlur stdDeviation="2.7"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
|
||||
<feBlend mode="normal" in2="effect1_dropShadow_6_66533" result="effect2_dropShadow_6_66533"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect3_dropShadow_6_66533"/>
|
||||
<feOffset dy="1.17"/>
|
||||
<feGaussianBlur stdDeviation="1.8"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0"/>
|
||||
<feBlend mode="normal" in2="effect2_dropShadow_6_66533" result="effect3_dropShadow_6_66533"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect4_dropShadow_6_66533"/>
|
||||
<feOffset dy="0.405"/>
|
||||
<feGaussianBlur stdDeviation="0.9"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.08 0"/>
|
||||
<feBlend mode="normal" in2="effect3_dropShadow_6_66533" result="effect4_dropShadow_6_66533"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect4_dropShadow_6_66533" result="shape"/>
|
||||
</filter>
|
||||
<filter id="filter1_ddd_6_66533" x="-4.5" y="6.525" width="171" height="18" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="2.025"/>
|
||||
<feGaussianBlur stdDeviation="2.25"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6_66533"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="0.855"/>
|
||||
<feGaussianBlur stdDeviation="0.9"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
|
||||
<feBlend mode="normal" in2="effect1_dropShadow_6_66533" result="effect2_dropShadow_6_66533"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="0.315"/>
|
||||
<feGaussianBlur stdDeviation="0.315"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.07 0"/>
|
||||
<feBlend mode="normal" in2="effect2_dropShadow_6_66533" result="effect3_dropShadow_6_66533"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect3_dropShadow_6_66533" result="shape"/>
|
||||
</filter>
|
||||
<clipPath id="clip0_6_66533">
|
||||
<rect width="162" height="117" rx="3.6" fill="white"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip1_6_66533">
|
||||
<rect width="5.4" height="5.4" fill="white" transform="translate(1.80078 1.80005)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,116 @@
|
|||
<svg width="162" height="117" viewBox="0 0 162 117" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6_66599)">
|
||||
<rect width="162" height="117" rx="3.6" fill="#F7F8FC"/>
|
||||
<g clip-path="url(#clip1_6_66599)" filter="url(#filter0_dddd_6_66599)">
|
||||
<rect width="135" height="99" transform="translate(27 18)" fill="white"/>
|
||||
<rect x="37.7988" y="27" width="113.4" height="5.4" rx="1.35" fill="#F1F4FA"/>
|
||||
<rect x="37.7988" y="39.6" width="113.4" height="5.4" rx="1.35" fill="#F1F4FA"/>
|
||||
<rect x="37.7988" y="52.2" width="113.4" height="5.4" rx="1.35" fill="#F1F4FA"/>
|
||||
<rect x="37.7988" y="64.8" width="113.4" height="5.4" rx="1.35" fill="#F1F4FA"/>
|
||||
<rect x="37.7988" y="77.4" width="113.4" height="5.4" rx="1.35" fill="#F1F4FA"/>
|
||||
<rect x="37.7988" y="90" width="113.4" height="5.4" rx="1.35" fill="#F1F4FA"/>
|
||||
<rect x="37.7988" y="102.6" width="113.4" height="5.4" rx="1.35" fill="#F1F4FA"/>
|
||||
<mask id="mask0_6_66599" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="27" y="18" width="135" height="99">
|
||||
<rect x="27" y="18" width="135" height="99" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_6_66599)">
|
||||
<rect x="37.7988" y="27" width="113.4" height="5.4" rx="1.35" fill="#6092C0"/>
|
||||
<rect x="37.7988" y="39.6" width="99.675" height="5.4" rx="1.35" fill="#6092C0"/>
|
||||
<rect x="63.8984" y="52.2" width="81.675" height="5.4" rx="1.35" fill="#54B399"/>
|
||||
<rect x="80.7734" y="64.8" width="49.05" height="5.4" rx="1.35" fill="#54B399"/>
|
||||
<rect x="93.373" y="77.4" width="31.5" height="5.4" rx="1.35" fill="#9170B8"/>
|
||||
<rect x="99.7871" y="90" width="18.675" height="5.4" rx="1.35" fill="#9170B8"/>
|
||||
<rect x="105.299" y="102.6" width="8.1" height="5.4" rx="1.35" fill="#D36086"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect x="3.15039" y="27" width="13.5" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="31.05" width="5.4" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="35.1" width="14.85" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="39.15" width="13.5" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="43.2" width="15.75" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="47.25" width="10.8" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="51.3" width="13.5" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="55.35" width="7.2" height="1.8" rx="0.9" fill="#98A2B3"/>
|
||||
<rect x="3.15039" y="59.4" width="12.15" height="1.8" rx="0.9" fill="#D3DAE6"/>
|
||||
<rect x="3.15039" y="21.15" width="16.65" height="2.7" rx="1.35" fill="#98A2B3"/>
|
||||
<g filter="url(#filter1_ddd_6_66599)">
|
||||
<rect width="162" height="9" transform="translate(0 9)" fill="white"/>
|
||||
<path d="M26.0996 11.25H35.0996C35.5967 11.25 35.9996 11.6529 35.9996 12.15V14.85C35.9996 15.3471 35.5967 15.75 35.0996 15.75H26.0996V11.25Z" fill="#69707D" fill-opacity="0.2"/>
|
||||
<path d="M15.75 12.15C15.75 11.6529 16.1529 11.25 16.65 11.25H25.65V15.75H16.65C16.1529 15.75 15.75 15.3471 15.75 14.85V12.15Z" fill="#006DE4" fill-opacity="0.2"/>
|
||||
<rect x="9" y="11.25" width="4.5" height="4.5" rx="0.9" fill="#00BFB3"/>
|
||||
<rect x="2.25" y="11.25" width="4.5" height="4.5" rx="0.9" fill="#D3DAE6"/>
|
||||
</g>
|
||||
<rect width="162" height="9" fill="#26282F"/>
|
||||
<circle cx="157.501" cy="4.50005" r="2.7" fill="#0077CC"/>
|
||||
<circle cx="150.3" cy="4.50005" r="2.7" fill="#69707D"/>
|
||||
<rect x="62.0996" y="1.80005" width="38.25" height="5.4" rx="1.35" fill="#69707D"/>
|
||||
<rect x="9.44922" y="3.15015" width="13.05" height="2.7" rx="1.35" fill="#69707D"/>
|
||||
<g clip-path="url(#clip2_6_66599)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.00646 4.01569C7.13221 4.19586 7.19938 4.4104 7.19883 4.63011C7.19775 4.85071 7.12934 5.06572 7.00275 5.24638C6.87641 5.42671 6.69784 5.564 6.4911 5.63974C6.55132 5.80519 6.55638 5.98569 6.50553 6.15426C6.45467 6.32283 6.35063 6.47041 6.20895 6.57495C6.06736 6.67901 5.89571 6.73408 5.72001 6.73183C5.54431 6.72957 5.37414 6.67012 5.23526 6.56246C5.04797 6.8251 4.78204 7.02142 4.47589 7.12305C4.17002 7.22454 3.83977 7.2259 3.53308 7.12693C3.22611 7.02771 2.95864 6.83346 2.76932 6.57225C2.57955 6.31058 2.47753 5.99554 2.47789 5.67231C2.47784 5.57465 2.48688 5.4772 2.50489 5.38121C2.29752 5.30689 2.11833 5.17004 1.99205 4.98954C1.86551 4.80864 1.79802 4.59303 1.79884 4.37226C1.79998 4.15164 1.86845 3.93663 1.99509 3.75598C2.1216 3.57564 2.30034 3.43841 2.50725 3.36279C2.44617 3.19726 2.44042 3.01638 2.49087 2.8473C2.54132 2.67822 2.64524 2.53006 2.78704 2.42505C2.92871 2.3205 3.10065 2.26507 3.27671 2.2672C3.45277 2.26934 3.62331 2.32891 3.76241 2.43686C3.96519 2.15372 4.25877 1.94851 4.59435 1.85535C4.92966 1.76245 5.28671 1.78741 5.60584 1.92606C5.92536 2.06499 6.18777 2.309 6.34952 2.61759C6.51159 2.92663 6.56355 3.28167 6.49684 3.62419C6.70304 3.69897 6.88106 3.83573 7.00646 4.01569ZM3.92171 4.12673L5.1033 4.66858L6.29569 3.62014C6.31296 3.53363 6.32155 3.44561 6.32134 3.35739C6.32146 3.07187 6.23041 2.79377 6.06146 2.56359C5.89291 2.33384 5.65516 2.16415 5.38309 2.07945C5.11127 1.99498 4.81951 2.00006 4.55081 2.09396C4.28173 2.18804 4.04989 2.36588 3.88931 2.60139L3.6912 3.63381L3.92188 4.12656L3.92171 4.12673ZM2.69878 5.38239C2.66143 5.56618 2.66296 5.75574 2.70327 5.93889C2.74358 6.12205 2.82178 6.29474 2.93284 6.44586C3.10231 6.67633 3.34128 6.84633 3.61459 6.93084C3.88757 7.01515 4.18043 7.00941 4.4499 6.91448C4.71977 6.81935 4.952 6.64012 5.11241 6.40316L5.30917 5.37345L5.04677 4.86973L3.86045 4.32788L2.69861 5.38223L2.69878 5.38239ZM3.50118 3.52209L2.69119 3.33023L2.69152 3.32989C2.64466 3.19977 2.64088 3.05804 2.68075 2.92561C2.72061 2.79319 2.80201 2.67709 2.91292 2.59448C3.02384 2.51227 3.15841 2.46822 3.29646 2.46892C3.43452 2.46962 3.56863 2.51504 3.67871 2.59836L3.50118 3.52209ZM2.62099 3.52378C2.4457 3.58185 2.29272 3.6928 2.18308 3.84137C2.07316 3.9902 2.01187 4.16933 2.00759 4.35429C2.0033 4.53926 2.05622 4.72103 2.15912 4.87479C2.26189 5.02836 2.40954 5.14648 2.58184 5.21229L3.71803 4.18275L3.50962 3.73556L2.62099 3.52378ZM5.70675 6.53563C5.56709 6.53539 5.43147 6.4888 5.32115 6.40316L5.49615 5.4828L6.30615 5.67264C6.34153 5.76956 6.35308 5.87357 6.33984 5.97589C6.32659 6.07822 6.28894 6.17585 6.23004 6.26057C6.17146 6.34521 6.09327 6.41443 6.00215 6.46233C5.91104 6.51022 5.80969 6.53537 5.70675 6.53563ZM5.48568 5.27018L6.37668 5.47909C6.55466 5.41887 6.70936 5.30452 6.81915 5.15205C6.92918 4.99933 6.98893 4.81614 6.99009 4.62791C6.99005 4.44652 6.93497 4.26941 6.83214 4.11998C6.72948 3.97073 6.5838 3.85631 6.41448 3.79193L5.24943 4.81624L5.48568 5.27018Z" fill="white"/>
|
||||
<path d="M3.92192 4.12677L5.10351 4.66862L6.29589 3.62018C6.31317 3.53367 6.32176 3.44565 6.32154 3.35743C6.32166 3.07191 6.23062 2.79381 6.06167 2.56363C5.89312 2.33388 5.65536 2.16419 5.38329 2.07949C5.11148 1.99501 4.81972 2.0001 4.55102 2.094C4.28194 2.18808 4.0501 2.36592 3.88952 2.60143L3.69141 3.63385L3.92209 4.1266L3.92192 4.12677Z" fill="#FEC514"/>
|
||||
<path d="M2.69879 5.3824C2.66145 5.56618 2.66298 5.75574 2.70329 5.9389C2.7436 6.12205 2.82179 6.29474 2.93285 6.44586C3.10232 6.67634 3.34129 6.84634 3.6146 6.93085C3.88758 7.01516 4.18044 7.00942 4.44991 6.91448C4.71979 6.81935 4.95201 6.64013 5.11242 6.40317L5.30919 5.37346L5.04678 4.86974L3.86047 4.32788L2.69862 5.38223L2.69879 5.3824Z" fill="#00BFB3"/>
|
||||
<path d="M2.69015 3.33018L3.50015 3.52205L3.67767 2.59831C3.56759 2.51499 3.43348 2.46958 3.29543 2.46888C3.15737 2.46818 3.0228 2.51223 2.91189 2.59443C2.80098 2.67705 2.71958 2.79314 2.67971 2.92557C2.63984 3.05799 2.64362 3.19973 2.69049 3.32984" fill="#F04E98"/>
|
||||
<path d="M2.62145 3.5238C2.44617 3.58187 2.29319 3.69282 2.18355 3.84139C2.07363 3.99022 2.01234 4.16935 2.00805 4.35431C2.00377 4.53928 2.05669 4.72106 2.15959 4.87482C2.26235 5.02838 2.41001 5.1465 2.5823 5.21232L3.7185 4.18277L3.51009 3.73558L2.62145 3.5238V3.5238Z" fill="#1BA9F5"/>
|
||||
<path d="M5.32227 6.40315C5.43258 6.48878 5.56821 6.53538 5.70786 6.53562C5.8108 6.53536 5.91215 6.51021 6.00327 6.46231C6.09438 6.41442 6.17257 6.3452 6.23115 6.26056C6.29005 6.17584 6.3277 6.0782 6.34095 5.97588C6.35419 5.87356 6.34264 5.76955 6.30726 5.67263L5.49726 5.48279L5.32227 6.40315Z" fill="#93C90E"/>
|
||||
<path d="M5.48625 5.27024L6.37725 5.47915C6.55522 5.41894 6.70993 5.30459 6.81971 5.15212C6.92975 4.9994 6.98949 4.81621 6.99066 4.62798C6.99061 4.44659 6.93554 4.26947 6.83271 4.12004C6.73005 3.9708 6.58436 3.85637 6.41505 3.79199L5.25 4.8163L5.48625 5.27024V5.27024Z" fill="#0077CC"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_dddd_6_66599" x="20.7" y="15.615" width="147.6" height="114.435" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect1_dropShadow_6_66599"/>
|
||||
<feOffset dy="6.75"/>
|
||||
<feGaussianBlur stdDeviation="3.375"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6_66599"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect2_dropShadow_6_66599"/>
|
||||
<feOffset dy="2.565"/>
|
||||
<feGaussianBlur stdDeviation="2.7"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
|
||||
<feBlend mode="normal" in2="effect1_dropShadow_6_66599" result="effect2_dropShadow_6_66599"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect3_dropShadow_6_66599"/>
|
||||
<feOffset dy="1.17"/>
|
||||
<feGaussianBlur stdDeviation="1.8"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0"/>
|
||||
<feBlend mode="normal" in2="effect2_dropShadow_6_66599" result="effect3_dropShadow_6_66599"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feMorphology radius="0.45" operator="erode" in="SourceAlpha" result="effect4_dropShadow_6_66599"/>
|
||||
<feOffset dy="0.405"/>
|
||||
<feGaussianBlur stdDeviation="0.9"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.08 0"/>
|
||||
<feBlend mode="normal" in2="effect3_dropShadow_6_66599" result="effect4_dropShadow_6_66599"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect4_dropShadow_6_66599" result="shape"/>
|
||||
</filter>
|
||||
<filter id="filter1_ddd_6_66599" x="-4.5" y="6.525" width="171" height="18" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="2.025"/>
|
||||
<feGaussianBlur stdDeviation="2.25"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6_66599"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="0.855"/>
|
||||
<feGaussianBlur stdDeviation="0.9"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
|
||||
<feBlend mode="normal" in2="effect1_dropShadow_6_66599" result="effect2_dropShadow_6_66599"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="0.315"/>
|
||||
<feGaussianBlur stdDeviation="0.315"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.07 0"/>
|
||||
<feBlend mode="normal" in2="effect2_dropShadow_6_66599" result="effect3_dropShadow_6_66599"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect3_dropShadow_6_66599" result="shape"/>
|
||||
</filter>
|
||||
<clipPath id="clip0_6_66599">
|
||||
<rect width="162" height="117" rx="3.6" fill="white"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip1_6_66599">
|
||||
<rect width="135" height="99" fill="white" transform="translate(27 18)"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip2_6_66599">
|
||||
<rect width="5.4" height="5.4" fill="white" transform="translate(1.79883 1.80017)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -10,7 +10,10 @@ import {
|
|||
ObservabilityPublicStart,
|
||||
} from '@kbn/observability-plugin/public';
|
||||
import {
|
||||
HttpStart,
|
||||
ObservabilitySharedPluginSetup,
|
||||
ObservabilitySharedPluginStart,
|
||||
} from '@kbn/observability-shared-plugin/public';
|
||||
import {
|
||||
AppMountParameters,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
|
@ -20,7 +23,12 @@ import {
|
|||
} from '@kbn/core/public';
|
||||
import type { CloudExperimentsPluginStart } from '@kbn/cloud-experiments-plugin/common';
|
||||
import { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/public';
|
||||
import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public';
|
||||
import { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { DiscoverSetup, DiscoverStart } from '@kbn/discover-plugin/public';
|
||||
import { FleetSetup, FleetStart } from '@kbn/fleet-plugin/public';
|
||||
import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
|
||||
import { UsageCollectionSetup, UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
|
||||
import type { ObservabilityOnboardingConfig } from '../server';
|
||||
import { PLUGIN_ID } from '../common';
|
||||
import { ObservabilityOnboardingLocatorDefinition } from './locators/onboarding_locator/locator_definition';
|
||||
|
@ -34,23 +42,30 @@ export type ObservabilityOnboardingPluginStart = void;
|
|||
export interface ObservabilityOnboardingPluginSetupDeps {
|
||||
data: DataPublicPluginSetup;
|
||||
observability: ObservabilityPublicSetup;
|
||||
observabilityShared: ObservabilitySharedPluginSetup;
|
||||
discover: DiscoverSetup;
|
||||
share: SharePluginSetup;
|
||||
fleet: FleetSetup;
|
||||
security: SecurityPluginSetup;
|
||||
cloud?: CloudSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
export interface ObservabilityOnboardingPluginStartDeps {
|
||||
cloudExperiments?: CloudExperimentsPluginStart;
|
||||
http: HttpStart;
|
||||
data: DataPublicPluginStart;
|
||||
observability: ObservabilityPublicStart;
|
||||
observabilityShared: ObservabilitySharedPluginStart;
|
||||
discover: DiscoverStart;
|
||||
share: SharePluginStart;
|
||||
fleet: FleetStart;
|
||||
security: SecurityPluginStart;
|
||||
cloud?: CloudStart;
|
||||
usageCollection?: UsageCollectionStart;
|
||||
cloudExperiments?: CloudExperimentsPluginStart;
|
||||
}
|
||||
|
||||
export interface ObservabilityOnboardingPluginContextValue {
|
||||
core: CoreStart;
|
||||
plugins: ObservabilityOnboardingPluginSetupDeps;
|
||||
data: DataPublicPluginStart;
|
||||
observability: ObservabilityPublicStart;
|
||||
config: ConfigSchema;
|
||||
}
|
||||
export type ObservabilityOnboardingContextValue = CoreStart &
|
||||
ObservabilityOnboardingPluginStartDeps & { config: ConfigSchema };
|
||||
|
||||
export class ObservabilityOnboardingPlugin
|
||||
implements Plugin<ObservabilityOnboardingPluginSetup, ObservabilityOnboardingPluginStart>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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 type { FleetStartContract } from '@kbn/fleet-plugin/server';
|
||||
|
||||
export function getAgentVersion(fleetStart: FleetStartContract, kibanaVersion: string) {
|
||||
// If undefined, we will follow fleet's strategy to select latest available version:
|
||||
// for serverless we will use the latest published version, for statefull we will use
|
||||
// current Kibana version. If false, irrespective of fleet flags and logic, we are
|
||||
// explicitly deciding to not append the current version.
|
||||
const includeCurrentVersion = kibanaVersion.endsWith('-SNAPSHOT') ? false : undefined;
|
||||
|
||||
const agentClient = fleetStart.agentService.asInternalUser;
|
||||
return agentClient.getLatestAgentAvailableVersion(includeCurrentVersion);
|
||||
}
|
|
@ -5,10 +5,19 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CoreStart } from '@kbn/core/server';
|
||||
import { CoreSetup } from '@kbn/core/server';
|
||||
import { CloudSetup } from '@kbn/cloud-plugin/server';
|
||||
import { EsLegacyConfigService } from '../services/es_legacy_config_service';
|
||||
|
||||
export function getFallbackKibanaUrl({ http }: CoreStart) {
|
||||
export function getKibanaUrl(coreSetup: CoreSetup, cloudSetup?: CloudSetup) {
|
||||
return (
|
||||
coreSetup.http.basePath.publicBaseUrl ?? // priority given to server.publicBaseUrl
|
||||
cloudSetup?.kibanaUrl ?? // then cloud id
|
||||
getFallbackKibanaUrl(coreSetup) // falls back to local network binding
|
||||
);
|
||||
}
|
||||
|
||||
export function getFallbackKibanaUrl({ http }: CoreSetup) {
|
||||
const basePath = http.basePath;
|
||||
const { protocol, hostname, port } = http.getServerInfo();
|
||||
return `${protocol}://${hostname}:${port}${basePath
|
||||
|
|
|
@ -7,52 +7,24 @@
|
|||
|
||||
import { ElasticsearchClient } from '@kbn/core/server';
|
||||
import { termQuery } from '@kbn/observability-plugin/server';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { AGENT_ID } from '../../../common/es_fields';
|
||||
import {
|
||||
LogFilesState,
|
||||
ObservabilityOnboardingType,
|
||||
SystemLogsState,
|
||||
} from '../../saved_objects/observability_onboarding_status';
|
||||
import { ElasticAgentStepPayload } from '../types';
|
||||
|
||||
export async function getHasLogs({
|
||||
type,
|
||||
state,
|
||||
esClient,
|
||||
payload,
|
||||
}: {
|
||||
type: ObservabilityOnboardingType;
|
||||
state?: LogFilesState | SystemLogsState;
|
||||
esClient: ElasticsearchClient;
|
||||
payload?: ElasticAgentStepPayload;
|
||||
}) {
|
||||
if (!state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function getHasLogs(esClient: ElasticsearchClient, agentId: string) {
|
||||
try {
|
||||
const { namespace } = state;
|
||||
const index =
|
||||
type === 'logFiles'
|
||||
? `logs-${(state as LogFilesState).datasetName}-${namespace}`
|
||||
: [`logs-system.syslog-${namespace}`, `logs-system.auth-${namespace}`];
|
||||
|
||||
const agentId = payload?.agentId;
|
||||
|
||||
const { hits } = await esClient.search({
|
||||
index,
|
||||
const result = await esClient.search({
|
||||
index: ['logs-*', 'metrics-*'],
|
||||
ignore_unavailable: true,
|
||||
size: 0,
|
||||
terminate_after: 1,
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
filter: [...termQuery(AGENT_ID, agentId)],
|
||||
},
|
||||
query: {
|
||||
bool: {
|
||||
filter: termQuery(AGENT_ID, agentId),
|
||||
},
|
||||
},
|
||||
});
|
||||
const total = hits.total as { value: number };
|
||||
return total.value > 0;
|
||||
const { value } = result.hits.total as estypes.SearchTotalHits;
|
||||
return value > 0;
|
||||
} catch (error) {
|
||||
if (error.statusCode === 404) {
|
||||
return false;
|
||||
|
|
|
@ -12,15 +12,20 @@ import {
|
|||
FleetUnauthorizedError,
|
||||
type PackageClient,
|
||||
} from '@kbn/fleet-plugin/server';
|
||||
import type { TemplateAgentPolicyInput } from '@kbn/fleet-plugin/common';
|
||||
import { dump } from 'js-yaml';
|
||||
import { PackageDataStreamTypes } from '@kbn/fleet-plugin/common/types';
|
||||
import { getObservabilityOnboardingFlow, saveObservabilityOnboardingFlow } from '../../lib/state';
|
||||
import type { SavedObservabilityOnboardingFlow } from '../../saved_objects/observability_onboarding_status';
|
||||
import { ObservabilityOnboardingFlow } from '../../saved_objects/observability_onboarding_status';
|
||||
import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route';
|
||||
import { getHasLogs } from './get_has_logs';
|
||||
|
||||
import { getKibanaUrl } from '../../lib/get_fallback_urls';
|
||||
import { hasLogMonitoringPrivileges } from '../logs/api_key/has_log_monitoring_privileges';
|
||||
import { createShipperApiKey } from '../logs/api_key/create_shipper_api_key';
|
||||
import { createInstallApiKey } from '../logs/api_key/create_install_api_key';
|
||||
import { getAgentVersion } from '../../lib/get_agent_version';
|
||||
import { getFallbackESUrl } from '../../lib/get_fallback_urls';
|
||||
import { ElasticAgentStepPayload, Integration, StepProgressPayloadRT } from '../types';
|
||||
import { ElasticAgentStepPayload, InstalledIntegration, StepProgressPayloadRT } from '../types';
|
||||
|
||||
const updateOnboardingFlowRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'PUT /internal/observability_onboarding/flow/{onboardingId}',
|
||||
|
@ -129,9 +134,7 @@ const getProgressRoute = createObservabilityOnboardingServerRoute({
|
|||
onboardingId: t.string,
|
||||
}),
|
||||
}),
|
||||
async handler(resources): Promise<{
|
||||
progress: Record<string, { status: string; message?: string }>;
|
||||
}> {
|
||||
async handler(resources): Promise<Pick<SavedObservabilityOnboardingFlow, 'progress'>> {
|
||||
const {
|
||||
params: {
|
||||
path: { onboardingId },
|
||||
|
@ -154,21 +157,11 @@ const getProgressRoute = createObservabilityOnboardingServerRoute({
|
|||
|
||||
const esClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser;
|
||||
|
||||
const type = savedObservabilityOnboardingState.type;
|
||||
|
||||
if (progress['ea-status']?.status === 'complete') {
|
||||
const { agentId } = progress['ea-status']?.payload as ElasticAgentStepPayload;
|
||||
try {
|
||||
const hasLogs = await getHasLogs({
|
||||
type,
|
||||
state: savedObservabilityOnboardingState.state,
|
||||
esClient,
|
||||
payload: progress['ea-status']?.payload as ElasticAgentStepPayload,
|
||||
});
|
||||
if (hasLogs) {
|
||||
progress['logs-ingest'] = { status: 'complete' };
|
||||
} else {
|
||||
progress['logs-ingest'] = { status: 'loading' };
|
||||
}
|
||||
const hasLogs = await getHasLogs(esClient, agentId);
|
||||
progress['logs-ingest'] = { status: hasLogs ? 'complete' : 'loading' };
|
||||
} catch (error) {
|
||||
progress['logs-ingest'] = { status: 'warning', message: error.message };
|
||||
}
|
||||
|
@ -180,6 +173,88 @@ const getProgressRoute = createObservabilityOnboardingServerRoute({
|
|||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* This endpoint starts a new onboarding flow and creates two API keys:
|
||||
* 1. A short-lived API key with privileges to install integrations.
|
||||
* 2. An API key with privileges to ingest log and metric data used to configure Elastic Agent.
|
||||
*
|
||||
* It also returns all required information to download the onboarding script and install the
|
||||
* Elastic agent.
|
||||
*
|
||||
* If the user does not have all necessary privileges a 403 Forbidden response is returned.
|
||||
*
|
||||
* This endpoint differs from the existing `POST /internal/observability_onboarding/logs/flow`
|
||||
* endpoint in that it caters for the auto-detect flow where integrations are detected and installed
|
||||
* on the host system, rather than in the Kiabana UI.
|
||||
*/
|
||||
const createFlowRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'POST /internal/observability_onboarding/flow',
|
||||
options: { tags: [] },
|
||||
params: t.type({
|
||||
body: t.type({
|
||||
name: t.string,
|
||||
}),
|
||||
}),
|
||||
async handler(resources) {
|
||||
const {
|
||||
context,
|
||||
params: {
|
||||
body: { name },
|
||||
},
|
||||
core,
|
||||
request,
|
||||
plugins,
|
||||
kibanaVersion,
|
||||
} = resources;
|
||||
const coreStart = await core.start();
|
||||
const {
|
||||
elasticsearch: { client },
|
||||
} = await context.core;
|
||||
const savedObjectsClient = coreStart.savedObjects.getScopedClient(request);
|
||||
|
||||
const hasPrivileges = await hasLogMonitoringPrivileges(client.asCurrentUser);
|
||||
if (!hasPrivileges) {
|
||||
throw Boom.forbidden('Unauthorized to create log indices');
|
||||
}
|
||||
|
||||
const fleetPluginStart = await plugins.fleet.start();
|
||||
const securityPluginStart = await plugins.security.start();
|
||||
|
||||
const [onboardingFlow, ingestApiKey, installApiKey, elasticAgentVersion] = await Promise.all([
|
||||
saveObservabilityOnboardingFlow({
|
||||
savedObjectsClient,
|
||||
observabilityOnboardingState: {
|
||||
type: 'autoDetect',
|
||||
state: undefined,
|
||||
progress: {},
|
||||
},
|
||||
}),
|
||||
createShipperApiKey(client.asCurrentUser, name),
|
||||
securityPluginStart.authc.apiKeys.create(request, createInstallApiKey(name)),
|
||||
getAgentVersion(fleetPluginStart, kibanaVersion),
|
||||
]);
|
||||
|
||||
if (!installApiKey) {
|
||||
throw Boom.notFound('License does not allow API key creation.');
|
||||
}
|
||||
|
||||
const kibanaUrl = getKibanaUrl(core.setup, plugins.cloud?.setup);
|
||||
const scriptDownloadUrl = new URL(
|
||||
core.setup.http.staticAssets.getPluginAssetHref('auto_detect.sh'),
|
||||
kibanaUrl
|
||||
).toString();
|
||||
|
||||
return {
|
||||
onboardingFlow,
|
||||
ingestApiKey: ingestApiKey.encoded,
|
||||
installApiKey: installApiKey.encoded,
|
||||
elasticAgentVersion,
|
||||
kibanaUrl,
|
||||
scriptDownloadUrl,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* This endpoints installs the requested integrations and returns the corresponding config file for Elastic Agent.
|
||||
*
|
||||
|
@ -239,9 +314,12 @@ const integrationsInstallRoute = createObservabilityOnboardingServerRoute({
|
|||
});
|
||||
}
|
||||
|
||||
let agentPolicyInputs: TemplateAgentPolicyInput[] = [];
|
||||
let installedIntegrations: InstalledIntegration[] = [];
|
||||
try {
|
||||
agentPolicyInputs = await ensureInstalledIntegrations(integrationsToInstall, packageClient);
|
||||
installedIntegrations = await ensureInstalledIntegrations(
|
||||
integrationsToInstall,
|
||||
packageClient
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof FleetUnauthorizedError) {
|
||||
return response.forbidden({
|
||||
|
@ -262,10 +340,10 @@ const integrationsInstallRoute = createObservabilityOnboardingServerRoute({
|
|||
...savedObservabilityOnboardingState.progress,
|
||||
'install-integrations': {
|
||||
status: 'complete',
|
||||
payload: integrationsToInstall,
|
||||
payload: installedIntegrations,
|
||||
},
|
||||
},
|
||||
} as ObservabilityOnboardingFlow,
|
||||
},
|
||||
});
|
||||
|
||||
const elasticsearchUrl = plugins.cloud?.setup?.elasticsearchUrl
|
||||
|
@ -278,55 +356,89 @@ const integrationsInstallRoute = createObservabilityOnboardingServerRoute({
|
|||
},
|
||||
body: generateAgentConfig({
|
||||
esHost: elasticsearchUrl,
|
||||
inputs: agentPolicyInputs,
|
||||
inputs: installedIntegrations.map(({ inputs }) => inputs).flat(),
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export interface RegistryIntegrationToInstall {
|
||||
pkgName: string;
|
||||
installSource: 'registry';
|
||||
}
|
||||
export interface CustomIntegrationToInstall {
|
||||
pkgName: string;
|
||||
installSource: 'custom';
|
||||
logFilePaths: string[];
|
||||
}
|
||||
export type IntegrationToInstall = RegistryIntegrationToInstall | CustomIntegrationToInstall;
|
||||
|
||||
async function ensureInstalledIntegrations(
|
||||
integrationsToInstall: Integration[],
|
||||
integrationsToInstall: IntegrationToInstall[],
|
||||
packageClient: PackageClient
|
||||
) {
|
||||
const agentPolicyInputs: TemplateAgentPolicyInput[] = [];
|
||||
for (const integration of integrationsToInstall) {
|
||||
const { pkgName, installSource } = integration;
|
||||
if (installSource === 'registry') {
|
||||
const pkg = await packageClient.ensureInstalledPackage({ pkgName });
|
||||
const inputs = await packageClient.getAgentPolicyInputs(pkg.name, pkg.version);
|
||||
agentPolicyInputs.push(...inputs.filter((input) => input.type !== 'httpjson'));
|
||||
} else if (installSource === 'custom') {
|
||||
const input: TemplateAgentPolicyInput = {
|
||||
id: `filestream-${pkgName}`,
|
||||
type: 'filestream',
|
||||
streams: [
|
||||
): Promise<InstalledIntegration[]> {
|
||||
return Promise.all(
|
||||
integrationsToInstall.map(async (integration) => {
|
||||
const { pkgName, installSource } = integration;
|
||||
|
||||
if (installSource === 'registry') {
|
||||
const pkg = await packageClient.ensureInstalledPackage({ pkgName });
|
||||
const inputs = await packageClient.getAgentPolicyInputs(pkg.name, pkg.version);
|
||||
const { packageInfo } = await packageClient.getPackage(pkg.name, pkg.version);
|
||||
|
||||
return {
|
||||
installSource,
|
||||
pkgName: pkg.name,
|
||||
pkgVersion: pkg.version,
|
||||
title: packageInfo.title,
|
||||
inputs: inputs.filter((input) => input.type !== 'httpjson'),
|
||||
dataStreams:
|
||||
packageInfo.data_streams?.map(({ type, dataset }) => ({ type, dataset })) ?? [],
|
||||
kibanaAssets: pkg.installed_kibana,
|
||||
};
|
||||
}
|
||||
|
||||
const dataStream = {
|
||||
type: 'logs',
|
||||
dataset: pkgName,
|
||||
};
|
||||
const installed: InstalledIntegration = {
|
||||
installSource,
|
||||
pkgName,
|
||||
pkgVersion: '1.0.0', // Custom integrations are always installed as version `1.0.0`
|
||||
title: pkgName,
|
||||
inputs: [
|
||||
{
|
||||
id: `filestream-${pkgName}`,
|
||||
data_stream: {
|
||||
type: 'logs',
|
||||
dataset: pkgName,
|
||||
},
|
||||
paths: integration.logFilePaths,
|
||||
type: 'filestream',
|
||||
streams: [
|
||||
{
|
||||
id: `filestream-${pkgName}`,
|
||||
data_stream: dataStream,
|
||||
paths: integration.logFilePaths,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
dataStreams: [dataStream],
|
||||
kibanaAssets: [],
|
||||
};
|
||||
try {
|
||||
await packageClient.installCustomIntegration({
|
||||
pkgName,
|
||||
datasets: [{ name: pkgName, type: 'logs' }],
|
||||
datasets: [{ name: dataStream.dataset, type: dataStream.type as PackageDataStreamTypes }],
|
||||
});
|
||||
agentPolicyInputs.push(input);
|
||||
return installed;
|
||||
} catch (error) {
|
||||
// If the error is a naming collision, we can assume the integration is already installed and treat this step as successful
|
||||
if (error instanceof NamingCollisionError) {
|
||||
agentPolicyInputs.push(input);
|
||||
return installed;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return agentPolicyInputs;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,48 +459,46 @@ async function ensureInstalledIntegrations(
|
|||
function parseIntegrationsTSV(tsv: string) {
|
||||
return Object.values(
|
||||
tsv
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => line.split('\t', 3))
|
||||
.reduce<Record<string, Integration>>((acc, [pkgName, installSource, logFilePath]) => {
|
||||
const key = `${pkgName}-${installSource}`;
|
||||
if (installSource === 'registry') {
|
||||
if (logFilePath) {
|
||||
throw new Error(`Integration '${pkgName}' does not support a file path`);
|
||||
}
|
||||
acc[key] = {
|
||||
pkgName,
|
||||
installSource,
|
||||
};
|
||||
return acc;
|
||||
} else if (installSource === 'custom') {
|
||||
if (!logFilePath) {
|
||||
throw new Error(`Missing file path for integration: ${pkgName}`);
|
||||
}
|
||||
// Append file path if integration is already in the list
|
||||
const existing = acc[key];
|
||||
if (existing && existing.installSource === 'custom') {
|
||||
existing.logFilePaths.push(logFilePath);
|
||||
.reduce<Record<string, IntegrationToInstall>>(
|
||||
(acc, [pkgName, installSource, logFilePath]) => {
|
||||
const key = `${pkgName}-${installSource}`;
|
||||
if (installSource === 'registry') {
|
||||
if (logFilePath) {
|
||||
throw new Error(`Integration '${pkgName}' does not support a file path`);
|
||||
}
|
||||
acc[key] = {
|
||||
pkgName,
|
||||
installSource,
|
||||
};
|
||||
return acc;
|
||||
} else if (installSource === 'custom') {
|
||||
if (!logFilePath) {
|
||||
throw new Error(`Missing file path for integration: ${pkgName}`);
|
||||
}
|
||||
// Append file path if integration is already in the list
|
||||
const existing = acc[key];
|
||||
if (existing && existing.installSource === 'custom') {
|
||||
existing.logFilePaths.push(logFilePath);
|
||||
return acc;
|
||||
}
|
||||
acc[key] = {
|
||||
pkgName,
|
||||
installSource,
|
||||
logFilePaths: [logFilePath],
|
||||
};
|
||||
return acc;
|
||||
}
|
||||
acc[key] = {
|
||||
pkgName,
|
||||
installSource,
|
||||
logFilePaths: [logFilePath],
|
||||
};
|
||||
return acc;
|
||||
}
|
||||
throw new Error(`Invalid install source: ${installSource}`);
|
||||
}, {})
|
||||
throw new Error(`Invalid install source: ${installSource}`);
|
||||
},
|
||||
{}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const generateAgentConfig = ({
|
||||
esHost,
|
||||
inputs = [],
|
||||
}: {
|
||||
esHost: string[];
|
||||
inputs: TemplateAgentPolicyInput[];
|
||||
}) => {
|
||||
const generateAgentConfig = ({ esHost, inputs = [] }: { esHost: string[]; inputs: unknown[] }) => {
|
||||
return dump({
|
||||
outputs: {
|
||||
default: {
|
||||
|
@ -402,6 +512,7 @@ const generateAgentConfig = ({
|
|||
};
|
||||
|
||||
export const flowRouteRepository = {
|
||||
...createFlowRoute,
|
||||
...updateOnboardingFlowRoute,
|
||||
...stepProgressUpdateRoute,
|
||||
...getProgressRoute,
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 { ALL_SPACES_ID } from '@kbn/spaces-plugin/common/constants';
|
||||
import type { CreateAPIKeyParams } from '@kbn/security-plugin/server';
|
||||
|
||||
/**
|
||||
* Creates a short lived API key with the necessary permissions to install integrations
|
||||
*/
|
||||
export function createInstallApiKey(name: string): CreateAPIKeyParams {
|
||||
return {
|
||||
name: `onboarding_install_${name}`,
|
||||
expiration: '1h', // This API key is only used for initial setup and should be short lived
|
||||
metadata: {
|
||||
managed: true,
|
||||
application: 'logs',
|
||||
},
|
||||
kibana_role_descriptors: {
|
||||
can_install_integrations: {
|
||||
elasticsearch: {
|
||||
cluster: [],
|
||||
indices: [],
|
||||
},
|
||||
kibana: [
|
||||
{
|
||||
feature: {
|
||||
fleet: ['all'],
|
||||
fleetv2: ['all'], // TODO: Remove this once #183020 is resolved
|
||||
},
|
||||
spaces: [ALL_SPACES_ID],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -13,7 +13,10 @@ export function createShipperApiKey(esClient: ElasticsearchClient, name: string)
|
|||
return esClient.security.createApiKey({
|
||||
body: {
|
||||
name: `standalone_agent_logs_onboarding_${name}`,
|
||||
metadata: { application: 'logs' },
|
||||
metadata: {
|
||||
managed: true,
|
||||
application: 'logs',
|
||||
},
|
||||
role_descriptors: {
|
||||
standalone_agent: {
|
||||
cluster,
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route';
|
||||
import { getFallbackKibanaUrl } from '../../lib/get_fallback_urls';
|
||||
import { getKibanaUrl } from '../../lib/get_fallback_urls';
|
||||
import { getAgentVersion } from '../../lib/get_agent_version';
|
||||
import { hasLogMonitoringPrivileges } from './api_key/has_log_monitoring_privileges';
|
||||
import { saveObservabilityOnboardingFlow } from '../../lib/state';
|
||||
import { createShipperApiKey } from './api_key/create_shipper_api_key';
|
||||
|
@ -39,27 +40,12 @@ const installShipperSetupRoute = createObservabilityOnboardingServerRoute({
|
|||
elasticAgentVersion: string;
|
||||
}> {
|
||||
const { core, plugins, kibanaVersion } = resources;
|
||||
const coreStart = await core.start();
|
||||
|
||||
const fleetPluginStart = await plugins.fleet.start();
|
||||
const agentClient = fleetPluginStart.agentService.asInternalUser;
|
||||
|
||||
// If undefined, we will follow fleet's strategy to select latest available version:
|
||||
// for serverless we will use the latest published version, for statefull we will use
|
||||
// current Kibana version. If false, irrespective of fleet flags and logic, we are
|
||||
// explicitly deciding to not append the current version.
|
||||
const includeCurrentVersion = kibanaVersion.endsWith('-SNAPSHOT') ? false : undefined;
|
||||
|
||||
const elasticAgentVersion = await agentClient.getLatestAgentAvailableVersion(
|
||||
includeCurrentVersion
|
||||
);
|
||||
|
||||
const kibanaUrl =
|
||||
core.setup.http.basePath.publicBaseUrl ?? // priority given to server.publicBaseUrl
|
||||
plugins.cloud?.setup?.kibanaUrl ?? // then cloud id
|
||||
getFallbackKibanaUrl(coreStart); // falls back to local network binding
|
||||
const elasticAgentVersion = await getAgentVersion(fleetPluginStart, kibanaVersion);
|
||||
const kibanaUrl = getKibanaUrl(core.setup, plugins.cloud?.setup);
|
||||
const scriptDownloadUrl = new URL(
|
||||
coreStart.http.staticAssets.getPluginAssetHref('standalone_agent_setup.sh'),
|
||||
core.setup.http.staticAssets.getPluginAssetHref('standalone_agent_setup.sh'),
|
||||
kibanaUrl
|
||||
).toString();
|
||||
|
||||
|
|
|
@ -52,19 +52,27 @@ export interface ObservabilityOnboardingRouteCreateOptions {
|
|||
};
|
||||
}
|
||||
|
||||
export const IntegrationRT = t.union([
|
||||
t.type({
|
||||
pkgName: t.string,
|
||||
installSource: t.literal('registry'),
|
||||
}),
|
||||
t.type({
|
||||
pkgName: t.string,
|
||||
installSource: t.literal('custom'),
|
||||
logFilePaths: t.array(t.string),
|
||||
}),
|
||||
]);
|
||||
export const IntegrationRT = t.type({
|
||||
installSource: t.union([t.literal('registry'), t.literal('custom')]),
|
||||
pkgName: t.string,
|
||||
pkgVersion: t.string,
|
||||
title: t.string,
|
||||
inputs: t.array(t.unknown),
|
||||
dataStreams: t.array(
|
||||
t.type({
|
||||
type: t.string,
|
||||
dataset: t.string,
|
||||
})
|
||||
),
|
||||
kibanaAssets: t.array(
|
||||
t.type({
|
||||
type: t.string,
|
||||
id: t.string,
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export type Integration = t.TypeOf<typeof IntegrationRT>;
|
||||
export type InstalledIntegration = t.TypeOf<typeof IntegrationRT>;
|
||||
|
||||
export const ElasticAgentStepPayloadRT = t.type({
|
||||
agentId: t.string,
|
||||
|
|
|
@ -23,7 +23,7 @@ export interface SystemLogsState {
|
|||
namespace: string;
|
||||
}
|
||||
|
||||
export type ObservabilityOnboardingType = 'logFiles' | 'systemLogs';
|
||||
export type ObservabilityOnboardingType = 'logFiles' | 'systemLogs' | 'autoDetect';
|
||||
|
||||
type ObservabilityOnboardingFlowState = LogFilesState | SystemLogsState | undefined;
|
||||
|
||||
|
@ -64,8 +64,21 @@ const ElasticAgentStepPayloadSchema = schema.object({
|
|||
export const InstallIntegrationsStepPayloadSchema = schema.arrayOf(
|
||||
schema.object({
|
||||
pkgName: schema.string(),
|
||||
installSource: schema.string(),
|
||||
logFilePaths: schema.maybe(schema.arrayOf(schema.string())),
|
||||
pkgVersion: schema.string(),
|
||||
installSource: schema.oneOf([schema.literal('registry'), schema.literal('custom')]),
|
||||
inputs: schema.arrayOf(schema.any()),
|
||||
dataStreams: schema.arrayOf(
|
||||
schema.object({
|
||||
type: schema.string(),
|
||||
dataset: schema.string(),
|
||||
})
|
||||
),
|
||||
kibanaAssets: schema.arrayOf(
|
||||
schema.object({
|
||||
type: schema.string(),
|
||||
id: schema.string(),
|
||||
})
|
||||
),
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
PluginStart as DataPluginStart,
|
||||
} from '@kbn/data-plugin/server';
|
||||
import { FleetSetupContract, FleetStartContract } from '@kbn/fleet-plugin/server';
|
||||
import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server';
|
||||
import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
|
||||
|
@ -21,6 +22,7 @@ export interface ObservabilityOnboardingPluginSetupDependencies {
|
|||
cloud: CloudSetup;
|
||||
usageCollection: UsageCollectionSetup;
|
||||
fleet: FleetSetupContract;
|
||||
security: SecurityPluginSetup;
|
||||
}
|
||||
|
||||
export interface ObservabilityOnboardingPluginStartDependencies {
|
||||
|
@ -29,6 +31,7 @@ export interface ObservabilityOnboardingPluginStartDependencies {
|
|||
cloud: CloudStart;
|
||||
usageCollection: undefined;
|
||||
fleet: FleetStartContract;
|
||||
security: SecurityPluginStart;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
|
|
|
@ -38,7 +38,14 @@
|
|||
"@kbn/home-sample-data-tab",
|
||||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/react-kibana-context-theme",
|
||||
"@kbn/ebt"
|
||||
"@kbn/discover-plugin",
|
||||
"@kbn/utility-types",
|
||||
"@kbn/spaces-plugin",
|
||||
"@kbn/ebt",
|
||||
"@kbn/dashboard-plugin",
|
||||
"@kbn/deeplinks-analytics"
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue