aws_advanced_ruby_driver_wrapper 1.0.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE +175 -0
- data/NOTICE +1 -0
- data/README.md +168 -0
- data/THIRD-PARTY-LICENSES +473 -0
- data/aws_advanced_ruby_driver_wrapper.gemspec +73 -0
- data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_mysql2_adapter.rb +73 -0
- data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_postgresql_adapter.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/custom_configuration.rb +58 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_mysql_dialect.rb +103 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_pg_dialect.rb +124 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/dialect_codes.rb +38 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_mysql_dialect.rb +91 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_pg_dialect.rb +92 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_mysql_dialect.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_pg_dialect.rb +86 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/mysql_dialect.rb +98 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/pg_dialect.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_mysql_dialect.rb +88 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_pg_dialect.rb +86 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/unknown_dialect.rb +72 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/utils/dialect_utils.rb +71 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect.rb +154 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect_manager.rb +55 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/mysql_driver_dialect.rb +165 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/pg_driver_dialect.rb +201 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors/error_handler.rb +62 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors/mysql_error_handler.rb +80 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors/pg_error_handler.rb +126 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors.rb +59 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/connection_string_host_list_provider.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/global_aurora_host_list_provider.rb +65 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability.rb +24 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability_strategy.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_info.rb +137 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_role.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/random_host_selector.rb +40 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/rds_host_list_provider.rb +206 -0
- data/lib/aws_advanced_ruby_driver_wrapper/logging.rb +110 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/cluster_topology_monitor.rb +709 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/global_cluster_topology_monitor.rb +72 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor.rb +99 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_connection.rb +57 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_state.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/mysql.rb +429 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/blue_green_plugin.rb +205 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/host_mapper.rb +132 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/iam_host_tracker.rb +84 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interim_status.rb +92 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interval_rate.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase.rb +69 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_event_log.rb +85 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_time_info.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/role.rb +38 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/base_routing.rb +83 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/reject_connect_routing.rb +40 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/substitute_connect_routing.rb +136 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_connect_routing.rb +53 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_execute_routing.rb +52 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_until_corresponding_host_found_connect_routing.rb +83 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status.rb +68 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_builder.rb +244 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_info.rb +30 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_monitor.rb +564 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_provider.rb +414 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_state.rb +98 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_timer.rb +46 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_monitor.rb +266 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_plugin.rb +158 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/info.rb +111 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/member_list_type.rb +31 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/role.rb +45 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/default_plugin.rb +108 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_mode.rb +43 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_plugin.rb +467 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_mode.rb +68 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_plugin.rb +403 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/iam_auth_plugin.rb +159 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/initial_connection_strategy_plugin.rb +485 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/audit_logger.rb +157 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_cipher.rb +159 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_encryption_config.rb +61 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/connection_source.rb +91 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/data_key_cache.rb +220 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_algorithm.rb +75 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_config.rb +146 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_service.rb +391 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/error_context.rb +198 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/errors.rb +259 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_management_utility.rb +435 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_manager.rb +378 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_metadata.rb +86 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_plugin.rb +890 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_utility.rb +281 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/metadata_manager.rb +332 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sanitizer.rb +147 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_name.rb +70 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_validator.rb +211 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sql_runner.rb +147 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/type_marker.rb +109 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/secrets_manager_plugin.rb +358 -0
- data/lib/aws_advanced_ruby_driver_wrapper/postgresql.rb +659 -0
- data/lib/aws_advanced_ruby_driver_wrapper/property_definition.rb +409 -0
- data/lib/aws_advanced_ruby_driver_wrapper/ruby_method.rb +122 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/connection_service.rb +143 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/dialect_service.rb +267 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/host_service.rb +199 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/monitor_service.rb +186 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_call_context.rb +63 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_manager.rb +273 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/service_container.rb +30 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/service_utility.rb +78 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/session_state_service.rb +56 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/accessible_regions.rb +52 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/ar_constants.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/aurora_topology_utils.rb +99 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/aws_credentials_utils.rb +62 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config.rb +91 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config_parser.rb +368 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/conversion_utils.rb +51 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/events/batching_event_publisher.rb +119 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/events/data_access_event.rb +26 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/events/monitor_reset_event.rb +26 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/global_aurora_topology_utils.rb +185 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/host_list_utils.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/iam_auth_utils.rb +112 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/multi_az_topology_utils.rb +117 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/encryption_annotation_parser.rb +99 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/mysql_statement_analyzer.rb +641 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/pg_statement_analyzer.rb +502 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_analysis.rb +63 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_type.rb +35 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint_parser.rb +50 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/sql_parser.rb +139 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_url_type.rb +71 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_utils.rb +575 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/retry_util.rb +153 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_encoding.rb +56 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_method_analyzer.rb +195 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/cache_entry.rb +56 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/expiration_cache.rb +108 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/sliding_expiration_cache.rb +137 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/storage_service.rb +172 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/topology_utils.rb +127 -0
- data/lib/aws_advanced_ruby_driver_wrapper/version.rb +19 -0
- data/lib/aws_advanced_ruby_driver_wrapper/wrapper_property.rb +64 -0
- data/lib/aws_advanced_ruby_driver_wrapper.rb +116 -0
- metadata +227 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative 'error_handler'
|
|
18
|
+
|
|
19
|
+
module AwsAdvancedRubyDriverWrapper
|
|
20
|
+
module Errors
|
|
21
|
+
class MysqlErrorHandler
|
|
22
|
+
include ErrorHandler
|
|
23
|
+
|
|
24
|
+
ACCESS_ERROR_SQL_STATE = '28000'
|
|
25
|
+
READ_ONLY_ERROR_CODES = Set[1290, 1836].freeze
|
|
26
|
+
NETWORK_ERROR_CODES = Set[
|
|
27
|
+
2002, # CR_CONNECTION_ERROR (can't connect via socket)
|
|
28
|
+
2003, # CR_CONN_HOST_ERROR (can't connect to host)
|
|
29
|
+
2006, # CR_SERVER_GONE_ERROR (server has gone away)
|
|
30
|
+
2013, # CR_SERVER_LOST (lost connection during query)
|
|
31
|
+
2026, # CR_SSL_CONNECTION_ERROR
|
|
32
|
+
2055 # CR_SERVER_LOST_EXTENDED (lost connection with state info)
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
def initialize(driver_dialect)
|
|
36
|
+
@driver_dialect = driver_dialect
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def network_error?(error)
|
|
40
|
+
return true if super
|
|
41
|
+
|
|
42
|
+
check_cause_chain(error) { |_, current| connection_error_network?(current) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def network_error_by_sql_state?(sql_state)
|
|
46
|
+
return false if sql_state.nil?
|
|
47
|
+
|
|
48
|
+
sql_state.start_with?('08') && sql_state != '08004'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def login_error_by_sql_state?(sql_state)
|
|
52
|
+
return false if sql_state.nil?
|
|
53
|
+
|
|
54
|
+
sql_state == ACCESS_ERROR_SQL_STATE
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def read_only_error?(error)
|
|
58
|
+
check_cause_chain(error) do |sql_state, ex|
|
|
59
|
+
error_code = ex.respond_to?(:error_number) ? ex.error_number : nil
|
|
60
|
+
read_only_error_by_sql_state?(sql_state, error_code)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def read_only_error_by_sql_state?(sql_state, error_code = nil)
|
|
65
|
+
sql_state == 'HY000' && !error_code.nil? && READ_ONLY_ERROR_CODES.include?(error_code)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def connection_error_network?(error)
|
|
71
|
+
return false unless defined?(Mysql2::Error::ConnectionError) && error.is_a?(Mysql2::Error::ConnectionError)
|
|
72
|
+
|
|
73
|
+
error_number = error.respond_to?(:error_number) ? error.error_number : nil
|
|
74
|
+
return true if error_number && NETWORK_ERROR_CODES.include?(error_number)
|
|
75
|
+
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative 'error_handler'
|
|
18
|
+
|
|
19
|
+
module AwsAdvancedRubyDriverWrapper
|
|
20
|
+
module Errors
|
|
21
|
+
class PgErrorHandler
|
|
22
|
+
include ErrorHandler
|
|
23
|
+
|
|
24
|
+
NETWORK_SQL_STATE_PREFIXES = %w[57P01 57P02 57P03 58 08 99 F0].freeze
|
|
25
|
+
ACCESS_ERROR_SQL_STATES = Set['08004', '28P01', '28000'].freeze
|
|
26
|
+
READ_ONLY_SQL_STATE = '25006'
|
|
27
|
+
LOGIN_ERROR_MESSAGE = 'authentication failed'
|
|
28
|
+
NETWORK_ERROR_MESSAGES = [
|
|
29
|
+
'unexpected eof',
|
|
30
|
+
'closed the connection unexpectedly',
|
|
31
|
+
'reset by peer',
|
|
32
|
+
'could not receive data',
|
|
33
|
+
'could not send data',
|
|
34
|
+
'connection not open',
|
|
35
|
+
'no connection to the server',
|
|
36
|
+
'connection is closed',
|
|
37
|
+
'broken pipe',
|
|
38
|
+
'terminating connection due to administrator command',
|
|
39
|
+
"can't get socket descriptor",
|
|
40
|
+
'ssl connection has been closed unexpectedly'
|
|
41
|
+
].freeze
|
|
42
|
+
|
|
43
|
+
# Failures raised while establishing a connection, where the server was never reached and so
|
|
44
|
+
# never had the chance to accept or reject the login. These are transient and worth retrying.
|
|
45
|
+
# libpq discards the structured error fields for connect-time failures, so the message text
|
|
46
|
+
# is the only signal available.
|
|
47
|
+
CONNECT_FAILURE_MESSAGES = [
|
|
48
|
+
'connection refused',
|
|
49
|
+
'timeout expired',
|
|
50
|
+
'could not translate host name',
|
|
51
|
+
'no route to host',
|
|
52
|
+
'network is unreachable',
|
|
53
|
+
'host is unreachable',
|
|
54
|
+
'could not connect to server',
|
|
55
|
+
'no such file or directory', # unix socket path does not exist
|
|
56
|
+
'connection timed out'
|
|
57
|
+
].freeze
|
|
58
|
+
|
|
59
|
+
# Rejections issued by a server that was successfully reached. Retrying to connect is futile because
|
|
60
|
+
# the cause is the credentials, the requested database, or server configuration rather than the network path.
|
|
61
|
+
SERVER_REJECTION_MESSAGES = [
|
|
62
|
+
LOGIN_ERROR_MESSAGE,
|
|
63
|
+
'pg_hba.conf',
|
|
64
|
+
'does not exist',
|
|
65
|
+
'is not permitted',
|
|
66
|
+
'too many clients'
|
|
67
|
+
].freeze
|
|
68
|
+
|
|
69
|
+
def initialize(driver_dialect)
|
|
70
|
+
@driver_dialect = driver_dialect
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def network_error?(error)
|
|
74
|
+
return true if super
|
|
75
|
+
|
|
76
|
+
check_cause_chain(error) { |_, current| connection_bad_network_error?(current) }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def network_error_by_sql_state?(sql_state)
|
|
80
|
+
return false if sql_state.nil?
|
|
81
|
+
|
|
82
|
+
NETWORK_SQL_STATE_PREFIXES.any? { |prefix| sql_state.start_with?(prefix) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def login_error?(error)
|
|
86
|
+
return true if super
|
|
87
|
+
|
|
88
|
+
# PG::ConnectionBad from auth failure during connect may not carry a SQLSTATE.
|
|
89
|
+
# Fall back to message inspection.
|
|
90
|
+
if defined?(PG::ConnectionBad) && error.is_a?(PG::ConnectionBad)
|
|
91
|
+
msg = error.message
|
|
92
|
+
return msg.include?(LOGIN_ERROR_MESSAGE) if msg
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
false
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def login_error_by_sql_state?(sql_state)
|
|
99
|
+
return false if sql_state.nil?
|
|
100
|
+
|
|
101
|
+
ACCESS_ERROR_SQL_STATES.include?(sql_state)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def read_only_error_by_sql_state?(sql_state, _error_code = nil)
|
|
105
|
+
sql_state == READ_ONLY_SQL_STATE
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def connection_bad_network_error?(error)
|
|
111
|
+
return false unless defined?(PG::ConnectionBad) && error.is_a?(PG::ConnectionBad)
|
|
112
|
+
|
|
113
|
+
msg = error.message&.downcase
|
|
114
|
+
return false if msg.nil?
|
|
115
|
+
return false if server_rejection?(msg)
|
|
116
|
+
|
|
117
|
+
NETWORK_ERROR_MESSAGES.any? { |pattern| msg.include?(pattern) } ||
|
|
118
|
+
CONNECT_FAILURE_MESSAGES.any? { |pattern| msg.include?(pattern) }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def server_rejection?(msg)
|
|
122
|
+
SERVER_REJECTION_MESSAGES.any? { |pattern| msg.include?(pattern) }
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module AwsAdvancedRubyDriverWrapper
|
|
18
|
+
module Errors
|
|
19
|
+
class AwsError < StandardError
|
|
20
|
+
attr_reader :connection_broken, :needs_reconfiguration
|
|
21
|
+
|
|
22
|
+
def initialize(message, connection_broken: false, needs_reconfiguration: false)
|
|
23
|
+
super(message)
|
|
24
|
+
@needs_reconfiguration = needs_reconfiguration
|
|
25
|
+
@connection_broken = connection_broken
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class FailoverFailedError < AwsError
|
|
30
|
+
def initialize(message)
|
|
31
|
+
super(message, connection_broken: true)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class FailoverSuccessError < AwsError
|
|
36
|
+
def initialize
|
|
37
|
+
super(
|
|
38
|
+
'The active SQL connection has changed due to a connection failure. Please re-configure session state if required.',
|
|
39
|
+
needs_reconfiguration: true)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class TransactionStateUnknownError < AwsError
|
|
44
|
+
def initialize
|
|
45
|
+
super(
|
|
46
|
+
'Transaction resolution unknown. Please re-configure session state if required and retry the transaction.',
|
|
47
|
+
connection_broken: true,
|
|
48
|
+
needs_reconfiguration: true
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class IamAuthError < AwsError; end
|
|
54
|
+
class SecretsManagerAuthError < AwsError; end
|
|
55
|
+
class PluginConflictError < AwsError; end
|
|
56
|
+
class BlueGreenTimeoutError < AwsError; end
|
|
57
|
+
class BlueGreenSwitchoverError < AwsError; end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative '../errors'
|
|
18
|
+
require_relative 'host_info'
|
|
19
|
+
require_relative 'host_role'
|
|
20
|
+
|
|
21
|
+
module AwsAdvancedRubyDriverWrapper
|
|
22
|
+
module Host
|
|
23
|
+
# A static host list provider that parses the connection string to determine host information.
|
|
24
|
+
# The host list is determined once during initialization and does not change over time.
|
|
25
|
+
class ConnectionStringHostListProvider
|
|
26
|
+
# @param service_container [Services::ServiceContainer]
|
|
27
|
+
def initialize(service_container:)
|
|
28
|
+
@service_container = service_container
|
|
29
|
+
@hosts = []
|
|
30
|
+
@initialized = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the static host list parsed from the connection string.
|
|
34
|
+
# @return [Array<HostInfo>]
|
|
35
|
+
def refresh
|
|
36
|
+
initialize_hosts
|
|
37
|
+
@hosts.map(&:deep_dup)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Same as {#refresh} — the host list is static and never changes.
|
|
41
|
+
# @param _verify_writer [Boolean] unused; accepted for compatibility with other host list providers.
|
|
42
|
+
# @param _timeout_ms [Integer] unused; accepted for compatibility with other host list providers.
|
|
43
|
+
# @return [Array<HostInfo>]
|
|
44
|
+
def force_refresh(_verify_writer = false, _timeout_ms = 0)
|
|
45
|
+
initialize_hosts
|
|
46
|
+
@hosts.map(&:deep_dup)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Returns the cluster ID. Since this is a static provider with no cluster awareness,
|
|
50
|
+
# returns a placeholder value.
|
|
51
|
+
# @return [String]
|
|
52
|
+
def cluster_id
|
|
53
|
+
'<none>'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# No-op — there is no monitor to stop for this host list provider.
|
|
57
|
+
def stop_monitor; end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def initialize_hosts
|
|
62
|
+
return if @initialized
|
|
63
|
+
|
|
64
|
+
connection_service = @service_container.connection_service
|
|
65
|
+
config = connection_service.config
|
|
66
|
+
@hosts = if config.multi_host_url?
|
|
67
|
+
build_multi_host_list(config.original_host, config.original_port)
|
|
68
|
+
else
|
|
69
|
+
[connection_service.initial_host_info]
|
|
70
|
+
end
|
|
71
|
+
@initialized = true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def build_multi_host_list(original_host, original_port)
|
|
75
|
+
hosts = original_host.split(',').map(&:strip)
|
|
76
|
+
port_str = original_port.to_s
|
|
77
|
+
|
|
78
|
+
# If a single port is specified (no commas), it applies to all hosts.
|
|
79
|
+
# If commas are present, each port maps positionally to each host (empty entries become NO_PORT).
|
|
80
|
+
single_port = !port_str.include?(',')
|
|
81
|
+
ports = port_str.split(',', -1)
|
|
82
|
+
|
|
83
|
+
hosts.each_with_index.map do |host, i|
|
|
84
|
+
port_value = if single_port
|
|
85
|
+
port_str.strip.empty? ? HostInfo::NO_PORT : port_str.strip
|
|
86
|
+
else
|
|
87
|
+
port = ports[i]&.strip
|
|
88
|
+
port.nil? || port.empty? ? HostInfo::NO_PORT : port
|
|
89
|
+
end
|
|
90
|
+
HostInfo.new(host:, port: port_value, role: HostRole::UNKNOWN)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative 'rds_host_list_provider'
|
|
18
|
+
require_relative '../monitoring/global_cluster_topology_monitor'
|
|
19
|
+
require_relative '../property_definition'
|
|
20
|
+
|
|
21
|
+
module AwsAdvancedRubyDriverWrapper
|
|
22
|
+
module Host
|
|
23
|
+
# Host list provider for Aurora Global Database clusters.
|
|
24
|
+
# Extends RdsHostListProvider with multi-region instance templates
|
|
25
|
+
# and uses GlobalClusterTopologyMonitor.
|
|
26
|
+
class GlobalAuroraHostListProvider < RdsHostListProvider
|
|
27
|
+
attr_reader :instance_templates_by_region
|
|
28
|
+
|
|
29
|
+
def initialize(service_container:, topology_utils:)
|
|
30
|
+
super
|
|
31
|
+
@instance_templates_by_region = build_instance_templates_by_region
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def force_refresh(verify_writer, timeout_sec)
|
|
35
|
+
monitor = @service_container.monitor_service.run_if_absent(:cluster_topology, @cluster_id, @service_container) do |_sc|
|
|
36
|
+
Monitoring::GlobalClusterTopologyMonitor.new(
|
|
37
|
+
service_container: @service_container,
|
|
38
|
+
cluster_id: @cluster_id,
|
|
39
|
+
instance_template: @instance_template,
|
|
40
|
+
instance_templates_by_region: @instance_templates_by_region,
|
|
41
|
+
topology_utils: @topology_utils,
|
|
42
|
+
monitoring_driver_props: @monitoring_driver_props,
|
|
43
|
+
monitoring_wrapper_props: @monitoring_wrapper_props
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
monitor.force_refresh(verify_writer, timeout_sec)
|
|
47
|
+
rescue Timeout::Error
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def build_instance_templates_by_region
|
|
54
|
+
props = @service_container.connection_service.wrapper_props
|
|
55
|
+
patterns_str = PropertyDefinition::GLOBAL_CLUSTER_INSTANCE_HOST_PATTERNS.get(props)
|
|
56
|
+
unless patterns_str
|
|
57
|
+
raise Errors::AwsError,
|
|
58
|
+
"#{PropertyDefinition::GLOBAL_CLUSTER_INSTANCE_HOST_PATTERNS.name} is required for Global Aurora Databases"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@topology_utils.parse_instance_templates(patterns_str, method(:validate_host_pattern!))
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module AwsAdvancedRubyDriverWrapper
|
|
18
|
+
module Host
|
|
19
|
+
module HostAvailability
|
|
20
|
+
AVAILABLE = :available
|
|
21
|
+
UNAVAILABLE = :unavailable
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module AwsAdvancedRubyDriverWrapper
|
|
18
|
+
module Host
|
|
19
|
+
class HostAvailabilityStrategy
|
|
20
|
+
def host_availability(raw_host_availability) = raw_host_availability
|
|
21
|
+
|
|
22
|
+
def host_availability=(_host_availability)
|
|
23
|
+
# Intentionally do nothing.
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative 'host_availability'
|
|
18
|
+
require_relative 'host_availability_strategy'
|
|
19
|
+
require_relative 'host_role'
|
|
20
|
+
|
|
21
|
+
module AwsAdvancedRubyDriverWrapper
|
|
22
|
+
module Host
|
|
23
|
+
class HostInfo
|
|
24
|
+
NO_PORT = '-1'
|
|
25
|
+
NO_HOST = ''
|
|
26
|
+
DEFAULT_WEIGHT = 100
|
|
27
|
+
|
|
28
|
+
# The attributes that define this host's identity, and that {#==} and {#hash} are derived from. They are
|
|
29
|
+
# read-only so that the hash code of an instance cannot change while it is held in a Hash or Set, which
|
|
30
|
+
# would otherwise make the instance impossible to look up. Use {#deep_dup} to obtain a copy with
|
|
31
|
+
# different values.
|
|
32
|
+
attr_reader :host, :port, :role
|
|
33
|
+
|
|
34
|
+
attr_accessor :availability_strategy, :weight, :id, :last_update_time
|
|
35
|
+
|
|
36
|
+
def initialize(
|
|
37
|
+
host: NO_HOST,
|
|
38
|
+
port: NO_PORT,
|
|
39
|
+
role: HostRole::WRITER,
|
|
40
|
+
availability: HostAvailability::AVAILABLE,
|
|
41
|
+
availability_strategy: HostAvailabilityStrategy.new,
|
|
42
|
+
weight: DEFAULT_WEIGHT,
|
|
43
|
+
id: nil,
|
|
44
|
+
last_update_time: nil
|
|
45
|
+
)
|
|
46
|
+
@host = host
|
|
47
|
+
@port = port
|
|
48
|
+
@role = role
|
|
49
|
+
@availability = availability
|
|
50
|
+
@availability_strategy = availability_strategy
|
|
51
|
+
@weight = weight
|
|
52
|
+
@id = id
|
|
53
|
+
@last_update_time = last_update_time
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ==(other)
|
|
57
|
+
return true if equal?(other)
|
|
58
|
+
return false unless other.is_a?(HostInfo)
|
|
59
|
+
|
|
60
|
+
host == other.host &&
|
|
61
|
+
port == other.port &&
|
|
62
|
+
role == other.role
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
alias eql? ==
|
|
66
|
+
|
|
67
|
+
def hash
|
|
68
|
+
[host, port, role].hash
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_s
|
|
72
|
+
"HostInfo(#{host}, #{port}, #{role}, #{availability})"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def inspect
|
|
76
|
+
to_s
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Returns a deep copy of this HostInfo, duplicating all mutable fields. Since {#host}, {#port} and {#role}
|
|
80
|
+
# are read-only, this is also the way to obtain an instance that differs from this one in any of them.
|
|
81
|
+
#
|
|
82
|
+
# @param host [String] the host of the copy, defaulting to this host's.
|
|
83
|
+
# @param port [String] the port of the copy, defaulting to this host's.
|
|
84
|
+
# @param role [Symbol] the role of the copy, defaulting to this host's.
|
|
85
|
+
# @return [HostInfo]
|
|
86
|
+
def deep_dup(host: self.host, port: self.port, role: self.role)
|
|
87
|
+
HostInfo.new(
|
|
88
|
+
host: host.dup,
|
|
89
|
+
port: port.dup,
|
|
90
|
+
role:,
|
|
91
|
+
availability:,
|
|
92
|
+
weight:,
|
|
93
|
+
id: id&.dup,
|
|
94
|
+
last_update_time:
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def url
|
|
99
|
+
"#{host_and_port}/"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def host_and_port
|
|
103
|
+
port_specified? ? "#{host}:#{port}" : host
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def port_specified?
|
|
107
|
+
port != NO_PORT
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def host_specified?
|
|
111
|
+
!host.nil? && host != NO_HOST
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Returns the availability of this host.
|
|
115
|
+
#
|
|
116
|
+
# @return [Symbol] either {HostAvailability::AVAILABLE} or {HostAvailability::UNAVAILABLE}
|
|
117
|
+
def availability
|
|
118
|
+
return availability_strategy.host_availability(@availability) if availability_strategy
|
|
119
|
+
|
|
120
|
+
@availability
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def availability=(availability)
|
|
124
|
+
@availability = availability
|
|
125
|
+
availability_strategy&.host_availability = availability
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Returns the raw availability of this host.
|
|
129
|
+
#
|
|
130
|
+
# @return [Symbol] the raw availability of this host, ignoring the
|
|
131
|
+
# {#availability_strategy} if it has one.
|
|
132
|
+
def raw_availability
|
|
133
|
+
@availability
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module AwsAdvancedRubyDriverWrapper
|
|
18
|
+
module Host
|
|
19
|
+
module HostRole
|
|
20
|
+
UNKNOWN = :unknown
|
|
21
|
+
READER = :reader
|
|
22
|
+
WRITER = :writer
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module AwsAdvancedRubyDriverWrapper
|
|
18
|
+
module Host
|
|
19
|
+
class RandomHostSelector
|
|
20
|
+
STRATEGY_NAME = 'random'
|
|
21
|
+
|
|
22
|
+
# Selects a random available host matching the requested role from the given host list.
|
|
23
|
+
#
|
|
24
|
+
# @param hosts [Array<HostInfo>] list of available hosts to pick from.
|
|
25
|
+
# @param role [Symbol, nil] the desired host role, or nil for no preference.
|
|
26
|
+
# @param _props [Hash, nil] connection properties.
|
|
27
|
+
# @return [HostInfo, nil] an available host matching the requested role, or nil if none are eligible.
|
|
28
|
+
def select_host(hosts, role, _props = nil)
|
|
29
|
+
eligible_hosts = hosts.select do |host|
|
|
30
|
+
(role.nil? || host.role == role) &&
|
|
31
|
+
host.availability == HostAvailability::AVAILABLE
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
return nil if eligible_hosts.empty?
|
|
35
|
+
|
|
36
|
+
eligible_hosts.sample
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|