Fix ticket ASCII art alignment, Ceph classification, and cleanup
- Fix all 9 box sections to produce exactly 80-char lines - Add Ceph/OSD keyword detection to _get_issue_type() - Make _get_impact_level() recognize HEALTH_WARN/HEALTH_ERR/DOWN - Remove unused make_box() method - Fix wrong Gitea URL (10.10.10.110 → 10.10.10.63) in README Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ sudo systemctl start hwmon.timer
|
|||||||
|
|
||||||
### One liner (run as root)
|
### One liner (run as root)
|
||||||
```bash
|
```bash
|
||||||
curl -o /etc/systemd/system/hwmon.service http://10.10.10.110:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.service && curl -o /etc/systemd/system/hwmon.timer http://10.10.10.110:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.timer && systemctl daemon-reload && systemctl enable hwmon.timer && systemctl start hwmon.timer
|
curl -o /etc/systemd/system/hwmon.service http://10.10.10.63:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.service && curl -o /etc/systemd/system/hwmon.timer http://10.10.10.63:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.timer && systemctl daemon-reload && systemctl enable hwmon.timer && systemctl start hwmon.timer
|
||||||
```
|
```
|
||||||
|
|
||||||
## Manual Execution
|
## Manual Execution
|
||||||
|
|||||||
@@ -1081,12 +1081,6 @@ class SystemHealthMonitor:
|
|||||||
|
|
||||||
return drive_details
|
return drive_details
|
||||||
|
|
||||||
def make_box(self, title: str, content: str, content_width: int = 70) -> str:
|
|
||||||
"""Create a formatted box with title and content."""
|
|
||||||
return f"""
|
|
||||||
┏━ {title} {'━' * (content_width - len(title) - 3)}┓
|
|
||||||
{content}
|
|
||||||
┗{'━' * content_width}┛"""
|
|
||||||
|
|
||||||
def _get_issue_type(self, issue: str) -> str:
|
def _get_issue_type(self, issue: str) -> str:
|
||||||
"""Determine issue type from issue description."""
|
"""Determine issue type from issue description."""
|
||||||
@@ -1094,8 +1088,10 @@ class SystemHealthMonitor:
|
|||||||
return "SMART Health Issue"
|
return "SMART Health Issue"
|
||||||
elif "Drive" in issue:
|
elif "Drive" in issue:
|
||||||
return "Storage Issue"
|
return "Storage Issue"
|
||||||
|
elif any(kw in issue for kw in ["Ceph", "OSD", "ceph"]):
|
||||||
|
return "Ceph Cluster Issue"
|
||||||
elif "ECC" in issue:
|
elif "ECC" in issue:
|
||||||
return "Memory Issue"
|
return "Memory Issue"
|
||||||
elif "CPU" in issue:
|
elif "CPU" in issue:
|
||||||
return "Performance Issue"
|
return "Performance Issue"
|
||||||
elif "Network" in issue:
|
elif "Network" in issue:
|
||||||
@@ -1104,9 +1100,10 @@ class SystemHealthMonitor:
|
|||||||
|
|
||||||
def _get_impact_level(self, issue: str) -> str:
|
def _get_impact_level(self, issue: str) -> str:
|
||||||
"""Determine impact level from issue description."""
|
"""Determine impact level from issue description."""
|
||||||
if "CRITICAL" in issue or "UNHEALTHY" in issue:
|
issue_upper = issue.upper()
|
||||||
|
if "CRITICAL" in issue_upper or "UNHEALTHY" in issue_upper or "HEALTH_ERR" in issue_upper:
|
||||||
return "🔴 Critical - Immediate Action Required"
|
return "🔴 Critical - Immediate Action Required"
|
||||||
elif "WARNING" in issue:
|
elif "WARNING" in issue_upper or "HEALTH_WARN" in issue_upper or "DOWN" in issue_upper:
|
||||||
return "🟡 Warning - Action Needed Soon"
|
return "🟡 Warning - Action Needed Soon"
|
||||||
return "🟢 Low - Monitor Only"
|
return "🟢 Low - Monitor Only"
|
||||||
|
|
||||||
@@ -1116,17 +1113,18 @@ class SystemHealthMonitor:
|
|||||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
priority = "⚠ HIGH" if "CRITICAL" in issue else "● MEDIUM"
|
priority = "⚠ HIGH" if "CRITICAL" in issue else "● MEDIUM"
|
||||||
|
|
||||||
# Standard box width for all sections (80 chars total)
|
# Box width: all lines are exactly 80 chars
|
||||||
|
# border lines: ┏ + 78 ━ + ┓ = 80
|
||||||
|
# content lines: prefix + field_width + ┃ = 80
|
||||||
box_width = 78
|
box_width = 78
|
||||||
field_width = 62 # Width for value fields after label
|
|
||||||
|
|
||||||
banner = f"""
|
banner = f"""
|
||||||
┏{'━' * box_width}┓
|
┏{'━' * box_width}┓
|
||||||
┃{' HARDWARE MONITORING ALERT TICKET '.center(box_width)}┃
|
┃{' HARDWARE MONITORING ALERT TICKET '.center(box_width)}┃
|
||||||
┣{'━' * box_width}┫
|
┣{'━' * box_width}┫
|
||||||
┃ Host : {hostname:<{box_width - 15}}┃
|
┃ Host : {hostname:<{box_width - 14}}┃
|
||||||
┃ Generated : {timestamp:<{box_width - 15}}┃
|
┃ Generated : {timestamp:<{box_width - 14}}┃
|
||||||
┃ Priority : {priority:<{box_width - 15}}┃
|
┃ Priority : {priority:<{box_width - 14}}┃
|
||||||
┗{'━' * box_width}┛"""
|
┗{'━' * box_width}┛"""
|
||||||
|
|
||||||
issue_type = self._get_issue_type(issue)
|
issue_type = self._get_issue_type(issue)
|
||||||
@@ -1134,8 +1132,8 @@ class SystemHealthMonitor:
|
|||||||
|
|
||||||
executive_summary = f"""
|
executive_summary = f"""
|
||||||
┏━ EXECUTIVE SUMMARY {'━' * (box_width - 20)}┓
|
┏━ EXECUTIVE SUMMARY {'━' * (box_width - 20)}┓
|
||||||
┃ Issue Type │ {issue_type:<{field_width}}┃
|
┃ Issue Type │ {issue_type:<60}┃
|
||||||
┃ Impact Level │ {impact_level:<{field_width}}┃
|
┃ Impact Level │ {impact_level:<60}┃
|
||||||
┗{'━' * box_width}┛"""
|
┗{'━' * box_width}┛"""
|
||||||
|
|
||||||
description = banner + executive_summary
|
description = banner + executive_summary
|
||||||
@@ -1179,12 +1177,12 @@ class SystemHealthMonitor:
|
|||||||
|
|
||||||
description += f"""
|
description += f"""
|
||||||
┏━ DRIVE SPECIFICATIONS {'━' * (box_width - 23)}┓
|
┏━ DRIVE SPECIFICATIONS {'━' * (box_width - 23)}┓
|
||||||
┃ Device Path │ {device_safe:<{field_width}}┃
|
┃ Device Path │ {device_safe:<61}┃
|
||||||
┃ Model │ {model_safe:<{field_width}}┃
|
┃ Model │ {model_safe:<61}┃
|
||||||
┃ Serial │ {serial_safe:<{field_width}}┃
|
┃ Serial │ {serial_safe:<61}┃
|
||||||
┃ Capacity │ {capacity_safe:<{field_width}}┃
|
┃ Capacity │ {capacity_safe:<61}┃
|
||||||
┃ Type │ {type_safe:<{field_width}}┃
|
┃ Type │ {type_safe:<61}┃
|
||||||
┃ Firmware │ {firmware_safe:<{field_width}}┃
|
┃ Firmware │ {firmware_safe:<61}┃
|
||||||
┗{'━' * box_width}┛
|
┗{'━' * box_width}┛
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1202,9 +1200,9 @@ class SystemHealthMonitor:
|
|||||||
|
|
||||||
description += f"""
|
description += f"""
|
||||||
┏━ DRIVE TIMELINE {'━' * (box_width - 17)}┓
|
┏━ DRIVE TIMELINE {'━' * (box_width - 17)}┓
|
||||||
┃ Power-On Hours │ {power_on_safe:<{field_width - 4}}┃
|
┃ Power-On Hours │ {power_on_safe:<56}┃
|
||||||
┃ Last SMART Test │ {last_test_safe:<{field_width - 4}}┃
|
┃ Last SMART Test │ {last_test_safe:<56}┃
|
||||||
┃ Drive Age │ {age_safe:<{field_width - 4}}┃
|
┃ Drive Age │ {age_safe:<56}┃
|
||||||
┗{'━' * box_width}┛
|
┗{'━' * box_width}┛
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1215,8 +1213,8 @@ class SystemHealthMonitor:
|
|||||||
|
|
||||||
description += f"""
|
description += f"""
|
||||||
┏━ SMART STATUS {'━' * (box_width - 15)}┓
|
┏━ SMART STATUS {'━' * (box_width - 15)}┓
|
||||||
┃ Status │ {smart_status_safe:<{field_width}}┃
|
┃ Status │ {smart_status_safe:<62}┃
|
||||||
┃ Temperature │ {temp_safe:<{field_width}}┃
|
┃ Temperature │ {temp_safe:<62}┃
|
||||||
┗{'━' * box_width}┛
|
┗{'━' * box_width}┛
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1225,7 +1223,7 @@ class SystemHealthMonitor:
|
|||||||
for attr, value in drive_info['smart_attributes'].items():
|
for attr, value in drive_info['smart_attributes'].items():
|
||||||
attr_safe = str(attr).replace('_', ' ') if attr else 'Unknown'
|
attr_safe = str(attr).replace('_', ' ') if attr else 'Unknown'
|
||||||
value_safe = str(value) if value is not None else 'N/A'
|
value_safe = str(value) if value is not None else 'N/A'
|
||||||
description += f"┃ {attr_safe:<27} │ {value_safe:<{field_width - 14}}┃\n"
|
description += f"┃ {attr_safe:<27} │ {value_safe:<46}┃\n"
|
||||||
description += f"┗{'━' * box_width}┛\n"
|
description += f"┗{'━' * box_width}┛\n"
|
||||||
|
|
||||||
if drive_info.get('partitions'):
|
if drive_info.get('partitions'):
|
||||||
@@ -1247,11 +1245,11 @@ class SystemHealthMonitor:
|
|||||||
|
|
||||||
description += f"""
|
description += f"""
|
||||||
┏━ PARTITION: {mountpoint_display} {'━' * (box_width - 14 - len(mountpoint_display))}┓
|
┏━ PARTITION: {mountpoint_display} {'━' * (box_width - 14 - len(mountpoint_display))}┓
|
||||||
┃ Filesystem │ {fstype_safe:<{field_width}}┃
|
┃ Filesystem │ {fstype_safe:<61}┃
|
||||||
┃ Usage Meter │ {usage_meter} {usage_pct_str:>5}┃
|
┃ Usage Meter │ {usage_meter} {usage_pct_str:>10}┃
|
||||||
┃ Total Space │ {total_space_safe:<{field_width}}┃
|
┃ Total Space │ {total_space_safe:<61}┃
|
||||||
┃ Used Space │ {used_space_safe:<{field_width}}┃
|
┃ Used Space │ {used_space_safe:<61}┃
|
||||||
┃ Free Space │ {free_space_safe:<{field_width}}┃
|
┃ Free Space │ {free_space_safe:<61}┃
|
||||||
┗{'━' * box_width}┛
|
┗{'━' * box_width}┛
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1260,7 +1258,7 @@ class SystemHealthMonitor:
|
|||||||
description += f"\n┏━ FIRMWARE ALERTS {'━' * (box_width - 18)}┓\n"
|
description += f"\n┏━ FIRMWARE ALERTS {'━' * (box_width - 18)}┓\n"
|
||||||
for issue_item in firmware_info['known_issues']:
|
for issue_item in firmware_info['known_issues']:
|
||||||
issue_safe = str(issue_item) if issue_item else 'Unknown issue'
|
issue_safe = str(issue_item) if issue_item else 'Unknown issue'
|
||||||
description += f"┃ ⚠ {issue_safe:<{box_width - 5}}┃\n"
|
description += f"┃ ⚠ {issue_safe:<{box_width - 4}}┃\n"
|
||||||
description += f"┗{'━' * box_width}┛\n"
|
description += f"┗{'━' * box_width}┛\n"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
description += f"\nError generating drive details: {str(e)}\n"
|
description += f"\nError generating drive details: {str(e)}\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user