Adobe Experience Manager (AEM)-Pakete sind die heimlichen Helden des Content Managements – leistungsstarke Container, die alles von Code und Konfigurationen bis hin zu kritischen Inhalten bündeln. Aber seien wir ehrlich: Das manuelle Erstellen, Konfigurieren und Herunterladen dieser Pakete kann sich wie ein mühsames Klicken anfühlen.
Was wäre, wenn Sie diesen Vorgang mit wenigen Tastenanschlägen automatisieren könnten und so Konsistenz, Geschwindigkeit, Zuverlässigkeit und weniger Schwerstarbeit gewährleisten könnten?
Ich zeige Ihnen ein Bash-Skript, das das Skript (Wortspiel beabsichtigt!) umdreht, wie AEM-Entwickler und -Administratoren mit der Package Manager-API arbeiten. Stellen Sie sich vor, Sie können Pakete in Sekundenschnelle erstellen, Filter im Handumdrehen anpassen und Backups mit chirurgischer Präzision erstellen – und das alles, bevor Ihr Kaffee auf die perfekte Trinktemperatur abgekühlt ist. ☕
Bevor wir loslegen, eine kurze Anmerkung : Dieser Artikel ist ein tiefer Einblick, akribisch detailliert und kompromisslos technisch. Wir werden die Logik des Skripts analysieren, die Feinheiten der AEM-API untersuchen und Randfälle beheben. Entwickler, die sich gleich in den Code stürzen möchten, können zum Ende des Artikels springen. Aber wenn Sie hier sind, um das Wie und Warum hinter der Automatisierung zu verstehen, schnallen Sie sich an – wir gehen den ganzen Weg in den Kaninchenbau. 🕳️
Das Skript create-remote-aem-pkg.sh
automatisiert Interaktionen mit der Package Manager-API von AEM und bietet einen strukturierten Ansatz für die Paketerstellung, -konfiguration und -verteilung. Es wurde für Entwickler und Administratoren entwickelt und ersetzt manuelle Arbeitsabläufe durch einen befehlszeilengesteuerten Prozess, bei dem Konsistenz und Zuverlässigkeit im Vordergrund stehen.
/content/dam
, /apps
), die in das Paket aufgenommen werden sollen.curl
./etc
oder /apps
, bevor Sie Systemupdates anwenden. ./create-remote-aem-pkg.sh admin securepass123 localhost 4502 backup-group "Content Backup" /backups /content/dam /etc/clientlibs
Dieser Befehl erstellt ein Paket mit dem Namen „Content Backup“ unter der Gruppe backup-group
, einschließlich /content/dam
und /etc/clientlibs
, und speichert die Ausgabe im Verzeichnis /backups
.
Lassen Sie uns das Skript create-remote-aem-pkg.sh
(Sie finden es am Ende des Artikels) analysieren, um zu verstehen, wie es die AEM-Paketverwaltung orchestriert. Wir konzentrieren uns auf seine Struktur, seine wichtigsten Funktionen und seine Workflow-Logik – ideal für Entwickler, die das Tool anpassen oder debuggen möchten.
_log()
: Eine Hilfsfunktion, die Nachrichten Zeitstempel voranstellt, um Prüfpfade zu löschen. _log () { echo "[$(date +%Y.%m.%d-%H:%M:%S)] $1" }
Warum es wichtig ist : Stellt sicher, dass jede Aktion (z. B. „Paket erstellt“) mit Kontext protokolliert wird, was die Fehlerbehebung vereinfacht.
check_last_exec()
: Überprüft den Erfolg vorheriger Befehle durch Überprüfen der Exitcodes und API-Antworten. check_last_exec () { # Checks $? (exit status) and $CURL_OUTPUT for errors if [ "$status" -ne 0 ] || [[ $output =~ .*success\":false* ]]; then _log "Error detected!"; exit 1; fi }
Warum es wichtig ist : Verhindert stille Fehler, indem die Ausführung bei kritischen Fehlern wie Authentifizierungsproblemen oder ungültigen Pfaden angehalten wird.
Das Skript akzeptiert sieben Positionsargumente, gefolgt von dynamischen Filtern:
USR="$1" # AEM username PWD="$2" # AEM password SVR="$3" # Server host (eg, localhost) PORT="$4" # Port (eg, 4502) PKG_GROUP="$5" # Package group (eg, "backups") PKG_NAME="$6" # Package name (eg, "dam-backup") BK_FOLDER="$7" # Backup directory (eg, "/backups") shift 7 # Remaining arguments become filters (eg, "/content/dam")
Positionsargumente sorgen für Einfachheit, während shift
variable Filterpfade flexibel handhabt.
PKG_NAME
durch Unterstriche, um URL-Probleme zu vermeiden. PKG_NAME=${PKG_NAME// /_}
curl
, um Pakete über die API von AEM aufzulisten und so redundante Erstellungen zu vermeiden. if [ $(curl ... | grep "$PKG_NAME.zip" | wc -l) -eq 1 ]; then _log "Package exists—skipping creation." else curl -X POST ... # Creates the package fi
Erstellt ein JSON-Array von Filtern aus Eingabepfaden:
FILTERS_PARAM="" for i in "${!FILTERS[@]}"; do FILTERS_PARAM+="{\"root\": \"${FILTERS[$i]}\", \"rules\": []}" # Adds commas between entries, but not after the last done
Beispielausgabe :
[{"root": "/content/dam"}, {"root": "/apps"}]
Dieses JSON wird über den Endpunkt /crx/packmgr/update.jsp
von AEM in die Paketdefinition eingefügt.
build
-Befehl von AEM aus: curl -X POST … -F "cmd=build"
Hinweis : Das Skript wartet, bis der Build abgeschlossen ist, bevor es fortfährt.
curl
, um die .zip
abzurufen und mit einem mit Zeitstempel versehenen Dateinamen zu speichern: BK_FILE="$PKG_NAME-$(date +%Y%m%d-%H%M%S).zip" curl -o "$BK_FOLDER/$BK_FILE" ...
Robuste Fehlerbehandlung und -protokollierung sind für unbeaufsichtigte Skripte wie create-remote-aem-pkg.sh
von entscheidender Bedeutung, da sie sicherstellen, dass Fehler frühzeitig erkannt und klar protokolliert werden. So schützt das Skript vor unerwarteten Problemen und bietet umsetzbare Erkenntnisse.
_log
versieht jede Nachricht mit einem Zeitstempel vom [YYYY.MM.DD-HH:MM:SS]
und erstellt so einen Prüfpfad zur Fehlerbehebung: _log "Starting backup process..." # Output: [2023.10.25-14:30:45] Starting backup process...
Warum es wichtig ist : Zeitstempel helfen dabei, Skriptaktivitäten mit AEM-Serverprotokollen oder externen Ereignissen (z. B. Cron-Job-Zeitplänen) zu korrelieren.
Kontrollen vor dem Flug :
BK_FOLDER
), bevor fortgefahren wird: if [ ! -d "$BK_FOLDER" ]; then _log "Backup folder '$BK_FOLDER' does not exist!" && exit 1 fi
PKG_NAME
, um URL-Probleme zu vermeiden (z. B. werden Leerzeichen durch Unterstriche ersetzt).
Validierung der API-Antwort :
Die Funktion check_last_exec
untersucht sowohl Shell-Exitcodes ( $?
) als auch AEM-API-Antworten:
check_last_exec "Error message" "$CURL_OUTPUT" $CURL_STATUS
curl
-Netzwerkfehler) lösen sofortige Exits aus.
success\":false
“-JSON-Antworten oder „HTTP ERROR“-Zeichenfolgen in der AEM-Ausgabe.
3.3 HTTP-Statusüberprüfung : Beim Herunterladen des Pakets prüft das Skript, ob ein Statuscode 200
vorliegt:
if [ "$(curl -w "%{http_code}" ...)" -eq "200" ]; then # Proceed if download succeeds else _log "Error downloading the package!" && exit 1 fi
check_last_exec
fängt 401 Unauthorized
Antworten ab und wird mit einer eindeutigen Fehlermeldung beendet.success:false
zurück, das Skript protokolliert „Fehler beim Hinzufügen der Filter“ und wird beendet.BK_FILE
kann nicht geschrieben werden, Dateigröße wird mit Flag -s
geprüft und vor dem Beenden eine Warnung ausgegeben.curl
wird mit einem Code ungleich Null beendet, das Skript protokolliert „Fehler beim Erstellen des Pakets“.curl -k
, wodurch die SSL-Verifizierung übersprungen wird. Empfehlung für die Produktion : Ersetzen Sie es durch --cacert
um ein CA-Bundle anzugeben.
$AEM_PASSWORD
).set -x
hinzu, um ausgeführte Befehle auszudrucken.curl
-Befehle außerhalb des Skripts ausführen ./create-remote-aem-pkg.sh ... >> /var/log/aem_backup.log 2>&1
Das Skript create-remote-aem-pkg.sh
ist als Ausgangspunkt gedacht – eine Grundlage, die Sie an die Bedürfnisse Ihres Teams anpassen können. Im Folgenden finden Sie allgemeine Anpassungen sowie Implementierungshinweise, um die Funktionalität zu erweitern oder an bestimmte Anwendungsfälle anzupassen.
Der Standarddateiname verwendet einen Zeitstempel ( $PKG_NAME-$(date +%Y%m%d-%H%M%S).zip
). Ändern Sie dies, um Umgebungsnamen, Projekt-IDs oder semantische Versionierung einzuschließen:
# Example: Include environment (eg, "dev", "prod") BK_FILE="${PKG_NAME}-${ENV}-$(date +%Y%m%d).zip" # Example: Add Git commit SHA for traceability COMMIT_SHA=$(git rev-parse --short HEAD) BK_FILE="${PKG_NAME}-${COMMIT_SHA}.zip"
Tipp : Achten Sie darauf, dass in Datums-/Uhrzeitformaten keine in Dateinamen verbotenen Zeichen enthalten sind (z. B. Doppelpunkte :
unter Windows).
Das Skript akzeptiert dynamische Pfade als Filter, Sie können jedoch auch häufig verwendete Pfade fest codieren oder Ausschlüsse hinzufügen:
# Hardcode essential paths (eg, "/var/audit") DEFAULT_FILTERS=("/content/dam" "/apps" "/var/audit") FILTERS=("${DEFAULT_FILTERS[@]}" "${@}") # Merge with command-line inputs # Add exclusion rules (requires AEM API support) FILTERS_PARAM+="{\"root\": \"${FILTERS[$i]}\", \"rules\": [{\"modifier\": \"exclude\", \"pattern\": \".*/test/*\"}]}"
Vermeiden Sie Klartext-Passwörter :
Verwenden Sie Umgebungsvariablen oder einen Geheimnis-Manager, um Anmeldeinformationen einzufügen:
# Fetch password from environment variable PWD="$AEM_PASSWORD" # Use AWS Secrets Manager (example) PWD=$(aws secretsmanager get-secret-value --secret-id aem/prod/password --query SecretString --output text)
SSL-Validierung erzwingen :
Ersetzen Sie curl -k
(unsicher) durch ein vertrauenswürdiges CA-Zertifikat:
curl --cacert /path/to/ca-bundle.crt -u "$USR":"$PWD" ...
Erweitern Sie das Skript, um nach einem erfolgreichen Download nachgelagerte Prozesse auszulösen:
# Example: Upload to cloud storage aws s3 cp "$BK_FOLDER/$BK_FILE" s3://my-backup-bucket/ # Example: Validate package integrity CHECKSUM=$(sha256sum "$BK_FOLDER/$BK_FILE" | cut -d ' ' -f 1) _log "SHA-256 checksum: $CHECKSUM" # Example: Clean up old backups (retain last 7 days) find "$BK_FOLDER" -name "*.zip" -mtime +7 -exec rm {} \;
Benachrichtigen Sie Teams über Erfolg/Misserfolg per Slack, E-Mail oder Überwachungstools:
# Post to Slack on failure curl -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"🚨 AEM backup failed: $(hostname)\"}" \ https://hooks.slack.com/services/YOUR/WEBHOOK/URL # Send email via sendmail if [ $? -ne 0 ]; then echo "Subject: Backup Failed" | sendmail [email protected] fi
Die Verwaltung von AEM-Paketen muss keine manuelle, fehleranfällige Aufgabe sein. Mit dem Skript create-remote-aem-pkg.sh
können Sie die Paketerstellung, -filterung und -verteilung in einen optimierten, wiederholbaren Prozess umwandeln. Mit diesem Tool können Sie nicht nur Zeit sparen, sondern auch Konsistenz, Zuverlässigkeit und Skalierbarkeit in Ihren AEM-Vorgängen ermöglichen.
Automatisierung ist von Vorteil : Durch die Vermeidung sich wiederholender GUI-Interaktionen reduziert das Skript menschliche Fehler und gibt den Teams die Möglichkeit, sich auf Aufgaben mit höherem Stellenwert zu konzentrieren.
Flexibilität ist wichtig : Ob beim Sichern kritischer Inhalte, beim Synchronisieren von Umgebungen oder beim Vorbereiten von Updates – das Skript passt sich mit minimalen Anpassungen an verschiedene Anwendungsfälle an.
Ausfallsicherheit ist der Schlüssel : Integrierte Protokollierung, Fehlerprüfungen und Sicherheitsüberlegungen stellen sicher, dass sich das Skript vorhersehbar verhält, auch wenn etwas schiefgeht.
Großartige Tools entstehen aus Herausforderungen der realen Welt. Dieses Skript ist ein Ausgangspunkt; betrachten Sie es als Grundlage, auf der Sie aufbauen können, wenn die Anforderungen Ihres Teams wachsen. Egal, ob Sie ein Einzelentwickler oder Teil eines großen DevOps-Teams sind, eine Automatisierung wie diese zeigt, wie kleine Investitionen in Code zu enormen Produktivitätsgewinnen und mehr Sicherheit führen können.
Bereit für den nächsten Schritt?
Vielen Dank, dass Sie mitgemacht haben – jetzt machen Sie weiter und automatisieren Sie! 🚀
#!/bin/bash set -eo pipefail # The script will create a package thought the package manager api: # - The package is created, if not already present # - Package filters are populated accordingly to specified paths # - Package is builded # - Package is download to the specified folder _log () { echo "[$(date +%Y.%m.%d-%H:%M:%S)] $1" } check_last_exec () { local message="$1" local output="$2" local status=$3 if [ "$status" -ne 0 ]; then echo && echo "$message" && echo exit 1 fi if [[ $output =~ .*success\":false* ]] || [[ $output =~ .*"HTTP ERROR"* ]]; then _log "$message" exit 1 fi } USR="$1" PWD="$2" SVR="$3" PORT="$4" PKG_GROUP="$5" PKG_NAME="$6" BK_FOLDER="$7" shift 7 # The following paths will be included in the package FILTERS=($@) BK_FILE=$PKG_NAME"-"$(date +%Y%m%d-%H%M%S).zip _log "Starting backup process..." echo "AEM instance: '$SVR':'$PORT' AEM User: '$USR' Package group: $PKG_GROUP Package name: '$PKG_NAME' Destination folder: $BK_FOLDER Destination file: '$BK_FILE' Filter paths: " printf '\t%s\n\n' "${FILTERS[@]}" if [ ! -d "$BK_FOLDER" ]; then _log "Backup folder '$BK_FOLDER' does not exist!" && echo exit 1 fi PKG_NAME=${PKG_NAME// /_} check_last_exec "Error replacing white space chars from package name!" "" $? || exit 1 _log "Removed whitespaces from package name: '$PKG_NAME'" BK_FILE=$PKG_NAME.zip _log "Backup file: '$BK_FILE'" _log "Creating the package..." if [ $(curl -k -u "$USR":"$PWD" "$SVR:$PORT/crx/packmgr/service.jsp?cmd=ls" 2>/dev/null | grep "$PKG_NAME.zip" | wc -l) -eq 1 ]; then _log " Package '$PKG_GROUP/$PKG_NAME' is already present: skipping creation." else curl -k --silent -u "$USR":"$PWD" -X POST \ "$SVR:$PORT/crx/packmgr/service/.json/etc/packages/$PKG_GROUP/$PKG_NAME?cmd=create" \ -d packageName="$PKG_NAME" -d groupName="$PKG_GROUP" check_last_exec " Error creating the package!" "" $? _log " Package created" fi # create filters variable FILTERS_PARAM="" ARR_LEN="${#FILTERS[@]}" for i in "${!FILTERS[@]}"; do FILTERS_PARAM=$FILTERS_PARAM"{\"root\": \"${FILTERS[$i]}\", \"rules\": []}" T=$((i+1)) if [ $T -ne $ARR_LEN ]; then FILTERS_PARAM=$FILTERS_PARAM", " fi done # add filters _log "Adding filters to the package..." CURL_OUTPUT=$(curl -k --silent -u "$USR":"$PWD" -X POST "$SVR:$PORT/crx/packmgr/update.jsp" \ -F path=/etc/packages/"$PKG_GROUP"/"$PKG_NAME".zip -F packageName="$PKG_NAME" \ -F groupName="$PKG_GROUP" \ -F filter="[$FILTERS_PARAM]" \ -F "_charset_=UTF-8") CURL_STATUS=$? # Pass the status to the check_last_exec function check_last_exec "Error adding filters to the package!" "$CURL_OUTPUT" $CURL_STATUS _log " Package filters updated successfully." # build package _log "Building the package..." CURL_OUTPUT=$(curl -k -u "$USR":"$PWD" -X POST \ "$SVR:$PORT/crx/packmgr/service/script.html/etc/packages/$PKG_GROUP/$PKG_NAME.zip" \ -F "cmd=build") check_last_exec " Error building the package!" "$CURL_OUTPUT" $? _log " Package built." # download package _log "Downloading the package..." if [ "$(curl -w "%{http_code}" -o "$BK_FOLDER/$BK_FILE" -k --silent -u "$USR":"$PWD" "$SVR:$PORT/etc/packages/$PKG_GROUP/$PKG_NAME.zip")" -eq "200" ]; then if [ -f "$BK_FOLDER/$BK_FILE" ] && [ -s "$BK_FOLDER/$BK_FILE" ]; then _log " Package $BK_FILE downloaded in $BK_FOLDER." exit 0 fi fi _log " Error downloading the package!" exit 1
[¹] Das Überspringen der SSL-Verifizierung mit curl -k
ist für Tests praktisch, aber in der Produktion werden Sie etwas Robusteres wollen (zum Beispiel --cacert
)!