From 394174eedf756d5676773f22a72828b786bf6b56 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Mon, 10 Apr 2023 12:38:45 -0400 Subject: [PATCH 001/105] [Fleet] Disable ILM policy in serverless (#154460) --- config/serverless.yml | 1 + x-pack/plugins/fleet/common/types/index.ts | 3 + x-pack/plugins/fleet/server/config.ts | 8 ++ .../template/default_settings.ts | 14 ++- .../epm/packages/_install_package.test.ts | 118 +++++++++++++++++- .../services/epm/packages/_install_package.ts | 30 +++-- 6 files changed, 156 insertions(+), 18 deletions(-) diff --git a/config/serverless.yml b/config/serverless.yml index 6eabe0049fbfd..80e4ab584f9f6 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -1 +1,2 @@ xpack.fleet.enableExperimental: ['fleetServerStandalone'] +xpack.fleet.internal.ILMPoliciesDisabled: true diff --git a/x-pack/plugins/fleet/common/types/index.ts b/x-pack/plugins/fleet/common/types/index.ts index d3a7f9ee95bd1..0daea71cd8271 100644 --- a/x-pack/plugins/fleet/common/types/index.ts +++ b/x-pack/plugins/fleet/common/types/index.ts @@ -44,6 +44,9 @@ export interface FleetConfigType { disableRegistryVersionCheck?: boolean; bundledPackageLocation?: string; }; + internal?: { + disableILMPolicies: boolean; + }; } // Calling Object.entries(PackagesGroupedByStatus) gave `status: string` diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index d5312bf9bc65c..267d9873aaa2d 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -158,6 +158,14 @@ export const config: PluginConfigDescriptor = { } }, }), + + internal: schema.maybe( + schema.object({ + disableILMPolicies: schema.boolean({ + defaultValue: false, + }), + }) + ), }), }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts index 658dde2ed760a..fe90954966f24 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts @@ -61,12 +61,18 @@ export function buildDefaultSettings({ : defaultFields ).map((field) => field.name); + const isILMPolicyDisabled = appContextService.getConfig()?.internal?.disableILMPolicies ?? false; + return { index: { - // ILM Policy must be added here, for now point to the default global ILM policy name - lifecycle: { - name: ilmPolicy ? ilmPolicy : type, - }, + ...(isILMPolicyDisabled + ? {} + : { + // ILM Policy must be added here, for now point to the default global ILM policy name + lifecycle: { + name: ilmPolicy ? ilmPolicy : type, + }, + }), // What should be our default for the compression? codec: 'best_compression', // All the default fields which should be queried have to be added here. diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts index 23cdd399344e7..7deadc45df8cd 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts @@ -8,11 +8,13 @@ import type { SavedObjectsClientContract, ElasticsearchClient } from '@kbn/core/server'; import { savedObjectsClientMock, elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; - import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; import { appContextService } from '../../app_context'; import { createAppContextStartContractMock } from '../../../mocks'; +import { saveArchiveEntries } from '../archive/storage'; +import { installILMPolicy } from '../elasticsearch/ilm/install'; +import { installIlmForDataStream } from '../elasticsearch/datastream_ilm/install'; jest.mock('../elasticsearch/template/template'); jest.mock('../kibana/assets/install'); @@ -20,6 +22,10 @@ jest.mock('../kibana/index_pattern/install'); jest.mock('./install'); jest.mock('./get'); +jest.mock('../archive/storage'); +jest.mock('../elasticsearch/ilm/install'); +jest.mock('../elasticsearch/datastream_ilm/install'); + import { updateCurrentWriteIndices } from '../elasticsearch/template/template'; import { installKibanaAssetsAndReferences } from '../kibana/assets/install'; @@ -47,8 +53,22 @@ describe('_installPackage', () => { beforeEach(async () => { soClient = savedObjectsClientMock.create(); + + soClient.update.mockImplementation(async (type, id, attributes) => { + return { id, attributes } as any; + }); + esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; appContextService.start(createAppContextStartContractMock()); + jest.mocked(installILMPolicy).mockReset(); + jest.mocked(installIlmForDataStream).mockReset(); + jest.mocked(installIlmForDataStream).mockResolvedValue({ + esReferences: [], + installedIlms: [], + }); + jest.mocked(saveArchiveEntries).mockResolvedValue({ + saved_objects: [], + }); }); afterEach(async () => { appContextService.stop(); @@ -96,4 +116,100 @@ describe('_installPackage', () => { await expect(installationPromise).rejects.toThrow('mocked'); await expect(installationPromise).rejects.toThrow('should be caught'); }); + + it('do not install ILM policies if disabled in config', async () => { + appContextService.start( + createAppContextStartContractMock({ + internal: { + disableILMPolicies: true, + }, + }) + ); + // force errors from this function + mockedInstallKibanaAssetsAndReferences.mockResolvedValue([]); + // pick any function between when those are called and when await Promise.all is defined later + // and force it to take long enough for the errors to occur + // @ts-expect-error about call signature + mockedUpdateCurrentWriteIndices.mockImplementation(async () => await sleep(1000)); + mockedInstallIndexTemplatesAndPipelines.mockResolvedValue({ + installedTemplates: [], + esReferences: [], + }); + await _installPackage({ + savedObjectsClient: soClient, + // @ts-ignore + savedObjectsImporter: jest.fn(), + esClient, + logger: loggerMock.create(), + paths: [], + packageInfo: { + title: 'title', + name: 'xyz', + version: '4.5.6', + description: 'test', + type: 'integration', + categories: ['cloud', 'custom'], + format_version: 'string', + release: 'experimental', + conditions: { kibana: { version: 'x.y.z' } }, + owner: { github: 'elastic/fleet' }, + }, + installType: 'install', + installSource: 'registry', + spaceId: DEFAULT_SPACE_ID, + }); + + expect(installILMPolicy).not.toBeCalled(); + expect(installIlmForDataStream).not.toBeCalled(); + // if we have a .catch this will fail nicely (test pass) + // otherwise the test will fail with either of the mocked errors + // await expect(installationPromise).rejects.toThrow('mocked'); + // await expect(installationPromise).rejects.toThrow('should be caught'); + }); + + it('install ILM policies if not disabled in config', async () => { + appContextService.start( + createAppContextStartContractMock({ + internal: { + disableILMPolicies: false, + }, + }) + ); + // force errors from this function + mockedInstallKibanaAssetsAndReferences.mockResolvedValue([]); + // pick any function between when those are called and when await Promise.all is defined later + // and force it to take long enough for the errors to occur + // @ts-expect-error about call signature + mockedUpdateCurrentWriteIndices.mockImplementation(async () => await sleep(1000)); + mockedInstallIndexTemplatesAndPipelines.mockResolvedValue({ + installedTemplates: [], + esReferences: [], + }); + await _installPackage({ + savedObjectsClient: soClient, + // @ts-ignore + savedObjectsImporter: jest.fn(), + esClient, + logger: loggerMock.create(), + paths: [], + packageInfo: { + title: 'title', + name: 'xyz', + version: '4.5.6', + description: 'test', + type: 'integration', + categories: ['cloud', 'custom'], + format_version: 'string', + release: 'experimental', + conditions: { kibana: { version: 'x.y.z' } }, + owner: { github: 'elastic/fleet' }, + }, + installType: 'install', + installSource: 'registry', + spaceId: DEFAULT_SPACE_ID, + }); + + expect(installILMPolicy).toBeCalled(); + expect(installIlmForDataStream).toBeCalled(); + }); }); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts index 7da483d0794a2..68c981a308f82 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts @@ -153,20 +153,24 @@ export async function _installPackage({ // currently only the base package has an ILM policy // at some point ILM policies can be installed/modified // per data stream and we should then save them - esReferences = await withPackageSpan('Install ILM policies', () => - installILMPolicy(packageInfo, paths, esClient, savedObjectsClient, logger, esReferences) - ); + const isILMPoliciesDisabled = + appContextService.getConfig()?.internal?.disableILMPolicies ?? false; + if (!isILMPoliciesDisabled) { + esReferences = await withPackageSpan('Install ILM policies', () => + installILMPolicy(packageInfo, paths, esClient, savedObjectsClient, logger, esReferences) + ); - ({ esReferences } = await withPackageSpan('Install Data Stream ILM policies', () => - installIlmForDataStream( - packageInfo, - paths, - esClient, - savedObjectsClient, - logger, - esReferences - ) - )); + ({ esReferences } = await withPackageSpan('Install Data Stream ILM policies', () => + installIlmForDataStream( + packageInfo, + paths, + esClient, + savedObjectsClient, + logger, + esReferences + ) + )); + } // installs ml models esReferences = await withPackageSpan('Install ML models', () => From 77498a9b69a929127bffe0da4bf836862b53e8ba Mon Sep 17 00:00:00 2001 From: Karl Godard Date: Mon, 10 Apr 2023 10:10:23 -0700 Subject: [PATCH 002/105] Fix for k8s dashboard getting letterboxed when there is no data. (#154094) ## Summary Fixes an display issue with the k8s dashboard. Currently this page doesn't render an empty state like other pages do, and so I've removed it from the list of pages with "empty state" in order to avoid the whole page having a restricted width of ~960px. Before: ![image](https://user-images.githubusercontent.com/16198204/228934077-add3ecdf-2845-4714-98f2-e791133505e8.png) After: ![image](https://user-images.githubusercontent.com/16198204/228934155-f785c0b9-2fbc-4a04-9522-4eecdd5d2a6c.png) --- .../common/utils/empty_view/use_show_pages_with_empty_view.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx index 7f9688ef3c04f..e9f54f8a9284f 100644 --- a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx +++ b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx @@ -18,7 +18,6 @@ const isPageNameWithEmptyView = (currentName: string) => { SecurityPageName.timelines, SecurityPageName.overview, SecurityPageName.users, - SecurityPageName.kubernetes, ]; return pageNamesWithEmptyView.includes(currentName); }; From a0f8d910b7715e6a0c9124e829ffb27681d5c8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Mon, 10 Apr 2023 13:11:04 -0400 Subject: [PATCH 003/105] [Profling] Adding symbols callout on frame information window (#154478) This PR adds a callout on the Frame information window for each symbol status and Storybook support. `Symbolized`: Screenshot 2023-04-05 at 2 46 36 PM `Native language`: Screenshot 2023-04-05 at 2 46 24 PM `Interpreted language`: Screenshot 2023-04-05 at 2 46 16 PM --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- src/dev/storybook/aliases.ts | 1 + .../profiling/.storybook/jest_setup.js | 11 +++ x-pack/plugins/profiling/.storybook/main.js | 8 ++ .../plugins/profiling/.storybook/preview.js | 10 ++ .../profiling/common/profiling.test.ts | 43 +++++++++ x-pack/plugins/profiling/common/profiling.ts | 55 ++++++++--- .../mock_profiling_dependencies_storybook.tsx | 93 +++++++++++++++++++ .../frame_information_tooltip.tsx | 2 +- .../frame_information_window/index.tsx | 13 +++ .../missing_symbols_callout.stories.tsx | 42 +++++++++ .../missing_symbols_callout.tsx | 90 ++++++++++++++++++ .../profiling_app_page_template/index.tsx | 2 +- x-pack/plugins/profiling/tsconfig.json | 3 + 13 files changed, 360 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/profiling/.storybook/jest_setup.js create mode 100644 x-pack/plugins/profiling/.storybook/main.js create mode 100644 x-pack/plugins/profiling/.storybook/preview.js create mode 100644 x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx create mode 100644 x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx create mode 100644 x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 76a0c23992d7a..3ad6852936aed 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -50,4 +50,5 @@ export const storybookAliases = { triggers_actions_ui: 'x-pack/plugins/triggers_actions_ui/.storybook', ui_actions_enhanced: 'src/plugins/ui_actions_enhanced/.storybook', unified_search: 'src/plugins/unified_search/.storybook', + profiling: 'x-pack/plugins/profiling/.storybook', }; diff --git a/x-pack/plugins/profiling/.storybook/jest_setup.js b/x-pack/plugins/profiling/.storybook/jest_setup.js new file mode 100644 index 0000000000000..32071b8aa3f62 --- /dev/null +++ b/x-pack/plugins/profiling/.storybook/jest_setup.js @@ -0,0 +1,11 @@ +/* + * 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 { setGlobalConfig } from '@storybook/testing-react'; +import * as globalStorybookConfig from './preview'; + +setGlobalConfig(globalStorybookConfig); diff --git a/x-pack/plugins/profiling/.storybook/main.js b/x-pack/plugins/profiling/.storybook/main.js new file mode 100644 index 0000000000000..86b48c32f103e --- /dev/null +++ b/x-pack/plugins/profiling/.storybook/main.js @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = require('@kbn/storybook').defaultConfig; diff --git a/x-pack/plugins/profiling/.storybook/preview.js b/x-pack/plugins/profiling/.storybook/preview.js new file mode 100644 index 0000000000000..3200746243d47 --- /dev/null +++ b/x-pack/plugins/profiling/.storybook/preview.js @@ -0,0 +1,10 @@ +/* + * 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 { EuiThemeProviderDecorator } from '@kbn/kibana-react-plugin/common'; + +export const decorators = [EuiThemeProviderDecorator]; diff --git a/x-pack/plugins/profiling/common/profiling.test.ts b/x-pack/plugins/profiling/common/profiling.test.ts index df014bada46bb..5115055ad3c94 100644 --- a/x-pack/plugins/profiling/common/profiling.test.ts +++ b/x-pack/plugins/profiling/common/profiling.test.ts @@ -8,11 +8,14 @@ import { createStackFrameID, createStackFrameMetadata, + FrameSymbolStatus, FrameType, getAddressFromStackFrameID, getCalleeFunction, getCalleeSource, getFileIDFromStackFrameID, + getFrameSymbolStatus, + getLanguageType, } from './profiling'; describe('Stack frame operations', () => { @@ -88,3 +91,43 @@ describe('Stack frame metadata operations', () => { expect(getCalleeSource(metadata)).toEqual('runtime/malloc.go'); }); }); + +describe('getFrameSymbolStatus', () => { + it('returns partially symbolized when metadata has executable name but no source name and source line', () => { + expect(getFrameSymbolStatus({ sourceFilename: '', sourceLine: 0, exeFileName: 'foo' })).toEqual( + FrameSymbolStatus.PARTIALLY_SYMBOLYZED + ); + }); + it('returns not symbolized when metadata has no source name and source line and executable name', () => { + expect(getFrameSymbolStatus({ sourceFilename: '', sourceLine: 0 })).toEqual( + FrameSymbolStatus.NOT_SYMBOLIZED + ); + }); + + it('returns symbolized when metadata has source name and source line', () => { + expect(getFrameSymbolStatus({ sourceFilename: 'foo', sourceLine: 10 })).toEqual( + FrameSymbolStatus.SYMBOLIZED + ); + }); +}); + +describe('getLanguageType', () => { + [FrameType.Native, FrameType.Kernel].map((type) => + it(`returns native for ${type}`, () => { + expect(getLanguageType({ frameType: type })).toEqual('NATIVE'); + }) + ); + [ + FrameType.JVM, + FrameType.JavaScript, + FrameType.PHP, + FrameType.PHPJIT, + FrameType.Perl, + FrameType.Python, + FrameType.Ruby, + ].map((type) => + it(`returns interpreted for ${type}`, () => { + expect(getLanguageType({ frameType: type })).toEqual('INTERPRETED'); + }) + ); +}); diff --git a/x-pack/plugins/profiling/common/profiling.ts b/x-pack/plugins/profiling/common/profiling.ts index 32f4e920306c4..8cb9558fcfc64 100644 --- a/x-pack/plugins/profiling/common/profiling.ts +++ b/x-pack/plugins/profiling/common/profiling.ts @@ -234,23 +234,56 @@ export function getCalleeFunction(frame: StackFrameMetadata): string { // When there is no function name, only use the executable name return frame.FunctionName ? exeDisplayName + ': ' + frame.FunctionName : exeDisplayName; } +export enum FrameSymbolStatus { + PARTIALLY_SYMBOLYZED = 'PARTIALLY_SYMBOLYZED', + NOT_SYMBOLIZED = 'NOT_SYMBOLIZED', + SYMBOLIZED = 'SYMBOLIZED', +} +export function getFrameSymbolStatus({ + sourceFilename, + sourceLine, + exeFileName, +}: { + sourceFilename: string; + sourceLine: number; + exeFileName?: string; +}) { + if (sourceFilename === '' && sourceLine === 0) { + if (exeFileName) { + return FrameSymbolStatus.PARTIALLY_SYMBOLYZED; + } + + return FrameSymbolStatus.NOT_SYMBOLIZED; + } + + return FrameSymbolStatus.SYMBOLIZED; +} + +const nativeLanguages = [FrameType.Native, FrameType.Kernel]; +export function getLanguageType({ frameType }: { frameType: FrameType }) { + return nativeLanguages.includes(frameType) ? 'NATIVE' : 'INTERPRETED'; +} export function getCalleeSource(frame: StackFrameMetadata): string { - if (frame.SourceFilename === '' && frame.SourceLine === 0) { - if (frame.ExeFileName) { + const frameSymbolStatus = getFrameSymbolStatus({ + sourceFilename: frame.SourceFilename, + sourceLine: frame.SourceLine, + exeFileName: frame.ExeFileName, + }); + + switch (frameSymbolStatus) { + case FrameSymbolStatus.NOT_SYMBOLIZED: { + // If we don't have the executable filename, display + return ''; + } + case FrameSymbolStatus.PARTIALLY_SYMBOLYZED: { // If no source line or filename available, display the executable offset return frame.ExeFileName + '+0x' + frame.AddressOrLine.toString(16); } - - // If we don't have the executable filename, display - return ''; - } - - if (frame.SourceFilename !== '' && frame.SourceLine === 0) { - return frame.SourceFilename; + case FrameSymbolStatus.SYMBOLIZED: { + return frame.SourceFilename + (frame.SourceLine !== 0 ? `#${frame.SourceLine}` : ''); + } } - - return frame.SourceFilename + (frame.SourceLine !== 0 ? `#${frame.SourceLine}` : ''); } export function groupStackFrameMetadataByStackTrace( diff --git a/x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx b/x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx new file mode 100644 index 0000000000000..67a28c6839979 --- /dev/null +++ b/x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { CoreStart } from '@kbn/core/public'; +import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; +import { MlLocatorDefinition } from '@kbn/ml-plugin/public'; +import { UrlService } from '@kbn/share-plugin/common/url_service'; +import React, { ReactNode } from 'react'; +import { Observable } from 'rxjs'; +import { ProfilingDependenciesContextProvider } from './profiling_dependencies_context'; + +const urlService = new UrlService({ + navigate: async () => {}, + getUrl: async ({ app, path }, { absolute }) => { + return `${absolute ? 'http://localhost:8888' : ''}/app/${app}${path}`; + }, + shortUrls: () => ({ get: () => {} } as any), +}); +const locator = urlService.locators.create(new MlLocatorDefinition()); + +const mockPlugin = { + ml: { + locator, + }, + data: { + query: { + timefilter: { timefilter: { setTime: () => {}, getTime: () => ({}) } }, + }, + }, +}; + +const mockCore = { + application: { + currentAppId$: new Observable(), + getUrlForApp: (appId: string) => '', + navigateToUrl: (url: string) => {}, + }, + chrome: { + docTitle: { change: () => {} }, + setBreadcrumbs: () => {}, + setHelpExtension: () => {}, + setBadge: () => {}, + }, + docLinks: { + DOC_LINK_VERSION: 'current', + ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', + links: { observability: { guide: '' } }, + }, + http: { + basePath: { + prepend: (path: string) => `/basepath${path}`, + get: () => '/basepath', + }, + }, + i18n: { + Context: ({ children }: { children: ReactNode }) => children, + }, + notifications: { + toasts: { + addWarning: () => {}, + addDanger: () => {}, + add: () => {}, + }, + }, +}; + +const mockProfilingDependenciesContext = { + core: mockCore, + plugins: mockPlugin, +} as any; + +export function MockProfilingDependenciesStorybook({ children }: { children?: ReactNode }) { + const KibanaReactContext = createKibanaReactContext( + mockProfilingDependenciesContext.core as unknown as Partial + ); + + return ( + + + + {children} + + + + ); +} diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_tooltip.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_tooltip.tsx index 587e660702c75..2ff6a36636d61 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_tooltip.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_tooltip.tsx @@ -14,7 +14,7 @@ interface Props extends FrameInformationWindowProps { export function FrameInformationTooltip({ onClose, ...props }: Props) { return ( - + diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx index 72913b8387707..520136c1f40ac 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx @@ -7,10 +7,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiText, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import { FrameSymbolStatus, getFrameSymbolStatus } from '../../../common/profiling'; import { FrameInformationPanel } from './frame_information_panel'; import { getImpactRows } from './get_impact_rows'; import { getInformationRows } from './get_information_rows'; import { KeyValueList } from './key_value_list'; +import { MissingSymbolsCallout } from './missing_symbols_callout'; export interface Props { frame?: { @@ -41,6 +43,12 @@ export function FrameInformationWindow({ frame, totalSamples, totalSeconds }: Pr ); } + const symbolStatus = getFrameSymbolStatus({ + sourceFilename: frame.sourceFileName, + sourceLine: frame.sourceLine, + exeFileName: frame.exeFileName, + }); + const { fileID, frameType, @@ -76,6 +84,11 @@ export function FrameInformationWindow({ frame, totalSamples, totalSeconds }: Pr + {symbolStatus !== FrameSymbolStatus.SYMBOLIZED && ( + + + + )} diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx new file mode 100644 index 0000000000000..ba353d48c6995 --- /dev/null +++ b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx @@ -0,0 +1,42 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { Meta } from '@storybook/react'; +import React from 'react'; +import { FrameType } from '../../../common/profiling'; +import { MockProfilingDependenciesStorybook } from '../contexts/profiling_dependencies/mock_profiling_dependencies_storybook'; +import { MissingSymbolsCallout } from './missing_symbols_callout'; + +const stories: Meta<{}> = { + title: 'shared/Frame information window/Missing symbols', + component: MissingSymbolsCallout, + decorators: [ + (StoryComponent, { globals }) => { + return ( + + + + ); + }, + ], +}; + +export default stories; + +export function Examples() { + return ( + + + + + + + + + ); +} diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx new file mode 100644 index 0000000000000..72fbe41c46993 --- /dev/null +++ b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx @@ -0,0 +1,90 @@ +/* + * 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 { EuiButton, EuiCallOut, EuiLink } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { FrameType, getLanguageType } from '../../../common/profiling'; +import { PROFILING_FEEDBACK_LINK } from '../profiling_app_page_template'; +import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; + +interface Props { + frameType: FrameType; +} + +export function MissingSymbolsCallout({ frameType }: Props) { + const languageType = getLanguageType({ frameType }); + const { docLinks } = useProfilingDependencies().start.core; + + if (languageType === 'NATIVE') { + return ( + +

+ + {i18n.translate( + 'xpack.profiling.frameInformationWindow.missingSymbols.native.readMore', + { defaultMessage: 'Read more' } + )} + + ), + }} + /> +

+ + {i18n.translate( + 'xpack.profiling.frameInformationWindow.missingSymbols.native.downloadBinary', + { defaultMessage: 'Download elastic-profiling binary' } + )} + +
+ ); + } + + return ( + +

+ {i18n.translate('xpack.profiling.frameInformationWindow.missingSymbols.interpreted', { + defaultMessage: + 'Symbols are not available because of an error in the unwinder for this language or an unknown error with the interpreter.', + })} +

+ + {i18n.translate( + 'xpack.profiling.frameInformationWindow.missingSymbols.interpreted.reportProblem', + { defaultMessage: 'Report a problem' } + )} + +
+ ); +} diff --git a/x-pack/plugins/profiling/public/components/profiling_app_page_template/index.tsx b/x-pack/plugins/profiling/public/components/profiling_app_page_template/index.tsx index 38a6f379643ed..4114082efe9e5 100644 --- a/x-pack/plugins/profiling/public/components/profiling_app_page_template/index.tsx +++ b/x-pack/plugins/profiling/public/components/profiling_app_page_template/index.tsx @@ -19,7 +19,7 @@ import { NoDataPageProps } from '@kbn/shared-ux-page-no-data-types'; import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; import { PrimaryProfilingSearchBar } from './primary_profiling_search_bar'; -const PROFILING_FEEDBACK_LINK = 'https://ela.st/profiling-feedback'; +export const PROFILING_FEEDBACK_LINK = 'https://ela.st/profiling-feedback'; export function ProfilingAppPageTemplate({ children, diff --git a/x-pack/plugins/profiling/tsconfig.json b/x-pack/plugins/profiling/tsconfig.json index 6364139982415..310a8c0b24bef 100644 --- a/x-pack/plugins/profiling/tsconfig.json +++ b/x-pack/plugins/profiling/tsconfig.json @@ -41,6 +41,9 @@ "@kbn/spaces-plugin", "@kbn/cloud-plugin", "@kbn/shared-ux-prompt-not-found", + "@kbn/i18n-react", + "@kbn/ml-plugin", + "@kbn/share-plugin", // add references to other TypeScript projects the plugin depends on // requiredPlugins from ./kibana.json From 9b84061d3b41cd218d4c15c6fb04c6f36d5e700a Mon Sep 17 00:00:00 2001 From: Rickyanto Ang Date: Mon, 10 Apr 2023 10:40:12 -0700 Subject: [PATCH 004/105] [Cloud Posture] Center Framework Sources icons centered (#154604) ## Summary This ticket is part of Quick Wins ticket This PR fixes the issue with Center Framework Sources icons not being centered on findings and rule flyout Screen Shot 2023-04-06 at 1 42 13 PM --- .../pages/configurations/findings_flyout/findings_flyout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx index 9a611c1059ceb..b1b58a107a5e4 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx @@ -93,7 +93,7 @@ export const CisKubernetesIcons = ({ benchmarkId: BenchmarkId; benchmarkName: BenchmarkName; }) => ( - + From a6642d0efe331fd51fa718f4578793d25202e667 Mon Sep 17 00:00:00 2001 From: Jon Date: Mon, 10 Apr 2023 12:49:34 -0500 Subject: [PATCH 005/105] Upgrade chromedriver to 112.0.0 (#154652) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b4a7a8ac9632c..e277bc93b5d36 100644 --- a/package.json +++ b/package.json @@ -1313,7 +1313,7 @@ "backport": "^8.9.7", "callsites": "^3.1.0", "chance": "1.0.18", - "chromedriver": "^110.0.0", + "chromedriver": "^112.0.0", "clean-webpack-plugin": "^3.0.0", "compression-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^6.0.2", diff --git a/yarn.lock b/yarn.lock index 4fe380b77943b..29b3711e877d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11866,10 +11866,10 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^110.0.0: - version "110.0.0" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-110.0.0.tgz#d00a1a2976592d933faa8e9839e97692922834a4" - integrity sha512-Le6q8xrA/3fAt+g8qiN0YjsYxINIhQMC6wj9X3W5L77uN4NspEzklDrqYNwBcEVn7PcAEJ73nLlS7mTyZRspHA== +chromedriver@^112.0.0: + version "112.0.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-112.0.0.tgz#34c86f6cfc8f5e208100088dbb9563439243f8b2" + integrity sha512-fEw1tI05dmK1KK8MGh99LAppP7zCOPEXUxxbYX5wpIBCCmKasyrwZhk/qsdnxJYKd/h0TfiHvGEj7ReDQXW1AA== dependencies: "@testim/chrome-version" "^1.1.3" axios "^1.2.1" From da47a1b7a53d8a1c6a97493fd2828d0e5fd16452 Mon Sep 17 00:00:00 2001 From: Rickyanto Ang Date: Mon, 10 Apr 2023 12:02:01 -0700 Subject: [PATCH 006/105] [Cloud Security] Added new Benchmark Error message component (#154636) ## Summary This ticket is part of Quick Wins ticket. This PR updates the Error message that user receive when the app can't retrieve Benchmark data due to issue with the API Screen Shot 2023-04-09 at 12 39 31 AM --- .../pages/benchmarks/benchmarks.test.tsx | 3 +- .../pages/benchmarks/benchmarks_table.tsx | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.test.tsx index 0d9a4eff3f958..2a123f6cfa201 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.test.tsx @@ -17,6 +17,7 @@ import { useCspBenchmarkIntegrations } from './use_csp_benchmark_integrations'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; import { useSubscriptionStatus } from '../../common/hooks/use_subscription_status'; import { useCspIntegrationLink } from '../../common/navigation/use_csp_integration_link'; +import { ERROR_STATE_TEST_SUBJECT } from './benchmarks_table'; jest.mock('./use_csp_benchmark_integrations'); jest.mock('../../common/api/use_setup_status_api'); @@ -80,7 +81,7 @@ describe('', () => { const error = new Error('message'); renderBenchmarks(createReactQueryResponse({ status: 'error', error })); - expect(screen.getByText(error.message)).toBeInTheDocument(); + expect(screen.getByTestId(ERROR_STATE_TEST_SUBJECT)).toBeInTheDocument(); }); it('renders the benchmarks table', () => { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.tsx index 35515ea1cca52..e37a9d6fcbe9c 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks_table.tsx @@ -14,18 +14,24 @@ import { EuiLink, EuiToolTip, EuiAvatar, + EuiEmptyPrompt, } from '@elastic/eui'; import React from 'react'; import { generatePath } from 'react-router-dom'; import { pagePathGetters } from '@kbn/fleet-plugin/public'; import { i18n } from '@kbn/i18n'; import type { PackagePolicy } from '@kbn/fleet-plugin/common'; +import { FormattedMessage } from '@kbn/i18n-react'; import { TimestampTableCell } from '../../components/timestamp_table_cell'; import type { Benchmark } from '../../../common/types'; import { useKibana } from '../../common/hooks/use_kibana'; import { benchmarksNavigation } from '../../common/navigation/constants'; import * as TEST_SUBJ from './test_subjects'; import { getEnabledCspIntegrationDetails } from '../../common/utils/get_enabled_csp_integration_details'; +import { isCommonError } from '../../components/cloud_posture_page'; +import { FullSizeCenteredPage } from '../../components/full_size_centered_page'; + +export const ERROR_STATE_TEST_SUBJECT = 'benchmark_page_error'; interface BenchmarksTableProps extends Pick, 'loading' | 'error' | 'noItemsMessage' | 'sorting'>, @@ -67,6 +73,39 @@ const IntegrationButtonLink = ({ ); }; +const ErrorMessageComponent = (error: { error: unknown }) => ( + + + + + } + body={ + isCommonError(error) ? ( +

+ +

+ ) : undefined + } + /> +
+); + const BENCHMARKS_TABLE_COLUMNS: Array> = [ { field: 'package_policy.name', @@ -193,6 +232,10 @@ export const BenchmarksTable = ({ setQuery({ page: { ...page, index: page.index + 1 }, sort }); }; + if (error) { + return ; + } + return ( Date: Mon, 10 Apr 2023 15:11:12 -0400 Subject: [PATCH 007/105] [Fleet] Loosen validation for experimental data stream features (#154661) ## Summary Closes https://github.com/elastic/kibana/issues/154585 Allow `PUT`ing partial request bodies for experimental features, which ensures we don't break package policies from prior versions of Kibana where not all experimental features were available. Added an FTR test to catch the error, which is an API schema validation one. Verified the test fails before the schema changes are made. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../plugins/fleet/common/types/models/epm.ts | 4 ++-- .../server/services/epm/packages/update.ts | 2 +- ...experimental_datastream_features_helper.ts | 9 ++++++-- .../server/types/models/package_policy.ts | 8 +++---- .../apis/epm/data_stream.ts | 23 ++++++++++++++++++- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 96977bc351b12..41974a5fa04d5 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -471,7 +471,7 @@ export type ExperimentalIndexingFeature = export interface ExperimentalDataStreamFeature { data_stream: string; - features: Record; + features: Partial>; } export interface Installation extends SavedObjectAttributes { @@ -493,7 +493,7 @@ export interface Installation extends SavedObjectAttributes { // TypeScript doesn't like using the `ExperimentalDataStreamFeature` type defined above here experimental_data_stream_features?: Array<{ data_stream: string; - features: Record; + features: Partial>; }>; } diff --git a/x-pack/plugins/fleet/server/services/epm/packages/update.ts b/x-pack/plugins/fleet/server/services/epm/packages/update.ts index 3f3633708b94c..3072dfed86636 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/update.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/update.ts @@ -56,7 +56,7 @@ export async function updateDatastreamExperimentalFeatures( pkgName: string, dataStreamFeatureMapping: Array<{ data_stream: string; - features: Record; + features: Partial>; }> ) { auditLoggingService.writeCustomSoAuditLog({ diff --git a/x-pack/plugins/fleet/server/services/experimental_datastream_features_helper.ts b/x-pack/plugins/fleet/server/services/experimental_datastream_features_helper.ts index 029215e282383..a33f936a613f4 100644 --- a/x-pack/plugins/fleet/server/services/experimental_datastream_features_helper.ts +++ b/x-pack/plugins/fleet/server/services/experimental_datastream_features_helper.ts @@ -46,7 +46,11 @@ export const applyDocOnlyValueToMapping = ( 'scaled_float', 'unsigned_long', ]; - if (isDocValueOnlyNumericChanged && numericTypes.includes(mapping.type ?? '')) { + if ( + isDocValueOnlyNumericChanged && + numericTypes.includes(mapping.type ?? '') && + featureMap.features.doc_value_only_numeric !== undefined + ) { updateMapping(mapping, featureMap.features.doc_value_only_numeric); } @@ -54,7 +58,8 @@ export const applyDocOnlyValueToMapping = ( if ( isDocValueOnlyOtherChanged && name !== '@timestamp' && - otherSupportedTypes.includes(mapping.type ?? '') + otherSupportedTypes.includes(mapping.type ?? '') && + featureMap.features.doc_value_only_other !== undefined ) { updateMapping(mapping, featureMap.features.doc_value_only_other); } diff --git a/x-pack/plugins/fleet/server/types/models/package_policy.ts b/x-pack/plugins/fleet/server/types/models/package_policy.ts index e1851693d3367..32199c2e8be48 100644 --- a/x-pack/plugins/fleet/server/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/package_policy.ts @@ -83,10 +83,10 @@ const ExperimentalDataStreamFeatures = schema.arrayOf( schema.object({ data_stream: schema.string(), features: schema.object({ - synthetic_source: schema.boolean(), - tsdb: schema.boolean(), - doc_value_only_numeric: schema.boolean(), - doc_value_only_other: schema.boolean(), + synthetic_source: schema.maybe(schema.boolean({ defaultValue: false })), + tsdb: schema.maybe(schema.boolean({ defaultValue: false })), + doc_value_only_numeric: schema.maybe(schema.boolean({ defaultValue: false })), + doc_value_only_other: schema.maybe(schema.boolean({ defaultValue: false })), }), }) ); diff --git a/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts b/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts index 2e5197f4543c8..80a5a2f5738fc 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts @@ -228,7 +228,7 @@ export default function (providerContext: FtrProviderContext) { return resLogsDatastream.body.data_streams[0].indices.length; } - it('should rollover datstream after enabling a expiremental datastream feature that need a rollover', async () => { + it('should rollover datstream after enabling a experimental datastream feature that need a rollover', async () => { expect(await getLogsDefaultBackingIndicesLength()).to.be(1); await supertest @@ -256,6 +256,27 @@ export default function (providerContext: FtrProviderContext) { // Datastream should have been rolled over expect(await getLogsDefaultBackingIndicesLength()).to.be(2); }); + + it('should allow updating a package policy with only a partial set of experimental datastream features', async () => { + await supertest + .put(`/api/fleet/package_policies/${packagePolicyId}`) + .set('kbn-xsrf', 'xxxx') + .send({ + ...packagePolicyData, + package: { + ...packagePolicyData.package, + experimental_data_stream_features: [ + { + data_stream: logsTemplateName, + features: { + synthetic_source: true, + }, + }, + ], + }, + }) + .expect(200); + }); }); }); } From 813c2a3c64d3eb3309c6f6a3de6d1d3b53072598 Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Mon, 10 Apr 2023 14:18:38 -0500 Subject: [PATCH 008/105] [Security Solution] skip failing related_integrations e2e test (#154662) --- .../cypress/e2e/detection_rules/related_integrations.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/related_integrations.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/related_integrations.cy.ts index 663317f334751..5b316b4136708 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/related_integrations.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/related_integrations.cy.ts @@ -111,7 +111,7 @@ describe('Related integrations', () => { }); }); - context( + context.skip( 'installed integrations: Amazon CloudFront, AWS CloudTrail, System, enabled integrations: Amazon CloudFront, Aws Cloudfront, System', () => { const rule = { From ee424cb3add25e755798dae6ddab71bb6e8e041d Mon Sep 17 00:00:00 2001 From: Sean Story Date: Mon, 10 Apr 2023 16:12:40 -0500 Subject: [PATCH 009/105] Update field mappings for ELSER pipelines (#154291) ## Summary When creating an ML inference pipeline that uses the new ELSER model, we need to be able to specify which fields to apply it to, and where the resulting values should go. These fields can then determine what mapping changes need to be made to the underlying index (setting `rank_features` fields). This PR adds `field_mappings` as a param to our kibana endpoint for creating these ML Inference pipelines, and based on that parameter, attempts to update mappings. A sample request might be: ``` curl -XPOST -u elastic:changeme "http://localhost:5601/mob/internal/enterprise_search/indices/search-test/ml_inference/pipeline_processors" \ -H 'kbn-xsrf: kibana' \ -H 'Content-Type: application/json' \ -d '{ "field_mappings": { "input": "output" }, "pipeline_definition": { "description" : "text", "processors": [] }, "pipeline_name": "test" }' | jq ``` And sample output might be: ``` { "created": "ml-inference-test", "mapping_updated": true } ``` OR ``` { "statusCode": 409, "error": "Conflict", "message": "One or more target fields for this pipeline already exist with a type that is incompatible with the specified model. Ensure that each target field is unique and not already in use.", "attributes": { "error_code": "mapping_update_failed" } } ``` ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../common/types/error_codes.ts | 3 +- .../common/types/pipelines.ts | 13 ++- .../create_ml_inference_pipeline.ts | 25 +++-- .../update_ml_inference_mappings.test.ts | 90 +++++++++++++++++ .../update_ml_inference_mappings.ts | 99 +++++++++++++++++++ .../routes/enterprise_search/indices.test.ts | 35 ++++--- .../routes/enterprise_search/indices.ts | 32 ++++-- .../server/utils/identify_exceptions.ts | 3 + .../plugins/enterprise_search/tsconfig.json | 1 + 9 files changed, 268 insertions(+), 33 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.test.ts create mode 100644 x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.ts diff --git a/x-pack/plugins/enterprise_search/common/types/error_codes.ts b/x-pack/plugins/enterprise_search/common/types/error_codes.ts index f250aa2dd9dd3..0ed9a2e1fad99 100644 --- a/x-pack/plugins/enterprise_search/common/types/error_codes.ts +++ b/x-pack/plugins/enterprise_search/common/types/error_codes.ts @@ -11,8 +11,10 @@ export enum ErrorCode { CONNECTOR_DOCUMENT_ALREADY_EXISTS = 'connector_document_already_exists', CRAWLER_ALREADY_EXISTS = 'crawler_already_exists', DOCUMENT_NOT_FOUND = 'document_not_found', + ENGINE_NOT_FOUND = 'engine_not_found', INDEX_ALREADY_EXISTS = 'index_already_exists', INDEX_NOT_FOUND = 'index_not_found', + MAPPING_UPDATE_FAILED = 'mapping_update_failed', PARAMETER_CONFLICT = 'parameter_conflict', PIPELINE_ALREADY_EXISTS = 'pipeline_already_exists', PIPELINE_IS_IN_USE = 'pipeline_is_in_use', @@ -20,5 +22,4 @@ export enum ErrorCode { RESOURCE_NOT_FOUND = 'resource_not_found', UNAUTHORIZED = 'unauthorized', UNCAUGHT_EXCEPTION = 'uncaught_exception', - ENGINE_NOT_FOUND = 'engine_not_found', } diff --git a/x-pack/plugins/enterprise_search/common/types/pipelines.ts b/x-pack/plugins/enterprise_search/common/types/pipelines.ts index a44c8e532e4ed..3e652d97c6f4f 100644 --- a/x-pack/plugins/enterprise_search/common/types/pipelines.ts +++ b/x-pack/plugins/enterprise_search/common/types/pipelines.ts @@ -43,9 +43,16 @@ export interface MlInferenceError { timestamp: string | undefined; // Date string } -export interface CreateMlInferencePipelineResponse { - addedToParentPipeline?: boolean; - created?: boolean; +export interface PreparePipelineAndIndexForMlInferenceResult { + added_to_parent_pipeline?: boolean; + created_pipeline?: boolean; + pipeline_id: string; + + mapping_updated: boolean; +} + +export interface CreatePipelineResult { + created: boolean; id: string; } diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.ts index 6a2354cde1ac1..eb8cdecb64a02 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.ts @@ -8,38 +8,43 @@ import { IngestGetPipelineResponse, IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; import { ElasticsearchClient } from '@kbn/core/server'; -import { formatPipelineName } from '../../../../../../common/ml_inference_pipeline'; +import { FieldMapping, formatPipelineName } from '../../../../../../common/ml_inference_pipeline'; import { ErrorCode } from '../../../../../../common/types/error_codes'; import type { - CreateMlInferencePipelineResponse, + PreparePipelineAndIndexForMlInferenceResult, InferencePipelineInferenceConfig, + CreatePipelineResult, } from '../../../../../../common/types/pipelines'; import { addSubPipelineToIndexSpecificMlPipeline } from '../../../../../utils/create_ml_inference_pipeline'; import { getPrefixedInferencePipelineProcessorName } from '../../../../../utils/ml_inference_pipeline_utils'; import { formatMlPipelineBody } from '../../../../pipelines/create_pipeline_definitions'; +import { updateMlInferenceMappings } from '../update_ml_inference_mappings'; /** * Creates a Machine Learning Inference pipeline with the given settings, if it doesn't exist yet, * then references it in the "parent" ML Inference pipeline that is associated with the index. + * Finally, updates the index's mappings to accommodate the specified outputs of the inference model (if able) * @param indexName name of the index this pipeline corresponds to. * @param pipelineName pipeline name set by the user. * @param pipelineDefinition * @param modelId model ID selected by the user. * @param sourceField The document field that model will read. * @param destinationField The document field that the model will write to. + * @param fieldMappings The array of objects representing the source field (text) names and target fields (ML output) names * @param inferenceConfig The configuration for the model. * @param esClient the Elasticsearch Client to use when retrieving pipeline and model details. */ -export const createAndReferenceMlInferencePipeline = async ( +export const preparePipelineAndIndexForMlInference = async ( indexName: string, pipelineName: string, pipelineDefinition: IngestPipeline | undefined, modelId: string | undefined, sourceField: string | undefined, destinationField: string | null | undefined, + fieldMappings: FieldMapping[] | undefined, inferenceConfig: InferencePipelineInferenceConfig | undefined, esClient: ElasticsearchClient -): Promise => { +): Promise => { const createPipelineResult = await createMlInferencePipeline( pipelineName, pipelineDefinition, @@ -56,9 +61,15 @@ export const createAndReferenceMlInferencePipeline = async ( esClient ); + const mappingResponse = fieldMappings + ? (await updateMlInferenceMappings(indexName, fieldMappings, esClient)).acknowledged + : false; + return { - ...createPipelineResult, - addedToParentPipeline: addSubPipelineResult.addedToParentPipeline, + added_to_parent_pipeline: addSubPipelineResult.addedToParentPipeline, + created_pipeline: createPipelineResult.created, + mapping_updated: mappingResponse, + pipeline_id: createPipelineResult.id, }; }; @@ -80,7 +91,7 @@ export const createMlInferencePipeline = async ( destinationField: string | null | undefined, inferenceConfig: InferencePipelineInferenceConfig | undefined, esClient: ElasticsearchClient -): Promise => { +): Promise => { const inferencePipelineGeneratedName = getPrefixedInferencePipelineProcessorName(pipelineName); // Check that a pipeline with the same name doesn't already exist diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.test.ts new file mode 100644 index 0000000000000..27425274608e1 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.test.ts @@ -0,0 +1,90 @@ +/* + * 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 { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; + +import { ErrorCode } from '../../../../../common/types/error_codes'; + +import { updateMlInferenceMappings } from './update_ml_inference_mappings'; + +describe('updateMlInferenceMappings', () => { + const indexName = 'my-index'; + + const mockClient = elasticsearchServiceMock.createScopedClusterClient(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + const expectedMapping = { + ml: { + properties: { + inference: { + properties: { + input_one_expanded: { + properties: { + predicted_value: { + type: 'rank_features', + }, + model_id: { + type: 'keyword', + }, + }, + }, + input_two_expanded: { + properties: { + predicted_value: { + type: 'rank_features', + }, + model_id: { + type: 'keyword', + }, + }, + }, + }, + }, + }, + }, + }; + + const fieldMappings = [ + { + sourceField: 'input_one', + targetField: 'ml.inference.input_one_expanded', + }, + { + sourceField: 'input_two', + targetField: 'ml.inference.input_two_expanded', + }, + ]; + + it('should update mappings for default output', async () => { + await updateMlInferenceMappings(indexName, fieldMappings, mockClient.asCurrentUser); + expect(mockClient.asCurrentUser.indices.putMapping).toHaveBeenLastCalledWith({ + index: indexName, + properties: expectedMapping, + }); + }); + + it('should raise an error if the update fails', async () => { + mockClient.asCurrentUser.indices.putMapping.mockImplementation(() => + Promise.reject({ + meta: { + body: { + error: { + type: 'illegal_argument_exception', + }, + }, + statusCode: 400, + }, + }) + ); + await expect( + updateMlInferenceMappings(indexName, fieldMappings, mockClient.asCurrentUser) + ).rejects.toThrowError(ErrorCode.MAPPING_UPDATE_FAILED); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.ts new file mode 100644 index 0000000000000..0108187efd120 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/update_ml_inference_mappings.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; + +import { FieldMapping } from '../../../../../common/ml_inference_pipeline'; + +import { ErrorCode } from '../../../../../common/types/error_codes'; + +import { isIllegalArgumentException } from '../../../../utils/identify_exceptions'; + +/** + * Creates Elasticsearch field mappings so that the outputs of ML Inference pipelines are not indexed as `float` fields + * @param indexName - the index whose mapping will be updated + * @param fieldMappings - the array of objects representing the source field (text) names and target fields (ML output) names + * @param esClient + */ +export const updateMlInferenceMappings = async ( + indexName: string, + fieldMappings: FieldMapping[], + esClient: ElasticsearchClient +) => { + const sourceFields = fieldMappings.map(({ sourceField }) => sourceField); + + const nonDefaultTargetFields = fieldMappings + .filter( + (fieldMapping) => + fieldMapping.targetField !== `ml.inference.${fieldMapping.sourceField}_expanded` + ) + .map((fieldMapping) => fieldMapping.targetField); + + // Today, we only update mappings for text_expansion fields. + const mapping = generateTextExpansionMappingProperties(sourceFields, nonDefaultTargetFields); + try { + return await esClient.indices.putMapping({ + index: indexName, + properties: mapping, + }); + } catch (e) { + if (isIllegalArgumentException(e)) { + throw new Error(ErrorCode.MAPPING_UPDATE_FAILED); + } else { + throw e; + } + } +}; + +const generateTextExpansionMappingProperties = (sourceFields: string[], targetFields: string[]) => { + return { + ml: { + properties: { + inference: { + properties: { + ...formDefaultElserMappingProps(sourceFields), + }, + }, + }, + }, + ...targetFields.reduce( + (previous, targetField) => ({ + ...previous, + [targetField]: { + properties: { + model_id: { + type: 'keyword', + }, + predicted_value: { + type: 'rank_features', + }, + }, + }, + }), + {} + ), + }; +}; + +const formDefaultElserMappingProps = (sourceFields: string[]) => { + return sourceFields.reduce( + (previous, sourceField) => ({ + ...previous, + [`${sourceField}_expanded`]: { + properties: { + model_id: { + type: 'keyword', + }, + predicted_value: { + type: 'rank_features', + }, + }, + }, + }), + {} + ); +}; diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts index be3c1be297df8..92977df6021d6 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts @@ -26,7 +26,7 @@ jest.mock( jest.mock( '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline', () => ({ - createAndReferenceMlInferencePipeline: jest.fn(), + preparePipelineAndIndexForMlInference: jest.fn(), }) ); jest.mock( @@ -61,7 +61,7 @@ import { indexOrAliasExists } from '../../lib/indices/exists_index'; import { getMlInferenceErrors } from '../../lib/indices/pipelines/ml_inference/get_ml_inference_errors'; import { fetchMlInferencePipelineHistory } from '../../lib/indices/pipelines/ml_inference/get_ml_inference_pipeline_history'; import { attachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline'; -import { createAndReferenceMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline'; +import { preparePipelineAndIndexForMlInference } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline'; import { deleteMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline'; import { detachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline'; import { fetchMlInferencePipelineProcessors } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors'; @@ -306,11 +306,12 @@ describe('Enterprise Search Managed Indices', () => { }); it('creates an ML inference pipeline from model and source_field', async () => { - (createAndReferenceMlInferencePipeline as jest.Mock).mockImplementationOnce(() => { + (preparePipelineAndIndexForMlInference as jest.Mock).mockImplementationOnce(() => { return Promise.resolve({ - id: 'ml-inference-my-pipeline-name', - created: true, - addedToParentPipeline: true, + added_to_parent_pipeline: true, + created_pipeline: true, + mapping_updated: false, + pipeline_id: 'ml-inference-my-pipeline-name', }); }); @@ -319,7 +320,7 @@ describe('Enterprise Search Managed Indices', () => { body: mockRequestBody, }); - expect(createAndReferenceMlInferencePipeline).toHaveBeenCalledWith( + expect(preparePipelineAndIndexForMlInference).toHaveBeenCalledWith( 'my-index-name', mockRequestBody.pipeline_name, undefined, @@ -327,37 +328,41 @@ describe('Enterprise Search Managed Indices', () => { mockRequestBody.source_field, mockRequestBody.destination_field, undefined, + undefined, mockClient.asCurrentUser ); expect(mockRouter.response.ok).toHaveBeenCalledWith({ body: { created: 'ml-inference-my-pipeline-name', + mapping_updated: false, }, headers: { 'content-type': 'application/json' }, }); }); it('creates an ML inference pipeline from pipeline definition', async () => { - (createAndReferenceMlInferencePipeline as jest.Mock).mockImplementationOnce(() => { + (preparePipelineAndIndexForMlInference as jest.Mock).mockImplementationOnce(() => { return Promise.resolve({ - id: 'ml-inference-my-pipeline-name', - created: true, - addedToParentPipeline: true, + added_to_parent_pipeline: true, + created_pipeline: true, + mapping_updated: true, + pipeline_id: 'ml-inference-my-pipeline-name', }); }); await mockRouter.callRoute({ params: { indexName: 'my-index-name' }, body: { - pipeline_name: 'my-pipeline-name', + field_mappings: [], pipeline_definition: { processors: [], }, + pipeline_name: 'my-pipeline-name', }, }); - expect(createAndReferenceMlInferencePipeline).toHaveBeenCalledWith( + expect(preparePipelineAndIndexForMlInference).toHaveBeenCalledWith( 'my-index-name', mockRequestBody.pipeline_name, { @@ -366,6 +371,7 @@ describe('Enterprise Search Managed Indices', () => { undefined, undefined, undefined, + [], undefined, mockClient.asCurrentUser ); @@ -373,13 +379,14 @@ describe('Enterprise Search Managed Indices', () => { expect(mockRouter.response.ok).toHaveBeenCalledWith({ body: { created: 'ml-inference-my-pipeline-name', + mapping_updated: true, }, headers: { 'content-type': 'application/json' }, }); }); it('responds with 409 CONFLICT if the pipeline already exists', async () => { - (createAndReferenceMlInferencePipeline as jest.Mock).mockImplementationOnce(() => { + (preparePipelineAndIndexForMlInference as jest.Mock).mockImplementationOnce(() => { return Promise.reject(new Error(ErrorCode.PIPELINE_ALREADY_EXISTS)); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts index 75cb055b34aac..cad33e310a832 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts @@ -33,7 +33,7 @@ import { generateApiKey } from '../../lib/indices/generate_api_key'; import { getMlInferenceErrors } from '../../lib/indices/pipelines/ml_inference/get_ml_inference_errors'; import { fetchMlInferencePipelineHistory } from '../../lib/indices/pipelines/ml_inference/get_ml_inference_pipeline_history'; import { attachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline'; -import { createAndReferenceMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline'; +import { preparePipelineAndIndexForMlInference } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline'; import { deleteMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline'; import { detachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline'; import { fetchMlInferencePipelineProcessors } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors'; @@ -388,6 +388,11 @@ export function registerIndexRoutes({ }), body: schema.object({ destination_field: schema.maybe(schema.nullable(schema.string())), + field_mappings: schema.maybe( + schema.arrayOf( + schema.object({ sourceField: schema.string(), targetField: schema.string() }) + ) + ), inference_config: schema.maybe( schema.object({ zero_shot_classification: schema.maybe( @@ -421,30 +426,31 @@ export function registerIndexRoutes({ source_field: sourceField, destination_field: destinationField, inference_config: inferenceConfig, + field_mappings: fieldMappings, } = request.body; // additional validations - if (pipelineDefinition && (sourceField || destinationField || modelId)) { + if ((pipelineDefinition || fieldMappings) && (sourceField || destinationField || modelId)) { return createError({ errorCode: ErrorCode.PARAMETER_CONFLICT, message: i18n.translate( 'xpack.enterpriseSearch.server.routes.createMlInferencePipeline.ParameterConflictError', { defaultMessage: - 'pipeline_definition should only be provided if source_field and destination_field and model_id are not provided', + 'pipeline_definition and field_mappings should only be provided if source_field and destination_field and model_id are not provided', } ), response, statusCode: 400, }); - } else if (!(pipelineDefinition || (sourceField && modelId))) { + } else if (!((pipelineDefinition && fieldMappings) || (sourceField && modelId))) { return createError({ errorCode: ErrorCode.PARAMETER_CONFLICT, message: i18n.translate( 'xpack.enterpriseSearch.server.routes.createMlInferencePipeline.ParameterMissingError', { defaultMessage: - 'either pipeline_definition or source_field AND model_id must be provided', + 'either pipeline_definition AND fieldMappings or source_field AND model_id must be provided', } ), response, @@ -454,19 +460,21 @@ export function registerIndexRoutes({ try { // Create the sub-pipeline for inference - const createPipelineResult = await createAndReferenceMlInferencePipeline( + const createPipelineResult = await preparePipelineAndIndexForMlInference( indexName, pipelineName, pipelineDefinition, modelId, sourceField, destinationField, + fieldMappings, inferenceConfig, client.asCurrentUser ); return response.ok({ body: { - created: createPipelineResult?.id, + created: createPipelineResult.pipeline_id, + mapping_updated: createPipelineResult.mapping_updated, }, headers: { 'content-type': 'application/json' }, }); @@ -484,7 +492,15 @@ export function registerIndexRoutes({ statusCode: 409, }); } - + if (fieldMappings && (error as Error).message === ErrorCode.MAPPING_UPDATE_FAILED) { + return createError({ + errorCode: (error as Error).message as ErrorCode, + message: + 'One or more target fields for this pipeline already exist with a type that is incompatible with the specified model. Ensure that each target field is unique and not already in use.', + response, + statusCode: 409, + }); + } throw error; } }) diff --git a/x-pack/plugins/enterprise_search/server/utils/identify_exceptions.ts b/x-pack/plugins/enterprise_search/server/utils/identify_exceptions.ts index 5874659c690f8..04b8a089fa009 100644 --- a/x-pack/plugins/enterprise_search/server/utils/identify_exceptions.ts +++ b/x-pack/plugins/enterprise_search/server/utils/identify_exceptions.ts @@ -36,3 +36,6 @@ export const isPipelineIsInUseException = (error: Error) => export const isNotFoundException = (error: ElasticsearchResponseError) => error.meta?.statusCode === 404; + +export const isIllegalArgumentException = (error: ElasticsearchResponseError) => + error.meta?.body?.error?.type === 'illegal_argument_exception'; diff --git a/x-pack/plugins/enterprise_search/tsconfig.json b/x-pack/plugins/enterprise_search/tsconfig.json index 8d83fd25fdf84..af660c1169d5a 100644 --- a/x-pack/plugins/enterprise_search/tsconfig.json +++ b/x-pack/plugins/enterprise_search/tsconfig.json @@ -57,5 +57,6 @@ "@kbn/expressions-plugin", "@kbn/react-field", "@kbn/field-types", + "@kbn/core-elasticsearch-server-mocks", ] } From 8770a1ceed41959fa1792b360c2295add288a3e4 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 10 Apr 2023 14:52:43 -0700 Subject: [PATCH 010/105] Update search session saved object mappings (#154401) ## Summary Part of https://github.com/elastic/kibana/pull/153070. Cleans up the saved object mappings for search session saved objects. Removes the non-searchable/sortable properties from the `mappings` property and introduces a `schema` property for validation. --- .../group2/check_registered_types.test.ts | 2 +- .../search/saved_objects/search_session.ts | 56 +++++++++---------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts index d876484aa16af..53176bd7b9860 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts @@ -126,7 +126,7 @@ describe('checking migration metadata changes on all registered SO types', () => "rules-settings": "9854495c3b54b16a6625fb250c35e5504da72266", "sample-data-telemetry": "c38daf1a49ed24f2a4fb091e6e1e833fccf19935", "search": "ed3a9b1681b57d69560909d51933fdf17576ea68", - "search-session": "58a44d14ec991739166b2ec28d718001ab0f4b28", + "search-session": "fae0dfc63274d6a3b90ca583802c48cab8760637", "search-telemetry": "1bbaf2db531b97fa04399440fa52d46e86d54dd8", "security-rule": "1ff82dfb2298c3caf6888fc3ef15c6bf7a628877", "security-solution-signals-migration": "c2db409c1857d330beb3d6fd188fa186f920302c", diff --git a/src/plugins/data/server/search/saved_objects/search_session.ts b/src/plugins/data/server/search/saved_objects/search_session.ts index ef0f960c84e8c..598229075df42 100644 --- a/src/plugins/data/server/search/saved_objects/search_session.ts +++ b/src/plugins/data/server/search/saved_objects/search_session.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { schema } from '@kbn/config-schema'; import { SavedObjectsType } from '@kbn/core/server'; import { SEARCH_SESSION_TYPE } from '../../../common'; import { searchSessionSavedObjectMigrations } from './search_session_migration'; @@ -15,37 +16,14 @@ export const searchSessionSavedObjectType: SavedObjectsType = { namespaceType: 'single', hidden: true, mappings: { + dynamic: false, properties: { sessionId: { type: 'keyword', }, - name: { - type: 'keyword', - }, created: { type: 'date', }, - expires: { - type: 'date', - }, - appId: { - type: 'keyword', - }, - locatorId: { - type: 'keyword', - }, - initialState: { - dynamic: false, - properties: {}, - }, - restoreState: { - dynamic: false, - properties: {}, - }, - idMapping: { - dynamic: false, - properties: {}, - }, realmType: { type: 'keyword', }, @@ -55,14 +33,32 @@ export const searchSessionSavedObjectType: SavedObjectsType = { username: { type: 'keyword', }, - version: { - type: 'keyword', - }, - isCanceled: { - type: 'boolean', - }, }, }, + schemas: { + '8.8.0': schema.object({ + sessionId: schema.string(), + name: schema.maybe(schema.string()), + created: schema.string(), + expires: schema.string(), + appId: schema.maybe(schema.string()), + locatorId: schema.maybe(schema.string()), + initialState: schema.maybe(schema.object({}, { unknowns: 'allow' })), + restoreState: schema.maybe(schema.object({}, { unknowns: 'allow' })), + idMapping: schema.mapOf( + schema.string(), + schema.object({ + id: schema.string(), + strategy: schema.string(), + }) + ), + realmType: schema.maybe(schema.string()), + realmName: schema.maybe(schema.string()), + username: schema.maybe(schema.string()), + version: schema.string(), + isCanceled: schema.maybe(schema.boolean()), + }), + }, migrations: searchSessionSavedObjectMigrations, excludeOnUpgrade: async () => { return { From 31b50a3906270b7e52a0b74fe236a22cc615e7bc Mon Sep 17 00:00:00 2001 From: Cee Chen <549407+cee-chen@users.noreply.github.com> Date: Mon, 10 Apr 2023 15:06:26 -0700 Subject: [PATCH 011/105] Upgrade EUI to v77.0.0 (#154379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > ⚠️ Synthetic failures are not related to any EUI changes and are likely already failing on main. Please ignore the failing CI status when reviewing. ## [`77.0.0`](https://github.com/elastic/eui/tree/v77.0.0) **Bug fixes** - Fixed named `EuiBadge` colors to reflect custom theme overrides ([#6659](https://github.com/elastic/eui/pull/6659)) - Fixed user-defined SCSS variables failing to override variables defined in Amsterdam typography overrides. ([#6665](https://github.com/elastic/eui/pull/6665)) - Fixed bold `EuiCode` tokens to actually be bold ([#6666](https://github.com/elastic/eui/pull/6666)) **Breaking changes** - Success- and accent-colored `EuiBadge`s and `EuiButton`s have had their fill colors tinted slightly on light mode to be more readable ([#6659](https://github.com/elastic/eui/pull/6659)) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Jon --- package.json | 2 +- .../__snapshots__/server_status.test.tsx.snap | 6 +++--- src/dev/license_checker/config.ts | 2 +- .../customize_panel_action.tsx | 2 -- .../__snapshots__/index.test.tsx.snap | 2 +- .../pages/endpoint_hosts/view/index.test.tsx | 19 ------------------- .../__snapshots__/index.test.tsx.snap | 4 ++-- .../__snapshots__/tag_label.test.tsx.snap | 2 +- .../__snapshots__/field.test.tsx.snap | 2 +- .../__snapshots__/tlp_badge.test.tsx.snap | 4 ++-- .../services/ml/data_visualizer_table.ts | 1 + yarn.lock | 8 ++++---- 12 files changed, 17 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index e277bc93b5d36..7e4a88d72b98e 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@elastic/datemath": "5.0.3", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.6.0-canary.3", "@elastic/ems-client": "8.4.0", - "@elastic/eui": "76.4.0", + "@elastic/eui": "77.0.0", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "1.2.1", "@elastic/numeral": "^2.5.1", diff --git a/packages/core/apps/core-apps-browser-internal/src/status/components/__snapshots__/server_status.test.tsx.snap b/packages/core/apps/core-apps-browser-internal/src/status/components/__snapshots__/server_status.test.tsx.snap index 60d1bad95e3e1..fe17c420479eb 100644 --- a/packages/core/apps/core-apps-browser-internal/src/status/components/__snapshots__/server_status.test.tsx.snap +++ b/packages/core/apps/core-apps-browser-internal/src/status/components/__snapshots__/server_status.test.tsx.snap @@ -5,7 +5,7 @@ exports[`ServerStatus renders correctly for green state 2`] = ` aria-label="Green" class="euiBadge emotion-euiBadge" data-test-subj="serverStatusTitleBadge" - style="background-color: rgb(109, 204, 177); color: rgb(0, 0, 0);" + style="background-color: rgb(77, 210, 202); color: rgb(0, 0, 0);" title="Green" > { size: 's', 'data-test-subj': 'customizePanel', - // @ts-ignore - TODO: Remove this once https://github.com/elastic/eui/pull/6645 lands in Kibana - focusTrapProps: { scrollLock: true }, } ); overlayTracker?.openOverlay(handle); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap index 89d876e5efa88..b6e9ea7a2ea0f 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap @@ -91,7 +91,7 @@ exports[`Event Details Overview Cards renders rows and spacers correctly 1`] = `