Skip to content

Commit

Permalink
[Enterprise Search] Error on version mismatches (elastic#119101)
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonStoltz authored and TinLe committed Dec 22, 2021
1 parent dda0aa4 commit b551772
Show file tree
Hide file tree
Showing 17 changed files with 292 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

export const DEFAULT_INITIAL_APP_DATA = {
kibanaVersion: '7.16.0',
enterpriseSearchVersion: '7.16.0',
readOnlyMode: false,
searchOAuth: {
clientId: 'someUID',
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
});
});
Original file line number Diff line number Diff line change
@@ -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;
};
2 changes: 2 additions & 0 deletions x-pack/plugins/enterprise_search/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
} from './workplace_search';

export interface InitialAppData {
enterpriseSearchVersion?: string;
kibanaVersion?: string;
readOnlyMode?: boolean;
searchOAuth?: SearchOAuth;
configuredLimits?: ConfiguredLimits;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() }));
Expand All @@ -41,6 +42,12 @@ describe('AppSearch', () => {
expect(wrapper.find(SetupGuide)).toHaveLength(1);
});

it('renders VersionMismatchPage when there are mismatching versions', () => {
const wrapper = shallow(<AppSearch enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" />);

expect(wrapper.find(VersionMismatchPage)).toHaveLength(1);
});

it('renders AppSearchUnconfigured when config.host is not set', () => {
setMockValues({ config: { host: '' } });
const wrapper = shallow(<AppSearch />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -43,21 +45,32 @@ import {
export const AppSearch: React.FC<InitialAppData> = (props) => {
const { config } = useValues(KibanaLogic);
const { errorConnecting } = useValues(HttpLogic);
const { enterpriseSearchVersion, kibanaVersion } = props;
const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion);

const showView = () => {
if (!config.host) {
return <AppSearchUnconfigured />;
} else if (incompatibleVersions) {
return (
<VersionMismatchPage
enterpriseSearchVersion={enterpriseSearchVersion}
kibanaVersion={kibanaVersion}
/>
);
} else if (errorConnecting) {
return <ErrorConnecting />;
}

return <AppSearchConfigured {...(props as Required<InitialAppData>)} />;
};

return (
<Switch>
<Route exact path={SETUP_GUIDE_PATH}>
<SetupGuide />
</Route>
<Route>
{!config.host ? (
<AppSearchUnconfigured />
) : errorConnecting ? (
<ErrorConnecting />
) : (
<AppSearchConfigured {...(props as Required<InitialAppData>)} />
)}
</Route>
<Route>{showView()}</Route>
</Switch>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -38,6 +39,7 @@ describe('EnterpriseSearch', () => {
});
const wrapper = shallow(<EnterpriseSearch />);

expect(wrapper.find(VersionMismatchPage)).toHaveLength(0);
expect(wrapper.find(ErrorConnecting)).toHaveLength(1);
expect(wrapper.find(ProductSelector)).toHaveLength(0);

Expand All @@ -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(
<EnterpriseSearch enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" />
);

expect(wrapper.find(VersionMismatchPage)).toHaveLength(1);
expect(wrapper.find(ErrorConnecting)).toHaveLength(0);
expect(wrapper.find(ProductSelector)).toHaveLength(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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<InitialAppData> = ({ access = {}, workplaceSearch }) => {
export const EnterpriseSearch: React.FC<InitialAppData> = ({
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 (
<VersionMismatchPage
enterpriseSearchVersion={enterpriseSearchVersion}
kibanaVersion={kibanaVersion}
/>
);
} else if (showErrorConnecting) {
return <ErrorConnecting />;
}

return <ProductSelector isWorkplaceSearchAdmin={isWorkplaceSearchAdmin} access={access} />;
};

return (
<Switch>
<Route exact path={SETUP_GUIDE_PATH}>
<SetupGuide />
</Route>
<Route exact path={ROOT_PATH}>
{showErrorConnecting ? (
<ErrorConnecting />
) : (
<ProductSelector isWorkplaceSearchAdmin={isWorkplaceSearchAdmin} access={access} />
)}
{showView()}
</Route>
</Switch>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Original file line number Diff line number Diff line change
@@ -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(
<VersionMismatchError kibanaVersion="8.1.0" enterpriseSearchVersion="8.0.0" />
);

expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Enterprise Search version: 8.0.0');
expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Kibana version: 8.1.0');
});
});
Original file line number Diff line number Diff line change
@@ -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<Props> = ({
enterpriseSearchVersion,
kibanaVersion,
}) => {
return (
<EuiEmptyPrompt
iconType="alert"
iconColor="danger"
title={
<h2>
{i18n.translate('xpack.enterpriseSearch.versionMismatch.title', {
defaultMessage: 'Incompatible version error',
})}
</h2>
}
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.',
})}
<EuiSpacer />
<div>
{i18n.translate('xpack.enterpriseSearch.versionMismatch.enterpriseSearchVersionText', {
defaultMessage: 'Enterprise Search version: {enterpriseSearchVersion}',
values: { enterpriseSearchVersion },
})}
</div>
<div>
{i18n.translate('xpack.enterpriseSearch.versionMismatch.kibanaVersionText', {
defaultMessage: 'Kibana version: {kibanaVersion}',
values: { kibanaVersion },
})}
</div>
</>
}
/>
);
};
Original file line number Diff line number Diff line change
@@ -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(
<VersionMismatchPage kibanaVersion="8.1.0" enterpriseSearchVersion="8.0.0" />
);
expect(wrapper.find(VersionMismatchError).exists()).toBe(true);
expect(wrapper.find(VersionMismatchError).props()).toEqual({
kibanaVersion: '8.1.0',
enterpriseSearchVersion: '8.0.0',
});
});
});
Original file line number Diff line number Diff line change
@@ -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> = (props) => (
<KibanaPageTemplate isEmptyState>
<VersionMismatchError {...props} />
</KibanaPageTemplate>
);
Loading

0 comments on commit b551772

Please sign in to comment.