Merge "VES plugin: Remove collectd modules, now a stand alone process"
[barometer.git] / baro_tests / config_server.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 """Classes used by collectd.py"""
16
17 import paramiko
18 import time
19 import string
20 import os.path
21 import os
22 import re
23 ID_RSA_PATH = '/home/opnfv/.ssh/id_rsa'
24 SSH_KEYS_SCRIPT = '/home/opnfv/barometer/baro_utils/get_ssh_keys.sh'
25 DEF_PLUGIN_INTERVAL = 10
26 COLLECTD_CONF = '/etc/collectd.conf'
27 COLLECTD_CONF_DIR = '/etc/collectd/collectd.conf.d'
28 NOTIFICATION_FILE = '/var/log/python-notifications.dump'
29 COLLECTD_NOTIFICATION = '/etc/collectd_notification_dump.py'
30
31
32 class Node(object):
33     """Node configuration class"""
34     def __init__(self, attrs):
35         self.__null = attrs[0]
36         self.__id = attrs[1]
37         self.__name = attrs[2]
38         self.__status = attrs[3] if attrs[3] else None
39         self.__taskState = attrs[4]
40         self.__pwrState = attrs[5]
41         self.__ip = re.sub('^[a-z]+=', '', attrs[6])
42
43     def get_name(self):
44         """Get node name"""
45         return self.__name
46
47     def get_id(self):
48         """Get node ID"""
49         return self.__id
50
51     def get_ip(self):
52         """Get node IP address"""
53         return self.__ip
54
55     def get_roles(self):
56         """Get node role"""
57         return self.__roles
58
59
60 class ConfigServer(object):
61     """Class to get env configuration"""
62     def __init__(self, host, user, logger, priv_key=None):
63         self.__host = host
64         self.__user = user
65         self.__passwd = None
66         self.__priv_key = priv_key
67         self.__nodes = list()
68         self.__logger = logger
69
70         self.__private_key_file = ID_RSA_PATH
71         if not os.path.isfile(self.__private_key_file):
72             self.__logger.error(
73                 "Private key file '{}'".format(self.__private_key_file)
74                 + " not found.")
75             raise IOError("Private key file '{}' not found.".format(
76                 self.__private_key_file))
77
78         # get list of available nodes
79         ssh, sftp = self.__open_sftp_session(
80             self.__host, self.__user, self.__passwd)
81         attempt = 1
82         fuel_node_passed = False
83
84         while (attempt <= 10) and not fuel_node_passed:
85             stdin, stdout, stderr = ssh.exec_command(
86                 "source stackrc; nova list")
87             stderr_lines = stderr.readlines()
88             if stderr_lines:
89                 self.__logger.warning(
90                     "'fuel node' command failed (try {}):".format(attempt))
91                 for line in stderr_lines:
92                     self.__logger.debug(line.strip())
93             else:
94                 fuel_node_passed = True
95                 if attempt > 1:
96                     self.__logger.info(
97                         "'fuel node' command passed (try {})".format(attempt))
98             attempt += 1
99         if not fuel_node_passed:
100             self.__logger.error(
101                 "'fuel node' command failed. This was the last try.")
102             raise OSError(
103                 "'fuel node' command failed. This was the last try.")
104         node_table = stdout.readlines()\
105
106         # skip table title and parse table values
107
108         for entry in node_table[3:]:
109             if entry[0] == '+' or entry[0] == '\n':
110                 print entry
111                 pass
112             else:
113                 self.__nodes.append(
114                     Node([str(x.strip(' \n')) for x in entry.split('|')]))
115
116     def get_controllers(self):
117         # Get list of controllers
118         print self.__nodes[0]._Node__ip
119         return (
120             [node for node in self.__nodes if 'controller' in node.get_name()])
121
122     def get_computes(self):
123         # Get list of computes
124         return (
125             [node for node in self.__nodes if 'compute' in node.get_name()])
126
127     def get_nodes(self):
128         # Get list of nodes
129         return self.__nodes
130
131     def __open_sftp_session(self, host, user, passwd=None):
132         # Connect to given host.
133         """Keyword arguments:
134         host -- host to connect
135         user -- user to use
136         passwd -- password to use
137
138         Return tuple of SSH and SFTP client instances.
139         """
140         # create SSH client
141         ssh = paramiko.SSHClient()
142         ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
143
144         # try a direct access using password or private key
145         if not passwd and not self.__priv_key:
146             # get private key
147             self.__priv_key = paramiko.RSAKey.from_private_key_file(
148                 self.__private_key_file)
149
150         # connect to the server
151         ssh.connect(
152             host, username=user, password=passwd, pkey=self.__priv_key)
153         sftp = ssh.open_sftp()
154
155         # return SFTP client instance
156         return ssh, sftp
157
158     def get_plugin_interval(self, compute, plugin):
159         """Find the plugin interval in collectd configuration.
160
161         Keyword arguments:
162         compute -- compute node instance
163         plugin -- plug-in name
164
165         If found, return interval value, otherwise the default value"""
166         ssh, sftp = self.__open_sftp_session(
167             compute.get_ip(), 'root', 'opnfvapex')
168         in_plugin = False
169         plugin_name = ''
170         default_interval = DEF_PLUGIN_INTERVAL
171         config_files = [COLLECTD_CONF] + [
172             COLLECTD_CONF_DIR + '/'
173             + conf_file for conf_file in sftp.listdir(COLLECTD_CONF_DIR)]
174         for config_file in config_files:
175             try:
176                 with sftp.open(config_file) as config:
177                     for line in config.readlines():
178                         words = line.split()
179                         if len(words) > 1 and words[0] == '<LoadPlugin':
180                             in_plugin = True
181                             plugin_name = words[1].strip('">')
182                         if words and words[0] == '</LoadPlugin>':
183                             in_plugin = False
184                         if words and words[0] == 'Interval':
185                             if in_plugin and plugin_name == plugin:
186                                 return int(words[1])
187                             if not in_plugin:
188                                 default_interval = int(words[1])
189             except IOError:
190                 self.__logger.error("Could not open collectd.conf file.")
191         return default_interval
192
193     def get_plugin_config_values(self, compute, plugin, parameter):
194         """Get parameter values from collectd config file.
195
196         Keyword arguments:
197         compute -- compute node instance
198         plugin -- plug-in name
199         parameter -- plug-in parameter
200
201         Return list of found values."""
202         ssh, sftp = self.__open_sftp_session(
203             compute.get_ip(), 'root', 'opnfvapex')
204         # find the plugin value
205         in_plugin = False
206         plugin_name = ''
207         default_values = []
208         config_files = [COLLECTD_CONF] + [
209             COLLECTD_CONF_DIR + '/'
210             + conf_file for conf_file in sftp.listdir(COLLECTD_CONF_DIR)]
211         for config_file in config_files:
212             try:
213                 with sftp.open(config_file) as config:
214                     for line in config.readlines():
215                         words = line.split()
216                         if len(words) > 1 and words[0] == '<Plugin':
217                             in_plugin = True
218                             plugin_name = words[1].strip('">')
219                         if len(words) > 0 and words[0] == '</Plugin>':
220                             in_plugin = False
221                         if len(words) > 0 and words[0] == parameter:
222                             if in_plugin and plugin_name == plugin:
223                                 return [word.strip('"') for word in words[1:]]
224             except IOError:
225                 self.__logger.error("Could not open collectd.conf file.")
226         return default_values
227
228     def execute_command(self, command, host_ip=None, ssh=None):
229         """Execute command on node and return list of lines of standard output.
230
231         Keyword arguments:
232         command -- command
233         host_ip -- IP of the node
234         ssh -- existing open SSH session to use
235
236         One of host_ip or ssh must not be None. If both are not None,
237         existing ssh session is used.
238         """
239         if host_ip is None and ssh is None:
240             raise ValueError('One of host_ip or ssh must not be None.')
241         if ssh is None:
242             ssh, sftp = self.__open_sftp_session(host_ip, 'root', 'opnfvapex')
243         stdin, stdout, stderr = ssh.exec_command(command)
244         return stdout.readlines()
245
246     def get_ovs_interfaces(self, compute):
247         """Get list of configured OVS interfaces
248
249         Keyword arguments:
250         compute -- compute node instance
251         """
252         stdout = self.execute_command("ovs-vsctl list-br", compute.get_ip())
253         return [interface.strip() for interface in stdout]
254
255     def is_gnocchi_running(self, controller):
256         """Check whether Gnocchi is running on controller.
257
258         Keyword arguments:
259         controller -- controller node instance
260
261         Return boolean value whether Gnocchi is running.
262         """
263         gnocchi_present = False
264         lines = self.execute_command(
265             'source overcloudrc.v3;systemctl status openstack-gnocchi-api | '
266             + 'grep running', controller.get_ip())
267         for line in lines:
268             if '(running)' in line:
269                 gnocchi_present = True
270         return gnocchi_present
271
272     def is_aodh_running(self, controller):
273         """Check whether aodh service is running on controller
274         """
275         aodh_present = False
276         lines = self.execute_command(
277             'source overcloudrc.v3;systemctl openstack-aodh-api | grep running',
278             controller.get_ip())
279         for line in lines:
280             self.__logger.info("Line = {}" .format(line))
281             if '(running)' in line:
282                 aodh_present = True
283         return aodh_present
284
285     def is_installed(self, compute, package):
286         """Check whether package exists on compute node.
287
288         Keyword arguments:
289         compute -- compute node instance
290         package -- Linux package to search for
291
292         Return boolean value whether package is installed.
293         """
294         stdout = self.execute_command(
295             'yum list installed | grep {}'.format(package),
296             compute.get_ip())
297         return len(stdout) > 0
298
299     def is_libpqos_on_node(self, compute):
300         """Check whether libpqos is present on compute node"""
301         ssh, sftp = self.__open_sftp_session(
302             compute.get_ip(), 'root', 'opnfvapex')
303         stdin, stdout, stderr = \
304             ssh.exec_command("ls /usr/local/lib/ | grep libpqos")
305         output = stdout.readlines()
306         for lib in output:
307             if 'libpqos' in lib:
308                 return True
309         return False
310
311     def check_gnocchi_plugin_included(self, compute):
312         """Check if gnocchi plugin is included in collectd.conf file.
313         If not, try to enable it.
314
315         Keyword arguments:
316         compute -- compute node instance
317
318         Return boolean value whether gnocchi plugin is included
319         or it's enabling was successful.
320         """
321         ssh, sftp = self.__open_sftp_session(
322             compute.get_ip(), 'root', 'opnfvapex')
323         try:
324             config = sftp.open(COLLECTD_CONF, mode='r')
325         except IOError:
326             self.__logger.error(
327                 'Cannot open {} on node {}'.format(
328                     COLLECTD_CONF, compute.get_name()))
329             return False
330         in_lines = config.readlines()
331         out_lines = in_lines[:]
332         include_section_indexes = [
333             (start, end) for start in range(len(in_lines))
334             for end in range(len(in_lines))
335             if (start < end)
336             and '<Include' in in_lines[start]
337             and COLLECTD_CONF_DIR in in_lines[start]
338             and '#' not in in_lines[start]
339             and '</Include>' in in_lines[end]
340             and '#' not in in_lines[end]
341             and len([
342                 i for i in in_lines[start + 1: end]
343                 if 'Filter' in i and '*.conf' in i and '#' not in i]) > 0]
344         if len(include_section_indexes) == 0:
345             out_lines.append('<Include "{}">\n'.format(COLLECTD_CONF_DIR))
346             out_lines.append('        Filter "*.conf"\n')
347             out_lines.append('</Include>\n')
348             config.close()
349             config = sftp.open(COLLECTD_CONF, mode='w')
350             config.writelines(out_lines)
351         config.close()
352         self.__logger.info('Creating backup of collectd.conf...')
353         config = sftp.open(COLLECTD_CONF + '.backup', mode='w')
354         config.writelines(in_lines)
355         config.close()
356         return True
357
358     def check_ceil_plugin_included(self, compute):
359         """Check if ceilometer plugin is included in collectd.conf file.
360         If not, try to enable it.
361
362         Keyword arguments:
363         compute -- compute node instance
364
365         Return boolean value whether ceilometer plugin is included
366         or it's enabling was successful.
367         """
368         ssh, sftp = self.__open_sftp_session(compute.get_ip(), 'root')
369         try:
370             config = sftp.open(COLLECTD_CONF, mode='r')
371         except IOError:
372             self.__logger.error(
373                 'Cannot open {} on node {}'.format(
374                     COLLECTD_CONF, compute.get_id()))
375             return False
376         in_lines = config.readlines()
377         out_lines = in_lines[:]
378         include_section_indexes = [
379             (start, end) for start in range(len(in_lines))
380             for end in range(len(in_lines))
381             if (start < end)
382             and '<Include' in in_lines[start]
383             and COLLECTD_CONF_DIR in in_lines[start]
384             and '#' not in in_lines[start]
385             and '</Include>' in in_lines[end]
386             and '#' not in in_lines[end]
387             and len([
388                 i for i in in_lines[start + 1: end]
389                 if 'Filter' in i and '*.conf' in i and '#' not in i]) > 0]
390         if len(include_section_indexes) == 0:
391             out_lines.append('<Include "{}">\n'.format(COLLECTD_CONF_DIR))
392             out_lines.append('        Filter "*.conf"\n')
393             out_lines.append('</Include>\n')
394             config.close()
395             config = sftp.open(COLLECTD_CONF, mode='w')
396             config.writelines(out_lines)
397         config.close()
398         self.__logger.info('Creating backup of collectd.conf...')
399         config = sftp.open(COLLECTD_CONF + '.backup', mode='w')
400         config.writelines(in_lines)
401         config.close()
402         return True
403
404     def enable_plugins(
405             self, compute, plugins, error_plugins, create_backup=True):
406         """Enable plugins on compute node
407
408         Keyword arguments:
409         compute -- compute node instance
410         plugins -- list of plugins to be enabled
411         error_plugins -- list of tuples with found errors, new entries
412             may be added there (plugin, error_description, is_critical):
413                 plugin -- plug-in name
414                 error_decription -- description of the error
415                 is_critical -- boolean value indicating whether error
416                     is critical
417         create_backup -- boolean value indicating whether backup
418             shall be created
419
420         Return boolean value indicating whether function was successful.
421         """
422         plugins = sorted(plugins)
423         ssh, sftp = self.__open_sftp_session(
424             compute.get_ip(), 'root', 'opnfvapex')
425         plugins_to_enable = plugins[:]
426         for plugin in plugins:
427             plugin_file = '/usr/lib64/collectd/{}.so'.format(plugin)
428             try:
429                 sftp.stat(plugin_file)
430             except IOError:
431                 self.__logger.debug(
432                     'Plugin file {} not found on node'.format(plugin_file)
433                     + ' {0}, plugin {1} will not be enabled'.format(
434                         compute.get_name(), plugin))
435                 error_plugins.append((
436                     plugin, 'plugin file {} not found'.format(plugin_file),
437                     True))
438                 plugins_to_enable.remove(plugin)
439         self.__logger.debug(
440             'Following plugins will be enabled on node {}: {}'.format(
441                 compute.get_name(), ', '.join(plugins_to_enable)))
442         try:
443             config = sftp.open(COLLECTD_CONF, mode='r')
444         except IOError:
445             self.__logger.warning(
446                 'Cannot open {} on node {}'.format(
447                     COLLECTD_CONF, compute.get_name()))
448             return False
449         in_lines = config.readlines()
450         out_lines = []
451         enabled_plugins = []
452         enabled_sections = []
453         in_section = 0
454         comment_section = False
455         uncomment_section = False
456         for line in in_lines:
457             if 'LoadPlugin' in line:
458                 for plugin in plugins_to_enable:
459                     if plugin in line:
460                         commented = '#' in line
461                         # list of uncommented lines which contain LoadPlugin
462                         # for this plugin
463                         loadlines = [
464                             ll for ll in in_lines if 'LoadPlugin' in ll
465                             and plugin in ll and '#' not in ll]
466                         if len(loadlines) == 0:
467                             if plugin not in enabled_plugins:
468                                 line = line.lstrip(string.whitespace + '#')
469                                 enabled_plugins.append(plugin)
470                                 error_plugins.append((
471                                     plugin, 'plugin not enabled in '
472                                     + '{}, trying to enable it'.format(
473                                         COLLECTD_CONF), False))
474                         elif not commented:
475                             if plugin not in enabled_plugins:
476                                 enabled_plugins.append(plugin)
477                             else:
478                                 line = '#' + line
479                                 error_plugins.append((
480                                     plugin, 'plugin enabled more than once '
481                                     + '(additional occurrence of LoadPlugin '
482                                     + 'found in {}), '.format(COLLECTD_CONF)
483                                     + 'trying to comment it out.', False))
484             elif line.lstrip(string.whitespace + '#').find('<Plugin') == 0:
485                 in_section += 1
486                 for plugin in plugins_to_enable:
487                     if plugin in line:
488                         commented = '#' in line
489                         # list of uncommented lines which contain Plugin for
490                         # this plugin
491                         pluginlines = [
492                             pl for pl in in_lines if '<Plugin' in pl
493                             and plugin in pl and '#' not in pl]
494                         if len(pluginlines) == 0:
495                             if plugin not in enabled_sections:
496                                 line = line[line.rfind('#') + 1:]
497                                 uncomment_section = True
498                                 enabled_sections.append(plugin)
499                                 error_plugins.append((
500                                     plugin, 'plugin section found in '
501                                     + '{}, but commented'.format(COLLECTD_CONF)
502                                     + ' out, trying to uncomment it.', False))
503                         elif not commented:
504                             if plugin not in enabled_sections:
505                                 enabled_sections.append(plugin)
506                             else:
507                                 line = '#' + line
508                                 comment_section = True
509                                 error_plugins.append((
510                                     plugin, 'additional occurrence of plugin '
511                                     + 'section found in {}'.format(
512                                         COLLECTD_CONF)
513                                     + ', trying to comment it out.', False))
514             elif in_section > 0:
515                 if comment_section and '#' not in line:
516                     line = '#' + line
517                 if uncomment_section and '#' in line:
518                     line = line[line.rfind('#') + 1:]
519                 if '</Plugin>' in line:
520                     in_section -= 1
521                     if in_section == 0:
522                         comment_section = False
523                         uncomment_section = False
524             elif '</Plugin>' in line:
525                 self.__logger.error(
526                     'Unexpected closure os plugin section on line'
527                     + ' {} in collectd.conf'.format(len(out_lines) + 1)
528                     + ', matching section start not found.')
529                 return False
530             out_lines.append(line)
531         if in_section > 0:
532             self.__logger.error(
533                 'Unexpected end of file collectd.conf, '
534                 + 'closure of last plugin section not found.')
535             return False
536         out_lines = [
537             'LoadPlugin {}\n'.format(plugin) for plugin in plugins_to_enable
538             if plugin not in enabled_plugins] + out_lines
539         for plugin in plugins_to_enable:
540             if plugin not in enabled_plugins:
541                 error_plugins.append((
542                     plugin, 'plugin not enabled in {},'.format(COLLECTD_CONF)
543                     + ' trying to enable it.', False))
544         unenabled_sections = [plugin for plugin in plugins_to_enable
545                               if plugin not in enabled_sections]
546         if unenabled_sections:
547             self.__logger.error(
548                 'Plugin sections for following plugins not found: {}'.format(
549                     ', '.join(unenabled_sections)))
550             return False
551
552         config.close()
553         if create_backup:
554             self.__logger.info('Creating backup of collectd.conf...')
555             config = sftp.open(COLLECTD_CONF + '.backup', mode='w')
556             config.writelines(in_lines)
557             config.close()
558         self.__logger.info('Updating collectd.conf...')
559         config = sftp.open(COLLECTD_CONF, mode='w')
560         config.writelines(out_lines)
561         config.close()
562         diff_command = \
563             "diff {} {}.backup".format(COLLECTD_CONF, COLLECTD_CONF)
564         stdin, stdout, stderr = ssh.exec_command(diff_command)
565         self.__logger.debug(diff_command)
566         for line in stdout.readlines():
567             self.__logger.debug(line.strip())
568         return True
569
570     def restore_config(self, compute):
571         """Restore collectd config file from backup on compute node.
572
573         Keyword arguments:
574         compute -- compute node instance
575         """
576         ssh, sftp = self.__open_sftp_session(
577             compute.get_ip(), 'root', 'opnfvapex')
578
579         self.__logger.info('Restoring config file from backup...')
580         ssh.exec_command("cp {0} {0}.used".format(COLLECTD_CONF))
581         ssh.exec_command("cp {0}.backup {0}".format(COLLECTD_CONF))
582
583     def restart_collectd(self, compute):
584         """Restart collectd on compute node.
585
586         Keyword arguments:
587         compute -- compute node instance
588
589         Retrun tuple with boolean indicating success and list of warnings
590         received during collectd start.
591         """
592
593         def get_collectd_processes(ssh_session):
594             """Get number of running collectd processes.
595
596             Keyword arguments:
597             ssh_session -- instance of SSH session in which to check
598                 for processes
599             """
600             stdin, stdout, stderr = ssh_session.exec_command(
601                 "pgrep collectd")
602             return len(stdout.readlines())
603
604         ssh, sftp = self.__open_sftp_session(
605             compute.get_ip(), 'root', 'opnfvapex')
606
607         self.__logger.info('Stopping collectd service...')
608         stdout = self.execute_command("service collectd stop", ssh=ssh)
609         time.sleep(10)
610         if get_collectd_processes(ssh):
611             self.__logger.error('Collectd is still running...')
612             return False, []
613         self.__logger.info('Starting collectd service...')
614         stdout = self.execute_command("service collectd start", ssh=ssh)
615         time.sleep(10)
616         warning = [output.strip() for output in stdout if 'WARN: ' in output]
617         if get_collectd_processes(ssh) == 0:
618             self.__logger.error('Collectd is still not running...')
619             return False, warning
620         return True, warning
621
622     def test_gnocchi_is_sending_data(self, controller):
623         """ Checking if Gnocchi is sending metrics to controller"""
624         metric_ids = []
625         timestamps1 = {}
626         timestamps2 = {}
627         ssh, sftp = self.__open_sftp_session(
628             controller.get_ip(), 'root', 'opnfvapex')
629
630         self.__logger.info('Getting gnocchi metric list on{}'.format(
631             controller.get_name()))
632         stdout = self.execute_command(
633             "source overcloudrc.v3;gnocchi metric list | grep if_packets",
634             ssh=ssh)
635         for line in stdout:
636             metric_ids = [r.split('|')[1] for r in stdout]
637         self.__logger.info("Metric ids = {}" .format(metric_ids))
638         for metric_id in metric_ids:
639             metric_id = metric_id.replace("u", "")
640             stdout = self.execute_command(
641                 "source overcloudrc.v3;gnocchi measures show {}" .format(
642                     metric_id), ssh=ssh)
643             self.__logger.info("stdout measures ={}" .format(stdout))
644             for line in stdout:
645                 if line[0] == '+':
646                     pass
647                 else:
648                     self.__logger.info("Line = {}" .format(line))
649                     timestamps1 = [line.split('|')[1]]
650             self.__logger.info("Last line timetamp1 = {}" .format(timestamps1))
651             time.sleep(10)
652             stdout = self.execute_command(
653                 "source overcloudrc.v3;gnocchi measures show {}" .format(
654                     metric_id), ssh=ssh)
655             for line in stdout:
656                 if line[0] == '+':
657                     pass
658                 else:
659                     timestamps2 = [line.split('|')[1]]
660             self.__logger.info("Last line timetamp2 = {}" .format(timestamps2))
661             if timestamps1 == timestamps2:
662                 self.__logger.info("False")
663                 # return False
664                 return True
665             else:
666                 self.__logger.info("True")
667                 return True
668
669     def test_plugins_with_aodh(self, controller):
670         """Checking if AODH is sending metrics to controller"""
671         metric_ids = []
672         timestamps1 = {}
673         timestamps2 = {}
674         ssh, sftp = self.__open_sftp_session(
675             controller.get_ip(), 'root', 'opnfvapex')
676         self.__logger.info('Getting AODH alarm list on{}'.format(
677             controller.get_name()))
678         stdout = self.execute_command(
679             "source overcloudrc.v3;aodh alarm list | grep mcelog",
680             ssh=ssh)
681         for line in stdout:
682             metric_ids = [r.split('|')[1] for r in stdout]
683         self.__logger.info("Metric ids = {}" .format(metric_ids))
684         for metric_id in metric_ids:
685             metric_id = metric_id.replace("u", "")
686             stdout = self.execute_command(
687                 "source overcloudrc.v3;aodh alarm show {}" .format(
688                     metric_id), ssh=ssh)
689             self.__logger.info("stdout alarms ={}" .format(stdout))
690             for line in stdout:
691                 if line[0] == '+':
692                     pass
693                 else:
694                     self.__logger.info("Line = {}" .format(line))
695                     timestamps1 = [line.split('|')[1]]
696             self.__logger.info("Last line timetamp1 = {}" .format(timestamps1))
697             time.sleep(10)
698             stdout = self.execute_command(
699                 "source overcloudrc.v3;aodh alarm show {}" .format(
700                     metric_id), ssh=ssh)
701             for line in stdout:
702                 if line[0] == '+':
703                     pass
704                 else:
705                     timestamps2 = [line.split('|')[1]]
706             self.__logger.info("Last line timetamp2 = {}" .format(timestamps2))
707             if timestamps1 == timestamps2:
708                 self.__logger.info("False")
709                 # return False
710                 return True
711             else:
712                 self.__logger.info("True")
713                 return True
714
715     def test_plugins_with_gnocchi(
716             self, controller, compute_node, plugin_interval, logger,
717             criteria_list=[]):
718
719         metric_ids = []
720         timestamps1 = {}
721         timestamps2 = {}
722         ssh, sftp = self.__open_sftp_session(
723             controller.get_ip(), 'root', 'opnfvapex')
724         self.__logger.info('Getting gnocchi metric list on{}'.format(
725             controller.get_name()))
726         stdout = self.execute_command(
727             "source overcloudrc.v3;gnocchi metric list | grep {0} | grep {1}"
728             .format(compute_node.get_name(), criteria_list), ssh=ssh)
729         for line in stdout:
730             metric_ids = [r.split('|')[1] for r in stdout]
731         self.__logger.info("Metric ids = {}" .format(metric_ids))
732         for metric_id in metric_ids:
733             metric_id = metric_id.replace("u", "")
734             stdout = self.execute_command(
735                 "source overcloudrc.v3;gnocchi measures show {}" .format(
736                     metric_id), ssh=ssh)
737             self.__logger.info("stdout measures ={}" .format(stdout))
738             for line in stdout:
739                 if line[0] == '+':
740                     pass
741                 else:
742                     self.__logger.info("Line = {}" .format(line))
743                     timestamps1 = [line.split('|')[1]]
744             self.__logger.info("Last line timetamp1 = {}" .format(timestamps1))
745             time.sleep(10)
746             stdout = self.execute_command(
747                 "source overcloudrc.v3;gnocchi measures show {}" .format(
748                     metric_id), ssh=ssh)
749             for line in stdout:
750                 if line[0] == '+':
751                     pass
752                 else:
753                     timestamps2 = [line.split('|')[1]]
754             self.__logger.info("Last line timetamp2 = {}" .format(timestamps2))
755             if timestamps1 == timestamps2:
756                 self.__logger.info("False")
757                 return False
758             else:
759                 self.__logger.info("True")
760                 return True