1# frozen_string_literal: true
2
3module Clusters
4  module Aws
5    class ProvisionService
6      attr_reader :provider
7
8      def execute(provider)
9        @provider = provider
10
11        configure_provider_credentials
12        provision_cluster
13
14        if provider.make_creating
15          WaitForClusterCreationWorker.perform_in(
16            Clusters::Aws::VerifyProvisionStatusService::INITIAL_INTERVAL,
17            provider.cluster_id
18          )
19        else
20          provider.make_errored!("Failed to update provider record; #{provider.errors.full_messages}")
21        end
22      rescue Clusters::Aws::FetchCredentialsService::MissingRoleError
23        provider.make_errored!('Amazon role is not configured')
24      rescue ::Aws::Errors::MissingCredentialsError
25        provider.make_errored!('Amazon credentials are not configured')
26      rescue ::Aws::STS::Errors::ServiceError => e
27        provider.make_errored!("Amazon authentication failed; #{e.message}")
28      rescue ::Aws::CloudFormation::Errors::ServiceError => e
29        provider.make_errored!("Amazon CloudFormation request failed; #{e.message}")
30      end
31
32      private
33
34      def provision_role
35        provider.created_by_user&.aws_role
36      end
37
38      def credentials
39        @credentials ||= Clusters::Aws::FetchCredentialsService.new(
40          provision_role,
41          provider: provider
42        ).execute
43      end
44
45      def configure_provider_credentials
46        provider.update!(
47          access_key_id: credentials.access_key_id,
48          secret_access_key: credentials.secret_access_key,
49          session_token: credentials.session_token
50        )
51      end
52
53      def provision_cluster
54        provider.api_client.create_stack(
55          stack_name: provider.cluster.name,
56          template_body: stack_template,
57          parameters: parameters,
58          capabilities: ["CAPABILITY_IAM"]
59        )
60      end
61
62      def parameters
63        [
64          parameter('ClusterName', provider.cluster.name),
65          parameter('ClusterRole', provider.role_arn),
66          parameter('KubernetesVersion', provider.kubernetes_version),
67          parameter('ClusterControlPlaneSecurityGroup', provider.security_group_id),
68          parameter('VpcId', provider.vpc_id),
69          parameter('Subnets', provider.subnet_ids.join(',')),
70          parameter('NodeAutoScalingGroupDesiredCapacity', provider.num_nodes.to_s),
71          parameter('NodeInstanceType', provider.instance_type),
72          parameter('KeyName', provider.key_name)
73        ]
74      end
75
76      def parameter(key, value)
77        { parameter_key: key, parameter_value: value }
78      end
79
80      def stack_template
81        File.read(Rails.root.join('vendor', 'aws', 'cloudformation', 'eks_cluster.yaml'))
82      end
83    end
84  end
85end
86