Skip to content

Commit ff5e445

Browse files
committed
Feat: Manual cleanup button and unused volumes and network deletion
1 parent e42c7e2 commit ff5e445

File tree

6 files changed

+98
-28
lines changed

6 files changed

+98
-28
lines changed

app/Actions/Server/CleanupDocker.php

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,30 @@ class CleanupDocker
1111
use AsAction;
1212

1313
public function handle(Server $server)
14-
{
15-
16-
$commands = $this->getCommands();
17-
18-
foreach ($commands as $command) {
19-
instant_remote_process([$command], $server, false);
20-
}
21-
}
22-
23-
private function getCommands(): array
2414
{
2515
$settings = InstanceSettings::get();
2616
$helperImageVersion = data_get($settings, 'helper_version');
2717
$helperImage = config('coolify.helper_image');
28-
$helperImageWithVersion = config('coolify.helper_image').':'.$helperImageVersion;
18+
$helperImageWithVersion = "$helperImage:$helperImageVersion";
2919

30-
$commonCommands = [
20+
$commands = [
3121
'docker container prune -f --filter "label=coolify.managed=true"',
3222
'docker image prune -af --filter "label!=coolify.managed=true"',
3323
'docker builder prune -af',
34-
"docker images --filter before=$helperImageWithVersion --filter reference=$helperImage | grep $helperImage | awk '{print $3}' | xargs -r docker rmi",
24+
"docker images --filter before=$helperImageWithVersion --filter reference=$helperImage | grep $helperImage | awk '{print \$3}' | xargs -r docker rmi",
3525
];
3626

37-
return $commonCommands;
27+
$serverSettings = $server->settings;
28+
if ($serverSettings->delete_unused_volumes) {
29+
$commands[] = 'docker volume prune -af';
30+
}
31+
32+
if ($serverSettings->delete_unused_networks) {
33+
$commands[] = 'docker network prune -f';
34+
}
35+
36+
foreach ($commands as $command) {
37+
instant_remote_process([$command], $server, false);
38+
}
3839
}
3940
}

app/Jobs/DockerCleanupJob.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
2424

2525
public ?string $usageBefore = null;
2626

27-
public function __construct(public Server $server) {}
27+
public function __construct(public Server $server, public bool $manualCleanup = false) {}
2828

2929
public function middleware(): array
3030
{
@@ -42,10 +42,10 @@ public function handle(): void
4242
if (! $this->server->isFunctional()) {
4343
return;
4444
}
45-
if ($this->server->settings->force_docker_cleanup) {
46-
Log::info('DockerCleanupJob force cleanup on '.$this->server->name);
47-
CleanupDocker::run(server: $this->server);
4845

46+
if ($this->manualCleanup || $this->server->settings->force_docker_cleanup) {
47+
Log::info('DockerCleanupJob ' . ($this->manualCleanup ? 'manual' : 'force') . ' cleanup on ' . $this->server->name);
48+
CleanupDocker::run(server: $this->server);
4949
return;
5050
}
5151

app/Livewire/Server/Form.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use App\Jobs\PullSentinelImageJob;
88
use App\Models\Server;
99
use Livewire\Component;
10+
use App\Jobs\DockerCleanupJob;
1011

1112
class Form extends Component
1213
{
@@ -24,6 +25,9 @@ class Form extends Component
2425

2526
public $timezones;
2627

28+
public $delete_unused_volumes = false;
29+
public $delete_unused_networks = false;
30+
2731
protected $listeners = [
2832
'serverInstalled',
2933
'refreshServerShow' => 'serverInstalled',
@@ -53,6 +57,8 @@ class Form extends Component
5357
'server.settings.force_docker_cleanup' => 'required|boolean',
5458
'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string',
5559
'server.settings.docker_cleanup_threshold' => 'required_if:server.settings.force_docker_cleanup,false|integer|min:1|max:100',
60+
'server.settings.delete_unused_volumes' => 'boolean',
61+
'server.settings.delete_unused_networks' => 'boolean',
5662
];
5763

5864
protected $validationAttributes = [
@@ -74,6 +80,8 @@ class Form extends Component
7480
'server.settings.metrics_history_days' => 'Metrics History',
7581
'server.settings.is_server_api_enabled' => 'Server API',
7682
'server.settings.server_timezone' => 'Server Timezone',
83+
'server.settings.delete_unused_volumes' => 'Delete Unused Volumes',
84+
'server.settings.delete_unused_networks' => 'Delete Unused Networks',
7785
];
7886

7987
public function mount(Server $server)
@@ -83,6 +91,8 @@ public function mount(Server $server)
8391
$this->wildcard_domain = $this->server->settings->wildcard_domain;
8492
$this->server->settings->docker_cleanup_threshold = $this->server->settings->docker_cleanup_threshold;
8593
$this->server->settings->docker_cleanup_frequency = $this->server->settings->docker_cleanup_frequency;
94+
$this->server->settings->delete_unused_volumes = $server->settings->delete_unused_volumes;
95+
$this->server->settings->delete_unused_networks = $server->settings->delete_unused_networks;
8696
}
8797

8898
public function updated($field)
@@ -126,6 +136,7 @@ public function instantSave()
126136
try {
127137
refresh_server_connection($this->server->privateKey);
128138
$this->validateServer(false);
139+
129140
$this->server->settings->save();
130141
$this->server->save();
131142
$this->dispatch('success', 'Server updated.');
@@ -143,6 +154,7 @@ public function instantSave()
143154
ray('Sentinel is not enabled');
144155
StopSentinel::dispatch($this->server);
145156
}
157+
$this->server->settings->save();
146158
// $this->checkPortForServerApi();
147159

148160
} catch (\Throwable $e) {
@@ -223,9 +235,9 @@ public function submit()
223235
$this->server->settings->server_timezone = $newTimezone;
224236
$this->server->settings->save();
225237
}
226-
227238
$this->server->settings->save();
228239
$this->server->save();
240+
229241
$this->dispatch('success', 'Server updated.');
230242
} catch (\Throwable $e) {
231243
return handleError($e, $this);
@@ -238,4 +250,14 @@ public function updatedServerSettingsServerTimezone($value)
238250
$this->server->settings->save();
239251
$this->dispatch('success', 'Server timezone updated.');
240252
}
253+
254+
public function manualCleanup()
255+
{
256+
try {
257+
DockerCleanupJob::dispatch($this->server, true);
258+
$this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.');
259+
} catch (\Throwable $e) {
260+
return handleError($e, $this);
261+
}
262+
}
241263
}

app/Models/Server.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
'validation_logs' => ['type' => 'string'],
3838
'log_drain_notification_sent' => ['type' => 'boolean'],
3939
'swarm_cluster' => ['type' => 'string'],
40+
'delete_unused_volumes' => ['type' => 'boolean'],
41+
'delete_unused_networks' => ['type' => 'boolean'],
4042
]
4143
)]
4244

@@ -106,6 +108,8 @@ protected static function booted()
106108
'proxy' => SchemalessAttributes::class,
107109
'logdrain_axiom_api_key' => 'encrypted',
108110
'logdrain_newrelic_license_key' => 'encrypted',
111+
'delete_unused_volumes' => 'boolean',
112+
'delete_unused_networks' => 'boolean',
109113
];
110114

111115
protected $schemalessAttributes = [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up()
10+
{
11+
Schema::table('server_settings', function (Blueprint $table) {
12+
$table->boolean('delete_unused_volumes')->default(false);
13+
$table->boolean('delete_unused_networks')->default(false);
14+
});
15+
}
16+
17+
public function down()
18+
{
19+
Schema::table('server_settings', function (Blueprint $table) {
20+
$table->dropColumn('delete_unused_volumes');
21+
$table->dropColumn('delete_unused_networks');
22+
});
23+
}
24+
};

resources/views/livewire/server/form.blade.php

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,26 +183,45 @@ class="px-4 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-coolgray-300 tex
183183

184184
@if ($server->isFunctional())
185185
<h3 class="pt-4">Settings</h3>
186-
<div class="flex flex-col gap-1">
186+
<div class="flex flex-col gap-4">
187187
<div class="flex flex-col gap-2">
188-
<div class="flex flex-col flex-wrap gap-2 sm:flex-nowrap">
188+
<div class="flex flex-wrap items-center gap-4">
189189
<div class="w-64">
190190
<x-forms.checkbox
191191
helper="Enable force Docker Cleanup. This will cleanup build caches / unused images / etc."
192192
instantSave id="server.settings.force_docker_cleanup" label="Force Docker Cleanup" />
193193
</div>
194-
@if ($server->settings->force_docker_cleanup)
195-
<x-forms.input placeholder="*/10 * * * *" id="server.settings.docker_cleanup_frequency"
196-
label="Docker cleanup frequency" required
197-
helper="Cron expression for Docker Cleanup.<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every night at midnight." />
198-
@else
194+
<x-forms.button wire:click="manualCleanup">
195+
Manually Trigger Cleanup
196+
</x-forms.button>
197+
</div>
198+
@if ($server->settings->force_docker_cleanup)
199+
<x-forms.input placeholder="*/10 * * * *" id="server.settings.docker_cleanup_frequency"
200+
label="Docker cleanup frequency" required
201+
helper="Cron expression for Docker Cleanup.<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every night at midnight." />
202+
@else
199203
<x-forms.input id="server.settings.docker_cleanup_threshold"
200204
label="Docker cleanup threshold (%)" required
201205
helper="The Docker cleanup tasks will run when the disk usage exceeds this threshold." />
202-
@endif
206+
@endif
207+
<div x-data="{ open: false }" class="mt-4 max-w-md">
208+
<button @click="open = !open" type="button" class="flex items-center justify-between w-full text-left text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100">
209+
<span>Advanced Options</span>
210+
<svg :class="{'rotate-180': open}" class="w-5 h-5 transition-transform duration-200" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
211+
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
212+
</svg>
213+
</button>
214+
<div x-show="open" class="mt-2 space-y-2">
215+
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2"><strong>Only enable if you know what you are doing! As data cold be lost and functional issues might occur.</strong></p>
216+
<x-forms.checkbox instantSave id="server.settings.delete_unused_volumes" label="Delete Unused Volumes"
217+
helper="This will remove all unused Docker volumes during cleanup. <br>Volumes are not removed by default to prevent data loss as if you have stopped a container that has a volume mounted your data would be lost." />
218+
<x-forms.checkbox instantSave id="server.settings.delete_unused_networks" label="Delete Unused Networks"
219+
helper="This will remove all unused Docker networks during cleanup. <br>Networks are not removed by default to prevent functional issues as if you have stopped a container that has a network attached to it the network will not be removed and other containers might not be able to connect to it anymore." />
220+
</div>
203221
</div>
204222
</div>
205-
<div class="flex flex-wrap gap-2 sm:flex-nowrap">
223+
224+
<div class="flex flex-wrap gap-4 sm:flex-nowrap">
206225
<x-forms.input id="server.settings.concurrent_builds" label="Number of concurrent builds" required
207226
helper="You can specify the number of simultaneous build processes/deployments that should run concurrently." />
208227
<x-forms.input id="server.settings.dynamic_timeout" label="Deployment timeout (seconds)" required

0 commit comments

Comments
 (0)