inprovise 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +4 -0
- data/.travis.yml +28 -0
- data/Gemfile +9 -0
- data/LICENSE +8 -0
- data/README.md +197 -0
- data/Rakefile.rb +9 -0
- data/bin/rig +5 -0
- data/inprovise.gemspec +22 -0
- data/lib/inprovise/channel/ssh.rb +202 -0
- data/lib/inprovise/cli/group.rb +86 -0
- data/lib/inprovise/cli/node.rb +95 -0
- data/lib/inprovise/cli/provision.rb +84 -0
- data/lib/inprovise/cli.rb +105 -0
- data/lib/inprovise/cmd_channel.rb +100 -0
- data/lib/inprovise/cmd_helper.rb +150 -0
- data/lib/inprovise/control.rb +326 -0
- data/lib/inprovise/execution_context.rb +277 -0
- data/lib/inprovise/group.rb +67 -0
- data/lib/inprovise/helper/cygwin.rb +43 -0
- data/lib/inprovise/helper/linux.rb +181 -0
- data/lib/inprovise/helper/windows.rb +123 -0
- data/lib/inprovise/infra.rb +122 -0
- data/lib/inprovise/local_file.rb +120 -0
- data/lib/inprovise/logger.rb +79 -0
- data/lib/inprovise/node.rb +271 -0
- data/lib/inprovise/remote_file.rb +128 -0
- data/lib/inprovise/resolver.rb +36 -0
- data/lib/inprovise/script.rb +175 -0
- data/lib/inprovise/script_index.rb +46 -0
- data/lib/inprovise/script_runner.rb +110 -0
- data/lib/inprovise/sniff.rb +46 -0
- data/lib/inprovise/sniffer/linux.rb +64 -0
- data/lib/inprovise/sniffer/platform.rb +46 -0
- data/lib/inprovise/sniffer/unknown.rb +11 -0
- data/lib/inprovise/sniffer/windows.rb +32 -0
- data/lib/inprovise/template/inprovise.rb.erb +92 -0
- data/lib/inprovise/template.rb +38 -0
- data/lib/inprovise/trigger_runner.rb +36 -0
- data/lib/inprovise/version.rb +10 -0
- data/lib/inprovise.rb +145 -0
- data/test/cli_test.rb +314 -0
- data/test/cli_test_helper.rb +19 -0
- data/test/dsl_test.rb +43 -0
- data/test/fixtures/example.txt +1 -0
- data/test/fixtures/include.rb +4 -0
- data/test/fixtures/inprovise.rb +1 -0
- data/test/fixtures/myscheme.rb +1 -0
- data/test/infra_test.rb +189 -0
- data/test/local_file_test.rb +64 -0
- data/test/remote_file_test.rb +106 -0
- data/test/resolver_test.rb +66 -0
- data/test/script_index_test.rb +53 -0
- data/test/script_test.rb +56 -0
- data/test/test_helper.rb +237 -0
- 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
|