openstax_aws 1.1.0 → 1.4.0

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 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