Skip to content

Python3 - Popen und seine Geheimnisse ;)

Python3
1 1 232
  • Eine der letzten Baustellen in meinem Tool Restic UI war die Funktion zum Mounten eines Restic Backups.

    Das größte Problem dabei war, das dieser Prozess nicht beendet wird sonder offen bleibt. Das kennt ihr, wenn ihr das schon mal über die Konsole gemacht habt, dann erscheint das folgende

    reading repository password from stdin
    repository 6859cd64 opened successfully, password is correct
    Now serving the repository at /home/frank/m5
    When finished, quit with Ctrl-c or umount the mountpoint.
    

    Jetzt kann man in meinem Tool das Passwort mittlerweile abspeichern oder wahlweise auch jedes mal eingeben. Aber, was mache ich wenn das Passwort falsch eingegeben wurde? Ich habe tagelang versucht, die Fehler abzufangen, das geht aber meiner Meinung nach nicht, da der Prozess am Laufen ist. Was machen?

    Ich habe so ziemlich jede Seite im Netz zum Thema Popen durch 😉 Nichts davon brachten den gewünschten Erfolg.

    Ok, fangen wir von vorne an, was sagt die Dokumentation von Restic?

    EXIT STATUS
    ===========
    
    Exit status is 0 if the command was successful, and non-zero if there was any error.
    

    Gut, wenn ich den richtigen Fehlercode nicht abfangen kann, dann kann ich evt. ermitteln ob der Prozess läuft oder einen Fehler ausgibt. Das würde mir zu mindestens helfen, den User zu informieren.

    Bei den hunderten von Webseiten, hatte ich irgendwo was über p.poll() aufgeschnappt. Das steht in der Python Dokumentation.

    Popen.poll()

    Check if child process has terminated. Set and return returncode attribute. Otherwise, returns None.
    

    Das sollte für meinen Zweck ausreichend sein. Erster Versuch

    # no passwd in backup_data? Ok, we ask for one
    if len(backup_data[row].password) == 0:
        pwd = get_password(self) ## pwd ('1234', True)
        if pwd[1] is False:
            return False
    
    try:
        cmd = ['restic',
                                        '-r',
                                        backup_data[row].repository,
                                        'mount',
                                        mount_path]
        
       
        # We create the object, here with stdin and open the asynchronous subprocess
        p1 = subprocess.Popen(cmd,stdin=subprocess.PIPE,stderr=subprocess.PIPE) 
        p1.stdin.write(pwd[0].encode()))
        p1.stdin.close()
    
    except Exception:
        pass
    
    finally:
        try:
            if p1.poll() == 1:                          
                 raise Exception("The Restic mount command was not successful. Probable cause: wrong password or no key found")
            else:
                msg_box(self, "Successful mount of the Repository!")    
        except Exception as e:
            msg_box_error(self, repr(e))
    

    Ich hoffe man versteht was ich hier mache.

    • Wir holen uns das Passort über eine Usereingabe
    • Wir bauen den Restic Befehl cmd
    • Wir starten den subprocess.Popen
    • Wir senden das Passwort auf stdin
    • Wir schließen stdin
    • In finally machen wir den p1.poll() und werten diesen aus.

    Bei den vielen, vielen, super vielen Test war mir aufgefallen, das das klappte.

    p1.poll() gab einmal None aus und einmal eine 1

    None war ein laufender Prozess, also erfolgreich gemountet.
    Eine 1 war ein Fehler, hier falsche Passwort Eingabe.

    Nach einigen weiteren Tests, ging es auf einmal nicht mehr. Ich wusste aber ganz genau, das es ging, ich konnte das in der Konsole noch lesen. Also meine Kontrollausgaben. Was war passiert. Eine halbe Stunde Grübeln und ich kam zu der Überzeugung, das muss ein Zeitproblem sein. Ok, also eine Bremse 🙂 einbauen. Im finally vor dem try kommt das rein.

    print("POLL", p1.poll()) 
    import time
    time.sleep(1.0)
    

    Kleine Kontrollausgabe, wir importieren das Modul time (ja, gehört nicht an diese Stelle, ich weiß...) und dann lassen wir den Prozess 1 Sekunde pausieren. Wir geben hier jetzt dem subprocess die Gelegenheit, das falsche Passwort zu erkennen und den richtigen Exit Status zu setzen. Und Bingo es ging so wie ich es mir vorgestellt hatte. 🤓

    Wieder extrem viel gelernt.

    Hinweis

    Der Code oben ist nur ein Ausschnitt, ich hoffe das er nachvollziehbar ist. Wenn nicht einfach hier drunter kommentieren, es gibt das dann in lang 😉

    Für Profis, die evt. hier mal drüber stolpern. Ich nehme jede Verbesserung gerne auf und probiere es auch aus.

    Wünsche mir eigentlich immer noch, das ich die Ausgabe

    Fatal: wrong password or no key found
    

    vernünftig abfangen und weiterverarbeiten kann. So wie mit

    output = process.stdout
    

    bei einem subprocess.run.

  • Forgejo Installation mit Restic nach Hetzner S3 sichern

    Verschoben Forgejo restic linux forgejo
    2
    2
    0 Stimmen
    2 Beiträge
    361 Aufrufe
    FrankMF
    Ich habe ja im obigen Beispiel, den gesamten Ordner von der Postgres Installation gesichert. backup_pfad_postgres="/home/pguser/db-data" Ich habe dann mal ein wenig in der Dokumentation gelesen und das hier gefunden. https://www.postgresql.org/docs/current/app-pgdump.html Einfach den Ordner zu sichern, ist ja bei jeder Datenbank ein gewisses Risiko. Die Konsistenz der Daten ist nicht gesichert. Darum gibt es bei den Datenbanken auch immer Tools, mit denen man die Daten sichern kann. In der Doku steht folgendes. pg_dump — extract a PostgreSQL database into a script file or other archive file Aber wichtiger ist das hier. pg_dump is a utility for backing up a PostgreSQL database. It makes consistent backups even if the database is being used concurrently. pg_dump does not block other users accessing the database (readers or writers). Das macht also konsistente Backups. Wichtig noch zu wissen ist folgendes. pg_dump only dumps a single database. To back up an entire cluster, or to back up global objects that are common to all databases in a cluster (such as roles and tablespaces), use pg_dumpall. Ok, das scheint gut geeignet zu sein, um die Datenbank zu sichern. Aber, wie? Auf meinen Eingangsbeitrag kam es zu folgendem Dialog auf Mastodon. https://nrw.social/deck/@nebucatnetzer@social.linux.pizza/114132208440509237 Das war der Anstoß sich mit dem Thema zu beschäftigen. Und ich hatte dann folgende Lösung. podman exec -it postgres pg_dump -U postgres -f /var/lib/postgresql/data/dump.txt Ok, was mache ich hier? Wir führen einen Befehl vom Host aus gesehen, im Container aus. podman exec -it postgres Der Teil führt den folgenden Befehl im Container aus. pg_dump -U postgres -f /var/lib/postgresql/data/dump.txt pg_dump - Das Tool fürs Backup -U postgres - Der Befehl wird als User postgres ausgeführt -f /var/lib/postgresql/data/dump.txt - Das Dump File wird im Data Ordner abgelegt, den haben wir ja persistent auf dem Host. Somit kann ich das jetzt einfach in mein Backup Script einbauen und brauchen nicht mehr den ganzen Ordner zu kopieren, sondern nur noch das Dump File. Ich werde diese Änderungen in das obige Script einbauen.
  • Restic feiert 10. Geburtstag

    Restic restic linux
    1
    1
    0 Stimmen
    1 Beiträge
    187 Aufrufe
    Niemand hat geantwortet
  • ResticUI with PyWebIO - Repo

    PyWebIO pywebio python restic-ui
    1
    0 Stimmen
    1 Beiträge
    135 Aufrufe
    Niemand hat geantwortet
  • Restic - Migrate

    Restic restic restic-ui
    1
    2
    0 Stimmen
    1 Beiträge
    280 Aufrufe
    Niemand hat geantwortet
  • PyQt6 - QRegularExpressionValidator

    Python3 pyqt6 python3
    1
    0 Stimmen
    1 Beiträge
    677 Aufrufe
    Niemand hat geantwortet
  • Python3 - HTML Text ausgeben

    Python3 python3
    1
    0 Stimmen
    1 Beiträge
    186 Aufrufe
    Niemand hat geantwortet
  • checkmk - Rest-Server überwachen

    Verschoben checkmk checkmk linux restic
    1
    3
    0 Stimmen
    1 Beiträge
    727 Aufrufe
    Niemand hat geantwortet
  • Python3 - QSettings

    Python3 python3
    1
    0 Stimmen
    1 Beiträge
    193 Aufrufe
    Niemand hat geantwortet