rhc 0.96.9 → 0.97.17

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 (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