Skip to content

Commit

Permalink
Uses uuid for auto-generated ids and prepends type (#12834) (#12877)
Browse files Browse the repository at this point in the history
* Uses uuid for auto-generated ids and prepends type (#12834)

Signed-off-by: Tyler Smalley <[email protected]>

* saved_objects: remove isSingleTypeError reference
  • Loading branch information
epixa authored Jul 14, 2017
1 parent 10656c2 commit 6c09a67
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ const { BadRequest } = elasticsearch.errors;
describe('SavedObjectsClient', () => {
let callAdminCluster;
let savedObjectsClient;
const illegalArgumentException = {
type: 'illegal_argument_exception',
reason: 'Rejecting mapping update to [.kibana-v6] as the final mapping would have more than 1 type: [doc, foo]'
};
const illegalArgumentException = { type: 'type_missing_exception' };

describe('mapping', () => {
beforeEach(() => {
Expand All @@ -25,7 +22,7 @@ describe('SavedObjectsClient', () => {


describe('#create', () => {
it('falls back to v6 mapping', async () => {
it('falls back to single-type mapping', async () => {
const error = new BadRequest('[illegal_argument_exception] Rejecting mapping update to [.kibana-v6]', {
body: {
error: illegalArgumentException
Expand All @@ -49,48 +46,66 @@ describe('SavedObjectsClient', () => {
}
});
});

it('prepends id for single-type', async () => {
const id = 'foo';
const error = new BadRequest('[illegal_argument_exception] Rejecting mapping update to [.kibana-v6]', {
body: {
error: illegalArgumentException
}
});

callAdminCluster
.onFirstCall().throws(error)
.onSecondCall().returns(Promise.resolve());

await savedObjectsClient.create('index-pattern', {}, { id });

const [, args] = callAdminCluster.getCall(1).args;
expect(args.id).to.eql('index-pattern:foo');
});
});

describe('#bulkCreate', () => {
it('falls back to v6 mappings', async () => {
const firstResponse = {
errors: true,
items: [{
create: {
_type: 'config',
_id: 'one',
_version: 2,
status: 400,
error: illegalArgumentException
}
}, {
create: {
_type: 'index-pattern',
_id: 'two',
_version: 2,
status: 400,
error: illegalArgumentException
}
}]
};

const secondResponse = {
errors: false,
items: [{
create: {
_type: 'config',
_id: 'one',
_version: 2
}
}, {
create: {
_type: 'index-pattern',
_id: 'two',
_version: 2
}
}]
};
const firstResponse = {
errors: true,
items: [{
create: {
_type: 'config',
_id: 'one',
_version: 2,
status: 400,
error: illegalArgumentException
}
}, {
create: {
_type: 'index-pattern',
_id: 'two',
_version: 2,
status: 400,
error: illegalArgumentException
}
}]
};

const secondResponse = {
errors: false,
items: [{
create: {
_type: 'config',
_id: 'one',
_version: 2
}
}, {
create: {
_type: 'index-pattern',
_id: 'two',
_version: 2
}
}]
};

it('falls back to single-type mappings', async () => {
callAdminCluster
.onFirstCall().returns(Promise.resolve(firstResponse))
.onSecondCall().returns(Promise.resolve(secondResponse));
Expand All @@ -116,23 +131,38 @@ describe('SavedObjectsClient', () => {
}
]);
});

it('prepends id for single-type', async () => {
callAdminCluster
.onFirstCall().returns(Promise.resolve(firstResponse))
.onSecondCall().returns(Promise.resolve(secondResponse));

await savedObjectsClient.bulkCreate([
{ type: 'config', id: 'one', attributes: { title: 'Test One' } },
{ type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } }
]);

const [, { body }] = callAdminCluster.getCall(1).args;
expect(body[0].create._id).to.eql('config:one');
expect(body[2].create._id).to.eql('index-pattern:two');
// expect(args.id).to.eql('index-pattern:foo');
});
});

describe('update', () => {
it('falls back to v6 mappings', async () => {
const id = 'logstash-*';
const type = 'index-pattern';
const version = 2;
const attributes = { title: 'Testing' };

const error = new BadRequest('[document_missing_exception] [config][logstash-*]: document missing', {
body: {
error: {
type: 'document_missing_exception'
}
const id = 'logstash-*';
const type = 'index-pattern';
const version = 2;
const attributes = { title: 'Testing' };
const error = new BadRequest('[document_missing_exception] [config][logstash-*]: document missing', {
body: {
error: {
type: 'document_missing_exception'
}
});
}
});

beforeEach(() => {
callAdminCluster
.onFirstCall().throws(error)
.onSecondCall().returns(Promise.resolve({
Expand All @@ -141,7 +171,10 @@ describe('SavedObjectsClient', () => {
_version: version,
result: 'updated'
}));
});


it('falls back to single-type mappings', async () => {
const response = await savedObjectsClient.update('index-pattern', 'logstash-*', attributes);
expect(response).to.eql({
id,
Expand All @@ -150,6 +183,13 @@ describe('SavedObjectsClient', () => {
attributes
});
});

it('prepends id for single-type', async () => {
await savedObjectsClient.update('index-pattern', 'logstash-*', attributes);

const [, args] = callAdminCluster.getCall(1).args;
expect(args.id).to.eql('index-pattern:logstash-*');
});
});
});
});
3 changes: 2 additions & 1 deletion src/server/saved_objects/client/lib/compatibility.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import uuid from 'uuid';
import { V6_TYPE } from '../saved_objects_client';

/**
Expand Down Expand Up @@ -29,7 +30,7 @@ export function v6BulkCreate(objects, options = {}) {

acc.push({ [method]: {
_type: V6_TYPE,
_id: object.id ? `${object.type}:${object.id}` : undefined
_id: `${object.type}:${object.id || uuid.v1()}`,
} });

acc.push(Object.assign({},
Expand Down
11 changes: 0 additions & 11 deletions src/server/saved_objects/client/lib/handle_es_error.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ const {
BadRequest
} = elasticsearch.errors;

export function isSingleTypeError(error) {
if (!error) return;

return error.type === 'illegal_argument_exception' &&
error.reason.match(/the final mapping would have more than 1 type/);
}

export function handleEsError(error) {
if (!(error instanceof Error)) {
throw new Error('Expected an instance of Error');
Expand Down Expand Up @@ -50,10 +43,6 @@ export function handleEsError(error) {
}

if (error instanceof BadRequest) {
if (isSingleTypeError(get(error, 'body.error'))) {
details.type = 'is_single_type';
}

throw Boom.badRequest(reason, details);
}

Expand Down
2 changes: 1 addition & 1 deletion src/server/saved_objects/client/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { createFindQuery } from './create_find_query';
export { createIdQuery } from './create_id_query';
export { handleEsError, isSingleTypeError } from './handle_es_error';
export { handleEsError } from './handle_es_error';
export { v5BulkCreate, v6BulkCreate } from './compatibility';
export { normalizeEsDoc } from './normalize_es_doc';
export { includedFields } from './included_fields';
15 changes: 8 additions & 7 deletions src/server/saved_objects/client/saved_objects_client.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Boom from 'boom';
import uuid from 'uuid';
import { get } from 'lodash';

import {
createFindQuery,
createIdQuery,
handleEsError,
isSingleTypeError,
v5BulkCreate,
v6BulkCreate,
normalizeEsDoc,
Expand Down Expand Up @@ -40,7 +40,7 @@ export class SavedObjectsClient {
refresh: 'wait_for'
}, {
type: V6_TYPE,
id: options.id ? `${type}:${options.id}` : undefined,
id: `${type}:${options.id || uuid.v1()}`,
body: {
type,
[type]: attributes
Expand Down Expand Up @@ -71,7 +71,7 @@ export class SavedObjectsClient {
const items = get(response, 'items', []);
const missingTypesCount = items.filter(item => {
const method = Object.keys(item)[0];
return isSingleTypeError(get(item, `${method}.error`));
return get(item, `${method}.error.type`) === 'type_missing_exception';
}).length;

const formatFallback = format === 'v5' && items.length > 0 && items.length === missingTypesCount;
Expand All @@ -82,10 +82,10 @@ export class SavedObjectsClient {

return get(response, 'items', []).map((resp, i) => {
const method = Object.keys(resp)[0];
const { id, type, attributes } = objects[i];
const { type, attributes } = objects[i];

return normalizeEsDoc(resp[method], {
id,
id: resp[method]._id,
type,
attributes,
error: resp[method].error ? { message: get(resp[method], 'error.reason') } : undefined
Expand Down Expand Up @@ -233,6 +233,7 @@ export class SavedObjectsClient {
}
}, {
type: V6_TYPE,
id: `${type}:${id}`,
body: {
doc: {
[type]: attributes
Expand All @@ -245,8 +246,8 @@ export class SavedObjectsClient {

_withKibanaIndexAndMappingFallback(method, params, fallbackParams) {
const fallbacks = {
'create': ['is_single_type'],
'index': ['is_single_type'],
'create': ['type_missing_exception'],
'index': ['type_missing_exception'],
'update': ['document_missing_exception']
};

Expand Down

0 comments on commit 6c09a67

Please sign in to comment.