mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Remove other unused Add Data code
This commit is contained in:
parent
0d087989f0
commit
b7fd17b492
24 changed files with 0 additions and 1333 deletions
|
@ -1,84 +0,0 @@
|
|||
<h2><em>Follow these instructions to install Filebeat.</em>
|
||||
Now that you've got a fresh pipeline and index pattern, let's throw some data at it!
|
||||
</h2>
|
||||
|
||||
<div class="install-filebeat">
|
||||
<ol>
|
||||
<li>
|
||||
<span>
|
||||
<strong>Install Filebeat</strong> on all servers on which you want to tail logs
|
||||
<a target="_blank" ng-href="{{installStep.docLinks.installation}}">
|
||||
<i aria-hidden="true" class="fa fa-info-circle"></i> instructions
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span>
|
||||
<strong>Point Filebeat</strong> at the log files you want to tail
|
||||
<a target="_blank" ng-href="{{installStep.docLinks.configuration}}">
|
||||
<i aria-hidden="true" class="fa fa-info-circle"></i> instructions
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li ng-if="installStep.results.pipeline.processors.length">
|
||||
<span>
|
||||
<strong>Configure Filebeat</strong> to send data through your new Elasticsearch pipeline
|
||||
<a target="_blank" ng-href="{{installStep.docLinks.elasticsearchOutput}}">
|
||||
<i aria-hidden="true" class="fa fa-info-circle"></i> instructions
|
||||
</a><br/>
|
||||
At minimum you'll need to configure Filebeat's Elasticsearch output with a hostname, an index name, and a
|
||||
<a target="_blank"
|
||||
ng-href="{{installStep.docLinks.elasticsearchOutputAnchorParameters}}">
|
||||
<i aria-hidden="true" class="fa fa-info-circle"></i> paramaters
|
||||
</a> block. Your config should end up looking something like this:<br/>
|
||||
<pre>
|
||||
output:
|
||||
elasticsearch:
|
||||
hosts: ["your-elasticsearch-host"]
|
||||
index: "your-base-index-name"
|
||||
parameters:
|
||||
pipeline: "{{installStep.pipelineId}}"</pre>
|
||||
<em>NOTE</em>: The Filebeat config takes a base index name and automatically rotates the target index by appending "-{date}"
|
||||
to the end, so if your pattern was "filebeat-*" you would make the index name "filebeat" in filebeat.yml.<br />
|
||||
</span>
|
||||
</li>
|
||||
|
||||
|
||||
<li ng-if="!installStep.results.pipeline.processors.length">
|
||||
<span>
|
||||
<strong>Configure Filebeat</strong> to send data to Elasticsearch
|
||||
<a target="_blank" ng-href="{{installStep.docLinks.elasticsearchOutput}}">
|
||||
<i aria-hidden="true" class="fa fa-info-circle"></i> instructions
|
||||
</a><br/>
|
||||
At minimum you'll need to configure Filebeat's Elasticsearch output with a hostname and an index name.
|
||||
Your config should end up looking something like this:<br />
|
||||
<pre>
|
||||
output:
|
||||
elasticsearch:
|
||||
hosts: ["your-elasticsearch-host"]
|
||||
index: "your-base-index-name"</pre>
|
||||
<em>NOTE</em>: The Filebeat config takes a base index name and automatically rotates the target index by appending "-{date}"
|
||||
to the end, so if your pattern was "filebeat-*" you would make the index name "filebeat" in filebeat.yml.<br />
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span>
|
||||
<strong>Run Filebeat</strong> on each server
|
||||
<a target="_blank" ng-href="{{installStep.docLinks.startup}}">
|
||||
<i aria-hidden="true" class="fa fa-info-circle"></i> instructions
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
<strong>Verify your filebeat installation below.</strong> We'll poll your new index pattern for documents and let you know when
|
||||
they show up. If you'd like to skip this step, simply click Done now.
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<pattern-checker pattern="installStep.results.indexPattern.id"/>
|
|
@ -1,23 +0,0 @@
|
|||
import modules from 'ui/modules';
|
||||
import template from './install_filebeat_step.html';
|
||||
import 'ui/pattern_checker';
|
||||
import { patternToIngest } from '../../../../../../common/lib/convert_pattern_and_ingest_name';
|
||||
import { filebeat as docLinks } from '../../../../../../../../ui/public/documentation_links/documentation_links';
|
||||
import './styles/_add_data_install_filebeat_step.less';
|
||||
|
||||
modules.get('apps/management')
|
||||
.directive('installFilebeatStep', function () {
|
||||
return {
|
||||
template: template,
|
||||
scope: {
|
||||
results: '='
|
||||
},
|
||||
bindToController: true,
|
||||
controllerAs: 'installStep',
|
||||
controller: function ($scope) {
|
||||
this.pipelineId = patternToIngest(this.results.indexPattern.id);
|
||||
this.docLinks = docLinks;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
install-filebeat-step {
|
||||
|
||||
.install-filebeat {
|
||||
> ol {
|
||||
padding-left: 1em;
|
||||
|
||||
> li {
|
||||
padding: 4px 0;
|
||||
font-weight: bold;
|
||||
|
||||
> span {
|
||||
font-weight: normal;
|
||||
|
||||
> pre {
|
||||
margin: 7px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<h2><em>Provide some sample logs.</em>
|
||||
Paste in one or more lines from the file you intend to tail. We'll use these samples in the following steps to help
|
||||
you build an ingest pipeline and configure a Kibana index pattern. Log lines can be raw strings or
|
||||
formatted as JSON. If your logs are raw strings but you intend to use
|
||||
<a target="_window" ng-href="{{pasteStep.docLinks.exportedFields}}">Filebeat's metadata</a>,
|
||||
you'll want to paste the JSON as it will come out of Filebeat.
|
||||
</h2>
|
||||
|
||||
<div class="paste-samples form-group">
|
||||
<textarea class="form-control" ng-model="pasteStep.rawSamples" placeholder="Paste your sample log lines here, separated by a newline"></textarea>
|
||||
</div>
|
|
@ -1,41 +0,0 @@
|
|||
import modules from 'ui/modules';
|
||||
import template from './paste_samples_step.html';
|
||||
import { filebeat as docLinks } from '../../../../../../../../ui/public/documentation_links/documentation_links';
|
||||
import _ from 'lodash';
|
||||
import './styles/_add_data_paste_samples_step.less';
|
||||
|
||||
modules.get('apps/management')
|
||||
.directive('pasteSamplesStep', function () {
|
||||
return {
|
||||
template: template,
|
||||
scope: {
|
||||
samples: '=',
|
||||
rawSamples: '='
|
||||
},
|
||||
bindToController: true,
|
||||
controllerAs: 'pasteStep',
|
||||
controller: function ($scope) {
|
||||
this.docLinks = docLinks;
|
||||
|
||||
if (_.isUndefined(this.rawSamples)) {
|
||||
this.rawSamples = '';
|
||||
}
|
||||
|
||||
$scope.$watch('pasteStep.rawSamples', (newValue) => {
|
||||
const splitRawSamples = newValue.split('\n');
|
||||
|
||||
try {
|
||||
this.samples = _.map(splitRawSamples, (sample) => {
|
||||
return JSON.parse(sample);
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
this.samples = _.map(splitRawSamples, (sample) => {
|
||||
return {message: sample};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
.paste-samples {
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
import forEachField from '../lib/for_each_field';
|
||||
import sinon from 'auto-release-sinon';
|
||||
import expect from 'expect.js';
|
||||
|
||||
describe('forEachField', function () {
|
||||
|
||||
let testDoc;
|
||||
|
||||
beforeEach(function () {
|
||||
testDoc = {
|
||||
foo: [
|
||||
{bar: [{'baz': 1}]},
|
||||
{bat: 'boo'}
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
it('should require a plain object argument', function () {
|
||||
expect(forEachField).withArgs([], () => {}).to.throwException(/first argument must be a plain object/);
|
||||
});
|
||||
|
||||
it('should not invoke iteratee if collection is null or empty', function () {
|
||||
const iteratee = sinon.spy();
|
||||
|
||||
forEachField({}, iteratee);
|
||||
|
||||
expect(iteratee.called).to.not.be.ok();
|
||||
});
|
||||
|
||||
it('should call iteratee for each item in an array field, but not for the array itself', function () {
|
||||
const iteratee = sinon.spy();
|
||||
|
||||
forEachField({foo: [1, 2, 3]}, iteratee);
|
||||
|
||||
expect(iteratee.callCount).to.be(3);
|
||||
expect(iteratee.calledWith(1, 'foo')).to.be.ok();
|
||||
expect(iteratee.calledWith(2, 'foo')).to.be.ok();
|
||||
expect(iteratee.calledWith(3, 'foo')).to.be.ok();
|
||||
});
|
||||
|
||||
it('should call iteratee for flattened inner object properties, as well as the object itself', function () {
|
||||
const iteratee = sinon.spy();
|
||||
|
||||
forEachField(testDoc, iteratee);
|
||||
|
||||
expect(iteratee.callCount).to.be(5);
|
||||
expect(iteratee.calledWith(testDoc.foo[0], 'foo')).to.be.ok();
|
||||
expect(iteratee.calledWith(testDoc.foo[1], 'foo')).to.be.ok();
|
||||
expect(iteratee.calledWith(testDoc.foo[0].bar[0], 'foo.bar')).to.be.ok();
|
||||
expect(iteratee.calledWith(1, 'foo.bar.baz')).to.be.ok();
|
||||
expect(iteratee.calledWith('boo', 'foo.bat')).to.be.ok();
|
||||
});
|
||||
|
||||
it('should detect geo_point fields and should not invoke iteratee for its lat and lon sub properties', function () {
|
||||
const iteratee = sinon.spy();
|
||||
const geo = {lat: 38.6631, lon: -90.5771};
|
||||
|
||||
forEachField({ geo }, iteratee);
|
||||
|
||||
expect(iteratee.callCount).to.be(1);
|
||||
expect(iteratee.calledWith(geo, 'geo')).to.be.ok();
|
||||
});
|
||||
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
import isGeoPointObject from '../lib/is_geo_point_object';
|
||||
import expect from 'expect.js';
|
||||
|
||||
describe('isGeoPointObject', function () {
|
||||
|
||||
it('should return true if an object has lat and lon properties', function () {
|
||||
expect(isGeoPointObject({lat: 38.6631, lon: -90.5771})).to.be(true);
|
||||
});
|
||||
|
||||
it('should return false if the value is not an object', function () {
|
||||
expect(isGeoPointObject('foo')).to.be(false);
|
||||
expect(isGeoPointObject(1)).to.be(false);
|
||||
expect(isGeoPointObject(true)).to.be(false);
|
||||
expect(isGeoPointObject(null)).to.be(false);
|
||||
});
|
||||
|
||||
it('should return false if the value is an object without lat an lon properties', function () {
|
||||
expect(isGeoPointObject({foo: 'bar'})).to.be(false);
|
||||
});
|
||||
|
||||
});
|
|
@ -1,91 +0,0 @@
|
|||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
|
||||
describe('pattern review directive', function () {
|
||||
let $rootScope;
|
||||
let $compile;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
beforeEach(ngMock.inject(function ($injector, Private) {
|
||||
$compile = $injector.get('$compile');
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
}));
|
||||
|
||||
describe('handling geopoints', function () {
|
||||
|
||||
it('should detect geo_point fields when they\'re expressed as an object', function () {
|
||||
const scope = $rootScope.$new();
|
||||
scope.sampleDoc = {
|
||||
geoip: {
|
||||
location: {
|
||||
lat: 38.6631,
|
||||
lon: -90.5771
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$compile('<pattern-review-step sample-doc="sampleDoc" index-pattern="indexPattern"></pattern-review-step>')(scope);
|
||||
scope.$digest();
|
||||
|
||||
expect(scope).to.have.property('indexPattern');
|
||||
expect(scope.indexPattern.fields[0].type).to.be('geo_point');
|
||||
});
|
||||
|
||||
it('should not count the lat and lon properties as their own fields', function () {
|
||||
const scope = $rootScope.$new();
|
||||
scope.sampleDoc = {
|
||||
geoip: {
|
||||
location: {
|
||||
lat: 38.6631,
|
||||
lon: -90.5771
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$compile('<pattern-review-step sample-doc="sampleDoc" index-pattern="indexPattern"></pattern-review-step>')(scope);
|
||||
scope.$digest();
|
||||
|
||||
expect(scope).to.have.property('indexPattern');
|
||||
expect(scope.indexPattern.fields[0].type).to.be('geo_point');
|
||||
expect(scope.indexPattern.fields.length).to.be(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('detecting date fields', function () {
|
||||
|
||||
it('should detect sample strings in ISO 8601 format as date fields', function () {
|
||||
const scope = $rootScope.$new();
|
||||
scope.sampleDoc = {
|
||||
isodate: '2004-03-08T00:05:49.000Z'
|
||||
};
|
||||
|
||||
$compile('<pattern-review-step sample-doc="sampleDoc" index-pattern="indexPattern"></pattern-review-step>')(scope);
|
||||
scope.$digest();
|
||||
|
||||
expect(scope).to.have.property('indexPattern');
|
||||
expect(scope.indexPattern.fields[0].type).to.be('date');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('conflicting array values', function () {
|
||||
|
||||
it('should detect heterogeneous arrays and flag them with an error message', function () {
|
||||
const scope = $rootScope.$new();
|
||||
scope.sampleDoc = {
|
||||
badarray: ['foo', 42]
|
||||
};
|
||||
|
||||
const element = $compile('<pattern-review-step sample-doc="sampleDoc" index-pattern="indexPattern"></pattern-review-step>')(scope);
|
||||
const controller = element.controller('patternReviewStep');
|
||||
scope.$digest();
|
||||
|
||||
expect(controller).to.have.property('errors');
|
||||
|
||||
// error message should mentioned the conflicting field
|
||||
expect(controller.errors[0]).to.contain('badarray');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,58 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import isGeoPointObject from './is_geo_point_object';
|
||||
|
||||
// This function recursively traverses an object, visiting each node that elasticsearch would index as a field.
|
||||
// Iteratee is invoked with two arguments: (value, fieldName). fieldName is the name of the field as elasticsearch
|
||||
// would see it. For example:
|
||||
//
|
||||
// const testDoc = {
|
||||
// foo: [
|
||||
// {bar: [{'baz': 1}]},
|
||||
// {bat: 'boo'}
|
||||
// ],
|
||||
// geo: {
|
||||
// lat: 38.6631,
|
||||
// lon: -90.5771
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// forEachField(testDoc, function(value, fieldName) { ... });
|
||||
//
|
||||
// The iteratee would be invoked six times, with the following parameters:
|
||||
// 1. fieldName = 'foo' value = {bar: [{'baz': 1}]}
|
||||
// 2. fieldName = 'foo' value = {bat: 'boo'}
|
||||
// 3. fieldName = 'foo.bar' value = {'baz': 1}
|
||||
// 4. fieldName = 'foo.bar.baz' value = 1
|
||||
// 5. fieldName = 'foo.bat' value = 'boo'
|
||||
// 6. fieldName = 'geo' value = {lat: 38.6631, lon: -90.5771}
|
||||
//
|
||||
// forEachField handles arrays, objects, and geo_points as elasticsearch would. It does not currently handle nested
|
||||
// type fields.
|
||||
|
||||
function forEachFieldAux(value, iteratee, fieldName) {
|
||||
if (!_.isObject(value) || isGeoPointObject(value)) {
|
||||
iteratee(value, fieldName);
|
||||
}
|
||||
else if (_.isPlainObject(value)) {
|
||||
if (!_.isEmpty(fieldName)) {
|
||||
iteratee(value, fieldName);
|
||||
fieldName += '.';
|
||||
}
|
||||
_.forEach(value, (subValue, key) => {
|
||||
forEachFieldAux(subValue, iteratee, fieldName + key);
|
||||
});
|
||||
}
|
||||
else if (_.isArray(value)) {
|
||||
_.forEach(value, (subValue) => {
|
||||
forEachFieldAux(subValue, iteratee, fieldName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default function forEachField(object, iteratee) {
|
||||
if (!_.isPlainObject(object)) {
|
||||
throw new Error('first argument must be a plain object');
|
||||
}
|
||||
|
||||
forEachFieldAux(object, iteratee, '');
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
export default function isGeoPointObject(object) {
|
||||
let retVal = false;
|
||||
|
||||
if (_.isPlainObject(object)) {
|
||||
const keys = _.keys(object);
|
||||
if (keys.length === 2 && _.contains(keys, 'lat') && _.contains(keys, 'lon')) {
|
||||
retVal = true;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<h2><em>Review the index pattern.</em>
|
||||
Here we'll define how and where to store your parsed events. We've made some intelligent guesses for you, but most
|
||||
fields can be changed if we got it wrong!
|
||||
</h2>
|
||||
|
||||
<form name="reviewStep.form">
|
||||
<div class="pattern-review form-inline">
|
||||
<div ng-show="reviewStep.errors.length" class="alert alert-danger">
|
||||
<div ng-repeat="error in reviewStep.errors">{{ error }}</div>
|
||||
</div>
|
||||
<div class="alert alert-danger"
|
||||
ng-show="reviewStep.form.pattern.$dirty && reviewStep.form.pattern.$error.lowercase">
|
||||
Index names must be all lowercase
|
||||
</div>
|
||||
<div class="alert alert-danger"
|
||||
ng-show="reviewStep.form.pattern.$dirty && reviewStep.form.pattern.$error.indexNameInput">
|
||||
An index name must not be empty and cannot contain whitespace or any of the following characters: ", *, \, <, |, ,, >, /, ?
|
||||
</div>
|
||||
|
||||
<label>{{ reviewStep.patternInput.label }}</label>
|
||||
<span id="pattern-help" class="help-block">{{ reviewStep.patternInput.helpText }}</span>
|
||||
<input name="pattern" ng-model="reviewStep.indexPattern.id"
|
||||
class="pattern-input form-control"
|
||||
novalidate
|
||||
required
|
||||
validate-index-name
|
||||
validate-lowercase
|
||||
placeholder="{{reviewStep.patternInput.placeholder}}"
|
||||
aria-describedby="pattern-help"/>
|
||||
<label>
|
||||
<input ng-model="reviewStep.isTimeBased" type="checkbox"/>
|
||||
time based
|
||||
</label>
|
||||
<label ng-if="reviewStep.isTimeBased" class="time-field-input">
|
||||
Time Field
|
||||
<select ng-model="reviewStep.indexPattern.timeFieldName" name="time_field_name" class="form-control">
|
||||
<option ng-repeat="field in reviewStep.dateFields" value="{{field}}">
|
||||
{{field}}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<paginated-table
|
||||
class="pattern-review-field-table"
|
||||
columns="reviewStep.columns"
|
||||
rows="reviewStep.rows"
|
||||
per-page="10">
|
||||
</paginated-table>
|
||||
</form>
|
|
@ -1,132 +0,0 @@
|
|||
import modules from 'ui/modules';
|
||||
import template from './pattern_review_step.html';
|
||||
import _ from 'lodash';
|
||||
import editFieldTypeHTML from '../../partials/_edit_field_type.html';
|
||||
import isGeoPointObject from './lib/is_geo_point_object';
|
||||
import forEachField from './lib/for_each_field';
|
||||
import './styles/_add_data_pattern_review_step.less';
|
||||
import moment from 'moment';
|
||||
import '../../../../../../../../ui/public/directives/validate_lowercase';
|
||||
|
||||
function pickDefaultTimeFieldName(dateFields) {
|
||||
if (_.isEmpty(dateFields)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return _.includes(dateFields, '@timestamp') ? '@timestamp' : dateFields[0];
|
||||
}
|
||||
|
||||
function findFieldsByType(indexPatternFields, type) {
|
||||
return _.map(_.filter(indexPatternFields, {type}), 'name');
|
||||
}
|
||||
|
||||
modules.get('apps/management')
|
||||
.directive('patternReviewStep', function () {
|
||||
return {
|
||||
template: template,
|
||||
scope: {
|
||||
indexPattern: '=',
|
||||
pipeline: '=',
|
||||
sampleDoc: '=',
|
||||
defaultIndexInput: '='
|
||||
},
|
||||
controllerAs: 'reviewStep',
|
||||
bindToController: true,
|
||||
controller: function ($scope, Private) {
|
||||
this.errors = [];
|
||||
const sampleFields = {};
|
||||
|
||||
this.patternInput = {
|
||||
label: 'Index name',
|
||||
helpText: 'The name of the Elasticsearch index you want to create for your data.',
|
||||
defaultValue: '',
|
||||
placeholder: 'Name'
|
||||
};
|
||||
|
||||
if (this.defaultIndexInput) {
|
||||
this.patternInput.defaultValue = this.defaultIndexInput;
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.indexPattern)) {
|
||||
this.indexPattern = {};
|
||||
}
|
||||
|
||||
forEachField(this.sampleDoc, (value, fieldName) => {
|
||||
let type = typeof value;
|
||||
|
||||
if (isGeoPointObject(value)) {
|
||||
type = 'geo_point';
|
||||
}
|
||||
|
||||
if (type === 'string' && moment(value, moment.ISO_8601).isValid()) {
|
||||
type = 'date';
|
||||
}
|
||||
|
||||
if (value === null) {
|
||||
type = 'string';
|
||||
}
|
||||
|
||||
if (!_.isUndefined(sampleFields[fieldName]) && (sampleFields[fieldName].type !== type)) {
|
||||
this.errors.push(`Error in field ${fieldName} - conflicting types '${sampleFields[fieldName].type}' and '${type}'`);
|
||||
}
|
||||
else {
|
||||
sampleFields[fieldName] = {type, value};
|
||||
}
|
||||
});
|
||||
|
||||
_.defaults(this.indexPattern, {
|
||||
id: this.patternInput.defaultValue,
|
||||
title: 'filebeat-*',
|
||||
fields: _(sampleFields)
|
||||
.map((field, fieldName) => {
|
||||
return {name: fieldName, type: field.type};
|
||||
})
|
||||
.reject({type: 'object'})
|
||||
.value()
|
||||
});
|
||||
|
||||
$scope.$watch('reviewStep.indexPattern.id', (value) => {
|
||||
this.indexPattern.title = value;
|
||||
});
|
||||
$scope.$watch('reviewStep.isTimeBased', (value) => {
|
||||
if (value) {
|
||||
this.indexPattern.timeFieldName = pickDefaultTimeFieldName(this.dateFields);
|
||||
}
|
||||
else {
|
||||
delete this.indexPattern.timeFieldName;
|
||||
}
|
||||
});
|
||||
$scope.$watch('reviewStep.indexPattern.fields', (fields) => {
|
||||
this.dateFields = findFieldsByType(fields, 'date');
|
||||
}, true);
|
||||
|
||||
|
||||
this.dateFields = findFieldsByType(this.indexPattern.fields, 'date');
|
||||
this.isTimeBased = !_.isEmpty(this.dateFields);
|
||||
|
||||
const buildRows = () => {
|
||||
this.rows = _.map(this.indexPattern.fields, (field) => {
|
||||
const {type: detectedType, value: sampleValue} = sampleFields[field.name];
|
||||
return [
|
||||
_.escape(field.name),
|
||||
{
|
||||
markup: editFieldTypeHTML,
|
||||
scope: _.assign($scope.$new(), {field: field, detectedType: detectedType, buildRows: buildRows}),
|
||||
value: field.type
|
||||
},
|
||||
typeof sampleValue === 'object' ? _.escape(JSON.stringify(sampleValue)) : _.escape(sampleValue)
|
||||
];
|
||||
});
|
||||
};
|
||||
|
||||
this.columns = [
|
||||
{title: 'Field'},
|
||||
{title: 'Type'},
|
||||
{title: 'Example', sortable: false}
|
||||
];
|
||||
|
||||
buildRows();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
@import (reference) "../../../styles/_add_data_wizard";
|
||||
|
||||
pattern-review-step {
|
||||
margin-bottom: 14px;
|
||||
|
||||
.pattern-review {
|
||||
margin-bottom: 15px;
|
||||
|
||||
label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.time-field-input {
|
||||
padding-left: 14px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.pattern-input {
|
||||
width: 300px;
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
> .help-block {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
paginated-table.pattern-review-field-table {
|
||||
table {
|
||||
border-bottom: 3px solid @settings-filebeat-wizard-panel-bg;
|
||||
|
||||
tr {
|
||||
.form-group;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 0;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
background-color: @settings-filebeat-wizard-panel-bg;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
td {
|
||||
border-top: 3px solid @settings-filebeat-wizard-panel-bg;
|
||||
vertical-align: middle;
|
||||
padding-right: 14px;
|
||||
}
|
||||
|
||||
select {
|
||||
.form-control;
|
||||
.wizard-container.form-control;
|
||||
|
||||
min-width: 105px;
|
||||
}
|
||||
}
|
||||
|
||||
paginate-controls {
|
||||
position: relative;
|
||||
|
||||
ul > li > a {
|
||||
background-color: @settings-filebeat-wizard-panel-bg;
|
||||
}
|
||||
|
||||
form.pagination-size {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
<div class="wizard-container">
|
||||
<div class="wizard-step-headings" ng-class="{complete: wizard.complete}">
|
||||
<span ng-class="{active: wizard.currentStep === 0}"
|
||||
class="wizard-step-heading"
|
||||
ng-click="wizard.setCurrentStep(0)">
|
||||
1. Paste
|
||||
</span>
|
||||
<span ng-class="{active: wizard.currentStep === 1, aheadActive: wizard.currentStep < 1}"
|
||||
class="wizard-step-heading"
|
||||
ng-click="wizard.currentStep < 1 || wizard.setCurrentStep(1)">
|
||||
2. Parse
|
||||
</span>
|
||||
<span ng-class="{active: wizard.currentStep === 2, aheadActive: wizard.currentStep < 2}"
|
||||
class="wizard-step-heading"
|
||||
ng-click="wizard.currentStep < 2 || wizard.setCurrentStep(2)">
|
||||
3. Review
|
||||
</span>
|
||||
<span ng-class="{active: wizard.currentStep === 3, aheadActive: wizard.currentStep < 3}"
|
||||
class="wizard-step-heading"
|
||||
ng-click="wizard.currentStep < 3 || wizard.setCurrentStep(3)">
|
||||
4. Install Filebeat
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div ng-switch="wizard.currentStep">
|
||||
<div ng-switch-when="0">
|
||||
<paste-samples-step samples="wizard.stepResults.samples" raw-samples="wizard.stepResults.rawSamples"></paste-samples-step>
|
||||
<div class="wizard-nav-buttons">
|
||||
<div></div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
ng-disabled="!wizard.stepResults.samples"
|
||||
ng-click="wizard.nextStep()">
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-switch-when="1">
|
||||
<pipeline-setup
|
||||
pipeline="wizard.stepResults.pipeline"
|
||||
samples="wizard.stepResults.samples">
|
||||
</pipeline-setup>
|
||||
|
||||
<div class="wizard-nav-buttons">
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
ng-click="wizard.prevStep()">
|
||||
Prev
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
ng-click="wizard.nextStep()">
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-switch-when="2">
|
||||
<pattern-review-step
|
||||
index-pattern="wizard.stepResults.indexPattern"
|
||||
pipeline="wizard.stepResults.pipeline"
|
||||
sample-doc="wizard.stepResults.pipeline.output">
|
||||
</pattern-review-step>
|
||||
|
||||
<div class="wizard-nav-buttons">
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
ng-click="wizard.prevStep()">
|
||||
Prev
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
ng-disabled="!wizard.stepResults.indexPattern || !wizard.stepResults.indexPattern.id"
|
||||
ng-click="wizard.save()">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-switch-when="3">
|
||||
<install-filebeat-step results="wizard.stepResults"></install-filebeat-step>
|
||||
|
||||
<div class="wizard-nav-buttons">
|
||||
<div></div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
ng-click="wizard.nextStep()">
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,99 +0,0 @@
|
|||
import modules from 'ui/modules';
|
||||
import template from 'plugins/kibana/management/sections/indices/filebeat/directives/filebeat_wizard.html';
|
||||
import IngestProvider from 'ui/ingest';
|
||||
import 'plugins/kibana/management/sections/indices/add_data_steps/pattern_review_step';
|
||||
import 'plugins/kibana/management/sections/indices/add_data_steps/paste_samples_step';
|
||||
import 'plugins/kibana/management/sections/indices/add_data_steps/install_filebeat_step';
|
||||
import '../../styles/_add_data_wizard.less';
|
||||
|
||||
// wrapper directive, which sets up the breadcrumb for all filebeat steps
|
||||
modules.get('apps/management')
|
||||
.directive('filebeatWizard', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: template,
|
||||
scope: {},
|
||||
bindToController: true,
|
||||
controllerAs: 'wizard',
|
||||
controller: function ($scope, AppState, safeConfirm, kbnUrl, Notifier, $window, Private) {
|
||||
const ingest = Private(IngestProvider);
|
||||
const $state = this.state = new AppState();
|
||||
|
||||
var notify = new Notifier({
|
||||
location: 'Add Data'
|
||||
});
|
||||
|
||||
var totalSteps = 4;
|
||||
this.stepResults = {};
|
||||
|
||||
this.setCurrentStep = (step) => {
|
||||
if (!this.complete) {
|
||||
$state.currentStep = step;
|
||||
$state.save();
|
||||
}
|
||||
};
|
||||
this.setCurrentStep(0);
|
||||
|
||||
this.nextStep = () => {
|
||||
if ($state.currentStep + 1 < totalSteps) {
|
||||
this.setCurrentStep($state.currentStep + 1);
|
||||
}
|
||||
else if ($state.currentStep + 1 === totalSteps) {
|
||||
kbnUrl.change('/discover');
|
||||
}
|
||||
};
|
||||
|
||||
this.prevStep = () => {
|
||||
if ($state.currentStep > 0) {
|
||||
this.setCurrentStep($state.currentStep - 1);
|
||||
}
|
||||
};
|
||||
|
||||
this.save = () => {
|
||||
const processors = this.stepResults.pipeline.processors.map(processor => processor.model);
|
||||
return ingest.save(this.stepResults.indexPattern, processors)
|
||||
.then(
|
||||
() => {
|
||||
this.nextStep();
|
||||
},
|
||||
(err) => {
|
||||
notify.error(err);
|
||||
$window.scrollTo(0,0);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.$watch('wizard.state.currentStep', (newValue, oldValue) => {
|
||||
if (this.complete) {
|
||||
$state.currentStep = totalSteps - 1;
|
||||
$state.save();
|
||||
return;
|
||||
}
|
||||
if (newValue + 1 === totalSteps) {
|
||||
this.complete = true;
|
||||
}
|
||||
if (newValue < oldValue) {
|
||||
return safeConfirm('Going back will reset any changes you\'ve made to this step, do you want to continue?')
|
||||
.then(
|
||||
() => {
|
||||
if ($state.currentStep < 1) {
|
||||
delete this.stepResults.pipeline;
|
||||
}
|
||||
if ($state.currentStep < 2) {
|
||||
delete this.stepResults.indexPattern;
|
||||
}
|
||||
this.currentStep = newValue;
|
||||
},
|
||||
() => {
|
||||
$state.currentStep = oldValue;
|
||||
$state.save();
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.currentStep = newValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
<kbn-management-app section="data">
|
||||
<filebeat-wizard/>
|
||||
</kbn-management-app>
|
|
@ -1,8 +0,0 @@
|
|||
import routes from 'ui/routes';
|
||||
import template from 'plugins/kibana/management/sections/indices/filebeat/index.html';
|
||||
import 'plugins/kibana/management/sections/indices/filebeat/directives/filebeat_wizard';
|
||||
|
||||
|
||||
routes.when('/management/data/filebeat', {
|
||||
template: template
|
||||
});
|
|
@ -1,12 +1,8 @@
|
|||
import { registerPost } from './register_post';
|
||||
import { registerDelete } from './register_delete';
|
||||
import { registerProcessors } from './register_processors';
|
||||
import { registerSimulate } from './register_simulate';
|
||||
import { registerFieldCapabilities } from './register_field_capabilities';
|
||||
|
||||
export default function (server) {
|
||||
registerPost(server);
|
||||
registerDelete(server);
|
||||
registerProcessors(server);
|
||||
registerSimulate(server);
|
||||
registerFieldCapabilities(server);
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import Promise from 'bluebird';
|
||||
import handleESError from '../../../lib/handle_es_error';
|
||||
import {ingestToPattern, patternToIngest} from '../../../../common/lib/convert_pattern_and_ingest_name';
|
||||
|
||||
export function registerDelete(server) {
|
||||
server.route({
|
||||
path: '/api/kibana/ingest/{id}',
|
||||
method: 'DELETE',
|
||||
handler: function (req, reply) {
|
||||
const kibanaIndex = server.config().get('kibana.index');
|
||||
const callWithRequest = server.plugins.elasticsearch.callWithRequest;
|
||||
const deletePatternParams = {
|
||||
index: kibanaIndex,
|
||||
type: 'index-pattern',
|
||||
id: req.params.id
|
||||
};
|
||||
|
||||
Promise.all([
|
||||
callWithRequest(req, 'delete', deletePatternParams),
|
||||
callWithRequest(req, 'indices.deleteTemplate', {name: patternToIngest(req.params.id), ignore: [404]})
|
||||
])
|
||||
.then(
|
||||
function (pattern) {
|
||||
reply({success: true});
|
||||
},
|
||||
function (error) {
|
||||
reply(handleESError(error));
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,105 +0,0 @@
|
|||
import Boom from 'boom';
|
||||
import _ from 'lodash';
|
||||
import ingestConfigSchema from '../../../lib/schemas/resources/ingest_config_schema';
|
||||
import handleESError from '../../../lib/handle_es_error';
|
||||
import createMappingsFromPatternFields from '../../../lib/create_mappings_from_pattern_fields';
|
||||
import initDefaultFieldProps from '../../../lib/init_default_field_props';
|
||||
import {ingestToPattern, patternToIngest} from '../../../../common/lib/convert_pattern_and_ingest_name';
|
||||
import { keysToCamelCaseShallow } from '../../../../common/lib/case_conversion';
|
||||
|
||||
export function registerPost(server) {
|
||||
const kibanaIndex = server.config().get('kibana.index');
|
||||
|
||||
function patternRollback(rootError, indexPatternId, boundCallWithRequest) {
|
||||
const deleteParams = {
|
||||
index: kibanaIndex,
|
||||
type: 'index-pattern',
|
||||
id: indexPatternId
|
||||
};
|
||||
|
||||
return boundCallWithRequest('delete', deleteParams)
|
||||
.then(
|
||||
() => {
|
||||
throw rootError;
|
||||
},
|
||||
(patternDeletionError) => {
|
||||
throw new Error(
|
||||
`index-pattern ${indexPatternId} created successfully but index template
|
||||
creation failed. Failed to rollback index-pattern creation, must delete manually.
|
||||
${patternDeletionError.toString()}
|
||||
${rootError.toString()}`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
server.route({
|
||||
path: '/api/kibana/ingest',
|
||||
method: 'POST',
|
||||
config: {
|
||||
validate: {
|
||||
payload: ingestConfigSchema
|
||||
}
|
||||
},
|
||||
handler: async function (req, reply) {
|
||||
const uiSettings = server.uiSettings();
|
||||
const metaFields = await uiSettings.get('metaFields');
|
||||
const boundCallWithRequest = _.partial(server.plugins.elasticsearch.callWithRequest, req);
|
||||
const requestDocument = _.cloneDeep(req.payload);
|
||||
const indexPattern = keysToCamelCaseShallow(requestDocument.index_pattern);
|
||||
const indexPatternId = indexPattern.id;
|
||||
const ingestConfigName = patternToIngest(indexPatternId);
|
||||
delete indexPattern.id;
|
||||
|
||||
const mappings = createMappingsFromPatternFields(indexPattern.fields);
|
||||
const indexPatternMetaFields = _.map(metaFields, name => ({name}));
|
||||
|
||||
indexPattern.fields = initDefaultFieldProps(indexPattern.fields.concat(indexPatternMetaFields));
|
||||
indexPattern.fields = JSON.stringify(indexPattern.fields);
|
||||
indexPattern.fieldFormatMap = JSON.stringify(indexPattern.fieldFormatMap);
|
||||
|
||||
// Set up call with request params
|
||||
const patternCreateParams = {
|
||||
index: kibanaIndex,
|
||||
type: 'index-pattern',
|
||||
id: indexPatternId,
|
||||
body: indexPattern
|
||||
};
|
||||
|
||||
const templateParams = {
|
||||
order: 1,
|
||||
create: true,
|
||||
name: ingestConfigName,
|
||||
body: {
|
||||
template: indexPatternId,
|
||||
mappings: {
|
||||
_default_: {
|
||||
properties: mappings
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return boundCallWithRequest('indices.exists', {index: indexPatternId})
|
||||
.then((matchingIndices) => {
|
||||
if (matchingIndices) {
|
||||
throw Boom.conflict('Cannot create an index pattern via this API if existing indices already match the pattern');
|
||||
}
|
||||
|
||||
return boundCallWithRequest('create', patternCreateParams)
|
||||
.then(() => {
|
||||
return boundCallWithRequest('indices.putTemplate', templateParams)
|
||||
.catch((templateError) => {return patternRollback(templateError, indexPatternId, boundCallWithRequest);});
|
||||
});
|
||||
})
|
||||
.then(
|
||||
function () {
|
||||
reply().code(204);
|
||||
},
|
||||
function (error) {
|
||||
reply(handleESError(error));
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,63 +0,0 @@
|
|||
define(function (require) {
|
||||
var Promise = require('bluebird');
|
||||
var createTestData = require('intern/dojo/node!../../../unit/api/ingest/data');
|
||||
var _ = require('intern/dojo/node!lodash');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
|
||||
|
||||
return function (bdd, scenarioManager, request) {
|
||||
|
||||
bdd.describe('DELETE ingest', function deleteIngestConfig() {
|
||||
|
||||
bdd.beforeEach(function () {
|
||||
return scenarioManager.reload('emptyKibana')
|
||||
.then(function () {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204);
|
||||
});
|
||||
});
|
||||
|
||||
bdd.afterEach(function () {
|
||||
return request.del('/kibana/ingest/logstash-*')
|
||||
.then(function () {
|
||||
return scenarioManager.client.indices.deleteTemplate({name: 'kibana-logstash-*'})
|
||||
.catch(function (err) {
|
||||
if (err.status !== 404) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should return 200 for successful deletion of pattern and template', function () {
|
||||
return request.del('/kibana/ingest/logstash-*')
|
||||
.expect(200)
|
||||
.then(function () {
|
||||
return request.get('/kibana/ingest/logstash-*').expect(404);
|
||||
})
|
||||
.then(function () {
|
||||
return scenarioManager.client.indices.getTemplate({name: 'kibana-logstash-*'})
|
||||
.catch(function (error) {
|
||||
expect(error.status).to.be(404);
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
return scenarioManager.client.transport.request({
|
||||
path: '_ingest/pipeline/kibana-logstash-*',
|
||||
method: 'GET'
|
||||
})
|
||||
.catch(function (error) {
|
||||
expect(error.status).to.be(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should return 404 for a non-existent id', function () {
|
||||
return request.del('/kibana/ingest/doesnotexist')
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
});
|
|
@ -1,216 +0,0 @@
|
|||
define(function (require) {
|
||||
var Promise = require('bluebird');
|
||||
var createTestData = require('intern/dojo/node!../../../unit/api/ingest/data');
|
||||
var _ = require('intern/dojo/node!lodash');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
|
||||
return function (bdd, scenarioManager, request) {
|
||||
bdd.describe('POST ingest', function postIngest() {
|
||||
|
||||
bdd.beforeEach(function () {
|
||||
return scenarioManager.reload('emptyKibana');
|
||||
});
|
||||
|
||||
bdd.afterEach(function () {
|
||||
return request.del('/kibana/ingest/logstash-*')
|
||||
.then(function () {
|
||||
return scenarioManager.client.indices.delete({
|
||||
index: 'logstash-*'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should return 400 for an invalid payload', function invalidPayload() {
|
||||
return Promise.all([
|
||||
request.post('/kibana/ingest').expect(400),
|
||||
|
||||
request.post('/kibana/ingest')
|
||||
.send({})
|
||||
.expect(400),
|
||||
|
||||
request.post('/kibana/ingest')
|
||||
.send(_.set(createTestData(), 'index_pattern.title', false))
|
||||
.expect(400),
|
||||
|
||||
request.post('/kibana/ingest')
|
||||
.send(_.set(createTestData(), 'index_pattern.fields', {}))
|
||||
.expect(400),
|
||||
|
||||
request.post('/kibana/ingest')
|
||||
.send(_.set(createTestData(), 'index_pattern.fields', []))
|
||||
.expect(400),
|
||||
|
||||
// Fields must have a name and type
|
||||
request.post('/kibana/ingest')
|
||||
.send(_.set(createTestData(), 'index_pattern.fields', [{count: 0}]))
|
||||
.expect(400)
|
||||
]);
|
||||
});
|
||||
|
||||
bdd.it('should return 204 when an ingest config is successfully created', function createIngestConfig() {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204);
|
||||
});
|
||||
|
||||
bdd.it('should create an index template if a fields array is included', function createTemplate() {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204)
|
||||
.then(function () {
|
||||
return scenarioManager.client.indices.getTemplate({name: 'kibana-logstash-*'});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should successfully create new indices based on the template', function newIndices() {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204)
|
||||
.then(function () {
|
||||
return scenarioManager.client.create({
|
||||
index: 'logstash-1',
|
||||
type: 'foo',
|
||||
id: '1',
|
||||
body: {
|
||||
ip: '192.168.1.1',
|
||||
'@timestamp': '2015-09-20T10:28:22.684Z',
|
||||
agent: 'Jack',
|
||||
bytes: 9001,
|
||||
geo: {coordinates: {lat: 43.07260861, lon: -92.61077833}}
|
||||
}
|
||||
})
|
||||
.then(function (response) {
|
||||
expect(response.created).to.be.ok();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should provide defaults for field properties', function createTemplate() {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204)
|
||||
.then(function () {
|
||||
return scenarioManager.client.get({
|
||||
index: '.kibana',
|
||||
type: 'index-pattern',
|
||||
id: 'logstash-*'
|
||||
})
|
||||
.then(function (res) {
|
||||
var fields = JSON.parse(res._source.fields);
|
||||
// @timestamp was created with only name and type, all other fields should be set as defaults by API
|
||||
expect(res._source.title).to.be('logstash-*');
|
||||
expect(fields[1].name).to.be('@timestamp');
|
||||
expect(fields[1].type).to.be('date');
|
||||
expect(fields[1].count).to.be(0);
|
||||
expect(fields[1].scripted).to.be(false);
|
||||
expect(fields[1].indexed).to.be(true);
|
||||
expect(fields[1].analyzed).to.be(false);
|
||||
expect(fields[1].doc_values).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should include meta fields specified in uiSettings in the index pattern', function metaFields() {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204)
|
||||
.then(function () {
|
||||
return scenarioManager.client.get({
|
||||
index: '.kibana',
|
||||
type: 'index-pattern',
|
||||
id: 'logstash-*'
|
||||
})
|
||||
.then(function (res) {
|
||||
const fields = JSON.parse(res._source.fields);
|
||||
const sourceField = _.find(fields, {name: '_source'});
|
||||
expect(sourceField).to.be.ok();
|
||||
expect(sourceField).to.have.property('name', '_source');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should create index template with _default_ mappings based on the info in the ingest config',
|
||||
function createTemplate() {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204)
|
||||
.then(function () {
|
||||
return scenarioManager.client.indices.getTemplate({name: 'kibana-logstash-*'})
|
||||
.then(function (template) {
|
||||
var mappings = template['kibana-logstash-*'].mappings._default_.properties;
|
||||
expect(mappings).to.be.ok();
|
||||
expect(_.isEqual(mappings.ip, {index: true, type: 'ip', doc_values: true})).to.be.ok();
|
||||
expect(_.isEqual(mappings['@timestamp'], {index: true, type: 'date', doc_values: true})).to.be.ok();
|
||||
expect(_.isEqual(mappings.bytes, {index: true, type: 'double', doc_values: true})).to.be.ok();
|
||||
|
||||
// object fields are mapped as such, with individual mappings for each of their properties
|
||||
expect(_.isEqual(mappings.geo, {
|
||||
properties: {
|
||||
coordinates: {
|
||||
index: true,
|
||||
type: 'geo_point',
|
||||
doc_values: true
|
||||
}
|
||||
}
|
||||
})).to.be.ok();
|
||||
|
||||
// strings should be mapped as multi fields
|
||||
expect(mappings.agent).to.have.property('fields');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should return 409 conflict when a pattern with the given ID already exists', function patternConflict() {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(204)
|
||||
.then(function () {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(409);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
bdd.it('should return 409 conflict when an index template with the given ID already exists', function templateConflict() {
|
||||
return scenarioManager.client.indices.putTemplate({
|
||||
name: 'kibana-logstash-*', body: {
|
||||
template: 'logstash-*'
|
||||
}
|
||||
}).then(function () {
|
||||
return request.post('/kibana/ingest')
|
||||
.send(createTestData())
|
||||
.expect(409);
|
||||
})
|
||||
.then(function () {
|
||||
return scenarioManager.client.indices.deleteTemplate({
|
||||
name: 'kibana-logstash-*'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should return 409 conflict when the pattern matches existing indices',
|
||||
function existingIndicesConflict() {
|
||||
var ingestConfig = createTestData();
|
||||
ingestConfig.index_pattern.id = ingestConfig.index_pattern.title = '.kib*';
|
||||
|
||||
return request.post('/kibana/ingest')
|
||||
.send(ingestConfig)
|
||||
.expect(409);
|
||||
});
|
||||
|
||||
bdd.it('should enforce snake_case in the request body', function () {
|
||||
var ingestConfig = createTestData();
|
||||
ingestConfig.index_pattern = _.mapKeys(ingestConfig.index_pattern, function (value, key) {
|
||||
return _.camelCase(key);
|
||||
});
|
||||
|
||||
return request.post('/kibana/ingest')
|
||||
.send(ingestConfig)
|
||||
.expect(400);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
});
|
|
@ -6,8 +6,6 @@ define(function (require) {
|
|||
var url = require('intern/dojo/node!url');
|
||||
var _ = require('intern/dojo/node!lodash');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
var post = require('./_post');
|
||||
var del = require('./_del');
|
||||
var simulate = require('./_simulate');
|
||||
var processors = require('./_processors');
|
||||
var processorTypes = require('./processors/index');
|
||||
|
@ -25,8 +23,6 @@ define(function (require) {
|
|||
return scenarioManager.unload('emptyKibana');
|
||||
});
|
||||
|
||||
post(bdd, scenarioManager, request);
|
||||
del(bdd, scenarioManager, request);
|
||||
simulate(bdd, scenarioManager, request);
|
||||
processors(bdd, scenarioManager, request);
|
||||
processorTypes(bdd, scenarioManager, request);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue