inprovise 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +28 -0
  4. data/Gemfile +9 -0
  5. data/LICENSE +8 -0
  6. data/README.md +197 -0
  7. data/Rakefile.rb +9 -0
  8. data/bin/rig +5 -0
  9. data/inprovise.gemspec +22 -0
  10. data/lib/inprovise/channel/ssh.rb +202 -0
  11. data/lib/inprovise/cli/group.rb +86 -0
  12. data/lib/inprovise/cli/node.rb +95 -0
  13. data/lib/inprovise/cli/provision.rb +84 -0
  14. data/lib/inprovise/cli.rb +105 -0
  15. data/lib/inprovise/cmd_channel.rb +100 -0
  16. data/lib/inprovise/cmd_helper.rb +150 -0
  17. data/lib/inprovise/control.rb +326 -0
  18. data/lib/inprovise/execution_context.rb +277 -0
  19. data/lib/inprovise/group.rb +67 -0
  20. data/lib/inprovise/helper/cygwin.rb +43 -0
  21. data/lib/inprovise/helper/linux.rb +181 -0
  22. data/lib/inprovise/helper/windows.rb +123 -0
  23. data/lib/inprovise/infra.rb +122 -0
  24. data/lib/inprovise/local_file.rb +120 -0
  25. data/lib/inprovise/logger.rb +79 -0
  26. data/lib/inprovise/node.rb +271 -0
  27. data/lib/inprovise/remote_file.rb +128 -0
  28. data/lib/inprovise/resolver.rb +36 -0
  29. data/lib/inprovise/script.rb +175 -0
  30. data/lib/inprovise/script_index.rb +46 -0
  31. data/lib/inprovise/script_runner.rb +110 -0
  32. data/lib/inprovise/sniff.rb +46 -0
  33. data/lib/inprovise/sniffer/linux.rb +64 -0
  34. data/lib/inprovise/sniffer/platform.rb +46 -0
  35. data/lib/inprovise/sniffer/unknown.rb +11 -0
  36. data/lib/inprovise/sniffer/windows.rb +32 -0
  37. data/lib/inprovise/template/inprovise.rb.erb +92 -0
  38. data/lib/inprovise/template.rb +38 -0
  39. data/lib/inprovise/trigger_runner.rb +36 -0
  40. data/lib/inprovise/version.rb +10 -0
  41. data/lib/inprovise.rb +145 -0
  42. data/test/cli_test.rb +314 -0
  43. data/test/cli_test_helper.rb +19 -0
  44. data/test/dsl_test.rb +43 -0
  45. data/test/fixtures/example.txt +1 -0
  46. data/test/fixtures/include.rb +4 -0
  47. data/test/fixtures/inprovise.rb +1 -0
  48. data/test/fixtures/myscheme.rb +1 -0
  49. data/test/infra_test.rb +189 -0
  50. data/test/local_file_test.rb +64 -0
  51. data/test/remote_file_test.rb +106 -0
  52. data/test/resolver_test.rb +66 -0
  53. data/test/script_index_test.rb +53 -0
  54. data/test/script_test.rb +56 -0
  55. data/test/test_helper.rb +237 -0
  56. metadata +182 -0
@@ -0,0 +1,326 @@
1
+ # Controller for Inprovise
2
+ #
3
+ # Author:: Martin Corino
4
+ # License:: Distributes under the same license as Ruby
5
+
6
+ require 'monitor'
7
+
8
+ class Inprovise::Controller
9
+
10
+ class << self
11
+
12
+ def controllers
13
+ @controllers ||= Array.new.extend(MonitorMixin)
14
+ end
15
+ private :controllers
16
+
17
+ def add(ctrl)
18
+ controllers.synchronize do
19
+ controllers << ctrl if ctrl
20
+ end
21
+ ctrl
22
+ end
23
+ private :add
24
+
25
+ def head
26
+ controllers.synchronize do
27
+ return controllers.first
28
+ end
29
+ end
30
+ private :head
31
+
32
+ def shift
33
+ controllers.synchronize do
34
+ return controllers.shift
35
+ end
36
+ end
37
+ private :shift
38
+
39
+ def empty?
40
+ controllers.synchronize do
41
+ return controllers.empty?
42
+ end
43
+ end
44
+ private :empty?
45
+
46
+ def get_value(v)
47
+ begin
48
+ Module.new { def self.eval(s); binding.eval(s); end }.eval(v)
49
+ rescue Exception
50
+ v
51
+ end
52
+ end
53
+ private :get_value
54
+
55
+ def list_scripts(options)
56
+ # load all specified schemes
57
+ (Array === options[:scheme] ? options[:scheme] : [options[:scheme]]).each {|s| Inprovise::DSL.include(s) }
58
+ $stdout.puts
59
+ $stdout.puts " PROVISIONING SCRIPTS"
60
+ $stdout.puts " ===================="
61
+ Inprovise::ScriptIndex.default.scripts.sort.each do |scrname|
62
+ script = Inprovise::ScriptIndex.default.get(scrname)
63
+ if script.description || options[:all]
64
+ script.describe.each {|l| $stdout.puts " #{l}" }
65
+ end
66
+ end
67
+ end
68
+
69
+ def parse_config(cfg, opts = {})
70
+ cfg.inject(opts) do |rc,cfg|
71
+ k,v = cfg.split('=')
72
+ k = k.split('.')
73
+ h = rc
74
+ while k.size > 1
75
+ hk = k.shift.to_sym
76
+ raise ArgumentError, "Conflicting config category #{hk}" unless !h.has_key?(hk) || Hash === h[hk]
77
+ h = (h[hk] ||= {})
78
+ end
79
+ h.store(k.shift.to_sym, get_value(v))
80
+ rc
81
+ end
82
+ end
83
+
84
+ def run(command, options, *args)
85
+ begin
86
+ case command
87
+ when :add, :remove, :update
88
+ case args.shift
89
+ when :node
90
+ run_node_command(command, options, *args)
91
+ when :group
92
+ run_group_command(command, options, *args)
93
+ end
94
+ else # :apply, :revert, :validate or :trigger
95
+ # load all specified schemes
96
+ (Array === options[:scheme] ? options[:scheme] : [options[:scheme]]).each {|s| Inprovise::DSL.include(s) }
97
+ # extract config
98
+ cfg = parse_config(options[:config])
99
+ # get script/action
100
+ sca = args.shift
101
+ run_provisioning_command(command, sca, cfg, *args)
102
+ end
103
+ rescue Exception => e
104
+ cleanup!
105
+ raise e
106
+ end
107
+ end
108
+
109
+ def wait!
110
+ ex = nil
111
+ begin
112
+ while !empty?
113
+ head.wait
114
+ shift
115
+ end
116
+ rescue Exception => e
117
+ ex = e
118
+ ensure
119
+ cleanup!
120
+ raise ex if ex
121
+ end
122
+ end
123
+
124
+ def cleanup!
125
+ while !empty?
126
+ head.cleanup rescue Exception $stderr.puts $!.backtrace
127
+ shift
128
+ end
129
+ end
130
+
131
+ def run_node_command(cmd, options, *names)
132
+ add(Inprovise::Controller.new).run_node_command(cmd, options, *names)
133
+ end
134
+
135
+ def run_group_command(cmd, options, *names)
136
+ add(Inprovise::Controller.new).run_group_command(cmd, options, *names)
137
+ end
138
+
139
+ def run_provisioning_command(command, script, opts, *targets)
140
+ add(Inprovise::Controller.new).run_provisioning_command(command, script, opts, *targets)
141
+ end
142
+
143
+ end
144
+
145
+ def initialize
146
+ @targets = []
147
+ @threads = []
148
+ end
149
+
150
+ def wait
151
+ return if @threads.empty?
152
+ Inprovise.log.local('Waiting for controller threads...') if Inprovise.verbosity > 0
153
+ @threads.each { |t| t.join }
154
+ end
155
+
156
+ def cleanup
157
+ return if @targets.empty?
158
+ Inprovise.log.local('Disconnecting...') if Inprovise.verbosity > 0
159
+ @targets.each {|tgt| tgt.disconnect! }
160
+ Inprovise.log.local('Done!') if Inprovise.verbosity > 0
161
+ end
162
+
163
+ def run_provisioning_command(command, cmdtgt, opts, *names)
164
+ # get intended infrastructure targets/config tuples
165
+ targets = get_targets(*names)
166
+ # create runner/config for each target/config
167
+ runners = targets.map do |tgt, cfg|
168
+ @targets << tgt
169
+ [
170
+ if command == :trigger
171
+ Inprovise::TriggerRunner.new(tgt, cmdtgt)
172
+ else
173
+ Inprovise::ScriptRunner.new(tgt, Inprovise::ScriptIndex.default.get(cmdtgt), Inprovise.skip_dependencies)
174
+ end,
175
+ cfg
176
+ ]
177
+ end
178
+ # execute runners
179
+ if Inprovise.sequential
180
+ runners.each {|runner, cfg| exec(runner, command, cfg.merge(opts)) }
181
+ else
182
+ @threads = runners.map {|runner, cfg| Thread.new { exec(runner, command, cfg.merge(opts)) } }
183
+ end
184
+ end
185
+
186
+ def run_node_command(command, options, *names)
187
+ case command
188
+ when :add
189
+ opts = self.class.parse_config(options[:config], { host: options[:address] })
190
+ opts[:credentials] = self.class.parse_config(options[:credential])
191
+ @targets << (node = Inprovise::Infrastructure::Node.new(names.first, opts))
192
+
193
+ Inprovise.log.local("Adding #{node.to_s}")
194
+
195
+ Inprovise::Sniffer.run_sniffers_for(node) if options[:sniff]
196
+
197
+ options[:group].each do |g|
198
+ grp = Inprovise::Infrastructure.find(g)
199
+ raise ArgumentError, "Unknown group #{g}" unless grp
200
+ node.add_to(grp)
201
+ end
202
+ when :remove
203
+ names.each do |name|
204
+ node = Inprovise::Infrastructure.find(name)
205
+ raise ArgumentError, "Invalid node #{name}" unless node && node.is_a?(Inprovise::Infrastructure::Node)
206
+
207
+ Inprovise.log.local("Removing #{node.to_s}")
208
+
209
+ Inprovise::Infrastructure.deregister(name)
210
+ end
211
+ when :update
212
+ @targets = names.collect do |name|
213
+ tgt = Inprovise::Infrastructure.find(name)
214
+ raise ArgumentError, "Unknown target [#{name}]" unless tgt
215
+ tgt.targets
216
+ end.flatten.uniq
217
+ opts = self.class.parse_config(options[:config])
218
+ opts[:credentials] = self.class.parse_config(options[:credential])
219
+ if Inprovise.sequential || (!options[:sniff]) || @targets.size == 1
220
+ @targets.each {|tgt| run_target_update(tgt, opts.dup, options) }
221
+ else
222
+ threads = @targets.map {|tgt| Thread.new { run_target_update(tgt, opts.dup, options) } }
223
+ threads.each {|t| t.join }
224
+ end
225
+ end
226
+ Inprovise::Infrastructure.save
227
+ end
228
+
229
+ def run_group_command(command, options, *names)
230
+ case command
231
+ when :add
232
+ options[:target].each {|t| raise ArgumentError, "Unknown target [#{t}]" unless Inprovise::Infrastructure.find(t) }
233
+ opts = self.class.parse_config(options[:config])
234
+ grp = Inprovise::Infrastructure::Group.new(names.first, opts, options[:target])
235
+
236
+ Inprovise.log.local("Adding #{grp.to_s}")
237
+
238
+ options[:target].each do |t|
239
+ tgt = Inprovise::Infrastructure.find(t)
240
+ raise ArgumentError, "Unknown target #{t}" unless tgt
241
+ tgt.add_to(grp)
242
+ end
243
+ when :remove
244
+ names.each do |name|
245
+ grp = Inprovise::Infrastructure.find(name)
246
+ raise ArgumentError, "Invalid group #{name}" unless grp && grp.is_a?(Inprovise::Infrastructure::Group)
247
+
248
+ Inprovise.log.local("Removing #{grp.to_s}")
249
+
250
+ Inprovise::Infrastructure.deregister(name)
251
+ end
252
+ when :update
253
+ groups = names.collect do |name|
254
+ grp = Inprovise::Infrastructure.find(name)
255
+ raise ArgumentError, "Invalid group #{name}" unless grp && grp.is_a?(Inprovise::Infrastructure::Group)
256
+ grp
257
+ end
258
+ opts = self.class.parse_config(options[:config])
259
+ grp_tgts = options[:target].collect do |t|
260
+ tgt = Inprovise::Infrastructure.find(t)
261
+ raise ArgumentError, "Unknown target #{t}" unless tgt
262
+ tgt
263
+ end
264
+ groups.each do |grp|
265
+ Inprovise.log.local("Updating #{grp.to_s}")
266
+
267
+ grp.config.clear if options[:reset]
268
+ grp.config.merge!(opts)
269
+ grp_tgts.each {|tgt| tgt.add_to(grp) }
270
+ end
271
+ end
272
+ Inprovise::Infrastructure.save
273
+ end
274
+
275
+ private
276
+
277
+ def get_targets(*names)
278
+ names.inject({}) do |hsh, name|
279
+ tgt = Inprovise::Infrastructure.find(name)
280
+ raise ArgumentError, "Unknown target [#{name}]" unless tgt
281
+ tgt.targets_with_config.each do |tgt_, cfg|
282
+ if hsh.has_key?(tgt_)
283
+ hsh[tgt_].merge!(cfg)
284
+ else
285
+ hsh[tgt_] = cfg
286
+ end
287
+ end
288
+ hsh
289
+ end
290
+ end
291
+
292
+ def exec(runner, command, opts)
293
+ if Inprovise.demonstrate
294
+ runner.demonstrate(command, opts)
295
+ else
296
+ runner.execute(command, opts)
297
+ end
298
+ end
299
+
300
+ def run_target_update(tgt, tgt_opts, options)
301
+ Inprovise.log.local("Updating #{tgt.to_s}")
302
+
303
+ if options[:reset]
304
+ # preserve :host
305
+ tgt_opts[:host] = tgt.get(:host) if tgt.get(:host)
306
+ # preserve :user if no new user specified
307
+ tgt_opts[:user] = tgt.get(:user) if tgt.get(:user) && !tgt_opts.has_key?(:user)
308
+ # preserve sniffed attributes when not running sniffers now
309
+ unless options[:sniff]
310
+ tgt_opts[:attributes] = tgt.get(:attributes)
311
+ end
312
+ # clear the target config
313
+ tgt.config.clear
314
+ end
315
+ tgt.config.merge!(tgt_opts) # merge new + preserved config
316
+ # force update of user if specified
317
+ tgt.prepare_connection_for_user!(tgt_opts[:user]) if tgt_opts[:user]
318
+ Inprovise::Sniffer.run_sniffers_for(tgt) if options[:sniff]
319
+ options[:group].each do |g|
320
+ grp = Inprovise::Infrastructure.find(g)
321
+ raise ArgumentError, "Unknown group #{g}" unless grp
322
+ tgt.add_to(grp)
323
+ end
324
+ end
325
+
326
+ end
@@ -0,0 +1,277 @@
1
+ # Execution context for Inprovise
2
+ #
3
+ # Author:: Martin Corino
4
+ # License:: Distributes under the same license as Ruby
5
+
6
+ require 'open3'
7
+ require 'ostruct'
8
+
9
+ class Inprovise::ExecutionContext
10
+
11
+ class DSL
12
+ def initialize(context)
13
+ @context = context
14
+ end
15
+
16
+ def method_missing(meth, *args)
17
+ @context.config.send(meth, *args)
18
+ end
19
+
20
+ def node
21
+ @context.node
22
+ end
23
+
24
+ def config
25
+ @context.config
26
+ end
27
+
28
+ def as(user, &blk)
29
+ @context.as(user, &blk)
30
+ end
31
+
32
+ def in_dir(path, &blk)
33
+ @context.in_dir(path, &blk)
34
+ end
35
+
36
+ def run_local(cmd)
37
+ @context.run_local(cmd)
38
+ end
39
+
40
+ def run(cmd, opts={})
41
+ @context.run(cmd, opts)
42
+ end
43
+
44
+ def sudo(cmd, opts={})
45
+ @context.sudo(cmd, opts)
46
+ end
47
+
48
+ def env(var)
49
+ @context.env(var)
50
+ end
51
+
52
+ def log(msg=nil)
53
+ @context.log(msg)
54
+ end
55
+
56
+ def upload(from, to)
57
+ @context.upload(from, to)
58
+ end
59
+
60
+ def download(from, to)
61
+ @context.download(from, to)
62
+ end
63
+
64
+ def mkdir(path)
65
+ @context.mkdir(path)
66
+ end
67
+
68
+ def remove(path)
69
+ @context.delete(path)
70
+ end
71
+
72
+ def local(path)
73
+ @context.local(path)
74
+ end
75
+
76
+ def remote(path)
77
+ @context.remote(path)
78
+ end
79
+
80
+ def template(path)
81
+ @context.template(path)
82
+ end
83
+
84
+ def trigger(action_ref, *args)
85
+ @context.trigger(action_ref, *args)
86
+ end
87
+
88
+ def binary_exists?(binary)
89
+ @context.binary_exists?(binary)
90
+ end
91
+ end
92
+
93
+ attr_reader :node, :config
94
+ attr_accessor :script
95
+
96
+ def initialize(node, log, index, config=nil)
97
+ @node = node
98
+ @log = log
99
+ @node.log_to(@log)
100
+ @config = init_config(config || @node.config)
101
+ @index = index
102
+ @script = nil
103
+ end
104
+
105
+ def init_config(hash)
106
+ hash.to_h.reduce(OpenStruct.new(hash)) do |os,(k,v)|
107
+ os[k] = init_config(v) if Hash === v
108
+ os
109
+ end
110
+ end
111
+
112
+ def exec(blk, *args)
113
+ if args.empty?
114
+ DSL.new(self).instance_eval(&blk)
115
+ else
116
+ DSL.new(self).instance_exec(*args, &blk)
117
+ end
118
+ end
119
+
120
+ def as(user, &blk)
121
+ for_user(user).exec(blk)
122
+ end
123
+
124
+ def in_dir(path, &blk)
125
+ rc = nil
126
+ old_cwd = @node.helper.set_cwd(path)
127
+ begin
128
+ rc = exec(blk)
129
+ ensure
130
+ @node.helper.set_cwd(old_cwd)
131
+ end
132
+ rc
133
+ end
134
+
135
+ def for_user(user)
136
+ return self if user.nil? || user == node.user
137
+ new_node = @node.for_user(user)
138
+ new_log = @log.clone_for_node(new_node)
139
+ self.class.new(new_node, new_log, @index, @config)
140
+ end
141
+
142
+ def run_local(cmd)
143
+ @log.local(cmd)
144
+ stdout, stderr, status = Open3.capture3(cmd)
145
+ @log.stdout(stdout)
146
+ @log.stderr(stderr)
147
+ end
148
+
149
+ def run(cmd, opts={})
150
+ @node.run(cmd, opts)
151
+ end
152
+
153
+ def sudo(cmd, opts={})
154
+ @node.sudo(cmd, opts)
155
+ end
156
+
157
+ def env(var)
158
+ @node.env(var)
159
+ end
160
+
161
+ def log(msg=nil)
162
+ @log.log(msg) if msg
163
+ @log
164
+ end
165
+
166
+ def upload(from, to)
167
+ @node.upload(from, to)
168
+ end
169
+
170
+ def download(from, to)
171
+ @node.download(from, to)
172
+ end
173
+
174
+ def mkdir(path)
175
+ @node.mkdir(path)
176
+ end
177
+
178
+ def remove(path)
179
+ @node.delete(path)
180
+ end
181
+
182
+ def copy(from, to)
183
+ @node.copy(from, to)
184
+ end
185
+
186
+ def local(path)
187
+ Inprovise::LocalFile.new(path)
188
+ end
189
+
190
+ def remote(path)
191
+ Inprovise::RemoteFile.new(self, path)
192
+ end
193
+
194
+ def set_permissions(path, mask)
195
+ @node.set_permissions(path, mask)
196
+ end
197
+
198
+ def set_owner(path, user, group=nil)
199
+ @node.set_owner(path, user, group)
200
+ end
201
+
202
+ def template(path)
203
+ Inprovise::Template.new(path, self)
204
+ end
205
+
206
+ def trigger(action_ref, *args)
207
+ action_name, pkg_name = *action_ref.split(':', 2).reverse
208
+ pkg = @script
209
+ pkg = @index.get(pkg_name) if pkg_name
210
+ action = pkg.actions[action_name] if pkg
211
+ raise Inprovise::MissingActionError.new(action_ref) unless action
212
+ curtask = @node.log.set_task(action_ref)
213
+ curscript = @script
214
+ @script = pkg
215
+ @script.merge_configuration(self.config)
216
+ begin
217
+ exec(action, *args)
218
+ ensure
219
+ @script = curscript
220
+ @node.log.set_task(curtask)
221
+ end
222
+ end
223
+
224
+ def binary_exists?(binary)
225
+ @node.binary_exists?(binary)
226
+ end
227
+ end
228
+
229
+ class Inprovise::MissingActionError < StandardError
230
+ def initialize(action_ref)
231
+ @action_ref = action_ref
232
+ end
233
+
234
+ def message
235
+ "Action '#{@action_ref}' could not be found."
236
+ end
237
+ end
238
+
239
+ class Inprovise::MockExecutionContext < Inprovise::ExecutionContext
240
+ def run(cmd)
241
+ @log.mock_execute(cmd)
242
+ ''
243
+ end
244
+
245
+ def sudo(cmd)
246
+ @log.mock_execute "sudo #{cmd}"
247
+ ''
248
+ end
249
+
250
+ def upload(from, to)
251
+ @log.mock_execute("UPLOAD: #{from} => #{to}")
252
+ end
253
+
254
+ def download(from, to)
255
+ @log.mock_execute("DOWLOAD: #{to} <= #{from}")
256
+ end
257
+
258
+ def mkdir(path)
259
+ @log.mock_execute("MKDIR: #{path}")
260
+ end
261
+
262
+ def remove(path)
263
+ @log.mock_execute("REMOVE: #{path}")
264
+ end
265
+
266
+ def copy(from, to)
267
+ @log.mock_execute("COPY: #{from} #{to}")
268
+ end
269
+
270
+ def set_permissions(path, mask)
271
+ @log.mock_execute("SET_PERMISSIONS: #{path} #{'%o' % mask}")
272
+ end
273
+
274
+ def set_owner(path, user, group=nil)
275
+ @log.mock_execute("SET_OWNER: #{path} #{user} #{group ? " #{group}" : ''}")
276
+ end
277
+ end
@@ -0,0 +1,67 @@
1
+ # Infrastructure group for Inprovise
2
+ #
3
+ # Author:: Martin Corino
4
+ # License:: Distributes under the same license as Ruby
5
+
6
+ require 'json'
7
+
8
+ class Inprovise::Infrastructure::Group < Inprovise::Infrastructure::Target
9
+
10
+ def initialize(name, config={}, targets=[])
11
+ @targets = targets.collect {|t| Inprovise::Infrastructure::Target === t ? t.name : t.to_s }
12
+ super(name, config)
13
+ end
14
+
15
+ def add_target(tgt)
16
+ tgt = Inprovise::Infrastructure::Target === tgt ? tgt : Inprovise::Infrastructure.find(tgt.to_s)
17
+ raise ArgumentError, "Circular reference detected in [#{tgt.to_s}] to [#{self.to_s}]" if tgt.includes?(self)
18
+ @targets << (Inprovise::Infrastructure::Target === tgt ? tgt.name : tgt.to_s)
19
+ end
20
+
21
+ def remove_target(tgt)
22
+ @targets.delete(Inprovise::Infrastructure::Target === tgt ? tgt.name : tgt.to_s)
23
+ end
24
+
25
+ def targets
26
+ @targets.collect {|t| Inprovise::Infrastructure.find(t).targets }.flatten.uniq
27
+ end
28
+
29
+ def targets_with_config
30
+ @targets.inject({}) do |hsh, t|
31
+ Inprovise::Infrastructure.find(t).targets_with_config.each do |tgt, cfg|
32
+ if hsh.has_key?(tgt)
33
+ hsh[tgt].merge!(cfg)
34
+ else
35
+ hsh[tgt] = cfg
36
+ end
37
+ hsh[tgt].merge!(config)
38
+ end
39
+ hsh
40
+ end
41
+ end
42
+
43
+ def includes?(tgt)
44
+ tgtname = Inprovise::Infrastructure::Target === tgt ? tgt.name : tgt.to_s
45
+ @targets.include?(tgtname) || @targets.any? {|t| Inprovise::Infrastructure.find(t).includes?(tgtname) }
46
+ end
47
+
48
+ def to_s
49
+ "Group:#{name}"
50
+ end
51
+
52
+ def to_json(*a)
53
+ {
54
+ JSON.create_id => self.class.name,
55
+ :data => {
56
+ :name => name,
57
+ :config => config,
58
+ :targets => @targets
59
+ }
60
+ }.to_json(*a)
61
+ end
62
+
63
+ def self.json_create(o)
64
+ data = o[:data]
65
+ new(data[:name], data[:config], data[:targets])
66
+ end
67
+ end
@@ -0,0 +1,43 @@
1
+ # Windows Cygwin Command helper for Inprovise
2
+ #
3
+ # Author:: Martin Corino
4
+ # License:: Distributes under the same license as Ruby
5
+
6
+ Inprovise::CmdHelper.define('cygwin', Inprovise::CmdHelper.implementations['linux']) do
7
+
8
+ def initialize(channel)
9
+ super(channel)
10
+ # only if this is *NOT* a sudo helper
11
+ unless channel.node.user == admin_user
12
+ if channel.node.config.has_key?(:credentials) && channel.node.config[:credentials].has_key?(:'public-key')
13
+ # trigger sudo channel creation to have pubkey installed for admin as well
14
+ sudo
15
+ end
16
+ end
17
+ end
18
+
19
+ # platform properties
20
+
21
+ def admin_user
22
+ 'administrator'
23
+ end
24
+
25
+ def env_reference(varname)
26
+ "\$#{varname}"
27
+ end
28
+
29
+ # generic command execution
30
+
31
+ def sudo
32
+ return self if channel.node.user == admin_user
33
+ unless @sudo
34
+ @sudo = channel.node.for_user(admin_user, "sudo:#{channel.node.user}").helper
35
+ end
36
+ @sudo.set_cwd(self.cwd)
37
+ @sudo.channel.node.log_to(channel.node.log.clone_for_node(@sudo.channel.node))
38
+ @sudo
39
+ end
40
+
41
+ # basic commands
42
+
43
+ end