Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support v6 mappings for saved objects import/export #12792

Merged
merged 3 commits into from
Jul 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { saveAs } from '@spalger/filesaver';
import { extend, find, flattenDeep, pluck, sortBy } from 'lodash';
import { find, flattenDeep, pluck, sortBy } from 'lodash';
import angular from 'angular';
import { savedObjectManagementRegistry } from 'plugins/kibana/management/saved_object_registry';
import objectIndexHTML from 'plugins/kibana/management/sections/objects/_objects.html';
Expand Down Expand Up @@ -137,9 +137,9 @@ uiModules.get('apps/management')
$scope.exportAll = () => Promise
.map($scope.services, service => service.service
.scanAll('')
.then(result => result.hits.map(hit => extend(hit, { type: service.type })))
.then(result => result.hits)
)
.then(results => retrieveAndExportDocs(flattenDeep(results)))
.then(results => saveToFile(flattenDeep(results)))
.catch(error => notify.error(error));

function retrieveAndExportDocs(objs) {
Expand Down
44 changes: 14 additions & 30 deletions src/core_plugins/kibana/public/management/sections/objects/_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import objectViewHTML from 'plugins/kibana/management/sections/objects/_view.htm
import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import { castEsToKbnFieldTypeName } from '../../../../../../utils';
import { SavedObjectsClientProvider } from 'ui/saved_objects';

uiRoutes
.when('/management/kibana/objects/:service/:id', {
Expand All @@ -16,10 +17,11 @@ uiModules.get('apps/management')
.directive('kbnManagementObjectsView', function (kbnIndex, Notifier, confirmModal) {
return {
restrict: 'E',
controller: function ($scope, $injector, $routeParams, $location, $window, $rootScope, esAdmin) {
controller: function ($scope, $injector, $routeParams, $location, $window, $rootScope, Private) {
const notify = new Notifier({ location: 'SavedObject view' });
const serviceObj = savedObjectManagementRegistry.get($routeParams.service);
const service = $injector.get(serviceObj.service);
const savedObjectsClient = Private(SavedObjectsClientProvider);

/**
* Creates a field definition and pushes it to the memo stack. This function
Expand Down Expand Up @@ -103,16 +105,12 @@ uiModules.get('apps/management')

$scope.title = service.type;

esAdmin.get({
index: kbnIndex,
type: service.type,
id: $routeParams.id
})
savedObjectsClient.get(service.type, $routeParams.id)
.then(function (obj) {
$scope.obj = obj;
$scope.link = service.urlFor(obj._id);
$scope.link = service.urlFor(obj.id);

const fields = _.reduce(obj._source, createField, []);
const fields = _.reduce(obj.attributes, createField, []);
if (service.Class) readObjectClass(fields, service.Class);

// sorts twice since we want numerical sort to prioritize over name,
Expand Down Expand Up @@ -170,11 +168,7 @@ uiModules.get('apps/management')
*/
$scope.delete = function () {
function doDelete() {
esAdmin.delete({
index: kbnIndex,
type: service.type,
id: $routeParams.id
})
savedObjectsClient.delete(service.type, $routeParams.id)
.then(function () {
return redirectHandler('deleted');
})
Expand Down Expand Up @@ -207,32 +201,22 @@ uiModules.get('apps/management')
_.set(source, field.name, value);
});

esAdmin.index({
index: kbnIndex,
type: service.type,
id: $routeParams.id,
body: source
})
savedObjectsClient.update(service.type, $routeParams.id, source)
.then(function () {
return redirectHandler('updated');
})
.catch(notify.fatal);
};

function redirectHandler(action) {
return esAdmin.indices.refresh({
index: kbnIndex
})
.then(function () {
const msg = 'You successfully ' + action + ' the "' + $scope.obj._source.title + '" ' + $scope.title.toLowerCase() + ' object';
const msg = 'You successfully ' + action + ' the "' + $scope.obj._source.title + '" ' + $scope.title.toLowerCase() + ' object';

$location.path('/management/kibana/objects').search({
_a: rison.encode({
tab: serviceObj.title
})
});
notify.info(msg);
$location.path('/management/kibana/objects').search({
_a: rison.encode({
tab: serviceObj.title
})
});
notify.info(msg);
}
}
};
Expand Down
3 changes: 1 addition & 2 deletions src/ui/public/courier/saved_object/saved_object.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function isErrorNonFatal(error) {
return error.message === OVERWRITE_REJECTED || error.message === SAVE_DUPLICATE_REJECTED;
}

export function SavedObjectProvider(esAdmin, kbnIndex, Promise, Private, Notifier, confirmModalPromise, indexPatterns) {
export function SavedObjectProvider(Promise, Private, Notifier, confirmModalPromise, indexPatterns) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
const SearchSource = Private(SearchSourceProvider);
const mappingSetup = Private(MappingSetupProvider);
Expand All @@ -53,7 +53,6 @@ export function SavedObjectProvider(esAdmin, kbnIndex, Promise, Private, Notifie

// type name for this object, used as the ES-type
const esType = config.type;
this.index = kbnIndex;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you remove this? Are you sure this doesn't have trickle down effects elsewhere, on xpack or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't find any instance of it being used and never ran into an error when testing.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is why I love getters so much, easier to find uses but mostly that unexpected accesses that are broken by changes/removal are much louder


this.getDisplayName = function () {
return esType;
Expand Down
12 changes: 1 addition & 11 deletions src/ui/public/courier/saved_object/saved_object_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,11 @@ export class SavedObjectLoader {
return source;
}

/**
* Updates hit._source to contain an id and url field, and returns the updated
* source object.
* @param hit
* @returns {hit._source} The modified hit._source object, with an id and url field.
*/
mapHits(hit) {
return this.mapHitSource(hit._source, hit._id);
}

scanAll(queryString, pageSize = 1000) {
return this.scanner.scanAndMap(queryString, {
pageSize,
docCount: Infinity
}, (hit) => this.mapHits(hit));
});
}

/**
Expand Down
15 changes: 12 additions & 3 deletions src/ui/public/utils/__tests__/scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ describe('Scanner', function () {
let scroll;
let scanner;
const mockSearch = { '_scroll_id':'abc','took':1,'timed_out':false,'_shards':{ 'total':1,'successful':1,'failed':0 },'hits':{ 'total':2,'max_score':0.0,'hits':[] } }; // eslint-disable-line max-len
const mockScroll = { 'took':1,'timed_out':false,'_shards':{ 'total':1,'successful':1,'failed':0 },'hits':{ 'total':2,'max_score':0.0,'hits':['one', 'two'] } }; // eslint-disable-line max-len
const hits = [{
_id: 'one',
_type: 'config',
_source: { title: 'First title' }
}, {
_id: 'two',
_type: 'config',
_source: { title: 'Second title' }
}];
const mockScroll = { 'took':1,'timed_out':false,'_shards':{ 'total':1,'successful':1,'failed':0 },'hits':{ 'total':2,'max_score':0.0,'hits':hits } }; // eslint-disable-line max-len

beforeEach(function () {
scanner = new Scanner(es, {
Expand Down Expand Up @@ -75,7 +84,7 @@ describe('Scanner', function () {

it('should map results if a function is provided', function () {
return scanner.scanAndMap(null, null, function (hit) {
return hit.toUpperCase();
return hit._id.toUpperCase();
})
.then(function (response) {
expect(response.hits[0]).to.be('ONE');
Expand All @@ -85,7 +94,7 @@ describe('Scanner', function () {

it('should only return the requested number of documents', function () {
return scanner.scanAndMap(null, { docCount: 1 }, function (hit) {
return hit.toUpperCase();
return hit._id.toUpperCase();
})
.then(function (response) {
expect(response.hits[0]).to.be('ONE');
Expand Down
60 changes: 47 additions & 13 deletions src/ui/public/utils/scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ export const Scanner = function (client, { index, type } = {}) {
};

Scanner.prototype.scanAndMap = function (searchString, options, mapFn) {
const bool = { must: [], filter: [] };

let scrollId;
let body;
const allResults = {
hits: [],
total: 0
Expand All @@ -22,18 +23,37 @@ Scanner.prototype.scanAndMap = function (searchString, options, mapFn) {
docCount: 1000
});

if (this.type) {
bool.filter.push({
bool: {
should: [
{
term: {
_type: this.type
}
},
{
term: {
type: this.type
}
}
]
}
});
}

if (searchString) {
body = {
query: {
simple_query_string: {
query: searchString + '*',
fields: ['title^3', 'description'],
default_operator: 'AND'
}
bool.must.push({
simple_query_string: {
query: searchString + '*',
fields: ['title^3', 'description'],
default_operator: 'AND'
}
};
});
} else {
body = { query: { match_all: {} } };
bool.must.push({
match_all: {}
});
}

return new Promise((resolve, reject) => {
Expand All @@ -48,6 +68,22 @@ Scanner.prototype.scanAndMap = function (searchString, options, mapFn) {

let hits = response.hits.hits
.slice(0, allResults.total - allResults.hits.length);

hits = hits.map(hit => {
if (hit._type === 'doc') {
return {
_id: hit._id.replace(`${this.type}:`, ''),
_type: this.type,
_source: hit._source[this.type],
_meta: {
Copy link
Contributor

Choose a reason for hiding this comment

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

😻

savedObjectVersion: 2
}
};
}

return _.pick(hit, ['_id', '_type', '_source']);
});

if (mapFn) hits = hits.map(mapFn);

allResults.hits = allResults.hits.concat(hits);
Expand All @@ -64,12 +100,10 @@ Scanner.prototype.scanAndMap = function (searchString, options, mapFn) {

this.client.search({
index: this.index,
type: this.type,
size: opts.pageSize,
body,
body: { query: { bool } },
scroll: '1m',
sort: '_doc',
}, getMoreUntilDone);
});
};