Webapp-Mechanismus (Phase 2): neue Rolle webapp-shortcuts
Kundeneigene URLs (workspace_webapps, siehe admin/provisioning-server) werden als .desktop-Menueintrag (/usr/share/applications) UND best-effort als Desktop-Icon ausgeliefert - kein present/absent pro Eintrag wie sonst im Katalog, sondern ein echter ABGLEICH: die Rolle bekommt bei jedem Lauf die komplette aktuelle Liste und sorgt dafuer, dass GENAU diese Eintraege existieren (Datei-Identifikation ueber die stabile DB-UUID, keine Namens-Slugifizierung noetig). Laeuft deshalb IMMER (site.yml-Play-Var tuxflotte_webapps, agent.py haengt sie immer in --tags ein, siehe admin/provisioning-agent), nicht nur bei Aenderungen. Desktop-Icon-Ablage bewusst pragmatisch: /etc/skel/Desktop (kuenftige Nutzer) + bestehende /home/*/Desktop-Ordner, falls schon vorhanden - kein erzwungenes Anlegen. Haengt an der noch offenen ADR-0026 (kein final festgelegter primaerer interaktiver Nutzer-Account) - deckt ab, was heute real existiert (z.B. den 'gast'-Account aus guest-session), ohne auf die endgueltige Klaerung zu warten. ECHT END-ZU-ENDE GETESTET (nicht nur Syntax-Check): echter ansible-playbook-Lauf gegen localhost mit Mock-Daten - Anlegen (mit+ohne Favicon), Aktualisieren, vollstaendiges Entfernen bei leerer Liste, Idempotenz. Favicon-Download-Pfad mit echter URL verifiziert. ansible-core dafuer neu installiert (vorher nicht vorhanden). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VLk93dhDMrkPXefVdknMV9
This commit is contained in:
1 parent
0f452c44ec
commit
e4edcf1011
4 files changed
+169
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
tuxflotte_webapps: []
|
||||||
|
tuxflotte_webapp_icons_dir: /usr/local/share/icons/tuxflotte-webapps
|
||||||
|
tuxflotte_webapp_applications_dir: /usr/share/applications
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
# Webapp-Mechanismus (Phase 2, 09.09.2026): kundeneigene URLs (kein fester
|
||||||
|
# Katalog-Merkmal wie sonst im Auftragskatalog - jeder Workspace hat seine
|
||||||
|
# eigene, freie Liste, siehe fetch_workspace_webapps() in
|
||||||
|
# provisioning-server/app.py). Deshalb kein present/absent pro Eintrag wie
|
||||||
|
# bei den anderen Rollen, sondern ein ECHTER ABGLEICH: die Rolle bekommt bei
|
||||||
|
# jedem Lauf die komplette aktuelle Liste (tuxflotte_webapps) und sorgt
|
||||||
|
# dafür, dass GENAU diese Einträge existieren - alles andere (frühere,
|
||||||
|
# inzwischen entfernte Webapps) wird aufgeräumt. Läuft deshalb bei jedem
|
||||||
|
# ansible-pull IMMER (siehe agent.py apply_roles()), nicht nur wenn sich
|
||||||
|
# etwas geändert hat.
|
||||||
|
#
|
||||||
|
# Dateibenennung nutzt die stabile UUID aus der DB (item.id), keine
|
||||||
|
# Slugifizierung des Namens nötig - vermeidet Kollisionen/Sonderzeichen-
|
||||||
|
# Probleme bei Namensänderungen.
|
||||||
|
|
||||||
|
- name: Ensure marker directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /run/tuxflotte/agent/applied
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Ensure icon and applications directories exist
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
loop:
|
||||||
|
- "{{ tuxflotte_webapp_icons_dir }}"
|
||||||
|
- "{{ tuxflotte_webapp_applications_dir }}"
|
||||||
|
- /etc/skel/Desktop
|
||||||
|
|
||||||
|
- name: Find existing tuxflotte-webapp .desktop files
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: "{{ tuxflotte_webapp_applications_dir }}"
|
||||||
|
patterns: "tuxflotte-webapp-*.desktop"
|
||||||
|
register: tuxflotte_webapp_existing_files
|
||||||
|
|
||||||
|
- name: Desired vs. vorhandene .desktop-Pfade ermitteln
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
tuxflotte_webapp_desired_files: >-
|
||||||
|
{{
|
||||||
|
tuxflotte_webapps
|
||||||
|
| map(attribute='id')
|
||||||
|
| map('regex_replace', '^(.*)$', tuxflotte_webapp_applications_dir ~ '/tuxflotte-webapp-\1.desktop')
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
tuxflotte_webapp_existing_paths: "{{ tuxflotte_webapp_existing_files.files | map(attribute='path') | list }}"
|
||||||
|
|
||||||
|
- name: Stale-Dateien (nicht mehr in der aktuellen Liste) berechnen
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
tuxflotte_webapp_stale_files: "{{ tuxflotte_webapp_existing_paths | difference(tuxflotte_webapp_desired_files) }}"
|
||||||
|
|
||||||
|
- name: Remove stale webapp .desktop files (nicht mehr in der aktuellen Liste)
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ tuxflotte_webapp_stale_files }}"
|
||||||
|
|
||||||
|
- name: Download favicon for each webapp (falls vorhanden)
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "{{ item.icon_url }}"
|
||||||
|
dest: "{{ tuxflotte_webapp_icons_dir }}/{{ item.icon_url | basename }}"
|
||||||
|
mode: "0644"
|
||||||
|
timeout: 10
|
||||||
|
loop: "{{ tuxflotte_webapps }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.name }}"
|
||||||
|
when: item.icon_url is not none
|
||||||
|
# Best-effort: ein einzelnes nicht erreichbares Favicon (Seite down,
|
||||||
|
# Netzwerkproblem auf dem Geraet) soll nicht den ganzen Lauf abbrechen -
|
||||||
|
# der .desktop-Eintrag selbst wird trotzdem angelegt (Icon zeigt dann
|
||||||
|
# kurzzeitig auf eine fehlende Datei, GTK faellt auf ein Platzhalter-Icon
|
||||||
|
# zurueck, kein Absturz).
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Create/update .desktop menu entry for each webapp
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: webapp.desktop.j2
|
||||||
|
dest: "{{ tuxflotte_webapp_applications_dir }}/tuxflotte-webapp-{{ item.id }}.desktop"
|
||||||
|
mode: "0644"
|
||||||
|
loop: "{{ tuxflotte_webapps }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.name }}"
|
||||||
|
|
||||||
|
- name: Copy .desktop entries into /etc/skel/Desktop (für künftig neu angelegte Nutzer)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ tuxflotte_webapp_applications_dir }}/tuxflotte-webapp-{{ item.id }}.desktop"
|
||||||
|
dest: "/etc/skel/Desktop/tuxflotte-webapp-{{ item.id }}.desktop"
|
||||||
|
mode: "0755"
|
||||||
|
remote_src: true
|
||||||
|
loop: "{{ tuxflotte_webapps }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.name }}"
|
||||||
|
|
||||||
|
- name: Remove stale .desktop entries from /etc/skel/Desktop
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/etc/skel/Desktop/{{ item | basename }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ tuxflotte_webapp_stale_files }}"
|
||||||
|
|
||||||
|
# Bestehende Nutzer-Homeverzeichnisse (z.B. der "gast"-Account aus der
|
||||||
|
# guest-session-Rolle, falls aktiv): nur befüllen, wenn dort bereits ein
|
||||||
|
# Desktop-Ordner existiert (kein aufgezwungenes Anlegen für Nutzer, deren
|
||||||
|
# Desktop-Umgebung keine Desktop-Icons zeigt). ADR-0026 (kein primärer
|
||||||
|
# interaktiver Nutzer-Account bisher final festgelegt) ist hier eine
|
||||||
|
# bekannte offene Abhängigkeit - dieser bewusst pragmatische Ansatz deckt
|
||||||
|
# ab, was heute an Accounts real existiert, ohne auf die endgültige
|
||||||
|
# Klärung zu warten. Siehe project_phase2_app_store_merkmale-Memory.
|
||||||
|
- name: Bestehende Nutzer-Homeverzeichnisse mit Desktop-Ordner ermitteln
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: /home
|
||||||
|
file_type: directory
|
||||||
|
patterns: "Desktop"
|
||||||
|
recurse: true
|
||||||
|
depth: 2
|
||||||
|
register: tuxflotte_webapp_user_desktops
|
||||||
|
|
||||||
|
- name: .desktop-Einträge in bestehende Nutzer-Desktop-Ordner kopieren
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ tuxflotte_webapp_applications_dir }}/tuxflotte-webapp-{{ item.0.id }}.desktop"
|
||||||
|
dest: "{{ item.1.path }}/tuxflotte-webapp-{{ item.0.id }}.desktop"
|
||||||
|
mode: "0755"
|
||||||
|
remote_src: true
|
||||||
|
loop: "{{ tuxflotte_webapps | product(tuxflotte_webapp_user_desktops.files) | list }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.0.name }} -> {{ item.1.path }}"
|
||||||
|
|
||||||
|
- name: Überzählige .desktop-Einträge aus bestehenden Nutzer-Desktop-Ordnern entfernen
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item.1.path }}/{{ item.0 | basename }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ tuxflotte_webapp_stale_files | product(tuxflotte_webapp_user_desktops.files) | list }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.0 }} -> {{ item.1.path }}"
|
||||||
|
|
||||||
|
- name: Record that the webapp-shortcuts role ran
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /run/tuxflotte/agent/applied/webapp-shortcuts.marker
|
||||||
|
content: "{{ ansible_date_time.iso8601 }}: {{ tuxflotte_webapps | length }} webapp(s)\n"
|
||||||
|
mode: "0644"
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name={{ item.name }}
|
||||||
|
Comment=Tuxflotte-Webapp: {{ item.url }}
|
||||||
|
Exec=xdg-open {{ item.url }}
|
||||||
|
{% if item.icon_url %}
|
||||||
|
Icon={{ tuxflotte_webapp_icons_dir }}/{{ item.icon_url | basename }}
|
||||||
|
{% else %}
|
||||||
|
Icon=web-browser
|
||||||
|
{% endif %}
|
||||||
|
Terminal=false
|
||||||
|
Categories=Network;WebBrowser;
|
||||||
|
NoDisplay=false
|
||||||
@@ -11,6 +11,11 @@
|
|||||||
# z.B. {"standardbrowser": true} bei brave. Rein additiv, opak für den
|
# z.B. {"standardbrowser": true} bei brave. Rein additiv, opak für den
|
||||||
# Server/Agenten - nur die jeweilige Rolle kennt die Bedeutung.
|
# Server/Agenten - nur die jeweilige Rolle kennt die Bedeutung.
|
||||||
tuxflotte_auftrag_optionen: {}
|
tuxflotte_auftrag_optionen: {}
|
||||||
|
# Vom Agenten per --extra-vars gesetzt (Check-in-Response "webapps",
|
||||||
|
# Phase 2 09.09.2026): Liste kundeneigener {id, name, url, icon_url}-
|
||||||
|
# Einträge, verarbeitet ausschließlich von der webapp-shortcuts-Rolle
|
||||||
|
# (siehe dort) - kein present/absent-Merkmal wie der Rest dieser Datei.
|
||||||
|
tuxflotte_webapps: []
|
||||||
tasks:
|
tasks:
|
||||||
- include_role:
|
- include_role:
|
||||||
name: guest-session
|
name: guest-session
|
||||||
@@ -362,3 +367,11 @@
|
|||||||
tuxflotte_state: "{{ tuxflotte_auftrag_states.get('turbowarp', 'present') }}"
|
tuxflotte_state: "{{ tuxflotte_auftrag_states.get('turbowarp', 'present') }}"
|
||||||
tuxflotte_optionen: "{{ tuxflotte_auftrag_optionen.get('turbowarp', {}) }}"
|
tuxflotte_optionen: "{{ tuxflotte_auftrag_optionen.get('turbowarp', {}) }}"
|
||||||
tags: turbowarp
|
tags: turbowarp
|
||||||
|
|
||||||
|
- include_role:
|
||||||
|
name: webapp-shortcuts
|
||||||
|
apply:
|
||||||
|
tags: webapp-shortcuts
|
||||||
|
vars:
|
||||||
|
tuxflotte_webapps: "{{ tuxflotte_webapps }}"
|
||||||
|
tags: webapp-shortcuts
|
||||||
Reference in new issue
Block a user