From b5517728444b0ebb23be125d5e5dc43ce866e97c Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Mon, 22 Nov 2021 10:53:54 -0500 Subject: [PATCH] [Enterprise Search] Error on version mismatches (#119101) --- .../common/__mocks__/initial_app_data.ts | 2 + .../common/is_version_mismatch/index.test.ts | 26 +++++++++ .../common/is_version_mismatch/index.ts | 15 +++++ .../enterprise_search/common/types/index.ts | 2 + .../applications/app_search/index.test.tsx | 7 +++ .../public/applications/app_search/index.tsx | 31 +++++++--- .../enterprise_search/index.test.tsx | 17 ++++++ .../applications/enterprise_search/index.tsx | 33 +++++++++-- .../shared/version_mismatch/index.ts | 9 +++ .../version_mismatch_error.test.tsx | 23 ++++++++ .../version_mismatch_error.tsx | 57 +++++++++++++++++++ .../version_mismatch_page.test.tsx | 26 +++++++++ .../version_mismatch_page.tsx | 23 ++++++++ .../workplace_search/index.test.tsx | 10 ++++ .../applications/workplace_search/index.tsx | 26 ++++++--- .../lib/enterprise_search_config_api.test.ts | 4 +- .../lib/enterprise_search_config_api.ts | 5 +- 17 files changed, 292 insertions(+), 24 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/common/is_version_mismatch/index.test.ts create mode 100644 x-pack/plugins/enterprise_search/common/is_version_mismatch/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx diff --git a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts index aa3020a9577f9..dd6dd58d02f70 100644 --- a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts +++ b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts @@ -6,6 +6,8 @@ */ export const DEFAULT_INITIAL_APP_DATA = { + kibanaVersion: '7.16.0', + enterpriseSearchVersion: '7.16.0', readOnlyMode: false, searchOAuth: { clientId: 'someUID', diff --git a/x-pack/plugins/enterprise_search/common/is_version_mismatch/index.test.ts b/x-pack/plugins/enterprise_search/common/is_version_mismatch/index.test.ts new file mode 100644 index 0000000000000..4cd7ceef0b758 --- /dev/null +++ b/x-pack/plugins/enterprise_search/common/is_version_mismatch/index.test.ts @@ -0,0 +1,26 @@ +/* + * 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 { isVersionMismatch } from './index'; + +describe('isVersionMismatch', () => { + it('no mismatch if major and minor are the same', () => { + expect(isVersionMismatch('8.0.0', '8.0.1')).toBe(false); + }); + + it('mismatch if kibana minor is different than enterprise search minor', () => { + expect(isVersionMismatch('8.0.0', '8.1.0')).toBe(true); + }); + + it('mismatch if major is different', () => { + expect(isVersionMismatch('7.0.0', '8.0.0')).toBe(true); + }); + + it('no mismatch if versions are not available to analyze', () => { + expect(isVersionMismatch()).toBe(false); + }); +}); diff --git a/x-pack/plugins/enterprise_search/common/is_version_mismatch/index.ts b/x-pack/plugins/enterprise_search/common/is_version_mismatch/index.ts new file mode 100644 index 0000000000000..4147b17feefa5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/common/is_version_mismatch/index.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export const isVersionMismatch = (enterpriseSearchVersion?: string, kibanaVersion?: string) => { + // Don't consider it a mismatch unless we know for certain it is + if (!enterpriseSearchVersion || !kibanaVersion) return false; + const [enterpriseSearchMajor, enterpriseSearchMinor] = enterpriseSearchVersion.split('.'); + const [kibanaMajor, kibanaMinor] = kibanaVersion.split('.'); + if (enterpriseSearchMajor !== kibanaMajor || enterpriseSearchMinor !== kibanaMinor) return true; + return false; +}; diff --git a/x-pack/plugins/enterprise_search/common/types/index.ts b/x-pack/plugins/enterprise_search/common/types/index.ts index 8addf17f97476..57fe3f3807783 100644 --- a/x-pack/plugins/enterprise_search/common/types/index.ts +++ b/x-pack/plugins/enterprise_search/common/types/index.ts @@ -15,6 +15,8 @@ import { } from './workplace_search'; export interface InitialAppData { + enterpriseSearchVersion?: string; + kibanaVersion?: string; readOnlyMode?: boolean; searchOAuth?: SearchOAuth; configuredLimits?: ConfiguredLimits; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index 6647b4032e4bc..2f415840a6c4a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -16,6 +16,7 @@ import { Redirect } from 'react-router-dom'; import { shallow, ShallowWrapper } from 'enzyme'; +import { VersionMismatchPage } from '../shared/version_mismatch'; import { rerender } from '../test_helpers'; jest.mock('./app_logic', () => ({ AppLogic: jest.fn() })); @@ -41,6 +42,12 @@ describe('AppSearch', () => { expect(wrapper.find(SetupGuide)).toHaveLength(1); }); + it('renders VersionMismatchPage when there are mismatching versions', () => { + const wrapper = shallow(); + + expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); + }); + it('renders AppSearchUnconfigured when config.host is not set', () => { setMockValues({ config: { host: '' } }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 11f706bff028f..027a4dbee5ef6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -10,9 +10,11 @@ import { Route, Redirect, Switch } from 'react-router-dom'; import { useValues } from 'kea'; +import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; import { HttpLogic } from '../shared/http'; import { KibanaLogic } from '../shared/kibana'; +import { VersionMismatchPage } from '../shared/version_mismatch'; import { AppLogic } from './app_logic'; import { Credentials } from './components/credentials'; @@ -43,21 +45,32 @@ import { export const AppSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); const { errorConnecting } = useValues(HttpLogic); + const { enterpriseSearchVersion, kibanaVersion } = props; + const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); + + const showView = () => { + if (!config.host) { + return ; + } else if (incompatibleVersions) { + return ( + + ); + } else if (errorConnecting) { + return ; + } + + return )} />; + }; return ( - - {!config.host ? ( - - ) : errorConnecting ? ( - - ) : ( - )} /> - )} - + {showView()} ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx index fbb3e58f198a7..7b5c748b013e5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx @@ -11,6 +11,7 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { VersionMismatchPage } from '../shared/version_mismatch'; import { rerender } from '../test_helpers'; import { ErrorConnecting } from './components/error_connecting'; @@ -38,6 +39,7 @@ describe('EnterpriseSearch', () => { }); const wrapper = shallow(); + expect(wrapper.find(VersionMismatchPage)).toHaveLength(0); expect(wrapper.find(ErrorConnecting)).toHaveLength(1); expect(wrapper.find(ProductSelector)).toHaveLength(0); @@ -47,7 +49,22 @@ describe('EnterpriseSearch', () => { }); rerender(wrapper); + expect(wrapper.find(VersionMismatchPage)).toHaveLength(0); expect(wrapper.find(ErrorConnecting)).toHaveLength(0); expect(wrapper.find(ProductSelector)).toHaveLength(1); }); + + it('renders the version error message if versions mismatch and the host is configured', () => { + setMockValues({ + errorConnecting: false, + config: { host: 'localhost' }, + }); + const wrapper = shallow( + + ); + + expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); + expect(wrapper.find(ErrorConnecting)).toHaveLength(0); + expect(wrapper.find(ProductSelector)).toHaveLength(0); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx index 17387ae482325..81aa587e3a133 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx @@ -10,33 +10,54 @@ import { Route, Switch } from 'react-router-dom'; import { useValues } from 'kea'; +import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; import { HttpLogic } from '../shared/http'; import { KibanaLogic } from '../shared/kibana'; +import { VersionMismatchPage } from '../shared/version_mismatch'; import { ErrorConnecting } from './components/error_connecting'; import { ProductSelector } from './components/product_selector'; import { SetupGuide } from './components/setup_guide'; import { ROOT_PATH, SETUP_GUIDE_PATH } from './routes'; -export const EnterpriseSearch: React.FC = ({ access = {}, workplaceSearch }) => { +export const EnterpriseSearch: React.FC = ({ + access = {}, + workplaceSearch, + enterpriseSearchVersion, + kibanaVersion, +}) => { const { errorConnecting } = useValues(HttpLogic); const { config } = useValues(KibanaLogic); const showErrorConnecting = !!(config.host && errorConnecting); + const incompatibleVersions = !!( + config.host && isVersionMismatch(enterpriseSearchVersion, kibanaVersion) + ); const isWorkplaceSearchAdmin = !!workplaceSearch?.account?.isAdmin; + const showView = () => { + if (incompatibleVersions) { + return ( + + ); + } else if (showErrorConnecting) { + return ; + } + + return ; + }; + return ( - {showErrorConnecting ? ( - - ) : ( - - )} + {showView()} ); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts new file mode 100644 index 0000000000000..90d007d1d9411 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { VersionMismatchPage } from './version_mismatch_page'; +export { VersionMismatchError } from './version_mismatch_error'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx new file mode 100644 index 0000000000000..f6d5ef4aa4212 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { mount } from 'enzyme'; + +import { VersionMismatchError } from './version_mismatch_error'; + +describe('VersionMismatchError', () => { + it('renders', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Enterprise Search version: 8.0.0'); + expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Kibana version: 8.1.0'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx new file mode 100644 index 0000000000000..f2f913902f97f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +interface Props { + enterpriseSearchVersion?: string; + kibanaVersion?: string; +} + +export const VersionMismatchError: React.FC = ({ + enterpriseSearchVersion, + kibanaVersion, +}) => { + return ( + + {i18n.translate('xpack.enterpriseSearch.versionMismatch.title', { + defaultMessage: 'Incompatible version error', + })} + + } + titleSize="l" + body={ + <> + {i18n.translate('xpack.enterpriseSearch.versionMismatch.body', { + defaultMessage: + 'Your Kibana and Enterprise Search versions do not match. To access Enterprise Search, use the same major and minor version for each service.', + })} + +
+ {i18n.translate('xpack.enterpriseSearch.versionMismatch.enterpriseSearchVersionText', { + defaultMessage: 'Enterprise Search version: {enterpriseSearchVersion}', + values: { enterpriseSearchVersion }, + })} +
+
+ {i18n.translate('xpack.enterpriseSearch.versionMismatch.kibanaVersionText', { + defaultMessage: 'Kibana version: {kibanaVersion}', + values: { kibanaVersion }, + })} +
+ + } + /> + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx new file mode 100644 index 0000000000000..d86a1187bd4b9 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { VersionMismatchError } from './version_mismatch_error'; +import { VersionMismatchPage } from './version_mismatch_page'; + +describe('VersionMismatchPage', () => { + it('renders', () => { + const wrapper = shallow( + + ); + expect(wrapper.find(VersionMismatchError).exists()).toBe(true); + expect(wrapper.find(VersionMismatchError).props()).toEqual({ + kibanaVersion: '8.1.0', + enterpriseSearchVersion: '8.0.0', + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx new file mode 100644 index 0000000000000..f60ccf2d19e50 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { KibanaPageTemplate } from '../../../../../../../src/plugins/kibana_react/public'; + +import { VersionMismatchError } from './version_mismatch_error'; + +interface Props { + enterpriseSearchVersion?: string; + kibanaVersion?: string; +} + +export const VersionMismatchPage: React.FC = (props) => ( + + + +); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx index 3ddccde6abd33..7274ee8855705 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx @@ -15,6 +15,8 @@ import { Redirect } from 'react-router-dom'; import { shallow } from 'enzyme'; +import { VersionMismatchPage } from '../shared/version_mismatch'; + import { WorkplaceSearchHeaderActions } from './components/layout'; import { SourceAdded } from './views/content_sources/components/source_added'; import { ErrorState } from './views/error_state'; @@ -24,6 +26,14 @@ import { SetupGuide } from './views/setup_guide'; import { WorkplaceSearch, WorkplaceSearchUnconfigured, WorkplaceSearchConfigured } from './'; describe('WorkplaceSearch', () => { + it('renders VersionMismatchPage when there are mismatching versions', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); + }); + it('renders WorkplaceSearchUnconfigured when config.host is not set', () => { setMockValues({ config: { host: '' } }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index 1ed77ea0fb1fd..2b24e09f96315 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -10,9 +10,11 @@ import { Route, Redirect, Switch, useRouteMatch } from 'react-router-dom'; import { useActions, useValues } from 'kea'; +import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; import { HttpLogic } from '../shared/http'; import { KibanaLogic } from '../shared/kibana'; +import { VersionMismatchPage } from '../shared/version_mismatch'; import { AppLogic } from './app_logic'; import { WorkplaceSearchHeaderActions } from './components/layout'; @@ -47,13 +49,23 @@ import { SetupGuide } from './views/setup_guide'; export const WorkplaceSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); const { errorConnecting } = useValues(HttpLogic); - return !config.host ? ( - - ) : errorConnecting ? ( - - ) : ( - - ); + const { enterpriseSearchVersion, kibanaVersion } = props; + const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); + + if (!config.host) { + return ; + } else if (incompatibleVersions) { + return ( + + ); + } else if (errorConnecting) { + return ; + } + + return ; }; export const WorkplaceSearchConfigured: React.FC = (props) => { diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index ba600de298976..f6e3280a8abb2 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -41,7 +41,7 @@ describe('callEnterpriseSearchConfigAPI', () => { const mockResponse = { version: { - number: '1.0.0', + number: '7.16.0', }, settings: { external_url: 'http://some.vanity.url/', @@ -120,6 +120,7 @@ describe('callEnterpriseSearchConfigAPI', () => { expect(await callEnterpriseSearchConfigAPI(mockDependencies)).toEqual({ ...DEFAULT_INITIAL_APP_DATA, + kibanaVersion: '1.0.0', access: { hasAppSearchAccess: true, hasWorkplaceSearchAccess: false, @@ -132,6 +133,7 @@ describe('callEnterpriseSearchConfigAPI', () => { (fetch as unknown as jest.Mock).mockReturnValueOnce(Promise.resolve(new Response('{}'))); expect(await callEnterpriseSearchConfigAPI(mockDependencies)).toEqual({ + kibanaVersion: '1.0.0', access: { hasAppSearchAccess: false, hasWorkplaceSearchAccess: false, diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts index d652d56c28efe..a427beb6769c9 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts @@ -12,6 +12,7 @@ import { kibanaPackageJson } from '@kbn/utils'; import { KibanaRequest, Logger } from 'src/core/server'; +import { isVersionMismatch } from '../../common/is_version_mismatch'; import { stripTrailingSlash } from '../../common/strip_slashes'; import { InitialAppData } from '../../common/types'; import { ConfigType } from '../index'; @@ -68,6 +69,8 @@ export const callEnterpriseSearchConfigAPI = async ({ warnMismatchedVersions(data?.version?.number, log); return { + enterpriseSearchVersion: data?.version?.number, + kibanaVersion: kibanaPackageJson.version, access: { hasAppSearchAccess: !!data?.current_user?.access?.app_search, hasWorkplaceSearchAccess: !!data?.current_user?.access?.workplace_search, @@ -147,7 +150,7 @@ export const callEnterpriseSearchConfigAPI = async ({ export const warnMismatchedVersions = (enterpriseSearchVersion: string, log: Logger) => { const kibanaVersion = kibanaPackageJson.version; - if (enterpriseSearchVersion !== kibanaVersion) { + if (isVersionMismatch(enterpriseSearchVersion, kibanaVersion)) { log.warn( `Your Kibana instance (v${kibanaVersion}) is not the same version as your Enterprise Search instance (v${enterpriseSearchVersion}), which may cause unexpected behavior. Use matching versions for the best experience.` );