summaryrefslogtreecommitdiff
path: root/lib/gitlab/kubernetes/kube_client.rb
blob: 4527ca2accbf9e5b7d284d0505abe76f4ecbd11a (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
# frozen_string_literal: true

require 'uri'

module Gitlab
  module Kubernetes
    # Wrapper around Kubeclient::Client to dispatch
    # the right message to the client that can respond to the message.
    # We must have a kubeclient for each ApiGroup as there is no
    # other way to use the Kubeclient gem.
    #
    # See https://github.com/abonas/kubeclient/issues/348.
    class KubeClient
      include Gitlab::Utils::StrongMemoize

      SUPPORTED_API_GROUPS = [
        'api',
        'apis/rbac.authorization.k8s.io',
        'apis/extensions'
      ].freeze

      LATEST_EXTENSIONS_VERSION = 'v1beta1'

      # Core API methods delegates to the core api group client
      delegate :get_pods,
        :get_secrets,
        :get_config_map,
        :get_namespace,
        :get_pod,
        :get_secret,
        :get_service,
        :get_service_account,
        :delete_pod,
        :create_config_map,
        :create_namespace,
        :create_pod,
        :create_secret,
        :create_service_account,
        :update_config_map,
        :update_service_account,
        to: :core_client

      # RBAC methods delegates to the apis/rbac.authorization.k8s.io api
      # group client
      delegate :create_cluster_role_binding,
        :get_cluster_role_binding,
        :update_cluster_role_binding,
        to: :rbac_client

      # Deployments resource is currently on the apis/extensions api group
      delegate :get_deployments,
        to: :extensions_client

      # non-entity methods that can only work with the core client
      # as it uses the pods/log resource
      delegate :get_pod_log,
        :watch_pod_log,
        to: :core_client

      attr_reader :api_prefix, :kubeclient_options, :default_api_version

      def initialize(api_prefix, default_api_version = 'v1', **kubeclient_options)
        @api_prefix = api_prefix
        @kubeclient_options = kubeclient_options
        @default_api_version = default_api_version
      end

      def core_client(api_version: default_api_version)
        core_clients[api_version]
      end

      def rbac_client(api_version: default_api_version)
        rbac_clients[api_version]
      end

      def extensions_client(api_version: LATEST_EXTENSIONS_VERSION)
        extensions_clients[api_version]
      end

      private

      def core_clients
        strong_memoize(:core_clients) do
          Hash.new do |hash, api_version|
            hash[api_version] = build_kubeclient('api', api_version)
          end
        end
      end

      def rbac_clients
        strong_memoize(:rbac_clients) do
          Hash.new do |hash, api_version|
            hash[api_version] = build_kubeclient('apis/rbac.authorization.k8s.io', api_version)
          end
        end
      end

      def extensions_clients
        strong_memoize(:extensions_clients) do
          Hash.new do |hash, api_version|
            hash[api_version] = build_kubeclient('apis/extensions', api_version)
          end
        end
      end

      def build_kubeclient(api_group, api_version)
        raise ArgumentError, "Unknown api group #{api_group}" unless SUPPORTED_API_GROUPS.include?(api_group)

        ::Kubeclient::Client.new(
          join_api_url(api_prefix, api_group),
          api_version,
          **kubeclient_options
        )
      end

      def join_api_url(api_prefix, api_path)
        url = URI.parse(api_prefix)
        prefix = url.path.sub(%r{/+\z}, '')

        url.path = [prefix, api_path].join("/")

        url.to_s
      end
    end
  end
end