Updated GET-all api endpoint and tests to use the new resource schema

This commit is contained in:
Matthew Bargar 2015-12-10 19:59:22 -05:00
parent 7ce3f1e790
commit 636b444bf5
14 changed files with 116 additions and 108 deletions

View file

@ -1,45 +0,0 @@
const expect = require('expect.js');
const stitchPatternAndMappings = require('../stitch_pattern_and_mappings');
const correctResult = require('../../../../../fixtures/index_pattern_with_mappings.json');
const indexPattern = {
title: 'logstash-*',
timeFieldName: '@timestamp',
fields: [
{
name: 'geo.coordinates',
count: 0,
scripted: false
},
{
name: 'ip',
count: 2,
scripted: false
}
]
};
const mappings = {
'geo.coordinates': {
index: 'not_analyzed',
type: 'geo_point',
doc_values: false
},
'ip': {
index: 'not_analyzed',
type: 'ip',
doc_values: true
}
};
describe('stitchPatternAndMappings', function () {
it('should fill in the mapping info in a given index pattern with a provided list of mappings', function () {
var result = stitchPatternAndMappings(indexPattern, mappings);
expect(result).to.eql(correctResult);
expect(result).to.have.property('fields');
expect(result.fields[0].mapping.type).to.be('geo_point');
});
});

View file

@ -0,0 +1,8 @@
module.exports = function createApiDocument(primary, included) {
const doc = {data: primary};
if (included) {
doc.included = included;
}
return doc;
};

View file

@ -0,0 +1,8 @@
module.exports = function createRelationshipObject(type, id) {
return {
data: {
type: type,
id: id
}
};
};

View file

@ -0,0 +1,12 @@
module.exports = function createResourceObject(type, id, attributes, relationships) {
const resource = {
type: type,
id: id,
attributes: attributes
};
if (relationships) {
resource.relationships = relationships;
}
return resource;
};

View file

@ -1,12 +1,12 @@
const Joi = require('joi');
const createApiDocumentSchema = require('./create_api_document_schema');
const createResourceObject = require('./create_resource_object');
const relationshipObjectSchema = require('./relationship_object_schema');
const createApiDocumentSchema = require('../common/create_api_document_schema');
const createResourceObjectSchema = require('../common/create_resource_object_schema');
const relationshipObjectSchema = require('../common/relationship_object_schema');
module.exports = {
post: createApiDocumentSchema(
createResourceObject(
createResourceObjectSchema(
Joi.object({
title: Joi.string().required(),
time_field_name: Joi.string(),
@ -25,7 +25,7 @@ module.exports = {
})
),
Joi.array().items(
createResourceObject(
createResourceObjectSchema(
Joi.object({
template: Joi.string().required(),
order: Joi.number().integer(),
@ -38,7 +38,7 @@ module.exports = {
// No attributes are required for an update
// Templates can't be updated in an index_pattern PUT
put: createApiDocumentSchema(
createResourceObject(
createResourceObjectSchema(
Joi.object({
title: Joi.string(),
time_field_name: Joi.string(),

View file

@ -1,19 +0,0 @@
const _ = require('lodash');
/**
*
* @param {Object} pattern - An index pattern from .kibana
* @param {Object} mappings - Mappings from the template or indices that match the pattern, keyed by field name
* @returns {Object} - The index pattern with the 'mapping' property added to each object in the fields array, matched
* from given array of mappings
*/
module.exports = function stitchPatternAndMappings(pattern, mappings) {
_.forEach(mappings, (value, key) => {
let field = _.find(pattern.fields, {name: key});
if (field) {
field.mapping = value;
}
});
return pattern;
};

View file

@ -4,6 +4,9 @@ const getMappings = require('../../../lib/get_mappings');
const stitchPatternAndMappings = require('../../../lib/stitch_pattern_and_mappings');
const removeDeprecatedFieldProps = require('../../../lib/remove_deprecated_field_props');
const handleESError = require('../../../lib/handle_es_error');
const createApiDocument = require('../../../lib/api_document_builders/create_api_document');
const createRelationshipObject = require('../../../lib/api_document_builders/create_relationship_object');
const createResourceObject = require('../../../lib/api_document_builders/create_resource_object');
module.exports = function registerGet(server) {
@ -18,6 +21,7 @@ module.exports = function registerGet(server) {
method: 'GET',
handler: function (req, reply) {
const boundCallWithRequest = _.partial(server.plugins.elasticsearch.callWithRequest, req);
const shouldIncludeTemplate = req.query.include === 'template';
const params = {
index: '.kibana',
@ -34,23 +38,41 @@ module.exports = function registerGet(server) {
const hits = results.hits.hits;
return _.map(hits, (patternHit) => {
patternHit._source.fields = JSON.parse(patternHit._source.fields);
return patternHit._source;
let relationshipsObject;
if (patternHit._source.template_id) {
relationshipsObject = {
template: createRelationshipObject('index_templates', patternHit._source.template_id)
};
delete patternHit._source.template_id;
}
const snakeAttributes = convertToSnakeCase(patternHit._source);
return createResourceObject('index_patterns', patternHit._id, snakeAttributes, relationshipsObject);
});
})
.then((patterns) => {
return Promise.map(patterns, (pattern) => {
return getMappings(pattern.title, boundCallWithRequest).catch(() => {
return {};
})
.then((mappings) => {
return stitchPatternAndMappings(pattern, mappings);
if (!shouldIncludeTemplate) {
return createApiDocument(patterns);
}
const templateIdSet = new Set();
patterns.forEach(pattern => {
const templateId = _.get(pattern, 'relationships.template.data.id');
if (templateId) {
templateIdSet.add(templateId);
}
});
return Promise.map(Array.from(templateIdSet), (templateId) => {
return boundCallWithRequest('indices.getTemplate', {name: templateId})
.then((template) => {
return createResourceObject('index_templates', templateId, template[templateId]);
});
})
.then((templates) => {
return createApiDocument(patterns, templates);
});
})
.then(removeDeprecatedFieldProps)
.then((patterns) => {
return _.map(patterns, convertToSnakeCase);
})
.then(
function (patterns) {
reply(patterns);

View file

@ -1,7 +1,7 @@
const Boom = require('boom');
const _ = require('lodash');
const {templateToPattern, patternToTemplate} = require('../../../lib/convert_pattern_and_template_name');
const indexPatternSchema = require('../../../lib/schemas/index_pattern_schema');
const indexPatternSchema = require('../../../lib/schemas/resources/index_pattern_schema');
const handleESError = require('../../../lib/handle_es_error');
const addMappingInfoToPatternFields = require('../../../lib/add_mapping_info_to_pattern_fields');
@ -28,13 +28,14 @@ module.exports = function registerPost(server) {
if (!_.isEmpty(templateResource)) {
addMappingInfoToPatternFields(indexPattern, templateResource.attributes);
indexPattern.template_id = templateResource.id;
}
indexPattern.fields = JSON.stringify(indexPattern.fields);
const patternCreateParams = {
index: '.kibana',
type: 'index-pattern',
id: indexPattern.title,
id: indexPatternId,
body: indexPattern
};
@ -63,13 +64,13 @@ module.exports = function registerPost(server) {
const deleteParams = {
index: '.kibana',
type: 'index-pattern',
id: indexPattern.title
id: indexPatternId
};
return callWithRequest(req, 'delete', deleteParams)
.then(() => {
throw templateError;
}, () => {
throw new Error(`index-pattern ${indexPattern.title} created successfully but index template
throw new Error(`index-pattern ${indexPatternId} created successfully but index template
creation failed. Failed to rollback index-pattern creation, must delete manually.`);
});
});

View file

@ -1,5 +1,5 @@
const Boom = require('boom');
const indexPatternSchema = require('../../../lib/schemas/index_pattern_schema');
const indexPatternSchema = require('../../../lib/schemas/resources/index_pattern_schema');
const _ = require('lodash');
const handleESError = require('../../../lib/handle_es_error');

View file

@ -3,7 +3,7 @@ define(function (require) {
var expect = require('intern/dojo/node!expect.js');
var createTestData = require('intern/dojo/node!../../../unit/api/index_patterns/data');
var Promise = require('bluebird');
var indexPatternSchema = require('intern/dojo/node!../../../../src/plugins/kibana/server/lib/schemas/index_pattern_schema');
var indexPatternSchema = require('intern/dojo/node!../../../../src/plugins/kibana/server/lib/schemas/resources/index_pattern_schema');
var Joi = require('intern/dojo/node!joi');
function expectSnakeCase(object) {
@ -19,11 +19,31 @@ define(function (require) {
bdd.before(function () {
return scenarioManager.reload('emptyKibana').then(function () {
return Promise.all([
request.post('/kibana/index_patterns').send(createTestData().indexPatternWithMappings),
request.post('/kibana/index_patterns').send(_.assign(createTestData().indexPatternWithMappings, {title: 'foo'})),
request.post('/kibana/index_patterns').send(_.assign(createTestData().indexPatternWithMappings, {title: 'bar*'})),
request.post('/kibana/index_patterns').send(_.assign(createTestData().indexPatternWithMappings,
{title: '[.marvel-es-]YYYY.MM.DD'}))
request.post('/kibana/index_patterns').send(createTestData().indexPatternWithTemplate),
request.post('/kibana/index_patterns').send(
_(createTestData().indexPatternWithTemplate)
.set('data.attributes.title', 'foo')
.set('data.id', 'foo')
.set('included[0].id', 'kibana-foo')
.set('included[0].attributes.template', 'foo')
.value()
),
request.post('/kibana/index_patterns').send(
_(createTestData().indexPatternWithTemplate)
.set('data.attributes.title', 'bar*')
.set('data.id', 'bar*')
.set('included[0].id', 'kibana-bar*')
.set('included[0].attributes.template', 'bar*')
.value()
),
request.post('/kibana/index_patterns').send(
_(createTestData().indexPatternWithTemplate)
.set('data.attributes.title', '[.marvel-es-]YYYY.MM.DD')
.set('data.id', '[.marvel-es-]YYYY.MM.DD')
.set('included[0].id', 'kibana-.marvel-es-*')
.set('included[0].attributes.template', '.marvel-es-*')
.value()
)
]).then(function () {
return scenarioManager.client.indices.refresh({
index: '.kibana'
@ -45,8 +65,8 @@ define(function (require) {
return request.get('/kibana/index_patterns')
.expect(200)
.then(function (res) {
expect(res.body).to.be.an('array');
expect(res.body.length).to.be(4);
expect(res.body.data).to.be.an('array');
expect(res.body.data.length).to.be(4);
});
});
@ -54,7 +74,10 @@ define(function (require) {
return request.get('/kibana/index_patterns')
.expect(200)
.then(function (res) {
_.forEach(res.body, expectSnakeCase);
_.forEach(res.body.data, function (resource) {
expectSnakeCase(resource);
expectSnakeCase(resource.attributes);
});
});
});
@ -78,7 +101,7 @@ define(function (require) {
});
bdd.it('should return mappings info from the indices if there is no template', function () {
var pattern = createTestData().indexPatternWithMappings;
var pattern = createTestData().indexPatternWithTemplate;
pattern.fields = _.map(pattern.fields, function (field) {
return _.omit(field, 'mapping');
});

View file

@ -10,7 +10,7 @@ define(function (require) {
bdd.beforeEach(function () {
return scenarioManager.reload('emptyKibana').then(function () {
return request.post('/kibana/index_patterns').send(createTestData().indexPatternWithMappings);
return request.post('/kibana/index_patterns').send(createTestData().indexPatternWithTemplate);
});
});
@ -19,12 +19,10 @@ define(function (require) {
});
bdd.it('should return 200 for a successful update', function () {
var pattern = createTestData().indexPatternWithMappings;
pattern.fields = _.map(pattern.fields, function (field) {
return _.omit(field, 'mapping');
});
pattern.time_field_name = 'foo';
pattern.fields[0].count = 5;
var pattern = createTestData().indexPatternWithTemplate;
delete pattern.included;
pattern.data.attributes.time_field_name = 'foo';
pattern.data.attributes.fields[0].count = 5;
return request.put('/kibana/index_patterns/logstash-*')
.send(pattern)
@ -39,7 +37,7 @@ define(function (require) {
});
bdd.it('should return 400 if you try to modify the title', function () {
var pattern = createTestData().indexPatternWithMappings;
var pattern = createTestData().indexPatternWithTemplate;
pattern.fields = _.map(pattern.fields, function (field) {
return _.omit(field, 'mapping');
});
@ -52,7 +50,7 @@ define(function (require) {
bdd.it('should return 400 if you try to update mappings', function () {
return request.put('/kibana/index_patterns/logstash-*')
.send(createTestData().indexPatternWithMappings)
.send(createTestData().indexPatternWithTemplate)
.expect(400);
});
@ -73,18 +71,18 @@ define(function (require) {
//fields must be an array
request.put('/kibana/index_patterns/logstash-*')
.send(_.assign(omitMappings(createTestData().indexPatternWithMappings), {fields: {}}))
.send(_.assign(omitMappings(createTestData().indexPatternWithTemplate), {fields: {}}))
.expect(400),
// field objects must have a name
request.put('/kibana/index_patterns/logstash-*')
.send(_.assign(omitMappings(createTestData().indexPatternWithMappings), {fields: [{count: 0}]}))
.send(_.assign(omitMappings(createTestData().indexPatternWithTemplate), {fields: [{count: 0}]}))
.expect(400)
]);
});
bdd.it('should return 404 for a non-existent id', function () {
var pattern = createTestData().indexPatternWithMappings;
var pattern = createTestData().indexPatternWithTemplate;
pattern.fields = _.map(pattern.fields, function (field) {
return _.omit(field, 'mapping');
});