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

Bugfix default index patterns [Health-check] - 4.2 #3232

Merged
merged 7 commits into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

All notable changes to the Wazuh app project will be documented in this file.

## Wazuh v4.2.0 - Kibana 7.10.2 , 7.11.2 - Revision 4202
## Wazuh v4.2.0 - Kibana 7.10.2 , 7.11.2 - Revision 4203

### Added

Expand Down Expand Up @@ -61,6 +61,7 @@ All notable changes to the Wazuh app project will be documented in this file.
- Fixed check for TCP protocol in deploy new agent [#3163](https://github.com/wazuh/wazuh-kibana-app/pull/3163)
- Fixed RBAC issue with agent group permissions [#3181](https://github.com/wazuh/wazuh-kibana-app/pull/3181)
- Fixed change index pattern from menu doesn't work [#3187](https://github.com/wazuh/wazuh-kibana-app/pull/3187)
- Conflict with the creation of the index pattern when performing the Health Check [#3223](https://github.com/wazuh/wazuh-kibana-app/pull/3223)

## Wazuh v4.1.5 - Kibana 7.10.0 , 7.10.2 - Revision 4106

Expand Down
3 changes: 2 additions & 1 deletion public/react-services/generic-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { OdfeUtils } from '../utils';
import { getHttp, getDataPlugin } from '../kibana-services';

export class GenericRequest {
static async request(method, path, payload = null) {
static async request(method, path, payload = null, returnError = false) {
try {
if (!method || !path) {
throw new Error('Missing parameters');
Expand Down Expand Up @@ -104,6 +104,7 @@ export class GenericRequest {
}
}
}
if (returnError) return Promise.reject(err);
return (((err || {}).response || {}).data || {}).message || false
? Promise.reject(err.response.data.message)
: Promise.reject(err || 'Server did not respond');
Expand Down
30 changes: 18 additions & 12 deletions public/react-services/pattern-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
*
* Find more information about this on the LICENSE file.
*/
import { GenericRequest } from './generic-request';
import { AppState } from './app-state';
import { WzMisc } from '../factories/misc';
import { SavedObject } from './saved-objects';
import { getDataPlugin, getToasts, getHttp } from '../kibana-services';
import { WazuhConfig } from '../react-services/wazuh-config';
Expand All @@ -23,26 +21,36 @@ export class PatternHandler {
*/
static async getPatternList(origin) {
try {
var patternList = await SavedObject.getListOfWazuhValidIndexPatterns();
const wazuhConfig = new WazuhConfig();
const { pattern } = wazuhConfig.getConfig();

if (origin == HEALTH_CHECK) {
const wazuhConfig = new WazuhConfig();
const { pattern } = wazuhConfig.getConfig();
const defaultPatterns = [pattern];
const selectedPattern = AppState.getCurrentPattern();
if (selectedPattern && selectedPattern !== pattern) defaultPatterns.push(selectedPattern);
let patternList = await SavedObject.getListOfWazuhValidIndexPatterns(defaultPatterns, origin);

if (origin === HEALTH_CHECK) {
const indexPatternFound = patternList.find((indexPattern) => indexPattern.title === pattern);

if (!indexPatternFound && pattern) {
// if no valid index patterns are found we try to create the wazuh-alerts-*
try {

getToasts().add({
color: 'warning',
title:
`No ${pattern} index pattern was found, proceeding to create it.`,
toastLifeTimeMs: 5000
});

await SavedObject.createWazuhIndexPattern(pattern);
getToasts().addSuccess(`${pattern} index pattern created successfully`);
if (await SavedObject.getExistingIndexPattern(pattern)) {
await SavedObject.refreshIndexPattern(pattern);
getToasts().addSuccess(`${pattern} index pattern updated successfully`);
} else {
await SavedObject.createWazuhIndexPattern(pattern);
getToasts().addSuccess(`${pattern} index pattern created successfully`);
}

patternList = await SavedObject.getListOfWazuhValidIndexPatterns(defaultPatterns, origin);
!AppState.getCurrentPattern() && AppState.setCurrentPattern(pattern);
} catch (err) {
getToasts().addDanger({
Expand All @@ -51,11 +59,10 @@ export class PatternHandler {
toastLifeTimeMs: 3000
});
AppState.removeCurrentPattern();

return;
}
}
patternList = await SavedObject.getListOfWazuhValidIndexPatterns();
}
if (AppState.getCurrentPattern() && patternList.length) {
let filtered = patternList.filter(
Expand All @@ -69,7 +76,6 @@ export class PatternHandler {
console.error("getPatternList", error)
throw new Error('Error Pattern Handler (getPatternList)');
}
return;
}

/**
Expand Down
105 changes: 67 additions & 38 deletions public/react-services/saved-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@
* Find more information about this on the LICENSE file.
*/

import { GenericRequest } from './generic-request';
import { KnownFields } from '../utils/known-fields';
import { FieldsStatistics } from '../utils/statistics-fields';
import { FieldsMonitoring } from '../utils/monitoring-fields';
import { WAZUH_INDEX_TYPE_MONITORING, WAZUH_INDEX_TYPE_STATISTICS, WAZUH_INDEX_TYPE_ALERTS } from '../../common/constants';
import {GenericRequest} from './generic-request';
import {KnownFields} from '../utils/known-fields';
import {FieldsStatistics} from '../utils/statistics-fields';
import {FieldsMonitoring} from '../utils/monitoring-fields';
import {
HEALTH_CHECK,
WAZUH_INDEX_TYPE_ALERTS,
WAZUH_INDEX_TYPE_MONITORING,
WAZUH_INDEX_TYPE_STATISTICS
} from '../../common/constants';

export class SavedObject {
/**
Expand All @@ -25,11 +30,9 @@ export class SavedObject {
try {
const result = await GenericRequest.request(
'GET',
`/api/saved_objects/_find?type=index-pattern&search_fields=title`
`/api/saved_objects/_find?type=index-pattern&fields=title&fields=fields&per_page=9999`
);
const indexPatterns = ((result || {}).data || {}).saved_objects || [];

return indexPatterns;
return ((result || {}).data || {}).saved_objects || [];
} catch (error) {
return ((error || {}).data || {}).message || false
? error.data.message
Expand All @@ -42,44 +45,51 @@ export class SavedObject {
* Returns the full list of index patterns that are valid
* An index is valid if its fields contain at least these 4 fields: 'timestamp', 'rule.groups', 'agent.id' and 'manager.name'
*/
static async getListOfWazuhValidIndexPatterns() {
static async getListOfWazuhValidIndexPatterns(defaultIndexPatterns, where) {
try {
const list = await this.getListOfIndexPatterns();
const result = list.filter(item => {
if (item.attributes && item.attributes.fields) {
const fields = JSON.parse(item.attributes.fields);
const minimum = {
timestamp: true,
'rule.groups': true,
'manager.name': true,
'agent.id': true
};
let validCount = 0;

fields.map(currentField => {
if (minimum[currentField.name]) {
validCount++;
}
});
let result = [];
if (where === HEALTH_CHECK) {
const list = await Promise.all(
defaultIndexPatterns.map(
async (pattern) => await SavedObject.getExistingIndexPattern(pattern)
)
);
result = this.validateIndexPatterns(list);
}

if (validCount === 4) {
return true;
}
}
return false;
});
if (!result.length) {
const list = await this.getListOfIndexPatterns();
result = this.validateIndexPatterns(list);
}

const validIndexPatterns = result.map(item => {
return result.map((item) => {
return { id: item.id, title: item.attributes.title };
});
return validIndexPatterns;
} catch (error) {
return ((error || {}).data || {}).message || false
? error.data.message
: error.message || error;
}
}

static validateIndexPatterns(list) {
return list.filter(item => {
if (item.attributes && item.attributes.fields) {
const fields = JSON.parse(item.attributes.fields);
const minimum = [
'timestamp',
'rule.groups',
'manager.name',
'agent.id',
];
return minimum.every((field => {
return fields.hasOwnProperty(field);
}));
}
return false;
});
}

static async existsOrCreateIndexPattern(patternID) {
const result = await SavedObject.existsIndexPattern(patternID);
if (!result.data) {
Expand All @@ -98,6 +108,23 @@ export class SavedObject {
}
}

/**
*
* Given an index pattern ID, checks if it exists
*/
static async getExistingIndexPattern(patternID) {
try {
const result = await GenericRequest.request(
'GET',
`/api/saved_objects/index-pattern/${patternID}?fields=title&fields=fields`
);

return result.data;
} catch (error) {
if (error && error.response && error.response.status == 404) return false;
return ((error || {}).data || {}).message || false ? error.data.message : error.message || false;
}
}

/**
*
Expand All @@ -107,16 +134,18 @@ export class SavedObject {
try {
const result = await GenericRequest.request(
'GET',
`/api/saved_objects/index-pattern/${patternID}`
`/api/saved_objects/index-pattern/${patternID}?fields=title&fields=fields`
);

const title = (((result || {}).data || {}).attributes || {}).title;
const fields = (((result || {}).data || {}).attributes || {}).fields;
if (title) {
return {
data: 'Index pattern found',
status: true,
statusCode: 200,
title: title
title,
fields
};
}
} catch (error) {
Expand Down Expand Up @@ -195,7 +224,7 @@ export class SavedObject {

/**
* Checks the field has a proper structure
* @param {index-pattern-field} field
* @param {index-pattern-field} field
*/
static isValidField(field) {

Expand Down