rouster 0.53 → 0.57
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.
- checksums.yaml +4 -4
- data/README.md +5 -2
- data/examples/passthrough.rb +71 -0
- data/lib/rouster.rb +194 -242
- data/lib/rouster/deltas.rb +44 -39
- data/lib/rouster/puppet.rb +82 -21
- data/lib/rouster/testing.rb +129 -19
- data/lib/rouster/tests.rb +34 -6
- data/lib/rouster/vagrant.rb +242 -0
- data/test/basic.rb +4 -1
- data/test/functional/deltas/test_get_crontab.rb +22 -1
- data/test/functional/deltas/test_get_services.rb +6 -0
- data/test/functional/test_inspect.rb +1 -1
- data/test/functional/test_is_file.rb +17 -1
- data/test/functional/test_new.rb +185 -16
- data/test/functional/test_passthroughs.rb +94 -0
- data/test/functional/test_put.rb +2 -2
- data/test/functional/test_validate_file.rb +55 -3
- data/test/puppet/test_apply.rb +7 -5
- data/test/unit/puppet/test_get_puppet_star.rb +27 -4
- data/test/unit/test_new.rb +23 -0
- data/test/unit/test_parse_ls_string.rb +24 -0
- data/test/unit/testing/test_validate_cron.rb +78 -0
- metadata +24 -20
data/test/functional/test_new.rb
CHANGED
@@ -7,39 +7,70 @@ require 'test/unit'
|
|
7
7
|
|
8
8
|
class TestNew < Test::Unit::TestCase
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
# when run under Rake, if named 'setup', @@user_sshkey is not initialized in the
|
11
|
+
# TestNew namespace (does not matter if running directly). since setup() really
|
12
|
+
# only needed to be run once anyway, this isn't a huge problem
|
13
|
+
def test_0_setup
|
14
|
+
@app = Rouster.new(:name => 'app', :sshtunnel => false)
|
15
|
+
@app.destroy() if @app.status().eql?('running') # TODO do we really need to do this?
|
13
16
|
@app = nil
|
17
|
+
|
18
|
+
@@user_sshkey = sprintf('%s/.ssh/id_rsa', ENV['HOME'])
|
19
|
+
|
20
|
+
unless File.file?(@@user_sshkey)
|
21
|
+
#`ssh-keygen -t rsa -q -f #{@@user_sshkey} -N ''` # this will create the file, and we can track with another class variable.. but how do we safely install/uninstall this to localhost ~/.ssh/authorized_keys ?
|
22
|
+
File.write(@@user_sshkey, '') # either this or `touch`
|
23
|
+
File.chmod(0600, @@user_sshkey)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_able_to_instantiate
|
29
|
+
|
30
|
+
assert_nothing_raised do
|
31
|
+
@app = Rouster.new(:name => 'app')
|
32
|
+
end
|
33
|
+
|
14
34
|
end
|
15
35
|
|
16
|
-
def
|
36
|
+
def test_defaults
|
17
37
|
|
18
38
|
assert_nothing_raised do
|
19
39
|
@app = Rouster.new(:name => 'app')
|
20
40
|
end
|
21
41
|
|
42
|
+
assert_equal('app', @app.name)
|
43
|
+
assert_equal(false, @app.cache_timeout)
|
44
|
+
assert_equal(false, @app.instance_variable_get(:@logfile))
|
45
|
+
assert_equal(false, @app.is_passthrough?())
|
46
|
+
assert_equal(0, @app.retries)
|
47
|
+
assert_equal(true, @app.instance_variable_get(:@sshtunnel))
|
48
|
+
assert_equal(false, @app.instance_variable_get(:@unittest))
|
49
|
+
assert_equal(false, @app.instance_variable_get(:@vagrant_concurrency))
|
50
|
+
assert_equal(3, @app.instance_variable_get(:@verbosity_console))
|
51
|
+
assert_equal(2, @app.instance_variable_get(:@verbosity_logfile))
|
52
|
+
|
22
53
|
end
|
23
54
|
|
24
|
-
def
|
55
|
+
def test_good_openssh_tunnel
|
25
56
|
@app = Rouster.new(:name => 'app', :sshtunnel => true)
|
26
|
-
7
|
27
|
-
# TODO how do we properly test this? we really need the rspec should_call mechanism...
|
28
57
|
|
58
|
+
# TODO how do we properly test this? we really need the rspec should_call mechanism...
|
29
59
|
assert_equal(true, @app.is_available_via_ssh?)
|
30
60
|
end
|
31
61
|
|
32
|
-
def
|
62
|
+
def test_good_advanced_instantiation
|
33
63
|
|
34
64
|
assert_nothing_raised do
|
35
65
|
@app = Rouster.new(
|
36
66
|
:name => 'app',
|
37
67
|
:passthrough => false,
|
38
68
|
:sudo => false,
|
39
|
-
:verbosity => 4,
|
69
|
+
:verbosity => [4,0],
|
40
70
|
#:vagrantfile => traverse_up(Dir.pwd, 'Vagrantfile'), # this is what happens anyway..
|
41
71
|
:sshkey => ENV['VAGRANT_HOME'].nil? ? sprintf('%s/.vagrant.d/insecure_private_key', ENV['HOME']) : sprintf('%s/insecure_private_key', ENV['VAGRANT_HOME']),
|
42
72
|
:cache_timeout => 10,
|
73
|
+
:logfile => true,
|
43
74
|
)
|
44
75
|
|
45
76
|
end
|
@@ -47,37 +78,48 @@ class TestNew < Test::Unit::TestCase
|
|
47
78
|
assert_equal('app', @app.name)
|
48
79
|
assert_equal(false, @app.is_passthrough?())
|
49
80
|
assert_equal(false, @app.uses_sudo?())
|
50
|
-
assert_equal(4, @app.
|
81
|
+
assert_equal(4, @app.instance_variable_get(:@verbosity_console))
|
82
|
+
assert_equal(0, @app.instance_variable_get(:@verbosity_logfile))
|
51
83
|
assert_equal(true, File.file?(@app.vagrantfile))
|
52
84
|
assert_equal(true, File.file?(@app.sshkey))
|
53
85
|
assert_equal(10, @app.cache_timeout)
|
86
|
+
|
87
|
+
## logfile validation -- do we need to do more here?
|
88
|
+
logfile = @app.instance_variable_get(:@logfile)
|
89
|
+
|
90
|
+
assert_not_equal(true, logfile)
|
91
|
+
assert(File.file?(logfile))
|
92
|
+
|
93
|
+
contents = File.read(logfile)
|
94
|
+
assert_not_nil(contents)
|
54
95
|
end
|
55
96
|
|
56
|
-
def
|
97
|
+
def test_bad_name_instantiation
|
57
98
|
|
99
|
+
# TODO this is probably wrong, should really be an ArgumentError
|
58
100
|
assert_raise Rouster::InternalError do
|
59
101
|
@app = Rouster.new(:name => 'foo')
|
60
102
|
end
|
61
103
|
|
62
|
-
assert_raise Rouster::
|
104
|
+
assert_raise Rouster::ArgumentError do
|
63
105
|
@app = Rouster.new(:not_a_name => 'test')
|
64
106
|
end
|
65
107
|
|
66
108
|
end
|
67
109
|
|
68
|
-
def
|
110
|
+
def test_bad_vagrantfile_instantiation
|
69
111
|
|
70
112
|
assert_raise Rouster::InternalError do
|
71
113
|
@app = Rouster.new(:name => 'FIZZY') # auto find Vagrantfile
|
72
114
|
end
|
73
115
|
|
74
|
-
assert_raise Rouster::
|
116
|
+
assert_raise Rouster::ArgumentError do
|
75
117
|
@app = Rouster.new(:name => 'testing', :vagrantfile => '/this/file/dne')
|
76
118
|
end
|
77
119
|
|
78
120
|
end
|
79
121
|
|
80
|
-
def
|
122
|
+
def test_bad_sshkey_instantiation
|
81
123
|
|
82
124
|
assert_raise Rouster::InternalError do
|
83
125
|
@app = Rouster.new(:name => 'app', :sshkey => '/this/file/dne')
|
@@ -85,9 +127,136 @@ class TestNew < Test::Unit::TestCase
|
|
85
127
|
|
86
128
|
end
|
87
129
|
|
130
|
+
def test_good_local_passthrough
|
131
|
+
|
132
|
+
assert_nothing_raised do
|
133
|
+
@app = Rouster.new(:name => 'local', :passthrough => { :type => :local }, :verbosity => 4)
|
134
|
+
end
|
135
|
+
|
136
|
+
assert_equal('local', @app.name)
|
137
|
+
assert_equal(true, @app.is_passthrough?())
|
138
|
+
assert_equal(false, @app.uses_sudo?())
|
139
|
+
assert_equal(true, @app.is_available_via_ssh?())
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_good_remote_passthrough
|
144
|
+
|
145
|
+
skip('not running test_good_remote_passthrough, autogenerated a fake ssh key') if File.file?(@@user_sshkey) and File.read(@@user_sshkey).eql?("")
|
146
|
+
|
147
|
+
host = '127.0.0.1'
|
148
|
+
`ssh -i #{@@user_sshkey} #{host}`
|
149
|
+
skip("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
|
150
|
+
|
151
|
+
assert_nothing_raised do
|
152
|
+
@app = Rouster.new(
|
153
|
+
:name => 'remote',
|
154
|
+
:sudo => false,
|
155
|
+
:passthrough => {
|
156
|
+
:type => :remote,
|
157
|
+
:host => host,
|
158
|
+
:user => ENV['USER'],
|
159
|
+
:key => @@user_sshkey,
|
160
|
+
},
|
161
|
+
:verbosity => 4,
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
assert_equal('remote', @app.name)
|
166
|
+
assert_equal(true, @app.is_passthrough?())
|
167
|
+
assert_equal(false, @app.uses_sudo?())
|
168
|
+
assert_equal(true, @app.is_available_via_ssh?())
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_invalid_passthrough
|
173
|
+
|
174
|
+
# invalid type
|
175
|
+
# missing required parameters
|
176
|
+
|
177
|
+
assert_raise Rouster::ArgumentError do
|
178
|
+
@app = Rouster.new(:name => 'fizzy', :passthrough => {}, :verbosity => 4)
|
179
|
+
end
|
180
|
+
|
181
|
+
assert_raise Rouster::ArgumentError do
|
182
|
+
@app = Rouster.new(:name => 'fizzy', :passthrough => { :type => 'invalid' }, :verbosity => 4)
|
183
|
+
end
|
184
|
+
|
185
|
+
assert_raise Rouster::ArgumentError do
|
186
|
+
@app = Rouster.new(:name => 'fizzy', :passthrough => { :type => :remote }, :verbosity => 4)
|
187
|
+
end
|
188
|
+
|
189
|
+
assert_raise Rouster::ArgumentError do
|
190
|
+
@app = Rouster.new(:name => 'fizzy', :passthrough => { :type => :remote, :user => 'foo' }, :verbosity => 4)
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_bad_passthrough
|
196
|
+
|
197
|
+
# invalid key
|
198
|
+
assert_raise Rouster::InternalError do
|
199
|
+
@app = Rouster.new(
|
200
|
+
:name => 'fizzy',
|
201
|
+
:passthrough => {
|
202
|
+
:type => :remote,
|
203
|
+
:key => '/etc/hosts',
|
204
|
+
:user => 'foo',
|
205
|
+
:host => 'bar',
|
206
|
+
},
|
207
|
+
:verbosity => 4,
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
# key that DNE
|
212
|
+
assert_raise Rouster::ArgumentError do
|
213
|
+
@app = Rouster.new(
|
214
|
+
:name => 'fizzy',
|
215
|
+
:passthrough => {
|
216
|
+
:type => :remote,
|
217
|
+
:key => '/etc/this-file-dne',
|
218
|
+
:user => 'foo',
|
219
|
+
:host => 'bar',
|
220
|
+
},
|
221
|
+
:verbosity => 4,
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
225
|
+
# host that DNE
|
226
|
+
# TODO should we be catching this ourselves?
|
227
|
+
assert_raise SocketError do
|
228
|
+
@app = Rouster.new(
|
229
|
+
:name => 'fizzy',
|
230
|
+
:passthrough => {
|
231
|
+
:type => :remote,
|
232
|
+
:key => @@user_sshkey,
|
233
|
+
:user => 'foo',
|
234
|
+
:host => 'this.host.does.not.exist',
|
235
|
+
},
|
236
|
+
:verbosity => 4,
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
# IP that doesn't resolve
|
241
|
+
# TODO should we be catching this ourselves?
|
242
|
+
assert_raise SocketError do
|
243
|
+
@app = Rouster.new(
|
244
|
+
:name => 'fizzy',
|
245
|
+
:passthrough => {
|
246
|
+
:type => :remote,
|
247
|
+
:key => @@user_sshkey,
|
248
|
+
:user => 'foo',
|
249
|
+
:host => '255.256.257.258',
|
250
|
+
},
|
251
|
+
:verbosity => 4,
|
252
|
+
)
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
88
256
|
|
89
257
|
def teardown
|
90
|
-
#
|
258
|
+
# if the file is empty, we know we created it (or it doesn't matter)..
|
259
|
+
File.delete(@@user_sshkey) if File.file?(@@user_sshkey) and File.read(@@user_sshkey).eql?('')
|
91
260
|
end
|
92
261
|
|
93
262
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
# most of the real passthrough testing is done in test_new.rb, since the only effective difference should be the target of the SSH connection
|
7
|
+
|
8
|
+
class TestPassthroughs < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@@user_sshkey = sprintf('%s/.ssh/id_rsa', ENV['HOME'])
|
12
|
+
|
13
|
+
unless File.file?(@@user_sshkey)
|
14
|
+
File.write(@@user_sshkey, '') # either this or `touch`
|
15
|
+
File.chmod(0600, @@user_sshkey)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_functional_local_passthrough
|
21
|
+
|
22
|
+
assert_nothing_raised do
|
23
|
+
@local = Rouster.new(
|
24
|
+
:name => 'local',
|
25
|
+
:passthrough => {
|
26
|
+
:type => :local,
|
27
|
+
},
|
28
|
+
:verbose => 4,
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
assert(@local.is_passthrough?(), 'worker is a passthrough')
|
33
|
+
assert(@local.is_available_via_ssh?(), 'worker is available via SSH')
|
34
|
+
|
35
|
+
# put a file in /tmp/fizz and read it back
|
36
|
+
tmpfile = sprintf('/tmp/fizzy.%s.%s', Time.now.to_i, $$)
|
37
|
+
content = 'this is some sample text'
|
38
|
+
|
39
|
+
assert_nothing_raised do
|
40
|
+
@local.run("echo #{content} >> #{tmpfile}")
|
41
|
+
end
|
42
|
+
|
43
|
+
read = @local.run("cat #{tmpfile}").chomp! # using >> automatically includes \n
|
44
|
+
|
45
|
+
assert_equal(content, read, 'worker is able to read and write files on system')
|
46
|
+
|
47
|
+
# TODO better here
|
48
|
+
assert_nothing_raised do
|
49
|
+
@local.file('/etc/hosts')
|
50
|
+
@local.dir('/tmp')
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_functional_remote_passthrough
|
56
|
+
|
57
|
+
skip('not running test_good_remote_passthrough, autogenerated a fake ssh key') if File.file?(@@user_sshkey) and File.read(@@user_sshkey).eql?("")
|
58
|
+
|
59
|
+
host = '127.0.0.1'
|
60
|
+
`ssh -i #{@@user_sshkey} #{host}`
|
61
|
+
skip("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
|
62
|
+
|
63
|
+
assert_nothing_raised do
|
64
|
+
@remote = Rouster.new(
|
65
|
+
:name => 'remote',
|
66
|
+
:passthrough => {
|
67
|
+
:type => :remote,
|
68
|
+
:host => host,
|
69
|
+
:user => ENV['USER'],
|
70
|
+
:key => @@user_sshkey,
|
71
|
+
},
|
72
|
+
:verbosity => 4,
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
assert_equal('remote', @remote.name)
|
77
|
+
assert_equal(true, @remote.is_passthrough?())
|
78
|
+
assert_equal(false, @remote.uses_sudo?())
|
79
|
+
assert_equal(true, @remote.is_available_via_ssh?())
|
80
|
+
|
81
|
+
# TODO better here
|
82
|
+
assert_nothing_raised do
|
83
|
+
@remote.file('/etc/hosts')
|
84
|
+
@remote.dir('/tmp')
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def teardown
|
90
|
+
# if the file is empty, we know we created it (or it doesn't matter)..
|
91
|
+
File.delete(@@user_sshkey) if File.file?(@@user_sshkey) and File.read(@@user_sshkey).eql?('')
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
data/test/functional/test_put.rb
CHANGED
@@ -17,9 +17,61 @@ class TestValidateFileFunctional < Test::Unit::TestCase
|
|
17
17
|
|
18
18
|
def test_negative_functional_fallthrough
|
19
19
|
|
20
|
-
assert_equal(false, @app.validate_file('/foo', {}, false, true))
|
21
|
-
assert_equal(false, @app.validate_file('/fizzy', { :ensure => 'directory' }, false, true))
|
22
|
-
assert_equal(false, @app.validate_file('/bang', { :ensure => 'file' }, false, true))
|
20
|
+
assert_equal(false, @app.validate_file('/foo', {}, false, true), 'when no expectation is specified, :ensure => present is assumed')
|
21
|
+
assert_equal(false, @app.validate_file('/fizzy', { :ensure => 'directory' }, false, true), 'standard DNE directory test')
|
22
|
+
assert_equal(false, @app.validate_file('/bang', { :ensure => 'file' }, false, true), '~standard DNE directory test')
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO tests
|
27
|
+
# :contains string
|
28
|
+
# :contains array
|
29
|
+
# :exists vs. :ensure -> what options are supported?
|
30
|
+
# :mode vs. :permissions
|
31
|
+
# :size
|
32
|
+
# :owner
|
33
|
+
# :group
|
34
|
+
# :constrain
|
35
|
+
|
36
|
+
|
37
|
+
def test_happy_basic
|
38
|
+
file = '/tmp/chiddy'
|
39
|
+
expectation = { :ensure => 'file' }
|
40
|
+
|
41
|
+
@app.run("touch #{file}")
|
42
|
+
|
43
|
+
assert_equal(true, @app.validate_file(file, expectation, false, true))
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_happy_doesnt_contain
|
48
|
+
file = '/etc/hosts'
|
49
|
+
expectations = {
|
50
|
+
:ensure => 'file',
|
51
|
+
:doesntcontain => 'fizzybang.12345',
|
52
|
+
:notcontains => 'this.isnt.there.either'
|
53
|
+
}
|
54
|
+
|
55
|
+
assert_equal(true, @app.validate_file(file, expectations, false, true))
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_happy_symlink
|
60
|
+
file = '/tmp/bang'
|
61
|
+
|
62
|
+
@app.run("ln -sf /etc/hosts #{file}")
|
63
|
+
|
64
|
+
expectations = [
|
65
|
+
{ :ensure => 'symlink' },
|
66
|
+
{ :ensure => 'link' },
|
67
|
+
{ :ensure => 'link', :target => '/etc/hosts' }
|
68
|
+
]
|
69
|
+
|
70
|
+
expectations.each do |e|
|
71
|
+
# this is a weird convention, maybe reconsider the calling signature for validate_file
|
72
|
+
# thinking something like validate_file(expectations) instead of validate_file(file, expectations)
|
73
|
+
assert_equal(true, @app.validate_file(file, e, false, true))
|
74
|
+
end
|
23
75
|
|
24
76
|
end
|
25
77
|
|
data/test/puppet/test_apply.rb
CHANGED
@@ -21,11 +21,13 @@ class TestPuppetApply < Test::Unit::TestCase
|
|
21
21
|
'test/puppet/modules/role/manifests/ui.pp' => 'modules/role/manifests/ui.pp',
|
22
22
|
}
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
['manifests/hieradata', 'modules/role/manifests'].each do |dir|
|
25
|
+
top = dir.split('/')[0]
|
26
|
+
|
27
|
+
@app.run("mkdir -p #{dir}")
|
28
|
+
@app.run("chown -R vagrant:vagrant #{top}") # because sudo=true, directories will be created with root:root
|
29
|
+
|
30
|
+
end
|
29
31
|
|
30
32
|
required_files.each_pair do |source,dest|
|
31
33
|
@app.put(source, dest)
|