Refactor code and add additional destinations
This commit is contained in:
parent
10e307f92b
commit
3616fc8ca9
@ -3,6 +3,8 @@
|
|||||||
namespace App\Actions\Application;
|
namespace App\Actions\Application;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
|
use App\Models\StandaloneDocker;
|
||||||
|
use App\Notifications\Application\StatusChanged;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class StopApplication
|
class StopApplication
|
||||||
@ -10,13 +12,20 @@ class StopApplication
|
|||||||
use AsAction;
|
use AsAction;
|
||||||
public function handle(Application $application)
|
public function handle(Application $application)
|
||||||
{
|
{
|
||||||
$server = $application->destination->server;
|
if ($application->destination->server->isSwarm()) {
|
||||||
if (!$server->isFunctional()) {
|
instant_remote_process(["docker stack rm {$application->uuid}"], $application->destination->server);
|
||||||
return 'Server is not functional';
|
return;
|
||||||
}
|
}
|
||||||
if ($server->isSwarm()) {
|
|
||||||
instant_remote_process(["docker stack rm {$application->uuid}" ], $server);
|
$servers = collect([]);
|
||||||
} else {
|
$servers->push($application->destination->server);
|
||||||
|
$application->additional_networks->map(function ($network) use ($servers) {
|
||||||
|
$servers->push($network->server);
|
||||||
|
});
|
||||||
|
foreach ($servers as $server) {
|
||||||
|
if (!$server->isFunctional()) {
|
||||||
|
return 'Server is not functional';
|
||||||
|
}
|
||||||
$containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
|
$containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
|
||||||
if ($containers->count() > 0) {
|
if ($containers->count() > 0) {
|
||||||
foreach ($containers as $container) {
|
foreach ($containers as $container) {
|
||||||
@ -28,20 +37,18 @@ class StopApplication
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: make notification for application
|
|
||||||
// $application->environment->project->team->notify(new StatusChanged($application));
|
// $application->environment->project->team->notify(new StatusChanged($application));
|
||||||
}
|
}
|
||||||
// Delete Preview Deployments
|
|
||||||
$previewDeployments = $application->previews;
|
|
||||||
foreach ($previewDeployments as $previewDeployment) {
|
|
||||||
$containers = getCurrentApplicationContainerStatus($server, $application->id, $previewDeployment->pull_request_id);
|
|
||||||
foreach ($containers as $container) {
|
|
||||||
$name = str_replace('/', '', $container['Names']);
|
|
||||||
instant_remote_process(["docker rm -f $name"], $application->destination->server, throwError: false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // Delete Preview Deployments
|
||||||
|
// $previewDeployments = $application->previews;
|
||||||
|
// foreach ($previewDeployments as $previewDeployment) {
|
||||||
|
// $containers = getCurrentApplicationContainerStatus($server, $application->id, $previewDeployment->pull_request_id);
|
||||||
|
// foreach ($containers as $container) {
|
||||||
|
// $name = str_replace('/', '', $container['Names']);
|
||||||
|
// instant_remote_process(["docker rm -f $name"], $application->destination->server, throwError: false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,11 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
// Otherwise built image needs to be pushed before from the build server.
|
// Otherwise built image needs to be pushed before from the build server.
|
||||||
if (!$this->use_build_server) {
|
if (!$this->use_build_server) {
|
||||||
$this->push_to_docker_registry();
|
if ($this->application->additional_networks->count() > 0) {
|
||||||
|
$this->push_to_docker_registry(forceFail: true);
|
||||||
|
} else {
|
||||||
|
$this->push_to_docker_registry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
@ -349,7 +353,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->application_deployment_queue->addLogEntry("Failed to push image to docker registry. Please check debug logs for more information.");
|
$this->application_deployment_queue->addLogEntry("Failed to push image to docker registry. Please check debug logs for more information.");
|
||||||
if ($forceFail) {
|
if ($forceFail) {
|
||||||
throw $e;
|
throw new RuntimeException($e->getMessage(), 69420);
|
||||||
}
|
}
|
||||||
ray($e);
|
ray($e);
|
||||||
}
|
}
|
||||||
@ -388,7 +392,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
private function just_restart()
|
private function just_restart()
|
||||||
{
|
{
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->check_git_if_build_needed();
|
$this->check_git_if_build_needed();
|
||||||
$this->set_base_dir();
|
$this->set_base_dir();
|
||||||
@ -443,7 +447,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->server = $this->build_server;
|
$this->server = $this->build_server;
|
||||||
}
|
}
|
||||||
$dockerfile_base64 = base64_encode($this->application->dockerfile);
|
$dockerfile_base64 = base64_encode($this->application->dockerfile);
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name} to {$this->server->name}.");
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
@ -451,6 +455,16 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
|
if (!$this->force_rebuild) {
|
||||||
|
$this->check_image_locally_or_remotely();
|
||||||
|
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||||
|
$this->create_workdir();
|
||||||
|
$this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
|
||||||
|
$this->generate_compose_file();
|
||||||
|
$this->rolling_update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
$this->generate_build_env_variables();
|
$this->generate_build_env_variables();
|
||||||
$this->add_build_env_variables_to_dockerfile();
|
$this->add_build_env_variables_to_dockerfile();
|
||||||
@ -462,8 +476,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
{
|
{
|
||||||
$this->dockerImage = $this->application->docker_registry_image_name;
|
$this->dockerImage = $this->application->docker_registry_image_name;
|
||||||
$this->dockerImageTag = $this->application->docker_registry_image_tag;
|
$this->dockerImageTag = $this->application->docker_registry_image_tag;
|
||||||
ray("echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag}.'");
|
ray("echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.'");
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.");
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
@ -481,9 +495,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->docker_compose_custom_build_command = $this->application->docker_compose_custom_build_command;
|
$this->docker_compose_custom_build_command = $this->application->docker_compose_custom_build_command;
|
||||||
}
|
}
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name} to {$this->server->name}.");
|
||||||
} else {
|
} else {
|
||||||
$this->application_deployment_queue->addLogEntry("Starting pull request (#{$this->pull_request_id}) deployment of {$this->customRepository}:{$this->application->git_branch}.");
|
$this->application_deployment_queue->addLogEntry("Starting pull request (#{$this->pull_request_id}) deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
|
||||||
}
|
}
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->check_git_if_build_needed();
|
$this->check_git_if_build_needed();
|
||||||
@ -551,12 +565,22 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if (data_get($this->application, 'dockerfile_location')) {
|
if (data_get($this->application, 'dockerfile_location')) {
|
||||||
$this->dockerfile_location = $this->application->dockerfile_location;
|
$this->dockerfile_location = $this->application->dockerfile_location;
|
||||||
}
|
}
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->check_git_if_build_needed();
|
$this->check_git_if_build_needed();
|
||||||
$this->clone_repository();
|
|
||||||
$this->set_base_dir();
|
$this->set_base_dir();
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
|
if (!$this->force_rebuild) {
|
||||||
|
$this->check_image_locally_or_remotely();
|
||||||
|
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||||
|
$this->create_workdir();
|
||||||
|
$this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
|
||||||
|
$this->generate_compose_file();
|
||||||
|
$this->rolling_update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->clone_repository();
|
||||||
$this->cleanup_git();
|
$this->cleanup_git();
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
$this->generate_build_env_variables();
|
$this->generate_build_env_variables();
|
||||||
@ -569,7 +593,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
$this->server = $this->build_server;
|
$this->server = $this->build_server;
|
||||||
}
|
}
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->check_git_if_build_needed();
|
$this->check_git_if_build_needed();
|
||||||
$this->set_base_dir();
|
$this->set_base_dir();
|
||||||
@ -601,11 +625,21 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
$this->server = $this->build_server;
|
$this->server = $this->build_server;
|
||||||
}
|
}
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->check_git_if_build_needed();
|
$this->check_git_if_build_needed();
|
||||||
$this->set_base_dir();
|
$this->set_base_dir();
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
|
if (!$this->force_rebuild) {
|
||||||
|
$this->check_image_locally_or_remotely();
|
||||||
|
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||||
|
$this->create_workdir();
|
||||||
|
$this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
|
||||||
|
$this->generate_compose_file();
|
||||||
|
$this->rolling_update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->clone_repository();
|
$this->clone_repository();
|
||||||
$this->cleanup_git();
|
$this->cleanup_git();
|
||||||
$this->build_image();
|
$this->build_image();
|
||||||
@ -787,10 +821,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
private function deploy_to_additional_destinations()
|
private function deploy_to_additional_destinations()
|
||||||
{
|
{
|
||||||
if (str($this->application->additional_destinations)->isEmpty()) {
|
if ($this->application->additional_networks->count() === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$destination_ids = collect(str($this->application->additional_destinations)->explode(','));
|
$destination_ids = $this->application->additional_networks->pluck('id');
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
$this->application_deployment_queue->addLogEntry("Additional destinations are not supported in swarm mode.");
|
$this->application_deployment_queue->addLogEntry("Additional destinations are not supported in swarm mode.");
|
||||||
return;
|
return;
|
||||||
@ -1529,7 +1563,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($status === ApplicationDeploymentStatus::FINISHED->value) {
|
if ($status === ApplicationDeploymentStatus::FINISHED->value) {
|
||||||
// $this->deploy_to_additional_destinations();
|
$this->deploy_to_additional_destinations();
|
||||||
$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
|
$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1542,10 +1576,14 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->application->build_pack !== 'dockercompose') {
|
if ($this->application->build_pack !== 'dockercompose') {
|
||||||
$this->application_deployment_queue->addLogEntry("Deployment failed. Removing the new version of your application.", 'stderr');
|
$code = $exception->getCode();
|
||||||
$this->execute_remote_command(
|
if ($code !== 69420) {
|
||||||
[executeInDocker($this->deployment_uuid, "docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true]
|
// 69420 means failed to push the image to the registry, so we don't need to remove the new version as it is the currently running one
|
||||||
);
|
$this->application_deployment_queue->addLogEntry("Deployment failed. Removing the new version of your application.", 'stderr');
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[executeInDocker($this->deployment_uuid, "docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->next(ApplicationDeploymentStatus::FAILED->value);
|
$this->next(ApplicationDeploymentStatus::FAILED->value);
|
||||||
|
@ -87,22 +87,6 @@ class Heading extends Component
|
|||||||
$this->application->save();
|
$this->application->save();
|
||||||
$this->application->refresh();
|
$this->application->refresh();
|
||||||
}
|
}
|
||||||
public function restartNew()
|
|
||||||
{
|
|
||||||
$this->setDeploymentUuid();
|
|
||||||
queue_application_deployment(
|
|
||||||
application: $this->application,
|
|
||||||
deployment_uuid: $this->deploymentUuid,
|
|
||||||
restart_only: true,
|
|
||||||
is_new_deployment: true,
|
|
||||||
);
|
|
||||||
return redirect()->route('project.application.deployment.show', [
|
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
|
||||||
'application_uuid' => $this->parameters['application_uuid'],
|
|
||||||
'deployment_uuid' => $this->deploymentUuid,
|
|
||||||
'environment_name' => $this->parameters['environment_name'],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function restart()
|
public function restart()
|
||||||
{
|
{
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
|
@ -2,11 +2,43 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Project\Shared;
|
namespace App\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Destination extends Component
|
class Destination extends Component
|
||||||
{
|
{
|
||||||
public $resource;
|
public $resource;
|
||||||
public $servers = [];
|
public $servers = [];
|
||||||
public $additional_servers = [];
|
public $networks = [];
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->loadData();
|
||||||
|
}
|
||||||
|
public function loadData()
|
||||||
|
{
|
||||||
|
$all_networks = collect([]);
|
||||||
|
$all_networks = $all_networks->push($this->resource->destination);
|
||||||
|
$all_networks = $all_networks->merge($this->resource->additional_networks);
|
||||||
|
|
||||||
|
$this->networks = Server::isUsable()->get()->map(function ($server) {
|
||||||
|
return $server->standaloneDockers;
|
||||||
|
})->flatten();
|
||||||
|
$this->networks = $this->networks->reject(function ($network) use ($all_networks) {
|
||||||
|
return $all_networks->pluck('id')->contains($network->id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public function addServer(int $network_id, int $server_id)
|
||||||
|
{
|
||||||
|
$this->resource->additional_networks()->attach($network_id, ['server_id' => $server_id]);
|
||||||
|
$this->resource->load(['additional_networks']);
|
||||||
|
$this->loadData();
|
||||||
|
|
||||||
|
}
|
||||||
|
public function removeServer(int $network_id, int $server_id)
|
||||||
|
{
|
||||||
|
$this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]);
|
||||||
|
$this->resource->load(['additional_networks']);
|
||||||
|
$this->loadData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ class All extends Component
|
|||||||
}
|
}
|
||||||
$environment->save();
|
$environment->save();
|
||||||
$this->refreshEnvs();
|
$this->refreshEnvs();
|
||||||
$this->dispatch('success', 'Environment variable added successfully.');
|
$this->dispatch('success', 'Environment variable added.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ class Application extends BaseModel
|
|||||||
{
|
{
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::saving(function ($application) {
|
static::saving(function ($application) {
|
||||||
@ -53,6 +52,16 @@ class Application extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function additional_servers()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Server::class, 'additional_destinations')
|
||||||
|
->withPivot('standalone_docker_id');
|
||||||
|
}
|
||||||
|
public function additional_networks()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(StandaloneDocker::class, 'additional_destinations')
|
||||||
|
->withPivot('server_id');
|
||||||
|
}
|
||||||
public function is_github_based(): bool
|
public function is_github_based(): bool
|
||||||
{
|
{
|
||||||
if (data_get($this, 'source')) {
|
if (data_get($this, 'source')) {
|
||||||
@ -216,7 +225,8 @@ class Application extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphToMany(Tag::class, 'taggable');
|
return $this->morphToMany(Tag::class, 'taggable');
|
||||||
}
|
}
|
||||||
public function project() {
|
public function project()
|
||||||
|
{
|
||||||
return data_get($this, 'environment.project');
|
return data_get($this, 'environment.project');
|
||||||
}
|
}
|
||||||
public function team()
|
public function team()
|
||||||
@ -435,7 +445,7 @@ class Application extends BaseModel
|
|||||||
{
|
{
|
||||||
return "/artifacts/{$uuid}";
|
return "/artifacts/{$uuid}";
|
||||||
}
|
}
|
||||||
function setGitImportSettings(string $deployment_uuid, string $git_clone_command)
|
function setGitImportSettings(string $deployment_uuid, string $git_clone_command)
|
||||||
{
|
{
|
||||||
$baseDir = $this->generateBaseDir($deployment_uuid);
|
$baseDir = $this->generateBaseDir($deployment_uuid);
|
||||||
if ($this->git_commit_sha !== 'HEAD') {
|
if ($this->git_commit_sha !== 'HEAD') {
|
||||||
|
@ -24,7 +24,6 @@ return new class extends Migration
|
|||||||
$table->string('taggable_type');
|
$table->string('taggable_type');
|
||||||
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
|
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
|
||||||
$table->unique(['tag_id', 'taggable_id', 'taggable_type'], 'taggable_unique'); // Composite unique index
|
$table->unique(['tag_id', 'taggable_id', 'taggable_type'], 'taggable_unique'); // Composite unique index
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('additional_destinations', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('application_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('server_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('standalone_docker_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
Schema::table('applications', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('additional_destinations');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('additional_destinations');
|
||||||
|
Schema::table('applications', function (Blueprint $table) {
|
||||||
|
$table->string('additional_destinations')->nullable()->after('destination');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -77,6 +77,11 @@
|
|||||||
Manual
|
Manual
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
@if (data_get($deployment, 'server_name'))
|
||||||
|
<div class="flex gap-1">
|
||||||
|
Server: {{ data_get($deployment, 'server_name') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col" x-data="elapsedTime('{{ $deployment->deployment_uuid }}', '{{ $deployment->status }}', '{{ $deployment->created_at }}', '{{ $deployment->updated_at }}')">
|
<div class="flex flex-col" x-data="elapsedTime('{{ $deployment->deployment_uuid }}', '{{ $deployment->status }}', '{{ $deployment->created_at }}', '{{ $deployment->updated_at }}')">
|
||||||
|
@ -1,38 +1,48 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2>Server</h2>
|
<h2>Server</h2>
|
||||||
<div class="">Server related configurations.</div>
|
<div class="">Server related configurations.</div>
|
||||||
<h3 class="pt-4">Destination Server & Network</h3>
|
<div class="grid grid-cols-2 gap-4 py-4">
|
||||||
<div class="py-4">
|
{{-- <a class="box"
|
||||||
<a class="box"
|
|
||||||
href="{{ route('server.show', ['server_uuid' => data_get($resource, 'destination.server.uuid')]) }}">On
|
href="{{ route('server.show', ['server_uuid' => data_get($resource, 'destination.server.uuid')]) }}">On
|
||||||
server <span class="px-1 text-warning">{{ data_get($resource, 'destination.server.name') }}</span>
|
server <span class="px-1 text-warning">{{ data_get($resource, 'destination.server.name') }}</span>
|
||||||
in <span class="px-1 text-warning"> {{ data_get($resource, 'destination.network') }} </span> network.</a>
|
in <span class="px-1 text-warning"> {{ data_get($resource, 'destination.network') }} </span> network</a>
|
||||||
|
@if (count($additional_destinations) > 0)
|
||||||
|
@foreach ($additional_destinations as $destination)
|
||||||
|
<a class="box"
|
||||||
|
href="{{ route('server.show', ['server_uuid' => data_get($destination, 'server.uuid')]) }}">On server
|
||||||
|
<span class="px-1 text-warning">{{ data_get($destination, 'server.name') }}</span> in <span
|
||||||
|
class="px-1 text-warning"> {{ data_get($destination, 'network') }} </span> network</a>
|
||||||
|
@endforeach
|
||||||
|
@endif --}}
|
||||||
|
<div class="box"
|
||||||
|
wire:click="removeServer('{{ data_get($resource, 'destination.id') }}','{{ data_get($resource, 'destination.server.id') }}')">
|
||||||
|
On
|
||||||
|
server <span class="px-1 text-warning">{{ data_get($resource, 'destination.server.name') }}</span>
|
||||||
|
in <span class="px-1 text-warning"> {{ data_get($resource, 'destination.network') }} </span> network</div>
|
||||||
|
@if (count($resource->additional_networks) > 0)
|
||||||
|
@foreach ($resource->additional_networks as $destination)
|
||||||
|
<div class="box"
|
||||||
|
wire:click="removeServer('{{ data_get($destination, 'id') }}','{{ data_get($destination, 'server.id') }}')">
|
||||||
|
On
|
||||||
|
server
|
||||||
|
<span class="px-1 text-warning">{{ data_get($destination, 'server.name') }}</span> in <span
|
||||||
|
class="px-1 text-warning"> {{ data_get($destination, 'network') }} </span> network
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
{{-- Additional Destinations:
|
<h4>Attach to a Server</h4>
|
||||||
{{$resource->additional_destinations}} --}}
|
@if (count($networks) > 0)
|
||||||
{{-- @if (count($servers) > 0)
|
<div class="grid grid-cols-2 gap-4">
|
||||||
<div>
|
@foreach ($networks as $network)
|
||||||
<h3>Additional Servers</h3>
|
<div wire:click="addServer('{{ $network->id }}','{{ data_get($network, 'server.id') }}')"
|
||||||
@foreach ($servers as $server)
|
class="box">
|
||||||
<form wire:submit='submit' class="p-2 border border-coolgray-400">
|
{{ data_get($network, 'server.name') }}
|
||||||
<h4>{{ $server->name }}</h4>
|
{{ $network->name }}
|
||||||
<div class="text-sm text-coolgray-600">{{ $server->description }}</div>
|
</div>
|
||||||
<x-forms.checkbox id="additionalServers.{{ $loop->index }}.enabled" label="Enabled">
|
|
||||||
</x-forms.checkbox>
|
|
||||||
<x-forms.select label="Destination" id="additionalServers.{{ $loop->index }}.destination" required>
|
|
||||||
@foreach ($server->destinations() as $destination)
|
|
||||||
@if ($loop->first)
|
|
||||||
<option selected value="{{ $destination->uuid }}">{{ $destination->name }}</option>
|
|
||||||
<option value="{{ $destination->uuid }}">{{ $destination->name }}</option>
|
|
||||||
@else
|
|
||||||
<option value="{{ $destination->uuid }}">{{ $destination->name }}</option>
|
|
||||||
<option value="{{ $destination->uuid }}">{{ $destination->name }}</option>
|
|
||||||
@endif
|
|
||||||
@endforeach
|
|
||||||
</x-forms.select>
|
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
|
||||||
</form>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@endif --}}
|
@else
|
||||||
|
<div class="text-neutral-500">No additional servers available to attach.</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user