prima-twig 1.2.6 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 665845adb115e9091a4d63673e3386d7b50e2043350ee342daee36122a6807f1
4
- data.tar.gz: d92dc143955f44ae455eb20bead9668737183bfab7fa7f62c9b116e279c9538e
3
+ metadata.gz: 94183c3b380822569fa755c6cd914da1eb15d36378d93a8faf827cf8b2a8a119
4
+ data.tar.gz: 865c21d79254b4b4ad2e8034d665f74301585fd50f4fd20b019e0c6bde977183
5
5
  SHA512:
6
- metadata.gz: 27bcc7a32bc312e359015843c05ad59872d54582ce342587894489407a6c48dbbce6997a7cbc5be2e7d246aead9dc0f235996658e450810e4409b829a670428a
7
- data.tar.gz: 2474944753cd11b793107b6b8de274e7460ea2f54a2587ee43f3bef89ca2ef2278b40f861e5198a79c4fb8acce32a1e14c6bc684b479e0a5b188417b2c939462
6
+ metadata.gz: 7604f33c35162fde446fb5e91e92451745d7eab126d09f417c36c835254949f2690c77c3f4ebbd8248c885c6c19b7786498da0cfbfe44adcb798b5641e53613f
7
+ data.tar.gz: 24f093ea1a89deef5debd86afdf69b5dbb43f5f1a6aef9bc68f8a8a0b9e2e938baee20ba897116d8a2d66e5e8d7b8d60a9e1f6af267973003e7357c34d138884
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require_relative '../lib/prima_twig'
5
+ require 'launchy'
6
+ require 'yaml'
7
+
8
+ class TwigPackerBuilder
9
+ include Command
10
+
11
+ def initialize
12
+ output 'Checking for new gem releases...'
13
+ unless `gem outdated`.lines.grep(/^prima-twig \(.*\)/).empty?
14
+ exec "gem update prima-twig && twig update-ami #{ARGV.join ' '}"
15
+ end
16
+ @templates_path = "#{Dir.pwd}/amis"
17
+ end
18
+
19
+ def execute!(args)
20
+ @template_name = args[0]
21
+ @env = args[1]
22
+ @country = args[2]
23
+
24
+ File.open("#{Dir.pwd}/ami_state.yml", 'r') do |f|
25
+ @config = YAML.load(f.read)
26
+ end
27
+
28
+ @country_conf = @config['countries'].detect { |country| country['name'] == @country }
29
+ stop_if(@country_conf.nil?, "Cannot find country #{@country} inside ami_state.yml, exiting...".red)
30
+
31
+ @ami_conf = @country_conf['amis'].detect { |ami| ami['template'] == @template_name and ami['env'] == @env }
32
+ stop_if(@ami_conf.nil?, "Cannot find an ami in #{@country} generated from #{@template_name} and env #{@env} inside ami_state.yml, exiting...".red)
33
+
34
+ output "Starting update process with #{@template_name} in env #{@env} in country #{@country}".light_green
35
+ output 'running packer (this could take some time)'.light_green
36
+ new_ami_id = execute_packer
37
+ stop_if(new_ami_id.to_s.empty?, 'Failed to generate AMI!'.red)
38
+
39
+ output "new ami id: #{new_ami_id}".light_green
40
+ output "ami id that can be replaced: #{@ami_conf['id']}".light_green
41
+ output "you can run \"aws-vault exec YOUR_CONTRY_PROFILE -- twig-update-ami #{@ami_conf['id']} #{new_ami_id}\" to update all stacks".light_green
42
+ output 'Done'.light_green
43
+ end
44
+
45
+ private
46
+
47
+ def execute_packer
48
+ execute_command "AWS_MAX_ATTEMPTS=90 AWS_POLL_DELAY_SECONDS=60 packer build -var env=#{@env} -var teams_mapping=#{@ami_conf['teams_mapping']} -var country=#{@country} -var aws_account=#{@country_conf['aws_account']} -machine-readable #{@templates_path}/#{@template_name} | tee build.log"
49
+
50
+ `grep 'artifact,0,id' build.log | cut -d, -f6 | cut -d: -f2`.sub(/\n/, '')
51
+ end
52
+
53
+ def help_content
54
+ <<-HELP
55
+
56
+ twig-packer-builder
57
+ ===========
58
+
59
+ Creates AMIs using umami's templates
60
+
61
+ Synopsis
62
+ --------
63
+
64
+ twig-packer-builder
65
+
66
+ Description
67
+ -----------
68
+
69
+ from umami main folder run
70
+ `aws-vault exec AWS_PROFILE_WITH_ACCESS_TO_COMMON_ACCOUNT -- twig-update-ami ${AMI_TEMPLATE} ${ENV} ${COUNTRY}`
71
+
72
+ Subcommand for Twig: <http://rondevera.github.io/twig/>
73
+ HELP
74
+ end
75
+
76
+ args = ARGV.dup
77
+
78
+ if args.include?('--help')
79
+ puts help_content
80
+ exit
81
+ end
82
+
83
+ TwigPackerBuilder.new.execute!(args)
84
+ end
@@ -1,164 +1,105 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'rubygems'
4
- require_relative '../lib/prima_twig.rb'
5
- require_relative '../lib/prima_aws_client.rb'
4
+ require_relative '../lib/prima_twig'
5
+ require_relative '../lib/prima_aws_client'
6
6
  require 'launchy'
7
- require 'json'
8
- require 'aws-sdk-s3'
7
+ require 'yaml'
9
8
 
10
9
  class TwigUpdateAmi
11
10
  include Command
12
11
  include PrimaAwsClient
12
+
13
13
  def initialize
14
- output 'Controllo se ci sono aggiornamenti da fare...'
15
- exec "gem update prima-twig && twig update-ami #{ARGV.join ' '}" unless `gem outdated`.lines.grep(/^prima-twig \(.*\)/).empty?
16
- @s3 = Aws::S3::Client.new
17
- @s3_bucket = 'prima-deploy'
18
- @templates_base_url = "https://s3-eu-west-1.amazonaws.com"
14
+ output 'Checking for new gem releases...'
15
+ unless `gem outdated`.lines.grep(/^prima-twig \(.*\)/).empty?
16
+ exec "gem update prima-twig && twig update-ami #{ARGV.join ' '}"
17
+ end
18
+ @state_path = "#{Dir.pwd}/ami_state.yml"
19
19
  end
20
20
 
21
21
  def execute!(args)
22
- update_amis(args[0], args[1], args[2], args[3], args[4])
23
- end
24
-
25
- private
26
-
27
- def update_amis(ami_template, ami_id, ami_name, ami_description, env)
28
- output "updating instance definition #{ami_template}".light_green
29
- Dir.chdir 'ami'
30
- update_instance_name(ami_id, ami_name, ami_description, ami_template)
31
- output 'running packer update (this could take some time)'.light_green
32
- ami_mappings = JSON.parse(@s3.get_object(bucket: @s3_bucket, key: "ami/ami-mappings.json")["body"].read())
33
-
34
- ami_mapping = nil
35
- ami_mappings.each do |item|
36
- if item['ami_template'].eql?(ami_template) and item['env'].eql?(env)
37
- ami_mapping = item
38
- end
39
- end
40
-
41
- stop_if(ami_mapping == nil, "No AMI found with parameters #{ami_template} and #{env}")
22
+ old_ami = args[0]
23
+ new_ami = args[1]
42
24
 
43
- new_ami_id = update_packer(ami_template, env, ami_mapping['teams_mapping'], ami_mapping['country'])
44
- # new_ami_id = 'ami-0d8488b68731e8756'
45
- Dir.chdir '..'
46
- stop_if(new_ami_id.to_s.empty?, 'Failed to generate AMI!'.red)
47
- output "new ami id: #{new_ami_id}"
48
-
49
- output 'searching for ami to update...'
50
- old_amis = update_ami_mappings(ami_mappings, ami_template, env, new_ami_id)
51
- stop_if(old_amis.empty?, "No ami to update! No #{ami_template} in env #{env}, exiting".yellow)
52
-
53
- output "retrieving stacks that uses old ami ids: #{old_amis}"
54
- exports = list_exports()
55
- stacks = get_stacks_from_exports(exports, old_amis)
56
- stop_if(stacks.empty?, "No stack to update found! This means that ami-mapping file is not in sync, please check manually")
25
+ output "retrieving stacks that uses old ami #{old_ami}".light_green
26
+ stacks = get_stacks_from_exports(list_exports, old_ami)
27
+ stop_if(stacks.empty?, 'No stack to update! Please check manually'.red)
57
28
 
58
29
  stacks.each do |stack|
59
- output "processing stack #{stack}"
30
+ output "processing stack #{stack}".light_green
60
31
  if stack.include?('qa')
61
- output "skipping stack #{stack} because is a qa"
32
+ output "skipping stack #{stack} because is a qa".yellow
62
33
  next
63
34
  else
64
35
  stack_parameters = get_stack_parameters(stack)
65
- stack_parameters = update_stack_parameters(stack_parameters, "AMIID", new_ami_id)
66
- if stack.include?('batch')
67
- if stack.include?('offsite-backups')
68
- stack_template = File.read("./cloudformation/stacks/batch/compute-environment-offsite-backups.yml")
69
- else
70
- stack_template = File.read("./cloudformation/stacks/batch/compute-environment.yml")
71
- end
72
- else
73
- stack_parameters = update_stack_parameters(stack_parameters, "DesiredCapacity", get_desired_capacity(stack).to_s)
74
- stack_template = File.read("./cloudformation/stacks/asg/#{stack.to_s.split("/")[1]}.yml")
36
+ stack_parameters = update_stack_parameters(stack_parameters, 'AMIID', new_ami)
37
+ unless stack.include?('batch')
38
+ stack_parameters = update_stack_parameters(stack_parameters, 'DesiredCapacity', get_desired_capacity(stack).to_s)
75
39
  end
76
- update_stack(stack, stack_template, stack_parameters)
40
+
41
+ update_stack_reuse_template(stack, stack_parameters)
77
42
  end
78
43
  end
79
44
 
80
45
  stacks.each do |stack|
81
- if stack.include?('qa')
82
- next
46
+ next if stack.include?('qa')
47
+
48
+ wait_for_stack_ready(stack, %w[CREATE_FAILED ROLLBACK_IN_PROGRESS ROLLBACK_FAILED DELETE_IN_PROGRESS DELETE_FAILED DELETE_COMPLETE UPDATE_ROLLBACK_FAILED UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS UPDATE_ROLLBACK_COMPLETE ROLLBACK_COMPLETE])
49
+ end
50
+
51
+ output 'Saving new ami in ami_state.yml'.light_green
52
+ File.open(@state_path, 'r') do |f|
53
+ @config = YAML.load(f.read)
54
+ end
55
+
56
+ @config['countries'].each do |country|
57
+ country['amis'].each do |ami|
58
+ ami['id'] = new_ami if ami['id'] == old_ami
83
59
  end
84
- wait_for_stack_ready(stack, ['CREATE_FAILED', 'ROLLBACK_IN_PROGRESS', 'ROLLBACK_FAILED', 'DELETE_IN_PROGRESS', 'DELETE_FAILED', 'DELETE_COMPLETE', 'UPDATE_ROLLBACK_FAILED', 'UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS', 'UPDATE_ROLLBACK_COMPLETE', 'ROLLBACK_COMPLETE'])
85
60
  end
86
61
 
87
- output 'writing new ami mapping'
88
- File.open("ami/ami-mappings.json", 'w+') do |f|
89
- mapping_file = JSON.pretty_generate(ami_mappings)
90
- f.write(mapping_file)
91
- @s3.put_object(bucket: @s3_bucket, key: "ami/ami-mappings.json", body: mapping_file)
62
+ File.open(@state_path, 'w+') do |f|
63
+ yaml = YAML.dump(@config)
64
+ f.write(yaml)
92
65
  end
93
66
 
94
- output 'Update finished! ( ͡° ͜ʖ ͡°)'
67
+ output 'Update finished! ( ͡° ͜ʖ ͡°)'.light_green
95
68
  end
96
69
 
97
- def get_stacks_from_exports(exports, old_amis)
70
+ private
71
+
72
+ def get_stacks_from_exports(exports, old_ami)
98
73
  stacks = []
99
- old_amis.each do |old_ami|
100
- exports.each do |export|
101
- if export.value.eql?(old_ami)
102
- stacks.insert(0,export.exporting_stack_id)
103
- end
104
- end
74
+ exports.each do |export|
75
+ stacks.insert(0, export.exporting_stack_id) if export.value.eql?(old_ami)
105
76
  end
106
77
  stacks
107
78
  end
108
79
 
109
- def update_ami_mappings(mappings, ami_template, env, new_ami_id)
110
- old_values = []
111
- mappings.each do |item|
112
- if item['ami_template'].eql?(ami_template) and item['env'].eql?(env)
113
- old_values.insert(0,item['ami_id'])
114
- item['ami_id'] = new_ami_id
115
- end
116
- end
117
- old_values.uniq
118
- end
119
-
120
80
  def update_stack_parameters(stack_parameters, key, value)
121
81
  stack_parameters.each do |param|
122
- if param.parameter_key == key
123
- param.parameter_value = value
124
- end
82
+ param.parameter_value = value if param.parameter_key == key
125
83
  end
126
84
  stack_parameters
127
85
  end
128
86
 
129
- def update_instance_name(ami_id, ami_name, ami_description, ecs_json_path)
130
- ecs_json = JSON.parse File.read(ecs_json_path)
131
-
132
- ecs_json['builders'][0]['source_ami'] = ami_id
133
- ecs_json['builders'][0]['ami_name'] = ami_name
134
- ecs_json['builders'][0]['ami_description'] = ami_description
135
-
136
- File.open ecs_json_path, 'w' do |f|
137
- f.write(JSON.pretty_generate(ecs_json))
138
- end
139
- end
140
-
141
87
  def get_desired_capacity(stack_name)
142
88
  stack_outputs = get_stack_outputs(stack_name)
143
89
  stack_outputs.each do |out|
144
- if out.export_name.include?('EC2Fleet') or out.export_name.include?('AutoScalingGroup') or out.export_name.include?('NodeGroup')
90
+ if out.export_name.include?('EC2Fleet') || out.export_name.include?('AutoScalingGroup') || out.export_name.include?('NodeGroup')
145
91
  return get_autoscaling_capacity(out.output_value)
146
92
  end
147
93
  end
148
94
  end
149
95
 
150
- def update_packer(json_filename, env, teams, country)
151
- execute_command "AWS_MAX_ATTEMPTS=90 AWS_POLL_DELAY_SECONDS=60 packer build -var datadog_apikey=`biscuit get -f ../configs/secrets/common.yml common_production_apikey_datadog` -var github_token=`biscuit get -f ../configs/secrets/common.yml common_private_repo_github_token` -var drone_key=\"`biscuit get -f ../configs/secrets/common.yml drone_license_key`\" -var env=#{env} -var teams_mapping=#{teams} -var country=#{country} -machine-readable ./#{json_filename} | tee build.log"
152
- `grep 'artifact,0,id' build.log | cut -d, -f6 | cut -d: -f2`.sub(/\n/, '')
153
- end
154
-
155
96
  def help_content
156
97
  <<-HELP
157
98
 
158
99
  twig-update-ami
159
100
  ===========
160
101
 
161
- Updates ami version and applies it to stacks on cloudformation
102
+ Updates AutoScalingGroups/BatchComputeEnvs with a new AMI
162
103
 
163
104
  Synopsis
164
105
  --------
@@ -168,8 +109,8 @@ class TwigUpdateAmi
168
109
  Description
169
110
  -----------
170
111
 
171
- from artemide main folder run
172
- `twig-update-ami ${AMI_TEMPLATE} ${AMI_ID} ${AMI_NAME} ${AMI_DESCRIPTION} ${ENV}`
112
+ from tsunami main folder run
113
+ `aws-vault exec AWS_PROFILE_WITH_ACCESS_TO_COUNTRY_ACCOUNT -- twig-update-ami ${OLD_AMI} ${NEW_AMI}`
173
114
 
174
115
  Subcommand for Twig: <http://rondevera.github.io/twig/>
175
116
  Author: Eugenio Laghi <https://github.com/eugeniolaghi>
@@ -177,13 +118,6 @@ class TwigUpdateAmi
177
118
  HELP
178
119
  end
179
120
 
180
- class ::Hash
181
- def deep_merge(second)
182
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
183
- self.merge(second.to_h, &merger)
184
- end
185
- end
186
-
187
121
  args = ARGV.dup
188
122
 
189
123
  if args.include?('--help')
@@ -175,6 +175,32 @@ module PrimaAwsClient
175
175
  end
176
176
  end
177
177
 
178
+ def update_stack_reuse_template(stack_name, parameters = [], tags = [], role = nil)
179
+ cf_args = {
180
+ stack_name: stack_name,
181
+ use_previous_template: true,
182
+ parameters: parameters,
183
+ tags: tags,
184
+ capabilities: ['CAPABILITY_IAM']
185
+ }
186
+
187
+ if role != nil then
188
+ cf_args.merge!(role_arn: role)
189
+ end
190
+
191
+ begin
192
+ cf_client.update_stack(cf_args)
193
+ rescue Aws::CloudFormation::Errors::Throttling => e
194
+ output 'Throttling, retrying in 15 seconds'.red
195
+ sleep 15
196
+ update_stack(stack_name, template_body, parameters = [], tags = [])
197
+ rescue Aws::CloudFormation::Errors::ValidationError => e
198
+ raise e
199
+ else
200
+ output "L'update dello stack #{stack_name} è stato avviato".green
201
+ end
202
+ end
203
+
178
204
  def stack_exists?(stack_name)
179
205
  begin
180
206
  cf_client.describe_stacks(stack_name: stack_name)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prima-twig
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.6
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matteo Giachino
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2020-10-21 00:00:00.000000000 Z
17
+ date: 2020-11-16 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: aws-sdk-autoscaling
@@ -73,21 +73,21 @@ dependencies:
73
73
  - !ruby/object:Gem::Version
74
74
  version: '1'
75
75
  - !ruby/object:Gem::Dependency
76
- name: aws-sdk-ec2
76
+ name: aws-sdk-core
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '1'
81
+ version: '3'
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '1'
88
+ version: '3'
89
89
  - !ruby/object:Gem::Dependency
90
- name: aws-sdk-ecs
90
+ name: aws-sdk-ec2
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - "~>"
@@ -101,7 +101,7 @@ dependencies:
101
101
  - !ruby/object:Gem::Version
102
102
  version: '1'
103
103
  - !ruby/object:Gem::Dependency
104
- name: aws-sdk-elasticloadbalancingv2
104
+ name: aws-sdk-ecs
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
@@ -115,7 +115,7 @@ dependencies:
115
115
  - !ruby/object:Gem::Version
116
116
  version: '1'
117
117
  - !ruby/object:Gem::Dependency
118
- name: aws-sdk-s3
118
+ name: aws-sdk-elasticloadbalancingv2
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - "~>"
@@ -129,19 +129,19 @@ dependencies:
129
129
  - !ruby/object:Gem::Version
130
130
  version: '1'
131
131
  - !ruby/object:Gem::Dependency
132
- name: aws-sdk-core
132
+ name: aws-sdk-s3
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: '3'
137
+ version: '1'
138
138
  type: :runtime
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '3'
144
+ version: '1'
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: colorize
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -286,11 +286,13 @@ description: Our tools to manage git and github
286
286
  email: matteo.giachino@prima.it
287
287
  executables:
288
288
  - twig-feature
289
+ - twig-packer-builder
289
290
  - twig-update-ami
290
291
  extensions: []
291
292
  extra_rdoc_files: []
292
293
  files:
293
294
  - bin/twig-feature
295
+ - bin/twig-packer-builder
294
296
  - bin/twig-update-ami
295
297
  - lib/command.rb
296
298
  - lib/prima_aws_client.rb
@@ -314,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
314
316
  - !ruby/object:Gem::Version
315
317
  version: '0'
316
318
  requirements: []
317
- rubygems_version: 3.0.1
319
+ rubygems_version: 3.0.3
318
320
  signing_key:
319
321
  specification_version: 4
320
322
  summary: The Prima twig toolbelt