1 # -*- coding: utf-8 -*-
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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
15 """Classes used by collectd.py"""
22 from opnfv.deployment import factory
23 ID_RSA_PATH = '/root/.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 APEX_IP = os.getenv("INSTALLER_IP").rstrip('\n')
32 APEX_USER_STACK = 'stack'
33 APEX_PKEY = '/root/.ssh/id_rsa'
34 PATH = os.path.dirname(os.path.realpath(__file__))
38 """Node configuration class"""
39 def __init__(self, attrs):
40 self.__null = attrs[0]
42 self.__name = attrs[2]
43 self.__status = attrs[3] if attrs[3] else None
44 self.__taskState = attrs[4]
45 self.__pwrState = attrs[5]
46 self.__ip = re.sub('^[a-z]+=', '', attrs[6])
57 """Get node IP address"""
66 handler = factory.Factory.get_handler('apex',
70 nodes = handler.get_nodes()
74 class ConfigServer(object):
75 """Class to get env configuration"""
76 def __init__(self, host, user, logger, priv_key=None):
80 self.__priv_key = priv_key
82 self.__logger = logger
84 self.__private_key_file = ID_RSA_PATH
85 if not os.path.isfile(self.__private_key_file):
87 "Private key file '{}'".format(self.__private_key_file)
89 raise IOError("Private key file '{}' not found.".format(
90 self.__private_key_file))
92 # get list of available nodes
93 ssh, sftp = self.__open_sftp_session(
94 self.__host, self.__user, self.__passwd)
96 fuel_node_passed = False
98 while (attempt <= 10) and not fuel_node_passed:
99 stdin, stdout, stderr = ssh.exec_command(
100 "source stackrc; nova list")
101 stderr_lines = stderr.readlines()
103 self.__logger.warning(
104 "'Apex node' command failed (try {}):".format(attempt))
105 for line in stderr_lines:
106 self.__logger.debug(line.strip())
108 fuel_node_passed = True
111 "'Apex node' command passed (try {})".format(attempt))
113 if not fuel_node_passed:
115 "'Apex node' command failed. This was the last try.")
117 "'Apex node' command failed. This was the last try.")
118 node_table = stdout.readlines()\
120 # skip table title and parse table values
122 for entry in node_table[3:]:
123 if entry[0] == '+' or entry[0] == '\n':
128 Node([str(x.strip(' \n')) for x in entry.split('|')]))
130 def get_controllers(self):
131 # Get list of controllers
132 print self.__nodes[0]._Node__ip
134 [node for node in self.__nodes if 'controller' in node.get_name()])
136 def get_computes(self):
137 # Get list of computes
139 [node for node in self.__nodes if 'compute' in node.get_name()])
145 def __open_sftp_session(self, host, user, passwd=None):
146 # Connect to given host.
147 """Keyword arguments:
148 host -- host to connect
150 passwd -- password to use
152 Return tuple of SSH and SFTP client instances.
155 ssh = paramiko.SSHClient()
156 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
158 # try a direct access using password or private key
159 if not passwd and not self.__priv_key:
161 self.__priv_key = paramiko.RSAKey.from_private_key_file(
162 self.__private_key_file)
164 # connect to the server
166 host, username=user, password=passwd, pkey=self.__priv_key)
167 sftp = ssh.open_sftp()
169 # return SFTP client instance
172 def get_plugin_interval(self, compute, plugin):
173 """Find the plugin interval in collectd configuration.
176 compute -- compute node instance
177 plugin -- plug-in name
179 If found, return interval value, otherwise the default value"""
180 default_interval = DEF_PLUGIN_INTERVAL
181 compute_name = compute.get_name()
182 nodes = get_apex_nodes()
184 if compute_name == node.get_dict()['name']:
185 stdout = node.run_cmd(
186 'cat /etc/collectd/collectd.conf.d/{}.conf'.format(plugin))
187 for line in stdout.split('\n'):
188 if 'Interval' in line:
190 return default_interval
192 def get_plugin_config_values(self, compute, plugin, parameter):
193 """Get parameter values from collectd config file.
196 compute -- compute node instance
197 plugin -- plug-in name
198 parameter -- plug-in parameter
200 Return list of found values."""
202 compute_name = compute.get_name()
203 nodes = get_apex_nodes()
205 if compute_name == node.get_dict()['name']:
206 stdout = node.run_cmd(
207 'cat /etc/collectd/collectd.conf.d/{}.conf' .format(plugin))
208 for line in stdout.split('\n'):
209 if 'Interfaces' in line:
210 return line.split(' ', 1)[1]
211 elif 'Bridges' in line:
212 return line.split(' ', 1)[1]
213 elif 'Cores' in line:
214 return line.split(' ', 1)[1]
217 return default_values
219 def execute_command(self, command, host_ip=None, ssh=None):
220 """Execute command on node and return list of lines of standard output.
224 host_ip -- IP of the node
225 ssh -- existing open SSH session to use
227 One of host_ip or ssh must not be None. If both are not None,
228 existing ssh session is used.
230 if host_ip is None and ssh is None:
231 raise ValueError('One of host_ip or ssh must not be None.')
233 ssh, sftp = self.__open_sftp_session(host_ip, 'root', 'opnfvapex')
234 stdin, stdout, stderr = ssh.exec_command(command)
235 return stdout.readlines()
237 def get_ovs_interfaces(self, compute):
238 """Get list of configured OVS interfaces
241 compute -- compute node instance
243 compute_name = compute.get_name()
244 nodes = get_apex_nodes()
246 if compute_name == node.get_dict()['name']:
247 stdout = node.run_cmd('sudo ovs-vsctl list-br')
250 def is_gnocchi_running(self, controller):
251 """Check whether Gnocchi is running on controller.
254 controller -- controller node instance
256 Return boolean value whether Gnocchi is running.
258 gnocchi_present = False
259 controller_name = controller.get_name()
260 nodes = get_apex_nodes()
262 if controller_name == node.get_dict()['name']:
264 '/home/opnfv/functest/conf/openstack.creds',
266 stdout = node.run_cmd(
267 "source overcloudrc.v3;"
268 + "openstack catalog list | grep gnocchi")
269 if 'gnocchi' in stdout:
270 gnocchi_present = True
271 return gnocchi_present
273 def is_aodh_running(self, controller):
274 """Check whether aodh service is running on controller
277 controller_name = controller.get_name()
278 nodes = get_apex_nodes()
280 if controller_name == node.get_dict()['name']:
282 '/home/opnfv/functest/conf/openstack.creds',
284 stdout = node.run_cmd(
285 "source overcloudrc.v3;"
286 + "openstack catalog list | grep aodh")
291 def is_mcelog_installed(self, compute, package):
292 """Check whether package exists on compute node.
295 compute -- compute node instance
296 package -- Linux package to search for
298 Return boolean value whether package is installed.
300 compute_name = compute.get_name()
301 nodes = get_apex_nodes()
303 if compute_name == node.get_dict()['name']:
304 stdout = node.run_cmd(
305 'yum list installed | grep mcelog')
308 elif 'mcelog' in stdout:
313 def is_libpqos_on_node(self, compute):
314 """Check whether libpqos is present on compute node"""
316 compute_name = compute.get_name()
317 nodes = get_apex_nodes()
319 if compute_name == node.get_dict()['name']:
320 stdout = node.run_cmd('ls /usr/local/lib/ | grep libpqos')
321 if 'libpqos' in stdout:
325 def check_aodh_plugin_included(self, compute):
326 """Check if aodh plugin is included in collectd.conf file.
327 If not, try to enable it.
330 compute -- compute node instance
332 Return boolean value whether AODH plugin is included
333 or it's enabling was successful.
335 compute_name = compute.get_name()
336 nodes = get_apex_nodes()
338 if compute_name == node.get_dict()['name']:
339 aodh_conf = node.run_cmd('ls /etc/collectd/collectd.conf.d')
340 if 'aodh.conf' not in aodh_conf:
342 "AODH Plugin not included in compute node")
346 "AODH plugin present in compute node {}" .format(
351 def check_gnocchi_plugin_included(self, compute):
352 """Check if gnocchi plugin is included in collectd.conf file.
353 If not, try to enable it.
356 compute -- compute node instance
358 Return boolean value whether gnocchi plugin is included
359 or it's enabling was successful.
361 compute_name = compute.get_name()
362 nodes = get_apex_nodes()
364 if compute_name == node.get_dict()['name']:
365 gnocchi_conf = node.run_cmd('ls /etc/collectd/collectd.conf.d')
366 if 'collectd-ceilometer-plugin.conf' not in gnocchi_conf:
367 self.__logger.info("Gnocchi Plugin not included")
371 "Gnochi plugin available in compute node {}" .format(
376 def check_snmp_plugin_included(self, compute):
377 """Check if SNMP plugin is active in compute node.
379 snmp_mib = '/usr/share/snmp/mibs/Intel-Rdt.txt'
380 snmp_string = 'INTEL-RDT-MIB::intelRdt'
381 compute_name = compute.get_name()
382 nodes = get_apex_nodes()
384 if compute_name == node.get_dict()['name']:
385 stdout = node.run_cmd(
386 'snmpwalk -v2c -m {0} -c public localhost {1}' .format(
387 snmp_mib, snmp_string))
388 self.__logger.info("snmp output = {}" .format(stdout))
395 self, compute, plugins, error_plugins, create_backup=True):
396 """Enable plugins on compute node
399 compute -- compute node instance
400 plugins -- list of plugins to be enabled
402 Return boolean value indicating whether function was successful.
404 plugins = sorted(plugins)
405 compute_name = compute.get_name()
406 nodes = get_apex_nodes()
408 if compute_name == node.get_dict()['name']:
410 'PATH/csv.conf', 'csv.conf')
413 + '/etc/collectd/collectd.conf.d/csv.conf')
416 def restart_collectd(self, compute):
417 """Restart collectd on compute node.
420 compute -- compute node instance
422 Retrun tuple with boolean indicating success and list of warnings
423 received during collectd start.
425 compute_name = compute.get_name()
426 nodes = get_apex_nodes()
428 def get_collectd_processes(compute_node):
429 """Get number of running collectd processes.
432 ssh_session -- instance of SSH session in which to check
435 stdout = compute_node.run_cmd("pgrep collectd")
439 if compute_name == node.get_dict()['name']:
440 # node.run_cmd('su; "opnfvapex"')
441 self.__logger.info('Stopping collectd service...')
442 node.run_cmd('sudo systemctl stop collectd')
444 if get_collectd_processes(node):
445 self.__logger.error('Collectd is still running...')
447 self.__logger.info('Starting collectd service...')
448 stdout = node.run_cmd('sudo systemctl start collectd')
451 output.strip() for output in stdout if 'WARN: ' in output]
452 if get_collectd_processes(node) == 0:
453 self.__logger.error('Collectd is still not running...')
454 return False, warning
457 def test_plugins_with_aodh(
458 self, compute, plugin_interval, logger,
464 nodes = get_apex_nodes()
466 if node.is_controller():
467 self.__logger.info('Getting AODH Alarm list on {}' .format(
468 (node.get_dict()['name'])))
470 '/home/opnfv/functest/conf/openstack.creds',
472 stdout = node.run_cmd(
473 "source overcloudrc.v3;"
474 + "aodh alarm list | grep {0} | grep {1}"
475 .format(criteria_list, compute))
476 for line in stdout.splitlines():
477 line = line.replace('|', "")
478 metric_id = line.split()[0]
479 stdout = node.run_cmd(
480 'source overcloudrc.v3; aodh alarm show {}' .format(
482 for line in stdout.splitlines()[3: -1]:
483 line = line.replace('|', "")
484 if line.split()[0] == 'timestamp':
485 timestamps1 = line.split()[1]
489 stdout = node.run_cmd(
490 "source overcloudrc.v3; aodh alarm show {}" .format(
492 for line in stdout.splitlines()[3:-1]:
493 line = line.replace('|', "")
494 if line.split()[0] == 'timestamp':
495 timestamps2 = line.split()[1]
498 if timestamps1 == timestamps2:
500 "Data not updated after interval of 12 seconds")
503 self.__logger.info("PASS")
506 def test_plugins_with_gnocchi(
507 self, compute, plugin_interval, logger,
513 nodes = get_apex_nodes()
515 if node.is_controller():
516 self.__logger.info('Getting gnocchi metric list on {}' .format(
517 (node.get_dict()['name'])))
519 '/home/opnfv/functest/conf/openstack.creds',
521 stdout = node.run_cmd(
522 "source overcloudrc.v3;"
523 + "gnocchi metric list | grep {0} | grep {1}"
524 .format(criteria_list, compute))
525 for line in stdout.splitlines():
526 line = line.replace('|', "")
527 metric_id = line.split()[0]
528 stdout = node.run_cmd(
529 'source overcloudrc.v3;gnocchi measures show {}'.format(
531 for line in stdout.splitlines()[3: -1]:
535 timestamps1 = line.replace('|', "")
536 timestamps1 = timestamps1.split()[0]
538 stdout = node.run_cmd(
539 "source overcloudrc.v3;gnocchi measures show {}".format(
541 for line in stdout.splitlines()[3:-1]:
545 timestamps2 = line.replace('|', "")
546 timestamps2 = timestamps2.split()[0]
547 if timestamps1 == timestamps2:
548 self.__logger.info("Data not updated after 12 seconds")
551 self.__logger.info("PASS")
554 def test_plugins_with_snmp(
555 self, compute, plugin_interval, logger, plugin, snmp_mib_files=[],
556 snmp_mib_strings=[], snmp_in_commands=[]):
558 if plugin == 'hugepages' or 'intel_rdt' or 'mcelog':
559 nodes = get_apex_nodes()
561 if compute == node.get_dict()['name']:
562 stdout = node.run_cmd(
563 'snmpwalk -v2c -m {0} -c public localhost {1}' .format(
564 snmp_mib_files, snmp_mib_strings))
565 self.__logger.info("{}" .format(stdout))
567 self.__logger.info("No output from snmpwalk")
569 elif 'OID' in stdout:
570 self.__logger.info("SNMP query failed")
573 counter1 = stdout.split()[3]
575 stdout = node.run_cmd(
576 'snmpwalk -v2c -m {0} -c public localhost {1}' .format(
577 snmp_mib_files, snmp_mib_strings))
578 self.__logger.info("{}" .format(stdout))
580 self.__logger.info("No output from snmpwalk")
581 elif 'OID' in stdout:
583 "SNMP query failed during second check")
584 self.__logger.info("waiting for 10 sec")
586 stdout = node.run_cmd(
587 'snmpwalk -v2c -m {0} -c public localhost {1}' .format(
588 snmp_mib_files, snmp_mib_strings))
589 self.__logger.info("{}" .format(stdout))
591 self.__logger.info("No output from snmpwalk")
592 elif 'OID' in stdout:
593 self.__logger.info("SNMP query failed again")
594 self.__logger.info("Failing this test case")
597 counter2 = stdout.split()[3]
599 if counter1 == counter2: