From 9e8daeb8a6066109c3254178fe689dc8066d88db Mon Sep 17 00:00:00 2001 From: Tiger Date: Thu, 22 Aug 2019 16:40:17 +1000 Subject: Move generic k8s services out of GCP namespace These services aren't specific to GCP, and will be used for AWS as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/46686 --- .../clusters/gcp/finalize_creation_service.rb | 8 +- app/services/clusters/gcp/kubernetes.rb | 16 --- .../create_or_update_namespace_service.rb | 47 ------- .../create_or_update_service_account_service.rb | 141 --------------------- .../kubernetes/fetch_kubernetes_token_service.rb | 42 ------ .../create_or_update_namespace_service.rb | 45 +++++++ .../create_or_update_service_account_service.rb | 139 ++++++++++++++++++++ .../kubernetes/fetch_kubernetes_token_service.rb | 40 ++++++ app/services/clusters/kubernetes/kubernetes.rb | 14 ++ 9 files changed, 242 insertions(+), 250 deletions(-) delete mode 100644 app/services/clusters/gcp/kubernetes.rb delete mode 100644 app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb delete mode 100644 app/services/clusters/gcp/kubernetes/create_or_update_service_account_service.rb delete mode 100644 app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb create mode 100644 app/services/clusters/kubernetes/create_or_update_namespace_service.rb create mode 100644 app/services/clusters/kubernetes/create_or_update_service_account_service.rb create mode 100644 app/services/clusters/kubernetes/fetch_kubernetes_token_service.rb create mode 100644 app/services/clusters/kubernetes/kubernetes.rb (limited to 'app/services') diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb index 2f3c1df7651..c5cde831964 100644 --- a/app/services/clusters/gcp/finalize_creation_service.rb +++ b/app/services/clusters/gcp/finalize_creation_service.rb @@ -26,7 +26,7 @@ module Clusters private def create_gitlab_service_account! - Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService.gitlab_creator( + Clusters::Kubernetes::CreateOrUpdateServiceAccountService.gitlab_creator( kube_client, rbac: create_rbac_cluster? ).execute @@ -49,10 +49,10 @@ module Clusters end def request_kubernetes_token - Clusters::Gcp::Kubernetes::FetchKubernetesTokenService.new( + Clusters::Kubernetes::FetchKubernetesTokenService.new( kube_client, - Clusters::Gcp::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, - Clusters::Gcp::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE + Clusters::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, + Clusters::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE ).execute end diff --git a/app/services/clusters/gcp/kubernetes.rb b/app/services/clusters/gcp/kubernetes.rb deleted file mode 100644 index 85711764785..00000000000 --- a/app/services/clusters/gcp/kubernetes.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Gcp - module Kubernetes - GITLAB_SERVICE_ACCOUNT_NAME = 'gitlab' - GITLAB_SERVICE_ACCOUNT_NAMESPACE = 'default' - GITLAB_ADMIN_TOKEN_NAME = 'gitlab-token' - GITLAB_CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin' - GITLAB_CLUSTER_ROLE_NAME = 'cluster-admin' - PROJECT_CLUSTER_ROLE_NAME = 'edit' - GITLAB_KNATIVE_SERVING_ROLE_NAME = 'gitlab-knative-serving-role' - GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME = 'gitlab-knative-serving-rolebinding' - end - end -end diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb deleted file mode 100644 index c45dac7b273..00000000000 --- a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Gcp - module Kubernetes - class CreateOrUpdateNamespaceService - def initialize(cluster:, kubernetes_namespace:) - @cluster = cluster - @kubernetes_namespace = kubernetes_namespace - @platform = cluster.platform - end - - def execute - create_project_service_account - configure_kubernetes_token - - kubernetes_namespace.save! - end - - private - - attr_reader :cluster, :kubernetes_namespace, :platform - - def create_project_service_account - Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService.namespace_creator( - platform.kubeclient, - service_account_name: kubernetes_namespace.service_account_name, - service_account_namespace: kubernetes_namespace.namespace, - rbac: platform.rbac? - ).execute - end - - def configure_kubernetes_token - kubernetes_namespace.service_account_token = fetch_service_account_token - end - - def fetch_service_account_token - Clusters::Gcp::Kubernetes::FetchKubernetesTokenService.new( - platform.kubeclient, - kubernetes_namespace.token_name, - kubernetes_namespace.namespace - ).execute - end - end - end - end -end diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_service_account_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_service_account_service.rb deleted file mode 100644 index 7c5450dbcd6..00000000000 --- a/app/services/clusters/gcp/kubernetes/create_or_update_service_account_service.rb +++ /dev/null @@ -1,141 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Gcp - module Kubernetes - class CreateOrUpdateServiceAccountService - def initialize(kubeclient, service_account_name:, service_account_namespace:, token_name:, rbac:, namespace_creator: false, role_binding_name: nil) - @kubeclient = kubeclient - @service_account_name = service_account_name - @service_account_namespace = service_account_namespace - @token_name = token_name - @rbac = rbac - @namespace_creator = namespace_creator - @role_binding_name = role_binding_name - end - - def self.gitlab_creator(kubeclient, rbac:) - self.new( - kubeclient, - service_account_name: Clusters::Gcp::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAME, - service_account_namespace: Clusters::Gcp::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE, - token_name: Clusters::Gcp::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, - rbac: rbac - ) - end - - def self.namespace_creator(kubeclient, service_account_name:, service_account_namespace:, rbac:) - self.new( - kubeclient, - service_account_name: service_account_name, - service_account_namespace: service_account_namespace, - token_name: "#{service_account_namespace}-token", - rbac: rbac, - namespace_creator: true, - role_binding_name: "gitlab-#{service_account_namespace}" - ) - end - - def execute - ensure_project_namespace_exists if namespace_creator - - kubeclient.create_or_update_service_account(service_account_resource) - kubeclient.create_or_update_secret(service_account_token_resource) - - return unless rbac - - create_role_or_cluster_role_binding - - return unless namespace_creator - - create_or_update_knative_serving_role - create_or_update_knative_serving_role_binding - end - - private - - attr_reader :kubeclient, :service_account_name, :service_account_namespace, :token_name, :rbac, :namespace_creator, :role_binding_name - - def ensure_project_namespace_exists - Gitlab::Kubernetes::Namespace.new( - service_account_namespace, - kubeclient - ).ensure_exists! - end - - def create_role_or_cluster_role_binding - if namespace_creator - kubeclient.create_or_update_role_binding(role_binding_resource) - else - kubeclient.create_or_update_cluster_role_binding(cluster_role_binding_resource) - end - end - - def create_or_update_knative_serving_role - kubeclient.update_role(knative_serving_role_resource) - end - - def create_or_update_knative_serving_role_binding - kubeclient.update_role_binding(knative_serving_role_binding_resource) - end - - def service_account_resource - Gitlab::Kubernetes::ServiceAccount.new( - service_account_name, - service_account_namespace - ).generate - end - - def service_account_token_resource - Gitlab::Kubernetes::ServiceAccountToken.new( - token_name, - service_account_name, - service_account_namespace - ).generate - end - - def cluster_role_binding_resource - subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: service_account_namespace }] - - Gitlab::Kubernetes::ClusterRoleBinding.new( - Clusters::Gcp::Kubernetes::GITLAB_CLUSTER_ROLE_BINDING_NAME, - Clusters::Gcp::Kubernetes::GITLAB_CLUSTER_ROLE_NAME, - subjects - ).generate - end - - def role_binding_resource - Gitlab::Kubernetes::RoleBinding.new( - name: role_binding_name, - role_name: Clusters::Gcp::Kubernetes::PROJECT_CLUSTER_ROLE_NAME, - role_kind: :ClusterRole, - namespace: service_account_namespace, - service_account_name: service_account_name - ).generate - end - - def knative_serving_role_resource - Gitlab::Kubernetes::Role.new( - name: Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, - namespace: service_account_namespace, - rules: [{ - apiGroups: %w(serving.knative.dev), - resources: %w(configurations configurationgenerations routes revisions revisionuids autoscalers services), - verbs: %w(get list create update delete patch watch) - }] - ).generate - end - - def knative_serving_role_binding_resource - Gitlab::Kubernetes::RoleBinding.new( - name: Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, - role_name: Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, - role_kind: :Role, - namespace: service_account_namespace, - service_account_name: service_account_name - ).generate - end - end - end - end -end diff --git a/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb b/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb deleted file mode 100644 index 5d9bdc52d37..00000000000 --- a/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Gcp - module Kubernetes - class FetchKubernetesTokenService - DEFAULT_TOKEN_RETRY_DELAY = 5.seconds - TOKEN_RETRY_LIMIT = 5 - - attr_reader :kubeclient, :service_account_token_name, :namespace - - def initialize(kubeclient, service_account_token_name, namespace, token_retry_delay: DEFAULT_TOKEN_RETRY_DELAY) - @kubeclient = kubeclient - @service_account_token_name = service_account_token_name - @namespace = namespace - @token_retry_delay = token_retry_delay - end - - def execute - # Kubernetes will create the Secret and set the token asynchronously - # so it is necessary to retry - # https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#token-controller - TOKEN_RETRY_LIMIT.times do - token_base64 = get_secret&.dig('data', 'token') - return Base64.decode64(token_base64) if token_base64 - - sleep @token_retry_delay - end - - nil - end - - private - - def get_secret - kubeclient.get_secret(service_account_token_name, namespace).as_json - rescue Kubeclient::ResourceNotFoundError - end - end - end - end -end diff --git a/app/services/clusters/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/kubernetes/create_or_update_namespace_service.rb new file mode 100644 index 00000000000..15be8446cc0 --- /dev/null +++ b/app/services/clusters/kubernetes/create_or_update_namespace_service.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Clusters + module Kubernetes + class CreateOrUpdateNamespaceService + def initialize(cluster:, kubernetes_namespace:) + @cluster = cluster + @kubernetes_namespace = kubernetes_namespace + @platform = cluster.platform + end + + def execute + create_project_service_account + configure_kubernetes_token + + kubernetes_namespace.save! + end + + private + + attr_reader :cluster, :kubernetes_namespace, :platform + + def create_project_service_account + Clusters::Kubernetes::CreateOrUpdateServiceAccountService.namespace_creator( + platform.kubeclient, + service_account_name: kubernetes_namespace.service_account_name, + service_account_namespace: kubernetes_namespace.namespace, + rbac: platform.rbac? + ).execute + end + + def configure_kubernetes_token + kubernetes_namespace.service_account_token = fetch_service_account_token + end + + def fetch_service_account_token + Clusters::Kubernetes::FetchKubernetesTokenService.new( + platform.kubeclient, + kubernetes_namespace.token_name, + kubernetes_namespace.namespace + ).execute + end + end + end +end diff --git a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb new file mode 100644 index 00000000000..8b8ad924b64 --- /dev/null +++ b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb @@ -0,0 +1,139 @@ +# frozen_string_literal: true + +module Clusters + module Kubernetes + class CreateOrUpdateServiceAccountService + def initialize(kubeclient, service_account_name:, service_account_namespace:, token_name:, rbac:, namespace_creator: false, role_binding_name: nil) + @kubeclient = kubeclient + @service_account_name = service_account_name + @service_account_namespace = service_account_namespace + @token_name = token_name + @rbac = rbac + @namespace_creator = namespace_creator + @role_binding_name = role_binding_name + end + + def self.gitlab_creator(kubeclient, rbac:) + self.new( + kubeclient, + service_account_name: Clusters::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAME, + service_account_namespace: Clusters::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE, + token_name: Clusters::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, + rbac: rbac + ) + end + + def self.namespace_creator(kubeclient, service_account_name:, service_account_namespace:, rbac:) + self.new( + kubeclient, + service_account_name: service_account_name, + service_account_namespace: service_account_namespace, + token_name: "#{service_account_namespace}-token", + rbac: rbac, + namespace_creator: true, + role_binding_name: "gitlab-#{service_account_namespace}" + ) + end + + def execute + ensure_project_namespace_exists if namespace_creator + + kubeclient.create_or_update_service_account(service_account_resource) + kubeclient.create_or_update_secret(service_account_token_resource) + + return unless rbac + + create_role_or_cluster_role_binding + + return unless namespace_creator + + create_or_update_knative_serving_role + create_or_update_knative_serving_role_binding + end + + private + + attr_reader :kubeclient, :service_account_name, :service_account_namespace, :token_name, :rbac, :namespace_creator, :role_binding_name + + def ensure_project_namespace_exists + Gitlab::Kubernetes::Namespace.new( + service_account_namespace, + kubeclient + ).ensure_exists! + end + + def create_role_or_cluster_role_binding + if namespace_creator + kubeclient.create_or_update_role_binding(role_binding_resource) + else + kubeclient.create_or_update_cluster_role_binding(cluster_role_binding_resource) + end + end + + def create_or_update_knative_serving_role + kubeclient.update_role(knative_serving_role_resource) + end + + def create_or_update_knative_serving_role_binding + kubeclient.update_role_binding(knative_serving_role_binding_resource) + end + + def service_account_resource + Gitlab::Kubernetes::ServiceAccount.new( + service_account_name, + service_account_namespace + ).generate + end + + def service_account_token_resource + Gitlab::Kubernetes::ServiceAccountToken.new( + token_name, + service_account_name, + service_account_namespace + ).generate + end + + def cluster_role_binding_resource + subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: service_account_namespace }] + + Gitlab::Kubernetes::ClusterRoleBinding.new( + Clusters::Kubernetes::GITLAB_CLUSTER_ROLE_BINDING_NAME, + Clusters::Kubernetes::GITLAB_CLUSTER_ROLE_NAME, + subjects + ).generate + end + + def role_binding_resource + Gitlab::Kubernetes::RoleBinding.new( + name: role_binding_name, + role_name: Clusters::Kubernetes::PROJECT_CLUSTER_ROLE_NAME, + role_kind: :ClusterRole, + namespace: service_account_namespace, + service_account_name: service_account_name + ).generate + end + + def knative_serving_role_resource + Gitlab::Kubernetes::Role.new( + name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, + namespace: service_account_namespace, + rules: [{ + apiGroups: %w(serving.knative.dev), + resources: %w(configurations configurationgenerations routes revisions revisionuids autoscalers services), + verbs: %w(get list create update delete patch watch) + }] + ).generate + end + + def knative_serving_role_binding_resource + Gitlab::Kubernetes::RoleBinding.new( + name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, + role_name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, + role_kind: :Role, + namespace: service_account_namespace, + service_account_name: service_account_name + ).generate + end + end + end +end diff --git a/app/services/clusters/kubernetes/fetch_kubernetes_token_service.rb b/app/services/clusters/kubernetes/fetch_kubernetes_token_service.rb new file mode 100644 index 00000000000..aaf437abfad --- /dev/null +++ b/app/services/clusters/kubernetes/fetch_kubernetes_token_service.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Clusters + module Kubernetes + class FetchKubernetesTokenService + DEFAULT_TOKEN_RETRY_DELAY = 5.seconds + TOKEN_RETRY_LIMIT = 5 + + attr_reader :kubeclient, :service_account_token_name, :namespace + + def initialize(kubeclient, service_account_token_name, namespace, token_retry_delay: DEFAULT_TOKEN_RETRY_DELAY) + @kubeclient = kubeclient + @service_account_token_name = service_account_token_name + @namespace = namespace + @token_retry_delay = token_retry_delay + end + + def execute + # Kubernetes will create the Secret and set the token asynchronously + # so it is necessary to retry + # https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#token-controller + TOKEN_RETRY_LIMIT.times do + token_base64 = get_secret&.dig('data', 'token') + return Base64.decode64(token_base64) if token_base64 + + sleep @token_retry_delay + end + + nil + end + + private + + def get_secret + kubeclient.get_secret(service_account_token_name, namespace).as_json + rescue Kubeclient::ResourceNotFoundError + end + end + end +end diff --git a/app/services/clusters/kubernetes/kubernetes.rb b/app/services/clusters/kubernetes/kubernetes.rb new file mode 100644 index 00000000000..7d5d0c2c1d6 --- /dev/null +++ b/app/services/clusters/kubernetes/kubernetes.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Clusters + module Kubernetes + GITLAB_SERVICE_ACCOUNT_NAME = 'gitlab' + GITLAB_SERVICE_ACCOUNT_NAMESPACE = 'default' + GITLAB_ADMIN_TOKEN_NAME = 'gitlab-token' + GITLAB_CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin' + GITLAB_CLUSTER_ROLE_NAME = 'cluster-admin' + PROJECT_CLUSTER_ROLE_NAME = 'edit' + GITLAB_KNATIVE_SERVING_ROLE_NAME = 'gitlab-knative-serving-role' + GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME = 'gitlab-knative-serving-rolebinding' + end +end -- cgit v1.2.1