From e7f35711ce276de7a0cecb7eb7aea66ebb86aa90 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 19 Mar 2024 11:42:54 -0400 Subject: [PATCH] Improved error messages for private object stores. --- .../Content/Dataset/DatasetDetails.vue | 5 +- .../Content/Dataset/DatasetMiscInfo.vue | 64 +++++++++++++++++++ lib/galaxy/jobs/runners/__init__.py | 5 +- lib/galaxy/objectstore/__init__.py | 20 +++++- 4 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 client/src/components/History/Content/Dataset/DatasetMiscInfo.vue diff --git a/client/src/components/History/Content/Dataset/DatasetDetails.vue b/client/src/components/History/Content/Dataset/DatasetDetails.vue index 23c1138714f5..5cf6b2880e1d 100644 --- a/client/src/components/History/Content/Dataset/DatasetDetails.vue +++ b/client/src/components/History/Content/Dataset/DatasetDetails.vue @@ -8,6 +8,7 @@ import { useDatasetStore } from "@/stores/datasetStore"; import { type ItemUrls } from "."; import DatasetActions from "./DatasetActions.vue"; +import DatasetMiscInfo from "./DatasetMiscInfo.vue"; const datasetStore = useDatasetStore(); @@ -56,9 +57,7 @@ function toggleHighlights() { result.genome_build }} -
- {{ result.misc_info }} -
+ +import { computed, ref, watch } from "vue"; + +interface Props { + miscInfo: string; +} + +const showErrorHelp = ref(false); +const sharingError = ref(false); + +// old sharable error: Attempted to create shared output datasets in objectstore with sharing disabled +// new sharable error: Job attempted to create sharable output datasets in a storage location with sharing disabled +const sharingErrorRex: RegExp = /with sharing disabled/g; +const knownErrors = [{ regex: sharingErrorRex, modalRef: sharingError }]; + +const props = defineProps(); + +const fixable = computed(() => { + return true; +}); + +watch( + props, + () => { + for (const knownError of knownErrors) { + const regex = knownError.regex; + if (props.miscInfo.match(regex)) { + knownError.modalRef.value = true; + } + } + }, + { immediate: true } +); + +function showHelp() { + showErrorHelp.value = true; +} + + + diff --git a/lib/galaxy/jobs/runners/__init__.py b/lib/galaxy/jobs/runners/__init__.py index 27d122eb2b4a..e87d7c1b0091 100644 --- a/lib/galaxy/jobs/runners/__init__.py +++ b/lib/galaxy/jobs/runners/__init__.py @@ -203,9 +203,10 @@ def put(self, job_wrapper: "MinimalJobWrapper"): queue_job = job_wrapper.enqueue() except Exception as e: queue_job = False - # Required for exceptions thrown by object store incompatiblity. + # Required for exceptions thrown by object store incompatibility. # tested by test/integration/objectstore/test_private_handling.py - job_wrapper.fail(str(e), exception=e) + message = e.client_message if hasattr(e, "client_message") else str(e) + job_wrapper.fail(message, exception=e) log.debug(f"Job [{job_wrapper.job_id}] failed to queue {put_timer}") return if queue_job: diff --git a/lib/galaxy/objectstore/__init__.py b/lib/galaxy/objectstore/__init__.py index c27ce3cf13fb..7df942976121 100644 --- a/lib/galaxy/objectstore/__init__.py +++ b/lib/galaxy/objectstore/__init__.py @@ -1613,6 +1613,22 @@ def ids_per_quota_source(self, include_default_quota_source=False): return quota_sources +class ObjectCreationProblem(Exception): + pass + + +# Calling these client_message to make it clear they should use the language of the +# Galaxy UI/UX - for instance "storage location" not "objectstore". +class ObjectCreationProblemSharingDisabled(ObjectCreationProblem): + client_message = "Job attempted to create sharable output datasets in a storage location with sharing disabled" + + +class ObjectCreationProblemStoreFull(ObjectCreationProblem): + client_message = ( + "Job attempted to create output datasets in a full storage location, please contact your admin for more details" + ) + + class ObjectStorePopulator: """Small helper for interacting with the object store and making sure all datasets from a job end up with the same object_store_id. @@ -1639,9 +1655,9 @@ def set_dataset_object_store_id(self, dataset, require_shareable=True): ensure_non_private = require_shareable concrete_store = self.object_store.create(dataset, ensure_non_private=ensure_non_private) if concrete_store.private and require_shareable: - raise Exception("Attempted to create shared output datasets in objectstore with sharing disabled") + raise ObjectCreationProblemSharingDisabled() except ObjectInvalid: - raise Exception("Unable to create output dataset: object store is full") + raise ObjectCreationProblemStoreFull() self.object_store_id = dataset.object_store_id # these will be the same thing after the first output