الفلاتر
طريقة البحث
  • الكلمات العادية تجد الأسماء والنصوص والأمثلة.
  • "كلمتان" تجد العبارة بالضبط.
  • --name أو -x تجد خيارًا.
  • #كلمة تبحث داخل الأوامر فقط.
  • @grep تجد الدروس والمعامل التي تستخدم grep.
  • الفلاتر: cat:network · in:labs · level:rhcsa · ch:8 · root:yes. ضع ! قبل كلمة لاستبعادها. OR بين الكلمات تعني إحداها.
  • ↑ ↓ للتنقل · Enter للفتح · Esc للإغلاق · / للبحث

الفصل 10الاسم في الدورة: Hands-on project

Build a daily server report

Put it all together: one script that checks servers, reads logs, calls an API, writes a JSON and CSV report, logs what it does, and runs every morning from a timer. Then publish it on GitHub with tests and CI.

  • 4 الدروس
  • 2 الأوامر

هذا الجزء لم يُترجم بعد. أنت ترى النص الإنجليزي.

$ مستخدم عادي# بصلاحية root (أو مع sudo)

10.1

Plan the report

Decide what the report must answer before you write code.

CheckSourcePython part
Disk, memory, loadLocal systemshutil, psutil
Failed servicessystemctl --failedsubprocess
Failed SSH logins/var/log/securere, Counter
Website up and certificate daysHTTPSrequests, ssl
OutputJSON for tools, CSV for peoplejson, csv

الأوامر في هذا الدرس

10.2

Write the main script

Small functions, one main(), logging, exit code.

server_report.py
#!/usr/bin/env python3
"""Daily server report: disk, services, SSH failures, websites."""
import json
import logging
import re
import shutil
import subprocess
import sys
from collections import Counter
from datetime import date
 
import requests
 
log = logging.getLogger("report")
 
 
def disk(path="/"):
    u = shutil.disk_usage(path)
    return round(u.used / u.total * 100, 1)
 
 
def failed_units():
    out = subprocess.run(["systemctl", "--failed", "--plain", "--no-legend"], capture_output=True, text=True).stdout
    return [line.split()[0] for line in out.splitlines() if line.strip()]
 
 
def ssh_failures(logfile="/var/log/secure", top=5):
    text = open(logfile, encoding="utf-8", errors="replace").read()
    return Counter(re.findall(r"Failed password for \S+ from (\S+)", text)).most_common(top)
 
 
def site(url):
    try:
        r = requests.get(url, timeout=10)
        return {"url": url, "status": r.status_code, "seconds": round(r.elapsed.total_seconds(), 2)}
    except requests.RequestException as e:
        return {"url": url, "status": None, "error": e.__class__.__name__}
 
 
def main():
    logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
    report = {
        "date": str(date.today()),
        "disk_root": disk("/"),
        "failed_units": failed_units(),
        "ssh_failures": ssh_failures(),
        "sites": [site(u) for u in ["https://s0sta.com/", "https://babolatksa.com/"]],
    }
    path = f"/var/lib/report/report-{report['date']}.json"
    with open(path, "w", encoding="utf-8") as f:
        json.dump(report, f, indent=2)
    log.info("report written to %s", path)
    bad = report["failed_units"] or report["disk_root"] > 90 or any(s["status"] != 200 for s in report["sites"])
    return 1 if bad else 0
 
 
if __name__ == "__main__":
    sys.exit(main())

10.3

Run it every morning

A timer at 07:00 on work days; the journal keeps the output.

mkdir -p /var/lib/report
install -m 755 server_report.py /usr/local/bin/server-report
systemctl edit --force --full server-report.service
systemctl edit --force --full server-report.timer
systemctl enable --now server-report.timer
systemctl list-timers server-report.timer

10.4

Publish it

The project is portfolio material when others can read, test and run it.

  • [ ] Repository with README (what, why, how to run), requirements.txt, tests.
  • [ ] GitHub Actions: ruff, pytest on every push.
  • [ ] No secrets in the code; tokens from environment variables.
  • [ ] A LinkedIn post with one screenshot of the report.

كل الأوامر في هذا الفصل