Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2017-10-13 20:21:23 +0300
committerShinya Maeda <shinya@gitlab.com>2017-10-23 08:57:52 +0300
commite1d12ba9b988e61afb9317f3a132d6e2caa93923 (patch)
tree2f68e95ed04d538dd0b4ddae338400b8af53379a /app/services
parentc4cbf115db1ca719b97677057b984672a0900bf8 (diff)
Refactor Clusters to be consisted from GcpProvider and KubernetesPlatform
Diffstat (limited to 'app/services')
-rw-r--r--app/services/ci/fetch_gcp_operation_service.rb17
-rw-r--r--app/services/ci/fetch_kubernetes_token_service.rb72
-rw-r--r--app/services/ci/finalize_cluster_creation_service.rb33
-rw-r--r--app/services/ci/integrate_cluster_service.rb26
-rw-r--r--app/services/ci/provision_cluster_service.rb36
-rw-r--r--app/services/ci/update_cluster_service.rb22
-rw-r--r--app/services/clusters/create_service.rb (renamed from app/services/ci/create_cluster_service.rb)7
-rw-r--r--app/services/clusters/gcp/fetch_operation_service.rb16
-rw-r--r--app/services/clusters/gcp/finalize_creation_service.rb66
-rw-r--r--app/services/clusters/gcp/provision_service.rb49
-rw-r--r--app/services/clusters/gcp/verify_provision_status_service.rb44
-rw-r--r--app/services/clusters/update_service.rb7
12 files changed, 185 insertions, 210 deletions
diff --git a/app/services/ci/fetch_gcp_operation_service.rb b/app/services/ci/fetch_gcp_operation_service.rb
deleted file mode 100644
index 0b68e4d6ea9..00000000000
--- a/app/services/ci/fetch_gcp_operation_service.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module Ci
- class FetchGcpOperationService
- def execute(cluster)
- api_client =
- GoogleApi::CloudPlatform::Client.new(cluster.gcp_token, nil)
-
- operation = api_client.projects_zones_operations(
- cluster.gcp_project_id,
- cluster.gcp_cluster_zone,
- cluster.gcp_operation_id)
-
- yield(operation) if block_given?
- rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
- return cluster.make_errored!("Failed to request to CloudPlatform; #{e.message}")
- end
- end
-end
diff --git a/app/services/ci/fetch_kubernetes_token_service.rb b/app/services/ci/fetch_kubernetes_token_service.rb
deleted file mode 100644
index 44da87cb00c..00000000000
--- a/app/services/ci/fetch_kubernetes_token_service.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-##
-# TODO:
-# Almost components in this class were copied from app/models/project_services/kubernetes_service.rb
-# We should dry up those classes not to repeat the same code.
-# Maybe we should have a special facility (e.g. lib/kubernetes_api) to maintain all Kubernetes API caller.
-module Ci
- class FetchKubernetesTokenService
- attr_reader :api_url, :ca_pem, :username, :password
-
- def initialize(api_url, ca_pem, username, password)
- @api_url = api_url
- @ca_pem = ca_pem
- @username = username
- @password = password
- end
-
- def execute
- read_secrets.each do |secret|
- name = secret.dig('metadata', 'name')
- if /default-token/ =~ name
- token_base64 = secret.dig('data', 'token')
- return Base64.decode64(token_base64) if token_base64
- end
- end
-
- nil
- end
-
- private
-
- def read_secrets
- kubeclient = build_kubeclient!
-
- kubeclient.get_secrets.as_json
- rescue KubeException => err
- raise err unless err.error_code == 404
- []
- end
-
- def build_kubeclient!(api_path: 'api', api_version: 'v1')
- raise "Incomplete settings" unless api_url && username && password
-
- ::Kubeclient::Client.new(
- join_api_url(api_path),
- api_version,
- auth_options: { username: username, password: password },
- ssl_options: kubeclient_ssl_options,
- http_proxy_uri: ENV['http_proxy']
- )
- end
-
- def join_api_url(api_path)
- url = URI.parse(api_url)
- prefix = url.path.sub(%r{/+\z}, '')
-
- url.path = [prefix, api_path].join("/")
-
- url.to_s
- end
-
- def kubeclient_ssl_options
- opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
-
- if ca_pem.present?
- opts[:cert_store] = OpenSSL::X509::Store.new
- opts[:cert_store].add_cert(OpenSSL::X509::Certificate.new(ca_pem))
- end
-
- opts
- end
- end
-end
diff --git a/app/services/ci/finalize_cluster_creation_service.rb b/app/services/ci/finalize_cluster_creation_service.rb
deleted file mode 100644
index 347875c5697..00000000000
--- a/app/services/ci/finalize_cluster_creation_service.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module Ci
- class FinalizeClusterCreationService
- def execute(cluster)
- api_client =
- GoogleApi::CloudPlatform::Client.new(cluster.gcp_token, nil)
-
- begin
- gke_cluster = api_client.projects_zones_clusters_get(
- cluster.gcp_project_id,
- cluster.gcp_cluster_zone,
- cluster.gcp_cluster_name)
- rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
- return cluster.make_errored!("Failed to request to CloudPlatform; #{e.message}")
- end
-
- endpoint = gke_cluster.endpoint
- api_url = 'https://' + endpoint
- ca_cert = Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate)
- username = gke_cluster.master_auth.username
- password = gke_cluster.master_auth.password
-
- kubernetes_token = Ci::FetchKubernetesTokenService.new(
- api_url, ca_cert, username, password).execute
-
- unless kubernetes_token
- return cluster.make_errored!('Failed to get a default token of kubernetes')
- end
-
- Ci::IntegrateClusterService.new.execute(
- cluster, endpoint, ca_cert, kubernetes_token, username, password)
- end
- end
-end
diff --git a/app/services/ci/integrate_cluster_service.rb b/app/services/ci/integrate_cluster_service.rb
deleted file mode 100644
index d123ce8d26b..00000000000
--- a/app/services/ci/integrate_cluster_service.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-module Ci
- class IntegrateClusterService
- def execute(cluster, endpoint, ca_cert, token, username, password)
- Gcp::Cluster.transaction do
- cluster.update!(
- enabled: true,
- endpoint: endpoint,
- ca_cert: ca_cert,
- kubernetes_token: token,
- username: username,
- password: password,
- service: cluster.project.find_or_initialize_service('kubernetes'),
- status_event: :make_created)
-
- cluster.service.update!(
- active: true,
- api_url: cluster.api_url,
- ca_pem: ca_cert,
- namespace: cluster.project_namespace,
- token: token)
- end
- rescue ActiveRecord::RecordInvalid => e
- cluster.make_errored!("Failed to integrate cluster into kubernetes_service: #{e.message}")
- end
- end
-end
diff --git a/app/services/ci/provision_cluster_service.rb b/app/services/ci/provision_cluster_service.rb
deleted file mode 100644
index 52d80b01813..00000000000
--- a/app/services/ci/provision_cluster_service.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-module Ci
- class ProvisionClusterService
- def execute(cluster)
- api_client =
- GoogleApi::CloudPlatform::Client.new(cluster.gcp_token, nil)
-
- begin
- operation = api_client.projects_zones_clusters_create(
- cluster.gcp_project_id,
- cluster.gcp_cluster_zone,
- cluster.gcp_cluster_name,
- cluster.gcp_cluster_size,
- machine_type: cluster.gcp_machine_type)
- rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
- return cluster.make_errored!("Failed to request to CloudPlatform; #{e.message}")
- end
-
- unless operation.status == 'RUNNING' || operation.status == 'PENDING'
- return cluster.make_errored!("Operation status is unexpected; #{operation.status_message}")
- end
-
- cluster.gcp_operation_id = api_client.parse_operation_id(operation.self_link)
-
- unless cluster.gcp_operation_id
- return cluster.make_errored!('Can not find operation_id from self_link')
- end
-
- if cluster.make_creating
- WaitForClusterCreationWorker.perform_in(
- WaitForClusterCreationWorker::INITIAL_INTERVAL, cluster.id)
- else
- return cluster.make_errored!("Failed to update cluster record; #{cluster.errors}")
- end
- end
- end
-end
diff --git a/app/services/ci/update_cluster_service.rb b/app/services/ci/update_cluster_service.rb
deleted file mode 100644
index 70d88fca660..00000000000
--- a/app/services/ci/update_cluster_service.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module Ci
- class UpdateClusterService < BaseService
- def execute(cluster)
- Gcp::Cluster.transaction do
- cluster.update!(params)
-
- if params['enabled'] == 'true'
- cluster.service.update!(
- active: true,
- api_url: cluster.api_url,
- ca_pem: cluster.ca_cert,
- namespace: cluster.project_namespace,
- token: cluster.kubernetes_token)
- else
- cluster.service.update!(active: false)
- end
- end
- rescue ActiveRecord::RecordInvalid => e
- cluster.errors.add(:base, e.message)
- end
- end
-end
diff --git a/app/services/ci/create_cluster_service.rb b/app/services/clusters/create_service.rb
index f7ee0e468e2..5429bc21256 100644
--- a/app/services/ci/create_cluster_service.rb
+++ b/app/services/clusters/create_service.rb
@@ -1,11 +1,10 @@
-module Ci
- class CreateClusterService < BaseService
+module Clusters
+ class CreateService < BaseService
def execute(access_token)
params['gcp_machine_type'] ||= GoogleApi::CloudPlatform::Client::DEFAULT_MACHINE_TYPE
cluster_params =
- params.merge(user: current_user,
- gcp_token: access_token)
+ params.merge(user: current_user)
project.create_cluster(cluster_params).tap do |cluster|
ClusterProvisionWorker.perform_async(cluster.id) if cluster.persisted?
diff --git a/app/services/clusters/gcp/fetch_operation_service.rb b/app/services/clusters/gcp/fetch_operation_service.rb
new file mode 100644
index 00000000000..013225efac4
--- /dev/null
+++ b/app/services/clusters/gcp/fetch_operation_service.rb
@@ -0,0 +1,16 @@
+module Clusters
+ module Gcp
+ class FetchOperationService
+ def execute(provider)
+ operation = provider.api_client.projects_zones_operations(
+ provider.project_id,
+ provider.cluster_zone,
+ provider.operation_id)
+
+ yield(operation) if block_given?
+ rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
+ return provider.make_errored!("Failed to request to CloudPlatform; #{e.message}")
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb
new file mode 100644
index 00000000000..b536285b368
--- /dev/null
+++ b/app/services/clusters/gcp/finalize_creation_service.rb
@@ -0,0 +1,66 @@
+module Clusters
+ module Gcp
+ class FinalizeCreationService
+ attr_reader :provider
+
+ def execute(provider)
+ @provider = provider
+
+ configure_provider
+ configure_kubernetes_platform
+ request_kuberenetes_platform_token
+
+ ActiveRecord::Base.transaction do
+ kubernetes_platform.update!
+ provider.make_created!
+ end
+ rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
+ return cluster.make_errored!("Failed to request to CloudPlatform; #{e.message}")
+ rescue ActiveRecord::RecordInvalid => e
+ cluster.make_errored!("Failed to configure GKE Cluster: #{e.message}")
+ end
+
+ private
+
+ def configure_provider
+ provider.endpoint = gke_cluster.endpoint
+ end
+
+ def configure_kubernetes_platform
+ kubernetes_platform = cluster.kubernetes_platform
+ kubernetes_platform.api_url = 'https://' + endpoint
+ kubernetes_platform.ca_cert = Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate)
+ kubernetes_platform.username = gke_cluster.master_auth.username
+ kubernetes_platform.password = gke_cluster.master_auth.password
+ end
+
+ def request_kuberenetes_platform_token
+ kubernetes_platform.read_secrets.each do |secret|
+ name = secret.dig('metadata', 'name')
+ if /default-token/ =~ name
+ token_base64 = secret.dig('data', 'token')
+ if token_base64
+ kubernetes_platform.token = Base64.decode64(token_base64)
+ break
+ end
+ end
+ end
+ end
+
+ def gke_cluster
+ @gke_cluster ||= provider.api_client.projects_zones_clusters_get(
+ provider.gcp_project_id,
+ provider.gcp_cluster_zone,
+ provider.gcp_cluster_name)
+ end
+
+ def cluster
+ provider.cluster
+ end
+
+ def kubernetes_platform
+ cluster.kubernetes_platform
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/gcp/provision_service.rb b/app/services/clusters/gcp/provision_service.rb
new file mode 100644
index 00000000000..269705000ac
--- /dev/null
+++ b/app/services/clusters/gcp/provision_service.rb
@@ -0,0 +1,49 @@
+module Clusters
+ module Gcp
+ class ProvisionService
+ attr_reader :provider
+
+ def execute(provider)
+ @provider = provider
+
+ unless operation.status == 'RUNNING' || operation.status == 'PENDING'
+ return provider.make_errored!("Operation status is unexpected; #{operation.status_message}")
+ end
+
+ provider.operation_id = operation_id
+
+ unless provider.operation_id
+ return provider.make_errored!('Can not find operation_id from self_link')
+ end
+
+ if provider.make_creating
+ WaitForClusterCreationWorker.perform_in(
+ WaitForClusterCreationWorker::INITIAL_INTERVAL, provider.id)
+ else
+ return provider.make_errored!("Failed to update provider record; #{provider.errors}")
+ end
+ rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
+ return provider.make_errored!("Failed to request to CloudPlatform; #{e.message}")
+ end
+
+ private
+
+ def operation_id
+ api_client.parse_operation_id(operation.self_link)
+ end
+
+ def operation
+ @operation ||= api_client.projects_zones_providers_create(
+ provider.project_id,
+ provider.provider_zone,
+ provider.provider_name,
+ provider.provider_size,
+ machine_type: provider.machine_type)
+ end
+
+ def api_client
+ provider.api_client
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/gcp/verify_provision_status_service.rb b/app/services/clusters/gcp/verify_provision_status_service.rb
new file mode 100644
index 00000000000..466ea986516
--- /dev/null
+++ b/app/services/clusters/gcp/verify_provision_status_service.rb
@@ -0,0 +1,44 @@
+module Clusters
+ module Gcp
+ class VerifyProvisionStatusService
+ attr_reader :provider
+
+ INITIAL_INTERVAL = 2.minutes
+ EAGER_INTERVAL = 10.seconds
+ TIMEOUT = 20.minutes
+
+ def execute(provider)
+ @provider = provider
+
+ request_operation do |operation|
+ case operation.status
+ when 'RUNNING'
+ continue_creation(operation)
+ when 'DONE'
+ finalize_creation
+ else
+ return provider.make_errored!("Unexpected operation status; #{operation.status} #{operation.status_message}")
+ end
+ end
+ end
+
+ private
+
+ def continue_creation(operation)
+ if TIMEOUT < Time.now.utc - operation.start_time.to_time.utc
+ return provider.make_errored!("Cluster creation time exceeds timeout; #{TIMEOUT}")
+ end
+
+ WaitForClusterCreationWorker.perform_in(EAGER_INTERVAL, provider.cluster_id)
+ end
+
+ def finalize_creation
+ Clusters::Gcp::FinalizeCreationService.new.execute(provider)
+ end
+
+ def request_operation(&blk)
+ Clusters::FetchGcpOperationService.new.execute(provider, &blk)
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/update_service.rb b/app/services/clusters/update_service.rb
new file mode 100644
index 00000000000..989218e32a2
--- /dev/null
+++ b/app/services/clusters/update_service.rb
@@ -0,0 +1,7 @@
+module Clusters
+ class UpdateService < BaseService
+ def execute(cluster)
+ cluster.update(params)
+ end
+ end
+end