From 1ba753ca54b5a20b03f28514894b71c2c966780a Mon Sep 17 00:00:00 2001 From: Nate Coraor Date: Thu, 18 Apr 2019 12:53:34 -0400 Subject: [PATCH 01/13] Catch and filter *all* Slurm cgroup-related messages --- lib/galaxy/jobs/runners/slurm.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/galaxy/jobs/runners/slurm.py b/lib/galaxy/jobs/runners/slurm.py index 333fd55d563..ec2ce131d45 100644 --- a/lib/galaxy/jobs/runners/slurm.py +++ b/lib/galaxy/jobs/runners/slurm.py @@ -28,13 +28,9 @@ SLURM_MEMORY_LIMIT_EXCEEDED_MSG = 'slurmstepd: error: Exceeded job memory limit' SLURM_MEMORY_LIMIT_EXCEEDED_PARTIAL_WARNINGS = [': Exceeded job memory limit at some point.', ': Exceeded step memory limit at some point.'] SLURM_MEMORY_LIMIT_SCAN_SIZE = 16 * 1024 * 1024 # 16MB -SLURM_UNABLE_TO_ADD_TASK_TO_MEMORY_CG_MSG_RE = re.compile(r"""slurmstepd: error: task/cgroup: unable to add task\[pid=\d+\] to memory cg '\(null\)'$""") -SLURM_UNABLE_TO_CREATE_CGROUP_MSG_RE = re.compile(r"""slurmstepd: error: xcgroup_instantiate: unable to create cgroup '[^']+' : No space left on device$""") -SLURM_UNABLE_TO_INSTANCIATE_CGROUP_MSG_RE = re.compile(r"""slurmstepd: error: jobacct_gather/cgroup: unable to instanciate (job|user) \d+ memory cgroup$""") +SLURM_CGROUP_RE = re.compile(r"""slurmstepd: .*cgroup.*$""") SLURM_TOP_WARNING_RES = ( - SLURM_UNABLE_TO_ADD_TASK_TO_MEMORY_CG_MSG_RE, - SLURM_UNABLE_TO_CREATE_CGROUP_MSG_RE, - SLURM_UNABLE_TO_INSTANCIATE_CGROUP_MSG_RE + SLURM_CGROUP_RE, ) # These messages are returned to the user From d0f07acd2d9993ac072f9c532c03fdd8e095ecd6 Mon Sep 17 00:00:00 2001 From: Thomas McGowan Date: Thu, 25 Apr 2019 13:36:43 -0500 Subject: [PATCH 02/13] Processes -> threads to minimize server load --- lib/galaxy/objectstore/s3_multipart_upload.py | 47 ++++--------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/lib/galaxy/objectstore/s3_multipart_upload.py b/lib/galaxy/objectstore/s3_multipart_upload.py index f564c1f8524..4f120ce60d3 100644 --- a/lib/galaxy/objectstore/s3_multipart_upload.py +++ b/lib/galaxy/objectstore/s3_multipart_upload.py @@ -5,13 +5,10 @@ This parallelizes the task over available cores using multiprocessing. Code mostly taken form CloudBioLinux. """ -import contextlib -import functools import glob -import multiprocessing import os import subprocess -from multiprocessing.pool import IMapIterator +import threading try: import boto @@ -20,13 +17,6 @@ except ImportError: boto = None -def map_wrap(f): - @functools.wraps(f) - def wrapper(args): - return f(*args) - return wrapper - - def mp_from_ids(s3server, mp_id, mp_keyname, mp_bucketname): """Get the multipart upload from the bucket and multipart IDs. @@ -51,7 +41,6 @@ def mp_from_ids(s3server, mp_id, mp_keyname, mp_bucketname): return mp -@map_wrap def transfer_part(s3server, mp_id, mp_keyname, mp_bucketname, i, part): """Transfer a part of a multipart upload. Designed to be run in parallel. """ @@ -64,8 +53,6 @@ def transfer_part(s3server, mp_id, mp_keyname, mp_bucketname, i, part): def multipart_upload(s3server, bucket, s3_key_name, tarball, mb_size): """Upload large files using Amazon's multipart upload functionality. """ - cores = multiprocessing.cpu_count() - def split_file(in_file, mb_size, split_num=5): prefix = os.path.join(os.path.dirname(in_file), "%sS3PART" % (os.path.basename(s3_key_name))) @@ -80,29 +67,11 @@ def multipart_upload(s3server, bucket, s3_key_name, tarball, mb_size): mp = bucket.initiate_multipart_upload(s3_key_name, reduced_redundancy=s3server['use_rr']) - with multimap(cores) as pmap: - for _ in pmap(transfer_part, ((s3server, mp.id, mp.key_name, mp.bucket_name, i, part) - for (i, part) in - enumerate(split_file(tarball, mb_size, cores)))): - pass + for (i, part) in enumerate(split_file(tarball, mb_size)): + t = threading.Thread( + target=transfer_part, + args=(s3server, mp.id, mp.key_name, mp.bucket_name, i, part)) + t.start() + t.join() + mp.complete_upload() - - -@contextlib.contextmanager -def multimap(cores=None): - """Provide multiprocessing imap like function. - - The context manager handles setting up the pool, worked around interrupt issues - and terminating the pool on completion. - """ - if cores is None: - cores = max(multiprocessing.cpu_count() - 1, 1) - - def wrapper(func): - def wrap(self, timeout=None): - return func(self, timeout=timeout if timeout is not None else 1e100) - return wrap - IMapIterator.next = wrapper(IMapIterator.next) - pool = multiprocessing.Pool(cores) - yield pool.imap - pool.terminate() From 966a46c9b4c87caa0d56491ef0e6d24877aaee97 Mon Sep 17 00:00:00 2001 From: Thomas McGowan Date: Thu, 25 Apr 2019 14:29:31 -0500 Subject: [PATCH 03/13] Removed trailing whitespace --- lib/galaxy/objectstore/s3_multipart_upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/objectstore/s3_multipart_upload.py b/lib/galaxy/objectstore/s3_multipart_upload.py index 4f120ce60d3..64b15ce76f9 100644 --- a/lib/galaxy/objectstore/s3_multipart_upload.py +++ b/lib/galaxy/objectstore/s3_multipart_upload.py @@ -69,7 +69,7 @@ def multipart_upload(s3server, bucket, s3_key_name, tarball, mb_size): for (i, part) in enumerate(split_file(tarball, mb_size)): t = threading.Thread( - target=transfer_part, + target=transfer_part, args=(s3server, mp.id, mp.key_name, mp.bucket_name, i, part)) t.start() t.join() From 7ac30ec59070672e0a01b86d7d9701f0ffd9ace1 Mon Sep 17 00:00:00 2001 From: Nate Coraor Date: Tue, 30 Apr 2019 14:14:18 -0400 Subject: [PATCH 04/13] Fix the job config's shared _get_default() method so it does the correct thing for destinations --- lib/galaxy/util/handlers.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/galaxy/util/handlers.py b/lib/galaxy/util/handlers.py index 00f6faa773c..063ab83f247 100644 --- a/lib/galaxy/util/handlers.py +++ b/lib/galaxy/util/handlers.py @@ -61,7 +61,9 @@ class ConfiguresHandlers(object): handler_id, [x.strip() for x in handler.get('tags', self.DEFAULT_HANDLER_TAG).split(',')] ) - self.default_handler_id = self._get_default(self.app.config, config_element, list(self.handlers.keys())) + self.default_handler_id = self._get_default( + self.app.config, config_element, list(self.handlers.keys()), + required=self.deterministic_handler_assignment) def _init_handler_assignment_methods(self, config_element=None): self.__is_handler = None @@ -115,7 +117,7 @@ class ConfiguresHandlers(object): def _parse_handler(self, handler_id, handler_def): pass - def _get_default(self, config, parent, names, auto=False): + def _get_default(self, config, parent, names, auto=False, required=True): """ Returns the default attribute set in a parent tag like or , or return the ID of the child, if there is no explicit @@ -127,6 +129,8 @@ class ConfiguresHandlers(object): :type names: list of str :param auto: Automatically set a default if there is no default in the parent tag and there is only one child. :type auto: bool + :param required: Require a default to be set or determined automatically, else raise Exception + :type required: bool :returns: str -- id or tag representing the default. """ @@ -141,12 +145,14 @@ class ConfiguresHandlers(object): if rval is not None: # If the parent element has a 'default' attribute, use the id or tag in that attribute - if self.deterministic_handler_assignment and rval not in names: + if required and rval not in names: raise Exception("<%s> default attribute '%s' does not match a defined id or tag in a child element" % (parent.tag, rval)) log.debug("<%s> default set to child with id or tag '%s'" % (parent.tag, rval)) elif auto and len(names) == 1: log.info("Setting <%s> default to child with id '%s'" % (parent.tag, names[0])) rval = names[0] + elif required: + raise Exception("No <%s> default specified, please specify a valid id or tag with the 'default' attribute" % parent.tag) return rval def _findall_with_required(self, parent, match, attribs=None): @@ -180,8 +186,7 @@ class ConfiguresHandlers(object): @property def deterministic_handler_assignment(self): - return self.handler_assignment_methods and all( - filter(lambda x: x in ( + return any(filter(lambda x: x in ( HANDLER_ASSIGNMENT_METHODS.UWSGI_MULE_MESSAGE, HANDLER_ASSIGNMENT_METHODS.DB_PREASSIGN, ), self.handler_assignment_methods)) From 1410e8cf93d0284a23253b5b053edb4374205924 Mon Sep 17 00:00:00 2001 From: Nate Coraor Date: Tue, 30 Apr 2019 14:44:45 -0400 Subject: [PATCH 05/13] Fix tests broken by previous commit, also, handler defaults are never required (preassign uses all defined handlers if no default is set). --- lib/galaxy/util/handlers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/util/handlers.py b/lib/galaxy/util/handlers.py index 063ab83f247..d249171b82b 100644 --- a/lib/galaxy/util/handlers.py +++ b/lib/galaxy/util/handlers.py @@ -62,8 +62,7 @@ class ConfiguresHandlers(object): [x.strip() for x in handler.get('tags', self.DEFAULT_HANDLER_TAG).split(',')] ) self.default_handler_id = self._get_default( - self.app.config, config_element, list(self.handlers.keys()), - required=self.deterministic_handler_assignment) + self.app.config, config_element, list(self.handlers.keys()), required=False) def _init_handler_assignment_methods(self, config_element=None): self.__is_handler = None @@ -186,7 +185,8 @@ class ConfiguresHandlers(object): @property def deterministic_handler_assignment(self): - return any(filter(lambda x: x in ( + return self.handler_assignment_methods and any( + filter(lambda x: x in ( HANDLER_ASSIGNMENT_METHODS.UWSGI_MULE_MESSAGE, HANDLER_ASSIGNMENT_METHODS.DB_PREASSIGN, ), self.handler_assignment_methods)) From ecdc3adbacfca0ede6566b4327f980f0fc216516 Mon Sep 17 00:00:00 2001 From: William Holden Date: Thu, 2 May 2019 16:32:17 +0000 Subject: [PATCH 06/13] allow typing e in float param field --- client/galaxy/scripts/mvc/ui/ui-slider.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/galaxy/scripts/mvc/ui/ui-slider.js b/client/galaxy/scripts/mvc/ui/ui-slider.js index f2c48634b7d..96dcb7913d5 100644 --- a/client/galaxy/scripts/mvc/ui/ui-slider.js +++ b/client/galaxy/scripts/mvc/ui/ui-slider.js @@ -47,6 +47,7 @@ var View = Backbone.View.extend({ v == 13 || v == 37 || v == 39 || + v == 69 || (v >= 48 && v <= 57) || (v >= 96 && v <= 105) || ((v == 190 || v == 110) && From 65082653e98ee530f40d0307b56db62d577def94 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Fri, 3 May 2019 16:21:54 +0200 Subject: [PATCH 07/13] Update Cheetah dependency, fixes `AssertionError: Requested __call__ column missing from column def` Fixes ``` Traceback (most recent call last): File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/jobs/runners/pulsar.py", line 350, in __prepare_job job_wrapper.prepare(**prepare_kwds) File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/jobs/__init__.py", line 871, in prepare self.command_line, self.extra_filenames, self.environment_variables = tool_evaluator.build() File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/tools/evaluation.py", line 451, in build raise e File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/tools/evaluation.py", line 447, in build self.__build_command_line() File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/tools/evaluation.py", line 472, in __build_command_line command_line = fill_template(command, context=param_dict) File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/util/template.py", line 18, in fill_template return unicodify(Template(source=template_text, searchList=[context])) File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/util/__init__.py", line 1018, in unicodify msg = "Value '%s' could not be coerced to Unicode" % value File "/cvmfs/test.galaxyproject.org/venv/lib/python3.6/site-packages/Cheetah/Template.py", line 1053, in __unicode__ return getattr(self, mainMethName)() File "cheetah_DynamicallyCompiledCheetahTemplate_1555443583_0915494_96112.py", line 261, in respond File "/cvmfs/test.galaxyproject.org/venv/lib/python3.6/site-packages/Cheetah/NameMapper.py", line 288, in valueFromSearchList executeCallables=executeCallables) File "/cvmfs/test.galaxyproject.org/venv/lib/python3.6/site-packages/Cheetah/NameMapper.py", line 231, in _valueForName if executeCallables and hasattr(nextObj, '__call__') and \ File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/tools/wrappers.py", line 138, in __getattr__ self._fields[name] = self._input.options.get_field_by_name_for_value(name, self._value, None, self._other_values) File "/cvmfs/test.galaxyproject.org/galaxy/lib/galaxy/tools/parameters/dynamic_options.py", line 658, in get_field_by_name_for_value assert field_name in self.columns, "Requested '%s' column missing from column def" % field_name AssertionError: Requested '__call__' column missing from column def ``` reported by @natefoo and seen on test.galaxyproject.org. This was fixed upstream in https://github.com/CheetahTemplate3/cheetah3/commit/354c885ae50c3d38b06928493ecd640c5d3bf768 by replacing `hasattr(nextObj, '__call__')` with `callable(nextObj)`. --- .../dependencies/pipfiles/default/pinned-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/dependencies/pipfiles/default/pinned-requirements.txt b/lib/galaxy/dependencies/pipfiles/default/pinned-requirements.txt index 5d05ea3e7a9..ea41b6dc6ff 100644 --- a/lib/galaxy/dependencies/pipfiles/default/pinned-requirements.txt +++ b/lib/galaxy/dependencies/pipfiles/default/pinned-requirements.txt @@ -36,7 +36,7 @@ cachetools==3.1.0 certifi==2019.3.9 cffi==1.12.3 chardet==3.0.4 -cheetah3==3.2.1 +cheetah3==3.2.2 cliff==2.14.1 cloudauthz==0.2.0 cloudbridge==2.0.0 From bfdc47143535af8c07411451dc06c8f66b819960 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Mon, 6 May 2019 14:09:22 +0200 Subject: [PATCH 08/13] Add local namespaced resolver to default container resolvers The mulled container resolvers are building containers that are namespaced to "local", so I think it makes a lot of sense to include local in the defaults. This prevents planemo from building the same image over and over again when run with `--biocontainers`. --- lib/galaxy/tools/deps/containers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/galaxy/tools/deps/containers.py b/lib/galaxy/tools/deps/containers.py index 5a8234f84db..35229b4e631 100644 --- a/lib/galaxy/tools/deps/containers.py +++ b/lib/galaxy/tools/deps/containers.py @@ -206,7 +206,9 @@ class ContainerRegistry(object): if self.enable_beta_mulled_containers: default_resolvers.extend([ CachedMulledDockerContainerResolver(self.app_info, namespace="biocontainers"), + CachedMulledDockerContainerResolver(self.app_info, namespace="local"), CachedMulledSingularityContainerResolver(self.app_info, namespace="biocontainers"), + CachedMulledSingularityContainerResolver(self.app_info, namespace="local"), MulledDockerContainerResolver(self.app_info, namespace="biocontainers"), MulledSingularityContainerResolver(self.app_info, namespace="biocontainers"), BuildMulledDockerContainerResolver(self.app_info), From 7d35b50a782694ee7b55ec4bb7fb5eeb774fce24 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Mon, 15 Apr 2019 13:57:18 -0400 Subject: [PATCH 09/13] Add a screen-reader only reference from workflow node to details pane as a test. --- client/galaxy/scripts/mvc/workflow/workflow-view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view.js b/client/galaxy/scripts/mvc/workflow/workflow-view.js index 23875f61489..7a108c93c4c 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view.js @@ -774,6 +774,7 @@ export default Backbone.View.extend({ // Fix width to computed width // Now add floats var buttons = $("
"); + buttons.append($(``)); if (type !== "subworkflow") { buttons.append( $("
") From 6d32634dd14fe19744e313183a30c3e51d549638 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Mon, 15 Apr 2019 16:07:22 -0400 Subject: [PATCH 10/13] Tool -> Node, since these can be subworkflows, etc. --- client/galaxy/scripts/mvc/workflow/workflow-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view.js b/client/galaxy/scripts/mvc/workflow/workflow-view.js index 7a108c93c4c..1d285a99908 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view.js @@ -774,7 +774,7 @@ export default Backbone.View.extend({ // Fix width to computed width // Now add floats var buttons = $("
"); - buttons.append($(``)); + buttons.append($(``)); if (type !== "subworkflow") { buttons.append( $("
") From c6515f491b24e6f904fe62b056a7fb4998311398 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Mon, 6 May 2019 12:06:16 -0400 Subject: [PATCH 11/13] (minor cleanup) Prefer dot notation for object access --- client/galaxy/scripts/mvc/workflow/workflow-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view.js b/client/galaxy/scripts/mvc/workflow/workflow-view.js index 1d285a99908..50465e6963f 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view.js @@ -258,7 +258,7 @@ export default Backbone.View.extend({ for (let i = 0; i < workflow_versions.length; i++) { const current_wf = workflow_versions[i]; - let version_text = `Version ${current_wf["version"]}, ${current_wf["steps"]} steps`; + let version_text = `Version ${current_wf.version}, ${current_wf.steps} steps`; let selected = false; if (i == self.workflow.workflow_version) { version_text = `${version_text} (active)`; @@ -287,7 +287,7 @@ export default Backbone.View.extend({ $("#workflow-version-switch").unbind("change"); if (this.value != self.workflow.workflow_version) { if (self.workflow && self.workflow.has_changes) { - const r = confirm("There are unsaved changes to your workflow which will be lost. Continue ?"); + const r = window.confirm("There are unsaved changes to your workflow which will be lost. Continue ?"); if (r == false) { // We rebuild the version select list, to reset the selected version self.build_version_select(); From 7a046d56f6654cd5283607bffe4fd24ade61ace4 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 7 May 2019 09:00:37 -0400 Subject: [PATCH 12/13] Fix multi-history copying of collections. Previously it would copy the collection but not the elements, so if the original HDAs were deleted or purged they'd be deleted in the new history as well. This was not the behavior of the "Copy Datasets" page for instance that would do a deep copy. There are downsides of doing it this way but this is probably the most intuitive behavior for the GUI for now. Fixes #7493. --- client/galaxy/scripts/mvc/history/history-contents.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/galaxy/scripts/mvc/history/history-contents.js b/client/galaxy/scripts/mvc/history/history-contents.js index a0049811ff6..54eb7757e80 100644 --- a/client/galaxy/scripts/mvc/history/history-contents.js +++ b/client/galaxy/scripts/mvc/history/history-contents.js @@ -442,7 +442,8 @@ export var HistoryContents = _super.extend(BASE_MVC.LoggableMixin).extend({ data: JSON.stringify({ content: id, source: contentType, - type: type + type: type, + copy_elements: true }) }) .done(response => { From 48c5b58ac68c7318edb68230e8331033502b2223 Mon Sep 17 00:00:00 2001 From: Nate Coraor Date: Mon, 6 May 2019 14:20:16 -0400 Subject: [PATCH 13/13] Fix application of history default permissions to anonymous histories carried over upon login. --- lib/galaxy/web/framework/webapp.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/galaxy/web/framework/webapp.py b/lib/galaxy/web/framework/webapp.py index f64e0a1d05b..88ca95eb8df 100644 --- a/lib/galaxy/web/framework/webapp.py +++ b/lib/galaxy/web/framework/webapp.py @@ -650,24 +650,27 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, Associate the user's last accessed history (if exists) with their new session """ history = None + set_permissions = False try: users_last_session = user.galaxy_sessions[0] - last_accessed = True except Exception: users_last_session = None - last_accessed = False if (prev_galaxy_session and prev_galaxy_session.current_history and not prev_galaxy_session.current_history.deleted and - prev_galaxy_session.current_history.datasets): - if prev_galaxy_session.current_history.user is None or prev_galaxy_session.current_history.user == user: - # If the previous galaxy session had a history, associate it with the new - # session, but only if it didn't belong to a different user. - history = prev_galaxy_session.current_history - if prev_galaxy_session.user is None: - # Increase the user's disk usage by the amount of the previous history's datasets if they didn't already own it. - for hda in history.datasets: - user.adjust_total_disk_usage(hda.quota_amount(user)) + prev_galaxy_session.current_history.datasets and + (prev_galaxy_session.current_history.user is None or + prev_galaxy_session.current_history.user == user)): + # If the previous galaxy session had a history, associate it with the new session, but only if it didn't + # belong to a different user. + history = prev_galaxy_session.current_history + if prev_galaxy_session.user is None: + # Increase the user's disk usage by the amount of the previous history's datasets if they didn't already + # own it. + for hda in history.datasets: + user.adjust_total_disk_usage(hda.quota_amount(user)) + # Only set default history permissions if the history is from the previous session and anonymous + set_permissions = True elif self.galaxy_session.current_history: history = self.galaxy_session.current_history if (not history and users_last_session and @@ -681,8 +684,7 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, if history.user is None: history.user = user self.galaxy_session.current_history = history - if not last_accessed: - # Only set default history permissions if current history is not from a previous session + if set_permissions: self.app.security_agent.history_set_default_permissions(history, dataset=True, bypass_manage_permission=True) self.sa_session.add_all((prev_galaxy_session, self.galaxy_session, history))