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
133
134
|
# frozen_string_literal: true
module Clusters
module Aws
class ProxyService
DEFAULT_REGION = 'us-east-1'
BadRequest = Class.new(StandardError)
Response = Struct.new(:status, :body)
def initialize(role, params:)
@role = role
@params = params
end
def execute
api_response = request_from_api!
Response.new(:ok, api_response.to_hash)
rescue *service_errors
Response.new(:bad_request, {})
end
private
attr_reader :role, :params
def request_from_api!
case requested_resource
when 'key_pairs'
ec2_client.describe_key_pairs
when 'instance_types'
instance_types
when 'roles'
iam_client.list_roles
when 'regions'
ec2_client.describe_regions
when 'security_groups'
raise BadRequest unless vpc_id.present?
ec2_client.describe_security_groups(vpc_filter)
when 'subnets'
raise BadRequest unless vpc_id.present?
ec2_client.describe_subnets(vpc_filter)
when 'vpcs'
ec2_client.describe_vpcs
else
raise BadRequest
end
end
def requested_resource
params[:resource]
end
def vpc_id
params[:vpc_id]
end
def region
params[:region] || DEFAULT_REGION
end
def vpc_filter
{
filters: [{
name: "vpc-id",
values: [vpc_id]
}]
}
end
##
# Unfortunately the EC2 API doesn't provide a list of
# possible instance types. There is a workaround, using
# the Pricing API, but instead of requiring the
# user to grant extra permissions for this we use the
# values that validate the CloudFormation template.
def instance_types
{
instance_types: cluster_stack_instance_types.map { |type| Hash(instance_type_name: type) }
}
end
def cluster_stack_instance_types
YAML.safe_load(stack_template).dig('Parameters', 'NodeInstanceType', 'AllowedValues')
end
def stack_template
File.read(Rails.root.join('vendor', 'aws', 'cloudformation', 'eks_cluster.yaml'))
end
def ec2_client
::Aws::EC2::Client.new(client_options)
end
def iam_client
::Aws::IAM::Client.new(client_options)
end
def credentials
Clusters::Aws::FetchCredentialsService.new(role, region: region).execute
end
def client_options
{
credentials: credentials,
region: region,
http_open_timeout: 5,
http_read_timeout: 10
}
end
def service_errors
[
BadRequest,
Clusters::Aws::FetchCredentialsService::MissingRoleError,
::Aws::Errors::MissingCredentialsError,
::Aws::EC2::Errors::ServiceError,
::Aws::IAM::Errors::ServiceError,
::Aws::STS::Errors::ServiceError
]
end
end
end
end
|