openstax_aws 1.1.0 → 1.4.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: 5a062d5bb4d0c5c73fd23b6ed4c1d1b36e18d24143e6a74c7a51e4e3c552048d
4
- data.tar.gz: a7fcc57860108b12434d66f5e5ccc90e27494bf892a67a1f961aba942398ab8e
3
+ metadata.gz: 75f65f32cd2e572d1e83f624977186c7aee220c6d51924333fa08af2255543ad
4
+ data.tar.gz: bf3969a29e8fb4ff94b54bbd9685581cdff28f9c160f3ebe0fa26b92f4875575
5
5
  SHA512:
6
- metadata.gz: 3be0e6e5c49c30f40e98575d0957fad14e025c6297f7276bcc71b8f42f427b0b349ff47b1c60ca3089a1901be4f9643afe68275aa468bb04e2a1412f426d5b37
7
- data.tar.gz: a369f3fb8b8a8f39165358cc24352b0a1b21c6af2fa1baf4bd4fc816877cf3ae8d2fa3e4bff67e49e7930ceb7e42e61942f31ee78c3e00bc92605fa3cb30dee8
6
+ metadata.gz: 76287d75f76a51cbeb635e6013f5e896174537fcba6352f5febba64c562c3cb857f82aa2a03f71af9583c5db3e8527bf0298e4e2759db9ac658b7a13c0fa6c14
7
+ data.tar.gz: f86924695c16ce1b3729e9a405e36603761477aa4c7af798ea50bd5faeffcaf18d3caca056db5f8d72127c8bf9c7edfd464d46a7e109f8597d1437ecffb2788f
@@ -0,0 +1,31 @@
1
+ name: Tests
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - master
8
+
9
+ jobs:
10
+ tests:
11
+ timeout-minutes: 10
12
+ runs-on: ubuntu-18.04
13
+
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - uses: actions/setup-ruby@v1
17
+ with:
18
+ ruby-version: 2.6
19
+ - uses: actions/cache@v2
20
+ with:
21
+ path: vendor/bundle
22
+ key: ${{ runner.os }}-gems-pr-${{ hashFiles('**/Gemfile.lock') }}
23
+ restore-keys: |
24
+ ${{ runner.os }}-gems-pr-
25
+ - name: Test
26
+ run: |
27
+ gem install bundler --force --no-document --version 2.1.4
28
+ bundle config path vendor/bundle
29
+ bundle config jobs 2
30
+ bundle install
31
+ bundle exec rspec
data/CHANGELOG.md CHANGED
@@ -6,16 +6,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- ## [1.1.0] - 2020-10-20
10
-
11
- Fixed Packer debug mode by reading and printing each character from Packer instead of each line.
9
+ ## [1.2.0] - 2021-01-12
12
10
 
13
- Restricted AMI search to images owned by the same account to prevent a potential security flaw.
11
+ - Added additional method to MskCluster resource, to return sorted list of bootstrap brokers
12
+ - Replaced Travis with GH Actions
13
+ - All secret types now default to SecureString, not just the RSA keys
14
+ - Added CloudFormation ERB templates (cfn files that end in .yml.erb)
15
+ - Gracefully handle interrupts while running Packer and return Packer's exit status from the call
14
16
 
15
- Gitignored Gemfile.lock.
17
+ ## [1.1.0] - 2020-10-20
16
18
 
17
- Removed development dependency on bundler 1.
19
+ - Fixed Packer debug mode by reading and printing each character from Packer instead of each line.
20
+ - Restricted AMI search to images owned by the same account to prevent a potential security flaw.
21
+ - Gitignored Gemfile.lock.
22
+ - Removed development dependency on bundler 1.
18
23
 
19
24
  ## [1.0.0] - 2020-10-03
20
25
 
21
- First official version.
26
+ - First official version.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # aws-ruby
2
2
 
3
- [![Build Status](https://travis-ci.org/openstax/aws-ruby.svg?branch=master)](https://travis-ci.org/openstax/aws-ruby)
3
+ [![Tests](https://github.com/openstax/aws-ruby/workflows/Tests/badge.svg)](https://github.com/openstax/aws-ruby/actions?query=workflow:Tests)
4
4
 
5
5
  The `openstax_aws` gem helps you deploy your applications to AWS using CloudFormation. It provides a layer on top of
6
6
  the AWS SDKs to help coordinate common deployment steps and configurations.
@@ -260,6 +260,32 @@ module OpenStax::Aws
260
260
  nil # can be overridden by the DSL
261
261
  end
262
262
 
263
+ def failed_statuses_table
264
+ rows = []
265
+
266
+ stacks.each do |stack|
267
+ stack.status(reload: false).failed_events_since_last_user_event.each do |event|
268
+ rows.push([stack.name, event.status_text, event.status_reason])
269
+ end if stack.status.failed?
270
+ end
271
+
272
+ column_widths = [
273
+ 2 + rows.reduce(0) { |result, rowdata| [result, rowdata[0].length].max },
274
+ 2 + rows.reduce(0) { |result, rowdata| [result, rowdata[1].length].max },
275
+ 0
276
+ ]
277
+
278
+ output = []
279
+
280
+ output.push(["Stack", "Status", "Reason"].each_with_index.map { |header, index| header.ljust(column_widths[index]) }.join(''))
281
+
282
+ rows.each { |rowdata|
283
+ output.push(rowdata.each_with_index.map { |value, index| value.ljust(column_widths[index]) }.join(''))
284
+ }
285
+
286
+ output.join("\n")
287
+ end
288
+
263
289
  protected
264
290
 
265
291
  def parameter_default(parameter_name)
@@ -360,13 +386,24 @@ module OpenStax::Aws
360
386
  get_image_tag(image_id: image_id, key: "sha")
361
387
  end
362
388
 
363
- protected
364
-
365
389
  def secrets_namespace(id: 'default')
366
390
  raise "Override this method in your deployment class and provide a namespace " \
367
391
  "for secrets data in the AWS Parameter Store. The key there will be this namespace " \
368
392
  "prefixed by the environment name and suffixed with the secret name."
369
393
  end
370
394
 
395
+ def log_and_exit_if_failed_status
396
+ begin
397
+ yield
398
+ rescue
399
+ if status.failed?
400
+ logger.fatal("The following errors have occurred: \n#{failed_statuses_table}")
401
+ exit(1)
402
+ else
403
+ raise
404
+ end
405
+ end
406
+ end
407
+
371
408
  end
372
409
  end
@@ -34,7 +34,8 @@ module OpenStax::Aws
34
34
  begin
35
35
  Aws::CloudFront::Waiters::InvalidationCompleted.new(
36
36
  client: client,
37
- before_attempt: ->(*) { wait_message.say_it }
37
+ before_attempt: ->(*) { wait_message.say_it },
38
+ max_attempts: 60
38
39
  ).wait(
39
40
  distribution_id: id,
40
41
  id: invalidation_id
@@ -8,11 +8,20 @@ module OpenStax::Aws
8
8
  ::Git.ls_remote("https://github.com/#{org_slash_repo}")["branches"][branch][:sha]
9
9
  end
10
10
 
11
- def self.file_content_at_sha(org_slash_repo:, sha:, path:)
12
- location = "https://raw.githubusercontent.com/#{org_slash_repo}/#{sha}/#{path}"
13
- file = open(location)
14
- file.read
11
+ def self.file_content_at_sha(org_slash_repo:, sha:, path:, github_token: nil )
12
+ if github_token.blank?
13
+ location = "https://raw.githubusercontent.com/#{org_slash_repo}/#{sha}/#{path}"
14
+ file = URI.open(location)
15
+ file.read
16
+ else
17
+ uri = URI("https://raw.githubusercontent.com/#{org_slash_repo}/#{sha}/#{path}")
18
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
19
+ request = Net::HTTP::Get.new uri.request_uri
20
+ request.basic_auth 'token', github_token
21
+ response = http.request request
22
+ response.body
23
+ end
24
+ end
15
25
  end
16
-
17
26
  end
18
27
  end
@@ -14,6 +14,10 @@ module OpenStax::Aws
14
14
  client.get_bootstrap_brokers(cluster_arn: cluster_arn).bootstrap_broker_string
15
15
  end
16
16
 
17
+ def sorted_bootstrap_broker_string
18
+ bootstrap_broker_string.split(',').sort.join(',')
19
+ end
20
+
17
21
  end
18
22
  end
19
23
 
@@ -55,7 +55,7 @@ module OpenStax::Aws
55
55
  stdout_err.sync = true
56
56
 
57
57
  while char = stdout_err.getc do
58
- print char
58
+ STDERR.print char
59
59
  end
60
60
  end
61
61
  end
@@ -41,36 +41,81 @@ module OpenStax::Aws
41
41
  cmd = "PACKER_LOG=1 #{cmd}" if @verbose
42
42
  cmd = "#{cmd} --debug" if @debug
43
43
 
44
- cmd = "#{cmd} #{@absolute_file_path}"
44
+ cmd
45
45
  end
46
46
 
47
47
  def run
48
48
  @logger.info("**** DRY RUN ****") if @dry_run
49
- @logger.info("Running: #{command}")
49
+ @logger.info("Running: #{command} #{@absolute_file_path}")
50
50
 
51
51
  if !@dry_run
52
52
  @logger.info("Printing stderr for desired verbosity")
53
- ami = ""
54
53
 
55
- Open3.popen2e(command) do |stdin, stdout_err, wait_thr|
56
- stdout_err.sync = true
54
+ tmpdir = nil
57
55
 
58
- line = ''
56
+ begin
57
+ config_path = @absolute_file_path
59
58
 
60
- while char = stdout_err.getc do
61
- line << char
62
- print char
59
+ # Can't handle modifying HCL2 templates yet
60
+ if config_path.ends_with?('.json')
61
+ config = JSON.parse(File.read(config_path))
62
+ config['post-processors'] ||= []
63
+ manifest_config = (config['post-processors']).find do |processor|
64
+ processor['type'] == 'manifest'
65
+ end
63
66
 
64
- next unless char == "\n"
67
+ # Configure a manifest post-processor if not already configured
68
+ if manifest_config.nil?
69
+ tmpdir = Dir.mktmpdir
65
70
 
66
- matchami = line.match(/AMI: (ami-[0-9\-a-z]*)/i)
67
- ami = matchami.captures[0] if matchami
71
+ manifest_config = { 'type' => 'manifest', 'output' => "#{tmpdir}/manifest.json" }
68
72
 
69
- line = ''
73
+ config['post-processors'] << manifest_config
74
+
75
+ config_path = "#{tmpdir}/packer.json"
76
+
77
+ File.write(config_path, JSON.dump(config))
78
+ end
70
79
  end
71
- end
72
80
 
73
- puts ami
81
+ Open3.popen2e("#{command} #{config_path}") do |stdin, stdout_err, wait_thr|
82
+ begin
83
+ previous_interrupt_handler = Signal.trap 'INT' do
84
+ # Interrupt Packer
85
+ Process.kill 'INT', wait_thr.pid
86
+
87
+ # Restore previous interrupt handler so we don't interrupt Packer again
88
+ Signal.trap 'INT', previous_interrupt_handler
89
+
90
+ # Disable other code that restores previous interrupt
91
+ previous_interrupt_handler = nil
92
+ end
93
+
94
+ stdout_err.sync = true
95
+
96
+ # Send all packer output to STDERR
97
+ while char = stdout_err.getc do
98
+ STDERR.print char
99
+ end
100
+ ensure
101
+ # Restore previous interrupt unless we did so already
102
+ Signal.trap 'INT', previous_interrupt_handler unless previous_interrupt_handler.nil?
103
+ end
104
+
105
+ # Read the AMI ID from the manifest file and output it to STDOUT
106
+ unless manifest_config.nil?
107
+ manifest = File.read(manifest_config['output']) rescue nil
108
+
109
+ puts JSON.parse(manifest)['builds'].last['artifact_id'].split(':', 2).last \
110
+ unless manifest.nil?
111
+ end
112
+
113
+ # Return Packer's exit status wrapped in a Process::Status object
114
+ wait_thr.value
115
+ end
116
+ ensure
117
+ FileUtils.remove_entry(tmpdir) unless tmpdir.nil?
118
+ end
74
119
  end
75
120
  end
76
121
 
@@ -32,9 +32,12 @@ module OpenStax::Aws
32
32
  dry_run: dry_run)
33
33
  end
34
34
 
35
- def build
35
+ def build(debug: false, env_vars: {})
36
36
  # SAM doesn't have an API or SDK - we have to make calls to its CLI
37
+ env_vars_prefix = env_vars.map { |variable, value| "#{variable}=#{value}" }.join(' ')
37
38
  command = "sam build -t #{absolute_template_path} -b #{build_directory}"
39
+ command += ' --debug' if debug
40
+ command = "#{env_vars_prefix} #{command}" if env_vars_prefix.present?
38
41
  System.call(command, logger: logger, dry_run: dry_run)
39
42
  end
40
43
 
@@ -50,7 +53,8 @@ module OpenStax::Aws
50
53
  " --capabilities CAPABILITY_IAM" \
51
54
  " --s3-bucket #{bucket_name}" \
52
55
  " --s3-prefix #{name}" \
53
- " --stack-name #{name}"
56
+ " --stack-name #{name}" \
57
+ " --region #{region}"
54
58
 
55
59
  if params.any?
56
60
  command += " --parameter-overrides #{self.class.format_hash_as_cli_stack_parameters(params)}"
@@ -146,7 +146,7 @@ module OpenStax::Aws
146
146
 
147
147
  def process_individual_spec_value(spec_value, substitutions)
148
148
  generated = false
149
- type = "String"
149
+ type = "SecureString"
150
150
 
151
151
  value = case spec_value
152
152
  when /^random\(hex,(\d+)\)$/
@@ -158,7 +158,6 @@ module OpenStax::Aws
158
158
  num_characters = $1.to_i
159
159
  SecureRandom.urlsafe_base64(num_characters)[0..num_characters-1]
160
160
  when /^rsa\((\d+)\)$/
161
- type = "SecureString"
162
161
  generated = true
163
162
  key_length = $1.to_i
164
163
  OpenSSL::PKey::RSA.new(key_length).to_s
@@ -39,6 +39,7 @@ module OpenStax::Aws
39
39
  org_slash_repo: attributes[:org_slash_repo],
40
40
  sha: attributes[:sha],
41
41
  path: attributes[:path],
42
+ github_token: attributes[:github_token],
42
43
  format: attributes[:format].to_sym,
43
44
  top_key: attributes[:top_key].to_sym,
44
45
  preparser: attributes[:preparser]
@@ -13,11 +13,12 @@ module OpenStax::Aws
13
13
  new(content: content, format: format, top_key: top_key, preparser: preparser)
14
14
  end
15
15
 
16
- def self.from_git(org_slash_repo:, sha:, path:, format:, top_key: nil, preparser: nil)
16
+ def self.from_git(org_slash_repo:, sha:, path:, github_token: nil, format:, top_key: nil, preparser: nil)
17
17
  content = OpenStax::Aws::GitHelper.file_content_at_sha(
18
18
  org_slash_repo: org_slash_repo,
19
19
  sha: sha,
20
- path: path
20
+ path: path,
21
+ github_token: github_token
21
22
  )
22
23
  new(content: content, format: format, top_key: top_key, preparser: preparser)
23
24
  end
@@ -52,9 +52,13 @@ module OpenStax::Aws
52
52
  path = File.join(base_directory, "#{@id}.yml")
53
53
 
54
54
  if !File.file?(path)
55
- path = File.join(base_directory, "#{@id}.json")
55
+ path = File.join(base_directory, "#{@id}.yml.erb")
56
+
56
57
  if !File.file?(path)
57
- raise "Couldn't infer an existing template file for stack #{@id}"
58
+ path = File.join(base_directory, "#{@id}.json")
59
+ if !File.file?(path)
60
+ raise "Couldn't infer an existing template file for stack #{@id}"
61
+ end
58
62
  end
59
63
  end
60
64
  end
@@ -26,8 +26,20 @@ module OpenStax::Aws
26
26
  File.basename(absolute_file_path)
27
27
  end
28
28
 
29
+ def extname
30
+ File.extname(absolute_file_path)
31
+ end
32
+
33
+ def erb?
34
+ extname == '.erb'
35
+ end
36
+
29
37
  def body
30
- @body ||= File.read(absolute_file_path)
38
+ return @body unless @body.nil?
39
+
40
+ @body = File.read(absolute_file_path)
41
+ @body = ERB.new(@body).tap { |erb| erb.filename = absolute_file_path }.result if erb?
42
+ @body
31
43
  end
32
44
 
33
45
  def hash
@@ -88,7 +100,7 @@ module OpenStax::Aws
88
100
  end
89
101
 
90
102
  def is_sam?
91
- body.match(/Transform: AWS::Serverless/).present?
103
+ body.match(/Transform: .?AWS::Serverless/).present?
92
104
  end
93
105
 
94
106
  protected
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module Aws
3
- VERSION = "1.1.0"
3
+ VERSION = "1.4.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstax_aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-20 00:00:00.000000000 Z
11
+ date: 2022-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-autoscaling
@@ -273,8 +273,8 @@ executables:
273
273
  extensions: []
274
274
  extra_rdoc_files: []
275
275
  files:
276
+ - ".github/workflows/tests.yml"
276
277
  - ".gitignore"
277
- - ".travis.yml"
278
278
  - CHANGELOG.md
279
279
  - Gemfile
280
280
  - LICENSE.txt
@@ -327,7 +327,7 @@ licenses:
327
327
  - MIT
328
328
  metadata:
329
329
  allowed_push_host: https://rubygems.org
330
- post_install_message:
330
+ post_install_message:
331
331
  rdoc_options: []
332
332
  require_paths:
333
333
  - lib
@@ -343,7 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
343
343
  version: '0'
344
344
  requirements: []
345
345
  rubygems_version: 3.1.4
346
- signing_key:
346
+ signing_key:
347
347
  specification_version: 4
348
348
  summary: openstax IaC
349
349
  test_files: []
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.6
5
- cache: bundler
6
- bundler_args: --retry=6
7
- script:
8
- - bundle exec rake
9
- notifications:
10
- email: false
11
- before_install:
12
- - gem install bundler