Skip to content

Commit

Permalink
Handle missing S.M.A.R.T metrics
Browse files Browse the repository at this point in the history
Handle unmounted drives
Bump version
  • Loading branch information
dormant-user committed Nov 29, 2024
1 parent 445a9ac commit 92f5d70
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 26 deletions.
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ repos:
- id: check-builtin-literals
- id: check-case-conflict
- id: check-docstring-first
- id: check-executables-have-shebangs
- id: check-json
# - id: check-executables-have-shebangs
# - id: check-json
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: check-toml
- id: check-vcs-permalinks
- id: check-xml
# - id: check-xml
- id: check-yaml
- id: debug-statements
- id: detect-aws-credentials
# - id: detect-aws-credentials
- id: detect-private-key
- id: end-of-file-fixer
- id: file-contents-sorter
Expand Down
8 changes: 5 additions & 3 deletions pyudisk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from .main import EnvConfig, generate_report, monitor, smart_metrics # noqa: F401

version = "0.1.0"
version = "0.1.1"


@click.command()
Expand All @@ -30,14 +30,16 @@ def commandline(*args, **kwargs) -> None:
- ``--env | -E``: Environment configuration filepath.
**Commands**
``start | run``: Initiates the monitoring/reporting process.
- ``monitor``: Initiates the monitoring and alerting process.
- ``report``: Generates a full disk-report HTML.
"""
assert sys.argv[0].lower().endswith("pyudisk"), "Invalid commandline trigger!!"
options = {
"--version | -V": "Prints the version.",
"--help | -H": "Prints the help section.",
"--env | -E": "Environment configuration filepath.",
"start | run": "Initiates the monitoring/reporting process.",
"monitor": "Initiates the monitoring and alerting process.",
"report": "Generates a full disk-report HTML",
}
# weird way to increase spacing to keep all values monotonic
_longest_key = len(max(options.keys()))
Expand Down
54 changes: 39 additions & 15 deletions pyudisk/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,28 @@ def smart_metrics(env: EnvConfig) -> Generator[Disk]:
)
)
drives = {k: v for k, v in sorted(parse_drives(smart_dump).items())}
assert len(block_devices) == len(drives)
if len(block_devices) != len(drives):
LOGGER.warning(
f"Number of block devices [{len(block_devices)}] does not match the number of drives [{len(drives)}]"
)
device_names = set(v["Drive"] for v in block_devices.values())
drive_names = set(drives.keys())
diff = (
drive_names - device_names
if len(drive_names) > len(device_names)
else device_names - drive_names
)
LOGGER.warning("UNmounted drive(s) found - '%s'", ", ".join(diff))
optional_fields = [
k
for k, v in Disk.model_json_schema().get("properties").items()
if v.get("anyOf", [{}])[-1].get("type", "") == "null"
]
# S.M.A.R.T metrics can be null, but the keys are mandatory
for drive in drives.values():
for key in optional_fields:
if key not in drive.keys():
drive[key] = None
for (drive, data), (partition, block_data) in zip(
drives.items(), block_devices.items()
):
Expand All @@ -224,20 +245,23 @@ def monitor_disk(env: EnvConfig) -> Generator[Disk]:
"""
message = ""
for disk in smart_metrics(env):
for metric in env.metrics:
attribute = disk.Attributes.model_dump().get(metric.attribute)
if metric.max_threshold and attribute >= metric.max_threshold:
msg = f"{metric.attribute!r} for {disk.id!r} is >= {metric.max_threshold} at {attribute}"
LOGGER.critical(msg)
message += msg + "\n"
if metric.min_threshold and attribute <= metric.min_threshold:
msg = f"{metric.attribute!r} for {disk.id!r} is <= {metric.min_threshold} at {attribute}"
LOGGER.critical(msg)
message += msg + "\n"
if metric.equal_match and attribute != metric.equal_match:
msg = f"{metric.attribute!r} for {disk.id!r} IS NOT {metric.equal_match} at {attribute}"
LOGGER.critical(msg)
message += msg + "\n"
if disk.Attributes:
for metric in env.metrics:
attribute = disk.Attributes.model_dump().get(metric.attribute)
if metric.max_threshold and attribute >= metric.max_threshold:
msg = f"{metric.attribute!r} for {disk.id!r} is >= {metric.max_threshold} at {attribute}"
LOGGER.critical(msg)
message += msg + "\n"
if metric.min_threshold and attribute <= metric.min_threshold:
msg = f"{metric.attribute!r} for {disk.id!r} is <= {metric.min_threshold} at {attribute}"
LOGGER.critical(msg)
message += msg + "\n"
if metric.equal_match and attribute != metric.equal_match:
msg = f"{metric.attribute!r} for {disk.id!r} IS NOT {metric.equal_match} at {attribute}"
LOGGER.critical(msg)
message += msg + "\n"
else:
LOGGER.warning("No attributes were loaded for %s", disk.model)
yield disk
if message:
notification_service(
Expand Down
8 changes: 4 additions & 4 deletions pyudisk/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class Disk(BaseModel):

id: str
model: str
Info: Info
Attributes: Attributes
Partition: Parition
Usage: Usage
Info: Optional[Info]
Attributes: Optional[Attributes]
Partition: Optional[Parition]
Usage: Optional[Usage]

0 comments on commit 92f5d70

Please sign in to comment.