- Posted on
- • Artificial Intelligence
Artificial Intelligence Projects for Sysadmins
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Artificial Intelligence Projects for Sysadmins (That Run on Bash-Friendly Linux)
Your fleet is already generating mountains of metrics and logs. The question is: will you sift through it at 3 a.m., or will a small, reliable AI tool do it for you—on your own servers, with your rules, and no GPU required?
This guide shows how to build practical, low-maintenance AI helpers for common sysadmin realities: catching weird logs fast, spotting risky disks before they die, forecasting capacity, and triaging tickets. Everything runs locally on Linux, glues nicely into Bash, and installs with apt, dnf, or zypper.
Why AI for sysadmins is worth your time
Your data is structured and abundant. Logs, SMART, load averages, and ticket text are perfect inputs for classic ML and light anomaly detection.
You don’t need a GPU. The projects below use lightweight Python libraries (scikit-learn, statsmodels) that run fine on modest VMs.
Immediate, measurable impact. Fewer false alarms, earlier warnings, and faster triage save real on-call hours.
Prereqs and installation
Run these once to prepare a clean Python environment and a few OS tools.
- Debian/Ubuntu (apt)
sudo apt update
sudo apt install -y python3 python3-venv python3-pip gcc g++ python3-dev \
smartmontools sysstat jq git
- Fedora/RHEL/CentOS Stream (dnf)
sudo dnf install -y python3 python3-virtualenv python3-pip gcc gcc-c++ python3-devel \
smartmontools sysstat jq git
- openSUSE/SLES (zypper)
sudo zypper install -y python3 python3-venv python3-pip gcc gcc-c++ python3-devel \
smartmontools sysstat jq git
Create a project directory and a Python virtual environment:
mkdir -p ~/ai-ops && cd ~/ai-ops
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
Tip: Use systemd timers or cron to schedule these scripts. Examples are included.
Project 1 — Log anomaly alerts with Isolation Forest
Goal: Catch unusual log lines in near real-time (e.g., nginx, sshd, app services) to surface weirdness faster than grep and thresholds.
Install Python deps:
pip install scikit-learn numpy
Minimal anomaly detector (detect_log_anomalies.py):
#!/usr/bin/env python3
import sys, re, json, os
import numpy as np
from sklearn.ensemble import IsolationForest
# Feature extraction for a log line
def features(line):
ln = line.strip()
length = len(ln)
digits = sum(c.isdigit() for c in ln)
specials = sum(not c.isalnum() and not c.isspace() for c in ln)
digit_ratio = digits / (length + 1e-6)
special_ratio = specials / (length + 1e-6)
# Try to pull HTTP status if present
m = re.search(r'\s(\d{3})\s', ln)
status = int(m.group(1)) if m else 0
return [length, digit_ratio, special_ratio, status]
# Train a baseline model from a sample file or stdin if baseline missing
BASELINE = os.environ.get("ANOMALY_BASELINE", "baseline_log_sample.txt")
clf = IsolationForest(n_estimators=100, contamination=0.01, random_state=42)
def load_baseline():
X = []
if os.path.exists(BASELINE):
with open(BASELINE, "r", errors="ignore") as f:
for line in f:
X.append(features(line))
else:
# If no baseline, collect first 200 lines from stdin for baseline
seed = []
for i, line in enumerate(sys.stdin):
seed.append(line)
if i >= 200:
break
with open(BASELINE, "w") as f:
f.writelines(seed)
X = [features(l) for l in seed]
return np.array(X)
X_base = load_baseline()
if len(X_base) < 10:
print("Baseline too small; collect more normal logs first.", file=sys.stderr)
sys.exit(1)
clf.fit(X_base)
# If we consumed some lines to build baseline from stdin, we need to continue with the rest
# Read remaining stdin lines for scoring
for line in sys.stdin:
x = np.array(features(line)).reshape(1, -1)
score = -clf.decision_function(x)[0] # higher => more anomalous
if score > 0.2: # tune threshold to taste
out = {"anomaly_score": round(score, 3), "line": line.strip()}
print(json.dumps(out))
Examples:
- Nginx access logs:
tail -F /var/log/nginx/access.log | python3 detect_log_anomalies.py
- Systemd service logs (e.g., sshd, last 5 minutes):
journalctl -u ssh --since "5 min ago" -o short-iso -n 2000 | python3 detect_log_anomalies.py
Optional systemd service/timer:
# /etc/systemd/system/log-anomaly.service
[Unit]
Description=Log anomaly scan (nginx)
[Service]
Type=oneshot
User=root
WorkingDirectory=/root/ai-ops
Environment="ANOMALY_BASELINE=/root/ai-ops/nginx_baseline.txt"
ExecStart=/bin/bash -lc 'journalctl -u nginx --since "-5 min" -o short-iso | /root/ai-ops/.venv/bin/python detect_log_anomalies.py >> /var/log/nginx_anomalies.jsonl'
# /etc/systemd/system/log-anomaly.timer
[Unit]
Description=Run log anomaly scan every 5 minutes
[Timer]
OnUnitActiveSec=5min
Persistent=true
[Install]
WantedBy=timers.target
Enable:
sudo systemctl daemon-reload
sudo systemctl enable --now log-anomaly.timer
Project 2 — SMART-based disk failure early warning
Goal: Use SMART attributes to detect “this disk looks unlike its healthy self” before it dies. Unsupervised anomaly detection per host is practical without labeled failures.
We already installed smartmontools. Add Python deps:
pip install scikit-learn numpy
Script (disk_smart_anomaly.py):
#!/usr/bin/env python3
import subprocess, json, os, datetime
import numpy as np
from sklearn.ensemble import IsolationForest
STATE = os.environ.get("SMART_STATE", "smart_baseline.json")
KEYS = [
"Reallocated_Sector_Ct",
"Current_Pending_Sector",
"Offline_Uncorrectable",
"UDMA_CRC_Error_Count",
"Power_On_Hours",
"Temperature_Celsius",
]
def list_disks():
out = subprocess.check_output(["lsblk", "-ndo", "NAME,TYPE"]).decode()
disks = []
for line in out.strip().splitlines():
name, typ = line.split()
if typ == "disk":
disks.append("/dev/" + name)
return disks
def smart_attrs(dev):
try:
out = subprocess.check_output(["smartctl", "-A", dev], stderr=subprocess.STDOUT).decode(errors="ignore")
except subprocess.CalledProcessError as e:
out = e.output.decode(errors="ignore")
vals = {}
for line in out.splitlines():
parts = line.split()
if len(parts) >= 10 and parts[0].isdigit():
attr_name = parts[1]
raw = parts[-1]
# Some RAW_VALUE entries like 35 (Min/Max 20/50); grab the leading int
try:
raw_int = int(raw.split()[0])
except:
raw_int = 0
vals[attr_name] = raw_int
vec = [vals.get(k, 0) for k in KEYS]
return vec
def load_state():
if os.path.exists(STATE):
with open(STATE) as f:
return json.load(f)
return {"history": {}}
def save_state(s):
with open(STATE, "w") as f:
json.dump(s, f)
def main():
s = load_state()
now = datetime.datetime.utcnow().isoformat()
results = []
for dev in list_disks():
vec = smart_attrs(dev)
hist = s["history"].get(dev, [])
hist.append(vec)
# cap history length
hist = hist[-500:]
s["history"][dev] = hist
X = np.array(hist)
if len(X) >= 20:
clf = IsolationForest(contamination=0.05, random_state=42).fit(X)
score = -clf.decision_function([vec])[0]
else:
score = 0.0
results.append({"device": dev, "time": now, "score": round(score, 3), "vector": dict(zip(KEYS, vec))})
save_state(s)
for r in results:
if r["score"] > 0.5:
print(json.dumps({"level": "WARN", **r}))
else:
print(json.dumps({"level": "OK", **r}))
if __name__ == "__main__":
main()
Run daily and log:
sudo /root/ai-ops/.venv/bin/python /root/ai-ops/disk_smart_anomaly.py >> /var/log/smart_anomaly.jsonl
Systemd timer (optional):
# /etc/systemd/system/smart-anomaly.service
[Unit]
Description=SMART anomaly check
[Service]
Type=oneshot
User=root
WorkingDirectory=/root/ai-ops
ExecStart=/root/ai-ops/.venv/bin/python /root/ai-ops/disk_smart_anomaly.py >> /var/log/smart_anomaly.jsonl
# /etc/systemd/system/smart-anomaly.timer
[Unit]
Description=Daily SMART anomaly check
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
Enable:
sudo systemctl daemon-reload
sudo systemctl enable --now smart-anomaly.timer
Project 3 — Capacity forecasting for load average (Holt-Winters)
Goal: Forecast 1–7 days ahead to anticipate when hosts will saturate CPU. We’ll collect 1‑minute load and use Holt‑Winters (no heavy dependencies).
Install Python deps:
pip install pandas numpy statsmodels
1) Lightweight collector (append timestamp + 1‑min load to CSV):
#!/usr/bin/env bash
# collect_load.sh
set -euo pipefail
OUT="${1:-/var/log/loadavg.csv}"
ts="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
load1="$(cut -d' ' -f1 </proc/loadavg)"
echo "$ts,$load1" >> "$OUT"
Cron every minute:
* * * * * /usr/local/bin/collect_load.sh /var/log/loadavg.csv
2) Forecaster (forecast_load.py) — warns if projected load exceeds CPU cores:
#!/usr/bin/env python3
import sys, pandas as pd, numpy as np, json, os
from statsmodels.tsa.holtwinters import ExponentialSmoothing
from datetime import timedelta
CSV = sys.argv[1] if len(sys.argv) > 1 else "/var/log/loadavg.csv"
CORES = os.cpu_count() or 1
HOURS_AHEAD = int(os.environ.get("FORECAST_HOURS", "24"))
df = pd.read_csv(CSV, names=["ts","load"], parse_dates=["ts"])
df = df.dropna()
df = df.set_index("ts").asfreq("1min").interpolate()
if len(df) < 120: # need some history
print("Not enough history", file=sys.stderr)
sys.exit(0)
# Daily seasonality guess for 1-min data: period ~ 1440
period = 1440
model = ExponentialSmoothing(df["load"], trend="add", seasonal="add", seasonal_periods=period)
fit = model.fit(optimized=True, use_brute=True)
future = fit.forecast(HOURS_AHEAD * 60)
peak = float(future.max())
warn = peak > CORES
out = {
"horizon_hours": HOURS_AHEAD,
"cpu_cores": CORES,
"projected_peak_load": round(peak, 2),
"status": "WARN" if warn else "OK"
}
print(json.dumps(out))
Run daily and alert if needed:
FORECAST_HOURS=48 /root/ai-ops/.venv/bin/python /root/ai-ops/forecast_load.py /var/log/loadavg.csv
You can wire this into email, Slack, or your monitoring system by parsing the JSON.
Note: If you prefer sar/sysstat, ensure it’s enabled and point the forecaster at its exports.
Project 4 — Ticket auto-tagging with TF‑IDF + LinearSVC
Goal: Suggest tags like “network”, “storage”, “auth” for new tickets to speed up routing. This uses classic text ML—fast, private, and easy to retrain.
Install Python deps:
pip install scikit-learn pandas joblib
Assume a CSV of historical tickets (tickets.csv) with columns: id,title,body,tag
Train and save model (train_tagger.py):
#!/usr/bin/env python3
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import Pipeline
from sklearn.svm import LinearSVC
from sklearn.metrics import classification_report
import joblib, sys
CSV = sys.argv[1] if len(sys.argv) > 1 else "tickets.csv"
df = pd.read_csv(CSV)
df["text"] = (df["title"].fillna("") + " " + df["body"].fillna("")).str.lower()
X_train, X_test, y_train, y_test = train_test_split(df["text"], df["tag"], test_size=0.2, random_state=42, stratify=df["tag"])
pipe = Pipeline([
("tfidf", TfidfVectorizer(max_features=50000, ngram_range=(1,2))),
("clf", LinearSVC())
])
pipe.fit(X_train, y_train)
pred = pipe.predict(X_test)
print(classification_report(y_test, pred))
joblib.dump(pipe, "ticket_tagger.joblib")
print("Saved model to ticket_tagger.joblib")
Predict for a new ticket (predict_tag.py):
#!/usr/bin/env python3
import sys, joblib
if len(sys.argv) < 2:
print("Usage: predict_tag.py 'ticket text here'")
sys.exit(1)
model = joblib.load("ticket_tagger.joblib")
text = sys.argv[1].lower()
pred = model.predict([text])[0]
print(pred)
Example:
python train_tagger.py tickets.csv
python predict_tag.py "Login fails with PAM error after LDAP change"
Wire this into your helpdesk intake flow or ChatOps bot to auto-apply tags.
Good practices and notes
Start simple and iterate. Tune anomaly thresholds once you see a week of data.
Keep models per host or per service to avoid mixing unrelated patterns.
Store baselines/state in a known directory and back them up lightly if useful.
Privacy/security: Everything here runs locally; no data leaves your servers unless you send alerts externally.
Observability: Log outputs in JSONL so you can ingest them with jq, Loki, Splunk, or ELK.
Conclusion and next steps
Pick one project and ship it this week:
If on-call pain is log noise: deploy the log anomaly watcher.
If hardware surprises bite: enable SMART anomaly checks.
If growth is your worry: forecast load and set a warning threshold.
If ticket routing drags: auto-tag with the TF‑IDF model.
Next, automate with a systemd timer, push JSON into your monitoring, and iterate thresholds. When you’re ready, expand features (e.g., include response times, per-disk read errors, or per-queue ticket latency). Small, local AI can quietly save hours—no GPUs, no drama.
If you want a follow-up post with containerized versions and ready-made systemd units, say the word.