inprovise 0.2.2

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