right_support 2.6.8 → 2.6.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.
@@ -9,11 +9,21 @@
9
9
  # License Agreement between RightScale.com, Inc. and the licensee.
10
10
 
11
11
  require 'socket'
12
+ require 'uri'
12
13
 
13
14
  module RightSupport::Net
14
-
15
15
  module DNS
16
+ DEFAULT_RESOLVE_OPTIONS = {
17
+ :address_family => Socket::AF_INET,
18
+ :socket_type => Socket::SOCK_STREAM,
19
+ :protocol => Socket::IPPROTO_TCP,
20
+ :retry => 3
21
+ }
16
22
 
23
+ # Resolve a set of DNS hostnames to the individual IP addresses to which they map. Only handles
24
+ # IPv4 addresses.
25
+ #
26
+ # @deprecated due to broken error handling - do not use; please use #resolve instead!
17
27
  def self.resolve_all_ip_addresses(hostnames)
18
28
  ips = []
19
29
  hostnames = [hostnames] unless hostnames.respond_to?(:each)
@@ -35,6 +45,74 @@ module RightSupport::Net
35
45
  ips
36
46
  end
37
47
 
48
+ # Perform DNS resolution on a set of endpoints, where the endpoints may be hostnames or URIs.
49
+ # Expand out the list to include one entry per distinct address that is assigned to a given
50
+ # hostname, but preserve other aspects of the endpoints --. URIs will remain URIs with the
51
+ # same protocol, path-info, and so forth, but the hostname component will be resolved to IP
52
+ # addresses and the URI will be duplicated in the output, once for each distinct IP address.
53
+ #
54
+ # Although this method does accept IPv4 dotted-quad addresses as input, it does not accept
55
+ # IPv6 addresses. However, given hostnames or URIs as input, one _can_ resolve the hostnames
56
+ # to IPv6 addresses by specifying the appropriate address_family in the options.
57
+ #
58
+ # It should never be necessary to specify a different :socket_type or :protocol, but these
59
+ # options are exposed just in case.
60
+ #
61
+ # @param [Array<String>] endpoints a mixed list of hostnames, IPv4 addresses or URIs that contain them
62
+ # @option opts [Integer] :retry number of times to retry SocketError; default is 3
63
+ # @option opts [Integer] :address_family what kind of IP addresses to resolve; default is Socket::AF_INET (IPv4)
64
+ # @option opts [Integer] :socket_type socket-type context to pass to getaddrinfo, default is Socket::SOCK_STREAM
65
+ # @option opts [Integer] :protocol protocol context to pass to getaddrinfo, default is Socket::IPPROTO_TCP
66
+ #
67
+ # @return [Array<String>] larger list of endpoints with all hostnames resolved to IP addresses
68
+ #
69
+ # @raise URI::InvalidURIError if endpoints contains an invalid or URI
70
+ # @raise SocketError if endpoints contains an invalid or unresolvable hostname
71
+ def self.resolve(endpoints, opts={})
72
+ opts = DEFAULT_RESOLVE_OPTIONS.merge(opts)
73
+ endpoints = [endpoints] unless endpoints.respond_to?(:each)
74
+
75
+ resolved_endpoints = []
76
+ retries = 0
77
+
78
+ endpoints.each do |endpoint|
79
+ begin
80
+ if endpoint.include?(':')
81
+ # It contains a colon, therefore it must be a URI -- we don't support IPv6
82
+ uri = URI.parse(endpoint)
83
+ hostname = uri.host
84
+ raise URI::InvalidURIError, "Could not parse host component of URI" unless hostname
85
+
86
+ infos = Socket.getaddrinfo(hostname, nil,
87
+ opts[:address_family], opts[:socket_type], opts[:protocol])
88
+
89
+ infos.each do |info|
90
+ transformed_uri = uri.dup
91
+ transformed_uri.host = info[3]
92
+ resolved_endpoints << transformed_uri.to_s
93
+ end
94
+ else
95
+ # No colon; it's a hostname or IP address
96
+ infos = Socket.getaddrinfo(endpoint, nil,
97
+ opts[:address_family], opts[:socket_type], opts[:protocol])
98
+
99
+ infos.each do |info|
100
+ resolved_endpoints << info[3]
101
+ end
102
+ end
103
+ rescue SocketError => e
104
+ retries += 1
105
+ if retries < opts[:retry]
106
+ retry
107
+ else
108
+ raise e
109
+ end
110
+ end
111
+ end
112
+
113
+ resolved_endpoints
114
+ end
115
+
38
116
  end
39
117
  end
40
118
 
@@ -112,12 +112,13 @@ module RightSupport::Net
112
112
  end
113
113
 
114
114
  def resolve(endpoints)
115
- endpoints = RightSupport::Net::DNS.resolve_all_ip_addresses(endpoints)
115
+ resolved_endpoints = RightSupport::Net::DNS.resolve(endpoints)
116
116
  @resolved_at = Time.now.to_i
117
- endpoints
117
+ logger.info("RequestBalancer: resolved #{endpoints.inspect} to #{resolved_endpoints.inspect}")
118
+ resolved_endpoints
118
119
  end
119
120
 
120
- def expired?
121
+ def need_resolve?
121
122
  @options[:resolve] && Time.now.to_i - @resolved_at > @options[:resolve]
122
123
  end
123
124
 
@@ -125,12 +126,20 @@ module RightSupport::Net
125
126
  # creation time; however, the ordering of the endpoints does not change thereafter
126
127
  # and the sequence is tried from the beginning for every request.
127
128
  #
129
+ # If you pass the :resolve option, then the list of endpoints is treated as a list
130
+ # of hostnames (or URLs containing hostnames) and the list is expanded out into a
131
+ # larger list with each hostname replaced by several entries, one for each of its IP
132
+ # addresses. If a single DNS hostname is associated with multiple A records, the
133
+ # :resolve option allows the balancer to treat each backing server as a distinct
134
+ # endpoint with its own health state, etc.
135
+ #
128
136
  # === Parameters
129
137
  # endpoints(Array):: a set of network endpoints (e.g. HTTP URLs) to be load-balanced
130
138
  #
131
139
  # === Options
132
140
  # retry:: a Class, array of Class or decision Proc to determine whether to keep retrying; default is to try all endpoints
133
141
  # fatal:: a Class, array of Class, or decision Proc to determine whether an exception is fatal and should not be retried
142
+ # resolve(Integer):: how often to re-resolve DNS hostnames of endpoints; default is nil (never resolve)
134
143
  # on_exception(Proc):: notification hook that accepts three arguments: whether the exception is fatal, the exception itself,
135
144
  # and the endpoint for which the exception happened
136
145
  # health_check(Proc):: callback that allows balancer to check an endpoint health; should raise an exception if the endpoint
@@ -197,7 +206,8 @@ module RightSupport::Net
197
206
  # Return the first non-nil value provided by the block.
198
207
  def request
199
208
  raise ArgumentError, "Must call this method with a block" unless block_given?
200
- if self.expired?
209
+
210
+ if need_resolve?
201
211
  @ips = self.resolve(@endpoints)
202
212
  @policy.set_endpoints(@ips)
203
213
  end
@@ -9,10 +9,12 @@
9
9
  # License Agreement between RightScale.com, Inc. and the licensee.
10
10
 
11
11
  module RightSupport::Net
12
- # Class provides S3 functionality.
12
+ # Class that provides S3 functionality.
13
13
  # As part of RightSupport S3Helper does not include Rightscale::S3 and Encryptor modules.
14
14
  # This modules must be included in application.
15
15
  #
16
+ # @deprecated do not use; please use RightServices::Util::S3Storage instead!
17
+ #
16
18
  # Example:
17
19
  #
18
20
  # require 'right_support'
@@ -7,8 +7,8 @@ spec = Gem::Specification.new do |s|
7
7
  s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
8
8
 
9
9
  s.name = 'right_support'
10
- s.version = '2.6.8'
11
- s.date = '2012-12-14'
10
+ s.version = '2.6.9'
11
+ s.date = '2013-01-01'
12
12
 
13
13
  s.authors = ['Tony Spataro', 'Sergey Sergyenko', 'Ryan Williamson', 'Lee Kirchhoff', 'Sergey Enin', 'Alexey Karpik', 'Scott Messier']
14
14
  s.email = 'support@rightscale.com'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_support
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 5
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
8
  - 6
9
- - 8
10
- version: 2.6.8
9
+ - 9
10
+ version: 2.6.9
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tony Spataro
@@ -21,7 +21,7 @@ autorequire:
21
21
  bindir: bin
22
22
  cert_chain: []
23
23
 
24
- date: 2012-12-14 00:00:00 -08:00
24
+ date: 2013-01-01 00:00:00 -08:00
25
25
  default_executable:
26
26
  dependencies: []
27
27