rhc 0.97.17 → 0.98.16

Sign up to get free protection for your applications and to get access to all the features.
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