rhc 0.96.9 → 0.97.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/README.md +1 -0
  2. data/bin/rhc +6 -18
  3. data/bin/rhc-app +3 -3
  4. data/bin/rhc-chk +2 -2
  5. data/bin/rhc-create-app +2 -2
  6. data/bin/rhc-create-domain +5 -2
  7. data/bin/rhc-ctl-app +2 -2
  8. data/bin/rhc-ctl-domain +5 -2
  9. data/bin/rhc-domain +6 -3
  10. data/bin/rhc-domain-info +6 -3
  11. data/bin/rhc-port-forward +9 -2
  12. data/bin/rhc-snapshot +2 -2
  13. data/bin/rhc-sshkey +2 -2
  14. data/bin/rhc-tail-files +2 -2
  15. data/features/lib/rhc_helper/app.rb +1 -1
  16. data/features/lib/rhc_helper/commandify.rb +32 -3
  17. data/features/lib/rhc_helper/domain.rb +46 -20
  18. data/features/step_definitions/cartridge_steps.rb +3 -3
  19. data/features/step_definitions/client_steps.rb +3 -1
  20. data/features/step_definitions/domain_steps.rb +45 -0
  21. data/features/verify.feature +36 -0
  22. data/lib/rhc-common.rb +6 -8
  23. data/lib/rhc-rest.rb +11 -2
  24. data/lib/rhc-rest/application.rb +20 -8
  25. data/lib/rhc-rest/cartridge.rb +18 -6
  26. data/lib/rhc-rest/client.rb +13 -37
  27. data/lib/rhc-rest/domain.rb +12 -4
  28. data/lib/rhc-rest/exceptions/exceptions.rb +1 -1
  29. data/lib/rhc-rest/key.rb +2 -2
  30. data/lib/rhc-rest/user.rb +2 -2
  31. data/lib/rhc/cli.rb +2 -3
  32. data/lib/rhc/commands.rb +154 -4
  33. data/lib/rhc/commands/base.rb +49 -12
  34. data/lib/rhc/commands/domain.rb +142 -0
  35. data/lib/rhc/commands/server.rb +1 -0
  36. data/lib/rhc/commands/setup.rb +3 -10
  37. data/lib/rhc/config.rb +20 -18
  38. data/lib/rhc/exceptions.rb +20 -0
  39. data/lib/rhc/help_formatter.rb +3 -22
  40. data/lib/rhc/helpers.rb +36 -5
  41. data/lib/rhc/json.rb +44 -44
  42. data/lib/rhc/targz.rb +3 -3
  43. data/lib/rhc/usage_templates/command_help.erb +26 -0
  44. data/lib/rhc/usage_templates/help.erb +27 -0
  45. data/lib/rhc/vendor/zliby.rb +563 -563
  46. data/lib/rhc/version.rb +2 -2
  47. data/lib/rhc/wizard.rb +10 -5
  48. data/spec/coverage_helper.rb +0 -1
  49. data/spec/rest_spec_helper.rb +95 -0
  50. data/spec/rhc/cli_spec.rb +7 -2
  51. data/spec/rhc/command_spec.rb +59 -13
  52. data/spec/rhc/commands/domain_spec.rb +225 -0
  53. data/spec/rhc/config_spec.rb +4 -4
  54. data/spec/rhc/helpers_spec.rb +27 -1
  55. data/spec/rhc/rest_application_spec.rb +6 -0
  56. data/spec/rhc/rest_client_spec.rb +32 -32
  57. data/spec/rhc/rest_spec.rb +2 -2
  58. data/spec/rhc/wizard_spec.rb +11 -4
  59. data/spec/spec_helper.rb +9 -9
  60. metadata +314 -312
@@ -70,6 +70,6 @@ module Rhc
70
70
  class ResourceAccessException < Rhc::Rest::BaseException; end
71
71
  #I/O Exceptions Connection timeouts, etc
72
72
  class ConnectionException < Rhc::Rest::BaseException; end
73
-
73
+ class TimeoutException < ConnectionException; end
74
74
  end
75
75
  end
data/lib/rhc-rest/key.rb CHANGED
@@ -16,7 +16,7 @@ module Rhc
16
16
  url = @links['UPDATE']['href']
17
17
  method = @links['UPDATE']['method']
18
18
  payload = {:type => type, :content => content}
19
- request = RestClient::Request.new(:url => url, :method => method, :headers => @@headers, :payload => payload)
19
+ request = new_request(:url => url, :method => method, :headers => @@headers, :payload => payload)
20
20
  return request(request)
21
21
  end
22
22
 
@@ -25,7 +25,7 @@ module Rhc
25
25
  logger.debug "Deleting key #{self.name}" if @mydebug
26
26
  url = @links['DELETE']['href']
27
27
  method = @links['DELETE']['method']
28
- request = RestClient::Request.new(:url => url, :method => method, :headers => @@headers)
28
+ request = new_request(:url => url, :method => method, :headers => @@headers)
29
29
  return request(request)
30
30
  end
31
31
  alias :delete :destroy
data/lib/rhc-rest/user.rb CHANGED
@@ -13,7 +13,7 @@ module Rhc
13
13
  url = @links['ADD_KEY']['href']
14
14
  method = @links['ADD_KEY']['method']
15
15
  payload = {:name => name, :type => type, :content => content}
16
- request = RestClient::Request.new(:url => url, :method => method, :headers => @@headers, :payload => payload)
16
+ request = new_request(:url => url, :method => method, :headers => @@headers, :payload => payload)
17
17
  return request(request)
18
18
  end
19
19
 
@@ -21,7 +21,7 @@ module Rhc
21
21
  def keys
22
22
  url = @links['LIST_KEYS']['href']
23
23
  method = @links['LIST_KEYS']['method']
24
- request = RestClient::Request.new(:url => url, :method => method, :headers => @@headers)
24
+ request = new_request(:url => url, :method => method, :headers => @@headers)
25
25
  return request(request)
26
26
  end
27
27
 
data/lib/rhc/cli.rb CHANGED
@@ -18,7 +18,6 @@ module RHC
18
18
  # from the gem directory.
19
19
  #
20
20
  module CLI
21
-
22
21
  extend Commander::Delegates
23
22
 
24
23
  def self.set_terminal
@@ -26,13 +25,13 @@ module RHC
26
25
  end
27
26
 
28
27
  def self.start(args)
29
- runner = Commander::Runner.new(args)
28
+ runner = RHC::Commands::Runner.new(args)
30
29
  Commander::Runner.instance_variable_set :@singleton, runner
31
30
 
32
31
  program :name, 'rhc'
33
32
  program :version, RHC::VERSION::STRING
34
33
  program :description, 'Command line interface for OpenShift.'
35
- program :help_formatter, :compact
34
+ program :help_formatter, RHC::UsageHelpFormatter
36
35
 
37
36
  RHC::Commands.load.to_commander
38
37
  exit(run! || 0)
data/lib/rhc/commands.rb CHANGED
@@ -1,5 +1,102 @@
1
+ require 'commander'
2
+ require 'rhc/helpers'
3
+
1
4
  module RHC
2
- module Commands
5
+ module Commands
6
+ class CommandHelpBindings
7
+ def initialize(command, instance_commands, global_options)
8
+ @command = command
9
+ @actions = instance_commands.collect do |ic|
10
+ m = /^#{command.name} ([^ ]+)/.match(ic[0])
11
+ # if we have a match and it is not an alias then we can use it
12
+ m and ic[0] == ic[1].name ? {:name => m[1], :summary => ic[1].summary || ""} : nil
13
+ end
14
+ @actions.compact!
15
+ @global_options = global_options
16
+ end
17
+ end
18
+ class Runner < Commander::Runner
19
+ # regex fix from git - match on word boundries
20
+ def valid_command_names_from *args
21
+ arg_string = args.delete_if { |value| value =~ /^-/ }.join ' '
22
+ commands.keys.find_all { |name| name if /^#{name}\b/.match arg_string }
23
+ end
24
+
25
+ # override so we can do our own error handling
26
+ def run!
27
+ trace = false
28
+ require_program :version, :description
29
+ trap('INT') { abort program(:int_message) } if program(:int_message)
30
+ trap('INT') { program(:int_block).call } if program(:int_block)
31
+ global_option('-h', '--help', 'Display help documentation') do
32
+ args = @args - %w[-h --help]
33
+ command(:help).run(*args)
34
+ return
35
+ end
36
+ global_option('-v', '--version', 'Display version information') { say version; return }
37
+ global_option('-t', '--trace', 'Display backtrace when an error occurs') { trace = true }
38
+ parse_global_options
39
+ remove_global_options options, @args
40
+
41
+ # if help is last arg run as if --help was passed in
42
+ if @args[-1] == "help"
43
+ args = @args - ["help"]
44
+ command(:help).run(*args)
45
+ return
46
+ end
47
+
48
+ unless trace
49
+ begin
50
+ run_active_command
51
+ rescue InvalidCommandError => e
52
+ usage = RHC::UsageHelpFormatter.new(self).render
53
+ i = @args.find_index { |a| a.start_with?('-') } || @args.length
54
+ abort "The command 'rhc #{@args[0,i].join(' ')}' is not recognized.\n#{usage}"
55
+ rescue \
56
+ ArgumentError,
57
+ OptionParser::InvalidOption,
58
+ OptionParser::InvalidArgument,
59
+ OptionParser::MissingArgument => e
60
+
61
+ help_bindings = CommandHelpBindings.new(active_command, commands, Commander::Runner.instance.options)
62
+ usage = RHC::UsageHelpFormatter.new(self).render_command(help_bindings)
63
+ say "#{e}\n#{usage}"
64
+ 1
65
+ rescue Rhc::Rest::BaseException => e
66
+ RHC::Helpers.results { say "#{e}" }
67
+ e.code.nil? ? 128 : e.code
68
+ rescue Exception => e
69
+ RHC::Helpers.results { say "error: #{e} Use --trace to view backtrace." }
70
+ 128
71
+ end
72
+ else
73
+ run_active_command
74
+ end
75
+ end
76
+
77
+ def create_default_commands
78
+ command :help do |c|
79
+ c.syntax = 'rhc help <command>'
80
+ c.description = 'Display global or <command> help documentation.'
81
+ c.when_called do |args, options|
82
+ if args.empty?
83
+ say help_formatter.render
84
+ else
85
+ command = command args.join(' ')
86
+ begin
87
+ require_valid_command command
88
+ rescue InvalidCommandError => e
89
+ abort "#{e}"
90
+ end
91
+
92
+ help_bindings = CommandHelpBindings.new command, commands, Commander::Runner.instance.options
93
+ say help_formatter.render_command help_bindings
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
3
100
  def self.load
4
101
  Dir[File.join(File.dirname(__FILE__), "commands", "*.rb")].each do |file|
5
102
  require file
@@ -9,17 +106,70 @@ module RHC
9
106
  def self.add(opts)
10
107
  commands[opts[:name]] = opts
11
108
  end
12
- def self.global_option(*args)
13
- global_options << args
109
+ def self.global_option(switches, description)
110
+ global_options << [switches, description].flatten(1)
111
+ end
112
+ def self.validate_command(c, args, options, args_metadata)
113
+ # check to see if an arg's option was set
114
+ raise ArgumentError.new("Invalid arguments") if args.length > args_metadata.length
115
+ args_metadata.each_with_index do |arg_meta, i|
116
+ switch = arg_meta[:switches]
117
+ value = options.__hash__[arg_meta[:name]]
118
+ unless value.nil?
119
+ raise ArgumentError.new("#{arg_meta[:name]} specified twice on the command line and as a #{switch[0]} switch") unless args.length == i
120
+ # add the option as an argument
121
+ args << value
122
+ end
123
+ end
124
+ end
125
+
126
+ def self.global_config_setup(options)
127
+ RHC::Config.set_opts_config(options.config) if options.config
128
+ RHC::Config.password = options.password if options.password
129
+ RHC::Config.opts_login = options.rhlogin if options.rhlogin
130
+ RHC::Config.noprompt(options.noprompt) if options.noprompt
131
+ RHC::Config
132
+ end
133
+
134
+ def self.needs_configuration!(cmd, config)
135
+ # check to see if we need to run wizard
136
+ if not cmd.class.suppress_wizard?
137
+ w = RHC::Wizard.new config
138
+ return w.run if w.needs_configuration?
139
+ end
140
+ false
14
141
  end
142
+
15
143
  def self.to_commander(instance=Commander::Runner.instance)
16
144
  global_options.each{ |args| instance.global_option *args }
17
145
  commands.each_pair do |name, opts|
18
146
  instance.command name do |c|
19
147
  c.description = opts[:description]
20
148
  c.summary = opts[:summary]
149
+ c.syntax = opts[:syntax]
150
+
151
+ (opts[:options]||[]).each { |o| c.option *o }
152
+ args_metadata = opts[:args] || []
153
+ (args_metadata).each do |arg_meta|
154
+ arg_switches = arg_meta[:switches]
155
+ arg_switches << arg_meta[:description]
156
+ c.option *arg_switches unless arg_switches.nil?
157
+ end
158
+
21
159
  c.when_called do |args, options|
22
- opts[:class].new(c, args, options).send(opts[:method])
160
+ validate_command c, args, options, args_metadata
161
+ config = global_config_setup options
162
+ cmd = opts[:class].new c, args, options, config
163
+ needs_configuration! cmd, config
164
+ cmd.send opts[:method], *args
165
+ end
166
+
167
+ unless opts[:aliases].nil?
168
+ opts[:aliases].each do |a|
169
+ alias_components = name.split(" ")
170
+ alias_components[-1] = a
171
+ instance.alias_command "#{alias_components.join(' ')}", :"#{name}"
172
+ end
23
173
  end
24
174
  end
25
175
  end
@@ -1,17 +1,27 @@
1
1
  require 'commander'
2
2
  require 'commander/delegates'
3
3
  require 'rhc/helpers'
4
+ require 'rhc/wizard'
5
+ require 'rhc/config'
6
+ require 'rhc/commands'
7
+ require 'rhc/exceptions'
4
8
 
5
9
  class RHC::Commands::Base
6
10
 
7
- def initialize(command=nil, args=[], options=OptionParser.new)
8
- @command, @args, @options = command, args, options
11
+ def initialize(command=nil,
12
+ args=[],
13
+ options=Commander::Command::Options.new,
14
+ config=RHC::Config)
15
+ @command, @args, @options, @config = command, args, options, config
16
+
17
+ # apply timeout here even though it isn't quite a global
18
+ $rest_timeout = @options.timeout ? @options.timeout.to_i : nil
9
19
  end
10
20
 
11
21
  protected
12
22
  include RHC::Helpers
13
23
 
14
- attr_reader :command, :args, :options
24
+ attr_reader :command, :args, :options, :config
15
25
 
16
26
  def application
17
27
  #@application ||= ... identify current application or throw,
@@ -33,15 +43,6 @@ class RHC::Commands::Base
33
43
  # object).
34
44
  end
35
45
 
36
- def config
37
- @config ||= begin
38
- RHC::Config.set_opts_config(options.config) if options.config
39
- RHC::Config.password = options.password if options.password
40
- RHC::Config.opts_login = options.rhlogin if options.rhlogin
41
- RHC::Config
42
- end
43
- end
44
-
45
46
  class InvalidCommand < StandardError ; end
46
47
 
47
48
  def self.inherited(klass)
@@ -81,9 +82,45 @@ class RHC::Commands::Base
81
82
  def self.summary(value)
82
83
  options[:summary] = value
83
84
  end
85
+ def self.syntax(value)
86
+ options[:syntax] = value
87
+ end
88
+
89
+ def self.suppress_wizard
90
+ @suppress_wizard = true
91
+ end
92
+
93
+ def self.suppress_wizard?
94
+ @suppress_wizard
95
+ end
96
+
97
+ def self.alias_action(action)
98
+ aliases << action
99
+ end
100
+
101
+ def self.option(switches, description)
102
+ options_metadata << [switches, description].flatten(1)
103
+ end
104
+
105
+ def self.argument(name, description, switches)
106
+ args_metadata << {:name => name, :description => description, :switches => switches}
107
+ end
108
+
109
+ def self.default_action(action)
110
+ define_method(:run) { |*args| send(action, *args) }
111
+ end
84
112
 
85
113
  private
114
+ def self.options_metadata
115
+ options[:options] ||= []
116
+ end
117
+ def self.args_metadata
118
+ options[:args] ||= []
119
+ end
86
120
  def self.options
87
121
  @options ||= {}
88
122
  end
123
+ def self.aliases
124
+ options[:aliases] ||= []
125
+ end
89
126
  end
@@ -0,0 +1,142 @@
1
+ require 'rhc/commands/base'
2
+
3
+ module RHC::Commands
4
+ class Domain < Base
5
+ summary "Manage your domain"
6
+ syntax "<action>"
7
+ default_action :show
8
+
9
+ summary "Bind a registered user to a domain"
10
+ syntax "<namespace> [--timeout timeout]"
11
+ argument :namespace, "Namespace for your application(s) (alphanumeric)", ["-n", "--namespace namespace"]
12
+ option ["--timeout timeout"], "Timeout, in seconds, for the session"
13
+ def create(namespace)
14
+ paragraph { say "Creating domain with namespace '#{namespace}'" }
15
+ rest_client.add_domain(namespace)
16
+
17
+ results do
18
+ say "Success!"
19
+ say "You may now create an application using the 'rhc app create' command"
20
+ end
21
+
22
+ 0
23
+ end
24
+
25
+ summary "Update namespace (will change urls)."
26
+ syntax "<namespace> [--timeout timeout]"
27
+ argument :namespace, "Namespace for your application(s) (alphanumeric)", ["-n", "--namespace namespace"]
28
+ option ["--timeout timeout"], "Timeout, in seconds, for the session"
29
+ alias_action :alter
30
+ def update(namespace)
31
+ # TODO: Support multiple domains. Right now we assume one domain so
32
+ # you don't have to send in the name of the domain you want to change
33
+ # but in the future this will be manditory if you have more than one
34
+ # domain. Figure out how to support overloading of commands
35
+ domain = rest_client.domains
36
+ raise RHC::DomainNotFoundException.new("No domains are registered to the user #{config.username}. Please use 'rhc domain create' to create one.") if domain.empty?
37
+
38
+ paragraph { say "Updating domain '#{domain[0].id}' to namespace '#{namespace}'" }
39
+
40
+ domain[0].update(namespace)
41
+
42
+ results do
43
+ say "Success!"
44
+ say "You can use 'rhc domain show' to view any url changes. Be sure to update any links including the url in your local git config: <local_git_repo>/.git/config"
45
+ end
46
+
47
+ 0
48
+ end
49
+
50
+ summary "Show your configured domains"
51
+ def show
52
+ domains = rest_client.domains
53
+ paragraph do
54
+ say "User Info"
55
+ say "========="
56
+ if domains.length == 0
57
+ say "Namespace: No namespaces found. You can use 'rhc domain create <namespace>' to create a namespace for your applications."
58
+ elsif domains.length == 1
59
+ say "Namespace: #{domains[0].id}"
60
+ else
61
+ domains.each_with_index { |d, i| say "Namespace(#{i}): #{d.id}" }
62
+ end
63
+ end
64
+
65
+ paragraph { say "Login: #{config.username}" }
66
+ domains.each do |d|
67
+ paragraph do
68
+ header = "Namespace #{d.id}'s Applications"
69
+ say header
70
+ say "=" * header.length
71
+ apps = d.applications
72
+ if apps.length == 0
73
+ say "No applications found. You can use 'rhc app create' to create new applications."
74
+ else
75
+ apps.each do |a|
76
+ carts = a.cartridges
77
+ paragraph do
78
+ say a.name
79
+ say " Framework: #{carts[0].name}"
80
+ say " Creation: #{a.creation_time}"
81
+ say " UUID: #{a.uuid}"
82
+ say " Git URL: #{a.git_url}" if a.git_url
83
+ say " Public URL: #{a.app_url}" if a.app_url
84
+ say " Aliases: #{a.aliases.join(', ')}" if a.aliases and not a.aliases.empty?
85
+ say " Cartridges:"
86
+ if carts.length > 1
87
+ carts.each do |c|
88
+ if c.type == 'embedded'
89
+ connection_url = c.property(:cart_data, :connection_url) || c.property(:cart_data, :job_url) || c.property(:cart_data, :monitoring_url)
90
+ value = connection_url ? " - #{connection_url['value']}" : ""
91
+ say " #{c.name}#{value}"
92
+ end
93
+ end
94
+ else
95
+ say " None"
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ 0
103
+ end
104
+
105
+ summary "Run a status check on your domain"
106
+ option ["--timeout timeout"], "Timeout, in seconds, for the session"
107
+ def status
108
+ args = []
109
+
110
+ options.__hash__.each do |key, value|
111
+ value = value.to_s
112
+ if value.length > 0 && value.to_s.strip.length == 0; value = "'#{value}'" end
113
+ args << "--#{key} #{value}"
114
+ end
115
+
116
+ Kernel.system("rhc-chk #{args.join(' ')} 2>&1")
117
+ $?.exitstatus.nil? ? 1 : $?.exitstatus
118
+ end
119
+
120
+ summary "Deletes your domain."
121
+ syntax "<namespace> [--timeout timeout]"
122
+ argument :namespace, "Namespace you wish to destroy", ["-n", "--namespace namespace"]
123
+ option ["--timeout timeout"], "Timeout, in seconds, for the session"
124
+ alias_action :destroy
125
+ def delete(namespace)
126
+ paragraph { say "Deleting domain '#{namespace}'" }
127
+ domain = rest_client.find_domain namespace
128
+
129
+ paragraph do
130
+ begin
131
+ domain.destroy
132
+ rescue Rhc::Rest::ClientErrorException
133
+ raise Rhc::Rest::ClientErrorException.new("Domain contains applications. Delete applications first.", 128)
134
+ end
135
+ end
136
+
137
+ results { say "Success!" }
138
+ 0
139
+ end
140
+ end
141
+
142
+ end