diff --git a/doc/source/releases/19.05.rst b/doc/source/releases/19.05.rst
index 7166c497f17..160ab07a718 100644
--- a/doc/source/releases/19.05.rst
+++ b/doc/source/releases/19.05.rst
@@ -393,6 +393,11 @@ Enhancements
Fixes
-------------------------------
+* Explicitly specify system user under which Kubernetes jobs should run.
+ `Pull Request 8103`_
+* Ensure Kubernetes job querries filter the same namespace as defined in the
+ job destination.
+ `Pull Request 8092`_
* Fix client styleguide asset handling.
`Pull Request 7664`_
* Handle subworkflows in view workflow mako
diff --git a/doc/source/releases/19.05_prs.rst b/doc/source/releases/19.05_prs.rst
index 59ca8a5b131..4498056e1a8 100644
--- a/doc/source/releases/19.05_prs.rst
+++ b/doc/source/releases/19.05_prs.rst
@@ -1,5 +1,7 @@
.. github_links
+.. _Pull Request 8103: https://github.com/galaxyproject/galaxy/pull/8103
+.. _Pull Request 8092: https://github.com/galaxyproject/galaxy/pull/8092
.. _Pull Request 4659: https://github.com/galaxyproject/galaxy/pull/4659
.. _Pull Request 5495: https://github.com/galaxyproject/galaxy/pull/5495
.. _Pull Request 6321: https://github.com/galaxyproject/galaxy/pull/6321
diff --git a/lib/galaxy/jobs/runners/kubernetes.py b/lib/galaxy/jobs/runners/kubernetes.py
index 782c4a3dc29..7c94edb654b 100644
--- a/lib/galaxy/jobs/runners/kubernetes.py
+++ b/lib/galaxy/jobs/runners/kubernetes.py
@@ -54,6 +54,8 @@ class KubernetesJobRunner(AsynchronousJobRunner):
k8s_job_api_version=dict(map=str, default="batch/v1"),
k8s_supplemental_group_id=dict(map=str),
k8s_pull_policy=dict(map=str, default="Default"),
+ k8s_run_as_user_id=dict(map=str, valid=lambda s: s == "$uid" or s.isdigit()),
+ k8s_run_as_group_id=dict(map=str, valid=lambda s: s == "$gid" or s.isdigit()),
k8s_fs_group_id=dict(map=int),
k8s_default_requests_cpu=dict(map=str, default=None),
k8s_default_requests_memory=dict(map=str, default=None),
@@ -76,6 +78,8 @@ class KubernetesJobRunner(AsynchronousJobRunner):
self._galaxy_instance_id = self.__get_galaxy_instance_id()
+ self._run_as_user_id = self.__get_run_as_user_id()
+ self._run_as_group_id = self.__get_run_as_group_id()
self._supplemental_group = self.__get_supplemental_group()
self._fs_group = self.__get_fs_group()
self._default_pull_policy = self.__get_pull_policy()
@@ -169,6 +173,24 @@ class KubernetesJobRunner(AsynchronousJobRunner):
return self.runner_params['k8s_pull_policy']
return None
+ def __get_run_as_user_id(self):
+ if "k8s_run_as_user_id" in self.runner_params:
+ run_as_user = self.runner_params["k8s_run_as_user_id"]
+ if run_as_user == "$uid":
+ return os.getuid()
+ else:
+ return int(self.runner_params["k8s_run_as_user_id"])
+ return None
+
+ def __get_run_as_group_id(self):
+ if "k8s_run_as_group_id" in self.runner_params:
+ run_as_group = self.runner_params["k8s_run_as_group_id"]
+ if run_as_group == "$gid":
+ return self.app.config.gid
+ else:
+ return int(self.runner_params["k8s_run_as_group_id"])
+ return None
+
def __get_supplemental_group(self):
if "k8s_supplemental_group_id" in self.runner_params:
try:
@@ -238,17 +260,21 @@ class KubernetesJobRunner(AsynchronousJobRunner):
}
# TODO include other relevant elements that people might want to use from
# TODO http://kubernetes.io/docs/api-reference/v1/definitions/#_v1_podspec
-
- if self._supplemental_group and self._supplemental_group > 0:
- k8s_spec_template["spec"]["securityContext"] = dict(supplementalGroups=[self._supplemental_group])
- if self._fs_group and self._fs_group > 0:
- if "securityContext" in k8s_spec_template["spec"]:
- k8s_spec_template["spec"]["securityContext"]["fsGroup"] = self._fs_group
- else:
- k8s_spec_template["spec"]["securityContext"] = dict(fsGroup=self._fs_group)
-
+ k8s_spec_template["spec"]["securityContext"] = self.__get_k8s_security_context()
return k8s_spec_template
+ def __get_k8s_security_context(self):
+ security_context = {}
+ if self._run_as_user_id:
+ security_context["runAsUser"] = self._run_as_user_id
+ if self._run_as_group_id:
+ security_context["runAsGroup"] = self._run_as_group_id
+ if self._supplemental_group and self._supplemental_group > 0:
+ security_context["supplementalGroups"] = [self._supplemental_group]
+ if self._fs_group and self._fs_group > 0:
+ security_context["fsGroup"] = self._fs_group
+ return security_context
+
def __get_k8s_restart_policy(self, job_wrapper):
"""The default Kubernetes restart policy for Jobs"""
return "Never"
@@ -475,7 +501,8 @@ class KubernetesJobRunner(AsynchronousJobRunner):
marks the job for resubmission (resubmit logic is part of destinations).
"""
- pods = Pod.objects(self._pykube_api).filter(selector="app=%s" % job_state.job_id)
+ pods = Pod.objects(self._pykube_api).filter(selector="app=%s" % job_state.job_id,
+ namespace=self.runner_params['k8s_namespace'])
pod = Pod(self._pykube_api, pods.response['items'][0])
if pod.obj['status']['phase'] == "Failed" and \
@@ -488,8 +515,9 @@ class KubernetesJobRunner(AsynchronousJobRunner):
"""Attempts to delete a dispatched job to the k8s cluster"""
job = job_wrapper.get_job()
try:
- jobs = Job.objects(self._pykube_api).filter(selector="app=" +
- self.__produce_unique_k8s_job_name(job.get_id_tag()))
+ jobs = Job.objects(self._pykube_api).filter(
+ selector="app=" + self.__produce_unique_k8s_job_name(job.get_id_tag()),
+ namespace=self.runner_params['k8s_namespace'])
if len(jobs.response['items']) >= 0:
job_to_delete = Job(self._pykube_api, jobs.response['items'][0])
job_to_delete.scale(replicas=0)
diff --git a/templates/base.mako b/templates/base.mako
index 062d988ede5..8c6e3f2ba1d 100644
--- a/templates/base.mako
+++ b/templates/base.mako
@@ -65,7 +65,9 @@
${ galaxy_client.load( app=self.js_app ) }
${ galaxy_client.config_sentry( app=self.js_app ) }
- ${ galaxy_client.config_google_analytics( app=self.js_app ) }
+ %if self.js_app and self.js_app.config and self.js_app.config.ga_code:
+ ${ galaxy_client.config_google_analytics(self.js_app.config.ga_code) }
+ %endif
%if not form_input_auto_focus is UNDEFINED and form_input_auto_focus:
%if t.webapp.name == 'galaxy' and app.config.ga_code:
- ${galaxy_client.config_google_analytics(app)}
+ ${galaxy_client.config_google_analytics(app.config.ga_code)}
%endif
%def>
diff --git a/templates/galaxy_client_app.mako b/templates/galaxy_client_app.mako
index 4b4cb51d032..7c22f5d77fa 100644
--- a/templates/galaxy_client_app.mako
+++ b/templates/galaxy_client_app.mako
@@ -39,8 +39,6 @@ ${ h.dumps( dictionary, indent=( 2 if trans.debug else 0 ) ) }
%if app and app.config:
- %endif
+ %else:
+ console.warn("Missing google analytics code");
+ %endif
+
%def>
diff --git a/templates/js-app.mako b/templates/js-app.mako
index 1f25ff30a46..f606b272ba2 100644
--- a/templates/js-app.mako
+++ b/templates/js-app.mako
@@ -74,8 +74,10 @@
%endif
- ## ${ galaxy_client.config_sentry(app)}
- ## ${ galaxy_client.config_google_analytics(app)}
+ ${ galaxy_client.config_sentry(app) }
+ %if app.config.ga_code:
+ ${ galaxy_client.config_google_analytics(app.config.ga_code) }
+ %endif
%def>
diff --git a/templates/webapps/galaxy/galaxy.panels.mako b/templates/webapps/galaxy/galaxy.panels.mako
index 324ca1d25d8..39fc84ec0e7 100644
--- a/templates/webapps/galaxy/galaxy.panels.mako
+++ b/templates/webapps/galaxy/galaxy.panels.mako
@@ -225,7 +225,7 @@
${ galaxy_client.load() }
- ## ${ galaxy_client.config_sentry(app) }
+ ${ galaxy_client.config_sentry(app) }
%def>
diff --git a/templates/webapps/tool_shed/base_panels.mako b/templates/webapps/tool_shed/base_panels.mako
index 295f897679f..dd4c983abe4 100644
--- a/templates/webapps/tool_shed/base_panels.mako
+++ b/templates/webapps/tool_shed/base_panels.mako
@@ -46,7 +46,7 @@
<%def name="masthead()">
%if app.config.ga_code:
- ${galaxy_client.config_google_analytics(app)}
+ ${ galaxy_client.config_google_analytics(app.config.ga_code)}
%endif
## start main tag