forked from coollabsio/coolify
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLocalPersistentVolume.php
More file actions
124 lines (103 loc) · 3.91 KB
/
Copy pathLocalPersistentVolume.php
File metadata and controls
124 lines (103 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Symfony\Component\Yaml\Yaml;
/**
* @property int $id
* @property string $name
* @property string $mount_path
* @property string|null $host_path
* @property Application|Service|ServiceApplication|ServiceDatabase|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|null $resource
*/
class LocalPersistentVolume extends Model
{
protected $guarded = [];
public function application(): \Illuminate\Database\Eloquent\Relations\MorphTo
{
return $this->morphTo('resource');
}
public function service(): \Illuminate\Database\Eloquent\Relations\MorphTo
{
return $this->morphTo('resource');
}
public function database(): \Illuminate\Database\Eloquent\Relations\MorphTo
{
return $this->morphTo('resource');
}
protected function customizeName($value)
{
return str($value)->trim()->value;
}
protected function mountPath(): Attribute
{
return Attribute::make(
set: fn (string $value) => str($value)->trim()->start('/')->value
);
}
protected function hostPath(): Attribute
{
return Attribute::make(
set: function (?string $value) {
if ($value) {
return str($value)->trim()->start('/')->value;
} else {
return $value;
}
}
);
}
// 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;
}
}
}