rhc 0.97.17 → 0.98.16

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 (93) hide show
  1. data/bin/rhc +9 -9
  2. data/bin/rhc-port-forward +3 -0
  3. data/bin/rhc-sshkey +3 -0
  4. data/features/README.md +163 -35
  5. data/features/application.feature +24 -0
  6. data/features/cartridge.feature +24 -0
  7. data/features/client.feature +11 -0
  8. data/features/domain.feature +29 -0
  9. data/features/lib/rhc_helper.rb +14 -0
  10. data/features/lib/rhc_helper/app.rb +2 -8
  11. data/features/lib/rhc_helper/cartridge.rb +1 -7
  12. data/features/lib/rhc_helper/commandify.rb +37 -6
  13. data/features/lib/rhc_helper/domain.rb +5 -1
  14. data/features/lib/rhc_helper/httpify.rb +124 -60
  15. data/features/lib/rhc_helper/loggable.rb +0 -2
  16. data/features/lib/rhc_helper/persistable.rb +12 -2
  17. data/features/lib/rhc_helper/sshkey.rb +29 -0
  18. data/features/multiple_cartridge.feature +17 -0
  19. data/features/sshkey.feature +58 -0
  20. data/features/step_definitions/application_steps.rb +60 -52
  21. data/features/step_definitions/cartridge_steps.rb +22 -24
  22. data/features/step_definitions/client_steps.rb +9 -2
  23. data/features/step_definitions/domain_steps.rb +4 -0
  24. data/features/step_definitions/sshkey_steps.rb +56 -0
  25. data/features/support/assumptions.rb +37 -0
  26. data/features/support/before_hooks.rb +25 -0
  27. data/features/support/env.rb +84 -39
  28. data/features/support/key1 +27 -0
  29. data/features/support/key1.pub +1 -0
  30. data/features/support/key2 +27 -0
  31. data/features/support/key2.pub +1 -0
  32. data/features/support/key3.pub +1 -0
  33. data/features/support/ssh.sh +2 -0
  34. data/features/verify.feature +18 -159
  35. data/lib/rhc-common.rb +8 -21
  36. data/lib/rhc.rb +9 -5
  37. data/lib/rhc/autocomplete.rb +68 -0
  38. data/lib/rhc/autocomplete_templates/rhc.erb +33 -0
  39. data/lib/rhc/cli.rb +9 -6
  40. data/lib/rhc/command_runner.rb +108 -0
  41. data/lib/rhc/commands.rb +66 -132
  42. data/lib/rhc/commands/base.rb +95 -24
  43. data/lib/rhc/commands/domain.rb +33 -50
  44. data/lib/rhc/commands/port-forward.rb +81 -0
  45. data/lib/rhc/commands/setup.rb +1 -1
  46. data/lib/rhc/commands/sshkey.rb +95 -0
  47. data/lib/rhc/config.rb +108 -103
  48. data/lib/rhc/context_helper.rb +19 -0
  49. data/lib/rhc/coverage_helper.rb +1 -1
  50. data/lib/rhc/exceptions.rb +55 -4
  51. data/lib/rhc/help_formatter.rb +2 -3
  52. data/lib/rhc/helpers.rb +31 -23
  53. data/lib/{rhc-rest.rb → rhc/rest.rb} +95 -23
  54. data/lib/{rhc-rest → rhc/rest}/application.rb +1 -1
  55. data/lib/{rhc-rest → rhc/rest}/cartridge.rb +1 -1
  56. data/lib/{rhc-rest → rhc/rest}/client.rb +40 -9
  57. data/lib/{rhc-rest → rhc/rest}/domain.rb +1 -1
  58. data/lib/{rhc-rest → rhc/rest}/key.rb +11 -1
  59. data/lib/{rhc-rest → rhc/rest}/user.rb +1 -1
  60. data/lib/rhc/ssh_key_helpers.rb +10 -1
  61. data/lib/rhc/targz.rb +7 -8
  62. data/lib/rhc/usage_templates/command_help.erb +7 -6
  63. data/lib/rhc/usage_templates/help.erb +6 -9
  64. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  65. data/lib/rhc/version.rb +2 -2
  66. data/lib/rhc/wizard.rb +4 -9
  67. data/spec/coverage_helper.rb +2 -2
  68. data/spec/rest_spec_helper.rb +66 -16
  69. data/spec/rhc/cli_spec.rb +16 -5
  70. data/spec/rhc/command_spec.rb +61 -6
  71. data/spec/rhc/commands/domain_spec.rb +50 -27
  72. data/spec/rhc/commands/port-forward_spec.rb +133 -0
  73. data/spec/rhc/commands/setup_spec.rb +2 -2
  74. data/spec/rhc/commands/sshkey_spec.rb +141 -0
  75. data/spec/rhc/common_spec.rb +1 -1
  76. data/spec/rhc/config_spec.rb +6 -4
  77. data/spec/rhc/helpers_spec.rb +0 -21
  78. data/spec/rhc/rest_application_spec.rb +7 -7
  79. data/spec/rhc/rest_client_spec.rb +87 -24
  80. data/spec/rhc/rest_spec.rb +36 -36
  81. data/spec/rhc/wizard_spec.rb +3 -3
  82. data/spec/spec.opts +1 -0
  83. data/spec/spec_helper.rb +3 -3
  84. metadata +61 -31
  85. data/lib/rhc-rest/exceptions/exceptions.rb +0 -75
  86. data/test/functional/application_test.rb +0 -71
  87. data/test/functional/domain_test.rb +0 -123
  88. data/test/functional/test_credentials.rb +0 -5
  89. data/test/sample-usage.rb +0 -122
  90. data/test/support/server.rb +0 -14
  91. data/test/support/testcase.rb +0 -3
  92. data/test/test_helper.rb +0 -4
  93. data/test/unit/command_test.rb +0 -19
@@ -0,0 +1,19 @@
1
+ module RHC
2
+ module ContextHelpers
3
+ def app_context
4
+ # We currently do not have a way of determening an app context so return nil
5
+ # In the future we will use the uuid embeded in the git config to query
6
+ # the server for the repo's app name
7
+ nil
8
+ end
9
+
10
+ def namespace_context
11
+ # right now we don't have any logic since we only support one domain
12
+ # :nocov: remove nocov when cart tests go back in
13
+ domain = rest_client.domains[0]
14
+ raise RHC::DomainNotFoundException("No domains configured for this user. You may create one using 'rhc domain create'.") if domain.nil?
15
+
16
+ domain.id
17
+ end
18
+ end
19
+ end
@@ -18,7 +18,7 @@ if RUBY_VERSION >= '1.9' and ENV['RHC_FEATURE_COVERAGE']
18
18
  # Groups - general categories of test areas
19
19
  add_group('Commands') { |src_file| src_file.filename.include?(File.join(%w[lib rhc commands])) }
20
20
  add_group('RHC Lib') { |src_file| src_file.filename.include?(File.join(%w[lib rhc])) }
21
- add_group('REST') { |src_file| src_file.filename.include?(File.join(%w[lib rhc-rest])) }
21
+ add_group('REST') { |src_file| src_file.filename.include?(File.join(%w[lib rhc/rest])) }
22
22
  add_group('Legacy') { |src_file| src_file.filename.include?(File.join(%w[bin])) or
23
23
  src_file.filename.include?(File.join(%w[lib rhc-common.rb])) }
24
24
  add_group('Test') { |src_file| src_file.filename.include?(File.join(%w[features])) or
@@ -1,20 +1,71 @@
1
- require 'rhc-rest/exceptions/exceptions'
2
1
  module RHC
3
- class DomainNotFoundException < Rhc::Rest::ResourceNotFoundException
2
+ class Exception < StandardError
3
+ attr_reader :code
4
+ def initialize(message=nil, code=nil)
5
+ super(message)
6
+ @code = code
7
+ end
8
+ end
9
+
10
+ class DomainNotFoundException < Exception
4
11
  def initialize(message="Domain not found")
5
12
  super message, 127
6
13
  end
7
14
  end
8
15
 
9
- class ApplicationNotFoundException < Rhc::Rest::ResourceNotFoundException
16
+ class ApplicationNotFoundException < Exception
10
17
  def initialize(message="Application not found")
11
18
  super message, 101
12
19
  end
13
20
  end
14
21
 
15
- class KeyNotFoundException < Rhc::Rest::ResourceNotFoundException
22
+ class KeyNotFoundException < Exception
16
23
  def initialize(message="SSHKey not found")
17
24
  super message, 118
18
25
  end
19
26
  end
27
+
28
+ class DeprecatedError < RuntimeError; end
29
+
30
+ class KeyFileNotExistentException < Exception
31
+ def initialize(message="SSH Key file not found")
32
+ super message, 128
33
+ end
34
+ end
35
+
36
+ class KeyFileAccessDeniedException < Exception
37
+ def initialize(message = "Insufficient acces to SSH Key file")
38
+ super message, 128
39
+ end
40
+ end
41
+
42
+ class KeyDataInvalidException < Exception
43
+ def initialize(message = "SSH Key file contains invalid data")
44
+ super message, 128
45
+ end
46
+ end
47
+
48
+ class ScaledApplicationsNotSupportedException < Exception
49
+ def initialize(message="Scaled applications not supported")
50
+ super message, 128
51
+ end
52
+ end
53
+
54
+ class PermissionDeniedException < Exception
55
+ def initialize(message="Permission denied")
56
+ super message, 129
57
+ end
58
+ end
59
+
60
+ class NoPortsToForwardException < Exception
61
+ def initialize(message="No available ports to forward")
62
+ super message, 102
63
+ end
64
+ end
65
+
66
+ class PortForwardFailedException < Exception
67
+ def initialize(message="Port forward failed")
68
+ super message, 1
69
+ end
70
+ end
20
71
  end
@@ -1,11 +1,10 @@
1
1
  require 'commander/help_formatters/base'
2
2
 
3
3
  module RHC
4
- class UsageHelpFormatter < Commander::HelpFormatter::Terminal
5
- def template name
4
+ class HelpFormatter < Commander::HelpFormatter::Terminal
5
+ def template(name)
6
6
  ERB.new(File.read(File.join(File.dirname(__FILE__), 'usage_templates', "#{name}.erb")), nil, '-')
7
7
  end
8
8
  end
9
-
10
9
  # TODO: class ManPageHelpFormatter
11
10
  end
data/lib/rhc/helpers.rb CHANGED
@@ -8,8 +8,8 @@ module RHC
8
8
 
9
9
  module Helpers
10
10
  private
11
- def self.global_option(switches, description)
12
- RHC::Commands.global_option switches, description
11
+ def self.global_option(*args, &block)
12
+ RHC::Commands.global_option *args, &block
13
13
  end
14
14
  end
15
15
 
@@ -21,6 +21,18 @@ module RHC
21
21
 
22
22
  extend self
23
23
 
24
+ def disable_deprecated?
25
+ # 1) default for now is false
26
+ # 2) when releasing a 1.0 beta flip this to true
27
+ # 3) all deprecated aliases should be removed right before 1.0
28
+ disable = false
29
+
30
+ env_disable = ENV['DISABLE_DEPRECATED']
31
+ disable = true if env_disable == '1'
32
+
33
+ disable
34
+ end
35
+
24
36
  def decode_json(s)
25
37
  RHC::Vendor::OkJson.decode(s)
26
38
  end
@@ -32,6 +44,8 @@ module RHC
32
44
  return d.strftime('%l:%M %p').strip if now.yday == d.yday
33
45
  end
34
46
  d.strftime('%b %d %l:%M %p')
47
+ rescue ArgumentError
48
+ "Unknown date"
35
49
  end
36
50
 
37
51
  def datetime_rfc3339(s)
@@ -44,7 +58,7 @@ module RHC
44
58
  #
45
59
 
46
60
  def user_agent
47
- "rhc/#{RHC::VERSION::STRING} (ruby #{RUBY_VERSION}; #{RUBY_PLATFORM})#{" (API #{Rhc::Rest::API_VERSION})" rescue ''}"
61
+ "rhc/#{RHC::VERSION::STRING} (ruby #{RUBY_VERSION}; #{RUBY_PLATFORM})#{" (API #{RHC::Rest::API_VERSION})" rescue ''}"
48
62
  end
49
63
 
50
64
  def get(uri, opts=nil, *args)
@@ -56,16 +70,16 @@ module RHC
56
70
  # Global config
57
71
  #
58
72
 
59
- global_option ['--config FILE'], "Path of a different config file"
73
+ global_option '-l', '--rhlogin login', "OpenShift login"
74
+ global_option '-p', '--password password', "OpenShift password"
75
+ global_option '-d', '--debug', "Turn on debugging"
76
+
77
+ global_option '--noprompt', "Do not ask for input"
78
+ global_option '--config FILE', "Path of a different config file"
60
79
  def config
61
80
  raise "Operations requiring configuration must define a config accessor"
62
81
  end
63
82
 
64
- global_option ['--noprompt'], "Bypass first run wizard"
65
- global_option ['-l', '--rhlogin login'], "Red Hat login (RedHat Network or OpenShift)"
66
- global_option ['-p', '--password password'], "Red Hat password"
67
- global_option ['-d', '--debug'], "Turn on debugging"
68
-
69
83
  def openshift_server
70
84
  config.get_value('libra_server')
71
85
  end
@@ -76,20 +90,6 @@ module RHC
76
90
  "#{openshift_url}/broker/rest/api"
77
91
  end
78
92
 
79
- def rest_client
80
- return @rest_client if @rest_client
81
-
82
- username = config.username
83
- unless username
84
- username = ask "To connect to #{openshift_server} enter your OpenShift login (email or Red Hat login id): "
85
- config.config_user(username)
86
- end
87
-
88
- password = RHC::Config.password || RHC::get_password
89
-
90
- @rest_client = Rhc::Rest::Client.new(openshift_rest_node, username, password, @options.debug)
91
- end
92
-
93
93
  #
94
94
  # Output helpers
95
95
  #
@@ -104,6 +104,9 @@ module RHC
104
104
  def warn(msg, *args)
105
105
  say color(msg, :yellow)
106
106
  end
107
+ def error(msg, *args)
108
+ say color(msg, :red)
109
+ end
107
110
 
108
111
  def color(s, color)
109
112
  $terminal.color(s, color)
@@ -129,6 +132,11 @@ module RHC
129
132
  end
130
133
  end
131
134
 
135
+ def header(s)
136
+ say s
137
+ say "=" * s.length
138
+ end
139
+
132
140
  ##
133
141
  # section
134
142
  #
@@ -1,18 +1,92 @@
1
- require 'rest-client'
2
1
  require 'logger'
3
- require 'rhc-rest/exceptions/exceptions'
4
- require 'rhc-rest/application'
5
- require 'rhc-rest/cartridge'
6
- require 'rhc-rest/client'
7
- require 'rhc-rest/domain'
8
- require 'rhc-rest/key'
9
- require 'rhc-rest/user'
10
-
11
- module Rhc
2
+ require 'rest-client'
3
+
4
+ module RHC
5
+ module Rest
6
+
7
+ autoload :Application, 'rhc/rest/application'
8
+ autoload :Cartridge, 'rhc/rest/cartridge'
9
+ autoload :Client, 'rhc/rest/client'
10
+ autoload :Domain, 'rhc/rest/domain'
11
+ autoload :Key, 'rhc/rest/key'
12
+ autoload :User, 'rhc/rest/user'
13
+
14
+ class Exception < RuntimeError
15
+ attr_reader :code
16
+ def initialize(message=nil, code=nil)
17
+ super(message)
18
+ @code = code
19
+ end
20
+ end
21
+
22
+ #Exceptions thrown in case of an HTTP 5xx is received.
23
+ class ServerErrorException < Exception; end
24
+
25
+ #Exceptions thrown in case of an HTTP 503 is received.
26
+ #
27
+ #503 Service Unavailable
28
+ #
29
+ #The server is currently unable to handle the request due to a temporary
30
+ #overloading or maintenance of the server. The implication is that this
31
+ #is a temporary condition which will be alleviated after some delay.
32
+ class ServiceUnavailableException < ServerErrorException; end
33
+
34
+ #Exceptions thrown in case of an HTTP 4xx is received with the exception
35
+ #of 401, 403, 403 and 422 where a more sepcific exception is thrown
36
+ #
37
+ #HTTP Error Codes 4xx
38
+ #
39
+ #The 4xx class of status code is intended for cases in which the client
40
+ #seems to have errored.
41
+ class ClientErrorException < Exception; end
42
+
43
+ #Exceptions thrown in case of an HTTP 404 is received.
44
+ #
45
+ #404 Not Found
46
+ #
47
+ #The server has not found anything matching the Request-URI or the
48
+ #requested resource does not exist
49
+ class ResourceNotFoundException < ClientErrorException; end
50
+
51
+ #Exceptions thrown in case of an HTTP 422 is received.
52
+ class ValidationException < ClientErrorException
53
+ attr_reader :field
54
+ def initialize(message, field=nil, error_code=nil)
55
+ super(message, error_code)
56
+ @field = field
57
+ end
58
+ end
59
+
60
+ #Exceptions thrown in case of an HTTP 403 is received.
61
+ #
62
+ #403 Forbidden
63
+ #
64
+ #The server understood the request, but is refusing to fulfill it.
65
+ #Authorization will not help and the request SHOULD NOT be repeated.
66
+ class RequestDeniedException < ClientErrorException; end
67
+
68
+ #Exceptions thrown in case of an HTTP 401 is received.
69
+ #
70
+ #401 Unauthorized
71
+ #
72
+ #The request requires user authentication. If the request already
73
+ #included Authorization credentials, then the 401 response indicates
74
+ #that authorization has been refused for those credentials.
75
+ class UnAuthorizedException < ClientErrorException; end
76
+
77
+ # Unreachable host, SSL Exception
78
+ class ResourceAccessException < Exception; end
79
+
80
+ #I/O Exceptions Connection timeouts, etc
81
+ class ConnectionException < Exception; end
82
+ class TimeoutException < ConnectionException; end
83
+ end
84
+
85
+
12
86
  module Rest
13
87
  #API_VERSION = '1.1'
14
88
  @@headers = {:accept => :json}
15
- #@@headers = {:accept => "application/json;version=#{Rhc::Rest::VERSION}"}
89
+ #@@headers = {:accept => "application/json;version=#{RHC::Rest::VERSION}"}
16
90
 
17
91
  def logger
18
92
  Logger.new(STDOUT)
@@ -84,7 +158,7 @@ module Rhc
84
158
  raise ConnectionException.new("Connection to server got interrupted: #{e.message}")
85
159
  rescue RestClient::ExceptionWithResponse => e
86
160
  process_error_response(e.response)
87
- rescue Exception => e
161
+ rescue => e
88
162
  raise ResourceAccessException.new("Failed to access resource: #{e.message}")
89
163
  end
90
164
  end
@@ -94,29 +168,28 @@ module Rhc
94
168
  begin
95
169
  result = RHC::Json.decode(response)
96
170
  messages = result['messages']
97
- rescue Exception => e
171
+ rescue => e
98
172
  logger.debug "Response did not include a message from server" if @mydebug
99
- #puts response
100
173
  end
101
174
  case response.code
102
175
  when 401
103
- raise UnAuthorizedException.new("Not authenticated")
176
+ raise UnAuthorizedException, "Not authenticated"
104
177
  when 403
105
178
  messages.each do |message|
106
179
  if message['severity'].upcase == "ERROR"
107
- raise RequestDeniedException.new(message['text'])
180
+ raise RequestDeniedException, message['text']
108
181
  end
109
182
  end
110
183
  when 404
111
184
  messages.each do |message|
112
185
  if message['severity'].upcase == "ERROR"
113
- raise ResourceNotFoundException.new(message['text'])
186
+ raise ResourceNotFoundException, message['text']
114
187
  end
115
188
  end
116
189
  when 409
117
190
  messages.each do |message|
118
191
  if message['severity'] and message['severity'].upcase == "ERROR"
119
- raise ValidationException.new(message['text'])
192
+ raise ValidationException, message['text']
120
193
  end
121
194
  end
122
195
  when 422
@@ -133,25 +206,24 @@ module Rhc
133
206
  when 400
134
207
  messages.each do |message|
135
208
  if message['severity'].upcase == "ERROR"
136
- raise ClientErrorException.new(message['text'])
209
+ raise ClientErrorException, message['text']
137
210
  end
138
211
  end
139
212
  when 500
140
213
  messages.each do |message|
141
214
  if message['severity'].upcase == "ERROR"
142
- raise ServerErrorException.new(message['text'])
215
+ raise ServerErrorException, message['text']
143
216
  end
144
217
  end
145
218
  when 503
146
219
  messages.each do |message|
147
220
  if message['severity'].upcase == "ERROR"
148
- raise ServiceUnavailableException.new(message['text'])
221
+ raise ServiceUnavailableException, message['text']
149
222
  end
150
223
  end
151
224
  else
152
- raise ResourceAccessException.new("Server returned error code with no output: #{response.code}")
225
+ raise ResourceAccessException, "Server returned error code with no output: #{response.code}"
153
226
  end
154
-
155
227
  end
156
228
  end
157
229
  end
@@ -1,5 +1,5 @@
1
1
 
2
- module Rhc
2
+ module RHC
3
3
  module Rest
4
4
  class Application
5
5
  include Rest
@@ -1,4 +1,4 @@
1
- module Rhc
1
+ module RHC
2
2
  module Rest
3
3
  class Cartridge
4
4
  include Rest
@@ -1,7 +1,7 @@
1
1
  require 'base64'
2
2
  require 'rhc/json'
3
3
 
4
- module Rhc
4
+ module RHC
5
5
  module Rest
6
6
  class Client
7
7
  include Rest
@@ -9,7 +9,16 @@ module Rhc
9
9
  # use mydebug for legacy reasons
10
10
  @mydebug = @mydebug || debug
11
11
  logger.debug "Connecting to #{end_point}" if @mydebug
12
- credentials = Base64.encode64("#{username}:#{password}")
12
+
13
+ credentials = nil
14
+ userpass = "#{username}:#{password}"
15
+ # :nocov: version dependent code
16
+ if RUBY_VERSION.to_f == 1.8
17
+ credentials = Base64.encode64(userpass).delete("\n")
18
+ else
19
+ credentials = Base64.strict_encode64(userpass)
20
+ end
21
+ # :nocov:
13
22
  @@headers["Authorization"] = "Basic #{credentials}"
14
23
  @@headers["User-Agent"] = RHC::Helpers.user_agent rescue nil
15
24
  #first get the API
@@ -19,9 +28,7 @@ module Rhc
19
28
  response = request.execute
20
29
  result = RHC::Json.decode(response)
21
30
  @links = request(request)
22
- rescue RestClient::ExceptionWithResponse => e
23
- logger.error "Failed to get API #{e.response}"
24
- rescue Exception => e
31
+ rescue => e
25
32
  raise ResourceAccessException.new("Resource could not be accessed:#{e.message}")
26
33
  end
27
34
  end
@@ -62,13 +69,21 @@ module Rhc
62
69
  return request(request)
63
70
  end
64
71
 
65
- #Find Cartridge by name
66
- def find_cartridge(name)
72
+ #Find Cartridge by name or regex
73
+ def find_cartridges(name)
67
74
  logger.debug "Finding cartridge #{name}" if @mydebug
75
+ regex = nil
76
+ if name.is_a?(Hash)
77
+ name = name[:name] if name[:name]
78
+ regex = name[:regex] if name[:regex]
79
+ end
80
+
68
81
  filtered = Array.new
69
82
  cartridges.each do |cart|
70
- if cart.name == name
71
- filtered.push(cart)
83
+ if regex
84
+ filtered.push(cart) if cart.name.match(regex)
85
+ else
86
+ filtered.push(cart) if cart.name == name
72
87
  end
73
88
  end
74
89
  return filtered
@@ -89,6 +104,22 @@ module Rhc
89
104
 
90
105
  raise RHC::KeyNotFoundException.new("Key #{name} does not exist")
91
106
  end
107
+
108
+ def sshkeys
109
+ logger.debug "Finding all keys for #{user.login}" if @mydebug
110
+ user.keys
111
+ end
112
+
113
+ def add_key(name, key, content)
114
+ logger.debug "Adding key #{key} for #{user.login}" if @mydebug
115
+ user.add_key name, key, content
116
+ end
117
+
118
+ def delete_key(name)
119
+ logger.debug "Deleting key '#{name}'" if @mydebug
120
+ key = find_key(name)
121
+ key.destroy
122
+ end
92
123
 
93
124
  def logout
94
125
  #TODO logout