Cronjob mit Python-Script wird nicht ausgeführt

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
McProgger
User
Beiträge: 11
Registriert: Mittwoch 30. September 2020, 14:13

Hi,

ein Python-Script, welches im Terminal ohne Probleme ausgeführt wird, wird als Cronjob vollständig ignoriert.

Hier der Code des Scripts:

Code: Alles auswählen

import logging

logging.basicConfig(filename='/home/user/checkUpdates.log', level=logging.DEBUG)

try:
 import smtplib

 from cryptography.fernet import Fernet
 from pathlib import Path
 from subprocess import run
 from email.mime.multipart import MIMEMultipart
 from email.mime.text import MIMEText

 if Path(".key.key").exists():
  key = ""
  encrypted_password = ""
  decrypted_password = ""
  cipher_suite = ""
  command = ""

  with open(".key.key", "rb") as key_file:
   key = key_file.read()

  cipher_suite = Fernet(key)

  with open(".encrypted_password.txt", "rb") as file:
   encrypted_password = file.read()

  # Descypt password
  decrypted_password = cipher_suite.decrypt(encrypted_password).decode("utf-8")
  command = "sudo apt update && sudo apt list --upgradable > /home/user/mail.txt".format(decrypted_password)

  run(command, shell=True, capture_output=True, text=True)

  # E-Mail
  from_email = "xxx@xxx.de"
  to_email = "xxx@xxx.de"
  subject = "STATUS SRV - Updates verfügbar"
  body = ""

  with open("mail.txt", "r") as file:
   body = file.read()

  # SMTP
  smtp_server = "xxx.xxx.xxx"
  smtp_port = 25

  # Create E-Mail
  msg = MIMEMultipart()
  msg["From"] = from_email
  msg["To"] = to_email
  msg["Subject"] = subject

  msg.attach(MIMEText(body, "plain"))

  # Send E-Mail
  with smtplib.SMTP(smtp_server, smtp_port) as server:
   # server.login(smtp_user, smtp_password)
   server.send_message(msg)

   # Delete file
   Path("mail.txt").unlink()

  logging.info("Update command executed successfully.")
except Exception as e:
 logging.error(f"Error executing update command: {e}")
Der entsprechende Cronjob sieht so aus (sudo crontab -e):

Code: Alles auswählen

15 15 * * * /usr/bin/python3 /home/user/checkUpdates.py
Ich habe mehrere Male eine Suchmaschine meines Vertrauens bemüht, um herauszufinden, warum der Cronjob nicht funktioniert. Vielleicht könnt ihr mir weiterhelfen.

LG McProgger
Benutzeravatar
__blackjack__
User
Beiträge: 14000
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@McProgger: Was steht denn im Log? Also sowohl dem was das Programm da schreiben soll, als auch was der crond so zu sagen hat.

*Ein* Leerzeichen pro Ebene ist nicht wirklich lesbar. Das sollten vier Leerzeichen pro Ebene sein.

Importe gehören an den Anfang des Moduls.

Das Hauptprogramm sollte in einer Funktion stehen, die üblicherweise `main()` heisst.

Wenn so scheinbar gar nichts passiert, kann das ja beispielsweise daran liegen, dass ".key.key" nicht existiert. Wo denkst Du denn wo gesucht wird? Es wird im aktuellen Arbeitsverzeichnis gesucht. Weisst Du welches das ist wenn Cron etwas ausführt? Man sollte Pfade deshalb immer absolut angeben oder in der Crontab vor dem ausführen explizit dort hin wechseln wo man das aktuelle Arbeitsverzeichnis gerne hätte.

Man definiert nicht auf Vorrat am Anfang von einem Block alle Namen mit irgendwelchen Dummy-Werten, die am Ende gar nicht verwendet werden.

Path-Objekte zu erzeugen um dann nur eine einzige Methode darauf aufzurufen, aber dann den Dateinamen später noch mal zu verwenden ist nicht Sinn der Sache. Da erstellt man einmal ein Path-Objekt und verwendet das dann auch durchgehend.

Der ganze Krypto-Kram wird am Ende gar nicht verwendet. Was soll der da? Wäre ausserdem auch kein wirklicher Schutz.

Warum `shell=True`? Das sollte man vermeiden, da fängt man sich die gleichen Probleme ein wegen denen man `os.system()` nicht verwenden sollte.

Warum `capture_output=True`, das dann aber gar nicht verwendet wird. Aber vielleicht verwendet werden sollte, damit man sich die Textdatei mit dem Mail-Inhalt sparen könnte, die ja offensichtlich gar nicht wirklich gewollt ist.

Die ``sudo`` sind zu viel, denn das Skript wird ja bereits als root-Benutzer ausgeführt.

Ausnahmen protokolliert man mit `exception()`, nicht mit `error()`, denn sonst hat man den Traceback nicht als Hilfe zur Fehler- oder Ursachensuche.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import logging
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from subprocess import run

SENDER_ADDRESS = "xxx@xxx.de"
RECEIPIENT_ADDRESS = "xxx@xxx.de"
SUBJECT = "STATUS SRV - Updates verfügbar"

SMTP_SERVER = "xxx.xxx.xxx"
SMTP_PORT = 25

logging.basicConfig(
    filename="/home/user/checkUpdates.log", level=logging.DEBUG
)


def main():
    try:
        run(["apt", "update"], check=True)
        apt_list_result = run(
            ["apt", "list", "--upgradable"],
            capture_output=True,
            universal_newlines=True,
            check=True,
        )
        message = MIMEMultipart()
        message["From"] = SENDER_ADDRESS
        message["To"] = RECEIPIENT_ADDRESS
        message["Subject"] = SUBJECT
        message.attach(MIMEText(apt_list_result.stdout, "plain"))

        with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
            server.send_message(message)

        logging.info("Update command executed successfully.")
    except:
        logging.exception("Unexpected error.")
        raise


if __name__ == "__main__":
    main()
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
McProgger
User
Beiträge: 11
Registriert: Mittwoch 30. September 2020, 14:13

Hi __blackjack__,

vielen Dank für deine hilfreiche Antwort. Deine Verbesserungen habe ich größtenteils umgesetzt. Mein Programm schickt mir jetzt auch über cron die E-Mail raus. Allerdings habe ich noch eine Frage:

1. Worauf zeigt dieser Shebang:

Code: Alles auswählen

#!/usr/bin/env python3
? Wenn ich ein ls /usr/bin/env ausführe, ist das Verzeichnis leer. Woran erkennt er nun, dass er genau aus DIESEM Verzeichnis python3 laden soll?

LG McProgger
Benutzeravatar
__blackjack__
User
Beiträge: 14000
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@McProgger: Was meinst Du mit „ist das Verzeichnis leer“? ``env`` ist ein Programm. Damit kann man die Umgebungsvariablen ändern bevor ``env`` dann das angegebene Programm mit gegebenenfalls weiteren Argumenten startet. Das Programm das ``env`` startet wird im $PATH gesucht. Und das ist der Grund warum man öfter mal diese Form sieht, auch für andere Programmiersprachen. Es ist kein fester Pfad zu einem Interpreter, sondern es verhält sich so als wenn man ``python3`` in der Shell eingibt.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Antworten