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,409 @@
|
|
|
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 'wrapper_property'
|
|
18
|
+
|
|
19
|
+
module AwsAdvancedRubyDriverWrapper
|
|
20
|
+
module PropertyDefinition
|
|
21
|
+
POSITIVE_INTEGER = lambda do |val, name|
|
|
22
|
+
raise ArgumentError, "#{name} must be a positive integer, got: #{val.inspect}" unless val&.to_i&.positive?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
NON_NEGATIVE_INTEGER = lambda do |val, name|
|
|
26
|
+
raise ArgumentError, "#{name} must be a non-negative integer, got: #{val.inspect}" if val&.to_i&.negative?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
POSITIVE_FLOAT = lambda do |val, name|
|
|
30
|
+
raise ArgumentError, "#{name} must be a positive number, got: #{val.inspect}" unless val&.to_f&.positive?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
NON_NEGATIVE_FLOAT = lambda do |val, name|
|
|
34
|
+
raise ArgumentError, "#{name} must be a non-negative number, got: #{val.inspect}" if val&.to_f&.negative?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Upper bound for the IAM token cache TTL. An RDS IAM auth token is only valid for 15 minutes
|
|
38
|
+
# (900s), so the cache must expire strictly before then to guarantee a cached token is never
|
|
39
|
+
# reused past its lifetime.
|
|
40
|
+
IAM_MAX_EXPIRATION_SEC = 870.0
|
|
41
|
+
|
|
42
|
+
IAM_EXPIRATION_SEC_BOUND = lambda do |val, name|
|
|
43
|
+
f = val&.to_f
|
|
44
|
+
unless f&.positive? && f <= IAM_MAX_EXPIRATION_SEC
|
|
45
|
+
raise ArgumentError,
|
|
46
|
+
"#{name} must be greater than 0 and at most #{IAM_MAX_EXPIRATION_SEC} seconds " \
|
|
47
|
+
"(the maximum keeps the IAM token cache below its 15-minute validity), got: #{val.inspect}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# -- General --
|
|
52
|
+
CLUSTER_ID = WrapperProperty.new(:cluster_id, 'Unique identifier for the database cluster', default_value: '1', type: String)
|
|
53
|
+
PLUGINS = WrapperProperty.new(:wrapper_plugins, 'Comma-separated list of plugin codes', default_value: 'failover,initial_connection',
|
|
54
|
+
type: String)
|
|
55
|
+
DIALECT = WrapperProperty.new(:wrapper_dialect, 'The database dialect identifier for the database in use.', type: String)
|
|
56
|
+
AWS_CREDENTIALS_PROVIDER = WrapperProperty.new(:aws_credentials_provider,
|
|
57
|
+
'AWS credentials provider for IAM token generation or Secrets Manager',
|
|
58
|
+
default_value: nil)
|
|
59
|
+
# -- Failover --
|
|
60
|
+
FAILOVER_TIMEOUT_SEC = WrapperProperty.new(
|
|
61
|
+
:failover_timeout_sec,
|
|
62
|
+
'Maximum allowed time in seconds for the failover process.',
|
|
63
|
+
default_value: 300.0,
|
|
64
|
+
type: Float,
|
|
65
|
+
validator: POSITIVE_FLOAT
|
|
66
|
+
)
|
|
67
|
+
FAILOVER_MODE = WrapperProperty.new(
|
|
68
|
+
:failover_mode,
|
|
69
|
+
'Set the desired instance role to target during failover.',
|
|
70
|
+
default_value: nil,
|
|
71
|
+
type: String
|
|
72
|
+
)
|
|
73
|
+
FAILOVER_READER_HOST_SELECTOR_STRATEGY = WrapperProperty.new(
|
|
74
|
+
:failover_reader_host_selector_strategy,
|
|
75
|
+
'The strategy that should be used to select a new reader host while opening a new connection.',
|
|
76
|
+
default_value: 'random',
|
|
77
|
+
type: String
|
|
78
|
+
)
|
|
79
|
+
ENABLE_CONNECT_FAILOVER = WrapperProperty.new(
|
|
80
|
+
:enable_connect_failover,
|
|
81
|
+
'Enable/disable cluster-aware failover if the initial connection fails due to a network exception.',
|
|
82
|
+
default_value: false,
|
|
83
|
+
type: :boolean
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# -- GDB Failover --
|
|
87
|
+
IN_HOME_FAILOVER_MODE = WrapperProperty.new(
|
|
88
|
+
:in_home_failover_mode,
|
|
89
|
+
'GDB-only: the host role to target during failover while the GDB primary region is the home region. ' \
|
|
90
|
+
'Valid values are strict_writer, strict_home_reader, strict_out_of_home_reader, strict_any_reader, ' \
|
|
91
|
+
'home_reader_or_writer, out_of_home_reader_or_writer, and any_reader_or_writer.',
|
|
92
|
+
default_value: nil,
|
|
93
|
+
type: String
|
|
94
|
+
)
|
|
95
|
+
OUT_OF_HOME_FAILOVER_MODE = WrapperProperty.new(
|
|
96
|
+
:out_of_home_failover_mode,
|
|
97
|
+
'GDB-only: the host role to target during failover while the GDB primary region is not the home region. ' \
|
|
98
|
+
'Accepts the same values as in_home_failover_mode.',
|
|
99
|
+
default_value: nil,
|
|
100
|
+
type: String
|
|
101
|
+
)
|
|
102
|
+
FAILOVER_HOME_REGION = WrapperProperty.new(
|
|
103
|
+
:failover_home_region,
|
|
104
|
+
'GDB-only: the AWS region the application runs in, e.g. us-east-1. Determines which of ' \
|
|
105
|
+
'in_home_failover_mode and out_of_home_failover_mode applies: the in-home mode is used while the GDB ' \
|
|
106
|
+
'primary is in this region, and the out-of-home mode is used while it is not. Defaults to the region ' \
|
|
107
|
+
'parsed from the connection endpoint, and is required when the endpoint carries no region, e.g. a global ' \
|
|
108
|
+
'endpoint, an IP address, or a custom domain.',
|
|
109
|
+
default_value: nil,
|
|
110
|
+
type: String
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# -- Topology Monitoring --
|
|
114
|
+
CLUSTER_INSTANCE_HOST_PATTERN = WrapperProperty.new(
|
|
115
|
+
:cluster_instance_host_pattern,
|
|
116
|
+
'Instance endpoint pattern with ? placeholder. Required for IP/custom domain connections.',
|
|
117
|
+
default_value: nil,
|
|
118
|
+
type: String
|
|
119
|
+
)
|
|
120
|
+
GLOBAL_CLUSTER_INSTANCE_HOST_PATTERNS = WrapperProperty.new(
|
|
121
|
+
:global_cluster_instance_host_patterns,
|
|
122
|
+
'Comma-separated list of region-prefixed instance patterns for Global Aurora Databases.',
|
|
123
|
+
default_value: nil,
|
|
124
|
+
type: String
|
|
125
|
+
)
|
|
126
|
+
CLUSTER_TOPOLOGY_REFRESH_RATE_SEC = WrapperProperty.new(
|
|
127
|
+
:cluster_topology_refresh_rate_sec,
|
|
128
|
+
'Cluster topology refresh rate in seconds',
|
|
129
|
+
default_value: 5.0,
|
|
130
|
+
type: Float,
|
|
131
|
+
validator: POSITIVE_FLOAT
|
|
132
|
+
)
|
|
133
|
+
CLUSTER_TOPOLOGY_HIGH_REFRESH_RATE_SEC = WrapperProperty.new(
|
|
134
|
+
:cluster_topology_high_refresh_rate_sec,
|
|
135
|
+
'Cluster topology high refresh rate in seconds (used post-failover)',
|
|
136
|
+
default_value: 0.1,
|
|
137
|
+
type: Float,
|
|
138
|
+
validator: POSITIVE_FLOAT
|
|
139
|
+
)
|
|
140
|
+
CLUSTER_TOPOLOGY_MAX_INSTANCE_MONITORS = WrapperProperty.new(
|
|
141
|
+
:cluster_topology_max_instance_monitors,
|
|
142
|
+
'Maximum number of parallel instance monitors during topology updates',
|
|
143
|
+
default_value: 16,
|
|
144
|
+
type: Integer
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# -- Blue/Green --
|
|
148
|
+
BGD_ID = WrapperProperty.new(:bgd_id, 'Blue/Green Deployment identifier that helps the driver to distinguish different deployments.',
|
|
149
|
+
default_value: '1', type: String)
|
|
150
|
+
BG_CONNECT_TIMEOUT_SEC = WrapperProperty.new(:bg_connect_timeout_sec, 'Blue/Green connect timeout in seconds',
|
|
151
|
+
default_value: 30.0, type: Float, validator: POSITIVE_FLOAT)
|
|
152
|
+
BG_INTERVAL_BASELINE_SEC = WrapperProperty.new(:bg_baseline_sec,
|
|
153
|
+
'Baseline Blue/Green Deployment status checking interval (in seconds).',
|
|
154
|
+
default_value: 60.0, type: Float, validator: POSITIVE_FLOAT)
|
|
155
|
+
BG_INTERVAL_INCREASED_SEC = WrapperProperty.new(:bg_increased_sec,
|
|
156
|
+
'Increased Blue/Green Deployment status checking interval (in seconds).',
|
|
157
|
+
default_value: 1.0, type: Float, validator: POSITIVE_FLOAT)
|
|
158
|
+
BG_INTERVAL_HIGH_SEC = WrapperProperty.new(:bg_high_sec, 'High Blue/Green Deployment status checking interval (in seconds).',
|
|
159
|
+
default_value: 0.1, type: Float, validator: POSITIVE_FLOAT)
|
|
160
|
+
BG_SWITCHOVER_TIMEOUT_SEC = WrapperProperty.new(:bg_switchover_timeout_sec, 'Blue/Green Deployment switchover timeout (in seconds).',
|
|
161
|
+
default_value: 180.0, type: Float, validator: POSITIVE_FLOAT)
|
|
162
|
+
|
|
163
|
+
# -- IAM Authentication --
|
|
164
|
+
IAM_HOST = WrapperProperty.new(:iam_host, 'Overrides the host used to generate the IAM token', default_value: nil, type: String)
|
|
165
|
+
IAM_PORT = WrapperProperty.new(:iam_port, 'Overrides the port used to generate the IAM token', default_value: nil, type: Integer)
|
|
166
|
+
IAM_REGION = WrapperProperty.new(:iam_region, 'Overrides the AWS region used to generate the IAM token', default_value: nil,
|
|
167
|
+
type: String)
|
|
168
|
+
IAM_EXPIRATION_SEC = WrapperProperty.new(:iam_expiration_sec,
|
|
169
|
+
'IAM token cache expiration in seconds.',
|
|
170
|
+
default_value: IAM_MAX_EXPIRATION_SEC, type: Float, validator: IAM_EXPIRATION_SEC_BOUND)
|
|
171
|
+
IAM_ACCESS_TOKEN_PROPERTY_NAME = WrapperProperty.new(:iam_access_token_property_name, 'Property name used to pass the IAM token',
|
|
172
|
+
default_value: :password, type: Symbol)
|
|
173
|
+
|
|
174
|
+
# -- Initial Connection Strategy --
|
|
175
|
+
INITIAL_CONNECTION_SUBSTITUTE_HOST = WrapperProperty.new(
|
|
176
|
+
:initial_connection_substitute_host,
|
|
177
|
+
'Role to substitute the endpoint with: writer, reader, any, or none. Auto-detects from endpoint type when not set.',
|
|
178
|
+
default_value: nil, type: String
|
|
179
|
+
)
|
|
180
|
+
INITIAL_CONNECTION_VERIFY_ROLE = WrapperProperty.new(
|
|
181
|
+
:initial_connection_verify_role,
|
|
182
|
+
'Role to verify after connecting: writer, reader, or none. Auto-detects from endpoint type when not set.',
|
|
183
|
+
default_value: nil, type: String
|
|
184
|
+
)
|
|
185
|
+
INITIAL_CONNECTION_HOST_SELECTOR_STRATEGY = WrapperProperty.new(
|
|
186
|
+
:initial_connection_host_selector_strategy,
|
|
187
|
+
'Strategy name for selecting a host when multiple match the substitution role.',
|
|
188
|
+
default_value: 'random', type: String
|
|
189
|
+
)
|
|
190
|
+
INITIAL_CONNECTION_RETRY_TIMEOUT_SEC = WrapperProperty.new(
|
|
191
|
+
:initial_connection_retry_timeout_sec,
|
|
192
|
+
'Maximum time in seconds to retry opening a connection.',
|
|
193
|
+
default_value: 30.0, type: Float, validator: POSITIVE_FLOAT
|
|
194
|
+
)
|
|
195
|
+
INITIAL_CONNECTION_RETRY_INTERVAL_SEC = WrapperProperty.new(
|
|
196
|
+
:initial_connection_retry_interval_sec,
|
|
197
|
+
'Time in seconds between retries when opening a connection.',
|
|
198
|
+
default_value: 1.0, type: Float, validator: POSITIVE_FLOAT
|
|
199
|
+
)
|
|
200
|
+
INITIAL_CONNECTION_WAIT_FOR_TOPOLOGY_SEC = WrapperProperty.new(
|
|
201
|
+
:initial_connection_wait_for_topology_sec,
|
|
202
|
+
'Maximum allowed time, in seconds, to wait for the cluster topology to be fetched before opening a new ' \
|
|
203
|
+
'connection. When set to a value greater than 0 and the topology is not yet available, the plugin ' \
|
|
204
|
+
'will block until the topology has been discovered (or this timeout is reached) instead of falling ' \
|
|
205
|
+
'back to connecting via the initial endpoint in the connection string.',
|
|
206
|
+
default_value: 0.0, type: Float, validator: NON_NEGATIVE_FLOAT
|
|
207
|
+
)
|
|
208
|
+
INITIAL_CONNECTION_INACTIVE_SUBSTITUTE_HOST = WrapperProperty.new(
|
|
209
|
+
:initial_connection_inactive_substitute_host,
|
|
210
|
+
'GDB-only: substitution role for inactive cluster writer endpoints. Valid values are writer or ' \
|
|
211
|
+
'none. When unset, the endpoint is passed through without substitution.',
|
|
212
|
+
default_value: nil, type: String
|
|
213
|
+
)
|
|
214
|
+
INITIAL_CONNECTION_INACTIVE_VERIFY_ROLE = WrapperProperty.new(
|
|
215
|
+
:initial_connection_inactive_verify_role,
|
|
216
|
+
'GDB-only: verification role for inactive cluster writer endpoints. Valid values are writer or ' \
|
|
217
|
+
'none. When unset, no role verification is performed unless a writer was substituted.',
|
|
218
|
+
default_value: nil, type: String
|
|
219
|
+
)
|
|
220
|
+
ACCESSIBLE_REGIONS = WrapperProperty.new(
|
|
221
|
+
:accessible_regions,
|
|
222
|
+
'Comma-separated list of AWS regions accessible by the application. All regions allowed when not set.',
|
|
223
|
+
default_value: nil, type: String
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# -- Custom Endpoint --
|
|
227
|
+
CUSTOM_ENDPOINT_INFO_REFRESH_RATE_SEC = WrapperProperty.new(
|
|
228
|
+
:custom_endpoint_info_refresh_rate_sec,
|
|
229
|
+
'How frequently custom endpoint monitors fetch custom endpoint info, in seconds.',
|
|
230
|
+
default_value: 30.0,
|
|
231
|
+
type: Float,
|
|
232
|
+
validator: POSITIVE_FLOAT
|
|
233
|
+
)
|
|
234
|
+
CUSTOM_ENDPOINT_INFO_REFRESH_RATE_BACKOFF_FACTOR = WrapperProperty.new(
|
|
235
|
+
:custom_endpoint_info_refresh_rate_backoff_factor,
|
|
236
|
+
'Exponential backoff factor for the custom endpoint monitor on throttling.',
|
|
237
|
+
default_value: 2,
|
|
238
|
+
type: Integer
|
|
239
|
+
)
|
|
240
|
+
CUSTOM_ENDPOINT_INFO_MAX_REFRESH_RATE_SEC = WrapperProperty.new(
|
|
241
|
+
:custom_endpoint_info_max_refresh_rate_sec,
|
|
242
|
+
'Maximum wait between custom endpoint info fetches, in seconds.',
|
|
243
|
+
default_value: 300.0,
|
|
244
|
+
type: Float,
|
|
245
|
+
validator: POSITIVE_FLOAT
|
|
246
|
+
)
|
|
247
|
+
WAIT_FOR_CUSTOM_ENDPOINT_INFO = WrapperProperty.new(
|
|
248
|
+
:wait_for_custom_endpoint_info,
|
|
249
|
+
'Controls whether to wait for custom endpoint info to become available before connecting or executing a ' \
|
|
250
|
+
'method. Waiting is only necessary if a connection to a given custom endpoint has not been opened or used ' \
|
|
251
|
+
'recently. Note that disabling this may result in occasional connections to instances outside of the ' \
|
|
252
|
+
'custom endpoint.',
|
|
253
|
+
default_value: true,
|
|
254
|
+
type: :boolean
|
|
255
|
+
)
|
|
256
|
+
WAIT_FOR_CUSTOM_ENDPOINT_INFO_TIMEOUT_SEC = WrapperProperty.new(
|
|
257
|
+
:wait_for_custom_endpoint_info_timeout_sec,
|
|
258
|
+
'Maximum time to wait for custom endpoint info, in seconds.',
|
|
259
|
+
default_value: 5.0,
|
|
260
|
+
type: Float,
|
|
261
|
+
validator: POSITIVE_FLOAT
|
|
262
|
+
)
|
|
263
|
+
CUSTOM_ENDPOINT_MONITOR_EXPIRATION_SEC = WrapperProperty.new(
|
|
264
|
+
:custom_endpoint_monitor_expiration_sec,
|
|
265
|
+
'How long a monitor runs without use before expiring, in seconds.',
|
|
266
|
+
default_value: 900.0,
|
|
267
|
+
type: Float,
|
|
268
|
+
validator: POSITIVE_FLOAT
|
|
269
|
+
)
|
|
270
|
+
CUSTOM_ENDPOINT_REGION = WrapperProperty.new(
|
|
271
|
+
:custom_endpoint_region,
|
|
272
|
+
'Region of the custom endpoint. Parsed from the URL when not specified.',
|
|
273
|
+
default_value: nil,
|
|
274
|
+
type: String
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# -- Secrets Manager --
|
|
278
|
+
SECRET_ID = WrapperProperty.new(
|
|
279
|
+
:secret_id, 'The name or ARN of the secret to retrieve', default_value: nil, type: String
|
|
280
|
+
)
|
|
281
|
+
SECRET_REGION = WrapperProperty.new(
|
|
282
|
+
:secret_region, 'AWS region for Secrets Manager API calls', default_value: nil, type: String
|
|
283
|
+
)
|
|
284
|
+
SECRET_ENDPOINT = WrapperProperty.new(
|
|
285
|
+
:secret_endpoint, 'Custom endpoint URL for Secrets Manager', default_value: nil, type: String
|
|
286
|
+
)
|
|
287
|
+
SECRET_USERNAME_KEY = WrapperProperty.new(
|
|
288
|
+
:secret_username_key, 'JSON key containing the username in the secret',
|
|
289
|
+
default_value: 'username', type: String
|
|
290
|
+
)
|
|
291
|
+
SECRET_PASSWORD_KEY = WrapperProperty.new(
|
|
292
|
+
:secret_password_key, 'JSON key containing the password in the secret',
|
|
293
|
+
default_value: 'password', type: String
|
|
294
|
+
)
|
|
295
|
+
SECRET_EXPIRATION_SEC = WrapperProperty.new(
|
|
296
|
+
:secret_expiration_sec, 'Cached secret expiration in seconds (minimum: 300)',
|
|
297
|
+
default_value: 870.0, type: Float, validator: POSITIVE_FLOAT
|
|
298
|
+
)
|
|
299
|
+
SECRET_ROTATION_RETRY_TIMEOUT_SEC = WrapperProperty.new(
|
|
300
|
+
:secret_rotation_retry_timeout_sec,
|
|
301
|
+
'Max time in seconds to retry connecting during a secret rotation window (0 = disabled)',
|
|
302
|
+
default_value: 0.0, type: Float, validator: NON_NEGATIVE_FLOAT
|
|
303
|
+
)
|
|
304
|
+
SECRET_ROTATION_RETRY_BASE_DELAY_SEC = WrapperProperty.new(
|
|
305
|
+
:secret_rotation_retry_base_delay_sec,
|
|
306
|
+
'Base delay in seconds for exponential backoff during rotation retry',
|
|
307
|
+
default_value: 0.5, type: Float, validator: POSITIVE_FLOAT
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# -- KMS Encryption --
|
|
311
|
+
ENCRYPTION_KMS_REGION = WrapperProperty.new(
|
|
312
|
+
:encryption_kms_region,
|
|
313
|
+
'AWS region for KMS calls made by the kms_encryption plugin. Required: falls back to the ' \
|
|
314
|
+
'AWS_REGION or AWS_DEFAULT_REGION environment variable, and is rejected if none is set.',
|
|
315
|
+
default_value: nil, type: String
|
|
316
|
+
)
|
|
317
|
+
ENCRYPTION_KMS_ENDPOINT = WrapperProperty.new(
|
|
318
|
+
:encryption_kms_endpoint, 'Custom endpoint URL for KMS', default_value: nil, type: String
|
|
319
|
+
)
|
|
320
|
+
ENCRYPTION_ALLOWED_MASTER_KEY_ARNS = WrapperProperty.new(
|
|
321
|
+
:encryption_allowed_master_key_arns,
|
|
322
|
+
'The KMS master keys the kms_encryption plugin may use, as a comma-separated string or an array. ' \
|
|
323
|
+
'Required by the plugin. Each entry must match a key_storage.master_key_arn value exactly; a stored ' \
|
|
324
|
+
'data key that names any other master key (or none) is refused before KMS is called.',
|
|
325
|
+
default_value: nil
|
|
326
|
+
)
|
|
327
|
+
ENCRYPTION_METADATA_SCHEMA = WrapperProperty.new(
|
|
328
|
+
:encryption_metadata_schema,
|
|
329
|
+
'Schema holding the encryption_metadata and key_storage tables',
|
|
330
|
+
default_value: 'encrypt', type: String
|
|
331
|
+
)
|
|
332
|
+
ENCRYPTION_METADATA_CACHE_ENABLED = WrapperProperty.new(
|
|
333
|
+
:encryption_metadata_cache_enabled,
|
|
334
|
+
'Cache the kms_encryption metadata in memory instead of querying it per statement',
|
|
335
|
+
default_value: true, type: :boolean
|
|
336
|
+
)
|
|
337
|
+
ENCRYPTION_METADATA_CACHE_EXPIRATION_SEC = WrapperProperty.new(
|
|
338
|
+
:encryption_metadata_cache_expiration_sec,
|
|
339
|
+
'How long cached kms_encryption metadata stays valid, in seconds',
|
|
340
|
+
default_value: 3600.0, type: Float, validator: POSITIVE_FLOAT
|
|
341
|
+
)
|
|
342
|
+
ENCRYPTION_METADATA_CACHE_REFRESH_INTERVAL_SEC = WrapperProperty.new(
|
|
343
|
+
:encryption_metadata_cache_refresh_interval_sec,
|
|
344
|
+
'How often the kms_encryption metadata is refreshed in the background, in seconds (0 disables background refresh)',
|
|
345
|
+
default_value: 300.0, type: Float, validator: NON_NEGATIVE_FLOAT
|
|
346
|
+
)
|
|
347
|
+
ENCRYPTION_KEY_MANAGEMENT_MAX_RETRIES = WrapperProperty.new(
|
|
348
|
+
:encryption_key_management_max_retries,
|
|
349
|
+
'Maximum number of retries for throttled or failed KMS calls',
|
|
350
|
+
default_value: 3, type: Integer, validator: NON_NEGATIVE_INTEGER
|
|
351
|
+
)
|
|
352
|
+
ENCRYPTION_KEY_MANAGEMENT_RETRY_BACKOFF_BASE_SEC = WrapperProperty.new(
|
|
353
|
+
:encryption_key_management_retry_backoff_base_sec,
|
|
354
|
+
'Base delay in seconds for the exponential backoff between KMS retries',
|
|
355
|
+
default_value: 0.1, type: Float, validator: POSITIVE_FLOAT
|
|
356
|
+
)
|
|
357
|
+
ENCRYPTION_AUDIT_LOGGING_ENABLED = WrapperProperty.new(
|
|
358
|
+
:encryption_audit_logging_enabled,
|
|
359
|
+
'Log an audit record for every key management, kms_encryption, and decryption operation',
|
|
360
|
+
default_value: false, type: :boolean
|
|
361
|
+
)
|
|
362
|
+
ENCRYPTION_RETURN_UNVERIFIED_DATA = WrapperProperty.new(
|
|
363
|
+
:encryption_return_unverified_data,
|
|
364
|
+
'On read, return a value as it is stored when it cannot be confirmed to be valid encrypted data ' \
|
|
365
|
+
'(too short to be a payload, or a failed HMAC) instead of raising. Intended only for reading data ' \
|
|
366
|
+
'written before kms_encryption was enabled. MUST NOT be enabled in production: it lets unverified ' \
|
|
367
|
+
'data reach the application. A value that verifies but cannot be decrypted still raises.',
|
|
368
|
+
default_value: false, type: :boolean
|
|
369
|
+
)
|
|
370
|
+
ENCRYPTION_DATA_KEY_CACHE_ENABLED = WrapperProperty.new(
|
|
371
|
+
:encryption_data_key_cache_enabled,
|
|
372
|
+
'Cache decrypted data keys in memory to avoid a KMS Decrypt call per statement',
|
|
373
|
+
default_value: true, type: :boolean
|
|
374
|
+
)
|
|
375
|
+
ENCRYPTION_DATA_KEY_CACHE_MAX_SIZE = WrapperProperty.new(
|
|
376
|
+
:encryption_data_key_cache_max_size,
|
|
377
|
+
'Maximum number of decrypted data keys held in memory',
|
|
378
|
+
default_value: 1000, type: Integer, validator: POSITIVE_INTEGER
|
|
379
|
+
)
|
|
380
|
+
ENCRYPTION_DATA_KEY_CACHE_EXPIRATION_SEC = WrapperProperty.new(
|
|
381
|
+
:encryption_data_key_cache_expiration_sec,
|
|
382
|
+
'How long a decrypted data key stays cached, in seconds',
|
|
383
|
+
default_value: 300.0, type: Float, validator: POSITIVE_FLOAT
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
# Built once at load time from constants — used by parser to split props
|
|
387
|
+
KNOWN_PROPERTIES = constants
|
|
388
|
+
.filter_map { |c| const_get(c) if const_get(c).is_a?(WrapperProperty) }
|
|
389
|
+
.to_h { |prop| [prop.name, prop] }
|
|
390
|
+
.freeze
|
|
391
|
+
|
|
392
|
+
# Known prefixes for internal connection overrides. Each prefix maps to a key
|
|
393
|
+
# used in ConnectionConfig#prefixed_wrapper_config and ConnectionConfig#prefixed_driver_config.
|
|
394
|
+
# Plugins define their own prefix here.
|
|
395
|
+
TOPOLOGY_MONITORING_PREFIX = 'topology_monitoring_'
|
|
396
|
+
BG_MONITORING_PROPERTY_PREFIX = 'bg_monitoring_'
|
|
397
|
+
|
|
398
|
+
KNOWN_PREFIXES = [
|
|
399
|
+
TOPOLOGY_MONITORING_PREFIX,
|
|
400
|
+
BG_MONITORING_PROPERTY_PREFIX
|
|
401
|
+
].freeze
|
|
402
|
+
|
|
403
|
+
BG_STORAGE_NAMESPACE = '941d00a8-8238-4f7d-bf59-771bff783a8e'
|
|
404
|
+
|
|
405
|
+
def self.wrapper_property?(key)
|
|
406
|
+
KNOWN_PROPERTIES.key?(key.to_sym)
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
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
|
+
MethodInfo = Data.define(:name, :check_bounded_connection) do
|
|
19
|
+
def to_s
|
|
20
|
+
name
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module RubyMethod
|
|
25
|
+
def self.define(name, check_bounded_connection:)
|
|
26
|
+
MethodInfo.new(name:, check_bounded_connection:)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# -- Internal pipeline methods --
|
|
30
|
+
CONNECT = define('connect', check_bounded_connection: false)
|
|
31
|
+
|
|
32
|
+
# -- Connection methods --
|
|
33
|
+
CONNECTION_CLOSE = define('connection.close', check_bounded_connection: false)
|
|
34
|
+
CONNECTION_RESET = define('connection.reset', check_bounded_connection: false)
|
|
35
|
+
CONNECTION_PREPARE = define('connection.prepare', check_bounded_connection: false)
|
|
36
|
+
CONNECTION_ESCAPE = define('connection.escape', check_bounded_connection: false)
|
|
37
|
+
|
|
38
|
+
# -- Connection methods (mysql2-specific) --
|
|
39
|
+
CONNECTION_PING = define('connection.ping', check_bounded_connection: false)
|
|
40
|
+
CONNECTION_QUERY = define('connection.query', check_bounded_connection: false)
|
|
41
|
+
CONNECTION_ASYNC_RESULT = define('connection.async_result', check_bounded_connection: true)
|
|
42
|
+
CONNECTION_SELECT_DB = define('connection.select_db', check_bounded_connection: false)
|
|
43
|
+
CONNECTION_MORE_RESULTS = define('connection.more_results?', check_bounded_connection: true)
|
|
44
|
+
CONNECTION_NEXT_RESULT = define('connection.next_result', check_bounded_connection: true)
|
|
45
|
+
CONNECTION_STORE_RESULT = define('connection.store_result', check_bounded_connection: true)
|
|
46
|
+
CONNECTION_ABANDON_RESULTS = define('connection.abandon_results!', check_bounded_connection: true)
|
|
47
|
+
CONNECTION_SET_SERVER_OPTION = define('connection.set_server_option', check_bounded_connection: false)
|
|
48
|
+
|
|
49
|
+
# -- Connection methods (pg-specific) --
|
|
50
|
+
CONNECTION_EXEC = define('connection.exec', check_bounded_connection: false)
|
|
51
|
+
CONNECTION_ASYNC_EXEC = define('connection.async_exec', check_bounded_connection: false)
|
|
52
|
+
CONNECTION_EXEC_PARAMS = define('connection.exec_params', check_bounded_connection: false)
|
|
53
|
+
CONNECTION_EXEC_PREPARED = define('connection.exec_prepared', check_bounded_connection: true)
|
|
54
|
+
CONNECTION_DESCRIBE_PREPARED = define('connection.describe_prepared', check_bounded_connection: true)
|
|
55
|
+
CONNECTION_DESCRIBE_PORTAL = define('connection.describe_portal', check_bounded_connection: true)
|
|
56
|
+
CONNECTION_TRANSACTION = define('connection.transaction', check_bounded_connection: false)
|
|
57
|
+
CONNECTION_COPY_DATA = define('connection.copy_data', check_bounded_connection: false)
|
|
58
|
+
CONNECTION_PUT_COPY_DATA = define('connection.put_copy_data', check_bounded_connection: true)
|
|
59
|
+
CONNECTION_GET_COPY_DATA = define('connection.get_copy_data', check_bounded_connection: true)
|
|
60
|
+
CONNECTION_PUT_COPY_END = define('connection.put_copy_end', check_bounded_connection: true)
|
|
61
|
+
CONNECTION_SEND_QUERY = define('connection.send_query', check_bounded_connection: false)
|
|
62
|
+
CONNECTION_SEND_QUERY_PARAMS = define('connection.send_query_params', check_bounded_connection: false)
|
|
63
|
+
CONNECTION_SEND_QUERY_PREPARED = define('connection.send_query_prepared', check_bounded_connection: true)
|
|
64
|
+
CONNECTION_SEND_PREPARE = define('connection.send_prepare', check_bounded_connection: false)
|
|
65
|
+
CONNECTION_GET_RESULT = define('connection.get_result', check_bounded_connection: true)
|
|
66
|
+
CONNECTION_GET_LAST_RESULT = define('connection.get_last_result', check_bounded_connection: true)
|
|
67
|
+
CONNECTION_CANCEL = define('connection.cancel', check_bounded_connection: false)
|
|
68
|
+
CONNECTION_SET_CLIENT_ENCODING = define('connection.set_client_encoding', check_bounded_connection: false)
|
|
69
|
+
CONNECTION_WAIT_FOR_NOTIFY = define('connection.wait_for_notify', check_bounded_connection: false)
|
|
70
|
+
CONNECTION_NOTIFIES = define('connection.notifies', check_bounded_connection: false)
|
|
71
|
+
CONNECTION_CONSUME_INPUT = define('connection.consume_input', check_bounded_connection: false)
|
|
72
|
+
CONNECTION_FLUSH = define('connection.flush', check_bounded_connection: false)
|
|
73
|
+
CONNECTION_LO_OPEN = define('connection.lo_open', check_bounded_connection: false)
|
|
74
|
+
CONNECTION_LO_READ = define('connection.lo_read', check_bounded_connection: true)
|
|
75
|
+
CONNECTION_LO_WRITE = define('connection.lo_write', check_bounded_connection: true)
|
|
76
|
+
CONNECTION_LO_CLOSE = define('connection.lo_close', check_bounded_connection: true)
|
|
77
|
+
CONNECTION_CLOSE_PREPARED = define('connection.close_prepared', check_bounded_connection: true)
|
|
78
|
+
CONNECTION_CLOSE_PORTAL = define('connection.close_portal', check_bounded_connection: true)
|
|
79
|
+
CONNECTION_DISCARD_RESULTS = define('connection.discard_results', check_bounded_connection: true)
|
|
80
|
+
CONNECTION_SEND_DESCRIBE_PREPARED = define('connection.send_describe_prepared', check_bounded_connection: true)
|
|
81
|
+
CONNECTION_SEND_DESCRIBE_PORTAL = define('connection.send_describe_portal', check_bounded_connection: true)
|
|
82
|
+
CONNECTION_SEND_FLUSH_REQUEST = define('connection.send_flush_request', check_bounded_connection: true)
|
|
83
|
+
CONNECTION_PIPELINE_SYNC = define('connection.pipeline_sync', check_bounded_connection: true)
|
|
84
|
+
CONNECTION_SEND_PIPELINE_SYNC = define('connection.send_pipeline_sync', check_bounded_connection: true)
|
|
85
|
+
CONNECTION_BLOCK = define('connection.block', check_bounded_connection: true)
|
|
86
|
+
CONNECTION_RESET_START = define('connection.reset_start', check_bounded_connection: false)
|
|
87
|
+
CONNECTION_RESET_POLL = define('connection.reset_poll', check_bounded_connection: false)
|
|
88
|
+
CONNECTION_ENCRYPT_PASSWORD = define('connection.encrypt_password', check_bounded_connection: false)
|
|
89
|
+
CONNECTION_SET_DEFAULT_ENCODING = define('connection.set_default_encoding', check_bounded_connection: false)
|
|
90
|
+
CONNECTION_INTERNAL_ENCODING_SET = define('connection.internal_encoding=', check_bounded_connection: false)
|
|
91
|
+
CONNECTION_LO_CREAT = define('connection.lo_creat', check_bounded_connection: false)
|
|
92
|
+
CONNECTION_LO_CREATE = define('connection.lo_create', check_bounded_connection: false)
|
|
93
|
+
CONNECTION_LO_IMPORT = define('connection.lo_import', check_bounded_connection: false)
|
|
94
|
+
CONNECTION_LO_EXPORT = define('connection.lo_export', check_bounded_connection: false)
|
|
95
|
+
CONNECTION_LO_UNLINK = define('connection.lo_unlink', check_bounded_connection: false)
|
|
96
|
+
CONNECTION_LO_LSEEK = define('connection.lo_lseek', check_bounded_connection: true)
|
|
97
|
+
CONNECTION_LO_TELL = define('connection.lo_tell', check_bounded_connection: true)
|
|
98
|
+
CONNECTION_LO_TRUNCATE = define('connection.lo_truncate', check_bounded_connection: true)
|
|
99
|
+
|
|
100
|
+
# -- Statement methods --
|
|
101
|
+
STATEMENT_EXECUTE = define('statement.execute', check_bounded_connection: true)
|
|
102
|
+
STATEMENT_CLOSE = define('statement.close', check_bounded_connection: false)
|
|
103
|
+
|
|
104
|
+
# -- Result methods --
|
|
105
|
+
RESULT_EACH = define('result.each', check_bounded_connection: true)
|
|
106
|
+
RESULT_EACH_ROW = define('result.each_row', check_bounded_connection: true)
|
|
107
|
+
RESULT_TO_A = define('result.to_a', check_bounded_connection: true)
|
|
108
|
+
RESULT_BRACKET = define('result.[]', check_bounded_connection: true)
|
|
109
|
+
RESULT_VALUES = define('result.values', check_bounded_connection: true)
|
|
110
|
+
RESULT_COLUMN_VALUES = define('result.column_values', check_bounded_connection: true)
|
|
111
|
+
RESULT_FIELD_VALUES = define('result.field_values', check_bounded_connection: true)
|
|
112
|
+
RESULT_TUPLE = define('result.tuple', check_bounded_connection: true)
|
|
113
|
+
RESULT_TUPLE_VALUES = define('result.tuple_values', check_bounded_connection: true)
|
|
114
|
+
RESULT_GETVALUE = define('result.getvalue', check_bounded_connection: true)
|
|
115
|
+
RESULT_STREAM_EACH = define('result.stream_each', check_bounded_connection: true)
|
|
116
|
+
RESULT_STREAM_EACH_ROW = define('result.stream_each_row', check_bounded_connection: true)
|
|
117
|
+
RESULT_STREAM_EACH_TUPLE = define('result.stream_each_tuple', check_bounded_connection: true)
|
|
118
|
+
# Freeing an unbuffered result has to read whatever rows are still on the wire before it can let
|
|
119
|
+
# the result go, so it is a call to the server on the connection the statement was sent on.
|
|
120
|
+
RESULT_FREE = define('result.free', check_bounded_connection: true)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
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 'monitor'
|
|
18
|
+
require_relative '../utils/host_list_utils'
|
|
19
|
+
|
|
20
|
+
module AwsAdvancedRubyDriverWrapper
|
|
21
|
+
module Services
|
|
22
|
+
class ConnectionService
|
|
23
|
+
attr_reader :current_connection, :config
|
|
24
|
+
|
|
25
|
+
# @param config [Utils::ConnectionConfig] the parsed connection configuration
|
|
26
|
+
def initialize(service_container, config)
|
|
27
|
+
@service_container = service_container
|
|
28
|
+
@config = config
|
|
29
|
+
@current_connection = nil
|
|
30
|
+
@current_host_info = config.initial_host_info
|
|
31
|
+
@connection_switch_lock = Monitor.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [Host::HostInfo, nil] host info for the current connection
|
|
35
|
+
def current_host_info
|
|
36
|
+
return @current_host_info if @current_host_info
|
|
37
|
+
|
|
38
|
+
@current_host_info = @config.initial_host_info
|
|
39
|
+
return @current_host_info if @current_host_info
|
|
40
|
+
|
|
41
|
+
host_service = @service_container.host_service
|
|
42
|
+
hosts = host_service.all_hosts
|
|
43
|
+
raise Errors::AwsError, 'Attempted to access the current host list, but the host list is empty' if host_service.all_hosts.empty?
|
|
44
|
+
|
|
45
|
+
@current_host_info = Utils::HostListUtils.writer(hosts)
|
|
46
|
+
allowed_hosts = host_service.hosts
|
|
47
|
+
if @current_host_info && !Utils::HostListUtils.contains_url?(allowed_hosts, @current_host_info.url)
|
|
48
|
+
raise Errors::AwsError,
|
|
49
|
+
'Current host is not in the list of allowed hosts: ' \
|
|
50
|
+
"current_host=#{@current_host_info.url}, " \
|
|
51
|
+
"allowed_hosts=#{Utils::HostListUtils.to_host_urls_s(allowed_hosts)}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
@current_host_info = hosts[0] if @current_host_info.nil? && hosts.any?
|
|
55
|
+
|
|
56
|
+
if @current_host_info.nil?
|
|
57
|
+
raise Errors::AwsError,
|
|
58
|
+
'Unable to identify a current host from the available host list'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@current_host_info
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @param connection [Object] the new connection
|
|
65
|
+
# @param host_info [Host::HostInfo] host info for the new connection
|
|
66
|
+
def update_current_connection(connection, host_info)
|
|
67
|
+
if connection.nil?
|
|
68
|
+
origin = caller(1, 5)
|
|
69
|
+
raise Errors::AwsError.new(
|
|
70
|
+
'[ConnectionService] update_current_connection called with nil connection! ' \
|
|
71
|
+
"host_info=#{host_info&.host}, caller=#{origin.join(' <- ')}",
|
|
72
|
+
connection_broken: true
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
@connection_switch_lock.synchronize do
|
|
77
|
+
# Close the connection being replaced so it does not leak.
|
|
78
|
+
previous = @current_connection
|
|
79
|
+
close_quietly(previous) unless previous.nil? || previous.equal?(connection)
|
|
80
|
+
|
|
81
|
+
@current_connection = connection
|
|
82
|
+
@current_host_info = host_info
|
|
83
|
+
@service_container.session_state_service.reset
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @return [Symbol] the driver name, e.g. :postgresql or :mysql2
|
|
88
|
+
def driver_name
|
|
89
|
+
@config.driver_name
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [Hash] wrapper-specific properties
|
|
93
|
+
def wrapper_props
|
|
94
|
+
@config.wrapper_props
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @return [Host::HostInfo, nil] the initial host info from config
|
|
98
|
+
def initial_host_info
|
|
99
|
+
@config.initial_host_info
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def initial_host_info=(host_info)
|
|
103
|
+
@config.initial_host_info = host_info
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @return [Hash{String => Hash}] prefixed wrapper props keyed by prefix (already stripped)
|
|
107
|
+
def prefixed_wrapper_config
|
|
108
|
+
@config.prefixed_wrapper_config
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# @return [Hash{String => Hash}] prefixed driver props keyed by prefix (already stripped)
|
|
112
|
+
def prefixed_driver_config
|
|
113
|
+
@config.prefixed_driver_config
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @return [Hash] driver-specific properties
|
|
117
|
+
def driver_props
|
|
118
|
+
@config.driver_props
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Whether the initial connection URL specified multiple hosts.
|
|
122
|
+
#
|
|
123
|
+
# @return [Boolean]
|
|
124
|
+
def multi_host_url?
|
|
125
|
+
@config.multi_host_url?
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @return [Boolean] whether the driver is PostgreSQL
|
|
129
|
+
def pg?
|
|
130
|
+
driver_name == :postgresql
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
# Closes a connection, ignoring any error. Used to release a connection that is being replaced.
|
|
136
|
+
def close_quietly(conn)
|
|
137
|
+
@service_container.dialect_service.driver_dialect.close_connection(conn)
|
|
138
|
+
rescue StandardError
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|