rhc 1.3.8 → 1.4.7

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.
@@ -1,595 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rhc/coverage_helper'
4
-
5
- require 'rhc-common'
6
- require 'net/http'
7
- require 'net/https'
8
- require 'net/ssh'
9
- require 'rbconfig'
10
- require 'yaml'
11
- require 'tempfile'
12
- require 'rhc/vendor/sshkey'
13
-
14
- if RUBY_VERSION.to_f == 1.9
15
- require 'rubygems'
16
- gem 'test-unit'#, '~> 1.2.3'
17
- end
18
-
19
- require 'test/unit'
20
- require 'test/unit/ui/console/testrunner'
21
-
22
- class Hash
23
- # given a potentially nested hash, overwrite the value
24
- # if the key matches the given key
25
- def deep_cleanse(key)
26
- each_pair do |k,v|
27
- case v
28
- when Hash
29
- v.deep_cleanse key
30
- when Array
31
- v.map {|e| e.deep_cleanse(key) if e.is_a? Hash}
32
- else
33
- if k.to_s == key
34
- self[k] = "*" * 12
35
- end
36
- end
37
- end
38
- end
39
- end
40
-
41
- #
42
- # print help
43
- #
44
- def p_usage(exit_code = 255)
45
- rhlogin = get_var('default_rhlogin') ? "Default: #{get_var('default_rhlogin')}" : "required"
46
- puts <<USAGE
47
-
48
- Usage: rhc domain status
49
- Run a simple check on local configs and credentials to confirm tools are
50
- properly setup. Often run to troubleshoot connection issues.
51
-
52
- -l|--rhlogin rhlogin OpenShift login (#{rhlogin})
53
- -p|--password password Password (optional, will prompt)
54
- -d|--debug Print Debug info
55
- -h|--help Show Usage info
56
- --config path Path of alternate config file
57
- --timeout # Timeout, in seconds, for the session
58
-
59
- USAGE
60
- exit exit_code
61
- end
62
-
63
- warn "#{$0} has been deprecated. Please run 'rhc setup' instead."
64
-
65
- begin
66
- opts = GetoptLong.new(
67
- ["--debug", "-d", GetoptLong::NO_ARGUMENT],
68
- ["--help", "-h", GetoptLong::NO_ARGUMENT],
69
- ["--rhlogin", "-l", GetoptLong::REQUIRED_ARGUMENT],
70
- ["--password", "-p", GetoptLong::REQUIRED_ARGUMENT],
71
- ["--config", GetoptLong::REQUIRED_ARGUMENT],
72
- ["--timeout", GetoptLong::REQUIRED_ARGUMENT]
73
- )
74
- $opt = {}
75
- opts.each do |o, a|
76
- $opt[o[2..-1]] = a.to_s
77
- end
78
- rescue Exception => e
79
- #puts e.message
80
- p_usage
81
- end
82
-
83
- if $opt["help"]
84
- p_usage 0
85
- end
86
-
87
- if 0 != ARGV.length
88
- p_usage
89
- end
90
-
91
- # If provided a config path, check it
92
- RHC::Config.check_cpath($opt)
93
-
94
- # Need to store the config information so tests can use it
95
- # since they are technically new objects
96
- $opts_config_path = @opts_config_path
97
- $local_config_path = @local_config_path
98
- $opts_config = @opts_config
99
- $local_config = @local_config
100
- $global_config = @global_config
101
-
102
- # Pull in configs from files
103
- $libra_server = get_var('libra_server')
104
- $debug = get_var('debug') == 'false' ? nil : get_var('debug')
105
-
106
-
107
- if $opt["debug"]
108
- $debug = true
109
- end
110
- RHC::debug($debug)
111
-
112
- RHC::timeout($opt["timeout"], get_var('timeout'))
113
- RHC::connect_timeout($opt["timeout"], get_var('timeout'))
114
-
115
-
116
- $opt["rhlogin"] = get_var('default_rhlogin') unless $opt["rhlogin"]
117
- if !RHC::check_rhlogin($opt['rhlogin'])
118
- p_usage
119
- end
120
- $rhlogin = $opt["rhlogin"]
121
-
122
- $password = $opt['password']
123
- if !$password
124
- $password = RHC::get_password
125
- end
126
-
127
- #
128
- # Generic Info
129
- #
130
- $debuginfo = {
131
- 'environment' => {
132
- 'Ruby Version' => RUBY_VERSION,
133
- "host_alias" => (Object.const_get(defined?(RbConfig) ? :RbConfig : :Config))::CONFIG['host_alias'],
134
- },
135
- 'options' => {
136
- "Command Line" => $opt,
137
- "Opts" => $opts_config,
138
- "Local" => $local_config,
139
- "Global" => $global_config
140
- }
141
- }
142
-
143
- #
144
- # Check for proxy environment
145
- #
146
- $http = RHC::Config.default_proxy
147
- $debuginfo['environment']['proxy'] = (RHC::Config.using_proxy? ? ENV['http_proxy'] : "none")
148
-
149
- #####################################
150
- # Done setting up environment #
151
- #####################################
152
-
153
- module TestBase
154
- def initialize(*args)
155
- super
156
- $connectivity ||= false
157
- # These need to be loaded for each test to be able to access them
158
- @opts_config_path = $opts_config_path
159
- @local_config_path = $local_config_path
160
- @opts_config = $opts_config
161
- @local_config = $local_config
162
- @global_config = $global_config
163
- end
164
-
165
- def fetch_url_json(uri, data)
166
- json_data = RHC::generate_json(data)
167
- url = URI.parse("https://#{$libra_server}#{uri}")
168
- req = $http::Post.new(url.path)
169
- req.set_form_data({'json_data' => json_data, 'password' => $password})
170
- http = $http.new(url.host, url.port)
171
- http.open_timeout = 10
172
- http.use_ssl = true
173
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
174
-
175
- response = http.start {|http| http.request(req)}
176
- return response
177
- ensure
178
- unless response.nil?
179
- $debuginfo['fetches'] ||= []
180
- body = RHC::json_decode(response.body)
181
- body['data'] = body['data'] && body['data'] != '' ? RHC::json_decode(body['data']) : ''
182
- $debuginfo['fetches'] << {url.to_s => {
183
- 'body' => body.deep_cleanse('password'),
184
- 'header' => response.instance_variable_get(:@header)
185
- }}
186
- end
187
- end
188
-
189
- def continue_test
190
- begin
191
- yield
192
- rescue Test::Unit::AssertionFailedError => e
193
- self.send(:add_failure,e.message,e.backtrace)
194
- end
195
- end
196
- end
197
-
198
- #####################################################
199
- # Tests start here #
200
- #####################################################
201
- # #
202
- # Note: Tests and testcases are run alphabetically #
203
- # #
204
- #####################################################
205
-
206
- def error_for(name,*args)
207
- # Make sure the name is a downcased symbol
208
- name = name.to_s.downcase.to_sym
209
-
210
- # Create message template
211
- message = [:errors,:solutions].map{|x| get_message(x,name) }.compact.join("\n")
212
-
213
- # Params for message template
214
- params = args.flatten
215
-
216
- # Ensure we have the right number of placeholders
217
- num_placeholders = message.scan("%s").length
218
- unless num_placeholders == params.length
219
- warn("\nWARNING: error_for called with wrong number of args from: \n\t%s\n" % caller[0]) if $debug
220
- # This will ensure we have the right number of arguments, but should not get here
221
- params << Array.new(num_placeholders,"???")
222
- end
223
-
224
- # Return the message
225
- message % params.flatten
226
- end
227
-
228
- def get_message(type,name)
229
- val = $messages[type][name]
230
- if val.is_a? Symbol
231
- val = get_message(type,val)
232
- end
233
- val
234
- end
235
-
236
- # This test tries to make sure we have the keys unlocked before testing
237
- # to ensure nicer workflow
238
- class Test0_SSH_Keys_Unlocked < Test::Unit::TestCase
239
- include TestBase
240
-
241
- def test_ssh_quick
242
- begin
243
- # Get user info from OpenShift
244
- data = {'rhlogin' => $rhlogin}
245
- response = fetch_url_json("/broker/userinfo", data)
246
- resp_json = RHC::json_decode(response.body)
247
- user_info = RHC::json_decode(resp_json['data'].to_s)
248
-
249
- # Get any keys Net::SSH thinks we'll need
250
- $ssh = Net::SSH
251
- needed_keys =
252
- user_info['app_info'].map do |name,opts|
253
- host = "%s-%s.%s" % [
254
- name,
255
- user_info['user_info']['namespace'],
256
- user_info['user_info']['rhc_domain']
257
- ]
258
- $ssh.configuration_for(host)[:keys].map{|f| File.expand_path(f)}
259
- end.compact.flatten
260
-
261
- agent_keys = Net::SSH::Authentication::Agent.connect.identities.map{|x| x.comment }
262
- missing_keys = needed_keys - agent_keys
263
-
264
- unless missing_keys.empty?
265
- $stderr.puts "\n NOTE: These tests may require you to unlock one or more of your SSH keys \n\n"
266
- end
267
- rescue
268
- end
269
- end
270
-
271
- end
272
-
273
- class Test1_Connectivity < Test::Unit::TestCase
274
- include TestBase
275
- def teardown
276
- # Set global variable in case we cannot connect to the server
277
- if method_name == 'test_connectivity'
278
- $connectivity = passed?
279
- end
280
- end
281
-
282
- #
283
- # Checking Connectivity / cart list
284
- #
285
- def test_connectivity
286
- data = {'cart_type' => 'standalone'}
287
-
288
- response = fetch_url_json("/broker/cartlist", data)
289
- assert_equal 200, response.code.to_i, error_for(:no_connectivity, $libra_server)
290
- end
291
- end
292
-
293
- class Test2_Authentication < Test::Unit::TestCase
294
- include TestBase
295
- #
296
- # Checking Authentication
297
- #
298
- def test_authentication
299
- assert $connectivity, error_for(:cant_connect)
300
-
301
- data = {'rhlogin' => $rhlogin}
302
- response = fetch_url_json("/broker/userinfo", data)
303
- resp_json = RHC::json_decode(response.body)
304
-
305
- case response.code.to_i
306
- when 404
307
- assert false, error_for(:_404, $rhlogin)
308
- when 401
309
- assert false, error_for(:_401, $rhlogin)
310
- when 200
311
- assert true
312
- else
313
- assert false, error_for(:_other_http, resp_json['result'])
314
- end
315
-
316
- $user_info = RHC::json_decode(resp_json['data'].to_s)
317
- end
318
- end
319
-
320
- #
321
- # Checking ssh key
322
- #
323
- class Test3_SSH < Test::Unit::TestCase
324
-
325
-
326
- include TestBase
327
-
328
- def setup
329
- @libra_kfile = get_kfile(false)
330
- if @libra_kfile
331
- @libra_kpfile = get_kpfile(@libra_kfile, false)
332
- end
333
- end
334
-
335
- def require_login(test)
336
- flunk(error_for(:no_account,test)) if $user_info.nil?
337
- end
338
-
339
- def require_domain(test)
340
- flunk(error_for(:no_domain,test)) if $user_info['user_info']['domains'].empty?
341
- end
342
-
343
- def require_remote_keys(test)
344
- require_login(test)
345
- require_domain(test)
346
- @@remote_pub_keys ||= (
347
- ssh_keys = RHC::get_ssh_keys($libra_server, $rhlogin, $password, $http)
348
- my_keys = [ssh_keys['ssh_key'], ssh_keys['keys'].values.map{|k| k['key']}].flatten
349
- my_keys.delete_if{|x| x.length == 0 }
350
- my_keys
351
- )
352
-
353
- missing_keys = [:nil?,:empty?].map{|f| @@remote_pub_keys.send(f) rescue false }.inject(:|)
354
-
355
- flunk(error_for(:no_remote_pub_keys,test)) if missing_keys
356
- end
357
-
358
- def require_agent_keys(fatal = true)
359
- @@agent_keys ||= (
360
- begin
361
- Net::SSH::Authentication::Agent.connect.identities
362
- rescue Exception
363
- nil
364
- end
365
- )
366
- flunk(error_for(:no_keys_loaded)) if (fatal && @@agent_keys.nil?)
367
- end
368
-
369
- def agent_key_names
370
- @@agent_keys.nil? ? nil : @@agent_keys.map{|x| File.expand_path(x.comment) }
371
- end
372
-
373
- def agent_key_fingerprints
374
- @@agent_keys.nil? ? nil : @@agent_keys.map{|x| x.fingerprint }
375
- end
376
-
377
- def libra_public_key
378
- @@local_ssh_pubkey ||= libra_public_key_content.split(' ')[1]
379
- end
380
-
381
- def libra_public_key_content
382
- @@local_ssh_pubkey_content ||= (
383
- fp = File.open(@libra_kpfile)
384
- fp.gets
385
- )
386
- ensure
387
- fp.close if fp
388
- end
389
-
390
- def libra_public_key_fingerprint
391
- @@local_ssh_pubkey_fingerprint ||= Net::SSH::KeyFactory.load_data_public_key(libra_public_key_content).fingerprint
392
- end
393
-
394
- def test_01_local_files
395
- [
396
- [@libra_kfile, /[4-7]00/], # Needs to at least be readable by user and nobody else
397
- [@libra_kpfile, /.../], # Any permissions are OK
398
- ].each do |args|
399
- continue_test{check_permissions(*args)}
400
- end
401
- end
402
-
403
- def test_02_ssh_agent
404
- require_agent_keys
405
-
406
- assert agent_key_fingerprints.include?(libra_public_key_fingerprint) ,error_for(:pubkey_not_loaded, ": #{@libra_kpfile}")
407
- end
408
-
409
- def test_03_remote_ssh_keys
410
- require_remote_keys("whether your local SSH keys match the ones in your account")
411
- require_agent_keys(false)
412
-
413
- assert !(@@remote_pub_keys & [agent_key_fingerprints,libra_public_key].flatten).empty? ,error_for(:pubkey_not_loaded," ")
414
- end
415
-
416
- def test_04_ssh_connect
417
- require_login("connecting to your applications")
418
- require_domain("connecting to your applications")
419
-
420
- host_template = "%%s-%s.%s" % [
421
- $user_info['user_info']['domains'][0]['namespace'],
422
- $user_info['user_info']['rhc_domain']
423
- ]
424
- $user_info['app_info'].each do |k,v|
425
- uuid = v['uuid']
426
- hostname = host_template % k
427
- timeout = 10
428
- begin
429
- @ssh = Net::SSH.start(hostname,uuid,{:timeout => timeout})
430
- rescue Timeout::Error
431
- if timeout < 30
432
- timeout += 10
433
- retry
434
- end
435
- ensure
436
- continue_test{ assert_not_nil @ssh, error_for(:cant_ssh, hostname) }
437
- @ssh.close if @ssh
438
- end
439
- end
440
- end
441
-
442
- private
443
- def check_permissions(file,permission)
444
- # IO#stat is platform-specific, on windows it's usually 644 but in fact it doesn't matter
445
- permission = /.../ if RHC::Helpers.windows?
446
-
447
- file = File.expand_path(file)
448
-
449
- assert File.exists?(file), error_for(:file_not_found,file)
450
-
451
- perms = sprintf('%o',File.stat(file).mode)[-3..-1]
452
-
453
- assert_match(permission, perms, error_for(:bad_permissions,[file,perms],permission.source))
454
- end
455
- end
456
-
457
- ############################################################
458
- # Below this line is the custom Test::Runner code #
459
- # Modification should not be necessary to add/modify tests #
460
- ############################################################
461
-
462
- class CheckRunner < Test::Unit::UI::Console::TestRunner
463
- def initialize(*args)
464
- super
465
- @output_level = 1
466
- puts get_message(:status,:started)
467
- end
468
-
469
- def add_fault(fault)
470
- @faults << fault
471
- print(fault.single_character_display)
472
- @already_outputted = true
473
- end
474
-
475
- def print_underlined(string)
476
- string = "|| #{string} ||"
477
- line = "=" * string.length
478
- puts
479
- puts line
480
- puts string
481
- puts line
482
- end
483
-
484
- def render_message(message)
485
- lines = message.send(message.respond_to?(:lines) ? :lines : :to_s).to_a
486
- message = []
487
- @num ||= 0
488
- message << "#{@num+=1}) #{lines.shift.strip}"
489
- lines.each do |line|
490
- # Break if we get the standard assert error information or a blank line
491
- break if line.match(/^\<.*?> /) or line.match(/^\s*$/)
492
- message << "\t#{line.strip}"
493
- end
494
- message.join("\n")
495
- end
496
-
497
- def finished(*args)
498
- super
499
- $debuginfo['errors'] = @faults
500
-
501
- if @faults.empty?
502
- print_underlined get_message(:status,:passed)
503
- else
504
- print_underlined get_message(:status,:failed)
505
- @errors = []
506
- # Need to separate the failures from the errors
507
-
508
- @faults.each do |f|
509
- case f
510
- when Test::Unit::Failure
511
- puts render_message(f.message)
512
- when Test::Unit::Error
513
- @errors << f
514
- end
515
- end
516
-
517
- # Errors mean something in the test is broken, not just failed
518
- unless @errors.empty?
519
- @num = 0
520
- print_underlined get_message(:status,:error)
521
- @errors.each do |e|
522
- display = e.long_display
523
- lines = display.send(display.respond_to?(:lines) ? :lines : :to_s).to_a[1..-1]
524
- puts "#{@num+=1}) #{lines.shift}"
525
- lines.each{|l| puts "\t#{l}"}
526
- end
527
- end
528
-
529
- end
530
-
531
- if $debug
532
- Tempfile.open(%w(rhc-chk. .log))do |file|
533
- ObjectSpace.undefine_finalizer(file) # persist tempfile
534
- file.write $debuginfo.deep_cleanse('password').to_yaml
535
- puts
536
- puts "Debugging information dumped to #{file.path}"
537
- end
538
- end
539
- end
540
- end
541
-
542
- # Need to register the default runner differently using the standard test-unit and the gem
543
- proc{|*r| CheckRunner}.tap do |_proc|
544
- if Test::Unit::AutoRunner.respond_to?(:register_runner)
545
- Test::Unit::AutoRunner.register_runner(:console, _proc)
546
- else
547
- Test::Unit::AutoRunner::RUNNERS[:console] = _proc
548
- end
549
- end
550
-
551
- ############################
552
- # The following are the error messages to be used for different tests
553
- # You need to specify a value in :errors
554
- # If there is a solution, it may also be specified in :solutions
555
- #
556
- # Values in may be reused by specifying another symbol as the value
557
- # for instance the following will use the solution for :bar as the solution for :foo
558
- #
559
- # :solutions
560
- # :foo: :bar
561
- ############################
562
- $messages = YAML.load <<-EOF
563
- ---
564
- :status:
565
- :started: Analyzing system
566
- :passed: Congratulations, your system has passed all tests
567
- :failed: Your system did not pass all of the tests
568
- :error: Something went wrong, and not all tests completed
569
- :errors:
570
- :no_derive: "We were unable to derive your public SSH key and compare it to the remote"
571
- :no_connectivity: "Cannot connect to server, therefore most tests will not work"
572
- :no_account: "You must have an account on the server in order to test: %s"
573
- :no_domain: "You must have a domain associated with this account in order to test: %s"
574
- :cant_connect: You need to be able to connect to the server in order to test authentication
575
- :no_match_pub: "Local %s does not match remote pub key, SSH auth will not work"
576
- :_404: "The user %s does not have an account on this server"
577
- :no_pubkey: We were unable to read your public SSH key to compare to %s
578
- :_401: "Invalid user credentials for %s"
579
- :file_not_found: File %s does not exist, cannot check permissions
580
- :_other_http: "There was an error communicating with the server: %s"
581
- :bad_permissions: "File %s has incorrect permissions %s"
582
- :no_keys_loaded: Either ssh-agent is not running or you do not have any keys loaded
583
- :pubkey_not_loaded: "Your public key is not loaded into a running ssh-agent%s"
584
- :cant_ssh: "Cannot SSH into your app: %s"
585
- :no_remote_pub_keys: "You do not have any public keys associated with your OpenShift account. Cannot test: %s"
586
- :solutions:
587
- :no_connectivity: "Ensure that you are able to connect to %s"
588
- :no_match_pub: "Perhaps you should regenerate your public key, or run 'rhc sshkey add' to add your new key"
589
- :_404: "Please ensure that you've entered the correct username or that you've created an account"
590
- :_401: "Please ensure you used the correct password"
591
- :bad_permissions: "Permissions should match %s"
592
- :no_remote_pub_keys: "You should try to add your ssh-key by running 'rhc sshkey add'"
593
- :pubkey_not_loaded: If this is your only error, your connection may still work, depending on your SSH configuration
594
- :no_keys_loaded: If this is your only error, your connection may still work, depending on your SSH configuration
595
- EOF