corl 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,52 @@
1
+
2
+ module CORL
3
+ module Mixin
4
+ module Macro
5
+ module NetworkSettings
6
+
7
+ def network_settings(_type)
8
+
9
+ # Networks are inherited unless explicitely set
10
+
11
+ define_method :network do
12
+ plugin_parent
13
+ end
14
+
15
+ define_method :network= do |network|
16
+ myself.plugin_parent = network
17
+ end
18
+
19
+ #---
20
+
21
+ define_method :setting do |property, default = nil, format = false|
22
+ network.send("#{_type}_setting", plugin_provider, plugin_name, property, default, format)
23
+ end
24
+
25
+ define_method :search do |property, default = nil, format = false|
26
+ network.send("search_#{_type}", plugin_provider, plugin_name, property, default, format)
27
+ end
28
+
29
+ define_method :set_setting do |property, value = nil|
30
+ network.send("set_#{_type}_setting", plugin_provider, plugin_name, property, value)
31
+ end
32
+
33
+ define_method :delete_setting do |property|
34
+ network.send("delete_#{_type}_setting", plugin_provider, plugin_name, property)
35
+ end
36
+
37
+ #---
38
+
39
+ define_method :[] do |name, default = nil, format = false|
40
+ search(name, default, format)
41
+ end
42
+
43
+ #---
44
+
45
+ define_method :[]= do |name, value|
46
+ set_setting(name, value)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -133,7 +133,7 @@ class CloudAction < CORL.plugin_class(:action)
133
133
  end
134
134
 
135
135
  # Load network if it exists
136
- network_config = extended_config(:network, { :directory => network_path })
136
+ network_config = extended_config(:network, { :directory => network_path, :name => network_path })
137
137
 
138
138
  network = CORL.network(
139
139
  CORL.sha1(network_config),
@@ -14,19 +14,44 @@ class Configuration < CORL.plugin_class(:base)
14
14
  logger.debug("Initializing source sub configuration")
15
15
  init_subconfig(true) unless reload
16
16
 
17
+ logger.info("Setting source configuration project")
18
+ @project = CORL.project(extended_config(:project, {
19
+ :directory => _delete(:directory, Dir.pwd),
20
+ :url => _delete(:url),
21
+ :revision => _delete(:revision),
22
+ :create => _delete(:create, false),
23
+ :pull => true
24
+ }), _delete(:project_provider))
25
+
17
26
  _init(:autoload, true)
18
27
  _init(:autosave, false)
28
+
29
+ yield if block_given?
30
+
31
+ set_location(@project)
19
32
  end
20
33
 
21
34
  #-----------------------------------------------------------------------------
22
35
  # Checks
23
36
 
24
37
  def can_persist?
25
- false
38
+ project.can_persist?
26
39
  end
27
40
 
28
41
  #-----------------------------------------------------------------------------
29
42
  # Property accessors / modifiers
43
+
44
+ def project
45
+ @project
46
+ end
47
+
48
+ #---
49
+
50
+ def directory
51
+ project.directory
52
+ end
53
+
54
+ #---
30
55
 
31
56
  def autoload(default = false)
32
57
  _get(:autoload, default)
@@ -45,6 +70,19 @@ class Configuration < CORL.plugin_class(:base)
45
70
  def autosave=autosave
46
71
  _set(:autosave, test(autosave))
47
72
  end
73
+
74
+ #-----------------------------------------------------------------------------
75
+
76
+ def set_location(directory)
77
+ if directory && directory.is_a?(CORL::Plugin::Project)
78
+ logger.debug("Setting source project directory from other project at #{directory.directory}")
79
+ project.set_location(directory.directory)
80
+
81
+ elsif directory && directory.is_a?(String) || directory.is_a?(Symbol)
82
+ logger.debug("Setting source project directory to #{directory}")
83
+ project.set_location(directory.to_s)
84
+ end
85
+ end
48
86
 
49
87
  #-----------------------------------------------------------------------------
50
88
 
@@ -70,14 +108,15 @@ class Configuration < CORL.plugin_class(:base)
70
108
  #-----------------------------------------------------------------------------
71
109
 
72
110
  def remote(name)
73
- nil
111
+ project.remote(name)
74
112
  end
75
-
113
+
76
114
  #---
77
115
 
78
116
  def set_remote(name, location)
117
+ project.set_remote(name, location)
79
118
  end
80
-
119
+
81
120
  #-----------------------------------------------------------------------------
82
121
  # Import / Export
83
122
 
@@ -12,7 +12,7 @@ class Network < CORL.plugin_class(:base)
12
12
  super
13
13
 
14
14
  logger.info("Initializing sub configuration from source with: #{myself._export.inspect}")
15
- myself.config = CORL.configuration(Config.new(myself._export).import({ :autosave => false })) unless reload
15
+ myself.config = CORL.configuration(Config.new(myself._export).import({ :autosave => false, :create => false })) unless reload
16
16
  end
17
17
 
18
18
  #-----------------------------------------------------------------------------
@@ -26,6 +26,7 @@ class Network < CORL.plugin_class(:base)
26
26
  # Property accessors / modifiers
27
27
 
28
28
  plugin_collection :node
29
+ plugin_collection :provisioner
29
30
 
30
31
  #---
31
32
 
@@ -35,6 +36,18 @@ class Network < CORL.plugin_class(:base)
35
36
 
36
37
  #---
37
38
 
39
+ def directory
40
+ config.directory
41
+ end
42
+
43
+ #---
44
+
45
+ def build_directory
46
+ File.join(directory, 'build')
47
+ end
48
+
49
+ #---
50
+
38
51
  def remote(name)
39
52
  config.remote(name)
40
53
  end
@@ -49,7 +62,7 @@ class Network < CORL.plugin_class(:base)
49
62
  groups = {}
50
63
 
51
64
  each_node_config do |provider, name, info|
52
- search_node(provider, name, :groups, [], :array).each do |group|
65
+ search_node(provider, name, :settings, [], :array).each do |group|
53
66
  group = group.to_sym
54
67
  groups[group] = [] unless groups.has_key?(group)
55
68
  groups[group] << { :provider => provider, :name => name }
@@ -211,7 +224,7 @@ class Network < CORL.plugin_class(:base)
211
224
 
212
225
  # Set node data
213
226
  node = set_node(provider, name, {
214
- :groups => array(config.delete(:groups, [])),
227
+ :settings => array(config.delete(:groups, [])),
215
228
  :region => config.delete(:region, nil),
216
229
  :machine_type => config.delete(:machine_type, nil),
217
230
  :image => config.delete(:image, nil),
@@ -20,7 +20,7 @@ class Node < CORL.plugin_class(:base)
20
20
  ui.resource = hostname
21
21
  logger = hostname
22
22
 
23
- myself[:groups] = [ "all", plugin_provider.to_s, plugin_name.to_s ] | groups
23
+ myself[:settings] = [ "all", plugin_provider.to_s, plugin_name.to_s ] | setting(:settings, [], :array)
24
24
 
25
25
  unless reload
26
26
  @cli_interface = Util::Liquid.new do |method, args, &code|
@@ -114,7 +114,7 @@ class Node < CORL.plugin_class(:base)
114
114
  #-----------------------------------------------------------------------------
115
115
 
116
116
  def groups
117
- array(myself[:groups])
117
+ array(myself[:settings])
118
118
  end
119
119
 
120
120
  #-----------------------------------------------------------------------------
@@ -308,6 +308,49 @@ class Node < CORL.plugin_class(:base)
308
308
  myself[:image]
309
309
  end
310
310
 
311
+ #---
312
+
313
+ def profiles=profiles
314
+ myself[:profiles] = array(profiles)
315
+ end
316
+
317
+ def profiles
318
+ array(myself[:profiles])
319
+ end
320
+
321
+ #---
322
+
323
+ def provisioner_info
324
+ provisioner_info = {}
325
+
326
+ # Compose needed provisioners and profiles
327
+ profiles.each do |profile|
328
+ if info = Plugin::Provisioner.translate_reference(profile)
329
+ provider = info[:provider]
330
+
331
+ provisioner_info[provider] = { :profiles => [] } unless provisioner_info.has_key?(provider)
332
+ provisioner_info[provider][:profiles] += info[:profiles]
333
+ end
334
+ end
335
+ provisioner_info
336
+ end
337
+
338
+ #---
339
+
340
+ def provisioners
341
+ provisioners = {}
342
+ provisioner_info.each do |provider, node_profiles|
343
+ provisioners[provider] = network.provisioners(provider)
344
+ end
345
+ provisioners
346
+ end
347
+
348
+ #---
349
+
350
+ def build_time
351
+ myself[:build]
352
+ end
353
+
311
354
  #-----------------------------------------------------------------------------
312
355
  # Settings groups
313
356
 
@@ -323,6 +366,29 @@ class Node < CORL.plugin_class(:base)
323
366
  #-----------------------------------------------------------------------------
324
367
  # Machine operations
325
368
 
369
+ def build(options = {})
370
+ config = Config.ensure(options)
371
+ info = provisioner_info
372
+
373
+ provisioners.each do |provider, collection|
374
+ provider_info = info[provider]
375
+ profiles = provider_info[:profiles]
376
+
377
+ collection.each do |name, provisioner|
378
+ provisioner.build(options)
379
+ end
380
+ end
381
+
382
+ myself[:build] = Time.now.to_s
383
+
384
+ save(extended_config(:build, {
385
+ :message => config.get(:message, "Built #{plugin_provider} node: #{plugin_name}"),
386
+ :remote => config.get(:remote, :edit)
387
+ }))
388
+ end
389
+
390
+ #---
391
+
326
392
  def attach_keys(keypair)
327
393
  base_name = "#{plugin_provider}-#{plugin_name}"
328
394
  save_config = {
@@ -911,6 +977,7 @@ class Node < CORL.plugin_class(:base)
911
977
  delete_setting(:public_ip)
912
978
  delete_setting(:private_ip)
913
979
  delete_setting(:ssh_port)
980
+ delete_setting(:build)
914
981
 
915
982
  myself[:state] = :stopped
916
983
 
@@ -2,49 +2,324 @@
2
2
  module Nucleon
3
3
  module Plugin
4
4
  class Provisioner < CORL.plugin_class(:base)
5
-
5
+
6
+ include Celluloid
7
+
6
8
  #-----------------------------------------------------------------------------
7
9
  # Provisioner plugin interface
8
10
 
9
11
  def normalize(reload)
10
12
  super
13
+ yield if block_given?
11
14
  end
12
15
 
13
- #---
16
+ #-----------------------------------------------------------------------------
17
+ # Checks
14
18
 
15
19
  def initialized?(options = {})
16
20
  end
17
21
 
22
+ #-----------------------------------------------------------------------------
23
+ # Property accessors / modifiers
24
+
25
+ network_settings :provisioner
26
+
18
27
  #---
19
28
 
20
- def register
29
+ def id(name = nil)
30
+ name = plugin_name if name.nil?
31
+ name.to_s.gsub('::', '_').to_sym
21
32
  end
22
33
 
23
- #-----------------------------------------------------------------------------
24
- # Property accessor / modifiers
25
-
26
- def hiera_config
34
+ #---
35
+
36
+ def directory=directory
37
+ myself[:directory] = directory
38
+ end
39
+
40
+ def directory
41
+ myself[:directory]
42
+ end
43
+
44
+ #---
45
+
46
+ def build_directory
47
+ File.join(network.build_directory, plugin_provider.to_s)
48
+ end
49
+
50
+ #---
51
+
52
+ def gateway=gateway
53
+ myself[:gateway] = gateway
54
+ end
55
+
56
+ def gateway
57
+ myself[:gateway]
58
+ end
59
+
60
+ #---
61
+
62
+ def packages
63
+ hash(myself[:packages])
64
+ end
65
+
66
+ #---
67
+
68
+ def profiles
69
+ hash(myself[:profiles])
70
+ end
71
+
72
+ def find_profiles(reset = false)
73
+ allowed_profiles = []
74
+ build_info(reset).each do |package_name, package_info|
75
+ hash(package_info[:profiles]).each do |profile_name, profile_info|
76
+ allowed_profiles << concatenate([ package_name, 'profile', profile_name ])
77
+ end
78
+ end
79
+ profiles.each do |profile_name, profile_info|
80
+ allowed_profiles << concatenate([ plugin_name, 'profile', profile_name ])
81
+ end
82
+ allowed_profiles
83
+ end
84
+ protected :find_profiles
85
+
86
+ #---
87
+
88
+ def supported_profiles(profile_names = nil)
89
+ found = []
90
+ profiles = build_profiles
91
+
92
+ if profile_names.nil?
93
+ found = profiles
94
+ else
95
+ profile_names.each do |name|
96
+ name = name.to_s
97
+ if profiles.include?(name)
98
+ found << name
99
+ end
100
+ end
101
+ end
102
+ found.empty? ? false : found
103
+ end
104
+
105
+ #---
106
+
107
+ def build_locations(reset = false)
108
+ locations = hash(myself[:build_locations])
109
+ build if reset || locations.empty?
110
+ myself[:build_locations]
111
+ end
112
+
113
+ #---
114
+
115
+ def build_info(reset = false)
116
+ info = hash(myself[:build_info])
117
+ build if reset || info.empty?
118
+ myself[:build_info]
119
+ end
120
+
121
+ #---
122
+
123
+ def build_profiles(reset = false)
124
+ profiles = array(myself[:build_profiles])
125
+ build if reset || profiles.empty?
126
+ myself[:build_profiles]
27
127
  end
28
128
 
29
129
  #-----------------------------------------------------------------------------
30
130
  # Provisioner operations
31
-
131
+
132
+ def register(options = {})
133
+ # Implement in providers
134
+ end
135
+
136
+ #---
137
+
138
+ def build(options = {})
139
+ config = Config.ensure(options)
140
+
141
+ locations = Config.new({ :package => {} })
142
+ package_info = Config.new
143
+
144
+ init_location = lambda do |name, ext = '', base_directory = nil|
145
+ name = name.to_sym
146
+ base_directory = directory if base_directory.nil?
147
+ build_base = build_directory
148
+
149
+ # Create directory
150
+ locations[name] = File.join(locations[:build], name.to_s)
151
+ FileUtils.mkdir_p(File.join(build_base, locations[name]))
152
+
153
+ # Copy directory contents
154
+ unless ext.nil?
155
+ ext = ! ext.to_s.empty? ? ".#{ext}" : ''
156
+ local_directory = File.join(base_directory, name.to_s)
157
+
158
+ if File.directory?(local_directory)
159
+ unless Dir.glob(File.join(local_directory, "*#{ext}")).empty?
160
+ FileUtils.cp_r(local_directory, File.join(build_base, locations[:build]))
161
+ end
162
+ end
163
+
164
+ # Copy gateway file
165
+ gateway_file = File.join(base_directory, "#{name}#{ext}")
166
+
167
+ if File.exists?(gateway_file)
168
+ FileUtils.cp(gateway_file, File.join(build_base, locations[:build]))
169
+ end
170
+ end
171
+ end
172
+
173
+ init_package = lambda do |name, reference|
174
+ package_directory = File.join(locations[:packages], id(name).to_s)
175
+
176
+ project = CORL.configuration(extended_config(:package, {
177
+ :directory => File.join(build_directory, package_directory),
178
+ :url => reference,
179
+ :create => true
180
+ }))
181
+ raise unless project
182
+
183
+ package_info.import(project.export)
184
+ locations[:package][name] = package_directory
185
+
186
+ if project.get([ :provisioners, plugin_provider ], false)
187
+ project.get_hash([ :provisioners, plugin_provider ]).each do |prov_name, info|
188
+ if info.has_key?(:packages)
189
+ info[:packages].each do |sub_name, sub_reference|
190
+ init_package.call(sub_name, sub_reference)
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ locations[:build] = id.to_s
198
+ local_build_directory = File.join(build_directory, locations[:build])
199
+
200
+ FileUtils.rm_rf(local_build_directory)
201
+ FileUtils.mkdir_p(local_build_directory)
202
+
203
+ init_location.call(:packages, nil)
204
+
205
+ # Build packages
206
+ packages.each do |name, reference|
207
+ init_package.call(name, reference)
208
+ end
209
+
210
+ yield(locations, package_info, init_location) if block_given?
211
+
212
+ myself[:build_locations] = locations.export
213
+ myself[:build_info] = package_info.get([ :provisioners, plugin_provider ])
214
+ myself[:build_profiles] = find_profiles
215
+
216
+ network.save(config.import({
217
+ :commit => true,
218
+ :allow_empty => true,
219
+ :message => config.get(:message, "Built #{plugin_provider} provisioner #{plugin_name}"),
220
+ :remote => config.get(:remote, :edit)
221
+ }))
222
+ end
223
+
224
+ #---
225
+
32
226
  def lookup(property, default = nil, options = {})
227
+ # Implement in providers
33
228
  end
34
229
 
35
230
  #--
36
231
 
37
- def import(files)
232
+ def import(files, options = {})
233
+ # Implement in providers
234
+ end
235
+
236
+ #---
237
+
238
+ def include(resource_name, properties = {}, options = {})
239
+ # Implement in providers
240
+ end
241
+
242
+ #---
243
+
244
+ def provision(profiles, options = {})
245
+ # Implement in providers
246
+ end
247
+
248
+ #-----------------------------------------------------------------------------
249
+ # Utilities
250
+
251
+ def self.build_info(type, data)
252
+ data = data.split(/\s*,\s*/) if data.is_a?(String)
253
+ super(type, data)
254
+ end
255
+
256
+ #---
257
+
258
+ def self.translate(data)
259
+ options = super(data)
260
+
261
+ case data
262
+ when String
263
+ options = { :profiles => array(data) }
264
+ when Hash
265
+ options = data
266
+ end
267
+
268
+ if options.has_key?(:profiles)
269
+ if matches = translate_reference(options[:profiles])
270
+ options[:provider] = matches[:provider]
271
+ options[:profiles] = matches[:profiles]
272
+
273
+ logger.debug("Translating provisioner options: #{options.inspect}")
274
+ end
275
+ end
276
+ options
277
+ end
278
+
279
+ #---
280
+
281
+ def self.translate_reference(reference)
282
+ # ex: puppetnode:::profile::something,profile::somethingelse
283
+ if reference && reference.match(/^\s*([a-zA-Z0-9_-]+):::([^\s]+)\s*$/)
284
+ provider = $1
285
+ profiles = $2
286
+
287
+ logger.debug("Translating provisioner reference: #{provider} #{profiles}")
288
+
289
+ info = {
290
+ :provider => provider,
291
+ :profiles => profiles.split(/\s*,\s*/)
292
+ }
293
+
294
+ logger.debug("Project reference info: #{info.inspect}")
295
+ return info
296
+ end
297
+ nil
38
298
  end
39
299
 
40
300
  #---
41
301
 
42
- def include(resource_name, properties, options = {})
302
+ def translate_reference(reference)
303
+ myself.class.translate_reference(reference)
43
304
  end
44
305
 
45
306
  #---
46
307
 
47
- def provision(options = {})
308
+ def concatenate(components, capitalize = false, joiner = '::')
309
+ if components.is_a?(Array)
310
+ components = components.collect do |str|
311
+ str.to_s.split('__')
312
+ end.flatten
313
+ else
314
+ components = [ components.to_s ]
315
+ end
316
+
317
+ if capitalize
318
+ name = components.collect {|str| str.capitalize }.join(joiner)
319
+ else
320
+ name = components.join(joiner)
321
+ end
322
+ name
48
323
  end
49
324
  end
50
325
  end