CluPilotCloud/app/Support/Readiness/ProvisioningChecks.php

97 lines
4.0 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'),
tab: 'integrations',
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'),
tab: 'integrations',
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'),
tab: 'integrations',
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,
severity: Check::SEVERITY_WARNING,
label: __('readiness.provisioning.monitoring_token'),
breaks: __('readiness.provisioning.monitoring_token_breaks'),
tab: 'integrations',
// Warning, never blocking: RegisterMonitoring itself already
// degrades (retries, then continues) rather than fail the run
// — this page must not claim a stricter rule than the pipeline
// actually enforces.
satisfied: filled(app(SecretVault::class)->get('monitoring.token')),
),
];
}
}