corl 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Gemfile.lock +1 -1
  2. data/VERSION +1 -1
  3. data/corl.gemspec +12 -7
  4. data/lib/CORL/action/build.rb +30 -0
  5. data/lib/CORL/action/provision.rb +34 -8
  6. data/lib/CORL/configuration/file.rb +50 -64
  7. data/lib/CORL/provisioner/puppetnode.rb +186 -314
  8. data/lib/core/mixin/lookup.rb +20 -15
  9. data/lib/core/mixin/macro/network_settings.rb +52 -0
  10. data/lib/core/plugin/action.rb +1 -1
  11. data/lib/core/plugin/configuration.rb +43 -4
  12. data/lib/core/plugin/network.rb +16 -3
  13. data/lib/core/plugin/node.rb +69 -2
  14. data/lib/core/plugin/provisioner.rb +286 -11
  15. data/lib/{CORL/provisioner/puppetnode → core/util/puppet}/resource.rb +36 -40
  16. data/lib/{CORL/provisioner/puppetnode → core/util/puppet}/resource_group.rb +33 -41
  17. data/lib/core/util/puppet.rb +303 -0
  18. data/lib/corl.rb +34 -11
  19. data/lib/facter/corl_build.rb +8 -0
  20. data/lib/facter/corl_exists.rb +3 -3
  21. data/lib/facter/corl_network.rb +1 -1
  22. data/lib/facter/custom_facts.rb +24 -0
  23. data/lib/facter/vagrant_exists.rb +15 -0
  24. data/lib/hiera/corl_logger.rb +1 -1
  25. data/lib/puppet/indirector/corl.rb +2 -2
  26. data/lib/puppet/parser/functions/corl_include.rb +10 -14
  27. data/lib/puppet/parser/functions/corl_initialize.rb +15 -0
  28. data/lib/puppet/parser/functions/{deep_merge.rb → corl_merge.rb} +4 -4
  29. data/lib/puppet/parser/functions/corl_resources.rb +9 -4
  30. data/lib/puppet/parser/functions/global_array.rb +1 -1
  31. data/lib/puppet/parser/functions/global_hash.rb +1 -1
  32. data/lib/puppet/parser/functions/global_param.rb +1 -1
  33. data/lib/puppet/parser/functions/interpolate.rb +1 -1
  34. data/lib/puppet/parser/functions/module_array.rb +8 -9
  35. data/lib/puppet/parser/functions/module_hash.rb +7 -8
  36. data/lib/puppet/parser/functions/module_param.rb +4 -5
  37. data/lib/puppet/parser/functions/name.rb +1 -1
  38. data/lib/puppet/parser/functions/render.rb +5 -5
  39. metadata +34 -29
  40. data/lib/CORL/extension/puppetloader.rb +0 -24
  41. data/lib/puppet/parser/functions/config_initialized.rb +0 -26
@@ -3,394 +3,266 @@ module CORL
3
3
  module Provisioner
4
4
  class Puppetnode < CORL.plugin_class(:provisioner)
5
5
 
6
+ @@puppet_lock = Mutex.new
7
+
6
8
  #-----------------------------------------------------------------------------
7
9
  # Provisioner plugin interface
8
10
 
9
11
  def normalize(reload)
10
- super
11
-
12
- unless reload
13
- require 'puppet'
14
-
12
+ super do
15
13
  if CORL.log_level == :debug
16
14
  Puppet.debug = true
17
- end
18
- Puppet.initialize_settings
19
-
20
- myself.plugin_name = :default if plugin_name.to_sym == :puppetnode
21
-
22
- @env = Puppet::Node::Environment.new
23
- @compiler = Puppet::Parser::Compiler.new(node)
15
+ end
24
16
  end
25
-
26
- init_scope
27
- register
28
17
  end
29
18
 
30
- #-----------------------------------------------------------------------------
31
- # Property accessor / modifiers
32
-
33
- def env
34
- @env
19
+ #---
20
+
21
+ def register(options = {})
22
+ Util::Puppet.register_plugins(Config.ensure(options).defaults({ :puppet_scope => scope }))
35
23
  end
36
24
 
37
- #---
25
+ #-----------------------------------------------------------------------------
26
+ # Property accessor / modifiers
38
27
 
39
28
  def compiler
40
29
  @compiler
41
30
  end
42
31
 
43
- #---
44
-
45
- def init_facts
46
- facts = {}
47
-
48
- unless Puppet[:node_name_value].empty?
49
- facts_obj = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value])
50
- facts = facts_obj.values if facts_obj
51
- end
52
-
53
- set(:facts, facts)
54
- end
55
- protected :init_facts
56
-
57
32
  #---
58
33
 
59
- def facts(reset = false)
60
- if reset || ! get(:facts)
61
- init_facts
62
- end
63
- get(:facts)
34
+ def scope
35
+ return compiler.topscope if compiler
36
+ nil
64
37
  end
65
38
 
66
- #---
67
-
68
- def init_node
69
- if name
70
- name_orig = Puppet[:node_name_value]
71
- Puppet[:node_name_value] = name
72
- end
39
+ #-----------------------------------------------------------------------------
40
+ # Puppet initialization
73
41
 
74
- node = Puppet::Node.indirection.find(Puppet[:node_name_value])
42
+ def init_puppet(profiles)
43
+ locations = build_locations
75
44
 
76
- if facts = facts(true)
77
- node.merge(facts.values)
78
- end
79
-
80
- file = Puppet[:classfile]
81
- if FileTest.exists?(file)
82
- node.classes = File.read(file).split(/[\s\n]+/)
83
- end
45
+ # Must be in this order!!
46
+ Puppet.initialize_settings
47
+ Puppet::Util::Log.newdestination(:console)
84
48
 
85
- Puppet[:node_name_value] = name_orig if name_orig
86
- @node = node
87
- end
88
- protected :init_node
89
-
90
- #---
91
-
92
- def node(reset = false)
93
- if reset || ! @node
94
- init_node
49
+ # TODO: Figure out how to store these damn settings in a specialized
50
+ # environment without phantom empty environment issues.
51
+
52
+ node = get_node
53
+ Puppet[:node_name_value] = id.to_s
54
+
55
+ if manifest = gateway
56
+ if manifest.match(/^packages\/.*/)
57
+ manifest = File.join(build_directory, locations[:build], manifest)
58
+ else
59
+ manifest = File.join(network.directory, directory, manifest)
60
+ end
61
+ Puppet[:manifest] = manifest
95
62
  end
96
- @node
97
- end
98
-
99
- #---
100
-
101
- def init_scope
102
- @scope = Puppet::Parser::Scope.new(compiler)
103
- scope.source = Puppet::Resource::Type.new(:node, node.name)
104
- scope.parent = compiler.topscope
105
- end
106
-
107
- #---
108
-
109
- def scope
110
- @scope
111
- end
112
-
113
- #---
114
-
115
- def init_catalog
116
- node = node(true)
117
63
 
118
- starttime = Time.now
119
- catalog = Puppet::Resource::Catalog.indirection.find(node.name, :use_node => node)
120
-
121
- catalog = catalog.to_ral
122
- catalog.finalize
123
-
124
- catalog.retrieval_duration = Time.now - starttime
125
-
126
- catalog.write_class_file
127
- catalog.write_resource_file
64
+ unless profiles.empty?
65
+ modulepath = profiles.collect do |profile|
66
+ File.join(build_directory, locations[:module][profile.to_sym])
67
+ end
68
+ Puppet[:modulepath] = array(modulepath).join(File::PATH_SEPARATOR)
69
+ end
128
70
 
129
- @catalog = catalog
71
+ @compiler = Puppet::Parser::Compiler.new(node)
72
+ register
73
+
74
+ # Initialize the compiler so we can can lookup and include stuff
75
+ # This is ugly but seems to be the only way.
76
+ compiler.compile
130
77
  end
78
+ protected :init_puppet
131
79
 
132
80
  #---
133
-
134
- def catalog(reset = false)
135
- if reset || ! @catalog
136
- init_catalog
81
+
82
+ def get_node
83
+ node_id = id.to_s
84
+ node = Puppet::Node.indirection.find(node_id)
85
+
86
+ if facts = Puppet::Node::Facts.indirection.find(node_id)
87
+ facts.name = node_id
88
+ node.merge(facts.values)
137
89
  end
138
- @catalog
90
+ node
139
91
  end
92
+ protected :get_node
140
93
 
141
94
  #-----------------------------------------------------------------------------
142
- # Resources
143
-
144
- def resource_types
145
- env.known_resource_types
146
- end
95
+ # Provisioner interface operations
147
96
 
148
- #---
149
-
150
- def type_info(type_name, reset = false)
151
- type_name = type_name.to_s.downcase
152
- type_info = get(:type_info, {})
153
-
154
- if reset || ! type_info.has_key?(type_name)
155
- resource_type = nil
156
- type_exported, type_virtual = false
97
+ def build(options = {})
98
+ super do |locations, package_info, init_location|
99
+ init_location.call(:modules, nil)
100
+
101
+ init_location.call(:profiles, :pp)
102
+ init_location.call(:default, :pp)
157
103
 
158
- if type_name.start_with?('@@')
159
- type_name = type_name[2..-1]
160
- type_exported = true
161
-
162
- elsif type_name.start_with?('@')
163
- type_name = type_name[1..-1]
164
- type_virtual = true
165
- end
104
+ # Build modules
105
+
106
+ locations[:module] = {}
107
+
108
+ init_profile = lambda do |package_name, profile_name, profile_info|
109
+ package_id = id(package_name)
110
+ base_directory = File.join(locations[:modules], package_id.to_s, profile_name.to_s)
166
111
 
167
- if type_name == 'class'
168
- resource_type = :class
169
- else
170
- if resource = Puppet::Type.type(type_name.to_sym)
171
- resource_type = :type
172
-
173
- elsif resource = find_definition(type_name)
174
- resource_type = :define
112
+ if profile_info.has_key?(:modules)
113
+ profile_info[:modules].each do |module_name, module_reference|
114
+ module_directory = File.join(base_directory, module_name.to_s)
115
+
116
+ module_project = CORL.project(extended_config(:puppet_module, {
117
+ :directory => File.join(build_directory, module_directory),
118
+ :url => module_reference,
119
+ :create => true,
120
+ :pull => true
121
+ }))
122
+ raise unless module_project
123
+ end
124
+ locations[:module][profile_id(package_name, profile_name)] = base_directory
125
+ end
126
+ end
127
+
128
+ hash(package_info.get([ :provisioners, plugin_provider ])).each do |package_name, info|
129
+ if info.has_key?(:profiles)
130
+ info[:profiles].each do |profile_name, profile_info|
131
+ init_profile.call(package_name, profile_name, profile_info)
132
+ end
175
133
  end
176
134
  end
177
-
178
- type_info[type_name] = {
179
- :name => type_name,
180
- :type => resource_type,
181
- :resource => resource,
182
- :exported => type_exported,
183
- :virtual => type_virtual
184
- }
185
- set(:type_info, type_info)
186
- end
187
-
188
- type_info[type_name]
135
+ profiles.each do |profile_name, profile_info|
136
+ init_profile.call(plugin_name, profile_name, profile_info)
137
+ end
138
+ end
189
139
  end
190
140
 
191
141
  #---
192
142
 
193
- def find_hostclass(name, options = {})
194
- resource_types.find_hostclass(scope.namespaces, name, options)
195
- end
196
-
197
- #---
198
-
199
- def find_definition(name)
200
- resource_types.find_definition(scope.namespaces, name)
143
+ def lookup(property, default = nil, options = {})
144
+ Util::Puppet.lookup(property, default, Config.ensure(options).defaults({
145
+ :provisioner => :puppetnode,
146
+ :puppet_scope => scope
147
+ }))
201
148
  end
202
-
203
- #-----------------------------------------------------------------------------
204
- # Catalog alterations
205
149
 
206
- def clear
207
- init_catalog
208
- myself
209
- end
150
+ #--
210
151
 
211
- #---
212
-
213
- def add(type_name, resources, defaults = {}, options = {})
214
- info = type_info(type_name)
215
- PuppetExt::ResourceGroup.new(self, info, defaults).add(resources, options)
152
+ def import(files, options = {})
153
+ Util::Puppet.import(files, Config.ensure(options).defaults({
154
+ :puppet_scope => scope,
155
+ :puppet_import_base => network.directory
156
+ }))
216
157
  end
217
158
 
218
159
  #---
219
160
 
220
- def add_resource(type, title, properties)
221
- if type_name.is_a?(String)
222
- type = type_info(type)
223
- end
224
-
225
- case type[:type]
226
- when :type, :define
227
- add_definition(type, title, properties)
228
- when :class
229
- add_class(title, properties)
230
- end
161
+ def include(resource_name, properties = {}, options = {})
162
+ Util::Puppet.include(resource_name, properties, Config.ensure(options).defaults({
163
+ :provisioner => :puppetnode,
164
+ :puppet_scope => scope
165
+ }))
231
166
  end
232
-
233
- #---
234
167
 
235
- def add_class(title, properties)
236
- klass = find_hostclass(title)
237
- if klass
238
- klass.ensure_in_catalog(scope, properties)
239
- catalog.add_class(title)
240
- end
241
- end
242
- protected :add_class
243
-
244
168
  #---
245
169
 
246
- def add_definition(type, title, properties)
247
- if type_name.is_a?(String)
248
- type = type_info(type)
249
- end
250
-
251
- resource = Puppet::Parser::Resource.new(type[:name], title, :scope => scope, :source => type[:resource])
252
- resource.virtual = type[:virtual]
253
- resource.exported = type[:exported]
254
-
255
- namevar = namevar(type[:name], title).to_sym
256
- resource_name = properties.has_key?(namevar) ? properties[namevar] : title
257
-
258
- { :name => resource_name }.merge(properties).each do |key, value|
259
- resource.set_parameter(key, value)
260
- end
261
- if type[:type] == :define
262
- type[:resource].instantiate_resource(scope, resource)
263
- end
264
- compiler.add_resource(scope, resource)
170
+ def add_search_path(type, resource_name)
171
+ Config.set_options([ :all, type ], { :search => [ resource_name.to_s ] })
265
172
  end
266
- protected :add_definition
267
-
268
- #-----------------------------------------------------------------------------
269
- # Puppet operations
270
-
271
- def lookup(property, default = nil, options = {})
272
- config = Config.ensure(options)
273
- value = nil
274
-
275
- puppet_scope = config.get(:puppet_scope, scope)
173
+
174
+ #---
276
175
 
277
- base_names = config.get(:search, nil)
278
-
279
- search_name = config.get(:search_name, true)
280
- reverse_lookup = config.get(:reverse_lookup, true)
176
+ def provision(profiles, options = {})
177
+ locations = build_locations
178
+ success = true
281
179
 
282
- log_level = ::Puppet::Util::Log.level
283
- Puppet::Util::Log.level = :err # Don't want failed parameter lookup warnings here.
284
-
285
- if base_names
286
- if base_names.is_a?(String)
287
- base_names = [ base_names ]
288
- end
289
- base_names = base_names.reverse if reverse_lookup
180
+ include_location = lambda do |type, add_to_catalog = true, add_search_path = false|
181
+ locations[:package].each do |name, package_directory|
182
+ gateway = File.join(build_directory, package_directory, "#{type}.pp")
183
+ resource_name = concatenate([ name, type ])
290
184
 
291
- base_names.each do |base|
292
- value = puppet_scope.lookupvar("::#{base}::#{property}")
293
- break unless Util::Data.undef?(value)
185
+ add_search_path(type, resource_name) if add_search_path
186
+
187
+ if File.exists?(gateway)
188
+ import(gateway)
189
+ include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
190
+ end
191
+
192
+ directory = File.join(build_directory, package_directory, type.to_s)
193
+ Dir.glob(File.join(directory, '*.pp')).each do |file|
194
+ resource_name = concatenate([ name, type, File.basename(file).gsub('.pp', '') ])
195
+ import(file)
196
+ include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
197
+ end
294
198
  end
295
- end
296
- if Util::Data.undef?(value) && search_name
297
- value = puppet_scope.lookupvar("::#{property}")
298
- end
299
199
 
300
- Puppet::Util::Log.level = log_level
301
- value
302
- end
303
-
304
- #--
305
-
306
- def import(files, base_dir = nil)
307
- resource_types.loader.import(file, base_dir + '/')
308
- end
309
-
310
- #---
311
-
312
- def include(resource_name, properties, options = {})
313
- class_data = {}
314
-
315
- if resource_name.is_a?(Array)
316
- resource_name = resource_name.flatten
317
- else
318
- resource_name = [ resource_name ]
319
- end
200
+ gateway = File.join(build_directory, locations[:build], "#{type}.pp")
201
+ resource_name = concatenate([ plugin_name, type ])
320
202
 
321
- resource_name.each do |name|
322
- classes = lookup(name, [], options)
323
- if classes.is_a?(Array)
324
- classes.each do |klass|
325
- class_data[klass] = parameters
203
+ add_search_path(type, resource_name) if add_search_path
204
+
205
+ if File.exists?(gateway)
206
+ import(gateway)
207
+ include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
208
+ end
209
+
210
+ if locations.has_key?(type)
211
+ directory = File.join(build_directory, locations[type])
212
+ Dir.glob(File.join(directory, '*.pp')).each do |file|
213
+ resource_name = concatenate([ plugin_name, type, File.basename(file).gsub('.pp', '') ])
214
+ import(file)
215
+ include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
326
216
  end
327
- end
328
- end
329
-
330
- klasses = compiler.evaluate_classes(class_data, myself, false)
331
- missing = class_data.keys.find_all do |klass|
332
- ! klasses.include?(klass)
217
+ end
333
218
  end
334
-
335
- return false unless missing.empty?
336
- true
337
- end
338
-
339
- #---
340
219
 
341
- def provision(options = {})
342
- config = Config.ensure(options)
343
-
344
- if ! Util::Data.empty?(config[:code])
345
- Puppet[:code] = config[:code]
220
+ @@puppet_lock.synchronize do
221
+ begin
222
+ start_time = Time.now
223
+
224
+ init_puppet(profiles)
225
+
226
+ # Include defaults
227
+ include_location.call(:default, true, true)
346
228
 
347
- elsif ! Util::Data.empty?(config[:manifest])
348
- Puppet[:manifest] = config[:manifest]
349
- end
350
-
351
- begin
352
- return configure(config[:node])
229
+ # Import and include needed profiles
230
+ include_location.call(:profiles, false)
353
231
 
354
- rescue => detail
355
- Puppet.log_exception(detail)
356
- end
357
- false
232
+ profiles.each do |profile|
233
+ include(profile, { :require => 'Anchor[gateway_exit]' })
234
+ end
235
+
236
+ # Start system configuration
237
+ catalog = compiler.catalog.to_ral
238
+ catalog.finalize
239
+ catalog.retrieval_duration = Time.now - start_time
240
+
241
+ configurer = Puppet::Configurer.new
242
+ if ! configurer.run(:catalog => catalog, :pluginsync => false)
243
+ success = false
244
+ end
245
+
246
+ rescue Exception => error
247
+ raise error
248
+ Puppet.log_exception(error)
249
+ end
250
+ end
251
+ success
358
252
  end
359
253
 
360
254
  #-----------------------------------------------------------------------------
361
255
  # Utilities
362
256
 
363
- def to_name(name)
364
- Util::Data.value(name).to_s.gsub(/[\/\\\-\.]/, '_')
257
+ def profile_id(package_name, profile_name)
258
+ concatenate([ package_name, 'profile', profile_name ], false)
365
259
  end
366
-
367
- #---
368
-
369
- def type_name(value) # Basically borrowed from Puppet (damn private methods!)
370
- return :main if value == :main
371
- return "Class" if value == "" or value.nil? or value.to_s.downcase == "component"
372
- value.to_s.split("::").collect { |s| s.capitalize }.join("::")
373
- end
374
-
375
- #---
376
-
377
- def namevar(type_name, resource_name) # Basically borrowed from Puppet (damn private methods!)
378
- resource = Puppet::Resource.new(type_name.sub(/^\@?\@/, ''), resource_name)
379
-
380
- if resource.builtin_type? and type = resource.resource_type and type.key_attributes.length == 1
381
- type.key_attributes.first.to_s
382
- else
383
- 'name'
384
- end
385
- end
386
-
260
+
387
261
  #---
388
262
 
389
- def configure
390
- configurer = Puppet::Configurer.new
391
- configurer.run(:catalog => catalog, :pluginsync => false)
263
+ def concatenate(components, capitalize = false)
264
+ super(components, capitalize, '::')
392
265
  end
393
- protected :configure
394
266
  end
395
267
  end
396
268
  end
@@ -8,14 +8,20 @@ module Lookup
8
8
 
9
9
  def facts
10
10
  fact_map = {}
11
- Facter.list.each do |name|
12
- fact_map[name] = Facter.value(name)
11
+
12
+ CORL.silence do
13
+ Facter.list.each do |name|
14
+ fact_map[name] = Facter.value(name)
15
+ end
13
16
  end
17
+
14
18
  fact_map
15
19
  end
16
20
 
17
21
  def fact(name)
18
- Facter.value(name)
22
+ CORL.silence do
23
+ Facter.value(name)
24
+ end
19
25
  end
20
26
 
21
27
  #-----------------------------------------------------------------------------
@@ -26,7 +32,7 @@ module Lookup
26
32
  #---
27
33
 
28
34
  def hiera_config
29
- config_file = CORL.value(:hiera_config_file, nil)
35
+ config_file = CORL.value(:hiera_config_file, File.join(Hiera::Util.config_dir, 'hiera.yaml'))
30
36
  config = {}
31
37
 
32
38
  if config_file && File.exist?(config_file)
@@ -51,7 +57,7 @@ module Lookup
51
57
  def config_initialized?
52
58
  ready = false
53
59
  if CORL.admin? && hiera && network_path = fact(:corl_network)
54
- ready = File.directory?(network_path) && File.directory?(File.join(network_path, 'config')) ? true : false
60
+ ready = File.directory?(File.join(network_path, 'config')) ? true : false
55
61
  end
56
62
  ready
57
63
  end
@@ -68,7 +74,6 @@ module Lookup
68
74
  override = config.get(:override, nil)
69
75
  context = config.get(:context, :priority)
70
76
 
71
-
72
77
  return_property = config.get(:return_property, false)
73
78
 
74
79
  unless properties.is_a?(Array)
@@ -88,12 +93,12 @@ module Lookup
88
93
  unless hiera_scope.respond_to?('[]')
89
94
  hiera_scope = Hiera::Scope.new(hiera_scope)
90
95
  end
91
- value = hiera.lookup(property, nil, hiera_scope, override, context)
96
+ value = hiera.lookup(property.to_s, nil, hiera_scope, override, context)
92
97
  end
93
98
 
94
99
  if provisioner && Util::Data.undef?(value)
95
100
  # Search the provisioner scope (only admins can provision a machine)
96
- value = CORL.provisioner(provisioner).lookup(property, default, config)
101
+ value = CORL.provisioner({ :name => :lookup }, provisioner).lookup(property, default, config)
97
102
  end
98
103
  end
99
104
  end
@@ -102,8 +107,9 @@ module Lookup
102
107
  value = Util::Data.value(value)
103
108
 
104
109
  if ! Config.get_property(first_property) || ! Util::Data.undef?(value)
105
- Config.set_property(first_property, value)
110
+ Config.set_property(first_property.to_s, value)
106
111
  end
112
+
107
113
  return value, first_property if return_property
108
114
  value
109
115
  end
@@ -113,7 +119,7 @@ module Lookup
113
119
  def lookup_array(properties, default = [], options = {})
114
120
  config = Config.ensure(options)
115
121
  value, property = lookup(properties, nil, config.import({ :return_property => true }))
116
-
122
+
117
123
  if Util::Data.undef?(value)
118
124
  value = default
119
125
 
@@ -126,8 +132,8 @@ module Lookup
126
132
  unless value.is_a?(Array)
127
133
  value = ( Util::Data.empty?(value) ? [] : [ value ] )
128
134
  end
129
-
130
- Config.set_property(property, value)
135
+
136
+ Config.set_property(property.to_s, value)
131
137
  value
132
138
  end
133
139
 
@@ -150,7 +156,7 @@ module Lookup
150
156
  value = ( Util::Data.empty?(value) ? {} : { :value => value } )
151
157
  end
152
158
 
153
- Config.set_property(property, value)
159
+ Config.set_property(property.to_s, value)
154
160
  value
155
161
  end
156
162
 
@@ -187,8 +193,7 @@ module Lookup
187
193
 
188
194
  when Hash
189
195
  results = data
190
- end
191
-
196
+ end
192
197
  results
193
198
  end
194
199
  end