From 7006b4b69298b0497e41bd5ab0380fb763f60c2c Mon Sep 17 00:00:00 2001 From: Lin Liu Date: Wed, 3 Apr 2024 10:11:41 +0000 Subject: [PATCH 1/5] CP-48221: Update plugin detect package manager dynamically Given XS9 has deplicated yum with dnf, to be compatible with XS8, - Use dnf if dnf is detected - Fallback to yum otherwise Signed-off-by: Lin Liu --- scripts/extensions/pool_update.apply | 13 ++++++++++--- scripts/extensions/pool_update.precheck | 7 +++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/extensions/pool_update.apply b/scripts/extensions/pool_update.apply index ab8f49478dc..a25b553b8a5 100644 --- a/scripts/extensions/pool_update.apply +++ b/scripts/extensions/pool_update.apply @@ -25,6 +25,9 @@ INVALID_UPDATE = 'INVALID_UPDATE' ERROR_MESSAGE_DOWNLOAD_PACKAGE = 'Error downloading packages:\n' ERROR_MESSAGE_START = 'Error: ' ERROR_MESSAGE_END = 'You could try ' +YUM_CMD = '/usr/bin/yum' +DNF_CMD = '/usr/bin/dnf' +PKG_MGR = DNF_CMD if os.path.exists(DNF_CMD) else YUM_CMD class EnvironmentFailure(Exception): pass @@ -50,7 +53,7 @@ def execute_apply(session, update_package, yum_conf_file): yum_env = os.environ.copy() yum_env['LANG'] = 'C' - cmd = ['yum', 'clean', 'all', '--noplugins', '-c', yum_conf_file] + cmd = [PKG_MGR, 'clean', 'all', '--noplugins', '-c', yum_conf_file] p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, env=yum_env, universal_newlines=True) output, _ = p.communicate() for line in output.split('\n'): @@ -58,8 +61,12 @@ def execute_apply(session, update_package, yum_conf_file): if p.returncode != 0: raise EnvironmentFailure("Error cleaning yum cache") - cmd = ['yum', 'upgrade', '-y', '--noplugins', '-c', yum_conf_file, update_package] - p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, env=yum_env, universal_newlines=True) + # dnf reject to upgrade group if it is not installed, + # `dnf install` upgrade the group if it is already installed + sub_cmd = 'upgrade' if PKG_MGR == YUM_CMD else 'install' + cmd = [PKG_MGR, sub_cmd, '-y', '--noplugins', '-c', yum_conf_file, update_package] + p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + close_fds=True, env=yum_env, universal_newlines=True) output, _ = p.communicate() xcp.logger.info('pool_update.apply %r returncode=%r output:', cmd, p.returncode) for line in output.split('\n'): diff --git a/scripts/extensions/pool_update.precheck b/scripts/extensions/pool_update.precheck index 161fad13740..7ef784cb773 100755 --- a/scripts/extensions/pool_update.precheck +++ b/scripts/extensions/pool_update.precheck @@ -48,6 +48,9 @@ ERRORCODE = 'errorcode' ERROR = 'error' FOUND = 'found' REQUIRED = 'required' +YUM_CMD = '/usr/bin/yum' +DNF_CMD = '/usr/bin/dnf' +PKG_MGR = DNF_CMD if os.path.exists(DNF_CMD) else YUM_CMD class EnvironmentFailure(Exception): pass @@ -130,7 +133,7 @@ def execute_precheck(session, control_package, yum_conf_file, update_precheck_fi yum_env = os.environ.copy() yum_env['LANG'] = 'C' - cmd = ['yum', 'clean', 'all', '--noplugins', '-c', yum_conf_file] + cmd = [PKG_MGR, 'clean', 'all', '--noplugins', '-c', yum_conf_file] p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, env=yum_env, universal_newlines=True) output, _ = p.communicate() for line in output.split('\n'): @@ -138,7 +141,7 @@ def execute_precheck(session, control_package, yum_conf_file, update_precheck_fi if p.returncode != 0: raise EnvironmentFailure("Error cleaning yum cache") - cmd = ['yum', 'install', '-y', '--noplugins', '-c', yum_conf_file, control_package] + cmd = [PKG_MGR, 'install', '-y', '--noplugins', '-c', yum_conf_file, control_package] p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, env=yum_env, universal_newlines=True) output, _ = p.communicate() xcp.logger.info('pool_update.precheck %r returncode=%r output:', cmd, p.returncode) From c94a562ade446ddea169d67c805f29fabad70259 Mon Sep 17 00:00:00 2001 From: Lin Liu Date: Sun, 7 Apr 2024 03:54:51 +0000 Subject: [PATCH 2/5] CP-48221: Make CI happy with various scans Signed-off-by: Lin Liu --- scripts/extensions/pool_update.apply | 33 ++++--- scripts/extensions/pool_update.precheck | 122 ++++++++++++++---------- 2 files changed, 94 insertions(+), 61 deletions(-) diff --git a/scripts/extensions/pool_update.apply b/scripts/extensions/pool_update.apply index a25b553b8a5..c860d965169 100644 --- a/scripts/extensions/pool_update.apply +++ b/scripts/extensions/pool_update.apply @@ -30,31 +30,38 @@ DNF_CMD = '/usr/bin/dnf' PKG_MGR = DNF_CMD if os.path.exists(DNF_CMD) else YUM_CMD class EnvironmentFailure(Exception): - pass + """Failure due to running environment""" class ApplyFailure(Exception): - pass + """Failed to apply update""" class InvalidUpdate(Exception): - pass + """Update is invalid""" def success_message(): + """success message to return""" rpcparams = {'Status': 'Success', 'Value': ''} return xmlrpc.client.dumps((rpcparams, ), '', True) -def failure_message(code, params): +def failure_message(code, args): + """failure message to return""" rpcparams = { - 'Status': 'Failure', 'ErrorDescription': [code] + params} + 'Status': 'Failure', 'ErrorDescription': [code] + args} return xmlrpc.client.dumps((rpcparams, ), '', True) -def execute_apply(session, update_package, yum_conf_file): +#pylint: disable=redefined-outer-name +def execute_apply(update_package, yum_conf_file): + """apply update""" yum_env = os.environ.copy() yum_env['LANG'] = 'C' cmd = [PKG_MGR, 'clean', 'all', '--noplugins', '-c', yum_conf_file] - p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, env=yum_env, universal_newlines=True) + # pylint: disable=consider-using-with + p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, close_fds=True, + env=yum_env, universal_newlines=True) output, _ = p.communicate() for line in output.split('\n'): xcp.logger.info(line) @@ -80,8 +87,7 @@ def execute_apply(session, update_package, yum_conf_file): errmsg = m.group() errmsg = re.sub(ERROR_MESSAGE_END + '.+', '', errmsg, flags=re.DOTALL) raise ApplyFailure(errmsg) - else: - raise ApplyFailure(output) + raise ApplyFailure(output) if __name__ == '__main__': @@ -89,6 +95,8 @@ if __name__ == '__main__': txt = sys.stdin.read() params, method = xmlrpc.client.loads(txt) + #pylint: disable=invalid-name + #pylint: disable=broad-exception-caught session = None lock_acquired = False try: @@ -120,9 +128,12 @@ if __name__ == '__main__': try: session.xenapi.pool_update.precheck(update, host) except Exception as e: + # Here catch broader exception, and try to explain it as sub concrete Exception. + # If failed, fallback to unknown exception + #pylint: disable=no-member try: print(failure_message(e.details[0], e.details[1:])) - except: + except Exception: print(failure_message(UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR, [str(e)])) sys.exit(0) @@ -146,7 +157,7 @@ if __name__ == '__main__': with open (yum_conf_file, "w+") as file: file.write("{0}".format(yum_conf)) - execute_apply(session, '@update', yum_conf_file) + execute_apply('@update', yum_conf_file) session.xenapi.pool_update.resync_host(host) print(success_message()) diff --git a/scripts/extensions/pool_update.precheck b/scripts/extensions/pool_update.precheck index 7ef784cb773..dfc79bfbf4a 100755 --- a/scripts/extensions/pool_update.precheck +++ b/scripts/extensions/pool_update.precheck @@ -52,6 +52,11 @@ YUM_CMD = '/usr/bin/yum' DNF_CMD = '/usr/bin/dnf' PKG_MGR = DNF_CMD if os.path.exists(DNF_CMD) else YUM_CMD +#pylint: disable=missing-class-docstring +#pylint: disable=redefined-outer-name +#pylint: disable=missing-function-docstring +#pylint: disable=consider-using-f-string + class EnvironmentFailure(Exception): pass @@ -83,25 +88,29 @@ class VmRunning(Exception): pass def success_message(result): + """success message to return""" rpcparams = {'Status': 'Success', 'Value': result} return xmlrpc.client.dumps((rpcparams, ), '', True) def failure_message(code, params): + """failure message to return""" rpcparams = { 'Status': 'Failure', 'ErrorDescription': [code] + params} return xmlrpc.client.dumps((rpcparams, ), '', True) -def parse_control_package(session, yum_url): +def parse_control_package(yum_url): + """ parse control package from update.xml""" if not yum_url.startswith('http://'): raise PrecheckFailure('Incorrect yum repo: %s' % yum_url) update_xml_url = yum_url + '/update.xml' try: + #pylint: disable=consider-using-with update_xml = urllib.request.urlopen(update_xml_url).read() - except: - raise PrecheckFailure("Couldn't fetch update.xml from '%s'" % update_xml_url) + except Exception as e: + raise PrecheckFailure("Couldn't fetch update.xml from '%s'" % update_xml_url) from e xmldoc = xml.dom.minidom.parse(io.StringIO(update_xml.decode('utf-8'))) items = xmldoc.getElementsByTagName('update') @@ -121,10 +130,12 @@ def parse_precheck_failure(xmldoc): if code in errors: params = [xmldoc.getElementsByTagName(a)[0].firstChild.nodeValue for a in errors[code]] raise PrecheckError(code, *params) - else: - raise PrecheckFailure(xmldoc.toxml()) + raise PrecheckFailure(xmldoc.toxml()) -def execute_precheck(session, control_package, yum_conf_file, update_precheck_file): +def execute_precheck(control_package, yum_conf_file, update_precheck_file): + #pylint: disable=too-many-locals + #pylint: disable=too-many-branches + #pylint: disable=too-many-statements if not control_package: return 'ok' livepatch_messages = {'PATCH_PRECHECK_LIVEPATCH_COMPLETE': 'ok_livepatch_complete', @@ -134,7 +145,9 @@ def execute_precheck(session, control_package, yum_conf_file, update_precheck_fi yum_env['LANG'] = 'C' cmd = [PKG_MGR, 'clean', 'all', '--noplugins', '-c', yum_conf_file] - p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, env=yum_env, universal_newlines=True) + #pylint: disable=consider-using-with + p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + close_fds=True, env=yum_env, universal_newlines=True) output, _ = p.communicate() for line in output.split('\n'): xcp.logger.info(line) @@ -142,7 +155,8 @@ def execute_precheck(session, control_package, yum_conf_file, update_precheck_fi raise EnvironmentFailure("Error cleaning yum cache") cmd = [PKG_MGR, 'install', '-y', '--noplugins', '-c', yum_conf_file, control_package] - p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, env=yum_env, universal_newlines=True) + p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + close_fds=True, env=yum_env, universal_newlines=True) output, _ = p.communicate() xcp.logger.info('pool_update.precheck %r returncode=%r output:', cmd, p.returncode) for line in output.split('\n'): @@ -164,26 +178,28 @@ def execute_precheck(session, control_package, yum_conf_file, update_precheck_fi if m: errmsg = m.group() errmsg = re.sub(ERROR_MESSAGE_END + '.+', '', errmsg, flags=re.DOTALL) - if ERROR_MESSAGE_CONFLICTS_WITH in errmsg and ERROR_MESSAGE_PROCESSING_CONFLICT in output: - regex = ERROR_MESSAGE_PROCESSING_CONFLICT + '(.*)' + ERROR_MESSAGE_CONFLICTS + '(.+?)\n' + if (ERROR_MESSAGE_CONFLICTS_WITH in errmsg and + ERROR_MESSAGE_PROCESSING_CONFLICT in output): + regex = (ERROR_MESSAGE_PROCESSING_CONFLICT + '(.*)' + + ERROR_MESSAGE_CONFLICTS + '(.+?)\n') conflict_tuples = re.findall(regex, output) if len(conflict_tuples) > 0: conflict_updates = '' - for tuple in conflict_tuples: - conflict_updates += tuple[1] + ' ' + for tup in conflict_tuples: + conflict_updates += tup[1] + ' ' raise ConflictPresent(conflict_updates.rstrip()) - else: - raise PrecheckFailure(errmsg) - elif ERROR_MESSAGE_VERSION_REQUIRED in errmsg and (ERROR_MESSAGE_VERSION_INSTALLED in errmsg or ERROR_MESSAGE_VERSION_UPDATED_BY in errmsg): + raise PrecheckFailure(errmsg) + if (ERROR_MESSAGE_VERSION_REQUIRED in errmsg and + (ERROR_MESSAGE_VERSION_INSTALLED in errmsg + or ERROR_MESSAGE_VERSION_UPDATED_BY in errmsg)): regex = ERROR_MESSAGE_VERSION_REQUIRED + '(.+?)\n.+ {2,2}(.+)$' match = re.search(regex, errmsg, flags=re.DOTALL) if match: required_version = match.group(1).rstrip() installed_version = match.group(2).rstrip() raise WrongServerVersion(required_version, installed_version) - else: - raise PrecheckFailure(errmsg) - elif ERROR_MESSAGE_PREREQUISITE in errmsg: + raise PrecheckFailure(errmsg) + if ERROR_MESSAGE_PREREQUISITE in errmsg: regex = ERROR_MESSAGE_PREREQUISITE + '(.+?)\n' prerequisite_list = re.findall(regex, errmsg) if len(prerequisite_list) > 0: @@ -191,23 +207,22 @@ def execute_precheck(session, control_package, yum_conf_file, update_precheck_fi for prerequisite in prerequisite_list: prerequisite_updates += prerequisite + ' ' raise PrerequisiteMissing(prerequisite_updates.rstrip()) - else: - raise PrecheckFailure(errmsg) - else: raise PrecheckFailure(errmsg) - else: - regex = ERROR_XML_START + '.+' + ERROR_XML_END - m = re.search(regex, output, flags=re.DOTALL) - if m: - try: - xmldoc = xml.dom.minidom.parseString(m.group(0)) - except: - raise PrecheckFailure(output) - parse_precheck_failure(xmldoc) - raise PrecheckFailure(output) + raise PrecheckFailure(errmsg) + + regex = ERROR_XML_START + '.+' + ERROR_XML_END + m = re.search(regex, output, flags=re.DOTALL) + if m: + try: + xmldoc = xml.dom.minidom.parseString(m.group(0)) + except Exception as e: + raise PrecheckFailure(output) from e + parse_precheck_failure(xmldoc) + raise PrecheckFailure(output) if os.path.isfile(update_precheck_file): - pp = subprocess.Popen(update_precheck_file, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, universal_newlines=True) + pp = subprocess.Popen(update_precheck_file, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, close_fds=True, universal_newlines=True) precheck_output, _ = pp.communicate() xcp.logger.info('pool_update.precheck %r precheck_output:', update_precheck_file) for line in precheck_output.split('\n'): @@ -218,15 +233,14 @@ def execute_precheck(session, control_package, yum_conf_file, update_precheck_fi if m: try: xmldoc = xml.dom.minidom.parseString(m.group(0)) - except: - raise PrecheckFailure(precheck_output) + except Exception as e: + raise PrecheckFailure(precheck_output) from e parse_precheck_failure(xmldoc) raise PrecheckFailure(precheck_output) - else: - if '\n' in precheck_output: - msg = precheck_output.split()[0] - if msg in list(livepatch_messages.keys()): - return livepatch_messages[msg] + if '\n' in precheck_output: + msg = precheck_output.split()[0] + if msg in list(livepatch_messages): + return livepatch_messages[msg] return 'ok' @@ -235,8 +249,11 @@ if __name__ == '__main__': txt = sys.stdin.read() params, method = xmlrpc.client.loads(txt) + #pylint: disable=invalid-name update_vdi_valid = False session = None + update_package = None + update = None try: session = XenAPI.xapi_local() session.xenapi.login_with_password('root', '', '', 'Pool_update') @@ -252,7 +269,7 @@ if __name__ == '__main__': try: update_vdi_uuid = session.xenapi.VDI.get_uuid(update_vdi) update_vdi_valid = True - except Exception as e: + except Exception as e: #pylint: disable=broad-exception-caught print(failure_message(CANNOT_FIND_UPDATE, [])) sys.exit(0) @@ -265,7 +282,7 @@ if __name__ == '__main__': print(failure_message(UPDATE_PRECHECK_FAILED_OUT_OF_SPACE, [update_package, str(available_dom0_disk_size), str(required_size)])) sys.exit(0) - except: + except Exception: #pylint: disable=broad-exception-caught print(failure_message(INVALID_UPDATE, ["Issue with in update.xml"])) sys.exit(0) @@ -280,25 +297,30 @@ if __name__ == '__main__': pass else: raise - with open(yum_conf_file, "w+") as file: + with open(yum_conf_file, "w+", encoding="utf-8") as file: file.write(yum_conf) config = configparser.ConfigParser() config.read(yum_conf_file) yum_url = config.get(update_package, 'baseurl') - control_package = parse_control_package(session, yum_url) + control_package = parse_control_package(yum_url) update_precheck_file = os.path.join(UPDATE_DIR, update_uuid, 'precheck') - print(success_message(execute_precheck(session, control_package, yum_conf_file, update_precheck_file))) + print(success_message(execute_precheck(control_package, + yum_conf_file, update_precheck_file))) except PrecheckError as e: - print(failure_message(e.args[0], [update_package] + [a for a in e.args[1:]])) + print(failure_message(e.args[0], [update_package] + list(e.args[1:]))) except PrerequisiteMissing as e: - print(failure_message(UPDATE_PRECHECK_FAILED_PREREQUISITE_MISSING, [update_package, str(e)])) + print(failure_message(UPDATE_PRECHECK_FAILED_PREREQUISITE_MISSING, + [update_package, str(e)])) except ConflictPresent as e: - print(failure_message(UPDATE_PRECHECK_FAILED_CONFLICT_PRESENT, [update_package, str(e)])) + print(failure_message(UPDATE_PRECHECK_FAILED_CONFLICT_PRESENT, + [update_package, str(e)])) except WrongServerVersion as e: + #pylint: disable=unbalanced-tuple-unpacking required_version, installed_version = e.args - print(failure_message(UPDATE_PRECHECK_FAILED_WRONG_SERVER_VERSION, [update_package, installed_version, required_version])) + print(failure_message(UPDATE_PRECHECK_FAILED_WRONG_SERVER_VERSION, + [update_package, installed_version, required_version])) except InvalidUpdate as e: print(failure_message(INVALID_UPDATE, [update_package, str(e)])) except GpgkeyNotImported as e: @@ -307,7 +329,7 @@ if __name__ == '__main__': print(failure_message(PATCH_PRECHECK_FAILED_ISO_MOUNTED, [update])) except VmRunning as e: print(failure_message(PATCH_PRECHECK_FAILED_VM_RUNNING, [update])) - except Exception as e: + except Exception as e: #pylint: disable=broad-exception-caught print(failure_message(UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR, [update_package, str(e)])) finally: if session is not None and update_vdi_valid is True: @@ -315,5 +337,5 @@ if __name__ == '__main__': session.xenapi.session.logout() try: shutil.rmtree(os.path.dirname(yum_conf_file)) - except Exception as e: + except Exception as e: #pylint: disable=broad-exception-caught pass From 085dc27d63b3be818c84582c1f0282caa0e9ca36 Mon Sep 17 00:00:00 2001 From: liulinC Date: Wed, 17 Apr 2024 17:42:32 +0800 Subject: [PATCH 3/5] Update scripts/extensions/pool_update.precheck Co-authored-by: Luca Zhang Signed-off-by: liulinC --- scripts/extensions/pool_update.precheck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/extensions/pool_update.precheck b/scripts/extensions/pool_update.precheck index dfc79bfbf4a..8e806f82d1d 100755 --- a/scripts/extensions/pool_update.precheck +++ b/scripts/extensions/pool_update.precheck @@ -239,7 +239,7 @@ def execute_precheck(control_package, yum_conf_file, update_precheck_file): raise PrecheckFailure(precheck_output) if '\n' in precheck_output: msg = precheck_output.split()[0] - if msg in list(livepatch_messages): + if msg in livepatch_messages: return livepatch_messages[msg] return 'ok' From b66da74eb65c9e517198271d3e4450e4aa744b4f Mon Sep 17 00:00:00 2001 From: liulinC Date: Wed, 17 Apr 2024 17:45:04 +0800 Subject: [PATCH 4/5] Update scripts/extensions/pool_update.precheck Co-authored-by: Luca Zhang Signed-off-by: liulinC --- scripts/extensions/pool_update.precheck | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/extensions/pool_update.precheck b/scripts/extensions/pool_update.precheck index 8e806f82d1d..184cf2df829 100755 --- a/scripts/extensions/pool_update.precheck +++ b/scripts/extensions/pool_update.precheck @@ -202,11 +202,8 @@ def execute_precheck(control_package, yum_conf_file, update_precheck_file): if ERROR_MESSAGE_PREREQUISITE in errmsg: regex = ERROR_MESSAGE_PREREQUISITE + '(.+?)\n' prerequisite_list = re.findall(regex, errmsg) - if len(prerequisite_list) > 0: - prerequisite_updates = '' - for prerequisite in prerequisite_list: - prerequisite_updates += prerequisite + ' ' - raise PrerequisiteMissing(prerequisite_updates.rstrip()) + if prerequisite_list: + raise PrerequisiteMissing(' '.join(prerequisite_list)) raise PrecheckFailure(errmsg) raise PrecheckFailure(errmsg) From ca9a01daa38cc152d9b21336be2f58fb08bcc09a Mon Sep 17 00:00:00 2001 From: Lin Liu Date: Wed, 17 Apr 2024 09:52:49 +0000 Subject: [PATCH 5/5] Update scripts/extensions/pool_update.precheck Signed-off-by: Lin Liu --- scripts/extensions/pool_update.precheck | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/extensions/pool_update.precheck b/scripts/extensions/pool_update.precheck index 184cf2df829..57c6596f280 100755 --- a/scripts/extensions/pool_update.precheck +++ b/scripts/extensions/pool_update.precheck @@ -183,11 +183,8 @@ def execute_precheck(control_package, yum_conf_file, update_precheck_file): regex = (ERROR_MESSAGE_PROCESSING_CONFLICT + '(.*)' + ERROR_MESSAGE_CONFLICTS + '(.+?)\n') conflict_tuples = re.findall(regex, output) - if len(conflict_tuples) > 0: - conflict_updates = '' - for tup in conflict_tuples: - conflict_updates += tup[1] + ' ' - raise ConflictPresent(conflict_updates.rstrip()) + if conflict_tuples: + raise ConflictPresent(' '.join([tup[1] for tup in conflict_tuples])) raise PrecheckFailure(errmsg) if (ERROR_MESSAGE_VERSION_REQUIRED in errmsg and (ERROR_MESSAGE_VERSION_INSTALLED in errmsg