summaryrefslogtreecommitdiff
path: root/app/models/clusters/applications/elastic_stack.rb
blob: 58ac0c1f1886375aa050f2da82c8c47c41a67c85 (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
132
# frozen_string_literal: true

module Clusters
  module Applications
    class ElasticStack < ApplicationRecord
      VERSION = '3.0.0'

      ELASTICSEARCH_PORT = 9200

      self.table_name = 'clusters_applications_elastic_stacks'

      include ::Clusters::Concerns::ApplicationCore
      include ::Clusters::Concerns::ApplicationStatus
      include ::Clusters::Concerns::ApplicationVersion
      include ::Clusters::Concerns::ApplicationData
      include ::Gitlab::Utils::StrongMemoize

      default_value_for :version, VERSION

      def chart
        'elastic-stack/elastic-stack'
      end

      def repository
        'https://charts.gitlab.io'
      end

      def install_command
        Gitlab::Kubernetes::Helm::InstallCommand.new(
          name: 'elastic-stack',
          version: VERSION,
          rbac: cluster.platform_kubernetes_rbac?,
          chart: chart,
          repository: repository,
          files: files,
          preinstall: migrate_to_3_script,
          postinstall: post_install_script,
          local_tiller_enabled: cluster.local_tiller_enabled?
        )
      end

      def uninstall_command
        Gitlab::Kubernetes::Helm::DeleteCommand.new(
          name: 'elastic-stack',
          rbac: cluster.platform_kubernetes_rbac?,
          files: files,
          postdelete: post_delete_script,
          local_tiller_enabled: cluster.local_tiller_enabled?
        )
      end

      def files
        super.merge('wait-for-elasticsearch.sh': File.read("#{Rails.root}/vendor/elastic_stack/wait-for-elasticsearch.sh"))
      end

      def elasticsearch_client(timeout: nil)
        strong_memoize(:elasticsearch_client) do
          next unless kube_client

          proxy_url = kube_client.proxy_url('service', service_name, ::Clusters::Applications::ElasticStack::ELASTICSEARCH_PORT, Gitlab::Kubernetes::Helm::NAMESPACE)

          Elasticsearch::Client.new(url: proxy_url) do |faraday|
            # ensures headers containing auth data are appended to original client options
            faraday.headers.merge!(kube_client.headers)
            # ensure TLS certs are properly verified
            faraday.ssl[:verify] = kube_client.ssl_options[:verify_ssl]
            faraday.ssl[:cert_store] = kube_client.ssl_options[:cert_store]
            faraday.options.timeout = timeout unless timeout.nil?
          end

        rescue Kubeclient::HttpError => error
          # If users have mistakenly set parameters or removed the depended clusters,
          # `proxy_url` could raise an exception because gitlab can not communicate with the cluster.
          # We check for a nil client in downstream use and behaviour is equivalent to an empty state
          log_exception(error, :failed_to_create_elasticsearch_client)

          nil
        end
      end

      def chart_above_v2?
        Gem::Version.new(version) >= Gem::Version.new('2.0.0')
      end

      def chart_above_v3?
        Gem::Version.new(version) >= Gem::Version.new('3.0.0')
      end

      private

      def service_name
        chart_above_v3? ? 'elastic-stack-elasticsearch-master' : 'elastic-stack-elasticsearch-client'
      end

      def pvc_selector
        chart_above_v3? ? "app=elastic-stack-elasticsearch-master" : "release=elastic-stack"
      end

      def post_install_script
        [
          "timeout -t60 sh /data/helm/elastic-stack/config/wait-for-elasticsearch.sh http://elastic-stack-elasticsearch-master:9200"
        ]
      end

      def post_delete_script
        [
          Gitlab::Kubernetes::KubectlCmd.delete("pvc", "--selector", pvc_selector, "--namespace", Gitlab::Kubernetes::Helm::NAMESPACE)
        ]
      end

      def kube_client
        cluster&.kubeclient&.core_client
      end

      def migrate_to_3_script
        return [] if !updating? || chart_above_v3?

        # Chart version 3.0.0 moves to our own chart at https://gitlab.com/gitlab-org/charts/elastic-stack
        # and is not compatible with pre-existing resources. We first remove them.
        [
          Gitlab::Kubernetes::Helm::DeleteCommand.new(
            name: 'elastic-stack',
            rbac: cluster.platform_kubernetes_rbac?,
            files: files,
            local_tiller_enabled: cluster.local_tiller_enabled?
          ).delete_command,
          Gitlab::Kubernetes::KubectlCmd.delete("pvc", "--selector", "release=elastic-stack", "--namespace", Gitlab::Kubernetes::Helm::NAMESPACE)
        ]
      end
    end
  end
end