Skip to content

Commit f993456

Browse files
committed
feat: #3 create init swarm cluster task
1 parent b213970 commit f993456

40 files changed

+1008
-36
lines changed

Diff for: api-nodes/Http/Controllers/EventController.php

-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ public function started(Node $node, NodeData $data)
1414

1515
$node->save();
1616

17-
dd($node->data);
18-
1917
return [
2018
'settings' => [
2119
'poll_interval' => 5

Diff for: api-nodes/Http/Controllers/NextTaskController.php

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace ApiNodes\Http\Controllers;
4+
5+
use App\Models\Node;
6+
use App\Models\NodeTask\TaskStatus;
7+
use App\Models\NodeTaskGroup;
8+
use Illuminate\Database\Eloquent\Builder;
9+
use Illuminate\Http\Response;
10+
11+
class NextTaskController
12+
{
13+
public function __invoke(Node $node)
14+
{
15+
$taskGroup = $node->taskGroups()->inProgress()->first();
16+
17+
$task = $taskGroup ? $this->getNextTaskFromGroup($taskGroup) : $this->pickNextTask($node);
18+
if ($task) {
19+
return $task;
20+
}
21+
22+
return new Response([
23+
'message' => 'No task found.'
24+
], 404);
25+
}
26+
27+
protected function getNextTaskFromGroup(NodeTaskGroup $taskGroup)
28+
{
29+
if ($taskGroup->tasks()->running()->first()) {
30+
return new Response([
31+
'error_message' => 'Another task should be already running.'
32+
], 409);
33+
}
34+
35+
$task = $taskGroup->tasks()->pending()->first();
36+
37+
$task->start();
38+
39+
return $task;
40+
}
41+
42+
protected function pickNextTask(Node $node)
43+
{
44+
$taskGroup = NodeTaskGroup::where('swarm_id', $node->swarm_id)->where(function (Builder $query) use ($node) {
45+
return $query->where('node_id', $node->id)->orWhere('node_id', null);
46+
})->pending()->first();
47+
48+
$task = $taskGroup->tasks()->first();
49+
50+
$taskGroup->startTask($node, $task);
51+
52+
return $task;
53+
}
54+
}

Diff for: api-nodes/Http/Controllers/TaskController.php

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace ApiNodes\Http\Controllers;
4+
5+
use App\Casts\TaskResultCast;
6+
use App\Models\NodeTask;
7+
use App\Models\NodeTask\ErrorResult;
8+
use Illuminate\Http\Request;
9+
use Illuminate\Http\Response;
10+
11+
class TaskController
12+
{
13+
public function complete(NodeTask $task, Request $request)
14+
{
15+
if ($task->is_ended) {
16+
return new Response(['error' => 'Already ended.'], 409);
17+
}
18+
19+
if ($task->is_pending) {
20+
return new Response(['error' => "Task didn't start yet."], 409);
21+
}
22+
23+
$result = TaskResultCast::RESULT_BY_TYPE[$task->type]::validateAndCreate($request->all());
24+
25+
$task->complete($result);
26+
27+
return new Response('', 204);
28+
}
29+
30+
public function fail(NodeTask $task, Request $request)
31+
{
32+
if ($task->is_ended) {
33+
return new Response(['error' => 'Already ended.'], 409);
34+
}
35+
36+
if ($task->is_pending) {
37+
return new Response(['error' => "Task didn't start yet."], 409);
38+
}
39+
40+
$result = ErrorResult::validateAndCreate($request->all());
41+
42+
$task->fail($result);
43+
44+
return new Response('', 204);
45+
}
46+
}

Diff for: api-nodes/Http/Middleware/AgentTokenAuth.php

+3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace ApiNodes\Http\Middleware;
44

55
use App\Models\Node;
6+
use App\Models\NodeTask;
67
use App\Models\Scopes\TeamScope;
8+
use App\Models\Team;
79
use Closure;
810
use Illuminate\Http\Request;
911
use Symfony\Component\HttpFoundation\Response;
@@ -34,6 +36,7 @@ public function handle(Request $request, Closure $next): Response
3436
$node->save();
3537

3638
app()->singleton(Node::class, fn() => $node);
39+
app()->singleton(Team::class, fn() => $node->team);
3740

3841
return $next($request);
3942
}

Diff for: app/Casts/TaskPayloadCast.php

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace App\Casts;
4+
5+
use App\Models\NodeTask;
6+
use App\Models\NodeTask\CreateNetworkTaskPayload;
7+
use App\Models\NodeTask\InitSwarmTaskPayload;
8+
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
9+
use Illuminate\Database\Eloquent\Model;
10+
use InvalidArgumentException;
11+
12+
class TaskPayloadCast implements CastsAttributes
13+
{
14+
public const TYPE_BY_PAYLOAD = [
15+
CreateNetworkTaskPayload::class => 0,
16+
InitSwarmTaskPayload::class => 1
17+
];
18+
19+
public const PAYLOAD_BY_TYPE = [
20+
0 => CreateNetworkTaskPayload::class,
21+
1 => InitSwarmTaskPayload::class
22+
];
23+
24+
/**
25+
* Cast the given value.
26+
*
27+
* @param array<string, mixed> $attributes
28+
*/
29+
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
30+
{
31+
if (!($model instanceof NodeTask)) {
32+
throw new InvalidArgumentException('Model must be an instance of NodeTask');
33+
}
34+
35+
return self::PAYLOAD_BY_TYPE[$model->type]::from($value);
36+
}
37+
38+
/**
39+
* Prepare the given value for storage.
40+
*
41+
* @param array<string, mixed> $attributes
42+
*/
43+
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
44+
{
45+
if (!($model instanceof NodeTask)) {
46+
throw new InvalidArgumentException('Model must be an instance of NodeTask');
47+
}
48+
49+
return $value->toJson();
50+
}
51+
}

Diff for: app/Casts/TaskResultCast.php

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace App\Casts;
4+
5+
use App\Models\NodeTask;
6+
use App\Models\NodeTask\CreateNetworkTaskResult;
7+
use App\Models\NodeTask\ErrorResult;
8+
use App\Models\NodeTask\InitSwarmTaskResult;
9+
use InvalidArgumentException;
10+
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
11+
use Illuminate\Database\Eloquent\Model;
12+
13+
class TaskResultCast implements CastsAttributes
14+
{
15+
16+
public const TYPE_BY_RESULT = [
17+
CreateNetworkTaskResult::class => 0,
18+
InitSwarmTaskResult::class => 1
19+
];
20+
21+
public const RESULT_BY_TYPE = [
22+
0 => CreateNetworkTaskResult::class,
23+
1 => InitSwarmTaskResult::class
24+
];
25+
26+
/**
27+
* Cast the given value.
28+
*
29+
* @param array<string, mixed> $attributes
30+
*/
31+
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
32+
{
33+
if (!($model instanceof NodeTask)) {
34+
throw new InvalidArgumentException('Model must be an instance of NodeTask');
35+
}
36+
37+
if ($model->is_failed) {
38+
return ErrorResult::from($value);
39+
}
40+
41+
if ($model->is_ended) {
42+
return self::RESULT_BY_TYPE[$model->type]::from($value);
43+
}
44+
45+
return null;
46+
}
47+
48+
/**
49+
* Prepare the given value for storage.
50+
*
51+
* @param array<string, mixed> $attributes
52+
*/
53+
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
54+
{
55+
if (!($model instanceof NodeTask)) {
56+
throw new InvalidArgumentException('Model must be an instance of NodeTask');
57+
}
58+
59+
return $value->toJson();
60+
}
61+
}

Diff for: app/Http/Controllers/NodeController.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use App\Http\Requests\StoreNodeRequest;
66
use App\Http\Requests\UpdateNodeRequest;
77
use App\Models\Node;
8+
use App\Models\NodeTask;
9+
use App\Models\NodeTask\InitSwarmTaskPayload;
810
use Inertia\Inertia;
911

1012
class NodeController extends Controller
@@ -40,7 +42,12 @@ public function store(StoreNodeRequest $request)
4042
*/
4143
public function show(Node $node)
4244
{
43-
return Inertia::render('Nodes/Show', ['node' => $node]);
45+
$initTaskGroup = $node->tasks()->inProgress()->ofType(InitSwarmTaskPayload::class)->first()?->taskGroup->with('tasks')->first();
46+
if (!$initTaskGroup) {
47+
$initTaskGroup = $node->tasks()->failed()->ofType(InitSwarmTaskPayload::class)->first()?->taskGroup->with('tasks')->first();
48+
}
49+
50+
return Inertia::render('Nodes/Show', ['node' => $node, 'initTaskGroup' => $initTaskGroup]);
4451
}
4552

4653
/**

Diff for: app/Http/Controllers/SwarmTaskController.php

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use App\Http\Requests\NodeTask\InitClusterFormRequest;
6+
use App\Models\Node;
7+
use App\Models\NodeTask\CreateNetworkTaskPayload;
8+
use App\Models\NodeTask\InitSwarmTaskPayload;
9+
use App\Models\NodeTaskGroup;
10+
use App\Models\Swarm;
11+
12+
class SwarmTaskController extends Controller
13+
{
14+
public function initCluster(InitClusterFormRequest $request)
15+
{
16+
$swarm = Swarm::create([
17+
'name' => $request->name,
18+
]);
19+
20+
Node::whereId($request->node_id)->update([
21+
'swarm_id' => $swarm->id,
22+
]);
23+
24+
$taskGroup = NodeTaskGroup::create([
25+
'swarm_id' => $swarm->id,
26+
'node_id' => $request->node_id,
27+
'invoker_id' => auth()->user()->id,
28+
]);
29+
30+
$taskGroup->tasks()->createMany([
31+
[
32+
'payload' => new CreateNetworkTaskPayload('ptah-net'),
33+
],
34+
[
35+
'payload' => new InitSwarmTaskPayload($request->name, $request->force_new_cluster),
36+
]
37+
]);
38+
}
39+
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace App\Http\Requests\NodeTask;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
7+
class InitClusterFormRequest extends FormRequest
8+
{
9+
public function authorize(): bool
10+
{
11+
return true;
12+
}
13+
14+
public function rules(): array
15+
{
16+
return [
17+
'node_id' => ['required'],
18+
'name' => ['required', 'string', 'max:255'],
19+
'advertise_addr' => ['required', 'ipv4'],
20+
'force_new_cluster' => ['boolean'],
21+
];
22+
}
23+
}

Diff for: app/Models/Node.php

+13-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
namespace App\Models;
44

5-
use App\HasOwningTeam;
5+
use App\Traits\HasOwningTeam;
66
use Illuminate\Database\Eloquent\Factories\HasFactory;
77
use Illuminate\Database\Eloquent\Model;
8-
use Illuminate\Support\Facades\Auth;
8+
use Illuminate\Database\Eloquent\Relations\HasMany;
9+
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
910
use Illuminate\Support\Str;
1011

1112
class Node extends Model
@@ -32,6 +33,16 @@ protected static function booted()
3233
});
3334
}
3435

36+
public function taskGroups(): HasMany
37+
{
38+
return $this->hasMany(NodeTaskGroup::class);
39+
}
40+
41+
public function tasks(): HasManyThrough
42+
{
43+
return $this->hasManyThrough(NodeTask::class, NodeTaskGroup::class, 'node_id', 'task_group_id', 'id', 'id');
44+
}
45+
3546
public function getOnlineAttribute()
3647
{
3748
return true;

0 commit comments

Comments
 (0)