rhc 1.6.8 → 1.7.8

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 (85) hide show
  1. data/autocomplete/rhc_bash +1167 -0
  2. data/features/README.md +1 -1
  3. data/features/domain.feature +1 -1
  4. data/features/lib/rhc_helper/persistable.rb +4 -1
  5. data/features/multiple_cartridge.feature +4 -3
  6. data/features/sshkey.feature +3 -3
  7. data/features/support/assumptions.rb +3 -3
  8. data/features/support/env.rb +10 -0
  9. data/features/support/platform_support.rb +2 -2
  10. data/lib/rhc.rb +6 -0
  11. data/lib/rhc/auth/token.rb +4 -0
  12. data/lib/rhc/autocomplete.rb +50 -52
  13. data/lib/rhc/autocomplete_templates/{rhc.erb → bash.erb} +8 -2
  14. data/lib/rhc/cartridge_helpers.rb +1 -1
  15. data/lib/rhc/cli.rb +1 -7
  16. data/lib/rhc/command_runner.rb +45 -16
  17. data/lib/rhc/commands.rb +75 -55
  18. data/lib/rhc/commands/account.rb +7 -51
  19. data/lib/rhc/commands/alias.rb +26 -17
  20. data/lib/rhc/commands/app.rb +75 -39
  21. data/lib/rhc/commands/authorization.rb +4 -2
  22. data/lib/rhc/commands/base.rb +31 -29
  23. data/lib/rhc/commands/cartridge.rb +66 -44
  24. data/lib/rhc/commands/domain.rb +20 -8
  25. data/lib/rhc/commands/git_clone.rb +3 -3
  26. data/lib/rhc/commands/logout.rb +51 -0
  27. data/lib/rhc/commands/port_forward.rb +15 -11
  28. data/lib/rhc/commands/setup.rb +25 -0
  29. data/lib/rhc/commands/snapshot.rb +20 -10
  30. data/lib/rhc/commands/sshkey.rb +21 -7
  31. data/lib/rhc/commands/tail.rb +2 -2
  32. data/lib/rhc/commands/threaddump.rb +2 -2
  33. data/lib/rhc/context_helper.rb +0 -4
  34. data/lib/rhc/core_ext.rb +96 -76
  35. data/lib/rhc/exceptions.rb +6 -0
  36. data/lib/rhc/help_formatter.rb +19 -2
  37. data/lib/rhc/helpers.rb +32 -194
  38. data/lib/rhc/highline_extensions.rb +412 -0
  39. data/lib/rhc/output_helpers.rb +31 -67
  40. data/lib/rhc/rest.rb +4 -2
  41. data/lib/rhc/rest/alias.rb +0 -2
  42. data/lib/rhc/rest/application.rb +9 -4
  43. data/lib/rhc/rest/authorization.rb +0 -2
  44. data/lib/rhc/rest/base.rb +1 -1
  45. data/lib/rhc/rest/client.rb +11 -9
  46. data/lib/rhc/rest/domain.rb +5 -1
  47. data/lib/rhc/rest/gear_group.rb +0 -2
  48. data/lib/rhc/rest/key.rb +0 -2
  49. data/lib/rhc/rest/mock.rb +32 -10
  50. data/lib/rhc/ssh_helpers.rb +2 -2
  51. data/lib/rhc/usage_templates/command_help.erb +20 -13
  52. data/lib/rhc/usage_templates/command_syntax_help.erb +1 -3
  53. data/lib/rhc/usage_templates/help.erb +15 -16
  54. data/lib/rhc/usage_templates/options_help.erb +7 -9
  55. data/lib/rhc/wizard.rb +193 -159
  56. data/spec/rest_spec_helper.rb +2 -2
  57. data/spec/rhc/cli_spec.rb +36 -5
  58. data/spec/rhc/command_spec.rb +94 -42
  59. data/spec/rhc/commands/account_spec.rb +1 -75
  60. data/spec/rhc/commands/alias_spec.rb +28 -28
  61. data/spec/rhc/commands/app_spec.rb +141 -33
  62. data/spec/rhc/commands/apps_spec.rb +4 -4
  63. data/spec/rhc/commands/authorization_spec.rb +8 -8
  64. data/spec/rhc/commands/cartridge_spec.rb +18 -9
  65. data/spec/rhc/commands/domain_spec.rb +16 -16
  66. data/spec/rhc/commands/git_clone_spec.rb +3 -3
  67. data/spec/rhc/commands/logout_spec.rb +86 -0
  68. data/spec/rhc/commands/port_forward_spec.rb +9 -9
  69. data/spec/rhc/commands/server_spec.rb +5 -5
  70. data/spec/rhc/commands/setup_spec.rb +19 -5
  71. data/spec/rhc/commands/snapshot_spec.rb +12 -12
  72. data/spec/rhc/commands/sshkey_spec.rb +11 -11
  73. data/spec/rhc/commands/tail_spec.rb +5 -5
  74. data/spec/rhc/commands/threaddump_spec.rb +3 -3
  75. data/spec/rhc/config_spec.rb +6 -6
  76. data/spec/rhc/helpers_spec.rb +72 -219
  77. data/spec/rhc/highline_extensions_spec.rb +269 -0
  78. data/spec/rhc/rest_application_spec.rb +28 -1
  79. data/spec/rhc/rest_client_spec.rb +20 -21
  80. data/spec/rhc/rest_spec.rb +10 -0
  81. data/spec/rhc/wizard_spec.rb +72 -32
  82. data/spec/spec_helper.rb +86 -56
  83. data/spec/wizard_spec_helper.rb +7 -4
  84. metadata +165 -160
  85. data/spec/spec.opts +0 -1
@@ -19,7 +19,7 @@ module RHC
19
19
  attr_reader :code
20
20
  def initialize(message=nil, code=1)
21
21
  super(message)
22
- @code = (Integer(code) rescue code)
22
+ @code = (Integer(code) rescue nil)
23
23
  end
24
24
  end
25
25
 
@@ -68,7 +68,7 @@ module RHC
68
68
  #Exceptions thrown in case of an HTTP 422 is received.
69
69
  class ValidationException < ClientErrorException
70
70
  attr_reader :field
71
- def initialize(message, field=nil, error_code=nil)
71
+ def initialize(message, field=nil, error_code=1)
72
72
  super(message, error_code)
73
73
  @field = field
74
74
  end
@@ -113,6 +113,8 @@ module RHC
113
113
 
114
114
  class MultipleCartridgeCreationNotSupported < Exception; end
115
115
 
116
+ class InitialGitUrlNotSupported < Exception; end
117
+
116
118
  class SslCertificatesNotSupported < Exception; end
117
119
 
118
120
  class AuthorizationsNotSupported < Exception
@@ -1,5 +1,3 @@
1
- require 'rhc/rest/base'
2
-
3
1
  module RHC
4
2
  module Rest
5
3
  class Alias < Base
@@ -106,10 +106,15 @@ module RHC
106
106
 
107
107
  def aliases
108
108
  debug "Getting all aliases for application #{name}"
109
- if (client.api_version_negotiated >= 1.4)
110
- rest_method "LIST_ALIASES"
111
- else
112
- attributes['aliases']
109
+ @aliases ||= begin
110
+ aliases = attributes['aliases']
111
+ if aliases.nil? or not aliases.is_a?(Array)
112
+ supports?('LIST_ALIASES') ? rest_method("LIST_ALIASES") : []
113
+ else
114
+ aliases.map do |a|
115
+ Alias.new(a.is_a?(String) ? {'id' => a} : a, client)
116
+ end
117
+ end
113
118
  end
114
119
  end
115
120
 
@@ -1,5 +1,3 @@
1
- require 'rhc/rest/base'
2
-
3
1
  module RHC
4
2
  module Rest
5
3
  class Authorization < Base
@@ -35,7 +35,7 @@ module RHC
35
35
  end
36
36
 
37
37
  def supports?(sym)
38
- links.has_key?(sym.to_s) || links.has_key?(sym.to_s.upcase)
38
+ !!(links[sym.to_s] || links[sym.to_s.upcase])
39
39
  end
40
40
 
41
41
  protected
@@ -199,14 +199,6 @@ module RHC
199
199
  # See #api_version_negotiated
200
200
  CLIENT_API_VERSIONS = [1.1, 1.2, 1.3, 1.4]
201
201
 
202
- # Set the http_proxy env variable, read by
203
- # HTTPClient, being sure to add the http protocol
204
- # if not specified already
205
- proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
206
- if proxy && proxy !~ /^(\w+):\/\// then
207
- ENV['http_proxy'] = "http://#{proxy}"
208
- end
209
-
210
202
  def initialize(*args)
211
203
  options = args[0].is_a?(Hash) && args[0] || {}
212
204
  @end_point, @debug, @preferred_api_versions =
@@ -237,6 +229,8 @@ module RHC
237
229
  self.headers.merge!(options.delete(:headers)) if options[:headers]
238
230
  self.options.merge!(options)
239
231
 
232
+ update_http_proxy_env
233
+
240
234
  debug "Connecting to #{@end_point}"
241
235
  end
242
236
 
@@ -266,7 +260,7 @@ module RHC
266
260
  auth = options[:auth] || self.auth
267
261
  response = nil
268
262
 
269
- debug "Request #{args[0].to_s.upcase} #{args[1]}" if debug?
263
+ debug "Request #{args[0].to_s.upcase} #{args[1]}#{"?#{args[2].map{|a| a.join('=')}.join(' ')}" if args[2] && args[0] == 'GET'}" if debug?
270
264
  time = Benchmark.realtime{ response = client.request(*(args << true)) }
271
265
  debug " code %s %4i ms" % [response.status, (time*1000).to_i] if debug? && response
272
266
 
@@ -598,6 +592,14 @@ module RHC
598
592
  keys = messages.group_by{ |m| m['field'] }.keys.compact.sort.map(&:to_sym) rescue []
599
593
  [messages_to_error(messages), keys]
600
594
  end
595
+
596
+ def update_http_proxy_env
597
+ # Set the http_proxy env variable, read by
598
+ # HTTPClient, being sure to add the http protocol
599
+ # if not specified already
600
+ proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
601
+ ENV['http_proxy'] = "http://#{proxy}" if proxy && proxy !~ /^(\w+):\/\//
602
+ end
601
603
  end
602
604
  end
603
605
  end
@@ -16,13 +16,17 @@ module RHC
16
16
  options.each{ |key, value| payload[key.to_sym] = value }
17
17
 
18
18
  cartridges = Array(payload.delete(:cartridge)).concat(Array(payload.delete(:cartridges))).compact.uniq
19
- if (client.api_version_negotiated >= 1.3)
19
+ if client.api_version_negotiated >= 1.3
20
20
  payload[:cartridges] = cartridges
21
21
  else
22
22
  raise RHC::Rest::MultipleCartridgeCreationNotSupported, "The server only supports creating an application with a single web cartridge." if cartridges.length > 1
23
23
  payload[:cartridge] = cartridges.first
24
24
  end
25
25
 
26
+ if client.api_version_negotiated < 1.3 && payload[:initial_git_url]
27
+ raise RHC::Rest::InitialGitUrlNotSupported, "The server does not support creating applications from a source repository."
28
+ end
29
+
26
30
  options = {:timeout => options[:scale] && 0 || nil}
27
31
  rest_method "ADD_APPLICATION", payload, options
28
32
  end
@@ -1,5 +1,3 @@
1
- require 'rhc/rest/base'
2
-
3
1
  module RHC
4
2
  module Rest
5
3
  class GearGroup < Base
@@ -1,5 +1,3 @@
1
- require 'rhc/rest/base'
2
-
3
1
  module RHC
4
2
  module Rest
5
3
  class Key < Base
@@ -1,5 +1,3 @@
1
- require "rhc/rest"
2
-
3
1
  module RHC::Rest::Mock
4
2
 
5
3
  def self.start
@@ -70,9 +68,9 @@ module RHC::Rest::Mock
70
68
  def stub_user(auth=mock_user_auth)
71
69
  stub_api_request(:get, 'broker/rest/user', auth).to_return(simple_user(username))
72
70
  end
73
- def stub_create_default_key
71
+ def stub_add_key(name='default')
74
72
  stub_api_request(:post, 'broker/rest/user/keys', mock_user_auth).
75
- with(:body => hash_including({:name => 'default', :type => 'ssh-rsa'})).
73
+ with(:body => hash_including({:name => name, :type => 'ssh-rsa'})).
76
74
  to_return({:status => 201, :body => {}.to_json})
77
75
  end
78
76
  def stub_update_key(name)
@@ -80,6 +78,11 @@ module RHC::Rest::Mock
80
78
  with(:body => hash_including({:type => 'ssh-rsa'})).
81
79
  to_return({:status => 200, :body => {}.to_json})
82
80
  end
81
+ def stub_add_key_error(name, message, code=422)
82
+ stub_api_request(:post, "broker/rest/user/keys", mock_user_auth).
83
+ with(:body => hash_including({:type => 'ssh-rsa'})).
84
+ to_return({:status => code, :body => {:messages => [{:text => message, :field => 'name', :severity => 'error'}]}.to_json})
85
+ end
83
86
  def stub_create_domain(name)
84
87
  stub_api_request(:post, 'broker/rest/domains', mock_user_auth).
85
88
  with(:body => hash_including({:id => name})).
@@ -117,7 +120,7 @@ module RHC::Rest::Mock
117
120
  to_return(new_authorization(params))
118
121
  end
119
122
  def stub_no_keys
120
- stub_api_request(:get, 'broker/rest/user/keys', mock_user_auth).to_return(no_keys)
123
+ stub_api_request(:get, 'broker/rest/user/keys', mock_user_auth).to_return(empty_keys)
121
124
  end
122
125
  def stub_mock_ssh_keys(name='test')
123
126
  stub_api_request(:get, 'broker/rest/user/keys', mock_user_auth).
@@ -156,7 +159,7 @@ module RHC::Rest::Mock
156
159
  })
157
160
  end
158
161
  def stub_no_domains
159
- stub_api_request(:get, 'broker/rest/domains', mock_user_auth).to_return(no_domains)
162
+ stub_api_request(:get, 'broker/rest/domains', mock_user_auth).to_return(empty_domains)
160
163
  end
161
164
  def stub_one_domain(name)
162
165
  stub_api_request(:get, 'broker/rest/domains', mock_user_auth).
@@ -218,10 +221,10 @@ module RHC::Rest::Mock
218
221
  EOM
219
222
  end
220
223
 
221
- def no_keys
224
+ def empty_keys
222
225
  empty_response_list('keys')
223
226
  end
224
- def no_domains
227
+ def empty_domains
225
228
  empty_response_list('domains')
226
229
  end
227
230
 
@@ -411,6 +414,20 @@ module RHC::Rest::Mock
411
414
  }
412
415
  end
413
416
 
417
+ def mock_alias_response(count=1)
418
+ aliases = count.times.inject([]) do |arr, i|
419
+ arr << {:id => "www.alias#{i}.com"}
420
+ end
421
+
422
+ return {
423
+ :body => {
424
+ :type => count == 1 ? 'alias' : 'aliases',
425
+ :data => aliases
426
+ }.to_json,
427
+ :status => 200
428
+ }
429
+ end
430
+
414
431
  def mock_gear_groups_response()
415
432
  groups = [{}]
416
433
  type = 'gear_groups'
@@ -428,7 +445,7 @@ module RHC::Rest::Mock
428
445
  class MockRestClient < RHC::Rest::Client
429
446
  include Helpers
430
447
 
431
- def initialize(config=RHC::Config)
448
+ def initialize(config=RHC::Config, version=1.0)
432
449
  obj = self
433
450
  if RHC::Rest::Client.respond_to?(:stub)
434
451
  RHC::Rest::Client.stub(:new) { obj }
@@ -443,6 +460,7 @@ module RHC::Rest::Mock
443
460
  @domains = []
444
461
  @user = MockRestUser.new(client, config.username)
445
462
  @api = MockRestApi.new(client, config)
463
+ @version = version
446
464
  end
447
465
 
448
466
  def api
@@ -457,6 +475,10 @@ module RHC::Rest::Mock
457
475
  @domains
458
476
  end
459
477
 
478
+ def api_version_negotiated
479
+ @version
480
+ end
481
+
460
482
  def cartridges
461
483
  premium_embedded = MockRestCartridge.new(self, "premium_cart", "embedded")
462
484
  premium_embedded.usage_rate = 0.05
@@ -618,7 +640,7 @@ module RHC::Rest::Mock
618
640
  end
619
641
  end
620
642
 
621
- def destroy
643
+ def destroy
622
644
  puts @application.inspect
623
645
  puts self.inspect
624
646
  @application.aliases.delete self
@@ -127,7 +127,7 @@ module RHC
127
127
  end
128
128
 
129
129
  def fingerprint_for_default_key
130
- fingerprint_for_local_key RHC::Config.ssh_pub_key_file_path
130
+ fingerprint_for_local_key(RHC::Config.ssh_pub_key_file_path)
131
131
  end
132
132
 
133
133
  # for an SSH public key specified by 'key', return a triple
@@ -144,7 +144,7 @@ module RHC
144
144
  end
145
145
 
146
146
  def ssh_key_triple_for_default_key
147
- ssh_key_triple_for RHC::Config.ssh_pub_key_file_path
147
+ ssh_key_triple_for(RHC::Config.ssh_pub_key_file_path)
148
148
  end
149
149
 
150
150
  private
@@ -4,27 +4,34 @@ Usage: <%= Array(program :name).first %> <%= @command.name %> <%= @command.synta
4
4
  <% if @actions.blank? -%>
5
5
  <% unless @command.options.blank? or @command.options.all?{ |o| o[:hide] } -%>
6
6
 
7
- Options for <%= @command.name %>
8
- <% for option in @command.options -%><% next if option[:hide] -%>
9
- <%= "%-25s %s\n" % [option[:switches].join(', '), option[:description]] -%>
10
- <% end -%>
7
+ Options
8
+ <%= table(
9
+ @command.options.select do |opt|
10
+ not opt[:hide]
11
+ end.map do |opt|
12
+ [opt[:switches].join(', '), opt[:description]]
13
+ end,
14
+ table_args(' ', 25)
15
+ ).join("\n") %>
11
16
  <% end -%>
12
17
 
13
18
  Global Options
14
- <% for option in @global_options -%><% next if option[:hide] || @command.options.any?{ |o| (o[:switches] & option[:switches]).present? } -%>
15
- <%= "%-25s %s\n" % [option[:switches].join(', '), option[:description]] -%>
16
- <% end -%>
17
-
18
- See 'rhc help options' for a full list of command-line options.
19
+ <%= table(
20
+ @global_options.select do |opt|
21
+ not (opt[:hide] || @command.options.any?{ |o| (o[:switches] & opt[:switches]).present? })
22
+ end.map do |opt|
23
+ [opt[:switches].join(', '), opt[:description]]
24
+ end,
25
+ table_args(' ', 25)
26
+ ).join("\n") %>
19
27
 
28
+ See 'rhc help options' for a full list of global options.
20
29
  <% else -%>
21
30
 
22
31
  List of Actions
23
- <% for action in @actions -%>
24
- <%= "%-18s %s\n" % [action[:name], action[:summary]] -%>
25
- <% end -%>
32
+ <%= table(@actions.map{ |a| [a[:name], a[:summary]] }, table_args(' ', 13)).join("\n") %>
26
33
  <% if @command.default_action? -%>
27
34
 
28
35
  The default action for this resource is '<%= @command.default_action %>'
29
36
  <% end -%>
30
- <% end -%>
37
+ <% end -%>
@@ -5,7 +5,5 @@ Pass '--help' to see the full list of options
5
5
  <% unless @actions.nil? or @actions.empty? -%>
6
6
 
7
7
  List of Actions
8
- <% for action in @actions -%>
9
- <%= "%-18s %s\n" % [action[:name], action[:summary]] -%>
10
- <% end -%>
8
+ <%= table(@actions.map{ |a| [a[:name], a[:summary]] }, table_args(' ', 18)).join("\n") %>
11
9
  <% end -%>
@@ -3,34 +3,33 @@ Usage: rhc [--help] [--version] [--debug] <command> [<args>]
3
3
  <%= Array(program :description).first %>
4
4
 
5
5
  <%
6
- remaining = Hash[@commands.dup.select{ |name, command| not alias?(name) and not command.summary.blank? }]
7
- basic = remaining.slice!('setup', 'app create', 'apps', 'cartridge list', 'cartridge add', 'server', 'account logout')
6
+ remaining = Hash[commands.dup.select{ |name, command| not command.summary.blank? }]
7
+ basic = remaining.slice!('setup', 'create-app', 'apps', 'cartridges', 'add-cartridge', 'server', 'logout')
8
+ remaining.delete_if{ |name, command| alias?(name) }
8
9
  begin -%>
9
10
  Getting started:
10
- <% for name, command in basic -%>
11
- <%="%-18s %s\n" % [command.name, command.summary || command.description] -%>
12
- <% end %>
13
- <% end unless basic.empty?
11
+ <%= table(basic.map{ |arr| arr[1] = arr[1].summary || arr[1].description; arr }, table_args(' ', 18)).join("\n") %>
12
+ <% end unless basic.empty? %>
13
+ <%
14
14
 
15
15
  debugging = remaining.slice!('app restart', 'app show', 'tail', 'port-forward', 'threaddump', 'snapshot', 'git-clone')
16
16
  begin -%>
17
17
  Working with apps:
18
- <% for name, command in debugging -%>
19
- <%="%-18s %s\n" % [command.name, command.summary || command.description] -%>
20
- <% end
21
- end unless debugging.empty?
22
- %>
18
+ <%= table(debugging.map{ |arr| arr[1] = arr[1].summary || arr[1].description; arr }, table_args(' ', 18)).join("\n") %>
19
+ <% end unless debugging.empty? %>
23
20
  Management commands:
24
- <% for name, command in remaining.sort -%>
25
- <%- unless alias? name or name.include?(' ') or command.summary.nil? -%> <%="%-18s %s\n" % [command.name, command.summary || command.description] %><%- end -%>
26
- <%- end -%>
21
+ <%= table(remaining.sort.select{ |arr| arr[1].root? and arr[1].summary.present? }.map do |arr|
22
+ arr[1] = arr[1].summary || arr[1].description
23
+ arr
24
+ end, table_args(' ', 18)).join("\n") %>
27
25
 
28
- See '<%= Array(program :name).first %> help <command>' for more information on a specific command. See 'rhc help options' for a list of global command-line options and information about the config file.
26
+ Some management commands have nested actions - run 'rhc help <command>' for more info.
29
27
 
28
+ See '<%= Array(program :name).first %> help <command>' for more information on a specific command. You can see a list of all commands with 'rhc help commands'. See 'rhc help options' for a list of global command-line options and information about the config file.
30
29
  <% if program :help -%>
31
30
  <% for title, body in program(:help) %>
32
31
  <%= $terminal.color title.to_s.upcase, :bold %>:
33
32
 
34
33
  <%= body %>
35
34
  <% end -%>
36
- <% end -%>
35
+ <% end -%>
@@ -1,14 +1,12 @@
1
1
  The following options can be passed to any command:
2
2
 
3
- <% for option in options -%>
4
- <%= "%-25s %s\n" % [option[:switches].join(', '), option[:description]] -%>
5
- <% end -%>
3
+ <%= table(options.map{ |option| [option[:switches].join(', '), option[:description]] }, table_args(' ', 26)).join("\n") %>
6
4
 
7
5
  The following configuration options are stored in the <%= RHC::Helpers.system_path('.openshift/express.conf') %> file in your home directory. Passing any of these options to 'rhc setup' will save that value to the file:
8
6
 
9
- <%= "%-25s %s\n" % ["Option", "In Config"] -%>
10
-
11
- <% for key, value in RHC::Config::OPTIONS -%>
12
- <% next if value.nil? -%>
13
- <%= "%-25s %s\n" % ["--#{key.to_s.gsub('_','-')}", value[0] || key] -%>
14
- <% end -%>
7
+ <%= table(
8
+ RHC::Config::OPTIONS.select{ |key,value| not value.nil? }.map do |key,value|
9
+ ["--#{key.to_s.gsub('_','-')}", value[0] || key]
10
+ end,
11
+ table_args(' ', 26).merge(:header => ['Option', 'In Config'])
12
+ ).join("\n") -%>
@@ -1,5 +1,4 @@
1
1
  require 'rhc'
2
- require 'highline/system_extensions'
3
2
  require 'fileutils'
4
3
  require 'socket'
5
4
 
@@ -13,16 +12,26 @@ module RHC
13
12
 
14
13
  DEFAULT_MAX_LENGTH = 16
15
14
 
16
- STAGES = [:greeting_stage,
17
- :login_stage,
18
- :create_config_stage,
19
- :config_ssh_key_stage,
20
- :upload_ssh_key_stage,
21
- :install_client_tools_stage,
22
- :setup_test_stage,
23
- :config_namespace_stage,
24
- :show_app_info_stage,
25
- :finalize_stage]
15
+ CONFIG_STAGES = [
16
+ :login_stage,
17
+ :create_config_stage,
18
+ ]
19
+ KEY_STAGES = [
20
+ :config_ssh_key_stage,
21
+ :upload_ssh_key_stage,
22
+ ]
23
+ TEST_STAGES = [
24
+ :install_client_tools_stage,
25
+ :setup_test_stage,
26
+ ]
27
+ NAMESPACE_STAGES = [
28
+ :config_namespace_stage,
29
+ ]
30
+ APP_STAGES = [
31
+ :show_app_info_stage,
32
+ ]
33
+ STAGES = [:greeting_stage] + CONFIG_STAGES + KEY_STAGES + TEST_STAGES + NAMESPACE_STAGES + APP_STAGES + [:finalize_stage]
34
+
26
35
  def stages
27
36
  STAGES
28
37
  end
@@ -58,55 +67,64 @@ module RHC
58
67
  end
59
68
 
60
69
  protected
61
- include RHC::Helpers
62
- include RHC::SSHHelpers
63
- include RHC::GitHelpers
64
- include RHC::CartridgeHelpers
65
- attr_reader :config, :options
66
- attr_accessor :auth, :user
67
-
68
- def openshift_server
69
- options.server || config['libra_server'] || "openshift.redhat.com"
70
- end
71
70
 
72
- def new_client_for_options
73
- client_from_options({
74
- :auth => auth,
75
- })
76
- end
71
+ include RHC::Helpers
72
+ include RHC::SSHHelpers
73
+ include RHC::GitHelpers
74
+ include RHC::CartridgeHelpers
75
+ attr_reader :config, :options
76
+ attr_accessor :auth, :user
77
+ attr_writer :rest_client
77
78
 
78
- def core_auth
79
- @core_auth ||= RHC::Auth::Basic.new(options)
80
- end
79
+ def debug?
80
+ @debug
81
+ end
81
82
 
82
- def token_auth
83
- RHC::Auth::Token.new(options, core_auth, token_store)
84
- end
83
+ def hostname
84
+ Socket.gethostname
85
+ end
85
86
 
86
- def auth(reset=false)
87
- @auth = nil if reset
88
- @auth ||= begin
89
- if options.token
90
- token_auth
91
- else
92
- core_auth
93
- end
87
+ def openshift_server
88
+ options.server || config['libra_server'] || "openshift.redhat.com"
89
+ end
90
+
91
+ def new_client_for_options
92
+ client_from_options({
93
+ :auth => auth,
94
+ })
95
+ end
96
+
97
+ def core_auth
98
+ @core_auth ||= RHC::Auth::Basic.new(options)
99
+ end
100
+
101
+ def token_auth
102
+ RHC::Auth::Token.new(options, core_auth, token_store)
103
+ end
104
+
105
+ def auth(reset=false)
106
+ @auth = nil if reset
107
+ @auth ||= begin
108
+ if options.token
109
+ token_auth
110
+ else
111
+ core_auth
94
112
  end
95
- end
113
+ end
114
+ end
96
115
 
97
- def token_store
98
- @token_store ||= RHC::Auth::TokenStore.new(config.home_conf_path)
99
- end
116
+ def token_store
117
+ @token_store ||= RHC::Auth::TokenStore.new(config.home_conf_path)
118
+ end
100
119
 
101
- def username
102
- auth.username if auth.respond_to?(:username)
103
- end
120
+ def username
121
+ options.rhlogin || (auth.username if auth.respond_to?(:username))
122
+ end
104
123
 
105
- def print_dot
106
- $terminal.instance_variable_get(:@output).print('.')
107
- end
124
+ def print_dot
125
+ $terminal.instance_variable_get(:@output).print('.')
126
+ end
108
127
 
109
- private
110
128
 
111
129
  # cache SSH keys from the REST client
112
130
  def ssh_keys
@@ -118,6 +136,29 @@ module RHC
118
136
  @ssh_keys = nil
119
137
  end
120
138
 
139
+ # return true if the account has the public key defined by
140
+ # RHC::Config::ssh_pub_key_file_path
141
+ def ssh_key_uploaded?
142
+ ssh_keys.present? && ssh_keys.any? { |k| k.fingerprint.present? && k.fingerprint == fingerprint_for_default_key }
143
+ end
144
+
145
+ def existing_keys_info
146
+ return unless ssh_keys
147
+ indent{ ssh_keys.each{ |key| paragraph{ display_key(key) } } }
148
+ end
149
+
150
+ def applications
151
+ @applications ||= rest_client.domains.map(&:applications).flatten
152
+ end
153
+
154
+ def namespace_optional?
155
+ true
156
+ end
157
+
158
+ #
159
+ # Stages
160
+ #
161
+
121
162
  def greeting_stage
122
163
  info "OpenShift Client Tools (RHC) Setup Wizard"
123
164
 
@@ -129,7 +170,8 @@ module RHC
129
170
  end
130
171
 
131
172
  def login_stage
132
- if options.token
173
+ if token_for_user
174
+ options.token = token_for_user
133
175
  say "Using an existing token for #{options.rhlogin} to login to #{openshift_server}"
134
176
  elsif options.rhlogin
135
177
  say "Using #{options.rhlogin} to login to #{openshift_server}"
@@ -161,6 +203,7 @@ module RHC
161
203
  end
162
204
 
163
205
  self.user = rest_client.user
206
+ options.rhlogin = self.user.login unless username
164
207
 
165
208
  if rest_client.supports_sessions? && !options.token && options.create_token != false
166
209
  paragraph do
@@ -215,122 +258,106 @@ module RHC
215
258
  true
216
259
  end
217
260
 
218
- # return true if the account has the public key defined by
219
- # RHC::Config::ssh_pub_key_file_path
220
- def ssh_key_uploaded?
221
- ssh_keys.any? { |k| k.fingerprint == fingerprint_for_default_key }
222
- end
261
+ def upload_ssh_key_stage
262
+ return true if ssh_key_uploaded?
223
263
 
224
- def existing_keys_info
225
- return unless ssh_keys
226
- indent{ ssh_keys.each{ |key| paragraph{ display_key(key) } } }
227
- end
264
+ upload = paragraph do
265
+ agree "Your public SSH key must be uploaded to the OpenShift server to access code. Upload now? (yes|no) "
266
+ end
228
267
 
229
- def get_preferred_key_name
230
- key_name = 'default'
268
+ if upload
269
+ if ssh_keys.empty?
270
+ paragraph do
271
+ info "Since you do not have any keys associated with your OpenShift account, "\
272
+ "your new key will be uploaded as the 'default' key."
273
+ upload_ssh_key('default')
274
+ end
275
+ else
276
+ paragraph { existing_keys_info }
277
+
278
+ key_fingerprint = fingerprint_for_default_key
279
+ unless key_fingerprint
280
+ paragraph do
281
+ warn "Your ssh public key at #{system_path(RHC::Config.ssh_pub_key_file_path)} is invalid or unreadable. "\
282
+ "Setup can not continue until you manually remove or fix your "\
283
+ "public and private keys id_rsa keys."
284
+ end
285
+ return false
286
+ end
231
287
 
232
- if ssh_keys.empty?
233
- paragraph do
234
- info "Since you do not have any keys associated with your OpenShift account, "\
235
- "your new key will be uploaded as the 'default' key."
288
+ paragraph do
289
+ say "You can enter a name for your key, or leave it blank to use the default name. " \
290
+ "Using the same name as an existing key will overwrite the old key."
291
+ end
292
+ ask_for_key_name
236
293
  end
237
294
  else
238
295
  paragraph do
239
- say "You can enter a name for your key, or leave it blank to use the default name. " \
240
- "Using the same name as an existing key will overwrite the old key."
241
- end
242
-
243
- paragraph { existing_keys_info }
244
-
245
- key_fingerprint = fingerprint_for_default_key
246
- unless key_fingerprint
247
- paragraph do
248
- warn "Your ssh public key at #{system_path(RHC::Config.ssh_pub_key_file_path)} is invalid or unreadable. "\
249
- "Setup can not continue until you manually remove or fix your "\
250
- "public and private keys id_rsa keys."
251
- end
252
- return nil
296
+ info "You can upload your SSH key at a later time using the 'rhc sshkey' command"
253
297
  end
298
+ end
254
299
 
255
- userkey = username ? username.gsub(/@.*/, '') : ''
256
- pubkey_base_name = "#{userkey}#{hostname.gsub(/\..*\z/,'')}".gsub(/[^A-Za-z0-9]/,'').slice(0,16)
257
- default_name = find_unique_key_name(
258
- :keys => ssh_keys,
259
- :base => pubkey_base_name,
260
- :max_length => DEFAULT_MAX_LENGTH
261
- )
300
+ true
301
+ end
262
302
 
263
- paragraph do
264
- key_name = ask("Provide a name for this key: ") do |q|
303
+ def ask_for_key_name(default_name=get_preferred_key_name)
304
+ key_name = nil
305
+ paragraph do
306
+ begin
307
+ key_name = ask "Provide a name for this key: " do |q|
265
308
  q.default = default_name
266
- q.validate = /^[0-9a-zA-Z]*$/
267
- q.responses[:not_valid] = 'Your key name must be letters and numbers only.'
309
+ q.responses[:ask_on_error] = ''
268
310
  end
269
- end
311
+ end while !upload_ssh_key(key_name)
270
312
  end
313
+ end
271
314
 
272
- key_name
315
+ def get_preferred_key_name
316
+ userkey = username ? username.gsub(/@.*/, '') : ''
317
+ pubkey_base_name = "#{userkey}#{hostname.gsub(/\..*\z/,'')}".gsub(/[^A-Za-z0-9]/,'').slice(0,16)
318
+ find_unique_key_name(pubkey_base_name)
273
319
  end
274
-
320
+
275
321
  # given the base name and the maximum length,
276
322
  # find a name that does not clash with what is in opts[:keys]
277
- def find_unique_key_name(opts)
278
- keys = opts[:keys] || ssh_keys
279
- base = opts[:base] || 'default'
280
- max = opts[:max_length] || DEFAULT_MAX_LENGTH
323
+ def find_unique_key_name(base='default')
324
+ max = DEFAULT_MAX_LENGTH
281
325
  key_name_suffix = 1
282
326
  candidate = base
283
327
  while ssh_keys.detect { |k| k.name == candidate }
284
- candidate = base.slice(0, max - key_name_suffix.to_s.length) +
285
- key_name_suffix.to_s
328
+ candidate = base.slice(0, max - key_name_suffix.to_s.length) + key_name_suffix.to_s
286
329
  key_name_suffix += 1
287
330
  end
288
331
  candidate
289
332
  end
290
333
 
291
- def upload_ssh_key
292
- key_name = get_preferred_key_name
293
- return false unless key_name
334
+ def upload_ssh_key(key_name)
335
+ return false unless key_name.present?
294
336
 
295
337
  type, content, comment = ssh_key_triple_for_default_key
296
- indent do
297
- say table([['Type:', type], ['Fingerprint:', fingerprint_for_default_key]])
298
- end
299
338
 
300
- paragraph do
301
- if !ssh_keys.empty? && ssh_keys.any? { |k| k.name == key_name }
302
- clear_ssh_keys_cache
303
- say "Key with the name #{key_name} already exists. Updating ... "
339
+ if ssh_keys.present? && ssh_keys.any? { |k| k.name == key_name }
340
+ clear_ssh_keys_cache
341
+ paragraph do
342
+ say "Key with the name '#{key_name}' already exists. Updating ... "
304
343
  key = rest_client.find_key(key_name)
305
344
  key.update(type, content)
306
- else
307
- clear_ssh_keys_cache
308
- say "Uploading key '#{key_name}' from #{system_path(RHC::Config::ssh_pub_key_file_path)} ... "
309
- rest_client.add_key key_name, content, type
345
+ success "done"
310
346
  end
311
- success "done"
312
- end
313
-
314
- true
315
- end
316
-
317
- def upload_ssh_key_stage
318
- return true if ssh_key_uploaded?
319
-
320
- upload = paragraph do
321
- agree "Your public SSH key must be uploaded to the OpenShift server to access code. Upload now? (yes|no) "
322
- end
323
-
324
- if upload
325
- upload_ssh_key
326
347
  else
327
- paragraph do
328
- info "You can upload your SSH key at a later time using the 'rhc sshkey' command"
348
+ clear_ssh_keys_cache
349
+ begin
350
+ rest_client.add_key(key_name, content, type)
351
+ paragraph{ say "Uploading key '#{key_name}' ... #{color('done', :green)}" }
352
+ rescue RHC::Rest::ValidationException => e
353
+ error e.message || "Unknown error during key upload."
354
+ return false
329
355
  end
330
356
  end
331
357
 
332
358
  true
333
- end
359
+ end
360
+
334
361
 
335
362
  ##
336
363
  # Alert the user that they should manually install tools if they are not
@@ -397,7 +424,7 @@ module RHC
397
424
  paragraph do
398
425
  say table(standalone_cartridges.sort {|a,b| a.display_name <=> b.display_name }.map do |cart|
399
426
  [' ', cart.display_name, "rhc app create <app name> #{cart.name}"]
400
- end).join("\n")
427
+ end)
401
428
  end
402
429
  end
403
430
  paragraph do
@@ -440,12 +467,7 @@ module RHC
440
467
  end
441
468
 
442
469
  def all_test_methods
443
- private_methods.select {|m| m.to_s.start_with? 'test_'}
444
- end
445
-
446
- # cached list of applications needed for test stage
447
- def applications
448
- @applications ||= rest_client.domains.map(&:applications).flatten
470
+ (protected_methods + private_methods).select {|m| m.to_s.start_with? 'test_'}
449
471
  end
450
472
 
451
473
  ###
@@ -491,13 +513,14 @@ module RHC
491
513
 
492
514
  def config_namespace(namespace)
493
515
  # skip if string is empty
494
- if namespace.nil? or namespace.chomp.length == 0
516
+ if namespace_optional? and (namespace.nil? or namespace.chomp.blank?)
495
517
  paragraph{ info "You may create a namespace later through 'rhc domain create'" }
496
518
  return true
497
519
  end
498
520
 
499
521
  begin
500
522
  domain = rest_client.add_domain(namespace)
523
+ options.namespace = namespace
501
524
 
502
525
  success "Your domain name '#{domain.id}' has been successfully created"
503
526
  rescue RHC::Rest::ValidationException => e
@@ -513,9 +536,7 @@ module RHC
513
536
  namespace = nil
514
537
  paragraph do
515
538
  begin
516
- namespace = ask "Please enter a namespace (letters and numbers only) |<none>|: " do |q|
517
- #q.validate = lambda{ |p| RHC::check_namespace p }
518
- #q.responses[:not_valid] = 'The namespace value must contain only letters and/or numbers (A-Za-z0-9):'
539
+ namespace = ask "Please enter a namespace (letters and numbers only)#{namespace_optional? ? " |<none>|" : ""}: " do |q|
519
540
  q.responses[:ask_on_error] = ''
520
541
  end
521
542
  end while !config_namespace(namespace)
@@ -557,21 +578,9 @@ We recommend these free applications:
557
578
 
558
579
  EOF
559
580
  end
560
-
561
- def debug?
562
- @debug
563
- end
564
-
565
- def hostname
566
- Socket.gethostname
567
- end
568
-
569
- protected
570
- attr_writer :rest_client
571
581
  end
572
582
 
573
583
  class RerunWizard < Wizard
574
-
575
584
  def finalize_stage
576
585
  section :top => 1 do
577
586
  success "Your client tools are now configured."
@@ -580,11 +589,36 @@ EOF
580
589
  end
581
590
  end
582
591
 
592
+ class EmbeddedWizard < Wizard
593
+ def stages
594
+ super - APP_STAGES - KEY_STAGES - [:setup_test_stage]
595
+ end
596
+
597
+ def finalize_stage
598
+ true
599
+ end
600
+ end
601
+
602
+ class DomainWizard < Wizard
603
+ def initialize(*args)
604
+ client = args.length == 3 ? args.pop : nil
605
+ super *args
606
+ self.rest_client = client || new_client_for_options
607
+ end
608
+
609
+ def stages
610
+ [:config_namespace_stage]
611
+ end
612
+
613
+ protected
614
+ def namespace_optional?
615
+ false
616
+ end
617
+ end
618
+
583
619
  class SSHWizard < Wizard
584
- STAGES = [:config_ssh_key_stage,
585
- :upload_ssh_key_stage]
586
620
  def stages
587
- STAGES
621
+ KEY_STAGES
588
622
  end
589
623
 
590
624
  def initialize(rest_client, config, options)