gitlab-exporter 14.5.0 → 15.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +24 -1
- data/Gemfile.lock +1 -1
- data/config/gitlab-exporter.yml.example +8 -0
- data/lib/gitlab_exporter/cli.rb +26 -8
- data/lib/gitlab_exporter/database/base.rb +4 -0
- data/lib/gitlab_exporter/sidekiq.rb +17 -1
- data/lib/gitlab_exporter/version.rb +1 -1
- data/spec/database/ci_builds_spec.rb +16 -0
- data/spec/integration/cli_spec.rb +17 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa3c6ff71709207bbbe1c85dea19eab223c678c721baf437eed2275ad73816b9
|
4
|
+
data.tar.gz: f263b55d0e45ece0a7d3124511c684eacbe78532eae81e2f4c11f3ec4279af9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8db3f5dd5db87f02d7a85fb58c13e8a48df40726c5718fd82d5b7ae792675948bd43664da3f94075527e5242c0dcf8bc5e150f8606611097677a812981d73354
|
7
|
+
data.tar.gz: 9411698d4c809eba8997bd8fc0f9cc4295dac625daa35a8faf37604909a20fde621afb161534bd82fa912087cf50de45e5e192186627cb95f5c8b5643de1742e
|
data/.gitlab-ci.yml
CHANGED
@@ -50,9 +50,32 @@ rspec_integration:
|
|
50
50
|
- bundle exec rspec spec -t integration -f d -c
|
51
51
|
before_script: *before_scripts
|
52
52
|
services:
|
53
|
-
- redis
|
53
|
+
- name: redis:${REDIS_VERSION}
|
54
|
+
alias: redis-master
|
55
|
+
- name: bitnami/redis-sentinel:${REDIS_SENTINEL_VERSION}
|
56
|
+
alias: redis-sentinel
|
57
|
+
command:
|
58
|
+
- /bin/sh
|
59
|
+
- -c
|
60
|
+
- |
|
61
|
+
echo "Starting Redis Sentinel..."
|
62
|
+
cat <<EOF > /opt/bitnami/redis-sentinel/etc/sentinel.conf
|
63
|
+
user default off
|
64
|
+
user ${REDIS_SENTINEL_USERNAME} on >${REDIS_SENTINEL_PASSWORD} +@all
|
65
|
+
sentinel monitor mymaster redis-master 6379 2
|
66
|
+
sentinel resolve-hostnames yes
|
67
|
+
sentinel down-after-milliseconds mymaster 5000
|
68
|
+
EOF
|
69
|
+
redis-sentinel /opt/bitnami/redis-sentinel/etc/sentinel.conf
|
70
|
+
|
54
71
|
variables:
|
55
72
|
REDIS_URL: "redis://redis"
|
73
|
+
REDIS_SENTINEL_URL: "redis://mymaster"
|
74
|
+
REDIS_SENTINELS: "redis-sentinel:26379"
|
75
|
+
REDIS_VERSION: latest
|
76
|
+
REDIS_SENTINEL_VERSION: latest
|
77
|
+
REDIS_SENTINEL_USERNAME: "my-sentinel-username"
|
78
|
+
REDIS_SENTINEL_PASSWORD: "my-sentinel-password"
|
56
79
|
parallel:
|
57
80
|
matrix:
|
58
81
|
- RUBY_VERSION: ["2.7", "3.0", "3.1", "3.2"]
|
data/Gemfile.lock
CHANGED
@@ -98,6 +98,14 @@ probes:
|
|
98
98
|
# redis_username: 'redis-username'
|
99
99
|
# redis_password: 'redis-password'
|
100
100
|
redis_enable_client: true
|
101
|
+
# Uncomment if Redis Sentinels are needed
|
102
|
+
# redis_sentinels:
|
103
|
+
# - host: 'localhost'
|
104
|
+
# port: 26380
|
105
|
+
# - host: 'localhost'
|
106
|
+
# port: 26381
|
107
|
+
# redis_sentinel_username: 'redis-sentinel-username'
|
108
|
+
# redis_sentinel_password: 'redis-sentinel-password'
|
101
109
|
|
102
110
|
ruby: &ruby
|
103
111
|
class_name: RubyProber
|
data/lib/gitlab_exporter/cli.rb
CHANGED
@@ -297,12 +297,24 @@ module GitLab
|
|
297
297
|
@target = File.open(@target, "a") if @target.is_a?(String)
|
298
298
|
end
|
299
299
|
|
300
|
-
def options(args)
|
300
|
+
def options(args) # rubocop:disable Metrics/MethodLength
|
301
301
|
args.options do |opts|
|
302
302
|
opts.banner = "Usage: #{EXECUTABLE_NAME} #{COMMAND_NAME} [options]"
|
303
303
|
opts.on("--redis-url=\"redis://localhost:6379\"", "Redis URL") do |val|
|
304
304
|
@redis_url = val
|
305
305
|
end
|
306
|
+
opts.on("--redis-sentinel-username=\"my-sentinel-username\"", "Redis Sentinel username") do |val|
|
307
|
+
@redis_sentinel_username = val
|
308
|
+
end
|
309
|
+
opts.on("--redis-sentinel-password=\"my-sentinel-password\"", "Redis Sentinel password") do |val|
|
310
|
+
@redis_sentinel_password = val
|
311
|
+
end
|
312
|
+
opts.on("--redis-sentinels=HOST1:PORT1,HOST2:PORT2", Array, "List of Redis Sentinels") do |val|
|
313
|
+
@redis_sentinels = val.map { |item|
|
314
|
+
host, port = item.split(":")
|
315
|
+
{ host: host, port: port.to_i }
|
316
|
+
}
|
317
|
+
end
|
306
318
|
end
|
307
319
|
end
|
308
320
|
|
@@ -313,13 +325,19 @@ module GitLab
|
|
313
325
|
def run
|
314
326
|
validate!
|
315
327
|
|
316
|
-
::GitLab::Exporter::SidekiqProber.new(redis_url: @redis_url
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
328
|
+
prober = ::GitLab::Exporter::SidekiqProber.new(redis_url: @redis_url,
|
329
|
+
redis_sentinels: @redis_sentinels,
|
330
|
+
redis_sentinel_username: @redis_sentinel_username,
|
331
|
+
redis_sentinel_password: @redis_sentinel_password,
|
332
|
+
logger: Logger.new(STDERR))
|
333
|
+
|
334
|
+
prober
|
335
|
+
.probe_stats
|
336
|
+
.probe_queues
|
337
|
+
.probe_jobs_limit
|
338
|
+
.probe_workers
|
339
|
+
.probe_retries
|
340
|
+
.write_to(@target)
|
323
341
|
end
|
324
342
|
|
325
343
|
private
|
@@ -62,6 +62,10 @@ module GitLab
|
|
62
62
|
conn.reset
|
63
63
|
raise e
|
64
64
|
end
|
65
|
+
rescue PG::ConnectionBad => e
|
66
|
+
@logger.error "Bad connection to the database, resetting pool: #{e}" if @logger
|
67
|
+
connection_pool.reload(&:close)
|
68
|
+
raise e
|
65
69
|
rescue PG::Error => e
|
66
70
|
@logger.error "Error connecting to the database: #{e}" if @logger
|
67
71
|
raise e
|
@@ -7,7 +7,7 @@ module GitLab
|
|
7
7
|
# A prober for Sidekiq queues
|
8
8
|
#
|
9
9
|
# It takes the Redis URL Sidekiq is connected to
|
10
|
-
class SidekiqProber
|
10
|
+
class SidekiqProber # rubocop:disable Metrics/ClassLength
|
11
11
|
# The maximum depth (from the head) of each queue to probe. Probing the
|
12
12
|
# entirety of a very large queue will take longer and run the risk of
|
13
13
|
# timing out. But when we have a very large queue, we are most in need of
|
@@ -195,6 +195,7 @@ module GitLab
|
|
195
195
|
def redis_options
|
196
196
|
options = {
|
197
197
|
url: @opts[:redis_url],
|
198
|
+
sentinels: redis_sentinel_options,
|
198
199
|
connect_timeout: 1,
|
199
200
|
reconnect_attempts: 0
|
200
201
|
}
|
@@ -207,6 +208,19 @@ module GitLab
|
|
207
208
|
options
|
208
209
|
end
|
209
210
|
|
211
|
+
def redis_sentinel_options
|
212
|
+
sentinels = @opts[:redis_sentinels]
|
213
|
+
|
214
|
+
return sentinels unless sentinels.is_a?(Array)
|
215
|
+
|
216
|
+
sentinels.each do |sentinel_config|
|
217
|
+
sentinel_config[:username] = @opts[:redis_sentinel_username] if @opts.key?(:redis_sentinel_username)
|
218
|
+
sentinel_config[:password] = @opts[:redis_sentinel_password] if @opts.key?(:redis_sentinel_password)
|
219
|
+
end
|
220
|
+
|
221
|
+
sentinels
|
222
|
+
end
|
223
|
+
|
210
224
|
def redis_enable_client?
|
211
225
|
return true if @opts[:redis_enable_client].nil?
|
212
226
|
|
@@ -221,6 +235,8 @@ module GitLab
|
|
221
235
|
end
|
222
236
|
rescue Redis::BaseConnectionError => e
|
223
237
|
@logger&.error "Error connecting to the Redis: #{e}"
|
238
|
+
pool = self.class.connection_pool[redis_options]
|
239
|
+
pool.reload(&:close)
|
224
240
|
@connected = false
|
225
241
|
end
|
226
242
|
end
|
@@ -290,6 +290,22 @@ describe GitLab::Exporter::Database do
|
|
290
290
|
expect(output).to match(/^ci_stale_builds 0.0$/m)
|
291
291
|
end
|
292
292
|
end
|
293
|
+
|
294
|
+
context "when PG connection shuts down" do
|
295
|
+
before do
|
296
|
+
allow(connection).to receive(:exec).and_raise(PG::ConnectionBad)
|
297
|
+
end
|
298
|
+
|
299
|
+
it "responds with Prometheus metrics" do
|
300
|
+
expect(connection_pool).to receive(:reload)
|
301
|
+
|
302
|
+
prober.probe_db
|
303
|
+
prober.write_to(writer)
|
304
|
+
output = writer.string
|
305
|
+
|
306
|
+
expect(output).to be_empty
|
307
|
+
end
|
308
|
+
end
|
293
309
|
end
|
294
310
|
|
295
311
|
context "when executed on EE" do
|
@@ -6,6 +6,13 @@ module GitLab
|
|
6
6
|
module CLI
|
7
7
|
describe SidekiqRunner, :integration do
|
8
8
|
let(:redis_url) { ENV.fetch("REDIS_URL", "redis://localhost:6379") }
|
9
|
+
let(:redis_sentinel_url) { ENV.fetch("REDIS_SENTINEL_URL", "redis://mymaster:6379") }
|
10
|
+
let(:redis_sentinel_username) { ENV.fetch("REDIS_SENTINEL_USERNAME", "my-sentinel-user") }
|
11
|
+
let(:redis_sentinel_password) { ENV.fetch("REDIS_SENTINEL_PASSWORD", "my-sentinel-password") }
|
12
|
+
let(:redis_sentinels) do
|
13
|
+
sentinels = ENV.fetch("REDIS_SENTINELS", "localhost:26379")
|
14
|
+
sentinels.split(" ")
|
15
|
+
end
|
9
16
|
let(:io) { StringIO.new }
|
10
17
|
|
11
18
|
it "can properly reach out to redis" do
|
@@ -14,6 +21,16 @@ module GitLab
|
|
14
21
|
|
15
22
|
expect { runner.run }.not_to raise_error
|
16
23
|
end
|
24
|
+
|
25
|
+
it "can properly reach out to redis-sentinel" do
|
26
|
+
args = CLIArgs.new([io], options: { /^--redis-url/ => redis_sentinel_url,
|
27
|
+
/^--redis-sentinel-username/ => redis_sentinel_username,
|
28
|
+
/^--redis-sentinel-password/ => redis_sentinel_password,
|
29
|
+
/^--redis-sentinels/ => redis_sentinels })
|
30
|
+
runner = SidekiqRunner.new(args)
|
31
|
+
|
32
|
+
expect { runner.run }.not_to raise_error
|
33
|
+
end
|
17
34
|
end
|
18
35
|
end
|
19
36
|
end
|