diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx index 33e472d841bbc..dd22b1735fc9f 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx @@ -19,6 +19,7 @@ import { SystemLogsPanel } from './quickstart_flows/system_logs'; import { CustomLogsPanel } from './quickstart_flows/custom_logs'; import { OtelLogsPanel } from './quickstart_flows/otel_logs'; import { AutoDetectPanel } from './quickstart_flows/auto_detect'; +import { KubernetesPanel } from './quickstart_flows/kubernetes'; import { BackButton } from './shared/back_button'; const queryClient = new QueryClient(); @@ -66,6 +67,10 @@ export function ObservabilityOnboardingFlow() { + + + + diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts index 5bc63403365cc..03d7d0278f374 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts @@ -34,6 +34,7 @@ export function useCustomCardsForCategory( const { href: systemLogsUrl } = reactRouterNavigate(history, `/systemLogs/${location.search}`); const { href: customLogsUrl } = reactRouterNavigate(history, `/customLogs/${location.search}`); const { href: otelLogsUrl } = reactRouterNavigate(history, `/otel-logs/${location.search}`); + const { href: kubernetesUrl } = reactRouterNavigate(history, `/kubernetes/${location.search}`); const otelCard: VirtualCard = { id: 'otel-logs', @@ -112,7 +113,23 @@ export function useCustomCardsForCategory( ]; case 'infra': return [ - toFeaturedCard('kubernetes'), + { + id: 'kubernetes-quick-start', + type: 'virtual', + title: 'Kubernetes', + description: 'Collect logs and metrics from Kubernetes using minimal configuration', + name: 'kubernetes-quick-start', + categories: ['observability'], + icons: [ + { + type: 'svg', + src: http?.staticAssets.getPluginAssetHref('kubernetes.svg') ?? '', + }, + ], + url: kubernetesUrl, + version: '', + integration: '', + }, toFeaturedCard('docker'), isServerless ? toFeaturedCard('prometheus') : otelCard, { diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts index 52e9a0f09c807..e0e468b0d80db 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts @@ -7,7 +7,7 @@ import { IntegrationCardItem } from '@kbn/fleet-plugin/public'; -export const QUICKSTART_FLOWS = ['system-logs-virtual']; +export const QUICKSTART_FLOWS = ['system-logs-virtual', 'kubernetes-quick-start']; export const toCustomCard = (card: IntegrationCardItem) => ({ ...card, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/build_kubectl_command.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/build_kubectl_command.ts new file mode 100644 index 0000000000000..59de30111649d --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/build_kubectl_command.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ + +interface Params { + encodedApiKey: string; + onboardingId: string; + elasticsearchUrl: string; + elasticAgentVersion: string; +} + +const KUSTOMIZE_TEMPLATE_URL = + 'https://github.com/elastic/elastic-agent/deploy/kubernetes/elastic-agent-kustomize/default/elastic-agent-standalone'; + +export function buildKubectlCommand({ + encodedApiKey, + onboardingId, + elasticsearchUrl, + elasticAgentVersion, +}: Params) { + const escapedElasticsearchUrl = elasticsearchUrl.replace(/\//g, '\\/'); + + return ` + kubectl kustomize ${KUSTOMIZE_TEMPLATE_URL}\\?ref\\=v${elasticAgentVersion} + | sed -e 's/JUFQSV9LRVkl/${encodedApiKey}/g' + -e "s/%ES_HOST%/${escapedElasticsearchUrl}/g" + -e "s/%ONBOARDING_ID%/${onboardingId}/g" + -e "s/\\(docker.elastic.co\\/beats\\/elastic-agent\:\\).*$/\\1${elasticAgentVersion}/g" + -e "/{CA_TRUSTED}/c\\ " + | kubectl apply -f- + ` + .trim() + .replace(/\n/g, ' ') + .replace(/\s\s+/g, ' '); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/command_snippet.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/command_snippet.tsx new file mode 100644 index 0000000000000..be7857676427c --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/command_snippet.tsx @@ -0,0 +1,72 @@ +/* + * 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 from 'react'; +import { EuiCodeBlock, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { buildKubectlCommand } from './build_kubectl_command'; +import { CopyToClipboardButton } from '../shared/copy_to_clipboard_button'; + +interface Props { + encodedApiKey: string; + onboardingId: string; + elasticsearchUrl: string; + elasticAgentVersion: string; +} + +export function CommandSnippet({ + encodedApiKey, + onboardingId, + elasticsearchUrl, + elasticAgentVersion, +}: Props) { + const command = buildKubectlCommand({ + encodedApiKey, + onboardingId, + elasticsearchUrl, + elasticAgentVersion, + }); + + return ( + <> + +

+ + {i18n.translate( + 'xpack.observability_onboarding.kubernetesPanel.scalingElasticAgentOnLinkLabel', + { defaultMessage: 'Scaling Elastic Agent on Kubernetes' } + )} + + ), + }} + /> +

+
+ + + + + {command} + + + + + + + ); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx new file mode 100644 index 0000000000000..3e91c20752bd4 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx @@ -0,0 +1,182 @@ +/* + * 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, { useEffect, useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + StepsProgress, + useFlowProgressTelemetry, +} from '../../../hooks/use_flow_progress_telemetry'; +import { ObservabilityOnboardingContextValue } from '../../../plugin'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; +import { ProgressIndicator } from '../shared/progress_indicator'; + +interface Props { + onboardingId: string; +} + +const FETCH_INTERVAL = 2000; +const SHOW_TROUBLESHOOTING_DELAY = 120000; // 2 minutes +const CLUSTER_OVERVIEW_DASHBOARD_ID = 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c'; + +export function DataIngestStatus({ onboardingId }: Props) { + const { + services: { share, http }, + } = useKibana(); + const [progress, setProgress] = useState(undefined); + const [checkDataStartTime] = useState(Date.now()); + + const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); + + const { data, status, refetch } = useFetcher( + (callApi) => { + return callApi('GET /internal/observability_onboarding/kubernetes/{onboardingId}/has-data', { + params: { path: { onboardingId } }, + }); + }, + [onboardingId] + ); + + useEffect(() => { + const pendingStatusList = [FETCH_STATUS.LOADING, FETCH_STATUS.NOT_INITIATED]; + + if (pendingStatusList.includes(status) || data?.hasData === true) { + return; + } + + const timeout = setTimeout(() => { + refetch(); + }, FETCH_INTERVAL); + + return () => clearTimeout(timeout); + }, [data?.hasData, refetch, status]); + + useEffect(() => { + if (data?.hasData === true) { + setProgress({ 'logs-ingest': { status: 'complete' } }); + } + }, [data?.hasData]); + + useFlowProgressTelemetry(progress, onboardingId); + + const isTroubleshootingVisible = + data?.hasData === false && Date.now() - checkDataStartTime > SHOW_TROUBLESHOOTING_DELAY; + + return ( + <> + + + {isTroubleshootingVisible && ( + <> + + + + {i18n.translate( + 'xpack.observability_onboarding.dataIngestStatus.troubleshootingLinkText', + { + defaultMessage: 'Open documentation', + } + )} + + ), + }} + /> + + + )} + + {data?.hasData === true && ( + <> + + + + + + + + + +

+ {i18n.translate( + 'xpack.observability_onboarding.kubernetesPanel.monitoringCluster', + { + defaultMessage: + 'Overview your Kubernetes cluster with this pre-made dashboard', + } + )} +

+
+ + + {i18n.translate('xpack.observability_onboarding.kubernetesPanel.exploreDashboard', { + defaultMessage: 'Explore Kubernetes cluster', + })} + +
+
+ + + + + + {i18n.translate( + 'xpack.observability_onboarding.dataIngestStatus.viewAllAssetsLinkText', + { + defaultMessage: 'View all assets', + } + )} + + ), + }} + /> + + + )} + + ); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/index.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/index.tsx new file mode 100644 index 0000000000000..58de3a72ca92f --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/index.tsx @@ -0,0 +1,73 @@ +/* + * 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, { useState } from 'react'; +import { + EuiPanel, + EuiSkeletonRectangle, + EuiSkeletonText, + EuiSpacer, + EuiSteps, + EuiStepStatus, +} from '@elastic/eui'; +import useEvent from 'react-use/lib/useEvent'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; +import { EmptyPrompt } from '../shared/empty_prompt'; +import { CommandSnippet } from './command_snippet'; +import { DataIngestStatus } from './data_ingest_status'; + +export const KubernetesPanel: React.FC = () => { + const [windowLostFocus, setWindowLostFocus] = useState(false); + const { data, status, error, refetch } = useFetcher((callApi) => { + return callApi('POST /internal/observability_onboarding/kubernetes/flow'); + }, []); + + useEvent('blur', () => setWindowLostFocus(true), window); + + if (error !== undefined) { + return ; + } + + const isMonitoringStepActive = + status === FETCH_STATUS.SUCCESS && data !== undefined && windowLostFocus; + + const steps = [ + { + title: 'Install Elastic Agent on your host', + children: ( + <> + {status !== FETCH_STATUS.SUCCESS && ( + <> + + + + + )} + {status === FETCH_STATUS.SUCCESS && data !== undefined && ( + + )} + + ), + }, + { + title: 'Monitor your Kubernetes cluster', + status: (isMonitoringStepActive ? 'current' : 'incomplete') as EuiStepStatus, + children: isMonitoringStepActive && , + }, + ]; + + return ( + + + + ); +}; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/kubernetes.svg b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/kubernetes.svg new file mode 100644 index 0000000000000..7f3e86f5482b9 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/kubernetes.svg @@ -0,0 +1 @@ + diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/hooks/use_flow_progress_telemetry.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/hooks/use_flow_progress_telemetry.ts index 95d93ad6af985..a580055f8e3c7 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/hooks/use_flow_progress_telemetry.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/hooks/use_flow_progress_telemetry.ts @@ -11,9 +11,9 @@ import { type LogsFlowProgressStepId } from '../../common/logs_flow_progress_ste import { OBSERVABILITY_ONBOARDING_TELEMETRY_EVENT } from '../../common/telemetry_events'; import { useKibana } from './use_kibana'; -type EuiStepStatus = EuiStepsProps['steps'][number]['status']; +export type EuiStepStatus = EuiStepsProps['steps'][number]['status']; -type StepsProgress = Partial< +export type StepsProgress = Partial< Record >; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/create_install_api_key.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/create_install_api_key.ts similarity index 96% rename from x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/create_install_api_key.ts rename to x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/create_install_api_key.ts index d97dd6ac6580c..eddc5e10b5c65 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/create_install_api_key.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/create_install_api_key.ts @@ -13,7 +13,7 @@ import type { CreateAPIKeyParams } from '@kbn/security-plugin/server'; */ export function createInstallApiKey(name: string): CreateAPIKeyParams { return { - name: `onboarding_install_${name}`, + name, expiration: '1h', // This API key is only used for initial setup and should be short lived metadata: { managed: true, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/create_shipper_api_key.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/create_shipper_api_key.ts similarity index 93% rename from x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/create_shipper_api_key.ts rename to x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/create_shipper_api_key.ts index 70a3bf344fee6..942ebdbbd07cd 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/create_shipper_api_key.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/create_shipper_api_key.ts @@ -12,7 +12,7 @@ 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_logs_onboarding_${name}`, + name, metadata: { managed: true, application: 'logs', diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/has_log_monitoring_privileges.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/has_log_monitoring_privileges.ts similarity index 100% rename from x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/has_log_monitoring_privileges.ts rename to x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/has_log_monitoring_privileges.ts diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/monitoring_config.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/monitoring_config.ts similarity index 100% rename from x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/monitoring_config.ts rename to x-pack/plugins/observability_solution/observability_onboarding/server/lib/api_key/monitoring_config.ts diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts index c58a5ef257fbb..80f0159f66594 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts @@ -20,12 +20,12 @@ import { ObservabilityOnboardingFlow } from '../../saved_objects/observability_o 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, InstalledIntegration, StepProgressPayloadRT } from '../types'; +import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key'; +import { createInstallApiKey } from '../../lib/api_key/create_install_api_key'; +import { hasLogMonitoringPrivileges } from '../../lib/api_key/has_log_monitoring_privileges'; const updateOnboardingFlowRoute = createObservabilityOnboardingServerRoute({ endpoint: 'PUT /internal/observability_onboarding/flow/{onboardingId}', @@ -229,8 +229,11 @@ const createFlowRoute = createObservabilityOnboardingServerRoute({ progress: {}, }, }), - createShipperApiKey(client.asCurrentUser, name), - securityPluginStart.authc.apiKeys.create(request, createInstallApiKey(name)), + createShipperApiKey(client.asCurrentUser, `onboarding_ingest_${name}`), + securityPluginStart.authc.apiKeys.create( + request, + createInstallApiKey(`onboarding_install_${name}`) + ), getAgentVersion(fleetPluginStart, kibanaVersion), ]); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts index 2f9ce174cf040..e444f2266f18f 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/index.ts @@ -7,6 +7,7 @@ import type { EndpointOf, ServerRouteRepository } from '@kbn/server-route-repository'; import { elasticAgentRouteRepository } from './elastic_agent/route'; import { flowRouteRepository } from './flow/route'; +import { kubernetesOnboardingRouteRepository } from './kubernetes/route'; import { logsOnboardingRouteRepository } from './logs/route'; function getTypedObservabilityOnboardingServerRouteRepository() { @@ -14,6 +15,7 @@ function getTypedObservabilityOnboardingServerRouteRepository() { ...flowRouteRepository, ...logsOnboardingRouteRepository, ...elasticAgentRouteRepository, + ...kubernetesOnboardingRouteRepository, }; return repository; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/kubernetes/route.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/kubernetes/route.ts new file mode 100644 index 0000000000000..efbea4a0bcd4e --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/kubernetes/route.ts @@ -0,0 +1,112 @@ +/* + * 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 { v4 as uuidv4 } from 'uuid'; +import * as t from 'io-ts'; +import Boom from '@hapi/boom'; +import { termQuery } from '@kbn/observability-plugin/server'; +import type { estypes } from '@elastic/elasticsearch'; +import { getFallbackESUrl } from '../../lib/get_fallback_urls'; +import { createObservabilityOnboardingServerRoute } from '../create_observability_onboarding_server_route'; +import { hasLogMonitoringPrivileges } from '../../lib/api_key/has_log_monitoring_privileges'; +import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key'; +import { getAgentVersion } from '../../lib/get_agent_version'; + +export interface CreateKubernetesOnboardingFlowRouteResponse { + apiKeyEncoded: string; + onboardingId: string; + elasticsearchUrl: string; + elasticAgentVersion: string; +} + +export interface HasKubernetesDataRouteResponse { + hasData: boolean; +} + +const createKubernetesOnboardingFlowRoute = createObservabilityOnboardingServerRoute({ + endpoint: 'POST /internal/observability_onboarding/kubernetes/flow', + options: { tags: [] }, + async handler({ + context, + request, + plugins, + services, + kibanaVersion, + }): Promise { + const { + elasticsearch: { client }, + } = await context.core; + + const hasPrivileges = await hasLogMonitoringPrivileges(client.asCurrentUser); + + if (!hasPrivileges) { + throw Boom.forbidden( + "You don't have enough privileges to start a new onboarding flow. Contact your system administrator to grant you the required privileges." + ); + } + + const fleetPluginStart = await plugins.fleet.start(); + const packageClient = fleetPluginStart.packageService.asScoped(request); + + await packageClient.ensureInstalledPackage({ pkgName: 'kubernetes' }); + + const [{ encoded: apiKeyEncoded }, elasticAgentVersion] = await Promise.all([ + createShipperApiKey(client.asCurrentUser, 'kubernetes_onboarding'), + getAgentVersion(fleetPluginStart, kibanaVersion), + ]); + const elasticsearchUrlList = plugins.cloud?.setup?.elasticsearchUrl + ? [plugins.cloud?.setup?.elasticsearchUrl] + : await getFallbackESUrl(services.esLegacyConfigService); + + return { + onboardingId: uuidv4(), + apiKeyEncoded, + elasticsearchUrl: elasticsearchUrlList.length > 0 ? elasticsearchUrlList[0] : '', + elasticAgentVersion, + }; + }, +}); + +const hasKubernetesDataRoute = createObservabilityOnboardingServerRoute({ + endpoint: 'GET /internal/observability_onboarding/kubernetes/{onboardingId}/has-data', + params: t.type({ + path: t.type({ + onboardingId: t.string, + }), + }), + options: { tags: [] }, + async handler(resources): Promise { + const { onboardingId } = resources.params.path; + const { elasticsearch } = await resources.context.core; + + try { + const result = await elasticsearch.client.asCurrentUser.search({ + index: ['logs-*', 'metrics-*'], + ignore_unavailable: true, + size: 0, + terminate_after: 1, + query: { + bool: { + filter: termQuery('fields.onboarding_id', onboardingId), + }, + }, + }); + const { value } = result.hits.total as estypes.SearchTotalHits; + + return { + hasData: value > 0, + }; + } catch (error) { + throw Boom.internal(`Elasticsearch responses with an error. ${error.message}`); + } + }, +}); + +export const kubernetesOnboardingRouteRepository = { + ...createKubernetesOnboardingFlowRoute, + ...hasKubernetesDataRoute, +}; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts index 524037c1c4222..6d17617e1a94e 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/route.ts @@ -10,10 +10,10 @@ import { createObservabilityOnboardingServerRoute } from '../create_observabilit import { getFallbackESUrl } 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'; +import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key'; import { ObservabilityOnboardingFlow } from '../../saved_objects/observability_onboarding_status'; +import { hasLogMonitoringPrivileges } from '../../lib/api_key/has_log_monitoring_privileges'; const logMonitoringPrivilegesRoute = createObservabilityOnboardingServerRoute({ endpoint: 'GET /internal/observability_onboarding/logs/setup/privileges', @@ -115,7 +115,10 @@ const createFlowRoute = createObservabilityOnboardingServerRoute({ const { elasticsearch: { client }, } = await context.core; - const { encoded: apiKeyEncoded } = await createShipperApiKey(client.asCurrentUser, name); + const { encoded: apiKeyEncoded } = await createShipperApiKey( + client.asCurrentUser, + `standalone_agent_logs_onboarding_${name}` + ); const generatedState = type === 'systemLogs' ? { namespace: 'default' } : state; const savedObjectsClient = coreStart.savedObjects.getScopedClient(request); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts index a7ef942d7ea0a..bf996b96e1958 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/saved_objects/observability_onboarding_status.ts @@ -23,10 +23,10 @@ export interface SystemLogsState { namespace: string; } -export type ObservabilityOnboardingType = 'logFiles' | 'systemLogs' | 'autoDetect'; - type ObservabilityOnboardingFlowState = LogFilesState | SystemLogsState | undefined; +type ObservabilityOnboardingType = 'logFiles' | 'systemLogs' | 'autoDetect' | 'kubernetes'; + export interface ObservabilityOnboardingFlow { type: ObservabilityOnboardingType; state: ObservabilityOnboardingFlowState; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/authentication.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/authentication.ts index 95da640fa40ae..340f0cb615651 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/authentication.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/test_helpers/create_observability_onboarding_users/authentication.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { cluster, indices } from '../../routes/logs/api_key/monitoring_config'; +import { cluster, indices } from '../../lib/api_key/monitoring_config'; export enum ObservabilityOnboardingUsername { noAccessUser = 'no_access_user',