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
@@ -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