corl 0.4.0

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 (132) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +4 -0
  3. data/Gemfile +24 -0
  4. data/Gemfile.lock +123 -0
  5. data/LICENSE.txt +674 -0
  6. data/README.rdoc +27 -0
  7. data/Rakefile +78 -0
  8. data/VERSION +1 -0
  9. data/bin/corl +55 -0
  10. data/corl.gemspec +228 -0
  11. data/lib/corl/action/add.rb +69 -0
  12. data/lib/corl/action/bootstrap.rb +83 -0
  13. data/lib/corl/action/clone.rb +40 -0
  14. data/lib/corl/action/create.rb +55 -0
  15. data/lib/corl/action/exec.rb +41 -0
  16. data/lib/corl/action/extract.rb +49 -0
  17. data/lib/corl/action/image.rb +30 -0
  18. data/lib/corl/action/images.rb +55 -0
  19. data/lib/corl/action/lookup.rb +35 -0
  20. data/lib/corl/action/machines.rb +51 -0
  21. data/lib/corl/action/provision.rb +37 -0
  22. data/lib/corl/action/remove.rb +51 -0
  23. data/lib/corl/action/save.rb +53 -0
  24. data/lib/corl/action/seed.rb +115 -0
  25. data/lib/corl/action/spawn.rb +75 -0
  26. data/lib/corl/action/start.rb +37 -0
  27. data/lib/corl/action/stop.rb +30 -0
  28. data/lib/corl/action/update.rb +37 -0
  29. data/lib/corl/command/shell.rb +164 -0
  30. data/lib/corl/configuration/file.rb +386 -0
  31. data/lib/corl/event/puppet.rb +90 -0
  32. data/lib/corl/event/regex.rb +52 -0
  33. data/lib/corl/extension/puppetloader.rb +24 -0
  34. data/lib/corl/machine/fog.rb +310 -0
  35. data/lib/corl/machine/physical.rb +161 -0
  36. data/lib/corl/network/default.rb +26 -0
  37. data/lib/corl/node/aws.rb +90 -0
  38. data/lib/corl/node/fog.rb +198 -0
  39. data/lib/corl/node/google.rb +115 -0
  40. data/lib/corl/node/local.rb +26 -0
  41. data/lib/corl/node/rackspace.rb +89 -0
  42. data/lib/corl/project/git.rb +465 -0
  43. data/lib/corl/project/github.rb +108 -0
  44. data/lib/corl/provisioner/puppetnode/resource.rb +245 -0
  45. data/lib/corl/provisioner/puppetnode/resource_group.rb +205 -0
  46. data/lib/corl/provisioner/puppetnode.rb +407 -0
  47. data/lib/corl/template/environment.rb +73 -0
  48. data/lib/corl/template/json.rb +16 -0
  49. data/lib/corl/template/wrapper.rb +16 -0
  50. data/lib/corl/template/yaml.rb +16 -0
  51. data/lib/corl/translator/json.rb +27 -0
  52. data/lib/corl/translator/yaml.rb +27 -0
  53. data/lib/corl.rb +173 -0
  54. data/lib/corl_core/codes.rb +107 -0
  55. data/lib/corl_core/config/collection.rb +57 -0
  56. data/lib/corl_core/config/options.rb +70 -0
  57. data/lib/corl_core/config.rb +337 -0
  58. data/lib/corl_core/core.rb +59 -0
  59. data/lib/corl_core/corl.rb +254 -0
  60. data/lib/corl_core/errors.rb +84 -0
  61. data/lib/corl_core/facade.rb +126 -0
  62. data/lib/corl_core/gems.rb +72 -0
  63. data/lib/corl_core/manager.rb +425 -0
  64. data/lib/corl_core/mixin/action/commit.rb +58 -0
  65. data/lib/corl_core/mixin/action/keypair.rb +105 -0
  66. data/lib/corl_core/mixin/action/node.rb +129 -0
  67. data/lib/corl_core/mixin/action/project.rb +53 -0
  68. data/lib/corl_core/mixin/action/push.rb +52 -0
  69. data/lib/corl_core/mixin/config/collection.rb +53 -0
  70. data/lib/corl_core/mixin/config/ops.rb +53 -0
  71. data/lib/corl_core/mixin/config/options.rb +39 -0
  72. data/lib/corl_core/mixin/lookup.rb +196 -0
  73. data/lib/corl_core/mixin/macro/object_interface.rb +361 -0
  74. data/lib/corl_core/mixin/macro/plugin_interface.rb +380 -0
  75. data/lib/corl_core/mixin/settings.rb +46 -0
  76. data/lib/corl_core/mixin/sub_config.rb +148 -0
  77. data/lib/corl_core/mod/hash.rb +29 -0
  78. data/lib/corl_core/mod/hiera_backend.rb +63 -0
  79. data/lib/corl_core/plugin/action.rb +381 -0
  80. data/lib/corl_core/plugin/base.rb +374 -0
  81. data/lib/corl_core/plugin/command.rb +98 -0
  82. data/lib/corl_core/plugin/configuration.rb +177 -0
  83. data/lib/corl_core/plugin/event.rb +53 -0
  84. data/lib/corl_core/plugin/extension.rb +12 -0
  85. data/lib/corl_core/plugin/machine.rb +266 -0
  86. data/lib/corl_core/plugin/network.rb +359 -0
  87. data/lib/corl_core/plugin/node.rb +904 -0
  88. data/lib/corl_core/plugin/project.rb +927 -0
  89. data/lib/corl_core/plugin/provisioner.rb +51 -0
  90. data/lib/corl_core/plugin/template.rb +80 -0
  91. data/lib/corl_core/plugin/translator.rb +38 -0
  92. data/lib/corl_core/util/cli.rb +352 -0
  93. data/lib/corl_core/util/data.rb +404 -0
  94. data/lib/corl_core/util/disk.rb +114 -0
  95. data/lib/corl_core/util/git.rb +47 -0
  96. data/lib/corl_core/util/interface.rb +319 -0
  97. data/lib/corl_core/util/liquid.rb +17 -0
  98. data/lib/corl_core/util/package.rb +93 -0
  99. data/lib/corl_core/util/shell.rb +239 -0
  100. data/lib/corl_core/util/ssh.rb +286 -0
  101. data/lib/facter/corl_config_ready.rb +13 -0
  102. data/lib/facter/corl_exists.rb +15 -0
  103. data/lib/facter/corl_network.rb +17 -0
  104. data/lib/hiera/corl_logger.rb +18 -0
  105. data/lib/puppet/indirector/corl.rb +27 -0
  106. data/lib/puppet/indirector/data_binding/corl.rb +6 -0
  107. data/lib/puppet/parser/functions/config_initialized.rb +26 -0
  108. data/lib/puppet/parser/functions/corl_include.rb +44 -0
  109. data/lib/puppet/parser/functions/corl_resources.rb +58 -0
  110. data/lib/puppet/parser/functions/deep_merge.rb +21 -0
  111. data/lib/puppet/parser/functions/ensure.rb +29 -0
  112. data/lib/puppet/parser/functions/file_exists.rb +19 -0
  113. data/lib/puppet/parser/functions/global_array.rb +35 -0
  114. data/lib/puppet/parser/functions/global_hash.rb +35 -0
  115. data/lib/puppet/parser/functions/global_options.rb +23 -0
  116. data/lib/puppet/parser/functions/global_param.rb +43 -0
  117. data/lib/puppet/parser/functions/interpolate.rb +26 -0
  118. data/lib/puppet/parser/functions/is_false.rb +21 -0
  119. data/lib/puppet/parser/functions/is_true.rb +21 -0
  120. data/lib/puppet/parser/functions/module_array.rb +38 -0
  121. data/lib/puppet/parser/functions/module_hash.rb +38 -0
  122. data/lib/puppet/parser/functions/module_options.rb +23 -0
  123. data/lib/puppet/parser/functions/module_param.rb +48 -0
  124. data/lib/puppet/parser/functions/name.rb +21 -0
  125. data/lib/puppet/parser/functions/render.rb +33 -0
  126. data/lib/puppet/parser/functions/value.rb +21 -0
  127. data/locales/en.yml +232 -0
  128. data/spec/corl_core/interface_spec.rb +489 -0
  129. data/spec/corl_mock_input.rb +29 -0
  130. data/spec/corl_test_kernel.rb +22 -0
  131. data/spec/spec_helper.rb +15 -0
  132. metadata +406 -0
@@ -0,0 +1,381 @@
1
+
2
+ module CORL
3
+ module Plugin
4
+ class Action < Base
5
+
6
+ include Mixin::Action::Node
7
+
8
+ #-----------------------------------------------------------------------------
9
+ # Default option interface
10
+
11
+ class Option
12
+ def initialize(provider, name, type, default, locale = nil, &validator)
13
+ @provider = provider
14
+ @name = name
15
+ @type = type
16
+ @default = default
17
+ @locale = locale.nil? ? "corl.actions.#{provider}.options.#{name}" : locale
18
+ @validator = validator if validator
19
+ end
20
+
21
+ #---
22
+
23
+ attr_reader :provider, :name, :type
24
+ attr_accessor :default, :locale, :validator
25
+
26
+ #---
27
+
28
+ def validate(value, node, network)
29
+ success = true
30
+ if @validator
31
+ success = @validator.call(value, node, network)
32
+ end
33
+ success
34
+ end
35
+ end
36
+
37
+ #-----------------------------------------------------------------------------
38
+ # Action plugin interface
39
+
40
+ def self.exec_safe(provider, options)
41
+ action_result = nil
42
+
43
+ begin
44
+ logger = CORL.logger
45
+
46
+ logger.debug("Running corl action #{provider} with #{options.inspect}")
47
+ action = CORL.action(provider, options)
48
+ exit_status = action.execute
49
+ action_result = action.result
50
+
51
+ rescue Exception => error
52
+ logger.error("Corl action #{provider} experienced an error:")
53
+ logger.error(error.inspect)
54
+ logger.error(error.message)
55
+ logger.error(CORL::Util::Data.to_yaml(error.backtrace))
56
+
57
+ CORL.ui.error(error.message, { :prefix => false }) if error.message
58
+
59
+ exit_status = error.status_code if error.respond_to?(:status_code)
60
+ end
61
+
62
+ CORL.remove_plugin(action) if action
63
+
64
+ exit_status = CORL.code.unknown_status unless exit_status.is_a?(Integer)
65
+ { :status => exit_status, :result => action_result }
66
+ end
67
+
68
+ def self.exec(provider, options, quiet = true)
69
+ exec_safe(provider, { :settings => Config.ensure(options), :quiet => quiet })
70
+ end
71
+
72
+ def self.exec_cli(provider, args, quiet = false)
73
+ results = exec_safe(provider, { :args => args, :quiet => quiet })
74
+ results[:status]
75
+ end
76
+
77
+ #---
78
+
79
+ def normalize
80
+ args = array(delete(:args, []))
81
+
82
+ @action_interface = Util::Liquid.new do |method, method_args|
83
+ options = {}
84
+ options = method_args[0] if method_args.length > 0
85
+
86
+ quiet = true
87
+ quiet = method_args[1] if method_args.length > 1
88
+
89
+ myself.class.exec(method, options, quiet)
90
+ end
91
+
92
+ set(:config, Config.new)
93
+
94
+ if get(:settings, nil)
95
+ # Internal processing
96
+ configure
97
+ set(:processed, true)
98
+ set(:settings, Config.ensure(get(:settings)))
99
+
100
+ CORL.log_level = settings[:log_level] if settings.has_key?(:log_level)
101
+ else
102
+ # External processing
103
+ set(:settings, Config.new)
104
+ configure
105
+ parse_base(args)
106
+ end
107
+ end
108
+
109
+ #-----------------------------------------------------------------------------
110
+ # Checks
111
+
112
+ def processed?
113
+ get(:processed, false)
114
+ end
115
+
116
+ #-----------------------------------------------------------------------------
117
+ # Property accessor / modifiers
118
+
119
+ def config
120
+ get(:config)
121
+ end
122
+
123
+ #---
124
+
125
+ def config_subset(names)
126
+ Util::Data.subset(config, names)
127
+ end
128
+
129
+ #---
130
+
131
+ def settings
132
+ get(:settings)
133
+ end
134
+
135
+ #---
136
+
137
+ def register(name, type, default, locale = nil)
138
+ name = name.to_sym
139
+
140
+ if block_given?
141
+ option = Option.new(plugin_provider, name, type, default, locale) do |value, success|
142
+ yield(value, success)
143
+ end
144
+ else
145
+ option = Option.new(plugin_provider, name, type, default, locale)
146
+ end
147
+
148
+ config[name] = option
149
+ settings[name] = option.default if settings[name].nil?
150
+ end
151
+
152
+ #---
153
+
154
+ def remove(names)
155
+ Util::Data.rm_keys(config, names)
156
+ Util::Data.rm_keys(settings, names)
157
+ end
158
+
159
+ #---
160
+
161
+ def ignore
162
+ []
163
+ end
164
+
165
+ def options
166
+ config.keys - arguments - ignore
167
+ end
168
+
169
+ def arguments
170
+ []
171
+ end
172
+
173
+ #---
174
+
175
+ def configure
176
+ node_config
177
+ yield if block_given?
178
+
179
+ usage = "corl #{plugin_provider} "
180
+ arguments.each do |arg|
181
+ arg_config = config[arg.to_sym]
182
+
183
+ if arg_config.type == :array
184
+ usage << "<#{arg}> ..."
185
+ else
186
+ usage << "<#{arg}> "
187
+ end
188
+ end
189
+ myself.usage = usage
190
+ myself
191
+ end
192
+
193
+ #---
194
+
195
+ def usage=usage
196
+ set(:usage, usage)
197
+ end
198
+
199
+ def usage
200
+ get(:usage, '')
201
+ end
202
+
203
+ #---
204
+
205
+ def help
206
+ return @parser.help if @parser
207
+ usage
208
+ end
209
+
210
+ #---
211
+
212
+ def result=result
213
+ set(:result, result)
214
+ end
215
+
216
+ def result
217
+ get(:result, nil)
218
+ end
219
+
220
+ #-----------------------------------------------------------------------------
221
+ # Operations
222
+
223
+ def parse_base(args)
224
+ logger.info("Parsing action #{plugin_provider} with: #{args.inspect}")
225
+
226
+ @parser = Util::CLI::Parser.new(args, usage) do |parser|
227
+ parse(parser)
228
+ extension(:parse, { :parser => parser, :config => config })
229
+ end
230
+
231
+ if @parser
232
+ if @parser.processed
233
+ set(:processed, true)
234
+ settings.import(Util::Data.merge([ @parser.options, @parser.arguments ], true))
235
+ logger.debug("Parse successful: #{export.inspect}")
236
+
237
+ elsif @parser.options[:help] && ! quiet?
238
+ puts I18n.t('corl.core.exec.help.usage') + ': ' + help + "\n"
239
+
240
+ else
241
+ if @parser.options[:help]
242
+ logger.debug("Help wanted but running in silent mode")
243
+ else
244
+ logger.warn("Parse failed for unknown reasons")
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ #---
251
+
252
+ def parse(parser)
253
+
254
+ generate = lambda do |format, name|
255
+ formats = [ :option, :arg ]
256
+ types = [ :bool, :int, :float, :str, :array ]
257
+ name = name.to_sym
258
+
259
+ if config.export.has_key?(name) && formats.include?(format.to_sym)
260
+ option_config = config[name]
261
+ type = option_config.type
262
+ default = option_config.default
263
+ locale = option_config.locale
264
+
265
+ if types.include?(type.to_sym)
266
+ value_label = "#{type.to_s.upcase}"
267
+
268
+ if type == :bool
269
+ parser.send("option_#{type}", name, default, "--[no-]#{name}", locale)
270
+ elsif format == :arg
271
+ parser.send("#{format}_#{type}", name, default, locale)
272
+ else
273
+ if type == :array
274
+ parser.send("option_#{type}", name, default, "--#{name} #{value_label},...", locale)
275
+ else
276
+ parser.send("option_#{type}", name, default, "--#{name} #{value_label}", locale)
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ #---
284
+
285
+ options.each do |name|
286
+ generate.call(:option, name)
287
+ end
288
+
289
+ arguments.each do |name|
290
+ generate.call(:arg, name)
291
+ end
292
+ end
293
+
294
+ #---
295
+
296
+ def validate(node, network)
297
+ # TODO: Add extension hooks and logging
298
+
299
+ # Validate all of the configurations
300
+ success = true
301
+ config.export.each do |name, option|
302
+ success = false unless option.validate(settings[name], node, network)
303
+ end
304
+ if success
305
+ # Check for missing arguments (in case of internal execution mode)
306
+ arguments.each do |name|
307
+ if settings[name.to_sym].nil?
308
+ warn('corl.core.exec.errors.missing_argument', { :name => name })
309
+ success = false
310
+ end
311
+ end
312
+ end
313
+ if ignore.include?(:nodes)
314
+ settings[:nodes] = []
315
+ end
316
+ success
317
+ end
318
+
319
+ #---
320
+
321
+ def execute
322
+ logger.info("Executing action #{plugin_provider}")
323
+
324
+ myself.status = code.success
325
+ myself.result = nil
326
+
327
+ if processed?
328
+ node_exec do |node, network|
329
+ hook_config = { :node => node, :network => network }
330
+
331
+ begin
332
+ yield(node, network) if block_given? && extension_check(:exec_init, hook_config)
333
+ myself.status = extension_set(:exec_exit, status, hook_config)
334
+ ensure
335
+ cleanup
336
+ end
337
+ end
338
+ else
339
+ if @parser.options[:help]
340
+ myself.status = code.help_wanted
341
+ else
342
+ myself.status = code.action_unprocessed
343
+ end
344
+ end
345
+
346
+ myself.status = code.unknown_status unless status.is_a?(Integer)
347
+
348
+ if processed? && status != code.success
349
+ logger.warn("Execution failed for #{plugin_provider} with status #{status}: #{export.inspect}")
350
+ alert(Codes.render_index(status))
351
+ end
352
+
353
+ status
354
+ end
355
+
356
+ #---
357
+
358
+ def run
359
+ @action_interface
360
+ end
361
+
362
+ #---
363
+
364
+ def cleanup
365
+ logger.info("Running cleanup for action #{plugin_provider}")
366
+
367
+ yield if block_given?
368
+
369
+ # Nothing to do right now
370
+ extension(:cleanup)
371
+ end
372
+
373
+ #-----------------------------------------------------------------------------
374
+ # Output
375
+
376
+ def render_options
377
+ settings
378
+ end
379
+ end
380
+ end
381
+ end