Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

Commit

Permalink
Alert handing changes:
Browse files Browse the repository at this point in the history
    * Alerts are ignored if the related rule is not active
    * Alerts of resetType "Manual" trigger only actions if there is no existing unsuppressed alert with state "New"
    * If Alerts are not triggering but valid, they are stored in DB as suppressed events
    * GUI is only showing active, i.e. non-suppressed event
    * URI parameter "active=true" can be used to get only non-suppressed event. Default behavior is to provide all events.
    * Introduced new DB upgrade logic with sequelize migrations
    * Updated createDB script to terminate correctly
    * Added upgradeDB script which can be used by Helm to upgrade DB

Signed-off-by: Marcel Wagner <wagmarcel@web.de>
  • Loading branch information
wagmarcel committed Oct 26, 2019
1 parent ee12fbf commit 42370b3
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 60 deletions.
59 changes: 49 additions & 10 deletions public-interface/admin/createDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,35 +28,74 @@ CreateDB.prototype.create = function(){
host: config.postgres.options.replication.write.host,
database: 'postgres',
password: config.postgres.su_password,
port: config.postgres.options.replication.write.port,
port: config.postgres.options.port,
});
const query = {text: 'CREATE DATABASE ' +
config.postgres.database + ';'
};
client.connect()
client.connect(
)
.then(() => console.log("Connected"))
.catch(function(err) {
console.log("Cannot connect: " + err);
process.exit(1);
})
.then(function() {
console.log("Executing query: ", query.text);
return client.query(query);
})
/*.catch(function(err) {
console.log("Cannot create db: " + err);
console.log("OK to continue!");
})*/
.then(function() {
console.log("Connected to postgres");
query.text = 'CREATE USER ' + config.postgres.su_username +
' WITH PASSWORD \'' + config.postgres.su_password + '\';';
console.log("Trying to create PG user. Executing query: ", query.text);
return client.query(query);
})
.catch(function(err) {
console.log("Cannot create user: " + err);
console.log("OK to continue ");
})
.then(function() {
query.text = 'CREATE USER ' + config.postgres.username +
' WITH PASSWORD ' + config.postgres.password + ';' +
' GRANT CONNECT ON DATABASE ' + config.postgres.database +
query.text = ' GRANT CONNECT ON DATABASE ' + config.postgres.database +
' TO ' + config.postgres.username + ';';
return client.query();
console.log("Trying grant rights to PG user. Executing query: ", query.text);
return client.query(query);
})
.catch(function(err) {
console.log("Cannot create user: " + err);
console.log("OK to continue ");
})
.then(function() {
query.text = 'CREATE DATABASE test; ' +
'GRANT ALL PRIVILEGES ON DATABASE test TO ' +
query.text = 'CREATE DATABASE test;';
console.log("Trying to create test database. Executing query: ", query.text);
return client.query(query);
})
.then(function() {
query.text = 'GRANT ALL PRIVILEGES ON DATABASE test TO ' +
config.postgres.su_username + '; ' +
'GRANT CONNECT ON DATABASE test TO ' +
config.postgres.username + ';';
return client.query();
console.log("Trying to create test database. Executing query: ", query.text);
return client.query(query);
})
.catch(function(err) {
console.log("Cannot create db test: " + err);
console.log("OK to continue ");
})
.then(() => {
console.log("Trying to create DB models ...");
return models.createDatabase();

})
.catch(function(err) {
console.log("Cannot create models: " + err);
console.log("OK to continue ");
})
.then(function() {
console.log("Trying to create system users.");
return systemUsers.create();
})
.then(function() {
Expand Down
6 changes: 6 additions & 0 deletions public-interface/admin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ var addUser = require('./addUser');
var RemoveTestUser = require('./removeTestUser');
var ResetDB = require('./resetDB');
var CreateDB = require('./createDB');
var UpdateDB = require('./updateDB');
var command = process.argv[2];
var arg = process.argv[3];

switch (command) {
case 'addUser':
Expand All @@ -44,6 +46,10 @@ case 'createDB':
var databaseCreater = new CreateDB();
databaseCreater.create();
break;
case 'updateDB':
var databaseUpdater = new UpdateDB();
databaseUpdater.update(arg);
break;
default:
console.log ("Command : ", command , " not supported ");
}
30 changes: 30 additions & 0 deletions public-interface/admin/updateDB.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const config = require('../config');
const { exec } = require('child_process');

var UpdateDB = function(){};

UpdateDB.prototype.update = function(test) {
var database = config.postgres.database;
if (test === "test") {
database = "test";
}

var cdCommand = "cd /app/iot-entities/postgresql;";
var dbupdateCommand = "npx sequelize-cli db:migrate --url postgres://" +
config.postgres.su_username +
":" + config.postgres.su_password +
"@" + config.postgres.options.replication.write.host +
"/" + database;
console.log("Executing " + cdCommand + dbupdateCommand);
exec(cdCommand + dbupdateCommand, (err, stdout, stderr) => {
if (err) {
console.log("Error: ", err);
process.exit(1);
}
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
process.exit(0);
});
};

module.exports = UpdateDB;
14 changes: 10 additions & 4 deletions public-interface/dashboard/public/js/services/alerts_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ iotServices.factory('alertsService', ['$http', 'utilityService','sessionService'
method: 'GET',
url: url,
params: {
"_" : utilityService.timeStamp()
"_" : utilityService.timeStamp(),
"active": true
}
}).success(function(data){
summary.unread = data;
Expand All @@ -56,7 +57,8 @@ iotServices.factory('alertsService', ['$http', 'utilityService','sessionService'
method: 'GET',
url: url,
params: {
"_" : utilityService.timeStamp()
"_" : utilityService.timeStamp(),
"active": true
}
}).success(function(data) {
summary.unread = removeReadAlerts(data);
Expand All @@ -71,7 +73,8 @@ iotServices.factory('alertsService', ['$http', 'utilityService','sessionService'
method: 'GET',
url: url,
params: {
"_" : utilityService.timeStamp()
"_" : utilityService.timeStamp(),
"active": true
}
}).success(successCallback).error(errorCallback);
});
Expand All @@ -87,7 +90,10 @@ iotServices.factory('alertsService', ['$http', 'utilityService','sessionService'
.then(function(url){
var requestOptions = {
method: 'PUT',
url: url
url: url,
params:{
"active": true
}
};
$http(requestOptions).success(function(data, status){
fireStatusUpdatedEvent(ngScope, {alert: alert, newStatus: newStatus});
Expand Down
6 changes: 6 additions & 0 deletions public-interface/doc/api/alerts.raml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ get:
example: 75
get:
is: [ authorization-header, response-errors-alerts, response-errors-generic ]
queryParameters:
active:
description: If true, ignore suppressed events
type: boolean
required: false
example: true
description: |
**Get Alert information**
Expand Down
135 changes: 93 additions & 42 deletions public-interface/engine/api/v1/alerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,37 @@ function parseAlertResponse(data) {
return results;
}

var findDeviceForAlert = function(alert, callback) {
Device.findByComponentId(alert.conditions[0].components[0].componentId, callback);
var findDeviceForAlert = function(alert) {
return new Promise(function(resolve, reject) {

var callback = function(err, deviceComponent) {
if (err) {
reject(err);
} else {
resolve(deviceComponent);
}
};
Device.findByComponentId(alert.conditions[0].components[0].componentId, callback);
});
};

var checkResetted = function(account, alert, rule) {
return new Promise(function(resolve, reject) {
var callback = function(err, foundAlert) {
if (err) {
reject(err);
} else {
resolve(foundAlert);
}
};
if (rule.resetType === Alert.resetType.automatic) {
resolve(null);
} else {
Alert.searchNewAlertsWithExternalId(account, rule.id, callback);
}
});
};
exports.trigger = function (alertData, accountId, hostUrl, resultCallback) {

async.parallel(alertData.map(function (alert) {
return function (done) {

Expand All @@ -158,46 +183,72 @@ exports.trigger = function (alertData, accountId, hostUrl, resultCallback) {
};
apiRules.getRule(options, function (err, rule) {
if (!err && rule) {
findDeviceForAlert(alert, function(err, deviceComponent) {
if (!err) {
//to internal from rule
var internalAlert = toInternalAlert(accountId, alert, rule, deviceComponent);
internalAlert["externalId"] = rule.externalId;
Alert.new(internalAlert, function(err){
if (err) {
logger.error('alerts. trigger, error: ' + JSON.stringify(err));
alert.err = errBuilder.build(errBuilder.Errors.Alert.SavingErrorAA).asResponse();
} else {
if(hostUrl.indexOf('internal-') > -1) {
internalAlert.host = hostUrl.substr(hostUrl.indexOf('-')+1);
}
else {
internalAlert.host = hostUrl;
}
// sometimes the rule-engine takes some time to adapt to new Rules
// The check for rule status makes sure that a rule which just has been disabled is no
// longer triggering anything
if (rule == null || rule.status !== "Active") {
alert.err = errBuilder.build(errBuilder.Errors.Alert.RuleNotActive).asResponse();
logger.error('alerts. trigger, error: ' + JSON.stringify(alert));
done(null, alert);
} else {
var suppressAlert = false;
checkResetted(accountId, alert, rule)
.then((found) => new Promise(function(resolve){
if (found) {
logger.info("Active alert found with same ruleid. Creating silent alert instead.");
suppressAlert = true;
}
resolve();
}))
.then(() => findDeviceForAlert(alert))
.then((deviceComponent) => new Promise(function(resolve, reject){
//to internal from rule

internalAlert.externalRule = rule;
actuationAlerts.addCommandsToActuationActions(accountId, rule)
.then(function onSuccess() {
actuationAlerts.saveAlertActuations(rule.actions, function (err) {
if (err) {
logger.error('alerts.saveActuations - unable to add new actuation message into DB: ' + JSON.stringify(err));
}
});
process.emit("incoming_alert", {alert: internalAlert, rule: rule});
}, function onError(err) {
logger.error('alerts.getCommands, error: ' + JSON.stringify(err));
});
var internalAlert = toInternalAlert(accountId, alert, rule, deviceComponent);
internalAlert["externalId"] = rule.externalId;
var suppressed = false;
if (suppressAlert) {
suppressed = true;
}
done(null, alert);
});
} else {
logger.error('alerts. trigger, error: ' + JSON.stringify(err));
alert.err = errBuilder.build(errBuilder.Errors.Alert.SavingErrorAA).asResponse();
}
});
Alert.new(internalAlert, suppressed, function(err){
if (err) {
logger.error('alerts. trigger, error: ' + JSON.stringify(err));
alert.err = errBuilder.build(errBuilder.Errors.Alert.SavingErrorAA).asResponse();
reject(alert);
} else {
if (!suppressAlert) {
if(hostUrl.indexOf('internal-') > -1) {
internalAlert.host = hostUrl.substr(hostUrl.indexOf('-')+1);
}
else {
internalAlert.host = hostUrl;
}

}
else {
internalAlert.externalRule = rule;
actuationAlerts.addCommandsToActuationActions(accountId, rule)
.then(function onSuccess() {
actuationAlerts.saveAlertActuations(rule.actions, function (err) {
if (err) {
logger.error('alerts.saveActuations - unable to add new actuation message into DB: ' + JSON.stringify(err));
}
});
process.emit("incoming_alert", {alert: internalAlert, rule: rule});
}, function onError(err) {
logger.error('alerts.getCommands, error: ' + JSON.stringify(err));
});
}
resolve(alert);
}
});
}))
.then((alert) => {done(null, alert);})
.catch((err) => {
logger.error('alerts. trigger, error: ' + JSON.stringify(err));
alert.err = errBuilder.build(errBuilder.Errors.Alert.SavingErrorAA).asResponse();
done(err, null);
});
}
} else {
alert.err = errBuilder.build(errBuilder.Errors.Alert.RuleNotFound).asResponse();
logger.error('alerts. trigger, error: ' + JSON.stringify(alert));
done(null, alert);
Expand All @@ -215,14 +266,14 @@ exports.trigger = function (alertData, accountId, hostUrl, resultCallback) {

exports.getUnreadAlerts = function (params, resultCallback) {

Alert.findByStatus(params.accountId, params.status, function (err, result) {
Alert.findByStatus(params.accountId, params.status, params.active, function (err, result) {
resultCallback(err, result);
});
};

exports.getAlerts = function (params, resultCallback) {

Alert.findByStatus(params.accountId, params.status, function (err, result) {
Alert.findByStatus(params.accountId, params.status, params.active, function (err, result) {
resultCallback(err, result);
});
};
Expand Down
3 changes: 3 additions & 0 deletions public-interface/engine/handlers/v1/alerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ exports.getAlerts = function(req, res, next) {
params.status = req.query.status.split(",");
}

if (req.query.active) {
params.active = req.query.active;
}
alert.getAlerts(params, function(err, result){
if(!err && result){
res.status(httpStatuses.OK.code).send(result);
Expand Down
1 change: 1 addition & 0 deletions public-interface/engine/res/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ module.exports = {
DeviceNotFound: {code: 8403, status: 400, message: "Device associated to this alert was not found"},
NotFound: {code: 8404, status: 404, message: "Alert not found"},
WrongAlertStatus: {code:8405, status: 400, message: "Wrong alert status"},
RuleNotActive: {code:8406, status: 400, message: "Rule is not active."},
AlreadyExists: {code: 8409, status: 409, message: "Alert already Exists"}, //Duplicate Alert
SavingErrorAA: {code: 8500, status: 500, message: "Error saving Alert"}, //Error saving in Advanced Analytics Backend
SavingError: {code: 8501, status: 500, message: "Error saving Alert"}, //Error saving locally
Expand Down
Loading

0 comments on commit 42370b3

Please sign in to comment.