mirror of
https://github.com/tiennm99/coolify.git
synced 2026-04-20 07:21:01 +00:00
feat(storage): add read-only volume handling and UI notifications
- Introduced `isReadOnlyVolume` method in `LocalFileVolume` and `LocalPersistentVolume` models to determine if a volume is read-only based on Docker Compose configuration. - Updated `FileStorage` and `Show` components to set `isReadOnly` state during mounting. - Enhanced UI to display notifications for read-only volumes, preventing modification actions in the interface. - Refactored file storage and directory management forms to conditionally enable or disable actions based on read-only status.
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class LocalPersistentVolume extends Model
|
||||
{
|
||||
@@ -48,4 +49,69 @@ class LocalPersistentVolume extends Model
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Check if this volume is read-only by parsing the docker-compose content
|
||||
public function isReadOnlyVolume(): bool
|
||||
{
|
||||
try {
|
||||
// Get the resource (can be application, service, or database)
|
||||
$resource = $this->resource;
|
||||
if (! $resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only check for services
|
||||
if (! method_exists($resource, 'service')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$actualService = $resource->service;
|
||||
if (! $actualService || ! $actualService->docker_compose_raw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the docker-compose content
|
||||
$compose = Yaml::parse($actualService->docker_compose_raw);
|
||||
if (! isset($compose['services'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the service that this volume belongs to
|
||||
$serviceName = $resource->name;
|
||||
if (! isset($compose['services'][$serviceName]['volumes'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$volumes = $compose['services'][$serviceName]['volumes'];
|
||||
|
||||
// Check each volume to find a match
|
||||
foreach ($volumes as $volume) {
|
||||
// Volume can be string like "host:container:ro" or "host:container"
|
||||
if (is_string($volume)) {
|
||||
$parts = explode(':', $volume);
|
||||
|
||||
// Check if this volume matches our mount_path
|
||||
if (count($parts) >= 2) {
|
||||
$containerPath = $parts[1];
|
||||
$options = $parts[2] ?? null;
|
||||
|
||||
// Match based on mount_path
|
||||
// Remove leading slash from mount_path if present for comparison
|
||||
$mountPath = str($this->mount_path)->ltrim('/')->toString();
|
||||
$containerPathClean = str($containerPath)->ltrim('/')->toString();
|
||||
|
||||
if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) {
|
||||
return $options === 'ro';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (\Throwable $e) {
|
||||
ray($e->getMessage(), 'Error checking read-only persistent volume');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user