Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3ac662c
don't hide wizard if clusters exist
mattkime Oct 22, 2018
4c4e4ba
revert mistaken commit
mattkime Oct 22, 2018
d2eb357
minor cleanup
mattkime Oct 22, 2018
1a966bf
add test
mattkime Oct 22, 2018
dfb3f37
fix http request
mattkime Oct 22, 2018
c5d48b5
Merge branch 'master' into index-pattern-wizard-cluster-fix-mattk
mattkime Oct 22, 2018
f4259ac
Merge remote-tracking branch 'elastic/master' into index-pattern-wiza…
mattkime Oct 22, 2018
75b0ee5
fix tests, add snapshot
mattkime Oct 22, 2018
885843a
add timeout to functional test
mattkime Oct 23, 2018
9427dcd
Update doc_level_security_roles.js
mattkime Oct 23, 2018
ae572ad
Merge branch 'master' into index-pattern-wizard-cluster-fix-mattk
mattkime Oct 24, 2018
871ee5c
fix typos
mattkime Oct 24, 2018
833b987
Merge branch 'index-pattern-wizard-cluster-fix-mattk' of github.com:m…
mattkime Oct 24, 2018
bbb3732
revert unneeded changes
mattkime Oct 24, 2018
9705784
Merge branch 'master' into index-pattern-wizard-cluster-fix-mattk
mattkime Oct 25, 2018
631274f
Merge branch 'index-pattern-wizard-cluster-fix-mattk' of github.com:m…
mattkime Oct 25, 2018
67fa885
merge
mattkime Oct 25, 2018
ef26dbd
snap snap
mattkime Oct 25, 2018
e3e78f5
Merge branch 'master' of github.com:elastic/kibana into index-pattern…
mattkime Oct 29, 2018
de94309
cross cluster search is oos
mattkime Oct 29, 2018
3f4002e
Merge branch 'master' into index-pattern-wizard-cluster-fix-mattk
mattkime Nov 8, 2018
ed7a6f2
catch errors
mattkime Nov 8, 2018
b768e73
add toast notifs if unable to load data
mattkime Nov 9, 2018
811ae9a
Merge branch 'master' into index-pattern-wizard-cluster-fix-mattk
mattkime Nov 10, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/core_plugins/kibana/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { managementApi } from './server/routes/api/management';
import { scriptsApi } from './server/routes/api/scripts';
import { registerSuggestionsApi } from './server/routes/api/suggestions';
import { registerKqlTelemetryApi } from './server/routes/api/kql_telemetry';
import { registerClustersRoute } from './server/routes/api/remote_info';
import { registerFieldFormats } from './server/field_formats/register';
import { registerTutorials } from './server/tutorials/register';
import * as systemApi from './server/lib/system_api';
Expand Down Expand Up @@ -167,6 +168,7 @@ export default function (kibana) {
registerFieldFormats(server);
registerTutorials(server);
makeKQLUsageCollector(server);
registerClustersRoute(server);
server.expose('systemApi', systemApi);
server.expose('handleEsError', handleEsError);
server.injectUiAppVars('kibana', () => injectVars(server));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,35 @@ exports[`CreateIndexPatternWizard renders time field step when step is set to 2
</div>
`;

exports[`CreateIndexPatternWizard renders when there are no indices but there are remote clusters 1`] = `
<div>
<Header
indexPatternName="name"
isIncludingSystemIndices={false}
onChangeIncludingSystemIndices={[Function]}
showSystemIndices={false}
/>
<StepIndexPattern
allIndices={Array []}
esService={Object {}}
goToNextStep={[Function]}
indexPatternCreationType={
Object {
"checkIndicesForErrors": [Function],
"getIndexPatternMappings": [Function],
"getIndexPatternName": [Function],
"getIndexPatternType": [Function],
"getShowSystemIndices": [Function],
"renderPrompt": [Function],
}
}
initialQuery=""
isIncludingSystemIndices={false}
savedObjectsClient={Object {}}
/>
</div>
`;

exports[`CreateIndexPatternWizard shows system indices even if there are no other indices if the include system indices is toggled 1`] = `
<div>
<Header
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jest.mock('../lib/get_indices', () => ({
];
},
}));
jest.mock('ui/chrome', () => ({
addBasePath: () => { },
}));

const loadingDataDocUrl = '';
const initialQuery = '';
Expand Down Expand Up @@ -79,6 +82,26 @@ describe('CreateIndexPatternWizard', () => {
component.setState({
isInitiallyLoadingIndices: false,
allIndices: [],
remoteClustersExist: false
});

await component.update();
expect(component).toMatchSnapshot();
});

it('renders when there are no indices but there are remote clusters', async () => {
const component = shallow(
<CreateIndexPatternWizard
loadingDataDocUrl={loadingDataDocUrl}
initialQuery={initialQuery}
services={services}
/>
);

component.setState({
isInitiallyLoadingIndices: false,
allIndices: [],
remoteClustersExist: true
});

await component.update();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jest.mock('ui/chrome', () => ({
getUiSettingsClient: () => ({
get: () => '',
}),
addBasePath: () => { },
}));

const { renderCreateIndexPatternWizard, destroyCreateIndexPatternWizard } = require('../render');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jest.mock('ui/chrome', () => ({
getUiSettingsClient: () => ({
get: () => '',
}),
addBasePath: () => { },
}));

jest.mock('../../../lib/get_indices', () => ({
Expand All @@ -62,7 +63,7 @@ const esService = {};
const savedObjectsClient = {
find: () => ({ savedObjects: [] })
};
const goToNextStep = () => {};
const goToNextStep = () => { };

const createComponent = props => {
return shallowWithIntl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ jest.mock('../components/action_buttons', () => ({ ActionButtons: 'ActionButtons
jest.mock('../../../lib/extract_time_fields', () => ({
extractTimeFields: fields => fields,
}));
jest.mock('ui/chrome', () => ({
addBasePath: () => { },
}));

const mockIndexPatternCreationType = {
getIndexPatternType: () => 'default',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { MAX_SEARCH_SIZE } from './constants';
import {
ensureMinimumTime,
getIndices,
getRemoteClusters
} from './lib';

export class CreateIndexPatternWizard extends Component {
Expand All @@ -52,20 +53,35 @@ export class CreateIndexPatternWizard extends Component {
step: 1,
indexPattern: '',
allIndices: [],
remoteClustersExist: false,
isInitiallyLoadingIndices: true,
isIncludingSystemIndices: false,
};
}

async componentWillMount() {
this.fetchIndices();
this.fetchData();
}

fetchIndices = async () => {
this.setState({ allIndices: [], isInitiallyLoadingIndices: true });
fetchData = async () => {
const { services } = this.props;
const allIndices = await ensureMinimumTime(getIndices(services.es, this.indexPatternCreationType, `*`, MAX_SEARCH_SIZE)); //
this.setState({ allIndices, isInitiallyLoadingIndices: false });

this.setState({
allIndices: [],
isInitiallyLoadingIndices: true,
remoteClustersExist: false
});

const [allIndices, remoteClusters] = await ensureMinimumTime([
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran into a scenario where I had my remote cluster mis-configured, resulting in a 500 timeout error, but the UI remained stuck on loading. I think this area of the code could benefit from try/catch to handle ES errors from either of the requests, but I won't block the PR on that because the previous version didn't have good error handling either

getIndices(services.es, this.indexPatternCreationType, `*`, MAX_SEARCH_SIZE),
getRemoteClusters(services.$http)
]);

this.setState({
allIndices,
isInitiallyLoadingIndices: false,
remoteClustersExist: remoteClusters.length !== 0
});
}

createIndexPattern = async (timeFieldName, indexPatternId) => {
Expand Down Expand Up @@ -126,15 +142,18 @@ export class CreateIndexPatternWizard extends Component {
isIncludingSystemIndices,
step,
indexPattern,
remoteClustersExist
} = this.state;

if (isInitiallyLoadingIndices) {
return <LoadingState />;
}

const hasDataIndices = allIndices.some(({ name }) => !name.startsWith('.'));
if (!hasDataIndices && !isIncludingSystemIndices) {
return <EmptyState onRefresh={this.fetchIndices} />;
if (!hasDataIndices &&
!isIncludingSystemIndices &&
!remoteClustersExist) {
return <EmptyState onRefresh={this.fetchData} />;
}

if (step === 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ uiRoutes.when('/management/kibana/index', {
config: $injector.get('config'),
es: $injector.get('es'),
indexPatterns: $injector.get('indexPatterns'),
$http: $injector.get('$http'),
savedObjectsClient: Private(SavedObjectsClientProvider),
indexPatternCreationType,
changeUrl: url => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import chrome from 'ui/chrome';
const apiPrefix = chrome.addBasePath('/api/kibana');

export async function getRemoteClusters($http) {
const response = await $http.get(`${apiPrefix}/clusters`);
return response.data;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ export { getMatchedIndices } from './get_matched_indices';
export { containsIllegalCharacters } from './contains_illegal_characters';

export { extractTimeFields } from './extract_time_fields';

export { getRemoteClusters } from './get_remote_clusters';
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { once } from 'lodash';

const callWithRequest = once(server => {
const cluster = server.plugins.elasticsearch.getCluster('data');
return cluster.callWithRequest;
});

export const callWithRequestFactory = (server, request) => {
return (...args) => {
return callWithRequest(server)(request, ...args);
};
};
50 changes: 50 additions & 0 deletions src/core_plugins/kibana/server/routes/api/remote_info/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { callWithRequestFactory } from './call_with_request_factory';

async function fetchRemoteClusters(callWithRequest) {
const options = {
method: 'GET',
path: '_remote/info'
};
const remoteInfo = await callWithRequest('transport.request', options);
return Object.keys(remoteInfo);
}

export function registerClustersRoute(server) {
server.route({
path: '/api/kibana/clusters',
method: 'GET',
handler: async request => {
const callWithRequest = callWithRequestFactory(server, request);
try {
return await fetchRemoteClusters(callWithRequest);
} catch (error) {
return error.body;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we re-use handleEsError?

}
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
import { isEsErrorFactory } from '../../../lib/is_es_error_factory';
import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory';
import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';

function formatHits(hits) {
return hits.map(hit => {
Expand Down Expand Up @@ -57,7 +57,7 @@ export function registerListRoute(server) {
}
},
config: {
pre: [ licensePreRouting ]
pre: [licensePreRouting]
}
});
}