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,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
+ require_relative 'phase'
18
+
19
+ module AwsAdvancedRubyDriverWrapper
20
+ module Plugins
21
+ module BlueGreen
22
+ PhaseTimeInfo = Struct.new(:timestamp, :timestamp_nano, :phase)
23
+ end
24
+ end
25
+ 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 Plugins
19
+ module BlueGreen
20
+ module Role
21
+ SOURCE = :source
22
+ TARGET = :target
23
+
24
+ ROLE_MAPPING_1_0 = {
25
+ 'BLUE_GREEN_DEPLOYMENT_SOURCE' => SOURCE,
26
+ 'BLUE_GREEN_DEPLOYMENT_TARGET' => TARGET
27
+ }.freeze
28
+
29
+ def self.parse_role(value, version)
30
+ raise ArgumentError, "Unknown Blue/Green version: #{version}" unless version == '1.0'
31
+ raise ArgumentError, 'Blue/Green role value is blank' if value.nil? || value.strip.empty?
32
+
33
+ ROLE_MAPPING_1_0.fetch(value.upcase) { raise ArgumentError, "Unknown Blue/Green role: #{value}" }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,83 @@
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 '../../../logging'
18
+
19
+ module AwsAdvancedRubyDriverWrapper
20
+ module Plugins
21
+ module BlueGreen
22
+ module Routing
23
+ module BaseRouting
24
+ include Logging
25
+
26
+ MINIMUM_SLEEP_CHUNK_SEC = 0.05
27
+
28
+ def match?(host_info, role)
29
+ (@host.nil? || @host.downcase == host_info&.host&.downcase) &&
30
+ (@port.nil? || @port == host_info&.port) &&
31
+ (@role.nil? || @role == role)
32
+ end
33
+
34
+ def to_s
35
+ "#{self.class.name.split('::').last}@#{object_id.to_s(16)} [" \
36
+ "host: #{@host || '<null>'}, " \
37
+ "port: #{@port || '<null>'}, " \
38
+ "role: #{@role || '<null>'}, " \
39
+ "bgd_id: #{defined?(@bgd_id) ? (@bgd_id || '<null>') : '<n/a>'}]"
40
+ end
41
+
42
+ # Blocks until the Blue/Green switchover phase is no longer IN_PROGRESS, or until the
43
+ # configured timeout elapses.
44
+ def wait_while_in_progress(wrapper_props, storage_service, bgd_id, sleep_time_sec = MINIMUM_SLEEP_CHUNK_SEC)
45
+ bg_status = storage_service.get(BlueGreenPlugin::BLUE_GREEN_NAME, bgd_id)
46
+ remaining_sec = PropertyDefinition::BG_CONNECT_TIMEOUT_SEC.get_float(wrapper_props)
47
+
48
+ while remaining_sec.positive? && bg_status&.current_phase == Phase::IN_PROGRESS
49
+ sleep_sec = [sleep_time_sec, remaining_sec].min
50
+ delay(sleep_sec, bg_status, storage_service, bgd_id)
51
+ remaining_sec -= sleep_sec
52
+ bg_status = storage_service.get(BlueGreenPlugin::BLUE_GREEN_NAME, bgd_id)
53
+ end
54
+
55
+ if bg_status&.current_phase == Phase::IN_PROGRESS
56
+ raise Errors::BlueGreenTimeoutError, yield(PropertyDefinition::BG_CONNECT_TIMEOUT_SEC.get_float(wrapper_props))
57
+ end
58
+
59
+ bg_status
60
+ end
61
+
62
+ protected
63
+
64
+ def delay(delay_sec, bg_status, storage_service, bgd_id)
65
+ if bg_status.nil?
66
+ sleep(delay_sec)
67
+ else
68
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay_sec
69
+ min_delay = [delay_sec, MINIMUM_SLEEP_CHUNK_SEC].min
70
+
71
+ # Wake early if the status reference changes or the deadline passes.
72
+ # Thread interruption surfaces as Interrupt raised into bg_status.wait, unwinding the caller.
73
+ until Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline ||
74
+ bg_status != storage_service.get(BlueGreenPlugin::BLUE_GREEN_NAME, bgd_id)
75
+ bg_status.wait(min_delay * 1000)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ 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
+ require_relative '../../../errors'
18
+
19
+ module AwsAdvancedRubyDriverWrapper
20
+ module Plugins
21
+ module BlueGreen
22
+ module Routing
23
+ # Rejects any attempt to open a new connection during a Blue/Green switchover.
24
+ class RejectConnectRouting
25
+ include BaseRouting
26
+
27
+ def initialize(host, port, role)
28
+ @host = host
29
+ @port = port
30
+ @role = role
31
+ end
32
+
33
+ def apply(*, **)
34
+ raise Errors::BlueGreenSwitchoverError, 'Blue/Green Deployment switchover is in progress. New connection can\'t be opened.'
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,136 @@
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 Plugins
19
+ module BlueGreen
20
+ module Routing
21
+ # Opens a new connection to a substitute host instead of the originally requested host.
22
+ # When IAM auth is active and the substitute host is an IP address, each configured IAM
23
+ # host is tried in turn so the IAM plugin can resolve the correct token hostname.
24
+ class SubstituteConnectRouting
25
+ include BaseRouting
26
+
27
+ def initialize(host, port, role, substitute_host, iam_hosts, iam_successful_connect_notify = nil)
28
+ @host = host
29
+ @port = port
30
+ @role = role
31
+ @substitute_host = substitute_host
32
+ @iam_hosts = iam_hosts
33
+ @iam_successful_connect_notify = iam_successful_connect_notify
34
+ end
35
+
36
+ def to_s
37
+ port_str = @port ? ":#{@port}" : ''
38
+ iam_hosts_str = @iam_hosts&.map(&:host_and_port)&.join(', ') || '<null>'
39
+ "#{self.class.name.split('::').last}@#{object_id.to_s(16)} [" \
40
+ "#{@host}#{port_str}, " \
41
+ "role: #{@role}, " \
42
+ "substitute: #{@substitute_host&.host_and_port || '<null>'}, " \
43
+ "iam_hosts: #{iam_hosts_str}]"
44
+ end
45
+
46
+ def apply(_host_info,
47
+ driver_props,
48
+ wrapper_props,
49
+ is_initial_connection,
50
+ service_container,
51
+ is_internal: false,
52
+ bg_plugin: nil)
53
+ plugin_manager = service_container.plugin_manager
54
+ dialect_service = service_container.dialect_service
55
+
56
+ unless Utils::RdsUtils.ip?(@substitute_host.host)
57
+ return open_connection(plugin_manager, @substitute_host, driver_props, wrapper_props, is_initial_connection, is_internal,
58
+ bg_plugin)
59
+ end
60
+
61
+ # mysql2 uses :host for both socket connection and TLS CN verification.
62
+ # Connecting to a raw IP with TLS active causes a CN mismatch.
63
+ # Fall back to connecting via hostname (DNS will resolve to the correct IP post-switchover),
64
+ # matching the effective behaviour of the Java/Go MySQL drivers which use the original
65
+ # hostname for TLS regardless of the socket address.
66
+ if driver_props[:sslca] && !plugin_manager.plugin_in_use?(Plugins::IamAuthPlugin)
67
+ hostname_host = @substitute_host.deep_dup(host: @host)
68
+ return open_connection(plugin_manager, hostname_host, driver_props, wrapper_props, is_initial_connection, is_internal,
69
+ bg_plugin)
70
+ end
71
+
72
+ if plugin_manager.plugin_in_use?(Plugins::IamAuthPlugin)
73
+ if @iam_hosts.nil? || @iam_hosts.empty?
74
+ raise StandardError,
75
+ 'Connecting with IP address when IAM authentication is enabled requires an \'iam_host\' parameter.'
76
+ end
77
+
78
+ @iam_hosts.each do |iam_host|
79
+ rerouted_host = @substitute_host.deep_dup
80
+ rerouted_host.id = iam_host.id
81
+ rerouted_host.availability = Host::HostAvailability::AVAILABLE
82
+
83
+ rerouted_wrapper_props = wrapper_props.dup
84
+ PropertyDefinition::IAM_HOST.set(rerouted_wrapper_props, iam_host.host)
85
+ PropertyDefinition::IAM_PORT.set(rerouted_wrapper_props, iam_host.port.to_s) if iam_host.port_specified?
86
+
87
+ begin
88
+ conn = plugin_manager.internal_connect(
89
+ rerouted_host,
90
+ driver_props,
91
+ rerouted_wrapper_props,
92
+ is_initial_connection,
93
+ plugin_to_skip: bg_plugin
94
+ )
95
+ begin
96
+ @iam_successful_connect_notify&.call(iam_host.host)
97
+ rescue StandardError
98
+ nil
99
+ end
100
+ return conn
101
+ rescue StandardError => e
102
+ raise unless dialect_service.login_error?(e)
103
+ end
104
+ end
105
+ return nil
106
+ end
107
+
108
+ open_connection(plugin_manager, @substitute_host, driver_props, wrapper_props, is_initial_connection, is_internal, bg_plugin)
109
+ rescue StandardError => e
110
+ raise unless dialect_service.login_error?(e)
111
+
112
+ nil
113
+ end
114
+
115
+ private
116
+
117
+ # Opens a connection through the plugin pipeline. Monitoring connections (is_internal: true)
118
+ # must use internal_connect so they do NOT mutate the shared current connection — otherwise
119
+ # one monitor thread's connect would close another monitor thread's live connection via
120
+ # update_current_connection, causing a use-after-free segfault in the mysql2 C extension.
121
+ #
122
+ # bg_plugin is skipped in the nested pipeline so this substitute connection does not re-enter
123
+ # BG routing. Without it, during the switchover window the opened connection matches the same
124
+ # routing again and recurses until the stack overflows (SystemStackError).
125
+ def open_connection(plugin_manager, host, driver_props, wrapper_props, is_initial_connection, is_internal, bg_plugin = nil)
126
+ if is_internal
127
+ plugin_manager.internal_connect(host, driver_props, wrapper_props, is_initial_connection, plugin_to_skip: bg_plugin)
128
+ else
129
+ plugin_manager.connect(host, driver_props, is_initial_connection, plugin_to_skip: bg_plugin)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,53 @@
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 Plugins
19
+ module BlueGreen
20
+ module Routing
21
+ class SuspendConnectRouting
22
+ include BaseRouting
23
+
24
+ SLEEP_TIME_SEC = 0.1
25
+
26
+ def initialize(host, port, role, bgd_id)
27
+ @host = host
28
+ @port = port
29
+ @role = role
30
+ @bgd_id = bgd_id
31
+ end
32
+
33
+ # Blocks until switchover is no longer IN_PROGRESS
34
+ def apply(_host_info, _, wrapper_props, _is_initial_connection, service_container, is_internal: false, bg_plugin: nil)
35
+ storage_service = service_container.storage_service
36
+ hold_start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
37
+
38
+ wait_while_in_progress(wrapper_props, storage_service, @bgd_id, SLEEP_TIME_SEC) do |timeout_sec|
39
+ "Blue/Green Deployment switchover is still in progress after #{timeout_sec} s. Try to connect again later."
40
+ end
41
+
42
+ elapsed_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - hold_start_time) * 1000).round
43
+ logger.debug do
44
+ "Blue/Green Deployment switchover is completed. Continue with connect call. The call was held for #{elapsed_ms} ms."
45
+ end
46
+
47
+ nil
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
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 Plugins
19
+ module BlueGreen
20
+ module Routing
21
+ class SuspendExecuteRouting
22
+ include BaseRouting
23
+
24
+ SLEEP_TIME_SEC = 0.1
25
+
26
+ def initialize(host, port, role, bgd_id)
27
+ @host = host
28
+ @port = port
29
+ @role = role
30
+ @bgd_id = bgd_id
31
+ end
32
+
33
+ # Blocks until switchover is no longer IN_PROGRESS
34
+ def apply(method_name, wrapper_props, storage_service)
35
+ hold_start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
36
+
37
+ wait_while_in_progress(wrapper_props, storage_service, @bgd_id, SLEEP_TIME_SEC) do |timeout_sec|
38
+ "Blue/Green Deployment switchover is still in progress after #{timeout_sec} s. Try '#{method_name}' again later."
39
+ end
40
+
41
+ elapsed_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - hold_start_time) * 1000).round
42
+ logger.debug do
43
+ "Blue/Green Deployment switchover is completed. Continue with '#{method_name}' call. The call was held for #{elapsed_ms} ms."
44
+ end
45
+
46
+ nil
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,83 @@
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 Plugins
19
+ module BlueGreen
20
+ module Routing
21
+ # Suspends a new connection attempt until a corresponding green host is found for the
22
+ # requested host, or until the switchover completes.
23
+ class SuspendUntilCorrespondingHostFoundConnectRouting
24
+ include BaseRouting
25
+
26
+ SLEEP_TIME_SEC = 0.1
27
+
28
+ def initialize(host, port, role, bgd_id)
29
+ @host = host
30
+ @port = port
31
+ @role = role
32
+ @bgd_id = bgd_id
33
+ end
34
+
35
+ # Blocks until a corresponding green host is found for host_info.host, the switchover
36
+ # completes, or the timeout elapses.
37
+ def apply(host_info, _, wrapper_props, _is_initial_connection, service_container, is_internal: false, bg_plugin: nil)
38
+ storage_service = service_container.storage_service
39
+
40
+ bg_status = storage_service.get(BlueGreenPlugin::BLUE_GREEN_NAME, @bgd_id)
41
+ corresponding_pair = bg_status&.corresponding_hosts&.[](host_info.host)
42
+
43
+ timeout_sec = PropertyDefinition::BG_CONNECT_TIMEOUT_SEC.get_float(wrapper_props)
44
+ hold_start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
45
+ end_time = hold_start_time + timeout_sec
46
+
47
+ # Wait until a corresponding host is found, or until switchover is completed.
48
+ while Process.clock_gettime(Process::CLOCK_MONOTONIC) <= end_time &&
49
+ !bg_status.nil? &&
50
+ bg_status.current_phase != Phase::COMPLETED &&
51
+ (corresponding_pair.nil? || corresponding_pair[1].nil?)
52
+ delay(SLEEP_TIME_SEC, bg_status, storage_service, @bgd_id)
53
+ bg_status = storage_service.get(BlueGreenPlugin::BLUE_GREEN_NAME, @bgd_id)
54
+ corresponding_pair = bg_status&.corresponding_hosts&.[](host_info.host)
55
+ end
56
+
57
+ elapsed_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - hold_start_time) * 1000).round
58
+
59
+ if bg_status.nil? || bg_status.current_phase == Phase::COMPLETED
60
+ logger.debug do
61
+ "Blue/Green Deployment status is completed. Continue with 'connect' call. The call was held for #{elapsed_ms} ms."
62
+ end
63
+ return nil
64
+ end
65
+
66
+ if Process.clock_gettime(Process::CLOCK_MONOTONIC) > end_time
67
+ raise Errors::BlueGreenTimeoutError,
68
+ 'Blue/Green Deployment switchover is still in progress and a corresponding ' \
69
+ "host for '#{host_info.host}' is not found after " \
70
+ "#{PropertyDefinition::BG_CONNECT_TIMEOUT_SEC.get_float(wrapper_props)} s. Try to connect again later."
71
+ end
72
+
73
+ logger.debug do
74
+ "A corresponding host for '#{host_info.host}' is found. Continue with connect call. The call was held for #{elapsed_ms} ms."
75
+ end
76
+
77
+ nil
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,68 @@
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 'concurrent'
18
+
19
+ module AwsAdvancedRubyDriverWrapper
20
+ module Plugins
21
+ module BlueGreen
22
+ class Status
23
+ attr_reader :bgd_id, :current_phase, :connect_routing, :execute_routing, :role_by_host, :corresponding_hosts
24
+
25
+ def initialize(bgd_id, phase, connect_routing: [], execute_routing: [], role_by_host: {}, corresponding_hosts: {})
26
+ @bgd_id = bgd_id
27
+ @current_phase = phase
28
+ @connect_routing = connect_routing.freeze
29
+ @execute_routing = execute_routing.freeze
30
+ @role_by_host = role_by_host.dup.freeze
31
+ @corresponding_hosts = corresponding_hosts.dup.freeze
32
+ @event = Concurrent::Event.new
33
+ end
34
+
35
+ def wait(timeout_ms)
36
+ @event.wait(timeout_ms / 1000.0)
37
+ end
38
+
39
+ def notify
40
+ @event.set
41
+ end
42
+
43
+ def role(host_spec)
44
+ @role_by_host[host_spec.host.downcase]
45
+ end
46
+
47
+ def to_s
48
+ role_map = @role_by_host.map { |k, v| "#{k} -> #{v}" }.join("\n")
49
+ connect_str = @connect_routing.join("\n")
50
+ execute_str = @execute_routing.join("\n")
51
+
52
+ <<~STATUS
53
+ Status [
54
+ bgd_id: '#{@bgd_id}',
55
+ phase: #{@current_phase},
56
+ Connect routing:
57
+ #{connect_str.empty? ? '-' : connect_str}
58
+ Execute routing:
59
+ #{execute_str.empty? ? '-' : execute_str}
60
+ role_by_host:
61
+ #{role_map.empty? ? '-' : role_map}
62
+ ]
63
+ STATUS
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end