Class: Yutani::Mod
Overview
Maps to a terraform module. Named ‘mod’ to avoid confusion with ruby ‘module’. It can contain :
-
other modules
-
resources
-
other resources (provider, data, etc)
-
variables
-
outputs
Its block is evaluated depending upon whether it is enclosed within another module It has the following properties
-
mandatory name of type symbol
-
optional scope of type hash
-
ability to output a tar of its contents
Direct Known Subclasses
Defined Under Namespace
Classes: InvalidReferencePathException, MyHash
Instance Attribute Summary collapse
-
#block ⇒ Object
Returns the value of attribute block.
-
#mods ⇒ Object
Returns the value of attribute mods.
-
#name ⇒ Object
Returns the value of attribute name.
-
#outputs ⇒ Object
Returns the value of attribute outputs.
-
#params ⇒ Object
Returns the value of attribute params.
-
#providers ⇒ Object
Returns the value of attribute providers.
-
#resources ⇒ Object
Returns the value of attribute resources.
-
#variables ⇒ Object
Returns the value of attribute variables.
Attributes inherited from DSLEntity
Instance Method Summary collapse
-
#child?(mod) ⇒ Boolean
given name of mod, return bool.
- #child_by_name(name) ⇒ Object
- #children ⇒ Object
- #create_dir_tree(prefix) ⇒ Object
- #debug ⇒ Object
- #descendents ⇒ Object
- #dir_path ⇒ Object
- #dir_tree(dt, prefix) ⇒ Object
-
#generate_pathway(mods, path) ⇒ Object
rel_path: relative path to a target mod ret an array of mods tracing that path sorted from target -> source mods: array of module objects, which after being built is returned path: array of path strings: i.e.
-
#initialize(name, parent, local_scope, parent_scope, &block) ⇒ Mod
constructor
A new instance of Mod.
- #mod(name, **scope, &block) ⇒ Object
- #parent?(mod) ⇒ Boolean
- #path ⇒ Object
- #pretty_json ⇒ Object
-
#propagate(prev, nxt, var) ⇒ Object
recursive linked-list function, propagating a variable from a target module to a source module seed var with array of [type,name,attr].
- #provider(provider_name, **scope, &block) ⇒ Object
- #resolve_references! ⇒ Object
- #resource(resource_type, identifiers, **scope, &block) ⇒ Object
- #resources_hash ⇒ Object
- #source(path) ⇒ Object
- #tar(filename) ⇒ Object
- #tf_name ⇒ Object
- #to_fs(prefix = './terraform') ⇒ Object
-
#to_h ⇒ Object
this generates the contents of *.tf.main.
Methods inherited from DSLEntity
Constructor Details
#initialize(name, parent, local_scope, parent_scope, &block) ⇒ Mod
Returns a new instance of Mod.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/yutani/mod.rb', line 23 def initialize(name, parent, local_scope, parent_scope, &block) @name = name.to_sym @scope = parent_scope.merge(local_scope) @scope[:module_name] = name @local_scope = local_scope @parent = parent @mods = [] @resources = [] @providers = [] @outputs = {} @params = {} @variables = {} instance_eval &block end |
Instance Attribute Details
#block ⇒ Object
Returns the value of attribute block.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def block @block end |
#mods ⇒ Object
Returns the value of attribute mods.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def mods @mods end |
#name ⇒ Object
Returns the value of attribute name.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def name @name end |
#outputs ⇒ Object
Returns the value of attribute outputs.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def outputs @outputs end |
#params ⇒ Object
Returns the value of attribute params.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def params @params end |
#providers ⇒ Object
Returns the value of attribute providers.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def providers @providers end |
#resources ⇒ Object
Returns the value of attribute resources.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def resources @resources end |
#variables ⇒ Object
Returns the value of attribute variables.
21 22 23 |
# File 'lib/yutani/mod.rb', line 21 def variables @variables end |
Instance Method Details
#child?(mod) ⇒ Boolean
given name of mod, return bool
138 139 140 |
# File 'lib/yutani/mod.rb', line 138 def child?(mod) children.map{|m| m.name }.include? mod.name end |
#child_by_name(name) ⇒ Object
142 143 144 |
# File 'lib/yutani/mod.rb', line 142 def child_by_name(name) children.find{|child| child.name == name.to_sym} end |
#children ⇒ Object
125 126 127 |
# File 'lib/yutani/mod.rb', line 125 def children @mods end |
#create_dir_tree(prefix) ⇒ Object
300 301 302 |
# File 'lib/yutani/mod.rb', line 300 def create_dir_tree(prefix) dir_tree(DirectoryTree.new(prefix), '') end |
#debug ⇒ Object
61 62 63 64 |
# File 'lib/yutani/mod.rb', line 61 def debug resolve_references!(self) #pp @mods.unshift(self).map{|m| m.to_h } end |
#descendents ⇒ Object
129 130 131 |
# File 'lib/yutani/mod.rb', line 129 def descendents children + children.map{|c| c.descendents}.flatten end |
#dir_path ⇒ Object
105 106 107 |
# File 'lib/yutani/mod.rb', line 105 def dir_path tf_name end |
#dir_tree(dt, prefix) ⇒ Object
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/yutani/mod.rb', line 304 def dir_tree(dt, prefix) full_dir_path = File.join(prefix, self.dir_path) main_tf_path = File.join(full_dir_path, 'main.tf.json') dt.add_file( main_tf_path, 0644, self.pretty_json ) mods.each do |m| m.dir_tree(dt, full_dir_path) end dt end |
#generate_pathway(mods, path) ⇒ Object
rel_path: relative path to a target mod ret an array of mods tracing that path sorted from target -> source mods: array of module objects, which after being built is returned path: array of path strings: i.e. [.. .. .. a b c]
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/yutani/mod.rb', line 158 def generate_pathway(mods, path) curr = path.shift case curr when /[a-z]+/ child = child_by_name(curr) if child.nil? raise InvalidReferencePathException, "no such module #{curr}" else child.generate_pathway(mods.unshift(self), path) end when '..' if @parent.nil? raise InvalidReferencePathException, "no such module #{curr}" else @parent.generate_pathway(mods.unshift(self), path) end when nil return mods.unshift(self) else raise InvalidReferencePathException, "invalid path component: #{curr}" end end |
#mod(name, **scope, &block) ⇒ Object
41 42 43 44 |
# File 'lib/yutani/mod.rb', line 41 def mod(name, **scope, &block) @mods << Mod.new(name, self, scope, @scope, &block) end |
#parent?(mod) ⇒ Boolean
133 134 135 |
# File 'lib/yutani/mod.rb', line 133 def parent?(mod) @parent.name == mod.name end |
#path ⇒ Object
146 147 148 |
# File 'lib/yutani/mod.rb', line 146 def path File.join(@parent.path, name.to_s) end |
#pretty_json ⇒ Object
121 122 123 |
# File 'lib/yutani/mod.rb', line 121 def pretty_json JSON.pretty_generate(to_h) end |
#propagate(prev, nxt, var) ⇒ Object
recursive linked-list function, propagating a variable from a target module to a source module seed var with array of [type,name,attr]
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/yutani/mod.rb', line 185 def propagate(prev, nxt, var) if prev.empty? # we are the source module if nxt.empty? # src and target in same mod "${%s}" % var.join('.') else if self.child? nxt.first # there is no 'composition' mod, new_var = [self.name, var].flatten nxt.first.params[new_var.join('_')] = "${%s}" % new_var.join('.') nxt.first.variables[new_var] = '' nxt.shift.propagate(prev.push(self), nxt, var) elsif self.parent?(nxt.first) # we are propagating upward the variable self.outputs[var.join('_')] = "${%s}" % var.join('.') nxt.shift.propagate(prev.push(self), nxt, var.join('_')) else raise "Propagation error!" end end else if nxt.empty? # we're the source module if self.child? prev.last # it's been propagated 'up' to us "${module.%s.%s}" % [prev.last.name, var] elsif self.parent? prev.last # it's been propagated 'down' to us "${var.%s}" % var else raise "Propagation error!" end else if self.child? prev.last and self.child? nxt.first # we're a 'composition' module; the common ancestor # to source and target modules new_var = [prev.last.name, var] nxt.first.params[new_var.join('_')] = "${module.%s.%s}" % new_var nxt.first.variables[new_var.join('_')] = "" nxt.shift.propagate(prev.push(self), nxt, new_var.join('_')) elsif self.child? prev.last and self.parent? nxt.first # we're propagating 'upward' the variable # towards the common ancestor new_var = [prev.last.name, var] self.outputs[new_var.join('_')] = "${module.%s.%s}" % new_var nxt.shift.propagate(prev.push(self), nxt, new_var.join('_')) elsif self.parent? prev.last and self.parent? nxt.first # we cannot be a child to two parents in a tree! raise "Progation error!" elsif self.parent? prev.last and self.child? nxt.first nxt.first.params[var] = "${var.%s}" % var nxt.first.variables[var] = "" nxt.shift.propagate(prev.push(self), nxt, var) else raise "Propagation error!" end end end end |
#provider(provider_name, **scope, &block) ⇒ Object
115 116 117 118 119 |
# File 'lib/yutani/mod.rb', line 115 def provider(provider_name, **scope, &block) merged_scope = @scope.merge(scope) @providers << Provider.new(provider_name, merged_scope, &block) end |
#resolve_references! ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/yutani/mod.rb', line 251 def resolve_references! @resources.each do |r| r.resolve_references! do |ref| matching_resources = [] path_components = ref.relative_path(self).split('/') mod_path = generate_pathway([], path_components) target_mod = mod_path.shift # lookup matching resources in mod_path.first matches = ref.find_matching_resources_in_module!(target_mod) if matches.empty? raise ReferenceException, "no matching resources found in mod #{target_mod.name}" end interpolation_strings = matches.map do |res| ra = ResourceAttribute.new(res.resource_type, res.resource_name, ref.attr) # clone mod_path, because propagate() will alter it target_mod.propagate([], mod_path.clone, [ra.type, ra.name, ra.attr]) end interpolation_strings.length == 1 ? interpolation_strings[0] : interpolation_strings end end children.each do |m| m.resolve_references! end end |
#resource(resource_type, identifiers, **scope, &block) ⇒ Object
109 110 111 112 113 |
# File 'lib/yutani/mod.rb', line 109 def resource(resource_type, identifiers, **scope, &block) merged_scope = @scope.merge(scope) @resources << Resource.new(resource_type, identifiers, merged_scope, &block) end |
#resources_hash ⇒ Object
53 54 55 56 57 58 59 |
# File 'lib/yutani/mod.rb', line 53 def resources_hash @resources.inject({}) do |r_hash, r| r_hash[r.resource_type] ||= {} r_hash[r.resource_type][r.resource_name] = r r_hash end end |
#source(path) ⇒ Object
46 47 48 49 50 51 |
# File 'lib/yutani/mod.rb', line 46 def source(path) absolute_path = File.(path, File.dirname(Yutani.entry_path)) contents = File.read absolute_path instance_eval contents, path end |
#tar(filename) ⇒ Object
284 285 286 287 288 289 290 291 |
# File 'lib/yutani/mod.rb', line 284 def tar(filename) # ideally, this needs to be done automatically as part of to_h resolve_references! File.open(filename, 'w+') do |tarball| create_dir_tree('./').to_tar(tarball) end end |
#tf_name ⇒ Object
99 100 101 102 103 |
# File 'lib/yutani/mod.rb', line 99 def tf_name dirs = @local_scope.values.map{|v| v.to_s.gsub('-', '_') } dirs.unshift(name) dirs.join('_') end |
#to_fs(prefix = './terraform') ⇒ Object
293 294 295 296 297 298 |
# File 'lib/yutani/mod.rb', line 293 def to_fs(prefix='./terraform') # ideally, this needs to be done automatically as part of to_h resolve_references! create_dir_tree(prefix).to_fs end |
#to_h ⇒ Object
this generates the contents of *.tf.main
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/yutani/mod.rb', line 71 def to_h h = { module: @mods.inject({}) {|modules,m| modules[m.tf_name] = {} modules[m.tf_name][:source] = m.dir_path modules[m.tf_name].merge! m.params modules }, resource: @resources.inject(MyHash.new){|resources,r| resources.deep_merge(r.to_h) }, provider: @providers.inject(MyHash.new){|providers,r| providers.deep_merge(r.to_h) }, output: @outputs.inject({}){|outputs,(k,v)| outputs[k] = { value: v } outputs }, variable: @variables.inject({}){|variables,(k,v)| variables[k] = {} variables } } # terraform doesn't like empty output and variable collections h.delete_if {|_,v| v.empty? } end |