feat: docker volume data cloning
- UI implementation - functional implementation for databases - volume gets cloned successfully
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Project;
|
namespace App\Livewire\Project;
|
||||||
|
|
||||||
|
use App\Actions\Application\StopApplication;
|
||||||
|
use App\Actions\Database\StartDatabase;
|
||||||
|
use App\Actions\Database\StopDatabase;
|
||||||
|
use App\Jobs\VolumeCloneJob;
|
||||||
use App\Models\Environment;
|
use App\Models\Environment;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
@@ -34,6 +38,8 @@ class CloneMe extends Component
|
|||||||
|
|
||||||
public string $newName = '';
|
public string $newName = '';
|
||||||
|
|
||||||
|
public bool $cloneVolumeData = false;
|
||||||
|
|
||||||
protected $messages = [
|
protected $messages = [
|
||||||
'selectedServer' => 'Please select a server.',
|
'selectedServer' => 'Please select a server.',
|
||||||
'selectedDestination' => 'Please select a server & destination.',
|
'selectedDestination' => 'Please select a server & destination.',
|
||||||
@@ -50,6 +56,12 @@ class CloneMe extends Component
|
|||||||
$this->newName = str($this->project->name.'-clone-'.(string) new Cuid2)->slug();
|
$this->newName = str($this->project->name.'-clone-'.(string) new Cuid2)->slug();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toggleVolumeCloning(bool $value)
|
||||||
|
{
|
||||||
|
$this->cloneVolumeData = $value;
|
||||||
|
$this->dispatch('refresh');
|
||||||
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.project.clone-me');
|
return view('livewire.project.clone-me');
|
||||||
@@ -192,6 +204,27 @@ class CloneMe extends Component
|
|||||||
'resource_id' => $newApplication->id,
|
'resource_id' => $newApplication->id,
|
||||||
]);
|
]);
|
||||||
$newPersistentVolume->save();
|
$newPersistentVolume->save();
|
||||||
|
|
||||||
|
if ($this->cloneVolumeData) {
|
||||||
|
try {
|
||||||
|
StopApplication::dispatch($application, false, false);
|
||||||
|
$sourceVolume = $volume->name;
|
||||||
|
$targetVolume = $newPersistentVolume->name;
|
||||||
|
$server = $application->destination->server;
|
||||||
|
|
||||||
|
VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $server, $newPersistentVolume);
|
||||||
|
|
||||||
|
queue_application_deployment(
|
||||||
|
deployment_uuid: (string) new Cuid2,
|
||||||
|
application: $application,
|
||||||
|
server: $server,
|
||||||
|
destination: $application->destination,
|
||||||
|
no_questions_asked: true
|
||||||
|
);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
logger()->error("Failed to copy volume data for {$volume->name}: ".$e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileStorages = $application->fileStorages()->get();
|
$fileStorages = $application->fileStorages()->get();
|
||||||
@@ -276,6 +309,22 @@ class CloneMe extends Component
|
|||||||
'resource_id' => $newDatabase->id,
|
'resource_id' => $newDatabase->id,
|
||||||
]);
|
]);
|
||||||
$newPersistentVolume->save();
|
$newPersistentVolume->save();
|
||||||
|
|
||||||
|
if ($this->cloneVolumeData) {
|
||||||
|
try {
|
||||||
|
StopDatabase::dispatch($database);
|
||||||
|
$sourceVolume = $volume->name;
|
||||||
|
$targetVolume = $newPersistentVolume->name;
|
||||||
|
$server = $database->destination->server;
|
||||||
|
|
||||||
|
VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $server, $newPersistentVolume);
|
||||||
|
|
||||||
|
StartDatabase::dispatch($database);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Log error but continue with cloning
|
||||||
|
logger()->error("Failed to copy volume data for {$volume->name}: ".$e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileStorages = $database->fileStorages()->get();
|
$fileStorages = $database->fileStorages()->get();
|
||||||
|
|||||||
@@ -9,7 +9,39 @@
|
|||||||
<x-forms.input required id="newName" label="New Name" />
|
<x-forms.input required id="newName" label="New Name" />
|
||||||
<x-forms.button isHighlighted wire:click="clone('project')" class="mt-4">Clone to a new Project</x-forms.button>
|
<x-forms.button isHighlighted wire:click="clone('project')" class="mt-4">Clone to a new Project</x-forms.button>
|
||||||
<x-forms.button isHighlighted wire:click="clone('environment')" class="mt-4">Clone to a new Environment</x-forms.button>
|
<x-forms.button isHighlighted wire:click="clone('environment')" class="mt-4">Clone to a new Environment</x-forms.button>
|
||||||
<h3 class="pt-4 pb-2">Servers</h3>
|
|
||||||
|
<div class="mt-8">
|
||||||
|
<h3 class="text-lg font-bold mb-2">Clone Volume Data</h3>
|
||||||
|
<div class="text-sm text-gray-600 dark:text-gray-300 mb-4">
|
||||||
|
Clone your volume data to the new resources volumes. This process requires a brief container downtime to ensure data consistency.
|
||||||
|
</div>
|
||||||
|
<div wire:poll>
|
||||||
|
@if(!$cloneVolumeData)
|
||||||
|
<div wire:key="volume-disabled">
|
||||||
|
<x-modal-confirmation
|
||||||
|
title="Enable Volume Data Cloning"
|
||||||
|
buttonTitle="Enable Cloning"
|
||||||
|
submitAction="toggleVolumeCloning(true)"
|
||||||
|
:actions="['This will temporarily stop all the containers to copy volume data.', 'The process runs in the background and may take a few minutes.']"
|
||||||
|
:confirmWithPassword="false"
|
||||||
|
:confirmWithText="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div wire:key="volume-enabled" class="max-w-md">
|
||||||
|
<x-forms.checkbox
|
||||||
|
label="Copy Volume Data"
|
||||||
|
id="cloneVolumeData"
|
||||||
|
wire:model="cloneVolumeData"
|
||||||
|
wire:change="toggleVolumeCloning(false)"
|
||||||
|
:checked="$cloneVolumeData"
|
||||||
|
helper="Containers will be temporarily stopped during the cloning process." />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="pt-8 pb-2">Servers</h3>
|
||||||
<div>Choose the server and network to clone the resources to.</div>
|
<div>Choose the server and network to clone the resources to.</div>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
@foreach ($servers->sortBy('id') as $server)
|
@foreach ($servers->sortBy('id') as $server)
|
||||||
@@ -29,7 +61,7 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="pt-4 pb-2">Resources</h3>
|
<h3 class="pt-8 pb-2">Resources</h3>
|
||||||
<div>These will be cloned to the new project</div>
|
<div>These will be cloned to the new project</div>
|
||||||
<div class="grid grid-cols-1 gap-2 pt-4 opacity-95 lg:grid-cols-2 xl:grid-cols-3">
|
<div class="grid grid-cols-1 gap-2 pt-4 opacity-95 lg:grid-cols-2 xl:grid-cols-3">
|
||||||
@foreach ($environment->applications->sortBy('name') as $application)
|
@foreach ($environment->applications->sortBy('name') as $application)
|
||||||
|
|||||||
Reference in New Issue
Block a user