Class: Lono::Cfn::Base

Inherits:
Object
  • Object
show all
Includes:
AwsService, Util
Defined in:
lib/lono/cfn/base.rb

Direct Known Subclasses

Create, Diff, Download, Preview, Update

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util

#are_you_sure?

Methods included from AwsService

#cfn, #stack_exists?, #testing_update?

Constructor Details

#initialize(stack_name, options = {}) ⇒ Base

Returns a new instance of Base.



8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/lono/cfn/base.rb', line 8

def initialize(stack_name, options={})
  @randomize_stack_name = options[:randomize_stack_name]
  @stack_name = randomize(stack_name)
  @options = options
  Lono::ProjectChecker.check unless options[:lono] # already ran checker in lono generate

  @template_name = options[:template] || derandomize(@stack_name)
  @param_name = options[:param] || @template_name
  @template_path = get_source_path(@template_name, :template)
  @param_path = get_source_path(@param_name, :param)
  puts "Using template: #{@template_path}" unless @options[:mute_using]
  puts "Using parameters: #{@param_path}" unless @options[:mute_using]
end

Instance Attribute Details

#randomize_stack_nameObject (readonly)

Returns the value of attribute randomize_stack_name.



7
8
9
# File 'lib/lono/cfn/base.rb', line 7

def randomize_stack_name
  @randomize_stack_name
end

Instance Method Details

#build_scriptsObject



66
67
68
# File 'lib/lono/cfn/base.rb', line 66

def build_scripts
  Lono::Script::Build.new.run
end

#capabilitiesObject



199
200
201
202
203
204
# File 'lib/lono/cfn/base.rb', line 199

def capabilities
  return @options[:capabilities] if @options[:capabilities]
  if @options[:iam]
    ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"]
  end
end

#check_filesObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/lono/cfn/base.rb', line 108

def check_files
  errors, warns = [], []
  unless File.exist?(@template_path)
    errors << "Template file missing: could not find #{@template_path}"
  end
  # Examples:
  #   @param_path = params/prod/ecs.txt
  #              => output/params/prod/ecs.json
  output_param_path = @param_path.sub(/\.txt/, '.json')
  output_param_path = "#{Lono.config.output_path}/#{output_param_path}"
  if @options[:param] && !File.exist?(output_param_path)
    warns << "Parameters file missing: could not find #{output_param_path}"
  end
  [errors, warns]
end

#check_for_errorsObject



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/lono/cfn/base.rb', line 95

def check_for_errors
  errors, warns = check_files
  unless errors.empty?
    puts "Please double check the command you ran.  There were some errors."
    puts "ERROR: #{errors.join("\n")}".colorize(:red)
    exit
  end
  unless warns.empty?
    puts "Please double check the command you ran.  There were some warnings."
    puts "WARN: #{warns.join("\n")}".colorize(:yellow)
  end
end

#command_with_iam(capabilities) ⇒ Object



48
49
50
# File 'lib/lono/cfn/base.rb', line 48

def command_with_iam(capabilities)
  "#{File.basename($0)} #{ARGV.join(' ')} --capabilities #{capabilities}"
end

#convention_path(name, type) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
# File 'lib/lono/cfn/base.rb', line 138

def convention_path(name, type)
  path = case type
  when :template
    "#{Lono.config.output_path}/templates/#{name}.yml"
  when :param
    "#{Lono.config.params_path}/#{Lono.env}/#{name}.txt"
  else
    raise "hell: dont come here"
  end
  path.sub(/^\.\//, '')
end

#derandomize(template_name) ⇒ Object

Strip the random string at end of the template name



181
182
183
184
185
186
187
# File 'lib/lono/cfn/base.rb', line 181

def derandomize(template_name)
  if randomize_stack_name?
    template_name.sub(/-(\w{3})$/,'') # strip the random part at the end
  else
    template_name
  end
end

#exit_unless_updatable!(status) ⇒ Object



160
161
162
163
164
165
166
167
168
# File 'lib/lono/cfn/base.rb', line 160

def exit_unless_updatable!(status)
  return true if testing_update?
  return false if @options[:noop]

  unless status =~ /_COMPLETE$/
    puts "Cannot create a change set for the stack because the #{@stack_name} is not in an updatable state.  Stack status: #{status}".colorize(:red)
    quit(1)
  end
end

#generate_allObject



52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/lono/cfn/base.rb', line 52

def generate_all
  if @options[:lono]
    build_scripts
    generate_templates
    unless @options[:noop]
      upload_scripts
      upload_templates
    end
  end
  params = generate_params(mute: @options[:mute_params])
  check_for_errors
  params
end

#generate_params(options = {}) ⇒ Object



85
86
87
88
89
90
91
92
93
# File 'lib/lono/cfn/base.rb', line 85

def generate_params(options={})
  generator_options = {
    path: @param_path,
    allow_no_file: true
  }.merge(options)
  generator = Lono::Param::Generator.new(@param_name, generator_options)
  generator.generate  # Writes the json file in CamelCase keys format
  generator.params    # Returns Array in underscore keys format
end

#generate_templatesObject



70
71
72
# File 'lib/lono/cfn/base.rb', line 70

def generate_templates
  Lono::Template::DSL.new.run
end

#get_source_path(path, type) ⇒ Object

if existing in params path then use that if it doesnt assume it is a full path and check that else fall back to convention, which also eventually gets checked in check_for_errors

Type - :param or :template



129
130
131
132
133
134
135
136
# File 'lib/lono/cfn/base.rb', line 129

def get_source_path(path, type)
  if path.nil?
    convention_path(@stack_name, type) # default convention
  else
    # convention path based on the input from the user
    convention_path(path, type)
  end
end

#prompt_for_iam(capabilities) ⇒ Object



40
41
42
43
44
45
46
# File 'lib/lono/cfn/base.rb', line 40

def prompt_for_iam(capabilities)
  puts "This stack will create IAM resources.  Please approve to run the command again with #{capabilities} capabilities."
  puts "  #{command_with_iam(capabilities)}"

  puts "Please confirm (y/n)"
  $stdin.gets
end

#quit(signal) ⇒ Object

To allow mocking in specs



171
172
173
# File 'lib/lono/cfn/base.rb', line 171

def quit(signal)
  exit signal
end

#randomize(stack_name) ⇒ Object

Do nothing unless in Create class



176
177
178
# File 'lib/lono/cfn/base.rb', line 176

def randomize(stack_name)
  stack_name
end

#randomize_stack_name?Boolean

Returns:

  • (Boolean)


189
190
191
192
193
194
195
196
197
# File 'lib/lono/cfn/base.rb', line 189

def randomize_stack_name?
  if !randomize_stack_name.nil?
    return randomize_stack_name # CLI option takes highest precedence
  end

  # otherwise use the settings preference
  settings = Lono::Setting.new
  settings.data['randomize_stack_name']
end

#runObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/lono/cfn/base.rb', line 22

def run
  params = generate_all
  begin
    save_stack(params) # defined in the sub class
  rescue Aws::CloudFormation::Errors::InsufficientCapabilitiesException => e
    capabilities = e.message.match(/\[(.*)\]/)[1]
    confirm = prompt_for_iam(capabilities)
    if confirm =~ /^y/
      @options.merge!(capabilities: [capabilities])
      puts "Re-running: #{command_with_iam(capabilities).colorize(:green)}"
      retry
    else
      puts "Exited"
      exit 1
    end
  end
end

#s3_folderObject



214
215
216
217
# File 'lib/lono/cfn/base.rb', line 214

def s3_folder
  setting = Lono::Setting.new
  setting.s3_folder
end

#show_parameters(params, meth = nil) ⇒ Object



206
207
208
209
210
211
212
# File 'lib/lono/cfn/base.rb', line 206

def show_parameters(params, meth=nil)
  params = params.clone.compact
  params[:template_body] = "Hidden due to size... View at: #{@template_path}"
  to = meth || "AWS API"
  puts "Parameters passed to #{to}:"
  puts YAML.dump(params.deep_stringify_keys)
end

#stack_status(stack_name) ⇒ Object



152
153
154
155
156
157
158
# File 'lib/lono/cfn/base.rb', line 152

def stack_status(stack_name)
  return true if testing_update?
  return false if @options[:noop]

  resp = cfn.describe_stacks(stack_name: stack_name)
  resp.stacks[0].stack_status
end

#upload_scriptsObject

only upload templates if s3_folder configured in settings



80
81
82
83
# File 'lib/lono/cfn/base.rb', line 80

def upload_scripts
  return unless s3_folder
  Lono::Script::Upload.new.run
end

#upload_templatesObject

only upload templates if s3_folder configured in settings



75
76
77
# File 'lib/lono/cfn/base.rb', line 75

def upload_templates
  Lono::Template::Upload.new.run if s3_folder
end