mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Logs Onboarding] Adds install shipper step for custom logs (#157802)
Closes #154937
This PR includes the steps to install standalone elastic agent +
reporting the status from bash script back to kibana.

---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Yngrid Coello <yngrid.coello@elastic.co>
Co-authored-by: Yngrid Coello <yngrdyn@gmail.com>
This commit is contained in:
parent
9e01dc815f
commit
12401b2216
24 changed files with 896 additions and 157 deletions
|
@ -2097,6 +2097,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"observability-onboarding-state": {
|
||||
"properties": {
|
||||
"state": {
|
||||
"type": "object",
|
||||
"dynamic": false
|
||||
},
|
||||
"progress": {
|
||||
"type": "object",
|
||||
"dynamic": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"ml-job": {
|
||||
"properties": {
|
||||
"job_id": {
|
||||
|
|
|
@ -119,6 +119,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
"ml-module": "c88b6a012cfb7b7adb7629b1edeab6b83f1fd048",
|
||||
"ml-trained-model": "49a1685d79990ad05ea1d1d30e28456fe002f3b9",
|
||||
"monitoring-telemetry": "24f7393dfacb6c7b0f7ad7d242171a1c29feaa48",
|
||||
"observability-onboarding-state": "9a55f01199158a68ea8a0123e99ff092cdcdb71c",
|
||||
"osquery-manager-usage-metric": "23a8f08a98dd0f58ab4e559daa35b06edc40ed4f",
|
||||
"osquery-pack": "edd84b2c59ef36214ece0676706da8f22175c660",
|
||||
"osquery-pack-asset": "18e08979d46ee7e5538f54c080aec4d8c58516ca",
|
||||
|
|
|
@ -233,6 +233,7 @@ describe('split .kibana index into multiple system indices', () => {
|
|||
"ml-module",
|
||||
"ml-trained-model",
|
||||
"monitoring-telemetry",
|
||||
"observability-onboarding-state",
|
||||
"osquery-manager-usage-metric",
|
||||
"osquery-pack",
|
||||
"osquery-pack-asset",
|
||||
|
|
|
@ -89,6 +89,7 @@ const previouslyRegisteredTypes = [
|
|||
'ml-module',
|
||||
'ml-telemetry',
|
||||
'monitoring-telemetry',
|
||||
'observability-onboarding-state',
|
||||
'osquery-pack',
|
||||
'osquery-pack-asset',
|
||||
'osquery-saved-query',
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
|
||||
API_KEY_ENCODED=$1
|
||||
API_ENDPOINT=$2
|
||||
|
||||
updateStepProgress() {
|
||||
echo " GET $API_ENDPOINT/step/$1?status=$2"
|
||||
curl --request GET \
|
||||
--url "$API_ENDPOINT/step/$1?status=$2" \
|
||||
--header "Authorization: ApiKey $API_KEY_ENCODED" \
|
||||
--header "Content-Type: application/json" \
|
||||
--header "kbn-xsrf: true"
|
||||
echo ""
|
||||
}
|
||||
|
||||
echo "Downloading Elastic Agent"
|
||||
# https://www.elastic.co/guide/en/fleet/8.7/install-standalone-elastic-agent.html
|
||||
curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.7.1-linux-x86_64.tar.gz
|
||||
updateStepProgress "ea-download" "success"
|
||||
echo "Extracting Elastic Agent"
|
||||
tar xzvf elastic-agent-8.7.1-linux-x86_64.tar.gz
|
||||
updateStepProgress "ea-extract" "success"
|
||||
echo "Installing Elastic Agent"
|
||||
cd elastic-agent-8.7.1-linux-x86_64
|
||||
./elastic-agent install -f
|
||||
updateStepProgress "ea-install" "success"
|
||||
echo "Sending status to Kibana..."
|
||||
updateStepProgress "ea-status" "active"
|
|
@ -5,20 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { PropsWithChildren, useState } from 'react';
|
||||
import { Buffer } from 'buffer';
|
||||
import { flatten, zip } from 'lodash';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
EuiButton,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
EuiSpacer,
|
||||
EuiCard,
|
||||
EuiIcon,
|
||||
EuiIconProps,
|
||||
EuiButtonGroup,
|
||||
EuiCodeBlock,
|
||||
EuiSteps,
|
||||
EuiSkeletonRectangle,
|
||||
} from '@elastic/eui';
|
||||
import {
|
||||
StepPanel,
|
||||
|
@ -26,178 +23,221 @@ import {
|
|||
StepPanelFooter,
|
||||
} from '../../../shared/step_panel';
|
||||
import { useWizard } from '.';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
|
||||
|
||||
type ElasticAgentPlatform = 'linux-tar' | 'macos' | 'windows';
|
||||
export function InstallElasticAgent() {
|
||||
const { goToStep, goBack, getState, setState } = useWizard();
|
||||
const { goToStep, goBack, getState, CurrentStep } = useWizard();
|
||||
const wizardState = getState();
|
||||
const [elasticAgentPlatform, setElasticAgentPlatform] = useState(
|
||||
wizardState.elasticAgentPlatform
|
||||
);
|
||||
const [alternativeShippers, setAlternativeShippers] = useState(
|
||||
wizardState.alternativeShippers
|
||||
);
|
||||
const [elasticAgentPlatform, setElasticAgentPlatform] =
|
||||
useState<ElasticAgentPlatform>('linux-tar');
|
||||
|
||||
function onContinue() {
|
||||
setState({ ...getState(), elasticAgentPlatform, alternativeShippers });
|
||||
goToStep('collectLogs');
|
||||
}
|
||||
|
||||
function createAlternativeShipperToggle(
|
||||
type: NonNullable<keyof typeof alternativeShippers>
|
||||
) {
|
||||
return () => {
|
||||
setAlternativeShippers({
|
||||
...alternativeShippers,
|
||||
[type]: !alternativeShippers[type],
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function onBack() {
|
||||
goBack();
|
||||
}
|
||||
|
||||
return (
|
||||
<StepPanel
|
||||
title="Install the Elastic Agent"
|
||||
panelFooter={
|
||||
<StepPanelFooter
|
||||
items={[
|
||||
<EuiButton color="ghost" fill onClick={onBack}>
|
||||
Back
|
||||
</EuiButton>,
|
||||
<EuiButton color="primary" fill onClick={onContinue}>
|
||||
Continue
|
||||
</EuiButton>,
|
||||
]}
|
||||
/>
|
||||
const { data: installShipperSetup, status: installShipperSetupStatus } =
|
||||
useFetcher((callApi) => {
|
||||
if (CurrentStep === InstallElasticAgent) {
|
||||
return callApi(
|
||||
'POST /internal/observability_onboarding/custom_logs/install_shipper_setup',
|
||||
{
|
||||
params: {
|
||||
body: {
|
||||
name: wizardState.datasetName,
|
||||
state: {
|
||||
datasetName: wizardState.datasetName,
|
||||
namespace: wizardState.namespace,
|
||||
customConfigurations: wizardState.customConfigurations,
|
||||
logFilePaths: wizardState.logFilePaths,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
>
|
||||
}, []);
|
||||
|
||||
const { data: yamlConfig = '', status: yamlConfigStatus } = useFetcher(
|
||||
(callApi) => {
|
||||
if (CurrentStep === InstallElasticAgent && installShipperSetup) {
|
||||
return callApi(
|
||||
'GET /api/observability_onboarding/elastic_agent/config',
|
||||
{
|
||||
headers: {
|
||||
authorization: `ApiKey ${installShipperSetup.apiKeyEncoded}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
[installShipperSetup?.apiKeyId, installShipperSetup?.apiKeyEncoded]
|
||||
);
|
||||
|
||||
const apiKeyEncoded = installShipperSetup?.apiKeyEncoded;
|
||||
|
||||
return (
|
||||
<StepPanel title="Install shipper to collect data">
|
||||
<StepPanelContent>
|
||||
<EuiText color="subdued">
|
||||
<p>
|
||||
Select a platform and run the command to install, enroll, and start
|
||||
the Elastic Agent. Do this for each host. For other platforms, see
|
||||
our downloads page. Review host requirements and other installation
|
||||
options.
|
||||
Add Elastic Agent to your hosts to begin sending data to your
|
||||
Elastic Cloud. Run standalone if you want to download and manage
|
||||
each agent configuration file on your own, or enroll in Fleet, for
|
||||
centralized management of all your agents through our Fleet managed
|
||||
interface.
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiButtonGroup
|
||||
isFullWidth
|
||||
legend="Choose platform"
|
||||
options={[
|
||||
{ id: 'linux-tar', label: 'Linux Tar' },
|
||||
{ id: 'macos', label: 'MacOs' },
|
||||
{ id: 'windows', label: 'Windows' },
|
||||
{ id: 'deb', label: 'DEB' },
|
||||
{ id: 'rpm', label: 'RPM' },
|
||||
<EuiSteps
|
||||
steps={[
|
||||
{
|
||||
title: 'Install the Elastic Agent',
|
||||
status:
|
||||
installShipperSetupStatus === FETCH_STATUS.LOADING
|
||||
? 'loading'
|
||||
: 'current',
|
||||
children: (
|
||||
<>
|
||||
<EuiText color="subdued">
|
||||
<p>
|
||||
Select a platform and run the command to install in your
|
||||
Terminal, enroll, and start the Elastic Agent. Do this for
|
||||
each host. For other platforms, see our downloads page.
|
||||
Review host requirements and other installation options.
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiButtonGroup
|
||||
isFullWidth
|
||||
legend="Choose platform"
|
||||
options={[
|
||||
{ id: 'linux-tar', label: 'Linux' },
|
||||
{ id: 'macos', label: 'MacOs', isDisabled: true },
|
||||
{ id: 'windows', label: 'Windows', isDisabled: true },
|
||||
]}
|
||||
type="single"
|
||||
idSelected={elasticAgentPlatform}
|
||||
onChange={(id: string) =>
|
||||
setElasticAgentPlatform(id as typeof elasticAgentPlatform)
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiSkeletonRectangle
|
||||
isLoading={
|
||||
installShipperSetupStatus === FETCH_STATUS.LOADING
|
||||
}
|
||||
contentAriaLabel="Command to install elastic agent"
|
||||
width="100%"
|
||||
height={80}
|
||||
borderRadius="s"
|
||||
>
|
||||
<EuiCodeBlock language="bash" isCopyable>
|
||||
{getInstallShipperCommand({
|
||||
elasticAgentPlatform,
|
||||
apiKeyEncoded,
|
||||
apiEndpoint: installShipperSetup?.apiEndpoint,
|
||||
scriptDownloadUrl:
|
||||
installShipperSetup?.scriptDownloadUrl,
|
||||
})}
|
||||
</EuiCodeBlock>
|
||||
</EuiSkeletonRectangle>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Configure the agent',
|
||||
status:
|
||||
yamlConfigStatus === FETCH_STATUS.LOADING
|
||||
? 'loading'
|
||||
: 'incomplete',
|
||||
children: (
|
||||
<>
|
||||
<EuiText color="subdued">
|
||||
<p>
|
||||
Copy the config below to the elastic agent.yml on the host
|
||||
where the Elastic Agent is installed.
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiSkeletonRectangle
|
||||
isLoading={yamlConfigStatus === FETCH_STATUS.LOADING}
|
||||
contentAriaLabel="Elastic agent yaml configuration"
|
||||
width="100%"
|
||||
height={300}
|
||||
borderRadius="s"
|
||||
>
|
||||
<EuiCodeBlock language="yaml" isCopyable>
|
||||
{yamlConfig}
|
||||
</EuiCodeBlock>
|
||||
</EuiSkeletonRectangle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiButton
|
||||
iconType="download"
|
||||
color="primary"
|
||||
href={`data:application/yaml;base64,${Buffer.from(
|
||||
yamlConfig,
|
||||
'utf8'
|
||||
).toString('base64')}`}
|
||||
download="elastic-agent.yml"
|
||||
target="_blank"
|
||||
>
|
||||
Download config file
|
||||
</EuiButton>
|
||||
</>
|
||||
),
|
||||
},
|
||||
]}
|
||||
type="single"
|
||||
idSelected={elasticAgentPlatform}
|
||||
onChange={(id: string) =>
|
||||
setElasticAgentPlatform(id as typeof elasticAgentPlatform)
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiCodeBlock language="html" isCopyable>
|
||||
{PLATFORM_COMMAND[elasticAgentPlatform]}
|
||||
</EuiCodeBlock>
|
||||
<EuiHorizontalRule margin="l" />
|
||||
<LogsTypeSection title="Or select alternative shippers" description="">
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<OptionCard
|
||||
title="Filebeat"
|
||||
iconType="document"
|
||||
onClick={createAlternativeShipperToggle('filebeat')}
|
||||
isSelected={alternativeShippers.filebeat}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<OptionCard
|
||||
title="fluentbit"
|
||||
iconType="package"
|
||||
onClick={createAlternativeShipperToggle('fluentbit')}
|
||||
isSelected={alternativeShippers.fluentbit}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<OptionCard
|
||||
title="Logstash"
|
||||
iconType="logstashIf"
|
||||
onClick={createAlternativeShipperToggle('logstash')}
|
||||
isSelected={alternativeShippers.logstash}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<OptionCard
|
||||
title="Fluentd"
|
||||
iconType="package"
|
||||
onClick={createAlternativeShipperToggle('fluentd')}
|
||||
isSelected={alternativeShippers.fluentd}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</LogsTypeSection>
|
||||
</StepPanelContent>
|
||||
<StepPanelFooter
|
||||
items={[
|
||||
<EuiButton color="ghost" fill onClick={onBack}>
|
||||
Back
|
||||
</EuiButton>,
|
||||
<EuiButton color="primary" fill onClick={onContinue}>
|
||||
Continue
|
||||
</EuiButton>,
|
||||
]}
|
||||
/>
|
||||
</StepPanel>
|
||||
);
|
||||
}
|
||||
|
||||
function LogsTypeSection({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
}: PropsWithChildren<{ title: string; description: string }>) {
|
||||
return (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3>{title}</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiText color="subdued">
|
||||
<p>{description}</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function OptionCard({
|
||||
title,
|
||||
iconType,
|
||||
onClick,
|
||||
isSelected,
|
||||
function getInstallShipperCommand({
|
||||
elasticAgentPlatform,
|
||||
apiKeyEncoded = '$API_KEY',
|
||||
apiEndpoint = '$API_ENDPOINT',
|
||||
scriptDownloadUrl = '$SCRIPT_DOWNLOAD_URL',
|
||||
}: {
|
||||
title: string;
|
||||
iconType: EuiIconProps['type'];
|
||||
onClick: () => void;
|
||||
isSelected: boolean;
|
||||
elasticAgentPlatform: ElasticAgentPlatform;
|
||||
apiKeyEncoded: string | undefined;
|
||||
apiEndpoint: string | undefined;
|
||||
scriptDownloadUrl: string | undefined;
|
||||
}) {
|
||||
return (
|
||||
<EuiCard
|
||||
layout="horizontal"
|
||||
icon={<EuiIcon type={iconType} size="l" />}
|
||||
title={title}
|
||||
titleSize="xs"
|
||||
paddingSize="m"
|
||||
style={{ height: 56 }}
|
||||
onClick={onClick}
|
||||
hasBorder={true}
|
||||
display={isSelected ? 'primary' : undefined}
|
||||
/>
|
||||
);
|
||||
const setupScriptFilename = 'standalone_agent_setup.sh';
|
||||
const PLATFORM_COMMAND: Record<ElasticAgentPlatform, string> = {
|
||||
'linux-tar': oneLine`
|
||||
curl ${scriptDownloadUrl} -o ${setupScriptFilename} &&
|
||||
sudo bash ${setupScriptFilename} ${apiKeyEncoded} ${apiEndpoint}
|
||||
`,
|
||||
macos: oneLine`
|
||||
curl -O https://elastic.co/agent-setup.sh &&
|
||||
sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==
|
||||
`,
|
||||
windows: oneLine`
|
||||
curl -O https://elastic.co/agent-setup.sh &&
|
||||
sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==
|
||||
`,
|
||||
};
|
||||
return PLATFORM_COMMAND[elasticAgentPlatform];
|
||||
}
|
||||
|
||||
const PLATFORM_COMMAND = {
|
||||
'linux-tar': `curl -O https://elastic.co/agent-setup.sh && sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==`,
|
||||
macos: `curl -O https://elastic.co/agent-setup.sh && sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==`,
|
||||
windows: `curl -O https://elastic.co/agent-setup.sh && sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==`,
|
||||
deb: `curl -O https://elastic.co/agent-setup.sh && sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==`,
|
||||
rpm: `curl -O https://elastic.co/agent-setup.sh && sudo bash agent-setup.sh -- service.name=my-service --url=https://elasticsearch:8220 --enrollment-token=SRSc2ozWUItWXNuWE5oZzdERFU6anJtY0FIzhSRGlzeTJYcUF5UklfUQ==`,
|
||||
} as const;
|
||||
function oneLine(parts: TemplateStringsArray, ...args: string[]) {
|
||||
const str = flatten(zip(parts, args)).join('');
|
||||
return str.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import React, {
|
|||
useRef,
|
||||
} from 'react';
|
||||
|
||||
interface WizardContext<T, StepKey extends string> {
|
||||
export interface WizardContext<T, StepKey extends string> {
|
||||
CurrentStep: ComponentType;
|
||||
goToStep: (step: StepKey) => void;
|
||||
goBack: () => void;
|
||||
|
@ -172,8 +172,9 @@ export function createWizardContext<
|
|||
}
|
||||
|
||||
function useWizard() {
|
||||
const { CurrentStep: _, ...rest } = useContext(context);
|
||||
return rest;
|
||||
// const { CurrentStep: _, ...rest } = useContext(context);
|
||||
// return rest;
|
||||
return useContext(context);
|
||||
}
|
||||
|
||||
return { context, Provider, Step, useWizard };
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 { KibanaRequest } from '@kbn/core-http-server';
|
||||
import { HTTPAuthorizationHeader } from '@kbn/security-plugin/server';
|
||||
|
||||
export const getAuthenticationAPIKey = (request: KibanaRequest) => {
|
||||
const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request);
|
||||
if (authorizationHeader && authorizationHeader.credentials) {
|
||||
const apiKey = Buffer.from(authorizationHeader.credentials, 'base64')
|
||||
.toString()
|
||||
.split(':');
|
||||
return {
|
||||
apiKeyId: apiKey[0],
|
||||
apiKey: apiKey[1],
|
||||
};
|
||||
}
|
||||
throw new Error('Authorization header is missing');
|
||||
};
|
|
@ -23,6 +23,7 @@ import {
|
|||
ObservabilityOnboardingPluginStartDependencies,
|
||||
} from './types';
|
||||
import { ObservabilityOnboardingConfig } from '.';
|
||||
import { observabilityOnboardingState } from './saved_objects/observability_onboarding_status';
|
||||
|
||||
export class ObservabilityOnboardingPlugin
|
||||
implements
|
||||
|
@ -47,6 +48,8 @@ export class ObservabilityOnboardingPlugin
|
|||
) {
|
||||
this.logger.debug('observability_onboarding: Setup');
|
||||
|
||||
core.savedObjects.registerType(observabilityOnboardingState);
|
||||
|
||||
const resourcePlugins = mapValues(plugins, (value, key) => {
|
||||
return {
|
||||
setup: value,
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 { ElasticsearchClient } from '@kbn/core/server';
|
||||
|
||||
export function createShipperApiKey(
|
||||
esClient: ElasticsearchClient,
|
||||
name: string
|
||||
) {
|
||||
// Based on https://www.elastic.co/guide/en/fleet/master/grant-access-to-elasticsearch.html#create-api-key-standalone-agent
|
||||
return esClient.security.createApiKey({
|
||||
body: {
|
||||
name: `standalone_agent_custom_logs_${name}`,
|
||||
metadata: { application: 'logs' },
|
||||
role_descriptors: {
|
||||
standalone_agent: {
|
||||
cluster: ['monitor'],
|
||||
indices: [
|
||||
{
|
||||
names: ['logs-*-*', 'metrics-*-*'],
|
||||
privileges: ['auto_configure', 'create_doc'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import {
|
||||
OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
ObservabilityOnboardingState,
|
||||
SavedObservabilityOnboardingState,
|
||||
} from '../../saved_objects/observability_onboarding_status';
|
||||
|
||||
export async function findLatestObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
}: {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
}): Promise<SavedObservabilityOnboardingState | undefined> {
|
||||
const result = await savedObjectsClient.find<ObservabilityOnboardingState>({
|
||||
type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
sortField: `updated_at`,
|
||||
sortOrder: 'desc',
|
||||
});
|
||||
if (result.total === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const { id, updated_at: updatedAt, attributes } = result.saved_objects[0];
|
||||
return {
|
||||
id,
|
||||
updatedAt: updatedAt ? Date.parse(updatedAt) : 0,
|
||||
...attributes,
|
||||
};
|
||||
}
|
|
@ -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 type { Client } from '@elastic/elasticsearch';
|
||||
import { CloudSetup } from '@kbn/cloud-plugin/server';
|
||||
import { decodeCloudId } from '@kbn/fleet-plugin/common';
|
||||
|
||||
const DEFAULT_ES_HOSTS = ['http://localhost:9200'];
|
||||
|
||||
export function getESHosts({
|
||||
cloudSetup,
|
||||
esClient,
|
||||
}: {
|
||||
cloudSetup: CloudSetup;
|
||||
esClient: Client;
|
||||
}): string[] {
|
||||
if (cloudSetup.cloudId) {
|
||||
const cloudUrl = decodeCloudId(cloudSetup.cloudId)?.elasticsearchUrl;
|
||||
if (cloudUrl) {
|
||||
return [cloudUrl];
|
||||
}
|
||||
}
|
||||
|
||||
const aliveConnections = esClient.connectionPool.connections.filter(
|
||||
({ status }) => status === 'alive'
|
||||
);
|
||||
if (aliveConnections.length) {
|
||||
return aliveConnections.map(({ url }) => {
|
||||
const { protocol, host } = new URL(url);
|
||||
return `${protocol}//${host}`;
|
||||
});
|
||||
}
|
||||
|
||||
return DEFAULT_ES_HOSTS;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 { CoreStart } from '@kbn/core/server';
|
||||
|
||||
export function getKibanaUrl({ http }: CoreStart, path = '') {
|
||||
const basePath = http.basePath;
|
||||
const { protocol, hostname, port } = http.getServerInfo();
|
||||
return `${protocol}://${hostname}:${port}${basePath.prepend(path)}`;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import {
|
||||
OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
ObservabilityOnboardingState,
|
||||
SavedObservabilityOnboardingState,
|
||||
} from '../../saved_objects/observability_onboarding_status';
|
||||
|
||||
export async function getObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
apiKeyId,
|
||||
}: {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
apiKeyId: string;
|
||||
}): Promise<SavedObservabilityOnboardingState | undefined> {
|
||||
try {
|
||||
const result = await savedObjectsClient.get<ObservabilityOnboardingState>(
|
||||
OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
apiKeyId
|
||||
);
|
||||
const { id, updated_at: updatedAt, attributes } = result;
|
||||
return {
|
||||
id,
|
||||
updatedAt: updatedAt ? Date.parse(updatedAt) : 0,
|
||||
...attributes,
|
||||
};
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* 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 * as t from 'io-ts';
|
||||
import Boom from '@hapi/boom';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route';
|
||||
import { getESHosts } from './get_es_hosts';
|
||||
import { getKibanaUrl } from './get_kibana_url';
|
||||
import { createShipperApiKey } from './create_shipper_api_key';
|
||||
import { saveObservabilityOnboardingState } from './save_observability_onboarding_state';
|
||||
import {
|
||||
ObservabilityOnboardingState,
|
||||
OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
SavedObservabilityOnboardingState,
|
||||
} from '../../saved_objects/observability_onboarding_status';
|
||||
import { getObservabilityOnboardingState } from './get_observability_onboarding_state';
|
||||
import { findLatestObservabilityOnboardingState } from './find_latest_observability_onboarding_state';
|
||||
import { getAuthenticationAPIKey } from '../../lib/get_authentication_api_key';
|
||||
|
||||
const createApiKeyRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint:
|
||||
'POST /internal/observability_onboarding/custom_logs/install_shipper_setup',
|
||||
options: { tags: [] },
|
||||
params: t.type({
|
||||
body: t.type({
|
||||
name: t.string,
|
||||
state: t.record(t.string, t.unknown),
|
||||
}),
|
||||
}),
|
||||
async handler(resources): Promise<{
|
||||
apiKeyId: string;
|
||||
apiKeyEncoded: string;
|
||||
apiEndpoint: string;
|
||||
scriptDownloadUrl: string;
|
||||
esHost: string;
|
||||
}> {
|
||||
const {
|
||||
context,
|
||||
params: {
|
||||
body: { name, state },
|
||||
},
|
||||
core,
|
||||
plugins,
|
||||
request,
|
||||
} = resources;
|
||||
const coreStart = await core.start();
|
||||
const scriptDownloadUrl = getKibanaUrl(
|
||||
coreStart,
|
||||
'/plugins/observabilityOnboarding/assets/standalone_agent_setup.sh'
|
||||
);
|
||||
const apiEndpoint = getKibanaUrl(
|
||||
coreStart,
|
||||
'/api/observability_onboarding/custom_logs'
|
||||
);
|
||||
const {
|
||||
elasticsearch: { client },
|
||||
} = await context.core;
|
||||
const { id: apiKeyId, encoded: apiKeyEncoded } = await createShipperApiKey(
|
||||
client.asCurrentUser,
|
||||
name
|
||||
);
|
||||
const [esHost] = getESHosts({
|
||||
cloudSetup: plugins.cloud.setup,
|
||||
esClient: coreStart.elasticsearch.client.asInternalUser as Client,
|
||||
});
|
||||
|
||||
const savedObjectsClient = coreStart.savedObjects.getScopedClient(request);
|
||||
|
||||
await saveObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
apiKeyId,
|
||||
observabilityOnboardingState: { state } as ObservabilityOnboardingState,
|
||||
});
|
||||
|
||||
return {
|
||||
apiKeyId, // key the status off this
|
||||
apiKeyEncoded,
|
||||
apiEndpoint,
|
||||
scriptDownloadUrl,
|
||||
esHost,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const stepProgressUpdateRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'GET /api/observability_onboarding/custom_logs/step/{name}',
|
||||
options: { tags: [] },
|
||||
params: t.type({
|
||||
path: t.type({
|
||||
name: t.string,
|
||||
}),
|
||||
query: t.type({
|
||||
status: t.string,
|
||||
}),
|
||||
}),
|
||||
async handler(resources): Promise<object> {
|
||||
const {
|
||||
params: {
|
||||
path: { name },
|
||||
query: { status },
|
||||
},
|
||||
request,
|
||||
core,
|
||||
} = resources;
|
||||
const { apiKeyId } = getAuthenticationAPIKey(request);
|
||||
const coreStart = await core.start();
|
||||
const savedObjectsClient =
|
||||
coreStart.savedObjects.createInternalRepository();
|
||||
|
||||
const savedObservabilityOnboardingState =
|
||||
await getObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
apiKeyId,
|
||||
});
|
||||
|
||||
if (!savedObservabilityOnboardingState) {
|
||||
return {
|
||||
message:
|
||||
'Unable to report setup progress - onboarding session not found.',
|
||||
};
|
||||
}
|
||||
|
||||
const { id, updatedAt, ...observabilityOnboardingState } =
|
||||
savedObservabilityOnboardingState;
|
||||
await saveObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
apiKeyId,
|
||||
observabilityOnboardingState: {
|
||||
...observabilityOnboardingState,
|
||||
progress: {
|
||||
...observabilityOnboardingState.progress,
|
||||
[name]: status,
|
||||
},
|
||||
},
|
||||
});
|
||||
return { name, status };
|
||||
},
|
||||
});
|
||||
|
||||
const getStateRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'GET /internal/observability_onboarding/custom_logs/state',
|
||||
options: { tags: [] },
|
||||
params: t.type({
|
||||
query: t.type({
|
||||
apiKeyId: t.string,
|
||||
}),
|
||||
}),
|
||||
async handler(resources): Promise<{
|
||||
savedObservabilityOnboardingState: SavedObservabilityOnboardingState | null;
|
||||
}> {
|
||||
const {
|
||||
params: {
|
||||
query: { apiKeyId },
|
||||
},
|
||||
core,
|
||||
} = resources;
|
||||
const coreStart = await core.start();
|
||||
const savedObjectsClient =
|
||||
coreStart.savedObjects.createInternalRepository();
|
||||
const savedObservabilityOnboardingState =
|
||||
(await getObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
apiKeyId,
|
||||
})) || null;
|
||||
return { savedObservabilityOnboardingState };
|
||||
},
|
||||
});
|
||||
|
||||
const getLatestStateRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'GET /internal/observability_onboarding/custom_logs/state/latest',
|
||||
options: { tags: [] },
|
||||
async handler(resources): Promise<{
|
||||
savedObservabilityOnboardingState: SavedObservabilityOnboardingState | null;
|
||||
}> {
|
||||
const { core } = resources;
|
||||
const coreStart = await core.start();
|
||||
const savedObjectsClient =
|
||||
coreStart.savedObjects.createInternalRepository();
|
||||
const savedObservabilityOnboardingState =
|
||||
(await findLatestObservabilityOnboardingState({ savedObjectsClient })) ||
|
||||
null;
|
||||
return { savedObservabilityOnboardingState };
|
||||
},
|
||||
});
|
||||
|
||||
const customLogsExistsRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'GET /internal/observability_onboarding/custom_logs/exists',
|
||||
options: { tags: [] },
|
||||
params: t.type({
|
||||
query: t.type({
|
||||
dataset: t.string,
|
||||
namespace: t.string,
|
||||
}),
|
||||
}),
|
||||
async handler(resources): Promise<{ exists: boolean }> {
|
||||
const {
|
||||
core,
|
||||
request,
|
||||
params: {
|
||||
query: { dataset, namespace },
|
||||
},
|
||||
} = resources;
|
||||
const coreStart = await core.start();
|
||||
const esClient =
|
||||
coreStart.elasticsearch.client.asScoped(request).asCurrentUser;
|
||||
try {
|
||||
const { hits } = await esClient.search({
|
||||
index: `logs-${dataset}-${namespace}`,
|
||||
terminate_after: 1,
|
||||
});
|
||||
const total = hits.total as { value: number };
|
||||
return { exists: total.value > 0 };
|
||||
} catch (error) {
|
||||
if (error.statusCode === 404) {
|
||||
return { exists: false };
|
||||
}
|
||||
throw Boom.boomify(error, {
|
||||
statusCode: error.statusCode,
|
||||
message: error.message,
|
||||
data: error.body,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const deleteStatesRoute = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'DELETE /internal/observability_onboarding/custom_logs/states',
|
||||
options: { tags: [] },
|
||||
async handler(resources): Promise<object> {
|
||||
const { core } = resources;
|
||||
const coreStart = await core.start();
|
||||
const savedObjectsClient =
|
||||
coreStart.savedObjects.createInternalRepository();
|
||||
const findStatesResult =
|
||||
await savedObjectsClient.find<ObservabilityOnboardingState>({
|
||||
type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
});
|
||||
const bulkDeleteResult = await savedObjectsClient.bulkDelete(
|
||||
findStatesResult.saved_objects
|
||||
);
|
||||
return { bulkDeleteResult };
|
||||
},
|
||||
});
|
||||
|
||||
export const customLogsRouteRepository = {
|
||||
...createApiKeyRoute,
|
||||
...stepProgressUpdateRoute,
|
||||
...getStateRoute,
|
||||
...getLatestStateRoute,
|
||||
...customLogsExistsRoute,
|
||||
...deleteStatesRoute,
|
||||
};
|
|
@ -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 { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import {
|
||||
OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
ObservabilityOnboardingState,
|
||||
SavedObservabilityOnboardingState,
|
||||
} from '../../saved_objects/observability_onboarding_status';
|
||||
|
||||
interface Options {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
observabilityOnboardingState: ObservabilityOnboardingState;
|
||||
apiKeyId: string;
|
||||
}
|
||||
export async function saveObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
observabilityOnboardingState,
|
||||
apiKeyId,
|
||||
}: Options): Promise<SavedObservabilityOnboardingState> {
|
||||
const {
|
||||
id,
|
||||
attributes,
|
||||
updated_at: updatedAt,
|
||||
} = await savedObjectsClient.update<ObservabilityOnboardingState>(
|
||||
OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
apiKeyId,
|
||||
observabilityOnboardingState,
|
||||
{ upsert: observabilityOnboardingState }
|
||||
);
|
||||
return {
|
||||
id,
|
||||
...(attributes as ObservabilityOnboardingState),
|
||||
updatedAt: updatedAt ? Date.parse(updatedAt) : 0,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { dump, load } from 'js-yaml';
|
||||
|
||||
export const generateYml = ({
|
||||
datasetName = '',
|
||||
namespace = '',
|
||||
customConfigurations,
|
||||
logFilePaths = [],
|
||||
apiKey,
|
||||
esHost,
|
||||
logfileId,
|
||||
}: {
|
||||
datasetName?: string;
|
||||
namespace?: string;
|
||||
customConfigurations?: string;
|
||||
logFilePaths?: string[];
|
||||
apiKey: string;
|
||||
esHost: string[];
|
||||
logfileId: string;
|
||||
}) => {
|
||||
const customConfigYaml = load(customConfigurations ?? '');
|
||||
|
||||
return dump({
|
||||
...{
|
||||
outputs: {
|
||||
default: {
|
||||
type: 'elasticsearch',
|
||||
hosts: esHost,
|
||||
api_key: apiKey,
|
||||
},
|
||||
},
|
||||
inputs: [
|
||||
{
|
||||
id: logfileId,
|
||||
type: 'logfile',
|
||||
data_stream: {
|
||||
namespace,
|
||||
},
|
||||
streams: [
|
||||
{
|
||||
id: `logs-onboarding-${datasetName}`,
|
||||
data_stream: {
|
||||
dataset: datasetName,
|
||||
},
|
||||
paths: logFilePaths,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
...customConfigYaml,
|
||||
});
|
||||
};
|
|
@ -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 type { Client } from '@elastic/elasticsearch';
|
||||
import { getAuthenticationAPIKey } from '../../lib/get_authentication_api_key';
|
||||
import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route';
|
||||
import { findLatestObservabilityOnboardingState } from '../custom_logs/find_latest_observability_onboarding_state';
|
||||
import { getESHosts } from '../custom_logs/get_es_hosts';
|
||||
import { generateYml } from './generate_yml';
|
||||
|
||||
const generateConfig = createObservabilityOnboardingServerRoute({
|
||||
endpoint: 'GET /api/observability_onboarding/elastic_agent/config',
|
||||
options: { tags: [] },
|
||||
async handler(resources): Promise<string> {
|
||||
const { core, plugins, request } = resources;
|
||||
const { apiKeyId, apiKey } = getAuthenticationAPIKey(request);
|
||||
|
||||
const coreStart = await core.start();
|
||||
const savedObjectsClient =
|
||||
coreStart.savedObjects.createInternalRepository();
|
||||
|
||||
const esHost = getESHosts({
|
||||
cloudSetup: plugins.cloud.setup,
|
||||
esClient: coreStart.elasticsearch.client.asInternalUser as Client,
|
||||
});
|
||||
|
||||
const savedState = await findLatestObservabilityOnboardingState({
|
||||
savedObjectsClient,
|
||||
});
|
||||
|
||||
const yaml = generateYml({
|
||||
datasetName: savedState?.state.datasetName,
|
||||
customConfigurations: savedState?.state.customConfigurations,
|
||||
logFilePaths: savedState?.state.logFilePaths,
|
||||
namespace: savedState?.state.namespace,
|
||||
apiKey: `${apiKeyId}:${apiKey}`,
|
||||
esHost,
|
||||
logfileId: `custom-logs-${Date.now()}`,
|
||||
});
|
||||
|
||||
return yaml;
|
||||
},
|
||||
});
|
||||
|
||||
export const elasticAgentRouteRepository = {
|
||||
...generateConfig,
|
||||
};
|
|
@ -9,10 +9,14 @@ import type {
|
|||
ServerRouteRepository,
|
||||
} from '@kbn/server-route-repository';
|
||||
import { statusRouteRepository } from './status/route';
|
||||
import { customLogsRouteRepository } from './custom_logs/route';
|
||||
import { elasticAgentRouteRepository } from './elastic_agent/route';
|
||||
|
||||
function getTypedObservabilityOnboardingServerRouteRepository() {
|
||||
const repository = {
|
||||
...statusRouteRepository,
|
||||
...customLogsRouteRepository,
|
||||
...elasticAgentRouteRepository,
|
||||
};
|
||||
|
||||
return repository;
|
||||
|
|
|
@ -66,6 +66,13 @@ export function registerRoutes({
|
|||
logger,
|
||||
params: decodedParams,
|
||||
plugins,
|
||||
core: {
|
||||
setup: core,
|
||||
start: async () => {
|
||||
const [coreStart] = await core.getStartServices();
|
||||
return coreStart;
|
||||
},
|
||||
},
|
||||
})) as any;
|
||||
|
||||
if (data === undefined) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { KibanaRequest, Logger } from '@kbn/core/server';
|
||||
import { CoreSetup, CoreStart, KibanaRequest, Logger } from '@kbn/core/server';
|
||||
import { ObservabilityOnboardingServerRouteRepository } from '.';
|
||||
import {
|
||||
ObservabilityOnboardingPluginSetupDependencies,
|
||||
|
@ -26,6 +26,10 @@ export interface ObservabilityOnboardingRouteHandlerResources {
|
|||
>;
|
||||
};
|
||||
};
|
||||
core: {
|
||||
setup: CoreSetup;
|
||||
start: () => Promise<CoreStart>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ObservabilityOnboardingRouteCreateOptions {
|
||||
|
|
|
@ -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 { SavedObjectsType } from '@kbn/core/server';
|
||||
|
||||
export const OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE =
|
||||
'observability-onboarding-state';
|
||||
|
||||
export interface ObservabilityOnboardingState {
|
||||
state: {
|
||||
datasetName: string;
|
||||
customConfigurations: string;
|
||||
logFilePaths: string[];
|
||||
namespace: string;
|
||||
};
|
||||
progress: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface SavedObservabilityOnboardingState
|
||||
extends ObservabilityOnboardingState {
|
||||
id: string;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export const observabilityOnboardingState: SavedObjectsType = {
|
||||
name: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE,
|
||||
hidden: false,
|
||||
namespaceType: 'multiple',
|
||||
mappings: {
|
||||
properties: {
|
||||
state: { type: 'object', dynamic: false },
|
||||
progress: { type: 'object', dynamic: false },
|
||||
},
|
||||
},
|
||||
};
|
|
@ -5,21 +5,27 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server';
|
||||
import { CustomRequestHandlerContext } from '@kbn/core/server';
|
||||
import {
|
||||
PluginSetup as DataPluginSetup,
|
||||
PluginStart as DataPluginStart,
|
||||
} from '@kbn/data-plugin/server';
|
||||
import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
|
||||
export interface ObservabilityOnboardingPluginSetupDependencies {
|
||||
data: DataPluginSetup;
|
||||
observability: ObservabilityPluginSetup;
|
||||
cloud: CloudSetup;
|
||||
usageCollection: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
export interface ObservabilityOnboardingPluginStartDependencies {
|
||||
data: DataPluginStart;
|
||||
observability: undefined;
|
||||
cloud: CloudStart;
|
||||
usageCollection: undefined;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
|
|
|
@ -23,7 +23,12 @@
|
|||
"@kbn/config-schema",
|
||||
"@kbn/shared-ux-router",
|
||||
"@kbn/i18n-react",
|
||||
"@kbn/cloud-plugin",
|
||||
"@kbn/fleet-plugin",
|
||||
"@kbn/usage-collection-plugin",
|
||||
"@kbn/observability-shared-plugin",
|
||||
"@kbn/core-http-server",
|
||||
"@kbn/security-plugin",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue