rouster 0.61 → 0.62

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: 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