Contrail Insights Object Plug-In
Object scope plug-in is supported to extend the instance and
host scope plug-in. It will assign an aggregate of hosts running a
plug-in script to collect data for an aggregate of objects (such as
instances). Currently, only an aggregate of instances can be monitored
and only the plug-in type object.rest
is
supported.
The collector failover High Availability (HA) feature is supported in object scope plug-ins. If one of the collectors in the aggregate is down, Contrail Insights will automatically assign another host in the same aggregate as the collector. As a result, you can set up an aggregate of several collectors which will make sure downtime of some of the collectors will not affect the object monitoring.
Create an Object Scope Plug-In
To add an object scope plug-in in Contrail Insights, you need
to supply both a plug-in script and plug-in JSON file. Contrail Insights
Agent will pass a list of object_ids
separated
by commas (-o
) and a dictionary to MetaData
(-p
) to the plug-in
script. The Contrail Insights Agent expects the plug-in script to
return data with the following format:
OK - {{plugin_name}}: [{"roomKey": {"value": {{instance_id_1}}, "unit": "roomKey"}, "metric_1": {"value": {{value_1}}, "unit": "m1_unit"}, "metric_2": {"value": {{value_2}}, "unit": "m2_unit"}}, {"roomKey": {"value": {{instance_id_2}}, "unit": "roomKey"}, "metric_1": {"value": {{value_3}}, "unit": "m1_unit"}, "metric_2": {"value": {{value_4}}, "unit": "m2_unit"}}]
The main body of the data should be a list of dictionaries and each entry should represent a data point with all of the metrics for one instance.
Following is an example of a plug-in script which will get instance
data from some endpoint, passed in from the MetaData
variable.
$ cat check_object_plugin.py import sys import traceback import requests import json import argparse def main(argv): instance_list = argv.instances.split(',') url = json.loads(argv.metadata)['url'] data = json.dumps({'InstanceList': instance_list}) resp = requests.get(url=url, data=data, headers={'content-type': 'application/json'}) result = json.loads(resp.text) return_value = [] for entry in result['data']: instance_data = \ {'roomKey': {'unit': 'roomKey', 'value': entry['id']}, 'm1': {'unit': 'm1_unit', 'value': entry['m1']}, 'm2': {'unit': 'm2_unit', 'value': entry['m2']}} return_value.append(instance_data) try: return_value = json.dumps(return_value) msg = 'instance_object_plugin: {}'.format(return_value) except Exception as e: traceback.print_exc() msg = 'instance_object_plugin: []' test_state = 0 logger_helper( msg, test_state ) def logger_helper(message, state): if state == 2: print "CRITICAL - " + message sys.exit(2) elif state == 1: print "WARNING - " + message sys.exit(1) elif state == 0: print "OK - " + message sys.exit(0) else: print "CRITICAL - Unexpected value : %d" % state + "; " + message sys.exit(2) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( '-o', '--instances', help='instance list', required=True, default='', type=unicode) parser.add_argument( '-p', '--metadata', help='metadata', required=False, default='{}', type=unicode) args = parser.parse_args() sys.exit(main(args))
Following is the corresponding flask server running on localhost:9999
for the above example:
from flask import Flask, request import json import copy data = {'a53a441b-fb1f-4e08-9e05-d94fd4d5a0ba': {'m1': 1, 'm2': 2}, '82c20111-32b2-4a47-a668-cd1d6c69270d': {'m1': 3, 'm2': 4}, 'fd5977d4-150d-4af4-bfaf-96663902447e': {'m1': 5, 'm2': 6}, 'a35414ab-e779-48a8-93d9-1ae50647fdc5': {'m1': 7, 'm2': 8}} app = Flask(__name__) @app.route('/', methods=['GET']) def app_message_get(): if request.headers['Content-Type'] != 'application/json': print "invalid" return json.dumps({'result': "invalid"}) args = request.json result = [] for instance_id in args.get('InstanceList', []): if instance_id in data: entry = copy.deepcopy(data[instance_id]) entry['id'] = instance_id result.append(entry) return json.dumps({'data': result}) if __name__ == '__main__': app.run( host="0.0.0.0", port=int("9999") )
For example, if you want to get data for instances fd5977d4-150d-4af4-bfaf-96663902447e
and a53a441b-fb1f-4e08-9e05-d94fd4d5a0ba
with URL http://localhost:9999 (because your server is running on localhost
port 9999), you can run the following command:
python check_object_plugin.py -o fd5977d4-150d-4af4-bfaf-96663902447e,a53a441b-fb1f-4e08-9e05-d94fd4d5a0ba -p '{"url": "http://localhost:9999"}'
The output of the command is:
OK - instance_object_plugin: [{"roomKey": {"value": "fd5977d4-150d-4af4-bfaf-96663902447e", "unit": "roomKey"}, "m1": {"value": 5, "unit": "m1_unit"}, "m2": {"value": 6, "unit": "m2_unit"}}, {"roomKey": {"value": "a53a441b-fb1f-4e08-9e05-d94fd4d5a0ba", "unit": "roomKey"}, "m1": {"value": 1, "unit": "m1_unit"}, "m2": {"value": 2, "unit": "m2_unit"}}]
The corresponding plug-in JSON file will be:
$ cat instance_usage.json { "Collection": "instance_plugin_usage_collection", "Config": { "CommandLine": "python check_object_plugin.py", "ObjectAggregateId": "7ae841ce-ead4-11e9-b283-0242ac130005" }, "MetaData": {"url": "http://localhost:9999"}, "AggregateId": "appformix_platform", "MetricMap": [ { "Name": "m1", "Units": "m1_unit" }, { "Name": "m2", "Units": "m2_unit" } ], "PluginId": "instance_object_plugin", "PluginName": "instance_object_plugin", "PluginType": "object.rest", "Scope": "object", "State": "enabled", "status": "success" }
Where ObjectAggregateId
should be
the aggregate identifier of the aggregate of instances you want to
monitor and AggregateId
should be the aggregate
identifier of the host aggregate which is assigned to collect the
data for the instances.
Note that you can put additional information in the MetaData
field in the plug-in as needed. The above
example is just a simple example.
Add Object Scope Plug-In to Contrail Insights
To add the object scope plug-in to Contrail Insights, you need
to post your plug-in to Contrail Insights through Ansible. Add the
following lines in your Ansible group_vars/all
file and re-run the Ansible playbook.
appformix_user_defined_plugins: - { plugin_info: 'user_defined_plugins/instance_usage.json', plugin_file: 'user_defined_plugins/check_object_plugin.py'}
The Contrail Insights Ansible playbooks will then copy these two types of files to all of the appropriate Agents and then configure the plug-in in the Contrail Insights Platform.