right_agent 0.17.2 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/lib/right_agent.rb +0 -1
  2. data/lib/right_agent/agent_config.rb +1 -1
  3. data/lib/right_agent/minimal.rb +8 -7
  4. data/lib/right_agent/monkey_patches.rb +4 -2
  5. data/lib/right_agent/monkey_patches/ruby_patch.rb +9 -9
  6. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +2 -2
  7. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +21 -51
  8. data/lib/right_agent/packets.rb +5 -1
  9. data/lib/right_agent/platform.rb +727 -299
  10. data/lib/right_agent/platform/unix/darwin/platform.rb +102 -0
  11. data/lib/right_agent/platform/unix/linux/platform.rb +305 -0
  12. data/lib/right_agent/platform/unix/platform.rb +226 -0
  13. data/lib/right_agent/platform/windows/mingw/platform.rb +447 -0
  14. data/lib/right_agent/platform/windows/mswin/platform.rb +236 -0
  15. data/lib/right_agent/platform/windows/platform.rb +1808 -0
  16. data/right_agent.gemspec +13 -8
  17. data/spec/platform/spec_helper.rb +216 -0
  18. data/spec/platform/unix/darwin/platform_spec.rb +181 -0
  19. data/spec/platform/unix/linux/platform_spec.rb +540 -0
  20. data/spec/platform/unix/spec_helper.rb +149 -0
  21. data/spec/platform/windows/mingw/platform_spec.rb +222 -0
  22. data/spec/platform/windows/mswin/platform_spec.rb +259 -0
  23. data/spec/platform/windows/spec_helper.rb +720 -0
  24. metadata +45 -30
  25. data/lib/right_agent/platform/darwin.rb +0 -285
  26. data/lib/right_agent/platform/linux.rb +0 -537
  27. data/lib/right_agent/platform/windows.rb +0 -1384
  28. data/spec/platform/darwin_spec.rb +0 -13
  29. data/spec/platform/linux_spec.rb +0 -38
  30. data/spec/platform/linux_volume_manager_spec.rb +0 -201
  31. data/spec/platform/platform_spec.rb +0 -80
  32. data/spec/platform/windows_spec.rb +0 -13
  33. data/spec/platform/windows_volume_manager_spec.rb +0 -318
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.2
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Lee Kirchhoff
9
9
  - Raphael Simon
10
10
  - Tony Spataro
11
+ - Scott Messier
11
12
  autorequire:
12
13
  bindir: bin
13
14
  cert_chain: []
14
- date: 2013-10-28 00:00:00.000000000 Z
15
+ date: 2013-10-29 00:00:00.000000000 Z
15
16
  dependencies:
16
17
  - !ruby/object:Gem::Dependency
17
18
  name: right_support
@@ -52,16 +53,16 @@ dependencies:
52
53
  - !ruby/object:Gem::Version
53
54
  version: '0.7'
54
55
  - !ruby/object:Gem::Dependency
55
- name: json
56
+ name: eventmachine
56
57
  requirement: !ruby/object:Gem::Requirement
57
58
  none: false
58
59
  requirements:
59
60
  - - ! '>='
60
61
  - !ruby/object:Gem::Version
61
- version: '1.4'
62
- - - <=
62
+ version: 0.12.10
63
+ - - <
63
64
  - !ruby/object:Gem::Version
64
- version: 1.7.6
65
+ version: '2.0'
65
66
  type: :runtime
66
67
  prerelease: false
67
68
  version_requirements: !ruby/object:Gem::Requirement
@@ -69,32 +70,42 @@ dependencies:
69
70
  requirements:
70
71
  - - ! '>='
71
72
  - !ruby/object:Gem::Version
72
- version: '1.4'
73
- - - <=
73
+ version: 0.12.10
74
+ - - <
74
75
  - !ruby/object:Gem::Version
75
- version: 1.7.6
76
+ version: '2.0'
76
77
  - !ruby/object:Gem::Dependency
77
- name: eventmachine
78
+ name: net-ssh
78
79
  requirement: !ruby/object:Gem::Requirement
79
80
  none: false
80
81
  requirements:
81
- - - ! '>='
82
- - !ruby/object:Gem::Version
83
- version: 0.12.10
84
- - - <
82
+ - - ~>
85
83
  - !ruby/object:Gem::Version
86
84
  version: '2.0'
87
85
  type: :runtime
88
86
  prerelease: false
89
87
  version_requirements: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ version: '2.0'
93
+ - !ruby/object:Gem::Dependency
94
+ name: ffi
95
+ requirement: !ruby/object:Gem::Requirement
90
96
  none: false
91
97
  requirements:
92
98
  - - ! '>='
93
99
  - !ruby/object:Gem::Version
94
- version: 0.12.10
95
- - - <
100
+ version: '0'
101
+ type: :runtime
102
+ prerelease: false
103
+ version_requirements: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
96
107
  - !ruby/object:Gem::Version
97
- version: '2.0'
108
+ version: '0'
98
109
  - !ruby/object:Gem::Dependency
99
110
  name: msgpack
100
111
  requirement: !ruby/object:Gem::Requirement
@@ -118,13 +129,13 @@ dependencies:
118
129
  - !ruby/object:Gem::Version
119
130
  version: '0.6'
120
131
  - !ruby/object:Gem::Dependency
121
- name: net-ssh
132
+ name: json
122
133
  requirement: !ruby/object:Gem::Requirement
123
134
  none: false
124
135
  requirements:
125
136
  - - ~>
126
137
  - !ruby/object:Gem::Version
127
- version: '2.0'
138
+ version: '1.4'
128
139
  type: :runtime
129
140
  prerelease: false
130
141
  version_requirements: !ruby/object:Gem::Requirement
@@ -132,7 +143,7 @@ dependencies:
132
143
  requirements:
133
144
  - - ~>
134
145
  - !ruby/object:Gem::Version
135
- version: '2.0'
146
+ version: '1.4'
136
147
  description: ! 'RightAgent provides a foundation for running an agent on a server
137
148
  to interface
138
149
 
@@ -224,9 +235,12 @@ files:
224
235
  - lib/right_agent/payload_formatter.rb
225
236
  - lib/right_agent/pid_file.rb
226
237
  - lib/right_agent/platform.rb
227
- - lib/right_agent/platform/darwin.rb
228
- - lib/right_agent/platform/linux.rb
229
- - lib/right_agent/platform/windows.rb
238
+ - lib/right_agent/platform/unix/darwin/platform.rb
239
+ - lib/right_agent/platform/unix/linux/platform.rb
240
+ - lib/right_agent/platform/unix/platform.rb
241
+ - lib/right_agent/platform/windows/mingw/platform.rb
242
+ - lib/right_agent/platform/windows/mswin/platform.rb
243
+ - lib/right_agent/platform/windows/platform.rb
230
244
  - lib/right_agent/scripts/agent_controller.rb
231
245
  - lib/right_agent/scripts/agent_deployer.rb
232
246
  - lib/right_agent/scripts/common_parser.rb
@@ -282,12 +296,13 @@ files:
282
296
  - spec/multiplexer_spec.rb
283
297
  - spec/operation_result_spec.rb
284
298
  - spec/packets_spec.rb
285
- - spec/platform/darwin_spec.rb
286
- - spec/platform/linux_spec.rb
287
- - spec/platform/linux_volume_manager_spec.rb
288
- - spec/platform/platform_spec.rb
289
- - spec/platform/windows_spec.rb
290
- - spec/platform/windows_volume_manager_spec.rb
299
+ - spec/platform/spec_helper.rb
300
+ - spec/platform/unix/darwin/platform_spec.rb
301
+ - spec/platform/unix/linux/platform_spec.rb
302
+ - spec/platform/unix/spec_helper.rb
303
+ - spec/platform/windows/mingw/platform_spec.rb
304
+ - spec/platform/windows/mswin/platform_spec.rb
305
+ - spec/platform/windows/spec_helper.rb
291
306
  - spec/results_mock.rb
292
307
  - spec/secure_identity_spec.rb
293
308
  - spec/security/cached_certificate_store_proxy_spec.rb
@@ -331,7 +346,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
331
346
  version: '0'
332
347
  segments:
333
348
  - 0
334
- hash: 435154341923902142
349
+ hash: -614048147788141961
335
350
  requirements: []
336
351
  rubyforge_project:
337
352
  rubygems_version: 1.8.26
@@ -1,285 +0,0 @@
1
- #
2
- # Copyright (c) 2009-2011 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
- module RightScale
24
-
25
- # Mac OS specific implementation
26
- class Platform
27
-
28
- attr_reader :flavor, :release
29
-
30
- # Initialize flavor and release
31
- def init
32
- @flavor = 'mac_os_x'
33
- @release = `sw_vers -productVersion`
34
- end
35
-
36
- class Filesystem
37
-
38
- # Is given command available in the PATH?
39
- #
40
- # === Parameters
41
- # command_name(String):: Name of command to be tested
42
- #
43
- # === Return
44
- # true:: If command is in path
45
- # false:: Otherwise
46
- def has_executable_in_path(command_name)
47
- return nil != find_executable_in_path(command_name)
48
- end
49
-
50
- # Finds the given command name in the PATH. this emulates the 'which'
51
- # command from linux (without the terminating newline).
52
- #
53
- # === Parameters
54
- # command_name(String):: Name of command to be tested
55
- #
56
- # === Return
57
- # path to first matching executable file in PATH or nil
58
- def find_executable_in_path(command_name)
59
- ENV['PATH'].split(/;|:/).each do |dir|
60
- path = File.join(dir, command_name)
61
- return path if File.executable?(path)
62
- end
63
- return nil
64
- end
65
-
66
- # Directory containing generated agent configuration files
67
- # @deprecated
68
- def cfg_dir
69
- warn "cfg_dir is deprecated; please use right_agent_cfg_dir"
70
- right_agent_cfg_dir
71
- end
72
-
73
- # RightScale state directory for the current platform
74
- # @deprecated
75
- def right_scale_state_dir
76
- warn "right_scale_state_dir is deprecated; please use either right_scale_static_state_dir or right_agent_dynamic_state_dir"
77
- right_scale_static_state_dir
78
- end
79
-
80
- # Directory containing generated agent configuration files
81
- def right_agent_cfg_dir
82
- '/var/lib/rightscale/right_agent'
83
- end
84
-
85
- # Static (time-invariant) state that is common to all RightScale apps/agents
86
- def right_scale_static_state_dir
87
- '/etc/rightscale.d'
88
- end
89
-
90
- # Static (time-invariant) state that is specific to RightLink
91
- def right_link_static_state_dir
92
- '/etc/rightscale.d/right_link'
93
- end
94
-
95
- # Dynamic, persistent runtime state that is specific to RightLink
96
- def right_link_dynamic_state_dir
97
- '/var/lib/rightscale/right_link'
98
- end
99
-
100
- # Data which is awaiting some kind of later processing
101
- def spool_dir
102
- '/var/spool'
103
- end
104
-
105
- def ssh_cfg_dir
106
- # TODO This is a guess, but since we don't have Darwin instances
107
- # it may need to be corrected later.
108
- '/etc/ssh'
109
- end
110
-
111
- # Cached data from applications. Such data is locally generated as a
112
- # result of time-consuming I/O or calculation. The application must
113
- # be able to regenerate or restore the data.
114
- def cache_dir
115
- '/var/cache'
116
- end
117
-
118
- # System logs
119
- def log_dir
120
- '/var/log'
121
- end
122
-
123
- # Source code, for reference purposes and for development.
124
- def source_code_dir
125
- '/usr/src'
126
- end
127
-
128
- # Temporary files.
129
- def temp_dir
130
- '/tmp'
131
- end
132
-
133
- # Path to place pid files
134
- def pid_dir
135
- '/var/run'
136
- end
137
-
138
- # Path to right link configuration and internal usage scripts
139
- def private_bin_dir
140
- '/opt/rightscale/bin'
141
- end
142
-
143
- def sandbox_dir
144
- '/opt/rightscale/sandbox'
145
- end
146
-
147
- # for windows compatibility; has no significance in darwin
148
- def long_path_to_short_path(long_path)
149
- return long_path
150
- end
151
-
152
- # for windows compatibility; has no significance in darwin
153
- def pretty_path(path, native_fs_flag = false)
154
- return path
155
- end
156
-
157
- # for windows compatibility; has no significance in linux
158
- def ensure_local_drive_path(path, temp_dir_name)
159
- return path
160
- end
161
-
162
- # for windows compatibility; just use File.symlink on Mac
163
- def create_symlink(old_name, new_name)
164
- File.symlink(old_name, new_name)
165
- end
166
- end # Filesystem
167
-
168
- # Provides utilities for managing volumes (disks).
169
- class VolumeManager
170
- def initialize
171
- raise "not yet implemented"
172
- end
173
- end
174
-
175
- class Shell
176
-
177
- NULL_OUTPUT_NAME = "/dev/null"
178
-
179
- def format_script_file_name(partial_script_file_path, default_extension = nil)
180
- # shell file extensions are not required in darwin assuming the script
181
- # contains a shebang. if not, the error should be obvious.
182
- return partial_script_file_path
183
- end
184
-
185
- def format_executable_command(executable_file_path, *arguments)
186
- escaped = []
187
- [executable_file_path, arguments].flatten.each do |arg|
188
- value = arg.to_s
189
- needs_escape = value.index(" ") || value.index("\"") || value.index("'")
190
- escaped << (needs_escape ? "\"#{value.gsub("\"", "\\\"")}\"" : value)
191
- end
192
- return escaped.join(" ")
193
- end
194
-
195
- def format_shell_command(shell_script_file_path, *arguments)
196
- # shell files containing shebang are directly executable in darwin, so
197
- # assume our scripts have shebang. if not, the error should be obvious.
198
- return format_executable_command(shell_script_file_path, arguments)
199
- end
200
-
201
- def format_redirect_stdout(cmd, target = NULL_OUTPUT_NAME)
202
- return cmd + " 1>#{target}"
203
- end
204
-
205
- def format_redirect_stderr(cmd, target = NULL_OUTPUT_NAME)
206
- return cmd + " 2>#{target}"
207
- end
208
-
209
- def format_redirect_both(cmd, target = NULL_OUTPUT_NAME)
210
- return cmd + " 1>#{target} 2>&1"
211
- end
212
-
213
- def sandbox_ruby
214
- "#{RightScale::Platform.filesystem.sandbox_dir}/bin/ruby"
215
- end
216
-
217
- # Gets the current system uptime.
218
- #
219
- # === Return
220
- # the time the machine has been up in seconds, 0 if there was an error.
221
- def uptime
222
- return (Time.now.to_i.to_f - booted_at.to_f) rescue 0.0
223
- end
224
-
225
- # Gets the time at which the system was booted
226
- #
227
- # === Return
228
- # the UTC timestamp at which the system was booted
229
- def booted_at
230
- match = /sec = ([0-9]+)/.match(`sysctl kern.boottime`)
231
-
232
- if match && (match[1].to_i > 0)
233
- return match[1].to_i
234
- else
235
- return nil
236
- end
237
- end
238
-
239
- end # Shell
240
-
241
- class Controller
242
- # Shutdown machine now
243
- def shutdown
244
- `shutdown -h now`
245
- end
246
-
247
- # Reboot machine now
248
- def reboot
249
- `shutdown -r now`
250
- end
251
- end
252
-
253
- class Rng
254
- def pseudorandom_bytes(count)
255
- f = File.open('/dev/urandom', 'r')
256
- bytes = f.read(count)
257
- f.close
258
-
259
- bytes
260
- end
261
- end
262
-
263
- class Process
264
- # queries resident set size (current working set size in Windows).
265
- #
266
- # === Parameters
267
- # pid(Fixnum):: process ID or nil for current process
268
- #
269
- # === Return
270
- # result(Fixnum):: current set size in KB
271
- def resident_set_size(pid=nil)
272
- pid = $$ unless pid
273
- return `ps -o rss= -p #{pid}`.to_i
274
- end
275
- end
276
-
277
- class Installer
278
- def install(packages)
279
- raise "not yet implemented"
280
- end
281
- end
282
-
283
- end # Platform
284
-
285
- end # RightScale
@@ -1,537 +0,0 @@
1
- #
2
- # Copyright (c) 2009-2011 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
- module RightScale
24
-
25
- # Linux specific implementation
26
- class Platform
27
-
28
- FEDORA_REL = '/etc/fedora-release'
29
- FEDORA_SIG = /Fedora release ([0-9]+) \(.*\)/
30
-
31
- attr_reader :flavor, :release, :codename
32
-
33
- # Initialize flavor, release and codename
34
- def init
35
- system('lsb_release --help > /dev/null 2>&1')
36
- if $?.success?
37
- # Use the lsb_release utility if it's available
38
- @flavor = `lsb_release -is`.strip.downcase
39
- @release = `lsb_release -rs`.strip
40
- @codename = `lsb_release -cs`.strip
41
- elsif File.exist?(FEDORA_REL) && (match = FEDORA_SIG.match(File.read(FEDORA_REL)))
42
- # Parse the fedora-release file if it exists
43
- @flavor = 'fedora'
44
- @release = match[1]
45
- @codename = match[2]
46
- else
47
- @distro = @release = @codename = 'unknown'
48
- end
49
- end
50
-
51
- # Is this machine running Ubuntu?
52
- #
53
- # === Return
54
- # true:: If Linux flavor is Ubuntu
55
- # false:: Otherwise
56
- def ubuntu?
57
- @flavor =~ /ubuntu/
58
- end
59
-
60
- # Is this machine running CentOS?
61
- #
62
- # === Return
63
- # true:: If Linux flavor is CentOS
64
- # false:: Otherwise
65
- def centos?
66
- @flavor =~ /centos/
67
- end
68
-
69
- # Is this machine running Suse
70
- #
71
- # === Return
72
- # true:: If Linux flavor is Suse
73
- # false:: Otherwise
74
- def suse?
75
- @flavor =~ /suse/
76
- end
77
-
78
- # Is this machine running rhel?
79
- #
80
- # === Return
81
- # true:: If Linux flavor is rhel
82
- # false:: Otherwise
83
- def rhel?
84
- @flavor =~ /redhatenterpriseserver/
85
- end
86
-
87
- class Filesystem
88
-
89
- # Is given command available in the PATH?
90
- #
91
- # === Parameters
92
- # command_name(String):: Name of command to be tested
93
- #
94
- # === Return
95
- # true:: If command is in path
96
- # false:: Otherwise
97
- def has_executable_in_path(command_name)
98
- return nil != find_executable_in_path(command_name)
99
- end
100
-
101
- # Finds the given command name in the PATH. this emulates the 'which'
102
- # command from linux (without the terminating newline).
103
- #
104
- # === Parameters
105
- # command_name(String):: Name of command to be tested
106
- #
107
- # === Return
108
- # path to first matching executable file in PATH or nil
109
- def find_executable_in_path(command_name)
110
- ENV['PATH'].split(/;|:/).each do |dir|
111
- path = File.join(dir, command_name)
112
- return path if File.executable?(path)
113
- end
114
- return nil
115
- end
116
-
117
- # Directory containing generated agent configuration files
118
- # @deprecated
119
- def cfg_dir
120
- warn "cfg_dir is deprecated; please use right_agent_cfg_dir"
121
- right_agent_cfg_dir
122
- end
123
-
124
- # RightScale state directory for the current platform
125
- # @deprecated
126
- def right_scale_state_dir
127
- warn "right_scale_state_dir is deprecated; please use either right_scale_static_state_dir or right_agent_dynamic_state_dir"
128
- right_scale_static_state_dir
129
- end
130
-
131
- # Directory containing generated agent configuration files
132
- def right_agent_cfg_dir
133
- '/var/lib/rightscale/right_agent'
134
- end
135
-
136
- # Static (time-invariant) state that is common to all RightScale apps/agents
137
- def right_scale_static_state_dir
138
- '/etc/rightscale.d'
139
- end
140
-
141
- # Static (time-invariant) state that is specific to RightLink
142
- def right_link_static_state_dir
143
- '/etc/rightscale.d/right_link'
144
- end
145
-
146
- # Dynamic, persistent runtime state that is specific to RightLink
147
- def right_link_dynamic_state_dir
148
- '/var/lib/rightscale/right_link'
149
- end
150
-
151
- # Data which is awaiting some kind of later processing
152
- def spool_dir
153
- '/var/spool'
154
- end
155
-
156
- def ssh_cfg_dir
157
- '/etc/ssh'
158
- end
159
-
160
- # Cached data from applications. Such data is locally generated as a
161
- # result of time-consuming I/O or calculation. The application must
162
- # be able to regenerate or restore the data.
163
- def cache_dir
164
- '/var/cache'
165
- end
166
-
167
- # System logs
168
- def log_dir
169
- '/var/log'
170
- end
171
-
172
- # Source code, for reference purposes and for development.
173
- def source_code_dir
174
- '/usr/src'
175
- end
176
-
177
- # Temporary files.
178
- def temp_dir
179
- '/tmp'
180
- end
181
-
182
- # Path to place pid files
183
- def pid_dir
184
- '/var/run'
185
- end
186
-
187
- # Path to right link configuration and internal usage scripts
188
- def private_bin_dir
189
- '/opt/rightscale/bin'
190
- end
191
-
192
- def sandbox_dir
193
- '/opt/rightscale/sandbox'
194
- end
195
-
196
- # for windows compatibility; has no significance in linux
197
- def long_path_to_short_path(long_path)
198
- return long_path
199
- end
200
-
201
- # for windows compatibility; has no significance in linux
202
- def pretty_path(path, native_fs_flag = false)
203
- return path
204
- end
205
-
206
- # for windows compatibility; has no significance in linux
207
- def ensure_local_drive_path(path, temp_dir_name)
208
- return path
209
- end
210
-
211
- # for windows compatibility; just use File.symlink on Linux
212
- def create_symlink(old_name, new_name)
213
- File.symlink(old_name, new_name)
214
- end
215
- end
216
-
217
- # Provides utilities for managing volumes (disks).
218
- class VolumeManager
219
-
220
- class ParserError < Exception; end
221
- class VolumeError < Exception; end
222
-
223
- def initialize
224
-
225
- end
226
-
227
- # Gets a list of currently visible volumes in the form:
228
- # [{:device, :label, :uuid, :type, :filesystem}]
229
- #
230
- # === Parameters
231
- # conditions(Hash):: hash of conditions to match, or nil (default)
232
- #
233
- # === Return
234
- # result(Array):: array of volume hashes, or an empty array
235
- #
236
- # === Raise
237
- # VolumeError:: on failure to execute `blkid` to obtain raw output
238
- # ParserError:: on failure to parse volume list
239
- def volumes(conditions = nil)
240
- exit_code, blkid_resp = blocking_popen('blkid')
241
- raise VolumeError.new("Failed to list volumes exit code = #{exit_code}\nblkid\n#{blkid_resp}") unless exit_code == 0
242
- return parse_volumes(blkid_resp, conditions)
243
- end
244
-
245
- # Parses raw output from `blkid` into a hash of volumes
246
- #
247
- # The hash will contain the device name with a key of :device, and each key value pair
248
- # for the device. In order to keep parity with the Windows VolumeManager.parse_volumes
249
- # method, the :type key will be duplicated as :filesystem
250
- #
251
- # Example of raw output from `blkid`
252
- #
253
- # /dev/xvdh1: SEC_TYPE="msdos" LABEL="METADATA" UUID="681B-8C5D" TYPE="vfat"
254
- # /dev/xvdb1: LABEL="SWAP-xvdb1" UUID="d51fcca0-6b10-4934-a572-f3898dfd8840" TYPE="swap"
255
- # /dev/xvda1: UUID="f4746f9c-0557-4406-9267-5e918e87ca2e" TYPE="ext3"
256
- # /dev/xvda2: UUID="14d88b9e-9fe6-4974-a8d6-180acdae4016" TYPE="ext3"
257
- #
258
- # === Parameters
259
- # output_text(String):: raw output from `blkid`
260
- # conditions(Hash):: hash of conditions to match, or nil (default)
261
- #
262
- # === Return
263
- # result(Array):: array of volume hashes, or an empty array
264
- #
265
- # === Raise
266
- # ParserError:: on failure to parse volume list
267
- def parse_volumes(output_text, conditions = nil)
268
- results = []
269
- output_text.lines.each do |line|
270
- volume = {}
271
- line_regex = /^([\/a-z0-9_\-\.]+):(.*)/
272
- volmatch = line_regex.match(line)
273
- raise ParserError.new("Failed to parse volume info from #{line.inspect} using #{line_regex.inspect}") unless volmatch
274
- volume[:device] = volmatch[1]
275
- volmatch[2].split(' ').each do |pair|
276
- pair_regex = /([a-zA-Z_\-]+)=(.*)/
277
- match = pair_regex.match(pair)
278
- raise ParserError.new("Failed to parse volume info from #{pair} using #{pair_regex.inspect}") unless match
279
- volume[:"#{match[1].downcase}"] = match[2].gsub('"', '')
280
- # Make this as much like the windows output as possible
281
- if match[1] == "TYPE"
282
- volume[:filesystem] = match[2].gsub('"', '')
283
- end
284
- end
285
- if conditions
286
- matched = true
287
- conditions.each do |key,value|
288
-
289
- unless volume[key] == value
290
- matched = false
291
- break
292
- end
293
- end
294
- results << volume if matched
295
- else
296
- results << volume
297
- end
298
- end
299
- results
300
- end
301
-
302
- # Mounts a volume (returned by VolumeManager.volumes) to the mountpoint specified.
303
- #
304
- # === Parameters
305
- # volume(Hash):: the volume hash returned by VolumeManager.volumes
306
- # mountpoint(String):: the exact path where the device will be mounted ex: /mnt
307
- #
308
- # === Return
309
- # always true
310
- #
311
- # === Raise
312
- # ArgumentError:: on invalid parameters
313
- # VolumeError:: on a failure to mount the device
314
- def mount_volume(volume, mountpoint)
315
- raise ArgumentError.new("Invalid volume = #{volume.inspect}") unless volume.is_a?(Hash) && volume[:device]
316
- exit_code, mount_list_output = blocking_popen('mount')
317
- raise VolumeError.new("Failed interrogation of current mounts; Exit Status: #{exit_code}\nError: #{mount_list_output}") unless exit_code == 0
318
-
319
- device_match = /^#{volume[:device]} on (.+?)\s/.match(mount_list_output)
320
- mountpoint_from_device_match = device_match ? device_match[1] : mountpoint
321
- unless (mountpoint_from_device_match && mountpoint_from_device_match == mountpoint)
322
- raise VolumeError.new("Attempted to mount volume \"#{volume[:device]}\" at \"#{mountpoint}\" but it was already mounted at #{mountpoint_from_device_match}")
323
- end
324
-
325
- mountpoint_match = /^(.+?) on #{mountpoint}/.match(mount_list_output)
326
- device_from_mountpoint_match = mountpoint_match ? mountpoint_match[1] : volume[:device]
327
- unless (device_from_mountpoint_match && device_from_mountpoint_match == volume[:device])
328
- raise VolumeError.new("Attempted to mount volume \"#{volume[:device]}\" at \"#{mountpoint}\" but \"#{device_from_mountpoint_match}\" was already mounted there.")
329
- end
330
-
331
- # The volume is already mounted at the correct mountpoint
332
- return true if /^#{volume[:device]} on #{mountpoint}/.match(mount_list_output)
333
-
334
- # TODO: Maybe validate that the mountpoint is valid *nix path?
335
- exit_code, mount_output = blocking_popen("mount -t #{volume[:filesystem].strip} #{volume[:device]} #{mountpoint}")
336
- raise VolumeError.new("Failed to mount volume to \"#{mountpoint}\" with device \"#{volume[:device]}\"; Exit Status: #{exit_code}\nError: #{mount_output}") unless exit_code == 0
337
- return true
338
- end
339
-
340
- # Runs the specified command synchronously using IO.popen
341
- #
342
- # === Parameters
343
- # command(String):: system command to be executed
344
- #
345
- # === Return
346
- # result(Array):: tuple of [exit_code, output_text]
347
- def blocking_popen(command)
348
- output_text = ""
349
- IO.popen(command) do |io|
350
- output_text = io.read
351
- end
352
- return $?.exitstatus, output_text
353
- end
354
- end # VolumeManager
355
-
356
- class Shell
357
-
358
- NULL_OUTPUT_NAME = "/dev/null"
359
-
360
- def format_script_file_name(partial_script_file_path, default_extension = nil)
361
- # shell file extensions are not required in linux assuming the script
362
- # contains a shebang. if not, the error should be obvious.
363
- return partial_script_file_path
364
- end
365
-
366
- def format_executable_command(executable_file_path, *arguments)
367
- escaped = []
368
- [executable_file_path, arguments].flatten.each do |arg|
369
- value = arg.to_s
370
- needs_escape = value.index(" ") || value.index("\"") || value.index("'")
371
- escaped << (needs_escape ? "\"#{value.gsub("\"", "\\\"")}\"" : value)
372
- end
373
- return escaped.join(" ")
374
- end
375
-
376
- def format_shell_command(shell_script_file_path, *arguments)
377
- # shell files containing shebang are directly executable in linux, so
378
- # assume our scripts have shebang. if not, the error should be obvious.
379
- return format_executable_command(shell_script_file_path, arguments)
380
- end
381
-
382
- def format_redirect_stdout(cmd, target = NULL_OUTPUT_NAME)
383
- return cmd + " 1>#{target}"
384
- end
385
-
386
- def format_redirect_stderr(cmd, target = NULL_OUTPUT_NAME)
387
- return cmd + " 2>#{target}"
388
- end
389
-
390
- def format_redirect_both(cmd, target = NULL_OUTPUT_NAME)
391
- return cmd + " 1>#{target} 2>&1"
392
- end
393
-
394
- def sandbox_ruby
395
- "#{RightScale::Platform.filesystem.sandbox_dir}/bin/ruby"
396
- end
397
-
398
- # Gets the current system uptime.
399
- #
400
- # === Return
401
- # the time the machine has been up in seconds, 0 if there was an error.
402
- def uptime
403
- return File.read('/proc/uptime').split(/\s+/)[0].to_f rescue 0.0
404
- end
405
-
406
- # Gets the time at which the system was booted
407
- #
408
- # === Return
409
- # the UTC timestamp at which the system was booted
410
- def booted_at
411
- match = /btime ([0-9]+)/.match(File.read('/proc/stat')) rescue nil
412
-
413
- if match && (match[1].to_i > 0)
414
- return match[1].to_i
415
- else
416
- return nil
417
- end
418
- end
419
- end
420
-
421
- class Controller
422
- # Shutdown machine now
423
- def shutdown
424
- `init 0`
425
- end
426
-
427
- # Reboot machine now
428
- def reboot
429
- `init 6`
430
- end
431
- end
432
-
433
- class Rng
434
- def pseudorandom_bytes(count)
435
- f = File.open('/dev/urandom', 'r')
436
- bytes = f.read(count)
437
- f.close
438
-
439
- bytes
440
- end
441
- end
442
-
443
- class Process
444
- # queries resident set size (current working set size in Windows).
445
- #
446
- # === Parameters
447
- # pid(Fixnum):: process ID or nil for current process
448
- #
449
- # === Return
450
- # result(Fixnum):: current set size in KB
451
- def resident_set_size(pid=nil)
452
- pid = $$ unless pid
453
- return `ps -o rss= -p #{pid}`.to_i
454
- end
455
- end
456
-
457
- class Installer
458
- # The output generated by the Installer class
459
- attr_accessor :output
460
-
461
- @output = ""
462
-
463
- class PackageNotFound < Exception; end
464
- class PackageManagerNotFound < Exception; end
465
-
466
- # Does this machine have aptitude
467
- #
468
- # === Return
469
- # true:: If aptitude is available in the expected directory
470
- # false:: Otherwise
471
- def aptitude?
472
- File.executable? '/usr/bin/apt-get'
473
- end
474
-
475
- # Does this machine have yum
476
- #
477
- # === Return
478
- # true:: If yum is available in the expected directory
479
- # false:: Otherwise
480
- def yum?
481
- File.executable? '/usr/bin/yum'
482
- end
483
-
484
- # Does this machine have zypper
485
- #
486
- # === Return
487
- # true:: If zypper is available in the expected directory
488
- # false:: Otherwise
489
- def zypper?
490
- File.executable? '/usr/bin/zypper'
491
- end
492
-
493
- # Install packages based on installed package manager
494
- #
495
- # === Parameters
496
- # command_name(Array):: Array of packages names to be installed
497
- #
498
- # === Return
499
- # true:: If installations of all packages was successfull
500
- # false:: Otherwise
501
- def install(packages)
502
- return true if packages.empty?
503
-
504
- packages = packages.uniq.join(' ')
505
- failed_packages = []
506
-
507
- if yum?
508
- command = "yum install -y #{packages} 2>&1"
509
- regex = /No package (.*) available\./
510
- elsif aptitude?
511
- ENV['DEBIAN_FRONTEND'] = "noninteractive"
512
- command = "apt-get install -y #{packages} 2>&1"
513
- regex = /E: Couldn't find package (.*)/
514
- elsif zypper?
515
- command = "zypper --no-gpg-checks -n #{packages} 2>&1"
516
- regex = /Package '(.*)' not found\./
517
- else
518
- raise PackageManagerNotFound, "No package manager binary (apt, yum, zypper) found in /usr/bin"
519
- end
520
-
521
- @output = run_installer_command(command)
522
- @output.scan(regex) { |package| failed_packages << package.first }
523
- raise PackageNotFound, "The following packages were not available: #{failed_packages.join(', ')}" unless failed_packages.empty?
524
- return true
525
- end
526
-
527
- protected
528
-
529
- # A test hook so we can mock the invocation of the installer.
530
- def run_installer_command(cmd)
531
- `#{cmd}`
532
- end
533
- end
534
-
535
- end # Platform
536
-
537
- end # RightScale