Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[24.0] Improved error messages for runtime sharing problems. #17794

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -56,9 +57,7 @@ function toggleHighlights() {
result.genome_build
}}</BLink>
</span>
<div v-if="result.misc_info" class="info">
<span class="value">{{ result.misc_info }}</span>
</div>
<DatasetMiscInfo v-if="result.misc_info" :misc-info="result.misc_info" />
</div>
<DatasetActions
:item="result"
Expand Down
64 changes: 64 additions & 0 deletions client/src/components/History/Content/Dataset/DatasetMiscInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script setup lang="ts">
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
Comment on lines +11 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this was for regex debugging, but did you actually want to include it here for posterity?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah - I thought it would be good for future austerity so we can keep ensuring this older message is caught and handled appropriately.

const sharingErrorRex: RegExp = /with sharing disabled/g;
const knownErrors = [{ regex: sharingErrorRex, modalRef: sharingError }];

const props = defineProps<Props>();

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;
}
</script>

<template>
<div class="info">
<b-modal v-if="sharingError" v-model="showErrorHelp" title="Dataset Sharing Misconfigured" ok-only>
<p>
This error message indicates that your history is setup to allow sharing but your job was run in a
configuration to target a storage location that explicitly disables sharing.
</p>
<p>
To fix this configure your history so that new datasets are private or target a different storage
location.
</p>
<p>
To re-configure your history, click the history menu and go to the "Set Permissions" option in the
dropdown. This should result in a toggle that allows you to configure the history so that new datasets
are created as private datasets.
</p>
<p>
There are many ways to instead target different storage for your job. This can be selected in the tool
or workflow form right before you execute your job or a different default for your history or user can
be chosen that allows for sharing.
</p>
</b-modal>
<span class="value">{{ miscInfo }} <a v-if="fixable" href="#" @click="showHelp">How do I fix this?</a></span>
</div>
</template>
5 changes: 3 additions & 2 deletions lib/galaxy/jobs/runners/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
20 changes: 18 additions & 2 deletions lib/galaxy/objectstore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1609,6 +1609,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.
Expand All @@ -1635,9 +1651,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


Expand Down
Loading