where('status', 'active') ->when($datacenter !== null, fn ($q) => $q->where('datacenter', $datacenter)) ->get() ->map(fn (Host $host) => $host->availableGb()) ->max() ?? 0; } /** * Sellable packages that no host could currently take. * * Keyed by plan key, valued by what it needs and what the roomiest host has * left — an operator deciding whether to buy a machine needs the shortfall, * not a yes/no. * * @return array */ public function unplaceablePlans(?string $datacenter = null): array { try { $sellable = app(PlanCatalogue::class)->sellable(); } catch (Throwable) { // A catalogue that cannot be read is its own alarm elsewhere. This // is a capacity warning; it does not get to be the thing that takes // the console's overview page down. return []; } // No host at all is not a capacity problem — it is an installation // nobody has onboarded a machine into yet, and it has its own notices. // Without this, a fresh console greeted the operator with one warning // per sellable package before they had done anything at all. $hasHost = Host::query() ->where('status', 'active') ->when($datacenter !== null, fn ($q) => $q->where('datacenter', $datacenter)) ->exists(); if (! $hasHost) { return []; } $largest = $this->largestPlaceableGb($datacenter); $atRisk = []; foreach ($sellable as $key => $plan) { $needs = (int) ($plan['disk_gb'] ?? 0); if ($needs > 0 && $needs > $largest) { $atRisk[$key] = [ 'name' => (string) ($plan['name'] ?? $key), 'needs' => $needs, 'largest' => $largest, ]; } } return $atRisk; } }