rhc 1.9.6 → 1.10.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/features/lib/rhc_helper.rb +0 -4
  3. data/features/lib/rhc_helper/app.rb +10 -10
  4. data/features/lib/rhc_helper/commandify.rb +6 -24
  5. data/features/support/before_hooks.rb +1 -1
  6. data/features/support/env.rb +9 -2
  7. data/features/support/platform_support.rb +11 -1
  8. data/lib/rhc/auth/basic.rb +4 -1
  9. data/lib/rhc/cartridge_helpers.rb +4 -8
  10. data/lib/rhc/commands.rb +6 -3
  11. data/lib/rhc/commands/alias.rb +1 -0
  12. data/lib/rhc/commands/app.rb +104 -67
  13. data/lib/rhc/commands/authorization.rb +2 -1
  14. data/lib/rhc/commands/base.rb +8 -1
  15. data/lib/rhc/commands/cartridge.rb +39 -16
  16. data/lib/rhc/commands/git_clone.rb +2 -1
  17. data/lib/rhc/commands/port_forward.rb +4 -6
  18. data/lib/rhc/commands/ssh.rb +54 -0
  19. data/lib/rhc/exceptions.rb +12 -7
  20. data/lib/rhc/git_helpers.rb +4 -5
  21. data/lib/rhc/help_formatter.rb +11 -6
  22. data/lib/rhc/helpers.rb +24 -3
  23. data/lib/rhc/highline_extensions.rb +31 -6
  24. data/lib/rhc/output_helpers.rb +0 -29
  25. data/lib/rhc/rest.rb +16 -1
  26. data/lib/rhc/rest/application.rb +7 -3
  27. data/lib/rhc/rest/base.rb +7 -2
  28. data/lib/rhc/rest/client.rb +7 -14
  29. data/lib/rhc/rest/gear_group.rb +10 -1
  30. data/lib/rhc/rest/mock.rb +34 -8
  31. data/lib/rhc/ssh_helpers.rb +144 -1
  32. data/lib/rhc/usage_templates/command_help.erb +16 -2
  33. data/spec/coverage_helper.rb +10 -7
  34. data/spec/rhc/commands/alias_spec.rb +28 -0
  35. data/spec/rhc/commands/app_spec.rb +64 -45
  36. data/spec/rhc/commands/authorization_spec.rb +16 -0
  37. data/spec/rhc/commands/cartridge_spec.rb +59 -3
  38. data/spec/rhc/commands/port_forward_spec.rb +6 -6
  39. data/spec/rhc/commands/ssh_spec.rb +125 -0
  40. data/spec/rhc/commands/tail_spec.rb +4 -3
  41. data/spec/rhc/helpers_spec.rb +70 -42
  42. data/spec/rhc/highline_extensions_spec.rb +23 -1
  43. data/spec/rhc/rest_client_spec.rb +6 -9
  44. data/spec/rhc/rest_spec.rb +41 -2
  45. data/spec/spec_helper.rb +38 -0
  46. metadata +336 -373
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7c23c41b519b26aa7aee54c9e93e0d47e8c54a51
4
+ data.tar.gz: 1859032019fb864654b41f9270bd42bcda16e6a8
5
+ SHA512:
6
+ metadata.gz: f21f8a5e3a943ffd84ace86a9a47c0ffa5c3327d93953bf14901c5ab6f9329d7d03f83220a59252d655f7c8c2aaab5b1097016215cb1ca4b35c5de972eb1a570
7
+ data.tar.gz: b0bb0eaba39778c409bbe84aa035b45b1c61867dfa2221b2cd61b6629da2476d56e38eed49d3cc0634acc544b094671b15d3913f37c70fb79a4fe80306c03736
@@ -5,10 +5,6 @@ require 'tmpdir'
5
5
  ### Some shared constant declarations
6
6
  module RHCHelper
7
7
  TEMP_DIR = File.join(Dir.tmpdir, "rhc") unless const_defined?(:TEMP_DIR)
8
- # The regex to parse the UUID output from the create app results
9
- UUID_OUTPUT_PATTERN = /UUID\s*(?:\:|=)\s*(.+)/i unless const_defined?(:UUID_OUTPUT_PATTERN)
10
- # The regex to parse the Gear Profile output from the create app results
11
- GEAR_PROFILE_OUTPUT_PATTERN = /Gear Size\s*(?:\:|=)\s*(\w+)/m unless const_defined?(:GEAR_PROFILE_OUTPUT_PATTERN)
12
8
  # Regex to parse passwords out of logging messages
13
9
  PASSWORD_REGEX = / -p [^\s]* / unless const_defined?(:PASSWORD_REGEX)
14
10
  end
@@ -117,20 +117,20 @@ module RHCHelper
117
117
  end
118
118
 
119
119
  def get_index_file
120
- case @type
121
- when "php-5.3","php-5.4" then "php/index.php"
122
- when "ruby-1.8" then "config.ru"
123
- when "python-2.6" then "wsgi/application"
124
- when "perl-5.10" then "perl/index.pl"
125
- when "jbossas-7" then "src/main/webapp/index.html"
126
- when "jbosseap-6.0" then "src/main/webapp/index.html"
127
- when "nodejs-0.6" then "index.html"
120
+ case @type.split("-").first
121
+ when "php" then "php/index.php"
122
+ when "ruby" then "config.ru"
123
+ when "python" then "wsgi/application"
124
+ when "perl" then "perl/index.pl"
125
+ when "jbossas" then "src/main/webapp/index.html"
126
+ when "jbosseap" then "src/main/webapp/index.html"
127
+ when "nodejs" then "index.html"
128
128
  end
129
129
  end
130
130
 
131
131
  def get_mysql_file
132
- case @type
133
- when "php-5.3","php-5.4" then File.expand_path("../misc/php/db_test.php", File.expand_path(File.dirname(__FILE__)))
132
+ case @type.split("-").first
133
+ when "php" then File.expand_path("../misc/php/db_test.php", File.expand_path(File.dirname(__FILE__)))
134
134
  end
135
135
  end
136
136
  end
@@ -124,34 +124,16 @@ module RHCHelper
124
124
  end
125
125
  end
126
126
 
127
+ # The regex to parse the UUID output from the create app results
128
+ UUID_OUTPUT_PATTERN = /UUID\s*(?:\:|=)\s*(.+)/i unless const_defined?(:UUID_OUTPUT_PATTERN)
129
+ # The regex to parse the Gear Profile output from the create app results
130
+ GEAR_PROFILE_OUTPUT_PATTERN = /Gear Size\s*(?:\:|=)\s*(\w+)/m unless const_defined?(:GEAR_PROFILE_OUTPUT_PATTERN)
131
+
127
132
  #
128
133
  # Begin Post Processing Callbacks
129
134
  #
130
135
  def app_create_callback(exitcode, stdout, stderr, arg)
131
- match = stdout.match(UUID_OUTPUT_PATTERN)
132
- @uid = match[1] if match
133
- match = stdout.match(GEAR_PROFILE_OUTPUT_PATTERN)
134
- @gear_profile = nil
135
- @gear_profile = match[1] if match
136
-
137
- def no_match(msg,expected,actual)
138
- [ msg,
139
- "-"*20,
140
- ("Expected: %s" % expected),
141
- ("Actual:\n%s" % actual),
142
- "-"*20,
143
- ].join("\n")
144
- end
145
-
146
- raise no_match(
147
- "UID not parsed from app create output",
148
- UUID_OUTPUT_PATTERN, stdout
149
- ) unless @uid
150
-
151
- raise no_match(
152
- "Gear Profile not parsed from app create output",
153
- GEAR_PROFILE_OUTPUT_PATTERN, stdout
154
- ) unless @gear_profile
136
+ stdout.should =~ /Your application '([^']+)' is now available./
155
137
 
156
138
  persist
157
139
  end
@@ -45,7 +45,7 @@ Before('@cartridge_storage_user_required') do
45
45
  $namespace = nil
46
46
 
47
47
  if !$cleaned_storage
48
- clean_applications($username)
48
+ clean_applications($username, true)
49
49
  $cleaned_storage = true
50
50
  end
51
51
  end
@@ -8,7 +8,15 @@ rescue
8
8
  exit 1
9
9
  end
10
10
 
11
- $target_os = ENV['RHC_TARGET'] || (File.exist?("/etc/fedora-release") ? "Fedora" : "RHEL")
11
+ $target_os = ENV['RHC_TARGET']
12
+ if $target_os.nil?
13
+ if File.exist?("/etc/fedora-release")
14
+ version = File.open("/etc/fedora-release").read.match(/[\w ]*release ([\d]+) [.]*/)[1]
15
+ $target_os = "fedora-#{version}"
16
+ else
17
+ $target_os = "rhel"
18
+ end
19
+ end
12
20
 
13
21
  require 'rhc/coverage_helper'
14
22
  SimpleCov.at_exit{ SimpleCov.result.format! } if defined? SimpleCov
@@ -82,7 +90,6 @@ if ENV['REGISTER_USER']
82
90
  command = $user_register_script_format % [$username,$password]
83
91
  if Object.const_defined?('Bundler')
84
92
  Bundler::with_clean_env do
85
- system "gem install activeresource bundler parseconfig --no-ri --no-rdoc"
86
93
  system command
87
94
  end
88
95
  else
@@ -1,4 +1,4 @@
1
- if $target_os == 'Fedora'
1
+ if $target_os == 'fedora-18'
2
2
  CARTRIDGE_MAP = {
3
3
  "php" => { type: "php-5.4", name: "PHP 5.4" },
4
4
  "mysql" => { type: "mysql-5.1", name: "MySQL Database 5.1" },
@@ -8,6 +8,16 @@ if $target_os == 'Fedora'
8
8
  "cron" => { type: "cron-1.4", name: "Cron 1.4" },
9
9
  "haproxy" => { type: "haproxy-1.4", name: "" }
10
10
  }
11
+ elsif $target_os == 'fedora-19'
12
+ CARTRIDGE_MAP = {
13
+ "php" => { type: "php-5.5", name: "PHP 5.5" },
14
+ "mysql" => { type: "mariadb-5.5", name: "MariaDB 5.5" },
15
+ "phpmyadmin" => { type: "phpmyadmin-3.5", name: "phpMyAdmin 3.5" },
16
+ "mongodb" => { type: "mongodb-2.2", name: "MongoDB NoSQL Database 2.2" },
17
+ "postgresql" => { type: "postgresql-9.2", name: "PostgreSQL Database 9.2" },
18
+ "cron" => { type: "cron-1.4", name: "Cron 1.4" },
19
+ "haproxy" => { type: "haproxy-1.4", name: "" }
20
+ }
11
21
  else
12
22
  CARTRIDGE_MAP = {
13
23
  "php" => { type: "php-5.3", name: "PHP 5.3" },
@@ -49,7 +49,10 @@ module RHC::Auth
49
49
  @username = ask("Login to #{openshift_server}: ") unless @no_interactive
50
50
  end
51
51
  def ask_password
52
- @password = ask("Password: ") { |q| q.echo = '*' } unless @no_interactive
52
+ @password = ask("Password: ") { |q|
53
+ q.echo = '*'
54
+ q.whitespace = :chomp
55
+ } unless @no_interactive
53
56
  end
54
57
 
55
58
  def username?
@@ -35,8 +35,8 @@ module RHC
35
35
  end
36
36
 
37
37
  def use_cart(cart, for_cartridge_name)
38
- if cart.custom?
39
- info "The cartridge '#{cart.url}' will be downloaded and installed"
38
+ if cart.name.blank? and cart.custom?
39
+ info "The cartridge '#{cart.url}' will be downloaded and installed"
40
40
  else
41
41
  info "Using #{cart.name}#{cart.display_name ? " (#{cart.display_name})" : ''} for '#{for_cartridge_name}'"
42
42
  end
@@ -57,9 +57,7 @@ module RHC
57
57
  next cart unless cart.is_a? Array
58
58
  name = cart.instance_variable_get(:@for)
59
59
  matching = cart.select{ |c| not c.only_in_existing? }
60
- if matching.empty?
61
- raise RHC::MultipleCartridgesException, "You must select only a single web cartridge. '#{name}' matches web cartridges."
62
- elsif matching.size == 1
60
+ if matching.size == 1
63
61
  use_cart(matching.first, name)
64
62
  else
65
63
  matching.instance_variable_set(:@for, name)
@@ -73,9 +71,7 @@ module RHC
73
71
  next cart unless cart.is_a? Array
74
72
  name = cart.instance_variable_get(:@for)
75
73
  matching = cart.select{ |c| not c.only_in_new? }
76
- if matching.empty?
77
- raise RHC::MultipleCartridgesException, "You must select only a single web cartridge. '#{name}' matches web cartridges."
78
- elsif matching.size == 1
74
+ if matching.size == 1
79
75
  use_cart(matching.first, name)
80
76
  else
81
77
  matching.instance_variable_set(:@for, name)
@@ -16,6 +16,7 @@ module Commander
16
16
  def deprecated(as_alias=nil)
17
17
  return false unless info
18
18
  return info[:deprecated] if info[:deprecated]
19
+ return false unless info[:aliases]
19
20
  info[:aliases].select{ |a| ['-',' '].map{ |s| Array(a[:action]).join(s) }.include?(as_alias) }.map{ |a| a[:deprecated] }.first if as_alias
20
21
  end
21
22
 
@@ -220,15 +221,17 @@ module RHC
220
221
 
221
222
  c.when_called do |args, options|
222
223
  deprecated!
223
-
224
+
224
225
  config = c.instance_variable_get(:@config)
225
-
226
+
226
227
  cmd = opts[:class].new
227
228
  cmd.options = options
228
229
  cmd.config = config
229
-
230
+
230
231
  args = fill_arguments(cmd, options, args_metadata, options_metadata, args)
231
232
  needs_configuration!(cmd, options, config)
233
+
234
+ return execute(cmd, :help, args) unless opts[:method]
232
235
  execute(cmd, opts[:method], args)
233
236
  end
234
237
  end
@@ -109,6 +109,7 @@ module RHC::Commands
109
109
  syntax "<application>"
110
110
  argument :app, "Application name (required)", ["-a", "--app name"], :context => :app_context, :required => true
111
111
  option ["-n", "--namespace NAME"], "Namespace of your application", :context => :namespace_context, :required => true
112
+ alias_action "aliases", :root_command => true
112
113
  def list(app)
113
114
  rest_app = rest_client.find_application(options.namespace, app)
114
115
  items = rest_app.aliases.map do |a|
@@ -75,6 +75,7 @@ module RHC::Commands
75
75
 
76
76
  rest_domain = check_domain!
77
77
  rest_app = nil
78
+ repo_dir = nil
78
79
 
79
80
  cart_names = cartridges.collect do |c|
80
81
  c.usage_rate? ? "#{c.short_name} (addtl. costs may apply)" : c.short_name
@@ -91,15 +92,14 @@ module RHC::Commands
91
92
  ).each { |s| say " #{s}" }
92
93
  end
93
94
 
94
- messages = []
95
-
96
95
  paragraph do
97
96
  say "Creating application '#{name}' ... "
98
97
 
99
98
  # create the main app
100
99
  rest_app = create_app(name, cartridges, rest_domain, options.gear_size, options.scaling, options.from_code)
101
- messages.concat(rest_app.messages)
102
100
  success "done"
101
+
102
+ paragraph{ indent{ success rest_app.messages.map(&:strip) } }
103
103
  end
104
104
 
105
105
  build_app_exists = rest_app.building_app
@@ -113,7 +113,7 @@ module RHC::Commands
113
113
  build_app_exists = add_jenkins_app(rest_domain)
114
114
 
115
115
  success "done"
116
- messages.concat(build_app_exists.messages)
116
+ paragraph{ indent{ success build_app_exists.messages.map(&:strip) } }
117
117
 
118
118
  rescue Exception => e
119
119
  warn "not complete"
@@ -126,7 +126,9 @@ module RHC::Commands
126
126
  end
127
127
 
128
128
  paragraph do
129
+ messages = []
129
130
  add_jenkins_client_to(rest_app, messages)
131
+ paragraph{ indent{ success messages.map(&:strip) } }
130
132
  end if build_app_exists
131
133
  end
132
134
 
@@ -150,31 +152,37 @@ module RHC::Commands
150
152
  end
151
153
 
152
154
  if options.git
153
- paragraph do
154
- say "Downloading the application Git repository ..."
155
- paragraph do
156
- begin
157
- git_clone_application(rest_app)
158
- rescue RHC::GitException => e
159
- warn "#{e}"
160
- unless RHC::Helpers.windows? and windows_nslookup_bug?(rest_app)
161
- add_issue("We were unable to clone your application's git repo - #{e}",
162
- "Clone your git repo",
163
- "rhc git-clone #{rest_app.name}")
164
- end
155
+ section(:now => true, :top => 1, :bottom => 1) do
156
+ begin
157
+ repo_dir = git_clone_application(rest_app)
158
+ rescue RHC::GitException => e
159
+ warn "#{e}"
160
+ unless RHC::Helpers.windows? and windows_nslookup_bug?(rest_app)
161
+ add_issue("We were unable to clone your application's git repo - #{e}",
162
+ "Clone your git repo",
163
+ "rhc git-clone #{rest_app.name}")
165
164
  end
166
165
  end
167
166
  end
168
167
  end
169
168
  end
170
169
 
171
- display_app(rest_app, rest_app.cartridges)
172
-
173
- if issues?
174
- output_issues(rest_app)
175
- else
176
- results{ messages.each { |msg| success msg } }.blank? and "Application created"
170
+ output_issues(rest_app) if issues?
171
+
172
+ paragraph do
173
+ say "Your application '#{rest_app.name}' is now available."
174
+ paragraph do
175
+ indent do
176
+ say table [
177
+ ['URL:', rest_app.app_url],
178
+ ['SSH to:', rest_app.ssh_string],
179
+ ['Git remote:', rest_app.git_url],
180
+ (['Cloned to:', repo_dir] if repo_dir)
181
+ ].compact
182
+ end
183
+ end
177
184
  end
185
+ paragraph{ say "Run 'rhc show-app #{name}' for more details about your app." }
178
186
 
179
187
  0
180
188
  end
@@ -198,6 +206,8 @@ module RHC::Commands
198
206
  rest_app.destroy
199
207
  success "deleted"
200
208
 
209
+ paragraph{ rest_app.messages.each{ |s| success s } }
210
+
201
211
  0
202
212
  end
203
213
 
@@ -268,17 +278,52 @@ module RHC::Commands
268
278
  end
269
279
 
270
280
  summary "Show information about an application"
281
+ description <<-DESC
282
+ Display the properties of an application, including its URL, the SSH
283
+ connection string, and the Git remote URL. Will also display any
284
+ cartridges, their scale, and any values they expose.
285
+
286
+ The '--state' option will retrieve information from each cartridge in
287
+ the application, which may include cartridge specific text.
288
+
289
+ To see information about the individual gears within an application,
290
+ use '--gears', including whether they are started or stopped and their
291
+ SSH host strings. Passing '--gears quota' will show the free and maximum
292
+ storage on each gear.
293
+
294
+ If you want to run commands against individual gears, use:
295
+
296
+ rhc ssh <app> --gears '<command>'
297
+
298
+ to run and display the output from each gear.
299
+ DESC
271
300
  syntax "<app> [--namespace NAME]"
272
301
  argument :app, "The name of the application you are getting information on", ["-a", "--app NAME"], :context => :app_context
273
302
  option ["-n", "--namespace NAME"], "Namespace of the application the cartridge belongs to", :context => :namespace_context, :required => true
274
303
  option ["--state"], "Get the current state of the cartridges in this application"
275
- option ["--gears"], "Show the ID, state, and cartridges on each gear in this application"
304
+ option ["--gears [quota|ssh]"], "Show information about the cartridges on each gear in this application. Pass 'quota' to see per gear disk usage and limits. Pass 'ssh' to print only the SSH connection strings of each gear."
276
305
  def show(app_name)
277
306
 
278
307
  if options.state
279
308
  gear_groups_for_app(app_name).each do |gg|
280
309
  say "Cartridge #{gg.cartridges.collect { |c| c['name'] }.join(', ')} is #{gear_group_state(gg.gears.map{ |g| g['state'] })}"
281
310
  end
311
+
312
+ elsif options.gears && options.gears != true
313
+ groups = rest_client.find_application_gear_groups(options.namespace, app_name)
314
+
315
+ case options.gears
316
+ when 'quota'
317
+ opts = {:as => :gear, :split_cells_on => /\s*\t/, :header => ['Gear', 'Cartridges', 'Used', 'Limit'], :align => [nil, nil, :right, :right]}
318
+ table_from_gears('echo "$(du -s 2>/dev/null | cut -f 1)"', groups, opts) do |gear, data, group|
319
+ [gear['id'], group.cartridges.collect{ |c| c['name'] }.join(' '), (human_size(data.chomp) rescue 'error'), human_size(group.quota)]
320
+ end
321
+ when 'ssh'
322
+ groups.each{ |group| group.gears.each{ |g| say (ssh_string(g['ssh_url']) or raise NoPerGearOperations) } }
323
+ else
324
+ run_on_gears(ssh_command_for_op(options.gears), groups)
325
+ end
326
+
282
327
  elsif options.gears
283
328
  gear_info = gear_groups_for_app(app_name).map do |group|
284
329
  group.gears.map do |gear|
@@ -301,28 +346,6 @@ module RHC::Commands
301
346
  0
302
347
  end
303
348
 
304
- summary "SSH into the specified application"
305
- syntax "<app> [--ssh path_to_ssh_executable]"
306
- argument :app, "The name of the application you want to SSH into", ["-a", "--app NAME"], :context => :app_context
307
- option ["--ssh PATH"], "Path to your SSH executable"
308
- option ["-n", "--namespace NAME"], "Namespace of the application the cartridge belongs to", :context => :namespace_context, :required => true
309
- alias_action 'ssh', :root_command => true
310
- def ssh(app_name)
311
- raise ArgumentError, "No application specified" unless app_name.present?
312
- raise OptionParser::InvalidOption, "No system SSH available. Please use the --ssh option to specify the path to your SSH executable, or install SSH." unless options.ssh or has_ssh?
313
-
314
- rest_app = rest_client.find_application(options.namespace, app_name)
315
-
316
- say "Connecting to #{rest_app.ssh_string.to_s} ..."
317
- if options.ssh
318
- debug "Using user specified SSH: #{options.ssh}"
319
- Kernel.send(:system, "#{options.ssh} #{rest_app.ssh_string.to_s}")
320
- else
321
- debug "Using system ssh"
322
- Kernel.send(:system, "ssh #{rest_app.ssh_string.to_s}")
323
- end
324
- end
325
-
326
349
  summary "DEPRECATED use 'show <app> --state' instead"
327
350
  syntax "<app> [--namespace NAME] [--app NAME]"
328
351
  argument :app, "The name of the application you are getting information on", ["-a", "--app NAME"], :context => :app_context
@@ -337,6 +360,7 @@ module RHC::Commands
337
360
  private
338
361
  include RHC::GitHelpers
339
362
  include RHC::CartridgeHelpers
363
+ include RHC::SSHHelpers
340
364
 
341
365
  def require_one_web_cart
342
366
  lambda{ |carts|
@@ -349,7 +373,7 @@ module RHC::Commands
349
373
  end
350
374
  if selected_web
351
375
  carts.map! &other_carts_only
352
- elsif possible_web
376
+ elsif possible_web && ambiguous.length == 1
353
377
  carts.map! &web_carts_only
354
378
  end
355
379
  }
@@ -518,22 +542,6 @@ module RHC::Commands
518
542
  # :nocov:
519
543
  end
520
544
 
521
- # check the version of SSH that is installed
522
- def ssh_version
523
- @ssh_version ||= `ssh -V 2>&1`.strip
524
- end
525
-
526
- # return whether or not SSH is installed
527
- def has_ssh?
528
- @has_ssh ||= begin
529
- @ssh_version = nil
530
- ssh_version
531
- $?.success?
532
- rescue
533
- false
534
- end
535
- end
536
-
537
545
  def windows_nslookup_bug?(rest_app)
538
546
  windows_nslookup = run_nslookup(rest_app.host)
539
547
  windows_ping = run_ping(rest_app.host)
@@ -573,20 +581,49 @@ WARNING: Your application was created successfully but had problems during
573
581
  #{reasons}
574
582
  Steps to complete your configuration:
575
583
  #{steps}
576
- If you can't get your application '#{rest_app.name}' running in the browser,
584
+ If you continue to experience problems after completing these steps,
577
585
  you can try destroying and recreating the application:
578
586
 
579
587
  $ rhc app delete #{rest_app.name} --confirm
580
588
 
581
- If this doesn't work for you, let us know in the forums or in IRC and we'll
582
- make sure to get you up and running.
589
+ Please contact us if you are unable to successfully create your
590
+ application:
583
591
 
584
- Forums - https://www.openshift.com/forums/openshift
585
- IRC - #openshift (on Freenode)
592
+ Support - https://www.openshift.com/support
586
593
 
587
594
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
588
595
 
589
596
  WARNING_OUTPUT
590
597
  end
598
+
599
+ # Issues collector collects a set of recoverable issues and steps to fix them
600
+ # for output at the end of a complex command
601
+ def add_issue(reason, commands_header, *commands)
602
+ @issues ||= []
603
+ issue = {:reason => reason,
604
+ :commands_header => commands_header,
605
+ :commands => commands}
606
+ @issues << issue
607
+ end
608
+
609
+ def format_issues(indent)
610
+ return nil unless issues?
611
+
612
+ indentation = " " * indent
613
+ reasons = ""
614
+ steps = ""
615
+
616
+ @issues.each_with_index do |issue, i|
617
+ reasons << "#{indentation}#{i+1}. #{issue[:reason].strip}\n"
618
+ steps << "#{indentation}#{i+1}. #{issue[:commands_header].strip}\n"
619
+ issue[:commands].each { |cmd| steps << "#{indentation} $ #{cmd}\n" }
620
+ end
621
+
622
+ [reasons, steps]
623
+ end
624
+
625
+ def issues?
626
+ not @issues.nil?
627
+ end
591
628
  end
592
629
  end