Add managed registry provisioning, pruning, and readiness tracking
This commit is contained in:
@@ -2,11 +2,15 @@
|
||||
|
||||
namespace App\Jobs\Services;
|
||||
|
||||
use App\Enums\BuildArtifactStatus;
|
||||
use App\Enums\OperationStatus;
|
||||
use App\Enums\RegistryType;
|
||||
use App\Enums\ServiceStatus;
|
||||
use App\Models\BuildArtifact;
|
||||
use App\Models\Environment;
|
||||
use App\Models\Operation;
|
||||
use App\Models\OperationStep;
|
||||
use App\Models\Registry;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use App\Models\ServiceReplica;
|
||||
@@ -110,6 +114,9 @@ class RunStep implements ShouldQueue
|
||||
if ($operation->is($this->step->operation)) {
|
||||
$this->markTargetCompleted();
|
||||
}
|
||||
|
||||
$this->markRegistryHealthOperationCompleted($operation);
|
||||
$this->markRegistryMaintenanceOperationCompleted($operation);
|
||||
}
|
||||
|
||||
private function dispatchNextChildOperation(Operation $operation): bool
|
||||
@@ -166,6 +173,7 @@ class RunStep implements ShouldQueue
|
||||
$target instanceof ServiceReplica => $target->server,
|
||||
$target instanceof Service => $target->replicas()->with('server')->first()?->server ?: $target->server,
|
||||
$target instanceof ServiceSlice => $target->service->replicas()->with('server')->first()?->server ?: $target->service->server,
|
||||
$target instanceof Server => $target,
|
||||
$target instanceof Environment => $target->services()->with(['server', 'replicas.server'])->get()
|
||||
->flatMap(fn (Service $service) => $service->replicas->pluck('server')->filter())
|
||||
->first() ?: $target->services()->with('server')->get()->pluck('server')->filter()->first(),
|
||||
@@ -190,10 +198,12 @@ class RunStep implements ShouldQueue
|
||||
'status' => OperationStatus::FAILED,
|
||||
'finished_at' => now(),
|
||||
'error_logs' => $this->step->error_logs."\n".trim($message),
|
||||
'secrets' => null,
|
||||
]);
|
||||
|
||||
$this->step->operation->steps()->where('order', '>', $this->step->order)->update([
|
||||
'status' => OperationStatus::CANCELLED,
|
||||
'secrets' => null,
|
||||
]);
|
||||
|
||||
$this->step->operation->update([
|
||||
@@ -203,13 +213,114 @@ class RunStep implements ShouldQueue
|
||||
|
||||
$this->cancelDescendants($this->step->operation);
|
||||
$this->cancelPendingSiblingsAndAncestors($this->step->operation);
|
||||
$this->markRegistryHealthOperationFailed($this->step->operation, trim($message));
|
||||
}
|
||||
|
||||
private function markRegistryHealthOperationCompleted(Operation $operation): void
|
||||
{
|
||||
if ($operation->kind !== \App\Enums\OperationKind::REGISTRY_HEALTH_CHECK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($operation->parent_id !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$registry = $this->managedRegistryForOperation($operation);
|
||||
|
||||
if (! $registry instanceof Registry) {
|
||||
return;
|
||||
}
|
||||
|
||||
$checks = collect($registry->readiness_checks ?? [])
|
||||
->map(fn (): string => 'passed')
|
||||
->all();
|
||||
|
||||
$registry->forceFill([
|
||||
'readiness_checks' => $checks,
|
||||
])->save();
|
||||
$registry->markHealthy('Managed registry smoke checks passed.');
|
||||
}
|
||||
|
||||
private function markRegistryHealthOperationFailed(Operation $operation, string $message): void
|
||||
{
|
||||
if ($operation->kind !== \App\Enums\OperationKind::REGISTRY_HEALTH_CHECK) {
|
||||
return;
|
||||
}
|
||||
|
||||
$registry = $this->managedRegistryForOperation($operation);
|
||||
|
||||
$registry?->markUnhealthy('Managed registry smoke check failed: '.$message);
|
||||
}
|
||||
|
||||
private function markRegistryMaintenanceOperationCompleted(Operation $operation): void
|
||||
{
|
||||
if ($operation->kind !== \App\Enums\OperationKind::REGISTRY_MAINTENANCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$registry = $this->managedRegistryForOperation($operation);
|
||||
|
||||
if (! $registry instanceof Registry) {
|
||||
return;
|
||||
}
|
||||
|
||||
$artifactIds = collect($operation->metadata['artifact_ids'] ?? [])
|
||||
->filter(fn ($id): bool => is_numeric($id))
|
||||
->map(fn ($id): int => (int) $id)
|
||||
->values();
|
||||
|
||||
BuildArtifact::query()
|
||||
->whereIn('id', $artifactIds)
|
||||
->where('status', BuildArtifactStatus::PRUNABLE)
|
||||
->where('registry_ref', 'like', rtrim((string) $registry->url, '/').'/%')
|
||||
->each(function ($artifact): void {
|
||||
$artifact->update([
|
||||
'status' => BuildArtifactStatus::PRUNED,
|
||||
'metadata' => [
|
||||
...($artifact->metadata ?? []),
|
||||
'pruned_at' => now()->toIso8601String(),
|
||||
],
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private function managedRegistryForOperation(Operation $operation): ?Registry
|
||||
{
|
||||
$registryId = $operation->metadata['registry_id'] ?? $operation->parent?->metadata['registry_id'] ?? null;
|
||||
|
||||
if ($registryId) {
|
||||
$registry = Registry::query()
|
||||
->where('type', RegistryType::MANAGED->value)
|
||||
->find($registryId);
|
||||
|
||||
if ($registry instanceof Registry) {
|
||||
return $registry;
|
||||
}
|
||||
}
|
||||
|
||||
$server = $operation->target;
|
||||
|
||||
if (! $server instanceof Server) {
|
||||
$server = $operation->parent?->target;
|
||||
}
|
||||
|
||||
if (! $server instanceof Server) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Registry::query()
|
||||
->where('type', RegistryType::MANAGED->value)
|
||||
->where('control_server_id', $server->id)
|
||||
->first();
|
||||
}
|
||||
|
||||
private function cancelDescendants(Operation $operation): void
|
||||
{
|
||||
$operation->children()->with('children')->get()->each(function (Operation $child): void {
|
||||
$child->steps()->where('status', OperationStatus::PENDING)->update([
|
||||
$child->steps()->whereIn('status', [OperationStatus::PENDING, OperationStatus::IN_PROGRESS])->update([
|
||||
'status' => OperationStatus::CANCELLED,
|
||||
'secrets' => null,
|
||||
]);
|
||||
$child->update([
|
||||
'status' => OperationStatus::CANCELLED,
|
||||
@@ -232,8 +343,9 @@ class RunStep implements ShouldQueue
|
||||
->whereIn('status', [OperationStatus::PENDING, OperationStatus::IN_PROGRESS])
|
||||
->get()
|
||||
->each(function (Operation $sibling): void {
|
||||
$sibling->steps()->where('status', OperationStatus::PENDING)->update([
|
||||
$sibling->steps()->whereIn('status', [OperationStatus::PENDING, OperationStatus::IN_PROGRESS])->update([
|
||||
'status' => OperationStatus::CANCELLED,
|
||||
'secrets' => null,
|
||||
]);
|
||||
$sibling->update([
|
||||
'status' => OperationStatus::CANCELLED,
|
||||
|
||||
Reference in New Issue
Block a user