rubycfn 0.5.0 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -1
- data/CloudFormationResourceSpecification.json +64738 -14039
- data/Gemfile.lock +50 -47
- data/README.md +5 -6
- data/lib/rubycfn/version.rb +1 -1
- data/rubycfn.gemspec +1 -1
- data/templates/.gitignore +4 -0
- data/templates/.rubocop.yml +3 -0
- data/templates/README.md +2 -1
- data/templates/Rakefile +1 -1
- data/templates/config.yaml +3 -0
- data/templates/lib/aws_helper/compiler.rb +1 -1
- data/templates/lib/aws_helper/dependencies.rb +17 -7
- data/templates/lib/aws_helper/deploy.rb +0 -1
- data/templates/lib/aws_helper/upload_stack.rb +3 -10
- data/templates/lib/core/applications.rb +178 -32
- data/templates/lib/core/dependencies.rb +11 -4
- data/templates/lib/core/deploy.rb +3 -3
- data/templates/lib/core/init.rb +60 -12
- data/templates/lib/main.rb +1 -1
- data/templates/lib/shared_concerns/global_variables.rb +1 -1
- data/templates/lib/shared_concerns/shared_methods.rb +3 -1
- data/templates/lib/stacks/ecs_stack/ecs_cluster.rb +276 -276
- data/templates/lib/stacks/ecs_stack/lifecycle_hook.rb +162 -160
- data/templates/lib/stacks/ecs_stack/load_balancer.rb +52 -50
- data/templates/lib/stacks/ecs_stack/main.rb +2 -0
- data/templates/lib/stacks/ecs_stack/rollback.rb +77 -0
- metadata +10 -10
- data/templates/bootstrap/dependency_stack.rb +0 -49
data/Gemfile.lock
CHANGED
@@ -1,35 +1,35 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rubycfn (0.5.
|
4
|
+
rubycfn (0.5.5)
|
5
5
|
activesupport (~> 5.1.5)
|
6
6
|
dotenv (~> 2.4.0)
|
7
|
-
json (~> 2.
|
7
|
+
json (~> 2.3.0)
|
8
8
|
neatjson (~> 0.8.4)
|
9
9
|
tty-prompt (~> 0.16.0)
|
10
10
|
|
11
11
|
GEM
|
12
12
|
remote: https://rubygems.org/
|
13
13
|
specs:
|
14
|
-
activesupport (
|
14
|
+
activesupport (6.0.3.1)
|
15
15
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
16
|
i18n (>= 0.7, < 2)
|
17
17
|
minitest (~> 5.1)
|
18
18
|
tzinfo (~> 1.1)
|
19
|
-
addressable (2.
|
19
|
+
addressable (2.8.0)
|
20
20
|
public_suffix (>= 2.0.2, < 5.0)
|
21
|
-
awesome_print (1.
|
22
|
-
coderay (1.1.
|
23
|
-
concurrent-ruby (1.1.
|
24
|
-
diff-lcs (1.
|
25
|
-
docile (1.
|
21
|
+
awesome_print (1.9.2)
|
22
|
+
coderay (1.1.3)
|
23
|
+
concurrent-ruby (1.1.9)
|
24
|
+
diff-lcs (1.4.4)
|
25
|
+
docile (1.4.0)
|
26
26
|
dotenv (2.4.0)
|
27
|
-
equatable (0.
|
28
|
-
ffi (1.
|
29
|
-
formatador (0.
|
30
|
-
given_core (3.8.
|
27
|
+
equatable (0.7.0)
|
28
|
+
ffi (1.15.3)
|
29
|
+
formatador (0.3.0)
|
30
|
+
given_core (3.8.2)
|
31
31
|
sorcerer (>= 0.3.7)
|
32
|
-
guard (2.
|
32
|
+
guard (2.17.0)
|
33
33
|
formatador (>= 0.2.4)
|
34
34
|
listen (>= 2.7, < 4.0)
|
35
35
|
lumberjack (>= 1.0.12, < 2.0)
|
@@ -43,65 +43,67 @@ GEM
|
|
43
43
|
guard (~> 2.1)
|
44
44
|
guard-compat (~> 1.1)
|
45
45
|
rspec (>= 2.99.0, < 4.0)
|
46
|
-
i18n (1.8.
|
46
|
+
i18n (1.8.10)
|
47
47
|
concurrent-ruby (~> 1.0)
|
48
|
-
json (2.1
|
48
|
+
json (2.3.1)
|
49
49
|
launchy (2.5.0)
|
50
50
|
addressable (~> 2.7)
|
51
|
-
listen (3.
|
51
|
+
listen (3.5.1)
|
52
52
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
53
53
|
rb-inotify (~> 0.9, >= 0.9.10)
|
54
|
-
lumberjack (1.2.
|
55
|
-
method_source (0.
|
56
|
-
minitest (5.14.
|
54
|
+
lumberjack (1.2.8)
|
55
|
+
method_source (1.0.0)
|
56
|
+
minitest (5.14.4)
|
57
57
|
neatjson (0.8.4)
|
58
58
|
necromancer (0.4.0)
|
59
59
|
nenv (0.3.0)
|
60
60
|
notiffany (0.1.3)
|
61
61
|
nenv (~> 0.1)
|
62
62
|
shellany (~> 0.0)
|
63
|
-
pastel (0.7.
|
63
|
+
pastel (0.7.4)
|
64
64
|
equatable (~> 0.6)
|
65
65
|
tty-color (~> 0.5)
|
66
|
-
pry (0.
|
67
|
-
coderay (~> 1.1
|
68
|
-
method_source (~>
|
69
|
-
public_suffix (4.0.
|
70
|
-
rake (13.0.
|
71
|
-
rb-fsevent (0.
|
66
|
+
pry (0.14.1)
|
67
|
+
coderay (~> 1.1)
|
68
|
+
method_source (~> 1.0)
|
69
|
+
public_suffix (4.0.6)
|
70
|
+
rake (13.0.4)
|
71
|
+
rb-fsevent (0.11.0)
|
72
72
|
rb-inotify (0.10.1)
|
73
73
|
ffi (~> 1.0)
|
74
|
-
rspec (3.
|
75
|
-
rspec-core (~> 3.
|
76
|
-
rspec-expectations (~> 3.
|
77
|
-
rspec-mocks (~> 3.
|
78
|
-
rspec-core (3.
|
79
|
-
rspec-support (~> 3.
|
80
|
-
rspec-expectations (3.
|
74
|
+
rspec (3.10.0)
|
75
|
+
rspec-core (~> 3.10.0)
|
76
|
+
rspec-expectations (~> 3.10.0)
|
77
|
+
rspec-mocks (~> 3.10.0)
|
78
|
+
rspec-core (3.10.1)
|
79
|
+
rspec-support (~> 3.10.0)
|
80
|
+
rspec-expectations (3.10.1)
|
81
81
|
diff-lcs (>= 1.2.0, < 2.0)
|
82
|
-
rspec-support (~> 3.
|
83
|
-
rspec-given (3.8.
|
84
|
-
given_core (= 3.8.
|
82
|
+
rspec-support (~> 3.10.0)
|
83
|
+
rspec-given (3.8.2)
|
84
|
+
given_core (= 3.8.2)
|
85
85
|
rspec (>= 2.14.0)
|
86
86
|
rspec-its (1.3.0)
|
87
87
|
rspec-core (>= 3.0.0)
|
88
88
|
rspec-expectations (>= 3.0.0)
|
89
|
-
rspec-mocks (3.
|
89
|
+
rspec-mocks (3.10.2)
|
90
90
|
diff-lcs (>= 1.2.0, < 2.0)
|
91
|
-
rspec-support (~> 3.
|
92
|
-
rspec-support (3.
|
91
|
+
rspec-support (~> 3.10.0)
|
92
|
+
rspec-support (3.10.2)
|
93
93
|
rspec_junit_formatter (0.4.1)
|
94
94
|
rspec-core (>= 2, < 4, != 2.12.0)
|
95
95
|
shellany (0.0.1)
|
96
|
-
simplecov (0.
|
96
|
+
simplecov (0.21.2)
|
97
97
|
docile (~> 1.1)
|
98
98
|
simplecov-html (~> 0.11)
|
99
|
-
|
99
|
+
simplecov_json_formatter (~> 0.1)
|
100
|
+
simplecov-html (0.12.3)
|
101
|
+
simplecov_json_formatter (0.1.3)
|
100
102
|
sorcerer (2.0.1)
|
101
|
-
thor (1.0
|
103
|
+
thor (1.1.0)
|
102
104
|
thread_safe (0.3.6)
|
103
|
-
timers (4.3.
|
104
|
-
tty-color (0.
|
105
|
+
timers (4.3.3)
|
106
|
+
tty-color (0.6.0)
|
105
107
|
tty-cursor (0.5.0)
|
106
108
|
tty-prompt (0.16.1)
|
107
109
|
necromancer (~> 0.4.0)
|
@@ -114,9 +116,10 @@ GEM
|
|
114
116
|
tty-screen (~> 0.6.4)
|
115
117
|
wisper (~> 2.0.0)
|
116
118
|
tty-screen (0.6.5)
|
117
|
-
tzinfo (1.2.
|
119
|
+
tzinfo (1.2.9)
|
118
120
|
thread_safe (~> 0.1)
|
119
121
|
wisper (2.0.1)
|
122
|
+
zeitwerk (2.3.0)
|
120
123
|
|
121
124
|
PLATFORMS
|
122
125
|
ruby
|
@@ -137,4 +140,4 @@ DEPENDENCIES
|
|
137
140
|
simplecov (~> 0.9)
|
138
141
|
|
139
142
|
BUNDLED WITH
|
140
|
-
2.
|
143
|
+
2.2.22
|
data/README.md
CHANGED
@@ -61,7 +61,7 @@ __________ ____ __________________.___._________ _____________________
|
|
61
61
|
| _/ | /| | _// | |/ \ \/ | __) | | _/
|
62
62
|
| | \ | / | | \\____ |\ \____| \ | | \
|
63
63
|
|____|_ /______/ |______ // ______| \______ /\___ / |______ /
|
64
|
-
\/ \/ \/ \/ \/ \/ [v0.5.
|
64
|
+
\/ \/ \/ \/ \/ \/ [v0.5.5]
|
65
65
|
Project name? example
|
66
66
|
Account ID? 1234567890
|
67
67
|
Select region EU (Frankfurt)
|
@@ -159,12 +159,11 @@ You can reuse these environment variables in your project code.
|
|
159
159
|
The `.env.rspec` is used when running unit tests. It contains mock variables
|
160
160
|
so that you can test the resulting CloudFormation templates properly.
|
161
161
|
|
162
|
-
#### The
|
162
|
+
#### The .env.private file
|
163
163
|
|
164
|
-
|
165
|
-
|
166
|
-
environment variables
|
167
|
-
precedence over environment variables set in other .env files.
|
164
|
+
This is a special file that allows you to override environment variables.
|
165
|
+
An environment variable set in .env.private always takes precedence over
|
166
|
+
environment variables set in other .env files.
|
168
167
|
|
169
168
|
#### .rubocop.yml
|
170
169
|
|
data/lib/rubycfn/version.rb
CHANGED
data/rubycfn.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "neatjson", "~> 0.8.4"
|
22
|
-
spec.add_runtime_dependency "json", "~> 2.
|
22
|
+
spec.add_runtime_dependency "json", "~> 2.3.0"
|
23
23
|
spec.add_runtime_dependency "activesupport", "~> 5.1.5"
|
24
24
|
spec.add_runtime_dependency "tty-prompt", "~> 0.16.0"
|
25
25
|
spec.add_runtime_dependency "dotenv", "~> 2.4.0"
|
data/templates/.gitignore
CHANGED
data/templates/.rubocop.yml
CHANGED
data/templates/README.md
CHANGED
@@ -16,11 +16,12 @@ __________ ____ __________________.___._________ _____________________
|
|
16
16
|
|
17
17
|
## Rake commands
|
18
18
|
|
19
|
-
`rake` - Compile the code into CloudFormation templates and run unit tests
|
19
|
+
`rake` - Retrieve required outputs from DependencyStack, Compile the code into CloudFormation templates and run unit tests
|
20
20
|
`rake init` - Deploy the DependencyStack in the AWS account
|
21
21
|
`rake compile` - Compile the code into CloudFormation templates
|
22
22
|
`rake spec` - Run unit tests
|
23
23
|
`rake upload` - Upload the CloudFormation templates to s3
|
24
|
+
`rake update` - Save required outputs from DependencyStack to .env.dependencies.<ENVIRONMENT>
|
24
25
|
`rake apply` - Deploy the CloudFormation templates
|
25
26
|
|
26
27
|
## Stack configuration
|
data/templates/Rakefile
CHANGED
@@ -36,7 +36,7 @@ task :clean do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
desc "Store dependencies of DependencyStack in .env.dependencies"
|
39
|
+
desc "Store dependencies of DependencyStack in .env.dependencies.<ENVIRONMENT>"
|
40
40
|
task :dependencies do
|
41
41
|
require_relative "lib/core/dependencies.rb"
|
42
42
|
end
|
data/templates/config.yaml
CHANGED
@@ -52,6 +52,9 @@ applications:
|
|
52
52
|
env:
|
53
53
|
SOME_ENV_VAR: Exposed
|
54
54
|
SOME_OTHER_VAR: desopxE
|
55
|
+
# SOME_REFFED_VAR: :foobar.ef
|
56
|
+
# SOME_OTHER_STACK_VAR: :vpc_stack.ref("Outputs.VpcId")
|
57
|
+
# SOME_ENV_VAR: ${MY_ENV_VAR}
|
55
58
|
hello-world2:
|
56
59
|
image: tutum/hello-world
|
57
60
|
container_port: 80
|
@@ -2,7 +2,7 @@ require "git-revision"
|
|
2
2
|
|
3
3
|
def update_references(contents, environment, _artifact_bucket)
|
4
4
|
Dotenv.load(".env.private")
|
5
|
-
Dotenv.load(".env.dependencies")
|
5
|
+
Dotenv.load(".env.dependencies.#{ENV["ENVIRONMENT"]}")
|
6
6
|
contents["Resources"].map do |resource|
|
7
7
|
resource_name = resource.shift
|
8
8
|
resource_values = resource.shift
|
@@ -1,25 +1,35 @@
|
|
1
|
+
def infra_config
|
2
|
+
config = YAML.safe_load(File.read("config.yaml"), [Symbol])
|
3
|
+
config["applications"] ||= {}
|
4
|
+
config["environments"] ||= {}
|
5
|
+
config["subnets"] ||= {}
|
6
|
+
config
|
7
|
+
end
|
8
|
+
|
1
9
|
def load_env_vars
|
2
10
|
Dotenv.load(".env.private")
|
3
|
-
Dotenv.load(".env.dependencies")
|
11
|
+
Dotenv.load(".env.dependencies.#{ENV["ENVIRONMENT"]}")
|
4
12
|
Dotenv.load(".env")
|
5
13
|
Dotenv.load(".env.#{ENV["ENVIRONMENT"]}")
|
6
14
|
|
7
15
|
check_dependencies
|
8
16
|
{
|
17
|
+
artifact_bucket: ENV["ARTIFACTBUCKET"],
|
9
18
|
aws_region: ENV["AWS_REGION"],
|
10
19
|
aws_access_key_id: ENV["AWS_ACCESS_KEY_ID"],
|
11
20
|
aws_secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
|
12
|
-
|
21
|
+
cloudformation_bucket: ENV["CLOUDFORMATIONBUCKET"],
|
13
22
|
environment: ENV["ENVIRONMENT"],
|
14
|
-
stack_name: ENV["
|
23
|
+
stack_name: infra_config["environments"][ENV["ENVIRONMENT"]]["stack_name"]
|
15
24
|
}
|
16
25
|
end
|
17
26
|
|
18
27
|
def check_dependencies
|
19
28
|
ENV["AWS_REGION"] ||= ENV["AWS_DEFAULT_REGION"]
|
20
|
-
raise "AWS_REGION not set" unless ENV["AWS_REGION"]
|
21
|
-
raise "
|
22
|
-
raise "
|
23
|
-
raise "
|
29
|
+
raise "AWS_REGION not set." unless ENV["AWS_REGION"]
|
30
|
+
raise "CLOUDFORMATIONBUCKET not set. Run `rake init` and `rake update` first!" unless ENV["CLOUDFORMATIONBUCKET"]
|
31
|
+
raise "ARTIFACTBUCKET not set. Run `rake init` and `rake update` first!" unless ENV["ARTIFACTBUCKET"]
|
32
|
+
raise "ENVIRONMENT not set." unless ENV["ENVIRONMENT"]
|
33
|
+
raise "`stack_name` not configured in config.yaml" unless infra_config["environments"][ENV["ENVIRONMENT"]]["stack_name"]
|
24
34
|
raise "AWS CREDENTIALS NOT SET" unless ENV["AWS_ACCESS_KEY_ID"] && ENV["AWS_SECRET_ACCESS_KEY"]
|
25
35
|
end
|
@@ -45,7 +45,6 @@ def get_parent_stack_s3_location(bucket, environment)
|
|
45
45
|
JSON.parse(stack)["Resources"].each do |_resource, payload|
|
46
46
|
if payload["Type"] == "AWS::CloudFormation::Stack"
|
47
47
|
parent_stack = stack_name
|
48
|
-
json_file = "build/#{environment}-#{stack_name.downcase}.json"
|
49
48
|
file_hash = git_revision
|
50
49
|
break
|
51
50
|
end
|
@@ -2,7 +2,7 @@ require_relative "../core/git"
|
|
2
2
|
|
3
3
|
def upload_stacks
|
4
4
|
Dotenv.load(".env.private")
|
5
|
-
Dotenv.load(".env.dependencies")
|
5
|
+
Dotenv.load(".env.dependencies.#{ENV["ENVIRONMENT"]}")
|
6
6
|
env_vars = load_env_vars
|
7
7
|
|
8
8
|
set_aws_credentials(
|
@@ -11,17 +11,10 @@ def upload_stacks
|
|
11
11
|
env_vars[:aws_secret_access_key]
|
12
12
|
)
|
13
13
|
|
14
|
-
|
15
|
-
s3 = create_bucket_if_not_exists(
|
16
|
-
env_vars[:aws_region],
|
17
|
-
env_vars[:artifact_bucket]
|
18
|
-
)
|
19
|
-
rescue => e
|
20
|
-
puts "Exception create_bucket_if_not_exists #{e}"
|
21
|
-
end
|
14
|
+
s3 = Aws::S3::Resource.new(region: env_vars[:aws_region])
|
22
15
|
|
23
16
|
stacks = compile_stacks(true)
|
24
|
-
raise "CLOUDFORMATIONBUCKET not found in DependencyStack outputs" unless ENV["CLOUDFORMATIONBUCKET"]
|
17
|
+
raise "CLOUDFORMATIONBUCKET not found in <%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack outputs" unless ENV["CLOUDFORMATIONBUCKET"]
|
25
18
|
stacks.each do |stack_name, stack|
|
26
19
|
next if JSON.parse(stack)["Resources"].nil?
|
27
20
|
hash = @stack_hashes[stack_name.to_sym]
|
@@ -1,44 +1,120 @@
|
|
1
|
+
def to_bool(val)
|
2
|
+
return false unless val.nil? || val.empty?
|
3
|
+
return false unless val != "true"
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
def env_vars_to_array(val)
|
8
|
+
if val.nil? || val.empty?
|
9
|
+
return [
|
10
|
+
{
|
11
|
+
Name: "WITHOUT_ENV",
|
12
|
+
Value: "true"
|
13
|
+
}
|
14
|
+
]
|
15
|
+
end
|
16
|
+
vars = []
|
17
|
+
|
18
|
+
# Create an array of variables to pass to this application.
|
19
|
+
# Resolve any references to its intrinsic function.
|
20
|
+
val.keys.each_with_index do |object, index|
|
21
|
+
value = val.values[index].class == Symbol && Kernel.class_eval(":#{val.values[index]}") || val.values[index]
|
22
|
+
|
23
|
+
# Support ${ENV_VAR} in config_yaml
|
24
|
+
if value =~ /\$\{([^\}]*)\}/
|
25
|
+
capture = $1
|
26
|
+
value = ENV[capture]
|
27
|
+
end
|
28
|
+
|
29
|
+
vars.push(
|
30
|
+
Name: object,
|
31
|
+
Value: value
|
32
|
+
)
|
33
|
+
end
|
34
|
+
vars
|
35
|
+
end
|
36
|
+
|
37
|
+
@ignore_params = {}
|
38
|
+
|
39
|
+
# Return the mandatory Stack parameters and add all defined ENV vars from config.yaml
|
40
|
+
def parent_parameters(env_vars, simple_name)
|
41
|
+
params = {
|
42
|
+
"Vpc": :vpc_stack.ref("Outputs.Vpc"),
|
43
|
+
"Cluster": :ecs_stack.ref("Outputs.EcsCluster"),
|
44
|
+
"Listener": :ecs_stack.ref("Outputs.EcsLoadBalancerListener"),
|
45
|
+
"EcsServiceAutoScalingRoleArn": :ecs_stack.ref("Outputs.EcsAutoScalingRoleArn"),
|
46
|
+
"HostedZoneId": "HOSTEDZONEID".ref,
|
47
|
+
"HostedZoneName": "HOSTEDZONENAME".ref,
|
48
|
+
"LoadBalancerDnsName": :ecs_stack.ref("Outputs.EcsLoadBalancerUrl"),
|
49
|
+
"CanonicalHostedZoneId": :ecs_stack.ref("Outputs.EcsLoadBalancerHostedZoneId"),
|
50
|
+
"CertificateProviderFunctionArn": :acm_stack.ref("Outputs.CertificateProviderFunctionArn"),
|
51
|
+
"ApplicationDeploymentFailureRollbackFunctionArn": :ecs_stack.ref("Outputs.ApplicationDeploymentFailureRollbackFunctionArn")
|
52
|
+
}
|
53
|
+
|
54
|
+
env_vars.each do |var|
|
55
|
+
TOPLEVEL_BINDING.eval("@ignore_params[:#{simple_name}] ||= []")
|
56
|
+
if var[:Value].class == Hash && var[:Value].keys[0] == :Ref
|
57
|
+
TOPLEVEL_BINDING.eval("@ignore_params[:#{simple_name}].push(\"#{var[:Name]}\")")
|
58
|
+
next
|
59
|
+
end
|
60
|
+
params[var[:Name].cfnize] = var[:Value]
|
61
|
+
end
|
62
|
+
params
|
63
|
+
end
|
64
|
+
|
65
|
+
def application_parameters(env_vars)
|
66
|
+
vars = []
|
67
|
+
|
68
|
+
env_vars.each do |var|
|
69
|
+
if var[:Value].class == Hash && var[:Value].keys[0] == :Ref
|
70
|
+
vars.push(
|
71
|
+
Name: var[:Name],
|
72
|
+
Value: var[:Value]
|
73
|
+
)
|
74
|
+
else
|
75
|
+
vars.push(
|
76
|
+
Name: var[:Name],
|
77
|
+
Value: var[:Name].cfnize.ref
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
vars
|
82
|
+
end
|
83
|
+
|
1
84
|
# Generate nested stacks for each defined application, and create module dynamically.
|
2
85
|
def create_applications
|
86
|
+
return if infra_config["environments"][environment]["cluster_size"].nil? || infra_config["environments"][environment]["cluster_size"].to_i.zero?
|
3
87
|
resource :applications_stack,
|
4
88
|
amount: infra_config["applications"].count,
|
5
89
|
type: "AWS::CloudFormation::Stack" do |r, index|
|
90
|
+
env_vars = env_vars_to_array(infra_config["applications"].values[index]["env"])
|
91
|
+
application_vars = application_parameters(env_vars) # rubocop:disable Lint/UselessAssignment
|
6
92
|
name = infra_config["applications"].keys[index]
|
7
93
|
resource_name = name.tr("-", "_").cfnize
|
8
94
|
simple_name = resource_name.downcase
|
9
95
|
app_config = infra_config["applications"].values[index]
|
10
|
-
|
11
|
-
# request_certificate("Gateway", gateway_domains[environment], :asellion_com_hosted_zone_id.ref, "us-east-1")
|
96
|
+
is_essential = to_bool(app_config["essential"].to_s)
|
12
97
|
|
13
98
|
r._id("#{resource_name}Stack")
|
14
99
|
r.property(:template_url) { "#{simple_name}stack" }
|
15
|
-
r.property(:parameters)
|
16
|
-
{
|
17
|
-
"Vpc": :vpc_stack.ref("Outputs.SfsVpc"),
|
18
|
-
"Cluster": :ecs_stack.ref("Outputs.SfsEcsCluster"),
|
19
|
-
"Listener": :ecs_stack.ref("Outputs.EcsLoadBalancerListener"),
|
20
|
-
"EcsServiceAutoScalingRoleArn": :ecs_stack.ref("Outputs.SfsEcsAutoScalingRoleArn"),
|
21
|
-
"HostedZoneId": :route53_stack.ref("Outputs.HostedZoneId"),
|
22
|
-
"HostedZoneName": :route53_stack.ref("Outputs.HostedZoneName"),
|
23
|
-
"LoadBalancerDnsName": :ecs_stack.ref("Outputs.EcsLoadBalancerUrl"),
|
24
|
-
"CanonicalHostedZoneId": :ecs_stack.ref("Outputs.EcsLoadBalancerHostedZoneId"),
|
25
|
-
"CertificateProviderFunctionArn": :acm_stack.ref("Outputs.CertificateProviderFunctionArn")
|
26
|
-
}
|
27
|
-
end
|
100
|
+
r.property(:parameters) { parent_parameters(env_vars, simple_name) }
|
28
101
|
Object.const_set("#{resource_name}Stack", Module.new).class_eval <<-RUBY
|
29
102
|
extend ActiveSupport::Concern
|
30
103
|
include Rubycfn
|
31
104
|
|
32
105
|
included do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
106
|
+
|
107
|
+
def get_aliases(val)
|
108
|
+
aliases = []
|
109
|
+
return aliases if val["aliases"].nil?
|
110
|
+
return aliases if val["aliases"][environment].nil?
|
111
|
+
val["aliases"][environment]
|
112
|
+
end
|
113
|
+
|
114
|
+
ignore_params = TOPLEVEL_BINDING.eval("@ignore_params[:#{simple_name}]")
|
115
|
+
application_vars.each do |var|
|
116
|
+
next if ignore_params.include? var[:Name]
|
117
|
+
Object.class_eval("parameter var[:Name].to_sym, description: 'Value for ENV var \#{var[:Name]}'")
|
42
118
|
end
|
43
119
|
|
44
120
|
parameter :vpc,
|
@@ -77,17 +153,34 @@ def create_applications
|
|
77
153
|
description: "ARN of certificate provider",
|
78
154
|
type: "String"
|
79
155
|
|
156
|
+
parameter :application_deployment_failure_rollback_function_arn,
|
157
|
+
description: "ARN of ECS deployment failure Lambda",
|
158
|
+
type: "String"
|
159
|
+
|
160
|
+
variable :aliases,
|
161
|
+
value: app_config,
|
162
|
+
filter: :get_aliases
|
163
|
+
|
164
|
+
variable :min_override,
|
165
|
+
value: app_config[environment].nil? ? "" : app_config[environment]["min"].to_s
|
166
|
+
|
80
167
|
variable :min,
|
81
|
-
value: app_config["min"].to_s
|
168
|
+
value: min_override.empty? ? app_config["min"].to_s : min_override
|
169
|
+
|
170
|
+
variable :max_override,
|
171
|
+
value: app_config[environment].nil? ? "" : app_config[environment]["max"].to_s
|
82
172
|
|
83
173
|
variable :max,
|
84
|
-
value: app_config["max"].to_s
|
174
|
+
value: max_override.empty? ? app_config["max"].to_s : max_override
|
85
175
|
|
86
176
|
variable :container_port,
|
87
177
|
value: app_config["container_port"].to_s
|
88
178
|
|
179
|
+
variable :memory_override,
|
180
|
+
value: app_config[environment].nil? ? "" : app_config[environment]["mem"].to_s
|
181
|
+
|
89
182
|
variable :memory,
|
90
|
-
value: app_config["mem"].to_s
|
183
|
+
value: memory_override.empty? ? app_config["mem"].to_s : memory_override
|
91
184
|
|
92
185
|
variable :image,
|
93
186
|
value: app_config["image"]
|
@@ -101,11 +194,14 @@ def create_applications
|
|
101
194
|
|
102
195
|
|
103
196
|
description generate_stack_description("#{resource_name}Stack")
|
197
|
+
|
104
198
|
resource :service,
|
199
|
+
amount: max.to_i.positive? ? 1 : 0,
|
105
200
|
type: "AWS::ECS::Service" do |r|
|
106
|
-
|
201
|
+
r.property(:service_name) { "#{environment}-<%= project_name %>-#{simple_name}" }
|
107
202
|
r.property(:cluster) { :cluster.ref }
|
108
203
|
r.property(:role) { :service_role.ref }
|
204
|
+
r.property(:health_check_grace_period_seconds) { 120 }
|
109
205
|
r.property(:desired_count) { min.to_i }
|
110
206
|
r.property(:task_definition) { :task_definition.ref }
|
111
207
|
r.property(:load_balancers) do
|
@@ -117,17 +213,27 @@ def create_applications
|
|
117
213
|
end
|
118
214
|
end
|
119
215
|
|
216
|
+
resource :application_deployment_health,
|
217
|
+
amount: max.to_i.positive? ? 1 : 0,
|
218
|
+
type: "Custom::EcsDeploymentCheck" do |r|
|
219
|
+
r.property(:service_token) { :application_deployment_failure_rollback_function_arn.ref }
|
220
|
+
r.property("AWSRegion") { "${AWS::Region}".fnsub }
|
221
|
+
r.property(:service) { "#{environment}-<%= project_name %>-#{simple_name}" }
|
222
|
+
r.property(:cluster) { :cluster.ref }
|
223
|
+
end
|
224
|
+
|
120
225
|
resource :task_definition,
|
226
|
+
amount: max.to_i.positive? ? 1 : 0,
|
121
227
|
type: "AWS::ECS::TaskDefinition" do |r|
|
122
228
|
r.property(:family) { "#{simple_name}-service" }
|
123
229
|
r.property(:container_definitions) do
|
124
230
|
[
|
125
231
|
{
|
126
232
|
"Name": "#{simple_name}-service",
|
127
|
-
"Essential":
|
233
|
+
"Essential": #{is_essential},
|
128
234
|
"Image": image,
|
129
235
|
"Memory": memory.to_i,
|
130
|
-
"Environment":
|
236
|
+
"Environment": application_vars,
|
131
237
|
"PortMappings": [
|
132
238
|
{
|
133
239
|
"ContainerPort": container_port.to_i
|
@@ -146,12 +252,14 @@ def create_applications
|
|
146
252
|
end
|
147
253
|
|
148
254
|
resource :cloud_watch_logs_group,
|
255
|
+
amount: max.to_i.positive? ? 1 : 0,
|
149
256
|
type: "AWS::Logs::LogGroup" do |r|
|
150
257
|
r.property(:log_group_name) { ["AWS::StackName".ref, "-#{simple_name}"].fnjoin }
|
151
258
|
r.property(:retention_in_days) { 30 }
|
152
259
|
end
|
153
260
|
|
154
261
|
resource :target_group,
|
262
|
+
amount: max.to_i.positive? ? 1 : 0,
|
155
263
|
type: "AWS::ElasticLoadBalancingV2::TargetGroup" do |r|
|
156
264
|
r.property(:vpc_id) { :vpc.ref }
|
157
265
|
r.property(:port) { container_port.to_i }
|
@@ -169,6 +277,7 @@ def create_applications
|
|
169
277
|
end
|
170
278
|
|
171
279
|
resource :listener_rule,
|
280
|
+
amount: max.to_i.positive? ? 1 : 0,
|
172
281
|
type: "AWS::ElasticLoadBalancingV2::ListenerRule" do |r|
|
173
282
|
r.property(:listener_arn) { :listener.ref }
|
174
283
|
r.property(:priority) { priority.to_i }
|
@@ -179,7 +288,7 @@ def create_applications
|
|
179
288
|
"Values": [
|
180
289
|
["origin", name.tr("_", "-"), :hosted_zone_name.ref].fnjoin("."),
|
181
290
|
[name.tr("_", "-"), :hosted_zone_name.ref].fnjoin(".")
|
182
|
-
]
|
291
|
+
] + aliases
|
183
292
|
}
|
184
293
|
]
|
185
294
|
end
|
@@ -210,6 +319,7 @@ def create_applications
|
|
210
319
|
}
|
211
320
|
|
212
321
|
resource :service_role,
|
322
|
+
amount: max.to_i.positive? ? 1 : 0,
|
213
323
|
type: "AWS::IAM::Role" do |r|
|
214
324
|
r.property(:role_name) { "ecs-service-${AWS::StackName}".fnsub }
|
215
325
|
r.property(:path) { "/" }
|
@@ -235,6 +345,27 @@ def create_applications
|
|
235
345
|
"elasticloadbalancing:RegisterTargets"
|
236
346
|
],
|
237
347
|
"Resource": "*"
|
348
|
+
},
|
349
|
+
{
|
350
|
+
"Effect": "Allow",
|
351
|
+
"Action": [
|
352
|
+
"ec2:DescribeTags",
|
353
|
+
"ecs:CreateCluster",
|
354
|
+
"ecs:DeregisterContainerInstance",
|
355
|
+
"ecs:DiscoverPollEndpoint",
|
356
|
+
"ecs:Poll",
|
357
|
+
"ecs:RegisterContainerInstance",
|
358
|
+
"ecs:StartTelemetrySession",
|
359
|
+
"ecs:UpdateContainerInstancesState",
|
360
|
+
"ecs:Submit*",
|
361
|
+
"ecr:GetAuthorizationToken",
|
362
|
+
"ecr:BatchCheckLayerAvailability",
|
363
|
+
"ecr:GetDownloadUrlForLayer",
|
364
|
+
"ecr:BatchGetImage",
|
365
|
+
"logs:CreateLogStream",
|
366
|
+
"logs:PutLogEvents"
|
367
|
+
],
|
368
|
+
"Resource": "*"
|
238
369
|
}
|
239
370
|
]
|
240
371
|
}
|
@@ -244,6 +375,7 @@ def create_applications
|
|
244
375
|
end
|
245
376
|
|
246
377
|
resource :application_load_balancer_record,
|
378
|
+
amount: max.to_i.positive? ? 1 : 0,
|
247
379
|
type: "AWS::Route53::RecordSet" do |r|
|
248
380
|
r.property(:type) { "A" }
|
249
381
|
r.property(:name) { ["origin", name.tr("_", "-"), :hosted_zone_name.ref].fnjoin(".") }
|
@@ -258,6 +390,7 @@ def create_applications
|
|
258
390
|
end
|
259
391
|
|
260
392
|
resource :service_scalable_target,
|
393
|
+
amount: max.to_i.positive? ? 1 : 0,
|
261
394
|
type: "AWS::ApplicationAutoScaling::ScalableTarget" do |r|
|
262
395
|
r.property(:max_capacity) { max.to_i }
|
263
396
|
r.property(:min_capacity) { min.to_i }
|
@@ -268,6 +401,7 @@ def create_applications
|
|
268
401
|
end
|
269
402
|
|
270
403
|
resource :service_scale_out_policy,
|
404
|
+
amount: max.to_i.positive? ? 1 : 0,
|
271
405
|
type: "AWS::ApplicationAutoScaling::ScalingPolicy" do |r|
|
272
406
|
r.property(:policy_name) { "ServiceScaleOutPolicy" }
|
273
407
|
r.property(:policy_type) { "StepScaling" }
|
@@ -288,6 +422,7 @@ def create_applications
|
|
288
422
|
end
|
289
423
|
|
290
424
|
resource :service_scale_in_policy,
|
425
|
+
amount: max.to_i.positive? ? 1 : 0,
|
291
426
|
type: "AWS::ApplicationAutoScaling::ScalingPolicy" do |r|
|
292
427
|
r.property(:policy_name) { "ServiceScaleInPolicy" }
|
293
428
|
r.property(:policy_type) { "StepScaling" }
|
@@ -308,6 +443,7 @@ def create_applications
|
|
308
443
|
end
|
309
444
|
|
310
445
|
resource :cpu_scale_out_alarm,
|
446
|
+
amount: max.to_i.positive? ? 1 : 0,
|
311
447
|
type: "AWS::CloudWatch::Alarm" do |r|
|
312
448
|
r.property(:alarm_name) { "CPU utilization greater than 90% on #{simple_name}-#{environment}" }
|
313
449
|
r.property(:alarm_description) { "Alarm if cpu utilization greater than 90% of reserved cpu" }
|
@@ -334,6 +470,7 @@ def create_applications
|
|
334
470
|
end
|
335
471
|
|
336
472
|
resource :cpu_scale_in_alarm,
|
473
|
+
amount: max.to_i.positive? ? 1 : 0,
|
337
474
|
type: "AWS::CloudWatch::Alarm" do |r|
|
338
475
|
r.property(:alarm_name) { "CPU utilization less than 70% on #{simple_name}-#{environment}" }
|
339
476
|
r.property(:alarm_description) { "Alarm if cpu utilization greater than 70% of reserved cpu" }
|
@@ -360,6 +497,7 @@ def create_applications
|
|
360
497
|
end
|
361
498
|
|
362
499
|
resource :ecs_application_certificate,
|
500
|
+
amount: max.to_i.positive? ? 1 : 0,
|
363
501
|
type: "Custom::Certificate" do |r|
|
364
502
|
r.property(:service_token) { :certificate_provider_function_arn.ref }
|
365
503
|
r.property(:region) { "us-east-1" }
|
@@ -368,6 +506,7 @@ def create_applications
|
|
368
506
|
end
|
369
507
|
|
370
508
|
resource :ecs_application_issued_certificate,
|
509
|
+
amount: max.to_i.positive? ? 1 : 0,
|
371
510
|
type: "Custom::IssuedCertificate" do |r|
|
372
511
|
r.property(:service_token) { :certificate_provider_function_arn.ref }
|
373
512
|
r.property(:region) { "us-east-1" }
|
@@ -375,6 +514,7 @@ def create_applications
|
|
375
514
|
end
|
376
515
|
|
377
516
|
resource :ecs_application_dns_record,
|
517
|
+
amount: max.to_i.positive? ? 1 : 0,
|
378
518
|
type: "Custom::CertificateDNSRecord" do |r|
|
379
519
|
r.property(:service_token) { :certificate_provider_function_arn.ref }
|
380
520
|
r.property(:region) { "us-east-1" }
|
@@ -383,6 +523,7 @@ def create_applications
|
|
383
523
|
end
|
384
524
|
|
385
525
|
resource :ecs_application_validation_record,
|
526
|
+
amount: max.to_i.positive? ? 1 : 0,
|
386
527
|
type: "AWS::Route53::RecordSetGroup" do |r|
|
387
528
|
r.property(:hosted_zone_id) { :hosted_zone_id.ref }
|
388
529
|
r.property(:record_sets) do
|
@@ -402,7 +543,11 @@ def create_applications
|
|
402
543
|
end
|
403
544
|
|
404
545
|
resource :cloudfront_distribution,
|
405
|
-
depends_on:
|
546
|
+
depends_on: [
|
547
|
+
:ecs_application_issued_certificate,
|
548
|
+
:application_deployment_health
|
549
|
+
],
|
550
|
+
amount: max.to_i.positive? ? 1 : 0,
|
406
551
|
type: "AWS::CloudFront::Distribution" do |r|
|
407
552
|
r.property(:distribution_config) do
|
408
553
|
{
|
@@ -458,6 +603,7 @@ def create_applications
|
|
458
603
|
end
|
459
604
|
|
460
605
|
resource :application_cloudfront_dns_record,
|
606
|
+
amount: max.to_i.positive? ? 1 : 0,
|
461
607
|
type: "AWS::Route53::RecordSetGroup" do |r|
|
462
608
|
r.property(:hosted_zone_id) { :hosted_zone_id.ref }
|
463
609
|
r.property(:record_sets) do
|