PNG  IHDR;IDATxܻn0K )(pA 7LeG{ §㻢|ذaÆ 6lذaÆ 6lذaÆ 6lom$^yذag5bÆ 6lذaÆ 6lذa{ 6lذaÆ `}HFkm,mӪôô! x|'ܢ˟;E:9&ᶒ}{v]n&6 h_tڠ͵-ҫZ;Z$.Pkž)!o>}leQfJTu іچ\X=8Rن4`Vwl>nG^is"ms$ui?wbs[m6K4O.4%/bC%t Mז -lG6mrz2s%9s@-k9=)kB5\+͂Zsٲ Rn~GRC wIcIn7jJhۛNCS|j08yiHKֶۛkɈ+;SzL/F*\Ԕ#"5m2[S=gnaPeғL lذaÆ 6l^ḵaÆ 6lذaÆ 6lذa; _ذaÆ 6lذaÆ 6lذaÆ RIENDB` import agent_util import sys import os import platform from agent_util import float NETWORK_FS = ['ncpfs', 'nfs', 'ntfs', 'smb', 'vfat', 'smb2', 'cifs', 'nfs4'] # Timeout after 10 seconds, so we don't get hung on remote filesystems TIMEOUT_LIMIT = 10 def get_findmnt_cmd(extra_args=""): timeout = "" if agent_util.which("timeout"): timeout = "timeout %s " % TIMEOUT_LIMIT return "%sfindmnt --fstab --df --bytes --raw --evaluate --all %s" % (timeout, extra_args) def get_df_cmd(extra_arg=""): timeout = "" if agent_util.which("timeout"): timeout = "timeout %s " % TIMEOUT_LIMIT if 'sunos' in sys.platform or "vmware" in sys.platform: return "%sdf -kT %s" % (timeout, extra_arg) elif "darwin" in sys.platform or "aix" in sys.platform: return "%sdf -Pk %s" % (timeout, extra_arg) else: return "%sdf -PkT %s" % (timeout, extra_arg) def get_idf_cmd(extra_arg=""): timeout = "" if agent_util.which("timeout"): timeout = "timeout %s " % TIMEOUT_LIMIT if 'sunos' in sys.platform or "vmware" in sys.platform: return "%sdf -iT %s" % (timeout, extra_arg) elif "darwin" in sys.platform: return "%sdf -iP %s" % (timeout, extra_arg) else: return "%sdf -iPT %s" % (timeout, extra_arg) class DiskUsagePlugin(agent_util.Plugin): textkey = "disk" label = "Disk" device_ignore_list = ("tmpfs", "devtmpfs", "none", "proc", "swap", "devices", "cgroup", "/dev/loop") darwin_fstype_excludes = 'nullfs,nodev,devfs,autofs' # adding min for disk usage min_capacity = 0 if "AIX" in os.uname(): sys.platform = "aix" @classmethod def get_metadata(self, config): status = agent_util.SUPPORTED msg = None if not agent_util.which("df", exc=False): self.log.info("df binary not found") status = agent_util.UNSUPPORTED msg = "df binary not found" return {} # See if there are custom DF flags specified in the config file extra_df_arg = config.get("extra_df_arg", "") if 'darwin' in sys.platform: configKey = 'ignore_fstypes' ignores = self.darwin_fstype_excludes if config.get(configKey, None): ignores = '{},{}'.format(ignores, config.get(configKey)) extra_df_arg ='{} -T no{}'.format(extra_df_arg, ignores) # See if there are custom device ignore specifications in the config file device_ignore_list = config.get("device_ignore_list", self.device_ignore_list) # See if the config file specifies to use findmnt to identify expected disks use_findmnt = config.get("use_findmnt") and agent_util.which("findmnt") extra_findmnt_arg = config.get("extra_findmnt_arg", "") devices = [] max_disk = {} idevices = [] imax_disk = {} custom_network_fs = config.get('network_fs', []) if custom_network_fs: custom_network_fs = custom_network_fs.split(',') if status is agent_util.SUPPORTED: if use_findmnt: ret_code, output = agent_util.execute_command(get_findmnt_cmd(extra_findmnt_arg), cache_timeout = agent_util.DEFAULT_CACHE_TIMEOUT) output = output.splitlines() ioutput = output else: ret_code, output = agent_util.execute_command(get_df_cmd(extra_df_arg), cache_timeout=agent_util.DEFAULT_CACHE_TIMEOUT) output = output.splitlines() iret_code, ioutput = agent_util.execute_command(get_idf_cmd(extra_df_arg), cache_timeout=agent_util.DEFAULT_CACHE_TIMEOUT) ioutput = ioutput.splitlines() if config.get("debug", False): self.log.debug('#####################################################') self.log.debug("Disk command '%s' output :" % get_df_cmd(extra_df_arg)) self.log.debug(output) self.log.debug('#####################################################') self.log.debug('#####################################################') self.log.debug("Disk command '%s' output :" % get_idf_cmd(extra_df_arg)) self.log.debug(ioutput) self.log.debug('#####################################################') if "aix" in sys.platform or "sunos" in sys.platform: device_ignore_list = device_ignore_list + ("proc", "swap") for line in output[1:]: line = line.strip() try: # Need to split findmnt output on individual spaces to preserve columns if use_findmnt: df_line_parts = line.split(" ") else: df_line_parts = line.split() if len(df_line_parts) == 7: device = df_line_parts[0] filesystem = df_line_parts[1] blocks = df_line_parts[2] used = df_line_parts[3] available = df_line_parts[4] capacity = df_line_parts[5] mounted = df_line_parts[6] else: device = df_line_parts[0] filesystem = "" blocks = df_line_parts[1] used = df_line_parts[2] available = df_line_parts[3] capacity = df_line_parts[4] mounted = df_line_parts[5] skip_device = False for test_device in device_ignore_list: if device.startswith(test_device) or filesystem.startswith(test_device): self.log.info("Skipping metadata for device %s" % device) skip_device = True if skip_device: continue desc = "%s mounted at %s" % (device, mounted) devices.append( { "device": device, "mountpoint": mounted, "filesystem": filesystem, "resource": desc, "is_network": filesystem in NETWORK_FS or filesystem in custom_network_fs } ) max_disk[desc] = available except: self.log.error("Unable to parse df output: %s" % line) continue for line in ioutput[1:]: line = line.strip() try: # Need to split findmnt output on individual spaces to preserve columns if use_findmnt: idf_line_parts = line.split(" ") else: idf_line_parts = line.split() if len(idf_line_parts) == 7: idevice = idf_line_parts[0] ifilesystem = idf_line_parts[1] iblocks = idf_line_parts[2] iused = idf_line_parts[3] iavailable = idf_line_parts[4] icapacity = idf_line_parts[5] imounted = idf_line_parts[6] else: idevice = idf_line_parts[0] ifilesystem = "" iblocks = idf_line_parts[1] iused = idf_line_parts[2] iavailable = idf_line_parts[3] icapacity = idf_line_parts[4] imounted = idf_line_parts[5] skip_device = False for test_device in device_ignore_list: if idevice.startswith(test_device) or ifilesystem.startswith(test_device): self.log.info("Skipping metadata for device %s" % idevice) skip_device = True if skip_device: continue desc = "%s mounted at %s" % (idevice, imounted) idevices.append( { "device": idevice, "mountpoint": imounted, "filesystem": ifilesystem, "resource": desc, "is_network": ifilesystem in NETWORK_FS or ifilesystem in custom_network_fs } ) imax_disk[desc] = iavailable except: self.log.error("Unable to parse df -i output: %s" % line) continue if status is agent_util.SUPPORTED and not devices: status = agent_util.MISCONFIGURED msg = "No disks found (or none visible from df)." options_schema = { 'device': 'string', 'mountpoint': 'string', 'filesystem': 'string', 'resource': 'string', 'is_network': 'boolean' } data = { "usage.percent_used": { "label": "Percentage of disk used", "options": devices, "options_schema": options_schema, "status": status, "error_message": msg, "unit": "percent", "min_value": 0, "max_value": 100, }, "usage.kb_available": { "label": "Disk space available", "options": devices, "options_schema": options_schema, "status": status, "error_message": msg, "unit": "kB", "min_value": 0, "max_value": max_disk, }, "filesystem.mounted": { "label": "Filesystem mounted", "options": devices, "options_schema": options_schema, "status": status, "error_message": msg, }, "inode.percent_used": { "label": "Inodes percent used", "options": idevices, "options_schema": options_schema, "status": status, "error_message": msg, "unit": "percent", "min_value": 0, "max_value": 100, }, "inode.used": { "label": "Inode used", "options": idevices, "options_schema": options_schema, "status": status, "error_message": msg, "unit": "Inodes", "min_value": 0, "max_value": imax_disk, }, "inode.available": { "label": "Inodes Available", "options": idevices, "options_schema": options_schema, "status": status, "error_message": msg, "unit": "Inodes", "min_value": 0, "max_value": imax_disk, }, } # no inodes for vmware to_del = [] if 'vmware' in sys.platform: for k in data.keys(): if 'inode' in k: to_del.append(k) for d in to_del: del data[d] return data def parse_disk_usage_line(self, line): """ Take a df results list and try to accomodate it according to the its columns. """ percent_value = [value for value in line if '%' in value or value == '-'][0] percent_index = line.index(percent_value) mounted_on = ' '.join(line[percent_index + 1:]) blocks, used, available = line[percent_index-3:percent_index] df_device = ' '.join(line[0:percent_index-3]) return df_device, blocks, used, available, percent_value, mounted_on def check(self, textkey, dev_mount, config): dev_mount = dev_mount.split() device = dev_mount[0] mounted = dev_mount[-1] extra_df_arg = config.get("extra_df_arg", "") if "vmware" in sys.platform: ret, output = agent_util.execute_command("stat -f %s" % mounted, cache_timeout=agent_util.DEFAULT_CACHE_TIMEOUT) # make sure it's mounted first if ret != 0 and textkey != 'filesystem.mounted': self.log.error("Unable to find disk %s, is it mounted?!" % mounted) self.log.error(output) return None elif ret != 0 and textkey == 'filesystem.mounted': return 0 block_size = 0 metrics = {} for line in output.split('\n'): l = str(line).strip().lower() if l.startswith('file:') or l.startswith('id:'): continue elif l.startswith('block size:'): block_size = l.split()[-1] if l.startswith('blocks:'): try: btext, ttext, total_size, ftext, free_size, atext, avail_size = l.split() except: self.log.error("Unable to parse disk output!") self.log.error(output) return None metrics['usage.percent_used'] = 100. - ((float(free_size) / float(total_size)) * 100) metrics['usage.kb_available'] = float(free_size) * float(block_size) return metrics[str(textkey)] if textkey.startswith("i"): ret_code, output = agent_util.execute_command(get_idf_cmd(extra_df_arg), cache_timeout=agent_util.DEFAULT_CACHE_TIMEOUT) self.log.debug(u"df -i output: %s" % output) output = output.splitlines() else: ret_code, output = agent_util.execute_command(get_df_cmd(extra_df_arg), cache_timeout=agent_util.DEFAULT_CACHE_TIMEOUT) self.log.debug(u"df output: %s" % output) output = output.splitlines() for line in output[1:]: if line.startswith('Filesystem'): continue line = line.strip() try: df_device, blocks, used, available, capacity, df_mounted = self.parse_disk_usage_line(line.split()) except: if textkey.startswith("i"): self.log.error("Unable to parse df -i output: %s" % line) else: self.log.error("Unable to parse df output: %s" % line) continue # max value that can be returned in kb blocks, just using the max_capacity = int(available) + int(used) if device in [df_device, df_mounted] or mounted in [df_device, df_mounted]: if textkey in ["usage.percent_used","inode.percent_used"]: if capacity == '-': return 0 else: return int(capacity.rstrip('%')) elif textkey == "inode.used": return int(used) elif textkey in ["usage.kb_available", "inode.available"]: return int(available) elif textkey == "filesystem.mounted": return True if textkey == "filesystem.mounted": return False else: self.log.error("device %r not found" % device) return None