blob: f31abe62ec90afedf44a0e27378cf7f0e8d68c73 [file] [log] [blame]
Peter D Phan72ce6b82021-06-03 06:18:26 -05001#!/usr/bin/env python
2
3r"""
4See class prolog below for details.
5"""
6
7import os
8import sys
9import yaml
10import time
11import platform
12from errno import EACCES, EPERM
Peter D Phan0c669772021-06-24 13:52:42 -050013import subprocess
Peter D Phan72ce6b82021-06-03 06:18:26 -050014from ssh_utility import SSHRemoteclient
Peter D Phan5963d632021-07-12 09:58:55 -050015from telnet_utility import TelnetRemoteclient
Peter D Phan72ce6b82021-06-03 06:18:26 -050016
17
18class FFDCCollector:
19
20 r"""
21 Sends commands from configuration file to the targeted system to collect log files.
22 Fetch and store generated files at the specified location.
23
24 """
25
Peter D Phan0c669772021-06-24 13:52:42 -050026 def __init__(self,
27 hostname,
28 username,
29 password,
30 ffdc_config,
31 location,
32 remote_type,
33 remote_protocol):
Peter D Phan72ce6b82021-06-03 06:18:26 -050034 r"""
35 Description of argument(s):
36
37 hostname name/ip of the targeted (remote) system
38 username user on the targeted system with access to FFDC files
39 password password for user on targeted system
40 ffdc_config configuration file listing commands and files for FFDC
Peter D Phan04aca3b2021-06-21 10:37:18 -050041 location where to store collected FFDC
42 remote_type os type of the remote host
Peter D Phan72ce6b82021-06-03 06:18:26 -050043
44 """
45 if self.verify_script_env():
46 self.hostname = hostname
47 self.username = username
48 self.password = password
49 self.ffdc_config = ffdc_config
George Keishing7b3a5132021-07-13 09:24:02 -050050 self.location = location + "/" + remote_type.upper()
Peter D Phan5963d632021-07-12 09:58:55 -050051 self.ssh_remoteclient = None
52 self.telnet_remoteclient = None
Peter D Phan72ce6b82021-06-03 06:18:26 -050053 self.ffdc_dir_path = ""
54 self.ffdc_prefix = ""
Peter D Phan04aca3b2021-06-21 10:37:18 -050055 self.target_type = remote_type.upper()
Peter D Phan0c669772021-06-24 13:52:42 -050056 self.remote_protocol = remote_protocol.upper()
Peter D Phan7610bc42021-07-06 06:31:05 -050057 self.start_time = 0
58 self.elapsed_time = ''
Peter D Phan72ce6b82021-06-03 06:18:26 -050059 else:
Peter D Phan8462faf2021-06-16 12:24:15 -050060 sys.exit(-1)
Peter D Phan72ce6b82021-06-03 06:18:26 -050061
George Keishing86764b52021-07-01 04:32:03 -050062 # Load default or user define YAML configuration file.
63 with open(self.ffdc_config, 'r') as file:
64 self.ffdc_actions = yaml.load(file, Loader=yaml.FullLoader)
65
Peter D Phan3beb02e2021-07-06 13:25:17 -050066 if self.target_type not in self.ffdc_actions.keys():
67 print("\n\tERROR: %s is not listed in %s.\n\n" % (self.target_type, self.ffdc_config))
68 sys.exit(-1)
George Keishing86764b52021-07-01 04:32:03 -050069
Peter D Phan72ce6b82021-06-03 06:18:26 -050070 def verify_script_env(self):
71
72 # Import to log version
73 import click
74 import paramiko
75
76 run_env_ok = True
Peter D Phan0c669772021-06-24 13:52:42 -050077
George Keishingeafba182021-06-29 13:44:58 -050078 redfishtool_version = self.run_redfishtool('-V').split(' ')[2].strip('\n')
79 ipmitool_version = self.run_ipmitool('-V').split(' ')[2]
Peter D Phan0c669772021-06-24 13:52:42 -050080
Peter D Phan72ce6b82021-06-03 06:18:26 -050081 print("\n\t---- Script host environment ----")
82 print("\t{:<10} {:<10}".format('Script hostname', os.uname()[1]))
83 print("\t{:<10} {:<10}".format('Script host os', platform.platform()))
84 print("\t{:<10} {:>10}".format('Python', platform.python_version()))
85 print("\t{:<10} {:>10}".format('PyYAML', yaml.__version__))
86 print("\t{:<10} {:>10}".format('click', click.__version__))
87 print("\t{:<10} {:>10}".format('paramiko', paramiko.__version__))
George Keishingeafba182021-06-29 13:44:58 -050088 print("\t{:<10} {:>9}".format('redfishtool', redfishtool_version))
89 print("\t{:<10} {:>12}".format('ipmitool', ipmitool_version))
Peter D Phan72ce6b82021-06-03 06:18:26 -050090
Peter D Phan8462faf2021-06-16 12:24:15 -050091 if eval(yaml.__version__.replace('.', ',')) < (5, 4, 1):
92 print("\n\tERROR: Python or python packages do not meet minimum version requirement.")
93 print("\tERROR: PyYAML version 5.4.1 or higher is needed.\n")
Peter D Phan72ce6b82021-06-03 06:18:26 -050094 run_env_ok = False
95
96 print("\t---- End script host environment ----")
97 return run_env_ok
98
99 def target_is_pingable(self):
Peter D Phan72ce6b82021-06-03 06:18:26 -0500100 r"""
101 Check if target system is ping-able.
102
103 """
George Keishing0662e942021-07-13 05:12:20 -0500104 response = os.system("ping -c 1 %s 2>&1 >/dev/null" % self.hostname)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500105 if response == 0:
George Keishing615fe322021-06-24 01:24:36 -0500106 print("\n\t[Check] %s is ping-able.\t\t [OK]" % self.hostname)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500107 return True
108 else:
109 print("\n>>>>>\tERROR: %s is not ping-able. FFDC collection aborted.\n" % self.hostname)
110 sys.exit(-1)
111
Peter D Phan72ce6b82021-06-03 06:18:26 -0500112 def collect_ffdc(self):
Peter D Phan72ce6b82021-06-03 06:18:26 -0500113 r"""
114 Initiate FFDC Collection depending on requested protocol.
115
116 """
117
George Keishing772c9772021-06-16 23:23:42 -0500118 print("\n\t---- Start communicating with %s ----" % self.hostname)
Peter D Phan7610bc42021-07-06 06:31:05 -0500119 self.start_time = time.time()
George Keishing772c9772021-06-16 23:23:42 -0500120 working_protocol_list = []
Peter D Phan72ce6b82021-06-03 06:18:26 -0500121 if self.target_is_pingable():
George Keishing772c9772021-06-16 23:23:42 -0500122 # Check supported protocol ping,ssh, redfish are working.
123 if self.ssh_to_target_system():
124 working_protocol_list.append("SSH")
George Keishing615fe322021-06-24 01:24:36 -0500125 working_protocol_list.append("SCP")
Peter D Phan0c669772021-06-24 13:52:42 -0500126
127 # Redfish
128 if self.verify_redfish():
129 working_protocol_list.append("REDFISH")
130 print("\n\t[Check] %s Redfish Service.\t\t [OK]" % self.hostname)
131 else:
Peter D Phan3beb02e2021-07-06 13:25:17 -0500132 print("\n\t[Check] %s Redfish Service.\t\t [NOT AVAILABLE]" % self.hostname)
Peter D Phan0c669772021-06-24 13:52:42 -0500133
Peter D Phan5963d632021-07-12 09:58:55 -0500134 # IPMI
George Keishingeafba182021-06-29 13:44:58 -0500135 if self.verify_ipmi():
136 working_protocol_list.append("IPMI")
137 print("\n\t[Check] %s IPMI LAN Service.\t\t [OK]" % self.hostname)
138 else:
Peter D Phan3beb02e2021-07-06 13:25:17 -0500139 print("\n\t[Check] %s IPMI LAN Service.\t\t [NOT AVAILABLE]" % self.hostname)
George Keishingeafba182021-06-29 13:44:58 -0500140
Peter D Phan5963d632021-07-12 09:58:55 -0500141 # Telnet
142 if self.telnet_to_target_system():
143 working_protocol_list.append("TELNET")
144
Peter D Phan72ce6b82021-06-03 06:18:26 -0500145 # Verify top level directory exists for storage
146 self.validate_local_store(self.location)
George Keishing772c9772021-06-16 23:23:42 -0500147 print("\n\t---- Completed protocol pre-requisite check ----\n")
Peter D Phan0c669772021-06-24 13:52:42 -0500148
149 if ((self.remote_protocol not in working_protocol_list) and (self.remote_protocol != 'ALL')):
150 print("\n\tWorking protocol list: %s" % working_protocol_list)
151 print(
152 '>>>>>\tERROR: Requested protocol %s is not in working protocol list.\n'
153 % self.remote_protocol)
154 sys.exit(-1)
155 else:
156 self.generate_ffdc(working_protocol_list)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500157
158 def ssh_to_target_system(self):
159 r"""
160 Open a ssh connection to targeted system.
161
162 """
163
Peter D Phan5963d632021-07-12 09:58:55 -0500164 self.ssh_remoteclient = SSHRemoteclient(self.hostname,
165 self.username,
166 self.password)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500167
Peter D Phan5963d632021-07-12 09:58:55 -0500168 if self.ssh_remoteclient.ssh_remoteclient_login():
169 print("\n\t[Check] %s SSH connection established.\t [OK]" % self.hostname)
Peter D Phan733df632021-06-17 13:13:36 -0500170
Peter D Phan5963d632021-07-12 09:58:55 -0500171 # Check scp connection.
172 # If scp connection fails,
173 # continue with FFDC generation but skip scp files to local host.
174 self.ssh_remoteclient.scp_connection()
175 return True
176 else:
177 print("\n\t[Check] %s SSH connection.\t [NOT AVAILABLE]" % self.hostname)
178 return False
179
180 def telnet_to_target_system(self):
181 r"""
182 Open a telnet connection to targeted system.
183 """
184 self.telnet_remoteclient = TelnetRemoteclient(self.hostname,
185 self.username,
186 self.password)
187 if self.telnet_remoteclient.tn_remoteclient_login():
188 print("\n\t[Check] %s Telnet connection established.\t [OK]" % self.hostname)
189 return True
190 else:
191 print("\n\t[Check] %s Telnet connection.\t [NOT AVAILABLE]" % self.hostname)
192 return False
Peter D Phan72ce6b82021-06-03 06:18:26 -0500193
George Keishing772c9772021-06-16 23:23:42 -0500194 def generate_ffdc(self, working_protocol_list):
Peter D Phan72ce6b82021-06-03 06:18:26 -0500195 r"""
Peter D Phan04aca3b2021-06-21 10:37:18 -0500196 Determine actions based on remote host type
Peter D Phan72ce6b82021-06-03 06:18:26 -0500197
Peter D Phan04aca3b2021-06-21 10:37:18 -0500198 Description of argument(s):
199 working_protocol_list list of confirmed working protocols to connect to remote host.
Peter D Phan72ce6b82021-06-03 06:18:26 -0500200 """
201
George Keishing772c9772021-06-16 23:23:42 -0500202 print("\n\t---- Executing commands on " + self.hostname + " ----")
203 print("\n\tWorking protocol list: %s" % working_protocol_list)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500204
Peter D Phan2b8052d2021-06-22 10:55:41 -0500205 # Set prefix values for scp files and directory.
206 # Since the time stamp is at second granularity, these values are set here
207 # to be sure that all files for this run will have same timestamps
208 # and they will be saved in the same directory.
209 # self.location == local system for now
210 self.set_ffdc_defaults()
George Keishing86764b52021-07-01 04:32:03 -0500211 ffdc_actions = self.ffdc_actions
Peter D Phan2b8052d2021-06-22 10:55:41 -0500212
Peter D Phan72ce6b82021-06-03 06:18:26 -0500213 for machine_type in ffdc_actions.keys():
George Keishing6ea92b02021-07-01 11:20:50 -0500214 if self.target_type != machine_type:
215 continue
Peter D Phan72ce6b82021-06-03 06:18:26 -0500216
George Keishing6ea92b02021-07-01 11:20:50 -0500217 print("\tSystem Type: %s" % machine_type)
218 for k, v in ffdc_actions[machine_type].items():
Peter D Phan72ce6b82021-06-03 06:18:26 -0500219
George Keishing6ea92b02021-07-01 11:20:50 -0500220 if self.remote_protocol != ffdc_actions[machine_type][k]['PROTOCOL'][0] \
221 and self.remote_protocol != 'ALL':
222 continue
Peter D Phan72ce6b82021-06-03 06:18:26 -0500223
Peter D Phanbabf2962021-07-07 11:24:40 -0500224 if ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'SSH' \
225 or ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'SCP':
226 if 'SSH' in working_protocol_list \
227 or 'SCP' in working_protocol_list:
Peter D Phan3beb02e2021-07-06 13:25:17 -0500228 self.protocol_ssh(ffdc_actions, machine_type, k)
229 else:
Peter D Phanbabf2962021-07-07 11:24:40 -0500230 print("\n\tERROR: SSH or SCP is not available for %s." % self.hostname)
George Keishing6ea92b02021-07-01 11:20:50 -0500231
Peter D Phan5963d632021-07-12 09:58:55 -0500232 if ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'TELNET':
233 if 'TELNET' in working_protocol_list:
234 self.protocol_telnet(ffdc_actions, machine_type, k)
235 else:
236 print("\n\tERROR: TELNET is not available for %s." % self.hostname)
237
George Keishing6ea92b02021-07-01 11:20:50 -0500238 if ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'REDFISH':
Peter D Phan3beb02e2021-07-06 13:25:17 -0500239 if 'REDFISH' in working_protocol_list:
240 self.protocol_redfish(ffdc_actions, machine_type, k)
241 else:
242 print("\n\tERROR: REDFISH is not available for %s." % self.hostname)
George Keishing6ea92b02021-07-01 11:20:50 -0500243
244 if ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'IPMI':
Peter D Phan3beb02e2021-07-06 13:25:17 -0500245 if 'IPMI' in working_protocol_list:
246 self.protocol_ipmi(ffdc_actions, machine_type, k)
247 else:
248 print("\n\tERROR: IMPI is not available for %s." % self.hostname)
George Keishingeafba182021-06-29 13:44:58 -0500249
Peter D Phan04aca3b2021-06-21 10:37:18 -0500250 # Close network connection after collecting all files
Peter D Phan7610bc42021-07-06 06:31:05 -0500251 self.elapsed_time = time.strftime("%H:%M:%S", time.gmtime(time.time() - self.start_time))
Peter D Phan5963d632021-07-12 09:58:55 -0500252 self.ssh_remoteclient.ssh_remoteclient_disconnect()
253 self.telnet_remoteclient.tn_remoteclient_disconnect()
Peter D Phan04aca3b2021-06-21 10:37:18 -0500254
Peter D Phan0c669772021-06-24 13:52:42 -0500255 def protocol_ssh(self,
256 ffdc_actions,
George Keishing6ea92b02021-07-01 11:20:50 -0500257 machine_type,
258 sub_type):
Peter D Phan0c669772021-06-24 13:52:42 -0500259 r"""
260 Perform actions using SSH and SCP protocols.
261
262 Description of argument(s):
263 ffdc_actions List of actions from ffdc_config.yaml.
264 machine_type OS Type of remote host.
George Keishing6ea92b02021-07-01 11:20:50 -0500265 sub_type Group type of commands.
Peter D Phan0c669772021-06-24 13:52:42 -0500266 """
267
George Keishing6ea92b02021-07-01 11:20:50 -0500268 if sub_type == 'DUMP_LOGS':
269 self.group_copy(ffdc_actions[machine_type][sub_type])
270 else:
271 self.collect_and_copy_ffdc(ffdc_actions[machine_type][sub_type])
Peter D Phan0c669772021-06-24 13:52:42 -0500272
Peter D Phan5963d632021-07-12 09:58:55 -0500273 def protocol_telnet(self,
274 ffdc_actions,
275 machine_type,
276 sub_type):
277 r"""
278 Perform actions using telnet protocol.
279 Description of argument(s):
280 ffdc_actions List of actions from ffdc_config.yaml.
281 machine_type OS Type of remote host.
282 """
283 print("\n\t[Run] Executing commands on %s using %s" % (self.hostname, 'TELNET'))
284 telnet_files_saved = []
285 progress_counter = 0
286 list_of_commands = ffdc_actions[machine_type][sub_type]['COMMANDS']
287 for index, each_cmd in enumerate(list_of_commands, start=0):
288 command_txt, command_timeout = self.unpack_command(each_cmd)
289 result = self.telnet_remoteclient.execute_command(command_txt, command_timeout)
290 if result:
291 try:
292 targ_file = ffdc_actions[machine_type][sub_type]['FILES'][index]
293 except IndexError:
294 targ_file = each_cmd
295 print("\n\t[WARN] Missing filename to store data from telnet %s." % each_cmd)
296 print("\t[WARN] Data will be stored in %s." % targ_file)
297 targ_file_with_path = (self.ffdc_dir_path
298 + self.ffdc_prefix
299 + targ_file)
300 # Creates a new file
301 with open(targ_file_with_path, 'wb') as fp:
302 fp.write(result)
303 fp.close
304 telnet_files_saved.append(targ_file)
305 progress_counter += 1
306 self.print_progress(progress_counter)
307 print("\n\t[Run] Commands execution completed.\t\t [OK]")
308 for file in telnet_files_saved:
309 print("\n\t\tSuccessfully save file " + file + ".")
310
Peter D Phan0c669772021-06-24 13:52:42 -0500311 def protocol_redfish(self,
312 ffdc_actions,
George Keishing6ea92b02021-07-01 11:20:50 -0500313 machine_type,
314 sub_type):
Peter D Phan0c669772021-06-24 13:52:42 -0500315 r"""
316 Perform actions using Redfish protocol.
317
318 Description of argument(s):
319 ffdc_actions List of actions from ffdc_config.yaml.
320 machine_type OS Type of remote host.
George Keishing6ea92b02021-07-01 11:20:50 -0500321 sub_type Group type of commands.
Peter D Phan0c669772021-06-24 13:52:42 -0500322 """
323
324 print("\n\t[Run] Executing commands to %s using %s" % (self.hostname, 'REDFISH'))
325 redfish_files_saved = []
326 progress_counter = 0
George Keishing6ea92b02021-07-01 11:20:50 -0500327 list_of_URL = ffdc_actions[machine_type][sub_type]['URL']
Peter D Phan0c669772021-06-24 13:52:42 -0500328 for index, each_url in enumerate(list_of_URL, start=0):
329 redfish_parm = '-u ' + self.username + ' -p ' + self.password + ' -r ' \
330 + self.hostname + ' -S Always raw GET ' + each_url
331
332 result = self.run_redfishtool(redfish_parm)
333 if result:
334 try:
Peter D Phanbabf2962021-07-07 11:24:40 -0500335 targ_file = self.get_file_list(ffdc_actions[machine_type][sub_type])[index]
Peter D Phan0c669772021-06-24 13:52:42 -0500336 except IndexError:
337 targ_file = each_url.split('/')[-1]
338 print("\n\t[WARN] Missing filename to store data from redfish URL %s." % each_url)
339 print("\t[WARN] Data will be stored in %s." % targ_file)
340
341 targ_file_with_path = (self.ffdc_dir_path
342 + self.ffdc_prefix
343 + targ_file)
344
345 # Creates a new file
346 with open(targ_file_with_path, 'w') as fp:
347 fp.write(result)
348 fp.close
349 redfish_files_saved.append(targ_file)
350
351 progress_counter += 1
352 self.print_progress(progress_counter)
353
354 print("\n\t[Run] Commands execution completed.\t\t [OK]")
355
356 for file in redfish_files_saved:
357 print("\n\t\tSuccessfully save file " + file + ".")
358
George Keishingeafba182021-06-29 13:44:58 -0500359 def protocol_ipmi(self,
360 ffdc_actions,
George Keishing6ea92b02021-07-01 11:20:50 -0500361 machine_type,
362 sub_type):
George Keishingeafba182021-06-29 13:44:58 -0500363 r"""
364 Perform actions using ipmitool over LAN protocol.
365
366 Description of argument(s):
367 ffdc_actions List of actions from ffdc_config.yaml.
368 machine_type OS Type of remote host.
George Keishing6ea92b02021-07-01 11:20:50 -0500369 sub_type Group type of commands.
George Keishingeafba182021-06-29 13:44:58 -0500370 """
371
372 print("\n\t[Run] Executing commands to %s using %s" % (self.hostname, 'IPMI'))
373 ipmi_files_saved = []
374 progress_counter = 0
Peter D Phanbabf2962021-07-07 11:24:40 -0500375 list_of_cmd = self.get_command_list(ffdc_actions[machine_type][sub_type])
George Keishingeafba182021-06-29 13:44:58 -0500376 for index, each_cmd in enumerate(list_of_cmd, start=0):
377 ipmi_parm = '-U ' + self.username + ' -P ' + self.password + ' -H ' \
378 + self.hostname + ' ' + each_cmd
379
380 result = self.run_ipmitool(ipmi_parm)
381 if result:
382 try:
Peter D Phanbabf2962021-07-07 11:24:40 -0500383 targ_file = self.get_file_list(ffdc_actions[machine_type][sub_type])[index]
George Keishingeafba182021-06-29 13:44:58 -0500384 except IndexError:
George Keishing6ea92b02021-07-01 11:20:50 -0500385 targ_file = each_cmd.split('/')[-1]
George Keishingeafba182021-06-29 13:44:58 -0500386 print("\n\t[WARN] Missing filename to store data from IPMI %s." % each_cmd)
387 print("\t[WARN] Data will be stored in %s." % targ_file)
388
389 targ_file_with_path = (self.ffdc_dir_path
390 + self.ffdc_prefix
391 + targ_file)
392
393 # Creates a new file
394 with open(targ_file_with_path, 'w') as fp:
395 fp.write(result)
396 fp.close
397 ipmi_files_saved.append(targ_file)
398
399 progress_counter += 1
400 self.print_progress(progress_counter)
401
402 print("\n\t[Run] Commands execution completed.\t\t [OK]")
403
404 for file in ipmi_files_saved:
405 print("\n\t\tSuccessfully save file " + file + ".")
406
Peter D Phan04aca3b2021-06-21 10:37:18 -0500407 def collect_and_copy_ffdc(self,
Peter D Phan2b8052d2021-06-22 10:55:41 -0500408 ffdc_actions_for_machine_type,
409 form_filename=False):
Peter D Phan04aca3b2021-06-21 10:37:18 -0500410 r"""
411 Send commands in ffdc_config file to targeted system.
412
413 Description of argument(s):
414 ffdc_actions_for_machine_type commands and files for the selected remote host type.
Peter D Phan2b8052d2021-06-22 10:55:41 -0500415 form_filename if true, pre-pend self.target_type to filename
Peter D Phan04aca3b2021-06-21 10:37:18 -0500416 """
417
Peter D Phan3beb02e2021-07-06 13:25:17 -0500418 # Executing commands, , if any
419 self.ssh_execute_ffdc_commands(ffdc_actions_for_machine_type,
420 form_filename)
Peter D Phan04aca3b2021-06-21 10:37:18 -0500421
Peter D Phan3beb02e2021-07-06 13:25:17 -0500422 # Copying files
Peter D Phan5963d632021-07-12 09:58:55 -0500423 if self.ssh_remoteclient.scpclient:
Peter D Phan04aca3b2021-06-21 10:37:18 -0500424 print("\n\n\tCopying FFDC files from remote system %s.\n" % self.hostname)
Peter D Phan2b8052d2021-06-22 10:55:41 -0500425
Peter D Phan04aca3b2021-06-21 10:37:18 -0500426 # Retrieving files from target system
Peter D Phanbabf2962021-07-07 11:24:40 -0500427 list_of_files = self.get_file_list(ffdc_actions_for_machine_type)
Peter D Phan2b8052d2021-06-22 10:55:41 -0500428 self.scp_ffdc(self.ffdc_dir_path, self.ffdc_prefix, form_filename, list_of_files)
Peter D Phan04aca3b2021-06-21 10:37:18 -0500429 else:
430 print("\n\n\tSkip copying FFDC files from remote system %s.\n" % self.hostname)
431
Peter D Phanbabf2962021-07-07 11:24:40 -0500432 def get_command_list(self,
433 ffdc_actions_for_machine_type):
434 r"""
435 Fetch list of commands from configuration file
436
437 Description of argument(s):
438 ffdc_actions_for_machine_type commands and files for the selected remote host type.
439 """
440 try:
441 list_of_commands = ffdc_actions_for_machine_type['COMMANDS']
442 except KeyError:
443 list_of_commands = []
444 return list_of_commands
445
446 def get_file_list(self,
447 ffdc_actions_for_machine_type):
448 r"""
449 Fetch list of commands from configuration file
450
451 Description of argument(s):
452 ffdc_actions_for_machine_type commands and files for the selected remote host type.
453 """
454 try:
455 list_of_files = ffdc_actions_for_machine_type['FILES']
456 except KeyError:
457 list_of_files = []
458 return list_of_files
459
Peter D Phan5963d632021-07-12 09:58:55 -0500460 def unpack_command(self,
461 command):
462 r"""
463 Unpack command from config file
464
465 Description of argument(s):
466 command Command from config file.
467 """
468 if isinstance(command, dict):
469 command_txt = next(iter(command))
470 command_timeout = next(iter(command.values()))
471 elif isinstance(command, str):
472 command_txt = command
473 # Default command timeout 60 seconds
474 command_timeout = 60
475
476 return command_txt, command_timeout
477
Peter D Phan3beb02e2021-07-06 13:25:17 -0500478 def ssh_execute_ffdc_commands(self,
479 ffdc_actions_for_machine_type,
480 form_filename=False):
481 r"""
482 Send commands in ffdc_config file to targeted system.
483
484 Description of argument(s):
485 ffdc_actions_for_machine_type commands and files for the selected remote host type.
486 form_filename if true, pre-pend self.target_type to filename
487 """
488 print("\n\t[Run] Executing commands on %s using %s"
489 % (self.hostname, ffdc_actions_for_machine_type['PROTOCOL'][0]))
Peter D Phan3beb02e2021-07-06 13:25:17 -0500490
Peter D Phanbabf2962021-07-07 11:24:40 -0500491 list_of_commands = self.get_command_list(ffdc_actions_for_machine_type)
Peter D Phan3beb02e2021-07-06 13:25:17 -0500492 # If command list is empty, returns
493 if not list_of_commands:
494 return
495
496 progress_counter = 0
497 for command in list_of_commands:
Peter D Phan5963d632021-07-12 09:58:55 -0500498 command_txt, command_timeout = self.unpack_command(command)
Peter D Phan3beb02e2021-07-06 13:25:17 -0500499
500 if form_filename:
501 command_txt = str(command_txt % self.target_type)
502
Peter D Phan5963d632021-07-12 09:58:55 -0500503 err, response = self.ssh_remoteclient.execute_command(command_txt, command_timeout)
Peter D Phanbabf2962021-07-07 11:24:40 -0500504
Peter D Phan3beb02e2021-07-06 13:25:17 -0500505 progress_counter += 1
506 self.print_progress(progress_counter)
507
508 print("\n\t[Run] Commands execution completed.\t\t [OK]")
509
Peter D Phan56429a62021-06-23 08:38:29 -0500510 def group_copy(self,
511 ffdc_actions_for_machine_type):
Peter D Phan56429a62021-06-23 08:38:29 -0500512 r"""
513 scp group of files (wild card) from remote host.
514
515 Description of argument(s):
516 ffdc_actions_for_machine_type commands and files for the selected remote host type.
517 """
Peter D Phan3beb02e2021-07-06 13:25:17 -0500518
Peter D Phan5963d632021-07-12 09:58:55 -0500519 if self.ssh_remoteclient.scpclient:
George Keishing615fe322021-06-24 01:24:36 -0500520 print("\n\tCopying DUMP files from remote system %s.\n" % self.hostname)
Peter D Phan56429a62021-06-23 08:38:29 -0500521
Peter D Phanbabf2962021-07-07 11:24:40 -0500522 list_of_commands = self.get_command_list(ffdc_actions_for_machine_type)
523 # If command list is empty, returns
524 if not list_of_commands:
525 return
Peter D Phan56429a62021-06-23 08:38:29 -0500526
Peter D Phanbabf2962021-07-07 11:24:40 -0500527 for command in list_of_commands:
528 try:
529 filename = command.split(' ')[2]
530 except IndexError:
531 print("\t\tInvalid command %s for DUMP_LOGS block." % command)
532 continue
533
Peter D Phan5963d632021-07-12 09:58:55 -0500534 err, response = self.ssh_remoteclient.execute_command(command)
Peter D Phanbabf2962021-07-07 11:24:40 -0500535
Peter D Phan56429a62021-06-23 08:38:29 -0500536 if response:
Peter D Phan5963d632021-07-12 09:58:55 -0500537 scp_result = self.ssh_remoteclient.scp_file_from_remote(filename, self.ffdc_dir_path)
Peter D Phan56429a62021-06-23 08:38:29 -0500538 if scp_result:
539 print("\t\tSuccessfully copied from " + self.hostname + ':' + filename)
540 else:
Peter D Phanbabf2962021-07-07 11:24:40 -0500541 print("\t\tThere is no " + filename)
Peter D Phan56429a62021-06-23 08:38:29 -0500542
543 else:
544 print("\n\n\tSkip copying files from remote system %s.\n" % self.hostname)
545
Peter D Phan72ce6b82021-06-03 06:18:26 -0500546 def scp_ffdc(self,
547 targ_dir_path,
Peter D Phan2b8052d2021-06-22 10:55:41 -0500548 targ_file_prefix,
549 form_filename,
Peter D Phan72ce6b82021-06-03 06:18:26 -0500550 file_list=None,
551 quiet=None):
Peter D Phan72ce6b82021-06-03 06:18:26 -0500552 r"""
553 SCP all files in file_dict to the indicated directory on the local system.
554
555 Description of argument(s):
556 targ_dir_path The path of the directory to receive the files.
557 targ_file_prefix Prefix which will be pre-pended to each
558 target file's name.
559 file_dict A dictionary of files to scp from targeted system to this system
560
561 """
562
Peter D Phan72ce6b82021-06-03 06:18:26 -0500563 progress_counter = 0
564 for filename in file_list:
Peter D Phan2b8052d2021-06-22 10:55:41 -0500565 if form_filename:
566 filename = str(filename % self.target_type)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500567 source_file_path = filename
568 targ_file_path = targ_dir_path + targ_file_prefix + filename.split('/')[-1]
569
Peter D Phanbabf2962021-07-07 11:24:40 -0500570 # If source file name contains wild card, copy filename as is.
571 if '*' in source_file_path:
Peter D Phan5963d632021-07-12 09:58:55 -0500572 scp_result = self.ssh_remoteclient.scp_file_from_remote(source_file_path, self.ffdc_dir_path)
Peter D Phanbabf2962021-07-07 11:24:40 -0500573 else:
Peter D Phan5963d632021-07-12 09:58:55 -0500574 scp_result = self.ssh_remoteclient.scp_file_from_remote(source_file_path, targ_file_path)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500575
576 if not quiet:
577 if scp_result:
Peter D Phan8462faf2021-06-16 12:24:15 -0500578 print("\t\tSuccessfully copied from " + self.hostname + ':' + source_file_path + ".\n")
Peter D Phan72ce6b82021-06-03 06:18:26 -0500579 else:
580 print("\t\tFail to copy from " + self.hostname + ':' + source_file_path + ".\n")
581 else:
582 progress_counter += 1
583 self.print_progress(progress_counter)
584
Peter D Phan72ce6b82021-06-03 06:18:26 -0500585 def set_ffdc_defaults(self):
Peter D Phan72ce6b82021-06-03 06:18:26 -0500586 r"""
587 Set a default value for self.ffdc_dir_path and self.ffdc_prefix.
588 Collected ffdc file will be stored in dir /self.location/hostname_timestr/.
589 Individual ffdc file will have timestr_filename.
590
591 Description of class variables:
592 self.ffdc_dir_path The dir path where collected ffdc data files should be put.
593
594 self.ffdc_prefix The prefix to be given to each ffdc file name.
595
596 """
597
598 timestr = time.strftime("%Y%m%d-%H%M%S")
599 self.ffdc_dir_path = self.location + "/" + self.hostname + "_" + timestr + "/"
George Keishing7b3a5132021-07-13 09:24:02 -0500600 print("\n\tFFDC Path: %s " % self.ffdc_dir_path)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500601 self.ffdc_prefix = timestr + "_"
602 self.validate_local_store(self.ffdc_dir_path)
603
604 def validate_local_store(self, dir_path):
605 r"""
606 Ensure path exists to store FFDC files locally.
607
608 Description of variable:
609 dir_path The dir path where collected ffdc data files will be stored.
610
611 """
612
613 if not os.path.exists(dir_path):
614 try:
George Keishing7b3a5132021-07-13 09:24:02 -0500615 os.makedirs(dir_path, 0o755)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500616 except (IOError, OSError) as e:
617 # PermissionError
618 if e.errno == EPERM or e.errno == EACCES:
George Keishing7b3a5132021-07-13 09:24:02 -0500619 print('>>>>>\tERROR: os.makedirs %s failed with PermissionError.\n' % dir_path)
Peter D Phan72ce6b82021-06-03 06:18:26 -0500620 else:
George Keishing7b3a5132021-07-13 09:24:02 -0500621 print('>>>>>\tERROR: os.makedirs %s failed with %s.\n' % (dir_path, e.strerror))
Peter D Phan72ce6b82021-06-03 06:18:26 -0500622 sys.exit(-1)
623
624 def print_progress(self, progress):
625 r"""
626 Print activity progress +
627
628 Description of variable:
629 progress Progress counter.
630
631 """
632
633 sys.stdout.write("\r\t" + "+" * progress)
634 sys.stdout.flush()
635 time.sleep(.1)
Peter D Phan0c669772021-06-24 13:52:42 -0500636
637 def verify_redfish(self):
638 r"""
639 Verify remote host has redfish service active
640
641 """
642 redfish_parm = '-u ' + self.username + ' -p ' + self.password + ' -r ' \
643 + self.hostname + ' -S Always raw GET /redfish/v1/'
644 return(self.run_redfishtool(redfish_parm, True))
645
George Keishingeafba182021-06-29 13:44:58 -0500646 def verify_ipmi(self):
647 r"""
648 Verify remote host has IPMI LAN service active
649
650 """
651 ipmi_parm = '-U ' + self.username + ' -P ' + self.password + ' -H ' \
652 + self.hostname + ' power status'
653 return(self.run_ipmitool(ipmi_parm, True))
654
Peter D Phan0c669772021-06-24 13:52:42 -0500655 def run_redfishtool(self,
656 parms_string,
657 quiet=False):
658 r"""
659 Run CLI redfishtool
660
661 Description of variable:
662 parms_string redfishtool subcommand and options.
663 quiet do not print redfishtool error message if True
664 """
665
666 result = subprocess.run(['redfishtool ' + parms_string],
667 stdout=subprocess.PIPE,
668 stderr=subprocess.PIPE,
669 shell=True,
670 universal_newlines=True)
671
672 if result.stderr and not quiet:
673 print('\n\t\tERROR with redfishtool ' + parms_string)
674 print('\t\t' + result.stderr)
675
676 return result.stdout
George Keishingeafba182021-06-29 13:44:58 -0500677
678 def run_ipmitool(self,
679 parms_string,
680 quiet=False):
681 r"""
682 Run CLI IPMI tool.
683
684 Description of variable:
685 parms_string ipmitool subcommand and options.
686 quiet do not print redfishtool error message if True
687 """
688
689 result = subprocess.run(['ipmitool -I lanplus -C 17 ' + parms_string],
690 stdout=subprocess.PIPE,
691 stderr=subprocess.PIPE,
692 shell=True,
693 universal_newlines=True)
694
695 if result.stderr and not quiet:
696 print('\n\t\tERROR with ipmitool -I lanplus -C 17 ' + parms_string)
697 print('\t\t' + result.stderr)
698
699 return result.stdout