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(config) {|@config| ... } ⇒ Stack

Returns a new instance of Stack.

Yields:



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

def initialize(config)
  @config = config
  @ilog = config.interactive_logger
  @name = [@config.app_name, @config.environment_name].join('-')

  yield @config if block_given?
end

Instance Attribute Details

#app_nameObject (readonly)

Returns the value of attribute app_name.



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

def app_name
  @app_name
end

#nameObject (readonly)

Returns the value of attribute name.



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

def name
  @name
end

Instance Method Details

#createObject



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

def create
  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.



145
146
147
148
149
150
151
# File 'lib/moonshot/stack.rb', line 145

def default_values
  h = {}
  template.parameters.each do |p|
    h[p.name] = h.default
  end
  h
end

#deleteObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/moonshot/stack.rb', line 65

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)


107
108
109
110
111
112
# File 'lib/moonshot/stack.rb', line 107

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

#outputsObject



100
101
102
103
104
105
# File 'lib/moonshot/stack.rb', line 100

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.



136
137
138
139
140
141
142
# File 'lib/moonshot/stack.rb', line 136

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

#parametersObject



93
94
95
96
97
98
# File 'lib/moonshot/stack.rb', line 93

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.



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

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

#physical_id_for(logical_id) ⇒ String?

Returns:

  • (String, nil)


120
121
122
123
124
125
# File 'lib/moonshot/stack.rb', line 120

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



115
116
117
# File 'lib/moonshot/stack.rb', line 115

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>)


128
129
130
131
132
# File 'lib/moonshot/stack.rb', line 128

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

#statusObject



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/moonshot/stack.rb', line 80

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



153
154
155
# File 'lib/moonshot/stack.rb', line 153

def template
  @template ||= load_template_file
end

#template_fileString

Returns the path to the template file.

Returns:

  • (String)

    the path to the template file.



158
159
160
161
162
163
164
165
166
167
168
# File 'lib/moonshot/stack.rb', line 158

def template_file
  json = json_template_path
  yaml = yaml_template_path

  @template_file ||= Dir[json].first || Dir[yaml].first

  raise 'CloudFormation template not found at'\
        "#{json} or #{yaml}!" unless @template_file

  @template_file
end

#updateObject



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

def update
  raise "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 'Failed to update the CloudFormation Stack.' unless success
  success
end