CluPilotCloud/app/Support/Readiness/ProvisioningChecks.php

108 lines
4.8 KiB
PHP

<?php
namespace App\Support\Readiness;
use App\Models\Host;
use App\Models\PlanVersion;
use App\Services\Secrets\SecretVault;
use App\Support\ProvisioningSettings;
/**
* What has to be in place for a PAID order to actually turn into a running,
* reachable machine: somewhere to put it, a name for it, and a router that
* knows about it.
*/
final class ProvisioningChecks
{
public const GROUP = 'provisioning';
/** @return array<int, Check> */
public static function all(): array
{
return [
new Check(
key: 'provisioning.dns_token',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.provisioning.dns_token'),
breaks: __('readiness.provisioning.dns_token_breaks'),
// The DNS card (token + zone + Traefik path) is on the
// 'services' tab — 'integrations' is not a member of
// Integrations::TABS at all (Fix-Runde, Befund 1).
tab: 'services',
satisfied: filled(app(SecretVault::class)->get('dns.token')),
),
new Check(
key: 'provisioning.dns_zone',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.provisioning.dns_zone'),
breaks: __('readiness.provisioning.dns_zone_breaks'),
// Same DNS card as provisioning.dns_token just above.
tab: 'services',
satisfied: filled(ProvisioningSettings::dnsZone()),
),
new Check(
key: 'provisioning.traefik_path',
group: self::GROUP,
severity: Check::SEVERITY_WARNING,
label: __('readiness.provisioning.traefik_path'),
breaks: __('readiness.provisioning.traefik_path_breaks'),
// Same DNS card — traefikDynamicPath is a field on it.
tab: 'services',
satisfied: filled(ProvisioningSettings::traefikDynamicPath()),
),
new Check(
key: 'provisioning.usable_host',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.provisioning.usable_host'),
breaks: __('readiness.provisioning.usable_host_breaks'),
tab: 'hosts',
// `active` ALONE is not enough. A host without a readable
// token is still selectable to ReserveResources, and the
// order then dies in CloneVirtualMachine — after payment.
satisfied: Host::query()
->where('status', 'active')
->whereNotNull('api_token_ref')
->exists(),
),
new Check(
key: 'provisioning.vm_template',
group: self::GROUP,
severity: Check::SEVERITY_BLOCKING,
label: __('readiness.provisioning.vm_template'),
breaks: __('readiness.provisioning.vm_template_breaks'),
tab: 'plans',
// A field check only. Whether the template actually EXISTS on
// a node is answered by the button in Task 9 — that has to
// ask Proxmox, and a live API call does not belong on every
// page load of this readiness page.
satisfied: PlanVersion::query()
->whereNotNull('published_at')
->whereNull('template_vmid')
->doesntExist(),
),
new Check(
key: 'provisioning.monitoring_token',
group: self::GROUP,
// Follows the same condition RegisterMonitoring itself reads
// (RegisterMonitoring.php: `if (config('provisioning.
// monitoring.required', false)) { throw $e; }`). Warning by
// default — monitoring degrades, then the run continues — but
// an operator who has switched that setting on made
// monitoring a real gate, and a fixed severity would then
// claim a looser rule than the pipeline actually enforces.
severity: config('provisioning.monitoring.required', false)
? Check::SEVERITY_BLOCKING
: Check::SEVERITY_WARNING,
label: __('readiness.provisioning.monitoring_token'),
breaks: __('readiness.provisioning.monitoring_token_breaks'),
// The monitoring card is on the 'services' tab too.
tab: 'services',
satisfied: filled(app(SecretVault::class)->get('monitoring.token')),
),
];
}
}