lono 2.1.0 → 3.0.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +16 -284
- data/lib/lono.rb +6 -0
- data/lib/lono/cfn.rb +5 -0
- data/lib/lono/cfn/base.rb +86 -9
- data/lib/lono/cfn/create.rb +27 -2
- data/lib/lono/cfn/help.rb +12 -12
- data/lib/lono/cfn/preview.rb +12 -11
- data/lib/lono/cfn/update.rb +3 -2
- data/lib/lono/default/settings.yml +13 -0
- data/lib/lono/env.rb +11 -0
- data/lib/lono/param.rb +1 -1
- data/lib/lono/param/generator.rb +144 -22
- data/lib/lono/settings.rb +28 -0
- data/lib/lono/template.rb +13 -2
- data/lib/lono/template/aws_services.rb +7 -0
- data/lib/lono/template/dsl.rb +24 -33
- data/lib/lono/template/helpers.rb +144 -0
- data/lib/lono/template/template.rb +69 -68
- data/lib/lono/template/upload.rb +75 -0
- data/lib/lono/version.rb +1 -1
- data/lib/starter_projects/json_project/config/{lono.rb → templates/base/blog.rb} +3 -3
- data/lib/starter_projects/{yaml_project/config/lono/api.rb → json_project/config/templates/base/stacks.rb} +9 -9
- data/lib/starter_projects/json_project/templates/{db.json.erb → db.json} +1 -1
- data/lib/starter_projects/json_project/templates/partial/{host_record.json.erb → host_record.json} +0 -0
- data/lib/starter_projects/json_project/templates/partial/{server.json.erb → server.json} +2 -2
- data/lib/starter_projects/json_project/templates/user_data/{app.sh.erb → app.sh} +0 -0
- data/lib/starter_projects/json_project/templates/user_data/{db.sh.erb → db.sh} +0 -0
- data/lib/starter_projects/json_project/templates/user_data/{db2.sh.erb → db2.sh} +0 -0
- data/lib/starter_projects/json_project/templates/user_data/{ruby_script.rb.erb → ruby_script.rb} +0 -0
- data/lib/starter_projects/json_project/templates/{web.json.erb → web.json} +2 -2
- data/lib/starter_projects/yaml_project/config/{lono.rb → templates/base/blog.rb} +4 -8
- data/lib/starter_projects/{json_project/config/lono/api.rb → yaml_project/config/templates/base/stacks.rb} +11 -13
- data/lib/starter_projects/yaml_project/config/templates/prod/stacks.rb +1 -0
- data/lib/starter_projects/yaml_project/config/templates/stag/stacks.rb +1 -0
- data/lib/starter_projects/yaml_project/config/variables/base/variables.rb +4 -0
- data/lib/starter_projects/yaml_project/config/variables/prod/variables.rb +1 -0
- data/lib/starter_projects/yaml_project/config/variables/stag/variables.rb +1 -0
- data/lib/starter_projects/yaml_project/helpers/my_custom_helper.rb +17 -0
- data/lib/starter_projects/yaml_project/params/{api-web-prod.txt → base/api-web-prod.txt} +0 -0
- data/lib/starter_projects/yaml_project/params/{example.txt → base/example.txt} +0 -0
- data/lib/starter_projects/yaml_project/params/prod/example.txt +1 -0
- data/lib/starter_projects/yaml_project/params/stag/example.txt +1 -0
- data/lib/starter_projects/yaml_project/templates/{db.yml.erb → db.yml} +1 -1
- data/lib/starter_projects/yaml_project/templates/{example.yml.erb → example.yml} +0 -0
- data/lib/starter_projects/yaml_project/templates/partial/{host_record.yml.erb → host_record.yml} +0 -0
- data/lib/starter_projects/yaml_project/templates/partial/{server.yml.erb → server.yml} +0 -0
- data/lib/starter_projects/yaml_project/templates/partial/user_data/{bootstrap.sh.erb → bootstrap.sh} +0 -0
- data/lib/starter_projects/yaml_project/templates/{web.yml.erb → web.yml} +2 -2
- data/lono.gemspec +1 -0
- data/spec/fixtures/params/baseonly/params/base/network.txt +1 -0
- data/spec/fixtures/params/envonly/params/prod/network.txt +1 -0
- data/spec/fixtures/params/overlay/params/base/network.txt +1 -0
- data/spec/fixtures/params/overlay/params/prod/network.txt +1 -0
- data/spec/lib/lono/new_spec.rb +1 -1
- data/spec/lib/lono/param/generator_spec.rb +34 -0
- data/spec/lib/lono/template/dsl_spec.rb +1 -1
- data/spec/lib/lono/template_spec.rb +5 -0
- metadata +60 -22
data/lib/lono/template/dsl.rb
CHANGED
@@ -2,7 +2,7 @@ class Lono::Template::DSL
|
|
2
2
|
def initialize(options={})
|
3
3
|
@options = options
|
4
4
|
@project_root = @options[:project_root] || '.'
|
5
|
-
@
|
5
|
+
@config_path = "#{@project_root}/config"
|
6
6
|
Lono::ProjectChecker.check(@project_root)
|
7
7
|
@templates = []
|
8
8
|
@results = {}
|
@@ -15,12 +15,23 @@ class Lono::Template::DSL
|
|
15
15
|
write_output
|
16
16
|
end
|
17
17
|
|
18
|
+
# Instance eval's all the files within each folder under
|
19
|
+
# config/lono/base and config/lono/[LONO_ENV]
|
20
|
+
# Base gets base first and then the LONO_ENV configs get evaluate second.
|
21
|
+
# This means the env specific configs override the base configs.
|
18
22
|
def evaluate_templates
|
19
|
-
|
20
|
-
|
23
|
+
evaluate_folder("base")
|
24
|
+
evaluate_folder(LONO_ENV)
|
21
25
|
@detected_format = detect_format
|
22
26
|
end
|
23
27
|
|
28
|
+
def evaluate_folder(folder)
|
29
|
+
paths = Dir.glob("#{@config_path}/templates/#{folder}/**/*")
|
30
|
+
paths.select{ |e| File.file?(e) }.each do |path|
|
31
|
+
evaluate_template(path)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
24
35
|
def evaluate_template(path)
|
25
36
|
begin
|
26
37
|
instance_eval(File.read(path), path)
|
@@ -55,35 +66,14 @@ class Lono::Template::DSL
|
|
55
66
|
end
|
56
67
|
end
|
57
68
|
|
58
|
-
# Detects the format of the templates.
|
69
|
+
# Detects the format of the templates. Checks the extension of all the
|
59
70
|
# templates files.
|
60
71
|
# All the templates must be of the same format, either all json or all yaml.
|
61
72
|
def detect_format
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if formats.size > 1
|
67
|
-
puts "ERROR: Detected multiple formats: #{formats.join(", ")}".colorize(:red)
|
68
|
-
puts "All the source values in the template blocks in the config folder must have the same format extension."
|
69
|
-
exit 1
|
70
|
-
else
|
71
|
-
found_format = formats.first
|
72
|
-
if found_format
|
73
|
-
detected_format = found_format.sub(/^\./,'')
|
74
|
-
detected_format = "yaml" if detected_format == "yml"
|
75
|
-
else # empty templates, no templates defined yet
|
76
|
-
detected_format = "yaml" # defaults to yaml
|
77
|
-
end
|
78
|
-
end
|
79
|
-
detected_format
|
80
|
-
end
|
81
|
-
|
82
|
-
# load any templates defined in project/config/lono/*
|
83
|
-
def load_subfolder
|
84
|
-
Dir.glob("#{File.dirname(@path)}/lono/**/*").select{ |e| File.file? e }.each do |path|
|
85
|
-
evaluate_template(path)
|
86
|
-
end
|
73
|
+
extensions = Dir.glob("#{@project_root}/templates/**/*").map do |path|
|
74
|
+
File.extname(path).sub(/^\./,'')
|
75
|
+
end.reject(&:empty?).uniq
|
76
|
+
extensions.include?('yml') ? 'yml' : 'json' # defaults to yml - falls back to json
|
87
77
|
end
|
88
78
|
|
89
79
|
def template(name, &block)
|
@@ -91,8 +81,9 @@ class Lono::Template::DSL
|
|
91
81
|
end
|
92
82
|
|
93
83
|
def build_templates
|
84
|
+
options = @options.merge(detected_format: @detected_format)
|
94
85
|
@templates.each do |t|
|
95
|
-
@results[t[:name]] = Lono::Template::Template.new(t[:name], t[:block],
|
86
|
+
@results[t[:name]] = Lono::Template::Template.new(t[:name], t[:block], options).build
|
96
87
|
end
|
97
88
|
end
|
98
89
|
|
@@ -102,7 +93,8 @@ class Lono::Template::DSL
|
|
102
93
|
FileUtils.mkdir(output_path) unless File.exist?(output_path)
|
103
94
|
puts "Generating CloudFormation templates:" unless @options[:quiet]
|
104
95
|
@results.each do |name,text|
|
105
|
-
path = "#{output_path}/#{name}".sub(/^\.\//,'')
|
96
|
+
path = "#{output_path}/#{name}".sub(/^\.\//,'') # strip leading '.'
|
97
|
+
path += ".#{@detected_format}"
|
106
98
|
puts " #{path}" unless @options[:quiet]
|
107
99
|
ensure_parent_dir(path)
|
108
100
|
validate(text, path)
|
@@ -112,7 +104,6 @@ class Lono::Template::DSL
|
|
112
104
|
end
|
113
105
|
end
|
114
106
|
|
115
|
-
# TODO: set @detected_format upon DSL.new
|
116
107
|
def validate(text, path)
|
117
108
|
if @detected_format == "json"
|
118
109
|
validate_json(text, path)
|
@@ -156,7 +147,7 @@ class Lono::Template::DSL
|
|
156
147
|
def yaml_format(text)
|
157
148
|
comment =<<~EOS
|
158
149
|
# This file was generated with lono. Do not edit directly, the changes will be lost.
|
159
|
-
# More info:
|
150
|
+
# More info: http://lono.cloud
|
160
151
|
EOS
|
161
152
|
"#{comment}#{remove_blank_lines(text)}"
|
162
153
|
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module Lono::Template::Helpers
|
2
|
+
def template_s3_path(template_name)
|
3
|
+
format = @_detected_format.sub('yaml','yml')
|
4
|
+
template_path = "#{template_name}.#{format}"
|
5
|
+
|
6
|
+
# must have settings.s3_path for this to owrk
|
7
|
+
settings = Lono::Settings.new(@project_root)
|
8
|
+
if settings.s3_path
|
9
|
+
# high jacking Upload for useful s3_https_url method
|
10
|
+
upload = Lono::Template::Upload.new(@_options)
|
11
|
+
upload.s3_https_url(template_path)
|
12
|
+
else
|
13
|
+
message = "template_s3_path helper called but s3.path not configured in lono/settings.yml"
|
14
|
+
puts "WARN: #{message}".colorize(:yellow)
|
15
|
+
message
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def template_params(param_name)
|
20
|
+
param_path = "params/#{LONO_ENV}/#{param_name}.txt"
|
21
|
+
generator_options = {
|
22
|
+
project_root: @_project_root,
|
23
|
+
path: param_path,
|
24
|
+
allow_no_file: true
|
25
|
+
}.merge(@_options)
|
26
|
+
generator = Lono::Param::Generator.new(param_name, generator_options)
|
27
|
+
# do not generate because lono cfn calling logic already generated it we only need the values
|
28
|
+
generator.params # Returns Array in underscore keys format
|
29
|
+
end
|
30
|
+
|
31
|
+
def user_data(path, vars={})
|
32
|
+
path = "#{@_project_root}/templates/user_data/#{path}"
|
33
|
+
template = IO.read(path)
|
34
|
+
variables(vars)
|
35
|
+
result = erb_result(path, template)
|
36
|
+
output = []
|
37
|
+
result.split("\n").each do |line|
|
38
|
+
output += transform(line)
|
39
|
+
end
|
40
|
+
json = output.to_json
|
41
|
+
json[0] = '' # remove first char: [
|
42
|
+
json.chop! # remove last char: ]
|
43
|
+
end
|
44
|
+
|
45
|
+
def ref(name)
|
46
|
+
%Q|{"Ref"=>"#{name}"}|
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_in_map(*args)
|
50
|
+
%Q|{"Fn::FindInMap" => [ #{transform_array(args)} ]}|
|
51
|
+
end
|
52
|
+
|
53
|
+
def base64(value)
|
54
|
+
%Q|{"Fn::Base64"=>"#{value}"}|
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_att(*args)
|
58
|
+
%Q|{"Fn::GetAtt" => [ #{transform_array(args)} ]}|
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_azs(region="AWS::Region")
|
62
|
+
%Q|{"Fn::GetAZs"=>"#{region}"}|
|
63
|
+
end
|
64
|
+
|
65
|
+
def join(delimiter, values)
|
66
|
+
%Q|{"Fn::Join" => ["#{delimiter}", [ #{transform_array(values)} ]]}|
|
67
|
+
end
|
68
|
+
|
69
|
+
def select(index, list)
|
70
|
+
%Q|{"Fn::Select" => ["#{index}", [ #{transform_array(list)} ]]}|
|
71
|
+
end
|
72
|
+
|
73
|
+
def partial_exist?(path)
|
74
|
+
path = partial_path_for(path)
|
75
|
+
path = auto_add_format(path)
|
76
|
+
path && File.exist?(path)
|
77
|
+
end
|
78
|
+
|
79
|
+
# The partial's path is a relative path given without the extension and
|
80
|
+
#
|
81
|
+
# Example:
|
82
|
+
# Given: file in templates/partial/iam/docker.yml
|
83
|
+
# The path should be: iam/docker
|
84
|
+
#
|
85
|
+
# If the user specifies the extension then use that instead of auto-adding
|
86
|
+
# the detected format.
|
87
|
+
def partial(path,vars={}, options={})
|
88
|
+
path = partial_path_for(path)
|
89
|
+
path = auto_add_format(path)
|
90
|
+
|
91
|
+
template = IO.read(path)
|
92
|
+
variables(vars)
|
93
|
+
result = erb_result(path, template)
|
94
|
+
result = indent(result, options[:indent]) if options[:indent]
|
95
|
+
if options[:indent]
|
96
|
+
# Add empty line at beginning because empty lines gets stripped during
|
97
|
+
# processing anyway. This allows the user to call partial without having
|
98
|
+
# to put the partial call at very beginning of the line.
|
99
|
+
# This only should happen if user is using indent option.
|
100
|
+
["\n", result].join("\n")
|
101
|
+
else
|
102
|
+
result
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# add indentation
|
107
|
+
def indent(text, indentation_amount)
|
108
|
+
text.split("\n").map do |line|
|
109
|
+
" " * indentation_amount + line
|
110
|
+
end.join("\n")
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def partial_path_for(path)
|
115
|
+
"#{@_project_root}/templates/partial/#{path}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def auto_add_format(path)
|
119
|
+
# Return immediately if user provided explicit extension
|
120
|
+
extension = File.extname(path) # current extension
|
121
|
+
return path if !extension.empty?
|
122
|
+
|
123
|
+
# Else let's auto detect
|
124
|
+
paths = Dir.glob("#{path}.*")
|
125
|
+
|
126
|
+
if paths.size == 1 # non-ambiguous match
|
127
|
+
return paths.first
|
128
|
+
end
|
129
|
+
|
130
|
+
if paths.size > 1 # ambiguous match
|
131
|
+
puts "ERROR: Multiple possible partials found:".colorize(:red)
|
132
|
+
paths.each do |path|
|
133
|
+
puts " #{path}"
|
134
|
+
end
|
135
|
+
puts "Please specify an extension in the name to remove the ambiguity.".colorize(:green)
|
136
|
+
exit 1
|
137
|
+
end
|
138
|
+
|
139
|
+
# Account for case when user wants to include a file with no extension at all
|
140
|
+
return path if File.exist?(path) && !File.directory?(path)
|
141
|
+
|
142
|
+
path # original path if this point is reached
|
143
|
+
end
|
144
|
+
end
|
@@ -3,45 +3,83 @@ require 'json'
|
|
3
3
|
require 'base64'
|
4
4
|
|
5
5
|
class Lono::Template::Template
|
6
|
+
include Lono::Template::Helpers
|
6
7
|
include ERB::Util
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
9
|
+
def initialize(name, block=nil, options={})
|
10
|
+
# Taking care to name instance variables with _ in front because we load the
|
11
|
+
# variables from config/variables and those instance variables can clobber these
|
12
|
+
# instance variables
|
13
|
+
@_name = name
|
14
|
+
@_options = options
|
15
|
+
@_detected_format = options[:detected_format]
|
16
|
+
@_block = block
|
17
|
+
@_project_root = options[:project_root] || '.'
|
18
|
+
@_config_path = "#{@_project_root}/config"
|
19
|
+
@_source = default_source(name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_source(name)
|
23
|
+
"#{@_project_root}/templates/#{name}.#{@_detected_format}" # defaults to name, source method overrides
|
13
24
|
end
|
14
25
|
|
15
26
|
def build
|
16
|
-
|
17
|
-
|
18
|
-
|
27
|
+
load_variables
|
28
|
+
load_custom_helpers
|
29
|
+
instance_eval(&@_block) if @_block
|
30
|
+
template = IO.read(@_source)
|
31
|
+
erb_result(@_source, template)
|
19
32
|
end
|
20
33
|
|
21
|
-
def
|
22
|
-
|
34
|
+
def load_variables
|
35
|
+
load_variables_folder("base")
|
36
|
+
load_variables_folder(LONO_ENV)
|
23
37
|
end
|
24
38
|
|
25
|
-
|
26
|
-
|
27
|
-
|
39
|
+
# Load the variables defined in config/variables/* to make available in the
|
40
|
+
# template blocks in config/templates/*.
|
41
|
+
#
|
42
|
+
# Example:
|
43
|
+
#
|
44
|
+
# `config/variables/base/variables.rb`:
|
45
|
+
# @foo = 123
|
46
|
+
#
|
47
|
+
# `config/templates/base/resources.rb`:
|
48
|
+
# template "mytemplate.yml" do
|
49
|
+
# source "mytemplate.yml.erb"
|
50
|
+
# variables(foo: @foo)
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# NOTE: Only able to make instance variables avaialble with instance_eval
|
54
|
+
# Wasnt able to make local variables available.
|
55
|
+
def load_variables_folder(folder)
|
56
|
+
paths = Dir.glob("#{@_config_path}/variables/#{folder}/**/*")
|
57
|
+
paths.select{ |e| File.file? e }.each do |path|
|
58
|
+
instance_eval(IO.read(path))
|
28
59
|
end
|
29
60
|
end
|
30
61
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
62
|
+
# Load custom helper methods from the user's infra repo
|
63
|
+
def load_custom_helpers
|
64
|
+
Dir.glob("#{@_project_root}/helpers/**/*_helper.rb").each do |path|
|
65
|
+
filename = path.sub(%r{.*/},'').sub('.rb','')
|
66
|
+
module_name = filename.classify
|
67
|
+
|
68
|
+
require path
|
69
|
+
self.class.send :include, module_name.constantize
|
70
|
+
end
|
71
|
+
|
38
72
|
end
|
39
73
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
74
|
+
def source(path)
|
75
|
+
@_source = path[0..0] == '/' ? path : "#{@_project_root}/templates/#{path}"
|
76
|
+
@_source += ".#{@_detected_format}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def variables(vars={})
|
80
|
+
vars.each do |var,value|
|
81
|
+
instance_variable_set("@#{var}", value)
|
82
|
+
end
|
45
83
|
end
|
46
84
|
|
47
85
|
def erb_result(path, template)
|
@@ -49,6 +87,7 @@ class Lono::Template::Template
|
|
49
87
|
ERB.new(template, nil, "-").result(binding)
|
50
88
|
rescue Exception => e
|
51
89
|
puts e
|
90
|
+
puts e.backtrace if ENV['DEBUG']
|
52
91
|
|
53
92
|
# how to know where ERB stopped? - https://www.ruby-forum.com/topic/182051
|
54
93
|
# syntax errors have the (erb):xxx info in e.message
|
@@ -57,7 +96,7 @@ class Lono::Template::Template
|
|
57
96
|
error_info ||= e.backtrace.grep(/\(erb\)/)[0]
|
58
97
|
raise unless error_info # unable to find the (erb):xxx: error line
|
59
98
|
line = error_info.split(':')[1].to_i
|
60
|
-
puts "Error evaluating ERB template on line #{line.to_s.colorize(:red)} of: #{path.sub(/^\.\//, '')}"
|
99
|
+
puts "Error evaluating ERB template on line #{line.to_s.colorize(:red)} of: #{path.sub(/^\.\//, '').colorize(:green)}"
|
61
100
|
|
62
101
|
template_lines = template.split("\n")
|
63
102
|
context = 5 # lines of context
|
@@ -75,48 +114,6 @@ class Lono::Template::Template
|
|
75
114
|
end
|
76
115
|
end
|
77
116
|
|
78
|
-
def user_data(path, vars={})
|
79
|
-
path = "#{@options[:project_root]}/templates/user_data/#{path}"
|
80
|
-
template = IO.read(path)
|
81
|
-
variables(vars)
|
82
|
-
result = erb_result(path, template)
|
83
|
-
output = []
|
84
|
-
result.split("\n").each do |line|
|
85
|
-
output += transform(line)
|
86
|
-
end
|
87
|
-
json = output.to_json
|
88
|
-
json[0] = '' # remove first char: [
|
89
|
-
json.chop! # remove last char: ]
|
90
|
-
end
|
91
|
-
|
92
|
-
def ref(name)
|
93
|
-
%Q|{"Ref"=>"#{name}"}|
|
94
|
-
end
|
95
|
-
|
96
|
-
def find_in_map(*args)
|
97
|
-
%Q|{"Fn::FindInMap" => [ #{transform_array(args)} ]}|
|
98
|
-
end
|
99
|
-
|
100
|
-
def base64(value)
|
101
|
-
%Q|{"Fn::Base64"=>"#{value}"}|
|
102
|
-
end
|
103
|
-
|
104
|
-
def get_att(*args)
|
105
|
-
%Q|{"Fn::GetAtt" => [ #{transform_array(args)} ]}|
|
106
|
-
end
|
107
|
-
|
108
|
-
def get_azs(region="AWS::Region")
|
109
|
-
%Q|{"Fn::GetAZs"=>"#{region}"}|
|
110
|
-
end
|
111
|
-
|
112
|
-
def join(delimiter, values)
|
113
|
-
%Q|{"Fn::Join" => ["#{delimiter}", [ #{transform_array(values)} ]]}|
|
114
|
-
end
|
115
|
-
|
116
|
-
def select(index, list)
|
117
|
-
%Q|{"Fn::Select" => ["#{index}", [ #{transform_array(list)} ]]}|
|
118
|
-
end
|
119
|
-
|
120
117
|
def transform_array(arr)
|
121
118
|
arr.map! {|x| x =~ /=>/ ? x : x.inspect }
|
122
119
|
arr.join(',')
|
@@ -248,4 +245,8 @@ class Lono::Template::Template
|
|
248
245
|
def encode_base64(text)
|
249
246
|
Base64.strict_encode64(text).strip
|
250
247
|
end
|
248
|
+
|
249
|
+
def name
|
250
|
+
@_name
|
251
|
+
end
|
251
252
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'json'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
class Lono::Template::Upload
|
6
|
+
include Lono::Template::AwsServices
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@options = options
|
10
|
+
@project_root = options[:project_root] || '.'
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
ensure_s3_setup!
|
15
|
+
paths = Dir.glob("#{@project_root}/output/**/*")
|
16
|
+
paths.reject { |p| p =~ %r{output/params} }.
|
17
|
+
select { |p| File.file?(p) }.each do |path|
|
18
|
+
upload(path)
|
19
|
+
end
|
20
|
+
say "Templates uploaded to s3."
|
21
|
+
end
|
22
|
+
|
23
|
+
def upload(path)
|
24
|
+
pretty_path = path.sub(/^\.\//, '')
|
25
|
+
key = "#{s3_path}/#{LONO_ENV}/#{pretty_path.sub(/^output\//,'')}"
|
26
|
+
s3_full_path = "s3://#{s3_bucket}/#{key}"
|
27
|
+
|
28
|
+
resp = s3.put_object(
|
29
|
+
body: IO.read(path),
|
30
|
+
bucket: s3_bucket,
|
31
|
+
key: key,
|
32
|
+
storage_class: "REDUCED_REDUNDANCY"
|
33
|
+
) unless @options[:noop]
|
34
|
+
|
35
|
+
message = "Uploaded: #{pretty_path} to #{s3_full_path}"
|
36
|
+
message = "NOOP: #{message}" if @options[:noop]
|
37
|
+
say message
|
38
|
+
end
|
39
|
+
|
40
|
+
# https://s3.amazonaws.com/mybucket/cloudformation-templates/prod/parent.yml
|
41
|
+
def s3_https_url(template_path)
|
42
|
+
ensure_s3_setup!
|
43
|
+
"https://s3.amazonaws.com/#{s3_bucket}/#{s3_path}/#{LONO_ENV}/#{template_path}"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Example:
|
47
|
+
# s3_bucket('s3://mybucket/templates/storage/path') => mybucket
|
48
|
+
def s3_bucket
|
49
|
+
@s3_full_path.sub('s3://','').split('/').first
|
50
|
+
end
|
51
|
+
|
52
|
+
# Example:
|
53
|
+
# s3_bucket('s3://mybucket/templates/storage/path') => templates/storage/path
|
54
|
+
def s3_path
|
55
|
+
@s3_full_path.sub('s3://','').split('/')[1..-1].join('/')
|
56
|
+
end
|
57
|
+
|
58
|
+
# nice warning if the s3 path not found
|
59
|
+
def ensure_s3_setup!
|
60
|
+
return if @options[:noop]
|
61
|
+
|
62
|
+
settings = Lono::Settings.new(@project_root)
|
63
|
+
if settings.s3_path
|
64
|
+
@s3_full_path = settings.s3_path
|
65
|
+
else
|
66
|
+
say "Unable to upload templates to s3 because you have not configured the s3.path option in .lono/settings.yml.".colorize(:red)
|
67
|
+
say "Please configure .lono/settings.yml with s3.path. Refer to http://lono.cloud/docs/settings/ for more help.".colorize(:red)
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def say(message)
|
73
|
+
puts message unless @options[:quiet]
|
74
|
+
end
|
75
|
+
end
|