Class: StackMate::Stacker

Inherits:
Object
  • Object
show all
Includes:
Logging, TSort
Defined in:
lib/stackmate/stack.rb

Direct Known Subclasses

StackExecutor

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging

configure_logger_for, #logger, logger_for

Constructor Details

#initialize(stackstr, stackname, params) ⇒ Stacker

Returns a new instance of Stacker.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/stackmate/stack.rb', line 15

def initialize(stackstr, stackname, params)
  @stackname = stackname
  @resolved = params
  @templ = JSON.parse(stackstr)
  @templ['StackName'] = @stackname
  @param_names = @templ['Parameters']
  @deps = {}
  @pdeps = {}
  validate_param_values
  resolve_dependencies()
  validate_dependencies
  @allowed_param_vales = get_allowed_values(@param_names)
  @templ['ResolvedNames'] = populate_parameters(@param_names,@resolved)
  #@templ['ResolvedNames']['StackId'] = SecureRandom.urlsafe_base64
  @templ['IdMap'] = {}
end

Instance Attribute Details

#templObject

Returns the value of attribute templ.



13
14
15
# File 'lib/stackmate/stack.rb', line 13

def templ
  @templ
end

Instance Method Details

#find_refs(parent, jsn, deps, pdeps) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/stackmate/stack.rb', line 114

def find_refs (parent, jsn, deps, pdeps)
  case jsn
  when Array
    jsn.each {|x| find_refs(parent, x, deps, pdeps)}
    #print parent, ": ", jsn, "\n"
  when Hash
    jsn.keys.each do |k|
      #TODO Fn::GetAtt
      if k == "Ref"
        #only resolve dependencies on other resources for now
        if !@param_names.keys.index(jsn[k]) && !@resolved.keys.index(jsn[k]) && jsn[k] != 'AWS::Region' && jsn[k] != 'AWS::StackId' && jsn[k] != 'AWS::StackName'
          deps << jsn[k]
          #print parent, ": ", deps.to_a, "\n"
        else if @param_names.keys.index(jsn[k])
          pdeps << jsn[k]
        end
      end
      else
        find_refs(parent, jsn[k], deps, pdeps)
      end
    end
  end
  return deps
end

#get_allowed_values(template_params) ⇒ Object



32
33
34
35
36
37
38
39
40
41
# File 'lib/stackmate/stack.rb', line 32

def get_allowed_values(template_params)
  allowed = {}
  template_params.each_key do |k|
    #Type is mandatory???
    allowed[k] = {}
    allowed[k]['Type'] = template_params[k]['Type'] if template_params[k].has_key?('Type')
    allowed[k]['AllowedValues'] = template_params[k]['AllowedValues'] if template_params[k].has_key?('AllowedValues')
  end
  allowed
end

#populate_parameters(params, overrides) ⇒ Object



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
# File 'lib/stackmate/stack.rb', line 43

def populate_parameters(params,overrides)
  populated={}
  #Populate defaults
  params.each_key do |k|
    populated[k] = params[k]['Default']
  end
  #Then load local YAML mappings
  begin
    #TODO change to use stackid
    #file_name = @stackname+".yml"
    file_name = "local.yml"
    localized = YAML.load_file(file_name)
    localized.each_key do |k|
      populated[k] = localized[k]
    end
  rescue
    #raise "ERROR : Unable to load end point parameters"
    logger.info("CAUTION: Unable to load end point parameters")
  end
  #Then override
  overrides.each_key do |k|
    populated[k] = overrides[k]
  end
  populated
end

#resolve_dependenciesObject



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/stackmate/stack.rb', line 86

def resolve_dependencies
  @templ['Resources'].each { |key,val|
    deps = Set.new
    pdeps = Set.new
    find_refs(key, val, deps, pdeps)
    deps << val['DependsOn'] if val['DependsOn']
    #print key, " depends on ", deps.to_a, "\n"
    @deps[key] = deps.to_a
    @pdeps[key] = pdeps.to_a
  }
  unresolved = []
  @pdeps.keys.each do |k|
    unres = @pdeps[k] - @resolved.keys
    if ! unres.empty?
      unres.each do |u|
        deflt = @param_names[u]['Default']
        #print "Found default value ", deflt, " for ", u, "\n" if deflt
        @resolved[u] = deflt if deflt
      end
      unres = @pdeps[k] - @resolved.keys
      unresolved = unresolved + unres
      #throw :unresolved, (@pdeps[k] - @resolved.keys) if !unres.empty?
    end
  end
  throw :unresolved, unresolved.uniq if !unresolved.empty?
end

#tsort_each_child(name, &block) ⇒ Object



143
144
145
# File 'lib/stackmate/stack.rb', line 143

def tsort_each_child(name, &block)
  @deps[name].each(&block) if @deps.has_key?(name)
end

#tsort_each_node(&block) ⇒ Object



139
140
141
# File 'lib/stackmate/stack.rb', line 139

def tsort_each_node(&block)
  @deps.each_key(&block)
end

#validate_dependenciesObject



75
76
77
78
79
80
81
82
83
84
# File 'lib/stackmate/stack.rb', line 75

def validate_dependencies
  resources = @deps.keys
  @deps.each_key do |k|
    @deps[k].each do |resource|
      if !resources.include?(resource)
        raise "Bad reference or dependency on resource #{resource}"
      end
    end
  end
end

#validate_param_valuesObject



69
70
71
72
73
# File 'lib/stackmate/stack.rb', line 69

def validate_param_values
  #TODO CloudFormation parameters have validity constraints specified
  #Use them to validate parameter values (e.g., email addresses)
  #As of now used only in actual cloudstack calls
end