summaryrefslogtreecommitdiff
path: root/app/services/clusters/gcp/finalize_creation_service.rb
blob: 0aff1bcc8b90fc4c9e99af05c1161893453448ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# frozen_string_literal: true

module Clusters
  module Gcp
    class FinalizeCreationService
      attr_reader :provider

      def execute(provider)
        @provider = provider

        configure_provider
        create_gitlab_service_account!
        configure_kubernetes
        configure_pre_installed_knative if provider.knative_pre_installed?
        cluster.save!
      rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
        log_service_error(e.class.name, provider.id, e.message)
        provider.make_errored!(s_('ClusterIntegration|Failed to request to Google Cloud Platform: %{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 Google Kubernetes Engine Cluster: %{message}') % { message: e.message })
      end

      private

      def create_gitlab_service_account!
        Clusters::Kubernetes::CreateOrUpdateServiceAccountService.gitlab_creator(
          kube_client,
          rbac: create_rbac_cluster?
        ).execute
      end

      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,
          authorization_type: authorization_type,
          token: request_kubernetes_token)
      end

      def configure_pre_installed_knative
        knative = cluster.build_application_knative(
          hostname: 'example.com'
        )
        knative.make_pre_installed!
      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 authorization_type
        create_rbac_cluster? ? 'rbac' : 'abac'
      end

      def create_rbac_cluster?
        !provider.legacy_abac?
      end

      def kube_client
        @kube_client ||= build_kube_client!(
          'https://' + gke_cluster.endpoint,
          Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate),
          gke_cluster.master_auth.username,
          gke_cluster.master_auth.password
        )
      end

      def build_kube_client!(api_url, ca_pem, username, password)
        raise "Incomplete settings" unless api_url && username && password

        Gitlab::Kubernetes::KubeClient.new(
          api_url,
          auth_options: { username: username, password: password },
          ssl_options: kubeclient_ssl_options(ca_pem),
          http_proxy_uri: ENV['http_proxy']
        )
      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 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

      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