fix: complex container status
feat: able to change primary server feat: links inside the logs
This commit is contained in:
		
							parent
							
								
									6a00d8c88c
								
							
						
					
					
						commit
						5179129a6b
					
				| @ -66,6 +66,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted | ||||
|     private Server $mainServer; | ||||
|     private ?ApplicationPreview $preview = null; | ||||
|     private ?string $git_type = null; | ||||
|     private bool $only_this_server = false; | ||||
| 
 | ||||
|     private string $container_name; | ||||
|     private ?string $currently_running_container_name = null; | ||||
| @ -115,6 +116,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted | ||||
|         $this->commit = $this->application_deployment_queue->commit; | ||||
|         $this->force_rebuild = $this->application_deployment_queue->force_rebuild; | ||||
|         $this->restart_only = $this->application_deployment_queue->restart_only; | ||||
|         $this->only_this_server = $this->application_deployment_queue->only_this_server; | ||||
| 
 | ||||
|         $this->git_type = data_get($this->application_deployment_queue, 'git_type'); | ||||
| 
 | ||||
| @ -887,7 +889,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted | ||||
|                 destination: $destination, | ||||
|                 no_questions_asked: true, | ||||
|             ); | ||||
|             $this->application_deployment_queue->addLogEntry("Deploying to additional server: {$server->name}. Click here to see the deployment status: " . route('project.application.deployment.show', [ | ||||
|             $this->application_deployment_queue->addLogEntry("Deployment to {$server->name}. Logs: " . route('project.application.deployment.show', [ | ||||
|                 'project_uuid' => data_get($this->application, 'environment.project.uuid'), | ||||
|                 'application_uuid' => data_get($this->application, 'uuid'), | ||||
|                 'deployment_uuid' => $deployment_uuid, | ||||
| @ -1619,7 +1621,9 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); | ||||
|             return; | ||||
|         } | ||||
|         if ($status === ApplicationDeploymentStatus::FINISHED->value) { | ||||
|             if (!$this->only_this_server) { | ||||
|                 $this->deploy_to_additional_destinations(); | ||||
|             } | ||||
|             $this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -44,17 +44,19 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted | ||||
|     public function handle() | ||||
|     { | ||||
|         $applications = $this->server->applications(); | ||||
|         $skip_these_applications = collect([]); | ||||
|         foreach ($applications as $application) { | ||||
|             if ($application->additional_servers->count() > 0) { | ||||
|                 $is_main_server = $application->destination->server->id === $this->server->id; | ||||
|                 if ($is_main_server) { | ||||
|                 $skip_these_applications->push($application); | ||||
|                 ComplexStatusCheck::run($application); | ||||
|                 $applications = $applications->filter(function ($value, $key) use ($application) { | ||||
|                     return $value->id !== $application->id; | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|         } | ||||
|         $applications = $applications->filter(function ($value, $key) use ($skip_these_applications) { | ||||
|             return !$skip_these_applications->pluck('id')->contains($value->id); | ||||
|         }); | ||||
| 
 | ||||
|         if (!$this->server->isFunctional()) { | ||||
|             return 'Server is not ready.'; | ||||
|  | ||||
| @ -33,15 +33,11 @@ class Heading extends Component | ||||
|     { | ||||
|         if ($this->application->destination->server->isFunctional()) { | ||||
|             dispatch(new ContainerStatusJob($this->application->destination->server)); | ||||
|             // $this->application->refresh();
 | ||||
|             // $this->application->previews->each(function ($preview) {
 | ||||
|             //     $preview->refresh();
 | ||||
|             // });
 | ||||
|         } else { | ||||
|             dispatch(new ServerStatusJob($this->application->destination->server)); | ||||
|         } | ||||
| 
 | ||||
|         if ($showNotification) $this->dispatch('success', "Application status updated."); | ||||
|         if ($showNotification) $this->dispatch('success', "Success", "Application status updated."); | ||||
|     } | ||||
| 
 | ||||
|     public function force_deploy_without_cache() | ||||
|  | ||||
| @ -38,7 +38,7 @@ class Heading extends Component | ||||
|     { | ||||
|         dispatch_sync(new ContainerStatusJob($this->database->destination->server)); | ||||
|         $this->database->refresh(); | ||||
|         if ($showNotification) $this->dispatch('success', 'Database status updated.'); | ||||
|         if ($showNotification) $this->dispatch('success', 'Success', 'Database status updated.'); | ||||
|     } | ||||
| 
 | ||||
|     public function mount() | ||||
|  | ||||
| @ -4,6 +4,7 @@ namespace App\Livewire\Project\Shared; | ||||
| 
 | ||||
| use App\Actions\Application\StopApplicationOneServer; | ||||
| use App\Events\ApplicationStatusChanged; | ||||
| use App\Jobs\ContainerStatusJob; | ||||
| use App\Models\Server; | ||||
| use App\Models\StandaloneDocker; | ||||
| use Livewire\Component; | ||||
| @ -19,7 +20,6 @@ class Destination extends Component | ||||
|         $teamId = auth()->user()->currentTeam()->id; | ||||
|         return [ | ||||
|             "echo-private:team.{$teamId},ApplicationStatusChanged" => 'loadData', | ||||
|             "loadData", | ||||
|         ]; | ||||
|     } | ||||
|     public function mount() | ||||
| @ -41,10 +41,18 @@ class Destination extends Component | ||||
|         $this->networks = $this->networks->reject(function ($network) { | ||||
|             return $this->resource->destination->server->id == $network->server->id; | ||||
|         }); | ||||
|         if ($this->resource?->additional_servers?->count() > 0) { | ||||
|             $this->networks = $this->networks->reject(function ($network) { | ||||
|                 return $this->resource->additional_servers->pluck('id')->contains($network->server->id); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|     public function stop(int $server_id) | ||||
|     { | ||||
|         $server = Server::find($server_id); | ||||
|         StopApplicationOneServer::run($this->resource, $server); | ||||
|         $this->refreshServers(); | ||||
|     } | ||||
|     public function redeploy(int $network_id, int $server_id) | ||||
|     { | ||||
|         if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) { | ||||
| @ -59,6 +67,7 @@ class Destination extends Component | ||||
|             application: $this->resource, | ||||
|             server: $server, | ||||
|             destination: $destination, | ||||
|             only_this_server: true, | ||||
|             no_questions_asked: true, | ||||
|         ); | ||||
|         return redirect()->route('project.application.deployment.show', [ | ||||
| @ -68,11 +77,28 @@ class Destination extends Component | ||||
|             'environment_name' => data_get($this->resource, 'environment.name'), | ||||
|         ]); | ||||
|     } | ||||
|     public function promote(int $network_id, int $server_id) | ||||
|     { | ||||
|         $main_destination = $this->resource->destination; | ||||
|         $this->resource->update([ | ||||
|             'destination_id' => $network_id, | ||||
|             'destination_type' => StandaloneDocker::class, | ||||
|         ]); | ||||
|         $this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]); | ||||
|         $this->resource->additional_networks()->attach($main_destination->id, ['server_id' => $main_destination->server->id]); | ||||
|         $this->refreshServers(); | ||||
|     } | ||||
|     public function refreshServers() | ||||
|     { | ||||
|         ContainerStatusJob::dispatchSync($this->resource->destination->server); | ||||
|         $this->loadData(); | ||||
|         $this->dispatch('refresh'); | ||||
|         ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.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->dispatch('loadData'); | ||||
|         $this->loadData(); | ||||
|         ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id')); | ||||
|     } | ||||
|     public function removeServer(int $network_id, int $server_id) | ||||
| @ -84,8 +110,7 @@ class Destination extends Component | ||||
|         $server = Server::find($server_id); | ||||
|         StopApplicationOneServer::run($this->resource, $server); | ||||
|         $this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]); | ||||
|         $this->resource->load(['additional_networks']); | ||||
|         $this->dispatch('loadData'); | ||||
|         $this->loadData(); | ||||
|         ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id')); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,6 @@ use App\Enums\ApplicationDeploymentStatus; | ||||
| use Illuminate\Database\Eloquent\Casts\Attribute; | ||||
| use Illuminate\Database\Eloquent\Relations\HasMany; | ||||
| use Illuminate\Database\Eloquent\SoftDeletes; | ||||
| use Illuminate\Support\Collection; | ||||
| use Spatie\Activitylog\Models\Activity; | ||||
| use Illuminate\Support\Str; | ||||
| use RuntimeException; | ||||
| @ -274,17 +273,13 @@ class Application extends BaseModel | ||||
|                     foreach ($additional_servers_status as $status) { | ||||
|                         $server_status = str($status)->before(':')->value(); | ||||
|                         $server_health = str($status)->after(':')->value() ?? 'unhealthy'; | ||||
|                         if ($server_status !== 'running') { | ||||
|                         if ($main_server_status !== $server_status) { | ||||
|                             $complex_status = 'degraded'; | ||||
|                         } | ||||
|                         } | ||||
|                         if ($server_health !== 'healthy') { | ||||
|                         if ($main_server_health !== $server_health) { | ||||
|                             $complex_health = 'unhealthy'; | ||||
|                         } | ||||
|                     } | ||||
|                     } | ||||
|                     return "$complex_status:$complex_health"; | ||||
|                 } | ||||
|             }, | ||||
|  | ||||
| @ -11,11 +11,12 @@ class Index extends Component | ||||
|     /** | ||||
|      * Create a new component instance. | ||||
|      */ | ||||
|     public $status = "exited:unhealthy"; | ||||
|     public function __construct( | ||||
|         public string $status = 'exited', | ||||
|     ) | ||||
|     { | ||||
|         //
 | ||||
|         public $resource = null, | ||||
|         public bool $showRefreshButton = true, | ||||
|     ) { | ||||
|         $this->status = $resource->status; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -8,7 +8,7 @@ use App\Models\Server; | ||||
| use App\Models\StandaloneDocker; | ||||
| use Spatie\Url\Url; | ||||
| 
 | ||||
| function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, Server $server = null, StandaloneDocker $destination = null) | ||||
| function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, Server $server = null, StandaloneDocker $destination = null, bool $only_this_server = false) | ||||
| { | ||||
|     $application_id = $application->id; | ||||
|     $deployment_link = Url::fromString($application->link() . "/deployment/{$deployment_uuid}"); | ||||
| @ -37,7 +37,8 @@ function queue_application_deployment(Application $application, string $deployme | ||||
|         'is_webhook' => $is_webhook, | ||||
|         'restart_only' => $restart_only, | ||||
|         'commit' => $commit, | ||||
|         'git_type' => $git_type | ||||
|         'git_type' => $git_type, | ||||
|         'only_this_server' => $only_this_server | ||||
|     ]); | ||||
| 
 | ||||
|     if ($no_questions_asked) { | ||||
|  | ||||
| @ -0,0 +1,28 @@ | ||||
| <?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::table('application_deployment_queues', function (Blueprint $table) { | ||||
|             $table->boolean('only_this_server')->default(false); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reverse the migrations. | ||||
|      */ | ||||
|     public function down(): void | ||||
|     { | ||||
|         Schema::table('application_deployment_queues', function (Blueprint $table) { | ||||
|             $table->dropColumn('only_this_server'); | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
| @ -41,7 +41,7 @@ | ||||
|         @if ($resource->getMorphClass() == 'App\Models\Service') | ||||
|             <x-status.services :service="$resource" /> | ||||
|         @else | ||||
|             <x-status.index :status="$resource->status" /> | ||||
|             <x-status.index :resource="$resource" /> | ||||
|         @endif | ||||
|     </ol> | ||||
| </nav> | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| @props(['status', 'showRefreshButton' => true]) | ||||
| @if (str($status)->startsWith('running')) | ||||
|     <x-status.running :status="$status" /> | ||||
| @elseif(str($status)->startsWith('restarting') || | ||||
| @ -6,7 +5,7 @@ | ||||
|         str($status)->startsWith('degraded')) | ||||
|     <x-status.restarting :status="$status" /> | ||||
| @else | ||||
|     <x-status.stopped :status="$status"/> | ||||
|     <x-status.stopped :status="$status" /> | ||||
| @endif | ||||
| 
 | ||||
| @if (!str($status)->contains('exited') && $showRefreshButton) | ||||
|  | ||||
| @ -12,5 +12,4 @@ | ||||
|             data_get($application_deployment_queue, 'status') === 'queued') | ||||
|         <x-forms.button isError wire:click.prevent="cancel">Cancel</x-forms.button> | ||||
|     @endif | ||||
| 
 | ||||
| </div> | ||||
|  | ||||
| @ -51,12 +51,17 @@ | ||||
|                     @if (decode_remote_command_output($application_deployment_queue)->count() > 0) | ||||
|                         @foreach (decode_remote_command_output($application_deployment_queue) as $line) | ||||
|                             <div @class([ | ||||
|                                 'font-mono whitespace-pre-line', | ||||
|                                 'font-mono', | ||||
|                                 'text-warning' => $line['hidden'], | ||||
|                                 'text-red-500' => $line['type'] == 'stderr', | ||||
|                             ])>[{{ $line['timestamp'] }}] @if ($line['hidden']) | ||||
|                                     <br>COMMAND: <br>{{ $line['command'] }} <br><br>OUTPUT: | ||||
|                                     @endif{{ $line['output'] }}@if ($line['hidden']) | ||||
|                                     @endif @if (str($line['output'])->contains('http://') || str($line['output'])->contains('https://')) | ||||
|                                         @php | ||||
|                                             $line['output'] = preg_replace('/(https?:\/\/[^\s]+)/', '<a href="$1" target="_blank" class="underline text-neutral-400">$1</a>', $line['output']); | ||||
|                                         @endphp {!! $line['output'] !!} | ||||
|                                     @else | ||||
|                                         {{ $line['output'] }} | ||||
|                                     @endif | ||||
|                             </div> | ||||
|                         @endforeach | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <nav wire:poll.30000ms="check_status"> | ||||
| <nav wire:poll.5000ms="check_status"> | ||||
|     <x-resources.breadcrumbs :resource="$application" :parameters="$parameters" /> | ||||
|     <div class="navbar-main"> | ||||
|         <a class="{{ request()->routeIs('project.application.configuration') ? 'text-white' : '' }}" | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
|     <div class="grid grid-cols-1 gap-4 py-4"> | ||||
|         <div class="flex gap-2"> | ||||
|             <div class="relative flex flex-col text-white cursor-default box-without-bg bg-coolgray-100 w-96"> | ||||
|                 <div class="font-bold">Main Server</div> | ||||
|                 <div class="text-xl font-bold">Primary Server</div> | ||||
|                 @if (str($resource->realStatus())->startsWith('running')) | ||||
|                     <div title="{{ $resource->realStatus() }}" class="absolute bg-success -top-1 -left-1 badge badge-xs"> | ||||
|                     </div> | ||||
| @ -21,7 +21,11 @@ | ||||
|             </div> | ||||
|             @if ($resource?->additional_networks?->count() > 0) | ||||
|                 <x-forms.button | ||||
|                     wire:click="redeploy('{{ data_get($resource, 'destination.id') }}','{{ data_get($resource, 'destination.server.id') }}')">Redeploy</x-forms.button> | ||||
|                     wire:click="redeploy('{{ data_get($resource, 'destination.id') }}','{{ data_get($resource, 'destination.server.id') }}')">Deploy</x-forms.button> | ||||
|                 @if (str($resource->realStatus())->startsWith('running')) | ||||
|                     <x-forms.button isError | ||||
|                         wire:click="stop('{{ data_get($resource, 'destination.server.id') }}')">Stop</x-forms.button> | ||||
|                 @endif | ||||
|             @endif | ||||
|         </div> | ||||
|         @if ($resource?->additional_networks?->count() > 0) | ||||
| @ -41,16 +45,23 @@ | ||||
|                         <div> | ||||
|                             Network: {{ data_get($destination, 'network') }} | ||||
|                         </div> | ||||
| 
 | ||||
|                     </div> | ||||
|                     <x-forms.button | ||||
|                         wire:click="redeploy('{{ data_get($destination, 'id') }}','{{ data_get($destination, 'server.id') }}')">Redeploy</x-forms.button> | ||||
|                         wire:click="redeploy('{{ data_get($destination, 'id') }}','{{ data_get($destination, 'server.id') }}')">Deploy</x-forms.button> | ||||
|                     <x-forms.button | ||||
|                         wire:click="promote('{{ data_get($destination, 'id') }}','{{ data_get($destination, 'server.id') }}')">Promote | ||||
|                         to Primary </x-forms.button> | ||||
|                     @if (data_get_str($destination, 'pivot.status')->startsWith('running')) | ||||
|                         <x-forms.button isError | ||||
|                             wire:click="stop('{{ data_get($destination, 'server.id') }}')">Stop</x-forms.button> | ||||
|                     @endif | ||||
|                     <x-new-modal | ||||
|                         action="removeServer({{ data_get($destination, 'id') }},{{ data_get($destination, 'server.id') }})" | ||||
|                         isErrorButton buttonTitle="Remove Server"> | ||||
|                         This will stop the running application in this server and remove it as a deployment | ||||
|                         destination.<br><br>Please think again. | ||||
|                     </x-new-modal> | ||||
| 
 | ||||
|                 </div> | ||||
|             @endforeach | ||||
|         @endif | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user