galaxyproject / galaxy

Data intensive science for everyone.
https://galaxyproject.org
Other
1.41k stars 1.01k forks source link

Install of tool with "too new" profile silently fails #12377

Open pvanheus opened 3 years ago

pvanheus commented 3 years ago

Describe the bug Attempting to install a tool that has a profile greater than than that supported by the Galaxy server leads to a failed installation with no message to the admin

Galaxy Version and/or server at which you observed the bug Galaxy 20.09 (Docker version)

To Reproduce Steps to reproduce the behavior:

  1. Go to admin/toolshed (Admin -> Install and Uninstall)
  2. Select a tool to install - choose one (e.g. tbprofiler 3.0.6) which has a recent (in this case 21.01) profile
  3. Click Install. The tool goes through "Cloning" and then "Installed" stages but (a) shed_tool_conf.xml is never updated and (b) dependencies are not installed.
  4. This error shows up in the logs:
    galaxy.tool_shed.tools.tool_validator ERROR 2021-08-25 11:07:36,366 [p:617,w:1,m:0] [uWSGIWorker1Core2] Caught exception loading tool from /galaxy-central/database/shed_tools/toolshed.g2.bx.psu.edu/repos/iuc/tbprofiler/ba6f87115e13/tbprofiler/tb_profiler_profile.xml:
    Traceback (most recent call last):
    File "lib/galaxy/tool_shed/tools/tool_validator.py", line 80, in load_tool_from_config
    tool = create_tool_from_source(config_file=full_path, app=self.app, tool_source=tool_source, repository_id=repository_id, allow_code_files=False)
    File "lib/galaxy/tools/__init__.py", line 239, in create_tool_from_source
    tool = ToolClass(config_file, tool_source, app, **kwds)
    File "lib/galaxy/tools/__init__.py", line 545, in __init__
    raise e
    File "lib/galaxy/tools/__init__.py", line 542, in __init__
    self.parse(tool_source, guid=guid, dynamic=dynamic)
    File "lib/galaxy/tools/__init__.py", line 772, in parse
    raise Exception(message)
    Exception: The tool tb_profiler_profile targets version 21.01 of Galaxy, you should upgrade Galaxy to ensure proper functioning of this tool.

Expected behavior The user should be informed about the failed install. Optionally, the user should be allowed to force an install, if they judge that the features required by the tool are adequately provided by their Galaxy version.

pvanheus commented 3 years ago

I think the problem is that tool installation expects an exception when a tool install fails (see https://github.com/galaxyproject/galaxy/blob/dev/lib/galaxy/tool_shed/galaxy_install/install_manager.py#L849) but the when the validation error is triggered from https://github.com/galaxyproject/galaxy/blob/dev/lib/galaxy/tool_shed/tools/tool_validator.py#L73 (load_tool_from_config()) it is handled, resulting in a situation where there is no valid tool install the tool is still marked as installed (here: https://github.com/galaxyproject/galaxy/blob/dev/lib/galaxy/tool_shed/galaxy_install/install_manager.py#L961).

pvanheus commented 3 years ago

Here is a potential patch - I don't really like this though as it does not really raise the error message appropriately in the web UI:

diff --git a/lib/galaxy/tool_shed/galaxy_install/install_manager.py b/lib/galaxy/tool_shed/galaxy_install/install_manager.py
index 73bf0067af..90e60658f1 100644
--- a/lib/galaxy/tool_shed/galaxy_install/install_manager.py
+++ b/lib/galaxy/tool_shed/galaxy_install/install_manager.py
@@ -516,6 +516,8 @@ class InstallRepositoryManager:
         irmm.generate_metadata_for_changeset_revision()
         irmm_metadata_dict = irmm.get_metadata_dict()
         tool_shed_repository.metadata = irmm_metadata_dict
+        if 'invalid_tools' in irmm_metadata_dict:
+            tool_shed_repository.invalid_tups = irmm.get_invalid_file_tups()
         # Update the tool_shed_repository.tool_shed_status column in the database.
         tool_shed_status_dict = repository_util.get_tool_shed_status_for_installed_repository(self.app, tool_shed_repository)
         if tool_shed_status_dict:
@@ -935,6 +937,15 @@ class InstallRepositoryManager:
                                           reinstalling=reinstalling,
                                           tool_panel_section_mapping=tool_panel_section_mapping)
         metadata = tool_shed_repository.metadata
+        if 'invalid_tools' in metadata:
+            self.update_tool_shed_repository_status(tool_shed_repository,
+                                                    self.install_model.ToolShedRepository.installation_status.ERROR)
+            if len(tool_shed_repository.invalid_tups) == 1:
+                # just one failed tool to worry about, extract install error message and use that
+                error_message = tool_shed_repository.invalid_tups[0][1]
+            else:
+                error_message = ', '.join([': '.join(invalid_tuple) for invalid_tuple in tool_shed_repository.invalid_tups])
+            raise RuntimeError(error_message)
         if 'tools' in metadata and install_resolver_dependencies:
             self.update_tool_shed_repository_status(tool_shed_repository,
                                                     self.install_model.ToolShedRepository.installation_status.INSTALLING_TOOL_DEPENDENCIES)