From 5e972e14d147e3c5232114690f61a96a493a28ae Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Mon, 4 May 2020 13:00:56 -0400 Subject: [PATCH] [Fleet] Better display of fleet requirements (#65027) --- .../ingest_manager/common/types/index.ts | 1 + .../common/types/rest_spec/fleet_setup.ts | 5 + x-pack/plugins/ingest_manager/kibana.json | 2 +- .../ingest_manager/hooks/use_fleet_status.tsx | 69 ++++++++++++ .../ingest_manager/hooks/use_request/index.ts | 1 + .../ingest_manager/hooks/use_request/setup.ts | 10 +- .../applications/ingest_manager/index.tsx | 5 +- .../agent_enrollment_flyout/index.tsx | 58 +++++++--- .../ingest_manager/sections/fleet/index.tsx | 18 ++- .../sections/fleet/setup_page/index.tsx | 103 ++++++++++++------ .../ingest_manager/types/index.ts | 2 + x-pack/plugins/ingest_manager/server/index.ts | 1 + .../plugins/ingest_manager/server/plugin.ts | 17 ++- .../server/routes/setup/handlers.ts | 47 +++++--- .../server/routes/setup/index.ts | 5 +- .../server/services/agent_config.ts | 10 +- .../server/services/app_context.ts | 27 ++++- .../server/services/datasource.ts | 3 + .../ingest_manager/server/services/output.ts | 5 +- .../ingest_manager/server/services/setup.ts | 7 +- .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 22 files changed, 309 insertions(+), 91 deletions(-) create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_fleet_status.tsx diff --git a/x-pack/plugins/ingest_manager/common/types/index.ts b/x-pack/plugins/ingest_manager/common/types/index.ts index 748bb14d2d35d..b357d0c2d75f4 100644 --- a/x-pack/plugins/ingest_manager/common/types/index.ts +++ b/x-pack/plugins/ingest_manager/common/types/index.ts @@ -14,6 +14,7 @@ export interface IngestManagerConfigType { }; fleet: { enabled: boolean; + tlsCheckDisabled: boolean; defaultOutputHost: string; kibana: { host?: string; diff --git a/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts b/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts index c4ba8ee595acf..ae4cb4e3fce49 100644 --- a/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts +++ b/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts @@ -7,3 +7,8 @@ export interface CreateFleetSetupResponse { isInitialized: boolean; } + +export interface GetFleetStatusResponse { + isReady: boolean; + missing_requirements: Array<'tls_required' | 'api_keys' | 'fleet_admin_user'>; +} diff --git a/x-pack/plugins/ingest_manager/kibana.json b/x-pack/plugins/ingest_manager/kibana.json index cef1a293c104b..382ea0444093d 100644 --- a/x-pack/plugins/ingest_manager/kibana.json +++ b/x-pack/plugins/ingest_manager/kibana.json @@ -5,5 +5,5 @@ "ui": true, "configPath": ["xpack", "ingestManager"], "requiredPlugins": ["licensing", "data", "encryptedSavedObjects"], - "optionalPlugins": ["security", "features"] + "optionalPlugins": ["security", "features", "cloud"] } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_fleet_status.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_fleet_status.tsx new file mode 100644 index 0000000000000..ef40c171b9ca3 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_fleet_status.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useState, useContext, useEffect } from 'react'; +import { useConfig } from './use_config'; +import { sendGetFleetStatus } from './use_request'; +import { GetFleetStatusResponse } from '../types'; + +interface FleetStatusState { + enabled: boolean; + isLoading: boolean; + isReady: boolean; + missingRequirements?: GetFleetStatusResponse['missing_requirements']; +} + +interface FleetStatus extends FleetStatusState { + refresh: () => Promise; +} + +const FleetStatusContext = React.createContext(undefined); + +export const FleetStatusProvider: React.FC = ({ children }) => { + const config = useConfig(); + const [state, setState] = useState({ + enabled: config.fleet.enabled, + isLoading: false, + isReady: false, + }); + async function sendGetStatus() { + try { + setState(s => ({ ...s, isLoading: true })); + const res = await sendGetFleetStatus(); + if (res.error) { + throw res.error; + } + + setState(s => ({ + ...s, + isLoading: false, + isReady: res.data?.isReady ?? false, + missingRequirements: res.data?.missing_requirements, + })); + } catch (error) { + setState(s => ({ ...s, isLoading: true })); + } + } + useEffect(() => { + sendGetStatus(); + }, []); + + return ( + sendGetStatus() }}> + {children} + + ); +}; + +export function useFleetStatus(): FleetStatus { + const context = useContext(FleetStatusContext); + + if (!context) { + throw new Error('FleetStatusContext not set'); + } + + return context; +} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts index c39d2a5860bf0..25cdffc5c6651 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts @@ -12,3 +12,4 @@ export * from './enrollment_api_keys'; export * from './epm'; export * from './outputs'; export * from './settings'; +export * from './setup'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/setup.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/setup.ts index 04fdf9f66948f..e4e84e4701f13 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/setup.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/setup.ts @@ -5,7 +5,8 @@ */ import { sendRequest } from './use_request'; -import { setupRouteService } from '../../services'; +import { setupRouteService, fleetSetupRouteService } from '../../services'; +import { GetFleetStatusResponse } from '../../types'; export const sendSetup = () => { return sendRequest({ @@ -13,3 +14,10 @@ export const sendSetup = () => { method: 'post', }); }; + +export const sendGetFleetStatus = () => { + return sendRequest({ + path: fleetSetupRouteService.getFleetSetupPath(), + method: 'get', + }); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx index 295a35693726f..f0a0c90a18c24 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx @@ -23,6 +23,7 @@ import { IngestManagerOverview, EPMApp, AgentConfigApp, FleetApp, DataStreamApp import { CoreContext, DepsContext, ConfigContext, setHttpClient, useConfig } from './hooks'; import { PackageInstallProvider } from './sections/epm/hooks'; import { sendSetup } from './hooks/use_request/setup'; +import { FleetStatusProvider } from './hooks/use_fleet_status'; import './index.scss'; export interface ProtectedRouteProps extends RouteProps { @@ -142,7 +143,9 @@ const IngestManagerApp = ({ - + + + diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx index dd34e7260b27b..e9347ccd2d6c9 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx @@ -15,11 +15,15 @@ import { EuiButtonEmpty, EuiButton, EuiFlyoutFooter, + EuiLink, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { AgentConfig } from '../../../../../types'; import { APIKeySelection } from './key_selection'; import { EnrollmentInstructions } from './instructions'; +import { useFleetStatus } from '../../../../../hooks/use_fleet_status'; +import { useLink } from '../../../../../hooks'; +import { FLEET_PATH } from '../../../../../constants'; interface Props { onClose: () => void; @@ -30,8 +34,11 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ onClose, agentConfigs = [], }) => { + const fleetStatus = useFleetStatus(); const [selectedAPIKeyId, setSelectedAPIKeyId] = useState(); + const fleetLink = useLink(FLEET_PATH); + return ( @@ -45,12 +52,33 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ - setSelectedAPIKeyId(keyId)} - /> - - + {fleetStatus.isReady ? ( + <> + setSelectedAPIKeyId(keyId)} + /> + + + + ) : ( + <> + + + + ), + }} + /> + + )} @@ -62,14 +90,16 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ /> - - - - - + {fleetStatus.isReady && ( + + + + + + )} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx index fac81ecc19cd1..b9c5418dbf6f3 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx @@ -6,35 +6,31 @@ import React from 'react'; import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; import { Loading } from '../../components'; -import { useConfig, useCore, useRequest } from '../../hooks'; +import { useConfig, useCore } from '../../hooks'; import { AgentListPage } from './agent_list_page'; import { SetupPage } from './setup_page'; import { AgentDetailsPage } from './agent_details_page'; import { NoAccessPage } from './error_pages/no_access'; -import { fleetSetupRouteService } from '../../services'; import { EnrollmentTokenListPage } from './enrollment_token_list_page'; import { ListLayout } from './components/list_layout'; +import { useFleetStatus } from '../../hooks/use_fleet_status'; export const FleetApp: React.FunctionComponent = () => { const core = useCore(); const { fleet } = useConfig(); - const setupRequest = useRequest({ - method: 'get', - path: fleetSetupRouteService.getFleetSetupPath(), - }); + const fleetStatus = useFleetStatus(); if (!fleet.enabled) return null; - if (setupRequest.isLoading) { + if (fleetStatus.isLoading) { return ; } - if (setupRequest.data.isInitialized === false) { + if (fleetStatus.isReady === false) { return ( { - await setupRequest.sendRequest(); - }} + missingRequirements={fleetStatus.missingRequirements || []} + refresh={fleetStatus.refresh} /> ); } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx index 96d4d01d67a49..4d89268c14b28 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx @@ -18,10 +18,12 @@ import { import { sendRequest, useCore } from '../../../hooks'; import { fleetSetupRouteService } from '../../../services'; import { WithoutHeaderLayout } from '../../../layouts'; +import { GetFleetStatusResponse } from '../../../types'; export const SetupPage: React.FunctionComponent<{ refresh: () => Promise; -}> = ({ refresh }) => { + missingRequirements: GetFleetStatusResponse['missing_requirements']; +}> = ({ refresh, missingRequirements }) => { const [isFormLoading, setIsFormLoading] = useState(false); const core = useCore(); @@ -40,46 +42,81 @@ export const SetupPage: React.FunctionComponent<{ } }; + const content = + missingRequirements.includes('tls_required') || missingRequirements.includes('api_keys') ? ( + <> + + + + +

+ +

+
+ + + , + }} + /> + + + + ) : ( + <> + + + + +

+ +

+
+ + + + + + +
+ + + +
+
+ + + ); + return ( - + - - - - -

- -

-
- - - - - - -
- - - -
-
- + {content}
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts index 602015d23cefb..ca5bf999aa81a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts @@ -20,6 +20,8 @@ export { DatasourceConfigRecordEntry, Output, DataStream, + // API schema - misc setup, status + GetFleetStatusResponse, // API schemas - Agent Config GetAgentConfigsResponse, GetAgentConfigsResponseItem, diff --git a/x-pack/plugins/ingest_manager/server/index.ts b/x-pack/plugins/ingest_manager/server/index.ts index 951ff2337d8c7..6096af8d80801 100644 --- a/x-pack/plugins/ingest_manager/server/index.ts +++ b/x-pack/plugins/ingest_manager/server/index.ts @@ -26,6 +26,7 @@ export const config = { }), fleet: schema.object({ enabled: schema.boolean({ defaultValue: true }), + tlsCheckDisabled: schema.boolean({ defaultValue: false }), kibana: schema.object({ host: schema.maybe(schema.string()), ca_sha256: schema.maybe(schema.string()), diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts index 3448685d1f279..3b0837565c36c 100644 --- a/x-pack/plugins/ingest_manager/server/plugin.ts +++ b/x-pack/plugins/ingest_manager/server/plugin.ts @@ -11,6 +11,7 @@ import { Plugin, PluginInitializerContext, SavedObjectsServiceStart, + HttpServerInfo, } from 'kibana/server'; import { LicensingPluginSetup, ILicense } from '../../licensing/server'; import { @@ -42,7 +43,6 @@ import { registerOutputRoutes, registerSettingsRoutes, } from './routes'; - import { IngestManagerConfigType } from '../common'; import { appContextService, @@ -52,12 +52,14 @@ import { AgentService, } from './services'; import { getAgentStatusById } from './services/agents'; +import { CloudSetup } from '../../cloud/server'; export interface IngestManagerSetupDeps { licensing: LicensingPluginSetup; security?: SecurityPluginSetup; features?: FeaturesPluginSetup; encryptedSavedObjects: EncryptedSavedObjectsPluginSetup; + cloud?: CloudSetup; } export type IngestManagerStartDeps = object; @@ -67,6 +69,9 @@ export interface IngestManagerAppContext { security?: SecurityPluginSetup; config$?: Observable; savedObjects: SavedObjectsServiceStart; + isProductionMode: boolean; + serverInfo?: HttpServerInfo; + cloud?: CloudSetup; } export type IngestManagerSetupContract = void; @@ -100,16 +105,23 @@ export class IngestManagerPlugin private licensing$!: Observable; private config$: Observable; private security: SecurityPluginSetup | undefined; + private cloud: CloudSetup | undefined; + + private isProductionMode: boolean; + private serverInfo: HttpServerInfo | undefined; constructor(private readonly initializerContext: PluginInitializerContext) { this.config$ = this.initializerContext.config.create(); + this.isProductionMode = this.initializerContext.env.mode.prod; } public async setup(core: CoreSetup, deps: IngestManagerSetupDeps) { + this.serverInfo = core.http.getServerInfo(); this.licensing$ = deps.licensing.license$; if (deps.security) { this.security = deps.security; } + this.cloud = deps.cloud; registerSavedObjects(core.savedObjects); registerEncryptedSavedObjects(deps.encryptedSavedObjects); @@ -184,6 +196,9 @@ export class IngestManagerPlugin security: this.security, config$: this.config$, savedObjects: core.savedObjects, + isProductionMode: this.isProductionMode, + serverInfo: this.serverInfo, + cloud: this.cloud, }); licenseService.start(this.licensing$); return { diff --git a/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts index 837e73b966feb..542dfa9cefe8f 100644 --- a/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts +++ b/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts @@ -4,28 +4,43 @@ * you may not use this file except in compliance with the Elastic License. */ import { RequestHandler } from 'src/core/server'; -import { outputService } from '../../services'; -import { CreateFleetSetupResponse } from '../../../common'; +import { outputService, appContextService } from '../../services'; +import { GetFleetStatusResponse } from '../../../common'; import { setupIngestManager, setupFleet } from '../../services/setup'; -export const getFleetSetupHandler: RequestHandler = async (context, request, response) => { +export const getFleetStatusHandler: RequestHandler = async (context, request, response) => { const soClient = context.core.savedObjects.client; - const successBody: CreateFleetSetupResponse = { isInitialized: true }; - const failureBody: CreateFleetSetupResponse = { isInitialized: false }; try { - const adminUser = await outputService.getAdminUser(soClient); - if (adminUser) { - return response.ok({ - body: successBody, - }); - } else { - return response.ok({ - body: failureBody, - }); + const isAdminUserSetup = (await outputService.getAdminUser(soClient)) !== null; + const isApiKeysEnabled = await appContextService.getSecurity().authc.areAPIKeysEnabled(); + const isTLSEnabled = appContextService.getServerInfo().protocol === 'https'; + const isProductionMode = appContextService.getIsProductionMode(); + const isCloud = appContextService.getCloud()?.isCloudEnabled ?? false; + const isTLSCheckDisabled = appContextService.getConfig()?.fleet?.tlsCheckDisabled ?? false; + + const missingRequirements: GetFleetStatusResponse['missing_requirements'] = []; + if (!isAdminUserSetup) { + missingRequirements.push('fleet_admin_user'); } - } catch (e) { + if (!isApiKeysEnabled) { + missingRequirements.push('api_keys'); + } + if (!isTLSCheckDisabled && !isCloud && isProductionMode && !isTLSEnabled) { + missingRequirements.push('tls_required'); + } + + const body: GetFleetStatusResponse = { + isReady: missingRequirements.length === 0, + missing_requirements: missingRequirements, + }; + return response.ok({ - body: failureBody, + body, + }); + } catch (e) { + return response.customError({ + statusCode: 500, + body: { message: e.message }, }); } }; diff --git a/x-pack/plugins/ingest_manager/server/routes/setup/index.ts b/x-pack/plugins/ingest_manager/server/routes/setup/index.ts index 5ee7ee7733220..43dcf47d26c18 100644 --- a/x-pack/plugins/ingest_manager/server/routes/setup/index.ts +++ b/x-pack/plugins/ingest_manager/server/routes/setup/index.ts @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import { IRouter } from 'src/core/server'; + import { PLUGIN_ID, FLEET_SETUP_API_ROUTES, SETUP_API_ROUTE } from '../../constants'; import { IngestManagerConfigType } from '../../../common'; import { - getFleetSetupHandler, + getFleetStatusHandler, createFleetSetupHandler, ingestManagerSetupHandler, } from './handlers'; @@ -36,7 +37,7 @@ export const registerRoutes = (router: IRouter, config: IngestManagerConfigType) validate: false, options: { tags: [`access:${PLUGIN_ID}-read`] }, }, - getFleetSetupHandler + getFleetStatusHandler ); // Create Fleet setup diff --git a/x-pack/plugins/ingest_manager/server/services/agent_config.ts b/x-pack/plugins/ingest_manager/server/services/agent_config.ts index 5ecbaff8ad71e..84bcd7db3f7b1 100644 --- a/x-pack/plugins/ingest_manager/server/services/agent_config.ts +++ b/x-pack/plugins/ingest_manager/server/services/agent_config.ts @@ -314,10 +314,12 @@ class AgentConfigService { if (!config) { return null; } - const defaultOutput = await outputService.get( - soClient, - await outputService.getDefaultOutputId(soClient) - ); + + const defaultOutputId = await outputService.getDefaultOutputId(soClient); + if (!defaultOutputId) { + throw new Error('Default output is not setup'); + } + const defaultOutput = await outputService.get(soClient, defaultOutputId); const agentConfig: FullAgentConfig = { id: config.id, diff --git a/x-pack/plugins/ingest_manager/server/services/app_context.ts b/x-pack/plugins/ingest_manager/server/services/app_context.ts index e917d2edd1309..5e538ad84b4c2 100644 --- a/x-pack/plugins/ingest_manager/server/services/app_context.ts +++ b/x-pack/plugins/ingest_manager/server/services/app_context.ts @@ -5,11 +5,12 @@ */ import { BehaviorSubject, Observable } from 'rxjs'; import { first } from 'rxjs/operators'; -import { SavedObjectsServiceStart } from 'src/core/server'; +import { SavedObjectsServiceStart, HttpServerInfo } from 'src/core/server'; import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server'; import { SecurityPluginSetup } from '../../../security/server'; import { IngestManagerConfigType } from '../../common'; import { IngestManagerAppContext } from '../plugin'; +import { CloudSetup } from '../../../cloud/server'; class AppContextService { private encryptedSavedObjects: EncryptedSavedObjectsPluginStart | undefined; @@ -17,11 +18,17 @@ class AppContextService { private config$?: Observable; private configSubject$?: BehaviorSubject; private savedObjects: SavedObjectsServiceStart | undefined; + private serverInfo: HttpServerInfo | undefined; + private isProductionMode: boolean = false; + private cloud?: CloudSetup; public async start(appContext: IngestManagerAppContext) { this.encryptedSavedObjects = appContext.encryptedSavedObjects; this.security = appContext.security; this.savedObjects = appContext.savedObjects; + this.serverInfo = appContext.serverInfo; + this.isProductionMode = appContext.isProductionMode; + this.cloud = appContext.cloud; if (appContext.config$) { this.config$ = appContext.config$; @@ -41,9 +48,16 @@ class AppContextService { } public getSecurity() { + if (!this.security) { + throw new Error('Secury service not set.'); + } return this.security; } + public getCloud() { + return this.cloud; + } + public getConfig() { return this.configSubject$?.value; } @@ -58,6 +72,17 @@ class AppContextService { } return this.savedObjects; } + + public getIsProductionMode() { + return this.isProductionMode; + } + + public getServerInfo() { + if (!this.serverInfo) { + throw new Error('Server info not set.'); + } + return this.serverInfo; + } } export const appContextService = new AppContextService(); diff --git a/x-pack/plugins/ingest_manager/server/services/datasource.ts b/x-pack/plugins/ingest_manager/server/services/datasource.ts index affd9b2755881..0497bc5a2b541 100644 --- a/x-pack/plugins/ingest_manager/server/services/datasource.ts +++ b/x-pack/plugins/ingest_manager/server/services/datasource.ts @@ -196,6 +196,9 @@ class DatasourceService { outputService.getDefaultOutputId(soClient), ]); if (pkgInfo) { + if (!defaultOutputId) { + throw new Error('Default output is not set'); + } return packageToConfigDatasource(pkgInfo, '', defaultOutputId); } } diff --git a/x-pack/plugins/ingest_manager/server/services/output.ts b/x-pack/plugins/ingest_manager/server/services/output.ts index 395c9af4a4ca2..3628c5bd9e183 100644 --- a/x-pack/plugins/ingest_manager/server/services/output.ts +++ b/x-pack/plugins/ingest_manager/server/services/output.ts @@ -48,7 +48,7 @@ class OutputService { }); if (!outputs.saved_objects.length) { - throw new Error('No default output'); + return null; } return outputs.saved_objects[0].id; @@ -56,6 +56,9 @@ class OutputService { public async getAdminUser(soClient: SavedObjectsClientContract) { const defaultOutputId = await this.getDefaultOutputId(soClient); + if (!defaultOutputId) { + return null; + } const so = await appContextService .getEncryptedSavedObjects() ?.getDecryptedAsInternalUser(OUTPUT_SAVED_OBJECT_TYPE, defaultOutputId); diff --git a/x-pack/plugins/ingest_manager/server/services/setup.ts b/x-pack/plugins/ingest_manager/server/services/setup.ts index 390e240841611..3619628bd4f8b 100644 --- a/x-pack/plugins/ingest_manager/server/services/setup.ts +++ b/x-pack/plugins/ingest_manager/server/services/setup.ts @@ -109,7 +109,12 @@ export async function setupFleet( }); // save fleet admin user - await outputService.updateOutput(soClient, await outputService.getDefaultOutputId(soClient), { + const defaultOutputId = await outputService.getDefaultOutputId(soClient); + if (!defaultOutputId) { + throw new Error('Default output does not exist'); + } + + await outputService.updateOutput(soClient, defaultOutputId, { fleet_enroll_username: FLEET_ENROLL_USERNAME, fleet_enroll_password: password, }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index da8673da67f42..11d1f864a3619 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8370,9 +8370,7 @@ "xpack.ingestManager.noAccess.accessDeniedTitle": "アクセスが拒否されました", "xpack.ingestManager.overviewPageSubtitle": "Ingest Manager についてのロレムイプサム説明文。", "xpack.ingestManager.overviewPageTitle": "Ingest Manager", - "xpack.ingestManager.setupPage.description": "フリートを使用するには、Elastic ユーザーを作成する必要があります。このユーザーは、API キーを作成して、logs-* および metrics-* に書き込むことができます。", "xpack.ingestManager.setupPage.enableFleet": "ユーザーを作成してフリートを有効にます", - "xpack.ingestManager.setupPage.title": "フリートを有効にする", "xpack.ingestManager.unenrollAgents.confirmModal.cancelButtonLabel": "キャンセル", "xpack.ingestManager.unenrollAgents.confirmModal.confirmButtonLabel": "登録解除", "xpack.ingestManager.unenrollAgents.confirmModal.deleteMultipleTitle": "{count, plural, one {# エージェント} other {# エージェント}}の登録を解除しますか?", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f66e9631b0168..9ee3b3d8f5931 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8376,9 +8376,7 @@ "xpack.ingestManager.noAccess.accessDeniedTitle": "访问被拒绝", "xpack.ingestManager.overviewPageSubtitle": "Lorem ipsum some description about ingest manager.", "xpack.ingestManager.overviewPageTitle": "Ingest Manager", - "xpack.ingestManager.setupPage.description": "要使用 Fleet,必须创建 Elastic 用户。此用户可以创建 API 密钥并写入到 logs-* and metrics-*。", "xpack.ingestManager.setupPage.enableFleet": "创建用户并启用 Fleet", - "xpack.ingestManager.setupPage.title": "启用 Fleet", "xpack.ingestManager.unenrollAgents.confirmModal.cancelButtonLabel": "取消", "xpack.ingestManager.unenrollAgents.confirmModal.confirmButtonLabel": "取消注册", "xpack.ingestManager.unenrollAgents.confirmModal.deleteMultipleTitle": "取消注册 {count, plural, one {# 个代理} other {# 个代理}}?",