mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-13 12:14:28 +00:00
feat(v5): sync resource firewall rules via Flux
This commit is contained in:
1 parent
22e3d6960e
commit
4061a3844b
8 files changed
+397
-66
No files matched your search
@@ -552,7 +552,7 @@ class DashboardController extends Controller
|
||||
], $connection->wasRecentlyCreated ? 201 : 200);
|
||||
}
|
||||
|
||||
public function updateResourceConnection(Request $request, ResourceConnection $connection): JsonResponse
|
||||
public function updateResourceConnection(Request $request, ResourceConnection $connection, FluxClient $fluxClient): JsonResponse
|
||||
{
|
||||
$currentTeam = $request->attributes->get('v5.currentTeam');
|
||||
|
||||
@@ -566,6 +566,8 @@ class DashboardController extends Controller
|
||||
'ports_by_direction.*.*' => ['integer', 'min:1', 'max:65535', 'distinct'],
|
||||
]);
|
||||
|
||||
$oldFirewallRules = $this->connectionFirewallRules($connection->load('rules'));
|
||||
|
||||
DB::transaction(function () use ($connection, $validated): void {
|
||||
$connection->rules()->delete();
|
||||
|
||||
@@ -589,12 +591,24 @@ class DashboardController extends Controller
|
||||
}
|
||||
});
|
||||
|
||||
$connection->refresh()->load('rules');
|
||||
$newFirewallRules = $this->connectionFirewallRules($connection);
|
||||
|
||||
try {
|
||||
$this->syncConnectionFirewallRules($fluxClient, $oldFirewallRules, $newFirewallRules);
|
||||
} catch (\RuntimeException $exception) {
|
||||
return response()->json([
|
||||
'message' => 'Could not sync firewall rules through Flux.',
|
||||
'detail' => $exception->getMessage(),
|
||||
], 502);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'connection' => $this->serializeResourceConnection($connection->refresh()->load('rules')),
|
||||
'connection' => $this->serializeResourceConnection($connection),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroyResourceConnection(Request $request, ResourceConnection $connection): \Illuminate\Http\Response
|
||||
public function destroyResourceConnection(Request $request, ResourceConnection $connection, FluxClient $fluxClient): \Illuminate\Http\Response|JsonResponse
|
||||
{
|
||||
$currentTeam = $request->attributes->get('v5.currentTeam');
|
||||
|
||||
@@ -602,6 +616,17 @@ class DashboardController extends Controller
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$oldFirewallRules = $this->connectionFirewallRules($connection->load('rules'));
|
||||
|
||||
try {
|
||||
$this->syncConnectionFirewallRules($fluxClient, $oldFirewallRules, collect());
|
||||
} catch (\RuntimeException $exception) {
|
||||
return response()->json([
|
||||
'message' => 'Could not sync firewall rules through Flux.',
|
||||
'detail' => $exception->getMessage(),
|
||||
], 502);
|
||||
}
|
||||
|
||||
$connection->delete();
|
||||
|
||||
return response()->noContent();
|
||||
@@ -1363,6 +1388,86 @@ class DashboardController extends Controller
|
||||
: $connection->resource_two_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, array{id: string, hostId: string, rule: array{id: string, namespace: string, src: string, dst: string, proto: string, port: int}}>
|
||||
*/
|
||||
private function connectionFirewallRules(ResourceConnection $connection): Collection
|
||||
{
|
||||
$applicationIds = $connection->rules
|
||||
->flatMap(fn ($rule) => [$rule->source_resource_id, $rule->target_resource_id])
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
$applications = V5Application::query()
|
||||
->whereIn('id', $applicationIds)
|
||||
->with('server')
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
return $connection->rules
|
||||
->map(function ($rule) use ($applications, $connection): ?array {
|
||||
$source = $applications->get($rule->source_resource_id);
|
||||
$target = $applications->get($rule->target_resource_id);
|
||||
|
||||
if (! $source instanceof V5Application || ! $target instanceof V5Application || ! $target->server instanceof V5Server) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$hostId = $target->server->wireguard_management_ip ?: $target->server->node_address;
|
||||
|
||||
if (! is_string($hostId) || $hostId === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firewallRule = [
|
||||
'id' => $this->connectionFirewallRuleId($connection, $rule),
|
||||
'namespace' => $target->mesh_namespace ?: 'default',
|
||||
'src' => $source->container_name,
|
||||
'dst' => $target->container_name,
|
||||
'proto' => $rule->protocol ?: 'tcp',
|
||||
'port' => (int) $rule->port,
|
||||
];
|
||||
|
||||
return [
|
||||
'id' => $firewallRule['id'],
|
||||
'hostId' => $hostId,
|
||||
'rule' => $firewallRule,
|
||||
];
|
||||
})
|
||||
->filter()
|
||||
->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, array{id: string, hostId: string, rule: array{id: string, namespace: string, src: string, dst: string, proto: string, port: int}}> $oldRules
|
||||
* @param Collection<int, array{id: string, hostId: string, rule: array{id: string, namespace: string, src: string, dst: string, proto: string, port: int}}> $newRules
|
||||
*/
|
||||
private function syncConnectionFirewallRules(FluxClient $fluxClient, Collection $oldRules, Collection $newRules): void
|
||||
{
|
||||
$newRuleIds = $newRules->pluck('id')->all();
|
||||
$oldRuleIds = $oldRules->pluck('id')->all();
|
||||
|
||||
$oldRules
|
||||
->reject(fn (array $oldRule): bool => in_array($oldRule['id'], $newRuleIds, true))
|
||||
->each(fn (array $oldRule): string => $fluxClient->revokeFirewallRule($oldRule['hostId'], $oldRule['id']));
|
||||
|
||||
$newRules
|
||||
->reject(fn (array $newRule): bool => in_array($newRule['id'], $oldRuleIds, true))
|
||||
->each(fn (array $newRule): string => $fluxClient->applyFirewallRule($newRule['hostId'], $newRule['rule']));
|
||||
}
|
||||
|
||||
private function connectionFirewallRuleId(ResourceConnection $connection, mixed $rule): string
|
||||
{
|
||||
return implode(':', [
|
||||
'v5-resource-connection',
|
||||
$connection->id,
|
||||
$rule->source_resource_id,
|
||||
$rule->target_resource_id,
|
||||
$rule->protocol ?: 'tcp',
|
||||
(int) $rule->port,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{uuid: string} $selectedProject
|
||||
* @param array{uuid: string} $selectedEnvironment
|
||||
@@ -1498,7 +1603,7 @@ class DashboardController extends Controller
|
||||
*/
|
||||
private function serverCapabilities(bool $builderEnabled, bool $ingressEnabled): array
|
||||
{
|
||||
return collect(['coold'])
|
||||
return collect()
|
||||
->when($ingressEnabled, fn ($capabilities) => $capabilities->push('ingress'))
|
||||
->unique()
|
||||
->values()
|
||||
|
||||
Reference in new issue
Block a user