From e2e68136329a05e0e3189da5260d575b44d9ef43 Mon Sep 17 00:00:00 2001
From: Stuart Rowlands
Date: Fri, 5 Jan 2024 15:06:36 +1000
Subject: [PATCH] Functional scheduled executions. Display last executions.
Support for Services.
---
app/Jobs/ScheduledTaskJob.php | 80 ++++++++++++++-----
.../Project/Shared/ScheduledTask/All.php | 1 +
.../Shared/ScheduledTask/Executions.php | 28 +++++++
app/Models/Service.php | 4 +
...31_173041_create_scheduled_tasks_table.php | 1 +
.../livewire/project/service/index.blade.php | 7 ++
.../shared/scheduled-task/all.blade.php | 16 ++--
.../scheduled-task/executions.blade.php | 27 +++++++
.../shared/scheduled-task/show.blade.php | 14 +++-
routes/web.php | 2 +
10 files changed, 144 insertions(+), 36 deletions(-)
create mode 100644 app/Livewire/Project/Shared/ScheduledTask/Executions.php
create mode 100644 resources/views/livewire/project/shared/scheduled-task/executions.blade.php
diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php
index f810e746a..104b5f7e3 100644
--- a/app/Jobs/ScheduledTaskJob.php
+++ b/app/Jobs/ScheduledTaskJob.php
@@ -3,17 +3,18 @@
namespace App\Jobs;
use App\Models\ScheduledTask;
+use App\Models\ScheduledTaskExecution;
use App\Models\Server;
use App\Models\Application;
use App\Models\Service;
-use Carbon\Carbon;
+use App\Models\Team;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
-use Illuminate\Support\Str;
+use Illuminate\Support\Collection;
use Throwable;
class ScheduledTaskJob implements ShouldQueue
@@ -25,13 +26,10 @@ class ScheduledTaskJob implements ShouldQueue
public ScheduledTask $task;
public Application|Service $resource;
- public ?string $container_name = null;
- public ?string $directory_name = null;
- public ?ScheduledTaskExecution $backup_log = null;
+ public ?ScheduledTaskExecution $task_log = null;
public string $task_status = 'failed';
- public int $size = 0;
- public ?string $backup_output = null;
- public ?S3Storage $s3 = null;
+ public ?string $task_output = null;
+ public array $containers = [];
public function __construct($task)
{
@@ -41,6 +39,7 @@ public function __construct($task)
} else if ($application = $task->application()->first()) {
$this->resource = $application;
}
+ $this->team = Team::find($task->team_id);
}
public function middleware(): array
@@ -55,23 +54,62 @@ public function uniqueId(): int
public function handle(): void
{
- file_put_contents('/tmp/scheduled-job-run', 'ran in handle');
try {
- echo($this->resource->type());
- file_put_contents('/tmp/scheduled-job-run-'.$this->task->id, $this->task->name);
+ $this->task_log = ScheduledTaskExecution::create([
+ 'scheduled_task_id' => $this->task->id,
+ ]);
+
+ $this->server = $this->resource->destination->server;
+
+ if ($this->resource->type() == 'application') {
+ $containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
+ if ($containers->count() > 0) {
+ $containers->each(function ($container) {
+ $this->containers[] = str_replace('/', '', $container['Names']);
+ });
+ }
+ }
+ elseif ($this->resource->type() == 'service') {
+ $this->resource->applications()->get()->each(function ($application) {
+ if (str(data_get($application, 'status'))->contains('running')) {
+ $this->containers[] = data_get($application, 'name') . '-' . data_get($this->resource, 'uuid');
+ }
+ });
+ }
+
+ if (count($this->containers) == 0) {
+ throw new \Exception('ScheduledTaskJob failed: No containers running.');
+ }
+
+ if (count($this->containers) > 1 && empty($this->task->container)) {
+ throw new \Exception('ScheduledTaskJob failed: More than one container exists but no container name was provided.');
+ }
+
+ foreach ($this->containers as $containerName) {
+ if (count($this->containers) == 1 || str_starts_with($containerName, $this->task->container . '-' . $this->resource->uuid)) {
+ $cmd = 'sh -c "' . str_replace('"', '\"', $this->task->command) . '"';
+ $exec = "docker exec {$containerName} {$cmd}";
+ $this->task_output = instant_remote_process([$exec], $this->server, true);
+ $this->task_log->update([
+ 'status' => 'success',
+ 'message' => $this->task_output,
+ ]);
+ return;
+ }
+ }
+
+ // No valid container was found.
+ throw new \Exception('ScheduledTaskJob failed: No valid container was found. Is the container name correct?');
+
} catch (\Throwable $e) {
+ if ($this->task_log) {
+ $this->task_log->update([
+ 'status' => 'failed',
+ 'message' => $this->task_output ?? $e->getMessage(),
+ ]);
+ }
send_internal_notification('ScheduledTaskJob failed with: ' . $e->getMessage());
throw $e;
- } finally {
- // BackupCreated::dispatch($this->team->id);
- }
- }
- private function add_to_backup_output($output): void
- {
- if ($this->backup_output) {
- $this->backup_output = $this->backup_output . "\n" . $output;
- } else {
- $this->backup_output = $output;
}
}
}
diff --git a/app/Livewire/Project/Shared/ScheduledTask/All.php b/app/Livewire/Project/Shared/ScheduledTask/All.php
index 7f61c30cc..4a876e72a 100644
--- a/app/Livewire/Project/Shared/ScheduledTask/All.php
+++ b/app/Livewire/Project/Shared/ScheduledTask/All.php
@@ -33,6 +33,7 @@ public function submit($data)
$task->command = $data['command'];
$task->frequency = $data['frequency'];
$task->container = $data['container'];
+ $task->team_id = currentTeam()->id;
switch ($this->resource->type()) {
case 'application':
diff --git a/app/Livewire/Project/Shared/ScheduledTask/Executions.php b/app/Livewire/Project/Shared/ScheduledTask/Executions.php
new file mode 100644
index 000000000..5351c3d4c
--- /dev/null
+++ b/app/Livewire/Project/Shared/ScheduledTask/Executions.php
@@ -0,0 +1,28 @@
+selectedKey) {
+ $this->selectedKey = null;
+ return;
+ }
+ $this->selectedKey = $key;
+ }
+}
diff --git a/app/Models/Service.php b/app/Models/Service.php
index eb0d96670..7f71ff865 100644
--- a/app/Models/Service.php
+++ b/app/Models/Service.php
@@ -396,6 +396,10 @@ public function byName(string $name)
}
return null;
}
+ public function scheduled_tasks(): HasMany
+ {
+ return $this->hasMany(ScheduledTask::class)->orderBy('name', 'asc');
+ }
public function environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->orderBy('key', 'asc');
diff --git a/database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php b/database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php
index b108cecf8..c3c2e2f48 100644
--- a/database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php
+++ b/database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php
@@ -23,6 +23,7 @@ public function up(): void
$table->foreignId('application_id')->nullable();
$table->foreignId('service_id')->nullable();
+ $table->foreignId('team_id');
});
}
diff --git a/resources/views/livewire/project/service/index.blade.php b/resources/views/livewire/project/service/index.blade.php
index 5f4363b31..3462730ec 100644
--- a/resources/views/livewire/project/service/index.blade.php
+++ b/resources/views/livewire/project/service/index.blade.php
@@ -26,6 +26,10 @@
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
href="#">Environment
Variables
+ Scheduled Tasks
+
+
+
+
diff --git a/resources/views/livewire/project/shared/scheduled-task/all.blade.php b/resources/views/livewire/project/shared/scheduled-task/all.blade.php
index 7a1f359ef..b860e00b1 100644
--- a/resources/views/livewire/project/shared/scheduled-task/all.blade.php
+++ b/resources/views/livewire/project/shared/scheduled-task/all.blade.php
@@ -8,24 +8,18 @@
-
- {{-- @if ($type === 'service-database' && $selectedBackup)
-
-
-
Executions
-
-
- @endif --}}
diff --git a/resources/views/livewire/project/shared/scheduled-task/executions.blade.php b/resources/views/livewire/project/shared/scheduled-task/executions.blade.php
new file mode 100644
index 000000000..9f0fd9208
--- /dev/null
+++ b/resources/views/livewire/project/shared/scheduled-task/executions.blade.php
@@ -0,0 +1,27 @@
+
+ @forelse($executions as $execution)
+
data_get($execution, 'status') === 'success',
+ 'border-red-500' => data_get($execution, 'status') === 'failed',
+ ])>
+ @if (data_get($execution, 'status') === 'running')
+
+
+
+ @endif
+ Status: {{ data_get($execution, 'status') }}
+ Started At: {{ data_get($execution, 'created_at') }}
+ @if (data_get($execution, 'id') == $selectedKey)
+ @if (data_get($execution, 'message'))
+ Output:
{{ data_get($execution, 'message') }}
+ @else
+ No output was recorded for this execution.
+ @endif
+ @endif
+
+
+ @empty
+
No executions found.
+ @endforelse
+
diff --git a/resources/views/livewire/project/shared/scheduled-task/show.blade.php b/resources/views/livewire/project/shared/scheduled-task/show.blade.php
index a53ed6fbb..e9ab765ee 100644
--- a/resources/views/livewire/project/shared/scheduled-task/show.blade.php
+++ b/resources/views/livewire/project/shared/scheduled-task/show.blade.php
@@ -7,7 +7,11 @@ class="font-bold text-warning">({{ $task->name }})?
Scheduled Backup
+ @if ($type === 'application')
+ @elseif ($type === 'service')
+
+ @endif