rouster 0.7 → 0.41

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/README.md +7 -241
  4. data/Rakefile +18 -55
  5. data/Vagrantfile +8 -26
  6. data/lib/rouster.rb +183 -404
  7. data/lib/rouster/deltas.rb +118 -577
  8. data/lib/rouster/puppet.rb +34 -209
  9. data/lib/rouster/testing.rb +59 -366
  10. data/lib/rouster/tests.rb +19 -70
  11. data/path_helper.rb +7 -5
  12. data/rouster.gemspec +1 -3
  13. data/test/basic.rb +1 -4
  14. data/test/functional/deltas/test_get_groups.rb +2 -74
  15. data/test/functional/deltas/test_get_packages.rb +4 -86
  16. data/test/functional/deltas/test_get_ports.rb +1 -26
  17. data/test/functional/deltas/test_get_services.rb +4 -43
  18. data/test/functional/deltas/test_get_users.rb +2 -35
  19. data/test/functional/puppet/test_facter.rb +1 -41
  20. data/test/functional/puppet/test_get_puppet_star.rb +68 -0
  21. data/test/functional/test_caching.rb +1 -5
  22. data/test/functional/test_dirs.rb +0 -25
  23. data/test/functional/test_get.rb +6 -10
  24. data/test/functional/test_inspect.rb +1 -1
  25. data/test/functional/test_is_file.rb +1 -17
  26. data/test/functional/test_new.rb +22 -233
  27. data/test/functional/test_put.rb +11 -9
  28. data/test/functional/test_restart.rb +4 -1
  29. data/test/functional/test_run.rb +3 -2
  30. data/test/puppet/test_apply.rb +11 -13
  31. data/test/puppet/test_roles.rb +173 -0
  32. data/test/unit/test_new.rb +0 -88
  33. data/test/unit/test_parse_ls_string.rb +0 -67
  34. data/test/unit/testing/test_validate_file.rb +47 -39
  35. data/test/unit/testing/test_validate_package.rb +10 -36
  36. metadata +6 -46
  37. data/.reek +0 -63
  38. data/.travis.yml +0 -11
  39. data/Gemfile +0 -17
  40. data/Gemfile.lock +0 -102
  41. data/LICENSE +0 -9
  42. data/examples/aws.rb +0 -85
  43. data/examples/openstack.rb +0 -61
  44. data/examples/passthrough.rb +0 -71
  45. data/lib/rouster/vagrant.rb +0 -311
  46. data/plugins/aws.rb +0 -347
  47. data/plugins/openstack.rb +0 -136
  48. data/test/functional/deltas/test_get_crontab.rb +0 -161
  49. data/test/functional/deltas/test_get_os.rb +0 -68
  50. data/test/functional/test_is_in_file.rb +0 -40
  51. data/test/functional/test_passthroughs.rb +0 -94
  52. data/test/functional/test_validate_file.rb +0 -131
  53. data/test/unit/puppet/resources/puppet_run_with_failed_exec +0 -59
  54. data/test/unit/puppet/resources/puppet_run_with_successful_exec +0 -61
  55. data/test/unit/puppet/test_get_puppet_star.rb +0 -91
  56. data/test/unit/puppet/test_puppet_parsing.rb +0 -44
  57. data/test/unit/testing/resources/osx-launchd +0 -285
  58. data/test/unit/testing/resources/rhel-systemd +0 -46
  59. data/test/unit/testing/resources/rhel-systemv +0 -41
  60. data/test/unit/testing/resources/rhel-upstart +0 -20
  61. data/test/unit/testing/test_get_services.rb +0 -178
  62. data/test/unit/testing/test_validate_cron.rb +0 -78
  63. data/test/unit/testing/test_validate_port.rb +0 -103
data/plugins/openstack.rb DELETED
@@ -1,136 +0,0 @@
1
- #!/usr/bin/ruby
2
- ## plugins/openstack.rb - provide helper functions for Rouster objects running on OpenStack/Compute
3
-
4
- require sprintf('%s/../%s', File.dirname(File.expand_path(__FILE__)), 'path_helper')
5
-
6
- require 'fog'
7
- require 'uri'
8
-
9
- class Rouster
10
-
11
- attr_reader :nova # expose OpenStack workers
12
- attr_reader :instance_data # the result of the runInstances request
13
-
14
- # return a hash containing meta-data items
15
- def ostack_get_instance_id ()
16
- # The instance id is kept in @passthrough[:instance] or
17
- # can be obtained from @instance_data which has all instance
18
- # details.
19
- if ! @instance_data.nil? and ! @instance_data.id.nil?
20
- return @instance_data.id # we already know the id
21
- elsif @passthrough.has_key?(:instance)
22
- return @passthrough[:instance] # we know the id we want
23
- else
24
- @logger.debug(sprintf('unable to determine id from instance_data[%s] or passthrough specification[%s]', @instance_data, @passthrough))
25
- return nil # we don't have an id yet, likely a up() call
26
- end
27
- end
28
-
29
- def ostack_up
30
- # wait for machine to transition to running state and become sshable (TODO maybe make the second half optional)
31
- self.ostack_connect
32
- # This will check if instance_id has been provided. If so, it will check on status of the instance.
33
- status = self.status()
34
- if status.eql?('running')
35
- self.passthrough[:instance] = self.ostack_get_instance_id
36
- @logger.debug(sprintf('Connecting to running instance [%s] while calling ostack_up()', self.passthrough[:instance]))
37
- self.connect_ssh_tunnel
38
- else
39
- server = @nova.servers.create(:name => @name, :flavor_ref => @passthrough[:flavor_ref],
40
- :image_ref => @passthrough[:image_ref], :key_name => @passthrough[:keypair], :user_data => @passthrough[:user_data])
41
- server.wait_for { ready? }
42
- @instance_data = server
43
- server.addresses.each_key do |address_key|
44
- if defined?(server.addresses[address_key])
45
- self.passthrough[:host] = server.addresses[address_key].first['addr']
46
- break
47
- end
48
- end
49
- self.passthrough[:instance] = self.ostack_get_instance_id
50
- @logger.debug(sprintf('Connecting to running instance [%s] while calling ostack_up()', self.passthrough[:instance]))
51
- self.connect_ssh_tunnel
52
- end
53
- self.passthrough[:instance]
54
- end
55
-
56
- def ostack_get_ip()
57
- self.passthrough[:host]
58
- end
59
-
60
- def ostack_destroy
61
- server = self.ostack_describe_instance
62
- raise sprintf("instance[%s] not found by destroy()", self.ostack_get_instance_id) if server.nil?
63
- server.destroy
64
- @instance_data = nil
65
- self.passthrough.delete(:instance)
66
- end
67
-
68
- def ostack_describe_instance(instance_id = ostack_get_instance_id)
69
-
70
- if @cache_timeout
71
- if @cache.has_key?(:ostack_describe_instance)
72
- if (Time.now.to_i - @cache[:ostack_describe_instance][:time]) < @cache_timeout
73
- @logger.debug(sprintf('using cached ostack_describe_instance?[%s] from [%s]', @cache[:ostack_describe_instance][:instance], @cache[:ostack_describe_instance][:time]))
74
- return @cache[:ostack_describe_instance][:instance]
75
- end
76
- end
77
- end
78
- # We don't have a instance.
79
- return nil if instance_id.nil?
80
- self.ostack_connect
81
- response = @nova.servers.get(instance_id)
82
- return nil if response.nil?
83
- @instance_data = response
84
-
85
- if @cache_timeout
86
- @cache[:ostack_describe_instance] = Hash.new unless @cache[:ostack_describe_instance].class.eql?(Hash)
87
- @cache[:ostack_describe_instance][:time] = Time.now.to_i
88
- @cache[:ostack_describe_instance][:instance] = response
89
- @logger.debug(sprintf('caching is_available_via_ssh?[%s] at [%s]', @cache[:ostack_describe_instance][:instance], @cache[:ostack_describe_instance][:time]))
90
- end
91
-
92
- @instance_data
93
- end
94
-
95
- def ostack_status
96
- self.ostack_describe_instance
97
- return 'not-created' if @instance_data.nil?
98
- if @instance_data.state.eql?('ACTIVE')
99
- # Make this consistent with AWS response.
100
- return 'running'
101
- else
102
- return @instance_data.state
103
- end
104
- end
105
-
106
-
107
- # TODO this will throw at the first error - should we catch?
108
- # run some commands, return an array of the output
109
- def ostack_bootstrap (commands)
110
- self.ostack_connect
111
- commands = (commands.is_a?(Array)) ? commands : [ commands ]
112
- output = Array.new
113
-
114
- commands.each do |command|
115
- output << self.run(command)
116
- end
117
-
118
- return output
119
- end
120
-
121
- def ostack_connect
122
- # Instantiates an Object which can communicate with OS Compute.
123
- # No instance specific information is set at this time.
124
- return @nova unless @nova.nil?
125
-
126
- config = {
127
- :provider => 'openstack', # OpenStack Fog provider
128
- :openstack_auth_url => self.passthrough[:openstack_auth_url], # OpenStack Keystone endpoint
129
- :openstack_username => self.passthrough[:openstack_username], # Your OpenStack Username
130
- :openstack_tenant => self.passthrough[:openstack_tenant], # Your tenant id
131
- :openstack_api_key => self.passthrough[:openstack_api_key], # Your OpenStack Password
132
- :connection_options => self.passthrough[:connection_options] # Optional
133
- }
134
- @nova = Fog::Compute.new(config)
135
- end
136
- end
@@ -1,161 +0,0 @@
1
- require sprintf('%s/../../../path_helper', File.dirname(File.expand_path(__FILE__)))
2
-
3
- require 'rouster'
4
- require 'rouster/deltas'
5
- require 'test/unit'
6
-
7
- class TestDeltasGetCrontab < Test::Unit::TestCase
8
-
9
- def setup
10
- assert_nothing_raised do
11
- @app = Rouster.new(:name => 'app', :cache_timeout => 20)
12
- end
13
-
14
- @app.up()
15
-
16
- ## setup some cronjobs so we have something to look at - and yes, this is hacktastic
17
- ['root', 'puppet'].each do | user|
18
- tmp = sprintf('/tmp/rouster.tmp.crontab.%s.%s.%s', user, Time.now.to_i, $$)
19
- @app.run("echo '0 0 * * * echo #{user}' > #{tmp}")
20
- #@app.run("crontab -u #{user} -f #{tmp}") # rhel
21
- @app.run("crontab -u #{user} #{tmp}") # centos
22
- end
23
-
24
- end
25
-
26
- def test_happy_path
27
-
28
- res = nil
29
-
30
- assert_nothing_raised do
31
- res = @app.get_crontab()
32
- end
33
-
34
- assert_equal(Hash, res.class)
35
- assert_equal(res, @app.deltas[:crontab]['root'])
36
- assert_not_nil(@app.deltas[:crontab]['root'])
37
-
38
- end
39
-
40
- def test_happy_path_specified_user
41
-
42
- res = nil
43
-
44
- assert_nothing_raised do
45
- res = @app.get_crontab('puppet')
46
- end
47
-
48
- assert_equal(Hash, res.class)
49
- assert_equal(res, @app.deltas[:crontab]['puppet'])
50
- assert_not_nil(@app.deltas[:crontab]['puppet'])
51
-
52
- end
53
-
54
- def test_happy_path_specified_star
55
-
56
- res = nil
57
-
58
- assert_nothing_raised do
59
- res = @app.get_crontab('*')
60
- end
61
-
62
- assert_equal(Hash, res.class)
63
- assert_equal(res, @app.deltas[:crontab])
64
- assert_not_nil(@app.deltas[:crontab]['root'])
65
- assert_not_nil(@app.deltas[:crontab]['puppet'])
66
-
67
- end
68
-
69
- def test_unhappy_path_non_existent_user
70
-
71
- res = nil
72
-
73
- assert_nothing_raised do
74
- res = @app.get_crontab('fizzybang')
75
- end
76
-
77
- assert_equal(Hash, res.class)
78
- assert_equal(0, res.keys.size)
79
-
80
- end
81
-
82
- def test_happy_path_no_cache
83
-
84
- res = nil
85
-
86
- assert_nothing_raised do
87
- res = @app.get_crontab('root', false)
88
- end
89
-
90
- assert_equal(Hash, res.class)
91
- assert_nil(@app.deltas[:crontab])
92
-
93
- end
94
-
95
- def test_happy_path_cache_invalidated
96
-
97
- res1, res2 = nil, nil
98
-
99
- assert_nothing_raised do
100
- res1 = @app.get_crontab('root', true)
101
- end
102
-
103
- first_cache_time = @app.cache[:crontab]
104
-
105
- sleep (@app.cache_timeout + 1)
106
-
107
- assert_nothing_raised do
108
- res2 = @app.get_crontab('root', true)
109
- end
110
-
111
- second_cache_time = @app.cache[:crontab]
112
-
113
- assert_equal(res1, res2)
114
- assert_not_equal(first_cache_time, second_cache_time)
115
-
116
- end
117
-
118
- def test_unhappy_duplicate_entries
119
-
120
- res = nil
121
-
122
- # do this in a saner way? crontab call is overwriting existing records
123
- user = 'puppet'
124
- tmp = sprintf('/tmp/rouster.tmp.crontab.%s.%s.%s', user, Time.now.to_i, $$)
125
- @app.run("echo '0 0 * * * echo #{user}' > #{tmp}")
126
- @app.run("echo '5 5 * * * echo #{user}' >> #{tmp}")
127
- @app.run("crontab -u #{user} #{tmp}")
128
-
129
- assert_nothing_raised do
130
- res = @app.get_crontab(user)
131
- end
132
-
133
- assert_equal(Hash, res.class)
134
- assert(res.has_key?('echo puppet'))
135
- assert(res.has_key?('echo puppet-duplicate.55***echopuppet'))
136
-
137
- end
138
-
139
- def test_non_matching_lines
140
- res = nil
141
- user = 'root'
142
- tmp = sprintf('/tmp/rouster.tmp.crontab.%s.%s.%s', user, Time.now.to_i, $$)
143
-
144
- @app.run("echo 'PATH=/sbin:/usr/bin:/usr/local/bin' > #{tmp}")
145
- @app.run("echo '5 5 * * * echo #{user}' >> #{tmp}")
146
- @app.run("crontab -u #{user} #{tmp}")
147
-
148
- assert_nothing_raised do
149
- res = @app.get_crontab(user, false)
150
- end
151
-
152
- assert_equal(Hash, res.class)
153
- assert(res.has_key?('echo root'))
154
-
155
- end
156
-
157
- def teardown
158
- @app = nil
159
- end
160
-
161
- end
@@ -1,68 +0,0 @@
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 teardown
19
- # put the flag file back in place
20
- Rouster.os_files.each_pair do |_os, ff|
21
- [ ff ].flatten.each do |f|
22
- bkup = sprintf('%s.bkup', f)
23
- if @app.is_file?(bkup)
24
- @app.run(sprintf('mv %s %s', bkup, f))
25
- end
26
- end
27
- end
28
- end
29
-
30
- def test_happy_path
31
-
32
- type = @app.os_type
33
- assert_not_nil(type, sprintf('unable to determine vm[%s] OS', @app))
34
- assert_not_equal(:invalid, type)
35
-
36
- version = @app.os_version(type)
37
- assert_not_nil(version, sprintf('unable to determine vm[%s] OS version', @app))
38
- assert_not_equal(:invalid, version)
39
-
40
- assert_nothing_raised do
41
- @app.get_services
42
- end
43
-
44
- end
45
-
46
- def test_unhappy_path
47
- # move the flag file out of the way
48
- Rouster.os_files.each_pair do |_os, ff|
49
- [ ff ].flatten.each do |f|
50
- if @app.is_file?(ff)
51
- @app.run(sprintf('mv %s %s.bkup', f, f))
52
- end
53
- end
54
- end
55
-
56
- type = @app.os_type
57
-
58
- assert_equal(:invalid, type, sprintf('got wrong value for unmarked OS[%s]', type))
59
-
60
- e = assert_raise do
61
- @app.get_services
62
- end
63
-
64
- assert_equal(Rouster::InternalError, e.class, sprintf('wrong exception raised[%s] [%s]', e.class, e.message))
65
-
66
- end
67
-
68
- end
@@ -1,40 +0,0 @@
1
- require sprintf('%s/../../path_helper', File.dirname(File.expand_path(__FILE__)))
2
-
3
- require 'rouster'
4
- require 'rouster/tests'
5
- require 'test/unit'
6
-
7
- class TestIsInFile < Test::Unit::TestCase
8
-
9
- SHIBBOLETH = 'foobar'
10
-
11
- def setup
12
- assert_nothing_raised do
13
- # no reason not to do this as a passthrough once we can
14
- @app = Rouster.new(:name => 'app', :sudo => false)
15
- @app.up()
16
- end
17
-
18
- # create some temporary files
19
- @dir_tmp = sprintf('/tmp/rouster-%s.%s', $$, Time.now.to_i)
20
- @app.run(sprintf('mkdir %s', @dir_tmp))
21
-
22
- @file = sprintf('%s/file', @dir_tmp)
23
- @app.run(sprintf('echo "%s" >> %s', SHIBBOLETH, @file))
24
- end
25
-
26
- def teardown; end
27
-
28
- def test_positive
29
-
30
- assert_equal(true, @app.is_in_file?(@file, SHIBBOLETH))
31
-
32
- end
33
-
34
- def test_negative
35
-
36
- assert_equal(false, @app.is_in_file?(@file, 'fizzbuzz'))
37
-
38
- end
39
-
40
- end
@@ -1,94 +0,0 @@
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_equal(false, @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
- omit('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} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null #{host} exit`
61
- omit("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