aws-sdk-core 2.0.18 → 2.0.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/apis/CloudFormation.resources.json +55 -20
  3. data/apis/CloudFront.waiters.json +35 -17
  4. data/apis/DynamoDB.waiters.json +27 -17
  5. data/apis/EC2.api.json +5 -0
  6. data/apis/EC2.resources.json +449 -319
  7. data/apis/EC2.waiters.json +389 -139
  8. data/apis/{EMR.waiters2.json → EMR.waiters.json} +0 -0
  9. data/apis/ElasticTranscoder.api.json +34 -3
  10. data/apis/ElasticTranscoder.waiters.json +22 -8
  11. data/apis/Glacier.resources.json +215 -117
  12. data/apis/Glacier.waiters.json +31 -15
  13. data/apis/IAM.resources.json +380 -169
  14. data/apis/{Kinesis.waiters2.json → Kinesis.waiters.json} +0 -0
  15. data/apis/OpsWorks.resources.json +51 -17
  16. data/apis/RDS.waiters.json +87 -26
  17. data/apis/Redshift.waiters.json +54 -29
  18. data/apis/S3.resources.json +404 -143
  19. data/apis/S3.waiters.json +47 -16
  20. data/apis/SES.waiters.json +11 -7
  21. data/apis/SNS.resources.json +67 -33
  22. data/apis/SQS.resources.json +57 -30
  23. data/lib/aws-sdk-core.rb +1 -0
  24. data/lib/aws-sdk-core/api/documenter.rb +4 -3
  25. data/lib/aws-sdk-core/api/service_customizations.rb +0 -6
  26. data/lib/aws-sdk-core/client_waiters.rb +65 -50
  27. data/lib/aws-sdk-core/emr.rb +1 -0
  28. data/lib/aws-sdk-core/errors.rb +4 -0
  29. data/lib/aws-sdk-core/instance_profile_credentials.rb +1 -0
  30. data/lib/aws-sdk-core/kinesis.rb +1 -0
  31. data/lib/aws-sdk-core/paging/pager.rb +5 -1
  32. data/lib/aws-sdk-core/refreshing_credentials.rb +2 -0
  33. data/lib/aws-sdk-core/version.rb +1 -1
  34. data/lib/aws-sdk-core/waiters/errors.rb +50 -12
  35. data/lib/aws-sdk-core/waiters/poller.rb +105 -0
  36. data/lib/aws-sdk-core/waiters/provider.rb +11 -30
  37. data/lib/aws-sdk-core/waiters/waiter.rb +42 -102
  38. metadata +5 -12
  39. data/apis/CloudFront.waiters2.json +0 -47
  40. data/apis/DynamoDB.waiters2.json +0 -35
  41. data/apis/EC2.waiters2.json +0 -341
  42. data/apis/ElasticTranscoder.waiters2.json +0 -30
  43. data/apis/RDS.waiters2.json +0 -97
  44. data/apis/Redshift.waiters2.json +0 -97
  45. data/apis/S3.waiters2.json +0 -63
  46. data/apis/SES.waiters2.json +0 -18
@@ -182,6 +182,7 @@ module Aws
182
182
  end
183
183
 
184
184
  module Waiters
185
+ autoload :Poller, 'aws-sdk-core/waiters/poller'
185
186
  autoload :Errors, 'aws-sdk-core/waiters/errors'
186
187
  autoload :NullProvider, 'aws-sdk-core/waiters/null_provider'
187
188
  autoload :Provider, 'aws-sdk-core/waiters/provider'
@@ -175,15 +175,16 @@ Constructs an API client.
175
175
  m.docstring = YARD::Registry['Aws::ClientWaiters#wait_until'].docstring
176
176
 
177
177
  waiters = @client_class.waiters.waiter_names.sort.inject('') do |w,name|
178
- operation = @client_class.waiters.waiter(name).send(:operation_name)
179
- w << "<tr><td><tt>:#{name}</tt></td><td>{##{operation}}</td></tr>"
178
+ waiter = @client_class.waiters.waiter(name)
179
+ operation = waiter.poller.operation_name
180
+ w << "<tr><td><tt>:#{name}</tt></td><td>{##{operation}}</td><td>#{waiter.delay}</td><td>#{waiter.max_attempts}</td></tr>"
180
181
  end
181
182
  docstring = <<-DOCSTRING
182
183
  Returns the list of supported waiters. The following table lists the supported
183
184
  waiters and the client method they call:
184
185
  <table>
185
186
  <thead>
186
- <tr><th>Waiter Name</th><th>Client Method</th></tr>
187
+ <tr><th>Waiter Name</th><th>Client Method</th><th>Delay</th><th>Max Attempts</th></tr>
187
188
  </thead>
188
189
  <tbody>
189
190
  #{waiters}
@@ -114,12 +114,6 @@ module Aws
114
114
  # parsing of the output
115
115
  client_class.api.operation(:get_bucket_location).
116
116
  instance_variable_set("@output", nil)
117
-
118
- defs = client_class.waiters.instance_variable_get("@definitions")
119
- defs[:bucket_exists]['ignore_errors'] = ['NotFound']
120
- defs[:object_exists]['ignore_errors'] = ['NotFound']
121
- defs[:bucket_not_exists]['success_value'] = 'NotFound'
122
- defs[:object_not_exists]['success_value'] = 'NotFound'
123
117
  end
124
118
 
125
119
  customize 'sqs' do
@@ -23,76 +23,91 @@ module Aws
23
23
  end
24
24
  end
25
25
 
26
- # Waits until a particular condition is satisfied. This works by
27
- # polling a client request and checking for particular response
28
- # data or errors. Waiters each have a default duration max attempts
29
- # which are configurable. Additionally, you can register callbacks
30
- # and stop waiters by throwing `:success` or `:failure`.
31
- #
32
- # @example Basic usage
33
- # client.wait_until(:waiter_name)
34
- #
35
- # @example Configuring interval and maximum attempts
36
- # client.wait_until(:waiter_name) do |w|
37
- # w.interval = 10 # number of seconds to sleep between attempts
38
- # w.max_attempts = 6 # maximum number of polling attempts
39
- # end
26
+ # Waiters polls an API operation until a resource enters a desired
27
+ # state.
40
28
  #
41
- # @example Rescuing a failed wait
42
- # begin
43
- # client.wait_until(:waiter_name)
44
- # rescue Aws::Waiters::Errors::WaiterFailed
45
- # # gave up waiting
46
- # end
29
+ # ## Basic Usage
47
30
  #
48
- # @example Waiting with progress callbacks
49
- # client.wait_until(:waiter_name) do |w|
31
+ # Waiters will poll until they are succesful, they fail by
32
+ # entering a terminal state, or until a maximum number of attempts
33
+ # are made.
50
34
  #
51
- # # yields just before polling for change
52
- # w.before_attempt do |attempt|
53
- # # attempts - number of previous attempts made
54
- # end
35
+ # # polls in a loop, sleeping between attempts
36
+ # client.waiter_until(waiter_name, params)
37
+ #
38
+ # ## Configuration
55
39
  #
56
- # # yields before sleeping
57
- # w.before_wait do |attempt, prev_response|
58
- # # attempts - number of previous attempts made
59
- # # prev_response - the last client response received
40
+ # You can configure the maximum number of polling attempts, and the
41
+ # delay (in seconds) between each polling attempt. You configure
42
+ # waiters by passing a block to #{wait_until}:
43
+ #
44
+ # # poll for ~25 seconds
45
+ # client.wait_until(...) do |w|
46
+ # w.max_attempts = 5
47
+ # w.delay = 5
60
48
  # end
61
- # end
62
49
  #
63
- # @example Throw :success or :failure to terminate early
64
- # # wait for an hour, not for a number of requests
65
- # client.wait_until(:waiter_name) do |waiter|
66
- # one_hour = Time.now + 3600
67
- # waiter.max_attempts = nil
68
- # waiter.before_attempt do |attempt|
69
- # throw(:failure, 'waited to long') if Time.now > one_hour
50
+ # ## Callbacks
51
+ #
52
+ # You can be notified before each polling attempt and before each
53
+ # delay. If you throw `:success` or `:failure` from these callbacks,
54
+ # it will terminate the waiter.
55
+ #
56
+ # started_at = Time.now
57
+ # client.wait_until(...) do |w|
58
+ #
59
+ # # disable max attempts
60
+ # w.max_attempts = nil
61
+ #
62
+ # # poll for 1 hour, instead of a number of attempts
63
+ # before_wait do |attempts, response|
64
+ # throw :failure if Time.now - started_at > 3600
65
+ # end
66
+ #
70
67
  # end
68
+ #
69
+ # ## Handling Errors
70
+ #
71
+ # When a waiter is successful, it returns `true`. When a waiter
72
+ # fails, it raises an error. **All errors raised extend from
73
+ # {Aws::Waiters::Errors::WaiterFailed}**.
74
+ #
75
+ # begin
76
+ # client.wait_until(...)
77
+ # rescue Aws::Waiters::Errors::WaiterFailed
78
+ # # resource did not enter the desired state in time
71
79
  # end
72
80
  #
73
81
  # @param [Symbol] waiter_name The name of the waiter. See {#waiter_names}
74
82
  # for a full list of supported waiters.
83
+ #
75
84
  # @param [Hash] params Additional request parameters. See the {#waiter_names}
76
85
  # for a list of supported waiters and what request they call. The
77
86
  # called request determines the list of accepted parameters.
78
- # @return [Seahorse::Client::Response] Returns the client response from
79
- # the successful polling request. If `:success` is thrown from a callback,
80
- # then the 2nd argument to `#throw` is returned.
81
- # @yieldparam [Waiters::Waiter] waiter Yields a {Waiters::Waiter Waiter}
87
+ #
88
+ # @yieldparam [Waiters::Waiter] waiter Yields a {Waiters::Waiter Waiter}
82
89
  # object that can be configured prior to waiting.
83
- # @raise [Waiters::Errors::NoSuchWaiter] Raised when the named waiter
84
- # is not defined.
85
- # @raise [Waiters::Errors::WaiterFailed] Raised when one of the
86
- # following conditions is met:
87
90
  #
88
- # * A failure condition is detected
89
- # * The maximum number of attempts has been made without success
90
- # * `:failure` is thrown from a callback
91
+ # @raise [Errors::FailureStateError] Raised when the waiter terminates
92
+ # because the waiter has entered a state that it will not transition
93
+ # out of, preventing success.
94
+ #
95
+ # @raise [Errors::TooManyAttemptsError] Raised when the configured
96
+ # maximum number of attempts have been made, and the waiter is not
97
+ # yet successful.
98
+ #
99
+ # @raise [Errors::UnexpectedError] Raised when an error is encounted
100
+ # while polling for a resource that is not expected.
101
+ #
102
+ # @raise [Errors::NoSuchWaiterError] Raised when you request to wait
103
+ # for an unknown state.
104
+ #
105
+ # @return [Boolean] Returns `true` if the waiter was successful.
91
106
  #
92
107
  def wait_until(waiter_name, params = {}, &block)
93
108
  waiter = self.class.waiters.waiter(waiter_name)
94
109
  yield(waiter) if block_given?
95
- waiter.wait(self, params)
110
+ waiter.wait(client:self, params:params)
96
111
  end
97
112
 
98
113
  # Returns the list of supported waiters.
@@ -2,4 +2,5 @@ Aws.add_service(:EMR, {
2
2
  api: File.join(Aws::API_DIR, 'EMR.api.json'),
3
3
  docs: File.join(Aws::API_DIR, 'EMR.docs.json'),
4
4
  paginators: File.join(Aws::API_DIR, 'EMR.paginators.json'),
5
+ waiters: File.join(Aws::API_DIR, 'EMR.waiters.json'),
5
6
  })
@@ -14,10 +14,14 @@ module Aws
14
14
  # @param [Seahorse::Client::RequestContext] context
15
15
  # @param [String] message
16
16
  def initialize(context, message)
17
+ @code = self.class.code
17
18
  @context = context
18
19
  super(message)
19
20
  end
20
21
 
22
+ # @return [String]
23
+ attr_reader :code
24
+
21
25
  # @return [Seahorse::Client::RequestContext] The context of the request
22
26
  # that triggered the remote service to return this error.
23
27
  attr_reader :context
@@ -17,6 +17,7 @@ module Aws
17
17
  FAILURES = [
18
18
  Errno::EHOSTUNREACH,
19
19
  Errno::ECONNREFUSED,
20
+ Errno::EHOSTDOWN,
20
21
  SocketError,
21
22
  Timeout::Error,
22
23
  Non200Response,
@@ -2,4 +2,5 @@ Aws.add_service(:Kinesis, {
2
2
  api: File.join(Aws::API_DIR, 'Kinesis.api.json'),
3
3
  docs: File.join(Aws::API_DIR, 'Kinesis.docs.json'),
4
4
  paginators: File.join(Aws::API_DIR, 'Kinesis.paginators.json'),
5
+ waiters: File.join(Aws::API_DIR, 'Kinesis.waiters.json'),
5
6
  })
@@ -20,7 +20,7 @@ module Aws
20
20
  def next_tokens(response)
21
21
  @tokens.each.with_object({}) do |(source, target), next_tokens|
22
22
  value = JMESPath.search(source, response.data)
23
- next_tokens[target.to_sym] = value unless value.nil?
23
+ next_tokens[target.to_sym] = value unless empty_value?(value)
24
24
  end
25
25
  end
26
26
 
@@ -51,6 +51,10 @@ module Aws
51
51
  gsub(/\w+/) { |part| Seahorse::Util.underscore(part) }
52
52
  end
53
53
 
54
+ def empty_value?(value)
55
+ value.nil? || value == [] || value == {}
56
+ end
57
+
54
58
  end
55
59
  end
56
60
  end
@@ -66,6 +66,8 @@ module Aws
66
66
  if @expiration
67
67
  # are we within 5 minutes of expiration?
68
68
  (Time.now.to_i + 5 * 60) > @expiration.to_i
69
+ else
70
+ true
69
71
  end
70
72
  end
71
73
 
@@ -1,3 +1,3 @@
1
1
  module Aws
2
- VERSION = '2.0.18'
2
+ VERSION = '2.0.19'
3
3
  end
@@ -6,23 +6,61 @@ module Aws
6
6
  # succeed.
7
7
  class WaiterFailed < StandardError; end
8
8
 
9
+ class FailureStateError < WaiterFailed
10
+
11
+ MSG = "stopped waiting, encountered a failure state"
12
+
13
+ def initialize(response)
14
+ @response = response
15
+ super(MSG)
16
+ end
17
+
18
+ # @return [Seahorse::Client::Response] The response that matched
19
+ # the failure state.
20
+ attr_reader :response
21
+
22
+ end
23
+
24
+ class TooManyAttemptsError < WaiterFailed
25
+
26
+ MSG = "stopped waiting after %d attempts without success"
27
+
28
+ def initialize(attempts)
29
+ @attempts = attempts
30
+ super(MSG % [attempts])
31
+ end
32
+
33
+ # @return [Integer]
34
+ attr_reader :attempts
35
+
36
+ end
37
+
38
+ class UnexpectedError < WaiterFailed
39
+
40
+ MSG = "stopped waiting due to an unexpected error: %s"
41
+
42
+ def initialize(error)
43
+ @error = error
44
+ super(MSG % [error.message])
45
+ end
46
+
47
+ # @return [Exception] The unexpected error.
48
+ attr_reader :error
49
+
50
+ end
51
+
9
52
  # Raised when attempting to get a waiter by name and the waiter has not
10
53
  # been defined.
11
- class NoSuchWaiter < ArgumentError
54
+ class NoSuchWaiterError < ArgumentError
55
+
56
+ MSG = "no such waiter %s; valid waiter names are: %s"
57
+
12
58
  def initialize(waiter_name, waiter_names)
13
- msg = "no definition found for #{waiter_name.inspect}"
14
- msg << "; valid waiter names are:"
15
- waiter_names.sort.each.with_index do |name, n|
16
- if n % 3 == 0
17
- msg << "\n #{name.inspect}"
18
- else
19
- msg << ", #{name.inspect}"
20
- end
21
- end
22
- super(msg)
59
+ waiter_names = waiter_names.map(&:inspect).join(', ')
60
+ super(MSG % [waiter_name.inspect, waiter_names])
23
61
  end
24
- end
25
62
 
63
+ end
26
64
  end
27
65
  end
28
66
  end
@@ -0,0 +1,105 @@
1
+ module Aws
2
+ module Waiters
3
+
4
+ # Polls a single API operation inspecting the response data and/or error
5
+ # for states matching one of its acceptors.
6
+ # @api private
7
+ class Poller
8
+
9
+ # @api private
10
+ RAISE_HANDLER = Seahorse::Client::Plugins::RaiseResponseErrors::Handler
11
+
12
+ # @api private
13
+ def initialize(options = {})
14
+ @operation_name = underscore(options['operation']).to_sym
15
+ @acceptors = options['acceptors'] || []
16
+ end
17
+
18
+ # @return [Symbol]
19
+ attr_reader :operation_name
20
+
21
+ # Makes an API call, returning the resultant state and the response.
22
+ #
23
+ # * `:success` - A success state has been matched.
24
+ # * `:failure` - A terminate failure state has been matched.
25
+ # * `:retry` - The waiter may be retried.
26
+ # * `:error` - The waiter encountered an un-expected error.
27
+ #
28
+ # @example A trival (bad) example of a waiter that polls indefinetly.
29
+ #
30
+ # loop do
31
+ #
32
+ # state, resp = poller.call(client:client, params:{})
33
+ #
34
+ # case state
35
+ # when :success then return true
36
+ # when :failure then return false
37
+ # when :retry then next
38
+ # when :error then raise 'oops'
39
+ # end
40
+ #
41
+ # end
42
+ #
43
+ # @option options [required,Client] :client
44
+ # @option options [required,Hash] :params
45
+ # @return [Array<Symbol,Response>]
46
+ def call(options = {})
47
+ response = send_request(options)
48
+ @acceptors.each do |acceptor|
49
+ if acceptor_matches?(acceptor, response)
50
+ return [acceptor['state'].to_sym, response]
51
+ end
52
+ end
53
+ [response.error ? :error : :retry, response]
54
+ end
55
+
56
+ private
57
+
58
+ def send_request(options)
59
+ req = options[:client].build_request(@operation_name, options[:params])
60
+ req.handlers.remove(RAISE_HANDLER)
61
+ req.send_request
62
+ end
63
+
64
+ def acceptor_matches?(acceptor, response)
65
+ send("matches_#{acceptor['matcher']}?", acceptor, response)
66
+ end
67
+
68
+ def matches_path?(acceptor, response)
69
+ JMESPath.search(path(acceptor), response.data) == acceptor['expected']
70
+ end
71
+
72
+ def matches_pathAll?(acceptor, response)
73
+ values = JMESPath.search(path(acceptor), response.data)
74
+ Array === values &&
75
+ values.count > 0 &&
76
+ values.all? { |value| value == acceptor['expected'] }
77
+ end
78
+
79
+ def matches_pathAny?(acceptor, response)
80
+ values = JMESPath.search(path(acceptor), response.data)
81
+ Array === values &&
82
+ values.count > 0 &&
83
+ values.any? { |value| value == acceptor['expected'] }
84
+ end
85
+
86
+ def matches_status?(acceptor, response)
87
+ response.context.http_response.status_code == acceptor['expected']
88
+ end
89
+
90
+ def matches_error?(acceptor, response)
91
+ Aws::Errors::ServiceError === response.error &&
92
+ response.error.code == acceptor['expected']
93
+ end
94
+
95
+ def path(acceptor)
96
+ acceptor['argument'].gsub(/\w+/) { |s| Seahorse::Util.underscore(s) }
97
+ end
98
+
99
+ def underscore(str)
100
+ Seahorse::Util.underscore(str)
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -1,54 +1,35 @@
1
- require 'set'
2
-
3
1
  module Aws
4
2
  module Waiters
5
3
  # @api private
6
4
  class Provider
7
5
 
8
6
  def initialize(definitions)
9
- @waiter_names = Set.new
10
- @definitions = definitions['waiters'].each.with_object({}) do |(k,v),h|
11
- if k.match(/^__/)
12
- h[k] = v
13
- else
14
- underscore(k).to_sym.tap do |name|
15
- @waiter_names << name
16
- h[name] = v
17
- end
18
- end
7
+ @waiters = {}
8
+ definitions['waiters'].each do |waiter_name, definition|
9
+ @waiters[Seahorse::Util.underscore(waiter_name).to_sym] = {
10
+ poller: Poller.new(definition),
11
+ max_attempts: definition['maxAttempts'],
12
+ delay: definition['delay'],
13
+ }
19
14
  end
20
15
  end
21
16
 
22
17
  # @return [Array<Symbol>]
23
18
  def waiter_names
24
- @waiter_names.to_a
19
+ @waiters.keys
25
20
  end
26
21
 
27
22
  # @param [Symbol] waiter_name
28
23
  # @return [Waiter]
29
24
  # @raise [ArgumentError]
30
25
  def waiter(waiter_name)
31
- if @waiter_names.include?(waiter_name)
32
- Waiter.new(resolve('extends' => waiter_name))
33
- else
34
- raise Errors::NoSuchWaiter.new(waiter_name, waiter_names)
35
- end
36
- end
37
-
38
- private
39
-
40
- def resolve(definition)
41
- if extends = definition.delete('extends')
42
- resolve(@definitions[extends].merge(definition))
26
+ if @waiters.key?(waiter_name)
27
+ Waiter.new(@waiters[waiter_name])
43
28
  else
44
- (@definitions['__default__'] || {}).merge(definition)
29
+ raise Errors::NoSuchWaiterError.new(waiter_name, waiter_names)
45
30
  end
46
31
  end
47
32
 
48
- def underscore(str)
49
- str.gsub(/\w+/) { |part| Seahorse::Util.underscore(part) }
50
- end
51
-
52
33
  end
53
34
  end
54
35
  end