<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Ansible on private Homepage von Rainer Rose</title>
    <link>https://www.rainerrose.de/tags/ansible/</link>
    <description>Recent content in Ansible on private Homepage von Rainer Rose</description>
    <generator>Hugo</generator>
    <language>de</language>
    <copyright>Copyright © 1998-2026 Rainer Rose. All Rights Reserved.
</copyright>
    <lastBuildDate>Thu, 08 May 2025 21:26:11 +0200</lastBuildDate><atom:link href="https://www.rainerrose.de/tags/ansible/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Ansible: source not found</title>
      <link>https://www.rainerrose.de/posts/2025/ansible-source-not-found/</link>
      <pubDate>Thu, 08 May 2025 21:26:11 +0200</pubDate>
      <guid>https://www.rainerrose.de/posts/2025/ansible-source-not-found/</guid>
      <description><![CDATA[<!-- Anreißer -->
<p>Vor ein paar Tagen habe ich mal wieder an einer <code>Ansible</code>-Rolle geschraubt und wurde beim Ausführen von <code>ansible-playbook</code> mit folgender Fehlermeldung begrüßt:</p>
<pre><code>Source /root/.ansible/tmp/ansible-tmp-1746359478.4110813-9236-74562322926004/.source not found
</code></pre>
<p>Das war seltsam, weil ich nur das Modul <code>ansible.builtin.copy</code> aufgerufen hatte, was vorher auf anderen Rechner problemlos funktioniert hatte.</p>
<p>Und jetzt?</p>]]></description>
      <content:encoded><![CDATA[<!-- Anreißer -->
<p>Vor ein paar Tagen habe ich mal wieder an einer <code>Ansible</code>-Rolle geschraubt und wurde beim Ausführen von <code>ansible-playbook</code> mit folgender Fehlermeldung begrüßt:</p>
<pre><code>Source /root/.ansible/tmp/ansible-tmp-1746359478.4110813-9236-74562322926004/.source not found
</code></pre>
<p>Das war seltsam, weil ich nur das Modul <code>ansible.builtin.copy</code> aufgerufen hatte, was vorher auf anderen Rechner problemlos funktioniert hatte.</p>
<p>Und jetzt?</p>

<h2 id="die-fehlermeldung" data-numberify>Die Fehlermeldung<a class="anchor ms-1" href="#die-fehlermeldung"></a></h2>
<pre><code>TASK [meine_rolle : inst | linux_install | Copy Binaries] *************************************************************************************************************************************************************************************************
failed: [t24] (item=/pfad/zur/datei/foo) =&gt; {&quot;ansible_loop_var&quot;: &quot;item&quot;, &quot;changed&quot;: false, &quot;checksum&quot;: &quot;884109935b2a432cb6edb5003c4ac5adc9462cbe&quot;, &quot;item&quot;: &quot;/pfad/zur/datei/foo&quot;, &quot;msg&quot;: &quot;Source /root/.ansible/tmp/ansible-tmp-1746359476.4233594-9236-186673184030632/.source not found&quot;}
failed: [t24] (item=/pfad/zur/datei/bar) =&gt; {&quot;ansible_loop_var&quot;: &quot;item&quot;, &quot;changed&quot;: false, &quot;checksum&quot;: &quot;9e184000b3f2541c07f62dcbf8bf7e8927757bec&quot;, &quot;item&quot;: &quot;/pfad/zur/datei/bar&quot;, &quot;msg&quot;: &quot;Source /root/.ansible/tmp/ansible-tmp-1746359478.4110813-9236-74562322926004/.source not found&quot;}
</code></pre>

<h2 id="die-task" data-numberify>Die Task<a class="anchor ms-1" href="#die-task"></a></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">inst | linux_install | Copy Binaries</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">ansible.builtin.copy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="nt">src</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;{{ item }}&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span><span class="nt">dest</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;{{ meine_rolle_install_path }}&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="nt">owner</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;root&#39;</span><span class="w"> 
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">group</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;root&#39;</span><span class="w"> 
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="nt">mode</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;0755&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">  </span><span class="nt">become</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">  </span><span class="nt">loop</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span>- <span class="s1">&#39;/pfad/zur/datei/foo&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span>- <span class="s1">&#39;/pfad/zur/datei/bar&#39;</span><span class="w">
</span></span></span></code></pre></div>
<h2 id="das-problem" data-numberify>Das Problem<a class="anchor ms-1" href="#das-problem"></a></h2>
<p>Ich bin per <code>ssh</code> auf die betroffene Maschine gesprungen und musste feststellen, dass das Verzeichnis <code>/root/.ansible/tmp/</code> auf der Remote-Maschine wirklich nicht da war. Auch wurde das <code>/root</code> Verzeichnis (meiner Erinnerung nach) nicht angefasst. Ein manuelles Erstellen des Verzeichnisses brachte keine Besserung.</p>
<p>Zuerst kam mir keine Idee und daher hatte ich diverse Suchmaschinen befragt. Ich erwähnte es eingangs: &ldquo;<em>auf anderen Rechner problemlos</em>&rdquo;.
Nun erinnerte ich mich, dass bei mir eine andere Distribution Einzug gehalten hat, die auf Ubuntu basiert.</p>

<h2 id="die-lösung" data-numberify>Die Lösung<a class="anchor ms-1" href="#die-lösung"></a></h2>
<p>Hier scheint das Modul <code>ansible.builtin.copy:</code> mit dem <code>become: true</code> laut meinen Recherchen das Problem zu sein.</p>
<p>Beheben lies sich dies, in dem ich in der <code>ansible.cfg</code> folgende Option gesetzt habe:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">remote_tmp</span> <span class="o">=</span> /tmp/ansible_tmp
</span></span></code></pre></div><p>Ich hab das Playbook dann noch mit einem Host, der unter einem Debian 12 läuft, probiert und auch da lief das Playbook anstandslos durch. Ich lass das jetzt so.</p>]]></content:encoded>
    <enclosure url="https://www.rainerrose.de/images/lupe.jpg" length="60818" type="image/.jpg" />
    </item>
    
    <item>
      <title>Ansible Rolle export_nextcloud</title>
      <link>https://www.rainerrose.de/posts/export-nextcloud-rolle/</link>
      <pubDate>Sat, 22 Feb 2025 15:37:52 +0100</pubDate>
      <guid>https://www.rainerrose.de/posts/export-nextcloud-rolle/</guid>
      <description><![CDATA[<!-- Anreißer -->
<p>Derzeit sichere ich meine Nextcloud-Instanz mit einem dateibasierten Backup-Tool, sowie einem Dump der Datenbank.
Letztens hatte ich in meinem Umfeld jemanden, der ein paar Kontakte aus Versehen gelöscht hat. Nun können die vermissten Kontakte zwar aus dem Dump der Datenbank herausgepfriemelt werden, schön ist das aber nicht.</p>
<p>Nach etwas Recherche bin ich auf einen recht simplen <code>curl</code>-Befehl gestoßen, der eine <code>.ics</code> bzw <code>.vcf</code>-Datei heraus exportiert.</p>
<p>Dies ist dann doch aus meiner Sicht etwas einfacher. Sofern z.B. alle Kontakte gelöscht worden sind, reicht dann sogar ein Doppelklick auf die Datei und alle Kontakte werden wieder importiert. Dies sollte wesentlich stressfreier sein.</p>
<p>Als Familien-Admin möchte ich den Export für alle Nutzenden der Instanz regelmäßig machen; daher habe ich mir eine Ansible-Rolle dafür gestrickt.</p>
<p>Das Grundprinzip und die Konfiguration der Rolle möchte ich in diesem Artikel beschreiben.</p>]]></description>
      <content:encoded><![CDATA[<!-- Anreißer -->
<p>Derzeit sichere ich meine Nextcloud-Instanz mit einem dateibasierten Backup-Tool, sowie einem Dump der Datenbank.
Letztens hatte ich in meinem Umfeld jemanden, der ein paar Kontakte aus Versehen gelöscht hat. Nun können die vermissten Kontakte zwar aus dem Dump der Datenbank herausgepfriemelt werden, schön ist das aber nicht.</p>
<p>Nach etwas Recherche bin ich auf einen recht simplen <code>curl</code>-Befehl gestoßen, der eine <code>.ics</code> bzw <code>.vcf</code>-Datei heraus exportiert.</p>
<p>Dies ist dann doch aus meiner Sicht etwas einfacher. Sofern z.B. alle Kontakte gelöscht worden sind, reicht dann sogar ein Doppelklick auf die Datei und alle Kontakte werden wieder importiert. Dies sollte wesentlich stressfreier sein.</p>
<p>Als Familien-Admin möchte ich den Export für alle Nutzenden der Instanz regelmäßig machen; daher habe ich mir eine Ansible-Rolle dafür gestrickt.</p>
<p>Das Grundprinzip und die Konfiguration der Rolle möchte ich in diesem Artikel beschreiben.</p>
<p>Auf die Bedienung und Verwendung von Ansible möchte ich hier nicht eingehen, da setze ich entsprechendes Wissen voraus.</p>
<p>Zum Zeitpunkt des Artikel ist die Nextcloud-Version 31 aktuell. Die Pfade, die in der Ansible-Rolle verwendet werden, orientieren sich an diesem Stand. Sollten sich die Subpfade der URLs ändern, müsste die Rolle angepasst werden.</p>

<h2 id="überblick" data-numberify>Überblick<a class="anchor ms-1" href="#überblick"></a></h2>
<p>Um die Rolle zu verstehen, ist es womöglich am einfachsten, sich das Vorgehen zu verdeutlichen, wenn ein manuelles Backup angefertigt werden soll. Dies soll hier in den nächsten Abschnitten beschrieben werden, um dann im nächsten Schritt zur Automatisierung zu kommen.</p>

<h2 id="händisches-backup" data-numberify>Händisches Backup<a class="anchor ms-1" href="#händisches-backup"></a></h2>
<p>Melde dich als ersten Schritt in Deiner Nextcloud an.</p>

<h3 id="kontakte" data-numberify>Kontakte<a class="anchor ms-1" href="#kontakte"></a></h3>
<ul>
<li>Wähle den Reiter <code>Kontakte</code>.</li>
<li>Gehe nach unten auf der linken Seite und klicke da auf <code>Kontakte-Einstellungen</code>.</li>
</ul>
<p><picture><img class="img-fluid " alt="Weg zu den Kontakte-Einstellungen" src="https://www.rainerrose.de/images/posts/export-nextcloud-rolle/nextcloud-kontakte-weg.jpg?v=59fab2dd88dc536d0263c9c2916f2368" loading="lazy" width="595" height="464" />
</picture>

</p>
<ul>
<li>Navigiere jetzt zu den <code>Allgemeinen Einstellungen</code>.</li>
<li>Beim gewünschten Adressbuch auf die drei Punkte klicken (1)</li>
<li>und auf <code>Herunterladen</code> klicken (2).</li>
</ul>
<p><picture><img class="img-fluid " alt="Weg zu den Export der Kontakte" src="https://www.rainerrose.de/images/posts/export-nextcloud-rolle/nextcloud-kontakte-export.jpg?v=59f012e6d6fa7c320100b4896e27c389" loading="lazy" width="925" height="693" />
</picture>

</p>
<ul>
<li>Voilà! Es wird eine <code>.vcf</code>-Datei mit einem aktuellen Datumsstempel zum Download angeboten.</li>
</ul>

<h3 id="kalender" data-numberify>Kalender<a class="anchor ms-1" href="#kalender"></a></h3>
<ul>
<li>Wähle den Reiter <code>Kontakte</code>.</li>
<li>Wähle Deinen Kalender aus, den du exportieren möchtest.</li>
<li>Fahre Deine Maus etwas nach rechts bis das Stift-Icon erscheint (1) und klicke auf diesen.</li>
</ul>
<p><picture><img class="img-fluid " alt="Weg zu den Kalender-Einstellungen" src="https://www.rainerrose.de/images/posts/export-nextcloud-rolle/kalender-einstellungen-weg.jpg?v=4a778c757475d6d8fdc941d53a6da564" loading="lazy" width="623" height="264" />
</picture>

</p>
<ul>
<li>Im nächsten Dialog <code>Kalender bearbeiten</code> gibt es dann eine Schaltfläche mit der Beschriftung <code>Exportieren</code>.</li>
</ul>
<p><picture><img class="img-fluid " alt="Weg zu den Kalender-Einstellungen" src="https://www.rainerrose.de/images/posts/export-nextcloud-rolle/kalender-export.jpg?v=801d80930c1b8ce33e664c38ade642e3" loading="lazy" width="330" height="454" />
</picture>

</p>
<ul>
<li>Voilà! Es wird eine <code>.ics</code>-Datei mit einem aktuellen Datumsstempel zum Download angeboten.</li>
</ul>

<h2 id="automatisierung" data-numberify>Automatisierung<a class="anchor ms-1" href="#automatisierung"></a></h2>
<p>Jetzt wollen wir das ganze automatisieren; dafür gibt es meine Ansible-Rolle <code>export_nextcloud</code>. Die Rolle findet Du auf meinem <a href="https://tools.rainerrose.de/redirect.php?id=46" target="_blank" rel="noopener noreferrer">Gitlab-Account<i class="fas fa-external-link-square-alt ms-1"></i></a>.</p>
<p>Die Rolle solltest Du auf einem Linux-Host deployen, dem Du vertraust und der Zugriff auf die Nextcloud hat.</p>

<h3 id="minimale-angaben" data-numberify>Minimale Angaben<a class="anchor ms-1" href="#minimale-angaben"></a></h3>

<h4 id="variable-export_nextcloud_url" data-numberify>Variable export_nextcloud_url<a class="anchor ms-1" href="#variable-export_nextcloud_url"></a></h4>
<p>Zunächst benötigt die Rolle die URL, worunter die Nextcloud-Instanz erreichbar ist.
Dazu hinterlegst Du diese in der Variable <code>export_nextcloud_url</code> als Hostvariable, wo das Export-Script später laufen soll.</p>
<p>Beispiel:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">export_nextcloud_url</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;https://meine.nextcloud.instanz&#34;</span><span class="w">
</span></span></span></code></pre></div>
<h4 id="variable-export_nextcloud_user" data-numberify>Variable export_nextcloud_user<a class="anchor ms-1" href="#variable-export_nextcloud_user"></a></h4>
<p>Jetzt brauchst Du eine Liste mit einem oder mehreren Usernamen, die du sichern möchtest. Zusätzlich ein Passwort und einen Zeitpunkt, wann das Export-Script laufen soll.</p>

<blockquote class="alert alert-warning" role="alert">
    <p class="alert-heading fw-bold">
      <i class="fas fa-exclamation-circle me-2"></i>Empfehlung
    </p>
    <p>Statt des regulären Passwortes für Deinen User, empfehle ich die Generierung eines Personal Access Token kurz &ldquo;<code>PAT</code>&rdquo;.</p>
</blockquote>
<p>Die Einrichtung eines <code>PAT</code> beschreibe ich <a href="/posts/nextcloud-pat-erstellen/">in einem anderem Blog-Artikel</a>.</p>
<p>Als dritten Parameter wird noch der Zeitstempel benötigt, wo der Export laufen soll.
Mit dieser Angabe wird später eine SystemD-Timer-Unit erstellt.</p>
<p>Die Syntax dieses Attributes folgt dem Parameter <code>on_calendar</code> von <a href="https://www.freedesktop.org/software/systemd/man/systemd.timer#OnCalendar=" target="_blank" rel="noopener noreferrer">systemd.unit(5)<i class="fas fa-external-link-square-alt ms-1"></i></a>.
Aus jeden <code>username</code> wird eine extra SystemD-Timer-Units erstellt, nach folgendem Muster:</p>
<ul>
<li><code>export_nextcloud-user1.timer</code></li>
<li><code>export_nextcloud-user2.timer</code></li>
</ul>
<p>Die Konfiguration sieht am Ende zum Beispiel so aus:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">export_nextcloud_user</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">  </span>- <span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;user1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">    </span><span class="nt">password</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;password1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="nt">on_calendar</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;*-*-* 03:00&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">  </span>- <span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;user2&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">    </span><span class="nt">password</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;password2&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="w">    </span><span class="nt">on_calendar</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;*-*-* 03:01&#39;</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="optionale-angaben" data-numberify>Optionale Angaben<a class="anchor ms-1" href="#optionale-angaben"></a></h3>

<h4 id="variable-export_nextcloud_script_path" data-numberify>Variable export_nextcloud_script_path<a class="anchor ms-1" href="#variable-export_nextcloud_script_path"></a></h4>
<p>Die nächste Variable bestimmt, wohin das Script kopiert werden soll. Der Standardpfad lautet <code>/opt/export_nextcloud</code>.</p>

<h4 id="variable-export_nextcloud_backup_path" data-numberify>Variable export_nextcloud_backup_path<a class="anchor ms-1" href="#variable-export_nextcloud_backup_path"></a></h4>
<p>Über diese Variable kann bestimmt werden, wohin die exportierten Kalender- und Kontakte-Dateien hingeschrieben werden sollen.
<code>/backup/nextcloud_export</code> lautet hier der Standardpfad.</p>
<p>Hier entsteht pro Username eine Kalender- und eine Kontakte-Datei mit dem Username
nach folgendem Muster:</p>
<ul>
<li><code>kalender-${username}.ics</code></li>
<li><code>kontakte-${username}.vcf</code></li>
</ul>
<p>Und ja, ich war zu faul, noch ein extra Aufräum-Mechanismus zu schreiben.
Für die Versionierung ist bei mir mein Backup-Programm zuständig ;-) .
Das kann mein Sicherungsprogramm viel effizienter als ich.
Wenn ich an ältere Versionen herankommen möchte, muss ich die Sicherung bemühen; ich spare mir dadurch zusätzliche Fehlerquellen und Abhängigkeiten.</p>

<h4 id="variable-export_nextcloud_prometheus_path" data-numberify>Variable export_nextcloud_prometheus_path<a class="anchor ms-1" href="#variable-export_nextcloud_prometheus_path"></a></h4>
<p>Diese Variable legt den Pfad fest, wo die Prometheus-Statistiken hingeschrieben werden.</p>

<h4 id="variable-export_nextcloud_extra_curl_options" data-numberify>Variable export_nextcloud_extra_curl_options<a class="anchor ms-1" href="#variable-export_nextcloud_extra_curl_options"></a></h4>
<p>Diese Variable habe ich am 03.10.2025 eingeführt, weil der zugrunde liegende <code>curl</code> sich am selbst-signierten Zertifikat meiner Nextcloud-Instanz störte.
Mit dem Parameter <code>-k</code> oder <code>--insecure</code> lässt sich das aber übersteuern. Dies erforderte allerdings eine Anpassung des Scriptes.</p>
<p>Nun können weitere Parameter über diese Variable optional mitgegeben werden.</p>
<p>Im unteren Beispiel Ansible Playbook fügt ihr an den einen Task folgende zwei Zeilen an.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="w">  </span><span class="nt">vars</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">    </span><span class="nt">export_nextcloud_extra_curl_options</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;--insecure&#34;</span><span class="w">
</span></span></span></code></pre></div>
<h3 id="ansible-playbook" data-numberify>Ansible Playbook<a class="anchor ms-1" href="#ansible-playbook"></a></h3>
<p>Jetzt kannst Du die Rolle in ein Ansible-Playbook einbinden.</p>
<p>Ein minimales Beispiel wäre:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Setup export_nextcloud</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">  </span><span class="nt">hosts</span><span class="p">:</span><span class="w"> </span><span class="l">export_nextcloud</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">  </span><span class="nt">roles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">    </span>- <span class="l">export_nextcloud</span><span class="w">
</span></span></span></code></pre></div>
<h2 id="backup" data-numberify>Backup<a class="anchor ms-1" href="#backup"></a></h2>
<p>Im Nachgang bzw. nach dem Ausführen der jeweiligen SystemD-Timer-Unit, empfehle ich noch ein Backup des Verzeichnisses wo die exportierten Dateien liegen.
Das Verzeichnis kannst zum Beispiel dateibasiert mittels deiner präferierten Wunsch-Backup-Software gesichert werden.
Ich selbst habe dazu die Pfade in meinem Sicherungsscript aufgenommen; hier verwende ich <code>restic</code> seit längerem erfolgreich.</p>

<h2 id="fertig" data-numberify>Fertig.<a class="anchor ms-1" href="#fertig"></a></h2>
<p>Im Grunde war es das auch schon. Viel Spaß beim Benutzen.
Der Source-Code der Rolle liegt in meinem <a href="https://tools.rainerrose.de/redirect.php?id=46" target="_blank" rel="noopener noreferrer">Gitlab-Account<i class="fas fa-external-link-square-alt ms-1"></i></a>.</p>

<h2 id="changelog" data-numberify>Changelog<a class="anchor ms-1" href="#changelog"></a></h2>
<table>
  <thead>
      <tr>
          <th>Datum</th>
          <th>Änderung</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>03.10.2025</td>
          <td>Neue optionale Variable <code>export_nextcloud_extra_curl_options</code></td>
      </tr>
  </tbody>
</table>]]></content:encoded>
    <enclosure url="https://www.rainerrose.de/wallpaper/posts/nextcloud.png" length="9229" type="image/.png" />
    </item>
    
    <item>
      <title>Starship - Ansible Rolle</title>
      <link>https://www.rainerrose.de/posts/starship-rolle/</link>
      <pubDate>Fri, 27 Dec 2024 15:11:01 +0100</pubDate>
      <guid>https://www.rainerrose.de/posts/starship-rolle/</guid>
      <description><![CDATA[<!-- Anreißer -->
<p>Das Tool <code>starship</code> hatte ich schon mal in einem <a href="/docs/howto/starship/">Blog-Artikel</a> erwähnt und genauer beschrieben:</p>
<blockquote>
<p>Der Standard-Prompt ist zu langweilig? Die Befüllung der Variablen PS1 ist zu kompliziert und unflexibel? Es sollen mehr Informationen dargestellt werden?</p>
<p>Kein Problem, ich habe jetzt das Tool <code>Starship</code> für mich entdeckt&hellip;</p>
</blockquote>
<p>Vor einiger Zeit habe ich die Installation des Tool inklusive mit meiner Konfiguration in eine Ansible-Rolle gegossen.</p>]]></description>
      <content:encoded><![CDATA[<!-- Anreißer -->
<p>Das Tool <code>starship</code> hatte ich schon mal in einem <a href="/docs/howto/starship/">Blog-Artikel</a> erwähnt und genauer beschrieben:</p>
<blockquote>
<p>Der Standard-Prompt ist zu langweilig? Die Befüllung der Variablen PS1 ist zu kompliziert und unflexibel? Es sollen mehr Informationen dargestellt werden?</p>
<p>Kein Problem, ich habe jetzt das Tool <code>Starship</code> für mich entdeckt&hellip;</p>
</blockquote>
<p>Vor einiger Zeit habe ich die Installation des Tool inklusive mit meiner Konfiguration in eine Ansible-Rolle gegossen.</p>

<h2 id="die-rolle" data-numberify>Die Rolle<a class="anchor ms-1" href="#die-rolle"></a></h2>
<p>Diese Ansible-Rolle findet sich auf meinem persönlichen gitlab-Account im Unterordner <a href="https://tools.rainerrose.de/redirect.php?id=45" target="_blank" rel="noopener noreferrer">ansible-roles<i class="fas fa-external-link-square-alt ms-1"></i></a> des Projektes.</p>
<p>Die Rolle muss nur in das <code>roles</code>-Verzeichnis der jeweiligen Ansible-Playbooks kopiert werden.
Danach kann sie in einem Playbook verwendet werden, wobei mindestens die Namen der Accounts angegeben müssen, wo die Rolle installiert werden soll. Ein Beispiel-Playbook findet sich in der Datei <code>README.md</code> des <a href="https://tools.rainerrose.de/redirect.php?id=45" target="_blank" rel="noopener noreferrer">Unterordners<i class="fas fa-external-link-square-alt ms-1"></i></a> der Rolle.</p>

<h2 id="rollen-variable-starship_user" data-numberify>Rollen-Variable: starship_user<a class="anchor ms-1" href="#rollen-variable-starship_user"></a></h2>
<p>Die Namen der Accounts, wo die Rolle installiert werden soll, müssen als Liste angegeben werden.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">starship_user</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">  </span>- <span class="l">user1</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span>- <span class="l">user2</span><span class="w">
</span></span></span></code></pre></div><p>Die Beschreibung der Rollen-Variablen findet sich aber ebenfalls noch einmal in der Datei <code>README.md</code> inklusive weiterer Erklärungen.</p>

<h2 id="schwierigkeiten-timeout" data-numberify>Schwierigkeiten: Timeout<a class="anchor ms-1" href="#schwierigkeiten-timeout"></a></h2>
<p>Allerdings stieß ich auf die Schwierigkeit bei einem meiner Rechner, dass das <code>git</code>-Kommando mehr als die vordefinierten 500 Millisekunden brauchte. <br>
Daher habe ich die Variable <code>starship_extra_options</code> eingeführt, wo ich das <code>command_timeout</code> höher setzen konnte:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">starship_extra_options</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;command_timeout = 1000&#39;</span><span class="w">
</span></span></span></code></pre></div><p>Theoretisch lassen sich da noch mehr individuelle Optionen setzen, sofern benötigt.</p>
<p>Beispiel:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">starship_extra_options</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="sd">  command_timeout = 1000
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="sd">  
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="sd">  [container]
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="sd">  format = &#39;[$symbol \[$name\]]($style) &#39;</span><span class="w">
</span></span></span></code></pre></div>
<h2 id="minimales-playbook" data-numberify>Minimales Playbook<a class="anchor ms-1" href="#minimales-playbook"></a></h2>
<p>Ein minimales Playbook sieht beispielsweise so aus:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Setup starship</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">  </span><span class="nt">hosts</span><span class="p">:</span><span class="w"> </span><span class="l">linuxhosts</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">  </span><span class="nt">roles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">    </span>- <span class="l">starship</span><span class="w">
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="w">  </span><span class="nt">vars</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="w">    </span><span class="nt">starship_user</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="w">      </span>- <span class="l">user1</span><span class="w">
</span></span></span></code></pre></div><p>Vorbei sich die Variable <code>starship_user</code> natürlich noch als Host- oder Gruppenvariable definieren lässt, womit das Playbook noch kleiner wird.</p>
<p>Der alte
<a href="/docs/howto/starship/">Blog-Artikel</a>
findet sich <a href="/docs/howto/starship/">hier</a>, dort wird das Tool noch einmal etwas genauer erklärt.</p>]]></content:encoded>
    <enclosure url="https://www.rainerrose.de/wallpaper/docs/linux/starship-screenshot.png" length="27725" type="image/.png" />
    </item>
    
    <item>
      <title>SSH-Tricks: Hold on</title>
      <link>https://www.rainerrose.de/posts/ssh-tricks_hold_on/</link>
      <pubDate>Thu, 08 Feb 2024 18:15:02 +0100</pubDate>
      <guid>https://www.rainerrose.de/posts/ssh-tricks_hold_on/</guid>
      <description><![CDATA[<!-- Anreißer -->
<p>Letztens habe ich ein weiteren Kniff gelernt, der in Zusammenhang mit <code>ssh</code>-Verbindungen hilfreich ist.</p>]]></description>
      <content:encoded><![CDATA[<!-- Anreißer -->
<p>Letztens habe ich ein weiteren Kniff gelernt, der in Zusammenhang mit <code>ssh</code>-Verbindungen hilfreich ist.</p>
<p>Führt man mehrere <code>ssh</code>-Kommandos kurz hintereinander aus, muss für jede Verbindung ein erneuter Kontakt zum jeweiligen Server aufgebaut werden.
Das sind zwar immer (je nach Verbindung und Schnelligkeit des Servers) vielleicht nur ein paar Millisekunden, aber zum Beispiel in Zusammenhang mit <code>Ansible</code>-Playbooks kann sich das schon mal addieren und den Lauf durchaus in die Länge ziehen. Zudem ist es nicht sehr ressourcenschonend.</p>
<p>In der <code>ssh</code>-Konfiguration des aktuellen Benutzers
(<code>~/.ssh/config</code>) kann jedoch eine Option gesetzt werden, die ein Socket-File aufmacht und somit die Verbindung offen hält. Mit einem gesetzten Timeout von zum Beispiel 30 Minuten, muss nun nicht mehr jedes Mal eine neue Verbindung initiiert werden. Damit entfällt das ganze Geraffel mit Handshake etc.</p>
<p><code>Ansible</code>-Playbooks laufen jetzt bei mir <strong>wesentlich</strong> schneller!</p>

<h2 id="konfiguration" data-numberify>Konfiguration<a class="anchor ms-1" href="#konfiguration"></a></h2>
<p>Konfiguriert wird dieses Verhalten in der <code>ssh</code>-Konfiguration des jeweiligen Benutzers.</p>
<p>Der entsprechende Ausschnitt aus meiner <code>~/.ssh/config</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">Host *
</span></span><span class="line"><span class="ln">2</span><span class="cl">  ControlPath ~/.ssh/connections/%C
</span></span><span class="line"><span class="ln">3</span><span class="cl">  ControlMaster auto
</span></span><span class="line"><span class="ln">4</span><span class="cl">  ControlPersist 30m
</span></span></code></pre></div><p>Eine paar kleine Erläuterungen und Hinweise zur obigen Datei:</p>

<h3 id="parameter-host" data-numberify>Parameter Host<a class="anchor ms-1" href="#parameter-host"></a></h3>
<p>Das Asterik (<code>*</code>) hinter <code>Host</code> sagt, dass es für jeden Host gilt.</p>

<h3 id="parameter-controlpath" data-numberify>Parameter ControlPath<a class="anchor ms-1" href="#parameter-controlpath"></a></h3>
<p>Das genannte Verzeichnis im <code>ControlPath</code> muss <strong>vorher</strong> angelegt werden:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">mkdir ~/.ssh/connections
</span></span></code></pre></div><p>Sofern das Unterverzeichnis <code>~/.ssh</code> noch nicht existiert, muss es mit den richtigen Rechten angelegt werden.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">mkdir ~/.ssh
</span></span><span class="line"><span class="ln">2</span><span class="cl">chmod <span class="m">700</span> ~/.ssh
</span></span></code></pre></div>
<h3 id="parameter-controlmaster" data-numberify>Parameter ControlMaster<a class="anchor ms-1" href="#parameter-controlmaster"></a></h3>
<p>Dieser Parameter aktiviert erst die gemeinsame Benutzung von mehreren Sitzungen über eine einzelne Netzwerkverbindung. Erst damit wird diese Funktionalität nutzbar bzw. aktiviert.</p>

<h3 id="parameter-controlpersist" data-numberify>Parameter ControlPersist<a class="anchor ms-1" href="#parameter-controlpersist"></a></h3>
<p>Hier wird die Haltedauer der Verbindung angegeben. In meinem Beispiel 30 Minuten.  Nach Ablauf der definierten Zeitspanne werden die Sockets automatisch gelöscht.</p>

<h2 id="tipps" data-numberify>Tipps<a class="anchor ms-1" href="#tipps"></a></h2>

<h3 id="problem-lösungen" data-numberify>Problem-Lösungen<a class="anchor ms-1" href="#problem-lösungen"></a></h3>
<p>Ändern sich die Hostkeys des Servers einmal, kann das Socket-File einfach gelöscht werden.
Dies passiert zum Beispiel in der Entwicklung-Phase wenn neue VMs neu deployed werden müssen und sich dann der <code>ssh</code>-Hostkey ändert. <code>ssh</code> wertet dies beim erneuten Verbindungsversuch als massives Problem und verweigert den Verbindungsaufbau. In so einem Fall, kann das entsprechende Socket einfach gelöscht werden, statt 30 Minuten zu warten.</p>

<h3 id="warum-c-" data-numberify>Warum %C ?<a class="anchor ms-1" href="#warum-c-"></a></h3>
<p>Ja, es gibt noch andere Parameter, wo der Dateinamen dann unter anderem dem Hostnamen entspricht. Dies würde das gezielte Löschen einzelner Sockets im oben beschrieben Fall vereinfachen.</p>
<p>Allerdings hat die Pfad-Länge von <code>ControlPath</code> eine maximal definierte Länge (den genauen Wert habe ich leider vergessen).
Der Parameter <code>%C</code> macht aus der Pfadangabe einen Hash-Wert, der dieses Problem umgeht.</p>

<h3 id="vpn-und-das-controlpersist" data-numberify>VPN und das ControlPersist<a class="anchor ms-1" href="#vpn-und-das-controlpersist"></a></h3>
<p>Ich muss des öfteren mal VPN-Verbindungen wechseln. Leider hat dies (bisher) den unschönen Nebeneffekt gehabt, dass das Socket noch bestehen bleibt.
Da ich mit jedem neuen Verbindungsaufbau allerdings eine neue Quell-IP etc. bekomme, komme ich nun nicht mehr auf das System. Nun muss ich das entsprechende Socket-File löschen.
Da ich ja Hash-Werte benutze, ist das nicht so einfach, zudem ist es eine händische Arbeit; mag ich nicht.</p>
<p>Da ich faul bin, habe ich nach einer Lösung gesucht und gefunden.</p>
<p>Unterhalb von <code>/etc/NetworkManager/dispatcher.d/</code> habe ich mir folgendes Script hingelegt:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="cp">#!/usr/bin/bash
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="cp"></span><span class="c1"># Connection-Pool aufräumen</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># Ort: /etc/NetworkManager/dispatcher.d</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">find /home/rainerr/.ssh/connections -type f -delete
</span></span></code></pre></div><p>Jetzt wird bei jedem neuen VPN-Verbindungsaufbau einfach alles stumpf weggeworfen. \o/</p>

<h2 id="changelog" data-numberify>Changelog<a class="anchor ms-1" href="#changelog"></a></h2>
<table>
  <thead>
      <tr>
          <th>Datum</th>
          <th>Änderung</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>08.02.2024</td>
          <td>neuer Absatz: <em>VPN und das ControlPersist</em></td>
      </tr>
  </tbody>
</table>]]></content:encoded>
    </item>
    
    <item>
      <title>SSH-Tricks: Config-Split</title>
      <link>https://www.rainerrose.de/posts/ssh-tricks_config_split/</link>
      <pubDate>Tue, 23 Jan 2024 17:21:12 +0100</pubDate>
      <guid>https://www.rainerrose.de/posts/ssh-tricks_config_split/</guid>
      <description><![CDATA[<!-- Anreißer -->
<p>Wenn man wie ich mit mehreren Servern jongiert, wird die <code>ssh</code>-Konfigurationsdatei irgendwann recht voll und unübersichtlich. Mittels eines Paramters, kann ich die Konfigurationsdatei allerdings in unterschiedliche Dateien aufteilen.</p>]]></description>
      <content:encoded><![CDATA[<!-- Anreißer -->
<p>Wenn man wie ich mit mehreren Servern jongiert, wird die <code>ssh</code>-Konfigurationsdatei irgendwann recht voll und unübersichtlich. Mittels eines Paramters, kann ich die Konfigurationsdatei allerdings in unterschiedliche Dateien aufteilen.</p>
<p>In der <code>SSH</code>-Konfiguration des aktuellen Benutzers</p>
<p><code>~/.ssh/config</code></p>
<p>kann ich mit dem Parameter <code>Include</code> sagen, wo die anderen Dateien liegen, die ich einbinden möchte:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="ln">1</span><span class="cl">Include config.d/*
</span></span></code></pre></div><p>Das genannte Verzeichnis im <code>Include</code>-Parameter muss <strong>vorher</strong> angelegt werden:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">mkdir ~/.ssh/connections
</span></span></code></pre></div><p>Sofern das Unterverzeichnis <code>~/.ssh</code> noch nicht existiert muss es mir den richtigen Rechten angelegt werden.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">mkdir ~/.ssh
</span></span><span class="line"><span class="ln">2</span><span class="cl">chmod <span class="m">700</span> ~/.ssh
</span></span></code></pre></div><p>In das oben genannte Verzeichnis <code>~/.ssh/connections</code> kann ich jetzt die Hosts strukturiert auslagern.</p>
<p>Mein Unterverzeichnis sieht dann z.B. folgendermaßen aus:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">ls -lR config.d/
</span></span><span class="line"><span class="ln">2</span><span class="cl">config.d/:
</span></span><span class="line"><span class="ln">3</span><span class="cl">insgesamt <span class="m">8</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">-rw-rw-r-- <span class="m">1</span> rainer rainerr <span class="m">239</span> Jan <span class="m">12</span> 17:52 produktionsSysteme
</span></span><span class="line"><span class="ln">5</span><span class="cl">-rw-rw-r-- <span class="m">1</span> rainer rainerr  <span class="m">60</span> Jan <span class="m">12</span> 17:52 testSysteme
</span></span></code></pre></div><p>Die oben genannten Dateien sind genauso aufgebaut wie auch sonst die Datei <code>~/.ssh/config</code>.</p>
<p>Vielleicht bringt es ja auch in Euren Alltag etwas mehr Ordnung.</p>]]></content:encoded>
    </item>
    
  </channel>
</rss>

