Class: Moonshot::Stack

Inherits:
Object
  • Object
show all
Includes:
CredsHelper, DoctorHelper
Defined in:
lib/moonshot/stack.rb

Overview

The Stack wraps all CloudFormation actions performed by Moonshot. It stores the state of the active stack running on AWS, but contains a reference to the StackTemplate that would be applied with an update action.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from DoctorHelper

#doctor_hook

Methods included from CredsHelper

#as_client, #cd_client, #cf_client, #ec2_client, #iam_client, #s3_client

Constructor Details

#initialize(name, app_name:, log:, ilog:, config: StackConfig.new) {|@config| ... } ⇒ Stack

TODO: Refactor more of these parameters into the config object.

Yields:

  • (@config)


24
25
26
27
28
29
30
31
# File 'lib/moonshot/stack.rb', line 24

def initialize(name, app_name:, log:, ilog:, config: StackConfig.new)
  @name = name
  @app_name = app_name
  @log = log
  @ilog = ilog
  @config = config
  yield @config if block_given?
end

Instance Attribute Details

#app_nameObject (readonly)

Returns the value of attribute app_name.



20
21
22
# File 'lib/moonshot/stack.rb', line 20

def app_name
  @app_name
end

#nameObject (readonly)

Returns the value of attribute name.



21
22
23
# File 'lib/moonshot/stack.rb', line 21

def name
  @name
end

Instance Method Details

#add_parameter_overrides(hash) ⇒ Object



170
171
172
173
174
175
# File 'lib/moonshot/stack.rb', line 170

def add_parameter_overrides(hash)
  new_overrides = hash.merge(overrides)
  File.open(parameters_file, 'w') do |f|
    YAML.dump(new_overrides, f)
  end
end

#createObject



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/moonshot/stack.rb', line 33

def create
  import_parent_parameters

  should_wait = true
  @ilog.start "Creating #{stack_name}." do |s|
    if stack_exists?
      s.success "#{stack_name} already exists."
      should_wait = false
    else
      create_stack
      s.success "Created #{stack_name}."
    end
  end

  should_wait ? wait_for_stack_state(:stack_create_complete, 'created') : true
end

#default_valuesObject

Return a Hash of the default values defined in the stack template.



148
149
150
151
152
153
154
# File 'lib/moonshot/stack.rb', line 148

def default_values
  h = {}
  JSON.parse(template.body).fetch('Parameters', {}).map do |k, v|
    h[k] = v['Default']
  end
  h
end

#deleteObject



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/moonshot/stack.rb', line 68

def delete
  should_wait = true
  @ilog.start "Deleting #{stack_name}." do |s|
    if stack_exists?
      cf_client.delete_stack(stack_name: @name)
      s.success "Initiated deletion of #{stack_name}."
    else
      s.success "#{stack_name} does not exist."
      should_wait = false
    end
  end

  should_wait ? wait_for_stack_state(:stack_delete_complete, 'deleted') : true
end

#exists?Boolean Also known as: stack_exists?

Returns:

  • (Boolean)


110
111
112
113
114
115
# File 'lib/moonshot/stack.rb', line 110

def exists?
  cf_client.describe_stacks(stack_name: @name)
  true
rescue Aws::CloudFormation::Errors::ValidationError
  false
end

#outputsObject



103
104
105
106
107
108
# File 'lib/moonshot/stack.rb', line 103

def outputs
  get_stack(@name)
    .outputs
    .map { |o| [o.output_key, o.output_value] }
    .to_h
end

#overridesObject

Build a hash of overrides that would be applied to this stack by an update.



139
140
141
142
143
144
145
# File 'lib/moonshot/stack.rb', line 139

def overrides
  if File.exist?(parameters_file)
    YAML.load_file(parameters_file) || {}
  else
    {}
  end
end

#parametersObject



96
97
98
99
100
101
# File 'lib/moonshot/stack.rb', line 96

def parameters
  get_stack(@name)
    .parameters
    .map { |p| [p.parameter_key, p.parameter_value] }
    .to_h
end

#parameters_fileString

Returns the path to the parameters file.

Returns:

  • (String)

    the path to the parameters file.



166
167
168
# File 'lib/moonshot/stack.rb', line 166

def parameters_file
  File.join(Dir.pwd, 'cloud_formation', 'parameters', "#{@name}.yml")
end

#physical_id_for(logical_id) ⇒ String?

Returns:

  • (String, nil)


123
124
125
126
127
128
# File 'lib/moonshot/stack.rb', line 123

def physical_id_for(logical_id)
  resource_summary = resource_summaries.find do |r|
    r.logical_resource_id == logical_id
  end
  resource_summary.physical_resource_id if resource_summary
end

#resource_summariesObject



118
119
120
# File 'lib/moonshot/stack.rb', line 118

def resource_summaries
  cf_client.list_stack_resources(stack_name: @name).stack_resource_summaries
end

#resources_of_type(type) ⇒ Array<Aws::CloudFormation::Types::StackResourceSummary>

Returns:

  • (Array<Aws::CloudFormation::Types::StackResourceSummary>)


131
132
133
134
135
# File 'lib/moonshot/stack.rb', line 131

def resources_of_type(type)
  resource_summaries.select do |r|
    r.resource_type == type
  end
end

#statusObject



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/moonshot/stack.rb', line 83

def status
  if exists?
    puts "#{stack_name} exists."
    t = UnicodeTable.new('')
    StackParameterPrinter.new(self, t).print
    StackOutputPrinter.new(self, t).print
    StackASGPrinter.new(self, t).print
    t.draw_children
  else
    puts "#{stack_name} does NOT exist."
  end
end

#templateObject



156
157
158
# File 'lib/moonshot/stack.rb', line 156

def template
  @template ||= StackTemplate.new(template_file, log: @log)
end

#template_fileString

Returns the path to the template file.

Returns:

  • (String)

    the path to the template file.



161
162
163
# File 'lib/moonshot/stack.rb', line 161

def template_file
  File.join(Dir.pwd, 'cloud_formation', "#{@app_name}.json")
end

#updateObject

Raises:

  • (Thor::Error)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/moonshot/stack.rb', line 50

def update
  raise Thor::Error, "No stack found #{@name.blue}!" unless stack_exists?

  should_wait = true
  @ilog.start "Updating #{stack_name}." do |s|
    if update_stack
      s.success "Initiated update for #{stack_name}."
    else
      s.success 'No Stack update required.'
      should_wait = false
    end
  end

  success = should_wait ? wait_for_stack_state(:stack_update_complete, 'updated') : true
  raise Thor::Error, 'Failed to update the CloudFormation Stack.' unless success
  success
end