corl 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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