diff options
author | Grzegorz Bizon <grzegorz@gitlab.com> | 2017-11-06 21:21:27 +0000 |
---|---|---|
committer | Grzegorz Bizon <grzegorz@gitlab.com> | 2017-11-06 21:21:27 +0000 |
commit | c71cf908cd4f289248598d9ea1c144c7b65cbb94 (patch) | |
tree | a032365288f3a73c56bc75336f3c88a649ee30d3 /app/services | |
parent | 4da03e9977ea3fa5bb422ab0f23f0a60406c7073 (diff) | |
parent | a99ad59e655d66fda8af7f2b89aced79b8bc1060 (diff) | |
download | gitlab-ce-c71cf908cd4f289248598d9ea1c144c7b65cbb94.tar.gz |
Merge branch 'refactor-clusters' into 'master'
Refactor Clusters to be consisted from GcpProvider and KubernetesPlatform
See merge request gitlab-org/gitlab-ce!14879
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/ci/create_cluster_service.rb | 15 | ||||
-rw-r--r-- | app/services/ci/fetch_gcp_operation_service.rb | 17 | ||||
-rw-r--r-- | app/services/ci/finalize_cluster_creation_service.rb | 33 | ||||
-rw-r--r-- | app/services/ci/integrate_cluster_service.rb | 26 | ||||
-rw-r--r-- | app/services/ci/provision_cluster_service.rb | 36 | ||||
-rw-r--r-- | app/services/ci/update_cluster_service.rb | 22 | ||||
-rw-r--r-- | app/services/clusters/create_service.rb | 29 | ||||
-rw-r--r-- | app/services/clusters/gcp/fetch_operation_service.rb | 16 | ||||
-rw-r--r-- | app/services/clusters/gcp/finalize_creation_service.rb | 56 | ||||
-rw-r--r-- | app/services/clusters/gcp/provision_service.rb | 47 | ||||
-rw-r--r-- | app/services/clusters/gcp/verify_provision_status_service.rb | 48 | ||||
-rw-r--r-- | app/services/clusters/update_service.rb | 7 |
12 files changed, 203 insertions, 149 deletions
diff --git a/app/services/ci/create_cluster_service.rb b/app/services/ci/create_cluster_service.rb deleted file mode 100644 index f7ee0e468e2..00000000000 --- a/app/services/ci/create_cluster_service.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Ci - class CreateClusterService < 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) - - project.create_cluster(cluster_params).tap do |cluster| - ClusterProvisionWorker.perform_async(cluster.id) if cluster.persisted? - end - end - end -end 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/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/clusters/create_service.rb b/app/services/clusters/create_service.rb new file mode 100644 index 00000000000..1d407739b21 --- /dev/null +++ b/app/services/clusters/create_service.rb @@ -0,0 +1,29 @@ +module Clusters + class CreateService < BaseService + attr_reader :access_token + + def execute(access_token) + @access_token = access_token + + create_cluster.tap do |cluster| + ClusterProvisionWorker.perform_async(cluster.id) if cluster.persisted? + end + end + + private + + def create_cluster + Clusters::Cluster.create(cluster_params) + end + + def cluster_params + return @cluster_params if defined?(@cluster_params) + + params[:provider_gcp_attributes].try do |provider| + provider[:access_token] = access_token + end + + @cluster_params = params.merge(user: current_user, projects: [project]) + end + end +end 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..a4cd3ca5c11 --- /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.gcp_project_id, + provider.zone, + provider.operation_id) + + yield(operation) if block_given? + rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e + 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..cea56f4e849 --- /dev/null +++ b/app/services/clusters/gcp/finalize_creation_service.rb @@ -0,0 +1,56 @@ +module Clusters + module Gcp + class FinalizeCreationService + attr_reader :provider + + def execute(provider) + @provider = provider + + configure_provider + configure_kubernetes + + cluster.save! + rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e + provider.make_errored!("Failed to request to CloudPlatform; #{e.message}") + rescue ActiveRecord::RecordInvalid => e + provider.make_errored!("Failed to configure GKE Cluster: #{e.message}") + end + + private + + def configure_provider + provider.endpoint = gke_cluster.endpoint + provider.status_event = :make_created + end + + def configure_kubernetes + cluster.platform_type = :kubernetes + cluster.build_platform_kubernetes( + api_url: 'https://' + gke_cluster.endpoint, + ca_cert: Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate), + username: gke_cluster.master_auth.username, + password: gke_cluster.master_auth.password, + token: request_kuberenetes_token) + end + + def request_kuberenetes_token + Ci::FetchKubernetesTokenService.new( + 'https://' + gke_cluster.endpoint, + Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate), + gke_cluster.master_auth.username, + gke_cluster.master_auth.password).execute + end + + def gke_cluster + @gke_cluster ||= provider.api_client.projects_zones_clusters_get( + provider.gcp_project_id, + provider.zone, + cluster.name) + end + + def cluster + @cluster ||= provider.cluster + 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..8beea5a8cfb --- /dev/null +++ b/app/services/clusters/gcp/provision_service.rb @@ -0,0 +1,47 @@ +module Clusters + module Gcp + class ProvisionService + attr_reader :provider + + def execute(provider) + @provider = provider + + get_operation_id do |operation_id| + if provider.make_creating(operation_id) + WaitForClusterCreationWorker.perform_in( + Clusters::Gcp::VerifyProvisionStatusService::INITIAL_INTERVAL, + provider.cluster_id) + else + provider.make_errored!("Failed to update provider record; #{provider.errors}") + end + end + end + + private + + def get_operation_id + operation = provider.api_client.projects_zones_clusters_create( + provider.gcp_project_id, + provider.zone, + provider.cluster.name, + provider.num_nodes, + machine_type: provider.machine_type) + + unless operation.status == 'PENDING' || operation.status == 'RUNNING' + return provider.make_errored!("Operation status is unexpected; #{operation.status_message}") + end + + operation_id = provider.api_client.parse_operation_id(operation.self_link) + + unless operation_id + return provider.make_errored!('Can not find operation_id from self_link') + end + + yield(operation_id) + + rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e + provider.make_errored!("Failed to request to CloudPlatform; #{e.message}") + 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..bc33756f27c --- /dev/null +++ b/app/services/clusters/gcp/verify_provision_status_service.rb @@ -0,0 +1,48 @@ +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 'PENDING', '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 elapsed_time_from_creation(operation) < TIMEOUT + WaitForClusterCreationWorker.perform_in(EAGER_INTERVAL, provider.cluster_id) + else + provider.make_errored!("Cluster creation time exceeds timeout; #{TIMEOUT}") + end + end + + def elapsed_time_from_creation(operation) + Time.now.utc - operation.start_time.to_time.utc + end + + def finalize_creation + Clusters::Gcp::FinalizeCreationService.new.execute(provider) + end + + def request_operation(&blk) + Clusters::Gcp::FetchOperationService.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 |