blob: fbcfc1f161249d90daf9e4a3bd61d20404420937 [file] [log] [blame]
#!/usr/bin/python
# Copyright 2016 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import collectd
import re
import collectd_base as base
NAME = 'glusterfs'
GLUSTER_BINARY = '/usr/sbin/gluster'
peer_re = re.compile(r'^Hostname: (?P<peer>.+)$', re.MULTILINE)
state_re = re.compile(r'^State: (?P<state>.+)$', re.MULTILINE)
vol_status_re = re.compile(r'\n\s*\n', re.MULTILINE)
vol_block_re = re.compile(r'^-+', re.MULTILINE)
volume_re = re.compile(r'^Status of volume:\s+(?P<volume>.+)', re.MULTILINE)
brick_server_re = re.compile(r'^Brick\s*:\s*Brick\s*(?P<peer>[^:]+)',
re.MULTILINE)
disk_free_re = re.compile(
r'^Disk Space Free\s*:\s+(?P<disk_free>[.\d]+)(?P<unit>\S+)',
re.MULTILINE)
disk_total_re = re.compile(
r'^Total Disk Space\s*:\s+(?P<disk_total>[.\d]+)(?P<unit>\S+)',
re.MULTILINE)
inode_free_re = re.compile(r'^Free Inodes\s*:\s+(?P<inode_free>\d+)',
re.MULTILINE)
inode_count_re = re.compile(r'^Inode Count\s*:\s+(?P<inode_count>\d+)',
re.MULTILINE)
def convert_to_bytes(v, unit):
try:
i = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB').index(unit)
except ValueError:
i = 1
return float(v) * (1024 ** i)
class GlusterfsPlugin(base.Base):
def __init__(self, *args, **kwargs):
super(GlusterfsPlugin, self).__init__(*args, **kwargs)
self.plugin = NAME
def itermetrics(self):
# Collect peers' metrics
out, err = self.execute([GLUSTER_BINARY, 'peer', 'status'],
shell=False)
if not out:
raise base.CheckException("Failed to execute 'gluster peer'")
total = 0
total_by_state = {
'up': 0,
'down': 0
}
for line in out.split('\n\n'):
peer_m = peer_re.search(line)
state_m = state_re.search(line)
if peer_m and state_m:
total += 1
if state_m.group('state') == 'Peer in Cluster (Connected)':
v = 1
total_by_state['up'] += 1
else:
v = 0
total_by_state['down'] += 1
yield {
'type_instance': 'peer_state',
'values': v,
'meta': {
'peer': peer_m.group('peer')
}
}
for state, count in total_by_state.items():
yield {
'type_instance': 'peers_count',
'values': count,
'meta': {
'state': state
}
}
yield {
'type_instance': 'peers_percent',
'values': 100.0 * count / total,
'meta': {
'state': state
}
}
# Collect volumes' metrics
out, err = self.execute(
[GLUSTER_BINARY, 'volume', 'status', 'all', 'detail'],
shell=False)
if not out:
raise base.CheckException("Failed to execute 'gluster volume'")
for vol_block in vol_status_re.split(out):
volume_m = volume_re.search(vol_block)
if not volume_m:
continue
volume = volume_m.group('volume')
for line in vol_block_re.split(vol_block):
peer_m = brick_server_re.search(line)
if not peer_m:
continue
volume = volume_m.group('volume')
peer = peer_m.group('peer')
disk_free_m = disk_free_re.search(line)
disk_total_m = disk_total_re.search(line)
inode_free_m = inode_free_re.search(line)
inode_count_m = inode_count_re.search(line)
if disk_free_m and disk_total_m:
free = convert_to_bytes(
disk_free_m.group('disk_free'),
disk_free_m.group('unit'))
total = convert_to_bytes(
disk_total_m.group('disk_total'),
disk_total_m.group('unit'))
used = total - free
yield {
'type_instance': 'space_free',
'values': free,
'meta': {
'volume': volume,
'peer': peer,
}
}
yield {
'type_instance': 'space_percent_free',
'values': free * 100.0 / total,
'meta': {
'volume': volume,
'peer': peer,
}
}
yield {
'type_instance': 'space_used',
'values': used,
'meta': {
'volume': volume,
'peer': peer,
}
}
yield {
'type_instance': 'space_percent_used',
'values': used * 100.0 / total,
'meta': {
'volume': volume,
'peer': peer,
}
}
if inode_free_m and inode_count_m:
free = int(inode_free_m.group('inode_free'))
total = int(inode_count_m.group('inode_count'))
used = total - free
yield {
'type_instance': 'inodes_free',
'values': free,
'meta': {
'volume': volume,
'peer': peer,
}
}
yield {
'type_instance': 'inodes_percent_free',
'values': free * 100.0 / total,
'meta': {
'volume': volume,
'peer': peer,
}
}
yield {
'type_instance': 'inodes_used',
'values': used,
'meta': {
'volume': volume,
'peer': peer,
}
}
yield {
'type_instance': 'inodes_percent_used',
'values': used * 100.0 / total,
'meta': {
'volume': volume,
'peer': peer,
}
}
plugin = GlusterfsPlugin(collectd)
def init_callback():
plugin.restore_sigchld()
def config_callback(conf):
plugin.config_callback(conf)
def read_callback():
plugin.read_callback()
collectd.register_init(init_callback)
collectd.register_config(config_callback)
collectd.register_read(read_callback)