diff --git a/src/core_plugins/kibana/public/management/sections/objects/_objects.js b/src/core_plugins/kibana/public/management/sections/objects/_objects.js index c203e0beebf17..d3ac12969861b 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/_objects.js +++ b/src/core_plugins/kibana/public/management/sections/objects/_objects.js @@ -42,7 +42,7 @@ function updateObjectsTable($scope, $injector) { basePath={chrome.getBasePath()} newIndexPatternUrl={kbnUrl.eval('#/management/kibana/index')} getEditUrl={(id, type) => { - if (type === 'index-pattern') { + if (type === 'index-pattern' || type === 'indexPatterns') { return kbnUrl.eval(`#/management/kibana/indices/${id}`); } const serviceName = typeToServiceName(type); diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js index 090ced0b83a37..a956f633d8d78 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js @@ -442,7 +442,7 @@ export class ObjectsTable extends Component { const filterOptions = INCLUDED_TYPES.map(type => ({ value: type, name: type, - view: `${type} (${savedObjectCounts[type]})`, + view: `${type} (${savedObjectCounts[type] || 0})`, })); return ( diff --git a/src/core_plugins/kibana/server/lib/__tests__/relationships.js b/src/core_plugins/kibana/server/lib/__tests__/relationships.js index a1988112a33ac..d5a0673251143 100644 --- a/src/core_plugins/kibana/server/lib/__tests__/relationships.js +++ b/src/core_plugins/kibana/server/lib/__tests__/relationships.js @@ -6,51 +6,41 @@ describe('findRelationships', () => { const type = 'dashboard'; const id = 'foo'; const size = 10; - const callCluster = () => ({ - docs: [ - { - _id: 'visualization:1', - found: true, - _source: { - visualization: { + + const savedObjectsClient = { + _index: '.kibana', + get: () => ({ + attributes: { + panelsJSON: JSON.stringify([{ id: '1' }, { id: '2' }, { id: '3' }]), + }, + }), + bulkGet: () => ({ + saved_objects: [ + { + id: '1', + attributes: { title: 'Foo', }, }, - }, - { - _id: 'visualization:2', - found: true, - _source: { - visualization: { + { + id: '2', + attributes: { title: 'Bar', }, }, - }, - { - _id: 'visualization:3', - found: true, - _source: { - visualization: { + { + id: '3', + attributes: { title: 'FooBar', }, }, - }, - ], - }); - - const savedObjectsClient = { - _index: '.kibana', - get: () => ({ - attributes: { - panelsJSON: JSON.stringify([{ id: '1' }, { id: '2' }, { id: '3' }]), - }, - }), + ], + }) }; const result = await findRelationships( type, id, size, - callCluster, savedObjectsClient ); expect(result).to.eql({ @@ -66,60 +56,50 @@ describe('findRelationships', () => { const type = 'visualization'; const id = 'foo'; const size = 10; - const callCluster = () => ({ - hits: { - hits: [ + + const savedObjectsClient = { + find: () => ({ + saved_objects: [ { - _id: 'dashboard:1', - found: true, - _source: { - dashboard: { - title: 'My Dashboard', - panelsJSON: JSON.stringify([ - { - type: 'visualization', - id, - }, - { - type: 'visualization', - id: 'foobar', - }, - ]), - }, + id: '1', + attributes: { + title: 'My Dashboard', + panelsJSON: JSON.stringify([ + { + type: 'visualization', + id, + }, + { + type: 'visualization', + id: 'foobar', + }, + ]), }, }, { - _id: 'dashboard:2', - found: true, - _source: { - dashboard: { - title: 'Your Dashboard', - panelsJSON: JSON.stringify([ - { - type: 'visualization', - id, - }, - { - type: 'visualization', - id: 'foobar', - }, - ]), - }, + id: '2', + attributes: { + title: 'Your Dashboard', + panelsJSON: JSON.stringify([ + { + type: 'visualization', + id, + }, + { + type: 'visualization', + id: 'foobar', + }, + ]), }, }, - ], - }, - }); - - const savedObjectsClient = { - _index: '.kibana', + ] + }) }; const result = await findRelationships( type, id, size, - callCluster, savedObjectsClient ); expect(result).to.eql({ @@ -134,46 +114,12 @@ describe('findRelationships', () => { const type = 'search'; const id = 'foo'; const size = 10; - const callCluster = () => ({ - hits: { - hits: [ - { - _id: 'visualization:1', - found: true, - _source: { - visualization: { - title: 'Foo', - }, - }, - }, - { - _id: 'visualization:2', - found: true, - _source: { - visualization: { - title: 'Bar', - }, - }, - }, - { - _id: 'visualization:3', - found: true, - _source: { - visualization: { - title: 'FooBar', - }, - }, - }, - ], - }, - }); const savedObjectsClient = { - _index: '.kibana', get: type => { if (type === 'search') { return { - id: 'search:1', + id: '1', attributes: { kibanaSavedObjectMeta: { searchSourceJSON: JSON.stringify({ @@ -191,13 +137,34 @@ describe('findRelationships', () => { }, }; }, + find: () => ({ + saved_objects: [ + { + id: '1', + attributes: { + title: 'Foo', + }, + }, + { + id: '2', + attributes: { + title: 'Bar', + }, + }, + { + id: '3', + attributes: { + title: 'FooBar', + }, + }, + ] + }) }; const result = await findRelationships( type, id, size, - callCluster, savedObjectsClient ); expect(result).to.eql({ @@ -214,117 +181,96 @@ describe('findRelationships', () => { const type = 'index-pattern'; const id = 'foo'; const size = 10; - const callCluster = (endpoint, options) => { - if (options._source[0] === 'visualization.title') { - return { - hits: { - hits: [ + + const savedObjectsClient = { + find: options => { + if (options.type === 'visualization') { + return { + saved_objects: [ { - _id: 'visualization:1', + id: '1', found: true, - _source: { - visualization: { - title: 'Foo', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'foo', - }), - }, + attributes: { + title: 'Foo', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + index: 'foo', + }), }, }, }, { - _id: 'visualization:2', + id: '2', found: true, - _source: { - visualization: { - title: 'Bar', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'foo', - }), - }, + attributes: { + title: 'Bar', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + index: 'foo', + }), }, }, }, { - _id: 'visualization:3', + id: '3', found: true, - _source: { - visualization: { - title: 'FooBar', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'foo2', - }), - }, + attributes: { + title: 'FooBar', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + index: 'foo2', + }), }, }, }, - ], - }, - }; - } + ] + }; + } - return { - hits: { - hits: [ + return { + saved_objects: [ { - _id: 'search:1', - found: true, - _source: { - search: { - title: 'Foo', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'foo', - }), - }, + id: '1', + attributes: { + title: 'Foo', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + index: 'foo', + }), }, }, }, { - _id: 'search:2', - found: true, - _source: { - search: { - title: 'Bar', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'foo', - }), - }, + id: '2', + attributes: { + title: 'Bar', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + index: 'foo', + }), }, }, }, { - _id: 'search:3', - found: true, - _source: { - search: { - title: 'FooBar', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'foo2', - }), - }, + id: '3', + attributes: { + title: 'FooBar', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + index: 'foo2', + }), }, }, }, - ], - }, - }; - }; - - const savedObjectsClient = { - _index: '.kibana', + ] + }; + } }; const result = await findRelationships( type, id, size, - callCluster, savedObjectsClient ); expect(result).to.eql({ diff --git a/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js b/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js index 0391055db34b2..b505da08cb9a3 100644 --- a/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js +++ b/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js @@ -1,9 +1,4 @@ -function formatId(id) { - return id.split(':')[1]; -} - -async function findDashboardRelationships(id, size, callCluster, savedObjectsClient) { - const kibanaIndex = savedObjectsClient._index; +async function findDashboardRelationships(id, size, savedObjectsClient) { const dashboard = await savedObjectsClient.get('dashboard', id); const visualizations = []; @@ -11,22 +6,16 @@ async function findDashboardRelationships(id, size, callCluster, savedObjectsCli const panelsJSON = JSON.parse(dashboard.attributes.panelsJSON); if (panelsJSON) { const visualizationIds = panelsJSON.map(panel => panel.id); - const visualizationResponse = await callCluster('mget', { - body: { - docs: visualizationIds.slice(0, size).map(id => ({ - _index: kibanaIndex, - _type: 'doc', - _id: `visualization:${id}`, - _source: [`visualization.title`] - })) - } - }); + const visualizationResponse = await savedObjectsClient.bulkGet(visualizationIds.slice(0, size).map(id => ({ + id, + type: 'visualization', + }))); - visualizations.push(...visualizationResponse.docs.reduce((accum, doc) => { - if (doc.found) { + visualizations.push(...visualizationResponse.saved_objects.reduce((accum, object) => { + if (!object.error) { accum.push({ - id: formatId(doc._id), - title: doc._source.visualization.title, + id: object.id, + title: object.attributes.title, }); } return accum; @@ -36,31 +25,24 @@ async function findDashboardRelationships(id, size, callCluster, savedObjectsCli return { visualizations }; } -async function findVisualizationRelationships(id, size, callCluster, savedObjectsClient) { - const kibanaIndex = savedObjectsClient._index; - const allDashboardsResponse = await callCluster('search', { - index: kibanaIndex, - size: 10000, - ignore: [404], - _source: [`dashboard.title`, `dashboard.panelsJSON`], - body: { - query: { - term: { - type: 'dashboard' - } - } - } +async function findVisualizationRelationships(id, size, savedObjectsClient) { + const allDashboardsResponse = await savedObjectsClient.find({ + type: 'dashboard', + fields: ['title', 'panelsJSON'] }); const dashboards = []; - for (const dashboard of allDashboardsResponse.hits.hits) { - const panelsJSON = JSON.parse(dashboard._source.dashboard.panelsJSON); + for (const dashboard of allDashboardsResponse.saved_objects) { + if (dashboard.error) { + continue; + } + const panelsJSON = JSON.parse(dashboard.attributes.panelsJSON); if (panelsJSON) { for (const panel of panelsJSON) { if (panel.type === 'visualization' && panel.id === id) { dashboards.push({ - id: formatId(dashboard._id), - title: dashboard._source.dashboard.title, + id: dashboard.id, + title: dashboard.attributes.title, }); } } @@ -74,8 +56,7 @@ async function findVisualizationRelationships(id, size, callCluster, savedObject return { dashboards }; } -async function findSavedSearchRelationships(id, size, callCluster, savedObjectsClient) { - const kibanaIndex = savedObjectsClient._index; +async function findSavedSearchRelationships(id, size, savedObjectsClient) { const search = await savedObjectsClient.get('search', id); const searchSourceJSON = JSON.parse(search.attributes.kibanaSavedObjectMeta.searchSourceJSON); @@ -88,93 +69,52 @@ async function findSavedSearchRelationships(id, size, callCluster, savedObjectsC // Do nothing } - const allVisualizationsResponse = await callCluster('search', { - index: kibanaIndex, - size, - ignore: [404], - _source: [`visualization.title`], - body: { - query: { - term: { - 'visualization.savedSearchId': id, - } - } - } + const allVisualizationsResponse = await savedObjectsClient.find({ + type: 'visualization', + searchFields: ['savedSearchId'], + search: id, + fields: ['title'] }); - const visualizations = allVisualizationsResponse.hits.hits.map(response => ({ - id: formatId(response._id), - title: response._source.visualization.title, - })); + const visualizations = allVisualizationsResponse.saved_objects.reduce((accum, object) => { + if (!object.error) { + accum.push({ + id: object.id, + title: object.attributes.title, + }); + } + return accum; + }, []); return { visualizations, indexPatterns }; } -async function findIndexPatternRelationships(id, size, callCluster, savedObjectsClient) { - const kibanaIndex = savedObjectsClient._index; - +async function findIndexPatternRelationships(id, size, savedObjectsClient) { const [allVisualizationsResponse, savedSearchResponse] = await Promise.all([ - callCluster('search', { - index: kibanaIndex, - size: 10000, - ignore: [404], - _source: [`visualization.title`, `visualization.kibanaSavedObjectMeta.searchSourceJSON`], - body: { - query: { - bool: { - filter: [ - { - exists: { - field: 'visualization.kibanaSavedObjectMeta.searchSourceJSON', - } - }, - { - term: { - type: { - value: 'visualization' - } - } - } - ], - } - } - } + savedObjectsClient.find({ + type: 'visualization', + searchFields: ['kibanaSavedObjectMeta.searchSourceJSON'], + search: '*', + fields: [`title`, `kibanaSavedObjectMeta.searchSourceJSON`], + }), + savedObjectsClient.find({ + type: 'search', + searchFields: ['kibanaSavedObjectMeta.searchSourceJSON'], + search: '*', + fields: [`title`, `kibanaSavedObjectMeta.searchSourceJSON`], }), - callCluster('search', { - index: kibanaIndex, - size: 10000, - ignore: [404], - _source: [`search.title`, `search.kibanaSavedObjectMeta.searchSourceJSON`], - body: { - query: { - bool: { - filter: [ - { - exists: { - field: 'search.kibanaSavedObjectMeta.searchSourceJSON', - } - }, - { - term: { - type: { - value: 'search' - } - } - } - ] - } - } - } - }) ]); const visualizations = []; - for (const visualization of allVisualizationsResponse.hits.hits) { - const searchSourceJSON = JSON.parse(visualization._source.visualization.kibanaSavedObjectMeta.searchSourceJSON); + for (const visualization of allVisualizationsResponse.saved_objects) { + if (visualization.error) { + continue; + } + const searchSourceJSON = JSON.parse(visualization.attributes.kibanaSavedObjectMeta.searchSourceJSON); if (searchSourceJSON && searchSourceJSON.index === id) { visualizations.push({ - id: formatId(visualization._id), - title: visualization._source.visualization.title, + id: visualization.id, + title: visualization.attributes.title, }); } @@ -184,12 +124,15 @@ async function findIndexPatternRelationships(id, size, callCluster, savedObjects } const searches = []; - for (const search of savedSearchResponse.hits.hits) { - const searchSourceJSON = JSON.parse(search._source.search.kibanaSavedObjectMeta.searchSourceJSON); + for (const search of savedSearchResponse.saved_objects) { + if (search.error) { + continue; + } + const searchSourceJSON = JSON.parse(search.attributes.kibanaSavedObjectMeta.searchSourceJSON); if (searchSourceJSON && searchSourceJSON.index === id) { searches.push({ - id: formatId(search._id), - title: search._source.search.title, + id: search.id, + title: search.attributes.title, }); } @@ -201,16 +144,16 @@ async function findIndexPatternRelationships(id, size, callCluster, savedObjects return { visualizations, searches }; } -export async function findRelationships(type, id, size, callCluster, savedObjectsClient) { +export async function findRelationships(type, id, size, savedObjectsClient) { switch (type) { case 'dashboard': - return await findDashboardRelationships(id, size, callCluster, savedObjectsClient); + return await findDashboardRelationships(id, size, savedObjectsClient); case 'visualization': - return await findVisualizationRelationships(id, size, callCluster, savedObjectsClient); + return await findVisualizationRelationships(id, size, savedObjectsClient); case 'search': - return await findSavedSearchRelationships(id, size, callCluster, savedObjectsClient); + return await findSavedSearchRelationships(id, size, savedObjectsClient); case 'index-pattern': - return await findIndexPatternRelationships(id, size, callCluster, savedObjectsClient); + return await findIndexPatternRelationships(id, size, savedObjectsClient); } return {}; } diff --git a/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js b/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js index 8fc23b79a8109..8f2080188e2e2 100644 --- a/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js +++ b/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js @@ -1,6 +1,5 @@ import Boom from 'boom'; import Joi from 'joi'; -import _ from 'lodash'; import { findRelationships } from '../../../../lib/management/saved_objects/relationships'; export function registerRelationships(server) { @@ -20,9 +19,6 @@ export function registerRelationships(server) { }, handler: async (req, reply) => { - const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); - const boundCallWithRequest = _.partial(callWithRequest, req); - const type = req.params.type; const id = req.params.id; const size = req.query.size || 10; @@ -32,7 +28,6 @@ export function registerRelationships(server) { type, id, size, - boundCallWithRequest, req.getSavedObjectsClient(), ); diff --git a/src/core_plugins/kibana/server/routes/api/management/saved_objects/scroll.js b/src/core_plugins/kibana/server/routes/api/management/saved_objects/scroll.js index f10bd5be4d290..36b1b75f872f6 100644 --- a/src/core_plugins/kibana/server/routes/api/management/saved_objects/scroll.js +++ b/src/core_plugins/kibana/server/routes/api/management/saved_objects/scroll.js @@ -1,17 +1,17 @@ -import Boom from 'boom'; import Joi from 'joi'; -import _ from 'lodash'; -// import { findRelationships } from '../../../../lib/management/saved_objects/relationships'; -async function fetchUntilDone(callCluster, response, results) { - results.push(...response.hits.hits); - if (response.hits.total > results.length) { - const nextResponse = await callCluster('scroll', { - scrollId: response._scroll_id, - scroll: '30s', - }); - await fetchUntilDone(callCluster, nextResponse, results); +async function findAll(savedObjectsClient, findOptions, page = 1, allObjects = []) { + const objects = await savedObjectsClient.find({ + ...findOptions, + page + }); + + allObjects.push(...objects.saved_objects); + if (allObjects.length < objects.total) { + return findAll(savedObjectsClient, findOptions, page + 1, allObjects); } + + return allObjects; } export function registerScrollForExportRoute(server) { @@ -27,54 +27,24 @@ export function registerScrollForExportRoute(server) { }, handler: async (req, reply) => { - const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); - const callCluster = _.partial(callWithRequest, req); - const results = []; - const body = { - query: { - bool: { - should: req.payload.typesToInclude.map(type => ({ - term: { - type: { - value: type, - } - } - })), + const savedObjectsClient = req.getSavedObjectsClient(); + const objects = await findAll(savedObjectsClient, { + perPage: 1000, + typesToInclude: req.payload.typesToInclude + }); + const response = objects.map(hit => { + const type = hit.type; + return { + _id: hit.id, + _type: type, + _source: hit.attributes, + _meta: { + savedObjectVersion: 2 } - } - }; - - try { - await fetchUntilDone(callCluster, await callCluster('search', { - index: server.config().get('kibana.index'), - scroll: '30s', - body, - }), results); - - const response = results.map(hit => { - const type = hit._source.type; - if (hit._type === 'doc') { - return { - _id: hit._id.replace(`${type}:`, ''), - _type: type, - _source: hit._source[type], - _meta: { - savedObjectVersion: 2 - } - }; - } - return { - _id: hit._id, - _type: hit._type, - _source: hit._source, - }; - }); + }; + }); - reply(response); - } - catch (err) { - reply(Boom.boomify(err, { statusCode: 500 })); - } + reply(response); } }); } @@ -93,59 +63,32 @@ export function registerScrollForCountRoute(server) { }, handler: async (req, reply) => { - const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); - const callCluster = _.partial(callWithRequest, req); - const results = []; - - const body = { - _source: 'type', - query: { - bool: { - should: req.payload.typesToInclude.map(type => ({ - term: { - type: { - value: type, - } - } - })), - } - } + const savedObjectsClient = req.getSavedObjectsClient(); + const findOptions = { + includeTypes: req.payload.typesToInclude, + perPage: 1000, }; if (req.payload.searchString) { - body.query.bool.must = { - simple_query_string: { - query: `${req.payload.searchString}*`, - fields: req.payload.typesToInclude.map(type => `${type}.title`), - } - }; + findOptions.search = `${req.payload.searchString}*`; + findOptions.searchFields = ['title']; } - try { - await fetchUntilDone(callCluster, await callCluster('search', { - index: server.config().get('kibana.index'), - scroll: '30s', - body, - }), results); + const objects = await findAll(savedObjectsClient, findOptions); + const counts = objects.reduce((accum, result) => { + const type = result.type; + accum[type] = accum[type] || 0; + accum[type]++; + return accum; + }, {}); - const counts = results.reduce((accum, result) => { - const type = result._source.type; - accum[type] = accum[type] || 0; - accum[type]++; - return accum; - }, {}); - - for (const type of req.payload.typesToInclude) { - if (!counts[type]) { - counts[type] = 0; - } + for (const type of req.payload.typesToInclude) { + if (!counts[type]) { + counts[type] = 0; } - - reply(counts); - } - catch (err) { - reply(Boom.boomify(err, { statusCode: 500 })); } + + reply(counts); } }); }