sensu-plugins-docker 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -1
- data/README.md +9 -0
- data/bin/check-container-logs.rb +86 -32
- data/bin/check-container.rb +26 -33
- data/bin/check-docker-container.rb +15 -17
- data/bin/metrics-docker-container.rb +40 -12
- data/bin/metrics-docker-info.rb +9 -35
- data/bin/metrics-docker-stats.rb +31 -48
- data/lib/sensu-plugins-docker/client_helpers.rb +55 -13
- data/lib/sensu-plugins-docker/version.rb +1 -1
- metadata +6 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00d6b43c8b66736073dd792abffe2d13f99034f0981795bf21663412ec64865e
|
4
|
+
data.tar.gz: 3f1fd2aedfcd7ac02eb06a8f5656b3527d670ef77fc61d192901b5d78770af37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58a4c4cf16098e2e57d0b28b38e6061b842d54df4deecca9c4e08f0bbca288541ac4faf095801b5f33627438aa56d2d4db01d99a7170e3f05cb8ec4a5225654f
|
7
|
+
data.tar.gz: 57fcb788326eee5cdb4a4df9aa731637f7407b8d51eacd901da12d1573e035c4f060884304bb00478a6ba48f35aae3610107c10429a43982fbed85bd3990e369
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,36 @@ Which is based on [Keep A Changelog](http://keepachangelog.com/)
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [3.0.0] - 2018-02-17
|
10
|
+
### Breaking Changes
|
11
|
+
- Default docker host defined by DockerApi Class ( ENV[DOCKER_URL] => ENV[DOCKER_HOST] => /var/run/docker.sock )
|
12
|
+
- check-container-logs.rb: -N (--container-name) instead of -n for container name. Now a 'CRITICAL' is trigger if a container doesn't exist (previously, a 'OK' was trigger)
|
13
|
+
- check-docker-container.rb: -H (--docker-host) instead of -h (--host) for docker Host
|
14
|
+
- check-container.rb: -H (--docker-host) for docker Host instead of -h (--host) for docker host, -N (--container-name) instead of -c (--container) for container name
|
15
|
+
- metrics-docker-stats.rb: -N (--container-name) instead of -c (--container) for Container name
|
16
|
+
|
17
|
+
### Added
|
18
|
+
- client_helpers.rb: Add a simple DockerApi class. Add parse_json method.
|
19
|
+
- metrics-docker-container.rb: Friendly names option added
|
20
|
+
- check-container-logs.rb: Add an option to check logs from stopped containers if all containers are checked. Add an option to don't check stderr logs. Add an option to don't check stdout logs. Add timestamp in logs output. Add the possibility to use -n multiple times to check multiple containers at once.
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
- metrics-docker-stats.rb: Make use of DockerApi class. Default docker_host defined by DockerApi class. Remove docker_api method.
|
24
|
+
- metrics-docker-info.rb: Make use of DockerApi class. Default docker_host defined by DockerApi class. Remove docker_api method.
|
25
|
+
- metrics-docker-container.rb: Make use of DockerApi class. Re-enable rubocop for container_metrics method.
|
26
|
+
- check-container.rb: Make use of DockerApi class.
|
27
|
+
- check-docker-container.rb: Make use of DockerApi class.
|
28
|
+
- check-container-logs.rb: Make use of DockerApi class. Check only logs generated with the 8 bits control to prevent to check logs generated in interactive mode. Check the newest logs rows first instead the oldest. Option -n is not required anymore, if -n option is not provided, the check will be applied to all running containers. Changed the messages displayed with ok and critical
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
- metrics-docker-stats.rb: Remove trailing / in name value.
|
32
|
+
|
33
|
+
### Removed
|
34
|
+
- Remove unnecessary `docker_api` dependency
|
35
|
+
- check-container-logs.rb: Logs generated in interactive mode are not checked anymore
|
36
|
+
- metrics-docker-stats.rb: option -p (--protocol) have been removed because new DockerApi don't use it
|
37
|
+
- metrics-docker-info.rb: option -p (--protocol) have been removed because new DockerApi don't use it
|
38
|
+
|
9
39
|
## [2.0.0] - 2017-11-06
|
10
40
|
### Fixed
|
11
41
|
- metrics-docker-stats.rb:: Fix gsub on nil docker environment variable (@epierotto)
|
@@ -111,7 +141,8 @@ changes some options. Review your check commands before deploying this version.
|
|
111
141
|
### Added
|
112
142
|
- initial release
|
113
143
|
|
114
|
-
[Unreleased]: https://github.com/sensu-plugins/sensu-plugins-docker/compare/
|
144
|
+
[Unreleased]: https://github.com/sensu-plugins/sensu-plugins-docker/compare/3.0.0...HEAD
|
145
|
+
[3.0.0]: https://github.com/sensu-plugins/sensu-plugins-docker/compare/2.0.0...3.0.0
|
115
146
|
[2.0.0]: https://github.com/sensu-plugins/sensu-plugins-docker/compare/1.5.0...2.0.0
|
116
147
|
[1.5.0]: https://github.com/sensu-plugins/sensu-plugins-docker/compare/1.4.0..1.5.0
|
117
148
|
[1.4.0]: https://github.com/sensu-plugins/sensu-plugins-docker/compare/1.3.1...1.4.0
|
data/README.md
CHANGED
@@ -19,6 +19,15 @@ This check supports docker versions >= 1.18. Check docker-engine API for more in
|
|
19
19
|
|
20
20
|
## Usage
|
21
21
|
|
22
|
+
### Default docker host
|
23
|
+
By default, all the checks will try to use a default docker host if a specific docker host is not provided to the check on the command line (-H <docker_host> / --docker-host <docker_host>).
|
24
|
+
|
25
|
+
Those paramaters will be tried in this order as default docker host :
|
26
|
+
|
27
|
+
DOCKER_URL environnement variable
|
28
|
+
DOCKER_HOST environnement variable
|
29
|
+
/var/run/docker.sock file
|
30
|
+
|
22
31
|
## Installation
|
23
32
|
|
24
33
|
[Installation and Setup](http://sensu-plugins.io/docs/installation_instructions.html)
|
data/bin/check-container-logs.rb
CHANGED
@@ -17,10 +17,21 @@
|
|
17
17
|
# gem: net_http_unix
|
18
18
|
#
|
19
19
|
# USAGE:
|
20
|
-
#
|
20
|
+
# # Check only one container
|
21
|
+
# check-container-logs.rb -H /tmp/docker.sock -N logspout -r 'problem sending' -r 'i/o timeout' -i 'Remark:' -i 'The configuration is'
|
21
22
|
# => 1 container running = OK
|
22
23
|
# => 4 container running = CRITICAL
|
23
24
|
#
|
25
|
+
# # Check multiple containers
|
26
|
+
# check-container-logs.rb -H /tmp/docker.sock -N logspout -N logtest -r 'problem sending' -r 'i/o timeout' -i 'Remark:' -i 'The configuration is'
|
27
|
+
# => 1 container running = OK
|
28
|
+
# => 4 container running = CRITICAL
|
29
|
+
#
|
30
|
+
# # Check all containers
|
31
|
+
# check-container-logs.rb -H /tmp/docker.sock -r 'problem sending' -r 'i/o timeout' -i 'Remark:' -i 'The configuration is'
|
32
|
+
# => 1 containers running = OK
|
33
|
+
# => 4 containers running = CRITICAL
|
34
|
+
#
|
24
35
|
# NOTES:
|
25
36
|
# The API parameter required to use the limited lookback (-t) was introduced
|
26
37
|
# the Docker server API version 1.19. This check may still work on older API
|
@@ -37,36 +48,33 @@ require 'sensu-plugins-docker/client_helpers'
|
|
37
48
|
|
38
49
|
class ContainerLogChecker < Sensu::Plugin::Check::CLI
|
39
50
|
option :docker_host,
|
40
|
-
description: 'Docker
|
51
|
+
description: 'Docker API URI. https://host, https://host:port, http://host, http://host:port, host:port, unix:///path',
|
41
52
|
short: '-H DOCKER_HOST',
|
42
|
-
long: '--docker-host DOCKER_HOST'
|
43
|
-
default: '127.0.0.1:2375'
|
53
|
+
long: '--docker-host DOCKER_HOST'
|
44
54
|
|
45
55
|
option :container,
|
46
|
-
description: 'name of container',
|
47
|
-
short: '-
|
56
|
+
description: 'name of container; can be used multiple times. /!\ All running containers will be check if this options is not provided',
|
57
|
+
short: '-N CONTAINER',
|
48
58
|
long: '--container-name CONTAINER',
|
49
|
-
|
59
|
+
default: [],
|
60
|
+
proc: proc { |flag| (@options[:container][:accumulated] ||= []).push(flag) }
|
50
61
|
|
51
62
|
option :red_flags,
|
52
|
-
description: '
|
53
|
-
|
54
|
-
|
55
|
-
long: '--red-flag "error occurred" --red-flag "problem encountered" --red-flag "error status"',
|
63
|
+
description: 'String whose presence (case-insensitive by default) in a log line indicates an error; can be used multiple times',
|
64
|
+
short: '-r ERR_STRING',
|
65
|
+
long: '--red-flag ERR_STRING',
|
56
66
|
default: [],
|
57
67
|
proc: proc { |flag| (@options[:red_flags][:accumulated] ||= []).push(flag) }
|
58
68
|
|
59
69
|
option :ignore_list,
|
60
|
-
description: '
|
61
|
-
|
62
|
-
|
63
|
-
long: '--ignore-lines-with "configuration:" --ignore-lines-with "# remark:"',
|
70
|
+
description: 'String whose presence (case-insensitive by default) in a log line indicates the line should be ignored; can be used multiple times',
|
71
|
+
short: '-i IGNSTR',
|
72
|
+
long: '--ignore-lines-with IGNSTR',
|
64
73
|
default: [],
|
65
74
|
proc: proc { |flag| (@options[:ignore_list][:accumulated] ||= []).push(flag) }
|
66
75
|
|
67
76
|
option :case_sensitive,
|
68
|
-
description: 'indicates all red_flag and ignore_list substring matching should be case-sensitive instead of the default case-
|
69
|
-
insensitive',
|
77
|
+
description: 'indicates all red_flag and ignore_list substring matching should be case-sensitive instead of the default case-insensitive',
|
70
78
|
short: '-c',
|
71
79
|
long: '--case-sensitive',
|
72
80
|
boolean: true
|
@@ -83,33 +91,60 @@ insensitive',
|
|
83
91
|
long: '--seconds-ago SECONDS',
|
84
92
|
required: false
|
85
93
|
|
94
|
+
option :check_all,
|
95
|
+
description: 'If all containers are checked (no container name provided with -n) , check offline containers too',
|
96
|
+
short: '-a',
|
97
|
+
long: '--all',
|
98
|
+
default: false,
|
99
|
+
boolean: true
|
100
|
+
|
101
|
+
option :disable_stdout,
|
102
|
+
description: 'Disable the check on STDOUT logs. By default both STDERR and STDOUT are checked',
|
103
|
+
short: '-1',
|
104
|
+
long: '--no-stdout',
|
105
|
+
default: true,
|
106
|
+
boolean: true,
|
107
|
+
proc: proc { false } # used to negate the false(default)->true boolean option behaviour to true(default)->false
|
108
|
+
|
109
|
+
option :disable_stderr,
|
110
|
+
description: 'Disable the check on STDERR logs. By default both STDERR and STDOUT are checked',
|
111
|
+
short: '-2',
|
112
|
+
long: '--no-stderr',
|
113
|
+
default: true,
|
114
|
+
boolean: true,
|
115
|
+
proc: proc { false } # used to negate the false(default)->true boolean option behaviour to true(default)->false
|
116
|
+
|
86
117
|
def calculate_timestamp(seconds_ago = nil)
|
87
118
|
seconds_ago = yield if block_given?
|
88
119
|
(Time.now - seconds_ago).to_i
|
89
120
|
end
|
90
121
|
|
91
122
|
def process_docker_logs(container_name)
|
92
|
-
|
93
|
-
path = "/containers/#{container_name}/logs?stdout=true&stderr=true"
|
123
|
+
path = "/containers/#{container_name}/logs?stdout=#{config[:disable_stdout]}&stderr=#{config[:disable_stderr]}×tamps=true"
|
94
124
|
if config.key? :hours_ago
|
95
125
|
timestamp = calculate_timestamp { config[:hours_ago].to_i * 3600 }
|
96
126
|
elsif config.key? :seconds_ago
|
97
127
|
timestamp = calculate_timestamp config[:seconds_ago].to_i
|
98
128
|
end
|
99
129
|
path = "#{path}&since=#{timestamp}"
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
response.read_body do |chunk|
|
104
|
-
yield remove_headers chunk
|
105
|
-
end
|
130
|
+
response = @client.call(path, false)
|
131
|
+
if response.code.to_i == 404
|
132
|
+
critical "Container '#{container_name}' not found on #{@client.uri}"
|
106
133
|
end
|
134
|
+
yield remove_headers response.read_body
|
107
135
|
end
|
108
136
|
|
109
137
|
def remove_headers(raw_logs)
|
110
138
|
lines = raw_logs.split("\n")
|
111
|
-
lines.map!
|
112
|
-
|
139
|
+
lines.map! do |line|
|
140
|
+
# Check only logs generated with the 8 bits control
|
141
|
+
if !line.nil? && /^(0|1|2)000$/ =~ line.byteslice(0, 4).unpack('C*').join('')
|
142
|
+
# Remove the first 8 bits and ansii colors too
|
143
|
+
line.byteslice(8, line.bytesize).gsub(/\x1b\[[\d;]*?m/, '')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
# We want the most recent logs lines first
|
147
|
+
lines.compact.reverse.join("\n")
|
113
148
|
end
|
114
149
|
|
115
150
|
def includes_any?(str, array_of_substrings)
|
@@ -135,11 +170,30 @@ insensitive',
|
|
135
170
|
end
|
136
171
|
|
137
172
|
def run
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
173
|
+
@client = DockerApi.new(config[:docker_host])
|
174
|
+
problem = []
|
175
|
+
problem_string = nil
|
176
|
+
path = "/containers/json?all=#{config[:check_all]}"
|
177
|
+
containers = config[:container]
|
178
|
+
if config[:container].none?
|
179
|
+
warn_msg = %(
|
180
|
+
Collecting logs from all containers is dangerous and could lead to sensu client hanging depending on volume of logs.
|
181
|
+
This not recommended for production environments.
|
182
|
+
).gsub(/\s+/, ' ').strip
|
183
|
+
message warn_msg
|
184
|
+
end
|
185
|
+
containers = @client.parse(path).map { |p| p['Names'][0].delete('/') } if containers.none?
|
186
|
+
critical 'Check all containers was asked but no containers was found' if containers.none?
|
187
|
+
containers.each do |container|
|
188
|
+
process_docker_logs container do |log_chunk|
|
189
|
+
problem_string = detect_problem(log_chunk)
|
190
|
+
break unless problem_string.nil?
|
191
|
+
end
|
192
|
+
problem << "\tError found inside container : '#{container}'\n\t\t#{problem_string}" unless problem_string.nil?
|
142
193
|
end
|
143
|
-
|
194
|
+
problem_string = problem.join("\n")
|
195
|
+
critical "Container(s) logs indicate problems :\n#{problem_string}" unless problem.none?
|
196
|
+
containers_string = containers.join(', ')
|
197
|
+
ok "No errors detected from logs inside container(s) : \n#{containers_string}"
|
144
198
|
end
|
145
199
|
end
|
data/bin/check-container.rb
CHANGED
@@ -16,11 +16,11 @@
|
|
16
16
|
# gem: sensu-plugin
|
17
17
|
#
|
18
18
|
# USAGE:
|
19
|
-
# check-container.rb -
|
19
|
+
# check-container.rb -H /var/run/docker.sock -N c92d402a5d14
|
20
20
|
# CheckDockerContainer OK: c92d402a5d14 is running on /var/run/docker.sock.
|
21
21
|
#
|
22
|
-
# check-container.rb -
|
23
|
-
# CheckDockerContainer CRITICAL: circle_burglar is not running on
|
22
|
+
# check-container.rb -H https://127.0.0.1:2376 -N circle_burglar
|
23
|
+
# CheckDockerContainer CRITICAL: circle_burglar is not running on https://127.0.0.1:2376
|
24
24
|
#
|
25
25
|
# NOTES:
|
26
26
|
# => State.running == true -> OK
|
@@ -37,52 +37,45 @@
|
|
37
37
|
|
38
38
|
require 'sensu-plugin/check/cli'
|
39
39
|
require 'sensu-plugins-docker/client_helpers'
|
40
|
-
require 'json'
|
41
40
|
|
42
41
|
#
|
43
42
|
# Check Docker Container
|
44
43
|
#
|
45
44
|
class CheckDockerContainer < Sensu::Plugin::Check::CLI
|
46
45
|
option :docker_host,
|
47
|
-
short: '-
|
48
|
-
long: '--host DOCKER_HOST',
|
49
|
-
description: 'Docker
|
50
|
-
|
46
|
+
short: '-H DOCKER_HOST',
|
47
|
+
long: '--docker-host DOCKER_HOST',
|
48
|
+
description: 'Docker API URI. https://host, https://host:port, http://host, http://host:port, host:port, unix:///path'
|
49
|
+
|
51
50
|
option :container,
|
52
|
-
short: '-
|
53
|
-
long: '--container CONTAINER',
|
51
|
+
short: '-N CONTAINER',
|
52
|
+
long: '--container-name CONTAINER',
|
54
53
|
required: true
|
54
|
+
|
55
55
|
option :tag,
|
56
56
|
short: '-t TAG',
|
57
57
|
long: '--tag TAG'
|
58
58
|
|
59
59
|
def run
|
60
|
-
client =
|
60
|
+
@client = DockerApi.new(config[:docker_host])
|
61
61
|
path = "/containers/#{config[:container]}/json"
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
unless match && match[4] == config[:tag]
|
75
|
-
critical "#{config[:container]}'s tag is '#{match[4]}', excepting '#{config[:tag]}'"
|
76
|
-
end
|
62
|
+
response = @client.call(path, false)
|
63
|
+
if response.code.to_i == 404
|
64
|
+
critical "Container #{config[:container]} is not running on #{@client.uri}"
|
65
|
+
end
|
66
|
+
body = parse_json(response)
|
67
|
+
container_running = body['State']['Running']
|
68
|
+
if container_running
|
69
|
+
if config[:tag]
|
70
|
+
image = body['Config']['Image']
|
71
|
+
match = image.match(/^(?:([^\/]+)\/)?(?:([^\/]+)\/)?([^@:\/]+)(?:[@:](.+))?$/)
|
72
|
+
unless match && match[4] == config[:tag]
|
73
|
+
critical "#{config[:container]}'s tag is '#{match[4]}', especting '#{config[:tag]}'"
|
77
74
|
end
|
78
|
-
ok "#{config[:container]} is running on #{config[:docker_host]}."
|
79
|
-
else
|
80
|
-
critical "#{config[:container]} is #{body['State']['Status']} on #{config[:docker_host]}."
|
81
75
|
end
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
warning "Error: #{e.inspect}"
|
76
|
+
ok "#{config[:container]} is running on #{@client.uri}."
|
77
|
+
else
|
78
|
+
critical "#{config[:container]} is #{body['State']['Status']} on #{@client.uri}."
|
86
79
|
end
|
87
80
|
end
|
88
81
|
end
|
@@ -20,6 +20,14 @@
|
|
20
20
|
# => 1 container running = OK.
|
21
21
|
# => 4 container running = CRITICAL
|
22
22
|
#
|
23
|
+
# check-docker-container.rb -H /var/run/docker.sock -w 3 -c 3
|
24
|
+
# => 1 container running = OK.
|
25
|
+
# => 4 container running = CRITICAL
|
26
|
+
#
|
27
|
+
# check-docker-container.rb -H https://127.0.0.1:2376 -w 3 -c 3
|
28
|
+
# => 1 container running = OK.
|
29
|
+
# => 4 container running = CRITICAL
|
30
|
+
#
|
23
31
|
# NOTES:
|
24
32
|
#
|
25
33
|
# LICENSE:
|
@@ -30,16 +38,15 @@
|
|
30
38
|
|
31
39
|
require 'sensu-plugin/check/cli'
|
32
40
|
require 'sensu-plugins-docker/client_helpers'
|
33
|
-
|
41
|
+
|
34
42
|
#
|
35
43
|
# Check Docker Containers
|
36
44
|
#
|
37
45
|
class CheckDockerContainers < Sensu::Plugin::Check::CLI
|
38
46
|
option :docker_host,
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
default: '127.0.0.1:2375'
|
47
|
+
description: 'Docker API URI. https://host, https://host:port, http://host, http://host:port, host:port, unix:///path',
|
48
|
+
short: '-H DOCKER_HOST',
|
49
|
+
long: '--docker-host DOCKER_HOST'
|
43
50
|
|
44
51
|
option :warn_over,
|
45
52
|
short: '-W N',
|
@@ -94,17 +101,8 @@ class CheckDockerContainers < Sensu::Plugin::Check::CLI
|
|
94
101
|
end
|
95
102
|
|
96
103
|
def run
|
97
|
-
client =
|
98
|
-
|
99
|
-
|
100
|
-
begin
|
101
|
-
response = client.request(req)
|
102
|
-
containers = JSON.parse(response.body)
|
103
|
-
evaluate_count containers.size
|
104
|
-
rescue JSON::ParserError => e
|
105
|
-
critical "JSON Error: #{e.inspect}"
|
106
|
-
rescue => e
|
107
|
-
warning "Error: #{e.inspect}"
|
108
|
-
end
|
104
|
+
@client = DockerApi.new(config[:docker_host])
|
105
|
+
containers = @client.parse('/containers/json')
|
106
|
+
evaluate_count containers.size
|
109
107
|
end
|
110
108
|
end
|
@@ -14,7 +14,22 @@
|
|
14
14
|
# gem: sensu-plugin
|
15
15
|
#
|
16
16
|
# USAGE:
|
17
|
-
#
|
17
|
+
#
|
18
|
+
# metrics-docker-container.rb -H /var/run/docker.sock -n
|
19
|
+
# docker.host.sensu.sh.rss 1 1508825823
|
20
|
+
# docker.host.sensu.sh.vsize 1572864 1508825823
|
21
|
+
# docker.host.sensu.sh.nswap 0 1508825823
|
22
|
+
# docker.host.sensu.sh.pctmem 0.0 1508825823
|
23
|
+
# docker.host.sensu.sh.fd 0 1508825823
|
24
|
+
# docker.host.sensu.sh.cpu 0 1508825823
|
25
|
+
#
|
26
|
+
# metrics-docker-container.rb -H https://127.0.0.1:2376
|
27
|
+
# docker.host.ff5240e079488d248c021f8da5d13074a6a9db72ffaf1129eded445f4e16cf50.sh.rss 183 1508825793
|
28
|
+
# docker.host.ff5240e079488d248c021f8da5d13074a6a9db72ffaf1129eded445f4e16cf50.sh.vsize 4616192 1508825793
|
29
|
+
# docker.host.ff5240e079488d248c021f8da5d13074a6a9db72ffaf1129eded445f4e16cf50.sh.nswap 0 1508825793
|
30
|
+
# docker.host.ff5240e079488d248c021f8da5d13074a6a9db72ffaf1129eded445f4e16cf50.sh.pctmem 0.01 1508825793
|
31
|
+
# docker.host.ff5240e079488d248c021f8da5d13074a6a9db72ffaf1129eded445f4e16cf50.sh.fd 0 1508825793
|
32
|
+
# docker.host.ff5240e079488d248c021f8da5d13074a6a9db72ffaf1129eded445f4e16cf50.sh.cpu 0 1508825793
|
18
33
|
#
|
19
34
|
# NOTES:
|
20
35
|
#
|
@@ -25,7 +40,7 @@
|
|
25
40
|
#
|
26
41
|
|
27
42
|
require 'sensu-plugin/metric/cli'
|
28
|
-
require '
|
43
|
+
require 'sensu-plugins-docker/client_helpers'
|
29
44
|
require 'pathname'
|
30
45
|
require 'sys/proctable'
|
31
46
|
|
@@ -46,23 +61,30 @@ class DockerContainerMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
46
61
|
default: '/sys/fs/cgroup'
|
47
62
|
|
48
63
|
option :docker_host,
|
49
|
-
description: 'Docker
|
64
|
+
description: 'Docker API URI. https://host, https://host:port, http://host, http://host:port, host:port, unix:///path',
|
50
65
|
short: '-H DOCKER_HOST',
|
51
|
-
long: '--docker-host DOCKER_HOST'
|
52
|
-
default: 'tcp://127.0.1.1:2376'
|
66
|
+
long: '--docker-host DOCKER_HOST'
|
53
67
|
|
54
68
|
option :cgroup_template,
|
55
69
|
description: 'cgroup_template',
|
56
|
-
short: '-T
|
57
|
-
long: '--cgroup-template
|
70
|
+
short: '-T TPL_STRING',
|
71
|
+
long: '--cgroup-template TPL_STRING',
|
58
72
|
default: 'cpu/docker/%{container}/cgroup.procs'
|
59
73
|
|
74
|
+
option :friendly_names,
|
75
|
+
description: 'use friendly name if available',
|
76
|
+
short: '-n',
|
77
|
+
long: '--names',
|
78
|
+
boolean: true,
|
79
|
+
default: false
|
80
|
+
|
60
81
|
def run
|
82
|
+
@client = DockerApi.new(config[:docker_host])
|
61
83
|
container_metrics
|
62
84
|
ok
|
63
85
|
end
|
64
86
|
|
65
|
-
def container_metrics
|
87
|
+
def container_metrics
|
66
88
|
cgroup = "#{config[:cgroup_path]}/#{config[:cgroup_template]}"
|
67
89
|
|
68
90
|
timestamp = Time.now.to_i
|
@@ -72,18 +94,24 @@ class DockerContainerMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
72
94
|
|
73
95
|
fields = [:rss, :vsize, :nswap, :pctmem]
|
74
96
|
|
75
|
-
|
76
|
-
containers =
|
97
|
+
path = '/containers/json'
|
98
|
+
containers = @client.parse(path)
|
77
99
|
|
78
100
|
containers.each do |container|
|
79
|
-
path = Pathname(format(cgroup, container: container))
|
101
|
+
path = Pathname(format(cgroup, container: container['Id']))
|
80
102
|
pids = path.readlines.map(&:to_i)
|
81
103
|
|
104
|
+
container_name = if config[:friendly_names]
|
105
|
+
container['Names'][0].delete('/')
|
106
|
+
else
|
107
|
+
container['Id']
|
108
|
+
end
|
109
|
+
|
82
110
|
processes = ps.values_at(*pids).flatten.compact.group_by(&:comm)
|
83
111
|
processes2 = ps2.values_at(*pids).flatten.compact.group_by(&:comm)
|
84
112
|
|
85
113
|
processes.each do |comm, process|
|
86
|
-
prefix = "#{config[:scheme]}.#{
|
114
|
+
prefix = "#{config[:scheme]}.#{container_name}.#{comm}"
|
87
115
|
fields.each do |field|
|
88
116
|
output "#{prefix}.#{field}", process.map(&field).reduce(:+), timestamp
|
89
117
|
end
|
data/bin/metrics-docker-info.rb
CHANGED
@@ -21,10 +21,10 @@
|
|
21
21
|
#
|
22
22
|
# USAGE:
|
23
23
|
# Gather stats using unix socket:
|
24
|
-
# metrics-docker-info.rb -
|
24
|
+
# metrics-docker-info.rb -H /var/run/docker.sock
|
25
25
|
#
|
26
|
-
# Gather stats from localhost using
|
27
|
-
# metrics-docker-info.rb -
|
26
|
+
# Gather stats from localhost using HTTP:
|
27
|
+
# metrics-docker-info.rb -H localhost:2375
|
28
28
|
#
|
29
29
|
# See metrics-docker-info.rb --help for full usage flags
|
30
30
|
#
|
@@ -37,9 +37,7 @@
|
|
37
37
|
#
|
38
38
|
|
39
39
|
require 'sensu-plugin/metric/cli'
|
40
|
-
require '
|
41
|
-
require 'net_http_unix'
|
42
|
-
require 'json'
|
40
|
+
require 'sensu-plugins-docker/client_helpers'
|
43
41
|
|
44
42
|
class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
45
43
|
option :scheme,
|
@@ -49,43 +47,19 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
49
47
|
default: "#{Socket.gethostname}.docker"
|
50
48
|
|
51
49
|
option :docker_host,
|
52
|
-
description: 'Docker
|
50
|
+
description: 'Docker API URI. https://host, https://host:port, http://host, http://host:port, host:port, unix:///path',
|
53
51
|
short: '-H DOCKER_HOST',
|
54
|
-
long: '--docker-host DOCKER_HOST'
|
55
|
-
default: '/var/run/docker.sock'
|
56
|
-
|
57
|
-
option :docker_protocol,
|
58
|
-
description: 'http or unix',
|
59
|
-
short: '-p PROTOCOL',
|
60
|
-
long: '--protocol PROTOCOL',
|
61
|
-
default: 'unix'
|
52
|
+
long: '--docker-host DOCKER_HOST'
|
62
53
|
|
63
54
|
def run
|
64
55
|
@timestamp = Time.now.to_i
|
65
|
-
|
66
|
-
|
56
|
+
@client = DockerApi.new(config[:docker_host])
|
57
|
+
path = '/info'
|
58
|
+
infolist = @client.parse(path)
|
67
59
|
filtered_list = infolist.select { |key, _value| key.match(/NCPU|NFd|Containers|Images|NGoroutines|NEventsListener|MemTotal/) }
|
68
60
|
filtered_list.each do |key, value|
|
69
61
|
output "#{config[:scheme]}.#{key}", value, @timestamp
|
70
62
|
end
|
71
63
|
ok
|
72
64
|
end
|
73
|
-
|
74
|
-
def docker_api(path)
|
75
|
-
if config[:docker_protocol] == 'unix'
|
76
|
-
session = NetX::HTTPUnix.new("unix://#{config[:docker_host]}")
|
77
|
-
request = Net::HTTP::Get.new "/#{path}"
|
78
|
-
else
|
79
|
-
uri = URI("#{config[:docker_protocol]}://#{config[:docker_host]}/#{path}")
|
80
|
-
session = Net::HTTP.new(uri.host, uri.port)
|
81
|
-
request = Net::HTTP::Get.new uri.request_uri
|
82
|
-
end
|
83
|
-
|
84
|
-
session.start do |http|
|
85
|
-
http.request request do |response|
|
86
|
-
response.value
|
87
|
-
return JSON.parse(response.read_body)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
65
|
end
|
data/bin/metrics-docker-stats.rb
CHANGED
@@ -19,13 +19,13 @@
|
|
19
19
|
#
|
20
20
|
# USAGE:
|
21
21
|
# Gather stats from all containers on a host using socket:
|
22
|
-
# metrics-docker-stats.rb -
|
22
|
+
# metrics-docker-stats.rb -H /var/run/docker.sock
|
23
23
|
#
|
24
|
-
# Gather stats from all containers on a host using
|
25
|
-
# metrics-docker-stats.rb -
|
24
|
+
# Gather stats from all containers on a host using HTTP:
|
25
|
+
# metrics-docker-stats.rb -H localhost:2375
|
26
26
|
#
|
27
27
|
# Gather stats from a specific container using socket:
|
28
|
-
# metrics-docker-stats.rb -
|
28
|
+
# metrics-docker-stats.rb -H /var/run/docker.sock -N 5bf1b82382eb
|
29
29
|
#
|
30
30
|
# See metrics-docker-stats.rb --help for full usage flags
|
31
31
|
#
|
@@ -38,9 +38,7 @@
|
|
38
38
|
#
|
39
39
|
|
40
40
|
require 'sensu-plugin/metric/cli'
|
41
|
-
require '
|
42
|
-
require 'net_http_unix'
|
43
|
-
require 'json'
|
41
|
+
require 'sensu-plugins-docker/client_helpers'
|
44
42
|
|
45
43
|
class Hash
|
46
44
|
def self.to_dotted_hash(hash, recursive_key = '')
|
@@ -64,21 +62,14 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
64
62
|
|
65
63
|
option :container,
|
66
64
|
description: 'Name of container to collect metrics for',
|
67
|
-
short: '-
|
68
|
-
long: '--container CONTAINER',
|
65
|
+
short: '-N CONTAINER',
|
66
|
+
long: '--container-name CONTAINER',
|
69
67
|
default: ''
|
70
68
|
|
71
69
|
option :docker_host,
|
72
|
-
description: 'Docker
|
70
|
+
description: 'Docker API URI. https://host, https://host:port, http://host, http://host:port, host:port, unix:///path',
|
73
71
|
short: '-H DOCKER_HOST',
|
74
|
-
long: '--docker-host DOCKER_HOST'
|
75
|
-
default: '127.0.0.1:2375'
|
76
|
-
|
77
|
-
option :docker_protocol,
|
78
|
-
description: 'http or unix',
|
79
|
-
short: '-p PROTOCOL',
|
80
|
-
long: '--protocol PROTOCOL',
|
81
|
-
default: 'http'
|
72
|
+
long: '--docker-host DOCKER_HOST'
|
82
73
|
|
83
74
|
option :friendly_names,
|
84
75
|
description: 'use friendly name if available',
|
@@ -88,8 +79,8 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
88
79
|
default: false
|
89
80
|
|
90
81
|
option :name_parts,
|
91
|
-
description: 'Partial names by spliting and returning at index(es).
|
92
|
-
|
82
|
+
description: 'Partial names by spliting and returning at index(es).
|
83
|
+
eg. -m 3,4 my-docker-container-process_name-b2ffdab8f1aceae85300 for process_name.b2ffdab8f1aceae85300',
|
93
84
|
short: '-m index',
|
94
85
|
long: '--match index'
|
95
86
|
|
@@ -101,8 +92,8 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
101
92
|
|
102
93
|
option :environment_tags,
|
103
94
|
description: 'Name of environment variables on each container to be appended to metric name, separated by commas',
|
104
|
-
short: '-e
|
105
|
-
long: '--environment-tags
|
95
|
+
short: '-e ENV_VARS',
|
96
|
+
long: '--environment-tags ENV_VARS'
|
106
97
|
|
107
98
|
option :ioinfo,
|
108
99
|
description: 'enable IO Docker metrics',
|
@@ -120,6 +111,7 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
120
111
|
|
121
112
|
def run
|
122
113
|
@timestamp = Time.now.to_i
|
114
|
+
@client = DockerApi.new(config[:docker_host])
|
123
115
|
|
124
116
|
list = if config[:container] != ''
|
125
117
|
[config[:container]]
|
@@ -150,6 +142,7 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
150
142
|
dotted_stats.each do |key, value|
|
151
143
|
next if key == 'read' # unecessary timestamp
|
152
144
|
next if value.is_a?(Array)
|
145
|
+
value.delete!('/') if key == 'name'
|
153
146
|
output "#{config[:scheme]}.#{container}.#{key}", value, @timestamp
|
154
147
|
end
|
155
148
|
if config[:ioinfo]
|
@@ -160,30 +153,12 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
160
153
|
output "#{config[:scheme]}.#{container}.cpu_stats.usage_percent", calculate_cpu_percent(stats), @timestamp if config[:cpupercent]
|
161
154
|
end
|
162
155
|
|
163
|
-
def docker_api(path)
|
164
|
-
if config[:docker_protocol] == 'unix'
|
165
|
-
session = NetX::HTTPUnix.new("unix://#{config[:docker_host]}")
|
166
|
-
request = Net::HTTP::Get.new "/#{path}"
|
167
|
-
else
|
168
|
-
uri = URI("#{config[:docker_protocol]}://#{config[:docker_host]}/#{path}")
|
169
|
-
session = Net::HTTP.new(uri.host, uri.port)
|
170
|
-
request = Net::HTTP::Get.new uri.request_uri
|
171
|
-
end
|
172
|
-
|
173
|
-
session.start do |http|
|
174
|
-
http.request request do |response|
|
175
|
-
response.value
|
176
|
-
return JSON.parse(response.read_body)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
156
|
def list_containers
|
182
157
|
list = []
|
183
|
-
path = 'containers/json'
|
184
|
-
|
158
|
+
path = '/containers/json'
|
159
|
+
containers = @client.parse(path)
|
185
160
|
|
186
|
-
|
161
|
+
containers.each do |container|
|
187
162
|
list << if config[:friendly_names]
|
188
163
|
container['Names'][0].delete('/')
|
189
164
|
elsif config[:name_parts]
|
@@ -196,17 +171,25 @@ class DockerStatsMetrics < Sensu::Plugin::Metric::CLI::Graphite
|
|
196
171
|
end
|
197
172
|
|
198
173
|
def container_stats(container)
|
199
|
-
path = "containers/#{container}/stats?stream=0"
|
200
|
-
|
174
|
+
path = "/containers/#{container}/stats?stream=0"
|
175
|
+
response = @client.call(path)
|
176
|
+
if response.code.to_i == 404
|
177
|
+
critical "#{config[:container]} is not running on #{@client.uri}"
|
178
|
+
end
|
179
|
+
parse_json(response)
|
201
180
|
end
|
202
181
|
|
203
182
|
def container_tags(container)
|
204
183
|
tags = ''
|
205
|
-
path = "containers/#{container}/json"
|
206
|
-
|
184
|
+
path = "/containers/#{container}/json"
|
185
|
+
response = @client.call(path)
|
186
|
+
if response.code.to_i == 404
|
187
|
+
critical "#{config[:container]} is not running on #{@client.uri}"
|
188
|
+
end
|
189
|
+
inspect = parse_json(response)
|
207
190
|
tag_list = config[:environment_tags].split(',')
|
208
191
|
tag_list.each do |value|
|
209
|
-
tags <<
|
192
|
+
tags << inspect['Config']['Env'].select { |tag| tag.to_s.match(/#{value}=/) }.first.to_s.gsub(/#{value}=/, '') + '.'
|
210
193
|
end
|
211
194
|
tags
|
212
195
|
end
|
@@ -1,18 +1,60 @@
|
|
1
1
|
require 'net_http_unix'
|
2
|
+
require 'json'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
class DockerApi
|
5
|
+
def initialize(uri = nil)
|
6
|
+
@client = nil
|
7
|
+
@docker_uri = uri || ENV['DOCKER_URL'] || ENV['DOCKER_HOST'] || '/var/run/docker.sock'
|
8
|
+
if @docker_uri.sub!(%r{^(unix://)?/}, '')
|
9
|
+
@docker_uri = 'unix:///' + @docker_uri
|
10
|
+
@client = NetX::HTTPUnix.new(@docker_uri)
|
11
|
+
else
|
12
|
+
protocol = %r{^(https?|tcp)://}.match(@docker_uri) || 'http://'
|
13
|
+
@docker_uri.sub!(protocol.to_s, '')
|
14
|
+
split_host = @docker_uri.split ':'
|
15
|
+
@client = if split_host.length == 2
|
16
|
+
NetX::HTTPUnix.new("#{protocol}#{split_host[0]}", split_host[1])
|
17
|
+
else
|
18
|
+
NetX::HTTPUnix.new("#{protocol}#{@docker_uri}", 2375)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
@client.start
|
15
22
|
end
|
16
23
|
|
17
|
-
|
24
|
+
def uri
|
25
|
+
@docker_uri
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(path, halt = true, limit = 10)
|
29
|
+
raise ArgumentError, "HTTP redirect too deep. Last url called : #{path}" if limit.zero?
|
30
|
+
if %r{^unix:///} =~ @docker_uri
|
31
|
+
request = Net::HTTP::Get.new path.to_s
|
32
|
+
else
|
33
|
+
uri = URI("#{@docker_uri}#{path}")
|
34
|
+
request = Net::HTTP::Get.new uri.request_uri
|
35
|
+
end
|
36
|
+
response = @client.request(request)
|
37
|
+
case response
|
38
|
+
when Net::HTTPSuccess then response
|
39
|
+
when Net::HTTPRedirection then call(response['location'], true, limit - 1)
|
40
|
+
else
|
41
|
+
return response.error! unless halt == false
|
42
|
+
return response
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse(path, halt = true, limit = 10)
|
47
|
+
parsed = parse_json(call(path, halt, limit))
|
48
|
+
parsed
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def parse_json(response)
|
53
|
+
parsed = nil
|
54
|
+
begin
|
55
|
+
parsed = JSON.parse(response.read_body)
|
56
|
+
rescue JSON::ParserError => e
|
57
|
+
raise "JSON Error: #{e.inspect}"
|
58
|
+
end
|
59
|
+
parsed
|
18
60
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu-plugins-docker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sensu-Plugins and contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: docker-api
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - '='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 1.21.0
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - '='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 1.21.0
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: sensu-plugin
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -199,12 +185,12 @@ description: |-
|
|
199
185
|
metrics via `docker ps`
|
200
186
|
email: "<sensu-users@googlegroups.com>"
|
201
187
|
executables:
|
202
|
-
- metrics-docker-container.rb
|
203
188
|
- metrics-docker-info.rb
|
204
|
-
-
|
189
|
+
- metrics-docker-container.rb
|
190
|
+
- check-docker-container.rb
|
205
191
|
- check-container-logs.rb
|
206
192
|
- metrics-docker-stats.rb
|
207
|
-
- check-
|
193
|
+
- check-container.rb
|
208
194
|
extensions: []
|
209
195
|
extra_rdoc_files: []
|
210
196
|
files:
|
@@ -246,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
246
232
|
version: '0'
|
247
233
|
requirements: []
|
248
234
|
rubyforge_project:
|
249
|
-
rubygems_version: 2.7.
|
235
|
+
rubygems_version: 2.7.6
|
250
236
|
signing_key:
|
251
237
|
specification_version: 4
|
252
238
|
summary: Sensu plugins for docker
|