Add a KantTresor tab to the central registry
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s

KantTresor instances (from 1.82.0) report to /api/kanttresor/melden with the
same key-then-HMAC protocol. The new tab lists them with tenants, disk usage
and failing services; it never offers or accepts an update order, since
KantTresor is updated with ./update.sh on the server. See ADR 124.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5.5 committed 2026-10-27 10:02:07 +01:00
1 parent 9d80af3795
commit 968d19b611
15 files changed
+392 -80

No files matched your search

+44 -3
View File
@@ -28,10 +28,18 @@ final class Bestand
{
}
/** Ab so viel Prozent belegtem Speicher gilt eine KantTresor-Instanz als knapp. */
public const SPEICHER_KNAPP = 90;
/** Die Produkte, die sich melden, mit ihrer Übersicht. */
public const PRODUKTE = ['kantsites' => 'KantSites', 'kanttresor' => 'KantTresor'];
/** @return list<array<string, mixed>> */
public function alle(?string $neueste): array
public function alle(?string $neueste, string $produkt = 'kantsites'): array
{
$zeilen = $this->db->query('SELECT * FROM installation ORDER BY domain, erste_meldung')->fetchAll();
$abfrage = $this->db->prepare('SELECT * FROM installation WHERE produkt = ? ORDER BY domain, erste_meldung');
$abfrage->execute([$produkt]);
$zeilen = $abfrage->fetchAll();
// Natürlich sortiert und ohne www: kunde-2 vor kunde-10, www.ebsolar.de bei e.
usort($zeilen, static fn (array $a, array $b): int => strnatcasecmp(preg_replace('/^www\./', '', (string) $a['domain']), preg_replace('/^www\./', '', (string) $b['domain'])));
$auftraege = [];
@@ -42,6 +50,34 @@ final class Bestand
return array_map(fn (array $zeile): array => $this->anreichern($zeile, $auftraege[$zeile['id']] ?? null, $neueste), $zeilen);
}
/**
* KantTresor hat keine öffentliche Releaseseite: Als neueste Fassung gilt die höchste, die
* eine Instanz meldet. Wer dahinter liegt, ist veraltet.
*/
public function hoechsteFassung(string $produkt): ?string
{
$abfrage = $this->db->prepare("SELECT fassung FROM installation WHERE produkt = ? AND fassung <> 'unbekannt'");
$abfrage->execute([$produkt]);
$hoechste = null;
foreach ($abfrage->fetchAll(\PDO::FETCH_COLUMN) as $fassung) {
if (null === $hoechste || version_compare((string) $fassung, $hoechste, '>')) {
$hoechste = (string) $fassung;
}
}
return $hoechste;
}
/** Zu welchem Produkt gehört diese Kennung? */
public function produkt(string $id): ?string
{
$abfrage = $this->db->prepare('SELECT produkt FROM installation WHERE id = ?');
$abfrage->execute([$id]);
$produkt = $abfrage->fetchColumn();
return false === $produkt ? null : (string) $produkt;
}
/** @return array<string, mixed>|null */
public function eine(string $id, ?string $neueste): ?array
{
@@ -117,7 +153,10 @@ final class Bestand
// Ein wartender Auftrag lässt sich noch ändern; ein abgeholter läuft.
$laeuft = 'laeuft' === ($zustand['art'] ?? null);
$tresor = 'kanttresor' === $zeile['produkt'];
$grund = match (true) {
$tresor => 'KantTresor wird auf dem Server mit ./update.sh aktualisiert, nicht von hier.',
null === $neueste => 'Die neueste Fassung ist gerade nicht bekannt.',
!$veraltet => 'Diese Installation ist auf dem neuesten Stand.',
'git' === $zeile['art'] => 'Eine Git-Arbeitskopie wird über Git aktualisiert, nicht aus der Ferne.',
@@ -135,7 +174,9 @@ final class Bestand
'auftrag_zustand' => $zustand,
'kann_update' => '' === $grund,
'kein_update_grund' => $grund,
'php_luecke' => self::phpLuecke((string) $zeile['php']),
'php_luecke' => $tresor ? null : self::phpLuecke((string) $zeile['php']),
'speicher_knapp' => null !== $zeile['speicher'] && (int) $zeile['speicher'] >= self::SPEICHER_KNAPP,
'gestoert' => '' !== (string) $zeile['stoerungen'] || (null !== $zeile['speicher'] && (int) $zeile['speicher'] >= self::SPEICHER_KNAPP),
];
}