diff --git a/VERSION b/VERSION index 9f7fc3e..f77f159 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.85 +1.3.86 diff --git a/app/Provisioning/Steps/Host/CreateAutomationToken.php b/app/Provisioning/Steps/Host/CreateAutomationToken.php index 0f28ab8..ec8b3bc 100644 --- a/app/Provisioning/Steps/Host/CreateAutomationToken.php +++ b/app/Provisioning/Steps/Host/CreateAutomationToken.php @@ -49,8 +49,18 @@ class CreateAutomationToken extends HostStep // there, which is the ordinary case and not an error. $roleArgs = escapeshellarg($role).' -privs '.escapeshellarg($privs); if (! $this->shell->run('pveum role add '.$roleArgs)->ok() - && ! $this->shell->run('pveum role modify '.$roleArgs)->ok()) { - return StepResult::retry(20, 'could not converge the Proxmox automation role privileges'); + && ! ($modify = $this->shell->run('pveum role modify '.$roleArgs))->ok()) { + // Der Grund von `pveum`, nicht nur die Feststellung, dass es nicht + // ging. Fünf Wiederholungen mit „could not converge the Proxmox + // automation role privileges" sagten, WAS scheiterte, und + // verschwiegen das Einzige, was weiterhilft: welches Privileg diese + // Proxmox-Fassung nicht kennt. Der Betreiber musste sich auf den + // Host melden und den Befehl von Hand nachstellen, um zu erfahren, + // was in der Zeile daneben schon gestanden hatte. + return StepResult::retry(20, trim( + 'could not converge the Proxmox automation role privileges: ' + .$this->firstLineOf($modify->stderr ?: $modify->stdout) + )); } // Idempotent: token already minted and persisted. Below the role @@ -89,4 +99,18 @@ class CreateAutomationToken extends HostStep return StepResult::advance(); } + + /** + * Die erste Zeile einer Fehlerausgabe, gekürzt. + * + * Die erste, weil `pveum` den Grund voranstellt und danach seine + * Aufrufhilfe ausbreitet — die ganze Ausgabe wäre ein Bildschirm Text in + * einer Ereigniszeile. Gekürzt, weil diese Zeile in einer Tabelle steht. + */ + private function firstLineOf(string $output): string + { + $first = trim((string) (preg_split('/\R/', trim($output))[0] ?? '')); + + return mb_strlen($first) > 200 ? mb_substr($first, 0, 200).'…' : $first; + } } diff --git a/tests/Feature/Provisioning/HostStepsTest.php b/tests/Feature/Provisioning/HostStepsTest.php index 665a6ed..ca836b5 100644 --- a/tests/Feature/Provisioning/HostStepsTest.php +++ b/tests/Feature/Provisioning/HostStepsTest.php @@ -1322,3 +1322,23 @@ it('ignores a stranger on wg0 and asks only about the configured hub', function expect(app(ConfigureWireguard::class)->execute($run)->type)->toBe('retry'); }); + +it('names the reason pveum gave instead of only that it failed', function () { + // Fünf Wiederholungen mit "could not converge the Proxmox automation role + // privileges" sagten, WAS scheiterte, und verschwiegen das Einzige, was + // weiterhilft: welches Privileg diese Proxmox-Fassung nicht kennt. Der + // Betreiber musste sich auf den Host melden und den Befehl von Hand + // nachstellen, um zu erfahren, was daneben schon gestanden hatte. + $s = fakeServices(); + $s['shell']->script('pveum role add', CommandResult::failure(2, 'role CluPilotAutomation already exists')); + $s['shell']->script('pveum role modify', CommandResult::failure(2, "unknown privilege 'VM.Snapshot.Rollback'\nUSAGE: pveum role modify …")); + $run = hostRun(Host::factory()->create()); + + $result = app(CreateAutomationToken::class)->execute($run); + + expect($result->type)->toBe('retry') + ->and($result->reason)->toContain("unknown privilege 'VM.Snapshot.Rollback'") + // Nur die erste Zeile: die Aufrufhilfe danach wäre ein Bildschirm Text + // in einer Ereigniszeile. + ->and($result->reason)->not->toContain('USAGE'); +});