80 lines
3.1 KiB
PHP
80 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Provisioning\Steps\Customer;
|
|
|
|
use App\Models\ProvisioningRun;
|
|
use App\Provisioning\StepResult;
|
|
use App\Services\Monitoring\MonitoringClient;
|
|
use App\Support\ProvisioningSettings;
|
|
|
|
class RegisterMonitoring extends CustomerStep
|
|
{
|
|
public function __construct(private MonitoringClient $monitoring) {}
|
|
|
|
public function key(): string
|
|
{
|
|
return 'register_monitoring';
|
|
}
|
|
|
|
public function maxDuration(): int
|
|
{
|
|
return 120;
|
|
}
|
|
|
|
public function execute(ProvisioningRun $run): StepResult
|
|
{
|
|
if ($this->hasResource($run, 'monitoring_target_id')) {
|
|
return StepResult::advance();
|
|
}
|
|
|
|
$instance = $this->instance($run);
|
|
$url = 'https://'.$instance->subdomain.'.'.ProvisioningSettings::dnsZone().'/status.php';
|
|
|
|
// Register with the monitoring service [E] before recording it.
|
|
// Monitoring is observability, not the product: a paid customer's cloud
|
|
// must not fail to be delivered because Kuma/the bridge is down. Retry a
|
|
// few times, then continue DEGRADED with a visible event — unless the
|
|
// operator declares monitoring mandatory.
|
|
try {
|
|
$targetId = $this->monitoring->registerTarget($instance->subdomain, $url);
|
|
} catch (\Throwable $e) {
|
|
if (config('provisioning.monitoring.required', false)) {
|
|
throw $e; // operator wants monitoring to gate delivery
|
|
}
|
|
|
|
// `attempt` is 0-based (this call IS attempt number attempt+1), so
|
|
// compare one-based: MONITORING_ATTEMPTS=2 really means two tries.
|
|
// Cap at the run's own retry budget — otherwise a large ATTEMPTS
|
|
// value would burn through max_attempts and fail the run, which is
|
|
// exactly what this degradation exists to prevent.
|
|
$configured = max(1, (int) config('provisioning.monitoring.attempts', 2));
|
|
$allowed = max(1, min($configured, (int) $run->max_attempts));
|
|
if ($run->attempt + 1 < $allowed) {
|
|
return StepResult::retry(30, 'monitoring unavailable: '.$e->getMessage());
|
|
}
|
|
|
|
// Give up on monitoring, keep the cloud. Recorded so it is visible in
|
|
// the admin console rather than silently missing.
|
|
$run->events()->create([
|
|
'step' => $this->key(),
|
|
'attempt' => $run->attempt,
|
|
'outcome' => 'info',
|
|
'message' => 'Monitoring übersprungen (Dienst nicht erreichbar): '.$e->getMessage(),
|
|
]);
|
|
|
|
return StepResult::advance();
|
|
}
|
|
|
|
// Local row BEFORE the breadcrumb (the short-circuit guard).
|
|
$instance->monitoringTargets()->firstOrCreate(
|
|
['external_id' => $targetId],
|
|
// 'unknown', not 'up': registering a check is not the same as
|
|
// passing one, and the sync job is what turns it into a verdict.
|
|
['url' => $url, 'status' => 'unknown'],
|
|
);
|
|
$this->recordResource($run, $instance->host, 'monitoring_target_id', $targetId);
|
|
|
|
return StepResult::advance();
|
|
}
|
|
}
|