[Fuego] UnicodeEncodeError fix (was RE: selftest instructions)
"Bird, Tim" <[email protected]>
| Newsgroups | dev.linux.lists.fuego |
|---|---|
| Message-ID | <CY4PR13MB11757D2222CF50706EBE0D59FD7F0@CY4PR13MB1175.namprd13.prod.outlook.com> |
> -----Original Message----- > From: Laszlo Sitzer > > Hello! > > I am working on updating the Fuego docker image and want to make sure I don't break anything. I notice in Fuego v1.3 a self-test was > introduced. > > I wanted to check if the following sequence is sufficient to test Fuego works correctly: > > >>> > ftc add-nodes -b docker > ftc add-jobs -b docker -t Functional.fuego_release_test > ftc run-test -b docker -t Functional.fuego_release_test > >>> I know that the UnicodeEncodeError exception that was raised during 'ftc add-nodes -b docker' was not the real error here. That was an error that was covering up the real error from Jenkins (which is now fixed with a hardcoded plugin version in the Dockerfile). However, I have made a patch to work around the UnicodeEncodeError. It required a bit more work than I expected, and uncovered some controversial decisions by the python community in the Python 2.X lifecycle. In any event, I'm inlining the patch below, which is now already committed to the Fuego master branch. In my testing here, it avoids masking errors from Jenkins. If someone sees some problem with this, let me know. Thanks very much to Laszlo Sitzer for bringing this to my attention. -- Tim patch follows: ----------------- From 600c12ffc55137aa31da709cfe3ed95d8853e76c Mon Sep 17 00:00:00 2001 From: Tim Bird <[email protected]> Date: Thu, 16 Jul 2020 13:23:28 -0600 Subject: [PATCH] ftc: handle UnicodeEncodeError from jenkins exceptions A cascade exception ('UnicodeEncodeError') was preventing user visibility on errors from the Jenkins server. Change the error handling so that if we get a UnicodeEncodeError when trying to convert an exception into a string, we change the default encoding for python string conversions from 'ascii' to 'utf8'. A description of the issues is in the comment in the code. If feels like a hack, but it gets the job done! Thanks to Laszlo Sitzer for the bug report. Signed-off-by: Tim Bird <[email protected]> --- scripts/ftc | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/scripts/ftc b/scripts/ftc index 1b8ec02..c5e11ba 100755 --- a/scripts/ftc +++ b/scripts/ftc @@ -5278,6 +5278,42 @@ def do_power_control(conf, options, command): error_out("BOARD_CONTROL value %s is not supported" % board_control) sys.exit(0) +# this takes an exception object (e), and formats it as a string +# safely (handling UnicodeEncode errors), then shows usage help, and +# exits the program with an error message. +# +# Background: +# python 2.7 uses default encoding of 'ascii'. If e is an exception from +# the jenkins module, then using str(e) will cause the module to use str() +# on the error message from the jenkins server. If that message has non-ascii +# chars (which is not uncommon), then python raises a UnicodeEncodeError +# exception. I don't want to change the code for the jenkins +# module, and I have no other way of retrieving the string, which I'd like +# to print. +# So, do this hack where we reload sys and change the defaultencoding from +# 'ascii' to 'utf8'. The function setdefaultencoding() exists in the +# sys module, but is deleted when it is imported (but not on 'reload'). +# I could have modified /usr/lib/python2.7/site.py inside the container +# to remove the code that deletes the function. This would have avoided +# the need to do the 'reload(sys)'. +# But I decided to limit the scope of this change. +# Sheesh - what a mess! +def safe_str_help_and_exit(e, ftc_cmd): + try: + err_msg = str(e) + prefix = "" + except UnicodeEncodeError: + if sys.version_info[0] < 3: + # this reload is hacky and can have bad side effects, but we're on + # our way out of the program, so we don't care + reload(sys) + sys.setdefaultencoding('utf8') + + err_msg = str(e) + prefix = "ERROR: Operation '%s' raised exception with string:\n" % ftc_cmd + msg = prefix + err_msg + '\n---\n' + command_help[ftc_cmd][1] + sys.exit(msg) + def main(): # use global module names global re, time, copy2, subprocess, signal, fcntl, requests, json @@ -5534,7 +5570,7 @@ def main(): do_add_jobs(conf, options) except Exception as e: # this assumes the problem is something with the options - sys.exit(str(e) + '\n' + command_help['add-jobs'][1]) + safe_str_help_and_exit(e, 'add-jobs') if command.startswith("rm-job"): # removes Jenkins jobs @@ -5542,7 +5578,7 @@ def main(): try: do_rm_jobs(conf, options) except Exception as e: - sys.exit(str(e) + '\n' + command_help['rm-jobs'][1]) + safe_str_help_and_exit(e, 'rm-jobs') if command.startswith("add-node"): # adds Jenkins nodes @@ -5550,7 +5586,7 @@ def main(): try: do_add_nodes(conf, options) except Exception as e: - sys.exit(str(e) + '\n' + command_help['add-nodes'][1]) + safe_str_help_and_exit(e, 'add-nodes') if command.startswith("rm-node"): # removes Jenkins nodes @@ -5558,7 +5594,7 @@ def main(): try: do_rm_nodes(conf, options) except Exception as e: - sys.exit(str(e) + '\n' + command_help['rm-nodes'][1]) + safe_str_help_and_exit(e, 'rm-nodes') if command == "list-nodes": # shows jenkins nodes -- 2.1.4