rouster 0.41 → 0.42
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +9 -0
- data/README.md +11 -3
- data/lib/rouster.rb +6 -2
- data/lib/rouster/deltas.rb +85 -0
- data/lib/rouster/testing.rb +14 -3
- data/lib/rouster/tests.rb +10 -0
- data/rouster.gemspec +1 -0
- data/test/functional/deltas/test_get_crontab.rb +99 -0
- data/test/functional/test_restart.rb +0 -2
- data/test/{functional → unit}/puppet/test_get_puppet_star.rb +1 -1
- data/test/unit/testing/test_validate_file.rb +5 -6
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d74bfb451922e3b85675d75df8eab08adcbb8f1
|
4
|
+
data.tar.gz: 8e16766740fb82932308c8e9ca1ff44e2ece3c70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5149f6ecef16db649b445602383708dc7a2f39b30dc8475edf408286dbe4c60105828af134d1a177e1c5a960e5e4515786798fe31fff351c9c1de604af1847c
|
7
|
+
data.tar.gz: c4b51b717eab079455f3cac15eab60d93c49403b8efe59c1886b0f300e8231143110140d99d3f62bac439cd792768386a5ddbc541a3f2aaa402f3e937feecbc9
|
data/LICENSE
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Copyright (c) 2012, Salesforce.com, Inc.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
8
|
+
Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
9
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
CHANGED
@@ -22,23 +22,31 @@ The first implementation of Rouster was in Perl, called [Salesforce::Vagrant](ht
|
|
22
22
|
|
23
23
|
## Requirements
|
24
24
|
|
25
|
+
* [Ruby](http://rubylang.org), version 2.0+ (best attempt made to support 1.8.7 and 1.9.3 as well)
|
25
26
|
* [Vagrant](http://vagrantup.com), version 1.0.5+
|
26
|
-
* a usable Vagrantfile
|
27
27
|
|
28
28
|
Note: Vagrant itself requires VirtualBox or VMWare Fusion (1.0.3+)
|
29
29
|
|
30
30
|
Note: Rouster should work exactly the same on Windows as it does on \*nix and OSX (minus rouster/deltas.rb functionality, at least currently),
|
31
31
|
but no real testing has been done to confirm this. Please file issues as appropriate.
|
32
32
|
|
33
|
-
###
|
33
|
+
### From-source installation (latest)
|
34
34
|
|
35
35
|
```sh
|
36
36
|
git clone https://github.com/chorankates/rouster.git
|
37
37
|
cd rouster
|
38
38
|
rake buildgem
|
39
|
-
gem install
|
39
|
+
gem install rouster-<version>.gem
|
40
40
|
```
|
41
41
|
|
42
|
+
### pre-built gem installation (stable)
|
43
|
+
|
44
|
+
[RubyGems](http://rubygems.org/gems/rouster)
|
45
|
+
[![Gem Version](https://badge.fury.io/rb/rouster.png)](http://badge.fury.io/rb/rouster)
|
46
|
+
|
47
|
+
```sh
|
48
|
+
gem install rouster
|
49
|
+
```
|
42
50
|
|
43
51
|
## Using Rouster
|
44
52
|
|
data/lib/rouster.rb
CHANGED
@@ -11,7 +11,7 @@ require 'rouster/tests'
|
|
11
11
|
class Rouster
|
12
12
|
|
13
13
|
# sporadically updated version number
|
14
|
-
VERSION = 0.
|
14
|
+
VERSION = 0.42
|
15
15
|
|
16
16
|
# custom exceptions -- what else do we want them to include/do?
|
17
17
|
class FileTransferError < StandardError; end # thrown by get() and put()
|
@@ -22,7 +22,7 @@ class Rouster
|
|
22
22
|
class SSHConnectionError < StandardError; end # thrown by available_via_ssh() -- and potentially _run()
|
23
23
|
|
24
24
|
attr_accessor :facts, :sudo, :verbosity
|
25
|
-
attr_reader :cache, :cache_timeout, :deltas, :exitcode, :log, :name, :output, :passthrough, :sshkey, :vagrantfile
|
25
|
+
attr_reader :cache, :cache_timeout, :deltas, :exitcode, :log, :name, :output, :passthrough, :sshkey, :unittest, :vagrantfile
|
26
26
|
|
27
27
|
##
|
28
28
|
# initialize - object instantiation
|
@@ -42,6 +42,7 @@ class Rouster
|
|
42
42
|
@passthrough = opts[:passthrough].nil? ? false : opts[:passthrough]
|
43
43
|
@sshkey = opts[:sshkey]
|
44
44
|
@sshtunnel = opts[:sshtunnel].nil? ? true : opts[:sshtunnel]
|
45
|
+
@unittest = opts[:unittest].nil? ? false : opts[:unittest]
|
45
46
|
@vagrantfile = opts[:vagrantfile].nil? ? traverse_up(Dir.pwd, 'Vagrantfile', 5) : opts[:vagrantfile]
|
46
47
|
@verbosity = opts[:verbosity].is_a?(Integer) ? opts[:verbosity] : 4
|
47
48
|
|
@@ -75,6 +76,7 @@ class Rouster
|
|
75
76
|
end
|
76
77
|
|
77
78
|
raise InternalError.new() if @name.nil?
|
79
|
+
|
78
80
|
return if opts[:unittest].eql?(true) # quick return if we're a unit test
|
79
81
|
|
80
82
|
begin
|
@@ -83,6 +85,8 @@ class Rouster
|
|
83
85
|
raise InternalError.new()
|
84
86
|
end
|
85
87
|
|
88
|
+
## TODO ensure 'vagrant' is in path
|
89
|
+
|
86
90
|
@log.debug('SSH key discovery and viability tests..')
|
87
91
|
if @sshkey.nil?
|
88
92
|
if @passthrough.eql?(true)
|
data/lib/rouster/deltas.rb
CHANGED
@@ -7,6 +7,91 @@ require 'rouster/tests'
|
|
7
7
|
# TODO use @cache_timeout to invalidate data cached here
|
8
8
|
|
9
9
|
class Rouster
|
10
|
+
|
11
|
+
##
|
12
|
+
# get_crontab
|
13
|
+
#
|
14
|
+
# runs `crontab -l <user>` and parses output, returns hash:
|
15
|
+
# {
|
16
|
+
# user => {
|
17
|
+
# logicalOrderInt => {
|
18
|
+
# :minute => minute,
|
19
|
+
# :hour => hour,
|
20
|
+
# :dom => dom, # day of month
|
21
|
+
# :mon => mon, # month
|
22
|
+
# :dow => dow, # day of week
|
23
|
+
# :command => command,
|
24
|
+
# }
|
25
|
+
# }
|
26
|
+
# }
|
27
|
+
#
|
28
|
+
# the hash will contain integers (not strings) for numerical values -- all but '*'
|
29
|
+
#
|
30
|
+
# parameters
|
31
|
+
# * <user> - name of user who owns crontab for examination -- or '*' to determine list of users and iterate over them to find all cron jobs
|
32
|
+
# * [cache] - boolean controlling whether or not retrieved/parsed data is cached, defaults to true
|
33
|
+
def get_crontab(user='root', cache=true)
|
34
|
+
|
35
|
+
if cache and self.deltas[:crontab].class.eql?(Hash)
|
36
|
+
if self.deltas[:crontab].has_key?(user)
|
37
|
+
return self.deltas[:crontab][user]
|
38
|
+
else
|
39
|
+
# noop fallthrough to gather data to cache
|
40
|
+
end
|
41
|
+
elsif cache and self.deltas[:crontab].class.eql?(Hash) and user.eql?('*')
|
42
|
+
return self.deltas[:crontab]
|
43
|
+
end
|
44
|
+
|
45
|
+
i = 0
|
46
|
+
res = Hash.new
|
47
|
+
users = nil
|
48
|
+
|
49
|
+
if user.eql?('*')
|
50
|
+
users = self.get_users().keys
|
51
|
+
else
|
52
|
+
users = [user]
|
53
|
+
end
|
54
|
+
|
55
|
+
users.each do |u|
|
56
|
+
begin
|
57
|
+
raw = self.run(sprintf('crontab -u %s -l', u))
|
58
|
+
rescue RemoteExecutionError => e
|
59
|
+
# crontab throws a non-0 exit code if there is no crontab for the specified user
|
60
|
+
res[u] ||= Hash.new
|
61
|
+
next
|
62
|
+
end
|
63
|
+
|
64
|
+
raw.split("\n").each do |line|
|
65
|
+
elements = line.split("\s")
|
66
|
+
|
67
|
+
res[u] ||= Hash.new
|
68
|
+
res[u][i] ||= Hash.new
|
69
|
+
|
70
|
+
res[u][i][:minute] = elements[0]
|
71
|
+
res[u][i][:hour] = elements[1]
|
72
|
+
res[u][i][:dom] = elements[2]
|
73
|
+
res[u][i][:mon] = elements[3]
|
74
|
+
res[u][i][:dow] = elements[4]
|
75
|
+
res[u][i][:command] = elements[5..elements.size].join(" ")
|
76
|
+
end
|
77
|
+
|
78
|
+
i += 1
|
79
|
+
end
|
80
|
+
|
81
|
+
if cache
|
82
|
+
if ! user.eql?('*')
|
83
|
+
self.deltas[:crontab] ||= Hash.new
|
84
|
+
self.deltas[:crontab][user] ||= Hash.new
|
85
|
+
self.deltas[:crontab][user] = res[user]
|
86
|
+
else
|
87
|
+
self.deltas[:crontab] ||= Hash.new
|
88
|
+
self.deltas[:crontab] = res
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
return user.eql?('*') ? res : res[user]
|
93
|
+
end
|
94
|
+
|
10
95
|
##
|
11
96
|
# get_groups
|
12
97
|
#
|
data/lib/rouster/testing.rb
CHANGED
@@ -48,7 +48,7 @@ class Rouster
|
|
48
48
|
# * :constrain
|
49
49
|
def validate_file(name, expectations, cache=false)
|
50
50
|
|
51
|
-
if expectations[:ensure].nil? and expectations[:exists].nil?
|
51
|
+
if expectations[:ensure].nil? and expectations[:exists].nil? and expectations[:directory].nil? and expectations[:file?].nil?
|
52
52
|
expectations[:ensure] = 'file'
|
53
53
|
end
|
54
54
|
|
@@ -66,7 +66,7 @@ class Rouster
|
|
66
66
|
expectations.delete(:constrain)
|
67
67
|
end
|
68
68
|
|
69
|
-
properties = (
|
69
|
+
properties = (expectations[:ensure].eql?('file')) ? self.file(name, cache) : self.dir(name, cache)
|
70
70
|
results = Hash.new()
|
71
71
|
local = nil
|
72
72
|
|
@@ -109,7 +109,7 @@ class Rouster
|
|
109
109
|
if properties[:directory?]
|
110
110
|
local = v.to_s.match(/absent|false/).nil?
|
111
111
|
else
|
112
|
-
local =
|
112
|
+
local = ! v.to_s.match(/absent|false/).nil?
|
113
113
|
end
|
114
114
|
else
|
115
115
|
local = false
|
@@ -557,6 +557,17 @@ class Rouster
|
|
557
557
|
res
|
558
558
|
end
|
559
559
|
|
560
|
+
##
|
561
|
+
# generic_comparator
|
562
|
+
#
|
563
|
+
# powers the 3 argument form of constraint (i.e. 'is_virtual != true', '<package_version> > 3.0', etc)
|
564
|
+
#
|
565
|
+
# should really be an eval{} of some sort (or would be in the perl world)
|
566
|
+
#
|
567
|
+
# parameters
|
568
|
+
# * <comparand1> - left side of the comparison
|
569
|
+
# * <comparator> - comparison to make
|
570
|
+
# * <comparand2> - right side of the comparison
|
560
571
|
def generic_comparator(comparand1, comparator, comparand2)
|
561
572
|
|
562
573
|
# TODO rewrite this as an eval so we don't have to support everything..
|
data/lib/rouster/tests.rb
CHANGED
@@ -30,6 +30,11 @@ class Rouster
|
|
30
30
|
return self.deltas[:files][dir]
|
31
31
|
end
|
32
32
|
|
33
|
+
if self.unittest and cache
|
34
|
+
# preventing a functional test fallthrough
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
33
38
|
begin
|
34
39
|
raw = self.run(sprintf('ls -ld %s', dir))
|
35
40
|
rescue Rouster::RemoteExecutionError
|
@@ -104,6 +109,11 @@ class Rouster
|
|
104
109
|
return self.deltas[:files][file]
|
105
110
|
end
|
106
111
|
|
112
|
+
if self.unittest and cache
|
113
|
+
# preventing a functional test fallthrough
|
114
|
+
return nil
|
115
|
+
end
|
116
|
+
|
107
117
|
begin
|
108
118
|
raw = self.run(sprintf('ls -l %s', file))
|
109
119
|
rescue Rouster::RemoteExecutionError
|
data/rouster.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.homepage = 'http://github.com/chorankates/rouster'
|
13
13
|
s.summary = 'Rouster is an abstraction layer for Vagrant'
|
14
14
|
s.description = 'Rouster allows you to programmatically control and interact with your existing Vagrant virtual machines'
|
15
|
+
s.license = 'BSD 3-Clause'
|
15
16
|
|
16
17
|
s.required_rubygems_version = '>= 1.3.6'
|
17
18
|
s.rubyforge_project = 'Rouster'
|
@@ -0,0 +1,99 @@
|
|
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')
|
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 teardown
|
96
|
+
@app = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -62,9 +62,8 @@ class TestValidateFile < Test::Unit::TestCase
|
|
62
62
|
assert(@app.validate_file('/etc/hosts', { :owner => 'root' }, true))
|
63
63
|
assert(@app.validate_file('/etc/hosts', { :group => 'root' }, true))
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
#assert(@app.validate_file('/etc/fizzbang', { :ensure => false }, true ))
|
65
|
+
assert(@app.validate_file('/etc/fizzbang', { :ensure => 'absent' }, true))
|
66
|
+
assert(@app.validate_file('/etc/fizzbang', { :ensure => false }, true ))
|
68
67
|
|
69
68
|
assert(@app.validate_file('/etc', { :ensure => 'directory' }, true))
|
70
69
|
assert(@app.validate_file('/etc', { :ensure => 'dir' }, true))
|
@@ -100,9 +99,9 @@ class TestValidateFile < Test::Unit::TestCase
|
|
100
99
|
assert_equal(false, @app.validate_file('/etc/hosts', { :size => '100'}, true))
|
101
100
|
|
102
101
|
# TODO figure out how to run these in a truly unit-y way, since the data is not present in faked hash, we will fall through to functional testing
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
assert_equal(false, @app.validate_file('/foo', {}, true))
|
103
|
+
assert_equal(false, @app.validate_file('/fizzy', { :ensure => 'directory' }, true))
|
104
|
+
assert_equal(false, @app.validate_file('/bang', { :ensure => 'file' }, true))
|
106
105
|
|
107
106
|
end
|
108
107
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rouster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.42'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Conor Horan-Kates
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -102,6 +102,7 @@ extensions: []
|
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
104
|
- .gitignore
|
105
|
+
- LICENSE
|
105
106
|
- README.md
|
106
107
|
- Rakefile
|
107
108
|
- Vagrantfile
|
@@ -116,13 +117,13 @@ files:
|
|
116
117
|
- path_helper.rb
|
117
118
|
- rouster.gemspec
|
118
119
|
- test/basic.rb
|
120
|
+
- test/functional/deltas/test_get_crontab.rb
|
119
121
|
- test/functional/deltas/test_get_groups.rb
|
120
122
|
- test/functional/deltas/test_get_packages.rb
|
121
123
|
- test/functional/deltas/test_get_ports.rb
|
122
124
|
- test/functional/deltas/test_get_services.rb
|
123
125
|
- test/functional/deltas/test_get_users.rb
|
124
126
|
- test/functional/puppet/test_facter.rb
|
125
|
-
- test/functional/puppet/test_get_puppet_star.rb
|
126
127
|
- test/functional/test_caching.rb
|
127
128
|
- test/functional/test_destroy.rb
|
128
129
|
- test/functional/test_dirs.rb
|
@@ -148,6 +149,7 @@ files:
|
|
148
149
|
- test/puppet/test_apply.rb
|
149
150
|
- test/puppet/test_roles.rb
|
150
151
|
- test/tunnel_vs_scp.rb
|
152
|
+
- test/unit/puppet/test_get_puppet_star.rb
|
151
153
|
- test/unit/test_generate_unique_mac.rb
|
152
154
|
- test/unit/test_new.rb
|
153
155
|
- test/unit/test_parse_ls_string.rb
|
@@ -159,7 +161,8 @@ files:
|
|
159
161
|
- test/unit/testing/test_validate_service.rb
|
160
162
|
- test/unit/testing/test_validate_user.rb
|
161
163
|
homepage: http://github.com/chorankates/rouster
|
162
|
-
licenses:
|
164
|
+
licenses:
|
165
|
+
- BSD 3-Clause
|
163
166
|
metadata: {}
|
164
167
|
post_install_message:
|
165
168
|
rdoc_options: []
|