rouster 0.5
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 +7 -0
- data/.gitignore +6 -0
- data/LICENSE +9 -0
- data/README.md +175 -0
- data/Rakefile +65 -0
- data/Vagrantfile +23 -0
- data/examples/bootstrap.rb +113 -0
- data/examples/demo.rb +71 -0
- data/examples/error.rb +30 -0
- data/lib/rouster.rb +737 -0
- data/lib/rouster/deltas.rb +481 -0
- data/lib/rouster/puppet.rb +398 -0
- data/lib/rouster/testing.rb +743 -0
- data/lib/rouster/tests.rb +596 -0
- data/path_helper.rb +21 -0
- data/rouster.gemspec +30 -0
- data/test/basic.rb +10 -0
- data/test/functional/deltas/test_get_crontab.rb +99 -0
- data/test/functional/deltas/test_get_groups.rb +48 -0
- data/test/functional/deltas/test_get_packages.rb +71 -0
- data/test/functional/deltas/test_get_ports.rb +119 -0
- data/test/functional/deltas/test_get_services.rb +43 -0
- data/test/functional/deltas/test_get_users.rb +45 -0
- data/test/functional/puppet/test_facter.rb +59 -0
- data/test/functional/test_caching.rb +124 -0
- data/test/functional/test_destroy.rb +51 -0
- data/test/functional/test_dirs.rb +88 -0
- data/test/functional/test_files.rb +64 -0
- data/test/functional/test_get.rb +76 -0
- data/test/functional/test_inspect.rb +31 -0
- data/test/functional/test_is_dir.rb +118 -0
- data/test/functional/test_is_file.rb +119 -0
- data/test/functional/test_new.rb +92 -0
- data/test/functional/test_put.rb +81 -0
- data/test/functional/test_rebuild.rb +49 -0
- data/test/functional/test_restart.rb +44 -0
- data/test/functional/test_run.rb +77 -0
- data/test/functional/test_status.rb +38 -0
- data/test/functional/test_suspend.rb +31 -0
- data/test/functional/test_up.rb +27 -0
- data/test/functional/test_validate_file.rb +30 -0
- data/test/puppet/manifests/default.pp +9 -0
- data/test/puppet/manifests/hiera.yaml +12 -0
- data/test/puppet/manifests/hieradata/common.json +3 -0
- data/test/puppet/manifests/hieradata/vagrant.json +3 -0
- data/test/puppet/manifests/manifest.pp +78 -0
- data/test/puppet/modules/role/manifests/ui.pp +5 -0
- data/test/puppet/test_apply.rb +149 -0
- data/test/puppet/test_roles.rb +186 -0
- data/test/tunnel_vs_scp.rb +41 -0
- data/test/unit/puppet/test_get_puppet_star.rb +68 -0
- data/test/unit/test_generate_unique_mac.rb +43 -0
- data/test/unit/test_new.rb +31 -0
- data/test/unit/test_parse_ls_string.rb +334 -0
- data/test/unit/test_traverse_up.rb +43 -0
- data/test/unit/testing/test_meets_constraint.rb +55 -0
- data/test/unit/testing/test_validate_file.rb +112 -0
- data/test/unit/testing/test_validate_group.rb +72 -0
- data/test/unit/testing/test_validate_package.rb +69 -0
- data/test/unit/testing/test_validate_port.rb +98 -0
- data/test/unit/testing/test_validate_service.rb +73 -0
- data/test/unit/testing/test_validate_user.rb +92 -0
- metadata +203 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'rouster/puppet'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
class TestRestart < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def setup
|
10
|
+
assert_nothing_raised do
|
11
|
+
@app = Rouster.new(:name => 'app', :verbosity => 4)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_happy_path
|
16
|
+
@app.up()
|
17
|
+
|
18
|
+
assert_equal(true, @app.is_available_via_ssh?)
|
19
|
+
sleep 10
|
20
|
+
original_uptime = @app.facter()['uptime_seconds'].to_i
|
21
|
+
|
22
|
+
assert_nothing_raised do
|
23
|
+
@app.restart()
|
24
|
+
end
|
25
|
+
|
26
|
+
count = 0
|
27
|
+
until @app.is_available_via_ssh?()
|
28
|
+
count += 1
|
29
|
+
break if count > 12 # wait up to 2 minutes
|
30
|
+
sleep 10
|
31
|
+
end
|
32
|
+
|
33
|
+
new_uptime = @app.facter(false)['uptime_seconds'].to_i
|
34
|
+
|
35
|
+
assert_not_equal(original_uptime, new_uptime)
|
36
|
+
assert(original_uptime > new_uptime)
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def teardown
|
41
|
+
# noop
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class TestRun < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@app = Rouster.new({:name => 'app', :verbose => 4})
|
10
|
+
@app_no_sudo = Rouster.new({:name => 'app', :verbose => 4, :sudo => false})
|
11
|
+
|
12
|
+
@app.up()
|
13
|
+
@app_no_sudo.up()
|
14
|
+
|
15
|
+
assert_equal(@app.is_available_via_ssh?, true, 'app is available via SSH')
|
16
|
+
assert_equal(@app.is_available_via_ssh?, true, 'app_no_sudo is available via SSH')
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_happy_path
|
20
|
+
|
21
|
+
assert_nothing_raised do
|
22
|
+
@app.run('ls -l')
|
23
|
+
end
|
24
|
+
|
25
|
+
assert_equal(0, @app.exitcode, 'got expected exit code')
|
26
|
+
assert_not_nil(@app.get_output(), 'output is populated')
|
27
|
+
assert_match(/^total\s\d/, @app.get_output(), 'output matches expectations')
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_bad_exit_codes
|
31
|
+
|
32
|
+
assert_raise Rouster::RemoteExecutionError do
|
33
|
+
@app.run('fizzbang')
|
34
|
+
end
|
35
|
+
|
36
|
+
assert_not_equal(0, @app.exitcode, 'got expected non-0 exit code')
|
37
|
+
assert_not_nil(@app.get_output(), 'output is populated')
|
38
|
+
assert_match(/fizzbang/, @app.get_output(), 'output matches expectations')
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_bad_custom_exit_codes
|
42
|
+
|
43
|
+
assert_raise Rouster::RemoteExecutionError do
|
44
|
+
@app.run('ls -l', 2)
|
45
|
+
end
|
46
|
+
|
47
|
+
assert_equal(0, @app.exitcode)
|
48
|
+
assert_not_nil(@app.get_output())
|
49
|
+
assert_match(/total/, @app.get_output())
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_sudo_enabled
|
53
|
+
|
54
|
+
assert_nothing_raised do
|
55
|
+
@app.run('ls -l /root')
|
56
|
+
end
|
57
|
+
|
58
|
+
assert_equal(0, @app.exitcode, 'got expected exit code')
|
59
|
+
assert_no_match(/Permission denied/i, @app.get_output(), 'output matches expectations 1of2')
|
60
|
+
assert_match(/^total\s\d/, @app.get_output(), 'output matches expectations 2of2')
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_sudo_disabled
|
64
|
+
|
65
|
+
assert_raise Rouster::RemoteExecutionError do
|
66
|
+
@app_no_sudo.run('ls -l /root')
|
67
|
+
end
|
68
|
+
|
69
|
+
assert_not_equal(0, @app_no_sudo.exitcode, 'got expected non-0 exit code')
|
70
|
+
assert_match(/Permission denied/i, @app_no_sudo.get_output(), 'output matches expectations')
|
71
|
+
end
|
72
|
+
|
73
|
+
def teardown
|
74
|
+
@app.suspend()
|
75
|
+
@app_no_sudo.suspend()
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class TestStatus < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
assert_nothing_raised do
|
10
|
+
@app = Rouster.new(:name => 'app')
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_1_destroyed
|
16
|
+
@app.destroy()
|
17
|
+
|
18
|
+
assert_equal('not created', @app.status())
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_2_upped
|
22
|
+
@app.up()
|
23
|
+
|
24
|
+
assert_equal('running', @app.status())
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_3_suspended
|
28
|
+
@app.up unless @app.status.eql?('running')
|
29
|
+
@app.suspend()
|
30
|
+
|
31
|
+
assert_equal('saved', @app.status())
|
32
|
+
end
|
33
|
+
|
34
|
+
def teardown
|
35
|
+
# noop
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class TestSuspend < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
assert_nothing_raised do
|
10
|
+
@app = Rouster.new(:name => 'app')
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_happy_path
|
16
|
+
@app.up()
|
17
|
+
|
18
|
+
assert_equal(true, @app.is_available_via_ssh?)
|
19
|
+
|
20
|
+
assert_nothing_raised do
|
21
|
+
@app.suspend()
|
22
|
+
end
|
23
|
+
|
24
|
+
assert_equal(false, @app.is_available_via_ssh?)
|
25
|
+
end
|
26
|
+
|
27
|
+
def teardown
|
28
|
+
# noop
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class TestUp < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
assert_nothing_raised do
|
10
|
+
@app = Rouster.new(:name => 'app')
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_happy_path
|
16
|
+
assert_nothing_raised do
|
17
|
+
@app.up()
|
18
|
+
end
|
19
|
+
|
20
|
+
assert_equal(true, @app.is_available_via_ssh?)
|
21
|
+
end
|
22
|
+
|
23
|
+
def teardown
|
24
|
+
# noop
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'rouster/puppet'
|
5
|
+
require 'rouster/testing'
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
class TestValidateFileFunctional < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
# expose private methods
|
12
|
+
Rouster.send(:public, *Rouster.private_instance_methods)
|
13
|
+
Rouster.send(:public, *Rouster.protected_instance_methods)
|
14
|
+
|
15
|
+
@app = Rouster.new(:name => 'app')
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_negative_functional_fallthrough
|
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))
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def teardown
|
27
|
+
# noop
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# == manifest.pp
|
2
|
+
|
3
|
+
node default {
|
4
|
+
include baseclass
|
5
|
+
}
|
6
|
+
node 'app.hsd1.ca.comcast.net' {
|
7
|
+
include app_role
|
8
|
+
}
|
9
|
+
|
10
|
+
node 'db' {
|
11
|
+
include db_role
|
12
|
+
}
|
13
|
+
|
14
|
+
notify { 'test':
|
15
|
+
message => 'this is a test',
|
16
|
+
}
|
17
|
+
|
18
|
+
class baseclass {
|
19
|
+
|
20
|
+
file { '/etc/passwd':
|
21
|
+
ensure => file,
|
22
|
+
owner => 'root',
|
23
|
+
group => 'root',
|
24
|
+
mode => '0644',
|
25
|
+
}
|
26
|
+
|
27
|
+
file { '/tmp/foo':
|
28
|
+
ensure => directory,
|
29
|
+
owner => 'root',
|
30
|
+
group => 'root',
|
31
|
+
}
|
32
|
+
|
33
|
+
package { ['puppet', 'facter'] :
|
34
|
+
ensure => installed,
|
35
|
+
}
|
36
|
+
|
37
|
+
}
|
38
|
+
|
39
|
+
class app_role {
|
40
|
+
|
41
|
+
package { 'rsync':
|
42
|
+
ensure => installed,
|
43
|
+
}
|
44
|
+
|
45
|
+
user { 'foo':
|
46
|
+
ensure => present,
|
47
|
+
groups => 'bar',
|
48
|
+
}
|
49
|
+
|
50
|
+
group { 'bar':
|
51
|
+
ensure => present,
|
52
|
+
before => User['foo'],
|
53
|
+
}
|
54
|
+
|
55
|
+
service { 'snmpd':
|
56
|
+
ensure => stopped,
|
57
|
+
}
|
58
|
+
|
59
|
+
}
|
60
|
+
|
61
|
+
class db_role {
|
62
|
+
|
63
|
+
package { 'httpd':
|
64
|
+
ensure => installed,
|
65
|
+
}
|
66
|
+
|
67
|
+
file { '/tmp/fizzy':
|
68
|
+
ensure => file,
|
69
|
+
content => 'this is a test',
|
70
|
+
owner => 'vagrant',
|
71
|
+
group => 'vagrant',
|
72
|
+
mode => '0444',
|
73
|
+
}
|
74
|
+
|
75
|
+
service { 'httpd':
|
76
|
+
ensure => running,
|
77
|
+
}
|
78
|
+
}
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
|
2
|
+
|
3
|
+
require 'rouster'
|
4
|
+
require 'rouster/puppet'
|
5
|
+
require 'rouster/testing'
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
class TestPuppetApply < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@app = Rouster.new(:name => 'app', :verbose => 1)
|
13
|
+
|
14
|
+
## TODO teach put() how to use -R (directories)
|
15
|
+
required_files = {
|
16
|
+
'test/puppet/manifests/default.pp' => 'manifests/default.pp',
|
17
|
+
'test/puppet/manifests/hiera.yaml' => 'manifests/hiera.yaml',
|
18
|
+
'test/puppet/manifests/manifest.pp' => 'manifests/manifest.pp',
|
19
|
+
'test/puppet/manifests/hieradata/common.json' => 'manifests/hieradata/common.json',
|
20
|
+
'test/puppet/manifests/hieradata/vagrant.json' => 'manifests/hieradata/vagrant.json',
|
21
|
+
'test/puppet/modules/role/manifests/ui.pp' => 'modules/role/manifests/ui.pp',
|
22
|
+
}
|
23
|
+
|
24
|
+
## TODO figure out a better pattern here -- scp tunnel is under 'vagrant' context, but dirs created with 'root'
|
25
|
+
@app.sudo = false
|
26
|
+
@app.run('mkdir -p manifests/hieradata')
|
27
|
+
@app.run('mkdir -p modules/role/manifests')
|
28
|
+
@app.sudo = true
|
29
|
+
|
30
|
+
required_files.each_pair do |source,dest|
|
31
|
+
@app.put(source, dest)
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_nothing_raised do
|
35
|
+
@app.run_puppet('masterless', {
|
36
|
+
:expected_exitcode => [0,2],
|
37
|
+
:hiera_config => 'manifests/hiera.yaml',
|
38
|
+
:manifest_file => 'manifests/manifest.pp',
|
39
|
+
:module_dir => 'modules/'
|
40
|
+
})
|
41
|
+
end
|
42
|
+
|
43
|
+
assert_match(/this is a test/, @app.get_output())
|
44
|
+
assert_match(/Finished catalog run in/, @app.get_output())
|
45
|
+
|
46
|
+
# define base here
|
47
|
+
@expected_packages = {
|
48
|
+
'puppet' => { :ensure => true },
|
49
|
+
'facter' => { :ensure => 'present' }
|
50
|
+
}
|
51
|
+
|
52
|
+
@expected_files = {
|
53
|
+
'/etc/passwd' => {
|
54
|
+
:contains => [ 'vagrant', 'root'],
|
55
|
+
:ensure => 'file',
|
56
|
+
:group => 'root',
|
57
|
+
:mode => '0644',
|
58
|
+
:owner => 'root'
|
59
|
+
},
|
60
|
+
|
61
|
+
'/tmp' => {
|
62
|
+
:ensure => 'directory',
|
63
|
+
:group => 'root',
|
64
|
+
:owner => 'root',
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
@expected_groups = {
|
69
|
+
'root' => { :ensure => 'true' }
|
70
|
+
}
|
71
|
+
|
72
|
+
@expected_services = Hash.new()
|
73
|
+
@expected_users = {
|
74
|
+
'root' => {
|
75
|
+
:ensure => 'present',
|
76
|
+
:group => 'root',
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_app
|
83
|
+
app_expected_packages = {
|
84
|
+
'rsync' => { :ensure => 'present' }
|
85
|
+
}.merge(@expected_packages)
|
86
|
+
|
87
|
+
app_expected_files = {
|
88
|
+
'/etc/hosts' => {
|
89
|
+
:contains => [ 'localhost', 'app' ],
|
90
|
+
:ensure => 'present',
|
91
|
+
:group => 'root',
|
92
|
+
:owner => 'root',
|
93
|
+
},
|
94
|
+
}.merge(@expected_files)
|
95
|
+
|
96
|
+
app_expected_groups = {
|
97
|
+
'vagrant' => {
|
98
|
+
:ensure => 'present',
|
99
|
+
}
|
100
|
+
}.merge(@expected_groups)
|
101
|
+
|
102
|
+
app_expected_services = {}.merge(@expected_services)
|
103
|
+
|
104
|
+
app_expected_users = {
|
105
|
+
'vagrant' => {
|
106
|
+
:ensure => 'present',
|
107
|
+
},
|
108
|
+
}.merge(@expected_users)
|
109
|
+
|
110
|
+
assert_nothing_raised do
|
111
|
+
@app.run_puppet('masterless', {
|
112
|
+
:expected_exitcode => [0,2],
|
113
|
+
:hiera_config => 'manifests/hiera.yaml',
|
114
|
+
:manifest_dir => 'manifests/',
|
115
|
+
:module_dir => 'modules/'
|
116
|
+
})
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
assert_match(/Finished catalog run in/, @app.get_output()) # this only examines the last manifest run
|
121
|
+
|
122
|
+
# manually specified testing
|
123
|
+
app_expected_files.each_pair do |f,e|
|
124
|
+
assert_equal(true, @app.validate_file(f,e), "file[#{f}] expectation[#{e}]")
|
125
|
+
end
|
126
|
+
|
127
|
+
app_expected_groups.each_pair do |g,e|
|
128
|
+
assert_equal(true, @app.validate_group(g,e), "group[#{g}] expectation[#{e}]")
|
129
|
+
end
|
130
|
+
|
131
|
+
app_expected_packages.each_pair do |p,e|
|
132
|
+
assert_equal(true, @app.validate_package(p, e), "package[#{p}] expectation[#{e}]")
|
133
|
+
end
|
134
|
+
|
135
|
+
app_expected_services.each_pair do |s,e|
|
136
|
+
assert_equal(true, @app.validate_service(s,e), "service[#{s}] expectation[#{e}]")
|
137
|
+
end
|
138
|
+
|
139
|
+
app_expected_users.each_pair do |u,e|
|
140
|
+
assert_equal(true, @app.validate_user(u,e), "user[#{u}] expectation[#{e}]")
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
def teardown
|
146
|
+
# noop
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|