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

Class Method 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:



36
37
38
39
40
41
42
# File 'lib/moonshot/stack.rb', line 36

def initialize(config)
  @config = config
  @ilog = config.interactive_logger
  @name = self.class.generate_name(@config)

  yield @config if block_given?
end

Instance Attribute Details

#app_nameObject (readonly)

Returns the value of attribute app_name.



14
15
16
# File 'lib/moonshot/stack.rb', line 14

def app_name
  @app_name
end

#nameObject (readonly)

Returns the value of attribute name.



14
15
16
# File 'lib/moonshot/stack.rb', line 14

def name
  @name
end

Class Method Details

.generate_name(config) ⇒ Object



17
18
19
# File 'lib/moonshot/stack.rb', line 17

def generate_name(config)
  [config.app_name, config.environment_name].join('-')
end

.make_tags(config) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/moonshot/stack.rb', line 21

def make_tags(config)
  default_tags = [
    { key: 'moonshot_application', value: config.app_name },
    { key: 'moonshot_environment', value: config.environment_name }
  ]
  name = generate_name(config)

  if config.additional_tag
    default_tags << { key: config.additional_tag, value: name }
  end

  default_tags + config.extra_tags
end

Instance Method Details

#createObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/moonshot/stack.rb', line 44

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.



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

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

#deleteObject



76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/moonshot/stack.rb', line 76

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)


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

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

#outputsObject



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

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

#parametersObject



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

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

#physical_id_for(logical_id) ⇒ String?

Returns:

  • (String, nil)


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

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
end

#resource_summariesObject



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

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


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

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

#statusObject



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/moonshot/stack.rb', line 91

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



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

def template
  load_template_file
end

#template_fileString

Returns the path to the template file.

Returns:

  • (String)

    the path to the template file.



159
160
161
# File 'lib/moonshot/stack.rb', line 159

def template_file
  load_template_file.filename
end

#update(dry_run:, force:) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/moonshot/stack.rb', line 59

def update(dry_run:, force:)
  raise "No stack found #{@name.blue}!" unless stack_exists?

  change_set = ChangeSet.new(new_change_set, @name)
  wait_for_change_set(change_set)
  return unless change_set.valid?

  if dry_run
    change_set.display_changes
  elsif !force
    change_set.display_changes
    change_set.confirm? || raise('ChangeSet rejected!')
  end

  execute_change_set(change_set)
end