terraspace-bundler 0.3.2 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/exe/{terraform-bundler → terraspace-bundler} +0 -0
  4. data/lib/terraspace_bundler/cli/bundle.rb +1 -1
  5. data/lib/terraspace_bundler/cli/purge_cache.rb +1 -1
  6. data/lib/terraspace_bundler/dsl/syntax.rb +4 -0
  7. data/lib/terraspace_bundler/exporter/base.rb +1 -1
  8. data/lib/terraspace_bundler/exporter/copy.rb +2 -1
  9. data/lib/terraspace_bundler/exporter.rb +4 -4
  10. data/lib/terraspace_bundler/extract/tar.rb +34 -0
  11. data/lib/terraspace_bundler/extract/zip.rb +16 -0
  12. data/lib/terraspace_bundler/extract.rb +21 -0
  13. data/lib/terraspace_bundler/info.rb +7 -0
  14. data/lib/terraspace_bundler/mod/concerns/local_concern.rb +10 -0
  15. data/lib/terraspace_bundler/mod/concerns/notation_concern.rb +42 -0
  16. data/lib/terraspace_bundler/mod/concerns/path_concern.rb +90 -0
  17. data/lib/terraspace_bundler/mod/{stack_concern.rb → concerns/stack_concern.rb} +16 -1
  18. data/lib/terraspace_bundler/mod/fetcher/base.rb +27 -0
  19. data/lib/terraspace_bundler/mod/fetcher/gcs.rb +48 -0
  20. data/lib/terraspace_bundler/mod/{downloader.rb → fetcher/git.rb} +10 -16
  21. data/lib/terraspace_bundler/mod/fetcher/local.rb +15 -0
  22. data/lib/terraspace_bundler/mod/fetcher/s3.rb +66 -0
  23. data/lib/terraspace_bundler/mod/fetcher.rb +18 -0
  24. data/lib/terraspace_bundler/mod/http/concern.rb +45 -0
  25. data/lib/terraspace_bundler/mod/http/source.rb +19 -0
  26. data/lib/terraspace_bundler/mod/{props_extension.rb → props/extension.rb} +6 -2
  27. data/lib/terraspace_bundler/mod/props/typer.rb +39 -0
  28. data/lib/terraspace_bundler/mod/props.rb +101 -0
  29. data/lib/terraspace_bundler/mod/registry.rb +77 -23
  30. data/lib/terraspace_bundler/mod.rb +23 -15
  31. data/lib/terraspace_bundler/syncer.rb +1 -1
  32. data/lib/terraspace_bundler/terrafile.rb +3 -3
  33. data/lib/terraspace_bundler/util/git.rb +10 -4
  34. data/lib/terraspace_bundler/version.rb +1 -1
  35. data/lib/terraspace_bundler.rb +1 -0
  36. data/spec/fixtures/terrafiles/example/Terrafile +29 -0
  37. data/spec/terraform_bundler/mod/props_spec.rb +34 -0
  38. data/terraspace-bundler.gemspec +4 -0
  39. metadata +83 -10
  40. data/lib/terraspace_bundler/mod/path_concern.rb +0 -37
  41. data/lib/terraspace_bundler/mod/props_builder.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a02d9119392f13a0a31079c756f565f1de0e4d200a3af9f84c732f4656ed6fc
4
- data.tar.gz: d9e07212f6efce634f6836bb8ac2a1dd184dc5a34562c24252c8e69c27f4889c
3
+ metadata.gz: f59f992f4e07582208760a29beac2bd1a507164e6cfb19fe4fca27ac1f9d04dc
4
+ data.tar.gz: df2b9be3142d30891cb959cafcd5376987e92192b24a85e274606fe761bb1742
5
5
  SHA512:
6
- metadata.gz: 6e79f9d42d0ddc7856877ce4d1ce0dd2452eddb883e68694b28bc776512a56bcf829747bd589a66a28bf9687dca590404ff6cc8906df57c96a8dc62c40d12571
7
- data.tar.gz: 1915a7ec28c0cdce027b5f5ebcee59924853d4ad3ad8de2cc6e0db5ab5ff7f6d4d2260881e9df42cbeddc226d5574793701533647d07c86f576c04c4b3dcc7dc
6
+ metadata.gz: 73a7f1ca1642c6fe6707b30ac429cc8ca958e37fb86393bf54fea2345ccc0d3cfee2a2a9e7b63dbcb936338e774d1feed95a3276bdbd9b906109671313f61de8
7
+ data.tar.gz: 02f65ae63819e83d994de88c57c6c32c078d9627a2e6bebea9711c74d47c48f18186d1bd734989618a17f096a0459586649a9a1b8615e30a73f29341200dbc92
data/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [0.4.1] - 2021-09-30
7
+ - [#13](https://github.com/boltops-tools/terraspace-bundler/pull/13) fix stacks Array option
8
+
9
+ ## [0.4.0] - 2021-08-10
10
+ - [#10](https://github.com/boltops-tools/terraspace-bundler/pull/10) terraspace bundle info: warning when no lockfile
11
+ - [#12](https://github.com/boltops-tools/terraspace-bundler/pull/12) support for: private registry, s3, gcs, local
12
+
13
+ ## [0.3.4] - 2021-04-15
14
+ - [#11](https://github.com/boltops-tools/terraspace-bundler/pull/11) improve registry dectection and gitlab repository support
15
+
16
+ ## [0.3.3] - 2021-02-24
17
+ - [#8](https://github.com/boltops-tools/terraspace-bundler/pull/8) fix https sources
18
+ - [#9](https://github.com/boltops-tools/terraspace-bundler/pull/9) Git checkout retry with v
19
+
6
20
  ## [0.3.2]
7
21
  - #4 only purge and export explicit mods
8
22
  - are you sure prompt for purge_cache
File without changes
@@ -37,7 +37,7 @@ class TerraspaceBundler::CLI
37
37
  terrafile_option.call
38
38
  def update(*mods)
39
39
  TB.update_mode = true
40
- TB::Runner.new(options.merge(mods: mods, mode: "update")).run
40
+ TB::Runner.new(options.merge(mods: mods)).run
41
41
  end
42
42
  end
43
43
  end
@@ -1,6 +1,6 @@
1
1
  class TerraspaceBundler::CLI
2
2
  class PurgeCache < Base
3
- include TB::Mod::PathConcern
3
+ include TB::Mod::Concerns::PathConcern
4
4
  include TB::Util::Logging
5
5
  include TB::Util::Sure
6
6
 
@@ -21,6 +21,10 @@ class TerraspaceBundler::Dsl
21
21
  config.stack_options.merge!(value)
22
22
  end
23
23
 
24
+ def clone_with(value)
25
+ config.clone_with = value
26
+ end
27
+
24
28
  def config
25
29
  TB.config
26
30
  end
@@ -1,6 +1,6 @@
1
1
  class TerraspaceBundler::Exporter
2
2
  class Base
3
- include TB::Mod::PathConcern
3
+ include TB::Mod::Concerns::PathConcern
4
4
  include TB::Util::Logging
5
5
  end
6
6
  end
@@ -7,6 +7,7 @@ class TerraspaceBundler::Exporter
7
7
  def mod
8
8
  FileUtils.rm_rf(mod_path)
9
9
  FileUtils.mkdir_p(File.dirname(mod_path))
10
+ logger.debug "Copy: cp -r #{src_path} #{mod_path}"
10
11
  FileUtils.cp_r(src_path, mod_path)
11
12
  FileUtils.rm_rf("#{mod_path}/.git")
12
13
  end
@@ -17,7 +18,7 @@ class TerraspaceBundler::Exporter
17
18
 
18
19
  # src path is from the stage area
19
20
  def src_path
20
- path = stage_path(@mod.full_repo) # from PathConcern
21
+ path = stage_path(rel_dest_dir)
21
22
  path = "#{path}/#{@mod.subfolder}" if @mod.subfolder
22
23
  path
23
24
  end
@@ -1,6 +1,6 @@
1
1
  module TerraspaceBundler
2
2
  class Exporter
3
- include TB::Mod::PathConcern
3
+ include TB::Mod::Concerns::PathConcern
4
4
  include TB::Util::Logging
5
5
 
6
6
  def initialize(options={})
@@ -25,9 +25,9 @@ module TerraspaceBundler
25
25
  end
26
26
 
27
27
  def export(mod)
28
- downloader = Mod::Downloader.new(mod)
29
- downloader.run
30
- downloader.switch_version(mod.sha)
28
+ fetcher = Mod::Fetcher.new(mod).instance
29
+ fetcher.run
30
+ fetcher.switch_version(mod.sha)
31
31
  copy = Copy.new(mod)
32
32
  copy.mod
33
33
  copy.stacks
@@ -0,0 +1,34 @@
1
+ require 'rubygems/package'
2
+ require 'zlib'
3
+ require 'fileutils'
4
+
5
+ # Thanks: https://gist.github.com/ForeverZer0/2adbba36fd452738e7cca6a63aee2f30
6
+ class TerraspaceBundler::Extract
7
+ class Tar
8
+ # tar_gz_archive = '/tmp/terraspace/bundler/stage/s3-us-west-2.amazonaws.com/demo-terraform-test/modules/example-module.tgz'
9
+ # destination = '/tmp/terraspace/where/extract/to'
10
+ def self.extract(tar_gz_archive, destination)
11
+ reader = Zlib::GzipReader.open(tar_gz_archive)
12
+ Gem::Package::TarReader.new(reader) do |tar|
13
+ dest = nil
14
+ tar.each do |entry|
15
+ dest ||= File.join destination, entry.full_name
16
+ if entry.directory?
17
+ FileUtils.rm_rf dest unless File.directory? dest
18
+ FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
19
+ elsif entry.file?
20
+ FileUtils.rm_rf dest unless File.file? dest
21
+ File.open dest, "wb" do |f|
22
+ f.print entry.read
23
+ end
24
+ FileUtils.chmod entry.header.mode, dest, :verbose => false
25
+ elsif entry.header.typeflag == '2' #Symlink!
26
+ File.symlink entry.header.linkname, dest
27
+ end
28
+ dest = nil
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'zip'
3
+
4
+ class TerraspaceBundler::Extract
5
+ class Zip
6
+ def self.extract(file, dest)
7
+ ::Zip::File.open(file) { |zip_file|
8
+ zip_file.each { |f|
9
+ f_path=File.join(dest, f.name)
10
+ FileUtils.mkdir_p(File.dirname(f_path))
11
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
12
+ }
13
+ }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module TerraspaceBundler
2
+ class Extract
3
+ def self.extract(archive, dest)
4
+ FileUtils.rm_rf(dest)
5
+ FileUtils.mkdir_p(File.dirname(dest))
6
+
7
+ if archive.ends_with?('.tgz') || archive.ends_with?('.tar.gz')
8
+ Tar.extract(archive, dest)
9
+ elsif archive.ends_with?('.zip')
10
+ Zip.extract(archive, dest)
11
+ else
12
+ puts <<~EOL.color(:red)
13
+ ERROR: Unable to extract. Unsupported archive extension for:
14
+
15
+ #{archive}
16
+ EOL
17
+ exit 1
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,13 @@
1
1
  module TerraspaceBundler
2
2
  class Info < TB::CLI::Base
3
3
  def run
4
+ file = TB.config.lockfile
5
+ unless File.exist?(file)
6
+ logger.info "No #{file} found".color(:red)
7
+ logger.info "Maybe run: terraspace bundle"
8
+ return
9
+ end
10
+
4
11
  name = @options[:mod]
5
12
  found = lockfile.mods.find { |m| m.name == @options[:mod] }
6
13
  if found
@@ -0,0 +1,10 @@
1
+ module TerraspaceBundler::Mod::Concerns
2
+ module LocalConcern
3
+ def local?
4
+ source.starts_with?("/") ||
5
+ source.starts_with?(".") ||
6
+ source.starts_with?("..") ||
7
+ source.starts_with?("~")
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ require 'uri'
2
+
3
+ module TerraspaceBundler::Mod::Concerns
4
+ module NotationConcern
5
+ def remove_notations(source)
6
+ remove_subfolder_notation(remove_ref_notation(source))
7
+ end
8
+
9
+ def remove_ref_notation(source)
10
+ source.sub(/\?.*/,'')
11
+ end
12
+
13
+ def remove_subfolder_notation(source)
14
+ parts = clean_notation(source).split('//')
15
+ if parts.size == 2 # has subfolder
16
+ source.split('//')[0..-2].join('//') # remove only subfolder, keep rest of original source
17
+ else
18
+ source
19
+ end
20
+ end
21
+
22
+ def subfolder(source)
23
+ parts = clean_notation(source).split('//')
24
+ if parts.size == 2 # has subfolder
25
+ remove_ref_notation(parts.last)
26
+ end
27
+ end
28
+
29
+ def ref(source)
30
+ url = clean_notation(source)
31
+ uri = URI(url)
32
+ if uri.query
33
+ params = URI::decode_www_form(uri.query).to_h # if you are in 2.1 or later version of Ruby
34
+ params['ref']
35
+ end
36
+ end
37
+
38
+ def clean_notation(source)
39
+ source.sub(/.*::/,'').sub(%r{http[s?]://},'').sub(%r{git@(.*?):},'') # also remove git@ notation
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,90 @@
1
+ module TerraspaceBundler::Mod::Concerns
2
+ module PathConcern
3
+ def setup_tmp
4
+ FileUtils.mkdir_p(cache_root)
5
+ FileUtils.mkdir_p(stage_root)
6
+ end
7
+
8
+ def tmp_root
9
+ "/tmp/terraspace/bundler"
10
+ end
11
+
12
+ def cache_root
13
+ "#{tmp_root}/cache"
14
+ end
15
+
16
+ def stage_root
17
+ "#{tmp_root}/stage"
18
+ end
19
+
20
+ def cache_path(name)
21
+ [cache_root, parent_stage_folder, name].compact.join('/')
22
+ end
23
+
24
+ def stage_path(name)
25
+ [stage_root, parent_stage_folder, name].compact.join('/')
26
+ end
27
+
28
+ # Fetcher: Downloader/Local copies to a slightly different folder.
29
+ # Also, Copy will use this and reference same method so it's consistent.
30
+ def rel_dest_dir
31
+ case @mod.type
32
+ when 'local'
33
+ @mod.name # example-module
34
+ when 's3'
35
+ path = type_path # https://s3-us-west-2.amazonaws.com/demo-terraform-test/example-module.zip
36
+ remove_ext(path) # demo-terraform-test/modules/example-module
37
+ when 'gcs'
38
+ path = type_path # https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip
39
+ path.sub!(%r{storage/v\d+/},'')
40
+ remove_ext(path) # terraform-example-modules/modules/example-module
41
+ when 'http'
42
+ path = type_path # https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip
43
+ remove_ext(path) # terraform-example-modules/modules/example-module
44
+ when -> (_) { @mod.source.include?('git::') }
45
+ @mod.name # example-module
46
+ else # inferred git, registry
47
+ @mod.full_repo # tongueroo/example-module
48
+ end
49
+ end
50
+
51
+ def parent_stage_folder
52
+ case @mod.type
53
+ when 'local'
54
+ 'local'
55
+ when 'http'
56
+ 'http'
57
+ else # gcs, s3, git, registry
58
+ @mod.vcs_provider
59
+ end
60
+ end
61
+
62
+ def type_path
63
+ source = @mod.source
64
+ url = source.sub("#{@mod.type}::",'')
65
+ uri = URI(url)
66
+ uri.path.sub('/','') # removing leading slash to bucket name is the first thing
67
+ .sub(%r{//(.*)},'') # remove subfolder
68
+ end
69
+
70
+ def remove_ext(path)
71
+ ext = File.extname(path)
72
+ path.sub(ext,'')
73
+ end
74
+
75
+ def get_bucket_key(path)
76
+ bucket, *rest = path.split('/')
77
+ key = rest.join('/')
78
+ [bucket, key]
79
+ end
80
+
81
+ def mod_path
82
+ get_mod_path(@mod)
83
+ end
84
+
85
+ def get_mod_path(mod)
86
+ export_to = mod.export_to || TB.config.export_to
87
+ "#{export_to}/#{mod.name}"
88
+ end
89
+ end
90
+ end
@@ -1,10 +1,12 @@
1
- class TerraspaceBundler::Mod
1
+ module TerraspaceBundler::Mod::Concerns
2
2
  module StackConcern
3
3
  def stacks
4
4
  stacks = @props[:stacks] || @props[:stack]
5
5
  return unless stacks
6
6
  if all_stacks?(stacks)
7
7
  stacks = all_stacks
8
+ elsif stacks.is_a?(Array)
9
+ stacks = array_stacks(stacks)
8
10
  end
9
11
  normalize_stacks(stacks)
10
12
  end
@@ -28,6 +30,19 @@ class TerraspaceBundler::Mod
28
30
  end
29
31
  end
30
32
 
33
+ def array_stacks(stacks)
34
+ stacks.map do |example|
35
+ if example.is_a?(Hash)
36
+ example
37
+ else
38
+ {
39
+ name: example,
40
+ src: example,
41
+ }
42
+ end
43
+ end
44
+ end
45
+
31
46
  # Normalizes stack options to an Array of Hashes or just a single Hash
32
47
  def normalize_stacks(option)
33
48
  defaults = TB.config.stack_options.dup
@@ -0,0 +1,27 @@
1
+ # Interface of subclasses should implement
2
+ #
3
+ # run
4
+ # switch_version(mod.sha)
5
+ # sha
6
+ #
7
+ class TerraspaceBundler::Mod::Fetcher
8
+ class Base
9
+ include TB::Util::Git
10
+ include TB::Util::Logging
11
+ include TB::Mod::Concerns::PathConcern
12
+
13
+ attr_reader :sha # returns nil for Local
14
+ def initialize(mod)
15
+ @mod = mod
16
+ end
17
+
18
+ def switch_version(*)
19
+ # noop
20
+ end
21
+
22
+ def extract(archive, dest)
23
+ TerraspaceBundler::Extract.extract(archive, dest)
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,48 @@
1
+ require "google/cloud/storage"
2
+
3
+ class TerraspaceBundler::Mod::Fetcher
4
+ class Gcs < Base
5
+ extend Memoist
6
+
7
+ def run
8
+ bucket, key, path = gcs_info
9
+ download(bucket, key, path)
10
+ end
11
+
12
+ def download(bucket_name, key, path)
13
+ # Download to cache area
14
+ bucket = storage.bucket(bucket_name)
15
+ unless bucket
16
+ logger.error "ERROR: bucket #{bucket_name} does not exist".color(:red)
17
+ exit 1
18
+ end
19
+ file = bucket.file(key)
20
+ unless file
21
+ logger.error "ERROR: Unable to find gs://#{bucket_name}/#{key}".color(:red)
22
+ exit 1
23
+ end
24
+
25
+ archive = cache_path(path) # temporary path
26
+ logger.debug "Gcs save archive to #{archive}"
27
+ FileUtils.mkdir_p(File.dirname(archive))
28
+ file.download(archive)
29
+
30
+ # Save to stage
31
+ dest = stage_path(rel_dest_dir)
32
+ extract(archive, dest)
33
+ end
34
+
35
+ private
36
+ def gcs_info
37
+ path = type_path
38
+ path.sub!(%r{storage/v\d+/},'')
39
+ bucket, key = get_bucket_key(path)
40
+ [bucket, key, path]
41
+ end
42
+
43
+ def storage
44
+ Google::Cloud::Storage.new
45
+ end
46
+ memoize :storage
47
+ end
48
+ end
@@ -1,24 +1,18 @@
1
- class TerraspaceBundler::Mod
2
- class Downloader
1
+ class TerraspaceBundler::Mod::Fetcher
2
+ class Git < Base
3
3
  extend Memoist
4
- include TB::Util::Git
5
- include TB::Util::Logging
6
- include TB::Mod::PathConcern
7
-
8
- attr_reader :sha
9
- def initialize(mod)
10
- @mod = mod
11
- end
12
4
 
13
5
  def run
14
6
  setup_tmp
15
- org_path = "#{cache_root}/#{@mod.org}"
7
+ org_path = cache_path(@mod.org)
16
8
  FileUtils.mkdir_p(org_path)
17
9
 
18
10
  Dir.chdir(org_path) do
11
+ logger.debug "Current root dir: #{org_path}"
19
12
  clone unless File.exist?(@mod.repo)
20
13
 
21
14
  Dir.chdir(@mod.repo) do
15
+ logger.debug "Change dir: #{@mod.repo}"
22
16
  git "pull"
23
17
  git "submodule update --init"
24
18
  stage
@@ -28,7 +22,8 @@ class TerraspaceBundler::Mod
28
22
  memoize :run
29
23
 
30
24
  def clone
31
- sh "git clone #{@mod.url}"
25
+ command = ["git clone", ENV['TB_GIT_CLONE_ARGS'], @mod.url].compact.join(' ')
26
+ sh command
32
27
  rescue TB::GitError => e
33
28
  logger.error "ERROR: #{e.message}".color(:red)
34
29
  exit 1
@@ -55,8 +50,7 @@ class TerraspaceBundler::Mod
55
50
  end
56
51
 
57
52
  def switch_version(version)
58
- stage_path = stage_path("#{@mod.org}/#{@mod.repo}")
59
- logger.debug "Within: #{stage_path}"
53
+ stage_path = stage_path(rel_dest_dir)
60
54
  Dir.chdir(stage_path) do
61
55
  git "checkout #{version}"
62
56
  @sha = git("rev-parse HEAD").strip
@@ -64,8 +58,8 @@ class TerraspaceBundler::Mod
64
58
  end
65
59
 
66
60
  def copy_to_stage
67
- cache_path = cache_path("#{@mod.org}/#{@mod.repo}")
68
- stage_path = stage_path("#{@mod.org}/#{@mod.repo}")
61
+ cache_path = cache_path(rel_dest_dir)
62
+ stage_path = stage_path(rel_dest_dir)
69
63
  FileUtils.rm_rf(stage_path)
70
64
  FileUtils.mkdir_p(File.dirname(stage_path))
71
65
  FileUtils.cp_r(cache_path, stage_path)
@@ -0,0 +1,15 @@
1
+ class TerraspaceBundler::Mod::Fetcher
2
+ class Local < Base
3
+ def run
4
+ stage_path = stage_path(rel_dest_dir)
5
+ source = @mod.source
6
+ src = source.sub(/^~/, ENV['HOME']) # allow ~/ notation
7
+ FileUtils.rm_rf(stage_path)
8
+ FileUtils.mkdir_p(File.dirname(stage_path))
9
+ logger.debug "Local: cp -r #{src} #{stage_path}"
10
+ # copy from stage area to vendor/modules/NAME
11
+ # IE: cp -r /tmp/terraspace/bundler/stage/local/local1 vendor/modules/local1
12
+ FileUtils.cp_r(src, stage_path)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ require 'aws-sdk-s3'
2
+ require 'uri'
3
+
4
+ class TerraspaceBundler::Mod::Fetcher
5
+ class S3 < Base
6
+ extend Memoist
7
+
8
+ def run
9
+ region, bucket, key, path = s3_info
10
+ download(region, bucket, key, path)
11
+ end
12
+
13
+ def download(region, bucket, key, path)
14
+ # Download to cache area
15
+ response_target = cache_path(path) # temporary path
16
+
17
+ unless File.exist?(response_target)
18
+ logger.debug "S3 save archive to #{response_target}".color(:yellow)
19
+ FileUtils.mkdir_p(File.dirname(response_target))
20
+ s3_get(region, response_target, bucket, key)
21
+ end
22
+
23
+ # Save to stage
24
+ dest = stage_path(rel_dest_dir)
25
+ extract(response_target, dest)
26
+ end
27
+
28
+ private
29
+ def s3_get(region, response_target, bucket, key)
30
+ s3(region).get_object(
31
+ response_target: response_target,
32
+ bucket: bucket,
33
+ key: key,
34
+ )
35
+ rescue Aws::S3::Errors::NoSuchBucket, Aws::S3::Errors::NoSuchKey => e
36
+ logger.error(<<~EOL.color(:red))
37
+ ERROR: #{e.class} #{e.message}
38
+
39
+ bucket: #{bucket}
40
+ key: #{key}
41
+
42
+ EOL
43
+ exit 1
44
+ end
45
+
46
+ def s3_info
47
+ path = type_path
48
+ bucket, key = get_bucket_key(path)
49
+
50
+ url = @mod.source.sub('s3::','')
51
+ uri = URI(url)
52
+ region = if uri.host == 'https://s3.amazonaws.com'
53
+ 'us-east-1'
54
+ else
55
+ uri.host.match(/s3-(.*)\.amazonaws/)[1]
56
+ end
57
+
58
+ [region, bucket, key, path]
59
+ end
60
+
61
+ def s3(region)
62
+ Aws::S3::Client.new(region: region)
63
+ end
64
+ memoize :s3
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ # Delegates to:
2
+ #
3
+ # 1. Local
4
+ # 2. Git
5
+ #
6
+ class TerraspaceBundler::Mod
7
+ class Fetcher
8
+ def initialize(mod)
9
+ @mod = mod
10
+ end
11
+
12
+ def instance
13
+ type = @mod.type == "registry" ? "git" : @mod.type
14
+ klass = "TerraspaceBundler::Mod::Fetcher::#{type.camelize}".constantize
15
+ klass.new(@mod) # IE: Local.new(@mod), Git.new(@mod), S3.new(@mod), etc
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ require 'net/http'
2
+ require 'open-uri'
3
+
4
+ module TerraspaceBundler::Mod::Http
5
+ module Concern
6
+ include TB::Util::Logging
7
+
8
+ def http_request(url, auth_domain: nil)
9
+ uri = URI(url)
10
+ http = Net::HTTP.new(uri.host, uri.port)
11
+ http.use_ssl = uri.scheme == "https"
12
+ # Total time will be 40s = 20 x 2
13
+ http.max_retries = 1 # Default is already 1, just being explicit
14
+ http.read_timeout = 20 # Sites that dont return in 20 seconds are considered down
15
+ request = Net::HTTP::Get.new(uri)
16
+
17
+ if auth_domain
18
+ path = "#{ENV['HOME']}/.terraform.d/credentials.tfrc.json"
19
+ if File.exist?(path)
20
+ data = JSON.load(IO.read(path))
21
+ token = data['credentials'][auth_domain]['token']
22
+ request.add_field 'Authorization', "Bearer #{token}"
23
+ else
24
+ auth_error_exit!
25
+ end
26
+ end
27
+
28
+ begin
29
+ http.request(request) # response
30
+ rescue Net::OpenTimeout => e # internal ELB but VPC is not configured for Lambda function
31
+ http_request_error_message(e)
32
+ rescue Exception => e
33
+ # Net::ReadTimeout - too slow
34
+ # Errno::ECONNREFUSED - completely down
35
+ # SocketError - improper url "dsfjsl" instead of example.com
36
+ http_request_error_message(e)
37
+ end
38
+ end
39
+
40
+ def http_request_error_message(e)
41
+ logger.info "ERROR: #{e.message}\n#{e.message}".color(:red)
42
+ exit 1
43
+ end
44
+ end
45
+ end