rubycfn 0.4.10 → 0.5.4
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 +22 -1
- data/Gemfile.lock +48 -46
- data/README.md +46 -71
- data/bin/rubycfn +17 -73
- data/lib/cli_methods.rb +2 -2
- data/lib/rubycfn/version.rb +1 -1
- data/rubycfn.gemspec +1 -1
- data/templates/.env +2 -0
- data/templates/.env.acceptance +1 -0
- data/templates/.env.dependencies.rspec +6 -0
- data/templates/.env.development +1 -0
- data/templates/.env.production +1 -0
- data/templates/.env.rspec +1 -0
- data/templates/.env.test +1 -0
- data/templates/{.gitignore.erb → .gitignore} +7 -0
- data/templates/{.rubocop.yml.erb → .rubocop.yml} +17 -1
- data/templates/{Gemfile.erb → Gemfile} +0 -1
- data/templates/README.md +58 -0
- data/templates/{Rakefile.erb → Rakefile} +15 -8
- data/templates/config.yaml +68 -0
- data/templates/lib/aws_helper/aws_sdk.rb +30 -0
- data/templates/{compiler.rb.erb → lib/aws_helper/compiler.rb} +15 -9
- data/templates/lib/aws_helper/dependencies.rb +35 -0
- data/templates/{deploy.rb.erb → lib/aws_helper/deploy.rb} +5 -4
- data/templates/lib/aws_helper/helpers.rb +3 -0
- data/templates/{main_aws_helper.rb.erb → lib/aws_helper/main.rb} +0 -0
- data/templates/{upload_stack.rb.erb → lib/aws_helper/upload_stack.rb} +8 -6
- data/templates/lib/core/applications.rb +625 -0
- data/templates/lib/core/assume_role.rb +40 -0
- data/templates/lib/core/classes.rb +25 -0
- data/templates/{core_compile.rb.erb → lib/core/compile.rb} +1 -0
- data/templates/lib/core/dependencies.rb +29 -0
- data/templates/{core_deploy.rb.erb → lib/core/deploy.rb} +20 -10
- data/templates/lib/core/git.rb +15 -0
- data/templates/lib/core/init.rb +221 -0
- data/templates/{core_upload.rb.erb → lib/core/upload.rb} +0 -0
- data/templates/{main.rb.erb → lib/main.rb} +8 -6
- data/templates/lib/shared_concerns/global_variables.rb +56 -0
- data/templates/{helper_methods.rb.erb → lib/shared_concerns/helper_functions.rb} +0 -0
- data/templates/lib/shared_concerns/helper_methods.rb +3 -0
- data/templates/{shared_methods.rb.erb → lib/shared_concerns/shared_methods.rb} +11 -0
- data/templates/lib/stacks/acm_stack/certificate_manager.rb +79 -0
- data/templates/{new_stack.rb.erb → lib/stacks/acm_stack/main.rb} +3 -4
- data/templates/lib/stacks/ecs_stack/ecs_cluster.rb +344 -0
- data/templates/lib/stacks/ecs_stack/lifecycle_hook.rb +190 -0
- data/templates/lib/stacks/ecs_stack/load_balancer.rb +70 -0
- data/templates/{ecs_stack.rb.erb → lib/stacks/ecs_stack/main.rb} +3 -0
- data/templates/lib/stacks/ecs_stack/rollback.rb +77 -0
- data/templates/{project_stack.rb.erb → lib/stacks/parent_stack/main.rb} +2 -2
- data/templates/lib/stacks/parent_stack/parent.rb +18 -0
- data/templates/lib/stacks/vpc_stack/infra_vpc.rb +193 -0
- data/templates/{vpc_stack.rb.erb → lib/stacks/vpc_stack/main.rb} +1 -2
- data/templates/{parent_stack_spec.rb.erb → spec/lib/parent_spec.rb} +2 -5
- data/templates/{spec_helper.rb.erb → spec/spec_helper.rb} +2 -2
- metadata +61 -51
- data/format.vim +0 -3
- data/templates/.env.erb +0 -4
- data/templates/.env.production.erb +0 -6
- data/templates/.env.rspec.erb +0 -6
- data/templates/.env.test.erb +0 -6
- data/templates/.gitlab-ci.yml.erb +0 -75
- data/templates/aws_sdk.rb.erb +0 -18
- data/templates/core_diff.rb.erb +0 -59
- data/templates/dependencies.rb.erb +0 -23
- data/templates/ecs_stack_concern.rb.erb +0 -20
- data/templates/global_variables.rb.erb +0 -16
- data/templates/helpers.rb.erb +0 -7
- data/templates/new_concern.rb.erb +0 -10
- data/templates/project_concern.rb.erb +0 -26
- data/templates/subnets.rb.erb +0 -18
- data/templates/vpc_concerns.rb.erb +0 -87
- data/templates/vpc_spec.rb.erb +0 -39
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "aws-sdk-core"
|
|
2
|
+
require "aws-sdk-s3"
|
|
3
|
+
require "aws-sdk-iam"
|
|
4
|
+
require "aws-sdk-organizations"
|
|
5
|
+
|
|
6
|
+
def generate_session_name
|
|
7
|
+
"assume_role_" + (0...12).map { ("a".."z").to_a[rand(26)] }.join
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def assume_role(aws_accounts, to_account, from_account = nil)
|
|
11
|
+
session_name = generate_session_name
|
|
12
|
+
if from_account
|
|
13
|
+
from_credentials = aws_accounts[from_account][:credentials]
|
|
14
|
+
credentials = Aws::AssumeRoleCredentials.new(
|
|
15
|
+
client: Aws::STS::Client.new(
|
|
16
|
+
access_key_id: from_credentials[:access_key_id],
|
|
17
|
+
region: "eu-central-1",
|
|
18
|
+
secret_access_key: from_credentials[:secret_access_key],
|
|
19
|
+
session_token: from_credentials[:session_token]
|
|
20
|
+
),
|
|
21
|
+
role_arn: "arn:aws:iam::#{aws_accounts[to_account][:account_id]}:role/#{aws_accounts[to_account][:role_name]}",
|
|
22
|
+
role_session_name: session_name
|
|
23
|
+
)
|
|
24
|
+
else
|
|
25
|
+
credentials = Aws::AssumeRoleCredentials.new(
|
|
26
|
+
client: Aws::STS::Client.new(region: aws_accounts[to_account][:region]),
|
|
27
|
+
role_arn: "arn:aws:iam::#{aws_accounts[to_account][:account_id]}:role/#{aws_accounts[to_account][:role_name]}",
|
|
28
|
+
role_session_name: session_name
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
aws_accounts[to_account][:credentials] = {
|
|
32
|
+
access_key_id: credentials.credentials.access_key_id,
|
|
33
|
+
credentials: credentials,
|
|
34
|
+
region: aws_accounts[to_account][:region],
|
|
35
|
+
secret_access_key: credentials.credentials.secret_access_key,
|
|
36
|
+
session_name: session_name,
|
|
37
|
+
session_token: credentials.credentials.session_token
|
|
38
|
+
}
|
|
39
|
+
aws_accounts
|
|
40
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Add convenient method to reference secrets.
|
|
2
|
+
# Would be nice for parameter store as well!
|
|
3
|
+
class String
|
|
4
|
+
def secret(argument)
|
|
5
|
+
[
|
|
6
|
+
"{{resolve:secretsmanager:",
|
|
7
|
+
self.ref,
|
|
8
|
+
":SecretString:",
|
|
9
|
+
argument,
|
|
10
|
+
"}}"
|
|
11
|
+
].fnjoin
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Symbol
|
|
16
|
+
def secret(argument)
|
|
17
|
+
[
|
|
18
|
+
"{{resolve:secretsmanager:",
|
|
19
|
+
self.ref,
|
|
20
|
+
":SecretString:",
|
|
21
|
+
argument,
|
|
22
|
+
"}}"
|
|
23
|
+
].fnjoin
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "aws-sdk-core"
|
|
2
|
+
require "aws-sdk-cloudformation"
|
|
3
|
+
require "dotenv"
|
|
4
|
+
|
|
5
|
+
Dotenv.load(".env.private")
|
|
6
|
+
Dotenv.load(".env")
|
|
7
|
+
Dotenv.load(".env.#{ENV["ENVIRONMENT"]}")
|
|
8
|
+
|
|
9
|
+
ENV["AWS_DEFAULT_REGION"] ||= "eu-west-1"
|
|
10
|
+
ENV["AWS_REGION"] ||= ENV["AWS_DEFAULT_REGION"]
|
|
11
|
+
|
|
12
|
+
client = Aws::CloudFormation::Client.new(region: ENV["AWS_REGION"])
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
res = client.describe_stacks(
|
|
16
|
+
stack_name: "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack"
|
|
17
|
+
)
|
|
18
|
+
rescue Aws::CloudFormation::Errors::InvalidClientTokenId, Aws::CloudFormation::Errors::ValidationError => e
|
|
19
|
+
puts "E: #{e.class}"
|
|
20
|
+
raise "ERROR: Your AWS credentials are not set or invalid." if e.class == Aws::CloudFormation::Errors::InvalidClientTokenId
|
|
21
|
+
raise "ERROR: <%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack does not exist. Run `rake init` first!" if e.class == Aws::CloudFormation::Errors::ValidationError
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
dep_file = File.open(".env.dependencies.#{ENV["ENVIRONMENT"]}", "w")
|
|
25
|
+
res[:stacks].each do |stack|
|
|
26
|
+
stack[:outputs].each do |output|
|
|
27
|
+
dep_file.puts "#{output[:output_key].upcase}=#{output[:output_value]}"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -6,6 +6,10 @@ require "aws-sdk"
|
|
|
6
6
|
|
|
7
7
|
require_relative "../aws_helper/main"
|
|
8
8
|
|
|
9
|
+
Dotenv.load(".env.private")
|
|
10
|
+
Dotenv.load(".env.dependencies.#{ENV["ENVIRONMENT"]}")
|
|
11
|
+
raise "CLOUDFORMATIONBUCKET not set. Run `rake init` and `rake update` first!" unless ENV["CLOUDFORMATIONBUCKET"]
|
|
12
|
+
|
|
9
13
|
env_vars = load_env_vars
|
|
10
14
|
|
|
11
15
|
set_aws_credentials(
|
|
@@ -15,12 +19,22 @@ set_aws_credentials(
|
|
|
15
19
|
)
|
|
16
20
|
|
|
17
21
|
s3_filename = get_parent_stack_s3_location(
|
|
18
|
-
|
|
22
|
+
ENV["CLOUDFORMATIONBUCKET"],
|
|
19
23
|
env_vars[:environment]
|
|
20
24
|
)
|
|
21
25
|
|
|
22
26
|
client = Aws::CloudFormation::Client.new
|
|
23
27
|
|
|
28
|
+
parent_parameters = []
|
|
29
|
+
File.open(".env.dependencies.#{ENV["ENVIRONMENT"]}").read.each_line do |line|
|
|
30
|
+
line.strip!
|
|
31
|
+
param, value = line.split("=")
|
|
32
|
+
parent_parameters.push(
|
|
33
|
+
parameter_key: param,
|
|
34
|
+
parameter_value: value
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
24
38
|
# Store previous CloudFormation events in an array, so that we don't output
|
|
25
39
|
# events from previous deploys.
|
|
26
40
|
|
|
@@ -47,15 +61,13 @@ if stack_exists
|
|
|
47
61
|
stack_name: env_vars[:stack_name],
|
|
48
62
|
template_url: s3_filename,
|
|
49
63
|
capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND),
|
|
50
|
-
|
|
51
|
-
# stack_policy_url: "StackPolicyURL",
|
|
64
|
+
parameters: parent_parameters,
|
|
52
65
|
tags: [
|
|
53
66
|
{
|
|
54
67
|
key: "team",
|
|
55
|
-
value: "
|
|
68
|
+
value: "infra"
|
|
56
69
|
}
|
|
57
|
-
]
|
|
58
|
-
# client_request_token: "ClientRequestToken",
|
|
70
|
+
]
|
|
59
71
|
)
|
|
60
72
|
else
|
|
61
73
|
client.create_stack(
|
|
@@ -64,15 +76,13 @@ else
|
|
|
64
76
|
timeout_in_minutes: 60,
|
|
65
77
|
capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND),
|
|
66
78
|
on_failure: "ROLLBACK",
|
|
67
|
-
|
|
68
|
-
# stack_policy_url: "StackPolicyURL",
|
|
79
|
+
parameters: parent_parameters,
|
|
69
80
|
tags: [
|
|
70
81
|
{
|
|
71
82
|
key: "team",
|
|
72
|
-
value: "
|
|
83
|
+
value: "infra"
|
|
73
84
|
}
|
|
74
85
|
],
|
|
75
|
-
# client_request_token: "ClientRequestToken",
|
|
76
86
|
enable_termination_protection: false
|
|
77
87
|
)
|
|
78
88
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require "git-revision"
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
class Revision
|
|
5
|
+
class << self
|
|
6
|
+
def dirty?
|
|
7
|
+
!`git diff --numstat | wc -l`.strip.to_i.zero?
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def git_revision
|
|
14
|
+
"#{Git::Revision.commit}#{Git::Revision.dirty? ? "-dirty" : ""}"
|
|
15
|
+
end
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
require "aws-sdk"
|
|
2
|
+
require "dotenv"
|
|
3
|
+
require "git-revision"
|
|
4
|
+
require "rubycfn"
|
|
5
|
+
require "yaml"
|
|
6
|
+
|
|
7
|
+
require_relative "../aws_helper/main"
|
|
8
|
+
|
|
9
|
+
Dotenv.load(".env.private")
|
|
10
|
+
Dotenv.load(".env")
|
|
11
|
+
Dotenv.load(".env.#{ENV["ENVIRONMENT"]}")
|
|
12
|
+
|
|
13
|
+
set_aws_credentials(
|
|
14
|
+
ENV["AWS_REGION"],
|
|
15
|
+
ENV["AWS_ACCESS_KEY_ID"],
|
|
16
|
+
ENV["AWS_SECRET_ACCESS_KEY"]
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def inject_dummy_resource(stack)
|
|
20
|
+
hack_stack = JSON.parse(stack)
|
|
21
|
+
hack_stack["Resources"] = {} if hack_stack["Resources"].nil?
|
|
22
|
+
hack_stack["Resources"]["CloudFormationDummyResource"] = {
|
|
23
|
+
"Type": "AWS::CloudFormation::WaitConditionHandle",
|
|
24
|
+
"Metadata": {
|
|
25
|
+
"Comment": "Resource to update stack even if there are no changes",
|
|
26
|
+
"GitCommitHash": Git::Revision.commit
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
hack_stack.to_json
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def read_domain_name
|
|
33
|
+
config = YAML.safe_load(File.read("config.yaml"), [Symbol])
|
|
34
|
+
config["applications"] ||= {}
|
|
35
|
+
config["environments"] ||= {}
|
|
36
|
+
config["subnets"] ||= {}
|
|
37
|
+
|
|
38
|
+
# Allow override by setting ENV var
|
|
39
|
+
domain_name = ENV["DOMAIN_NAME"]
|
|
40
|
+
subdomain = ENV["SUBDOMAIN"] # rubocop:disable Lint/UselessAssignment
|
|
41
|
+
|
|
42
|
+
# First, look at environment specific domain name configuration
|
|
43
|
+
domain_name ||= config["environments"][ENV["ENVIRONMENT"]]["domain_name"].nil? && nil || config["environments"][ENV["ENVIRONMENT"]]["domain_name"]
|
|
44
|
+
|
|
45
|
+
# Assign the global domain name configuration unless domain_name was set to false in environment config.yaml
|
|
46
|
+
domain_name ||= config["domain_name"] unless domain_name.class == FalseClass
|
|
47
|
+
|
|
48
|
+
# Set domain name to an empty string if domain_name was set to false
|
|
49
|
+
domain_name = "" if domain_name.class == FalseClass
|
|
50
|
+
|
|
51
|
+
# If the no_subdomain setting for environments in config.yaml is omitted or set to false, set subdomain to environment, else assign empty string
|
|
52
|
+
subdomain = (config["environments"][ENV["ENVIRONMENT"]]["no_subdomain"].nil? || config["environments"][ENV["ENVIRONMENT"]]["no_subdomain"] == false) && ENV["ENVIRONMENT"] || ""
|
|
53
|
+
|
|
54
|
+
# Return an array with t he subdomain and domain_name
|
|
55
|
+
[subdomain, domain_name]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
subdomain, domain_name = read_domain_name
|
|
59
|
+
|
|
60
|
+
raise "ENVIRONMENT not set" unless ENV["ENVIRONMENT"]
|
|
61
|
+
warn "WARNING: domain_name not set in config.yaml... Route53 Hosted Zone will not be created" if domain_name.empty?
|
|
62
|
+
|
|
63
|
+
module Project<%= project_name %>DependencyStack
|
|
64
|
+
extend ActiveSupport::Concern
|
|
65
|
+
include Rubycfn
|
|
66
|
+
|
|
67
|
+
included do
|
|
68
|
+
description "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}Dependency Stack"
|
|
69
|
+
|
|
70
|
+
parameter :environment,
|
|
71
|
+
description: "Environment name",
|
|
72
|
+
type: "String"
|
|
73
|
+
|
|
74
|
+
parameter :domain_name,
|
|
75
|
+
description: "Domain name",
|
|
76
|
+
type: "String"
|
|
77
|
+
|
|
78
|
+
condition :has_environment,
|
|
79
|
+
[["", :environment.ref].fnequals].fnnot
|
|
80
|
+
|
|
81
|
+
condition :has_domain_name,
|
|
82
|
+
[["", :domain_name.ref].fnequals].fnnot
|
|
83
|
+
|
|
84
|
+
%i(
|
|
85
|
+
artifact_bucket
|
|
86
|
+
cloudformation_bucket
|
|
87
|
+
lambda_bucket
|
|
88
|
+
logging_bucket
|
|
89
|
+
).each do |bucket|
|
|
90
|
+
resource bucket,
|
|
91
|
+
deletion_policy: "Retain",
|
|
92
|
+
update_replace_policy: "Retain",
|
|
93
|
+
type: "AWS::S3::Bucket"
|
|
94
|
+
|
|
95
|
+
output bucket,
|
|
96
|
+
value: bucket.ref
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
resource :hosted_zone,
|
|
100
|
+
condition: "HasDomainName",
|
|
101
|
+
type: "AWS::Route53::HostedZone" do |r|
|
|
102
|
+
r.property(:hosted_zone_config) do
|
|
103
|
+
{
|
|
104
|
+
"Comment": ["Hosted zone for ", ["HasEnvironment", [:environment.ref, "."].fnjoin, ""].fnif, :domain_name.ref].fnjoin
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
r.property(:name) { [["HasEnvironment", [:environment.ref, "."].fnjoin, ""].fnif, :domain_name.ref].fnjoin }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
output :hosted_zone_id,
|
|
111
|
+
condition: "HasDomainName",
|
|
112
|
+
value: :hosted_zone.ref
|
|
113
|
+
|
|
114
|
+
output :hosted_zone_name,
|
|
115
|
+
condition: "HasDomainName",
|
|
116
|
+
value: [["HasEnvironment", [:environment.ref, "."].fnjoin, ""].fnif, :domain_name.ref].fnjoin
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
stack = include Project<%= project_name %>DependencyStack # rubocop:disable Style/MixinUsage
|
|
121
|
+
template = stack.render_template
|
|
122
|
+
|
|
123
|
+
client = Aws::CloudFormation::Client.new
|
|
124
|
+
|
|
125
|
+
stack_exists = false
|
|
126
|
+
previous_statuses = []
|
|
127
|
+
80.times do
|
|
128
|
+
previous_events = get_prior_events(client, "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack")
|
|
129
|
+
previous_statuses = previous_events.map(&:event_id)
|
|
130
|
+
stack_exists = previous_events.size.to_i.positive? ? true : false
|
|
131
|
+
break unless stack_exists
|
|
132
|
+
|
|
133
|
+
events_last_deploy = get_events_last_deploy(previous_events)
|
|
134
|
+
last_event = events_last_deploy.shift
|
|
135
|
+
break if last_event \
|
|
136
|
+
&& (last_event.logical_resource_id == "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack") \
|
|
137
|
+
&& (last_event.stack_name == "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack") \
|
|
138
|
+
&& (DEPLOYABLE_STATES.include? last_event.resource_status)
|
|
139
|
+
puts "Stack is currently in #{last_event.resource_status} mode. Waiting for it to finish..." if last_event
|
|
140
|
+
sleep 15
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
template = inject_dummy_resource(template)
|
|
144
|
+
|
|
145
|
+
parameters = [
|
|
146
|
+
{
|
|
147
|
+
parameter_key: "Environment",
|
|
148
|
+
parameter_value: subdomain
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
parameter_key: "DomainName",
|
|
152
|
+
parameter_value: domain_name
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
if stack_exists
|
|
157
|
+
client.update_stack(
|
|
158
|
+
stack_name: "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack",
|
|
159
|
+
template_body: template,
|
|
160
|
+
capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM),
|
|
161
|
+
parameters: parameters,
|
|
162
|
+
tags: [
|
|
163
|
+
{
|
|
164
|
+
key: "team",
|
|
165
|
+
value: "infra"
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
)
|
|
169
|
+
else
|
|
170
|
+
client.create_stack(
|
|
171
|
+
stack_name: "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack",
|
|
172
|
+
template_body: template,
|
|
173
|
+
timeout_in_minutes: 60,
|
|
174
|
+
capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM),
|
|
175
|
+
on_failure: "ROLLBACK",
|
|
176
|
+
parameters: parameters,
|
|
177
|
+
tags: [
|
|
178
|
+
{
|
|
179
|
+
key: "team",
|
|
180
|
+
value: "infra"
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
enable_termination_protection: false
|
|
184
|
+
)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
shown_log_lines = {}
|
|
188
|
+
|
|
189
|
+
360.times do
|
|
190
|
+
resp = client.describe_stack_events(
|
|
191
|
+
stack_name: "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack"
|
|
192
|
+
)
|
|
193
|
+
resp.stack_events.to_a.reverse.each_with_index do |event, index|
|
|
194
|
+
next if previous_statuses.include? event.event_id
|
|
195
|
+
@completed = false
|
|
196
|
+
@stack_name = event.stack_name
|
|
197
|
+
@logical_resource_id = event.logical_resource_id
|
|
198
|
+
@resource_type = event.resource_type
|
|
199
|
+
@timestamp = event.timestamp
|
|
200
|
+
@resource_status = event.resource_status
|
|
201
|
+
@resource_status_reason = event.resource_status_reason
|
|
202
|
+
log_line = "[#{@logical_resource_id.green}] #{@timestamp.to_s.blue}: " \
|
|
203
|
+
"#{@resource_status.white} #{@resource_status_reason.to_s.red}"
|
|
204
|
+
puts log_line unless shown_log_lines[log_line]
|
|
205
|
+
shown_log_lines[log_line] = true
|
|
206
|
+
if (@stack_name == "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack") \
|
|
207
|
+
&& (@logical_resource_id == "<%= project_name %>#{ENV["ENVIRONMENT"].capitalize}DependencyStack") \
|
|
208
|
+
&& (END_STATES.include? @resource_status) \
|
|
209
|
+
&& (index + 1 == resp.stack_events.to_a.size)
|
|
210
|
+
@completed = true
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
if @completed
|
|
214
|
+
puts "==================================="
|
|
215
|
+
puts " STATUS: #{@resource_status} #{@resource_status_reason}"
|
|
216
|
+
puts "==================================="
|
|
217
|
+
raise "#{@resource_status} #{@resource_status_reason}" if FAILURE_STATES.include? @resource_status
|
|
218
|
+
break
|
|
219
|
+
end
|
|
220
|
+
sleep(10)
|
|
221
|
+
end
|
|
File without changes
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
require "rubycfn"
|
|
2
2
|
require "dotenv"
|
|
3
|
+
require_relative "core/classes"
|
|
3
4
|
|
|
4
|
-
Dotenv.load(".env")
|
|
5
5
|
Dotenv.load(".env.private")
|
|
6
|
+
Dotenv.load(".env.dependencies.#{ENV["ENVIRONMENT"]}")
|
|
7
|
+
Dotenv.load(".env")
|
|
6
8
|
Dotenv.load(".env.#{ENV["ENVIRONMENT"]}")
|
|
7
9
|
|
|
8
10
|
# Include all group concerns
|
|
@@ -21,10 +23,10 @@ module SharedConcerns
|
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
# Include all stack concerns
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Dir[File.expand_path("../stacks/",
|
|
27
|
-
require
|
|
26
|
+
# Load module code first, and last include main.rb's.
|
|
27
|
+
2.times do |i|
|
|
28
|
+
Dir[File.expand_path("../stacks/", __FILE__) + "/**/*.rb"].sort.each do |file|
|
|
29
|
+
require file unless File.basename(file) == "main.rb" || i.positive?
|
|
30
|
+
require file if File.basename(file) == "main.rb" && i.positive?
|
|
28
31
|
end
|
|
29
|
-
require file
|
|
30
32
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
|
|
3
|
+
module Concerns
|
|
4
|
+
module GlobalVariables
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
def load_config(_val)
|
|
9
|
+
config = YAML.safe_load(File.read("config.yaml"), [Symbol])
|
|
10
|
+
config["applications"] ||= {}
|
|
11
|
+
config["environments"] ||= {}
|
|
12
|
+
config["subnets"] ||= {}
|
|
13
|
+
config
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def global_tags(_val)
|
|
17
|
+
[
|
|
18
|
+
{
|
|
19
|
+
"Key": "Team",
|
|
20
|
+
"Value": "infra"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"Key": "Environment",
|
|
24
|
+
"Value": environment.to_s
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"Key": "StackName",
|
|
28
|
+
"Value": stack_name.to_s
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
variable :environment,
|
|
34
|
+
default: "development",
|
|
35
|
+
global: true,
|
|
36
|
+
value: ENV["ENVIRONMENT"]
|
|
37
|
+
|
|
38
|
+
variable :region,
|
|
39
|
+
global: true,
|
|
40
|
+
default: ENV["DEFAULT_AWS_REGION"],
|
|
41
|
+
value: ENV["AWS_REGION"]
|
|
42
|
+
|
|
43
|
+
variable :infra_config,
|
|
44
|
+
global: true,
|
|
45
|
+
filter: :load_config
|
|
46
|
+
|
|
47
|
+
variable :stack_name,
|
|
48
|
+
global: true,
|
|
49
|
+
default: infra_config["environments"][environment]["stack_name"]
|
|
50
|
+
|
|
51
|
+
variable :default_tags,
|
|
52
|
+
global: true,
|
|
53
|
+
filter: :global_tags
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|