From 4a451844e65b33ec2686a2f326c81a98dd45a4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Behmo?= Date: Thu, 3 Jun 2021 18:12:52 +0200 Subject: [PATCH] fix: avoid namespace edition for k8s users without access rights In most cases, it makes very little sense to edit the namespace that an application is running in. Quite often, users are granted access to just one namespace and don't have the necessary rights to edit the namespace -- and for good security reasons. In such cases, the k8s namespace object already exists and there is no need for the user to edit or create it. Here, what we do is that we create the namespace only if it does not exist. This should solve quite a few permission issues, notably for Openshift users. --- CHANGELOG.md | 1 + tutor/commands/k8s.py | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0dd4ba00c..e8f3a15144 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Note: Breaking changes between versions are indicated by "💥". ## Unreleased +- [Improvement] Avoid permission issues in Kubernetes/Openshift for users who do not have the rights to edit their namespace. - [Improvement] Better Kubernetes object creation. ## v11.3.0 (2021-05-18) diff --git a/tutor/commands/k8s.py b/tutor/commands/k8s.py index 0e0c3b2cc3..c91f2fc5e9 100644 --- a/tutor/commands/k8s.py +++ b/tutor/commands/k8s.py @@ -151,7 +151,7 @@ def run_job(self, service: str, command: str) -> int: field_selector = "metadata.name={}".format(job_name) while True: namespaced_jobs = K8sClients.instance().batch_api.list_namespaced_job( - self.config["K8S_NAMESPACE"], field_selector=field_selector + k8s_namespace(self.config), field_selector=field_selector ) if not namespaced_jobs.items: continue @@ -215,15 +215,23 @@ def quickstart(context: click.Context, non_interactive: bool) -> None: @click.command(help="Run all configured Open edX services") @click.pass_obj def start(context: Context) -> None: - # Create namespace - utils.kubectl( - "apply", - "--kustomize", - tutor_env.pathjoin(context.root), - "--wait", - "--selector", - "app.kubernetes.io/component=namespace", - ) + config = tutor_config.load(context.root) + # Create namespace, if necessary + # Note that this step should not be run for some users, in particular those + # who do not have permission to edit the namespace. + try: + utils.kubectl("get", "namespaces", k8s_namespace(config)) + fmt.echo_info("Namespace already exists: skipping creation.") + except exceptions.TutorError: + fmt.echo_info("Namespace does not exist: now creating it...") + utils.kubectl( + "apply", + "--kustomize", + tutor_env.pathjoin(context.root), + "--wait", + "--selector", + "app.kubernetes.io/component=namespace", + ) # Create volumes utils.kubectl( "apply", @@ -455,7 +463,7 @@ def kubectl_exec( ) -> int: selector = "app.kubernetes.io/name={}".format(service) pods = K8sClients.instance().core_api.list_namespaced_pod( - namespace=config["K8S_NAMESPACE"], label_selector=selector + namespace=k8s_namespace(config), label_selector=selector ) if not pods.items: raise exceptions.TutorError(