continuent-tools-core 0.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.
- checksums.yaml +7 -0
- data/LICENSE +202 -0
- data/README.md +44 -0
- data/lib/continuent-tools-core.rb +20 -0
- data/lib/tungsten.rb +46 -0
- data/lib/tungsten/README +297 -0
- data/lib/tungsten/api.rb +553 -0
- data/lib/tungsten/common.rb +190 -0
- data/lib/tungsten/exec.rb +570 -0
- data/lib/tungsten/install.rb +332 -0
- data/lib/tungsten/properties.rb +476 -0
- data/lib/tungsten/script.rb +952 -0
- data/lib/tungsten/status.rb +177 -0
- data/lib/tungsten/util.rb +523 -0
- metadata +154 -0
@@ -0,0 +1,190 @@
|
|
1
|
+
DEFAULTS = "defaults"
|
2
|
+
REPL_RMI_PORT = "repl_rmi_port"
|
3
|
+
MGR_RMI_PORT = "mgr_rmi_port"
|
4
|
+
HOST_ENABLE_REPLICATOR = "host_enable_replicator"
|
5
|
+
HOST_ENABLE_MANAGER = "host_enable_manager"
|
6
|
+
HOST_ENABLE_CONNECTOR = "host_enable_connector"
|
7
|
+
MGR_API = "mgr_api"
|
8
|
+
MGR_API_PORT = "mgr_api_port"
|
9
|
+
MGR_API_ADDRESS = "mgr_api_address"
|
10
|
+
DEPLOYMENT_HOST = "deployment_host"
|
11
|
+
DEPLOYMENT_DATASERVICE = "deployment_dataservice"
|
12
|
+
DEPLOYMENT_SERVICE = "service_name"
|
13
|
+
HOSTS = "hosts"
|
14
|
+
DATASERVICES = "dataservices"
|
15
|
+
DATASOURCES = "datasources"
|
16
|
+
MANAGERS = "managers"
|
17
|
+
REPL_SERVICES = "repl_services"
|
18
|
+
CONNECTORS = "connectors"
|
19
|
+
CURRENT_RELEASE_DIRECTORY = "tungsten"
|
20
|
+
|
21
|
+
class MessageError < StandardError
|
22
|
+
end
|
23
|
+
|
24
|
+
class CommandError < StandardError
|
25
|
+
attr_reader :command, :rc, :result, :errors
|
26
|
+
|
27
|
+
def initialize(command, rc, result, errors="")
|
28
|
+
@command = command
|
29
|
+
@rc = rc
|
30
|
+
@result = result
|
31
|
+
@errors = errors
|
32
|
+
|
33
|
+
super(build_message())
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_message
|
37
|
+
if @errors == ""
|
38
|
+
errors = "No Errors"
|
39
|
+
else
|
40
|
+
errors = "Errors: #{errors}"
|
41
|
+
end
|
42
|
+
|
43
|
+
"Failed: #{command}, RC: #{rc}, Result: #{result}, #{errors}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class RemoteCommandError < CommandError
|
48
|
+
attr_reader :user, :host
|
49
|
+
|
50
|
+
def initialize(user, host, command, rc, result, errors = "")
|
51
|
+
@user = user
|
52
|
+
@host = host
|
53
|
+
super(command, rc, result, errors)
|
54
|
+
end
|
55
|
+
|
56
|
+
def build_message
|
57
|
+
if @errors == ""
|
58
|
+
errors = "No Errors"
|
59
|
+
else
|
60
|
+
errors = "Errors: #{errors}"
|
61
|
+
end
|
62
|
+
|
63
|
+
"Failed: #{command}, RC: #{rc}, Result: #{result}, #{errors}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class IgnoreError < StandardError
|
68
|
+
end
|
69
|
+
|
70
|
+
# Disable guessing by the OptionParser
|
71
|
+
class OptionParser
|
72
|
+
def stack
|
73
|
+
@stack
|
74
|
+
end
|
75
|
+
|
76
|
+
class OptionMap < Hash
|
77
|
+
end
|
78
|
+
|
79
|
+
module Completion
|
80
|
+
def complete(key, icase = false, pat = nil)
|
81
|
+
end
|
82
|
+
|
83
|
+
def convert(opt = nil, val = nil, *)
|
84
|
+
val
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Define an additional Logger level
|
90
|
+
class Logger
|
91
|
+
NOTICE = 1.5
|
92
|
+
end
|
93
|
+
|
94
|
+
class String
|
95
|
+
if RUBY_VERSION < "1.9"
|
96
|
+
def getbyte(index)
|
97
|
+
self[index]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Apply sorting when building a JSON string
|
103
|
+
module JSON
|
104
|
+
module Pure
|
105
|
+
module Generator
|
106
|
+
module GeneratorMethods
|
107
|
+
module Hash
|
108
|
+
private
|
109
|
+
|
110
|
+
def json_transform(state)
|
111
|
+
valid_keys = 0
|
112
|
+
|
113
|
+
delim = ','
|
114
|
+
delim << state.object_nl
|
115
|
+
result = '{'
|
116
|
+
result << state.object_nl
|
117
|
+
depth = state.depth += 1
|
118
|
+
first = true
|
119
|
+
indent = !state.object_nl.empty?
|
120
|
+
keys().sort{ |a, b| a.to_s() <=> b.to_s() }.each{|key|
|
121
|
+
value = self[key]
|
122
|
+
json = value.to_json(state)
|
123
|
+
if json == ""
|
124
|
+
next
|
125
|
+
end
|
126
|
+
valid_keys = valid_keys+1
|
127
|
+
|
128
|
+
result << delim unless first
|
129
|
+
result << state.indent * depth if indent
|
130
|
+
result << key.to_s.to_json(state)
|
131
|
+
result << state.space_before
|
132
|
+
result << ':'
|
133
|
+
result << state.space
|
134
|
+
result << json
|
135
|
+
first = false
|
136
|
+
}
|
137
|
+
depth = state.depth -= 1
|
138
|
+
result << state.object_nl
|
139
|
+
result << state.indent * depth if indent if indent
|
140
|
+
result << '}'
|
141
|
+
|
142
|
+
if valid_keys == 0 && depth != 0
|
143
|
+
return ""
|
144
|
+
end
|
145
|
+
|
146
|
+
result
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
module Array
|
151
|
+
private
|
152
|
+
|
153
|
+
def json_transform(state)
|
154
|
+
valid_keys = 0
|
155
|
+
|
156
|
+
delim = ','
|
157
|
+
delim << state.array_nl
|
158
|
+
result = '['
|
159
|
+
result << state.array_nl
|
160
|
+
depth = state.depth += 1
|
161
|
+
first = true
|
162
|
+
indent = !state.array_nl.empty?
|
163
|
+
each { |value|
|
164
|
+
json = value.to_json(state)
|
165
|
+
if json == ""
|
166
|
+
next
|
167
|
+
end
|
168
|
+
valid_keys = valid_keys+1
|
169
|
+
|
170
|
+
result << delim unless first
|
171
|
+
result << state.indent * depth if indent
|
172
|
+
result << json
|
173
|
+
first = false
|
174
|
+
}
|
175
|
+
depth = state.depth -= 1
|
176
|
+
result << state.array_nl
|
177
|
+
result << state.indent * depth if indent
|
178
|
+
result << ']'
|
179
|
+
|
180
|
+
if valid_keys == 0 && depth != 0
|
181
|
+
return ""
|
182
|
+
end
|
183
|
+
|
184
|
+
result
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,570 @@
|
|
1
|
+
require "open4"
|
2
|
+
require "resolv"
|
3
|
+
require "ifconfig"
|
4
|
+
|
5
|
+
class TungstenUtil
|
6
|
+
def initialize()
|
7
|
+
super()
|
8
|
+
|
9
|
+
@log_results = false
|
10
|
+
@forward_results = false
|
11
|
+
@forward_results_level = Logger::INFO
|
12
|
+
end
|
13
|
+
|
14
|
+
# Disable debug logging of command output
|
15
|
+
def log_cmd_results?(v = nil)
|
16
|
+
if v != nil
|
17
|
+
@log_results = v
|
18
|
+
end
|
19
|
+
|
20
|
+
if @log_results == nil && forward_cmd_results?() == true
|
21
|
+
false
|
22
|
+
elsif @log_results == false
|
23
|
+
false
|
24
|
+
else
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def forward_cmd_results?(v = nil, level = Logger::INFO)
|
30
|
+
if v != nil
|
31
|
+
@forward_results = v
|
32
|
+
@forward_results_level = level
|
33
|
+
end
|
34
|
+
|
35
|
+
if @forward_results == true
|
36
|
+
true
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_forward_log_level
|
43
|
+
@forward_results_level
|
44
|
+
end
|
45
|
+
|
46
|
+
# Run the {command} and return a string of STDOUT
|
47
|
+
def cmd_result(command, ignore_fail = false)
|
48
|
+
errors = ""
|
49
|
+
result = ""
|
50
|
+
threads = []
|
51
|
+
|
52
|
+
debug("Execute `#{command}`")
|
53
|
+
status = Open4::popen4("export LANG=en_US; #{command}") do |pid, stdin, stdout, stderr|
|
54
|
+
stdin.close
|
55
|
+
|
56
|
+
threads << Thread.new{
|
57
|
+
while data = stdout.gets()
|
58
|
+
if data.to_s() != ""
|
59
|
+
result+=data
|
60
|
+
|
61
|
+
if data != "" && forward_cmd_results?()
|
62
|
+
write(data, (parse_log_level(data) || get_forward_log_level()), nil, false)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
}
|
67
|
+
threads << Thread.new{
|
68
|
+
while edata = stderr.gets()
|
69
|
+
if edata.to_s() != ""
|
70
|
+
errors+=edata
|
71
|
+
|
72
|
+
if edata != "" && forward_cmd_results?()
|
73
|
+
write(edata, (parse_log_level(edata) || get_forward_log_level()), nil, false)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
}
|
78
|
+
|
79
|
+
threads.each{|t| t.join() }
|
80
|
+
end
|
81
|
+
|
82
|
+
result.strip!()
|
83
|
+
errors.strip!()
|
84
|
+
|
85
|
+
original_errors = errors
|
86
|
+
rc = status.exitstatus
|
87
|
+
if errors == ""
|
88
|
+
errors = "No Errors"
|
89
|
+
else
|
90
|
+
errors = "Errors: #{errors}"
|
91
|
+
end
|
92
|
+
|
93
|
+
if log_cmd_results?()
|
94
|
+
debug("RC: #{rc}, Result: #{result}, #{errors}")
|
95
|
+
elsif forward_cmd_results?()
|
96
|
+
debug("RC: #{rc}, Result length #{result.length}, Errors length #{original_errors.length}")
|
97
|
+
else
|
98
|
+
debug("RC: #{rc}, Result length #{result.length}, #{errors}")
|
99
|
+
end
|
100
|
+
if rc != 0 && ! ignore_fail
|
101
|
+
raise CommandError.new(command, rc, result, original_errors)
|
102
|
+
end
|
103
|
+
|
104
|
+
return result
|
105
|
+
end
|
106
|
+
|
107
|
+
def cmd(cmd)
|
108
|
+
begin
|
109
|
+
cmd_result(cmd)
|
110
|
+
return true
|
111
|
+
rescue CommandError
|
112
|
+
return false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Run the {command} and run {&block} for each line of STDOUT
|
117
|
+
def cmd_stdout(command, ignore_fail = false, &block)
|
118
|
+
errors = ""
|
119
|
+
result = ""
|
120
|
+
threads = []
|
121
|
+
|
122
|
+
debug("Execute `#{command}`")
|
123
|
+
status = Open4::popen4("export LANG=en_US; #{command}") do |pid, stdin, stdout, stderr|
|
124
|
+
stdin.close
|
125
|
+
|
126
|
+
threads << Thread.new{
|
127
|
+
while data = stdout.gets()
|
128
|
+
if data.to_s() != ""
|
129
|
+
result+=data
|
130
|
+
|
131
|
+
if data != "" && forward_cmd_results?()
|
132
|
+
write(data, (parse_log_level(data) || get_forward_log_level()), nil, false)
|
133
|
+
end
|
134
|
+
|
135
|
+
block.call(data)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
}
|
139
|
+
threads << Thread.new{
|
140
|
+
while edata = stderr.gets()
|
141
|
+
if edata.to_s() != ""
|
142
|
+
errors+=edata
|
143
|
+
|
144
|
+
if edata != "" && forward_cmd_results?()
|
145
|
+
write(edata, (parse_log_level(edata) || get_forward_log_level()), nil, false)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
}
|
150
|
+
|
151
|
+
threads.each{|t| t.join() }
|
152
|
+
end
|
153
|
+
|
154
|
+
result.strip!()
|
155
|
+
errors.strip!()
|
156
|
+
|
157
|
+
original_errors = errors
|
158
|
+
rc = status.exitstatus
|
159
|
+
if errors == ""
|
160
|
+
errors = "No Errors"
|
161
|
+
else
|
162
|
+
errors = "Errors: #{errors}"
|
163
|
+
end
|
164
|
+
|
165
|
+
if log_cmd_results?()
|
166
|
+
debug("RC: #{rc}, Result: #{result}, #{errors}")
|
167
|
+
elsif forward_cmd_results?()
|
168
|
+
debug("RC: #{rc}, Result length #{result.length}, Errors length #{original_errors.length}")
|
169
|
+
else
|
170
|
+
debug("RC: #{rc}, Result length #{result.length}, #{errors}")
|
171
|
+
end
|
172
|
+
if rc != 0 && ! ignore_fail
|
173
|
+
raise CommandError.new(command, rc, result, original_errors)
|
174
|
+
end
|
175
|
+
|
176
|
+
return
|
177
|
+
end
|
178
|
+
|
179
|
+
# Run the {command} and run {&block} for each line of STDERR
|
180
|
+
def cmd_stderr(command, ignore_fail = false, &block)
|
181
|
+
errors = ""
|
182
|
+
result = ""
|
183
|
+
threads = []
|
184
|
+
|
185
|
+
debug("Execute `#{command}`")
|
186
|
+
status = Open4::popen4("export LANG=en_US; #{command}") do |pid, stdin, stdout, stderr|
|
187
|
+
stdin.close
|
188
|
+
|
189
|
+
threads << Thread.new{
|
190
|
+
while data = stdout.gets()
|
191
|
+
if data.to_s() != ""
|
192
|
+
result+=data
|
193
|
+
|
194
|
+
if data != "" && forward_cmd_results?()
|
195
|
+
write(data, (parse_log_level(data) || get_forward_log_level()), nil, false)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
}
|
200
|
+
threads << Thread.new{
|
201
|
+
while edata = stderr.gets()
|
202
|
+
if edata.to_s() != ""
|
203
|
+
errors+=edata
|
204
|
+
|
205
|
+
if edata != "" && forward_cmd_results?()
|
206
|
+
write(edata, (parse_log_level(edata) || get_forward_log_level()), nil, false)
|
207
|
+
end
|
208
|
+
|
209
|
+
block.call(edata)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
}
|
213
|
+
|
214
|
+
threads.each{|t| t.join() }
|
215
|
+
end
|
216
|
+
|
217
|
+
result.strip!()
|
218
|
+
errors.strip!()
|
219
|
+
|
220
|
+
original_errors = errors
|
221
|
+
rc = status.exitstatus
|
222
|
+
if errors == ""
|
223
|
+
errors = "No Errors"
|
224
|
+
else
|
225
|
+
errors = "Errors: #{errors}"
|
226
|
+
end
|
227
|
+
|
228
|
+
if log_cmd_results?()
|
229
|
+
debug("RC: #{rc}, Result: #{result}, #{errors}")
|
230
|
+
elsif forward_cmd_results?()
|
231
|
+
debug("RC: #{rc}, Result length #{result.length}, Errors length #{original_errors.length}")
|
232
|
+
else
|
233
|
+
debug("RC: #{rc}, Result length #{result.length}, #{errors}")
|
234
|
+
end
|
235
|
+
if rc != 0 && ! ignore_fail
|
236
|
+
raise CommandError.new(command, rc, result, original_errors)
|
237
|
+
end
|
238
|
+
|
239
|
+
return
|
240
|
+
end
|
241
|
+
|
242
|
+
# Run a standard check to see if SSH connectivity to the host works
|
243
|
+
def test_ssh(host, user)
|
244
|
+
begin
|
245
|
+
login_result = ssh_result("whoami", host, user)
|
246
|
+
|
247
|
+
if login_result != user
|
248
|
+
if login_result=~ /#{user}/
|
249
|
+
error "SSH to #{host} as #{user} is returning more than one line."
|
250
|
+
error "Ensure that the .bashrc and .bash_profile files are not printing messages on #{host} with out using a test like this. if [ \"$PS1\" ]; then echo \"Your message here\"; fi"
|
251
|
+
error "If you are using the 'Banner' argument in /etc/ssh/sshd_config, try putting the contents into /etc/motd"
|
252
|
+
else
|
253
|
+
error "Unable to SSH to #{host} as #{user}."
|
254
|
+
|
255
|
+
if is_localhost?(host)
|
256
|
+
error "Try running the command as #{user}"
|
257
|
+
else
|
258
|
+
error "Ensure that the host is running and that you can login as #{user} via SSH using key authentication"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
return false
|
263
|
+
else
|
264
|
+
return true
|
265
|
+
end
|
266
|
+
rescue => e
|
267
|
+
exception(e)
|
268
|
+
return false
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# Run the {command} on {host} as {user}
|
273
|
+
# Return a string of STDOUT
|
274
|
+
def ssh_result(command, host, user)
|
275
|
+
if host == DEFAULTS
|
276
|
+
debug("Unable to run '#{command}' because '#{host}' is not valid")
|
277
|
+
raise RemoteCommandError.new(user, host, command, nil, '')
|
278
|
+
end
|
279
|
+
|
280
|
+
# Run the command outside of SSH if possible
|
281
|
+
if is_localhost?(host) &&
|
282
|
+
user == whoami()
|
283
|
+
return cmd_result(command)
|
284
|
+
end
|
285
|
+
|
286
|
+
unless defined?(Net::SSH)
|
287
|
+
begin
|
288
|
+
require "openssl"
|
289
|
+
rescue LoadError
|
290
|
+
raise("Unable to find the Ruby openssl library. Try installing the openssl package for your version of Ruby (libopenssl-ruby#{RUBY_VERSION[0,3]}).")
|
291
|
+
end
|
292
|
+
require 'net/ssh'
|
293
|
+
end
|
294
|
+
|
295
|
+
ssh_user = get_ssh_user(user)
|
296
|
+
if user != ssh_user
|
297
|
+
debug("SSH user changed to #{ssh_user}")
|
298
|
+
command = command.tr('"', '\"')
|
299
|
+
command = "echo \"#{command}\" | sudo -u #{user} -i"
|
300
|
+
end
|
301
|
+
|
302
|
+
debug("Execute `#{command}` on #{host} as #{user}")
|
303
|
+
result = ""
|
304
|
+
rc = nil
|
305
|
+
exit_signal=nil
|
306
|
+
|
307
|
+
connection_error = "Net::SSH was unable to connect to #{host} as #{ssh_user}. Check that #{host} is online, #{ssh_user} exists and your SSH private keyfile or ssh-agent settings. Try adding --net-ssh-option=port=<SSH port number> if you are using an SSH port other than 22. Review https://docs.continuent.com/wiki/display/TEDOC/Unable+to+use+the+tpm+command+over+SSH for more help on diagnosing SSH problems."
|
308
|
+
begin
|
309
|
+
Net::SSH.start(host, ssh_user, get_ssh_options()) {
|
310
|
+
|ssh|
|
311
|
+
stdout_data = ""
|
312
|
+
|
313
|
+
ssh.open_channel do |channel|
|
314
|
+
channel.exec(". /etc/profile; #{ssh_init_profile_script()} export LANG=en_US; export LC_ALL=\"en_US.UTF-8\"; #{command}") do |ch, success|
|
315
|
+
channel.on_data do |ch,data|
|
316
|
+
stdout_data+=data
|
317
|
+
|
318
|
+
if data != "" && forward_cmd_results?()
|
319
|
+
log_level,log_data = split_log_content(data)
|
320
|
+
write(log_data, (log_level || get_forward_log_level()), host)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
channel.on_extended_data do |ch,type,data|
|
325
|
+
data = data.chomp
|
326
|
+
|
327
|
+
if data != "" && forward_cmd_results?()
|
328
|
+
log_level,log_data = split_log_content(data)
|
329
|
+
write(log_data, (log_level || get_forward_log_level()), host)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
channel.on_request("exit-status") do |ch,data|
|
334
|
+
rc = data.read_long
|
335
|
+
end
|
336
|
+
|
337
|
+
channel.on_request("exit-signal") do |ch, data|
|
338
|
+
exit_signal = data.read_long
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
ssh.loop
|
343
|
+
result = stdout_data.to_s.chomp
|
344
|
+
}
|
345
|
+
rescue Errno::ENOENT => ee
|
346
|
+
raise MessageError.new("Net::SSH was unable to find a private key to use for SSH authenticaton. Try creating a private keyfile or setting up ssh-agent.")
|
347
|
+
rescue OpenSSL::PKey::RSAError
|
348
|
+
raise MessageError.new(connection_error)
|
349
|
+
rescue Net::SSH::AuthenticationFailed
|
350
|
+
raise MessageError.new(connection_error)
|
351
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::EHOSTDOWN
|
352
|
+
raise MessageError.new(connection_error)
|
353
|
+
rescue Timeout::Error
|
354
|
+
raise MessageError.new(connection_error)
|
355
|
+
rescue NotImplementedError => nie
|
356
|
+
raise MessageError.new(nie.message + ". Try modifying your ~/.ssh/config file to define values for Cipher and Ciphers that do not include this algorithm. The supported encryption algorithms are #{Net::SSH::Transport::CipherFactory::SSH_TO_OSSL.keys().delete_if{|e| e == "none"}.join(", ")}.")
|
357
|
+
rescue => e
|
358
|
+
raise e
|
359
|
+
end
|
360
|
+
|
361
|
+
if rc != 0
|
362
|
+
raise RemoteCommandError.new(user, host, command, rc, result)
|
363
|
+
else
|
364
|
+
if log_cmd_results?()
|
365
|
+
debug("RC: #{rc}, Result: #{result}")
|
366
|
+
else
|
367
|
+
debug("RC: #{rc}, Result length #{result.length}")
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
return result
|
372
|
+
end
|
373
|
+
|
374
|
+
def get_ssh_options
|
375
|
+
@ssh_options
|
376
|
+
end
|
377
|
+
|
378
|
+
def get_ssh_command_options
|
379
|
+
opts = ["-A", "-oStrictHostKeyChecking=no", "-oUserKnownHostsFile=/dev/null"]
|
380
|
+
@ssh_options.each{
|
381
|
+
|k,v|
|
382
|
+
opts << "-o#{k.to_s()}=#{v}"
|
383
|
+
}
|
384
|
+
return opts.join(" ")
|
385
|
+
end
|
386
|
+
|
387
|
+
def get_tungsten_command_options
|
388
|
+
opts = []
|
389
|
+
|
390
|
+
case get_log_level()
|
391
|
+
when Logger::INFO then opts << "-i"
|
392
|
+
when Logger::NOTICE then opts << "-n"
|
393
|
+
when Logger::WARN then opts << "-q"
|
394
|
+
when Logger::DEBUG then opts << "-v"
|
395
|
+
end
|
396
|
+
|
397
|
+
@ssh_options.each{
|
398
|
+
|k,v|
|
399
|
+
opts << "--net-ssh-option=#{k.to_s()}=#{v}"
|
400
|
+
}
|
401
|
+
return opts.join(" ")
|
402
|
+
end
|
403
|
+
|
404
|
+
def get_ssh_user(user = nil)
|
405
|
+
ssh_options = get_ssh_options
|
406
|
+
if ssh_options.has_key?(:user) && ssh_options[:user].to_s != ""
|
407
|
+
ssh_options[:user]
|
408
|
+
else
|
409
|
+
user
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
def get_ssh_port(port = 22)
|
414
|
+
ssh_options = get_ssh_options
|
415
|
+
if ssh_options.has_key?(:port) && ssh_options[:port].to_s != ""
|
416
|
+
ssh_options[:port]
|
417
|
+
else
|
418
|
+
port
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def ssh_init_profile_script
|
423
|
+
if @ssh_init_profile_script == nil
|
424
|
+
init_profile_script_parts = []
|
425
|
+
[
|
426
|
+
"$HOME/.bash_profile",
|
427
|
+
"$HOME/.bash_login",
|
428
|
+
"$HOME/.profile"
|
429
|
+
].each{
|
430
|
+
|filename|
|
431
|
+
|
432
|
+
if init_profile_script_parts.size() == 0
|
433
|
+
init_profile_script_parts << "if"
|
434
|
+
else
|
435
|
+
init_profile_script_parts << "elif"
|
436
|
+
end
|
437
|
+
|
438
|
+
init_profile_script_parts << "[ -f #{filename} ]; then . #{filename};"
|
439
|
+
}
|
440
|
+
init_profile_script_parts << "fi;"
|
441
|
+
@ssh_init_profile_script = init_profile_script_parts.join(" ")
|
442
|
+
end
|
443
|
+
|
444
|
+
return @ssh_init_profile_script
|
445
|
+
end
|
446
|
+
|
447
|
+
def hostname
|
448
|
+
`hostname 2>/dev/null`.chomp
|
449
|
+
end
|
450
|
+
|
451
|
+
def is_localhost?(hostname)
|
452
|
+
if hostname == DEFAULTS
|
453
|
+
return false
|
454
|
+
end
|
455
|
+
|
456
|
+
@_is_localhost_cache ||= {}
|
457
|
+
unless @_is_localhost_cache.has_key?(hostname)
|
458
|
+
@_is_localhost_cache[hostname] = _is_localhost?(hostname)
|
459
|
+
end
|
460
|
+
|
461
|
+
return @_is_localhost_cache[hostname]
|
462
|
+
end
|
463
|
+
|
464
|
+
def _is_localhost?(hostname)
|
465
|
+
if hostname == hostname()
|
466
|
+
return true
|
467
|
+
end
|
468
|
+
|
469
|
+
ip_addresses = get_ip_addresses(hostname)
|
470
|
+
if ip_addresses == false
|
471
|
+
return false
|
472
|
+
end
|
473
|
+
|
474
|
+
debug("Search ifconfig for #{ip_addresses.join(', ')}")
|
475
|
+
ifconfig = IfconfigWrapper.new().parse()
|
476
|
+
ifconfig.each{
|
477
|
+
|iface|
|
478
|
+
|
479
|
+
begin
|
480
|
+
# Do a string comparison so that we only match the address portion
|
481
|
+
iface.addresses().each{
|
482
|
+
|a|
|
483
|
+
if ip_addresses.include?(a.to_s())
|
484
|
+
return true
|
485
|
+
end
|
486
|
+
}
|
487
|
+
rescue ArgumentError
|
488
|
+
end
|
489
|
+
}
|
490
|
+
|
491
|
+
false
|
492
|
+
end
|
493
|
+
|
494
|
+
def get_ip_addresses(hostname)
|
495
|
+
begin
|
496
|
+
if hostname == DEFAULTS
|
497
|
+
return false
|
498
|
+
end
|
499
|
+
|
500
|
+
ip_addresses = Timeout.timeout(5) {
|
501
|
+
Resolv.getaddresses(hostname)
|
502
|
+
}
|
503
|
+
|
504
|
+
if ip_addresses.length == 0
|
505
|
+
begin
|
506
|
+
ping_result = cmd_result("ping -c1 #{hostname} 2>/dev/null | grep PING")
|
507
|
+
matches = ping_result.match("[0-9]+.[0-9]+.[0-9]+.[0-9]+")
|
508
|
+
if matches && matches.size() > 0
|
509
|
+
return [matches[0]]
|
510
|
+
end
|
511
|
+
rescue CommandError
|
512
|
+
end
|
513
|
+
|
514
|
+
warning "Unable to determine the IP addresses for '#{hostname}'"
|
515
|
+
return false
|
516
|
+
end
|
517
|
+
|
518
|
+
return ip_addresses
|
519
|
+
rescue Timeout::Error
|
520
|
+
warning "Unable to lookup #{hostname} because of a DNS timeout"
|
521
|
+
return false
|
522
|
+
rescue => e
|
523
|
+
warning "Unable to determine the IP addresses for '#{hostname}'"
|
524
|
+
return false
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
def is_real_hostname?(hostname)
|
529
|
+
begin
|
530
|
+
ip_addresses = Timeout.timeout(5) {
|
531
|
+
Resolv.getaddresses(hostname)
|
532
|
+
}
|
533
|
+
|
534
|
+
if ip_addresses.length == 0
|
535
|
+
begin
|
536
|
+
ping_result = cmd_result("ping -c1 #{hostname} 2>/dev/null | grep PING")
|
537
|
+
matches = ping_result.match("[0-9]+.[0-9]+.[0-9]+.[0-9]+")
|
538
|
+
if matches && matches.size() > 0
|
539
|
+
ip_addresses = [matches[0]]
|
540
|
+
end
|
541
|
+
rescue CommandError
|
542
|
+
end
|
543
|
+
end
|
544
|
+
rescue Timeout::Error
|
545
|
+
rescue
|
546
|
+
end
|
547
|
+
|
548
|
+
if ip_addresses.size() == 0
|
549
|
+
return false
|
550
|
+
else
|
551
|
+
return true
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
# Find out the full executable path or return nil
|
556
|
+
# if this is not executable.
|
557
|
+
def which(cmd)
|
558
|
+
if ! cmd
|
559
|
+
nil
|
560
|
+
else
|
561
|
+
path = cmd_result("which #{cmd} 2>/dev/null", true)
|
562
|
+
path.chomp!
|
563
|
+
if File.executable?(path)
|
564
|
+
path
|
565
|
+
else
|
566
|
+
nil
|
567
|
+
end
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|