terraspace-bundler 0.3.3 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/exe/{terraform-bundler → terraspace-bundler} +0 -0
- data/lib/terraspace_bundler/cli/purge_cache.rb +1 -1
- data/lib/terraspace_bundler/dsl/syntax.rb +4 -0
- data/lib/terraspace_bundler/exporter/base.rb +1 -1
- data/lib/terraspace_bundler/exporter/copy.rb +2 -1
- data/lib/terraspace_bundler/exporter/stacks/stack.rb +2 -1
- data/lib/terraspace_bundler/exporter.rb +4 -4
- data/lib/terraspace_bundler/extract/tar.rb +34 -0
- data/lib/terraspace_bundler/extract/zip.rb +16 -0
- data/lib/terraspace_bundler/extract.rb +21 -0
- data/lib/terraspace_bundler/info.rb +7 -0
- data/lib/terraspace_bundler/mod/concerns/local_concern.rb +10 -0
- data/lib/terraspace_bundler/mod/concerns/notation_concern.rb +42 -0
- data/lib/terraspace_bundler/mod/concerns/path_concern.rb +90 -0
- data/lib/terraspace_bundler/mod/{stack_concern.rb → concerns/stack_concern.rb} +16 -1
- data/lib/terraspace_bundler/mod/fetcher/base.rb +27 -0
- data/lib/terraspace_bundler/mod/fetcher/gcs.rb +48 -0
- data/lib/terraspace_bundler/mod/{downloader.rb → fetcher/git.rb} +10 -16
- data/lib/terraspace_bundler/mod/fetcher/local.rb +15 -0
- data/lib/terraspace_bundler/mod/fetcher/s3.rb +66 -0
- data/lib/terraspace_bundler/mod/fetcher.rb +18 -0
- data/lib/terraspace_bundler/mod/http/concern.rb +45 -0
- data/lib/terraspace_bundler/mod/http/source.rb +19 -0
- data/lib/terraspace_bundler/mod/{props_extension.rb → props/extension.rb} +6 -2
- data/lib/terraspace_bundler/mod/props/typer.rb +39 -0
- data/lib/terraspace_bundler/mod/props.rb +101 -0
- data/lib/terraspace_bundler/mod/registry.rb +77 -23
- data/lib/terraspace_bundler/mod.rb +18 -7
- data/lib/terraspace_bundler/terrafile.rb +3 -3
- data/lib/terraspace_bundler/version.rb +1 -1
- data/spec/fixtures/terrafiles/example/Terrafile +29 -0
- data/spec/terraform_bundler/mod/props_spec.rb +34 -0
- data/terraspace-bundler.gemspec +4 -0
- metadata +83 -10
- data/lib/terraspace_bundler/mod/path_concern.rb +0 -37
- data/lib/terraspace_bundler/mod/props_builder.rb +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d61db038a37cd472b7be9b5f3d15a2388254a4b2a3c0d3af3dabb2e10e8c4fc1
|
4
|
+
data.tar.gz: 83630195dceb5e35dee5be326311806cb8b06a3eedad4ca10f6b98c4962fe0bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d4cc8ad358e17708a27085a4a523e4fcddfb007c81d507c07a7c736a851c48f5ed93ca4d9f6b5f64561c822a1e813a4850d7076f1c419869e01626f91e12682
|
7
|
+
data.tar.gz: 322b70b512a594212f3530d7d0b99d0f55fa15ecfa496c4aee13f0df0bede32f7628c541179697171a1384e81a07a18871378d348dfe90b2bd131c0592e4008a
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,19 @@
|
|
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.2] - 2021-10-02
|
7
|
+
- stack src option: also understand example and name
|
8
|
+
|
9
|
+
## [0.4.1] - 2021-09-30
|
10
|
+
- [#13](https://github.com/boltops-tools/terraspace-bundler/pull/13) fix stacks Array option
|
11
|
+
|
12
|
+
## [0.4.0] - 2021-08-10
|
13
|
+
- [#10](https://github.com/boltops-tools/terraspace-bundler/pull/10) terraspace bundle info: warning when no lockfile
|
14
|
+
- [#12](https://github.com/boltops-tools/terraspace-bundler/pull/12) support for: private registry, s3, gcs, local
|
15
|
+
|
16
|
+
## [0.3.4] - 2021-04-15
|
17
|
+
- [#11](https://github.com/boltops-tools/terraspace-bundler/pull/11) improve registry dectection and gitlab repository support
|
18
|
+
|
6
19
|
## [0.3.3] - 2021-02-24
|
7
20
|
- [#8](https://github.com/boltops-tools/terraspace-bundler/pull/8) fix https sources
|
8
21
|
- [#9](https://github.com/boltops-tools/terraspace-bundler/pull/9) Git checkout retry with v
|
File without changes
|
@@ -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(
|
21
|
+
path = stage_path(rel_dest_dir)
|
21
22
|
path = "#{path}/#{@mod.subfolder}" if @mod.subfolder
|
22
23
|
path
|
23
24
|
end
|
@@ -3,6 +3,7 @@ class TerraspaceBundler::Exporter::Stacks
|
|
3
3
|
attr_reader :mod
|
4
4
|
def initialize(mod, options={})
|
5
5
|
@mod, @options = mod, options
|
6
|
+
@src = @options[:src] || @options[:example] || @options[:name]
|
6
7
|
end
|
7
8
|
|
8
9
|
def export
|
@@ -25,7 +26,7 @@ class TerraspaceBundler::Exporter::Stacks
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def src
|
28
|
-
src = @
|
29
|
+
src = @src
|
29
30
|
without_examples = [mod_path, src].compact.join('/')
|
30
31
|
with_examples = [examples_folder, src].compact.join('/')
|
31
32
|
paths = [with_examples, without_examples]
|
@@ -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
|
-
|
29
|
-
|
30
|
-
|
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,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
|
-
|
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
|
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 =
|
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
|
-
|
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(
|
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(
|
68
|
-
stage_path = stage_path(
|
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
|