+ {i18n.translate(
+ 'xpack.observability_onboarding.autoDetectPanel.p.thereWasAProblemLabel',
+ {
+ defaultMessage:
+ 'There was a problem loading the application. Retry or contact your administrator for help.',
+ }
+ )}
+
+ }
+ actions={
+
+ {i18n.translate(
+ 'xpack.observability_onboarding.autoDetectPanel.backToSelectionButtonLabel',
+ { defaultMessage: 'Retry' }
+ )}
+
+ }
+ />
+ );
+};
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/locator_button_empty.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/locator_button_empty.tsx
new file mode 100644
index 0000000000000..73fe406c46e6e
--- /dev/null
+++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/locator_button_empty.tsx
@@ -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
+>;
+
+export interface LocatorButtonEmptyProps
+ extends Omit {
+ locator: string | LocatorPublic;
+ 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
+ *
+ * View dashboard
+ *
+ * ```
+ *
+ * Example 2:
+ *
+ * ```ts
+ * import { type SingleDatasetLocatorParams, SINGLE_DATASET_LOCATOR_ID } from '@kbn/deeplinks-observability/locators';
+ *
+ *
+ * locator={SINGLE_DATASET_LOCATOR_ID}
+ * params={{
+ * integration: 'system',
+ * dataset: 'system.syslog',
+ * }}
+ * >
+ * View in Logs Explorer
+ *
+ * ```
+ */
+export const LocatorButtonEmpty = ({
+ locator,
+ params,
+ ...rest
+}: LocatorButtonEmptyProps) => {
+ const {
+ services: { share },
+ } = useKibana();
+
+ const locatorObj =
+ typeof locator === 'string' ? share.url.locators.get(locator) : locator;
+
+ return (
+
+ );
+};
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/progress_indicator.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/progress_indicator.tsx
new file mode 100644
index 0000000000000..337ab8172e971
--- /dev/null
+++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/progress_indicator.tsx
@@ -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 = ({
+ iconType,
+ isLoading = true,
+ title,
+ color = isLoading ? 'primary' : 'success',
+ ...rest
+}) => {
+ return (
+
+ {isLoading ? (
+
+
+
+ ) : iconType ? (
+
+
+
+ ) : null}
+ {title}
+
+ }
+ color={color}
+ {...rest}
+ />
+ );
+};
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh
index 718107050335f..e946fb6653542 100755
--- a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh
+++ b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh
@@ -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=""
+
+ 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")
- update_step_progress "ea-config" "loading"
+ 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."
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/charts_screen.svg b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/charts_screen.svg
new file mode 100644
index 0000000000000..925d71c174061
--- /dev/null
+++ b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/charts_screen.svg
@@ -0,0 +1,128 @@
+
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/waterfall_screen.svg b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/waterfall_screen.svg
new file mode 100644
index 0000000000000..7501d44620a94
--- /dev/null
+++ b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/waterfall_screen.svg
@@ -0,0 +1,116 @@
+
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts
index 8afe3b29c30e0..be73b77bd336e 100644
--- a/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts
+++ b/x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts
@@ -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
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/lib/get_agent_version.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/get_agent_version.ts
new file mode 100644
index 0000000000000..c9dd959e6bb75
--- /dev/null
+++ b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/get_agent_version.ts
@@ -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);
+}
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/lib/get_fallback_urls.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/get_fallback_urls.ts
index fc79d7e37cebb..15185521563a1 100644
--- a/x-pack/plugins/observability_solution/observability_onboarding/server/lib/get_fallback_urls.ts
+++ b/x-pack/plugins/observability_solution/observability_onboarding/server/lib/get_fallback_urls.ts
@@ -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
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/get_has_logs.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/get_has_logs.ts
index bedd1de0a80da..7816843bca3dc 100644
--- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/get_has_logs.ts
+++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/get_has_logs.ts
@@ -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;
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 b43edf76ce0a5..c58a5ef257fbb 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
@@ -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;
- }> {
+ async handler(resources): Promise> {
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 {
+ 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>((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>(
+ (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,
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/routes/logs/api_key/create_install_api_key.ts
new file mode 100644
index 0000000000000..d97dd6ac6580c
--- /dev/null
+++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/logs/api_key/create_install_api_key.ts
@@ -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],
+ },
+ ],
+ },
+ },
+ };
+}
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/routes/logs/api_key/create_shipper_api_key.ts
index 80814aa308abc..70a3bf344fee6 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/routes/logs/api_key/create_shipper_api_key.ts
@@ -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,
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 b46b1508ed21b..4f7c1360dc082 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
@@ -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();
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts
index e9ab6b14dab54..de2e7ce65fd2d 100644
--- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts
+++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts
@@ -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;
+export type InstalledIntegration = t.TypeOf;
export const ElasticAgentStepPayloadRT = t.type({
agentId: t.string,
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 297f7f33a9d64..a7ef942d7ea0a 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,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(),
+ })
+ ),
})
);
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/types.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/types.ts
index 1c3cbbf26937c..8eee0943d3590 100644
--- a/x-pack/plugins/observability_solution/observability_onboarding/server/types.ts
+++ b/x-pack/plugins/observability_solution/observability_onboarding/server/types.ts
@@ -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
diff --git a/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json b/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json
index 947a1230afd16..5833bba22a6e4 100644
--- a/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json
+++ b/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json
@@ -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/**/*"
+ ]
}