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