diff --git a/app/Provisioning/Steps/Customer/ConfigureInstanceMail.php b/app/Provisioning/Steps/Customer/ConfigureInstanceMail.php index 75ac205..37095fe 100644 --- a/app/Provisioning/Steps/Customer/ConfigureInstanceMail.php +++ b/app/Provisioning/Steps/Customer/ConfigureInstanceMail.php @@ -28,13 +28,20 @@ use Illuminate\Support\Facades\Log; * in der PFLICHT-Pipeline `customer`, und ein Kunde, der bezahlt hat, bekommt * seine Cloud auch dann, wenn der Mailversand noch nicht eingerichtet ist — * genau wie RegisterMonitoring die Bereitstellung nie an einer nicht - * erreichbaren Ueberwachung scheitern laesst (siehe deren Kopfkommentar). - * Mailversand ist hier dieselbe Nebenfunktion: fehlt er, funktioniert die - * Cloud vollstaendig, nur Einladungen und Freigabe-Benachrichtigungen gehen - * nicht. Der Schritt geht in diesem Fall mit `advance()` weiter und - * protokolliert den Grund per `Log::warning`, damit der Betreiber es findet; - * nachgeholt wird es ueber `clupilot:configure-instance-mail` (Aufgabe 4), - * sobald Server und Postfach stehen. + * erreichbaren Ueberwachung scheitern laesst (siehe deren Kopfkommentar). Der + * Schritt geht in diesem Fall mit `advance()` weiter; nachgeholt wird es ueber + * `clupilot:configure-instance-mail` (Aufgabe 4), sobald Server und Postfach + * stehen. + * + * Die Rueckmeldung dazu geht an ZWEI Stellen, nicht nur einer — genau wie bei + * RegisterMonitoring. Ein Lauf-Ereignis (`outcome: info`) haengt sich an den + * Lauf, den der Betreiber in der Konsole sieht; `Log::warning` bleibt daneben + * fuer die Nachschau ausserhalb der Konsole. Das Lauf-Ereignis ist hier nicht + * optional: solange der Mailserver noch nicht steht, tritt dieser Zweig bei + * JEDER einzelnen Bestellung ein, und die einzige Rueckmeldung darf dann + * nicht in einer Logdatei verschwinden, in die niemand schaut. Mailversand + * ist eine Nebenfunktion: fehlt er, funktioniert die Cloud vollstaendig, nur + * Einladungen und Freigabe-Benachrichtigungen gehen nicht. * * Nicht eingerichtet ist etwas anderes als kaputt: sobald Server und Postfach * da sind, wird geschrieben, und ein Fehler beim Schreiben selbst (occ liefert @@ -90,11 +97,20 @@ class ConfigureInstanceMail extends CustomerStep if (! $config->available()) { // Nicht eingerichtet, nicht kaputt — siehe Kopfkommentar. Die Cloud - // wird trotzdem ausgeliefert; der Grund geht ins Log, nicht in - // einen gescheiterten Lauf. + // wird trotzdem ausgeliefert. available() === false heisst hier + // immer, dass problem() einen Grund liefert (siehe GuestMailConfig) + // — kein Rueckfall auf einen Fall, der nicht eintreten kann. + $grund = $config->problem(); + + $run->events()->create([ + 'step' => $this->key(), + 'attempt' => $run->attempt, + 'outcome' => 'info', + 'message' => 'Mailversand uebersprungen (nicht eingerichtet): '.$grund, + ]); Log::warning('Mailversand fuer Instanz uebersprungen (nicht eingerichtet)', [ 'instance' => $instance->uuid, - 'reason' => $config->problem() ?? 'mail_unavailable', + 'reason' => $grund, ]); return StepResult::advance(); diff --git a/tests/Feature/Provisioning/ConfigureInstanceMailTest.php b/tests/Feature/Provisioning/ConfigureInstanceMailTest.php index 3caa871..cf2f9a4 100644 --- a/tests/Feature/Provisioning/ConfigureInstanceMailTest.php +++ b/tests/Feature/Provisioning/ConfigureInstanceMailTest.php @@ -55,10 +55,16 @@ it('traegt jeden Wert einzeln in den Gast', function () { $befehle = implode("\n", $pve->guestCommands); - expect($befehle)->toContain('config:system:set mail_smtphost --value=') - ->and($befehle)->toContain('mail.clupilot.cloud') - ->and($befehle)->toContain('config:system:set mail_domain --value=') - ->and($befehle)->toContain('clupilot.cloud'); + // Alle acht Werte aus GuestMailConfig::values(), nicht nur zwei — ein + // vergessener Schluessel soll hier auffallen, nicht erst beim Kunden. + expect($befehle)->toContain('config:system:set mail_smtpmode --value='.escapeshellarg('smtp')) + ->and($befehle)->toContain('config:system:set mail_smtphost --value='.escapeshellarg('mail.clupilot.cloud')) + ->and($befehle)->toContain('config:system:set mail_smtpport --value='.escapeshellarg('587')) + ->and($befehle)->toContain('config:system:set mail_smtpsecure --value='.escapeshellarg('tls')) + ->and($befehle)->toContain('config:system:set mail_smtpauth --value='.escapeshellarg('true')) + ->and($befehle)->toContain('config:system:set mail_smtpname --value='.escapeshellarg('noreply@clupilot.cloud')) + ->and($befehle)->toContain('config:system:set mail_from_address --value='.escapeshellarg('noreply')) + ->and($befehle)->toContain('config:system:set mail_domain --value='.escapeshellarg('clupilot.cloud')); }); it('maskiert das Passwort, sodass es keinen zweiten Befehl starten kann', function () { @@ -111,6 +117,26 @@ it('schreibt GAR NICHTS, wenn der Mailserver fehlt', function () { ); }); +it('haengt ein Lauf-Ereignis an, das der Betreiber in der Konsole sieht', function () { + // Log::warning allein reicht hier nicht: bis der Mailserver steht, trifft + // dieser Zweig auf JEDE Bestellung zu, und die einzige Rueckmeldung darf + // nicht in einer Logdatei verschwinden, in die niemand schaut — + // RegisterMonitoring macht sein Ueberspringen genauso am Lauf sichtbar. + Settings::set('mail.host', ''); + $pve = new FakeProxmoxClient; + app()->instance(ProxmoxClient::class, $pve); + $run = laufMitInstanz(Instance::factory()->create()); + + app(ConfigureInstanceMail::class)->execute($run); + + $ereignis = $run->events()->first(); + + expect($ereignis)->not->toBeNull() + ->and($ereignis->step)->toBe('configure_instance_mail') + ->and($ereignis->outcome)->toBe('info') + ->and($ereignis->message)->toContain('no_server'); +}); + it('schreibt beim zweiten Lauf erneut, statt sich mit einem Merker zu sperren', function () { versandbereitFuerSchritt(); $pve = new FakeProxmoxClient;