rhc 1.0.4 → 1.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -526,8 +526,13 @@ class CheckRunner < Test::Unit::UI::Console::TestRunner
526
526
  end
527
527
  end
528
528
 
529
- Test::Unit::AutoRunner::RUNNERS[:console] = proc do |r|
530
- CheckRunner
529
+ # Need to register the default runner differently using the standard test-unit and the gem
530
+ proc{|*r| CheckRunner}.tap do |_proc|
531
+ if Test::Unit::AutoRunner.respond_to?(:register_runner)
532
+ Test::Unit::AutoRunner.register_runner(:console, _proc)
533
+ else
534
+ Test::Unit::AutoRunner::RUNNERS[:console] = _proc
535
+ end
531
536
  end
532
537
 
533
538
  ############################
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- # print deprecation warning
3
- RHC::Helpers.deprecated_command('rhc-domain-info',true)
4
2
 
5
3
  args = ""
6
4
  ARGV.each do|a|
@@ -22,3 +22,13 @@ Feature: Single Cartridge Tests
22
22
  | running | restarted | running |
23
23
  | running | stopped | stopped |
24
24
  | stopped | started | running |
25
+
26
+ Scenario Outline: Cartridge List
27
+ When we list cartridges
28
+ Then the list should contain the cartridge <cart> with display name "<name>"
29
+
30
+ Examples:
31
+ | cart | name |
32
+ | php-5.3 | PHP 5.3 |
33
+ | mongodb-2.2 | MongoDB NoSQL |
34
+ | cron-1.4 | Cron 1.4 |
@@ -7,6 +7,7 @@ module RHCHelper
7
7
  #
8
8
  class Cartridge
9
9
  extend Runnable
10
+ extend Commandify
10
11
  extend Persistable
11
12
  include Loggable
12
13
  include Runnable
@@ -19,19 +20,25 @@ module RHCHelper
19
20
  # Create the data structure for a test cartridge
20
21
  def initialize(app, name)
21
22
  @name = name
22
- @app_name = app.name
23
+ @app_name = app.name unless app.nil?
23
24
  @hostname = "#{@app_name}-#{$namespace}.#{$domain}"
24
25
  @file = "#{TEMP_DIR}/#{$namespace}.json"
25
26
  end
26
27
 
27
28
  def rhc_cartridge(cmd)
28
- full_cmd = "rhc cartridge #{cmd} -l #{$username} -p #{$password} -a #{@app_name}"
29
+ full_cmd = "rhc cartridge #{cmd} -l #{$username} -p #{$password} #{@app_name ? "-a #{@app_name}" : ""}"
29
30
  full_cmd += " #{@name}" if cmd != "list"
30
31
  run(full_cmd, nil) do |exitstatus, out, err, arg|
31
32
  yield exitstatus, out, err, arg if block_given?
32
33
  end
33
34
  end
34
35
 
36
+ def self.list
37
+ rhc_cartridge_list do |exitstatus, out, err, arg|
38
+ return [exitstatus, out, err, arg]
39
+ end
40
+ end
41
+
35
42
  def add
36
43
  rhc_cartridge('add') do |exitstatus, out, err, arg|
37
44
  yield exitstatus, out, err, arg if block_given?
@@ -11,7 +11,7 @@ module RHCHelper
11
11
  cmd = get_cmd(sym)
12
12
 
13
13
  # Get any blocks that should be run after processing
14
- cmd_callback = get_cmd_callback(cmd, args[0])
14
+ cmd_callback = get_cmd_callback(cmd, args[0]) || block
15
15
 
16
16
  # Add arguments to the command
17
17
  cmd << get_args(cmd, args[0])
@@ -85,8 +85,7 @@ module RHCHelper
85
85
  raise "No alias set" unless @alias
86
86
  args << "--alias #{@alias} "
87
87
  when /cartridge/
88
- raise "No cartridge supplied" unless arg0
89
- args << "-c #{arg0}"
88
+ args << "-c #{arg0}" if arg0
90
89
  when /sshkey/
91
90
  # in RHCHelper::Sshkey, we pass *args to method_missing here, so that
92
91
  # we _know_ that arg0 is an Array.
@@ -47,6 +47,10 @@ When /^the (\w+) scaling value is set to (.*)$/ do |minmax,value|
47
47
  @exitcode = @app.cartridge(@cartridge_name).send(:scale,"--#{minmax} #{value}")
48
48
  end
49
49
 
50
+ When /^we list cartridges$/ do
51
+ @exitcode, @cartridge_output = Cartridge.list
52
+ end
53
+
50
54
  Then /^the (\w+) scaling value should be (.*)$/ do |minmax,value|
51
55
  expected = {
52
56
  :min => "Minimum",
@@ -64,3 +68,9 @@ end
64
68
  Then /^it should fail with code (\d+)$/ do |code|
65
69
  @exitcode.should == code.to_i
66
70
  end
71
+
72
+ Then /^the list should contain the cartridge ([^\s]+) with display name "([^"]+)"$/ do |name, display_name|
73
+ line = @cartridge_output.each_line.find{ |s| s.include?(name) }
74
+ line.should_not be_nil
75
+ line.should match(display_name)
76
+ end
@@ -471,9 +471,7 @@ end
471
471
  # Check if host exists
472
472
  #
473
473
  def self.hostexist?(host)
474
- dns = Resolv::DNS.new
475
- resp = dns.getresources(host, Resolv::DNS::Resource::IN::A)
476
- return resp.any?
474
+ RHC::Helpers.host_exists?(host)
477
475
  end
478
476
 
479
477
  def self.create_app(libra_server, net_http, user_info, app_name, app_type, rhlogin, password, repo_dir=nil, no_dns=false, no_git=false, is_embedded_jenkins=false, gear_size='small',scale=false)
@@ -1,5 +1,6 @@
1
1
  module RHC
2
2
  module CartridgeHelpers
3
+
3
4
  def find_cartridge(rest_obj, cartridge_name, type="embedded")
4
5
  carts = rest_obj.find_cartridges :regex => cart_regex(cartridge_name), :type => type
5
6
 
@@ -35,10 +35,6 @@ module RHC
35
35
  return
36
36
  end
37
37
  global_option('-v', '--version', 'Display version information') { say version; return }
38
- global_option('--timeout seconds', Integer, 'Set the timeout in seconds for network commands') do |value|
39
- # FIXME: Refactor so we don't have to use a global var here
40
- $rest_timeout = value
41
- end
42
38
 
43
39
  # remove these because we monkey patch Commands to process all options
44
40
  # at once, avoiding conflicts between the global and command options
@@ -71,9 +67,9 @@ module RHC
71
67
  OptionParser::MissingArgument => e
72
68
 
73
69
  help_bindings = CommandHelpBindings.new(active_command, commands, Commander::Runner.instance.options)
74
- usage = RHC::HelpFormatter.new(self).render_command(help_bindings)
70
+ usage = RHC::HelpFormatter.new(self).render_command_syntax(help_bindings)
75
71
  RHC::Helpers.error e.message
76
- say "\n#{usage}"
72
+ say "#{usage}"
77
73
  1
78
74
  rescue RHC::Exception, RHC::Rest::Exception => e
79
75
  RHC::Helpers.error e.message
@@ -100,18 +96,16 @@ module RHC
100
96
  c.syntax = 'rhc help <command>'
101
97
  c.description = 'Display global or <command> help documentation.'
102
98
  c.when_called do |args, options|
99
+ cmd = (1..args.length).reverse_each.map{ |n| args[0,n].join(' ') }.find{ |cmd| command_exists?(cmd) }
100
+
103
101
  if args.empty?
104
102
  say help_formatter.render
103
+ elsif cmd.nil?
104
+ RHC::Helpers.error "The command '#{program :name} #{provided_arguments.join(' ')}' is not recognized.\n"
105
+ say "See '#{program :name} help' for a list of valid commands."
106
+ next
105
107
  else
106
- command = command args.join(' ')
107
- begin
108
- require_valid_command command
109
- rescue InvalidCommandError => e
110
- RHC::Helpers.error "The command '#{program :name} #{provided_arguments.join(' ')}' is not recognized.\n"
111
- say "See '#{program :name} help' for a list of valid commands."
112
- next
113
- end
114
-
108
+ command = command(cmd)
115
109
  help_bindings = CommandHelpBindings.new command, commands, Commander::Runner.instance.options
116
110
  say help_formatter.render_command help_bindings
117
111
  end
@@ -66,7 +66,10 @@ module RHC
66
66
  options.help or
67
67
  config.has_local_config? or
68
68
  config.has_opts_config?)
69
- RHC::Wizard.new(config).run
69
+
70
+ RHC::Helpers.warn(
71
+ "You have not yet configured the OpenShift client tools. Please run 'rhc setup'.",
72
+ :stderr => true)
70
73
  end
71
74
  end
72
75
 
@@ -1,7 +1,7 @@
1
1
  require 'rhc/commands/base'
2
2
  require 'resolv'
3
3
  require 'rhc/git_helper'
4
- require 'rhc/cartridge_helper'
4
+ require 'rhc/cartridge_helpers'
5
5
 
6
6
  module RHC::Commands
7
7
  class App < Base
@@ -11,24 +11,26 @@ module RHC::Commands
11
11
  default_action :help
12
12
 
13
13
  summary "Create an application and adds it to a domain"
14
- syntax "<name> <cartridge> [... <other cartridges>][--namespace namespace]"
15
- option ["-n", "--namespace namespace"], "Namespace to add your application to", :context => :namespace_context, :required => true
16
- option ["-g", "--gear-size size"], "The size of the gear for this app. Available gear sizes depend on the type of account you have."
17
- option ["-s", "--scaling"], "Enable scaling for this application"
18
- option ["-r", "--repo dir"], "Git Repo path (defaults to ./$app_name) (applicable to the create command)"
19
- option ["--[no-]git"], "Only create remote space, don't pull it locally"
20
- option ["--nogit"], "DEPRECATED! Only create remote space, don't pull it locally", :deprecated => {:key => :git, :value => false}
21
- option ["--[no-]dns"], "Skip DNS check. Must be used in combination with --no-git"
22
- option ["--enable-jenkins [server_name]"], "Indicates to create a Jenkins application (if not already available) and embed the Jenkins client into this application. The default name will be 'jenkins' if not specified. Note that --no-dns is ignored for the creation of the Jenkins application."
23
- argument :name, "The name you wish to give your application", ["-a", "--app name"]
24
- argument :cartridge, "The first cartridge added to the application. Usually a web framework", ["-t", "--type cartridge"]
25
- argument :additional_cartridges, "A list of other cartridges such as databases you wish to add. Cartridges can also be added later using 'rhc cartridge add'", [], :arg_type => :list
26
- def create(name, cartridge, additional_cartridges)
14
+ description "Create an application in your domain. You can see a list of all valid cartridge types by running 'rhc cartridge list'."
15
+ syntax "<name> <cartridge> [-n namespace]"
16
+ option ["-n", "--namespace namespace"], "Namespace for the application", :context => :namespace_context, :required => true
17
+ option ["-g", "--gear-size size"], "Gear size controls how much memory and CPU your cartridges can use."
18
+ option ["-s", "--scaling"], "Enable scaling for the web cartridge."
19
+ option ["-r", "--repo dir"], "Path to the Git repository (defaults to ./$app_name)"
20
+ option ["--[no-]git"], "Skip creating the local Git repository."
21
+ option ["--nogit"], "DEPRECATED: Skip creating the local Git repository.", :deprecated => {:key => :git, :value => false}
22
+ option ["--[no-]dns"], "Skip waiting for the application DNS name to resolve. Must be used in combination with --no-git"
23
+ option ["--enable-jenkins [server_name]"], "Enable Jenkins builds for this application (will create a Jenkins application if not already available). The default name will be 'jenkins' if not specified."
24
+ argument :name, "Name for your application", ["-a", "--app name"]
25
+ argument :cartridges, "The web framework this application should use", ["-t", "--type cartridge"], :arg_type => :list
26
+ #argument :additional_cartridges, "A list of other cartridges such as databases you wish to add. Cartridges can also be added later using 'rhc cartridge add'", [], :arg_type => :list
27
+ def create(name, cartridges)
28
+ cartridge = check_cartridges(cartridges).first
29
+
27
30
  options.default \
28
31
  :dns => true,
29
32
  :git => true
30
33
 
31
- warnings = []
32
34
  header "Creating application '#{name}'"
33
35
  paragraph do
34
36
  table({"Namespace:" => options.namespace,
@@ -72,7 +74,7 @@ module RHC::Commands
72
74
  # error downloading Jenkins /jnlpJars/jenkins-cli.jar
73
75
  attempts += 1
74
76
  debug "Jenkins server could not be contacted, sleep and then retry: attempt #{attempts}\n #{e.message}"
75
- sleep(10)
77
+ Kernel.sleep(10)
76
78
  end
77
79
  exit_code = e.code
78
80
  exit_message = e.message
@@ -269,6 +271,42 @@ module RHC::Commands
269
271
  include RHC::GitHelpers
270
272
  include RHC::CartridgeHelpers
271
273
 
274
+ def standalone_cartridges
275
+ @standalone_cartridges ||= rest_client.cartridges.select{ |c| c.type == 'standalone' }
276
+ end
277
+
278
+ def check_cartridges(cartridge_names)
279
+ cartridge_names = Array(cartridge_names).map{ |s| s.strip if s && s.length > 0 }.compact
280
+
281
+ unless cartridge_name = cartridge_names.first
282
+ section(:bottom => 1){ list_cartridges }
283
+ raise ArgumentError.new "Every application needs a web cartridge to handle incoming web requests. Please provide the short name of one of the carts listed above."
284
+ end
285
+
286
+ unless standalone_cartridges.find{ |c| c.name == cartridge_name }
287
+ matching_cartridges = standalone_cartridges.select{ |c| c.name.include?(cartridge_name) }
288
+ if matching_cartridges.length == 1
289
+ cartridge_names[0] = use_cart(matching_cartridges.first, cartridge_name)
290
+ elsif matching_cartridges.present?
291
+ paragraph { list_cartridges(matching_cartridges) }
292
+ raise RHC::MultipleCartridgesException.new("There are multiple web cartridges named '#{cartridge_name}'. Please provide the short name of your desired cart.")
293
+ end
294
+ end
295
+ cartridge_names.first(1)
296
+ end
297
+
298
+ def use_cart(cart, for_cartridge_name)
299
+ info "Using #{cart.name}#{cart.display_name ? " (#{cart.display_name})" : ''} instead of '#{for_cartridge_name}'"
300
+ cart.name
301
+ end
302
+
303
+ def list_cartridges(cartridges=standalone_cartridges)
304
+ carts = cartridges.map{ |c| [c.name, c.display_name || ''] }.sort{ |a,b| a[1].downcase <=> b[1].downcase }
305
+ carts.unshift ['==========', '=========']
306
+ carts.unshift ['Short Name', 'Full name']
307
+ say table(carts).join("\n")
308
+ end
309
+
272
310
  def app_action(app, action, *args)
273
311
  rest_domain = rest_client.find_domain(options.namespace)
274
312
  rest_app = rest_domain.find_application(app)
@@ -282,16 +320,17 @@ module RHC::Commands
282
320
  app_options[:scale] = scale if scale
283
321
  app_options[:debug] = true if @debug
284
322
 
285
- debug "Creating application '#{name}' with these options - #{app_options}.inspect"
286
-
287
- rest_cartridge = find_cartridge rest_client, cartridge, "standalone"
288
- app_options[:cartridge] = rest_cartridge.name
289
-
323
+ debug "Creating application '#{name}' with these options - #{app_options.inspect}"
290
324
  rest_app = rest_domain.add_application name, app_options
291
-
292
325
  debug "'#{rest_app.name}' created"
293
326
 
294
327
  rest_app
328
+ rescue RHC::Rest::Exception => e
329
+ if e.code == 109
330
+ paragraph{ say "Valid cartridge types:" }
331
+ paragraph{ list_cartridges }
332
+ end
333
+ raise
295
334
  end
296
335
 
297
336
  def dns_propagated?(host, sleep_time=2)
@@ -307,7 +346,7 @@ module RHC::Commands
307
346
 
308
347
  # Now start checking for DNS
309
348
  for i in 0..MAX_RETRIES-1
310
- found = host_exist?(host)
349
+ found = host_exists?(host)
311
350
  break if found
312
351
 
313
352
  say " retry # #{i+1} - Waiting for DNS: #{host}"
@@ -320,13 +359,6 @@ module RHC::Commands
320
359
  found
321
360
  end
322
361
 
323
- def host_exist?(host)
324
- # :nocov:
325
- dns = Resolv::DNS.new
326
- dns.getresources(host, Resolv::DNS::Resource::IN::A).any?
327
- # :nocov:
328
- end
329
-
330
362
  def check_sshkeys!
331
363
  wizard = RHC::SSHWizard.new(rest_client)
332
364
  wizard.run
@@ -59,7 +59,7 @@ class RHC::Commands::Base
59
59
  end
60
60
  end
61
61
 
62
- raise ArgumentError.new("Too many arguments passed in.") unless fill_args.empty?
62
+ raise ArgumentError.new("Too many arguments passed in: #{fill_args.reverse.join(" ")}") unless fill_args.empty?
63
63
 
64
64
  arg_slots
65
65
  end
@@ -1,5 +1,5 @@
1
1
  require 'rhc/commands/base'
2
- require 'rhc/cartridge_helper'
2
+ require 'rhc/cartridge_helpers'
3
3
 
4
4
  module RHC::Commands
5
5
  class Cartridge < Base
@@ -11,8 +11,25 @@ module RHC::Commands
11
11
  summary "List supported embedded cartridges"
12
12
  alias_action :"app cartridge list", :root_command => true, :deprecated => true
13
13
  def list
14
- carts = rest_client.find_cartridges(:type => 'embedded').collect { |c| c.name }
15
- results { say "#{carts.join(', ')}" }
14
+ rest_client = RHC::Rest::Client.new(openshift_rest_node, nil, nil)
15
+ list = rest_client.cartridges.
16
+ map{ |c| [c.name, c.display_name || '', c.type == 'standalone' ? 'Y' : ''] }.
17
+ sort do |a,b|
18
+ if a[2] == 'Y' && b[2] == ''
19
+ -1
20
+ elsif a[2] == '' && b[2] == 'Y'
21
+ 1
22
+ else
23
+ a[1].downcase <=> b[1].downcase
24
+ end
25
+ end
26
+ list.unshift ['==========', '=========', '=============']
27
+ list.unshift ['Short Name', 'Full name', 'New apps only']
28
+
29
+ paragraph{ say "Use the short name of a cartridge when interacting with your applications." }
30
+
31
+ say table(list).join("\n")
32
+
16
33
  0
17
34
  end
18
35
 
@@ -176,14 +193,14 @@ module RHC::Commands
176
193
  end
177
194
 
178
195
  private
179
- include RHC::CartridgeHelpers
180
-
181
- def cartridge_action(cartridge, action)
182
- rest_domain = rest_client.find_domain(options.namespace)
183
- rest_app = rest_domain.find_application(options.app)
184
- rest_cartridge = find_cartridge rest_app, cartridge
185
- result = rest_cartridge.send action
186
- [result, rest_cartridge, rest_app, rest_domain]
187
- end
196
+ include RHC::CartridgeHelpers
197
+
198
+ def cartridge_action(cartridge, action)
199
+ rest_domain = rest_client.find_domain(options.namespace)
200
+ rest_app = rest_domain.find_application(options.app)
201
+ rest_cartridge = find_cartridge rest_app, cartridge
202
+ result = rest_cartridge.send action
203
+ [result, rest_cartridge, rest_app, rest_domain]
204
+ end
188
205
  end
189
206
  end
@@ -13,11 +13,12 @@ module RHC::Commands
13
13
  summary 'Display all the SSH keys for the user account'
14
14
  syntax ''
15
15
  def list
16
+ keys = rest_client.sshkeys
17
+
16
18
  results do
17
- result = rest_client.sshkeys.inject('') do |r, key|
19
+ result = keys.inject('') do |r, key|
18
20
  r += format(key, erb)
19
21
  end
20
-
21
22
  say result
22
23
  end
23
24
 
@@ -5,6 +5,9 @@ module RHC
5
5
  def template(name)
6
6
  ERB.new(File.read(File.join(File.dirname(__FILE__), 'usage_templates', "#{name}.erb")), nil, '-')
7
7
  end
8
+ def render_command_syntax command
9
+ template(:command_syntax_help).result command.get_binding
10
+ end
8
11
  end
9
12
  # TODO: class ManPageHelpFormatter
10
13
  end
@@ -4,6 +4,8 @@ require 'rhc/config'
4
4
  require 'rhc/commands'
5
5
  require 'rhc/output_helpers'
6
6
 
7
+ require 'resolv'
8
+
7
9
  OptionParser.accept(URI) {|s,| URI.parse(s) if s}
8
10
 
9
11
  module RHC
@@ -80,6 +82,10 @@ module RHC
80
82
  global_option '-p', '--password password', "OpenShift password"
81
83
  global_option '-d', '--debug', "Turn on debugging"
82
84
 
85
+ global_option('--timeout seconds', Integer, 'Set the timeout in seconds for network commands') do |value|
86
+ # FIXME: Refactor so we don't have to use a global var here
87
+ $rest_timeout = value
88
+ end
83
89
  global_option '--noprompt', "Suppress the interactive setup wizard from running before a command"
84
90
  global_option '--config FILE', "Path of a different config file"
85
91
  def config
@@ -113,6 +119,8 @@ module RHC
113
119
  end
114
120
 
115
121
  def deprecated(msg,short = false)
122
+ HighLine::use_color = false if windows? # handle deprecated commands that does not start through highline
123
+
116
124
  info = " For porting and testing purposes you may switch this %s to %s by setting the DISABLE_DEPRECATED environment variable to %d. It is not recommended to do so in a production environment as this option may be removed in future releases."
117
125
 
118
126
  msg << info unless short
@@ -123,18 +131,29 @@ module RHC
123
131
  end
124
132
  end
125
133
 
126
- def say(msg)
127
- super
134
+ def say(msg, *args)
135
+ if Hash[*args][:stderr]
136
+ $stderr.puts msg
137
+ else
138
+ super(msg)
139
+ end
128
140
  msg
129
141
  end
142
+
130
143
  def success(msg, *args)
131
- say color(msg, :green)
144
+ say color(msg, :green), *args
132
145
  end
146
+
147
+ def info(msg, *args)
148
+ say color(msg, :cyan), *args
149
+ end
150
+
133
151
  def warn(msg, *args)
134
- say color(msg, :yellow)
152
+ say color(msg, :yellow), *args
135
153
  end
154
+
136
155
  def error(msg, *args)
137
- say color(msg, :red)
156
+ say color(msg, :red), *args
138
157
  end
139
158
 
140
159
  def color(s, color)
@@ -306,5 +325,15 @@ Fingerprint: <%= key.fingerprint %>
306
325
  FORMAT
307
326
  end
308
327
 
328
+ #
329
+ # Check if host exists
330
+ #
331
+ def host_exists?(host)
332
+ # :nocov:
333
+ # Patch for BZ840938 to support Ruby 1.8 on machines without /etc/resolv.conf
334
+ dns = Resolv::DNS.new((Resolv::DNS::Config.default_config_hash || {}))
335
+ dns.getresources(host, Resolv::DNS::Resource::IN::A).any?
336
+ # :nocov:
337
+ end
309
338
  end
310
339
  end