summaryrefslogtreecommitdiff
path: root/spec/services/clusters/aws/provision_service_spec.rb
blob: 5efac29ec1e143d0342034480ced01688794124b (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
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Clusters::Aws::ProvisionService do
  describe '#execute' do
    let(:provider) { create(:cluster_provider_aws) }

    let(:provision_role) { create(:aws_role, user: provider.created_by_user) }
    let(:client) { instance_double(Aws::CloudFormation::Client, create_stack: true) }
    let(:cloudformation_template) { double }
    let(:credentials) do
      instance_double(
        Aws::Credentials,
        access_key_id: 'key',
        secret_access_key: 'secret',
        session_token: 'token'
      )
    end

    let(:parameters) do
      [
        { parameter_key: 'ClusterName', parameter_value: provider.cluster.name },
        { parameter_key: 'ClusterRole', parameter_value: provider.role_arn },
        { parameter_key: 'KubernetesVersion', parameter_value: provider.kubernetes_version },
        { parameter_key: 'ClusterControlPlaneSecurityGroup', parameter_value: provider.security_group_id },
        { parameter_key: 'VpcId', parameter_value: provider.vpc_id },
        { parameter_key: 'Subnets', parameter_value: provider.subnet_ids.join(',') },
        { parameter_key: 'NodeAutoScalingGroupDesiredCapacity', parameter_value: provider.num_nodes.to_s },
        { parameter_key: 'NodeInstanceType', parameter_value: provider.instance_type },
        { parameter_key: 'KeyName', parameter_value: provider.key_name }
      ]
    end

    subject { described_class.new.execute(provider) }

    before do
      allow(Clusters::Aws::FetchCredentialsService).to receive(:new)
        .with(provision_role, provider: provider)
        .and_return(double(execute: credentials))

      allow(provider).to receive(:api_client)
        .and_return(client)

      stub_file_read(Rails.root.join('vendor', 'aws', 'cloudformation', 'eks_cluster.yaml'), content: cloudformation_template)
    end

    it 'updates the provider status to :creating and configures the provider with credentials' do
      subject

      expect(provider).to be_creating
      expect(provider.access_key_id).to eq 'key'
      expect(provider.secret_access_key).to eq 'secret'
      expect(provider.session_token).to eq 'token'
    end

    it 'creates a CloudFormation stack' do
      expect(client).to receive(:create_stack).with(
        stack_name: provider.cluster.name,
        template_body: cloudformation_template,
        parameters: parameters,
        capabilities: ["CAPABILITY_IAM"]
      )

      subject
    end

    it 'schedules a worker to monitor creation status' do
      expect(WaitForClusterCreationWorker).to receive(:perform_in)
        .with(Clusters::Aws::VerifyProvisionStatusService::INITIAL_INTERVAL, provider.cluster_id)

      subject
    end

    describe 'error handling' do
      shared_examples 'provision error' do |message|
        it "sets the status to :errored with an appropriate error message" do
          subject

          expect(provider).to be_errored
          expect(provider.status_reason).to include(message)
        end
      end

      context 'invalid state transition' do
        before do
          allow(provider).to receive(:make_creating).and_return(false)
        end

        include_examples 'provision error', 'Failed to update provider record'
      end

      context 'AWS role is not configured' do
        before do
          allow(Clusters::Aws::FetchCredentialsService).to receive(:new)
            .and_raise(Clusters::Aws::FetchCredentialsService::MissingRoleError)
        end

        include_examples 'provision error', 'Amazon role is not configured'
      end

      context 'AWS credentials are not configured' do
        before do
          allow(Clusters::Aws::FetchCredentialsService).to receive(:new)
            .and_raise(Aws::Errors::MissingCredentialsError)
        end

        include_examples 'provision error', 'Amazon credentials are not configured'
      end

      context 'Authentication failure' do
        before do
          allow(Clusters::Aws::FetchCredentialsService).to receive(:new)
            .and_raise(Aws::STS::Errors::ServiceError.new(double, 'Error message'))
        end

        include_examples 'provision error', 'Amazon authentication failed'
      end

      context 'CloudFormation failure' do
        before do
          allow(client).to receive(:create_stack)
            .and_raise(Aws::CloudFormation::Errors::ServiceError.new(double, 'Error message'))
        end

        include_examples 'provision error', 'Amazon CloudFormation request failed'
      end
    end
  end
end