From 5c22dd35cf9e17febb4a03b92b2983a5f21c9231 Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Sat, 18 Mar 2023 17:59:37 +0000 Subject: [PATCH 01/14] Environment setup --- .env.example | 24 ++++-------------------- docker-compose.yaml | 10 +++------- package-lock.json | 2 +- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/.env.example b/.env.example index ab8f68072..f6b965c91 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,10 @@ ############################################################################################################ # Development Environment -# Userid for the user that will run the application inside the container +# User and group id for the user that will run the application inside the container +# Run in your terminal: `id -u` and `id -g` and that's the results USERID= +GROUPID= ############################################################################################################ APP_NAME=Laravel @@ -11,10 +13,6 @@ APP_KEY= APP_DEBUG=true APP_URL=http://localhost -LOG_CHANNEL=stack -LOG_DEPRECATIONS_CHANNEL=null -LOG_LEVEL=debug - DB_CONNECTION=pgsql DB_HOST=postgres DB_PORT=5432 @@ -22,18 +20,4 @@ DB_DATABASE=coolify DB_USERNAME=sail DB_PASSWORD=password -BROADCAST_DRIVER=log -CACHE_DRIVER=file -FILESYSTEM_DISK=local -QUEUE_CONNECTION=sync -SESSION_DRIVER=file -SESSION_LIFETIME=120 - -MAIL_MAILER=smtp -MAIL_HOST=mailpit -MAIL_PORT=1025 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_ENCRYPTION=null -MAIL_FROM_ADDRESS="hello@example.com" -MAIL_FROM_NAME="${APP_NAME}" \ No newline at end of file +QUEUE_CONNECTION=redis diff --git a/docker-compose.yaml b/docker-compose.yaml index dc02e3db8..b22e872fe 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -8,11 +8,11 @@ services: - "${APP_PORT:-8000}:80" - "${VITE_PORT:-5173}:${VITE_PORT:-5173}" environment: - PGID: "${USERID:-9999}" PUID: "${USERID:-9999}" + PGID: "${GROUPID:-9999}" SSL_MODE: 'off' volumes: - - .:/var/www/html:cached + - .:/var/www/html postgres: image: postgres:15-alpine ports: @@ -34,11 +34,7 @@ services: ] retries: 3 timeout: 5s - mailpit: - image: "axllent/mailpit:latest" - ports: - - "${FORWARD_MAILPIT_PORT:-1025}:1025" - - "${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025" + volumes: db-coolify: driver: local diff --git a/package-lock.json b/package-lock.json index 63682f793..ece4b4d9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "html", + "name": "coolify", "lockfileVersion": 3, "requires": true, "packages": { From 315d35ca10744229d5808a50a36be275150f1f51 Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Mon, 20 Mar 2023 11:04:14 +0000 Subject: [PATCH 02/14] Adds `testing-host` w/ a dummy project. --- Dockerfile | 24 ++++--- docker-compose.yaml | 20 ++++++ docker/testing-host/Dockerfile | 67 +++++++++++++++++++ docker/testing-host/dummy-project/Dockerfile | 31 +++++++++ .../dummy-project/docker-compose.yml | 10 +++ docker/testing-host/dummy-project/index.php | 3 + docker/testing-host/start-container | 3 + docker/testing-host/supervisord.conf | 13 ++++ 8 files changed, 161 insertions(+), 10 deletions(-) create mode 100644 docker/testing-host/Dockerfile create mode 100644 docker/testing-host/dummy-project/Dockerfile create mode 100644 docker/testing-host/dummy-project/docker-compose.yml create mode 100644 docker/testing-host/dummy-project/index.php create mode 100644 docker/testing-host/start-container create mode 100644 docker/testing-host/supervisord.conf diff --git a/Dockerfile b/Dockerfile index fd4edd2bf..6ccc38764 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,21 +6,25 @@ ARG POSTGRES_VERSION=15 RUN apt-get update \ && curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \ && apt-get install -y nodejs \ - && npm install -g npm + && npm install -g npm -RUN apt-get install -y php-pgsql +RUN apt-get install -y php-pgsql openssh-client RUN apt-get -y autoremove \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* -# Adding test ssh key +# Adding Coolify User and SSH key to connect to the Testing-Host (which is simulation of a VPS) +RUN useradd -ms /bin/bash coolify +USER coolify RUN mkdir -p ~/.ssh RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\ - b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\ - QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\ - hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\ - AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\ - uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\ - -----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519 -RUN chmod 0600 ~/.ssh/id_ed25519 \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\ +QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\ +hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\ +AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\ +uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\ +-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519 +RUN chmod 0600 ~/.ssh/id_ed25519 + +USER root diff --git a/docker-compose.yaml b/docker-compose.yaml index b22e872fe..ae1dc82f8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,6 +1,7 @@ version: '3.8' services: php: + image: coolify:4 build: context: . dockerfile: Dockerfile @@ -13,12 +14,16 @@ services: SSL_MODE: 'off' volumes: - .:/var/www/html + networks: + - coolify postgres: image: postgres:15-alpine ports: - "${FORWARD_DB_PORT:-5432}:5432" volumes: - db-coolify:/var/lib/postgresql/data + networks: + - coolify environment: POSTGRES_USER: "${DB_USERNAME}" POSTGRES_PASSWORD: "${DB_PASSWORD}" @@ -34,7 +39,22 @@ services: ] retries: 3 timeout: 5s + testing-host: + container_name: coolify-testing-host + image: coolify-testing-host + build: + dockerfile: Dockerfile + context: ./docker/testing-host + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./docker/testing-host/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf + networks: + - coolify volumes: db-coolify: driver: local + +networks: + coolify: + driver: bridge diff --git a/docker/testing-host/Dockerfile b/docker/testing-host/Dockerfile new file mode 100644 index 000000000..8125614f0 --- /dev/null +++ b/docker/testing-host/Dockerfile @@ -0,0 +1,67 @@ +FROM ubuntu:22.04 + +ARG TARGETPLATFORM + +# https://download.docker.com/linux/static/stable/ +ARG DOCKER_VERSION=20.10.18 +# https://github.com/docker/compose/releases +# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug. +ARG DOCKER_COMPOSE_VERSION=2.6.1 +# https://github.com/buildpacks/pack/releases +ARG PACK_VERSION=v0.27.0 + +ENV DEBIAN_FRONTEND noninteractive +ENV TZ=UTC + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +RUN apt-get update \ + && apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor \ + sqlite3 libcap2-bin libpng-dev python2 dnsutils openssh-server sudo \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Setup sshd +RUN ssh-keygen -A +RUN mkdir -p /run/sshd + +# Install Docker CLI, Docker Compose, and Pack +RUN mkdir -p ~/.docker/cli-plugins +RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker +RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose +RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack +RUN curl -sSL https://nixpacks.com/install.sh | bash +RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack +RUN groupadd docker + +# Setup coolify user +RUN useradd -ms /bin/bash coolify +RUN usermod -aG sudo coolify +RUN usermod -aG docker coolify +RUN echo 'coolify ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +# Setup ssh'ing into the destination as Coolify User +USER coolify +RUN mkdir -p ~/.ssh +RUN echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68 coolify@coolify-instance" >> ~/.ssh/authorized_keys + +USER root + +# Setup ssh'ing into the destination as Root +RUN mkdir -p ~/.ssh +RUN echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68 coolify@coolify-instance" >> ~/.ssh/authorized_keys + +EXPOSE 22 + +COPY start-container /usr/local/bin/start-container +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +RUN chmod +x /usr/local/bin/start-container + +WORKDIR /root + +# Prepare projects +RUN mkdir -p projects +COPY dummy-project projects/dummy-project + +ENTRYPOINT ["start-container"] diff --git a/docker/testing-host/dummy-project/Dockerfile b/docker/testing-host/dummy-project/Dockerfile new file mode 100644 index 000000000..e18a991dd --- /dev/null +++ b/docker/testing-host/dummy-project/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:22.04 + +ARG WWWGROUP + +WORKDIR /var/www/html + +ENV DEBIAN_FRONTEND noninteractive +ENV TZ=UTC + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +RUN apt-get update \ + && apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \ + && curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \ + && echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \ + && apt-get update \ + && apt-get install -y php8.2-cli php8.2-dev \ + php8.2-curl php8.2-mbstring php8.2-xml php8.2-zip php8.2-bcmath \ + php8.2-intl php8.2-readline php8.2-msgpack php8.2-igbinary \ + && php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2 + +EXPOSE 8000 + +COPY . . + +ENTRYPOINT ["php", "-S", "0.0.0.0:8000"] diff --git a/docker/testing-host/dummy-project/docker-compose.yml b/docker/testing-host/dummy-project/docker-compose.yml new file mode 100644 index 000000000..ea23501c2 --- /dev/null +++ b/docker/testing-host/dummy-project/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3" + +services: + dummy-project: + image: dummy-project + build: + context: . + dockerfile: Dockerfile + extra_hosts: + - "host.docker.internal:host-gateway" diff --git a/docker/testing-host/dummy-project/index.php b/docker/testing-host/dummy-project/index.php new file mode 100644 index 000000000..42cfa8699 --- /dev/null +++ b/docker/testing-host/dummy-project/index.php @@ -0,0 +1,3 @@ + Date: Mon, 20 Mar 2023 11:05:08 +0000 Subject: [PATCH 03/14] Run file for running common tasks with few keystrokes :) --- run | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 run diff --git a/run b/run new file mode 100755 index 000000000..0888bd9d2 --- /dev/null +++ b/run @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +# Inspired on https://github.com/adriancooney/Taskfile +# Install an alias, to be able to simply execute `run` => echo 'alias run=./run' >> ~/.aliases +# + +set -e + +function help { + echo "$0 " + echo "Tasks:" + compgen -A function | cat -n +} + +function default { + help +} + +function bash { + docker-compose exec -u $(id -u) php bash +} + +# The user with native SSH capability +function coolify-bash { + docker-compose exec -u coolify php bash +} + +function root-bash { + docker-compose exec php bash +} + +# Usage: ./Taskfile envFile:set FOOBAR abc +# This will set the FOOBAR variable to "abc" in the .env file +function envFile:set { + sed -i "s#^$1=.*#$1=$2#g" .env +} + +TIMEFORMAT="Task completed in %3lR" +time "${@:-default}" From 75326f6626982b20b8b16e0c8e03a2f957126253 Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Mon, 20 Mar 2023 12:04:22 +0000 Subject: [PATCH 04/14] wip --- Dockerfile | 30 - app/Http/Livewire/RunCommand.php | 51 + app/Jobs/ExecuteCoolifyProcess.php | 131 +++ app/Services/CoolifyProcess.php | 45 + app/Services/ProcessStatus.php | 11 + app/Services/Ssh.php | 259 +++++ bootstrap/helpers.php | 24 + composer.json | 8 +- composer.lock | 966 ++++++++++++++++-- config/ray.php | 108 ++ coolify_id25519 | 7 + ...03_20_112410_create_activity_log_table.php | 27 + ...add_event_column_to_activity_log_table.php | 22 + ...atch_uuid_column_to_activity_log_table.php | 22 + .../2023_03_20_112810_create_jobs_table.php | 32 + docker-compose.yaml | 2 +- docker/dev/Dockerfile | 20 + .../etc/s6-overlay/s6-rc.d/queue-worker/run | 2 + .../etc/s6-overlay/s6-rc.d/queue-worker/type | 1 + .../s6-rc.d/user/contents.d/queue-worker | 0 resources/views/components/button.blade.php | 3 + resources/views/components/layout.blade.php | 24 + resources/views/components/navbar.blade.php | 15 + resources/views/demo.blade.php | 5 + .../views/livewire/run-command.blade.php | 44 + resources/views/welcome.blade.php | 4 + routes/web.php | 2 + 27 files changed, 1770 insertions(+), 95 deletions(-) delete mode 100644 Dockerfile create mode 100755 app/Http/Livewire/RunCommand.php create mode 100755 app/Jobs/ExecuteCoolifyProcess.php create mode 100644 app/Services/CoolifyProcess.php create mode 100644 app/Services/ProcessStatus.php create mode 100644 app/Services/Ssh.php create mode 100644 bootstrap/helpers.php create mode 100644 config/ray.php create mode 100644 coolify_id25519 create mode 100755 database/migrations/2023_03_20_112410_create_activity_log_table.php create mode 100755 database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php create mode 100755 database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php create mode 100755 database/migrations/2023_03_20_112810_create_jobs_table.php create mode 100644 docker/dev/Dockerfile create mode 100644 docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/run create mode 100644 docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/type create mode 100644 docker/dev/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker create mode 100644 resources/views/components/button.blade.php create mode 100644 resources/views/components/layout.blade.php create mode 100644 resources/views/components/navbar.blade.php create mode 100644 resources/views/demo.blade.php create mode 100755 resources/views/livewire/run-command.blade.php diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 6ccc38764..000000000 --- a/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM serversideup/php:8.2-fpm-nginx - -ARG NODE_VERSION=18 -ARG POSTGRES_VERSION=15 - -RUN apt-get update \ - && curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \ - && apt-get install -y nodejs \ - && npm install -g npm - -RUN apt-get install -y php-pgsql openssh-client - -RUN apt-get -y autoremove \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* - -# Adding Coolify User and SSH key to connect to the Testing-Host (which is simulation of a VPS) -RUN useradd -ms /bin/bash coolify -USER coolify -RUN mkdir -p ~/.ssh -RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\ -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\ -QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\ -hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\ -AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\ -uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\ ------END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519 -RUN chmod 0600 ~/.ssh/id_ed25519 - -USER root diff --git a/app/Http/Livewire/RunCommand.php b/app/Http/Livewire/RunCommand.php new file mode 100755 index 000000000..e99ca0da1 --- /dev/null +++ b/app/Http/Livewire/RunCommand.php @@ -0,0 +1,51 @@ +activity = coolifyProcess($this->command, 'testing-host'); + + + // Override manual to experiment +// $sleepingBeauty = 'x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done'; +// +// $commandString = <<activity = coolifyProcess($commandString, 'testing-host'); + + + $this->isKeepAliveOn = true; + } + + public function polling() + { + $this->activity?->refresh(); + + if ($this->activity?->properties['status'] === 'finished') { + $this->isKeepAliveOn = false; + } + } +} diff --git a/app/Jobs/ExecuteCoolifyProcess.php b/app/Jobs/ExecuteCoolifyProcess.php new file mode 100755 index 000000000..d1ba2c478 --- /dev/null +++ b/app/Jobs/ExecuteCoolifyProcess.php @@ -0,0 +1,131 @@ +clearAll(); + $this->timeStart = $start = hrtime(true); + + $user = $this->activity->getExtraProperty('user'); + $destination = $this->activity->getExtraProperty('destination'); + $port = $this->activity->getExtraProperty('port'); + $command = $this->activity->getExtraProperty('command'); + + $delimiter = 'EOF-COOLIFY-SSH'; + + File::chmod(base_path('coolify_id25519'), '0600'); + + $sshCommand = 'ssh ' + . '-i ./coolify_id25519' + . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' + . '-o PasswordAuthentication=no ' + . "{$user}@{$destination} " + . " 'bash -se' << \\$delimiter" . PHP_EOL + . $command . PHP_EOL + . $delimiter; + +// $sshCommand = "whoami ; pwd ; ls "; + + $process = Process::start( + $sshCommand, + $this->handleOutput(...), + ); + + + $res = $process->wait(); + + if (app()->environment('testing')) { + return $res; + } + + // TODO Why is this not persisting?? Immutable property?? + $this->activity->properties->put('pid', $process->id()); + $this->activity->properties->put('exitCode', $res->exitCode()); + $this->activity->properties->put('stdout', $res->output()); + $this->activity->properties->put('stderr', $res->errorOutput()); + $this->activity->save(); + } + + protected function handleOutput(string $type, string $output) + { + $this->currentTime = $this->elapsedTime(); + + if ($type === 'out') { + $this->stdOutIncremental .= $output; + } else { + $this->stdErrIncremental .= $output; + } + + $this->activity->description .= $output; + + if ($this->isAfterLastThrottle()) { + // Let's write to database. + DB::transaction(function () { + $this->activity->save(); + $this->lastWriteAt = $this->currentTime; + }); + } + } + + /** + * Decides if it's time to write again to database. + * + * @return bool + */ + protected function isAfterLastThrottle() + { + // If DB was never written, then we immediately decide we have to write. + if ($this->lastWriteAt === 0) { + return true; + } + + return ($this->currentTime - $this->throttleIntervalMS) > $this->lastWriteAt; + } + + protected function elapsedTime(): int + { + $timeMs = (hrtime(true) - $this->timeStart) / 1_000_000; + + return intval($timeMs); + } +} diff --git a/app/Services/CoolifyProcess.php b/app/Services/CoolifyProcess.php new file mode 100644 index 000000000..bc21bda98 --- /dev/null +++ b/app/Services/CoolifyProcess.php @@ -0,0 +1,45 @@ +activity = activity() + ->withProperty('type', 'COOLIFY_PROCESS') + ->withProperty('user', $this->user) + ->withProperty('destination', $this->destination) + ->withProperty('port', $this->port) + ->withProperty('command', $this->command) + ->withProperty('status', ProcessStatus::HOLDING) + ->log("Awaiting to start command...\n\n"); + } + + public function __invoke(): Activity|ProcessResult + { + $job = new ExecuteCoolifyProcess($this->activity); + + if (app()->environment('testing')) { + return $job->handle(); + } + + dispatch($job); + + return $this->activity; + } + + +} diff --git a/app/Services/ProcessStatus.php b/app/Services/ProcessStatus.php new file mode 100644 index 000000000..a835d29d3 --- /dev/null +++ b/app/Services/ProcessStatus.php @@ -0,0 +1,11 @@ +user = $user; + + $this->host = $host; + + if ($port !== null) { + $this->usePort($port); + } + + $this->processConfigurationClosure = fn(Process $process) => null; + + $this->onOutput = fn($type, $line) => null; + } + + public static function create(...$args): self + { + return new static(...$args); + } + + public function usePrivateKey(string $pathToPrivateKey): self + { + $this->extraOptions['private_key'] = '-i ' . $pathToPrivateKey; + + return $this; + } + + public function useJumpHost(string $jumpHost): self + { + $this->extraOptions['jump_host'] = '-J ' . $jumpHost; + + return $this; + } + + public function usePort(int $port): self + { + if ($port < 0) { + throw new Exception('Port must be a positive integer.'); + } + $this->extraOptions['port'] = '-p ' . $port; + + return $this; + } + + public function useMultiplexing(string $controlPath, string $controlPersist = '10m'): self + { + $this->extraOptions['control_master'] = '-o ControlMaster=auto -o ControlPath=' . $controlPath . ' -o ControlPersist=' . $controlPersist; + + return $this; + } + + public function configureProcess(Closure $processConfigurationClosure): self + { + $this->processConfigurationClosure = $processConfigurationClosure; + + return $this; + } + + public function onOutput(Closure $onOutput): self + { + $this->onOutput = $onOutput; + + return $this; + } + + public function enableStrictHostKeyChecking(): self + { + unset($this->extraOptions['enable_strict_check']); + + return $this; + } + + public function disableStrictHostKeyChecking(): self + { + $this->extraOptions['enable_strict_check'] = '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'; + + return $this; + } + + public function enableQuietMode(): self + { + $this->extraOptions['quiet'] = '-q'; + + return $this; + } + + public function disableQuietMode(): self + { + unset($this->extraOptions['quiet']); + + return $this; + } + + public function disablePasswordAuthentication(): self + { + $this->extraOptions['password_authentication'] = '-o PasswordAuthentication=no'; + + return $this; + } + + public function enablePasswordAuthentication(): self + { + unset($this->extraOptions['password_authentication']); + + return $this; + } + + public function addExtraOption(string $option): self + { + $this->extraOptions[] = $option; + + return $this; + } + + /** + * @param string|array $command + * + * @return string + */ + public function getExecuteCommand($command): string + { + $commands = $this->wrapArray($command); + + $extraOptions = implode(' ', $this->getExtraOptions()); + + $commandString = implode(PHP_EOL, $commands); + + $delimiter = 'EOF-SPATIE-SSH'; + + $target = $this->getTargetForSsh(); + + if (in_array($this->host, ['local', 'localhost', '127.0.0.1'])) { + return $commandString; + } + + return "ssh {$extraOptions} {$target} 'bash -se' << \\$delimiter" . PHP_EOL + . $commandString . PHP_EOL + . $delimiter; + } + + /** + * @param string|array $command + * + * @return \Symfony\Component\Process\Process + **/ + public function execute($command): Process + { + $sshCommand = $this->getExecuteCommand($command); + + return $this->run($sshCommand); + } + + /** + * @param string|array $command + * + * @return \Symfony\Component\Process\Process + */ + public function executeAsync($command): Process + { + $sshCommand = $this->getExecuteCommand($command); + + return $this->run($sshCommand, 'start'); + } + + public function getDownloadCommand(string $sourcePath, string $destinationPath): string + { + return "scp {$this->getExtraScpOptions()} {$this->getTargetForScp()}:$sourcePath $destinationPath"; + } + + public function download(string $sourcePath, string $destinationPath): Process + { + $downloadCommand = $this->getDownloadCommand($sourcePath, $destinationPath); + + return $this->run($downloadCommand); + } + + public function getUploadCommand(string $sourcePath, string $destinationPath): string + { + return "scp {$this->getExtraScpOptions()} $sourcePath {$this->getTargetForScp()}:$destinationPath"; + } + + public function upload(string $sourcePath, string $destinationPath): Process + { + $uploadCommand = $this->getUploadCommand($sourcePath, $destinationPath); + + return $this->run($uploadCommand); + } + + protected function getExtraScpOptions(): string + { + $extraOptions = $this->extraOptions; + + if (isset($extraOptions['port'])) { + $extraOptions['port'] = str_replace('-p', '-P', $extraOptions['port']); + } + + $extraOptions[] = '-r'; + + return implode(' ', array_values($extraOptions)); + } + + private function getExtraOptions(): array + { + return array_values($this->extraOptions); + } + + protected function wrapArray($arrayOrString): array + { + return (array)$arrayOrString; + } + + protected function run(string $command, string $method = 'run'): Process + { + $process = Process::fromShellCommandline($command); + + $process->setTimeout(0); + + ($this->processConfigurationClosure)($process); + + $process->{$method}($this->onOutput); + + return $process; + } + + protected function getTargetForScp(): string + { + $host = filter_var($this->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? '[' . $this->host . ']' : $this->host; + + return "{$this->user}@{$host}"; + } + + protected function getTargetForSsh(): string + { + return "{$this->user}@{$this->host}"; + } +} diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php new file mode 100644 index 000000000..0d48f5401 --- /dev/null +++ b/bootstrap/helpers.php @@ -0,0 +1,24 @@ + $destination, + 'command' => $command, + ]); + + $activityLog = $process(); + + return $activityLog; + } +} diff --git a/composer.json b/composer.json index 4958668f0..db88251ca 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,10 @@ "guzzlehttp/guzzle": "^7.2", "laravel/framework": "^10.0", "laravel/sanctum": "^3.2", - "laravel/tinker": "^2.8" + "laravel/tinker": "^2.8", + "livewire/livewire": "^2.12", + "spatie/laravel-activitylog": "^4.7", + "spatie/laravel-ray": "^1.32" }, "require-dev": { "fakerphp/faker": "^1.9.1", @@ -21,6 +24,9 @@ "spatie/laravel-ignition": "^2.0" }, "autoload": { + "files": [ + "bootstrap/helpers.php" + ], "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", diff --git a/composer.lock b/composer.lock index 9976cf5ae..ca08edfc6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "121ea3a2fffe49b3ef9aa4d064b28c19", + "content-hash": "262dce663830cec0e39428d0d3d76c7e", "packages": [ { "name": "brick/math", @@ -1709,6 +1709,79 @@ ], "time": "2022-04-17T13:12:02+00:00" }, + { + "name": "livewire/livewire", + "version": "v2.12.3", + "source": { + "type": "git", + "url": "https://github.com/livewire/livewire.git", + "reference": "019b1e69d8cd8c7e749eba7a38e4fa69ecbc8f74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/livewire/livewire/zipball/019b1e69d8cd8c7e749eba7a38e4fa69ecbc8f74", + "reference": "019b1e69d8cd8c7e749eba7a38e4fa69ecbc8f74", + "shasum": "" + }, + "require": { + "illuminate/database": "^7.0|^8.0|^9.0|^10.0", + "illuminate/support": "^7.0|^8.0|^9.0|^10.0", + "illuminate/validation": "^7.0|^8.0|^9.0|^10.0", + "league/mime-type-detection": "^1.9", + "php": "^7.2.5|^8.0", + "symfony/http-kernel": "^5.0|^6.0" + }, + "require-dev": { + "calebporzio/sushi": "^2.1", + "laravel/framework": "^7.0|^8.0|^9.0|^10.0", + "mockery/mockery": "^1.3.1", + "orchestra/testbench": "^5.0|^6.0|^7.0|^8.0", + "orchestra/testbench-dusk": "^5.2|^6.0|^7.0|^8.0", + "phpunit/phpunit": "^8.4|^9.0", + "psy/psysh": "@stable" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Livewire\\LivewireServiceProvider" + ], + "aliases": { + "Livewire": "Livewire\\Livewire" + } + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Livewire\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Caleb Porzio", + "email": "calebporzio@gmail.com" + } + ], + "description": "A front-end framework for Laravel.", + "support": { + "issues": "https://github.com/livewire/livewire/issues", + "source": "https://github.com/livewire/livewire/tree/v2.12.3" + }, + "funding": [ + { + "url": "https://github.com/livewire", + "type": "github" + } + ], + "time": "2023-03-03T20:12:38+00:00" + }, { "name": "monolog/monolog", "version": "3.3.1", @@ -2278,6 +2351,59 @@ ], "time": "2023-02-25T19:38:58+00:00" }, + { + "name": "pimple/pimple", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a94b3a4db7fb774b3d78dad2315ddc07629e1bed", + "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1 || ^2.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.4@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "https://pimple.symfony.com", + "keywords": [ + "container", + "dependency injection" + ], + "support": { + "source": "https://github.com/silexphp/Pimple/tree/v3.5.0" + }, + "time": "2021-10-28T11:13:42+00:00" + }, { "name": "psr/container", "version": "2.0.2", @@ -2943,6 +3069,430 @@ ], "time": "2023-01-12T18:13:24+00:00" }, + { + "name": "spatie/backtrace", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/backtrace.git", + "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/ec4dd16476b802dbdc6b4467f84032837e316b8c", + "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "ext-json": "*", + "phpunit/phpunit": "^9.3", + "spatie/phpunit-snapshot-assertions": "^4.2", + "symfony/var-dumper": "^5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Backtrace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van de Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A better backtrace", + "homepage": "https://github.com/spatie/backtrace", + "keywords": [ + "Backtrace", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/backtrace/tree/1.4.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2023-03-04T08:57:24+00:00" + }, + { + "name": "spatie/laravel-activitylog", + "version": "4.7.3", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-activitylog.git", + "reference": "ec65a478a909b8df1b4f0c3c45de2592ca7639e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-activitylog/zipball/ec65a478a909b8df1b4f0c3c45de2592ca7639e5", + "reference": "ec65a478a909b8df1b4f0c3c45de2592ca7639e5", + "shasum": "" + }, + "require": { + "illuminate/config": "^8.0 || ^9.0 || ^10.0", + "illuminate/database": "^8.69 || ^9.27 || ^10.0", + "illuminate/support": "^8.0 || ^9.0 || ^10.0", + "php": "^8.0", + "spatie/laravel-package-tools": "^1.6.3" + }, + "require-dev": { + "ext-json": "*", + "orchestra/testbench": "^6.23 || ^7.0 || ^8.0", + "pestphp/pest": "^1.20" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\Activitylog\\ActivitylogServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Activitylog\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + }, + { + "name": "Sebastian De Deyne", + "email": "sebastian@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + }, + { + "name": "Tom Witkowski", + "email": "dev.gummibeer@gmail.com", + "homepage": "https://gummibeer.de", + "role": "Developer" + } + ], + "description": "A very simple activity logger to monitor the users of your website or application", + "homepage": "https://github.com/spatie/activitylog", + "keywords": [ + "activity", + "laravel", + "log", + "spatie", + "user" + ], + "support": { + "issues": "https://github.com/spatie/laravel-activitylog/issues", + "source": "https://github.com/spatie/laravel-activitylog/tree/4.7.3" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-01-25T17:04:51+00:00" + }, + { + "name": "spatie/laravel-package-tools", + "version": "1.14.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "bab62023a4745a61170ad5424184533685e73c2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/bab62023a4745a61170ad5424184533685e73c2d", + "reference": "bab62023a4745a61170ad5424184533685e73c2d", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.28|^10.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^7.7|^8.0", + "pestphp/pest": "^1.22", + "phpunit/phpunit": "^9.5.24", + "spatie/pest-plugin-test-time": "^1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.14.2" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-03-14T16:41:21+00:00" + }, + { + "name": "spatie/laravel-ray", + "version": "1.32.3", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-ray.git", + "reference": "8c7ea86c8092bcfe7a046f640b6ac9e5d7ec98cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/8c7ea86c8092bcfe7a046f640b6ac9e5d7ec98cd", + "reference": "8c7ea86c8092bcfe7a046f640b6ac9e5d7ec98cd", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/contracts": "^7.20|^8.19|^9.0|^10.0", + "illuminate/database": "^7.20|^8.19|^9.0|^10.0", + "illuminate/queue": "^7.20|^8.19|^9.0|^10.0", + "illuminate/support": "^7.20|^8.19|^9.0|^10.0", + "php": "^7.4|^8.0", + "spatie/backtrace": "^1.0", + "spatie/ray": "^1.37", + "symfony/stopwatch": "4.2|^5.1|^6.0", + "zbateson/mail-mime-parser": "^1.3.1|^2.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.3", + "laravel/framework": "^7.20|^8.19|^9.0|^10.0", + "orchestra/testbench-core": "^5.0|^6.0|^7.0|^8.0", + "pestphp/pest": "^1.22", + "phpstan/phpstan": "^0.12.93", + "phpunit/phpunit": "^9.3", + "spatie/pest-plugin-snapshots": "^1.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.29.x-dev" + }, + "laravel": { + "providers": [ + "Spatie\\LaravelRay\\RayServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\LaravelRay\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily debug Laravel apps", + "homepage": "https://github.com/spatie/laravel-ray", + "keywords": [ + "laravel-ray", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-ray/issues", + "source": "https://github.com/spatie/laravel-ray/tree/1.32.3" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2023-03-03T13:37:21+00:00" + }, + { + "name": "spatie/macroable", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/macroable.git", + "reference": "ec2c320f932e730607aff8052c44183cf3ecb072" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/macroable/zipball/ec2c320f932e730607aff8052c44183cf3ecb072", + "reference": "ec2c320f932e730607aff8052c44183cf3ecb072", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.0|^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Macroable\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A trait to dynamically add methods to a class", + "homepage": "https://github.com/spatie/macroable", + "keywords": [ + "macroable", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/macroable/issues", + "source": "https://github.com/spatie/macroable/tree/2.0.0" + }, + "time": "2021-03-26T22:39:02+00:00" + }, + { + "name": "spatie/ray", + "version": "1.37.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/ray.git", + "reference": "a915e327f04c0fbed3bdd26e076e39feea091062" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/ray/zipball/a915e327f04c0fbed3bdd26e076e39feea091062", + "reference": "a915e327f04c0fbed3bdd26e076e39feea091062", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "php": "^7.3|^8.0", + "ramsey/uuid": "^3.0|^4.1", + "spatie/backtrace": "^1.1", + "spatie/macroable": "^1.0|^2.0", + "symfony/stopwatch": "^4.0|^5.1|^6.0", + "symfony/var-dumper": "^4.2|^5.1|^6.0" + }, + "require-dev": { + "illuminate/support": "6.x|^8.18|^9.0", + "nesbot/carbon": "^2.63", + "pestphp/pest": "^1.22", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2" + }, + "type": "library", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Ray\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Debug with Ray to fix problems faster", + "homepage": "https://github.com/spatie/ray", + "keywords": [ + "ray", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/ray/issues", + "source": "https://github.com/spatie/ray/tree/1.37.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2023-03-06T07:22:28+00:00" + }, { "name": "symfony/console", "version": "v6.2.7", @@ -3901,6 +4451,89 @@ ], "time": "2022-11-03T14:55:06+00:00" }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "927013f3aac555983a5059aada98e1907d842695" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/927013f3aac555983a5059aada98e1907d842695", + "reference": "927013f3aac555983a5059aada98e1907d842695", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-iconv": "*" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.27.0", @@ -4711,6 +5344,68 @@ ], "time": "2023-03-01T10:32:47+00:00" }, + { + "name": "symfony/stopwatch", + "version": "v6.2.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "f3adc98c1061875dd2edcd45e5b04e63d0e29f8f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f3adc98c1061875dd2edcd45e5b04e63d0e29f8f", + "reference": "f3adc98c1061875dd2edcd45e5b04e63d0e29f8f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/service-contracts": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v6.2.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:44:56+00:00" + }, { "name": "symfony/string", "version": "v6.2.7", @@ -5406,6 +6101,213 @@ "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, "time": "2022-06-03T18:03:27+00:00" + }, + { + "name": "zbateson/mail-mime-parser", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/zbateson/mail-mime-parser.git", + "reference": "20b3e48eb799537683780bc8782fbbe9bc25934a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/20b3e48eb799537683780bc8782fbbe9bc25934a", + "reference": "20b3e48eb799537683780bc8782fbbe9bc25934a", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^1.7.0|^2.0", + "php": ">=7.1", + "pimple/pimple": "^3.0", + "zbateson/mb-wrapper": "^1.0.1", + "zbateson/stream-decorators": "^1.0.6" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "mikey179/vfsstream": "^1.6.0", + "phpstan/phpstan": "*", + "phpunit/phpunit": "<10" + }, + "suggest": { + "ext-iconv": "For best support/performance", + "ext-mbstring": "For best support/performance" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\MailMimeParser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + }, + { + "name": "Contributors", + "homepage": "https://github.com/zbateson/mail-mime-parser/graphs/contributors" + } + ], + "description": "MIME email message parser", + "homepage": "https://mail-mime-parser.org", + "keywords": [ + "MimeMailParser", + "email", + "mail", + "mailparse", + "mime", + "mimeparse", + "parser", + "php-imap" + ], + "support": { + "docs": "https://mail-mime-parser.org/#usage-guide", + "issues": "https://github.com/zbateson/mail-mime-parser/issues", + "source": "https://github.com/zbateson/mail-mime-parser" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2023-02-14T22:58:03+00:00" + }, + { + "name": "zbateson/mb-wrapper", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/zbateson/mb-wrapper.git", + "reference": "faf35dddfacfc5d4d5f9210143eafd7a7fe74334" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/faf35dddfacfc5d4d5f9210143eafd7a7fe74334", + "reference": "faf35dddfacfc5d4d5f9210143eafd7a7fe74334", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-iconv": "^1.9", + "symfony/polyfill-mbstring": "^1.9" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "<=9.0" + }, + "suggest": { + "ext-iconv": "For best support/performance", + "ext-mbstring": "For best support/performance" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\MbWrapper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + } + ], + "description": "Wrapper for mbstring with fallback to iconv for encoding conversion and string manipulation", + "keywords": [ + "charset", + "encoding", + "http", + "iconv", + "mail", + "mb", + "mb_convert_encoding", + "mbstring", + "mime", + "multibyte", + "string" + ], + "support": { + "issues": "https://github.com/zbateson/mb-wrapper/issues", + "source": "https://github.com/zbateson/mb-wrapper/tree/1.2.0" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2023-01-11T23:05:44+00:00" + }, + { + "name": "zbateson/stream-decorators", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/zbateson/stream-decorators.git", + "reference": "7466ff45d249c86b96267a83cdae68365ae1787e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/7466ff45d249c86b96267a83cdae68365ae1787e", + "reference": "7466ff45d249c86b96267a83cdae68365ae1787e", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^1.9 | ^2.0", + "php": ">=7.1", + "zbateson/mb-wrapper": "^1.0.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "<=9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\StreamDecorators\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + } + ], + "description": "PHP psr7 stream decorators for mime message part streams", + "keywords": [ + "base64", + "charset", + "decorators", + "mail", + "mime", + "psr7", + "quoted-printable", + "stream", + "uuencode" + ], + "support": { + "issues": "https://github.com/zbateson/stream-decorators/issues", + "source": "https://github.com/zbateson/stream-decorators/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2023-01-11T23:22:44+00:00" } ], "packages-dev": [ @@ -7394,68 +8296,6 @@ ], "time": "2023-02-07T11:34:05+00:00" }, - { - "name": "spatie/backtrace", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/spatie/backtrace.git", - "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/ec4dd16476b802dbdc6b4467f84032837e316b8c", - "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "ext-json": "*", - "phpunit/phpunit": "^9.3", - "spatie/phpunit-snapshot-assertions": "^4.2", - "symfony/var-dumper": "^5.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Backtrace\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van de Herten", - "email": "freek@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "A better backtrace", - "homepage": "https://github.com/spatie/backtrace", - "keywords": [ - "Backtrace", - "spatie" - ], - "support": { - "source": "https://github.com/spatie/backtrace/tree/1.4.0" - }, - "funding": [ - { - "url": "https://github.com/sponsors/spatie", - "type": "github" - }, - { - "url": "https://spatie.be/open-source/support-us", - "type": "other" - } - ], - "time": "2023-03-04T08:57:24+00:00" - }, { "name": "spatie/flare-client-php", "version": "1.3.5", diff --git a/config/ray.php b/config/ray.php new file mode 100644 index 000000000..08598c4e8 --- /dev/null +++ b/config/ray.php @@ -0,0 +1,108 @@ + env('RAY_ENABLED', true), + + /* + * When enabled, all cache events will automatically be sent to Ray. + */ + 'send_cache_to_ray' => env('SEND_CACHE_TO_RAY', false), + + /* + * When enabled, all things passed to `dump` or `dd` + * will be sent to Ray as well. + */ + 'send_dumps_to_ray' => env('SEND_DUMPS_TO_RAY', true), + + /* + * When enabled all job events will automatically be sent to Ray. + */ + 'send_jobs_to_ray' => env('SEND_JOBS_TO_RAY', false), + + /* + * When enabled, all things logged to the application log + * will be sent to Ray as well. + */ + 'send_log_calls_to_ray' => env('SEND_LOG_CALLS_TO_RAY', true), + + /* + * When enabled, all queries will automatically be sent to Ray. + */ + 'send_queries_to_ray' => env('SEND_QUERIES_TO_RAY', false), + + /** + * When enabled, all duplicate queries will automatically be sent to Ray. + */ + 'send_duplicate_queries_to_ray' => env('SEND_DUPLICATE_QUERIES_TO_RAY', false), + + /* + * When enabled, slow queries will automatically be sent to Ray. + */ + 'send_slow_queries_to_ray' => env('SEND_SLOW_QUERIES_TO_RAY', false), + + /** + * Queries that are longer than this number of milliseconds will be regarded as slow. + */ + 'slow_query_threshold_in_ms' => env('RAY_SLOW_QUERY_THRESHOLD_IN_MS', 500), + + /* + * When enabled, all requests made to this app will automatically be sent to Ray. + */ + 'send_requests_to_ray' => env('SEND_REQUESTS_TO_RAY', false), + + /** + * When enabled, all Http Client requests made by this app will be automatically sent to Ray. + */ + 'send_http_client_requests_to_ray' => env('SEND_HTTP_CLIENT_REQUESTS_TO_RAY', false), + + /* + * When enabled, all views that are rendered automatically be sent to Ray. + */ + 'send_views_to_ray' => env('SEND_VIEWS_TO_RAY', false), + + /* + * When enabled, all exceptions will be automatically sent to Ray. + */ + 'send_exceptions_to_ray' => env('SEND_EXCEPTIONS_TO_RAY', true), + + /* + * When enabled, all deprecation notices will be automatically sent to Ray. + */ + 'send_deprecated_notices_to_ray' => env('SEND_DEPRECATED_NOTICES_TO_RAY', false), + + /* + * The host used to communicate with the Ray app. + * When using Docker on Mac or Windows, you can replace localhost with 'host.docker.internal' + * When using Docker on Linux, you can replace localhost with '172.17.0.1' + * When using Homestead with the VirtualBox provider, you can replace localhost with '10.0.2.2' + * When using Homestead with the Parallels provider, you can replace localhost with '10.211.55.2' + */ + 'host' => env('RAY_HOST', 'host.docker.internal'), + + /* + * The port number used to communicate with the Ray app. + */ + 'port' => env('RAY_PORT', 23517), + + /* + * Absolute base path for your sites or projects in Homestead, + * Vagrant, Docker, or another remote development server. + */ + 'remote_path' => env('RAY_REMOTE_PATH', null), + + /* + * Absolute base path for your sites or projects on your local + * computer where your IDE or code editor is running on. + */ + 'local_path' => env('RAY_LOCAL_PATH', null), + + /* + * When this setting is enabled, the package will not try to format values sent to Ray. + */ + 'always_send_raw_values' => false, +]; diff --git a/coolify_id25519 b/coolify_id25519 new file mode 100644 index 000000000..c67d90a64 --- /dev/null +++ b/coolify_id25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk +hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA +AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV +uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== +-----END OPENSSH PRIVATE KEY----- diff --git a/database/migrations/2023_03_20_112410_create_activity_log_table.php b/database/migrations/2023_03_20_112410_create_activity_log_table.php new file mode 100755 index 000000000..7c05bc892 --- /dev/null +++ b/database/migrations/2023_03_20_112410_create_activity_log_table.php @@ -0,0 +1,27 @@ +create(config('activitylog.table_name'), function (Blueprint $table) { + $table->bigIncrements('id'); + $table->string('log_name')->nullable(); + $table->text('description'); + $table->nullableMorphs('subject', 'subject'); + $table->nullableMorphs('causer', 'causer'); + $table->json('properties')->nullable(); + $table->timestamps(); + $table->index('log_name'); + }); + } + + public function down() + { + Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name')); + } +} diff --git a/database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php b/database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php new file mode 100755 index 000000000..7b797fd5e --- /dev/null +++ b/database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php @@ -0,0 +1,22 @@ +table(config('activitylog.table_name'), function (Blueprint $table) { + $table->string('event')->nullable()->after('subject_type'); + }); + } + + public function down() + { + Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) { + $table->dropColumn('event'); + }); + } +} diff --git a/database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php b/database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php new file mode 100755 index 000000000..8f7db6654 --- /dev/null +++ b/database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php @@ -0,0 +1,22 @@ +table(config('activitylog.table_name'), function (Blueprint $table) { + $table->uuid('batch_uuid')->nullable()->after('properties'); + }); + } + + public function down() + { + Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) { + $table->dropColumn('batch_uuid'); + }); + } +} diff --git a/database/migrations/2023_03_20_112810_create_jobs_table.php b/database/migrations/2023_03_20_112810_create_jobs_table.php new file mode 100755 index 000000000..6098d9b12 --- /dev/null +++ b/database/migrations/2023_03_20_112810_create_jobs_table.php @@ -0,0 +1,32 @@ +bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + } +}; diff --git a/docker-compose.yaml b/docker-compose.yaml index ae1dc82f8..9fe23b25f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,8 +3,8 @@ services: php: image: coolify:4 build: - context: . dockerfile: Dockerfile + context: ./docker/dev ports: - "${APP_PORT:-8000}:80" - "${VITE_PORT:-5173}:${VITE_PORT:-5173}" diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile new file mode 100644 index 000000000..ccfda8f89 --- /dev/null +++ b/docker/dev/Dockerfile @@ -0,0 +1,20 @@ +FROM serversideup/php:8.2-fpm-nginx + +ARG NODE_VERSION=18 +ARG POSTGRES_VERSION=15 + +RUN apt-get update \ + && curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \ + && apt-get install -y nodejs \ + && npm install -g npm + +RUN apt-get install -y php-pgsql openssh-client + +RUN apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* + +USER root + +# S6 Overlay config +COPY --chmod=755 etc/s6-overlay/ /etc/s6-overlay/ diff --git a/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/run b/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/run new file mode 100644 index 000000000..23dddd030 --- /dev/null +++ b/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/run @@ -0,0 +1,2 @@ +#!/command/execlineb -P +su webuser -c "php /var/www/html/artisan queue:listen --tries=3" diff --git a/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/type b/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/type new file mode 100644 index 000000000..5883cff0c --- /dev/null +++ b/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/type @@ -0,0 +1 @@ +longrun diff --git a/docker/dev/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker b/docker/dev/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker new file mode 100644 index 000000000..e69de29bb diff --git a/resources/views/components/button.blade.php b/resources/views/components/button.blade.php new file mode 100644 index 000000000..f59d45973 --- /dev/null +++ b/resources/views/components/button.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/resources/views/components/layout.blade.php b/resources/views/components/layout.blade.php new file mode 100644 index 000000000..f69d56d92 --- /dev/null +++ b/resources/views/components/layout.blade.php @@ -0,0 +1,24 @@ + + + + + + + {{ $title ?? 'Coolify' }} + + @vite(['resources/js/app.js', 'resources/css/app.css']) + @livewireStyles + + + + @auth + + @endauth +
+ {{ $slot }} +
+ + @livewireScripts + + + diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php new file mode 100644 index 000000000..8635e6cfc --- /dev/null +++ b/resources/views/components/navbar.blade.php @@ -0,0 +1,15 @@ + diff --git a/resources/views/demo.blade.php b/resources/views/demo.blade.php new file mode 100644 index 000000000..3247b6d59 --- /dev/null +++ b/resources/views/demo.blade.php @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/views/livewire/run-command.blade.php b/resources/views/livewire/run-command.blade.php new file mode 100755 index 000000000..fe24caab3 --- /dev/null +++ b/resources/views/livewire/run-command.blade.php @@ -0,0 +1,44 @@ +
+
+
+ +
+ + @isset($activity?->id) +
+ Activity: {{ $activity?->id ?? 'waiting' }} +
+ @endisset +
+ +
+ +
+        {{ data_get($activity, 'description') }}
+    
+ +
+ + +
+ + @if($isKeepAliveOn || $manualKeepAlive) + Polling... + @endif +
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index da211600d..443ef8bae 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -13,6 +13,10 @@

Hello from Coolify!

+ +

+ See demo +

diff --git a/routes/web.php b/routes/web.php index d259f33ea..cb09e09d9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -16,3 +16,5 @@ use Illuminate\Support\Facades\Route; Route::get('/', function () { return view('welcome'); }); + +Route::view('/demo', 'demo'); From a613e9f113d5cce04e334ae4695aa5915803dff6 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 20 Mar 2023 13:26:54 +0100 Subject: [PATCH 05/14] fix: ssh --- app/Jobs/ExecuteCoolifyProcess.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Jobs/ExecuteCoolifyProcess.php b/app/Jobs/ExecuteCoolifyProcess.php index d1ba2c478..9c9a10771 100755 --- a/app/Jobs/ExecuteCoolifyProcess.php +++ b/app/Jobs/ExecuteCoolifyProcess.php @@ -53,10 +53,10 @@ class ExecuteCoolifyProcess implements ShouldQueue $delimiter = 'EOF-COOLIFY-SSH'; - File::chmod(base_path('coolify_id25519'), '0600'); + File::chmod(base_path('coolify_id25519'), 0600); $sshCommand = 'ssh ' - . '-i ./coolify_id25519' + . '-i ./coolify_id25519 ' . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' . '-o PasswordAuthentication=no ' . "{$user}@{$destination} " @@ -78,12 +78,14 @@ class ExecuteCoolifyProcess implements ShouldQueue return $res; } + // TODO Why is this not persisting?? Immutable property?? $this->activity->properties->put('pid', $process->id()); $this->activity->properties->put('exitCode', $res->exitCode()); $this->activity->properties->put('stdout', $res->output()); $this->activity->properties->put('stderr', $res->errorOutput()); $this->activity->save(); + return $res; } protected function handleOutput(string $type, string $output) From bfdae4339c6493df933f55285c4946dd0315574f Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Mon, 20 Mar 2023 14:04:35 +0000 Subject: [PATCH 06/14] Have Sail and SSU. Runs a command on a remote host. --- .env.example | 5 +- app/Http/Livewire/RunCommand.php | 32 ++++--- app/Jobs/ExecuteCoolifyProcess.php | 36 ++++--- app/Services/CoolifyProcess.php | 14 +-- coolify_id25519 | 7 -- docker-compose.yaml | 11 ++- docker/dev/Dockerfile | 93 +++++++++++++++++-- docker/dev/php.ini | 4 + docker/dev/start-container | 17 ++++ docker/dev/supervisord.conf | 27 ++++++ docker/staging/Dockerfile | 20 ++++ .../etc/s6-overlay/s6-rc.d/queue-worker/run | 0 .../etc/s6-overlay/s6-rc.d/queue-worker/type | 0 .../s6-rc.d/user/contents.d/queue-worker | 0 .../views/livewire/run-command.blade.php | 45 ++++++--- 15 files changed, 234 insertions(+), 77 deletions(-) delete mode 100644 coolify_id25519 create mode 100644 docker/dev/php.ini create mode 100644 docker/dev/start-container create mode 100644 docker/dev/supervisord.conf create mode 100644 docker/staging/Dockerfile rename docker/{dev => staging}/etc/s6-overlay/s6-rc.d/queue-worker/run (100%) rename docker/{dev => staging}/etc/s6-overlay/s6-rc.d/queue-worker/type (100%) rename docker/{dev => staging}/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker (100%) diff --git a/.env.example b/.env.example index f6b965c91..952d224e9 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,7 @@ GROUPID= ############################################################################################################ APP_NAME=Laravel +APP_SERVICE=php APP_ENV=local APP_KEY= APP_DEBUG=true @@ -17,7 +18,7 @@ DB_CONNECTION=pgsql DB_HOST=postgres DB_PORT=5432 DB_DATABASE=coolify -DB_USERNAME=sail +DB_USERNAME=coolify DB_PASSWORD=password -QUEUE_CONNECTION=redis +QUEUE_CONNECTION=database diff --git a/app/Http/Livewire/RunCommand.php b/app/Http/Livewire/RunCommand.php index e99ca0da1..11dad0893 100755 --- a/app/Http/Livewire/RunCommand.php +++ b/app/Http/Livewire/RunCommand.php @@ -12,7 +12,7 @@ class RunCommand extends Component public $manualKeepAlive = false; - public $command = ''; + public $command = 'ls'; public function render() { @@ -21,30 +21,32 @@ class RunCommand extends Component public function runCommand() { - // TODO Execute with Livewire Normally - $this->activity = coolifyProcess($this->command, 'testing-host'); - + $this->isKeepAliveOn = true; // Override manual to experiment -// $sleepingBeauty = 'x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done'; -// -// $commandString = <<activity = coolifyProcess($commandString, 'testing-host'); + $override = 0; + if($override) { + // Good to play with the throttle feature + $sleepingBeauty = 'x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done'; - $this->isKeepAliveOn = true; + $this->activity = coolifyProcess(<<activity = coolifyProcess($this->command, 'testing-host'); } public function polling() { $this->activity?->refresh(); - if ($this->activity?->properties['status'] === 'finished') { + if (data_get($this->activity, 'properties.exitCode') !== null) { $this->isKeepAliveOn = false; } } diff --git a/app/Jobs/ExecuteCoolifyProcess.php b/app/Jobs/ExecuteCoolifyProcess.php index 9c9a10771..18e1715b9 100755 --- a/app/Jobs/ExecuteCoolifyProcess.php +++ b/app/Jobs/ExecuteCoolifyProcess.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use App\Services\ProcessStatus; use Illuminate\Support\Facades\DB; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeUnique; @@ -11,7 +12,6 @@ use Illuminate\Process\InvokedProcess; use Illuminate\Process\ProcessResult; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Process; use Spatie\Activitylog\Contracts\Activity; @@ -43,8 +43,7 @@ class ExecuteCoolifyProcess implements ShouldQueue */ public function handle(): ?ProcessResult { - ray()->clearAll(); - $this->timeStart = $start = hrtime(true); + $this->timeStart = hrtime(true); $user = $this->activity->getExtraProperty('user'); $destination = $this->activity->getExtraProperty('destination'); @@ -53,24 +52,16 @@ class ExecuteCoolifyProcess implements ShouldQueue $delimiter = 'EOF-COOLIFY-SSH'; - File::chmod(base_path('coolify_id25519'), 0600); - $sshCommand = 'ssh ' - . '-i ./coolify_id25519 ' . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' . '-o PasswordAuthentication=no ' + . "-p {$port} " . "{$user}@{$destination} " . " 'bash -se' << \\$delimiter" . PHP_EOL . $command . PHP_EOL . $delimiter; -// $sshCommand = "whoami ; pwd ; ls "; - - $process = Process::start( - $sshCommand, - $this->handleOutput(...), - ); - + $process = Process::start($sshCommand, $this->handleOutput(...)); $res = $process->wait(); @@ -78,13 +69,20 @@ class ExecuteCoolifyProcess implements ShouldQueue return $res; } - - // TODO Why is this not persisting?? Immutable property?? - $this->activity->properties->put('pid', $process->id()); - $this->activity->properties->put('exitCode', $res->exitCode()); - $this->activity->properties->put('stdout', $res->output()); - $this->activity->properties->put('stderr', $res->errorOutput()); + $status = match ($res->exitCode()) { + 0 => ProcessStatus::FINISHED, + default => ProcessStatus::ERROR, + }; + + $this->activity->properties = $this->activity->properties->merge([ + 'exitCode' => $res->exitCode(), + 'stdout' => $res->output(), + 'stderr' => $res->errorOutput(), + 'status' => $status, + ]); + $this->activity->save(); + return $res; } diff --git a/app/Services/CoolifyProcess.php b/app/Services/CoolifyProcess.php index bc21bda98..16071ebd7 100644 --- a/app/Services/CoolifyProcess.php +++ b/app/Services/CoolifyProcess.php @@ -19,12 +19,14 @@ class CoolifyProcess protected ?string $user = 'root', ){ $this->activity = activity() - ->withProperty('type', 'COOLIFY_PROCESS') - ->withProperty('user', $this->user) - ->withProperty('destination', $this->destination) - ->withProperty('port', $this->port) - ->withProperty('command', $this->command) - ->withProperty('status', ProcessStatus::HOLDING) + ->withProperties([ + 'type' => 'COOLIFY_PROCESS', + 'user' => $this->user, + 'destination' => $this->destination, + 'port' => $this->port, + 'command' => $this->command, + 'status' => ProcessStatus::HOLDING, + ]) ->log("Awaiting to start command...\n\n"); } diff --git a/coolify_id25519 b/coolify_id25519 deleted file mode 100644 index c67d90a64..000000000 --- a/coolify_id25519 +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk -hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA -AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV -uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== ------END OPENSSH PRIVATE KEY----- diff --git a/docker-compose.yaml b/docker-compose.yaml index 9fe23b25f..39a1537e3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,15 +3,18 @@ services: php: image: coolify:4 build: - dockerfile: Dockerfile context: ./docker/dev + dockerfile: Dockerfile + args: + WWWGROUP: '${WWWGROUP}' ports: - "${APP_PORT:-8000}:80" - "${VITE_PORT:-5173}:${VITE_PORT:-5173}" environment: - PUID: "${USERID:-9999}" - PGID: "${GROUPID:-9999}" - SSL_MODE: 'off' + WWWUSER: "${WWWUSER}" + LARAVEL_SAIL: 1 + XDEBUG_MODE: "${SAIL_XDEBUG_MODE:-off}" + XDEBUG_CONFIG: "${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}" volumes: - .:/var/www/html networks: diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index ccfda8f89..239bf9fa8 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -1,20 +1,93 @@ -FROM serversideup/php:8.2-fpm-nginx +FROM ubuntu:22.04 + +ARG WWWGROUP +ARG TARGETPLATFORM ARG NODE_VERSION=18 -ARG POSTGRES_VERSION=15 +ARG POSTGRES_VERSION=14 + +# https://download.docker.com/linux/static/stable/ +ARG DOCKER_VERSION=20.10.18 +# https://github.com/docker/compose/releases +# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug. +ARG DOCKER_COMPOSE_VERSION=2.6.1 +# https://github.com/buildpacks/pack/releases +ARG PACK_VERSION=v0.27.0 + +WORKDIR /var/www/html + +ENV DEBIAN_FRONTEND noninteractive +ENV TZ=UTC + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN apt-get update \ + && apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \ + && curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \ + && echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \ + && apt-get update \ + && apt-get install -y php8.2-cli php8.2-dev \ + php8.2-pgsql php8.2-sqlite3 php8.2-gd \ + php8.2-curl \ + php8.2-imap php8.2-mysql php8.2-mbstring \ + php8.2-xml php8.2-zip php8.2-bcmath php8.2-soap \ + php8.2-intl php8.2-readline \ + php8.2-ldap \ + php8.2-msgpack php8.2-igbinary php8.2-redis php8.2-swoole \ + php8.2-memcached php8.2-pcov php8.2-xdebug \ + && php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \ && curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \ && apt-get install -y nodejs \ - && npm install -g npm - -RUN apt-get install -y php-pgsql openssh-client - -RUN apt-get -y autoremove \ + && npm install -g npm \ + && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarn.gpg >/dev/null \ + && echo "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \ + && curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \ + && echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \ + && apt-get update \ + && apt-get install -y yarn \ + && apt-get install -y mysql-client \ + && apt-get install -y postgresql-client-$POSTGRES_VERSION \ + && apt-get -y autoremove \ && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2 + +RUN groupadd --force -g $WWWGROUP sail +RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail + +USER sail +RUN mkdir -p ~/.ssh +RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\ +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\ +QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\ +hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\ +AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\ +uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\ +-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519 +RUN chmod 0600 ~/.ssh/id_ed25519 USER root -# S6 Overlay config -COPY --chmod=755 etc/s6-overlay/ /etc/s6-overlay/ +COPY start-container /usr/local/bin/start-container +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY php.ini /etc/php/8.2/cli/conf.d/99-sail.ini +RUN chmod +x /usr/local/bin/start-container + +# Install Docker CLI, Docker Compose, and Pack +RUN mkdir -p ~/.docker/cli-plugins +RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker +RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose -o /home/sail/.docker/cli-plugins/docker-compose +RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack +RUN curl -sSL https://nixpacks.com/install.sh | bash + +RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack +RUN chmod +x /usr/local/bin/pack + +RUN mkdir -p /home/sail/.docker/cli-plugins +RUN cp ~/.docker/cli-plugins/docker-compose /home/sail/.docker/cli-plugins/docker-compose +RUN chown -R sail:sail /home/sail + +EXPOSE 8000 + +ENTRYPOINT ["start-container"] diff --git a/docker/dev/php.ini b/docker/dev/php.ini new file mode 100644 index 000000000..66d04d5be --- /dev/null +++ b/docker/dev/php.ini @@ -0,0 +1,4 @@ +[PHP] +post_max_size = 100M +upload_max_filesize = 100M +variables_order = EGPCS diff --git a/docker/dev/start-container b/docker/dev/start-container new file mode 100644 index 000000000..b86439907 --- /dev/null +++ b/docker/dev/start-container @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +if [ ! -z "$WWWUSER" ]; then + usermod -u $WWWUSER sail +fi + +if [ ! -d /.composer ]; then + mkdir /.composer +fi + +chmod -R ugo+rw /.composer + +if [ $# -gt 0 ]; then + exec gosu $WWWUSER "$@" +else + exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf +fi diff --git a/docker/dev/supervisord.conf b/docker/dev/supervisord.conf new file mode 100644 index 000000000..a2ff48927 --- /dev/null +++ b/docker/dev/supervisord.conf @@ -0,0 +1,27 @@ +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:php] +command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80 +user=sail +environment=LARAVEL_SAIL="1" +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:laravel-worker] +process_name=%(program_name)s_%(process_num)02d +command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan queue:listen +user=sail +autostart=true +autorestart=true +stopasgroup=true +killasgroup=true +numprocs=8 +redirect_stderr=true +stdout_logfile=/var/www/html/storage/logs/worker.log +stopwaitsecs=3600 diff --git a/docker/staging/Dockerfile b/docker/staging/Dockerfile new file mode 100644 index 000000000..ccfda8f89 --- /dev/null +++ b/docker/staging/Dockerfile @@ -0,0 +1,20 @@ +FROM serversideup/php:8.2-fpm-nginx + +ARG NODE_VERSION=18 +ARG POSTGRES_VERSION=15 + +RUN apt-get update \ + && curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \ + && apt-get install -y nodejs \ + && npm install -g npm + +RUN apt-get install -y php-pgsql openssh-client + +RUN apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* + +USER root + +# S6 Overlay config +COPY --chmod=755 etc/s6-overlay/ /etc/s6-overlay/ diff --git a/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/run b/docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/run similarity index 100% rename from docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/run rename to docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/run diff --git a/docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/type b/docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/type similarity index 100% rename from docker/dev/etc/s6-overlay/s6-rc.d/queue-worker/type rename to docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/type diff --git a/docker/dev/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker b/docker/staging/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker similarity index 100% rename from docker/dev/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker rename to docker/staging/etc/s6-overlay/s6-rc.d/user/contents.d/queue-worker diff --git a/resources/views/livewire/run-command.blade.php b/resources/views/livewire/run-command.blade.php index fe24caab3..782b5c309 100755 --- a/resources/views/livewire/run-command.blade.php +++ b/resources/views/livewire/run-command.blade.php @@ -6,7 +6,7 @@ -
-
-
-
- - - @isset($activity?->id) -
- Activity: {{ $activity?->id ?? 'waiting' }} -
- @endisset + + - -
- - -
-
-        {{ data_get($activity, 'description') }}
-    
- -
- - -
- - @if($isKeepAliveOn || $manualKeepAlive) +
+ + + @if ($isKeepAliveOn || $manualKeepAlive) Polling... @endif -
- -
{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}
+ @isset($activity?->id) +
+ Activity: {{ $activity?->id ?? 'waiting' }} +
+
 {{ data_get($activity, 'description') }}
+
+
Details:
+
{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}
+
+ @endisset
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index 443ef8bae..2c34fca5d 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -11,7 +11,7 @@

- Hello from Coolify! + Coolify v4