PK \~Im$! # fiware-monitoring-latest/.buildinfo# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config:
tags:
PK \~Iy $ fiware-monitoring-latest/objects.inv# Sphinx inventory version 2
# Project: FIWARE
Monitoring
# Version:
# The remainder of this file is compressed using zlib.
xKOKIP(.IILJQ5THe(+x\)XT$}SJsRS3P@Ġ!
S D1PK \~I~D # fiware-monitoring-latest/index.html
FIWARE Monitoring GEri is the key component to allow incorporating monitoring
and metering mechanisms in order be able to constantly check the performance
of the system, but the architecture should be easily extended to collect data
for other required needs. Monitoring involves gathering operational data in a
running system. Collected information can be used for several purposes:
Cloud users to track the performance of their own instances.
SLA management, in order to check adherence to agreement terms.
Optimization of virtual machines.
The monitoring system is used by different Cloud GEs in order to track the
status of the resources. They use gathered data to take decisions about
elasticity or for SLA management. Whenever a new resource is deployed in the
cloud, the proper monitoring probe is set up and configured to start providing
monitoring data.
Welcome the User and Programmers Guide for the Monitoring Generic Enabler.
This GE is built up from different distributed components, as depicted in the
following figure:
This User and Programmers Guide relates to the Scalability Manager GE which is
part of the Cloud Hosting Chapter. Please find more information about this
Generic Enabler in the following Open Specification.
Probe raw data should be sent as body of a POST request to the adapter,
identifying the source entity being monitored in the query parameters.
For example, given the following scenario:
Monitored host:
178.23.5.23
Monitoring tool:
Nagios
Monitoring probe name:
check_load
NGSI Adapter endpoint:
http://adapterhost:1337
then requests would look like:
HTTP POST http://adapterhost:1337/check_load?id=178.23.5.23&type=host
Content-Type: text/plain
OK - load average: 0.36, 0.25, 0.24|load1=0.360;1.000;1.000;0;
load5=0.250;5.000;5.000;0; load15=0.240;15.000;15.000;0;
Please take into account that NGSI standard identify entities (in this case,
the resources being monitored) using a pair <entityId,entityType>. This
identification of the monitored resource has to be provided as the query
parameters id and type, respectively. The probe name included in
the URL lets NGSI Adapter know the originating monitoring probe, therefore
selecting the proper parser for it. This API is fully described in Apiary.
Monitoring framework is expected to schedule the execution of probes and send
the raw data been gathered to the NGSI Adapter. Depending on the tool that has
been chosen, this would require the development of a custom component (a kind
of monitoring collector) to automatically forward such data to the
adaptation layer.
In case UDP endpoints are defined (specifying the target parser to be loaded),
probe raw data should be sent as UDP request to the adapter. Such message is
expected to include both the id and the type of the NGSI Entity whose data is
about to be parsed.
NGSI Adapter processes requests asynchronously, trying to load a valid parser
named after the originating probe, located at any of the directories specified
(see Installation and Administration Guide). If probe is unknown (parser not
found), HTTP response status will be 404; otherwise, response status will
be 200, parser will be dynamically loaded, and then its parseRequest()
and getContextAttrs() methods will be called. The attribute list returned
by the latter will be used to invoke Context Broker.
Custom parsers for new probes may be easily added to NGSI Adapter, just
extending a base abstract object and implementing the aforementioned methods.
For example, suppose we want to support a new “myProbe” whose data is a
comma-separated list of values of two attributes myAttr0 and myAttr1:
/**
* module "myProbe" at any directory included in ADAPTER_PARSERS_PATH
*/
// @augments base parser (must redefine parseRequest and getContextAttrs)
var myParser = Object.create(null);
// @param Domain object including context, timestamp, id, type & body
myParser.parseRequest = function (reqDomain) {
var reqDataContent = this.doSomeParsing(reqDomain.body);
return { data: reqDataContent };
};
// @param EntityData object including data attribute
myParser.getContextAttrs = function (entityData) {
var items = this.doMoreParsing(entityData.data);
return { myAttr0: items[0], myAttr1: items[1] };
};
exports.parser = myParser;
Custom parsers for UDP request must also set the attributes entityId and
entityType of the input object reqDomain on return, given that such
information is part of the UDP message itself being parsed:
Retrieval of historical data stored at a distributed filesystem (e.g. Hadoop)
is handled by the Query Manager component, whose API is described in this
preliminary specification.
This guide defines the procedure to install the different components that build
up the Monitoring GE, including its requirements and possible troubleshooting.
For general information, please refer to GitHub’s README.
Monitoring GE is agnostic to the framework used to gather monitoring data. It
just assumes there are several probes collecting such data, which somehow will
be forwarded to the adaptation layer (NGSI Adapter).
It is up to the infrastructure owner which tool (like Nagios, Zabbix,
openNMS, perfSONAR, etc.) is installed for this purpose.
Probes must “publish” their data to NGSI Adapter. Depending on the exact
monitoring tool installed, a kind of collector has to be deployed in
order to send data to the adapter:
NGSI Event Broker is an example specific for Nagios, implemented as
a loadable module. Description and installation details can be found here.
NGSI Adapter should work on a variety of operating systems, particularly on the
majority of GNU/Linux distributions (e.g. Debian, Ubuntu, CentOS), as it only
requires a V8 JavaScript Engine to run a Node.js server.
NGSI Adapter is a standalone Node.js process, so node and its package
manager npm should be installed previously. These requirements are
automatically checked when installing the fiware-monitoring-ngsi-adapter
package. However, for manual installation please visit NodeSource.
NGSI Adapter currently includes a predefined set of parsers for Nagios probes
at lib/parsers/nagios directory, each named after its corresponding probe.
This can be extended with additional parsers found at additional directories.
To do so, please configure --parsersPath command line option (or set the
variable ADAPTER_PARSERS_PATH) with a colon-separated list of absolute (or
relative to Adapter root) directories where parsers are located.
This component subscribes to changes at Context Broker and writes data into a
distributed filesystem storage (usually HDFS from Hadoop). Historically the
ngsi2cosmos connector implementation has been used (installation details
here), although from March 2014 this component is deprecated and a brand new
Cygnus implementation (installation details here) is available.
As stated before, there are a number of distributed components involved in the
monitoring. Please refer to their respective installation manuals for execution
details (this applies to probes & monitoring software, Context Broker, Hadoop,
etc.). This section focuses on NGSI Adapter specific instructions.
Once installed, there are two ways of running NGSI Adapter: manually from the
command line or as a system service. It is not recommended to mix both ways
(e.g. start it manually but using the service scripts to stop it).
These are the steps that a System Administrator will take to verify that an
installation is ready to be tested. This is therefore a preliminary set of
tests to ensure that obvious or basic malfunctioning is fixed before proceeding
to unit tests, integration tests and user validation.
Use the commands of the monitoring framework being used (for example, Nagios)
to reschedule some probe execution and force the generation of new monitoring
data:
Check the logs of the framework (i.e. /var/log/nagios/nagios.log) for
a new probe execution detected by the collector:
$ cat /var/log/nagios/nagios.log
[1439283831] lvl=INFO | corr=rdPmJ/uHE62a | comp=ngsi-event-broker-fiware |
... op=NGSIAdapter |
... msg=Request sent to http://host:1337/check_xxx?id=xxx&type=host
Check NGSI Adapter logs for incoming requests with raw data, and for the
corresponding updateContext() request to Context Broker:
$ cat /var/log/ngsi_adapter/ngsi_adapter.log
time=xxx | lvl=INFO | corr=rdPmJ/uHE62a | trans=ciw4p8cc6ar6dt5iz3c8qurf5 |
... op=POST |
... msg=Request on resource /check_xxx with params id=xxx&type=xxx
time=xxx | lvl=INFO | corr=rdPmJ/uHE62a | trans=ciw4p8cc6ar6dt5iz3c8qurf5 |
... op=POST |
... msg=Response status 200 OK
time=xxx | lvl=INFO | corr=rdPmJ/uHE62a | trans=ciw4p8cc6ar6dt5iz3c8qurf5 |
... op=UpdateContext |
... msg=Request to ContextBroker at http://host:1026/...
Finally, query Context Broker API to check whether entity attributes have
been updated according to the new monitoring data (see details here)
The Diagnosis Procedures are the first steps that a System Administrator will
take to locate the source of an error in a GE. Once the nature of the error is
identified with these tests, the system admin will very often have to resort to
more concrete and specific testing to pinpoint the exact point of error and a
possible solution. Such specific testing is out of the scope of this section.
Although we haven’t done yet a precise profiling on NGSI Adapter, tests done in
our development and testing environment show that a host with 2 CPU cores and
4 GB RAM is fine to run server.
No issues related to resources consumption have been detected neither with
the NGSI Adapter server nor with the NGSI Event Broker loaded as a “pluggable”
module on Nagios startup.
')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});
PK \~I8c c . fiware-monitoring-latest/_static/websupport.js/*
* websupport.js
* ~~~~~~~~~~~~~
*
* sphinx.websupport utilties for all documentation.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
(function($) {
$.fn.autogrow = function() {
return this.each(function() {
var textarea = this;
$.fn.autogrow.resize(textarea);
$(textarea)
.focus(function() {
textarea.interval = setInterval(function() {
$.fn.autogrow.resize(textarea);
}, 500);
})
.blur(function() {
clearInterval(textarea.interval);
});
});
};
$.fn.autogrow.resize = function(textarea) {
var lineHeight = parseInt($(textarea).css('line-height'), 10);
var lines = textarea.value.split('\n');
var columns = textarea.cols;
var lineCount = 0;
$.each(lines, function() {
lineCount += Math.ceil(this.length / columns) || 1;
});
var height = lineHeight * (lineCount + 1);
$(textarea).css('height', height);
};
})(jQuery);
(function($) {
var comp, by;
function init() {
initEvents();
initComparator();
}
function initEvents() {
$(document).on("click", 'a.comment-close', function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
});
$(document).on("click", 'a.vote', function(event) {
event.preventDefault();
handleVote($(this));
});
$(document).on("click", 'a.reply', function(event) {
event.preventDefault();
openReply($(this).attr('id').substring(2));
});
$(document).on("click", 'a.close-reply', function(event) {
event.preventDefault();
closeReply($(this).attr('id').substring(2));
});
$(document).on("click", 'a.sort-option', function(event) {
event.preventDefault();
handleReSort($(this));
});
$(document).on("click", 'a.show-proposal', function(event) {
event.preventDefault();
showProposal($(this).attr('id').substring(2));
});
$(document).on("click", 'a.hide-proposal', function(event) {
event.preventDefault();
hideProposal($(this).attr('id').substring(2));
});
$(document).on("click", 'a.show-propose-change', function(event) {
event.preventDefault();
showProposeChange($(this).attr('id').substring(2));
});
$(document).on("click", 'a.hide-propose-change', function(event) {
event.preventDefault();
hideProposeChange($(this).attr('id').substring(2));
});
$(document).on("click", 'a.accept-comment', function(event) {
event.preventDefault();
acceptComment($(this).attr('id').substring(2));
});
$(document).on("click", 'a.delete-comment', function(event) {
event.preventDefault();
deleteComment($(this).attr('id').substring(2));
});
$(document).on("click", 'a.comment-markup', function(event) {
event.preventDefault();
toggleCommentMarkupBox($(this).attr('id').substring(2));
});
}
/**
* Set comp, which is a comparator function used for sorting and
* inserting comments into the list.
*/
function setComparator() {
// If the first three letters are "asc", sort in ascending order
// and remove the prefix.
if (by.substring(0,3) == 'asc') {
var i = by.substring(3);
comp = function(a, b) { return a[i] - b[i]; };
} else {
// Otherwise sort in descending order.
comp = function(a, b) { return b[by] - a[by]; };
}
// Reset link styles and format the selected sort option.
$('a.sel').attr('href', '#').removeClass('sel');
$('a.by' + by).removeAttr('href').addClass('sel');
}
/**
* Create a comp function. If the user has preferences stored in
* the sortBy cookie, use those, otherwise use the default.
*/
function initComparator() {
by = 'rating'; // Default to sort by rating.
// If the sortBy cookie is set, use that instead.
if (document.cookie.length > 0) {
var start = document.cookie.indexOf('sortBy=');
if (start != -1) {
start = start + 7;
var end = document.cookie.indexOf(";", start);
if (end == -1) {
end = document.cookie.length;
by = unescape(document.cookie.substring(start, end));
}
}
}
setComparator();
}
/**
* Show a comment div.
*/
function show(id) {
$('#ao' + id).hide();
$('#ah' + id).show();
var context = $.extend({id: id}, opts);
var popup = $(renderTemplate(popupTemplate, context)).hide();
popup.find('textarea[name="proposal"]').hide();
popup.find('a.by' + by).addClass('sel');
var form = popup.find('#cf' + id);
form.submit(function(event) {
event.preventDefault();
addComment(form);
});
$('#s' + id).after(popup);
popup.slideDown('fast', function() {
getComments(id);
});
}
/**
* Hide a comment div.
*/
function hide(id) {
$('#ah' + id).hide();
$('#ao' + id).show();
var div = $('#sc' + id);
div.slideUp('fast', function() {
div.remove();
});
}
/**
* Perform an ajax request to get comments for a node
* and insert the comments into the comments tree.
*/
function getComments(id) {
$.ajax({
type: 'GET',
url: opts.getCommentsURL,
data: {node: id},
success: function(data, textStatus, request) {
var ul = $('#cl' + id);
var speed = 100;
$('#cf' + id)
.find('textarea[name="proposal"]')
.data('source', data.source);
if (data.comments.length === 0) {
ul.html('
No comments yet.
');
ul.data('empty', true);
} else {
// If there are comments, sort them and put them in the list.
var comments = sortComments(data.comments);
speed = data.comments.length * 100;
appendComments(comments, ul);
ul.data('empty', false);
}
$('#cn' + id).slideUp(speed + 200);
ul.slideDown(speed);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem retrieving the comments.');
},
dataType: 'json'
});
}
/**
* Add a comment via ajax and insert the comment into the comment tree.
*/
function addComment(form) {
var node_id = form.find('input[name="node"]').val();
var parent_id = form.find('input[name="parent"]').val();
var text = form.find('textarea[name="comment"]').val();
var proposal = form.find('textarea[name="proposal"]').val();
if (text == '') {
showError('Please enter a comment.');
return;
}
// Disable the form that is being submitted.
form.find('textarea,input').attr('disabled', 'disabled');
// Send the comment to the server.
$.ajax({
type: "POST",
url: opts.addCommentURL,
dataType: 'json',
data: {
node: node_id,
parent: parent_id,
text: text,
proposal: proposal
},
success: function(data, textStatus, error) {
// Reset the form.
if (node_id) {
hideProposeChange(node_id);
}
form.find('textarea')
.val('')
.add(form.find('input'))
.removeAttr('disabled');
var ul = $('#cl' + (node_id || parent_id));
if (ul.data('empty')) {
$(ul).empty();
ul.data('empty', false);
}
insertComment(data.comment);
var ao = $('#ao' + node_id);
ao.find('img').attr({'src': opts.commentBrightImage});
if (node_id) {
// if this was a "root" comment, remove the commenting box
// (the user can get it back by reopening the comment popup)
$('#ca' + node_id).slideUp();
}
},
error: function(request, textStatus, error) {
form.find('textarea,input').removeAttr('disabled');
showError('Oops, there was a problem adding the comment.');
}
});
}
/**
* Recursively append comments to the main comment list and children
* lists, creating the comment tree.
*/
function appendComments(comments, ul) {
$.each(comments, function() {
var div = createCommentDiv(this);
ul.append($(document.createElement('li')).html(div));
appendComments(this.children, div.find('ul.comment-children'));
// To avoid stagnating data, don't store the comments children in data.
this.children = null;
div.data('comment', this);
});
}
/**
* After adding a new comment, it must be inserted in the correct
* location in the comment tree.
*/
function insertComment(comment) {
var div = createCommentDiv(comment);
// To avoid stagnating data, don't store the comments children in data.
comment.children = null;
div.data('comment', comment);
var ul = $('#cl' + (comment.node || comment.parent));
var siblings = getChildren(ul);
var li = $(document.createElement('li'));
li.hide();
// Determine where in the parents children list to insert this comment.
for(i=0; i < siblings.length; i++) {
if (comp(comment, siblings[i]) <= 0) {
$('#cd' + siblings[i].id)
.parent()
.before(li.html(div));
li.slideDown('fast');
return;
}
}
// If we get here, this comment rates lower than all the others,
// or it is the only comment in the list.
ul.append(li.html(div));
li.slideDown('fast');
}
function acceptComment(id) {
$.ajax({
type: 'POST',
url: opts.acceptCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
$('#cm' + id).fadeOut('fast');
$('#cd' + id).removeClass('moderate');
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem accepting the comment.');
}
});
}
function deleteComment(id) {
$.ajax({
type: 'POST',
url: opts.deleteCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
var div = $('#cd' + id);
if (data == 'delete') {
// Moderator mode: remove the comment and all children immediately
div.slideUp('fast', function() {
div.remove();
});
return;
}
// User mode: only mark the comment as deleted
div
.find('span.user-id:first')
.text('[deleted]').end()
.find('div.comment-text:first')
.text('[deleted]').end()
.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
.remove();
var comment = div.data('comment');
comment.username = '[deleted]';
comment.text = '[deleted]';
div.data('comment', comment);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem deleting the comment.');
}
});
}
function showProposal(id) {
$('#sp' + id).hide();
$('#hp' + id).show();
$('#pr' + id).slideDown('fast');
}
function hideProposal(id) {
$('#hp' + id).hide();
$('#sp' + id).show();
$('#pr' + id).slideUp('fast');
}
function showProposeChange(id) {
$('#pc' + id).hide();
$('#hc' + id).show();
var textarea = $('#pt' + id);
textarea.val(textarea.data('source'));
$.fn.autogrow.resize(textarea[0]);
textarea.slideDown('fast');
}
function hideProposeChange(id) {
$('#hc' + id).hide();
$('#pc' + id).show();
var textarea = $('#pt' + id);
textarea.val('').removeAttr('disabled');
textarea.slideUp('fast');
}
function toggleCommentMarkupBox(id) {
$('#mb' + id).toggle();
}
/** Handle when the user clicks on a sort by link. */
function handleReSort(link) {
var classes = link.attr('class').split(/\s+/);
for (var i=0; iThank you! Your comment will show up '
+ 'once it is has been approved by a moderator.');
}
// Prettify the comment rating.
comment.pretty_rating = comment.rating + ' point' +
(comment.rating == 1 ? '' : 's');
// Make a class (for displaying not yet moderated comments differently)
comment.css_class = comment.displayed ? '' : ' moderate';
// Create a div for this comment.
var context = $.extend({}, opts, comment);
var div = $(renderTemplate(commentTemplate, context));
// If the user has voted on this comment, highlight the correct arrow.
if (comment.vote) {
var direction = (comment.vote == 1) ? 'u' : 'd';
div.find('#' + direction + 'v' + comment.id).hide();
div.find('#' + direction + 'u' + comment.id).show();
}
if (opts.moderator || comment.text != '[deleted]') {
div.find('a.reply').show();
if (comment.proposal_diff)
div.find('#sp' + comment.id).show();
if (opts.moderator && !comment.displayed)
div.find('#cm' + comment.id).show();
if (opts.moderator || (opts.username == comment.username))
div.find('#dc' + comment.id).show();
}
return div;
}
/**
* A simple template renderer. Placeholders such as <%id%> are replaced
* by context['id'] with items being escaped. Placeholders such as <#id#>
* are not escaped.
*/
function renderTemplate(template, context) {
var esc = $(document.createElement('div'));
function handle(ph, escape) {
var cur = context;
$.each(ph.split('.'), function() {
cur = cur[this];
});
return escape ? esc.text(cur || "").html() : cur;
}
return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
return handle(arguments[2], arguments[1] == '%' ? true : false);
});
}
/** Flash an error message briefly. */
function showError(message) {
$(document.createElement('div')).attr({'class': 'popup-error'})
.append($(document.createElement('div'))
.attr({'class': 'error-message'}).text(message))
.appendTo('body')
.fadeIn("slow")
.delay(2000)
.fadeOut("slow");
}
/** Add a link the user uses to open the comments popup. */
$.fn.comment = function() {
return this.each(function() {
var id = $(this).attr('id').substring(1);
var count = COMMENT_METADATA[id];
var title = count + ' comment' + (count == 1 ? '' : 's');
var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
var addcls = count == 0 ? ' nocomment' : '';
$(this)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-open' + addcls,
id: 'ao' + id
})
.append($(document.createElement('img')).attr({
src: image,
alt: 'comment',
title: title
}))
.click(function(event) {
event.preventDefault();
show($(this).attr('id').substring(2));
})
)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-close hidden',
id: 'ah' + id
})
.append($(document.createElement('img')).attr({
src: opts.closeCommentImage,
alt: 'close',
title: 'close'
}))
.click(function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
})
);
});
};
var opts = {
processVoteURL: '/_process_vote',
addCommentURL: '/_add_comment',
getCommentsURL: '/_get_comments',
acceptCommentURL: '/_accept_comment',
deleteCommentURL: '/_delete_comment',
commentImage: '/static/_static/comment.png',
closeCommentImage: '/static/_static/comment-close.png',
loadingImage: '/static/_static/ajax-loader.gif',
commentBrightImage: '/static/_static/comment-bright.png',
upArrow: '/static/_static/up.png',
downArrow: '/static/_static/down.png',
upArrowPressed: '/static/_static/up-pressed.png',
downArrowPressed: '/static/_static/down-pressed.png',
voting: false,
moderator: false
};
if (typeof COMMENT_OPTIONS != "undefined") {
opts = jQuery.extend(opts, COMMENT_OPTIONS);
}
var popupTemplate = '\
\ Sort by:\ best rated\ newest\ oldest\
\\
Add a comment\ (markup):
\``code``
, \ code blocks:::
and an indented block after blank line