instance($run); $node = (string) $run->context('node'); $vmid = (int) $run->context('vmid'); $fqdn = $instance->subdomain.'.'.ProvisioningSettings::dnsZone(); $pve = $this->pve->forHost($instance->host); $occ = 'cd /opt/nextcloud && docker compose exec -T app php occ '; // TLS + routing actually serving. if (! $instance->cert_ok || ! $this->traefik->certReachable($fqdn)) { return StepResult::fail('acceptance_failed:cert'); } // Nextcloud installed, not in maintenance, DB reachable. $status = $pve->guestExec($node, $vmid, $occ.'status --output=json'); $health = json_decode($status['out-data'] ?? '', true) ?: []; if ((int) ($status['exitcode'] ?? 1) !== 0 || ($health['installed'] ?? false) !== true || ($health['maintenance'] ?? false) !== false) { return StepResult::fail('acceptance_failed:nextcloud'); } // The admin account exists and is queryable. $admin = $pve->guestExec($node, $vmid, $occ.'user:info '.escapeshellarg((string) $instance->nc_admin_ref)); if ((int) ($admin['exitcode'] ?? 1) !== 0) { return StepResult::fail('acceptance_failed:admin'); } // A backup job is registered. if (! $this->hasResource($run, 'backup_job_id')) { return StepResult::fail('acceptance_failed:backup'); } // Monitoring is a SECONDARY signal: it depends on an external poller, and // a freshly created monitor legitimately has no heartbeat yet. The four // checks above already prove the service itself works, so only gate on // monitoring when the operator declared it required — otherwise record it // and deliver (consistent with RegisterMonitoring's degrade-on-outage). $target = $instance->monitoringTargets()->first(); $monitoringGreen = $target !== null && $this->monitoring->isHealthy($target->external_id); if (! $monitoringGreen) { if (config('provisioning.monitoring.required', false)) { return StepResult::fail('acceptance_failed:monitoring'); } $run->events()->create([ 'step' => $this->key(), 'attempt' => $run->attempt, 'outcome' => 'info', 'message' => $target === null ? 'Abnahme ohne Monitoring: kein Monitor registriert.' : 'Abnahme ohne Monitoring-Bestätigung: Monitor noch nicht grün.', ]); } return StepResult::advance(); } }