inprovise 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,10 +9,11 @@ class Inprovise::Controller
9
9
 
10
10
  class << self
11
11
 
12
+ private
13
+
12
14
  def controllers
13
15
  @controllers ||= Array.new.extend(MonitorMixin)
14
16
  end
15
- private :controllers
16
17
 
17
18
  def add(ctrl)
18
19
  controllers.synchronize do
@@ -20,28 +21,24 @@ class Inprovise::Controller
20
21
  end
21
22
  ctrl
22
23
  end
23
- private :add
24
24
 
25
25
  def head
26
26
  controllers.synchronize do
27
27
  return controllers.first
28
28
  end
29
29
  end
30
- private :head
31
30
 
32
31
  def shift
33
32
  controllers.synchronize do
34
33
  return controllers.shift
35
34
  end
36
35
  end
37
- private :shift
38
36
 
39
37
  def empty?
40
38
  controllers.synchronize do
41
39
  return controllers.empty?
42
40
  end
43
41
  end
44
- private :empty?
45
42
 
46
43
  def get_value(v)
47
44
  begin
@@ -50,14 +47,19 @@ class Inprovise::Controller
50
47
  v
51
48
  end
52
49
  end
53
- private :get_value
54
50
 
55
- def list_scripts(options)
51
+ def load_schemes(options)
56
52
  # load all specified schemes
57
53
  (Array === options[:scheme] ? options[:scheme] : [options[:scheme]]).each {|s| Inprovise::DSL.include(s) }
54
+ end
55
+
56
+ public
57
+
58
+ def list_scripts(options)
59
+ load_schemes(options)
58
60
  $stdout.puts
59
- $stdout.puts " PROVISIONING SCRIPTS"
60
- $stdout.puts " ===================="
61
+ $stdout.puts ' PROVISIONING SCRIPTS'
62
+ $stdout.puts ' ===================='
61
63
  Inprovise::ScriptIndex.default.scripts.sort.each do |scrname|
62
64
  script = Inprovise::ScriptIndex.default.get(scrname)
63
65
  if script.description || options[:all]
@@ -66,8 +68,8 @@ class Inprovise::Controller
66
68
  end
67
69
  end
68
70
 
69
- def parse_config(cfg, opts = {})
70
- cfg.inject(opts) do |rc,cfg|
71
+ def parse_config(cfglist, opts = {})
72
+ cfglist.inject(opts) do |rc, cfg|
71
73
  k,v = cfg.split('=')
72
74
  k = k.split('.')
73
75
  h = rc
@@ -92,8 +94,7 @@ class Inprovise::Controller
92
94
  run_group_command(command, options, *args)
93
95
  end
94
96
  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
+ load_schemes(options)
97
98
  # extract config
98
99
  cfg = parse_config(options[:config])
99
100
  # get script/action
@@ -129,11 +130,13 @@ class Inprovise::Controller
129
130
  end
130
131
 
131
132
  def run_node_command(cmd, options, *names)
132
- add(Inprovise::Controller.new).run_node_command(cmd, options, *names)
133
+ add(Inprovise::Controller.new).send(:"#{cmd}_node", options, *names)
134
+ Inprovise::Infrastructure.save
133
135
  end
134
136
 
135
137
  def run_group_command(cmd, options, *names)
136
- add(Inprovise::Controller.new).run_group_command(cmd, options, *names)
138
+ add(Inprovise::Controller.new).send(:"#{cmd}_group", options, *names)
139
+ Inprovise::Infrastructure.save
137
140
  end
138
141
 
139
142
  def run_provisioning_command(command, script, opts, *targets)
@@ -183,93 +186,93 @@ class Inprovise::Controller
183
186
  end
184
187
  end
185
188
 
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))
189
+ def add_node(options, *names)
190
+ opts = self.class.parse_config(options[:config], { host: options[:address] })
191
+ opts[:credentials] = self.class.parse_config(options[:credential])
192
+ @targets << (node = Inprovise::Infrastructure::Node.new(names.first, opts))
192
193
 
193
- Inprovise.log.local("Adding #{node.to_s}")
194
+ Inprovise.log.local("Adding #{node}")
194
195
 
195
- Inprovise::Sniffer.run_sniffers_for(node) if options[:sniff]
196
+ Inprovise::Sniffer.run_sniffers_for(node) if options[:sniff]
196
197
 
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)
198
+ options[:group].each do |g|
199
+ grp = Inprovise::Infrastructure.find(g)
200
+ raise ArgumentError, "Unknown group #{g}" unless grp
201
+ node.add_to(grp)
202
+ end
203
+ end
206
204
 
207
- Inprovise.log.local("Removing #{node.to_s}")
205
+ def remove_node(_options, *names)
206
+ names.each do |name|
207
+ node = Inprovise::Infrastructure.find(name)
208
+ raise ArgumentError, "Invalid node #{name}" unless node && node.is_a?(Inprovise::Infrastructure::Node)
208
209
 
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
210
+ Inprovise.log.local("Removing #{node}")
211
+
212
+ Inprovise::Infrastructure.deregister(name)
225
213
  end
226
- Inprovise::Infrastructure.save
227
214
  end
228
215
 
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])
216
+ def update_node(options, *names)
217
+ @targets = names.collect do |name|
218
+ tgt = Inprovise::Infrastructure.find(name)
219
+ raise ArgumentError, "Unknown target [#{name}]" unless tgt
220
+ tgt.targets
221
+ end.flatten.uniq
222
+ opts = self.class.parse_config(options[:config])
223
+ opts[:credentials] = self.class.parse_config(options[:credential])
224
+ if Inprovise.sequential || (!options[:sniff]) || @targets.size == 1
225
+ @targets.each {|tgt| run_target_update(tgt, opts.dup, options) }
226
+ else
227
+ threads = @targets.map {|tgt| Thread.new { run_target_update(tgt, opts.dup, options) } }
228
+ threads.each {|t| t.join }
229
+ end
230
+ end
235
231
 
236
- Inprovise.log.local("Adding #{grp.to_s}")
232
+ def add_group(options, *names)
233
+ options[:target].each {|t| raise ArgumentError, "Unknown target [#{t}]" unless Inprovise::Infrastructure.find(t) }
234
+ opts = self.class.parse_config(options[:config])
235
+ grp = Inprovise::Infrastructure::Group.new(names.first, opts, options[:target])
237
236
 
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)
237
+ Inprovise.log.local("Adding #{grp}")
247
238
 
248
- Inprovise.log.local("Removing #{grp.to_s}")
239
+ options[:target].each do |t|
240
+ tgt = Inprovise::Infrastructure.find(t)
241
+ raise ArgumentError, "Unknown target #{t}" unless tgt
242
+ tgt.add_to(grp)
243
+ end
244
+ end
249
245
 
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
246
+ def remove_group(_options, *names)
247
+ names.each do |name|
248
+ grp = Inprovise::Infrastructure.find(name)
249
+ raise ArgumentError, "Invalid group #{name}" unless grp && grp.is_a?(Inprovise::Infrastructure::Group)
250
+
251
+ Inprovise.log.local("Removing #{grp}")
252
+
253
+ Inprovise::Infrastructure.deregister(name)
254
+ end
255
+ end
256
+
257
+ def update_group(options, *names)
258
+ groups = names.collect do |name|
259
+ tgt = Inprovise::Infrastructure.find(name)
260
+ raise ArgumentError, "Invalid group #{name}" unless tgt && tgt.is_a?(Inprovise::Infrastructure::Group)
261
+ tgt
262
+ end
263
+ opts = self.class.parse_config(options[:config])
264
+ grp_tgts = options[:target].collect do |tnm|
265
+ tgt = Inprovise::Infrastructure.find(tnm)
266
+ raise ArgumentError, "Unknown target #{tnm}" unless tgt
267
+ tgt
268
+ end
269
+ groups.each do |grp|
270
+ Inprovise.log.local("Updating #{grp}")
271
+
272
+ grp.config.clear if options[:reset]
273
+ grp.config.merge!(opts)
274
+ grp_tgts.each {|gt| gt.add_to(grp) }
271
275
  end
272
- Inprovise::Infrastructure.save
273
276
  end
274
277
 
275
278
  private
@@ -298,7 +301,7 @@ class Inprovise::Controller
298
301
  end
299
302
 
300
303
  def run_target_update(tgt, tgt_opts, options)
301
- Inprovise.log.local("Updating #{tgt.to_s}")
304
+ Inprovise.log.local("Updating #{tgt}")
302
305
 
303
306
  if options[:reset]
304
307
  # preserve :host
@@ -3,6 +3,8 @@
3
3
  # Author:: Martin Corino
4
4
  # License:: Distributes under the same license as Ruby
5
5
 
6
+ # :nocov:
7
+
6
8
  Inprovise::CmdHelper.define('cygwin', Inprovise::CmdHelper.implementations['linux']) do
7
9
 
8
10
  def initialize(channel)
@@ -41,3 +43,6 @@ Inprovise::CmdHelper.define('cygwin', Inprovise::CmdHelper.implementations['linu
41
43
  # basic commands
42
44
 
43
45
  end
46
+
47
+ # :nocov:
48
+
@@ -3,6 +3,8 @@
3
3
  # Author:: Martin Corino
4
4
  # License:: Distributes under the same license as Ruby
5
5
 
6
+ # :nocov:
7
+
6
8
  Inprovise::CmdHelper.define('linux') do
7
9
 
8
10
  def initialize(channel, sudo=false)
@@ -48,11 +50,11 @@ Inprovise::CmdHelper.define('linux') do
48
50
  # file management
49
51
 
50
52
  def upload(from, to)
51
- @channel.upload(real_path(from), real_path(to))
53
+ @channel.upload(from, real_path(to))
52
54
  end
53
55
 
54
56
  def download(from, to)
55
- @channel.download(real_path(from), real_path(to))
57
+ @channel.download(real_path(from), to)
56
58
  end
57
59
 
58
60
  # basic commands
@@ -101,7 +103,7 @@ Inprovise::CmdHelper.define('linux') do
101
103
  def directory?(path)
102
104
  path = real_path(path)
103
105
  begin
104
- @channel.file?(path)
106
+ @channel.directory?(path)
105
107
  rescue
106
108
  (exec("stat --format=%f #{path}").chomp.hex & 0x4000) == 0x4000
107
109
  end
@@ -185,3 +187,6 @@ Inprovise::CmdHelper.define('linux') do
185
187
  end
186
188
 
187
189
  end
190
+
191
+ # :nocov:
192
+
@@ -5,6 +5,8 @@
5
5
 
6
6
  require 'digest/sha1'
7
7
 
8
+ # :nocov:
9
+
8
10
  Inprovise::CmdHelper.define('windows') do
9
11
 
10
12
  # platform properties
@@ -125,3 +127,5 @@ Inprovise::CmdHelper.define('windows') do
125
127
  end
126
128
 
127
129
  end
130
+
131
+ # :nocov:
@@ -253,7 +253,7 @@ class Inprovise::Infrastructure::Node < Inprovise::Infrastructure::Target
253
253
  @history << {cmd:cmd, output:output}
254
254
  output
255
255
  rescue Exception
256
- raise RuntimeError, "Failed to communicate with [#{self.to_s}]"
256
+ raise RuntimeError, "Failed to communicate with [#{self}]"
257
257
  end
258
258
  end
259
259
 
@@ -5,6 +5,8 @@
5
5
 
6
6
  Inprovise::Sniffer.define('linux', false) do
7
7
 
8
+ # :nocov:
9
+
8
10
  action('main') do |attrs|
9
11
  attrs[:machine] = run('uname -m').chomp
10
12
  if remote('/etc/os-release').exists?
@@ -61,4 +63,6 @@ Inprovise::Sniffer.define('linux', false) do
61
63
  end
62
64
  end
63
65
 
66
+ # :nocov:
67
+
64
68
  end
@@ -5,6 +5,8 @@
5
5
 
6
6
  Inprovise::Sniffer.define('platform') do
7
7
 
8
+ # :nocov:
9
+
8
10
  action('helper') do |attrs|
9
11
  # determin the best CmdHelper if not user defined
10
12
  attrs[:helper] = case attrs[:os]
@@ -39,6 +41,8 @@ Inprovise::Sniffer.define('platform') do
39
41
  (node.config[:attributes][:platform] ||= {}).merge!(attrs)
40
42
  end
41
43
 
44
+ # :nocov:
45
+
42
46
  end
43
47
 
44
48
  require_relative './windows.rb'
@@ -5,6 +5,8 @@
5
5
 
6
6
  Inprovise::Sniffer.define('windows', false) do
7
7
 
8
+ # :nocov:
9
+
8
10
  action('main') do |attrs|
9
11
  attrs[:machine] = env('PROCESSOR_ARCHITECTURE').chomp =~ /amd64/i ? 'x86_64' : 'x86'
10
12
  osver = run('cmd /c ver').strip
@@ -29,4 +31,6 @@ Inprovise::Sniffer.define('windows', false) do
29
31
  end
30
32
  end
31
33
 
34
+ # :nocov:
35
+
32
36
  end
@@ -19,7 +19,7 @@ class Inprovise::Template
19
19
  end
20
20
 
21
21
  def render_to_tempfile(locals={})
22
- basename = @path.respond_to?(:call) ? 'inprovise-inline-tpl' : File.basename(@path).gsub('.', '-')
22
+ basename = @path.respond_to?(:call) ? 'inprovise-inline-tpl' : File.basename(@path).tr('.', '-')
23
23
  file = Tempfile.new(basename)
24
24
  file.write render(locals)
25
25
  file.close
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Inprovise
7
7
 
8
- VERSION = '0.2.4'
8
+ VERSION = '0.2.5'
9
9
 
10
10
  end
@@ -0,0 +1,189 @@
1
+ # ScriptRunner tests for Inprovise
2
+ #
3
+ # Author:: Martin Corino
4
+ # License:: Distributes under the same license as Ruby
5
+
6
+ require_relative 'test_helper'
7
+
8
+ describe Inprovise::CmdHelper do
9
+ before :each do
10
+ @node = Inprovise::Infrastructure::Node.new('myNode', {channel: 'test', helper: 'linux'})
11
+ end
12
+
13
+ after :each do
14
+ reset_infrastructure!
15
+ end
16
+
17
+ describe 'helper' do
18
+
19
+ describe 'platform specifics' do
20
+ it 'provides appropriate administrator account' do
21
+ @node.helper.admin_user.must_equal 'root'
22
+ end
23
+
24
+ it 'provides appropriate environment variable format' do
25
+ @node.helper.env_reference('VAR').must_equal '$VAR'
26
+ end
27
+ end
28
+
29
+ describe 'working directory' do
30
+ it 'manages working directory' do
31
+ @node.channel.expects(:run).with('pwd', false).returns('/root')
32
+ @node.helper.cwd.must_equal '/root'
33
+ end
34
+
35
+ it 'returns old cwd on setting cwd' do
36
+ @node.helper.set_cwd('/home/user').must_be_nil
37
+ @node.helper.cwd.must_equal '/home/user'
38
+ @node.helper.set_cwd('/root').must_equal '/home/user'
39
+ @node.helper.cwd.must_equal '/root'
40
+ @node.helper.set_cwd(nil).must_equal '/root'
41
+ @node.channel.expects(:run).with('pwd', false).returns('/root')
42
+ @node.helper.cwd.must_equal '/root'
43
+ end
44
+ end
45
+
46
+ describe 'command execution' do
47
+ it 'runs commands' do
48
+ @node.channel.expects(:run).with('echo ok', false).returns('ok')
49
+ @node.helper.run('echo ok').must_equal 'ok'
50
+ end
51
+
52
+ it 'runs sudo commands' do
53
+ @node.channel.expects(:run).with('sudo sh -c "echo ok"', false).returns('ok')
54
+ @node.helper.sudo.run('echo ok').must_equal 'ok'
55
+ end
56
+
57
+ it 'runs commands in cwd' do
58
+ @node.helper.set_cwd('/home/user')
59
+ @node.channel.expects(:run).with('cd /home/user; echo ok', false).returns('ok')
60
+ @node.helper.run('echo ok').must_equal 'ok'
61
+ end
62
+ end
63
+
64
+ describe 'file transfer' do
65
+ it 'uploads files' do
66
+ @node.channel.expects(:upload).with('/from/path', '/to/path')
67
+ @node.helper.upload('/from/path', '/to/path')
68
+ end
69
+
70
+ it 'downloads files' do
71
+ @node.channel.expects(:download).with('/from/path', '/to/path')
72
+ @node.helper.download('/from/path', '/to/path')
73
+ end
74
+
75
+ it 'uploads files with changed cwd' do
76
+ @node.helper.set_cwd('/home/user')
77
+ @node.channel.expects(:upload).with('/from/path', '/home/user/to/path')
78
+ @node.helper.upload('/from/path', 'to/path')
79
+ end
80
+
81
+ it 'downloads files with changed cwd' do
82
+ @node.helper.set_cwd('/home/user')
83
+ @node.channel.expects(:download).with('/home/user/from/path', '/to/path')
84
+ @node.helper.download('from/path', '/to/path')
85
+ end
86
+ end
87
+
88
+ describe 'file management' do
89
+
90
+ it 'returns file content' do
91
+ @node.channel.expects(:content).with('/file/path')
92
+ @node.helper.cat('/file/path')
93
+ end
94
+
95
+ it 'returns file content from cwd' do
96
+ @node.helper.set_cwd('/home/user')
97
+ @node.channel.expects(:content).with('/home/user/file/path')
98
+ @node.helper.cat('file/path')
99
+ end
100
+
101
+ it 'creates a directory' do
102
+ @node.channel.expects(:run).with('mkdir -p /dir/path', false)
103
+ @node.helper.mkdir('/dir/path')
104
+ end
105
+
106
+ it 'creates a directory from cwd' do
107
+ @node.helper.set_cwd('/home/user')
108
+ @node.channel.expects(:run).with('mkdir -p /home/user/dir/path', false)
109
+ @node.helper.mkdir('dir/path')
110
+ end
111
+
112
+ it 'checks path existence' do
113
+ @node.channel.expects(:exists?).with('/file/path').returns(true)
114
+ @node.helper.exists?('/file/path').must_equal true
115
+ end
116
+
117
+ it 'check file existence' do
118
+ @node.channel.expects(:file?).with('/file/path').returns(true)
119
+ @node.helper.file?('/file/path').must_equal true
120
+ end
121
+
122
+ it 'checks directory existence' do
123
+ @node.channel.expects(:directory?).with('/dir/path').returns(true)
124
+ @node.helper.directory?('/dir/path').must_equal true
125
+ end
126
+
127
+ it 'copies files' do
128
+ @node.channel.expects(:run).with("cp /from/path /to/path", false)
129
+ @node.helper.copy('/from/path', '/to/path')
130
+ end
131
+
132
+ it 'moves files' do
133
+ @node.channel.expects(:run).with("mv /from/path /to/path", false)
134
+ @node.helper.move('/from/path', '/to/path')
135
+ end
136
+
137
+ it 'deletes files' do
138
+ @node.channel.expects(:delete).with('/file/path')
139
+ @node.helper.delete('/file/path')
140
+ end
141
+
142
+ it 'returns file permissions' do
143
+ @node.channel.expects(:permissions).with('/file/path').returns(0755)
144
+ @node.helper.permissions('/file/path').must_equal 0755
145
+ end
146
+
147
+ it 'sets file permissions' do
148
+ @node.channel.expects(:set_permissions).with('/file/path', 0755)
149
+ @node.helper.set_permissions('/file/path', 0755)
150
+ end
151
+
152
+ it 'returns file owner' do
153
+ @node.channel.expects(:owner).with('/file/path').returns({ :user => 'me', :group => 'them' })
154
+ @node.helper.owner('/file/path').must_equal({ :user => 'me', :group => 'them' })
155
+ end
156
+
157
+ it 'sets file owner' do
158
+ @node.channel.expects(:set_owner).with('/file/path', 'me','them')
159
+ @node.helper.set_owner('/file/path', 'me','them')
160
+ end
161
+
162
+ end
163
+
164
+ describe 'shell utilities' do
165
+
166
+ it 'echoes' do
167
+ @node.channel.expects(:run).with('echo ok', false).returns('ok')
168
+ @node.helper.echo('ok').must_equal 'ok'
169
+ end
170
+
171
+ it 'returns an environment variables value' do
172
+ @node.channel.expects(:run).with('echo $HOME', false).returns('/home/user')
173
+ @node.helper.env('HOME').must_equal '/home/user'
174
+ end
175
+
176
+ it 'returns an SHA1 hash for the file content' do
177
+ @node.channel.expects(:run).with('sha1sum /file/path', false).returns('A1B2C3D4')
178
+ @node.helper.hash_for('/file/path').must_equal 'A1B2C3D4'
179
+ end
180
+
181
+ it 'checks binary existence' do
182
+ @node.channel.expects(:run).with('which ruby', false).returns('/usr/bin/ruby')
183
+ @node.helper.binary_exists?('ruby').must_equal true
184
+ end
185
+
186
+ end
187
+
188
+ end
189
+ end