diff options
Diffstat (limited to 'app/services/clusters/aws/finalize_creation_service.rb')
-rw-r--r-- | app/services/clusters/aws/finalize_creation_service.rb | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/app/services/clusters/aws/finalize_creation_service.rb b/app/services/clusters/aws/finalize_creation_service.rb new file mode 100644 index 00000000000..54f07e1d44c --- /dev/null +++ b/app/services/clusters/aws/finalize_creation_service.rb @@ -0,0 +1,139 @@ +# frozen_string_literal: true + +module Clusters + module Aws + class FinalizeCreationService + include Gitlab::Utils::StrongMemoize + + attr_reader :provider + + delegate :cluster, to: :provider + + def execute(provider) + @provider = provider + + configure_provider + create_gitlab_service_account! + configure_platform_kubernetes + configure_node_authentication! + + cluster.save! + rescue ::Aws::CloudFormation::Errors::ServiceError => e + log_service_error(e.class.name, provider.id, e.message) + provider.make_errored!(s_('ClusterIntegration|Failed to fetch CloudFormation stack: %{message}') % { message: e.message }) + rescue Kubeclient::HttpError => e + log_service_error(e.class.name, provider.id, e.message) + provider.make_errored!(s_('ClusterIntegration|Failed to run Kubeclient: %{message}') % { message: e.message }) + rescue ActiveRecord::RecordInvalid => e + log_service_error(e.class.name, provider.id, e.message) + provider.make_errored!(s_('ClusterIntegration|Failed to configure EKS provider: %{message}') % { message: e.message }) + end + + private + + def create_gitlab_service_account! + Clusters::Kubernetes::CreateOrUpdateServiceAccountService.gitlab_creator( + kube_client, + rbac: true + ).execute + end + + def configure_provider + provider.status_event = :make_created + end + + def configure_platform_kubernetes + cluster.build_platform_kubernetes( + api_url: cluster_endpoint, + ca_cert: cluster_certificate, + token: request_kubernetes_token) + end + + def request_kubernetes_token + Clusters::Kubernetes::FetchKubernetesTokenService.new( + kube_client, + Clusters::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, + Clusters::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE + ).execute + end + + def kube_client + @kube_client ||= build_kube_client!( + cluster_endpoint, + cluster_certificate + ) + end + + def build_kube_client!(api_url, ca_pem) + raise "Incomplete settings" unless api_url + + Gitlab::Kubernetes::KubeClient.new( + api_url, + auth_options: kubeclient_auth_options, + ssl_options: kubeclient_ssl_options(ca_pem), + http_proxy_uri: ENV['http_proxy'] + ) + end + + def kubeclient_auth_options + { bearer_token: Kubeclient::AmazonEksCredentials.token(provider.credentials, cluster.name) } + end + + def kubeclient_ssl_options(ca_pem) + 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 + + def cluster_stack + @cluster_stack ||= provider.api_client.describe_stacks(stack_name: provider.cluster.name).stacks.first + end + + def stack_output_value(key) + cluster_stack.outputs.detect { |output| output.output_key == key }.output_value + end + + def node_instance_role_arn + stack_output_value('NodeInstanceRole') + end + + def cluster_endpoint + strong_memoize(:cluster_endpoint) do + stack_output_value('ClusterEndpoint') + end + end + + def cluster_certificate + strong_memoize(:cluster_certificate) do + Base64.decode64(stack_output_value('ClusterCertificate')) + end + end + + def configure_node_authentication! + kube_client.create_config_map(node_authentication_config) + end + + def node_authentication_config + Gitlab::Kubernetes::ConfigMaps::AwsNodeAuth.new(node_instance_role_arn).generate + end + + def logger + @logger ||= Gitlab::Kubernetes::Logger.build + end + + def log_service_error(exception, provider_id, message) + logger.error( + exception: exception.class.name, + service: self.class.name, + provider_id: provider_id, + message: message + ) + end + end + end +end |