rouster 0.61 → 0.62

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d37f795615a19e7523b738d759e48f3e61fdc81c
4
- data.tar.gz: 898b4400f00d4675061d9dd5e0716fc9a7ec21ce
3
+ metadata.gz: 8bce9804eb72b059c106b689793f06a26a55dcdb
4
+ data.tar.gz: 278dadb5f13e14a71ea84adecc751989f74ee810
5
5
  SHA512:
6
- metadata.gz: 7442ac64dc582dbc03be7aaecc9f481ca7f9d1d0c43608faab5ea3f947ae4a696a0ab1c6d2467223b289e09faa762adfbdd24db8e2d5f8949f174f35922a73d4
7
- data.tar.gz: 13e407ab375276b8bf8c2054008668d2471e2be685224b3da62424cd6d92ff83ee3ceddadb6e0388db7df715d5ea654753dece45c374d2ce2348b302f3a26c4e
6
+ metadata.gz: ae9a583d9d11112ada1f3a17295f41f6d8d5563af4e389af2b1a090f9327a6b5441929199d205bcca341b770e68128cf0514ed7953b154f861651e5d0ab6067e
7
+ data.tar.gz: 2f012c9ca78fb82ff64c079ad5e262b77203021e74de3d0e20a1444a20d62633ba7119dbd962b57577fba4f77896930199cd61ba76e9555b85ec1787418fcc23
data/README.md CHANGED
@@ -29,7 +29,7 @@ The first implementation of Rouster was in Perl, called [Salesforce::Vagrant](ht
29
29
  * log4r
30
30
  * net-scp
31
31
  * net-ssh
32
- * fog (only if using AWS)
32
+ * fog (only if using AWS or OpenStack)
33
33
 
34
34
  Note: Rouster should work exactly the same on Windows as it does on \*nix and OSX (minus rouster/deltas.rb functionality, at least currently),
35
35
  but no real testing has been done to confirm this. Please file issues as appropriate.
@@ -149,13 +149,14 @@ app.destroy()
149
149
 
150
150
  ### advanced instantiation (passthroughs!)
151
151
 
152
- detailed options in ```examples/passthrough.rb``` and ```examples/aws.rb```
152
+ detailed options in ```examples/passthrough.rb```, ```examples/aws.rb``` and ```examples/openstack.rb```
153
153
 
154
154
  since Rouster only requires an SSH connection to control a machine, why stop at Vagrant?
155
155
 
156
156
  ```rb
157
157
  require 'rouster'
158
158
  require 'rouster/plugins/aws'
159
+ require 'rouster/plugins/openstack'
159
160
 
160
161
  # control the machine rouster itself is running on
161
162
  local = Rouster.new(:name => 'local', :passthrough => { :type => :local } }
@@ -195,6 +196,38 @@ aws_start_me_up = Rouster.new(
195
196
  }
196
197
  )
197
198
 
199
+ # create a remote OpenStack instance
200
+ ostack = Rouster.new(
201
+ :name => 'ostack-testing',
202
+ :passthrough => {
203
+ :type => :openstack,
204
+ :openstack_auth_url => 'http://hostname.domain.com:5000/v2.0/tokens',
205
+ :openstack_username => 'some_console_user',
206
+ :openstack_tenant => 'tenant_id',
207
+ :user => 'some_ssh_userid',
208
+ :keypair => 'keypair_name',
209
+ :image_ref => 'c0340afb-577d-4db6-1234-aebdd6d1838f',
210
+ :flavor_ref => '547d9af5-096c-44a3-1234-7d23162556b8',
211
+ :openstack_api_key => 'some_api_key',
212
+ :key => '/path/to/private/key.pem',
213
+ },
214
+ :sudo => true, # false by default, enabling requires that sshd is not enforcing 'requiretty'
215
+ )
216
+
217
+ # control a running OpenStack instance
218
+ openstack_already_running = Rouster.new(
219
+ :name => 'ostack-copy',
220
+ :passthrough => {
221
+ :type => :openstack,
222
+ :openstack_auth_url => 'http://hostname.domain.com:5000/v2.0/tokens',
223
+ :openstack_username => 'some_console_user',
224
+ :openstack_tenant => 'tenant_id',
225
+ :user => 'ssh_user',
226
+ :keypair => 'keypair_name',
227
+ :instance => 'your-instance-id',
228
+ },
229
+ )
230
+
198
231
  ```
199
232
 
200
233
  ### functional puppet test
@@ -353,3 +386,17 @@ irb(main):004:0> pp (Rouster.new(:name => 'aws', :passthrough => { :type => :aws
353
386
  ...
354
387
  ]
355
388
  ```
389
+
390
+ ## Openstack methods
391
+
392
+ ```rb
393
+ [
394
+ :ostack_connect,
395
+ :ostack_describe_instance,
396
+ :ostack_destroy,
397
+ :ostack_get_instance_id,
398
+ :ostack_get_ip,
399
+ :ostack_status,
400
+ :ostack_up
401
+ ]
402
+ ```
data/Rakefile CHANGED
@@ -6,6 +6,10 @@ task :buildgem do
6
6
  sh 'gem build rouster.gemspec'
7
7
  end
8
8
 
9
+ task :clean do
10
+ sh 'rm /tmp/rouster-*'
11
+ end
12
+
9
13
  task :default do
10
14
  sh 'ruby test/basic.rb'
11
15
  end
@@ -0,0 +1,61 @@
1
+ require sprintf('%s/../%s', File.dirname(File.expand_path(__FILE__)), 'path_helper')
2
+
3
+ require 'rouster'
4
+ require 'plugins/openstack' # brings in fog and some helpers
5
+
6
+ ostack = Rouster.new(
7
+ :name => 'ostack-testing',
8
+ :sudo => false,
9
+ :logfile => true,
10
+ :passthrough => {
11
+ :type => :openstack, # Indicate OpenStack provider
12
+ :openstack_auth_url => 'http://hostname.acme.com:5000/v2.0/tokens', # OpenStack API endpoint
13
+ :openstack_username => 'some_user', # OpenStack console username
14
+ :openstack_tenant => 'tenant_id', # Tenant ID
15
+ :user => 'ssh_user_id', # SSH login ID
16
+ :keypair => 'openstack_key_name', # Name of ssh keypair in OpenStack
17
+ :image_ref => 'c0340afb-577d-1234-87b2-aebdd6d1838f', # Image ID in OpenStack
18
+ :flavor_ref => '547d9af5-096c-1234-98df-7d23162556b8', # Flavor ID in OpenStack
19
+ :openstack_api_key => 'secret_openstack_key', # OpenStack console password
20
+ :key => '/path/to/ssh_keys.pem', # SSH key filename
21
+ },
22
+ :sshtunnel => false,
23
+ :verbosity => 1,
24
+ )
25
+
26
+ p "UP(): #{ostack.up}"
27
+ p "STATUS(): #{ostack.status}"
28
+
29
+ ostack_copy = Rouster.new(
30
+ :name => 'ostack-copy',
31
+ :sudo => false,
32
+ :logfile => true,
33
+ :passthrough => {
34
+ :type => :openstack, # Indicate OpenStack provider
35
+ :openstack_auth_url => 'http://hostname.acme.com:5000/v2.0/tokens', # OpenStack API endpoint
36
+ :openstack_username => 'some_user', # OpenStack console username
37
+ :openstack_tenant => 'tenant_id', # Tenant ID
38
+ :user => 'ssh_user_id', # SSH login ID
39
+ :keypair => 'openstack_key_name', # Name of ssh keypair in OpenStack
40
+ :openstack_api_key => 'secret_openstack_key', # OpenStack console password
41
+ :instance => ostack.ostack_get_instance_id, # ID of a running OpenStack instance.
42
+ },
43
+ :sshtunnel => false,
44
+ :verbosity => 1,
45
+ )
46
+
47
+ [ ostack, ostack_copy ].each do |o|
48
+ p "ostack_get_instance_id: #{o.ostack_get_instance_id}"
49
+
50
+ p "status: #{o.status}"
51
+
52
+ p "ostack_get_ip(): #{o.ostack_get_ip()}"
53
+
54
+ p "run(uptime): #{o.run('uptime')}"
55
+ p "get(/etc/hosts): #{o.get('/etc/hosts')}"
56
+ p "put(/etc/hosts, /tmp): #{o.put('/etc/hosts', '/tmp')}"
57
+
58
+ end
59
+
60
+ p "DESTROY(): #{ostack.destroy}"
61
+ exit
@@ -12,7 +12,7 @@ require 'rouster/vagrant'
12
12
  class Rouster
13
13
 
14
14
  # sporadically updated version number
15
- VERSION = 0.61
15
+ VERSION = 0.62
16
16
 
17
17
  # custom exceptions -- what else do we want them to include/do?
18
18
  class ArgumentError < StandardError; end # thrown by methods that take parameters from users
@@ -145,6 +145,7 @@ class Rouster
145
145
  aws_defaults = {
146
146
  :ami => 'ami-7bdaa84b', # RHEL 6.5 x64 in us-west-2
147
147
  :dns_propagation_sleep => 30, # how much time to wait after ELB creation before attempting to connect
148
+ :elb_cleanup => false,
148
149
  :key_id => ENV['AWS_ACCESS_KEY_ID'],
149
150
  :min_count => 1,
150
151
  :max_count => 1,
@@ -187,9 +188,30 @@ class Rouster
187
188
 
188
189
  raise ArgumentError.new('AWS passthrough requires valid :sshkey specification, should be path to private half') unless File.file?(@passthrough[:key])
189
190
  @sshkey = @passthrough[:key]
191
+ elsif @passthrough[:type].eql?(:openstack)
192
+ @logger.debug(sprintf('instantiating an %s passthrough worker', @passthrough[:type]))
193
+ @sshkey = @passthrough[:key]
194
+
195
+ ostack_defaults = {
196
+ :ssh_port => 22,
197
+ }
198
+ @passthrough = ostack_defaults.merge(@passthrough)
190
199
 
200
+ [:openstack_auth_url, :openstack_username, :openstack_tenant, :openstack_api_key,
201
+ :key ].each do |r|
202
+ raise ArgumentError.new(sprintf('OpenStack passthrough requires %s specification', r)) if @passthrough[r].nil?
203
+ end
204
+
205
+ if @passthrough.has_key?(:image_ref)
206
+ @logger.debug(':image_ref specified, will start new Nova instance')
207
+ elsif @passthrough.has_key?(:instance)
208
+ @logger.debug(':instance specified, will connect to existing OpenStack instance')
209
+ inst_details = self.ostack_describe_instance(@passthrough[:instance])
210
+ raise ArgumentError.new(sprintf('No such instance found in OpenStack - %s', @passthrough[:instance])) if inst_details.nil?
211
+ @passthrough[:host] = inst_details.addresses["NextGen"][0]["addr"]
212
+ end
191
213
  else
192
- raise ArgumentError.new(sprintf('passthrough :type [%s] unknown, allowed: :aws, :local, :remote', @passthrough[:type]))
214
+ raise ArgumentError.new(sprintf('passthrough :type [%s] unknown, allowed: :aws, :openstack, :local, :remote', @passthrough[:type]))
193
215
  end
194
216
 
195
217
  else
@@ -70,6 +70,12 @@ class Rouster
70
70
  next if line.match(/^#|^\s+$/)
71
71
  elements = line.split("\s")
72
72
 
73
+ if elements.size < 5
74
+ # this is usually (only?) caused by ENV_VARIABLE=VALUE directives
75
+ @logger.debug(sprintf('line [%s] did not match format expectations for a crontab entry, skipping', line))
76
+ next
77
+ end
78
+
73
79
  command = elements[5..elements.size].join(' ')
74
80
 
75
81
  res[u] ||= Hash.new
@@ -234,10 +234,10 @@ class Rouster
234
234
  local = true
235
235
  begin
236
236
  self.run(sprintf("grep -c '%s' %s", regex, name))
237
- rescue
237
+ rescue => e
238
238
  local = false
239
239
  end
240
- next if local.false?
240
+ break if local.false?
241
241
  end
242
242
  when :notcontains, :doesntcontain # TODO determine the appropriate attribute title here
243
243
  v = v.class.eql?(Array) ? v : [v]
@@ -246,10 +246,10 @@ class Rouster
246
246
  begin
247
247
  self.run(sprintf("grep -c '%s' %s", regex, name))
248
248
  local = false
249
- rescue
249
+ rescue => e
250
250
  local = true
251
251
  end
252
- next if local.false?
252
+ break if local.false?
253
253
  end
254
254
  when :mode, :permissions
255
255
  if properties.nil?
@@ -48,8 +48,14 @@ class Rouster
48
48
  @logger.info('up()')
49
49
 
50
50
  # don't like putting this here, may be refactored
51
- if self.is_passthrough? and (self.passthrough[:type].equal?(:aws) or self.passthrough[:type].equal?(:raiden))
52
- self.aws_up()
51
+ if self.is_passthrough?
52
+ if (self.passthrough[:type].equal?(:aws) or self.passthrough[:type].equal?(:raiden))
53
+ self.aws_up()
54
+ elsif (self.passthrough[:type].equal?(:openstack))
55
+ self.ostack_up()
56
+ else
57
+ self.vagrant(sprintf('up %s', @name))
58
+ end
53
59
  else
54
60
  self.vagrant(sprintf('up %s', @name))
55
61
  end
@@ -81,8 +87,14 @@ class Rouster
81
87
  @logger.info('destroy()')
82
88
 
83
89
  # don't like putting this here, may be refactored
84
- if self.is_passthrough? and (self.passthrough[:type].equal?(:aws) or self.passthrough[:type].equal?(:raiden))
85
- self.aws_destroy()
90
+ if self.is_passthrough?
91
+ if (self.passthrough[:type].equal?(:aws) or self.passthrough[:type].equal?(:raiden))
92
+ self.aws_destroy()
93
+ elsif self.is_passthrough? and self.passthrough[:type].equal?(:openstack)
94
+ self.ostack_destroy()
95
+ else
96
+ raise InternalError.new(sprintf('failed to execute destroy(), unsupported passthrough type %s', self.passthrough[:type]))
97
+ end
86
98
  else
87
99
  self.vagrant(sprintf('destroy -f %s', @name))
88
100
  end
@@ -109,8 +121,14 @@ class Rouster
109
121
 
110
122
  # don't like putting this here, may be refactored
111
123
  @logger.info('status()')
112
- if self.is_passthrough? and (self.passthrough[:type].equal?(:aws) or self.passthrough[:type].equal?(:raiden))
113
- status = self.aws_status()
124
+ if self.is_passthrough?
125
+ if (self.passthrough[:type].equal?(:aws) or self.passthrough[:type].equal?(:raiden))
126
+ status = self.aws_status()
127
+ elsif self.passthrough[:type].equal?(:openstack)
128
+ status = self.ostack_status()
129
+ else
130
+ raise InternalError.new(sprintf('failed to execute status(), unsupported passthrough type %s', self.passthrough[:type]))
131
+ end
114
132
  else
115
133
  self.vagrant(sprintf('status %s', @name))
116
134
 
@@ -274,5 +292,4 @@ class Rouster
274
292
  end
275
293
  end
276
294
 
277
-
278
- end
295
+ end
@@ -176,11 +176,9 @@ class Rouster
176
176
 
177
177
  server = @ec2.terminate_instances(self.aws_get_instance)
178
178
 
179
- if @passthrough.has_key?(:created_elb)
180
- elb = @passthrough[:created_elb]
181
-
182
- @logger.info(sprintf('deleting ELB[%s]', elb))
183
- @elb.delete_load_balancer(elb)
179
+ if self.passthrough[:created_elb] && self.passthrough[:elb_cleanup]
180
+ @logger.info(sprintf('deleting ELB[%s]', self.passthrough[:created_elb]))
181
+ @elb.delete_load_balancer(self.passthrough[:created_elb])
184
182
  end
185
183
 
186
184
  self.aws_status
@@ -264,6 +262,8 @@ class Rouster
264
262
  @logger.debug(sprintf('sleeping[%s] to allow DNS propagation', self.passthrough[:dns_propagation_sleep]))
265
263
  sleep self.passthrough[:dns_propagation_sleep]
266
264
 
265
+ self.passthrough[:created_elb] = elbname
266
+
267
267
  return dnsname
268
268
  end
269
269
 
@@ -0,0 +1,129 @@
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])
41
+ server.wait_for { ready? }
42
+ @instance_data = server
43
+ self.passthrough[:host] = server.addresses["NextGen"][0]["addr"]
44
+ self.passthrough[:instance] = self.ostack_get_instance_id
45
+ end
46
+ self.passthrough[:instance]
47
+ end
48
+
49
+ def ostack_get_ip()
50
+ self.passthrough[:host]
51
+ end
52
+
53
+ def ostack_destroy
54
+ server = self.ostack_describe_instance
55
+ raise sprintf("instance[%s] not found by destroy()", self.ostack_get_instance_id) if server.nil?
56
+ server.destroy
57
+ @instance_data = nil
58
+ self.passthrough.delete(:instance)
59
+ end
60
+
61
+ def ostack_describe_instance(instance_id = ostack_get_instance_id)
62
+
63
+ if @cache_timeout
64
+ if @cache.has_key?(:ostack_describe_instance)
65
+ if (Time.now.to_i - @cache[:ostack_describe_instance][:time]) < @cache_timeout
66
+ @logger.debug(sprintf('using cached ostack_describe_instance?[%s] from [%s]', @cache[:ostack_describe_instance][:instance], @cache[:ostack_describe_instance][:time]))
67
+ return @cache[:ostack_describe_instance][:instance]
68
+ end
69
+ end
70
+ end
71
+ # We don't have a instance.
72
+ return nil if instance_id.nil?
73
+ self.ostack_connect
74
+ response = @nova.servers.get(instance_id)
75
+ return nil if response.nil?
76
+ @instance_data = response
77
+
78
+ if @cache_timeout
79
+ @cache[:ostack_describe_instance] = Hash.new unless @cache[:ostack_describe_instance].class.eql?(Hash)
80
+ @cache[:ostack_describe_instance][:time] = Time.now.to_i
81
+ @cache[:ostack_describe_instance][:instance] = response
82
+ @logger.debug(sprintf('caching is_available_via_ssh?[%s] at [%s]', @cache[:ostack_describe_instance][:instance], @cache[:ostack_describe_instance][:time]))
83
+ end
84
+
85
+ @instance_data
86
+ end
87
+
88
+ def ostack_status
89
+ self.ostack_describe_instance
90
+ return 'not-created' if @instance_data.nil?
91
+ if @instance_data.state.eql?('ACTIVE')
92
+ # Make this consistent with AWS response.
93
+ return 'running'
94
+ else
95
+ return @instance_data.state
96
+ end
97
+ end
98
+
99
+
100
+ # TODO this will throw at the first error - should we catch?
101
+ # run some commands, return an array of the output
102
+ def ostack_bootstrap (commands)
103
+ self.ostack_connect
104
+ commands = (commands.is_a?(Array)) ? commands : [ commands ]
105
+ output = Array.new
106
+
107
+ commands.each do |command|
108
+ output << self.run(command)
109
+ end
110
+
111
+ return output
112
+ end
113
+
114
+ def ostack_connect
115
+ # Instantiates an Object which can communicate with OS Compute.
116
+ # No instance specific information is set at this time.
117
+ return @nova unless @nova.nil?
118
+
119
+ config = {
120
+ :provider => 'openstack', # OpenStack Fog provider
121
+ :openstack_auth_url => self.passthrough[:openstack_auth_url], # OpenStack Keystone endpoint
122
+ :openstack_username => self.passthrough[:openstack_username], # Your OpenStack Username
123
+ :openstack_tenant => self.passthrough[:openstack_tenant], # Your tenant id
124
+ :openstack_api_key => self.passthrough[:openstack_api_key], # Your OpenStack Password
125
+ :connection_options => self.passthrough[:connection_options] # Optional
126
+ }
127
+ @nova = Fog::Compute.new(config)
128
+ end
129
+ end
@@ -127,7 +127,7 @@ class TestDeltasGetCrontab < Test::Unit::TestCase
127
127
  @app.run("crontab -u #{user} #{tmp}")
128
128
 
129
129
  assert_nothing_raised do
130
- res = @app.get_crontab('puppet')
130
+ res = @app.get_crontab(user)
131
131
  end
132
132
 
133
133
  assert_equal(Hash, res.class)
@@ -136,6 +136,24 @@ class TestDeltasGetCrontab < Test::Unit::TestCase
136
136
 
137
137
  end
138
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
+
139
157
  def teardown
140
158
  @app = nil
141
159
  end
@@ -54,7 +54,7 @@ class TestDeltasGetGroups < Test::Unit::TestCase
54
54
  if @app.os_type.eql?(:redhat)
55
55
  @app.run(sprintf('groupadd %s', new_group))
56
56
  else
57
- skip('only doing group creation on RHEL hosts')
57
+ omit('only doing group creation on RHEL hosts')
58
58
  end
59
59
 
60
60
  assert_nothing_raised do
@@ -142,11 +142,11 @@ class TestNew < Test::Unit::TestCase
142
142
 
143
143
  def test_good_remote_passthrough
144
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?("")
145
+ omit('not running test_good_remote_passthrough, autogenerated a fake ssh key') if File.file?(@@user_sshkey) and File.read(@@user_sshkey).eql?("")
146
146
 
147
147
  host = '127.0.0.1'
148
148
  `ssh -i #{@@user_sshkey} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null #{host} exit` # if this succeeds, we want to exit immediately so we don't get hung
149
- skip("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
149
+ omit("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
150
150
 
151
151
  assert_nothing_raised do
152
152
  @app = Rouster.new(
@@ -172,11 +172,11 @@ class TestNew < Test::Unit::TestCase
172
172
 
173
173
  def test_paranoia_remote_passthrough
174
174
 
175
- skip('not running test_good_remote_passthrough, autogenerated a fake ssh key') if File.file?(@@user_sshkey) and File.read(@@user_sshkey).eql?("")
175
+ omit('not running test_good_remote_passthrough, autogenerated a fake ssh key') if File.file?(@@user_sshkey) and File.read(@@user_sshkey).eql?("")
176
176
 
177
177
  host = '127.0.0.1'
178
178
  `ssh -i #{@@user_sshkey} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null #{host} exit` # if this succeeds, we want to exit immediately so we don't get hung
179
- skip("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
179
+ omit("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
180
180
 
181
181
  assert_nothing_raised do
182
182
  @app = Rouster.new(
@@ -54,11 +54,11 @@ class TestPassthroughs < Test::Unit::TestCase
54
54
 
55
55
  def test_functional_remote_passthrough
56
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?("")
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
58
 
59
59
  host = '127.0.0.1'
60
60
  `ssh -i #{@@user_sshkey} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null #{host} exit`
61
- skip("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
61
+ omit("found an ssh key, but it doesn't appear to be valid for this host") unless $?.success?
62
62
 
63
63
  assert_nothing_raised do
64
64
  @remote = Rouster.new(
@@ -24,8 +24,6 @@ class TestValidateFileFunctional < Test::Unit::TestCase
24
24
  end
25
25
 
26
26
  # TODO tests
27
- # :contains string
28
- # :contains array
29
27
  # :exists vs. :ensure -> what options are supported?
30
28
  # :mode vs. :permissions
31
29
  # :size
@@ -56,6 +54,57 @@ class TestValidateFileFunctional < Test::Unit::TestCase
56
54
 
57
55
  end
58
56
 
57
+ def test_happy_contains_string
58
+ file = '/etc/hosts'
59
+ expectations = {
60
+ :ensure => 'file',
61
+ :contains => 'localhost'
62
+ }
63
+
64
+ assert_equal(true, @app.validate_file(file, expectations, false, true))
65
+
66
+ end
67
+
68
+ def test_contains_array_ordering
69
+
70
+ file = '/etc/hosts'
71
+
72
+ expectation1 = {
73
+ :ensure => 'file',
74
+ :contains => [ 'localhost', 'foobar' ]
75
+ }
76
+
77
+ expectation2 = {
78
+ :ensure => 'file',
79
+ :contains => [ 'foobar', 'localhost' ]
80
+ }
81
+
82
+ [expectation1, expectation2].each do |expectation|
83
+ assert_equal(false, @app.validate_file(file, expectation, false, true))
84
+ end
85
+
86
+ end
87
+
88
+ def test_not_contains_array_ordering
89
+ file = '/etc/hosts'
90
+
91
+
92
+ expectation1 = {
93
+ :ensure => 'file',
94
+ :notcontains => [ 'localhost', 'foobar']
95
+ }
96
+
97
+ expectation2 = {
98
+ :ensure => 'file',
99
+ :notcontains => [ 'foobar', 'localhost' ],
100
+ }
101
+
102
+ [expectation1, expectation2].each do |expectation|
103
+ assert_equal(false, @app.validate_file(file, expectation, false, true))
104
+ end
105
+
106
+ end
107
+
59
108
  def test_happy_symlink
60
109
  file = '/tmp/bang'
61
110
 
@@ -51,7 +51,7 @@ class TestNew < Test::Unit::TestCase
51
51
  def test_default_overrides_aws_passthrough
52
52
 
53
53
  key = sprintf('%s/.ssh/id_rsa', ENV['HOME'])
54
- skip(sprintf('no suitable private key found at [%s]', key)) unless File.file?(key)
54
+ omit(sprintf('no suitable private key found at [%s]', key)) unless File.file?(key)
55
55
 
56
56
  @app = Rouster.new(
57
57
  :name => 'aws',
@@ -353,7 +353,7 @@ class TestParseLsString < Test::Unit::TestCase
353
353
  def test_suid
354
354
  str = "drwxr-sr-x 2 root root 4096 Oct 7 17:09 /etc/nagios/objects\n"
355
355
 
356
- skip('need to improve (read: implement) actual suid support')
356
+ omit('need to improve (read: implement) actual suid support')
357
357
 
358
358
  expectation = {
359
359
  :directory? => true,
@@ -22,6 +22,7 @@ portreserve is stopped
22
22
  master is stopped
23
23
  puppet is stopped
24
24
  rdisc is stopped
25
+ redis-server (pid 7295) is running...
25
26
  restorecond is stopped
26
27
  rhsmcertd (pid 1023) is running...
27
28
  rpcbind (pid 887) is running...
@@ -27,11 +27,12 @@ class TestUnitGetPackages < Test::Unit::TestCase
27
27
  end
28
28
 
29
29
  expected = {
30
- 'acpid' => 'running', # acpid (pid 945) is running...
31
- 'ip6tables' => 'stopped', # ip6tables: Firewall is not running.
32
- 'Kdump' => 'stopped', # Kdump is not operational
33
- 'mdmonitor' => 'stopped', # mdmonitor is stopped
34
- 'netconsole' => 'stopped', # netconsole module not loaded
30
+ 'acpid' => 'running', # acpid (pid 945) is running...
31
+ 'ip6tables' => 'stopped', # ip6tables: Firewall is not running.
32
+ 'Kdump' => 'stopped', # Kdump is not operational
33
+ 'mdmonitor' => 'stopped', # mdmonitor is stopped
34
+ 'netconsole' => 'stopped', # netconsole module not loaded
35
+ 'redis-server' => 'running' # redis-server (pid 11285) is running...
35
36
  }
36
37
 
37
38
  expected.each_pair do |service,state|
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.61'
4
+ version: '0.62'
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: 2015-01-20 00:00:00.000000000 Z
11
+ date: 2015-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -126,6 +126,7 @@ files:
126
126
  - examples/bootstrap.rb
127
127
  - examples/demo.rb
128
128
  - examples/error.rb
129
+ - examples/openstack.rb
129
130
  - examples/passthrough.rb
130
131
  - lib/rouster.rb
131
132
  - lib/rouster/deltas.rb
@@ -135,6 +136,7 @@ files:
135
136
  - lib/rouster/vagrant.rb
136
137
  - path_helper.rb
137
138
  - plugins/aws.rb
139
+ - plugins/openstack.rb
138
140
  - rouster.gemspec
139
141
  - test/basic.rb
140
142
  - test/functional/deltas/test_get_crontab.rb
@@ -207,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
209
  version: 1.3.6
208
210
  requirements: []
209
211
  rubyforge_project: Rouster
210
- rubygems_version: 2.4.2
212
+ rubygems_version: 2.4.6
211
213
  signing_key:
212
214
  specification_version: 4
213
215
  summary: Rouster is an abstraction layer for Vagrant