right_agent 0.17.2 → 1.0.1
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.
- data/lib/right_agent.rb +0 -1
- data/lib/right_agent/agent_config.rb +1 -1
- data/lib/right_agent/minimal.rb +8 -7
- data/lib/right_agent/monkey_patches.rb +4 -2
- data/lib/right_agent/monkey_patches/ruby_patch.rb +9 -9
- data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +2 -2
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +21 -51
- data/lib/right_agent/packets.rb +5 -1
- data/lib/right_agent/platform.rb +727 -299
- data/lib/right_agent/platform/unix/darwin/platform.rb +102 -0
- data/lib/right_agent/platform/unix/linux/platform.rb +305 -0
- data/lib/right_agent/platform/unix/platform.rb +226 -0
- data/lib/right_agent/platform/windows/mingw/platform.rb +447 -0
- data/lib/right_agent/platform/windows/mswin/platform.rb +236 -0
- data/lib/right_agent/platform/windows/platform.rb +1808 -0
- data/right_agent.gemspec +13 -8
- data/spec/platform/spec_helper.rb +216 -0
- data/spec/platform/unix/darwin/platform_spec.rb +181 -0
- data/spec/platform/unix/linux/platform_spec.rb +540 -0
- data/spec/platform/unix/spec_helper.rb +149 -0
- data/spec/platform/windows/mingw/platform_spec.rb +222 -0
- data/spec/platform/windows/mswin/platform_spec.rb +259 -0
- data/spec/platform/windows/spec_helper.rb +720 -0
- metadata +45 -30
- data/lib/right_agent/platform/darwin.rb +0 -285
- data/lib/right_agent/platform/linux.rb +0 -537
- data/lib/right_agent/platform/windows.rb +0 -1384
- data/spec/platform/darwin_spec.rb +0 -13
- data/spec/platform/linux_spec.rb +0 -38
- data/spec/platform/linux_volume_manager_spec.rb +0 -201
- data/spec/platform/platform_spec.rb +0 -80
- data/spec/platform/windows_spec.rb +0 -13
- data/spec/platform/windows_volume_manager_spec.rb +0 -318
data/right_agent.gemspec
CHANGED
@@ -24,9 +24,9 @@ require 'rubygems'
|
|
24
24
|
|
25
25
|
Gem::Specification.new do |spec|
|
26
26
|
spec.name = 'right_agent'
|
27
|
-
spec.version = '0.
|
28
|
-
spec.date = '2013-10-
|
29
|
-
spec.authors = ['Lee Kirchhoff', 'Raphael Simon', 'Tony Spataro']
|
27
|
+
spec.version = '1.0.1'
|
28
|
+
spec.date = '2013-10-29'
|
29
|
+
spec.authors = ['Lee Kirchhoff', 'Raphael Simon', 'Tony Spataro', 'Scott Messier']
|
30
30
|
spec.email = 'lee@rightscale.com'
|
31
31
|
spec.homepage = 'https://github.com/rightscale/right_agent'
|
32
32
|
spec.platform = Gem::Platform::RUBY
|
@@ -39,15 +39,20 @@ Gem::Specification.new do |spec|
|
|
39
39
|
|
40
40
|
spec.add_dependency('right_support', ['>= 2.4.1', '< 3.0'])
|
41
41
|
spec.add_dependency('right_amqp', '~> 0.7')
|
42
|
-
spec.add_dependency('json', ['>= 1.4', '<= 1.7.6']) # json_create behavior change in 1.7.7
|
43
42
|
spec.add_dependency('eventmachine', ['>= 0.12.10', '< 2.0'])
|
44
|
-
spec.add_dependency('msgpack', ['>= 0.4.4', '< 0.6'])
|
45
43
|
spec.add_dependency('net-ssh', '~> 2.0')
|
46
44
|
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
# not currently needed by Linux but it does no harm to have it.
|
46
|
+
spec.add_dependency('ffi')
|
47
|
+
case RUBY_PLATFORM
|
48
|
+
when /mswin|mingw/i
|
49
|
+
spec.add_dependency('win32-dir', '~> 0.4.6')
|
50
|
+
spec.add_dependency('win32-process', '~> 0.7.3')
|
51
|
+
when /win32|dos|cygwin/i
|
52
|
+
raise ::NotImplementedError, 'Unsupported Ruby-on-Windows variant'
|
50
53
|
end
|
54
|
+
spec.add_dependency('msgpack', ['>= 0.4.4', '< 0.6'])
|
55
|
+
spec.add_dependency('json', '~> 1.4')
|
51
56
|
|
52
57
|
spec.description = <<-EOF
|
53
58
|
RightAgent provides a foundation for running an agent on a server to interface
|
@@ -0,0 +1,216 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2013 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require ::File.expand_path('../../spec_helper', __FILE__)
|
24
|
+
|
25
|
+
# reloads the Platform overrides for the current platform under test and then
|
26
|
+
# restores the default platform to avoid breaking subsequent spec tests. works
|
27
|
+
# because each implementation is expected to fully override the methods in the
|
28
|
+
# base Platform class and so support multiple redefinition.
|
29
|
+
#
|
30
|
+
# requires the following to be defined by spec in a platform-specific manner:
|
31
|
+
# instrument_booted_at
|
32
|
+
module PlatformSpecHelper
|
33
|
+
|
34
|
+
# references mocked Platform class and instance to simplify singleton testing.
|
35
|
+
attr_reader :file_class, :platform_class, :platform_instance
|
36
|
+
|
37
|
+
# resets the Platform singleton.
|
38
|
+
def reset_platform_singleton
|
39
|
+
# release any existing singleton to force full reload from source.
|
40
|
+
::RightScale::Platform.instance_variable_set(:@singleton__instance__, nil)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
# Invoke within a before(:all) in described class.
|
45
|
+
def before_all_platform_tests
|
46
|
+
return true if RUBY_VERSION =~ /^1\.8/ # see below
|
47
|
+
|
48
|
+
reset_platform_singleton
|
49
|
+
|
50
|
+
# redefine Platform#initialize_platform_specific to defeat load-upon-
|
51
|
+
# initialize behavior of singleton and give us a chance to set genus/species
|
52
|
+
# explicitly before any loading occurs.
|
53
|
+
::RightScale::Platform.class_eval('def initialize_platform_specific; end')
|
54
|
+
|
55
|
+
instance = ::RightScale::Platform.instance
|
56
|
+
instance.instance_variable_set(:@genus, expected_genus)
|
57
|
+
instance.instance_variable_set(:@species, expected_species)
|
58
|
+
|
59
|
+
# invoke require logic for load-once behavior.
|
60
|
+
unless instance.send(:load_platform_specific)
|
61
|
+
# forcibly reload platform under test when require returns false.
|
62
|
+
load instance.send(:platform_base_path) + '.rb'
|
63
|
+
load instance.send(:platform_genus_path) + '.rb'
|
64
|
+
load instance.send(:platform_species_path) + '.rb'
|
65
|
+
end
|
66
|
+
::RightScale::Platform.genus.should == expected_genus
|
67
|
+
::RightScale::Platform.species.should == expected_species
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
# Invoke within a after(:all) in described class.
|
72
|
+
def after_all_platform_tests
|
73
|
+
return true if RUBY_VERSION =~ /^1\.8/ # see below
|
74
|
+
|
75
|
+
# 'restore' original singleton. this does not undefine any additional nested
|
76
|
+
# classes that are platform-specific (for other than the current platform)
|
77
|
+
# but they will not be invoked and so are harmless.
|
78
|
+
reset_platform_singleton
|
79
|
+
instance = ::RightScale::Platform.instance
|
80
|
+
load instance.send(:platform_base_path) + '.rb'
|
81
|
+
load instance.send(:platform_genus_path) + '.rb'
|
82
|
+
load instance.send(:platform_species_path) + '.rb'
|
83
|
+
instance.send(:initialize_genus)
|
84
|
+
instance.send(:initialize_species)
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
# Invoke within a before(:each) in described class.
|
89
|
+
def before_each_platform_test
|
90
|
+
# TEAL FIX might be that flexmock version is too new for ruby 1.8 to work,
|
91
|
+
# but not really important going forward.
|
92
|
+
if RUBY_VERSION =~ /^1\.8/
|
93
|
+
pending 'before(:all) mocks do not work in ruby 1.8'
|
94
|
+
end
|
95
|
+
|
96
|
+
# reset singleton again but no need to reload platform code at this point.
|
97
|
+
# the issue is that flexmock needs a fresh instance to mock out each time or
|
98
|
+
# else the mock teardown goes haywire and spews meaningless stack-traces to
|
99
|
+
# the console. the problem seems to be exacerbated by these tests redefining
|
100
|
+
# methods of Platform (out of necessity).
|
101
|
+
reset_platform_singleton
|
102
|
+
platform = ::RightScale::Platform
|
103
|
+
instance = platform.instance
|
104
|
+
instance.instance_variable_set(:@genus, expected_genus)
|
105
|
+
instance.instance_variable_set(:@species, expected_species)
|
106
|
+
|
107
|
+
# create mocks.
|
108
|
+
@file_class = flexmock(::File)
|
109
|
+
@platform_class = flexmock(platform)
|
110
|
+
@platform_instance = flexmock(instance)
|
111
|
+
|
112
|
+
# require normalize_path to be mocked during spec runs as it actually
|
113
|
+
# invokes APIs on Windows.
|
114
|
+
file_class.should_receive(:normalize_path).and_return do |*args|
|
115
|
+
raise ::NotImplementedError, "Must mock all calls to File.normalize_path: #{args.inspect}"
|
116
|
+
end.by_default
|
117
|
+
|
118
|
+
# defeat any shell execution by default (i.e. until properly mocked).
|
119
|
+
platform_class.should_receive(:execute).and_return do |*args|
|
120
|
+
raise ::NotImplementedError, "Must mock all calls to Platform.execute for class: #{args.inspect}"
|
121
|
+
end.by_default
|
122
|
+
platform_instance.should_receive(:execute).and_return do |*args|
|
123
|
+
raise ::NotImplementedError, "Must instrument all calls to Platform#execute for instance: #{args.inspect}"
|
124
|
+
end.by_default
|
125
|
+
::RightScale::Platform.genus.should == expected_genus
|
126
|
+
::RightScale::Platform.species.should == expected_species
|
127
|
+
expect { ::RightScale::Platform.execute(nil) }.to raise_error(::NotImplementedError)
|
128
|
+
expect { ::RightScale::Platform.instance.execute(nil) }.to raise_error(::NotImplementedError)
|
129
|
+
true
|
130
|
+
end
|
131
|
+
|
132
|
+
# Invoke within a after(:each) in described class.
|
133
|
+
def after_each_platform_test
|
134
|
+
@file_class = nil
|
135
|
+
@platform_class = nil
|
136
|
+
@platform_instance = nil
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
end # PlatformSpecHelper
|
141
|
+
|
142
|
+
shared_examples_for 'supports any platform shell' do
|
143
|
+
let(:minimum_uptime) { 10 * 60 }
|
144
|
+
let(:expected_booted_at) { ::Time.now.to_i - minimum_uptime }
|
145
|
+
|
146
|
+
# Sleeps until timer ticks over. Note that sleep(1) does not guarantee
|
147
|
+
# a tick-over and it may take sleep(< 1) to observe the tick-over.
|
148
|
+
def wait_for_tick_change
|
149
|
+
start_tick = ::Time.now.to_i
|
150
|
+
while ::Time.now.to_i == start_tick
|
151
|
+
sleep 0.1
|
152
|
+
end
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
context '#format_redirect_stdout' do
|
157
|
+
it 'should format redirect of stdout' do
|
158
|
+
subject.format_redirect_stdout('foo bar').
|
159
|
+
should == "foo bar 1>#{subject.null_output_name}"
|
160
|
+
subject.format_redirect_stdout('bar foo', '/tmp/foo').
|
161
|
+
should == 'bar foo 1>/tmp/foo'
|
162
|
+
end
|
163
|
+
end # format_redirect_stdout
|
164
|
+
|
165
|
+
context '#format_redirect_stderr' do
|
166
|
+
it 'should format redirect of stderr' do
|
167
|
+
subject.format_redirect_stderr('foo bar').
|
168
|
+
should == "foo bar 2>#{subject.null_output_name}"
|
169
|
+
subject.format_redirect_stderr('bar foo', '/tmp/foo').
|
170
|
+
should == 'bar foo 2>/tmp/foo'
|
171
|
+
end
|
172
|
+
end # format_redirect_stderr
|
173
|
+
|
174
|
+
context '#format_redirect_both' do
|
175
|
+
it 'should format redirect of stderr' do
|
176
|
+
subject.format_redirect_both('foo bar').
|
177
|
+
should == "foo bar 1>#{subject.null_output_name} 2>&1"
|
178
|
+
subject.format_redirect_both('bar foo', '/tmp/foo').
|
179
|
+
should == 'bar foo 1>/tmp/foo 2>&1'
|
180
|
+
end
|
181
|
+
end # format_redirect_both
|
182
|
+
|
183
|
+
context '#uptime' do
|
184
|
+
it 'should be positive' do
|
185
|
+
instrument_booted_at(expected_booted_at) { minimum_uptime }
|
186
|
+
subject.uptime.should >= minimum_uptime
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should be strictly increasing' do
|
190
|
+
uptime = minimum_uptime
|
191
|
+
instrument_booted_at(expected_booted_at) { uptime }
|
192
|
+
u0 = subject.uptime
|
193
|
+
wait_for_tick_change # uptime may use either system data or a relative time
|
194
|
+
uptime += 1
|
195
|
+
u1 = subject.uptime
|
196
|
+
(u1 - u0).should > 0.0
|
197
|
+
end
|
198
|
+
end # uptime
|
199
|
+
|
200
|
+
context '#booted_at' do
|
201
|
+
it 'should be some time in the past' do
|
202
|
+
instrument_booted_at(expected_booted_at) { minimum_uptime }
|
203
|
+
subject.booted_at.should == expected_booted_at
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should be constant' do
|
207
|
+
uptime = minimum_uptime
|
208
|
+
instrument_booted_at(expected_booted_at) { uptime }
|
209
|
+
b0 = subject.booted_at
|
210
|
+
wait_for_tick_change # uptime may use either system data or a relative time
|
211
|
+
uptime += 1
|
212
|
+
b1 = subject.booted_at
|
213
|
+
b0.should == b1
|
214
|
+
end
|
215
|
+
end # booted_at
|
216
|
+
end # supports any platform shell
|
@@ -0,0 +1,181 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require ::File.expand_path('../../spec_helper', __FILE__)
|
24
|
+
|
25
|
+
describe RightScale::Platform do
|
26
|
+
include PlatformSpecHelper
|
27
|
+
|
28
|
+
context 'unix/darwin' do
|
29
|
+
|
30
|
+
# required by before_all_platform_tests
|
31
|
+
# called by before(:all) so not defined using let().
|
32
|
+
def expected_genus; :unix; end
|
33
|
+
def expected_species; :darwin; end
|
34
|
+
|
35
|
+
before(:all) do
|
36
|
+
before_all_platform_tests
|
37
|
+
end
|
38
|
+
|
39
|
+
after(:all) do
|
40
|
+
after_all_platform_tests
|
41
|
+
end
|
42
|
+
|
43
|
+
before(:each) do
|
44
|
+
before_each_platform_test
|
45
|
+
end
|
46
|
+
|
47
|
+
after(:each) do
|
48
|
+
after_each_platform_test
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'statics' do
|
52
|
+
subject { platform_class }
|
53
|
+
|
54
|
+
it 'should be linux' do
|
55
|
+
subject.unix?.should be_true
|
56
|
+
subject.windows?.should be_false
|
57
|
+
subject.linux?.should be_false
|
58
|
+
subject.darwin?.should be_true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'initialization' do
|
63
|
+
|
64
|
+
let(:sw_vers_cmd) { 'sw_vers -productVersion 2>&1' }
|
65
|
+
|
66
|
+
context 'when sw_vers is available' do
|
67
|
+
it 'should initialize from sw_vers data' do
|
68
|
+
platform_instance.
|
69
|
+
should_receive(:execute).
|
70
|
+
with(sw_vers_cmd).
|
71
|
+
and_return("10.8.5\n").
|
72
|
+
once
|
73
|
+
platform_instance.send(:initialize_species)
|
74
|
+
platform_instance.flavor.should == 'mac_os_x'
|
75
|
+
platform_instance.release.should == '10.8.5'
|
76
|
+
platform_instance.codename.should == ''
|
77
|
+
end
|
78
|
+
end # when lsb_release is available
|
79
|
+
|
80
|
+
context 'when sw_vers is not available' do
|
81
|
+
it 'should be unknown release' do
|
82
|
+
platform_instance.
|
83
|
+
should_receive(:execute).
|
84
|
+
with(sw_vers_cmd).
|
85
|
+
and_raise(described_class::CommandError).
|
86
|
+
once
|
87
|
+
platform_instance.send(:initialize_species)
|
88
|
+
platform_instance.flavor.should == 'mac_os_x'
|
89
|
+
platform_instance.release.should == 'unknown'
|
90
|
+
platform_instance.codename.should == 'unknown'
|
91
|
+
end
|
92
|
+
end # when lsb_release is not available
|
93
|
+
end # initialization
|
94
|
+
|
95
|
+
context :controller do
|
96
|
+
subject { described_class.controller }
|
97
|
+
|
98
|
+
context '#reboot' do
|
99
|
+
it 'should call shutdown -r now under darwin' do
|
100
|
+
platform_class.should_receive(:execute).with('shutdown -r now 2>&1', {}).and_return('')
|
101
|
+
subject.reboot.should be_true
|
102
|
+
end
|
103
|
+
end # reboot
|
104
|
+
|
105
|
+
context '#shutdown' do
|
106
|
+
it 'should call shutdown -h now under darwin' do
|
107
|
+
platform_class.should_receive(:execute).with('shutdown -h now 2>&1', {}).and_return('')
|
108
|
+
subject.shutdown.should be_true
|
109
|
+
end
|
110
|
+
end # shutdown
|
111
|
+
end # controller
|
112
|
+
|
113
|
+
context :filesystem do
|
114
|
+
subject { described_class.filesystem }
|
115
|
+
|
116
|
+
it_should_behave_like 'supports unix platform filesystem'
|
117
|
+
end
|
118
|
+
|
119
|
+
context :installer do
|
120
|
+
subject { described_class.installer }
|
121
|
+
|
122
|
+
context :install do
|
123
|
+
it 'should raise not implemented' do
|
124
|
+
expect { subject.install(%w[foo bar]) }.
|
125
|
+
to raise_error(
|
126
|
+
::NotImplementedError, 'Not yet supporting Mac OS package install')
|
127
|
+
end
|
128
|
+
end # install
|
129
|
+
end # installer
|
130
|
+
|
131
|
+
context :shell do
|
132
|
+
subject { described_class.shell }
|
133
|
+
|
134
|
+
# required by 'supports any platform shell'
|
135
|
+
def instrument_booted_at(booted_at)
|
136
|
+
time = ::Time.at(booted_at.to_i)
|
137
|
+
platform_class.
|
138
|
+
should_receive(:execute).
|
139
|
+
with('sysctl kern.boottime', {}).
|
140
|
+
and_return("kern.boottime: { sec = #{time.to_i}, usec = 0 } #{time.to_s}")
|
141
|
+
|
142
|
+
# note that uptime is computed relative to boottime.
|
143
|
+
true
|
144
|
+
end
|
145
|
+
|
146
|
+
it_should_behave_like 'supports unix platform shell'
|
147
|
+
end
|
148
|
+
|
149
|
+
context :rng do
|
150
|
+
subject { described_class.rng }
|
151
|
+
|
152
|
+
it_should_behave_like 'supports unix platform rng'
|
153
|
+
end
|
154
|
+
|
155
|
+
context :process do
|
156
|
+
subject { described_class.process }
|
157
|
+
|
158
|
+
it_should_behave_like 'supports unix platform process'
|
159
|
+
end
|
160
|
+
|
161
|
+
context :volume_manager do
|
162
|
+
subject { platform_class.volume_manager }
|
163
|
+
|
164
|
+
context :volumes do
|
165
|
+
it 'should raise not implemented' do
|
166
|
+
expect { subject.volumes }.
|
167
|
+
to raise_error(
|
168
|
+
::NotImplementedError, 'Not yet supporting Mac OS volume query')
|
169
|
+
end
|
170
|
+
end # volumes
|
171
|
+
|
172
|
+
context :mount_volume do
|
173
|
+
it 'should raise not implemented' do
|
174
|
+
expect { subject.volumes }.
|
175
|
+
to raise_error(
|
176
|
+
::NotImplementedError, 'Not yet supporting Mac OS volume query')
|
177
|
+
end
|
178
|
+
end # mount_volume
|
179
|
+
end # volume_manager
|
180
|
+
end # under unix/darwin
|
181
|
+
end # RightScale::Platform
|
@@ -0,0 +1,540 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require ::File.expand_path('../../spec_helper', __FILE__)
|
24
|
+
|
25
|
+
describe RightScale::Platform do
|
26
|
+
|
27
|
+
include PlatformSpecHelper
|
28
|
+
|
29
|
+
context 'unix/linux' do
|
30
|
+
|
31
|
+
# required by before_all_platform_tests
|
32
|
+
# called by before(:all) so not defined using let().
|
33
|
+
def expected_genus; :unix; end
|
34
|
+
def expected_species; :linux; end
|
35
|
+
|
36
|
+
before(:all) do
|
37
|
+
before_all_platform_tests
|
38
|
+
end
|
39
|
+
|
40
|
+
after(:all) do
|
41
|
+
after_all_platform_tests
|
42
|
+
end
|
43
|
+
|
44
|
+
before(:each) do
|
45
|
+
before_each_platform_test
|
46
|
+
end
|
47
|
+
|
48
|
+
after(:each) do
|
49
|
+
after_each_platform_test
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'statics' do
|
53
|
+
subject { platform_class }
|
54
|
+
|
55
|
+
it 'should be linux' do
|
56
|
+
subject.unix?.should be_true
|
57
|
+
subject.windows?.should be_false
|
58
|
+
subject.linux?.should be_true
|
59
|
+
subject.darwin?.should be_false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'initialization' do
|
64
|
+
let(:lsb_help_cmd) { 'lsb_release --help >/dev/null 2>&1' }
|
65
|
+
|
66
|
+
context 'when lsb_release is available' do
|
67
|
+
it 'should initialize from lsb_release data' do
|
68
|
+
platform_instance.
|
69
|
+
should_receive(:execute).
|
70
|
+
with(lsb_help_cmd).
|
71
|
+
and_return("lsb_release\nhelp\ndump\n").
|
72
|
+
once
|
73
|
+
platform_instance.
|
74
|
+
should_receive(:execute).
|
75
|
+
with('lsb_release -is', { :raise_on_failure => false }).
|
76
|
+
and_return("Ubuntu\n").
|
77
|
+
once
|
78
|
+
platform_instance.
|
79
|
+
should_receive(:execute).
|
80
|
+
with('lsb_release -rs', { :raise_on_failure => false }).
|
81
|
+
and_return("11.04\n").
|
82
|
+
once
|
83
|
+
platform_instance.
|
84
|
+
should_receive(:execute).
|
85
|
+
with('lsb_release -cs', { :raise_on_failure => false }).
|
86
|
+
and_return("natty\n").
|
87
|
+
once
|
88
|
+
platform_instance.send(:initialize_species)
|
89
|
+
platform_instance.flavor.should == 'ubuntu'
|
90
|
+
platform_instance.release.should == '11.04'
|
91
|
+
platform_instance.codename.should == 'natty'
|
92
|
+
platform_instance.ubuntu?.should be_true
|
93
|
+
platform_instance.centos?.should be_false
|
94
|
+
platform_instance.suse?.should be_false
|
95
|
+
platform_instance.rhel?.should be_false
|
96
|
+
end
|
97
|
+
end # when lsb_release is available
|
98
|
+
|
99
|
+
context 'when lsb_release is not available' do
|
100
|
+
before(:each) do
|
101
|
+
platform_instance.
|
102
|
+
should_receive(:execute).
|
103
|
+
with(lsb_help_cmd).
|
104
|
+
and_raise(described_class::CommandError).
|
105
|
+
once
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when fedora release is available' do
|
109
|
+
it 'should be fedora' do
|
110
|
+
file_mock = flexmock(::File)
|
111
|
+
file_mock.
|
112
|
+
should_receive(:exist?).
|
113
|
+
with(described_class::FEDORA_REL).
|
114
|
+
and_return(true).
|
115
|
+
once
|
116
|
+
file_mock.
|
117
|
+
should_receive(:read).
|
118
|
+
with(described_class::FEDORA_REL).
|
119
|
+
and_return("Fedora release 7 (Moonshine)\n").
|
120
|
+
once
|
121
|
+
platform_instance.send(:initialize_species)
|
122
|
+
platform_instance.flavor.should == 'fedora'
|
123
|
+
platform_instance.release.should == '7'
|
124
|
+
platform_instance.codename.should == 'Moonshine'
|
125
|
+
platform_instance.ubuntu?.should be_false
|
126
|
+
platform_instance.centos?.should be_false
|
127
|
+
platform_instance.suse?.should be_false
|
128
|
+
platform_instance.rhel?.should be_false
|
129
|
+
end
|
130
|
+
end # when fedora release is available
|
131
|
+
|
132
|
+
context 'when fedora release is not available' do
|
133
|
+
it 'should be unknown' do
|
134
|
+
file_mock = flexmock(::File)
|
135
|
+
file_mock.
|
136
|
+
should_receive(:exist?).
|
137
|
+
with(described_class::FEDORA_REL).
|
138
|
+
and_return(false).
|
139
|
+
once
|
140
|
+
platform_instance.send(:initialize_species)
|
141
|
+
platform_instance.flavor.should == 'unknown'
|
142
|
+
platform_instance.release.should == 'unknown'
|
143
|
+
platform_instance.codename.should == 'unknown'
|
144
|
+
platform_instance.ubuntu?.should be_false
|
145
|
+
platform_instance.centos?.should be_false
|
146
|
+
platform_instance.suse?.should be_false
|
147
|
+
platform_instance.rhel?.should be_false
|
148
|
+
end
|
149
|
+
end # when fedora release is not available
|
150
|
+
end # when lsb_release is not available
|
151
|
+
end # initialization
|
152
|
+
|
153
|
+
context :controller do
|
154
|
+
subject { described_class.controller }
|
155
|
+
|
156
|
+
context '#reboot' do
|
157
|
+
it 'should call init 6 under unix' do
|
158
|
+
platform_class.should_receive(:execute).with('init 6 2>&1', {}).and_return('')
|
159
|
+
subject.reboot.should be_true
|
160
|
+
end
|
161
|
+
end # reboot
|
162
|
+
|
163
|
+
context '#shutdown' do
|
164
|
+
it 'should call init 0 under unix' do
|
165
|
+
platform_class.should_receive(:execute).with('init 0 2>&1', {}).and_return('')
|
166
|
+
subject.shutdown.should be_true
|
167
|
+
end
|
168
|
+
end # shutdown
|
169
|
+
end # controller
|
170
|
+
|
171
|
+
context :filesystem do
|
172
|
+
subject { described_class.filesystem }
|
173
|
+
|
174
|
+
it_should_behave_like 'supports unix platform filesystem'
|
175
|
+
end
|
176
|
+
|
177
|
+
context :installer do
|
178
|
+
subject { installer = described_class.installer; flexmock(installer) }
|
179
|
+
|
180
|
+
context :install do
|
181
|
+
let(:packages) { %w[foo bar] }
|
182
|
+
|
183
|
+
let(:installer_data) do
|
184
|
+
{
|
185
|
+
:aptitude => {
|
186
|
+
:command => "apt-get install -y #{packages.join(' ')} 2>&1",
|
187
|
+
:failure => "E: Couldn't find package #{packages.last}"
|
188
|
+
},
|
189
|
+
:yum => {
|
190
|
+
:command => "yum install -y #{packages.join(' ')} 2>&1",
|
191
|
+
:failure => "No package #{packages.last} available."
|
192
|
+
},
|
193
|
+
:zypper => {
|
194
|
+
:command => "zypper --no-gpg-checks -n #{packages.join(' ')} 2>&1",
|
195
|
+
:failure => "Package '#{packages.last}' not found."
|
196
|
+
}
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
before(:each) do
|
201
|
+
installer_data.keys.each do |installer_kind|
|
202
|
+
quiz = (installer_kind.to_s + '?').to_sym
|
203
|
+
subject.should_receive(quiz).and_return do
|
204
|
+
installer_kind == expected_installer_kind
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
shared_examples_for 'supports linux platform installer install' do
|
210
|
+
it 'should succeed if no packages are specified' do
|
211
|
+
subject.install([]).should == true
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should succeed if all packages install successfully' do
|
215
|
+
platform_class.
|
216
|
+
should_receive(:execute).
|
217
|
+
with(installer_data[expected_installer_kind][:command], {}).
|
218
|
+
and_return('ok')
|
219
|
+
subject.install(packages).should == true
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'should fail if one more packages are not found' do
|
223
|
+
platform_class.
|
224
|
+
should_receive(:execute).
|
225
|
+
with(installer_data[expected_installer_kind][:command], {}).
|
226
|
+
and_return(installer_data[expected_installer_kind][:failure])
|
227
|
+
expect { subject.install(packages) }.
|
228
|
+
to raise_error(
|
229
|
+
described_class::Installer::PackageNotFound,
|
230
|
+
'The following packages were not available: bar')
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
[:aptitude, :yum, :zypper].each do |eik|
|
235
|
+
context eik do
|
236
|
+
let(:expected_installer_kind) { eik }
|
237
|
+
|
238
|
+
it_should_behave_like 'supports linux platform installer install'
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
context 'given no installers' do
|
243
|
+
let(:expected_installer_kind) { nil }
|
244
|
+
|
245
|
+
it 'should fail if no installers are found' do
|
246
|
+
expect { subject.install(packages) }.
|
247
|
+
to raise_error(
|
248
|
+
described_class::Installer::PackageManagerNotFound,
|
249
|
+
'No package manager binary (apt, yum, zypper) found in /usr/bin')
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end # install
|
253
|
+
end # installer
|
254
|
+
|
255
|
+
context :shell do
|
256
|
+
subject { described_class.shell }
|
257
|
+
|
258
|
+
# required by 'supports any platform shell'
|
259
|
+
def instrument_booted_at(booted_at)
|
260
|
+
mock_file = flexmock(::File)
|
261
|
+
mock_file.should_receive(:read).with('/proc/stat').and_return(
|
262
|
+
<<EOF
|
263
|
+
...
|
264
|
+
ctxt 234567
|
265
|
+
btime #{booted_at.to_i}
|
266
|
+
processes 2345
|
267
|
+
...
|
268
|
+
EOF
|
269
|
+
)
|
270
|
+
mock_file.should_receive(:read).with('/proc/uptime').and_return do
|
271
|
+
uptime = yield
|
272
|
+
"#{uptime.to_f} #{0.99 * uptime.to_f}"
|
273
|
+
end
|
274
|
+
true
|
275
|
+
end
|
276
|
+
|
277
|
+
it_should_behave_like 'supports unix platform shell'
|
278
|
+
end
|
279
|
+
|
280
|
+
context :rng do
|
281
|
+
subject { described_class.rng }
|
282
|
+
|
283
|
+
it_should_behave_like 'supports unix platform rng'
|
284
|
+
end
|
285
|
+
|
286
|
+
context :process do
|
287
|
+
subject { described_class.process }
|
288
|
+
|
289
|
+
it_should_behave_like 'supports unix platform process'
|
290
|
+
end
|
291
|
+
|
292
|
+
context :volume_manager do
|
293
|
+
let(:blkid_cmd) { 'blkid 2>&1' }
|
294
|
+
|
295
|
+
subject { platform_class.volume_manager }
|
296
|
+
|
297
|
+
context :volumes do
|
298
|
+
it 'can parse volumes from blkid output' do
|
299
|
+
expected_volumes = [
|
300
|
+
{
|
301
|
+
:device => '/dev/xvdh1',
|
302
|
+
:sec_type => 'msdos',
|
303
|
+
:label => 'METADATA',
|
304
|
+
:uuid => '681B-8C5D',
|
305
|
+
:type => 'vfat',
|
306
|
+
:filesystem => 'vfat'
|
307
|
+
},
|
308
|
+
{
|
309
|
+
:device => '/dev/xvdb1',
|
310
|
+
:label => 'SWAP-xvdb1',
|
311
|
+
:uuid => 'd51fcca0-6b10-4934-a572-f3898dfd8840',
|
312
|
+
:type => 'swap',
|
313
|
+
:filesystem => 'swap'
|
314
|
+
},
|
315
|
+
{
|
316
|
+
:device => '/dev/xvda1',
|
317
|
+
:uuid => 'f4746f9c-0557-4406-9267-5e918e87ca2e',
|
318
|
+
:type => 'ext3',
|
319
|
+
:filesystem => 'ext3'
|
320
|
+
},
|
321
|
+
{
|
322
|
+
:device => '/dev/xvda2',
|
323
|
+
:uuid => '14d88b9e-9fe6-4974-a8d6-180acdae4016',
|
324
|
+
:type => 'ext3',
|
325
|
+
:filesystem => 'ext3'
|
326
|
+
}
|
327
|
+
]
|
328
|
+
platform_class.should_receive(:execute).with(blkid_cmd, {}).and_return(
|
329
|
+
<<EOF
|
330
|
+
/dev/xvdh1: SEC_TYPE="msdos" LABEL="METADATA" UUID="681B-8C5D" TYPE="vfat"
|
331
|
+
/dev/xvdb1: LABEL="SWAP-xvdb1" UUID="d51fcca0-6b10-4934-a572-f3898dfd8840" TYPE="swap"
|
332
|
+
/dev/xvda1: UUID="f4746f9c-0557-4406-9267-5e918e87ca2e" TYPE="ext3"
|
333
|
+
/dev/xvda2: UUID="14d88b9e-9fe6-4974-a8d6-180acdae4016" TYPE="ext3"
|
334
|
+
EOF
|
335
|
+
).once
|
336
|
+
subject.volumes.should == expected_volumes
|
337
|
+
end
|
338
|
+
|
339
|
+
it 'can parse volumes with hyphens or underscores (lvm use case)' do
|
340
|
+
expected_volumes = [
|
341
|
+
{
|
342
|
+
:device => '/dev/vg-rightscale-data_storage1/lvol0',
|
343
|
+
:uuid => 'ee34706d-866f-476e-9da4-6a18745456a4',
|
344
|
+
:type => 'xfs',
|
345
|
+
:filesystem => 'xfs'
|
346
|
+
}
|
347
|
+
]
|
348
|
+
platform_class.should_receive(:execute).with(blkid_cmd, {}).and_return(
|
349
|
+
<<EOF
|
350
|
+
/dev/vg-rightscale-data_storage1/lvol0: UUID="ee34706d-866f-476e-9da4-6a18745456a4" TYPE="xfs"
|
351
|
+
EOF
|
352
|
+
).once
|
353
|
+
subject.volumes.should == expected_volumes
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'can parse volumes with periods' do
|
357
|
+
expected_volumes = [
|
358
|
+
{
|
359
|
+
:device => '/dev/please.dont.do.this',
|
360
|
+
:uuid => 'ee34706d-866f-476e-9da4-6a18745456a4',
|
361
|
+
:type => 'xfs',
|
362
|
+
:filesystem => 'xfs'
|
363
|
+
}
|
364
|
+
]
|
365
|
+
platform_class.should_receive(:execute).with(blkid_cmd, {}).and_return(
|
366
|
+
<<EOF
|
367
|
+
/dev/please.dont.do.this: UUID="ee34706d-866f-476e-9da4-6a18745456a4" TYPE="xfs"
|
368
|
+
EOF
|
369
|
+
).once
|
370
|
+
subject.volumes.should == expected_volumes
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'raises a parser error when blkid output is malformed' do
|
374
|
+
platform_class.should_receive(:execute).with(blkid_cmd, {}).and_return('gibberish').once
|
375
|
+
expect { subject.volumes }.
|
376
|
+
to raise_error(described_class::VolumeManager::ParserError)
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'returns an empty list of volumes when blkid output is empty' do
|
380
|
+
platform_class.should_receive(:execute).with(blkid_cmd, {}).and_return('').once
|
381
|
+
subject.volumes.should == []
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'can filter results with single condition and single match' do
|
385
|
+
expected_volumes = [
|
386
|
+
{
|
387
|
+
:device => '/dev/xvdh1',
|
388
|
+
:sec_type => 'msdos',
|
389
|
+
:label => 'METADATA',
|
390
|
+
:uuid => '681B-8C5D',
|
391
|
+
:type => 'vfat',
|
392
|
+
:filesystem => 'vfat'
|
393
|
+
}
|
394
|
+
]
|
395
|
+
platform_class.should_receive(:execute).with(blkid_cmd, {}).and_return(
|
396
|
+
<<EOF
|
397
|
+
/dev/xvdh1: SEC_TYPE="msdos" LABEL="METADATA" UUID="681B-8C5D" TYPE="vfat"
|
398
|
+
/dev/xvdb1: LABEL="SWAP-xvdb1" UUID="d51fcca0-6b10-4934-a572-f3898dfd8840" TYPE="swap"
|
399
|
+
/dev/xvda1: UUID="f4746f9c-0557-4406-9267-5e918e87ca2e" TYPE="ext3"
|
400
|
+
/dev/xvda2: UUID="14d88b9e-9fe6-4974-a8d6-180acdae4016" TYPE="ext3"
|
401
|
+
EOF
|
402
|
+
).once
|
403
|
+
subject.volumes(:uuid => expected_volumes[0][:uuid]).should == expected_volumes
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'can filter results with multiple matches' do
|
407
|
+
expected_volumes = [
|
408
|
+
{
|
409
|
+
:device => '/dev/xvda1',
|
410
|
+
:uuid => 'f4746f9c-0557-4406-9267-5e918e87ca2e',
|
411
|
+
:type => 'ext3',
|
412
|
+
:filesystem => 'ext3'
|
413
|
+
},
|
414
|
+
{
|
415
|
+
:device => '/dev/xvda2',
|
416
|
+
:uuid => '14d88b9e-9fe6-4974-a8d6-180acdae4016',
|
417
|
+
:type => 'ext3',
|
418
|
+
:filesystem => 'ext3'
|
419
|
+
}
|
420
|
+
]
|
421
|
+
platform_class.should_receive(:execute).with(blkid_cmd, {}).and_return(
|
422
|
+
<<EOF
|
423
|
+
/dev/xvdh1: SEC_TYPE="msdos" LABEL="METADATA" UUID="681B-8C5D" TYPE="vfat"
|
424
|
+
/dev/xvdb1: LABEL="SWAP-xvdb1" UUID="d51fcca0-6b10-4934-a572-f3898dfd8840" TYPE="swap"
|
425
|
+
/dev/xvda1: UUID="f4746f9c-0557-4406-9267-5e918e87ca2e" TYPE="ext3"
|
426
|
+
/dev/xvda2: UUID="14d88b9e-9fe6-4974-a8d6-180acdae4016" TYPE="ext3"
|
427
|
+
EOF
|
428
|
+
).once
|
429
|
+
subject.volumes(:filesystem => 'ext3', :type => 'ext3').should == expected_volumes
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
context :mount_volume do
|
434
|
+
it 'mounts the specified volume if it is not already mounted' do
|
435
|
+
platform_class.
|
436
|
+
should_receive(:execute).
|
437
|
+
with('mount 2>&1', {}).
|
438
|
+
and_return(
|
439
|
+
<<EOF
|
440
|
+
/dev/xvda2 on / type ext3 (rw,noatime,errors=remount-ro)
|
441
|
+
proc on /proc type proc (rw,noexec,nosuid,nodev)
|
442
|
+
EOF
|
443
|
+
)
|
444
|
+
platform_class.
|
445
|
+
should_receive(:execute).
|
446
|
+
with('mount -t vfat /dev/xvdh1 /var/spool/softlayer 2>&1', {}).
|
447
|
+
and_return('')
|
448
|
+
subject.mount_volume(
|
449
|
+
{ :device => '/dev/xvdh1', :filesystem => 'vfat' },
|
450
|
+
'/var/spool/softlayer')
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'does not attempt to re-mount the volume' do
|
454
|
+
platform_class.
|
455
|
+
should_receive(:execute).
|
456
|
+
with('mount 2>&1', {}).
|
457
|
+
and_return(
|
458
|
+
<<EOF
|
459
|
+
/dev/xvda2 on / type ext3 (rw,noatime,errors=remount-ro)
|
460
|
+
proc on /proc type proc (rw,noexec,nosuid,nodev)
|
461
|
+
/dev/xvdh1 on /var/spool/softlayer type vfat (rw) [METADATA]
|
462
|
+
EOF
|
463
|
+
)
|
464
|
+
platform_class.
|
465
|
+
should_receive(:execute).
|
466
|
+
with('mount -t vfat /dev/xvdh1 /var/spool/softlayer 2>&1', {}).
|
467
|
+
and_return('')
|
468
|
+
subject.mount_volume(
|
469
|
+
{:device => '/dev/xvdh1', :filesystem => 'vfat'},
|
470
|
+
'/var/spool/softlayer')
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'raises argument error when the volume parameter is not a hash' do
|
474
|
+
expect { subject.mount_volume('', '') }.
|
475
|
+
to raise_error(ArgumentError)
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'raises argument error when the volume parameter is a hash but does not contain :device' do
|
479
|
+
expect { subject.mount_volume({}, '') }.
|
480
|
+
to raise_error(ArgumentError)
|
481
|
+
end
|
482
|
+
|
483
|
+
it 'raises volume error when the device is already mounted to a different mountpoint' do
|
484
|
+
platform_class.
|
485
|
+
should_receive(:execute).
|
486
|
+
with('mount 2>&1', {}).
|
487
|
+
and_return(
|
488
|
+
<<EOF
|
489
|
+
/dev/xvda2 on / type ext3 (rw,noatime,errors=remount-ro)
|
490
|
+
proc on /proc type proc (rw,noexec,nosuid,nodev)
|
491
|
+
none on /sys type sysfs (rw,noexec,nosuid,nodev)
|
492
|
+
none on /sys/kernel/debug type debugfs (rw)
|
493
|
+
none on /sys/kernel/security type securityfs (rw)
|
494
|
+
none on /dev type devtmpfs (rw,mode=0755)
|
495
|
+
none on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
|
496
|
+
none on /dev/shm type tmpfs (rw,nosuid,nodev)
|
497
|
+
none on /var/run type tmpfs (rw,nosuid,mode=0755)
|
498
|
+
none on /var/lock type tmpfs (rw,noexec,nosuid,nodev)
|
499
|
+
none on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
|
500
|
+
/dev/xvda1 on /boot type ext3 (rw,noatime)
|
501
|
+
/dev/xvdh1 on /mnt type vfat (rw) [METADATA]
|
502
|
+
EOF
|
503
|
+
)
|
504
|
+
expect do
|
505
|
+
subject.mount_volume(
|
506
|
+
{ :device => '/dev/xvdh1' }, '/var/spool/softlayer')
|
507
|
+
end.to raise_error(described_class::VolumeManager::VolumeError)
|
508
|
+
end
|
509
|
+
|
510
|
+
it 'raises volume error when a different device is already mounted to the specified mountpoint' do
|
511
|
+
platform_class.
|
512
|
+
should_receive(:execute).
|
513
|
+
with('mount 2>&1', {}).
|
514
|
+
and_return(
|
515
|
+
<<EOF
|
516
|
+
/dev/xvda2 on / type ext3 (rw,noatime,errors=remount-ro)
|
517
|
+
proc on /proc type proc (rw,noexec,nosuid,nodev)
|
518
|
+
none on /sys type sysfs (rw,noexec,nosuid,nodev)
|
519
|
+
none on /sys/kernel/debug type debugfs (rw)
|
520
|
+
none on /sys/kernel/security type securityfs (rw)
|
521
|
+
none on /dev type devtmpfs (rw,mode=0755)
|
522
|
+
none on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
|
523
|
+
none on /dev/shm type tmpfs (rw,nosuid,nodev)
|
524
|
+
none on /var/run type tmpfs (rw,nosuid,mode=0755)
|
525
|
+
none on /var/lock type tmpfs (rw,noexec,nosuid,nodev)
|
526
|
+
none on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
|
527
|
+
/dev/xvda1 on /boot type ext3 (rw,noatime)
|
528
|
+
/dev/xvdh2 on /var/spool/softlayer type vfat (rw) [METADATA]
|
529
|
+
EOF
|
530
|
+
)
|
531
|
+
expect do
|
532
|
+
subject.mount_volume(
|
533
|
+
{ :device => '/dev/xvdh1' }, '/var/spool/softlayer')
|
534
|
+
end.to raise_error(described_class::VolumeManager::VolumeError)
|
535
|
+
end
|
536
|
+
|
537
|
+
end # mount_volume
|
538
|
+
end # volume_manager
|
539
|
+
end # under unix/linux
|
540
|
+
end # RightScale::Platform
|