From f56ef8a6e2a049eeeb1848241beb00b8e6834f3b Mon Sep 17 00:00:00 2001 From: Oleksandr Andriienko Date: Tue, 21 Jan 2020 11:54:14 +0200 Subject: [PATCH 1/4] Add serviceaccount permissions for -che as default namespace Signed-off-by: Oleksandr Andriienko --- src/api/kube.ts | 35 ++++++ src/tasks/installers/operator.ts | 181 +++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) diff --git a/src/api/kube.ts b/src/api/kube.ts index 1ce35051f..acaf8cd1d 100644 --- a/src/api/kube.ts +++ b/src/api/kube.ts @@ -313,6 +313,22 @@ export class KubeHelper { } } + async createClusterRoleBindingFromFile(filePath: string, namespace: string) { + const yamlRoleBinding = this.safeLoadFromYamlFile(filePath) as V1ClusterRoleBinding + if (yamlRoleBinding.subjects && namespace) { + for (const subject of yamlRoleBinding.subjects) { + subject.namespace = namespace + } + } + + const k8sRbacAuthApi = this.kc.makeApiClient(RbacAuthorizationV1Api) + try { + return await k8sRbacAuthApi.createClusterRoleBinding(yamlRoleBinding) + } catch (e) { + throw this.wrapK8sClientError(e) + } + } + async createClusterRoleBinding(name: string, saName: string, saNamespace = '', roleName = '') { const clusterRoleBinding = { apiVersion: 'rbac.authorization.k8s.io/v1', @@ -367,6 +383,25 @@ export class KubeHelper { } } + async replaceClusterRoleBindingFromFile(filePath: string, namespace: string) { + const yamlClusterRoleBinding = this.safeLoadFromYamlFile(filePath) as V1ClusterRoleBinding + if (!yamlClusterRoleBinding.metadata || !yamlClusterRoleBinding.metadata.name) { + throw new Error(`Cluster role binding read from ${filePath} must have name specified`) + } + + const k8sRbacAuthApi = this.kc.makeApiClient(RbacAuthorizationV1Api) + try { + if (yamlClusterRoleBinding.subjects && namespace) { + for (const subject of yamlClusterRoleBinding.subjects) { + subject.namespace = namespace + } + } + return await k8sRbacAuthApi.replaceClusterRoleBinding(yamlClusterRoleBinding.metadata.name, yamlClusterRoleBinding) + } catch (e) { + throw this.wrapK8sClientError(e) + } + } + async deleteRoleBinding(name = '', namespace = '') { const k8sRbacAuthApi = this.kc.makeApiClient(RbacAuthorizationV1Api) try { diff --git a/src/tasks/installers/operator.ts b/src/tasks/installers/operator.ts index 22c689631..ee3bdbd93 100644 --- a/src/tasks/installers/operator.ts +++ b/src/tasks/installers/operator.ts @@ -26,6 +26,17 @@ export class OperatorTasks { operatorClusterRole = 'che-operator' operatorRoleBinding = 'che-operator' operatorClusterRoleBinding = 'che-operator' + + cheClusterRoleCreateNamespaces = 'che-create-namespaces' + cheOperatorClusterRoleBindingCreateNamespaces = 'che-operator-create-namespaces' + // Cluster rolebindings for che-server to have ability create new namespace for workspace using defaut namespace strategy. + cheClusterRoleBindingCreateNamespace = 'che-namespaces-creator' + + cheClusterRole = 'che' + cheClusterRoleBinding = 'che-operator-che' + // Cluster rolebindings for che-server to manage che workspaces out of che namespace + cheClusterRoleBindingManagerNamespaces = 'che-namespaces-manager' + cheClusterCrd = 'checlusters.org.eclipse.che' operatorName = 'che-operator' operatorCheCluster = 'eclipse-che' @@ -105,6 +116,64 @@ export class OperatorTasks { } } }, + { + title: `Create ClusterRole ${this.cheClusterRoleCreateNamespaces}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleExist(this.cheClusterRoleCreateNamespaces) + if (exist) { + task.title = `${task.title}...It already exists.` + } else { + const yamlFilePath = this.resourcesPath + 'cluster_role_createns.yaml' + const statusCode = await kube.createClusterRoleFromFile(yamlFilePath) + if (statusCode === 403) { + command.error('ERROR: It looks like you don\'t have enough privileges. You need to grant more privileges to current user or use a different user. If you are using minishift you can "oc login -u system:admin"') + } + task.title = `${task.title}...done.` + } + } + }, + { + title: `Create ClusterRoleBinding ${this.cheOperatorClusterRoleBindingCreateNamespaces} in namespace ${flags.chenamespace}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleBindingExist(this.cheOperatorClusterRoleBindingCreateNamespaces) + if (exist) { + task.title = `${task.title}...It already exists.` + } else { + const yamlFilePath = this.resourcesPath + 'cluster_role_binding_createns.yaml' + await kube.createClusterRoleBindingFromFile(yamlFilePath, flags.chenamespace) + task.title = `${task.title}...done.` + } + } + }, + { + title: `Create Cluster role ${this.cheClusterRole}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleExist(this.cheClusterRole) + if (exist) { + task.title = `${task.title}...It already exists.` + } else { + const yamlFilePath = this.resourcesPath + 'cluster_role_che.yaml' + const statusCode = await kube.createClusterRoleFromFile(yamlFilePath) + if (statusCode === 403) { + command.error('ERROR: It looks like you don\'t have enough privileges. You need to grant more privileges to current user or use a different user. If you are using minishift you can "oc login -u system:admin"') + } + task.title = `${task.title}...done.` + } + } + }, + { + title: `Create RoleBinding ${this.cheClusterRoleBinding} in namespace ${flags.chenamespace}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleBindingExist(this.cheClusterRoleBinding) + if (exist) { + task.title = `${task.title}...It already exists.` + } else { + const yamlFilePath = this.resourcesPath + 'cluster_role_binding_che.yaml' + await kube.createClusterRoleBindingFromFile(yamlFilePath, flags.chenamespace) + task.title = `${task.title}...done.` + } + } + }, { title: `Create RoleBinding ${this.operatorRoleBinding} in namespace ${flags.chenamespace}`, task: async (_ctx: any, task: any) => { @@ -301,6 +370,62 @@ export class OperatorTasks { } } }, + { + title: `Update ClusterRole ${this.cheClusterRoleCreateNamespaces}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleExist(this.cheClusterRoleCreateNamespaces) + const yamlFilePath = this.resourcesPath + 'cluster_role_createns.yaml' + if (exist) { + await kube.replaceClusterRoleFromFile(yamlFilePath) + task.title = `${task.title}...updated.` + } else { + await kube.createClusterRoleFromFile(yamlFilePath) + task.title = `${task.title}...created a new one.` + } + } + }, + { + title: `Update ClusterRoleBinding ${this.cheOperatorClusterRoleBindingCreateNamespaces} in namespace ${flags.chenamespace}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleBindingExist(this.cheOperatorClusterRoleBindingCreateNamespaces) + const yamlFilePath = this.resourcesPath + 'cluster_role_binding_createns.yaml' + if (exist) { + await kube.replaceClusterRoleBindingFromFile(yamlFilePath, flags.chenamespace) + task.title = `${task.title}...updated.` + } else { + await kube.createClusterRoleBindingFromFile(yamlFilePath, flags.chenamespace) + task.title = `${task.title}...created new one.` + } + } + }, + { + title: `Update ClusterRole ${this.cheClusterRole}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleExist(this.cheClusterRole) + const yamlFilePath = this.resourcesPath + 'cluster_role_che.yaml' + if (exist) { + await kube.replaceClusterRoleFromFile(yamlFilePath) + task.title = `${task.title}...updated.` + } else { + await kube.createClusterRoleFromFile(yamlFilePath) + task.title = `${task.title}...created a new one.` + } + } + }, + { + title: `Update ClusterRoleBinding ${this.cheClusterRoleBinding} in namespace ${flags.chenamespace}`, + task: async (_ctx: any, task: any) => { + const exist = await kube.clusterRoleBindingExist(this.cheClusterRoleBinding) + const yamlFilePath = this.resourcesPath + 'cluster_role_binding_che.yaml' + if (exist) { + await kube.replaceClusterRoleBindingFromFile(yamlFilePath, flags.chenamespace) + task.title = `${task.title}...updated.` + } else { + await kube.createClusterRoleBindingFromFile(yamlFilePath, flags.chenamespace) + task.title = `${task.title}...created new one.` + } + } + }, { title: `Updating Che Cluster CRD ${this.cheClusterCrd}`, task: async (_ctx: any, task: any) => { @@ -412,6 +537,62 @@ export class OperatorTasks { task.title = await `${task.title}...OK` } }, + // -- Remove cluster rolebindings created for che by che-operator itself -- + { + title: `Delete cluster role binding ${this.cheClusterRoleBindingCreateNamespace}`, + task: async (_ctx: any, task: any) => { + if (await kh.clusterRoleBindingExist(this.cheClusterRoleBindingCreateNamespace)) { + await kh.deleteClusterRoleBinding(this.cheClusterRoleBindingCreateNamespace) + } + task.title = await `${task.title}...OK` + } + }, + { + title: `Delete cluster role binding ${this.cheClusterRoleBindingManagerNamespaces}`, + task: async (_ctx: any, task: any) => { + if (await kh.clusterRoleBindingExist(this.cheClusterRoleBindingManagerNamespaces)) { + await kh.deleteClusterRoleBinding(this.cheClusterRoleBindingManagerNamespaces) + } + task.title = await `${task.title}...OK` + } + }, + // -- -- + { + title: `Delete cluster role binding ${this.cheOperatorClusterRoleBindingCreateNamespaces}`, + task: async (_ctx: any, task: any) => { + if (await kh.clusterRoleBindingExist(this.cheOperatorClusterRoleBindingCreateNamespaces)) { + await kh.deleteClusterRoleBinding(this.cheOperatorClusterRoleBindingCreateNamespaces) + } + task.title = await `${task.title}...OK` + } + }, + { + title: `Delete cluster role ${this.cheClusterRoleCreateNamespaces}`, + task: async (_ctx: any, task: any) => { + if (await kh.clusterRoleExist(this.cheClusterRoleCreateNamespaces)) { + await kh.deleteClusterRole(this.cheClusterRoleCreateNamespaces) + } + task.title = await `${task.title}...OK` + } + }, + { + title: `Delete cluster role binding ${this.cheClusterRoleBinding}`, + task: async (_ctx: any, task: any) => { + if (await kh.clusterRoleBindingExist(this.cheClusterRoleBinding)) { + await kh.deleteClusterRoleBinding(this.cheClusterRoleBinding) + } + task.title = await `${task.title}...OK` + } + }, + { + title: `Delete cluster role ${this.cheClusterRole}`, + task: async (_ctx: any, task: any) => { + if (await kh.clusterRoleExist(this.cheClusterRole)) { + await kh.deleteClusterRole(this.cheClusterRole) + } + task.title = await `${task.title}...OK` + } + }, { title: 'Delete server and workspace rolebindings', task: async (_ctx: any, task: any) => { From 64fa0c4fcce506e278cdda80e0718d49a0b03c45 Mon Sep 17 00:00:00 2001 From: Oleksandr Andriienko Date: Mon, 27 Jan 2020 13:26:09 +0200 Subject: [PATCH 2/4] Rename cluster role binding che to che-manage-namespaces. Signed-off-by: Oleksandr Andriienko --- src/tasks/installers/operator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tasks/installers/operator.ts b/src/tasks/installers/operator.ts index ee3bdbd93..e4057ad45 100644 --- a/src/tasks/installers/operator.ts +++ b/src/tasks/installers/operator.ts @@ -30,9 +30,9 @@ export class OperatorTasks { cheClusterRoleCreateNamespaces = 'che-create-namespaces' cheOperatorClusterRoleBindingCreateNamespaces = 'che-operator-create-namespaces' // Cluster rolebindings for che-server to have ability create new namespace for workspace using defaut namespace strategy. - cheClusterRoleBindingCreateNamespace = 'che-namespaces-creator' + cheClusterRoleBindingCreateNamespace = 'che-create-namespaces' - cheClusterRole = 'che' + cheClusterRole = 'che-manage-namespaces' cheClusterRoleBinding = 'che-operator-che' // Cluster rolebindings for che-server to manage che workspaces out of che namespace cheClusterRoleBindingManagerNamespaces = 'che-namespaces-manager' From 4f0e6060275a0c5004c2e885e49537ef8c3063db Mon Sep 17 00:00:00 2001 From: Oleksandr Andriienko Date: Mon, 27 Jan 2020 16:50:50 +0200 Subject: [PATCH 3/4] Rename rolebinging che to che-manage-namespaces Signed-off-by: Oleksandr Andriienko --- src/tasks/installers/operator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/installers/operator.ts b/src/tasks/installers/operator.ts index e4057ad45..00b11e12a 100644 --- a/src/tasks/installers/operator.ts +++ b/src/tasks/installers/operator.ts @@ -35,7 +35,7 @@ export class OperatorTasks { cheClusterRole = 'che-manage-namespaces' cheClusterRoleBinding = 'che-operator-che' // Cluster rolebindings for che-server to manage che workspaces out of che namespace - cheClusterRoleBindingManagerNamespaces = 'che-namespaces-manager' + cheClusterRoleBindingManagerNamespaces = 'che-manage-namespaces' cheClusterCrd = 'checlusters.org.eclipse.che' operatorName = 'che-operator' From 7a8da16ae923db1d63076ffbdab4a301e341cfb6 Mon Sep 17 00:00:00 2001 From: Oleksandr Andriienko Date: Mon, 27 Jan 2020 17:30:51 +0200 Subject: [PATCH 4/4] Don't clean che server clusterrolebinding created by che-operator. Don't clean che server clusterrolebinding created by che-operator. che-operator should clean up these resources itself Signed-off-by: Oleksandr Andriienko --- src/tasks/installers/operator.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/tasks/installers/operator.ts b/src/tasks/installers/operator.ts index 00b11e12a..5744e415c 100644 --- a/src/tasks/installers/operator.ts +++ b/src/tasks/installers/operator.ts @@ -29,13 +29,9 @@ export class OperatorTasks { cheClusterRoleCreateNamespaces = 'che-create-namespaces' cheOperatorClusterRoleBindingCreateNamespaces = 'che-operator-create-namespaces' - // Cluster rolebindings for che-server to have ability create new namespace for workspace using defaut namespace strategy. - cheClusterRoleBindingCreateNamespace = 'che-create-namespaces' cheClusterRole = 'che-manage-namespaces' cheClusterRoleBinding = 'che-operator-che' - // Cluster rolebindings for che-server to manage che workspaces out of che namespace - cheClusterRoleBindingManagerNamespaces = 'che-manage-namespaces' cheClusterCrd = 'checlusters.org.eclipse.che' operatorName = 'che-operator' @@ -537,26 +533,6 @@ export class OperatorTasks { task.title = await `${task.title}...OK` } }, - // -- Remove cluster rolebindings created for che by che-operator itself -- - { - title: `Delete cluster role binding ${this.cheClusterRoleBindingCreateNamespace}`, - task: async (_ctx: any, task: any) => { - if (await kh.clusterRoleBindingExist(this.cheClusterRoleBindingCreateNamespace)) { - await kh.deleteClusterRoleBinding(this.cheClusterRoleBindingCreateNamespace) - } - task.title = await `${task.title}...OK` - } - }, - { - title: `Delete cluster role binding ${this.cheClusterRoleBindingManagerNamespaces}`, - task: async (_ctx: any, task: any) => { - if (await kh.clusterRoleBindingExist(this.cheClusterRoleBindingManagerNamespaces)) { - await kh.deleteClusterRoleBinding(this.cheClusterRoleBindingManagerNamespaces) - } - task.title = await `${task.title}...OK` - } - }, - // -- -- { title: `Delete cluster role binding ${this.cheOperatorClusterRoleBindingCreateNamespaces}`, task: async (_ctx: any, task: any) => {