Class: Lono::Param::Generator

Inherits:
Object
  • Object
show all
Includes:
Blueprint::Root, Conventions
Defined in:
lib/lono/param/generator.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Conventions

#template_param_convention

Methods included from Blueprint::Root

#bundler_groups, #find_blueprint_root, #require_bundle_gems, #set_blueprint_root

Constructor Details

#initialize(blueprint, options = {}) ⇒ Generator

Returns a new instance of Generator.



6
7
8
9
10
# File 'lib/lono/param/generator.rb', line 6

def initialize(blueprint, options={})
  @blueprint, @options = blueprint, options
  set_blueprint_root(@blueprint)
  @template, @param = template_param_convention(options)
end

Instance Attribute Details

#base_pathObject (readonly)

set when generate is called



5
6
7
# File 'lib/lono/param/generator.rb', line 5

def base_path
  @base_path
end

#env_pathObject (readonly)

set when generate is called



5
6
7
# File 'lib/lono/param/generator.rb', line 5

def env_path
  @env_path
end

Instance Method Details

#contextObject

Context for ERB rendering. This is where we control what references get passed to the ERB rendering.



149
150
151
# File 'lib/lono/param/generator.rb', line 149

def context
  @context ||= Lono::Template::Context.new(@blueprint, @options)
end

#convert_to_cfn_format(contents, casing = :camel) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/lono/param/generator.rb', line 164

def convert_to_cfn_format(contents, casing=:camel)
  lines = parse_contents(contents)

  # First use a Hash structure so that overlay env files will override
  # the base param file.
  data = {}
  lines.each do |line|
    key,value = line.strip.split("=").map {|x| x.strip}
    data[key] = value
  end

  # Now build up the aws json format for parameters
  params = []
  data.each do |key,value|
    param = if value == "use_previous_value"
              {
                "ParameterKey": key,
                "UsePreviousValue": true
              }
            elsif value
              {
                "ParameterKey": key,
                "ParameterValue": value
              }
            end
    if param
      param = param.to_snake_keys if casing == :underscore
      params << param
    end
  end
  params
end

#generateObject



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/lono/param/generator.rb', line 67

def generate
  puts "Generating parameter files for blueprint #{@blueprint.color(:green)}:"

  @base_path, @env_path = lookup_paths

  return unless @base_path || @env_path

  # useful option for lono cfn, since some templates dont require params
  return if @options[:allow_not_exists] && !source_exist?

  if source_exist?
    contents = process_erb
    data = convert_to_cfn_format(contents)
    json = JSON.pretty_generate(data)
    write_output(json)
    unless @options[:mute]
      short_output_path = output_path.sub("#{Lono.root}/","")
      puts "  #{short_output_path}"
    end
  else
    puts "#{@base_path} or #{@env_path} could not be found?  Are you sure it exist?"
    exit 1
  end
  json
end

#lookup_param_file(root: Lono.root, env: Lono.env) ⇒ Object

Lookup precedence:

configs/BLUEPRINT/params/development/TEMPLATE/PARAM.txt
configs/BLUEPRINT/params/development/PARAM.txt
configs/BLUEPRINT/params/development.txt


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/lono/param/generator.rb', line 27

def lookup_param_file(root: Lono.root, env: Lono.env)
  long_form = "#{root}/configs/#{@blueprint}/params/#{env}/#{@template}/#{@param}.txt"
  medium_form = "#{root}/configs/#{@blueprint}/params/#{env}/#{@param}.txt"
  short_form = "#{root}/configs/#{@blueprint}/params/#{env}.txt"

  if ENV['LONO_PARAM_DEBUG']
    puts "Lono.blueprint_root #{Lono.blueprint_root}"
    puts "long_form #{long_form}"
    puts "medium_form #{medium_form}"
    puts "short_form #{short_form}"
  end

  return long_form if File.exist?(long_form) # always consider this first because its so explicit

  # All 3 are the same
  if @blueprint == @template && @template == @param
    return medium_form if File.exist?(medium_form) # higher precedence between longer but short form should be encouraged
    return short_form if File.exist?(short_form)
    return # cannot find a param file
  end

  # Only template and param are the same
  if @template == @param
    return medium_form if File.exist?(medium_form) # only consider medium form
    return # cannot find a param file
  end
end

#lookup_pathsObject



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/lono/param/generator.rb', line 55

def lookup_paths
  @base_path = lookup_param_file(env: "base")
  @env_path = lookup_param_file(env: Lono.env)

  if ENV['LONO_PARAM_DEBUG']
    puts "  @base_path #{@base_path.inspect}"
    puts "  @env_path #{@env_path.inspect}"
  end

  [@base_path, @env_path]
end

#output_pathObject



197
198
199
200
201
202
203
204
205
206
# File 'lib/lono/param/generator.rb', line 197

def output_path
  output = Lono.config.output_path.sub("#{Lono.root}/","")
  path = if @base_path && !@env_path
           # Handle case when base config exist but the env config does not
           @base_path.sub("configs", output).sub("base", Lono.env)
         else
           @env_path.sub("configs", output)
         end
  path.sub(/\.txt$/,'.json')
end

#params(casing = :underscore) ⇒ Object

useful for when calling CloudFormation via the aws-sdk gem



103
104
105
106
107
108
109
110
111
# File 'lib/lono/param/generator.rb', line 103

def params(casing = :underscore)
  @base_path, @env_path = lookup_paths

  # useful option for lono cfn
  return {} if @options[:allow_not_exists] && !source_exist?

  contents = process_erb
  convert_to_cfn_format(contents, casing)
end

#parse_contents(contents) ⇒ Object



153
154
155
156
157
158
159
160
161
162
# File 'lib/lono/param/generator.rb', line 153

def parse_contents(contents)
  lines = contents.split("\n")
  # remove comment at the end of the line
  lines.map! { |l| l.sub(/#.*/,'').strip }
  # filter out commented lines
  lines = lines.reject { |l| l =~ /(^|\s)#/i }
  # filter out empty lines
  lines = lines.reject { |l| l.strip.empty? }
  lines
end

#process_erbObject

Reads both the base source and env source and overlay the two Example 1:

params/base/mystack.txt - base path
params/production/mystack.txt - env path

the base/mystack.txt gets combined with the prod/mystack.txt
it produces a final prod/mystack.txt

Example 2:

params/base/mystack.txt - base path

the base/mystack.txt is used to produced a prod/mystack.txt

Example 3:

params/production/mystack.txt - env path

the prod/mystack.txt is used to produced a prod/mystack.txt


130
131
132
133
134
135
136
137
138
# File 'lib/lono/param/generator.rb', line 130

def process_erb
  contents = []
  contents << render_erb(@base_path)
  contents << render_erb(@env_path)
  result = contents.compact.join("\n")
  # puts "process_erb result".color(:yellow)
  # puts result
  result
end

#puts_param_message(type) ⇒ Object



12
13
14
15
16
17
18
19
# File 'lib/lono/param/generator.rb', line 12

def puts_param_message(type)
  path = send("#{type}_path")
  return unless path
  if File.exist?(path)
    pretty_path = path.sub("#{Lono.root}/",'')
    puts "Using param: #{pretty_path}".color(:yellow)
  end
end

#render_erb(path) ⇒ Object



140
141
142
143
144
145
# File 'lib/lono/param/generator.rb', line 140

def render_erb(path)
  return unless path
  if File.exist?(path)
    RenderMePretty.result(path, context: context)
  end
end

#source_exist?Boolean

Checks both base and source path for existing of the param file. Example:

params/base/mystack.txt - base path
params/production/mystack.txt - source path

Returns:

  • (Boolean)


97
98
99
100
# File 'lib/lono/param/generator.rb', line 97

def source_exist?
  @base_path && File.exist?(@base_path) ||
  @env_path && File.exist?(@env_path)
end

#write_output(json) ⇒ Object



208
209
210
211
212
# File 'lib/lono/param/generator.rb', line 208

def write_output(json)
  dir = File.dirname(output_path)
  FileUtils.mkdir_p(dir)
  IO.write(output_path, json)
end