rhc 1.15.6 → 1.16.9

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.
@@ -120,6 +120,18 @@ module RHC
120
120
  end
121
121
  end
122
122
 
123
+ class DeploymentNotFoundException < Exception
124
+ def initialize(message="Deployment not found")
125
+ super message, 131
126
+ end
127
+ end
128
+
129
+ class DeploymentsNotSupportedException < Exception
130
+ def initialize(message="The server does not support deployments")
131
+ super message, 132
132
+ end
133
+ end
134
+
123
135
  class MissingScalingValueException < Exception
124
136
  def initialize(message="Must provide either a min or max value for scaling")
125
137
  super message
@@ -135,12 +147,24 @@ module RHC
135
147
  class ConnectionFailed < Exception
136
148
  end
137
149
 
150
+ class SSHAuthenticationFailed < Exception
151
+ def initialize(host, user)
152
+ super "Authentication to server #{host} with user #{user} failed"
153
+ end
154
+ end
155
+
138
156
  class SSHConnectionRefused < ConnectionFailed
139
157
  def initialize(host, user)
140
158
  super "The server #{host} refused a connection with user #{user}. The application may be unavailable.", 1
141
159
  end
142
160
  end
143
161
 
162
+ class SSHCommandFailed < Exception
163
+ def initialize(exit_status, message=nil)
164
+ super message || "SSH command finished with exit status = #{exit_status}", 133
165
+ end
166
+ end
167
+
144
168
  class AdditionalStorageArgumentsException < Exception
145
169
  def initialize(message="Only one storage action can be performed at a time.")
146
170
  super message, 1
@@ -1,4 +1,4 @@
1
- require 'open4'
1
+ require 'open4'
2
2
  require 'fileutils'
3
3
 
4
4
  module RHC
@@ -330,24 +330,27 @@ module RHC
330
330
  headings.merge!({
331
331
  :creation_time => "Created",
332
332
  :expires_in_seconds => "Expires In",
333
- :uuid => "ID",
334
- :id => 'ID',
335
- :current_scale => "Current",
336
- :scales_from => "Minimum",
337
- :scales_to => "Maximum",
338
- :gear_sizes => "Allowed Gear Sizes",
339
- :consumed_gears => "Gears Used",
340
- :max_gears => "Gears Allowed",
341
- :max_domains => "Domains Allowed",
333
+ :uuid => "ID",
334
+ :id => 'ID',
335
+ :current_scale => "Current",
336
+ :scales_from => "Minimum",
337
+ :scales_to => "Maximum",
338
+ :gear_sizes => "Allowed Gear Sizes",
339
+ :consumed_gears => "Gears Used",
340
+ :max_gears => "Gears Allowed",
341
+ :max_domains => "Domains Allowed",
342
342
  :compact_members => "Members",
343
- :gear_info => "Gears",
344
- :plan_id => "Plan",
345
- :url => "URL",
346
- :ssh_string => "SSH",
343
+ :gear_info => "Gears",
344
+ :plan_id => "Plan",
345
+ :url => "URL",
346
+ :ssh_string => "SSH",
347
347
  :connection_info => "Connection URL",
348
- :gear_profile => "Gear Size",
348
+ :gear_profile => "Gear Size",
349
349
  :visible_to_ssh? => 'Available',
350
350
  :downloaded_cartridge_url => 'From',
351
+ :auto_deploy => 'Deployment',
352
+ :sha1 => 'SHA1',
353
+ :ref => 'Git Reference'
351
354
  })
352
355
 
353
356
  headings[value]
@@ -53,13 +53,13 @@ class HighLineExtension < HighLine
53
53
  @last_line_open = false
54
54
  @output.puts
55
55
  end
56
- statement = statement.join("#{indentation}\n")
56
+ statement = statement.join("#{indentation}\n")
57
57
  end
58
58
  statement = send(:page_print, statement) unless @page_at.nil?
59
59
 
60
60
  @output.print(indentation) unless @last_line_open
61
61
 
62
- @last_line_open =
62
+ @last_line_open =
63
63
  if statement[-1, 1] == " " or statement[-1, 1] == "\t"
64
64
  @output.print(statement)
65
65
  @output.flush
@@ -147,7 +147,7 @@ class HighLineExtension < HighLine
147
147
  @multi_indent = multi
148
148
  @indent_level -= increase
149
149
  end
150
- end
150
+ end
151
151
  #:nocov:
152
152
 
153
153
  ##
@@ -170,7 +170,7 @@ class HighLineExtension < HighLine
170
170
  #
171
171
  # > Hello
172
172
  # >
173
- # > World
173
+ # > World
174
174
  #
175
175
  # with only one newline between the two. Biggest margin wins.
176
176
  #
@@ -298,7 +298,7 @@ end
298
298
 
299
299
  #
300
300
  # Represent a columnar layout of items with wrapping and flexible layout.
301
- #
301
+ #
302
302
  class HighLine::Table
303
303
  include RowBased
304
304
 
@@ -310,7 +310,7 @@ class HighLine::Table
310
310
  opts[:color]
311
311
  end
312
312
 
313
- protected
313
+ protected
314
314
  attr_reader :items
315
315
 
316
316
  def opts
@@ -333,7 +333,7 @@ class HighLine::Table
333
333
  def source_rows
334
334
  @source_rows ||= begin
335
335
  (@mapper ? (items.map &@mapper) : items).each do |row|
336
- row.map! do |col|
336
+ row.map! do |col|
337
337
  case col
338
338
  when Array then col.join("\n")
339
339
  when String then col
@@ -388,17 +388,17 @@ class HighLine::Table
388
388
  end
389
389
  end
390
390
 
391
- remaining = column_widths.inject(0) do |sum, w|
391
+ remaining = column_widths.inject(0) do |sum, w|
392
392
  if w.set == 0
393
393
  sum += w.max
394
- available -= w.min
394
+ available -= w.min
395
395
  end
396
396
  sum
397
397
  end
398
398
  fair = available.to_f / remaining.to_f
399
399
 
400
400
  column_widths.
401
- each do |w|
401
+ each do |w|
402
402
  if w.set == 0
403
403
  alloc = (w.max * fair).to_i
404
404
  overflow = alloc + w.min - w.max
@@ -424,7 +424,7 @@ class HighLine::Table
424
424
  @widths ||= begin
425
425
  case w = opts[:width]
426
426
  when Array
427
- column_widths.zip(w[1..-1]).each do |width, col|
427
+ column_widths.zip(w[1..-1]).each do |width, col|
428
428
  width.set = col || 0
429
429
  width.max = width.set if width.set > width.max
430
430
  end
@@ -450,15 +450,15 @@ class HighLine::Table
450
450
 
451
451
  def rows
452
452
  @rows ||= begin
453
- body = (header_rows + source_rows).inject([]) do |a,row|
453
+ body = (header_rows + source_rows).inject([]) do |a,row|
454
454
  row = row.zip(widths).map{ |column,w| w && w > 0 ? column.textwrap_ansi(w, false) : [column] }
455
455
  (row.map(&:length).max || 0).times do |i|
456
456
  s = []
457
457
  row.each_with_index do |lines, j|
458
458
  cell = lines[i]
459
459
  l = cell ? cell.strip_ansi.length : 0
460
- s <<
461
- if align[j] == :right
460
+ s <<
461
+ if align[j] == :right
462
462
  "#{' '*(widths[j]-l) if l < widths[j]}#{cell}"
463
463
  else
464
464
  "#{cell}#{' '*(widths[j]-l) if l < widths[j]}"
@@ -468,7 +468,7 @@ class HighLine::Table
468
468
  end
469
469
  a
470
470
  end
471
-
471
+
472
472
  body = heading.to_a.concat(body) if heading
473
473
  body
474
474
  end
@@ -26,22 +26,21 @@ module RHC
26
26
  #---------------------------
27
27
  # Application information
28
28
  #---------------------------
29
- def display_app(app,cartridges = nil)
29
+ def display_app(app, cartridges=nil, properties=nil)
30
30
  paragraph do
31
31
  header [app.name, "@ #{app.app_url}", "(uuid: #{app.uuid})"] do
32
32
  section(:bottom => 1) do
33
33
  say format_table \
34
34
  nil,
35
- get_properties(
36
- app,
37
- :domain,
35
+ get_properties(app, properties ||
36
+ [:domain,
38
37
  :creation_time,
39
38
  :gear_info,
40
39
  :git_url,
41
40
  :initial_git_url,
42
41
  :ssh_string,
43
- :aliases
44
- ),
42
+ :auto_deploy,
43
+ :aliases]),
45
44
  :delete => true
46
45
  end
47
46
  cartridges.each{ |c| section(:bottom => 1){ display_cart(c) } } if cartridges
@@ -49,6 +48,10 @@ module RHC
49
48
  end
50
49
  end
51
50
 
51
+ def display_app_configurations(rest_app)
52
+ display_app(rest_app, nil, [:auto_deploy, :keep_deployments, :deployment_type, :deployment_branch])
53
+ end
54
+
52
55
  def format_cart_header(cart)
53
56
  [
54
57
  cart.name,
@@ -94,7 +97,7 @@ module RHC
94
97
  end
95
98
 
96
99
  def display_key(key, *properties)
97
- properties = [:fingerprint, :visible_to_ssh?] if properties.empty?
100
+ properties = [:fingerprint, :principal, :visible_to_ssh?] if properties.empty?
98
101
  say format_table(
99
102
  properties.include?(:name) ? nil : format_key_header(key),
100
103
  get_properties(key, *properties),
@@ -153,6 +156,41 @@ module RHC
153
156
  end
154
157
  end
155
158
 
159
+ def display_deployment(item, highlight_active=true)
160
+ deployment = item[:deployment]
161
+ active = item[:active]
162
+ paragraph do
163
+ say format_table(
164
+ "Deployment ID #{deployment.id} #{active ? '(active)' : '(inactive)'}",
165
+ get_properties(deployment, :ref, :sha1, :created_at, :artifact_url, :hot_deploy, :force_clean_build, :activations),
166
+ {
167
+ :delete => true,
168
+ :color => (:green if active && highlight_active)
169
+ }
170
+ )
171
+ end
172
+ end
173
+
174
+ def display_deployment_list(deployment_activations, highlight_active=true)
175
+ if deployment_activations.present?
176
+ paragraph do
177
+ deployment_activations.each do |item|
178
+ activation = item[:activation]
179
+ deployment = item[:deployment]
180
+ rollback = item[:rollback]
181
+ rollback_to = item[:rollback_to]
182
+ rolled_back = item[:rolled_back]
183
+ active = item[:active]
184
+ say color(
185
+ date(activation.created_at.to_s) +
186
+ ', deployment ' + deployment.id +
187
+ (rollback ? " (rollback to #{date(rollback_to.to_s)}#{rolled_back ? ', rolled back' : ''})" : rolled_back ? ' (rolled back)' : ''),
188
+ active ? :green : rolled_back ? :yellow : nil)
189
+ end
190
+ end
191
+ end
192
+ end
193
+
156
194
  private
157
195
  def format_table(heading,values,opts = {})
158
196
  values = values.to_a if values.is_a? Hash
@@ -171,7 +209,7 @@ module RHC
171
209
 
172
210
  # This uses the array of properties to retrieve them from an object
173
211
  def get_properties(object,*properties)
174
- properties.map do |prop|
212
+ properties.flatten.map do |prop|
175
213
  # Either send the property to the object or yield it
176
214
  next if prop.nil?
177
215
  value = begin
@@ -195,7 +233,7 @@ module RHC
195
233
  end
196
234
  when :visible_to_ssh?
197
235
  value || nil
198
- when :creation_time
236
+ when :creation_time, :created_at
199
237
  date(value)
200
238
  when :scales_from,:scales_to
201
239
  (value == -1 ? "available" : value)
@@ -207,6 +245,10 @@ module RHC
207
245
  value.kind_of?(Array) ? value.join(', ') : value
208
246
  when :expires_in_seconds
209
247
  distance_of_time_in_words(value)
248
+ when :activations
249
+ value.collect{|item| date(item.created_at.to_s)}.join("\n")
250
+ when :auto_deploy
251
+ value ? 'auto (on git push)' : "manual (use 'rhc deploy')"
210
252
  else
211
253
  case value
212
254
  when Array then value.empty? ? '<none>' : value.join(', ')
@@ -12,6 +12,7 @@ module RHC
12
12
  autoload :Authorization, 'rhc/rest/authorization'
13
13
  autoload :Cartridge, 'rhc/rest/cartridge'
14
14
  autoload :Client, 'rhc/rest/client'
15
+ autoload :Deployment, 'rhc/rest/deployment'
15
16
  autoload :Domain, 'rhc/rest/domain'
16
17
  autoload :EnvironmentVariable, 'rhc/rest/environment_variable'
17
18
  autoload :GearGroup, 'rhc/rest/gear_group'
@@ -0,0 +1,11 @@
1
+ module RHC
2
+ module Rest
3
+ class Activation < Base
4
+ define_attr :created_at
5
+
6
+ def <=>(other)
7
+ other.created_at <=> created_at
8
+ end
9
+ end
10
+ end
11
+ end
@@ -8,7 +8,8 @@ module RHC
8
8
  define_attr :domain_id, :name, :creation_time, :uuid,
9
9
  :git_url, :app_url, :gear_profile, :framework,
10
10
  :scalable, :health_check_path, :embedded, :gear_count,
11
- :ssh_url, :building_app, :cartridges, :initial_git_url
11
+ :ssh_url, :building_app, :cartridges, :initial_git_url,
12
+ :auto_deploy, :deployment_branch, :deployment_type, :keep_deployments, :deployments
12
13
  alias_method :domain_name, :domain_id
13
14
 
14
15
  # Query helper to say consistent with cartridge
@@ -177,6 +178,57 @@ module RHC
177
178
  has_param?('ADD_CARTRIDGE', 'environment_variables')
178
179
  end
179
180
 
181
+ def deployments
182
+ debug "Listing deployments for application #{name}"
183
+ raise RHC::DeploymentsNotSupportedException if !supports? "LIST_DEPLOYMENTS"
184
+ rest_method("LIST_DEPLOYMENTS").sort
185
+ end
186
+
187
+ def deployment_activations
188
+ items = []
189
+
190
+ # building an array of activations with their deployments
191
+ deployments.each do |deployment|
192
+ deployment.activations.each do |activation|
193
+ items << {:activation => activation, :deployment => deployment}
194
+ end
195
+ end
196
+
197
+ items.sort! {|a,b| a[:activation].created_at <=> b[:activation].created_at }
198
+
199
+ first_activation = {}
200
+
201
+ items.each do |item|
202
+ deployment = item[:deployment]
203
+ activation = item[:activation]
204
+
205
+ # set the currently active (last activation by date)
206
+ item[:active] = item == items.last
207
+
208
+ # mark rollbacks (activations whose deployment had previous activations)
209
+ if rollback_to = first_activation[deployment.id]
210
+ item[:rollback] = true
211
+ item[:rollback_to] = rollback_to
212
+ # mark rolled back (all in between a rollback and its original deployment)
213
+ items.each {|i| i[:rolled_back] = true if i[:activation].created_at > rollback_to && i[:activation].created_at < activation.created_at }
214
+ else
215
+ first_activation[deployment.id] = activation.created_at
216
+ end
217
+
218
+ end
219
+
220
+ items
221
+ end
222
+
223
+ def configure(options={})
224
+ debug "Running update for #{name} with options #{options.inspect}"
225
+ if supports? "UPDATE"
226
+ rest_method "UPDATE", options
227
+ else
228
+ raise RHC::DeploymentsNotSupportedException
229
+ end
230
+ end
231
+
180
232
  def add_alias(app_alias)
181
233
  debug "Running add_alias for #{name}"
182
234
  rest_method "ADD_ALIAS", :event => "add-alias", :alias => app_alias
@@ -518,24 +518,33 @@ module RHC
518
518
  data.map{ |json| Alias.new(json, self) }
519
519
  when 'environment-variables'
520
520
  data.map{ |json| EnvironmentVariable.new(json, self) }
521
+ when 'deployments'
522
+ data.map{ |json| Deployment.new(json, self) }
521
523
  else
522
524
  data
523
525
  end
524
526
  end
525
527
 
526
528
  def parse_messages(result, data)
527
- warnings, messages = Array(result['messages']).inject([[],[]]) do |a, m|
529
+ raw = (result || {})['messages'] || []
530
+ raw.delete_if do |m|
531
+ m.delete_if{ |k,v| k.nil? || v.blank? } if m.is_a? Hash
532
+ m.blank?
533
+ end
534
+ warnings, messages, raw = Array(raw).inject([[],[],[]]) do |a, m|
528
535
  severity, field, text = m.values_at('severity', 'field', 'text')
529
- text.gsub!(/\A\n+/m, "")
530
- text.rstrip!
536
+ text = (text || "").gsub(/\A\n+/m, "").rstrip
531
537
  case severity
532
538
  when 'warning'
533
539
  a[0] << text
534
540
  when 'debug'
541
+ a[2] << m
535
542
  a[1] << text if debug?
536
543
  when 'info'
544
+ a[2] << m
537
545
  a[1] << text if debug? || field == 'result'
538
546
  else
547
+ a[2] << m
539
548
  a[1] << text
540
549
  end
541
550
  a
@@ -548,17 +557,16 @@ module RHC
548
557
  end
549
558
  elsif data.is_a?(Hash)
550
559
  data['messages'] = messages
551
- data['warnings'] = warnings
560
+ data['warnings'] = warnings
552
561
  end
553
562
 
554
563
  warnings.each do |warning|
555
- # Prevent repeated warnings during the same client session
556
- if !defined?(@warning_map) || !@warning_map.include?(warning)
557
- @warning_map ||= Set.new
564
+ unless (@warning_map ||= Set.new).include?(warning)
558
565
  @warning_map << warning
559
566
  warn warning
560
567
  end
561
568
  end if respond_to? :warn
569
+ raw
562
570
  end
563
571
 
564
572
  def raise_generic_error(url, client)
@@ -576,11 +584,7 @@ module RHC
576
584
  parse_error = nil
577
585
  begin
578
586
  result = RHC::Json.decode(response.content)
579
- messages = Array(result['messages'])
580
- messages.delete_if do |m|
581
- m.delete_if{ |k,v| k.nil? || v.blank? } if m.is_a? Hash
582
- m.blank?
583
- end
587
+ messages = parse_messages(result, {})
584
588
  rescue => e
585
589
  debug "Response did not include a message from server: #{e.message}"
586
590
  end