api_spec.rb 9.18 KB
Newer Older
Alessio Caiazza's avatar
Alessio Caiazza committed
1 2
require 'spec_helper'

3
describe Gitlab::Kubernetes::Helm::Api do
Alessio Caiazza's avatar
Alessio Caiazza committed
4 5
  let(:client) { double('kubernetes client') }
  let(:helm) { described_class.new(client) }
6 7
  let(:gitlab_namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
  let(:namespace) { Gitlab::Kubernetes::Namespace.new(gitlab_namespace, client) }
8 9 10 11 12 13 14 15 16 17 18 19
  let(:application_name) { 'app-name' }
  let(:rbac) { false }
  let(:files) { {} }

  let(:command) do
    Gitlab::Kubernetes::Helm::InstallCommand.new(
      name: application_name,
      chart: 'chart-name',
      rbac: rbac,
      files: files
    )
  end
20

Alessio Caiazza's avatar
Alessio Caiazza committed
21 22 23
  subject { helm }

  before do
24
    allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client).and_return(namespace)
25
    allow(client).to receive(:create_config_map)
Alessio Caiazza's avatar
Alessio Caiazza committed
26 27 28 29
  end

  describe '#initialize' do
    it 'creates a namespace object' do
30
      expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client)
Alessio Caiazza's avatar
Alessio Caiazza committed
31 32 33 34 35

      subject
    end
  end

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
  describe '#uninstall' do
    before do
      allow(client).to receive(:create_pod).and_return(nil)
      allow(client).to receive(:delete_pod).and_return(nil)
      allow(namespace).to receive(:ensure_exists!).once
    end

    it 'ensures the namespace exists before creating the POD' do
      expect(namespace).to receive(:ensure_exists!).once.ordered
      expect(client).to receive(:create_pod).once.ordered

      subject.uninstall(command)
    end

    it 'removes an existing pod before installing' do
      expect(client).to receive(:delete_pod).with('install-app-name', 'gitlab-managed-apps').once.ordered
      expect(client).to receive(:create_pod).once.ordered

      subject.uninstall(command)
    end
  end

Alessio Caiazza's avatar
Alessio Caiazza committed
58 59 60
  describe '#install' do
    before do
      allow(client).to receive(:create_pod).and_return(nil)
61
      allow(client).to receive(:get_config_map).and_return(nil)
62
      allow(client).to receive(:create_config_map).and_return(nil)
63 64
      allow(client).to receive(:create_service_account).and_return(nil)
      allow(client).to receive(:create_cluster_role_binding).and_return(nil)
65
      allow(client).to receive(:delete_pod).and_return(nil)
Alessio Caiazza's avatar
Alessio Caiazza committed
66 67 68 69 70 71 72 73 74
      allow(namespace).to receive(:ensure_exists!).once
    end

    it 'ensures the namespace exists before creating the POD' do
      expect(namespace).to receive(:ensure_exists!).once.ordered
      expect(client).to receive(:create_pod).once.ordered

      subject.install(command)
    end
75

76 77 78 79 80 81 82
    it 'removes an existing pod before installing' do
      expect(client).to receive(:delete_pod).with('install-app-name', 'gitlab-managed-apps').once.ordered
      expect(client).to receive(:create_pod).once.ordered

      subject.install(command)
    end

83
    context 'with a ConfigMap' do
84
      let(:resource) { Gitlab::Kubernetes::ConfigMap.new(application_name, files).generate }
85 86 87 88 89 90

      it 'creates a ConfigMap on kubeclient' do
        expect(client).to receive(:create_config_map).with(resource).once

        subject.install(command)
      end
91 92 93 94 95 96 97 98 99 100 101 102

      context 'config map already exists' do
        before do
          expect(client).to receive(:get_config_map).with("values-content-configuration-#{application_name}", gitlab_namespace).and_return(resource)
        end

        it 'updates the config map' do
          expect(client).to receive(:update_config_map).with(resource).once

          subject.install(command)
        end
      end
103
    end
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 133

    context 'without a service account' do
      it 'does not create a service account on kubeclient' do
        expect(client).not_to receive(:create_service_account)
        expect(client).not_to receive(:create_cluster_role_binding)

        subject.install(command)
      end
    end

    context 'with a service account' do
      let(:command) { Gitlab::Kubernetes::Helm::InitCommand.new(name: application_name, files: files, rbac: rbac) }

      context 'rbac-enabled cluster' do
        let(:rbac) { true }

        let(:service_account_resource) do
          Kubeclient::Resource.new(metadata: { name: 'tiller', namespace: 'gitlab-managed-apps' })
        end

        let(:cluster_role_binding_resource) do
          Kubeclient::Resource.new(
            metadata: { name: 'tiller-admin' },
            roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'ClusterRole', name: 'cluster-admin' },
            subjects: [{ kind: 'ServiceAccount', name: 'tiller', namespace: 'gitlab-managed-apps' }]
          )
        end

        context 'service account and cluster role binding does not exist' do
          before do
134 135
            expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil))
            expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil))
136 137 138 139 140 141 142 143 144 145 146 147
          end

          it 'creates a service account, followed the cluster role binding on kubeclient' do
            expect(client).to receive(:create_service_account).with(service_account_resource).once.ordered
            expect(client).to receive(:create_cluster_role_binding).with(cluster_role_binding_resource).once.ordered

            subject.install(command)
          end
        end

        context 'service account already exists' do
          before do
148 149
            expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_return(service_account_resource)
            expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil))
150 151 152 153 154 155 156 157 158 159 160 161
          end

          it 'updates the service account, followed by creating the cluster role binding' do
            expect(client).to receive(:update_service_account).with(service_account_resource).once.ordered
            expect(client).to receive(:create_cluster_role_binding).with(cluster_role_binding_resource).once.ordered

            subject.install(command)
          end
        end

        context 'service account and cluster role binding already exists' do
          before do
162 163
            expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_return(service_account_resource)
            expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_return(cluster_role_binding_resource)
164 165 166 167 168 169 170 171 172 173 174 175
          end

          it 'updates the service account, followed by creating the cluster role binding' do
            expect(client).to receive(:update_service_account).with(service_account_resource).once.ordered
            expect(client).to receive(:update_cluster_role_binding).with(cluster_role_binding_resource).once.ordered

            subject.install(command)
          end
        end

        context 'a non-404 error is thrown' do
          before do
176
            expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil))
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
          end

          it 'raises an error' do
            expect { subject.install(command) }.to raise_error(Kubeclient::HttpError)
          end
        end
      end

      context 'legacy abac cluster' do
        it 'does not create a service account on kubeclient' do
          expect(client).not_to receive(:create_service_account)
          expect(client).not_to receive(:create_cluster_role_binding)

          subject.install(command)
        end
      end
    end
Alessio Caiazza's avatar
Alessio Caiazza committed
194 195
  end

196
  describe '#status' do
Alessio Caiazza's avatar
Alessio Caiazza committed
197 198 199 200
    let(:phase) { Gitlab::Kubernetes::Pod::RUNNING }
    let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation

    it 'fetches POD phase from kubernetes cluster' do
201
      expect(client).to receive(:get_pod).with(command.pod_name, gitlab_namespace).once.and_return(pod)
Alessio Caiazza's avatar
Alessio Caiazza committed
202

203
      expect(subject.status(command.pod_name)).to eq(phase)
Alessio Caiazza's avatar
Alessio Caiazza committed
204 205 206
    end
  end

207
  describe '#log' do
Alessio Caiazza's avatar
Alessio Caiazza committed
208 209 210 211
    let(:log) { 'some output' }
    let(:response) { RestClient::Response.new(log) }

    it 'fetches POD phase from kubernetes cluster' do
212
      expect(client).to receive(:get_pod_log).with(command.pod_name, gitlab_namespace).once.and_return(response)
Alessio Caiazza's avatar
Alessio Caiazza committed
213

214
      expect(subject.log(command.pod_name)).to eq(log)
Alessio Caiazza's avatar
Alessio Caiazza committed
215 216 217
    end
  end

218
  describe '#delete_pod!' do
Alessio Caiazza's avatar
Alessio Caiazza committed
219
    it 'deletes the POD from kubernetes cluster' do
220
      expect(client).to receive(:delete_pod).with('install-app-name', 'gitlab-managed-apps').once
Alessio Caiazza's avatar
Alessio Caiazza committed
221

222 223 224 225 226 227 228 229 230 231
      subject.delete_pod!('install-app-name')
    end

    context 'when the resource being deleted does not exist' do
      it 'catches the error' do
        expect(client).to receive(:delete_pod).with('install-app-name', 'gitlab-managed-apps')
          .and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil))

        subject.delete_pod!('install-app-name')
      end
Alessio Caiazza's avatar
Alessio Caiazza committed
232 233
    end
  end
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

  describe '#get_config_map' do
    before do
      allow(namespace).to receive(:ensure_exists!).once
      allow(client).to receive(:get_config_map).and_return(nil)
    end

    it 'ensures the namespace exists before retrieving the config map' do
      expect(namespace).to receive(:ensure_exists!).once

      subject.get_config_map('example-config-map-name')
    end

    it 'gets the config map on kubeclient' do
      expect(client).to receive(:get_config_map)
        .with('example-config-map-name', namespace.name)
        .once

      subject.get_config_map('example-config-map-name')
    end
  end
Alessio Caiazza's avatar
Alessio Caiazza committed
255
end