lib/api/redfish-1.0/event-service.js
// Copyright 2016, EMC, Inc.
'use strict';
var urlParse = require('url-parse');
var injector = require('../../../index.js').injector;
var redfish = injector.get('Http.Api.Services.Redfish');
var Promise = injector.get('Promise'); // jshint ignore:line
var _ = injector.get('_'); // jshint ignore:line
var Constants = injector.get('Constants');
var RedfishTool = injector.get('JobUtils.RedfishTool');
var controller = injector.get('Http.Services.Swagger').controller;
var Errors = injector.get('Errors');
var messenger = injector.get('Services.Messenger');
var Logger = injector.get('Logger');
var uuid = injector.get('uuid');
var timeoutInSeconds = 10;
var retryAttempts = 3;
var eventSubscriptions = {};
var subscription;
var logger = Logger.initialize('event-service');
var eventListener = function(callback) {
if(subscription) {
return subscription;
}
return messenger.subscribe(
Constants.Protocol.Exchanges.Events.Name,
'poller.alert.#',
function(data) {
callback(data);
}
).then(function(sub) {
subscription = sub;
return subscription;
});
};
var sendClient = function(client, retry, data) {
return client.clientRequest(client.settings.root, 'POST', data)
.catch(function(error) {
if(0 !== retry) {
logger.warning('Send Error', {
error:error,
settings:client.settings,
retry:retry
});
return sendClient(client, retry - 1);
}
throw error;
});
};
var eventCallback = function(events) {
var clients;
if(_.isArray(events.value)) {
return _.forEach(events.value, function(event) {
if(event.reading.sdrType === 'Threshold') {
clients = _.filter(eventSubscriptions, _.matches({EventTypes:["Alert"]}));
return _.forEach(clients, function(client) {
var record = {};
var parse = urlParse(client.Destination);
var tool = new RedfishTool();
tool.settings.host = parse.host.split(':')[0];
tool.settings.port = parse.port;
tool.settings.root = parse.pathname;
tool.settings.recvTimeoutMs = timeoutInSeconds * 1000;
record.MemberId = event.node;
record.EventType = "Alert";
record.EventId = event.reading.sensorId;
record.EventTimestamp = new Date().toISOString();
record.Severity = event.reading.status;
record.Message = event.reading.entryIdName + ' ' +
event.reading.sensorReading + ' ' +
(event.reading.sensorReadingUnits ? event.reading.sensorReadingUnits : '');
record.MessageId = "Alert.1.0." +
event.reading.sensorId.replace(/[^A-Za-z0-9.]/g,'');
return redfish.validateSchema(record, 'Event.v1_1_2.json#/definitions/EventRecord') //jshint ignore: line
.then(function(result) {
if(result.error) {
throw new Error(result.error);
}
return sendClient(tool, retryAttempts, record);
})
.catch(function(error) {
throw error;
});
});
}
if(event.reading.sdrType === 'Discrete') {
clients = _.filter(eventSubscriptions, _.matches({EventTypes:["StatusChange"]}));
return _.forEach(clients, function(client) {
var record = {};
var parse = urlParse(client.Destination);
var tool = new RedfishTool();
tool.settings.host = parse.host.split(':')[0];
tool.settings.port = parse.port;
record.MemberId = event.node;
record.EventType = "StatusChange";
record.EventId = event.reading.sensorId;
record.EventTimestamp = new Date().toISOString();
record.Message = event.reading.entryIdName + ', statesAsserted: ' +
event.reading.statesAsserted.toString();
record.MessageId = "StatusChange.1.0." +
event.reading.sensorId.replace(/[^A-Za-z0-9.]/g,'');
return redfish.validateSchema(record, 'Event.v1_1_2.json#/definitions/EventRecord') //jshint ignore: line
.then(function(result) {
if(result.error) {
throw new Error(result.error);
}
return sendClient(tool, retryAttempts, record);
})
.catch(function(error) {
throw error;
});
});
}
});
} else {
var pollerName = _.get(events, 'value.pollerName');
if(pollerName === 'FabricService') {
var event = events.value;
return _.forEach(_.values(eventSubscriptions), function(client) {
if(_.includes(client.EventTypes, event.EventType)) {
var record = {};
var parse = urlParse(client.Destination);
var tool = new RedfishTool();
tool.settings.host = parse.host.split(':')[0];
tool.settings.port = parse.port;
record.MemberId = 'EndPoints';
record.EventType = event.EventType;
record.EventId = event.pollerName + '_' + event.EventType;
record.EventTimestamp = new Date().toISOString();
record.Message = JSON.stringify(event.data);
record.MessageId = event.EventType + ".1.0.EndPoints";
return redfish.validateSchema(record, 'Event.v1_1_2.json#/definitions/EventRecord') //jshint ignore: line
.then(function(result) {
if(result.error) {
throw new Error(result.error);
}
return sendClient(tool, retryAttempts, record);
})
.catch(function(error) {
throw error;
});
}
});
}
}
};
var eventServiceRoot = controller(function(req, res) {
var options = redfish.makeOptions(req, res);
return Promise.resolve()
.then(function() {
options.timeoutInSeconds = timeoutInSeconds;
options.retryAttempts = retryAttempts;
return redfish.render('redfish.1.0.0.eventservice.1.0.0.json',
'EventService.v1_0_3.json#/definitions/EventService',
options);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
var getEventsCollection = controller(function(req, res) {
var options = redfish.makeOptions(req, res);
return Promise.resolve()
.then(function() {
options.subscriptions = _.values(eventSubscriptions);
return redfish.render('redfish.1.0.0.eventdestinationcollection.json',
'EventDestinationCollection.json#/definitions/EventDestinationCollection',
options);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
var createSubscription = controller(function(req, res) {
var options = redfish.makeOptions(req, res);
var event = req.swagger.params.payload.value;
return redfish.validateSchema(event,
'EventDestination.v1_1_1.json#/definitions/EventDestination'
)
.then(function validatePayload(result) {
if(result.error) {
throw new Error(result.error);
}
var index = _.findIndex(_.values(eventSubscriptions), function(subscription) {
return subscription.Destination === event.Destination;
});
if(index > -1) {
var err = new Errors.BaseError('EventDestination Exists');
err.status = 409;
throw err;
}
event.Id = uuid('v4');
_.set(eventSubscriptions, event.Id, event);
return event;
})
.then(function(output) {
eventListener(eventCallback);
res.setHeader('Location',
options.basepath + '/EventService/Subscription/' + output.Id
);
res.status(201).json(output);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
var testEvent = controller({success: 202},function(req, res) {
return Promise.resolve()
.then(function() {
return _.forEach(_.values(eventSubscriptions), function(subscription) {
var record = {};
var parse = urlParse(subscription.Destination);
var tool = new RedfishTool();
tool.settings.host = parse.host.split(':')[0];
tool.settings.port = parse.port;
record.MemberId = subscription.Id;
record.EventType = 'Alert';
record.EventId = '0';
record.EventTimestamp = new Date().toISOString();
record.Message = 'Generated TestEvent to ' + subscription.Destination;
record.MessageId = 'TestEvent.1.0.0';
return redfish.validateSchema(record, 'Event.v1_1_2.json#/definitions/EventRecord')
.then(function(result) {
if(result.error) {
throw new Error(result.error);
}
return sendClient(tool, retryAttempts, record);
});
});
})
.all()
.then(function() {
res.status(202);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
var getEvent = controller(function(req, res) {
var options = redfish.makeOptions(req, res);
var id = req.swagger.params.index.value;
return Promise.resolve()
.then(function() {
var event = _.get(eventSubscriptions, id);
if(_.isUndefined(event)) {
throw new Errors.NotFoundError(
'EventDestination ' + id + ' Not Found'
);
}
options.subscription = event;
return redfish.render('redfish.1.0.0.eventdestination.json',
'EventDestination.v1_1_1.json#/definitions/EventDestination',
options);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
var deleteEvent = controller({success: 204}, function(req, res) {
var id = req.swagger.params.index.value;
return Promise.resolve()
.then(function() {
var event = _.get(eventSubscriptions, id);
if(_.isUndefined(event)) {
throw new Errors.NotFoundError(
'EventDestination ' + id + ' Not Found'
);
}
delete eventSubscriptions[id];
})
.then(function() {
if(!_.keys(eventSubscriptions).length) {
if(subscription) {
subscription.dispose();
subscription = undefined;
}
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
module.exports = {
eventServiceRoot: eventServiceRoot,
createSubscription: createSubscription,
getEventsCollection: getEventsCollection,
getEvent: getEvent,
deleteEvent: deleteEvent,
testEvent: testEvent,
eventListener: eventListener,
sendClient: sendClient,
eventCallback: eventCallback
};