Das ist eine für den Ausdruck optimierte Ansicht des gesamten Kapitels inkl. Unterseiten. Druckvorgang starten.

Zur Standardansicht zurückkehren.

Script API

Referenz der Script API

Script API

Der NOREYA REPO MEISTER verfügt über eine API mit der belibige Scriptsprachen ausgeführt werden können.

Dazu können z.b: Python, Bash oder Perl verwendet werden.

1.1) Pfad für Scripte

Der Standardpfad für Scripte ist /var/lib/deb-repo-diff/scripts.

Scripte können dort unter einem beliebigen Name abgelegt werden und werden einfach sortiert nach einander ausgeführt.

1.2) Umgebungsbedingungen

1.2.1) Sicherheitskontext

Die Scripte werden im Kontext des repo-sync.service ausgeführt.
Dies bedeutet das diese stark eingeschränkte Berechtigungen haben.

Der Benutzer/Gruppen Kontext ist debrepo:www-data.
Schreibzugriff ist nur auf die Verzeichnisse /srv und /var möglich.

Es wird empfohlen vom Script aus über Netzwerkschnittstellen wie HTTP/TCP/UDS zu interagieren.

Schlägt die Ausführung eines Scripts fehl wird mit dem nächsten Script fortgefahren.
Auch die weitere Ausführung des repo-sync.service wird nicht beeinträchtigt.

Der repo-sync.service beendet allerdings mit einem Fehlercode.

1.2.1) Header

Das Script muss über einen gültigen Shebang Header verfügen um ausgeführt zu werden.
z.B:
Bash:

                #!/bin/bash -e

oder Python:

                #!/usr/bin/python3

1.2.1) Umgebungsvariabeln

Alle Umgebungsvariablen werden als Strings übergeben.

Umgebungsvariable Bescheibung Mögliche WErte
REPO_NAME “display_name” des Repos e.g: “debian-12”
REPO_UID “uid” des Repos e.g: “3”
SUCCESS Script erfolgreich oder nicht “TRUE” oder “FALSE” im Fehlerfall
NEW_PKGS_JSON_PATH_V1 Pfad zu einer JSON Datei die die neuen Pakete enthält e.g: /tmp/repo-changes-fe51afbf-0e3b-4a65-8f35-79d8af8d8842.json
NEW_PKGS_YAML_PATH_V1 Pfad zu einer YAML Datei die die neuen Pakete enthält e.g: /tmp/repo-changes-fe51afbf-0e3b-4a65-8f35-79d8af8d8842.yaml

Im Fehlerfall enthalten die NEW_PKGS_* Dateien leere Listen und sollten nicht gelesen werden.

Der Beispielhafe Inhalt eine YAML Datei ist:

                repo_name: debian-security-10/11-arm/amd64
repo_uid: 5
only_watched: false
releases:
- name: bullseye-security
  new_packages:
  - name: php7.4
    version: 7.4.33-1+deb11u7
    sub_packages:
    - name: libapache2-mod-php7.4
      version: 7.4.33-1+deb11u7
      arch: arm64
    - name: libaache2-mpod-php7.4
      version: 7.4.33-1+deb11u7
      arch: amd64
    - name: php7.4-xsl
      version: 7.4.33-1+deb11u7
      arch: all
    #...
- name: bookworm-security
  new_packages: []

Die JSON Datei ist exakt gleich aufgebaut.

Die Struktur entspricht dem Repo Aufbau.
Sind in einem Release keine neuen Pakete ist die entsprechende List leer.
Die Pakete sind nach ihrem Source Namen gruppiert.
Die sub_packages beschreiben die tatsächlich installierbaren Pakete.
Die arch gibt die Architektur an.
Die only_watched ist true wenn eine [watchlist gesetzt ist und der flag TODO].

1.2.2) Kompatibilität

Das Schema der NEW_PKGS_*_PATH_V1 Daten ist garantiert.
Es ist jedoch möglich das neue Felder hinzugefügt werden.
Dies muss vom Script berücksichtigt werden!

Neue Schemas werden unter NEW_PKGS_*_PATH_V2/V3... bereitgestellt.

1.3) Ausführungszeiten

Die Scripte werden, nach dem alle Repos synchronisiert, wurden ausgeführt vom repo-sync.service.
Die Ausführung erfolgt pro Repo und Script.
e.g:

                repo: debian-11 script: 01_notify.py  
repo: debian-11 script: 02_notify.sh  
repo: debian-12 script: 01_notify.py  
repo: debian-12 script: 02_notify.sh  

2) Nutzungsbeispiele

Die Script API kann genutzt werden um direkt nach der Synchronisierung Ereignisse oder Meldungen auszulösen.
Typische Beispiele sind:

  • Versenden von Emails/Messenger Nachrichten
  • Starten von Test-Pipelines im CI System

TODO: Kopieren Beispielscript von Verzeichniss

Ein Python Script welches Emails versendet findet sich hier:
Es ist notwendig folgendes Systempaket zu installieren apt install python3-yaml.

                #!/usr/bin/python3

import os
import json
import yaml # apt install python3-yaml
import smtplib
import socket
import ssl
from email.message import EmailMessage
from email.utils import formatdate
from pathlib import Path

def send_mail(subject, msg):
    try:
        if not EMAIL_PASSWORD:
            print("No email password set")
            exit(1)
        if len(str(msg)) > 1_000_000:  # ~1MiB
            msg = msg[:1_000_000] + '\n Message truncated here...'

        email = EmailMessage()
        email['Subject'] = subject
        email['From'] = EMAIL_SENDER
        email['To'] = EMAIL_RECEIVER
        email['Date'] = formatdate(localtime=True)
        email.set_content(str(msg))

        context = ssl.create_default_context()
        with smtplib.SMTP(EMAIL_SMTP_SRV, EMAIL_PORT, timeout=60) as server:
            server.starttls(context=context)
            server.login(EMAIL_SENDER, EMAIL_PASSWORD)
            server.sendmail(EMAIL_SENDER, EMAIL_RECEIVER, email.as_string())
            print('Sending mail done!')
    except Exception as ex:
        print('Failed sending mail: ' + str(ex))

if __name__ == '__main__':
    try:
        print("Script executing")
        SEND_JSON_MAIL = False
        SEND_YAML_MAIL = True
        EMAIL_PORT = 587  # For starttls
        EMAIL_SMTP_SRV = "mail.example.com"
        EMAIL_SENDER = "updates@example.com"
        EMAIL_RECEIVER = "user@example.com"
        EMAIL_PASSWORD = Path("/var/lib/deb-repo-diff/passwd").read_text().strip("\n").strip()
        
        PREFIX = "[" + str(socket.gethostname()) + "] "
        repo_name = "Unknown"
        repo_uid = ""
        if os.getenv("REPO_NAME"):
            repo_name = os.getenv("REPO_NAME")

        if os.getenv("REPO_UID"):
            repo_uid = os.getenv("REPO_UID")

        if os.getenv("SUCCESS") == "FALSE":
            send_mail(PREFIX + "Failed to sync repo '" + repo_name + "' (" + repo_uid + ")", "Check the server log for errors!")
            exit(0)
        elif os.getenv("SUCCESS") == "TRUE":
            pass
        else:
            raise RuntimeError("SUCCESS env variable has invalid value!")

        print("Processing JSON")
        changes_json = os.getenv("NEW_PKGS_JSON_PATH_V1")
        if changes_json:
            changes = json.loads(Path(changes_json).read_text())
            subject = PREFIX + "Updates for repo"
            if changes["repo_name"]:
                subject = (PREFIX + "Updates for repo '" + repo_name + "' (" + repo_uid + ")")

            for release in changes["releases"]:
                for new_pkg in release["new_packages"]:
                    del new_pkg["sub_packages"] # Simplify the view by removing the sub_packages
            if SEND_JSON_MAIL:
                send_mail(subject, str(json.dumps(changes, indent=4)))
        else:
            raise RuntimeError("No NEW_PKGS_JSON_PATH_V1 set")

        print("Processing YAML")
        changes_yaml = os.getenv("NEW_PKGS_YAML_PATH_V1")
        if changes_yaml:
            changes_yaml = Path(changes_yaml).read_text()
            changes = yaml.safe_load(changes_yaml)

            for release in changes["releases"]:
                for new_pkg in release["new_packages"]:
                    del new_pkg["sub_packages"] # Simplify the view by removing the sub_packages
            if SEND_YAML_MAIL:
                send_mail(PREFIX + "Updates for repo '" + repo_name + "' (" + repo_uid + ")", yaml.safe_dump(changes, indent=4))
        else:
            raise RuntimeError("No NEW_PKGS_YAML_PATH_V1 set")
        exit(0)
    except Exception as ex:
        print("Script failed: " + str(ex), flush=True)
        exit(1)