diff --git a/check_btrfs.py b/check_btrfs.py index da2a405..690ff2f 100644 --- a/check_btrfs.py +++ b/check_btrfs.py @@ -10,6 +10,10 @@ ESC = {"reset": "\033[0m", "red": "\033[31m", "yellow": "\033[33m", "green": "\0 def color_text(text, color): return f"{ESC[color]}{text}{ESC['reset']}" +def is_interactive(): + """Detect if running interactively (not Nagios)""" + return sys.stdout.isatty() + def run_cmd(cmd): try: return subprocess.check_output(cmd, shell=True, text=True, stderr=subprocess.STDOUT).strip() @@ -84,9 +88,9 @@ Examples: else: target_mounts = find_btrfs_mounts() - # Nagios: No mounts = UNKNOWN (3) + # Nagios: No mounts = UNKNOWN (3) - SINGLE LINE if not target_mounts: - print(color_text("UNKNOWN No BTRFS mount points found or specified|", "yellow")) + print("UNKNOWN No BTRFS mount points found or specified|") sys.exit(3) data_warn = args.data_threshold @@ -97,31 +101,38 @@ Examples: global_status = 0 all_perfdata = [] - - # Nagios: Human-readable output only (colorful) - print(color_text("Checking BTRFS filesystems:", "bold")) - print(f"Thresholds: Data(W>{data_warn}/C>{data_crit}) Meta(W>{meta_warn}/C>{meta_crit}) Scrub(>{max_scrub_err})") - print("=" * 80) + + # ONLY show verbose colorful output in INTERACTIVE mode + if is_interactive(): + print(color_text("Checking BTRFS filesystems:", "bold")) + print(f"Thresholds: Data(W>{data_warn}/C>{data_crit}) Meta(W>{meta_warn}/C>{meta_crit}) Scrub(>{max_scrub_err})") + print("=" * 80) for mount in target_mounts: - print(f"\n{color_text(mount, 'cyan')}") + if is_interactive(): + print(f"\n{color_text(mount, 'cyan')}") # Validate mount point if not is_btrfs_mount(mount): - print(color_text(f" UNKNOWN: Mount point not found or not BTRFS", "red")) + if is_interactive(): + print(color_text(" UNKNOWN: Mount point not found or not BTRFS", "red")) global_status = max(global_status, 3) - all_perfdata.append(f"{mount}_status=3") + mount_name = mount.replace('/', '_').replace(' ', '_') + all_perfdata.append(f"{mount_name}_status=3") continue # Test btrfs df df_output = run_cmd(f"btrfs filesystem df {mount}") if not df_output or "Data" not in df_output: - print(color_text(" UNKNOWN: btrfs filesystem df failed", "red")) + if is_interactive(): + print(color_text(" UNKNOWN: btrfs filesystem df failed", "red")) global_status = max(global_status, 3) - all_perfdata.append(f"{mount}_status=3") + mount_name = mount.replace('/', '_').replace(' ', '_') + all_perfdata.append(f"{mount_name}_status=3") continue - print(color_text(" BTRFS filesystem accessible", "green")) + if is_interactive(): + print(color_text(" BTRFS filesystem accessible", "green")) # Parse usage percentages data_match = re.search(r'Data.*?(\d+)%', df_output, re.IGNORECASE) @@ -130,45 +141,48 @@ Examples: data_pct = int(data_match.group(1)) if data_match else 0 meta_pct = int(meta_match.group(1)) if meta_match else 0 - # Determine status colors - data_color = "green" if data_pct < data_warn else "yellow" if data_pct < data_crit else "red" - meta_color = "green" if meta_pct < meta_warn else "yellow" if meta_pct < meta_crit else "red" - - print(f" Data: {color_text(f'{data_pct}%', data_color)}") - print(f" Metadata: {color_text(f'{meta_pct}%', meta_color)}") + # Determine status + data_status = 2 if data_pct >= data_crit else 1 if data_pct >= data_warn else 0 + meta_status = 2 if meta_pct >= meta_crit else 1 if meta_pct >= meta_warn else 0 + + if is_interactive(): + data_color = "green" if data_status == 0 else "yellow" if data_status == 1 else "red" + meta_color = "green" if meta_status == 0 else "yellow" if meta_status == 1 else "red" + print(f" Data: {color_text(f'{data_pct}%', data_color)}") + print(f" Metadata: {color_text(f'{meta_pct}%', meta_color)}") # Scrub status scrub = run_cmd(f"btrfs scrub status {mount}") scrub_errors = len(re.findall(r'(\d+) errors?', scrub, re.IGNORECASE)) - scrub_color = "green" if scrub_errors <= max_scrub_err else "red" - print(f" Scrub errors: {color_text(str(scrub_errors), scrub_color)}") - - # Update global status per Nagios standard - data_status = 2 if data_pct >= data_crit else 1 if data_pct >= data_warn else 0 - meta_status = 2 if meta_pct >= meta_crit else 1 if meta_pct >= meta_warn else 0 scrub_status = 2 if scrub_errors > max_scrub_err else 0 + if is_interactive(): + scrub_color = "green" if scrub_status == 0 else "red" + print(f" Scrub errors: {color_text(str(scrub_errors), scrub_color)}") + + # Final status for this mount mount_status = max(data_status, meta_status, scrub_status) global_status = max(global_status, mount_status) - # Nagios perfdata format: metric=value;warn;crit;min;max - perf = f"data_pct={data_pct};{data_warn};{data_crit} meta_pct={meta_pct};{meta_warn};{meta_crit} scrub_err={scrub_errors};{max_scrub_err}" + # Nagios perfdata format + mount_name = mount.replace('/', '_').replace(' ', '_') + perf = f"{mount_name}_data_pct={data_pct};{data_warn};{data_crit} {mount_name}_meta_pct={meta_pct};{meta_warn};{meta_crit} {mount_name}_scrub_err={scrub_errors};{max_scrub_err}" all_perfdata.append(perf) - # Nagios: Single line FINAL STATUS + perfdata - perfdata = " ".join(all_perfdata) + perfdata = "| " + " ".join(all_perfdata) status_text = {0: "OK", 1: "WARNING", 2: "CRITICAL", 3: "UNKNOWN"} - # Colorful human output - status_color = "green" if global_status == 0 else "yellow" if global_status == 1 else "red" - print("\n" + "=" * 80) - print(color_text(f"FINAL STATUS: {status_text[global_status]}", status_color)) - print(f"| {perfdata}") + # ALWAYS: Clean Nagios output FIRST LINE (parseable) + print(f"{status_text[global_status]} BTRFS check: {len(target_mounts)} mount(s){perfdata}") - # Nagios: Clean single-line output (no colors for parsing) - print(f"\n{status_text[global_status]} BTRFS check complete| {perfdata}") + # ONLY interactive: Additional colorful summary + if is_interactive(): + status_color = "green" if global_status == 0 else "yellow" if global_status == 1 else "red" + print("\n" + "=" * 80) + print(color_text(f"FINAL STATUS: {status_text[global_status]}", status_color)) + print(f"{perfdata}") - # Nagios standard exit codes + # Nagios standard exit codes: 0=OK, 1=WARNING, 2=CRITICAL, 3=UNKNOWN sys.exit(global_status) if __name__ == "__main__":