active_postgres 0.4.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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +23 -0
  3. data/README.md +158 -0
  4. data/exe/activepostgres +5 -0
  5. data/lib/active_postgres/cli.rb +157 -0
  6. data/lib/active_postgres/cluster_deployment_flow.rb +85 -0
  7. data/lib/active_postgres/component_resolver.rb +24 -0
  8. data/lib/active_postgres/components/base.rb +38 -0
  9. data/lib/active_postgres/components/core.rb +158 -0
  10. data/lib/active_postgres/components/extensions.rb +99 -0
  11. data/lib/active_postgres/components/monitoring.rb +55 -0
  12. data/lib/active_postgres/components/pgbackrest.rb +94 -0
  13. data/lib/active_postgres/components/pgbouncer.rb +137 -0
  14. data/lib/active_postgres/components/repmgr.rb +651 -0
  15. data/lib/active_postgres/components/ssl.rb +86 -0
  16. data/lib/active_postgres/configuration.rb +190 -0
  17. data/lib/active_postgres/connection_pooler.rb +429 -0
  18. data/lib/active_postgres/credentials.rb +17 -0
  19. data/lib/active_postgres/deployment_flow.rb +154 -0
  20. data/lib/active_postgres/error_handler.rb +185 -0
  21. data/lib/active_postgres/failover.rb +83 -0
  22. data/lib/active_postgres/generators/active_postgres/install_generator.rb +186 -0
  23. data/lib/active_postgres/health_checker.rb +244 -0
  24. data/lib/active_postgres/installer.rb +114 -0
  25. data/lib/active_postgres/log_sanitizer.rb +67 -0
  26. data/lib/active_postgres/logger.rb +125 -0
  27. data/lib/active_postgres/performance_tuner.rb +246 -0
  28. data/lib/active_postgres/rails/database_config.rb +174 -0
  29. data/lib/active_postgres/rails/migration_guard.rb +25 -0
  30. data/lib/active_postgres/railtie.rb +28 -0
  31. data/lib/active_postgres/retry_helper.rb +80 -0
  32. data/lib/active_postgres/rollback_manager.rb +140 -0
  33. data/lib/active_postgres/secrets.rb +86 -0
  34. data/lib/active_postgres/ssh_executor.rb +288 -0
  35. data/lib/active_postgres/standby_deployment_flow.rb +122 -0
  36. data/lib/active_postgres/validator.rb +143 -0
  37. data/lib/active_postgres/version.rb +3 -0
  38. data/lib/active_postgres.rb +67 -0
  39. data/lib/tasks/postgres.rake +855 -0
  40. data/lib/tasks/rolling_update.rake +258 -0
  41. data/lib/tasks/rotate_credentials.rake +193 -0
  42. data/templates/pg_hba.conf.erb +47 -0
  43. data/templates/pgbackrest.conf.erb +43 -0
  44. data/templates/pgbouncer.ini.erb +55 -0
  45. data/templates/postgresql.conf.erb +157 -0
  46. data/templates/repmgr.conf.erb +40 -0
  47. metadata +224 -0
@@ -0,0 +1,157 @@
1
+ # PostgreSQL configuration file
2
+ # Generated by active_postgres
3
+ <%
4
+ # pg_config is now provided by the Core component
5
+ # It contains either user config OR auto-tuned + user config (merged)
6
+ core_config = config.component_config(:core)
7
+ %>
8
+
9
+ # Cluster Settings
10
+ data_directory = '/var/lib/postgresql/<%= config.version %>/main'
11
+ hba_file = '/etc/postgresql/<%= config.version %>/main/pg_hba.conf'
12
+ ident_file = '/etc/postgresql/<%= config.version %>/main/pg_ident.conf'
13
+ external_pid_file = '/var/run/postgresql/<%= config.version %>-main.pid'
14
+ cluster_name = '<%= config.version %>-main'
15
+
16
+ # Connection Settings
17
+ listen_addresses = '<%= pg_config[:listen_addresses] || '*' %>'
18
+ port = <%= pg_config[:port] || 5432 %>
19
+ max_connections = <%= pg_config[:max_connections] || 100 %>
20
+ unix_socket_directories = '/var/run/postgresql'
21
+
22
+ # Memory Settings
23
+ shared_buffers = <%= pg_config[:shared_buffers] || '256MB' %>
24
+ effective_cache_size = <%= pg_config[:effective_cache_size] || '1GB' %>
25
+ work_mem = <%= pg_config[:work_mem] || '4MB' %>
26
+ maintenance_work_mem = <%= pg_config[:maintenance_work_mem] || '64MB' %>
27
+ <% if pg_config[:wal_buffers] %>
28
+ wal_buffers = <%= pg_config[:wal_buffers] %>
29
+ <% end %>
30
+ <% if pg_config[:huge_pages] %>
31
+ huge_pages = <%= pg_config[:huge_pages] %>
32
+ <% end %>
33
+
34
+ # WAL Settings (for replication)
35
+ wal_level = <%= pg_config[:wal_level] || 'replica' %>
36
+ max_wal_senders = <%= pg_config[:max_wal_senders] || 10 %>
37
+ max_replication_slots = <%= pg_config[:max_replication_slots] || 10 %>
38
+ wal_keep_size = <%= pg_config[:wal_keep_size] || '1GB' %>
39
+ <% if pg_config[:hot_standby] %>
40
+ hot_standby = <%= pg_config[:hot_standby] %>
41
+ <% end %>
42
+ <% if pg_config[:wal_compression] %>
43
+ wal_compression = <%= pg_config[:wal_compression] %>
44
+ <% end %>
45
+ <% if pg_config[:archive_mode] %>
46
+ archive_mode = <%= pg_config[:archive_mode] %>
47
+ <% end %>
48
+ <% if pg_config[:archive_command] %>
49
+ archive_command = '<%= pg_config[:archive_command] %>'
50
+ <% end %>
51
+ <% if pg_config[:shared_memory_type] %>
52
+ shared_memory_type = <%= pg_config[:shared_memory_type] %>
53
+ <% end %>
54
+ <% if pg_config[:wal_init_zero] %>
55
+ wal_init_zero = <%= pg_config[:wal_init_zero] %>
56
+ <% end %>
57
+ <% if pg_config[:wal_recycle] %>
58
+ wal_recycle = <%= pg_config[:wal_recycle] %>
59
+ <% end %>
60
+
61
+ # Checkpoint Settings
62
+ checkpoint_completion_target = <%= pg_config[:checkpoint_completion_target] || 0.9 %>
63
+ checkpoint_timeout = <%= pg_config[:checkpoint_timeout] || '15min' %>
64
+
65
+ # Query Planner Settings
66
+ <% if pg_config[:default_statistics_target] %>
67
+ default_statistics_target = <%= pg_config[:default_statistics_target] %>
68
+ <% end %>
69
+ <% if pg_config[:random_page_cost] %>
70
+ random_page_cost = <%= pg_config[:random_page_cost] %>
71
+ <% end %>
72
+ <% if pg_config[:effective_io_concurrency] %>
73
+ effective_io_concurrency = <%= pg_config[:effective_io_concurrency] %>
74
+ <% end %>
75
+
76
+ # Parallel Query Settings
77
+ <% if pg_config[:max_worker_processes] %>
78
+ max_worker_processes = <%= pg_config[:max_worker_processes] %>
79
+ <% end %>
80
+ <% if pg_config[:max_parallel_workers_per_gather] %>
81
+ max_parallel_workers_per_gather = <%= pg_config[:max_parallel_workers_per_gather] %>
82
+ <% end %>
83
+ <% if pg_config[:max_parallel_workers] %>
84
+ max_parallel_workers = <%= pg_config[:max_parallel_workers] %>
85
+ <% end %>
86
+ <% if pg_config[:max_parallel_maintenance_workers] %>
87
+ max_parallel_maintenance_workers = <%= pg_config[:max_parallel_maintenance_workers] %>
88
+ <% end %>
89
+
90
+ # Logging
91
+ logging_collector = <%= pg_config[:logging_collector] || 'on' %>
92
+ log_directory = '<%= pg_config[:log_directory] || 'log' %>'
93
+ log_filename = '<%= pg_config[:log_filename] || 'postgresql-%Y-%m-%d_%H%M%S.log' %>'
94
+ log_rotation_age = <%= pg_config[:log_rotation_age] || '1d' %>
95
+ log_rotation_size = <%= pg_config[:log_rotation_size] || '100MB' %>
96
+ log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
97
+ log_timezone = 'UTC'
98
+ <% if pg_config[:log_checkpoints] %>
99
+ log_checkpoints = <%= pg_config[:log_checkpoints] %>
100
+ <% end %>
101
+ <% if pg_config[:log_connections] %>
102
+ log_connections = <%= pg_config[:log_connections] %>
103
+ <% end %>
104
+ <% if pg_config[:log_disconnections] %>
105
+ log_disconnections = <%= pg_config[:log_disconnections] %>
106
+ <% end %>
107
+ <% if pg_config[:log_lock_waits] %>
108
+ log_lock_waits = <%= pg_config[:log_lock_waits] %>
109
+ <% end %>
110
+ <% if pg_config[:log_temp_files] %>
111
+ log_temp_files = <%= pg_config[:log_temp_files] %>
112
+ <% end %>
113
+ <% if pg_config[:log_autovacuum_min_duration] %>
114
+ log_autovacuum_min_duration = <%= pg_config[:log_autovacuum_min_duration] %>
115
+ <% end %>
116
+ <% if pg_config[:log_min_duration_statement] %>
117
+ log_min_duration_statement = <%= pg_config[:log_min_duration_statement] %>
118
+ <% end %>
119
+
120
+ # Locale
121
+ datestyle = 'iso, mdy'
122
+ timezone = 'UTC'
123
+ lc_messages = '<%= core_config[:locale] || 'en_US.UTF-8' %>'
124
+ lc_monetary = '<%= core_config[:locale] || 'en_US.UTF-8' %>'
125
+ lc_numeric = '<%= core_config[:locale] || 'en_US.UTF-8' %>'
126
+ lc_time = '<%= core_config[:locale] || 'en_US.UTF-8' %>'
127
+ default_text_search_config = 'pg_catalog.english'
128
+
129
+ <% if config.component_enabled?(:ssl) %>
130
+ # SSL Configuration
131
+ ssl = on
132
+ ssl_cert_file = '/etc/postgresql/<%= config.version %>/main/server.crt'
133
+ ssl_key_file = '/etc/postgresql/<%= config.version %>/main/server.key'
134
+ <% end %>
135
+
136
+ # JIT Compilation
137
+ <% if pg_config[:jit] %>
138
+ jit = <%= pg_config[:jit] %>
139
+ <% end %>
140
+
141
+ # Additional settings
142
+ shared_preload_libraries = '<%= pg_config[:shared_preload_libraries] || 'pg_stat_statements' %>'
143
+ <% if pg_config[:'pg_stat_statements.max'] %>
144
+ pg_stat_statements.max = <%= pg_config[:'pg_stat_statements.max'] %>
145
+ <% end %>
146
+ <% if pg_config[:'pg_stat_statements.track'] %>
147
+ pg_stat_statements.track = <%= pg_config[:'pg_stat_statements.track'] %>
148
+ <% end %>
149
+
150
+ <% if pg_config[:custom] %>
151
+ # Custom configuration
152
+ <% pg_config[:custom].each do |key, value| %>
153
+ <%= key %> = <%= value %>
154
+ <% end %>
155
+ <% end %>
156
+
157
+
@@ -0,0 +1,40 @@
1
+ <%
2
+ # Get node label from config for professional naming
3
+ node_label = config.node_label_for(host)
4
+ if node_label.nil?
5
+ node_label = if host == config.primary_host
6
+ "primary-#{host.split('.').first}"
7
+ else
8
+ "standby-#{host.split('.').first}"
9
+ end
10
+ end
11
+ %>
12
+ node_id=<%= host == config.primary_host ? 1 : config.standby_hosts.index(host) + 2 %>
13
+ node_name='<%= node_label %>'
14
+ <%
15
+ # conninfo describes how OTHER nodes connect to THIS node
16
+ repmgr_host = config.replication_host_for(host)
17
+ %>
18
+ conninfo='host=<%= repmgr_host %> user=<%= config.repmgr_user %> dbname=<%= config.repmgr_database %> password=<%= secrets_obj.resolve('repmgr_password') %> connect_timeout=2'
19
+ data_directory='/var/lib/postgresql/<%= config.version %>/main'
20
+
21
+ <% if host == config.primary_host %>
22
+ failover=automatic
23
+ priority=<%= repmgr_config[:priority] || 100 %>
24
+ <% else %>
25
+ failover=automatic
26
+ priority=<%= repmgr_config[:priority] || 100 %>
27
+ promote_command='repmgr standby promote -f /etc/repmgr.conf'
28
+ follow_command='repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n'
29
+ <% end %>
30
+
31
+ reconnect_attempts=<%= repmgr_config[:reconnect_attempts] || 6 %>
32
+ reconnect_interval=<%= repmgr_config[:reconnect_interval] || 10 %>
33
+
34
+ log_level=INFO
35
+ log_facility=STDERR
36
+ log_file='/var/log/postgresql/repmgr.log'
37
+
38
+ monitoring_history=yes
39
+ monitor_interval_secs=5
40
+
metadata ADDED
@@ -0,0 +1,224 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_postgres
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - BoringCache
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bcrypt_pbkdf
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ed25519
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.3'
40
+ - !ruby/object:Gem::Dependency
41
+ name: pg
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: railties
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '6.0'
61
+ - - "<"
62
+ - !ruby/object:Gem::Version
63
+ version: '9.0'
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '6.0'
71
+ - - "<"
72
+ - !ruby/object:Gem::Version
73
+ version: '9.0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: sshkit
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.21'
81
+ type: :runtime
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.21'
88
+ - !ruby/object:Gem::Dependency
89
+ name: thor
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '1.3'
95
+ type: :runtime
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.3'
102
+ - !ruby/object:Gem::Dependency
103
+ name: minitest
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '5.0'
109
+ type: :development
110
+ prerelease: false
111
+ version_requirements: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '5.0'
116
+ - !ruby/object:Gem::Dependency
117
+ name: rubocop
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '1.50'
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '1.50'
130
+ - !ruby/object:Gem::Dependency
131
+ name: simplecov
132
+ requirement: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '0.22'
137
+ type: :development
138
+ prerelease: false
139
+ version_requirements: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '0.22'
144
+ description: Production-grade PostgreSQL HA with deep Rails integration. Automated
145
+ deployment, replication, failover, and monitoring.
146
+ email:
147
+ - oss@boringcache.com
148
+ executables:
149
+ - activepostgres
150
+ extensions: []
151
+ extra_rdoc_files: []
152
+ files:
153
+ - LICENSE
154
+ - README.md
155
+ - exe/activepostgres
156
+ - lib/active_postgres.rb
157
+ - lib/active_postgres/cli.rb
158
+ - lib/active_postgres/cluster_deployment_flow.rb
159
+ - lib/active_postgres/component_resolver.rb
160
+ - lib/active_postgres/components/base.rb
161
+ - lib/active_postgres/components/core.rb
162
+ - lib/active_postgres/components/extensions.rb
163
+ - lib/active_postgres/components/monitoring.rb
164
+ - lib/active_postgres/components/pgbackrest.rb
165
+ - lib/active_postgres/components/pgbouncer.rb
166
+ - lib/active_postgres/components/repmgr.rb
167
+ - lib/active_postgres/components/ssl.rb
168
+ - lib/active_postgres/configuration.rb
169
+ - lib/active_postgres/connection_pooler.rb
170
+ - lib/active_postgres/credentials.rb
171
+ - lib/active_postgres/deployment_flow.rb
172
+ - lib/active_postgres/error_handler.rb
173
+ - lib/active_postgres/failover.rb
174
+ - lib/active_postgres/generators/active_postgres/install_generator.rb
175
+ - lib/active_postgres/health_checker.rb
176
+ - lib/active_postgres/installer.rb
177
+ - lib/active_postgres/log_sanitizer.rb
178
+ - lib/active_postgres/logger.rb
179
+ - lib/active_postgres/performance_tuner.rb
180
+ - lib/active_postgres/rails/database_config.rb
181
+ - lib/active_postgres/rails/migration_guard.rb
182
+ - lib/active_postgres/railtie.rb
183
+ - lib/active_postgres/retry_helper.rb
184
+ - lib/active_postgres/rollback_manager.rb
185
+ - lib/active_postgres/secrets.rb
186
+ - lib/active_postgres/ssh_executor.rb
187
+ - lib/active_postgres/standby_deployment_flow.rb
188
+ - lib/active_postgres/validator.rb
189
+ - lib/active_postgres/version.rb
190
+ - lib/tasks/postgres.rake
191
+ - lib/tasks/rolling_update.rake
192
+ - lib/tasks/rotate_credentials.rake
193
+ - templates/pg_hba.conf.erb
194
+ - templates/pgbackrest.conf.erb
195
+ - templates/pgbouncer.ini.erb
196
+ - templates/postgresql.conf.erb
197
+ - templates/repmgr.conf.erb
198
+ homepage: https://github.com/boringcache/active_postgres
199
+ licenses:
200
+ - MIT
201
+ metadata:
202
+ homepage_uri: https://github.com/boringcache/active_postgres
203
+ source_code_uri: https://github.com/boringcache/active_postgres
204
+ documentation_uri: https://github.com/boringcache/active_postgres/blob/main/README.md
205
+ changelog_uri: https://github.com/boringcache/active_postgres/blob/main/CHANGELOG.md
206
+ rubygems_mfa_required: 'true'
207
+ rdoc_options: []
208
+ require_paths:
209
+ - lib
210
+ required_ruby_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: 3.3.0
215
+ required_rubygems_version: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ requirements: []
221
+ rubygems_version: 3.6.7
222
+ specification_version: 4
223
+ summary: PostgreSQL High Availability for Rails, made simple
224
+ test_files: []