rhc 1.27.4 → 1.28.5

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.
@@ -29,8 +29,22 @@ class RHC::Commands::Base
29
29
  # should be through this call pattern.
30
30
  def rest_client(opts={})
31
31
  @rest_client ||= begin
32
- auth = RHC::Auth::Basic.new(options)
33
- auth = RHC::Auth::Token.new(options, auth, token_store) if (options.use_authorization_tokens || options.token) && !(options.rhlogin && options.password)
32
+ core_auth = if (options.ssl_client_cert_file && options.ssl_client_key_file)
33
+ RHC::Auth::X509.new(options)
34
+ else
35
+ RHC::Auth::Basic.new(options)
36
+ end
37
+
38
+ # Specifying a username and password on the CLI trumps token
39
+ # authentication.
40
+ auth = if options.rhlogin && options.password
41
+ RHC::Auth::Basic.new(options)
42
+ elsif (options.use_authorization_tokens || options.token)
43
+ RHC::Auth::Token.new(options, core_auth, token_store)
44
+ else
45
+ core_auth
46
+ end
47
+
34
48
  debug "Authenticating with #{auth.class}"
35
49
  client_from_options(:auth => auth)
36
50
  end
@@ -93,7 +93,7 @@ module RHC::Commands
93
93
  confirm_action "Are you sure you wish to remove the environment variable(s) above from application '#{rest_app.name}'?"
94
94
  say 'Removing environment variable(s) ... '
95
95
  rest_app.unset_environment_variables(env)
96
- success 'removed'
96
+ success 'done'
97
97
 
98
98
  0
99
99
  end
@@ -109,6 +109,7 @@ module RHC::Commands
109
109
  takes_application :argument => true
110
110
  option ["--table"], "Format the output list as a table"
111
111
  option ["--quotes"], "Format the output list with double quotes for env var values"
112
+ alias_action :"envs", :root_command => true
112
113
  def list(app)
113
114
  rest_app = find_app
114
115
  rest_env_vars = rest_app.environment_variables
@@ -0,0 +1,27 @@
1
+ require 'rhc/commands/base'
2
+
3
+ module RHC::Commands
4
+ class Region < Base
5
+ summary "Display the regions and zones available on the OpenShift server"
6
+ default_action :list
7
+
8
+ summary "List the regions and zones available on the OpenShift server"
9
+ alias_action :"regions", :root_command => true
10
+ def list
11
+ regions = rest_client.regions
12
+
13
+ raise RHC::NoRegionConfiguredException if regions.empty?
14
+
15
+ paragraph{ say "Server #{options.server}" }
16
+
17
+ regions.sort.each do |region|
18
+ display_region(region)
19
+ end
20
+
21
+ paragraph{ say "To create an app in a specific region use 'rhc create-app <name> <cartridge> --region <region>'." }
22
+
23
+ 0
24
+ end
25
+
26
+ end
27
+ end
@@ -46,7 +46,6 @@ module RHC::Commands
46
46
  say "Connected to #{openshift_server}"
47
47
 
48
48
  if openshift_online_server?
49
- #status = decode_json(get("#{openshift_url}/app/status/status.json").body)
50
49
  status = rest_client.request(:method => :get, :url => "#{openshift_url}/app/status/status.json", :lazy_auth => true){ |res| decode_json(res.content) }
51
50
  open = status['open']
52
51
 
@@ -55,9 +54,9 @@ module RHC::Commands
55
54
  open.each do |i|
56
55
  i = i['issue']
57
56
  say color("%-3s %s" % ["##{i['id']}", i['title']], :bold)
58
- items = i['updates'].map{ |u| [u['description'], date(u['created_at'])] }
59
- items.unshift ['Opened', date(i['created_at'])]
60
- table(items, :align => [nil,:right], :join => ' ').each{ |s| say " #{s}" }
57
+ items = i['updates'].map{ |u| [date(u['created_at']), u['description']] }
58
+ items.unshift [date(i['created_at']), 'Opened']
59
+ say table(items, :align => [nil,:left], :join => ' ')
61
60
  end
62
61
  say "\n"
63
62
  warn pluralize(open.length, "open issue")
@@ -76,7 +75,7 @@ module RHC::Commands
76
75
  When adding a new server users can optionally provide a 'nickname'
77
76
  that will allow to easily switch between servers.
78
77
  DESC
79
- syntax "<hostname> [<nickname>] [--rhlogin LOGIN] [--[no-]use-authorization-tokens] [--[no-]insecure]"
78
+ syntax "<hostname> [<nickname>] [--rhlogin LOGIN] [--[no-]use-authorization-tokens] [--[no-]insecure] [--use] [--skip-wizard] [--timeout SECONDS] [--ssl-ca-file FILE] [--ssl-client-cert-file FILE] [--ssl-version VERSION]"
80
79
  argument :hostname, "Hostname of the server you are adding", ["--server HOSTNAME"]
81
80
  argument :nickname, "Optionally provide a nickname to the server you are adding (e.g. 'development', 'production', 'online')", ["--nickname NICKNAME"], :optional => true
82
81
  option ["-l", "--rhlogin LOGIN"], "Change the default OpenShift login used on this server"
@@ -84,10 +83,14 @@ module RHC::Commands
84
83
  option ["--[no-]insecure"], "If true, certificate errors will be ignored"
85
84
  option ["--use"], "If provided, the server being added will be set as default (same as 'rhc server use')"
86
85
  option ["--skip-wizard"], "If provided, the wizard will be skipped and a session token will not be estabilished"
86
+ option ["--timeout SECONDS"], "The default timeout for operations on this server", :type => Integer
87
+ option ["--ssl-ca-file FILE"], "An SSL certificate CA file (may contain multiple certs) to be used on this server", :type => CertificateFile, :optional => true
88
+ option ["--ssl-client-cert-file FILE"], "An SSL x509 client certificate file to be used on this server", :type => CertificateFile, :optional => true
89
+ option ["--ssl-version VERSION"], "The version of SSL to use to be used on this server", :type => SSLVersion, :optional => true
87
90
  def add(hostname, nickname)
88
91
  raise ArgumentError, "The --use and --skip-wizard options cannot be used together." if options.use && options.skip_wizard
89
92
 
90
- attrs = [:login, :use_authorization_tokens, :insecure, :timeout, :ssl_version, :ssl_client_cert_file, :ssl_ca_file]
93
+ attrs = [:login, :use_authorization_tokens, :insecure, :timeout, :ssl_version, :ssl_client_cert_file, :ssl_client_key_file, :ssl_ca_file]
91
94
 
92
95
  server = server_configs.add(hostname,
93
96
  attrs.inject({:nickname => nickname}){ |h, (k, v)| h[k] = options[k == :login ? :rhlogin : k]; h })
@@ -132,7 +135,7 @@ module RHC::Commands
132
135
  def use(server)
133
136
  server = server_configs.find(server)
134
137
 
135
- attrs = [:login, :use_authorization_tokens, :insecure, :timeout, :ssl_version, :ssl_client_cert_file, :ssl_ca_file]
138
+ attrs = [:login, :use_authorization_tokens, :insecure, :timeout, :ssl_version, :ssl_client_cert_file, :ssl_client_key_file, :ssl_ca_file]
136
139
 
137
140
  if wizard_to_server(server.hostname, true, attrs.inject({}){ |h, (k, v)| h[k] = server.send(k); h })
138
141
  paragraph { success "Now using '#{server.hostname}'" }
@@ -162,7 +165,7 @@ module RHC::Commands
162
165
  end
163
166
 
164
167
  summary "Update server attributes"
165
- syntax "<server> [--hostname HOSTNAME] [--nickname NICKNAME] [--rhlogin LOGIN] [--[no-]use-authorization-tokens] [--[no-]insecure]"
168
+ syntax "<server> [--hostname HOSTNAME] [--nickname NICKNAME] [--rhlogin LOGIN] [--[no-]use-authorization-tokens] [--[no-]insecure] [--use] [--skip-wizard] [--timeout SECONDS] [--ssl-ca-file FILE] [--ssl-client-cert-file FILE] [--ssl-version VERSION]"
166
169
  argument :server, "Server hostname or nickname to be configured", ["--server SERVER"]
167
170
  option ["--hostname HOSTNAME"], "Change the hostname of this server"
168
171
  option ["--nickname NICKNAME"], "Change the nickname of this server"
@@ -171,12 +174,16 @@ module RHC::Commands
171
174
  option ["--[no-]insecure"], "If true, certificate errors will be ignored"
172
175
  option ["--use"], "If provided, the server being configured will be set as default (same as 'rhc server use')"
173
176
  option ["--skip-wizard"], "If provided, the wizard will be skipped and a session token will not be estabilished"
177
+ option ["--timeout SECONDS"], "The default timeout for operations on this server", :type => Integer
178
+ option ["--ssl-ca-file FILE"], "An SSL certificate CA file (may contain multiple certs) to be used on this server", :type => CertificateFile, :optional => true
179
+ option ["--ssl-client-cert-file FILE"], "An SSL x509 client certificate file to be used on this server", :type => CertificateFile, :optional => true
180
+ option ["--ssl-version VERSION"], "The version of SSL to use to be used on this server", :type => SSLVersion, :optional => true
174
181
  def configure(server)
175
182
  raise ArgumentError, "The --use and --skip-wizard options cannot be used together." if options.use && options.skip_wizard
176
183
 
177
184
  server = server_configs.find(server)
178
185
 
179
- attrs = [:hostname, :nickname, :login, :use_authorization_tokens, :insecure, :timeout, :ssl_version, :ssl_client_cert_file, :ssl_ca_file].inject({}){ |h, (k, v)| v = options[k == :login ? :rhlogin : k]; h[k] = (v.nil? ? server.send(k) : v); h }
186
+ attrs = [:hostname, :nickname, :login, :use_authorization_tokens, :insecure, :timeout, :ssl_version, :ssl_client_cert_file, :ssl_client_key_file, :ssl_ca_file].inject({}){ |h, (k, v)| v = options[k == :login ? :rhlogin : k]; h[k] = (v.nil? ? server.send(k) : v); h }
180
187
 
181
188
  raise RHC::ServerNicknameExistsException.new(options.nickname) if options.nickname &&
182
189
  server_configs.nickname_exists?(options.nickname) &&
@@ -213,10 +220,12 @@ module RHC::Commands
213
220
  options['server'] = hostname
214
221
  options['rhlogin'] = args[:login] if args[:login]
215
222
  options['use_authorization_tokens'] = args[:use_authorization_tokens] unless args[:use_authorization_tokens].nil?
223
+ options['create_token'] = args[:use_authorization_tokens] unless args[:use_authorization_tokens].nil?
216
224
  options['insecure'] = args[:insecure] unless args[:insecure].nil?
217
- options['timeout'] = args[:timeout] unless args[:timeout].nil?
225
+ options['timeout'] = args[:timeout]
218
226
  options['ssl_version'] = args[:ssl_version]
219
227
  options['ssl_client_cert_file'] = args[:ssl_client_cert_file]
228
+ options['ssl_client_key_file'] = args[:ssl_client_key_file]
220
229
  options['ssl_ca_file'] = args[:ssl_ca_file]
221
230
  RHC::ServerWizard.new(config, options, server_configs, set_default).run
222
231
  end
@@ -22,6 +22,7 @@ module RHC::Commands
22
22
 
23
23
  summary 'Display all the SSH keys for your account'
24
24
  syntax ''
25
+ alias_action :"sshkeys", :root_command => true
25
26
  def list
26
27
  keys = rest_client.sshkeys.each{ |key| paragraph{ display_key(key) } }
27
28
 
@@ -61,6 +61,7 @@ module RHC
61
61
  :insecure => [nil, :boolean, "If true, certificate errors will be ignored.\nWARNING: This may allow others to eavesdrop on your communication with OpenShift."],
62
62
  :ssl_version => [nil, nil, 'The SSL protocol version to use when connecting to this server'],
63
63
  :ssl_client_cert_file => [nil, :path_to_file, 'A client certificate file for use with your server'],
64
+ :ssl_client_key_file => [nil, :path_to_file, 'The corresponding key for the client certificate'],
64
65
  :ssl_ca_file => [nil, :path_to_file, 'A file containing CA one or more certificates'],
65
66
  }
66
67
 
@@ -83,17 +83,7 @@ module RHC
83
83
  end
84
84
 
85
85
  def find_membership_container(opts={})
86
- domain, app =
87
- if options.target.present?
88
- options.target.split(/\//)
89
- elsif options.namespace || options.app
90
- if options.app =~ /\//
91
- options.app.split(/\//)
92
- else
93
- [options.namespace || namespace_context, options.app]
94
- end
95
- end
96
-
86
+ domain, app = discover_domain_and_app
97
87
  if options.team_id.present?
98
88
  rest_client.find_team_by_id(options.team_id)
99
89
  elsif options.team_name.present?
@@ -161,5 +151,17 @@ module RHC
161
151
 
162
152
  domain.name
163
153
  end
154
+
155
+ def discover_domain_and_app
156
+ if options.target.present?
157
+ options.target.split(/\//)
158
+ elsif options.namespace || options.app
159
+ if options.app =~ /\//
160
+ options.app.split(/\//)
161
+ else
162
+ [options.namespace || namespace_context, options.app]
163
+ end
164
+ end
165
+ end
164
166
  end
165
167
  end
@@ -109,6 +109,18 @@ module RHC
109
109
  end
110
110
  end
111
111
 
112
+ class RegionsAndZonesNotSupportedException < Exception
113
+ def initialize(message="Server does not support regions and zones")
114
+ super message, 168
115
+ end
116
+ end
117
+
118
+ class NoRegionConfiguredException < Exception
119
+ def initialize(message="Server doesn't have any regions or zones configured")
120
+ super message, 169
121
+ end
122
+ end
123
+
112
124
  class GitPermissionDenied < GitException; end
113
125
  class GitDirectoryExists < GitException; end
114
126
 
@@ -117,7 +117,7 @@ module RHC
117
117
  global_option '--raw', "Do not format the output from the requested operations.", :hide => true
118
118
  global_option '--always-prefix', "Include the gear prefix on all output from the server.", :hide => true
119
119
 
120
- OptionParser.accept(SSLVersion = Class.new){ |s| OpenSSL::SSL::SSLContext::METHODS.find{ |m| m.to_s.downcase == s.downcase } or raise OptionParser::InvalidOption.new(nil, "The provided SSL version '#{s}' is not valid. Supported values: #{OpenSSL::SSL::SSLContext::METHODS.map(&:to_s).map(&:downcase).join(', ')}") }
120
+ OptionParser.accept(SSLVersion = Class.new){ |s| parse_ssl_version(s) }
121
121
  global_option '--ssl-version VERSION', SSLVersion, "The version of SSL to use", :hide => true do |value|
122
122
  raise RHC::Exception, "You are using an older version of the httpclient gem which prevents the use of --ssl-version. Please run 'gem update httpclient' to install a newer version (2.2.6 or newer)." unless HTTPClient::SSLConfig.method_defined? :ssl_version
123
123
  end
@@ -127,6 +127,9 @@ module RHC
127
127
  global_option '--ssl-client-cert-file FILE', "An SSL x509 client certificate file", :hide => true do |value|
128
128
  debug certificate_file(value)
129
129
  end
130
+ global_option '--ssl-client-key-file FILE', "An RSA client certificate key", :hide => true do |value|
131
+ debug certificate_key(value)
132
+ end
130
133
 
131
134
  global_option('--timeout SECONDS', Integer, 'The timeout for operations') do |value|
132
135
  raise RHC::Exception, "Timeout must be a positive integer" unless value > 0
@@ -150,6 +153,8 @@ module RHC
150
153
  raise OptionParser::InvalidOption.new(nil, "The provided role '#{s}' is not valid. Supported values: #{ROLES.keys.join(', ')}")
151
154
  end
152
155
 
156
+ OptionParser.accept(CertificateFile = Class.new) {|s| certificate_file(s); s}
157
+
153
158
  def role_name(s)
154
159
  ROLES[s.downcase]
155
160
  end
@@ -196,7 +201,6 @@ module RHC
196
201
  def ssl_options
197
202
  {
198
203
  :ssl_version => options.ssl_version,
199
- :client_cert => certificate_file(options.ssl_client_cert),
200
204
  :ca_file => options.ssl_ca_file && File.expand_path(options.ssl_ca_file),
201
205
  :verify_mode => options.insecure ? OpenSSL::SSL::VERIFY_NONE : nil,
202
206
  }.delete_if{ |k,v| v.nil? }
@@ -209,6 +213,16 @@ module RHC
209
213
  raise OptionParser::InvalidOption.new(nil, "The certificate '#{file}' cannot be loaded: #{e.message} (#{e.class})")
210
214
  end
211
215
 
216
+ def certificate_key(file)
217
+ file && OpenSSL::PKey::RSA.new(IO.read(File.expand_path(file)))
218
+ rescue => e
219
+ debug e
220
+ raise OptionParser::InvalidOption.new(nil, "The key '#{file}' cannot be loaded: #{e.message} (#{e.class})")
221
+ end
222
+
223
+ def parse_ssl_version(version)
224
+ OpenSSL::SSL::SSLContext::METHODS.find{ |m| m.to_s.downcase == version.to_s.downcase } or raise OptionParser::InvalidOption.new(nil, "The provided SSL version '#{version}' is not valid. Supported values: #{OpenSSL::SSL::SSLContext::METHODS.map(&:to_s).map(&:downcase).join(', ')}") unless version.nil?
225
+ end
212
226
 
213
227
  #
214
228
  # Output helpers
@@ -281,10 +295,14 @@ module RHC
281
295
 
282
296
  # OVERRIDE: Replaces default commander behavior
283
297
  def color(item, *args)
284
- if item.is_a? Array
285
- item.map{ |i| $terminal.color(i, *args) }
286
- else
287
- $terminal.color(item, *args)
298
+ unless (options.raw rescue false)
299
+ if item.is_a? Array
300
+ item.map{ |i| $terminal.color(i, *args) }
301
+ else
302
+ $terminal.color(item, *args)
303
+ end
304
+ else
305
+ item
288
306
  end
289
307
  end
290
308
 
@@ -341,7 +359,8 @@ module RHC
341
359
  :use_authorization_tokens => 'Use Auth Tokens',
342
360
  :ssl_ca_file => 'SSL Cert CA File',
343
361
  :ssl_version => 'SSL Version',
344
- :ssl_client_cert_file => 'SSL x509 Client Cert File'
362
+ :ssl_client_cert_file => 'SSL x509 Client Cert File',
363
+ :zones => 'Available Zones'
345
364
  })
346
365
 
347
366
  headings[value]
@@ -30,6 +30,7 @@ module RHC
30
30
  :creation_time,
31
31
  (:id if ids),
32
32
  (:allowed_gear_sizes unless domain.allowed_gear_sizes.nil?),
33
+ (:suffix unless domain.suffix.nil? || openshift_online_server?),
33
34
  :compact_members
34
35
  ),
35
36
  :delete => true
@@ -96,6 +97,26 @@ module RHC
96
97
  end
97
98
  end
98
99
 
100
+ def display_region(region)
101
+ paragraph do
102
+ header ["Region '#{region.name}'", "(uuid: #{region.uuid})", ("(default)" if region.default?)], {:color => (:green if region.default?)} do
103
+ section(:bottom => 1) do
104
+ say format_table \
105
+ nil,
106
+ get_properties(
107
+ region,
108
+ :description,
109
+ :zones
110
+ ),
111
+ {
112
+ :delete => true,
113
+ :color => (:green if region.default?)
114
+ }
115
+ end
116
+ end
117
+ end
118
+ end
119
+
99
120
  def format_cart_header(cart)
100
121
  [
101
122
  cart.name,
@@ -18,6 +18,7 @@ module RHC
18
18
  autoload :GearGroup, 'rhc/rest/gear_group'
19
19
  autoload :Key, 'rhc/rest/key'
20
20
  autoload :Membership, 'rhc/rest/membership'
21
+ autoload :Region, 'rhc/rest/region'
21
22
  autoload :Team, 'rhc/rest/team'
22
23
  autoload :User, 'rhc/rest/user'
23
24
 
@@ -10,6 +10,7 @@ module RHC
10
10
  :scalable, :health_check_path, :embedded, :gear_count,
11
11
  :ssh_url, :building_app, :cartridges, :initial_git_url,
12
12
  :auto_deploy, :deployment_branch, :deployment_type, :keep_deployments, :deployments
13
+ :region
13
14
  alias_method :domain_name, :domain_id
14
15
 
15
16
  # Query helper to say consistent with cartridge
@@ -100,6 +101,10 @@ module RHC
100
101
  gear['ssh_url'] or raise NoPerGearOperations
101
102
  end
102
103
 
104
+ def region
105
+ gears.first['region'] rescue nil
106
+ end
107
+
103
108
  def tidy
104
109
  debug "Starting application #{name}"
105
110
  rest_method 'TIDY', :event => "tidy"
@@ -59,6 +59,15 @@ module RHC
59
59
  @cartridges ||= api.rest_method("LIST_CARTRIDGES", nil, :lazy_auth => true)
60
60
  end
61
61
 
62
+ def regions
63
+ debug "Getting all regions and zones available"
64
+ if supports_regions_and_zones?
65
+ @regions ||= api.rest_method("LIST_REGIONS")
66
+ else
67
+ raise RHC::RegionsAndZonesNotSupportedException
68
+ end
69
+ end
70
+
62
71
  def user
63
72
  debug "Getting user info"
64
73
  @user ||= api.rest_method "GET_USER"
@@ -156,6 +165,12 @@ module RHC
156
165
  request(:url => link_show_application_by_domain_name(domain, application, "gear_groups"), :method => "GET", :payload => options)
157
166
  end
158
167
 
168
+ def find_application_gear_groups_endpoints(domain, application, options={})
169
+ precheck_domain_id(domain)
170
+ precheck_application_id(application)
171
+ request(:url => link_show_application_by_domain_name(domain, application, "gear_groups"), :method => "GET", :payload => options.merge(:include => 'endpoints'))
172
+ end
173
+
159
174
  def find_application_aliases(domain, application, options={})
160
175
  precheck_domain_id(domain)
161
176
  precheck_application_id(application)
@@ -266,6 +281,10 @@ module RHC
266
281
  api.supports? 'ADD_AUTHORIZATION'
267
282
  end
268
283
 
284
+ def supports_regions_and_zones?
285
+ api.supports? :LIST_REGIONS
286
+ end
287
+
269
288
  def authorizations
270
289
  raise AuthorizationsNotSupported unless supports_sessions?
271
290
  api.rest_method 'LIST_AUTHORIZATIONS'
@@ -640,6 +659,8 @@ module RHC
640
659
  RHC::Rest::Membership::Member.new(data, self)
641
660
  when 'members'
642
661
  data.map{ |json| RHC::Rest::Membership::Member.new(json, self) }
662
+ when 'regions'
663
+ data.map{ |json| Region.new(json, self) }
643
664
  else
644
665
  data
645
666
  end
@@ -6,7 +6,8 @@ module RHC
6
6
  define_attr :id, # Domain name for API version < 1.6, domain unique id otherwise
7
7
  :name, # Available from API version 1.6 onwards
8
8
  :allowed_gear_sizes, # Available from API version 1.3 onwards on compatible servers
9
- :creation_time # Available from API version 1.3 onwards on compatible servers
9
+ :creation_time, # Available from API version 1.3 onwards on compatible servers
10
+ :suffix
10
11
 
11
12
  def id
12
13
  id_and_name.first
@@ -143,6 +143,8 @@ module RHC::Rest
143
143
 
144
144
  def owner
145
145
  members.find(&:owner?)
146
+ rescue RHC::MembersNotSupported
147
+ nil
146
148
  end
147
149
  end
148
150
  end