pgbouncerhero 3.0.0 → 3.2.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 +4 -4
- data/CHANGELOG.md +45 -0
- data/README.md +119 -4
- data/app/assets/builds/pgbouncerhero/application.css +2 -2
- data/app/assets/stylesheets/pgbouncerhero/application.css +11 -1
- data/app/controllers/pg_bouncer_hero/application_controller.rb +4 -3
- data/app/controllers/pg_bouncer_hero/database_controller.rb +93 -9
- data/app/helpers/pg_bouncer_hero/application_helper.rb +54 -0
- data/app/javascript/pgbouncerhero/controllers/data_table_controller.js +183 -0
- data/app/javascript/pgbouncerhero/controllers/fleet_controller.js +52 -0
- data/app/javascript/pgbouncerhero/controllers/polling_controller.js +49 -5
- data/app/views/layouts/pg_bouncer_hero/application.html.erb +1 -1
- data/app/views/pg_bouncer_hero/database/_actions.html.erb +1 -1
- data/app/views/pg_bouncer_hero/database/_clients.html.erb +9 -8
- data/app/views/pg_bouncer_hero/database/_conf.html.erb +10 -9
- data/app/views/pg_bouncer_hero/database/_databases.html.erb +30 -9
- data/app/views/pg_bouncer_hero/database/_menu.html.erb +19 -4
- data/app/views/pg_bouncer_hero/database/_pools.html.erb +10 -9
- data/app/views/pg_bouncer_hero/database/_servers.html.erb +31 -0
- data/app/views/pg_bouncer_hero/database/_state.html.erb +11 -0
- data/app/views/pg_bouncer_hero/database/_stats.html.erb +12 -11
- data/app/views/pg_bouncer_hero/database/_users.html.erb +31 -0
- data/app/views/pg_bouncer_hero/database/clients.html.erb +4 -2
- data/app/views/pg_bouncer_hero/database/conf.html.erb +4 -2
- data/app/views/pg_bouncer_hero/database/databases.html.erb +4 -2
- data/app/views/pg_bouncer_hero/database/pools.html.erb +4 -2
- data/app/views/pg_bouncer_hero/database/servers.html.erb +6 -0
- data/app/views/pg_bouncer_hero/database/state.html.erb +6 -0
- data/app/views/pg_bouncer_hero/database/stats.html.erb +4 -2
- data/app/views/pg_bouncer_hero/database/users.html.erb +6 -0
- data/app/views/pg_bouncer_hero/home/_card.html.erb +5 -2
- data/app/views/pg_bouncer_hero/home/_card_content.html.erb +48 -31
- data/app/views/pg_bouncer_hero/home/index.html.erb +28 -8
- data/app/views/shared/_data_table_toolbar.html.erb +13 -0
- data/config/routes.rb +16 -2
- data/lib/generators/pgbouncerhero/templates/config.yml +7 -0
- data/lib/pgbouncerhero/connection.rb +54 -13
- data/lib/pgbouncerhero/database.rb +73 -3
- data/lib/pgbouncerhero/methods/basics.rb +86 -10
- data/lib/pgbouncerhero/version.rb +1 -1
- data/lib/pgbouncerhero.rb +139 -38
- metadata +83 -3
data/lib/pgbouncerhero.rb
CHANGED
|
@@ -1,26 +1,47 @@
|
|
|
1
|
-
require "
|
|
2
|
-
|
|
3
|
-
require "
|
|
4
|
-
|
|
5
|
-
require "
|
|
6
|
-
require "
|
|
7
|
-
|
|
8
|
-
require "pgbouncerhero/connection"
|
|
9
|
-
|
|
1
|
+
require "erb"
|
|
2
|
+
require "monitor"
|
|
3
|
+
require "pathname"
|
|
4
|
+
require "yaml"
|
|
5
|
+
require "rails"
|
|
6
|
+
require "active_support/notifications"
|
|
10
7
|
require "pg"
|
|
11
8
|
require "importmap-rails"
|
|
12
9
|
require "turbo-rails"
|
|
13
10
|
require "stimulus-rails"
|
|
14
11
|
|
|
12
|
+
require "pgbouncerhero/version"
|
|
13
|
+
require "pgbouncerhero/methods/basics"
|
|
14
|
+
require "pgbouncerhero/connection"
|
|
15
|
+
require "pgbouncerhero/group"
|
|
16
|
+
require "pgbouncerhero/engine"
|
|
17
|
+
|
|
15
18
|
module PgBouncerHero
|
|
19
|
+
ADMIN_COMMAND_EVENT = "admin_command.pgbouncerhero"
|
|
20
|
+
|
|
21
|
+
class ConfigurationError < StandardError; end
|
|
22
|
+
|
|
23
|
+
BOOLEAN_SETTINGS = {
|
|
24
|
+
true => true,
|
|
25
|
+
false => false,
|
|
26
|
+
"1" => true,
|
|
27
|
+
"0" => false,
|
|
28
|
+
"true" => true,
|
|
29
|
+
"false" => false,
|
|
30
|
+
"yes" => true,
|
|
31
|
+
"no" => false,
|
|
32
|
+
"on" => true,
|
|
33
|
+
"off" => false
|
|
34
|
+
}.freeze
|
|
35
|
+
private_constant :BOOLEAN_SETTINGS
|
|
36
|
+
|
|
37
|
+
STATE_MONITOR = Monitor.new
|
|
38
|
+
private_constant :STATE_MONITOR
|
|
39
|
+
|
|
16
40
|
mattr_accessor :importmap, default: Importmap::Map.new
|
|
17
41
|
|
|
18
42
|
class << self
|
|
19
|
-
|
|
20
|
-
end
|
|
21
|
-
self.env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
43
|
+
attr_reader :env
|
|
22
44
|
|
|
23
|
-
class << self
|
|
24
45
|
def time_zone=(time_zone)
|
|
25
46
|
@time_zone = time_zone.is_a?(ActiveSupport::TimeZone) ? time_zone : ActiveSupport::TimeZone[time_zone.to_s]
|
|
26
47
|
end
|
|
@@ -29,38 +50,118 @@ module PgBouncerHero
|
|
|
29
50
|
@time_zone || Time.zone
|
|
30
51
|
end
|
|
31
52
|
|
|
53
|
+
def env=(env)
|
|
54
|
+
STATE_MONITOR.synchronize do
|
|
55
|
+
@env = env.to_s
|
|
56
|
+
reset!
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def config_path
|
|
61
|
+
STATE_MONITOR.synchronize { @config_path || default_config_path }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def config_path=(path)
|
|
65
|
+
STATE_MONITOR.synchronize do
|
|
66
|
+
@config_path = path && Pathname(path)
|
|
67
|
+
reset!
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
32
71
|
def config
|
|
33
|
-
@config ||=
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
config[env]
|
|
41
|
-
elsif config["pgbouncers"]
|
|
42
|
-
config
|
|
43
|
-
else
|
|
44
|
-
{
|
|
45
|
-
"pgbouncers" => {
|
|
46
|
-
"default" => {
|
|
47
|
-
"primary" => {
|
|
48
|
-
"url" => ENV["PGBOUNCERHERO_DATABASE_URL"]
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
72
|
+
STATE_MONITOR.synchronize { @config ||= selected_config(load_config) }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def groups
|
|
76
|
+
STATE_MONITOR.synchronize do
|
|
77
|
+
@groups ||= config.fetch("pgbouncers").to_h do |group_id, _databases|
|
|
78
|
+
[ group_id.parameterize, PgBouncerHero::Group.new(group_id, config.fetch("pgbouncers")) ]
|
|
53
79
|
end
|
|
54
80
|
end
|
|
55
81
|
end
|
|
56
82
|
|
|
57
|
-
def
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
83
|
+
def read_only?
|
|
84
|
+
value = ENV.fetch("PGBOUNCERHERO_READ_ONLY") { config.fetch("read_only", false) }
|
|
85
|
+
parse_read_only(value)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def read_only_for?(database)
|
|
89
|
+
value = ENV.fetch("PGBOUNCERHERO_READ_ONLY") do
|
|
90
|
+
database.config.fetch("read_only") { config.fetch("read_only", false) }
|
|
91
|
+
end
|
|
92
|
+
parse_read_only(value)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def parse_read_only(value)
|
|
96
|
+
BOOLEAN_SETTINGS.fetch(value.is_a?(String) ? value.downcase : value)
|
|
97
|
+
rescue KeyError
|
|
98
|
+
raise ConfigurationError, "read_only must be a boolean"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def disconnect!
|
|
102
|
+
STATE_MONITOR.synchronize do
|
|
103
|
+
@groups&.each_value do |group|
|
|
104
|
+
group.databases.each(&:disconnect!)
|
|
61
105
|
end
|
|
62
|
-
Hash[mapped]
|
|
63
106
|
end
|
|
64
107
|
end
|
|
108
|
+
|
|
109
|
+
def reset!
|
|
110
|
+
STATE_MONITOR.synchronize do
|
|
111
|
+
disconnect!
|
|
112
|
+
@config = nil
|
|
113
|
+
@groups = nil
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private :parse_read_only
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
def default_config_path
|
|
122
|
+
(Rails.root || Pathname.pwd).join("config/pgbouncerhero.yml")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def load_config
|
|
126
|
+
return {} unless config_path.file?
|
|
127
|
+
|
|
128
|
+
loaded = YAML.safe_load(ERB.new(config_path.read).result, aliases: true)
|
|
129
|
+
return {} if loaded.nil?
|
|
130
|
+
return loaded if loaded.is_a?(Hash)
|
|
131
|
+
|
|
132
|
+
raise ConfigurationError, "#{config_path} must contain a YAML mapping"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def selected_config(loaded)
|
|
136
|
+
selected = loaded.fetch(env, loaded)
|
|
137
|
+
unless selected.is_a?(Hash)
|
|
138
|
+
raise ConfigurationError, "configuration for #{env.inspect} must be a YAML mapping"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
return default_config unless selected.key?("pgbouncers")
|
|
142
|
+
|
|
143
|
+
pgbouncers = selected["pgbouncers"]
|
|
144
|
+
unless pgbouncers.is_a?(Hash) && pgbouncers.any? && pgbouncers.values.all? { |databases| databases.is_a?(Hash) && databases.any? }
|
|
145
|
+
raise ConfigurationError, '"pgbouncers" must contain at least one group with one database'
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
selected
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def default_config
|
|
152
|
+
{
|
|
153
|
+
"pgbouncers" => {
|
|
154
|
+
"default" => {
|
|
155
|
+
"primary" => {
|
|
156
|
+
"url" => ENV["PGBOUNCERHERO_DATABASE_URL"]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
end
|
|
65
162
|
end
|
|
163
|
+
|
|
164
|
+
self.env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
66
165
|
end
|
|
166
|
+
|
|
167
|
+
at_exit { PgBouncerHero.disconnect! }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pgbouncerhero
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Quentin Rousseau
|
|
@@ -16,6 +16,9 @@ dependencies:
|
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
18
|
version: '7.2'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '9'
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -23,6 +26,29 @@ dependencies:
|
|
|
23
26
|
- - ">="
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
28
|
version: '7.2'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '9'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: propshaft
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '1.0'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '2'
|
|
42
|
+
type: :runtime
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '1.0'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '2'
|
|
26
52
|
- !ruby/object:Gem::Dependency
|
|
27
53
|
name: importmap-rails
|
|
28
54
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -30,6 +56,9 @@ dependencies:
|
|
|
30
56
|
- - ">="
|
|
31
57
|
- !ruby/object:Gem::Version
|
|
32
58
|
version: '1.2'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3'
|
|
33
62
|
type: :runtime
|
|
34
63
|
prerelease: false
|
|
35
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -37,6 +66,9 @@ dependencies:
|
|
|
37
66
|
- - ">="
|
|
38
67
|
- !ruby/object:Gem::Version
|
|
39
68
|
version: '1.2'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '3'
|
|
40
72
|
- !ruby/object:Gem::Dependency
|
|
41
73
|
name: turbo-rails
|
|
42
74
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -44,6 +76,9 @@ dependencies:
|
|
|
44
76
|
- - ">="
|
|
45
77
|
- !ruby/object:Gem::Version
|
|
46
78
|
version: '1.0'
|
|
79
|
+
- - "<"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '3'
|
|
47
82
|
type: :runtime
|
|
48
83
|
prerelease: false
|
|
49
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -51,6 +86,9 @@ dependencies:
|
|
|
51
86
|
- - ">="
|
|
52
87
|
- !ruby/object:Gem::Version
|
|
53
88
|
version: '1.0'
|
|
89
|
+
- - "<"
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '3'
|
|
54
92
|
- !ruby/object:Gem::Dependency
|
|
55
93
|
name: stimulus-rails
|
|
56
94
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,6 +96,9 @@ dependencies:
|
|
|
58
96
|
- - ">="
|
|
59
97
|
- !ruby/object:Gem::Version
|
|
60
98
|
version: '1.0'
|
|
99
|
+
- - "<"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '2'
|
|
61
102
|
type: :runtime
|
|
62
103
|
prerelease: false
|
|
63
104
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -65,6 +106,9 @@ dependencies:
|
|
|
65
106
|
- - ">="
|
|
66
107
|
- !ruby/object:Gem::Version
|
|
67
108
|
version: '1.0'
|
|
109
|
+
- - "<"
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '2'
|
|
68
112
|
- !ruby/object:Gem::Dependency
|
|
69
113
|
name: pg
|
|
70
114
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,6 +116,9 @@ dependencies:
|
|
|
72
116
|
- - ">="
|
|
73
117
|
- !ruby/object:Gem::Version
|
|
74
118
|
version: '1.2'
|
|
119
|
+
- - "<"
|
|
120
|
+
- !ruby/object:Gem::Version
|
|
121
|
+
version: '2'
|
|
75
122
|
type: :runtime
|
|
76
123
|
prerelease: false
|
|
77
124
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -79,6 +126,29 @@ dependencies:
|
|
|
79
126
|
- - ">="
|
|
80
127
|
- !ruby/object:Gem::Version
|
|
81
128
|
version: '1.2'
|
|
129
|
+
- - "<"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '2'
|
|
132
|
+
- !ruby/object:Gem::Dependency
|
|
133
|
+
name: connection_pool
|
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '3.0'
|
|
139
|
+
- - "<"
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: '4'
|
|
142
|
+
type: :runtime
|
|
143
|
+
prerelease: false
|
|
144
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
145
|
+
requirements:
|
|
146
|
+
- - ">="
|
|
147
|
+
- !ruby/object:Gem::Version
|
|
148
|
+
version: '3.0'
|
|
149
|
+
- - "<"
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '4'
|
|
82
152
|
- !ruby/object:Gem::Dependency
|
|
83
153
|
name: rake
|
|
84
154
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -113,14 +183,14 @@ dependencies:
|
|
|
113
183
|
requirements:
|
|
114
184
|
- - "~>"
|
|
115
185
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: '
|
|
186
|
+
version: '6.0'
|
|
117
187
|
type: :development
|
|
118
188
|
prerelease: false
|
|
119
189
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
190
|
requirements:
|
|
121
191
|
- - "~>"
|
|
122
192
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: '
|
|
193
|
+
version: '6.0'
|
|
124
194
|
- !ruby/object:Gem::Dependency
|
|
125
195
|
name: appraisal
|
|
126
196
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -195,6 +265,8 @@ files:
|
|
|
195
265
|
- app/controllers/pg_bouncer_hero/home_controller.rb
|
|
196
266
|
- app/helpers/pg_bouncer_hero/application_helper.rb
|
|
197
267
|
- app/javascript/pgbouncerhero/application.js
|
|
268
|
+
- app/javascript/pgbouncerhero/controllers/data_table_controller.js
|
|
269
|
+
- app/javascript/pgbouncerhero/controllers/fleet_controller.js
|
|
198
270
|
- app/javascript/pgbouncerhero/controllers/polling_controller.js
|
|
199
271
|
- app/views/layouts/pg_bouncer_hero/application.html.erb
|
|
200
272
|
- app/views/pg_bouncer_hero/database/_actions.html.erb
|
|
@@ -203,18 +275,25 @@ files:
|
|
|
203
275
|
- app/views/pg_bouncer_hero/database/_databases.html.erb
|
|
204
276
|
- app/views/pg_bouncer_hero/database/_menu.html.erb
|
|
205
277
|
- app/views/pg_bouncer_hero/database/_pools.html.erb
|
|
278
|
+
- app/views/pg_bouncer_hero/database/_servers.html.erb
|
|
279
|
+
- app/views/pg_bouncer_hero/database/_state.html.erb
|
|
206
280
|
- app/views/pg_bouncer_hero/database/_stats.html.erb
|
|
281
|
+
- app/views/pg_bouncer_hero/database/_users.html.erb
|
|
207
282
|
- app/views/pg_bouncer_hero/database/clients.html.erb
|
|
208
283
|
- app/views/pg_bouncer_hero/database/conf.html.erb
|
|
209
284
|
- app/views/pg_bouncer_hero/database/databases.html.erb
|
|
210
285
|
- app/views/pg_bouncer_hero/database/pools.html.erb
|
|
286
|
+
- app/views/pg_bouncer_hero/database/servers.html.erb
|
|
287
|
+
- app/views/pg_bouncer_hero/database/state.html.erb
|
|
211
288
|
- app/views/pg_bouncer_hero/database/stats.html.erb
|
|
212
289
|
- app/views/pg_bouncer_hero/database/summary.html.erb
|
|
290
|
+
- app/views/pg_bouncer_hero/database/users.html.erb
|
|
213
291
|
- app/views/pg_bouncer_hero/home/_card.html.erb
|
|
214
292
|
- app/views/pg_bouncer_hero/home/_card_content.html.erb
|
|
215
293
|
- app/views/pg_bouncer_hero/home/_card_loading_content.html.erb
|
|
216
294
|
- app/views/pg_bouncer_hero/home/index.html.erb
|
|
217
295
|
- app/views/shared/_alert.html.erb
|
|
296
|
+
- app/views/shared/_data_table_toolbar.html.erb
|
|
218
297
|
- app/views/shared/_flash_messages.html.erb
|
|
219
298
|
- config/importmap.rb
|
|
220
299
|
- config/routes.rb
|
|
@@ -233,6 +312,7 @@ licenses:
|
|
|
233
312
|
metadata:
|
|
234
313
|
source_code_uri: https://github.com/kwent/pgbouncerhero
|
|
235
314
|
changelog_uri: https://github.com/kwent/pgbouncerhero/blob/master/CHANGELOG.md
|
|
315
|
+
documentation_uri: https://github.com/kwent/pgbouncerhero#readme
|
|
236
316
|
bug_tracker_uri: https://github.com/kwent/pgbouncerhero/issues
|
|
237
317
|
rubygems_mfa_required: 'true'
|
|
238
318
|
rdoc_options: []
|