rouster 0.41 → 0.42

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05f007fa8cb115a1889737b42c19eb6ab3a1029e
4
- data.tar.gz: c58f43def276534730ead0ffb636254805ce8080
3
+ metadata.gz: 5d74bfb451922e3b85675d75df8eab08adcbb8f1
4
+ data.tar.gz: 8e16766740fb82932308c8e9ca1ff44e2ece3c70
5
5
  SHA512:
6
- metadata.gz: 6465a1136c9506cb9f6fd7a7dd46d90eb39d30501ab7162d2f1635bad69a6cb349bfd45eb1d183f19abdd5e214cdca81cf02f6337fd2f7f72093bd343644f7d3
7
- data.tar.gz: 88f46d185da9d5f61193ca97651d0a16165c05e2b68871fbfb57dc6a219865054c60218682d90cb0bceaff48319b3511906570aec5597de678dd4e1a6ac0daab
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
- ### Easiest installation
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 Rouster-<version>.gem
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.41
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)
@@ -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
  #
@@ -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 = (! expectations[:ensure].eql?('file')) ? self.file(name, cache) : self.dir(name, cache)
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 = true
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
@@ -36,10 +36,8 @@
36
36
  assert_not_equal(original_uptime, new_uptime)
37
37
  assert(original_uptime > new_uptime)
38
38
 
39
-
40
39
  end
41
40
 
42
-
43
41
  def teardown
44
42
  # noop
45
43
  end
@@ -10,7 +10,7 @@ class TestGetPuppetStar < Test::Unit::TestCase
10
10
 
11
11
  def setup
12
12
  assert_nothing_raised do
13
- @app = Rouster.new(:name => 'app')
13
+ @app = Rouster.new(:name => 'app', :unittest => true)
14
14
  end
15
15
 
16
16
  # expose private methods
@@ -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
- # 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
66
- #assert(@app.validate_file('/etc/fizzbang', { :ensure => 'absent' }, true))
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
- #assert_equal(false, @app.validate_file('/foo', {}, true))
104
- #assert_equal(false, @app.validate_file('/fizzy', { :ensure => 'directory' }, true))
105
- #assert_equal(false, @app.validate_file('/bang', { :ensure => 'file' }, true))
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.41'
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-03 00:00:00.000000000 Z
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: []