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.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +23 -0
  3. data/LICENSE +175 -0
  4. data/NOTICE +1 -0
  5. data/README.md +168 -0
  6. data/THIRD-PARTY-LICENSES +473 -0
  7. data/aws_advanced_ruby_driver_wrapper.gemspec +73 -0
  8. data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_mysql2_adapter.rb +73 -0
  9. data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_postgresql_adapter.rb +95 -0
  10. data/lib/aws_advanced_ruby_driver_wrapper/custom_configuration.rb +58 -0
  11. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_mysql_dialect.rb +103 -0
  12. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_pg_dialect.rb +124 -0
  13. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/dialect_codes.rb +38 -0
  14. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_mysql_dialect.rb +91 -0
  15. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_pg_dialect.rb +92 -0
  16. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_mysql_dialect.rb +95 -0
  17. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_pg_dialect.rb +86 -0
  18. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/mysql_dialect.rb +98 -0
  19. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/pg_dialect.rb +95 -0
  20. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_mysql_dialect.rb +88 -0
  21. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_pg_dialect.rb +86 -0
  22. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/unknown_dialect.rb +72 -0
  23. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/utils/dialect_utils.rb +71 -0
  24. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect.rb +154 -0
  25. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect_manager.rb +55 -0
  26. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/mysql_driver_dialect.rb +165 -0
  27. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/pg_driver_dialect.rb +201 -0
  28. data/lib/aws_advanced_ruby_driver_wrapper/errors/error_handler.rb +62 -0
  29. data/lib/aws_advanced_ruby_driver_wrapper/errors/mysql_error_handler.rb +80 -0
  30. data/lib/aws_advanced_ruby_driver_wrapper/errors/pg_error_handler.rb +126 -0
  31. data/lib/aws_advanced_ruby_driver_wrapper/errors.rb +59 -0
  32. data/lib/aws_advanced_ruby_driver_wrapper/host/connection_string_host_list_provider.rb +95 -0
  33. data/lib/aws_advanced_ruby_driver_wrapper/host/global_aurora_host_list_provider.rb +65 -0
  34. data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability.rb +24 -0
  35. data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability_strategy.rb +27 -0
  36. data/lib/aws_advanced_ruby_driver_wrapper/host/host_info.rb +137 -0
  37. data/lib/aws_advanced_ruby_driver_wrapper/host/host_role.rb +25 -0
  38. data/lib/aws_advanced_ruby_driver_wrapper/host/random_host_selector.rb +40 -0
  39. data/lib/aws_advanced_ruby_driver_wrapper/host/rds_host_list_provider.rb +206 -0
  40. data/lib/aws_advanced_ruby_driver_wrapper/logging.rb +110 -0
  41. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/cluster_topology_monitor.rb +709 -0
  42. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/global_cluster_topology_monitor.rb +72 -0
  43. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor.rb +99 -0
  44. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_connection.rb +57 -0
  45. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_state.rb +25 -0
  46. data/lib/aws_advanced_ruby_driver_wrapper/mysql.rb +429 -0
  47. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/blue_green_plugin.rb +205 -0
  48. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/host_mapper.rb +132 -0
  49. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/iam_host_tracker.rb +84 -0
  50. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interim_status.rb +92 -0
  51. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interval_rate.rb +27 -0
  52. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase.rb +69 -0
  53. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_event_log.rb +85 -0
  54. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_time_info.rb +25 -0
  55. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/role.rb +38 -0
  56. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/base_routing.rb +83 -0
  57. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/reject_connect_routing.rb +40 -0
  58. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/substitute_connect_routing.rb +136 -0
  59. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_connect_routing.rb +53 -0
  60. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_execute_routing.rb +52 -0
  61. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_until_corresponding_host_found_connect_routing.rb +83 -0
  62. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status.rb +68 -0
  63. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_builder.rb +244 -0
  64. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_info.rb +30 -0
  65. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_monitor.rb +564 -0
  66. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_provider.rb +414 -0
  67. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_state.rb +98 -0
  68. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_timer.rb +46 -0
  69. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_monitor.rb +266 -0
  70. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_plugin.rb +158 -0
  71. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/info.rb +111 -0
  72. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/member_list_type.rb +31 -0
  73. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/role.rb +45 -0
  74. data/lib/aws_advanced_ruby_driver_wrapper/plugins/default_plugin.rb +108 -0
  75. data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_mode.rb +43 -0
  76. data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_plugin.rb +467 -0
  77. data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_mode.rb +68 -0
  78. data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_plugin.rb +403 -0
  79. data/lib/aws_advanced_ruby_driver_wrapper/plugins/iam_auth_plugin.rb +159 -0
  80. data/lib/aws_advanced_ruby_driver_wrapper/plugins/initial_connection_strategy_plugin.rb +485 -0
  81. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/audit_logger.rb +157 -0
  82. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_cipher.rb +159 -0
  83. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_encryption_config.rb +61 -0
  84. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/connection_source.rb +91 -0
  85. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/data_key_cache.rb +220 -0
  86. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_algorithm.rb +75 -0
  87. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_config.rb +146 -0
  88. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_service.rb +391 -0
  89. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/error_context.rb +198 -0
  90. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/errors.rb +259 -0
  91. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_management_utility.rb +435 -0
  92. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_manager.rb +378 -0
  93. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_metadata.rb +86 -0
  94. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_plugin.rb +890 -0
  95. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_utility.rb +281 -0
  96. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/metadata_manager.rb +332 -0
  97. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sanitizer.rb +147 -0
  98. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_name.rb +70 -0
  99. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_validator.rb +211 -0
  100. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sql_runner.rb +147 -0
  101. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/type_marker.rb +109 -0
  102. data/lib/aws_advanced_ruby_driver_wrapper/plugins/secrets_manager_plugin.rb +358 -0
  103. data/lib/aws_advanced_ruby_driver_wrapper/postgresql.rb +659 -0
  104. data/lib/aws_advanced_ruby_driver_wrapper/property_definition.rb +409 -0
  105. data/lib/aws_advanced_ruby_driver_wrapper/ruby_method.rb +122 -0
  106. data/lib/aws_advanced_ruby_driver_wrapper/services/connection_service.rb +143 -0
  107. data/lib/aws_advanced_ruby_driver_wrapper/services/dialect_service.rb +267 -0
  108. data/lib/aws_advanced_ruby_driver_wrapper/services/host_service.rb +199 -0
  109. data/lib/aws_advanced_ruby_driver_wrapper/services/monitor_service.rb +186 -0
  110. data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_call_context.rb +63 -0
  111. data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_manager.rb +273 -0
  112. data/lib/aws_advanced_ruby_driver_wrapper/services/service_container.rb +30 -0
  113. data/lib/aws_advanced_ruby_driver_wrapper/services/service_utility.rb +78 -0
  114. data/lib/aws_advanced_ruby_driver_wrapper/services/session_state_service.rb +56 -0
  115. data/lib/aws_advanced_ruby_driver_wrapper/utils/accessible_regions.rb +52 -0
  116. data/lib/aws_advanced_ruby_driver_wrapper/utils/ar_constants.rb +25 -0
  117. data/lib/aws_advanced_ruby_driver_wrapper/utils/aurora_topology_utils.rb +99 -0
  118. data/lib/aws_advanced_ruby_driver_wrapper/utils/aws_credentials_utils.rb +62 -0
  119. data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config.rb +91 -0
  120. data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config_parser.rb +368 -0
  121. data/lib/aws_advanced_ruby_driver_wrapper/utils/conversion_utils.rb +51 -0
  122. data/lib/aws_advanced_ruby_driver_wrapper/utils/events/batching_event_publisher.rb +119 -0
  123. data/lib/aws_advanced_ruby_driver_wrapper/utils/events/data_access_event.rb +26 -0
  124. data/lib/aws_advanced_ruby_driver_wrapper/utils/events/monitor_reset_event.rb +26 -0
  125. data/lib/aws_advanced_ruby_driver_wrapper/utils/global_aurora_topology_utils.rb +185 -0
  126. data/lib/aws_advanced_ruby_driver_wrapper/utils/host_list_utils.rb +27 -0
  127. data/lib/aws_advanced_ruby_driver_wrapper/utils/iam_auth_utils.rb +112 -0
  128. data/lib/aws_advanced_ruby_driver_wrapper/utils/multi_az_topology_utils.rb +117 -0
  129. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/encryption_annotation_parser.rb +99 -0
  130. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/mysql_statement_analyzer.rb +641 -0
  131. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/pg_statement_analyzer.rb +502 -0
  132. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_analysis.rb +63 -0
  133. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_type.rb +35 -0
  134. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint.rb +27 -0
  135. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint_parser.rb +50 -0
  136. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/sql_parser.rb +139 -0
  137. data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_url_type.rb +71 -0
  138. data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_utils.rb +575 -0
  139. data/lib/aws_advanced_ruby_driver_wrapper/utils/retry_util.rb +153 -0
  140. data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_encoding.rb +56 -0
  141. data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_method_analyzer.rb +195 -0
  142. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/cache_entry.rb +56 -0
  143. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/expiration_cache.rb +108 -0
  144. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/sliding_expiration_cache.rb +137 -0
  145. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/storage_service.rb +172 -0
  146. data/lib/aws_advanced_ruby_driver_wrapper/utils/topology_utils.rb +127 -0
  147. data/lib/aws_advanced_ruby_driver_wrapper/version.rb +19 -0
  148. data/lib/aws_advanced_ruby_driver_wrapper/wrapper_property.rb +64 -0
  149. data/lib/aws_advanced_ruby_driver_wrapper.rb +116 -0
  150. metadata +227 -0
@@ -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 'active_record/connection_adapters/postgresql_adapter'
18
+ require_relative '../postgresql'
19
+ require_relative '../errors'
20
+ require_relative '../utils/ar_constants'
21
+
22
+ module ActiveRecord
23
+ module ConnectionAdapters
24
+ class AwsPostgreSQLAdapter < PostgreSQLAdapter
25
+ ADAPTER_NAME = 'AwsPostgreSQL'
26
+
27
+ # ActiveRecord-only keys that should not be passed to the wrapper or native driver.
28
+ AR_ONLY_KEYS = (AwsAdvancedRubyDriverWrapper::Utils::AR_COMMON_KEYS + %i[advisory_locks schema_search_path]).freeze
29
+
30
+ # ActiveRecord uses :username and :database, but the PG gem expects :user and :dbname.
31
+ # The parent adapter translates these in @connection_parameters, but also strips
32
+ # non-PG keys (including wrapper properties) via slice!. Since we rebuild from @config
33
+ # to preserve wrapper properties, we need to redo this translation ourselves.
34
+ AR_TO_PG_KEY_MAP = { username: :user, database: :dbname }.freeze
35
+
36
+ def initialize(...)
37
+ # Capture the full config before the parent's initialize strips it
38
+ # down to only PG-recognized keys in @connection_parameters.
39
+ super
40
+ @connection_broken = false
41
+ # Store non-AR parameters in @wrapper_config.
42
+ wrapper_config = @config.compact.except(*AR_ONLY_KEYS)
43
+ # Remap ActiveRecord key names to PG gem key names.
44
+ AR_TO_PG_KEY_MAP.each { |ar_key, pg_key| wrapper_config[pg_key] = wrapper_config.delete(ar_key) if wrapper_config.key?(ar_key) }
45
+ @wrapper_config = wrapper_config
46
+ end
47
+
48
+ def adapter_name = ADAPTER_NAME
49
+
50
+ # Note that this config includes wrapper properties.
51
+ def self.new_client(config)
52
+ AwsAdvancedRubyDriverWrapper::WrapperPgConnection.new(**config)
53
+ end
54
+
55
+ def connect
56
+ @connection_broken = false
57
+ # Override @connection_parameters with the full config so the parent's
58
+ # call to new_client(@connection_parameters) includes wrapper properties.
59
+ @connection_parameters = @wrapper_config
60
+ super
61
+ end
62
+
63
+ def reconnect
64
+ @connection_broken = false
65
+ super
66
+ end
67
+
68
+ def active?
69
+ return false if @connection_broken
70
+
71
+ super
72
+ end
73
+
74
+ def translate_exception(exception, message:, sql:, binds:)
75
+ return super unless exception.is_a?(AwsAdvancedRubyDriverWrapper::Errors::AwsError)
76
+
77
+ if exception.needs_reconfiguration
78
+ configure_connection
79
+ exception
80
+ elsif exception.is_a?(AwsAdvancedRubyDriverWrapper::Errors::FailoverFailedError)
81
+ @connection_broken = true
82
+ ActiveRecord::ConnectionFailed.new(message, sql:, binds:, connection_pool: @pool)
83
+ else
84
+ exception
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ ActiveRecord::ConnectionAdapters.register(
92
+ 'aws_postgresql',
93
+ 'ActiveRecord::ConnectionAdapters::AwsPostgreSQLAdapter',
94
+ 'aws_advanced_ruby_driver_wrapper/active_record/aws_postgresql_adapter'
95
+ )
@@ -0,0 +1,58 @@
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
+ class Configuration
19
+ VALID_KEYS = %i[
20
+ prepare_host_func
21
+ custom_dialect
22
+ custom_error_handler
23
+ connection_init_func
24
+ ].freeze
25
+
26
+ def initialize
27
+ @mutex = Mutex.new
28
+ @values = {}
29
+ end
30
+
31
+ (VALID_KEYS - %i[prepare_host_func]).each do |key|
32
+ define_method(key) { @mutex.synchronize { @values[key] } }
33
+ define_method(:"#{key}=") { |val| @mutex.synchronize { @values[key] = val } }
34
+ end
35
+
36
+ def prepare_host_func
37
+ Utils::RdsUtils.prepare_host_func
38
+ end
39
+
40
+ def prepare_host_func=(func)
41
+ Utils::RdsUtils.prepare_host_func = func
42
+ end
43
+
44
+ def update(**options)
45
+ options.each do |key, value|
46
+ raise ArgumentError, "Unknown configuration key: #{key}" unless VALID_KEYS.include?(key)
47
+
48
+ public_send(:"#{key}=", value)
49
+ end
50
+ self
51
+ end
52
+
53
+ def reset!
54
+ VALID_KEYS.each { |key| public_send(:"#{key}=", nil) }
55
+ self
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,103 @@
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 'mysql_dialect'
18
+ require_relative 'utils/dialect_utils'
19
+
20
+ module AwsAdvancedRubyDriverWrapper
21
+ module DbDialects
22
+ class AuroraMysqlDialect < MysqlDialect
23
+ AURORA_VERSION_EXISTS_QUERY = <<~SQL
24
+ SHOW VARIABLES LIKE 'aurora_version'
25
+ SQL
26
+
27
+ TOPOLOGY_QUERY = <<~SQL
28
+ SELECT SERVER_ID AS instance_id,
29
+ CASE WHEN SESSION_ID = 'MASTER_SESSION_ID' THEN TRUE ELSE FALSE END AS is_writer,
30
+ CPU AS cpu_utilization,
31
+ REPLICA_LAG_IN_MILLISECONDS AS instance_lag,
32
+ LAST_UPDATE_TIMESTAMP AS last_update_time
33
+ FROM information_schema.replica_host_status
34
+ WHERE time_to_sec(timediff(now(), LAST_UPDATE_TIMESTAMP)) <= 300 OR SESSION_ID = 'MASTER_SESSION_ID'
35
+ SQL
36
+
37
+ # We need to extract ID and instance name. For Aurora they are equivalent, but for multi-az clusters they are not.
38
+ INSTANCE_IDENTITY_QUERY = <<~SQL
39
+ SELECT @@aurora_server_id, @@aurora_server_id
40
+ SQL
41
+
42
+ WRITER_ID_QUERY = <<~SQL
43
+ SELECT SERVER_ID FROM information_schema.replica_host_status
44
+ WHERE SESSION_ID = 'MASTER_SESSION_ID' AND SERVER_ID = @@aurora_server_id
45
+ SQL
46
+
47
+ IS_READER_QUERY = <<~SQL
48
+ SELECT @@innodb_read_only
49
+ SQL
50
+
51
+ BG_TOPOLOGY_EXISTS_QUERY = <<~SQL
52
+ SELECT 1 AS tmp FROM information_schema.tables WHERE
53
+ table_schema = 'mysql' AND table_name = 'rds_topology'
54
+ SQL
55
+
56
+ BG_STATUS_QUERY = <<~SQL
57
+ SELECT * FROM mysql.rds_topology
58
+ SQL
59
+
60
+ DIALECT_UPDATE_CANDIDATES = [
61
+ AwsAdvancedRubyDriverWrapper::DialectCodes::GLOBAL_AURORA_MYSQL,
62
+ AwsAdvancedRubyDriverWrapper::DialectCodes::MULTI_AZ_MYSQL_CLUSTER
63
+ ].freeze
64
+
65
+ def dialect?(connection)
66
+ check_existence_queries(@driver_dialect, connection, AURORA_VERSION_EXISTS_QUERY)
67
+ end
68
+
69
+ def dialect_update_candidates
70
+ DIALECT_UPDATE_CANDIDATES
71
+ end
72
+
73
+ def instance_identity(connection)
74
+ query_instance_identity(@driver_dialect, connection, INSTANCE_IDENTITY_QUERY)
75
+ end
76
+
77
+ def topology_query
78
+ TOPOLOGY_QUERY
79
+ end
80
+
81
+ def writer_id_query
82
+ WRITER_ID_QUERY
83
+ end
84
+
85
+ def blue_green_status_available?(connection)
86
+ check_existence_queries(@driver_dialect, connection, BG_TOPOLOGY_EXISTS_QUERY)
87
+ end
88
+
89
+ def blue_green_status_query
90
+ BG_STATUS_QUERY
91
+ end
92
+
93
+ # @param service_container [Services::ServiceContainer]
94
+ # @return [Host::RdsHostListProvider] the host list provider
95
+ def create_host_list_provider(service_container)
96
+ require_relative '../utils/aurora_topology_utils'
97
+ require_relative '../host/rds_host_list_provider'
98
+ topology_utils = Utils::AuroraTopologyUtils.new(dialect: self)
99
+ Host::RdsHostListProvider.new(service_container:, topology_utils:)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,124 @@
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 'pg_dialect'
18
+ require_relative 'utils/dialect_utils'
19
+
20
+ module AwsAdvancedRubyDriverWrapper
21
+ module DbDialects
22
+ class AuroraPgDialect < PgDialect
23
+ AURORA_UTILS_EXIST_QUERY = <<~SQL
24
+ SELECT (setting OPERATOR(pg_catalog.~~) '%aurora_stat_utils%') AS aurora_stat_utils
25
+ FROM pg_catalog.pg_settings
26
+ WHERE name OPERATOR(pg_catalog.=) 'rds.extensions'
27
+ SQL
28
+
29
+ TOPOLOGY_EXISTS_QUERY = <<~SQL
30
+ SELECT 1 FROM pg_catalog.aurora_replica_status() LIMIT 1
31
+ SQL
32
+
33
+ TOPOLOGY_QUERY = <<~SQL
34
+ SELECT SERVER_ID AS instance_id,
35
+ CASE WHEN SESSION_ID OPERATOR(pg_catalog.=) 'MASTER_SESSION_ID' THEN TRUE ELSE FALSE END AS is_writer,
36
+ CPU AS cpu_utilization,
37
+ COALESCE(REPLICA_LAG_IN_MSEC, 0) AS instance_lag,
38
+ LAST_UPDATE_TIMESTAMP AS last_update_time
39
+ FROM pg_catalog.aurora_replica_status()
40
+ WHERE EXTRACT(EPOCH FROM(pg_catalog.NOW() OPERATOR(pg_catalog.-) LAST_UPDATE_TIMESTAMP)) OPERATOR(pg_catalog.<=) 300
41
+ OR SESSION_ID OPERATOR(pg_catalog.=) 'MASTER_SESSION_ID'
42
+ OR LAST_UPDATE_TIMESTAMP IS NULL
43
+ SQL
44
+
45
+ INSTANCE_IDENTITY_QUERY = <<~SQL
46
+ SELECT pg_catalog.aurora_db_instance_identifier() AS instance_id,
47
+ pg_catalog.aurora_db_instance_identifier() AS instance_name
48
+ SQL
49
+
50
+ WRITER_ID_QUERY = <<~SQL
51
+ SELECT SERVER_ID FROM pg_catalog.aurora_replica_status()
52
+ WHERE SESSION_ID OPERATOR(pg_catalog.=) 'MASTER_SESSION_ID'
53
+ AND SERVER_ID OPERATOR(pg_catalog.=) pg_catalog.aurora_db_instance_identifier()
54
+ SQL
55
+
56
+ BG_TOPOLOGY_EXISTS_QUERY = <<~SQL
57
+ SELECT 'pg_catalog.get_blue_green_fast_switchover_metadata'::pg_catalog.regproc
58
+ SQL
59
+
60
+ BG_STATUS_QUERY = <<~SQL.freeze
61
+ SELECT * FROM pg_catalog.get_blue_green_fast_switchover_metadata('aws_advanced_ruby_driver_wrapper-#{AwsAdvancedRubyDriverWrapper::VERSION}')
62
+ SQL
63
+
64
+ DIALECT_UPDATE_CANDIDATES = [
65
+ AwsAdvancedRubyDriverWrapper::DialectCodes::GLOBAL_AURORA_PG,
66
+ AwsAdvancedRubyDriverWrapper::DialectCodes::MULTI_AZ_PG_CLUSTER,
67
+ AwsAdvancedRubyDriverWrapper::DialectCodes::RDS_PG
68
+ ].freeze
69
+
70
+ def dialect?(connection)
71
+ return false unless super
72
+
73
+ begin
74
+ result = @driver_dialect.execute(connection, AURORA_UTILS_EXIST_QUERY)
75
+ return false unless result.any?
76
+ return false unless result.first['aurora_stat_utils'] == 't'
77
+ rescue StandardError
78
+ return false
79
+ end
80
+
81
+ result = @driver_dialect.execute(connection, TOPOLOGY_EXISTS_QUERY)
82
+ !result.nil? && result.any?
83
+ rescue StandardError
84
+ false
85
+ end
86
+
87
+ def dialect_update_candidates
88
+ DIALECT_UPDATE_CANDIDATES
89
+ end
90
+
91
+ def topology_query
92
+ TOPOLOGY_QUERY
93
+ end
94
+
95
+ def writer_id_query
96
+ WRITER_ID_QUERY
97
+ end
98
+
99
+ def blue_green_status_available?(connection)
100
+ result = @driver_dialect.execute(connection, BG_TOPOLOGY_EXISTS_QUERY)
101
+ !result.nil? && result.any?
102
+ rescue StandardError
103
+ false
104
+ end
105
+
106
+ def instance_identity(connection)
107
+ query_instance_identity(@driver_dialect, connection, INSTANCE_IDENTITY_QUERY)
108
+ end
109
+
110
+ def blue_green_status_query
111
+ BG_STATUS_QUERY
112
+ end
113
+
114
+ # @param service_container [Services::ServiceContainer]
115
+ # @return [Host::RdsHostListProvider] the host list provider
116
+ def create_host_list_provider(service_container)
117
+ require_relative '../utils/aurora_topology_utils'
118
+ require_relative '../host/rds_host_list_provider'
119
+ topology_utils = Utils::AuroraTopologyUtils.new(dialect: self)
120
+ Host::RdsHostListProvider.new(service_container:, topology_utils:)
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,38 @@
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 DialectCodes
19
+ # MySQL variants
20
+ GLOBAL_AURORA_MYSQL = 'global-aurora-mysql'
21
+ AURORA_MYSQL = 'aurora-mysql'
22
+ RDS_MYSQL = 'rds-mysql'
23
+ MYSQL = 'mysql'
24
+ # https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html
25
+ MULTI_AZ_MYSQL_CLUSTER = 'multi-az-mysql-cluster'
26
+
27
+ # PostgreSQL variants
28
+ GLOBAL_AURORA_PG = 'global-aurora-pg'
29
+ AURORA_PG = 'aurora-pg'
30
+ RDS_PG = 'rds-pg'
31
+ # https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html
32
+ MULTI_AZ_PG_CLUSTER = 'multi-az-pg-cluster'
33
+ PG = 'pg'
34
+
35
+ UNKNOWN = 'unknown'
36
+ CUSTOM = 'custom'
37
+ end
38
+ end
@@ -0,0 +1,91 @@
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 'aurora_mysql_dialect'
18
+ require_relative 'utils/dialect_utils'
19
+
20
+ module AwsAdvancedRubyDriverWrapper
21
+ module DbDialects
22
+ class GlobalMysqlDialect < AuroraMysqlDialect
23
+ GLOBAL_STATUS_TABLE_EXISTS_QUERY = <<~SQL
24
+ SELECT 1 AS tmp FROM information_schema.tables WHERE
25
+ upper(table_schema) = 'INFORMATION_SCHEMA' AND upper(table_name) = 'AURORA_GLOBAL_DB_STATUS'
26
+ SQL
27
+
28
+ GLOBAL_INSTANCE_STATUS_EXISTS_QUERY = <<~SQL
29
+ SELECT 1 AS tmp FROM information_schema.tables WHERE
30
+ upper(table_schema) = 'INFORMATION_SCHEMA' AND upper(table_name) = 'AURORA_GLOBAL_DB_INSTANCE_STATUS'
31
+ SQL
32
+
33
+ GLOBAL_TOPOLOGY_QUERY = <<~SQL
34
+ SELECT SERVER_ID AS instance_id,
35
+ CASE WHEN SESSION_ID = 'MASTER_SESSION_ID' THEN TRUE ELSE FALSE END AS is_writer,
36
+ VISIBILITY_LAG_IN_MSEC AS instance_lag,
37
+ AWS_REGION AS aws_region
38
+ FROM information_schema.aurora_global_db_instance_status
39
+ SQL
40
+
41
+ REGION_COUNT_QUERY = <<~SQL
42
+ SELECT count(1) FROM information_schema.aurora_global_db_status
43
+ SQL
44
+
45
+ REGION_BY_INSTANCE_ID_QUERY = <<~SQL
46
+ SELECT AWS_REGION FROM information_schema.aurora_global_db_instance_status WHERE SERVER_ID = ?
47
+ SQL
48
+
49
+ def dialect?(connection)
50
+ return false unless
51
+ check_existence_queries(@driver_dialect, connection, GLOBAL_STATUS_TABLE_EXISTS_QUERY, GLOBAL_INSTANCE_STATUS_EXISTS_QUERY)
52
+
53
+ begin
54
+ result = @driver_dialect.execute(connection, REGION_COUNT_QUERY)
55
+ return false unless result.any?
56
+
57
+ row = result.first
58
+ aws_region_count = row.values.first.to_i
59
+ aws_region_count > 1
60
+ rescue StandardError
61
+ false
62
+ end
63
+ end
64
+
65
+ def global?
66
+ true
67
+ end
68
+
69
+ def dialect_update_candidates
70
+ []
71
+ end
72
+
73
+ def topology_query
74
+ GLOBAL_TOPOLOGY_QUERY
75
+ end
76
+
77
+ def region_by_instance_id_query
78
+ REGION_BY_INSTANCE_ID_QUERY
79
+ end
80
+
81
+ # @param service_container [Services::ServiceContainer]
82
+ # @return [Host::GlobalAuroraHostListProvider] the host list provider
83
+ def create_host_list_provider(service_container)
84
+ require_relative '../utils/global_aurora_topology_utils'
85
+ require_relative '../host/global_aurora_host_list_provider'
86
+ topology_utils = Utils::GlobalAuroraTopologyUtils.new(dialect: self)
87
+ Host::GlobalAuroraHostListProvider.new(service_container:, topology_utils:)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,92 @@
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 'aurora_pg_dialect'
18
+ require_relative 'utils/dialect_utils'
19
+
20
+ module AwsAdvancedRubyDriverWrapper
21
+ module DbDialects
22
+ class GlobalPgDialect < AuroraPgDialect
23
+ GLOBAL_STATUS_FUNC_EXISTS_QUERY = <<~SQL
24
+ SELECT 'pg_catalog.aurora_global_db_status'::pg_catalog.regproc
25
+ SQL
26
+
27
+ GLOBAL_INSTANCE_STATUS_FUNC_EXISTS_QUERY = <<~SQL
28
+ SELECT 'pg_catalog.aurora_global_db_instance_status'::pg_catalog.regproc
29
+ SQL
30
+
31
+ GLOBAL_TOPOLOGY_QUERY = <<~SQL
32
+ SELECT SERVER_ID AS instance_id,
33
+ CASE WHEN SESSION_ID OPERATOR(pg_catalog.=) 'MASTER_SESSION_ID' THEN TRUE ELSE FALSE END AS is_writer,
34
+ VISIBILITY_LAG_IN_MSEC AS instance_lag,
35
+ AWS_REGION AS aws_region
36
+ FROM pg_catalog.aurora_global_db_instance_status()
37
+ SQL
38
+
39
+ REGION_COUNT_QUERY = <<~SQL
40
+ SELECT pg_catalog.count(1) FROM pg_catalog.aurora_global_db_status()
41
+ SQL
42
+
43
+ REGION_BY_INSTANCE_ID_QUERY = <<~SQL
44
+ SELECT AWS_REGION FROM pg_catalog.aurora_global_db_instance_status() WHERE SERVER_ID OPERATOR(pg_catalog.=) $1
45
+ SQL
46
+
47
+ def dialect?(connection)
48
+ result = @driver_dialect.execute(connection, AURORA_UTILS_EXIST_QUERY)
49
+ return false unless result.any?
50
+
51
+ return false unless result.first['aurora_stat_utils'] == 't'
52
+
53
+ return false unless
54
+ check_existence_queries(@driver_dialect, connection, GLOBAL_STATUS_FUNC_EXISTS_QUERY, GLOBAL_INSTANCE_STATUS_FUNC_EXISTS_QUERY)
55
+
56
+ result = connection.exec(REGION_COUNT_QUERY)
57
+ return false unless result.any?
58
+
59
+ row = result.first
60
+ aws_region_count = row.is_a?(Hash) ? row.values.first.to_i : row[0].to_i
61
+ aws_region_count > 1
62
+ rescue StandardError
63
+ false
64
+ end
65
+
66
+ def global?
67
+ true
68
+ end
69
+
70
+ def dialect_update_candidates
71
+ []
72
+ end
73
+
74
+ def topology_query
75
+ GLOBAL_TOPOLOGY_QUERY
76
+ end
77
+
78
+ def region_by_instance_id_query
79
+ REGION_BY_INSTANCE_ID_QUERY
80
+ end
81
+
82
+ # @param service_container [Services::ServiceContainer]
83
+ # @return [Host::GlobalAuroraHostListProvider] the host list provider
84
+ def create_host_list_provider(service_container)
85
+ require_relative '../utils/global_aurora_topology_utils'
86
+ require_relative '../host/global_aurora_host_list_provider'
87
+ topology_utils = Utils::GlobalAuroraTopologyUtils.new(dialect: self)
88
+ Host::GlobalAuroraHostListProvider.new(service_container:, topology_utils:)
89
+ end
90
+ end
91
+ end
92
+ end