Merge "src: rename dir - collectd-ceilometer-plugin/ -> collectd-openstack-plugin/"
[barometer.git] / baro_tests / collectd.py
1 # -*- coding: utf-8 -*-
2
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
13 # under the License.
14
15 """Executing test of plugins"""
16
17 import requests
18 from keystoneclient.v3 import client
19 import os
20 import sys
21 import time
22 import logging
23 import config_server
24 import tests
25 import subprocess
26 from opnfv.deployment import factory
27
28 AODH_NAME = 'aodh'
29 GNOCCHI_NAME = 'gnocchi'
30 ID_RSA_SRC = '/root/.ssh/id_rsa'
31 ID_RSA_DST_DIR = '/root/.ssh'
32 ID_RSA_DST = ID_RSA_DST_DIR + '/id_rsa'
33 APEX_IP = subprocess.check_output("echo $INSTALLER_IP", shell=True)
34 APEX_USER = 'root'
35 APEX_USER_STACK = 'stack'
36 APEX_PKEY = '/root/.ssh/id_rsa'
37
38
39 class KeystoneException(Exception):
40     """Keystone exception class"""
41     def __init__(self, message, exc=None, response=None):
42         """
43         Keyword arguments:
44         message -- error message
45         exc -- exception
46         response -- response
47         """
48         if exc:
49             message += "\nReason: %s" % exc
50         super(KeystoneException, self).__init__(message)
51
52         self.response = response
53         self.exception = exc
54
55
56 class InvalidResponse(KeystoneException):
57     """Invalid Keystone exception class"""
58     def __init__(self, exc, response):
59         """
60         Keyword arguments:
61         exc -- exception
62         response -- response
63         """
64         super(InvalidResponse, self).__init__(
65             "Invalid response", exc, response)
66
67
68 def get_apex_nodes():
69     handler = factory.Factory.get_handler('apex',
70                                           APEX_IP,
71                                           APEX_USER_STACK,
72                                           APEX_PKEY)
73     nodes = handler.get_nodes()
74     return nodes
75
76
77 class GnocchiClient(object):
78     # Gnocchi Client to authenticate and request meters
79     def __init__(self):
80         self._auth_token = None
81         self._gnocchi_url = None
82         self._meter_list = None
83
84     def auth_token(self):
85         # Get auth token
86         self._auth_server()
87         return self._auth_token
88
89     def get_gnocchi_url(self):
90         # Get Gnocchi  URL
91         return self._gnocchi_url
92
93     def get_gnocchi_metrics(self, criteria=None):
94         # Subject to change if metric gathering is different for gnocchi
95         self._request_meters(criteria)
96         return self._meter_list
97
98     def _auth_server(self):
99         # Request token in authentication server
100         logger.debug('Connecting to the auth server {}'.format(
101             os.environ['OS_AUTH_URL']))
102         keystone = client.Client(username=os.environ['OS_USERNAME'],
103                                  password=os.environ['OS_PASSWORD'],
104                                  tenant_name=os.environ['OS_USERNAME'],
105                                  auth_url=os.environ['OS_AUTH_URL'])
106         self._auth_token = keystone.auth_token
107         for service in keystone.service_catalog.get_data():
108             if service['name'] == GNOCCHI_NAME:
109                 for service_type in service['endpoints']:
110                     if service_type['interface'] == 'internal':
111                         self._gnocchi_url = service_type['url']
112
113         if self._gnocchi_url is None:
114             logger.warning('Gnocchi is not registered in service catalog')
115
116     def _request_meters(self, criteria):
117         """Request meter list values from ceilometer
118
119         Keyword arguments:
120         criteria -- criteria for ceilometer meter list
121         """
122         if criteria is None:
123             url = self._gnocchi_url + ('/v2/metric?limit=400')
124         else:
125             url = self._gnocchi_url \
126                 + ('/v3/metric/%s?q.field=metric&limit=400' % criteria)
127         headers = {'X-Auth-Token': self._auth_token}
128         resp = requests.get(url, headers=headers)
129         try:
130             resp.raise_for_status()
131             self._meter_list = resp.json()
132         except (KeyError, ValueError, requests.exceptions.HTTPError) as err:
133             raise InvalidResponse(err, resp)
134
135
136 class AodhClient(object):
137     # Gnocchi Client to authenticate and request meters
138     def __init__(self):
139         self._auth_token = None
140         self._aodh_url = None
141         self._meter_list = None
142
143     def auth_token(self):
144         # Get auth token
145         self._auth_server()
146         return self._auth_token
147
148     def get_aodh_url(self):
149         # Get Gnocchi  URL
150         return self._gnocchi_url
151
152     def get_aodh_metrics(self, criteria=None):
153         # Subject to change if metric gathering is different for gnocchi
154         self._request_meters(criteria)
155         return self._meter_list
156
157     def _auth_server(self):
158         # Request token in authentication server
159         logger.debug('Connecting to the AODH auth server {}'.format(
160             os.environ['OS_AUTH_URL']))
161         keystone = client.Client(username=os.environ['OS_USERNAME'],
162                                  password=os.environ['OS_PASSWORD'],
163                                  tenant_name=os.environ['OS_USERNAME'],
164                                  auth_url=os.environ['OS_AUTH_URL'])
165         self._auth_token = keystone.auth_token
166         for service in keystone.service_catalog.get_data():
167             if service['name'] == AODH_NAME:
168                 for service_type in service['endpoints']:
169                     if service_type['interface'] == 'internal':
170                         self._gnocchi_url = service_type['url']
171
172         if self._aodh_url is None:
173             logger.warning('Aodh is not registered in service catalog')
174
175
176 class SNMPClient(object):
177     """Client to request SNMP meters"""
178     def __init__(self, conf, compute_node):
179         """
180         Keyword arguments:
181         conf -- ConfigServer instance
182         compute_node -- Compute node object
183         """
184         self.conf = conf
185         self.compute_node = compute_node
186
187     def get_snmp_metrics(self, compute_node, mib_file, mib_strings):
188         snmp_output = {}
189         if mib_file is None:
190             cmd = "snmpwalk -v 2c -c public localhost IF-MIB::interfaces"
191             ip = compute_node.get_ip()
192             snmp_output = self.conf.execute_command(cmd, ip)
193         else:
194             for mib_string in mib_strings:
195                 snmp_output[mib_string] = self.conf.execute_command(
196                     "snmpwalk -v2c -m {} -c public localhost {}".format(
197                         mib_file, mib_string), compute_node.get_ip())
198         return snmp_output
199
200
201 class CSVClient(object):
202     """Client to request CSV meters"""
203     def __init__(self, conf):
204         """
205         Keyword arguments:
206         conf -- ConfigServer instance
207         """
208         self.conf = conf
209
210     def get_csv_metrics(
211             self, compute_node, plugin_subdirectories, meter_categories):
212         """Get CSV metrics.
213
214         Keyword arguments:
215         compute_node -- compute node instance
216         plugin_subdirectories -- list of subdirectories of plug-in
217         meter_categories -- categories which will be tested
218
219         Return list of metrics.
220         """
221         compute_name = compute_node.get_name()
222         nodes = get_apex_nodes()
223         for node in nodes:
224             if compute_name == node.get_dict()['name']:
225                 date = node.run_cmd(
226                     "date '+%Y-%m-%d'")
227                 hostname = node.run_cmd('hostname -A')
228                 hostname = hostname.split()[0]
229                 metrics = []
230                 for plugin_subdir in plugin_subdirectories:
231                     for meter_category in meter_categories:
232                         stdout1 = node.run_cmd(
233                             "tail -2 /var/lib/collectd/csv/"
234                             + "{0}/{1}/{2}-{3}".format(
235                                 hostname, plugin_subdir,
236                                 meter_category, date))
237                         stdout2 = node.run_cmd(
238                             "tail -1 /var/lib/collectd/csv/"
239                             + "{0}.jf.intel.com/{1}/{2}-{3}".format(
240                                 compute_node.get_name(), plugin_subdir,
241                                 meter_category, date))
242                 # Storing last two values
243                         values = stdout1
244                         if values is None:
245                             logger.error(
246                                 'Getting last two CSV entries of meter category'
247                                 + ' {0} in {1} subdir failed'.format(
248                                     meter_category, plugin_subdir))
249                         else:
250                             values = values.split(',')
251                             old_value = float(values[0])
252                             stdout2 = stdout2.split(',')
253                             new_value = float(stdout2[0])
254                             metrics.append((
255                                 plugin_subdir, meter_category, old_value,
256                                 new_value))
257         return metrics
258
259
260 def get_csv_categories_for_ipmi(conf, compute_node):
261     """Get CSV metrics.
262
263     Keyword arguments:
264     compute_node -- compute node instance
265
266     Return list of categories.
267     """
268     stdout = conf.execute_command(
269         "date '+%Y-%m-%d'", compute_node.get_ip())
270     date = stdout[0].strip()
271     categories = conf.execute_command(
272         "ls /var/lib/collectd/csv/{0}.jf.intel.com/ipmi | grep {1}".format(
273             compute_node.get_name(), date), compute_node.get_ip())
274     return [category.strip()[:-11] for category in categories]
275
276
277 def _process_result(compute_node, out_plugin, test, result, results_list):
278     """Print test result and append it to results list.
279
280     Keyword arguments:
281     test -- testcase name
282     result -- boolean test result
283     results_list -- results list
284     """
285     if result:
286         logger.info(
287             'Test case {0} PASSED with {1}.'.format(
288                 test, out_plugin))
289     else:
290         logger.error(
291             'Test case {0} FAILED with {1}.'.format(
292                 test, out_plugin))
293     results_list.append((compute_node, out_plugin, test, result))
294
295
296 def _print_label(label):
297     """Print label on the screen
298
299     Keyword arguments:
300     label -- label string
301     """
302     label = label.strip()
303     length = 70
304     if label != '':
305         label = ' ' + label + ' '
306     length_label = len(label)
307     length1 = (length - length_label) / 2
308     length2 = length - length_label - length1
309     length1 = max(3, length1)
310     length2 = max(3, length2)
311     logger.info(('=' * length1) + label + ('=' * length2))
312
313
314 def _print_plugin_label(plugin, node_name):
315     """Print plug-in label.
316
317     Keyword arguments:
318     plugin -- plug-in name
319     node_id -- node ID
320     """
321     _print_label(
322         'Node {0}: Plug-in {1} Test case execution'.format(node_name, plugin))
323
324
325 def _print_final_result_of_plugin(
326         plugin, compute_ids, results, out_plugins, out_plugin):
327     """Print final results of plug-in.
328
329     Keyword arguments:
330     plugin -- plug-in name
331     compute_ids -- list of compute node IDs
332     results -- results list
333     out_plugins -- list of out plug-ins
334     out_plugin -- used out plug-in
335     """
336     print_line = ''
337     for id in compute_ids:
338         if out_plugin == 'Gnocchi':
339             if (id, out_plugin, plugin, True) in results:
340                 print_line += ' PASS   |'
341             elif (id, out_plugin, plugin, False) in results:
342                 print_line += ' FAIL   |'
343             else:
344                 print_line += ' NOT EX |'
345         elif out_plugin == 'AODH':
346             if (id, out_plugin, plugin, True) in results:
347                 print_line += ' PASS   |'
348             elif (id, out_plugin, plugin, False) in results:
349                 print_line += ' FAIL   |'
350             else:
351                 print_line += ' NOT EX |'
352         elif out_plugin == 'CSV':
353             if (id, out_plugin, plugin, True) in results:
354                 print_line += ' PASS   |'
355             elif (id, out_plugin, plugin, False) in results:
356                 print_line += ' FAIL   |'
357             else:
358                 print_line += ' NOT EX |'
359         else:
360             print_line += ' SKIP   |'
361     return print_line
362
363
364 def print_overall_summary(
365         compute_ids, tested_plugins, aodh_plugins, results, out_plugins):
366     """Print overall summary table.
367
368     Keyword arguments:
369     compute_ids -- list of compute IDs
370     tested_plugins -- list of plug-ins
371     results -- results list
372     out_plugins --  list of used out plug-ins
373     """
374     compute_node_names = ['Node-{}'.format(i) for i in range(
375         len((compute_ids)))]
376     all_computes_in_line = ''
377     for compute in compute_node_names:
378         all_computes_in_line += '| ' + compute + (' ' * (7 - len(compute)))
379     line_of_nodes = '| Test           ' + all_computes_in_line + '|'
380     logger.info('=' * 70)
381     logger.info('+' + ('-' * ((9 * len(compute_node_names))+16)) + '+')
382     logger.info(
383         '|' + ' ' * ((9*len(compute_node_names))/2)
384         + ' OVERALL SUMMARY'
385         + ' ' * (
386             9*len(compute_node_names) - (9*len(compute_node_names))/2)
387         + '|')
388     logger.info(
389         '+' + ('-' * 16) + '+' + (('-' * 8) + '+') * len(compute_node_names))
390     logger.info(line_of_nodes)
391     logger.info(
392         '+' + ('-' * 16) + '+' + (('-' * 8) + '+') * len(compute_node_names))
393     out_plugins_print = []
394     out_plugins_print1 = []
395     for key in out_plugins.keys():
396         if 'Gnocchi' in out_plugins[key]:
397             out_plugins_print1.append('Gnocchi')
398         if 'AODH' in out_plugins[key]:
399             out_plugins_print1.append('AODH')
400         if 'SNMP' in out_plugins[key]:
401             out_plugins_print1.append('SNMP')
402         if 'CSV' in out_plugins[key]:
403             out_plugins_print1.append('CSV')
404     for i in out_plugins_print1:
405         if i not in out_plugins_print:
406             out_plugins_print.append(i)
407     for out_plugin in out_plugins_print:
408         output_plugins_line = ''
409         for id in compute_ids:
410             out_plugin_result = '----'
411             if out_plugin == 'Gnocchi':
412                 out_plugin_result = \
413                     'PASS' if 'Gnocchi' in out_plugins_print else 'FAIL'
414             if out_plugin == 'AODH':
415                 out_plugin_result = \
416                     'PASS' if out_plugin in out_plugins_print else 'FAIL'
417             if out_plugin == 'SNMP':
418                 out_plugin_result = \
419                     'PASS' if [
420                         plugin for comp_id, out_pl, plugin, res in results
421                         if comp_id == id and res] else 'FAIL'
422             if out_plugin == 'CSV':
423                 out_plugin_result = \
424                     'PASS' if [
425                         plugin for comp_id, out_pl, plugin, res in results
426                         if comp_id == id and res] else 'FAIL'
427             else:
428                 out_plugin_result = 'FAIL'
429             output_plugins_line += '| ' + out_plugin_result + '   '
430         logger.info(
431             '| OUT:{}'.format(out_plugin) + (' ' * (11 - len(out_plugin)))
432             + output_plugins_line + '|')
433
434         if out_plugin == 'AODH':
435             for plugin in sorted(aodh_plugins.values()):
436                 line_plugin = _print_final_result_of_plugin(
437                     plugin, compute_ids, results, out_plugins, out_plugin)
438                 logger.info(
439                     '|  IN:{}'.format(plugin) + (' ' * (11-len(plugin)))
440                     + '|' + line_plugin)
441         else:
442             for plugin in sorted(tested_plugins.values()):
443                 line_plugin = _print_final_result_of_plugin(
444                     plugin, compute_ids, results, out_plugins, out_plugin)
445                 logger.info(
446                     '|  IN:{}'.format(plugin) + (' ' * (11-len(plugin)))
447                     + '|' + line_plugin)
448         logger.info(
449             '+' + ('-' * 16) + '+'
450             + (('-' * 8) + '+') * len(compute_node_names))
451     logger.info('=' * 70)
452
453
454 def _exec_testcase(
455         test_labels, name, out_plugin, controllers, compute_node,
456         conf, results, error_plugins, out_plugins):
457     """Execute the testcase.
458
459     Keyword arguments:
460     test_labels -- dictionary of plug-in IDs and their display names
461     name -- plug-in ID, key of test_labels dictionary
462     ceilometer_running -- boolean indicating whether Ceilometer is running
463     compute_node -- compute node ID
464     conf -- ConfigServer instance
465     results -- results list
466     error_plugins -- list of tuples with plug-in errors
467         (plugin, error_description, is_critical):
468         plugin -- plug-in ID, key of test_labels dictionary
469         error_decription -- description of the error
470         is_critical -- boolean value indicating whether error is critical
471     """
472     ovs_interfaces = conf.get_ovs_interfaces(compute_node)
473     ovs_configured_interfaces = conf.get_plugin_config_values(
474         compute_node, 'ovs_events', 'Interfaces')
475     ovs_configured_bridges = conf.get_plugin_config_values(
476          compute_node, 'ovs_stats', 'Bridges')
477     ovs_existing_configured_int = [
478         interface for interface in ovs_interfaces
479         if interface in ovs_configured_interfaces]
480     ovs_existing_configured_bridges = [
481         bridge for bridge in ovs_interfaces
482         if bridge in ovs_configured_bridges]
483     plugin_prerequisites = {
484         'intel_rdt': [(
485             conf.is_libpqos_on_node(compute_node),
486             'libpqos must be installed.')],
487         'mcelog': [(
488             conf.is_mcelog_installed(compute_node, 'mcelog'),
489             'mcelog must be installed.')],
490         'ovs_events': [(
491             len(ovs_existing_configured_int) > 0 or len(ovs_interfaces) > 0,
492             'Interfaces must be configured.')],
493         'ovs_stats': [(
494             len(ovs_existing_configured_bridges) > 0,
495             'Bridges must be configured.')]}
496     gnocchi_criteria_lists = {
497         'hugepages': 'hugepages',
498         'mcelog': 'mcelog',
499         'ovs_events': 'interface-ovs-system',
500         'ovs_stats': 'ovs_stats-br0.br0'}
501     aodh_criteria_lists = {
502         'mcelog': 'mcelog',
503         'ovs_events': 'ovs_events'}
504     snmp_mib_files = {
505         'intel_rdt': '/usr/share/snmp/mibs/Intel-Rdt.txt',
506         'hugepages': '/usr/share/snmp/mibs/Intel-Hugepages.txt',
507         'mcelog': '/usr/share/snmp/mibs/Intel-Mcelog.txt'}
508     snmp_mib_strings = {
509         'intel_rdt': [
510             'INTEL-RDT-MIB::rdtLlc.1',
511             'INTEL-RDT-MIB::rdtIpc.1',
512             'INTEL-RDT-MIB::rdtMbmRemote.1',
513             'INTEL-RDT-MIB::rdtMbmLocal.1'],
514         'hugepages': [
515             'INTEL-HUGEPAGES-MIB::hugepagesPageFree'],
516         'mcelog': [
517             'INTEL-MCELOG-MIB::memoryCorrectedErrors.1',
518             'INTEL-MCELOG-MIB::memoryCorrectedErrors.2']}
519     nr_hugepages = int(time.time()) % 10000
520     snmp_in_commands = {
521         'intel_rdt': None,
522         'hugepages': 'echo {} > /sys/kernel/'.format(nr_hugepages)
523                      + 'mm/hugepages/hugepages-2048kB/nr_hugepages',
524         'mcelog': '/root/mce-inject_df < /root/corrected'}
525     csv_subdirs = {
526         'intel_rdt': [
527             'intel_rdt-{}'.format(core)
528             for core in conf.get_plugin_config_values(
529                 compute_node, 'intel_rdt', 'Cores')],
530         'hugepages': [
531             'hugepages-mm-2048Kb', 'hugepages-node0-2048Kb',
532             'hugepages-node1-2048Kb'],
533         # 'ipmi': ['ipmi'],
534         'mcelog': [
535             'mcelog-SOCKET_0_CHANNEL_0_DIMM_any',
536             'mcelog-SOCKET_0_CHANNEL_any_DIMM_any'],
537         'ovs_stats': [
538             'ovs_stats-br0.br0'],
539         'ovs_events': [
540             'ovs_events-br0']}
541     # csv_meter_categories_ipmi = get_csv_categories_for_ipmi(conf,
542     # compute_node)
543     csv_meter_categories = {
544         'intel_rdt': [
545             'bytes-llc', 'ipc', 'memory_bandwidth-local',
546             'memory_bandwidth-remote'],
547         'hugepages': ['vmpage_number-free', 'vmpage_number-used'],
548         # 'ipmi': csv_meter_categories_ipmi,
549         'mcelog': [
550             'errors-corrected_memory_errors',
551             'errors-uncorrected_memory_errors'],
552         'ovs_stats': [
553             'if_dropped', 'if_errors', 'if_packets'],
554         'ovs_events': ['gauge-link_status']}
555
556     _print_plugin_label(
557         test_labels[name] if name in test_labels else name,
558         compute_node.get_name())
559     plugin_critical_errors = [
560         error for plugin, error, critical in error_plugins
561         if plugin == name and critical]
562     if plugin_critical_errors:
563         logger.error('Following critical errors occurred:'.format(name))
564         for error in plugin_critical_errors:
565             logger.error(' * ' + error)
566         _process_result(
567             compute_node.get_id(), out_plugin, test_labels[name], False,
568             results)
569     else:
570         plugin_errors = [
571             error for plugin, error, critical in error_plugins
572             if plugin == name and not critical]
573         if plugin_errors:
574             logger.warning('Following non-critical errors occured:')
575             for error in plugin_errors:
576                 logger.warning(' * ' + error)
577         failed_prerequisites = []
578         if name in plugin_prerequisites:
579             failed_prerequisites = [
580                 prerequisite_name for prerequisite_passed,
581                 prerequisite_name in plugin_prerequisites[name]
582                 if not prerequisite_passed]
583         if failed_prerequisites:
584             logger.error(
585                 '{} test will not be executed, '.format(name)
586                 + 'following prerequisites failed:')
587             for prerequisite in failed_prerequisites:
588                 logger.error(' * {}'.format(prerequisite))
589         else:
590             plugin_interval = conf.get_plugin_interval(compute_node, name)
591             if out_plugin == 'Gnocchi':
592                 res = conf.test_plugins_with_gnocchi(
593                     compute_node.get_name(), plugin_interval,
594                     logger, criteria_list=gnocchi_criteria_lists[name])
595             if out_plugin == 'AODH':
596                 res = conf.test_plugins_with_aodh(
597                     compute_node.get_name(), plugin_interval,
598                     logger, criteria_list=aodh_criteria_lists[name])
599             if out_plugin == 'SNMP':
600                 res = \
601                     name in snmp_mib_files and name in snmp_mib_strings \
602                     and tests.test_snmp_sends_data(
603                         compute_node,
604                         plugin_interval, logger,
605                         SNMPClient(conf, compute_node), snmp_mib_files[name],
606                         snmp_mib_strings[name], snmp_in_commands[name], conf)
607             if out_plugin == 'CSV':
608                 res = tests.test_csv_handles_plugin_data(
609                     compute_node, conf.get_plugin_interval(compute_node, name),
610                     name, csv_subdirs[name], csv_meter_categories[name],
611                     logger, CSVClient(conf))
612
613             if res and plugin_errors:
614                 logger.info(
615                     'Test works, but will be reported as failure,'
616                     + 'because of non-critical errors.')
617                 res = False
618             _process_result(
619                 compute_node.get_id(), out_plugin, test_labels[name],
620                 res, results)
621
622
623 def get_results_for_ovs_events(
624         plugin_labels, plugin_name, gnocchi_running,
625         compute_node, conf, results, error_plugins):
626     """ Testing OVS Events with python plugin
627     """
628     plugin_label = 'OVS events'
629     res = conf.enable_ovs_events(
630         compute_node, plugin_label, error_plugins, create_backup=False)
631     _process_result(
632         compute_node.get_id(), plugin_label, res, results)
633     logger.info("Results for OVS Events = {}" .format(results))
634
635
636 def create_ovs_bridge():
637     """Create OVS brides on compute nodes"""
638     handler = factory.Factory.get_handler('apex',
639                                           APEX_IP,
640                                           APEX_USER_STACK,
641                                           APEX_PKEY)
642     nodes = handler.get_nodes()
643     for node in nodes:
644         if node.is_compute():
645             node.run_cmd('sudo ovs-vsctl add-br br0')
646             node.run_cmd('sudo ovs-vsctl set-manager ptcp:6640')
647     logger.info('OVS Bridges created on compute nodes')
648
649
650 def mcelog_install():
651     """Install mcelog on compute nodes."""
652     _print_label('Enabling mcelog on compute nodes')
653     handler = factory.Factory.get_handler('apex',
654                                           APEX_IP,
655                                           APEX_USER_STACK,
656                                           APEX_PKEY)
657     nodes = handler.get_nodes()
658     for node in nodes:
659         if node.is_compute():
660             centos_release = node.run_cmd('uname -r')
661             if '3.10.0-514.26.2.el7.x86_64' not in centos_release:
662                 logger.info(
663                     'Mcelog will not be enabled '
664                     + 'on node-{0}, '.format(node.get_dict()['name'])
665                     + 'unsupported CentOS release found ({1}).'.format(
666                         centos_release))
667             else:
668                 logger.info(
669                     'Checking if  mcelog is enabled'
670                     + ' on node-{}...'.format(node.get_dict()['name']))
671                 res = node.run_cmd('ls')
672             if 'mce-inject_ea' and 'corrected' in res:
673                 logger.info(
674                     'Mcelog seems to be already installed '
675                     + 'on node-{}.'.format(node.get_dict()['name']))
676                 node.run_cmd('sudo modprobe mce-inject')
677                 node.run_cmd('sudo ./mce-inject_ea < corrected')
678             else:
679                 logger.info(
680                     'Mcelog will be enabled on node-{}...'.format(
681                         node.get_dict()['id']))
682                 node.put_file(
683                     '/usr/local/lib/python2.7/dist-packages/baro_tests/'
684                     + 'mce-inject_ea', 'mce-inject_ea')
685                 node.run_cmd('chmod a+x mce-inject_ea')
686                 node.run_cmd('echo "CPU 0 BANK 0" > corrected')
687                 node.run_cmd(
688                     'echo "STATUS 0xcc00008000010090" >>'
689                     + ' corrected')
690                 node.run_cmd(
691                     'echo "ADDR 0x0010FFFFFFF" >> corrected')
692                 node.run_cmd('sudo modprobe mce-inject')
693                 node.run_cmd('sudo ./mce-inject_ea < corrected')
694     logger.info('Mcelog is installed on all compute nodes')
695
696
697 def mcelog_delete():
698     """Uninstall mcelog from compute nodes."""
699     handler = factory.Factory.get_handler(
700             'apex', APEX_IP, APEX_USER, APEX_PKEY)
701     nodes = handler.get_nodes()
702     for node in nodes:
703         if node.is_compute():
704             output = node.run_cmd('ls')
705             if 'mce-inject_ea' in output:
706                 node.run_cmd('rm mce-inject_ea')
707             if 'corrected' in output:
708                 node.run_cmd('rm corrected')
709             node.run_cmd('sudo systemctl restart mcelog')
710     logger.info('Mcelog is deleted from all compute nodes')
711
712
713 def get_ssh_keys():
714     if not os.path.isdir(ID_RSA_DST_DIR):
715         os.makedirs(ID_RSA_DST_DIR)
716     if not os.path.isfile(ID_RSA_DST):
717         logger.info(
718             "RSA key file {} doesn't exist".format(ID_RSA_DST)
719             + ", it will be downloaded from installer node.")
720         handler = factory.Factory.get_handler(
721             'apex', APEX_IP, APEX_USER, APEX_PKEY)
722         apex = handler.get_installer_node()
723         apex.get_file(ID_RSA_SRC, ID_RSA_DST)
724     else:
725         logger.info("RSA key file {} exists.".format(ID_RSA_DST))
726
727
728 def _check_logger():
729     """Check whether there is global logger available and if not, define one."""
730     if 'logger' not in globals():
731         global logger
732         logger = logger.Logger("barometercollectd").getLogger()
733
734
735 def main(bt_logger=None):
736     """Check each compute node sends gnocchi metrics.
737
738     Keyword arguments:
739     bt_logger -- logger instance
740     """
741     logging.getLogger("paramiko").setLevel(logging.WARNING)
742     logging.getLogger("stevedore").setLevel(logging.WARNING)
743     logging.getLogger("opnfv.deployment.manager").setLevel(logging.WARNING)
744     if bt_logger is None:
745         _check_logger()
746     else:
747         global logger
748         logger = bt_logger
749     _print_label("Starting barometer tests suite")
750     get_ssh_keys()
751     conf = config_server.ConfigServer(APEX_IP, APEX_USER, logger)
752     controllers = conf.get_controllers()
753     if len(controllers) == 0:
754         logger.error('No controller nodes found!')
755         return 1
756     computes = conf.get_computes()
757     if len(computes) == 0:
758         logger.error('No compute nodes found!')
759         return 1
760
761     _print_label(
762         'Display of Control and Compute nodes available in the set up')
763     logger.info('controllers: {}'.format([('{0}: {1}'.format(
764         node.get_name(), node.get_ip())) for node in controllers]))
765     logger.info('computes: {}'.format([('{0}: {1}'.format(
766         node.get_name(), node.get_ip())) for node in computes]))
767
768     mcelog_install()
769     create_ovs_bridge()
770     gnocchi_running_on_con = False
771     aodh_running_on_con = False
772     snmp_running = False
773     _print_label('Testing Gnocchi, AODH and SNMP on nodes')
774
775     for controller in controllers:
776         gnocchi_running = (
777             gnocchi_running_on_con and conf.is_gnocchi_running(controller))
778         aodh_running = (
779             aodh_running_on_con or conf.is_aodh_running(controller))
780
781     compute_ids = []
782     compute_node_names = []
783     results = []
784     plugin_labels = {
785         'intel_rdt': 'Intel RDT',
786         'hugepages': 'Hugepages',
787         # 'ipmi': 'IPMI',
788         'mcelog': 'Mcelog',
789         'ovs_stats': 'OVS stats',
790         'ovs_events': 'OVS events'}
791     aodh_plugin_labels = {
792         'mcelog': 'Mcelog',
793         'ovs_events': 'OVS events'}
794     out_plugins = {}
795     out_plugins_to_test = []
796     for compute_node in computes:
797         node_id = compute_node.get_id()
798         node_name = compute_node.get_name()
799         out_plugins[node_id] = []
800         compute_ids.append(node_id)
801         compute_node_names.append(node_name)
802         plugins_to_enable = []
803         error_plugins = []
804         gnocchi_running = (
805             gnocchi_running or conf.check_gnocchi_plugin_included(
806                 compute_node))
807         aodh_running = (
808             aodh_running and conf.check_aodh_plugin_included(compute_node))
809         if gnocchi_running:
810             out_plugins[node_id].append("Gnocchi")
811         if aodh_running:
812             out_plugins[node_id].append("AODH")
813         if snmp_running:
814             out_plugins_to_test.append("SNMP")
815
816         if 'gnocchi' not in out_plugins[node_id]:
817             logger.info("CSV will be enabled for verification")
818             plugins_to_enable.append('csv')
819             out_plugins[node_id].append("CSV")
820             if plugins_to_enable:
821                 _print_label(
822                     'NODE {}: Enabling Test Plug-in '.format(node_name)
823                     + 'and Test case execution')
824             if plugins_to_enable and not conf.enable_plugins(
825                     compute_node, plugins_to_enable, error_plugins,
826                     create_backup=False):
827                 logger.error(
828                     'Failed to test plugins on node {}.'.format(node_id))
829                 logger.info(
830                     'Testcases on node {} will not be executed'.format(
831                         node_id))
832             else:
833                 if plugins_to_enable:
834                     collectd_restarted, collectd_warnings = \
835                         conf.restart_collectd(compute_node)
836                     sleep_time = 10
837                     logger.info(
838                         'Sleeping for {} seconds'.format(sleep_time)
839                         + ' after collectd restart...')
840                     time.sleep(sleep_time)
841                 if plugins_to_enable and not collectd_restarted:
842                     for warning in collectd_warnings:
843                         logger.warning(warning)
844                     logger.error(
845                         'Restart of collectd on node {} failed'.format(
846                             node_id))
847                     logger.info(
848                         'Testcases on node {}'.format(node_id)
849                         + ' will not be executed.')
850                 else:
851                     if collectd_warnings:
852                         for warning in collectd_warnings:
853                             logger.warning(warning)
854
855         for i in out_plugins[node_id]:
856             if i == 'AODH':
857                 for plugin_name in sorted(aodh_plugin_labels.keys()):
858                     _exec_testcase(
859                         aodh_plugin_labels, plugin_name, i,
860                         controllers, compute_node, conf, results,
861                         error_plugins, out_plugins[node_id])
862             else:
863                 for plugin_name in sorted(plugin_labels.keys()):
864                     _exec_testcase(
865                         plugin_labels, plugin_name, i,
866                         controllers, compute_node, conf, results,
867                         error_plugins, out_plugins[node_id])
868
869     mcelog_delete()
870     print_overall_summary(
871         compute_ids, plugin_labels, aodh_plugin_labels, results, out_plugins)
872
873     if ((len([res for res in results if not res[2]]) > 0)
874             or (len(results) < len(computes) * len(plugin_labels))):
875         logger.error('Some tests have failed or have not been executed')
876         return 1
877     return 0
878
879
880 if __name__ == '__main__':
881     sys.exit(main())