Class: Cfer::Core::Stack

Inherits:
Block
  • Object
show all
Includes:
Functions, Hooks
Defined in:
lib/cfer/core/stack.rb

Overview

Defines the structure of a CloudFormation stack

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Hooks

included, #post_block, #pre_block

Methods included from Functions

#and, #equals, #find_in_map, #get_att, #get_azs, #if, #join, #not, #notification_arns, #or, #ref, #select, #sub

Methods inherited from Block

#build_from_block, #build_from_file, #build_from_string, #include_file, #post_block, #pre_block

Constructor Details

#initialize(options = {}) ⇒ Stack

Returns a new instance of Stack.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/cfer/core/stack.rb', line 30

def initialize(options = {})
  self[:AWSTemplateFormatVersion] = '2010-09-09'
  self[:Description] = ''

  @options = options

  self[:Metadata] = {
    :Cfer => {
      :Version => Cfer::SEMANTIC_VERSION.to_h.delete_if { |k, v| v === nil }
    }
  }

  self[:Parameters] = {}
  self[:Mappings] = {}
  self[:Conditions] = {}
  self[:Resources] = {}
  self[:Outputs] = {}

  if options[:client] && git = options[:client].git && @git_version = (git.object('HEAD^').sha rescue nil)
    self[:Metadata][:Cfer][:Git] = {
      Rev: @git_version,
      Clean: git.status.changed.empty?
    }
  end

  @parameters = HashWithIndifferentAccess.new
  @input_parameters = HashWithIndifferentAccess.new

  if options[:client]
    begin
      @parameters.merge! options[:client].fetch_parameters
    rescue Cfer::Util::StackDoesNotExistError
      Cfer::LOGGER.debug "Can't include current stack parameters because the stack doesn't exist yet."
    end
  end

  if options[:parameters]
    options[:parameters].each do |key, val|
      @input_parameters[key] = @parameters[key] = val
    end
  end
end

Instance Attribute Details

#git_versionObject (readonly)

Returns the value of attribute git_version.



16
17
18
# File 'lib/cfer/core/stack.rb', line 16

def git_version
  @git_version
end

#input_parametersObject (readonly)

The parameters strictly as passed via command line



9
10
11
# File 'lib/cfer/core/stack.rb', line 9

def input_parameters
  @input_parameters
end

#optionsObject (readonly)

Returns the value of attribute options.



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

def options
  @options
end

#parametersObject (readonly)

The fully resolved parameters, including defaults and parameters fetched from an existing stack during an update



12
13
14
# File 'lib/cfer/core/stack.rb', line 12

def parameters
  @parameters
end

Class Method Details

.extend_stack(&block) ⇒ Object



195
196
197
# File 'lib/cfer/core/stack.rb', line 195

def extend_stack(&block)
  class_eval(&block)
end

Instance Method Details

#clientObject

Gets the Cfn client, if one exists, or throws an error if one does not



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

def client
  @options[:client] || raise('No client set on this stack')
end

#condition(name, expr) ⇒ Object

Adds a condition to the template.

Parameters:



128
129
130
# File 'lib/cfer/core/stack.rb', line 128

def condition(name, expr)
  self[:Conditions][name] = expr
end

#converge!(options = {}) ⇒ Object



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

def converge!(options = {})
  client.converge self, options
end

#description(desc) ⇒ Object

Sets the description for this CloudFormation stack



74
75
76
# File 'lib/cfer/core/stack.rb', line 74

def description(desc)
  self[:Description] = desc
end

#include_template(*files) ⇒ Object

Includes template code from one or more files, and evals it in the context of this stack. Filenames are relative to the file containing the invocation of this method.



172
173
174
175
176
177
178
# File 'lib/cfer/core/stack.rb', line 172

def include_template(*files)
  include_base = options[:include_base] || File.dirname(caller.first.split(/:\d/,2).first)
  files.each do |file|
    path = File.join(include_base, file)
    include_file(path)
  end
end

#lookup_output(stack, out) ⇒ Object

Looks up a specific output of another CloudFormation stack in the same region.

Parameters:

  • stack (String)

    The name of the stack to fetch an output from

  • out (String)

    The name of the output to fetch from the stack



183
184
185
# File 'lib/cfer/core/stack.rb', line 183

def lookup_output(stack, out)
  lookup_outputs(stack).fetch(out)
end

#lookup_outputs(stack) ⇒ Object

Looks up a hash of all outputs from another CloudFormation stack in the same region.

Parameters:

  • stack (String)

    The name of the stack to fetch outputs from



189
190
191
192
# File 'lib/cfer/core/stack.rb', line 189

def lookup_outputs(stack)
  client = @options[:client] || raise(Cfer::Util::CferError, "Can not fetch stack outputs without a client")
  client.fetch_outputs(stack)
end

#mappings(mappings) ⇒ Object

Sets the mappings block for this stack. See The CloudFormation Documentation for more details



121
122
123
# File 'lib/cfer/core/stack.rb', line 121

def mappings(mappings)
  self[:Mappings] = mappings
end

#output(name, value, options = {}) ⇒ Object

Adds an output to the CloudFormation stack.

Parameters:

  • name (String)

    The Logical ID of the output parameter

  • value (String)

    Value to return

  • options (Hash) (defaults to: {})

    Extra options for this output parameter

Options Hash (options):

  • :Description (String)

    Information about the value



151
152
153
# File 'lib/cfer/core/stack.rb', line 151

def output(name, value, options = {})
  self[:Outputs][name] = options.merge('Value' => value)
end

#parameter(name, options = {}) ⇒ Object

Declares a CloudFormation parameter

Parameters:

  • name (String)

    The parameter name

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :type (String)

    The type for the CloudFormation parameter

  • :default (String)

    A value of the appropriate type for the template to use if no value is specified when a stack is created. If you define constraints for the parameter, you must specify a value that adheres to those constraints.

  • :no_echo (String)

    Whether to mask the parameter value whenever anyone makes a call that describes the stack. If you set the value to true, the parameter value is masked with asterisks (*****).

  • :allowed_values (String)

    An array containing the list of values allowed for the parameter.

  • :allowed_pattern (String)

    A regular expression that represents the patterns you want to allow for String types.

  • :max_length (Number)

    An integer value that determines the largest number of characters you want to allow for String types.

  • :min_length (Number)

    An integer value that determines the smallest number of characters you want to allow for String types.

  • :max_value (Number)

    A numeric value that determines the largest numeric value you want to allow for Number types.

  • :min_value (Number)

    A numeric value that determines the smallest numeric value you want to allow for Number types.

  • :description (String)

    A string of up to 4000 characters that describes the parameter.

  • :constraint_description (String)

    A string that explains the constraint when the constraint is violated. For example, without a constraint description, a parameter that has an allowed pattern of [A-Za-z0-9]+ displays the following error message when the user specifies an invalid value:

    Malformed input-Parameter MyParameter must match pattern [A-Za-z0-9]+

    By adding a constraint description, such as must only contain upper- and lowercase letters, and numbers, you can display a customized error message:

    Malformed input-Parameter MyParameter must only contain upper and lower case letters and numbers



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/cfer/core/stack.rb', line 99

def parameter(name, options = {})
  param = {}
  options.each do |key, v|
    next if v === nil

    k = key.to_s.camelize.to_sym
    param[k] =
      case k
      when :AllowedPattern
        if v.class == Regexp
          v.source
        end
      when :Default
        @parameters[name] ||= v
      end
    param[k] ||= v
  end
  param[:Type] ||= 'String'
  self[:Parameters][name] = param
end

#resource(name, type, options = {}, &block) ⇒ Object

Creates a CloudFormation resource

Parameters:

  • name (String)

    The name of the resource (must be alphanumeric)

  • type (String)

    The type of CloudFormation resource to create.

  • options (Hash) (defaults to: {})

    Additional attributes to add to the resource block (such as the UpdatePolicy for an AWS::AutoScaling::AutoScalingGroup)



136
137
138
139
140
141
142
143
144
# File 'lib/cfer/core/stack.rb', line 136

def resource(name, type, options = {}, &block)
  Preconditions.check_argument(/[[:alnum:]]+/ =~ name, "Resource name must be alphanumeric")

  clazz = Cfer::Core::Resource.resource_class(type)
  rc = clazz.new(name, type, self, options, &block)

  self[:Resources][name] = rc
  rc
end

#tail!(options = {}, &block) ⇒ Object



26
27
28
# File 'lib/cfer/core/stack.rb', line 26

def tail!(options = {}, &block)
  client.tail self, options, &block
end

#to_cfnString

Renders the stack into a CloudFormation template.

Returns:

  • (String)

    The final template



157
158
159
160
161
162
163
# File 'lib/cfer/core/stack.rb', line 157

def to_cfn
  if @options[:pretty_print]
    JSON.pretty_generate(to_h)
  else
    to_h.to_json
  end
end