2023-04-25 08:47:13 +00:00
< ? php
2023-12-07 18:06:32 +00:00
namespace App\Livewire\Server ;
2023-04-25 08:47:13 +00:00
2024-06-18 14:42:42 +00:00
use App\Actions\Server\StartSentinel ;
use App\Actions\Server\StopSentinel ;
use App\Jobs\PullSentinelImageJob ;
2024-08-14 21:18:55 +00:00
use App\Models\Server ;;
2024-08-15 10:04:06 +00:00
2023-04-25 08:47:13 +00:00
use Livewire\Component ;
class Form extends Component
{
public Server $server ;
2024-06-10 20:43:34 +00:00
2023-10-09 09:00:18 +00:00
public bool $isValidConnection = false ;
2024-06-10 20:43:34 +00:00
2023-10-09 09:00:18 +00:00
public bool $isValidDocker = false ;
2024-06-10 20:43:34 +00:00
2023-10-09 09:00:18 +00:00
public ? string $wildcard_domain = null ;
2024-06-10 20:43:34 +00:00
2023-07-07 19:07:42 +00:00
public int $cleanup_after_percentage ;
2024-06-10 20:43:34 +00:00
2023-09-18 09:49:26 +00:00
public bool $dockerInstallationStarted = false ;
2024-06-10 20:43:34 +00:00
2024-02-15 13:14:11 +00:00
public bool $revalidate = false ;
2024-02-05 13:40:54 +00:00
2024-02-15 13:14:11 +00:00
protected $listeners = [ 'serverInstalled' , 'revalidate' => '$refresh' ];
2023-04-25 08:47:13 +00:00
protected $rules = [
2023-11-28 14:49:24 +00:00
'server.name' => 'required' ,
2023-04-25 08:47:13 +00:00
'server.description' => 'nullable' ,
2023-10-13 07:31:44 +00:00
'server.ip' => 'required' ,
2023-04-25 08:47:13 +00:00
'server.user' => 'required' ,
'server.port' => 'required' ,
2023-11-28 14:49:24 +00:00
'server.settings.is_cloudflare_tunnel' => 'required|boolean' ,
2023-06-15 11:51:31 +00:00
'server.settings.is_reachable' => 'required' ,
2023-11-29 09:06:52 +00:00
'server.settings.is_swarm_manager' => 'required|boolean' ,
2023-12-18 13:01:25 +00:00
'server.settings.is_swarm_worker' => 'required|boolean' ,
2024-01-16 14:19:14 +00:00
'server.settings.is_build_server' => 'required|boolean' ,
2024-07-18 12:38:56 +00:00
'server.settings.is_force_cleanup_enabled' => 'required|boolean' ,
2024-01-25 10:57:47 +00:00
'server.settings.concurrent_builds' => 'required|integer|min:1' ,
2024-02-08 11:34:01 +00:00
'server.settings.dynamic_timeout' => 'required|integer|min:1' ,
2024-06-18 14:42:42 +00:00
'server.settings.is_metrics_enabled' => 'required|boolean' ,
'server.settings.metrics_token' => 'required' ,
'server.settings.metrics_refresh_rate_seconds' => 'required|integer|min:1' ,
'server.settings.metrics_history_days' => 'required|integer|min:1' ,
2023-06-23 12:20:47 +00:00
'wildcard_domain' => 'nullable|url' ,
2024-06-20 11:17:06 +00:00
'server.settings.is_server_api_enabled' => 'required|boolean' ,
2024-08-12 16:40:32 +00:00
'server.settings.server_timezone' => 'required|string|timezone' ,
2023-04-25 08:47:13 +00:00
];
2024-06-10 20:43:34 +00:00
2023-06-16 10:35:40 +00:00
protected $validationAttributes = [
2023-10-12 09:41:37 +00:00
'server.name' => 'Name' ,
'server.description' => 'Description' ,
2023-11-03 09:57:58 +00:00
'server.ip' => 'IP address/Domain' ,
2023-10-12 09:41:37 +00:00
'server.user' => 'User' ,
'server.port' => 'Port' ,
2023-09-23 11:34:40 +00:00
'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel' ,
2023-11-29 09:06:52 +00:00
'server.settings.is_reachable' => 'Is reachable' ,
'server.settings.is_swarm_manager' => 'Swarm Manager' ,
2023-12-18 13:01:25 +00:00
'server.settings.is_swarm_worker' => 'Swarm Worker' ,
2024-01-16 14:19:14 +00:00
'server.settings.is_build_server' => 'Build Server' ,
2024-01-24 10:12:23 +00:00
'server.settings.concurrent_builds' => 'Concurrent Builds' ,
2024-02-08 11:34:01 +00:00
'server.settings.dynamic_timeout' => 'Dynamic Timeout' ,
2024-06-18 14:42:42 +00:00
'server.settings.is_metrics_enabled' => 'Metrics' ,
'server.settings.metrics_token' => 'Metrics Token' ,
'server.settings.metrics_refresh_rate_seconds' => 'Metrics Interval' ,
'server.settings.metrics_history_days' => 'Metrics History' ,
2024-06-20 11:17:06 +00:00
'server.settings.is_server_api_enabled' => 'Server API' ,
2024-08-12 16:40:32 +00:00
'server.settings.server_timezone' => 'Server Timezone' ,
2023-06-16 10:35:40 +00:00
];
2023-08-08 09:51:36 +00:00
2024-08-12 16:40:32 +00:00
public $timezones ;
public function mount ( Server $server )
2023-06-22 13:25:57 +00:00
{
2024-08-12 16:40:32 +00:00
$this -> server = $server ;
$this -> timezones = collect ( timezone_identifiers_list ()) -> sort () -> values () -> toArray ();
2023-06-22 13:25:57 +00:00
$this -> wildcard_domain = $this -> server -> settings -> wildcard_domain ;
2023-07-07 19:07:42 +00:00
$this -> cleanup_after_percentage = $this -> server -> settings -> cleanup_after_percentage ;
2024-08-15 10:04:06 +00:00
2024-08-14 22:31:23 +00:00
if ( $this -> server -> settings -> server_timezone === '' ) {
$defaultTimezone = config ( 'app.timezone' );
$this -> updateServerTimezone ( $defaultTimezone );
}
2023-06-22 13:25:57 +00:00
}
2024-06-10 20:43:34 +00:00
2024-02-05 13:40:54 +00:00
public function serverInstalled ()
2023-10-13 07:31:44 +00:00
{
2024-02-05 13:40:54 +00:00
$this -> server -> refresh ();
$this -> server -> settings -> refresh ();
2023-10-09 09:00:18 +00:00
}
2024-06-10 20:43:34 +00:00
2024-05-24 10:01:04 +00:00
public function updatedServerSettingsIsBuildServer ()
{
2024-06-18 14:42:42 +00:00
$this -> dispatch ( 'refreshServerShow' );
2024-05-24 10:01:04 +00:00
$this -> dispatch ( 'serverRefresh' );
$this -> dispatch ( 'proxyStatusUpdated' );
}
2024-06-10 20:43:34 +00:00
2024-06-20 11:17:06 +00:00
public function checkPortForServerApi ()
{
try {
if ( $this -> server -> settings -> is_server_api_enabled === true ) {
$this -> server -> checkServerApi ();
$this -> dispatch ( 'success' , 'Server API is reachable.' );
}
} catch ( \Throwable $e ) {
return handleError ( $e , $this );
}
}
2023-10-09 09:00:18 +00:00
public function instantSave ()
{
2023-11-28 14:49:24 +00:00
try {
refresh_server_connection ( $this -> server -> privateKey );
$this -> validateServer ( false );
$this -> server -> settings -> save ();
2024-06-18 14:42:42 +00:00
$this -> server -> save ();
2024-02-22 13:53:42 +00:00
$this -> dispatch ( 'success' , 'Server updated.' );
2024-06-18 14:42:42 +00:00
$this -> dispatch ( 'refreshServerShow' );
2024-06-20 11:17:06 +00:00
if ( $this -> server -> isSentinelEnabled ()) {
2024-06-18 14:42:42 +00:00
PullSentinelImageJob :: dispatchSync ( $this -> server );
2024-06-20 11:17:06 +00:00
ray ( 'Sentinel is enabled' );
if ( $this -> server -> settings -> isDirty ( 'is_metrics_enabled' )) {
$this -> dispatch ( 'reloadWindow' );
}
if ( $this -> server -> settings -> isDirty ( 'is_server_api_enabled' ) && $this -> server -> settings -> is_server_api_enabled === true ) {
ray ( 'Starting sentinel' );
}
2024-06-18 14:42:42 +00:00
} else {
2024-06-20 11:17:06 +00:00
ray ( 'Sentinel is not enabled' );
2024-06-18 14:42:42 +00:00
StopSentinel :: dispatch ( $this -> server );
}
2024-06-20 11:17:06 +00:00
// $this->checkPortForServerApi();
2024-06-18 14:42:42 +00:00
} catch ( \Throwable $e ) {
return handleError ( $e , $this );
}
}
2024-06-18 14:43:18 +00:00
public function restartSentinel ()
{
2024-06-18 14:42:42 +00:00
try {
$version = get_latest_sentinel_version ();
StartSentinel :: run ( $this -> server , $version , true );
$this -> dispatch ( 'success' , 'Sentinel restarted.' );
2023-11-28 14:49:24 +00:00
} catch ( \Throwable $e ) {
return handleError ( $e , $this );
}
2023-09-23 11:34:40 +00:00
}
2024-06-10 20:43:34 +00:00
2024-02-15 13:14:11 +00:00
public function revalidate ()
{
$this -> revalidate = true ;
2024-02-15 12:52:54 +00:00
}
2024-06-10 20:43:34 +00:00
2023-10-13 07:31:44 +00:00
public function checkLocalhostConnection ()
{
2024-04-10 13:00:46 +00:00
$this -> submit ();
2024-04-16 13:42:38 +00:00
[ 'uptime' => $uptime , 'error' => $error ] = $this -> server -> validateConnection ();
2023-10-11 11:30:36 +00:00
if ( $uptime ) {
2023-12-07 18:06:32 +00:00
$this -> dispatch ( 'success' , 'Server is reachable.' );
2023-10-11 11:30:36 +00:00
$this -> server -> settings -> is_reachable = true ;
2023-10-11 11:34:51 +00:00
$this -> server -> settings -> is_usable = true ;
2023-10-11 11:30:36 +00:00
$this -> server -> settings -> save ();
2024-05-03 08:54:46 +00:00
$this -> dispatch ( 'proxyStatusUpdated' );
2023-10-11 11:30:36 +00:00
} else {
2024-08-15 10:04:06 +00:00
$this -> dispatch ( 'error' , 'Server is not reachable.' , 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: ' . $error );
2024-06-10 20:43:34 +00:00
2023-10-11 11:30:36 +00:00
return ;
}
}
2024-06-10 20:43:34 +00:00
2023-10-09 09:00:18 +00:00
public function validateServer ( $install = true )
2023-04-26 13:38:50 +00:00
{
2024-07-23 12:20:53 +00:00
$this -> server -> update ([
'validation_logs' => null ,
]);
2024-02-22 10:28:45 +00:00
$this -> dispatch ( 'init' , $install );
2023-04-26 13:38:50 +00:00
}
2023-08-08 09:51:36 +00:00
2023-04-25 08:47:13 +00:00
public function submit ()
{
2024-08-14 21:18:55 +00:00
if ( isCloud () && ! isDev ()) {
2023-10-13 07:31:44 +00:00
$this -> validate ();
$this -> validate ([
2023-11-03 09:57:58 +00:00
'server.ip' => 'required' ,
2023-10-13 07:31:44 +00:00
]);
2023-10-13 07:34:11 +00:00
} else {
$this -> validate ();
2023-10-13 07:31:44 +00:00
}
2023-09-14 16:10:13 +00:00
$uniqueIPs = Server :: all () -> reject ( function ( Server $server ) {
return $server -> id === $this -> server -> id ;
}) -> pluck ( 'ip' ) -> toArray ();
if ( in_array ( $this -> server -> ip , $uniqueIPs )) {
2023-12-07 18:06:32 +00:00
$this -> dispatch ( 'error' , 'IP address is already in use by another team.' );
2023-09-14 16:10:13 +00:00
return ;
}
2023-10-11 11:34:51 +00:00
refresh_server_connection ( $this -> server -> privateKey );
2023-06-22 13:25:57 +00:00
$this -> server -> settings -> wildcard_domain = $this -> wildcard_domain ;
2023-07-07 19:07:42 +00:00
$this -> server -> settings -> cleanup_after_percentage = $this -> cleanup_after_percentage ;
2024-08-12 16:40:32 +00:00
2024-08-14 21:18:55 +00:00
$currentTimezone = $this -> server -> settings -> getOriginal ( 'server_timezone' );
$newTimezone = $this -> server -> settings -> server_timezone ;
if ( $currentTimezone !== $newTimezone || $currentTimezone === '' ) {
2024-08-12 16:40:32 +00:00
try {
2024-08-14 21:18:55 +00:00
$timezoneUpdated = $this -> updateServerTimezone ( $newTimezone );
if ( $timezoneUpdated ) {
$this -> server -> settings -> server_timezone = $newTimezone ;
$this -> server -> settings -> save ();
} else {
return ;
}
2024-08-12 16:40:32 +00:00
} catch ( \Exception $e ) {
$this -> dispatch ( 'error' , 'Failed to update server timezone: ' . $e -> getMessage ());
return ;
}
}
2023-06-22 13:25:57 +00:00
$this -> server -> settings -> save ();
2023-04-25 08:47:13 +00:00
$this -> server -> save ();
2024-02-22 13:53:42 +00:00
$this -> dispatch ( 'success' , 'Server updated.' );
2023-04-25 08:47:13 +00:00
}
2024-08-15 10:04:06 +00:00
2024-08-12 16:40:32 +00:00
public function updatedServerTimezone ( $value )
{
if ( ! is_string ( $value ) || ! in_array ( $value , timezone_identifiers_list ())) {
$this -> addError ( 'server.settings.server_timezone' , 'Invalid timezone.' );
return ;
}
$this -> server -> settings -> server_timezone = $value ;
2024-08-14 21:29:33 +00:00
$this -> updateServerTimezone ( $value );
2024-08-12 16:40:32 +00:00
}
2024-08-15 10:04:06 +00:00
private function updateServerTimezone ( $desired_timezone )
2024-08-12 16:40:32 +00:00
{
try {
2024-08-14 21:18:55 +00:00
$commands = [
2024-08-15 11:13:52 +00:00
" if command -v timedatectl > /dev/null 2>&1 && pidof systemd > /dev/null; then " ,
" timedatectl set-timezone " . escapeshellarg ( $desired_timezone ),
" elif [ -f /etc/timezone ]; then " ,
2024-08-15 10:04:06 +00:00
" echo " . escapeshellarg ( $desired_timezone ) . " > /etc/timezone " ,
2024-08-15 11:13:52 +00:00
" rm -f /etc/localtime " ,
2024-08-15 10:04:06 +00:00
" ln -sf /usr/share/zoneinfo/ " . escapeshellarg ( $desired_timezone ) . " /etc/localtime " ,
" elif [ -f /etc/localtime ]; then " ,
2024-08-15 11:13:52 +00:00
" rm -f /etc/localtime " ,
2024-08-15 10:04:06 +00:00
" ln -sf /usr/share/zoneinfo/ " . escapeshellarg ( $desired_timezone ) . " /etc/localtime " ,
" else " ,
" echo 'Unable to set timezone' " ,
" exit 1 " ,
" fi " ,
2024-08-15 11:13:52 +00:00
" if command -v dpkg-reconfigure > /dev/null 2>&1; then " ,
" dpkg-reconfigure -f noninteractive tzdata " ,
" elif command -v tzdata-update > /dev/null 2>&1; then " ,
" tzdata-update " ,
" elif [ -f /etc/sysconfig/clock ]; then " ,
" sed -i 's/^ZONE=.*/ZONE= \" " . $desired_timezone . " \" /' /etc/sysconfig/clock " ,
" source /etc/sysconfig/clock " ,
" fi " ,
" if command -v systemctl > /dev/null 2>&1 && pidof systemd > /dev/null; then " ,
" systemctl try-restart systemd-timesyncd.service || true " ,
" elif command -v service > /dev/null 2>&1; then " ,
" service ntpd restart || service ntp restart || true " ,
" fi " ,
2024-08-15 10:04:06 +00:00
" echo \" Timezone updated to: $desired_timezone\ " " ,
" date "
2024-08-14 21:18:55 +00:00
];
2024-08-15 11:36:17 +00:00
2024-08-15 11:37:52 +00:00
instant_remote_process ( $commands , $this -> server );
2024-08-15 11:36:17 +00:00
2024-08-15 11:25:30 +00:00
$verificationCommands = [
" readlink /etc/localtime | sed 's#/usr/share/zoneinfo/##' " ,
2024-08-15 11:30:08 +00:00
" date +'%Z %:z' "
2024-08-15 11:25:30 +00:00
];
$verificationResult = instant_remote_process ( $verificationCommands , $this -> server , false );
$verificationLines = explode ( " \n " , trim ( $verificationResult ));
2024-08-15 11:36:17 +00:00
2024-08-15 11:25:30 +00:00
if ( count ( $verificationLines ) !== 2 ) {
$this -> dispatch ( 'error' , 'Failed to verify timezone update. Unexpected server response.' );
return false ;
}
2024-08-15 11:36:17 +00:00
2024-08-15 11:30:08 +00:00
$actualTimezone = trim ( $verificationLines [ 0 ]);
[ $abbreviation , $offset ] = explode ( ' ' , trim ( $verificationLines [ 1 ]));
2024-08-15 11:36:17 +00:00
2024-08-15 11:25:30 +00:00
$desiredTz = new \DateTimeZone ( $desired_timezone );
$desiredAbbr = ( new \DateTime ( 'now' , $desiredTz )) -> format ( 'T' );
2024-08-15 11:30:08 +00:00
$desiredOffset = $this -> formatOffset ( $desiredTz -> getOffset ( new \DateTime ( 'now' , $desiredTz )));
2024-08-15 11:36:17 +00:00
2024-08-15 11:30:08 +00:00
if ( $actualTimezone === $desired_timezone && $abbreviation === $desiredAbbr && $offset === $desiredOffset ) {
2024-08-15 11:25:30 +00:00
$this -> server -> settings -> server_timezone = $desired_timezone ;
$this -> server -> settings -> save ();
return true ;
} else {
2024-08-14 22:51:45 +00:00
$this -> dispatch ( 'error' , 'Failed to update server timezone. The server reported a different timezone than requested.' );
return false ;
}
2024-08-12 16:40:32 +00:00
} catch ( \Exception $e ) {
2024-08-14 22:51:45 +00:00
$this -> dispatch ( 'error' , 'Failed to update server timezone: ' . $e -> getMessage ());
2024-08-14 21:18:55 +00:00
return false ;
2024-08-12 16:40:32 +00:00
}
}
2024-08-15 11:36:17 +00:00
2024-08-15 11:25:30 +00:00
private function formatOffset ( $offsetSeconds )
{
$hours = abs ( $offsetSeconds ) / 3600 ;
$minutes = ( abs ( $offsetSeconds ) % 3600 ) / 60 ;
return sprintf ( '%s%02d:%02d' , $offsetSeconds >= 0 ? '+' : '-' , $hours , $minutes );
}
2024-08-15 11:36:17 +00:00
}