diff --git a/plane/README.md b/plane/README.md new file mode 100644 index 0000000..f7db4a8 --- /dev/null +++ b/plane/README.md @@ -0,0 +1,4 @@ +# Supabase + +- copied from https://github.com/makeplane/plane +- removed `ports` diff --git a/plane/code/.env.example b/plane/code/.env.example new file mode 100644 index 0000000..4120ee5 --- /dev/null +++ b/plane/code/.env.example @@ -0,0 +1,51 @@ +APP_DOMAIN=localhost +APP_RELEASE=stable + +WEB_REPLICAS=1 +SPACE_REPLICAS=1 +ADMIN_REPLICAS=1 +API_REPLICAS=1 + +NGINX_PORT=80 +WEB_URL=http://${APP_DOMAIN} +DEBUG=0 +SENTRY_DSN= +SENTRY_ENVIRONMENT=production +CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN} + +#DB SETTINGS +PGHOST=plane-db +PGDATABASE=plane +POSTGRES_USER=plane +POSTGRES_PASSWORD=plane +POSTGRES_DB=plane +POSTGRES_PORT=5432 +PGDATA=/var/lib/postgresql/data +DATABASE_URL= + +# REDIS SETTINGS +REDIS_HOST=plane-redis +REDIS_PORT=6379 +REDIS_URL= + +# Secret Key +SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5 + +# DATA STORE SETTINGS +USE_MINIO=1 +AWS_REGION= +AWS_ACCESS_KEY_ID=access-key +AWS_SECRET_ACCESS_KEY=secret-key +AWS_S3_ENDPOINT_URL=http://plane-minio:9000 +AWS_S3_BUCKET_NAME=uploads +MINIO_ROOT_USER=access-key +MINIO_ROOT_PASSWORD=secret-key +BUCKET_NAME=uploads +FILE_SIZE_LIMIT=5242880 + +# Gunicorn Workers +GUNICORN_WORKERS=1 + +# UNCOMMENT `DOCKER_PLATFORM` IF YOU ARE ON `ARM64` AND DOCKER IMAGE IS NOT AVAILABLE FOR RESPECTIVE `APP_RELEASE` +# DOCKER_PLATFORM=linux/amd64 + diff --git a/plane/code/README.md b/plane/code/README.md new file mode 100644 index 0000000..d93d85c --- /dev/null +++ b/plane/code/README.md @@ -0,0 +1,483 @@ +# Self Hosting + +In this guide, we will walk you through the process of setting up a self-hosted environment. Self-hosting allows you to have full control over your applications and data. It's a great way to ensure privacy, control, and customization. + +We will cover two main options for setting up your self-hosted environment: using a cloud server or using your desktop. For the cloud server, we will use an AWS EC2 instance. For the desktop, we will use Docker to create a local environment. + +Let's get started! + +## Setting up Docker Environment + +
+ Option 1 - Using Cloud Server +

Best way to start is to create EC2 machine on AWS. It must have minimum of 2vCPU and 4GB RAM.

+

Run the below command to install docker engine.

+ +`curl -fsSL https://get.docker.com | sh -` + +
+ +--- + +
+ Option 2 - Using Desktop + +#### For Mac + +
    +
  1. Download Docker Desktop for Mac from the Docker Hub.
  2. +
  3. Double-click the downloaded `.dmg` file and drag the Docker app icon to the Applications folder.
  4. +
  5. Open Docker Desktop from the Applications folder. You might be asked to provide your system password to install additional software.
  6. +
+ +#### For Windows: + +
    +
  1. Download Docker Desktop for Windows from the Docker Hub.
  2. +
  3. Run the installer and follow the instructions. You might be asked to enable Hyper-V and "Containers" Windows features.
  4. +
  5. Open Docker Desktop. You might be asked to log out and log back in, or restart your machine, for changes to take effect.
  6. +
+ +After installation, you can verify the installation by opening a terminal (Command Prompt on Windows, Terminal app on Mac) and running the command `docker --version`. This should display the installed version of Docker. + +
+ +--- + +## Installing Plane + +Installing plane is a very easy and minimal step process. + +### Prerequisite + +- Docker installed and running +- OS with bash scripting enabled (Ubuntu, Linux AMI, macos). Windows systems need to have [gitbash](https://git-scm.com/download/win) +- User context used must have access to docker services. In most cases, use sudo su to switch as root user +- Use the terminal (or gitbash) window to run all the future steps + +### Downloading Latest Stable Release + +``` +mkdir plane-selfhost + +cd plane-selfhost + +curl -fsSL -o setup.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/install.sh + +chmod +x setup.sh +``` + +--- + +### Proceed with setup + +Above steps will set you ready to install and start plane services. + +Lets get started by running the `./setup.sh` command. + +This will prompt you with the below options. + +```bash +Select a Action you want to perform: + 1) Install (x86_64) + 2) Start + 3) Stop + 4) Restart + 5) Upgrade + 6) View Logs + 7) Backup Data + 8) Exit +Action [2]: 1 +``` + +For the 1st time setup, type "1" as action input. + +This will create a create a folder `plane-app` or `plane-app-preview` (in case of preview deployment) and will download 2 files inside that + +- `docker-compose.yaml` +- `plane.env` + +Again the `options [1-8]` will be popped up and this time hit `8` to exit. + +--- + +### Continue with setup - Environment Settings + +Before proceeding, we suggest used to review `.env` file and set the values. +Below are the most import keys you must refer to. _You can use any text editor to edit this file_. + +> `NGINX_PORT` - This is default set to `80`. Make sure the port you choose to use is not preoccupied. (e.g `NGINX_PORT=8080`) + +> `WEB_URL` - This is default set to `http://localhost`. Change this to the FQDN you plan to use along with NGINX_PORT (eg. `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`) + +> `CORS_ALLOWED_ORIGINS` - This is default set to `http://localhost`. Change this to the FQDN you plan to use along with NGINX_PORT (eg. `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`) + +There are many other settings you can play with, but we suggest you configure `EMAIL SETTINGS` as it will enable you to invite your teammates onto the platform. + +--- + +### Continue with setup - Start Server + +Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `2` to start the sevices + +```bash +Select a Action you want to perform: + 1) Install (x86_64) + 2) Start + 3) Stop + 4) Restart + 5) Upgrade + 6) View Logs + 7) Backup Data + 8) Exit + +Action [2]: 2 +``` + +Expect something like this. +![Downloading docker images](images/download.png) + +Be patient as it might take sometime based on download speed and system configuration. If all goes well, you must see something like this + +![Downloading completed](images/started.png) + +This is the confirmation that all images were downloaded and the services are up & running. + +You have successfully self hosted `Plane` instance. Access the application by going to IP or domain you have configured it (e.g `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`) + +--- + +### Stopping the Server + +In case you want to make changes to `.env` variables, we suggest you to stop the services before doing that. + +Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `3` to stop the sevices + +```bash +Select a Action you want to perform: + 1) Install (x86_64) + 2) Start + 3) Stop + 4) Restart + 5) Upgrade + 6) View Logs + 7) Backup Data + 8) Exit + +Action [2]: 3 +``` + +If all goes well, you must see something like this + +![Stop Services](images/stopped.png) + +--- + +### Restarting the Server + +In case you want to make changes to `.env` variables, without stopping the server or you noticed some abnormalies in services, you can restart the services with RESTART option. + +Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `4` to restart the sevices + +```bash +Select a Action you want to perform: + 1) Install (x86_64) + 2) Start + 3) Stop + 4) Restart + 5) Upgrade + 6) View Logs + 7) Backup Data + 8) Exit + +Action [2]: 4 +``` + +If all goes well, you must see something like this + +![Restart Services](images/restart.png) + +--- + +### Upgrading Plane Version + +It is always advised to keep Plane up to date with the latest release. + +Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release. + +```bash +Select a Action you want to perform: + 1) Install (x86_64) + 2) Start + 3) Stop + 4) Restart + 5) Upgrade + 6) View Logs + 7) Backup Data + 8) Exit + +Action [2]: 5 +``` + +By choosing this, it will stop the services and then will download the latest `docker-compose.yaml` and `plane.env`. + +You must expect the below message + +![Alt text](images/upgrade.png) + +Once done, choose `8` to exit from prompt. + +> It is very important for you to validate the `plane.env` for the new changes. + +Once done with making changes in `plane.env` file, jump on to `Start Server` + +--- + +### View Logs + +There would a time when you might want to check what is happening inside the API, Worker or any other container. + +Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `6` to view logs. + +```bash +Select a Action you want to perform: + 1) Install (x86_64) + 2) Start + 3) Stop + 4) Restart + 5) Upgrade + 6) View Logs + 7) Backup Data + 8) Exit + +Action [2]: 6 +``` + + +This will further open sub-menu with list of services +```bash +Select a Service you want to view the logs for: + 1) Web + 2) Space + 3) API + 4) Worker + 5) Beat-Worker + 6) Migrator + 7) Proxy + 8) Redis + 9) Postgres + 10) Minio + 0) Back to Main Menu + +Service: +``` + +Select any of the service to view the logs e.g. `3`. Expect something similar to this +```bash +api-1 | Waiting for database... +api-1 | Database available! +api-1 | Waiting for database migrations to complete... +api-1 | Waiting for database migrations to complete... +api-1 | Waiting for database migrations to complete... +api-1 | Waiting for database migrations to complete... +api-1 | Waiting for database migrations to complete... +api-1 | Waiting for database migrations to complete... +api-1 | Waiting for database migrations to complete... +api-1 | No migrations Pending. Starting processes ... +api-1 | Instance registered +api-1 | ENABLE_SIGNUP loaded with value from environment variable. +api-1 | ENABLE_EMAIL_PASSWORD loaded with value from environment variable. +api-1 | ENABLE_MAGIC_LINK_LOGIN loaded with value from environment variable. +api-1 | GOOGLE_CLIENT_ID loaded with value from environment variable. +api-1 | GITHUB_CLIENT_ID loaded with value from environment variable. +api-1 | GITHUB_CLIENT_SECRET loaded with value from environment variable. +api-1 | EMAIL_HOST loaded with value from environment variable. +api-1 | EMAIL_HOST_USER loaded with value from environment variable. +api-1 | EMAIL_HOST_PASSWORD loaded with value from environment variable. +api-1 | EMAIL_PORT loaded with value from environment variable. +api-1 | EMAIL_FROM loaded with value from environment variable. +api-1 | EMAIL_USE_TLS loaded with value from environment variable. +api-1 | EMAIL_USE_SSL loaded with value from environment variable. +api-1 | OPENAI_API_KEY loaded with value from environment variable. +api-1 | GPT_ENGINE loaded with value from environment variable. +api-1 | UNSPLASH_ACCESS_KEY loaded with value from environment variable. +api-1 | Checking bucket... +api-1 | Bucket 'uploads' does not exist. Creating bucket... +api-1 | Bucket 'uploads' created successfully. +api-1 | Public read access policy set for bucket 'uploads'. +api-1 | Cache Cleared +api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Starting gunicorn 21.2.0 +api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) +api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Using worker: uvicorn.workers.UvicornWorker +api-1 | [2024-05-02 03:56:01 +0000] [25] [INFO] Booting worker with pid: 25 +api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Started server process [25] +api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Waiting for application startup. +api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] ASGI 'lifespan' protocol appears unsupported. +api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Application startup complete. + +``` + +To exit this, use `CTRL+C` and then you will land on to the main-menu with the list of actions. + +Similarly, you can view the logs of other services. + +--- + +### Backup Data + +There would a time when you might want to backup your data from docker volumes to external storage like S3 or drives. + +Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `7` to Backup the data. + +```bash +Select a Action you want to perform: + 1) Install (x86_64) + 2) Start + 3) Stop + 4) Restart + 5) Upgrade + 6) View Logs + 7) Backup Data + 8) Exit + +Action [2]: 7 +``` + +In response, you can find the backup folder + +```bash +Backing Up plane-app_pgdata +Backing Up plane-app_redisdata +Backing Up plane-app_uploads + +Backup completed successfully. Backup files are stored in /....../plane-app/backup/20240502-1120 +``` + +--- + +### Restore Data + +When you want to restore the previously backed-up data, follow the instructions below. + +1. Make sure that Plane-CE is installed, started, and then stopped. This ensures that the Docker volumes are created. + +1. Download the restore script using the command below. We suggest downloading it in the same folder as `setup.sh`. + + ```bash + curl -fsSL -o restore.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/restore.sh + chmod +x restore.sh + ``` + +1. Execute the command below to restore your data. + + ```bash + ./restore.sh + ``` + + As an example, for a backup folder `/opt/plane-selfhost/plane-app/backup/20240722-0914`, expect the response below: + + ```bash + -------------------------------------------- + ____ _ ///////// + | _ \| | __ _ _ __ ___ ///////// + | |_) | |/ _` | '_ \ / _ \ ///// ///// + | __/| | (_| | | | | __/ ///// ///// + |_| |_|\__,_|_| |_|\___| //// + //// + -------------------------------------------- + Project management tool from the future + -------------------------------------------- + Found /opt/plane-selfhost/plane-app/backup/20240722-0914/pgdata.tar.gz + .....Restoring plane-app_pgdata + .....Successfully restored volume plane-app_pgdata from pgdata.tar.gz + + Found /opt/plane-selfhost/plane-app/backup/20240722-0914/redisdata.tar.gz + .....Restoring plane-app_redisdata + .....Successfully restored volume plane-app_redisdata from redisdata.tar.gz + + Found /opt/plane-selfhost/plane-app/backup/20240722-0914/uploads.tar.gz + .....Restoring plane-app_uploads + .....Successfully restored volume plane-app_uploads from uploads.tar.gz + + + Restore completed successfully. + ``` + +1. Start the Plane instance using `./setup.sh start`. + +--- + +
+

Upgrading from v0.13.2 to v0.14.x

+ +This is one time activity for users who are upgrading from v0.13.2 to v0.14.0 + +As there has been significant changes to Self Hosting process, this step mainly covers the data migration from current (v0.13.2) docker volumes from newly created volumes + +> Before we begin with migration, make sure your v0.14.0 was started and then stopped. This is required to know the newly created docker volume names. + +Begin with downloading the migration script using below command + +``` + +curl -fsSL -o migrate.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/migration-0.13-0.14.sh + +chmod +x migrate.sh + +``` + +Now run the `./migrate.sh` command and expect the instructions as below + +``` +****************************************************************** + +This script is solely for the migration purpose only. +This is a 1 time migration of volume data from v0.13.2 => v0.14.x + +Assumption: +1. Postgres data volume name ends with _pgdata +2. Minio data volume name ends with _uploads +3. Redis data volume name ends with _redisdata + +Any changes to this script can break the migration. + +Before you proceed, make sure you run the below command +to know the docker volumes + +docker volume ls -q | grep -i "_pgdata" +docker volume ls -q | grep -i "_uploads" +docker volume ls -q | grep -i "_redisdata" + +******************************************************* + +Given below list of REDIS volumes, identify the prefix of source and destination volumes leaving "_redisdata" +--------------------- +plane-app_redisdata +v0132_redisdata + +Provide the Source Volume Prefix : +``` + +**Open another terminal window**, and run the mentioned 3 command. This may be different for users who have changed the volume names in their previous setup (v0.13.2) + +For every command you must see 2 records something like shown in above example of `redisdata` + +To move forward, you would need PREFIX of old setup and new setup. As per above example, `v0132` is the prefix of v0.13.2 and `plane-app` is the prefix of v0.14.0 setup + +**Back to original terminal window**, _Provide the Source Volume Prefix_ and hit ENTER. + +Now you will be prompted to _Provide Destination Volume Prefix_. Provide the value and hit ENTER + +``` +Provide the Source Volume Prefix : v0132 +Provide the Destination Volume Prefix : plane-app +``` + +In case the suffixes are wrong or the mentioned volumes are not found, you will receive the error shown below. The image below displays an error for source volumes. + +![Migrate Error](images/migrate-error.png) + +In case of successful migration, it will be a silent exit without error. + +Now its time to restart v0.14.0 setup. +
\ No newline at end of file diff --git a/plane/code/build.yml b/plane/code/build.yml new file mode 100644 index 0000000..b65d297 --- /dev/null +++ b/plane/code/build.yml @@ -0,0 +1,30 @@ +services: + web: + image: ${DOCKERHUB_USER:-local}/plane-frontend:${APP_RELEASE:-latest} + build: + context: . + dockerfile: ./web/Dockerfile.web + + space: + image: ${DOCKERHUB_USER:-local}/plane-space:${APP_RELEASE:-latest} + build: + context: ./ + dockerfile: ./space/Dockerfile.space + + admin: + image: ${DOCKERHUB_USER:-local}/plane-admin:${APP_RELEASE:-latest} + build: + context: ./ + dockerfile: ./admin/Dockerfile.admin + + api: + image: ${DOCKERHUB_USER:-local}/plane-backend:${APP_RELEASE:-latest} + build: + context: ./apiserver + dockerfile: ./Dockerfile.api + + proxy: + image: ${DOCKERHUB_USER:-local}/plane-proxy:${APP_RELEASE:-latest} + build: + context: ./nginx + dockerfile: ./Dockerfile diff --git a/plane/code/docker-compose.yml b/plane/code/docker-compose.yml new file mode 100644 index 0000000..dacc35f --- /dev/null +++ b/plane/code/docker-compose.yml @@ -0,0 +1,184 @@ +x-app-env: &app-env + environment: + - NGINX_PORT=${NGINX_PORT:-80} + - WEB_URL=${WEB_URL:-http://localhost} + - DEBUG=${DEBUG:-0} + - SENTRY_DSN=${SENTRY_DSN} + - SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-"production"} + - CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS} + # Gunicorn Workers + - GUNICORN_WORKERS=${GUNICORN_WORKERS:-1} + #DB SETTINGS + - PGHOST=${PGHOST:-plane-db} + - PGDATABASE=${PGDATABASE:-plane} + - POSTGRES_USER=${POSTGRES_USER:-plane} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-plane} + - POSTGRES_DB=${POSTGRES_DB:-plane} + - POSTGRES_PORT=${POSTGRES_PORT:-5432} + - PGDATA=${PGDATA:-/var/lib/postgresql/data} + - DATABASE_URL=${DATABASE_URL:-postgresql://plane:plane@plane-db/plane} + # REDIS SETTINGS + - REDIS_HOST=${REDIS_HOST:-plane-redis} + - REDIS_PORT=${REDIS_PORT:-6379} + - REDIS_URL=${REDIS_URL:-redis://plane-redis:6379/} + # Application secret + - SECRET_KEY=${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5} + # DATA STORE SETTINGS + - USE_MINIO=${USE_MINIO:-1} + - AWS_REGION=${AWS_REGION:-""} + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-"access-key"} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-"secret-key"} + - AWS_S3_ENDPOINT_URL=${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000} + - AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME:-uploads} + - MINIO_ROOT_USER=${MINIO_ROOT_USER:-"access-key"} + - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-"secret-key"} + - BUCKET_NAME=${BUCKET_NAME:-uploads} + - FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880} + # Admin and Space URLs + - ADMIN_BASE_URL=${ADMIN_BASE_URL} + - SPACE_BASE_URL=${SPACE_BASE_URL} + - APP_BASE_URL=${APP_BASE_URL} + +services: + web: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: unless-stopped + command: node web/server.js web + deploy: + replicas: ${WEB_REPLICAS:-1} + depends_on: + - api + - worker + + space: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: unless-stopped + command: node space/server.js space + deploy: + replicas: ${SPACE_REPLICAS:-1} + depends_on: + - api + - worker + - web + + admin: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-admin:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: unless-stopped + command: node admin/server.js admin + deploy: + replicas: ${ADMIN_REPLICAS:-1} + depends_on: + - api + - web + + api: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: unless-stopped + command: ./bin/docker-entrypoint-api.sh + deploy: + replicas: ${API_REPLICAS:-1} + volumes: + - logs_api:/code/plane/logs + depends_on: + - plane-db + - plane-redis + + worker: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: unless-stopped + command: ./bin/docker-entrypoint-worker.sh + volumes: + - logs_worker:/code/plane/logs + depends_on: + - api + - plane-db + - plane-redis + + beat-worker: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: unless-stopped + command: ./bin/docker-entrypoint-beat.sh + volumes: + - logs_beat-worker:/code/plane/logs + depends_on: + - api + - plane-db + - plane-redis + + migrator: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: "no" + command: ./bin/docker-entrypoint-migrator.sh + volumes: + - logs_migrator:/code/plane/logs + depends_on: + - plane-db + - plane-redis + + plane-db: + <<: *app-env + image: postgres:15.5-alpine + pull_policy: if_not_present + restart: unless-stopped + command: postgres -c 'max_connections=1000' + volumes: + - pgdata:/var/lib/postgresql/data + + plane-redis: + <<: *app-env + image: valkey/valkey:7.2.5-alpine + pull_policy: if_not_present + restart: unless-stopped + volumes: + - redisdata:/data + + plane-minio: + <<: *app-env + image: minio/minio:latest + pull_policy: if_not_present + restart: unless-stopped + command: server /export --console-address ":9090" + volumes: + - uploads:/export + + # Comment this if you already have a reverse proxy running + proxy: + <<: *app-env + image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-stable} + platform: ${DOCKER_PLATFORM:-} + pull_policy: if_not_present + restart: unless-stopped + depends_on: + - web + - api + - space + +volumes: + pgdata: + redisdata: + uploads: + logs_api: + logs_worker: + logs_beat-worker: + logs_migrator: diff --git a/plane/code/images/download.png b/plane/code/images/download.png new file mode 100644 index 0000000..bb0d118 Binary files /dev/null and b/plane/code/images/download.png differ diff --git a/plane/code/images/migrate-error.png b/plane/code/images/migrate-error.png new file mode 100644 index 0000000..f42ec44 Binary files /dev/null and b/plane/code/images/migrate-error.png differ diff --git a/plane/code/images/restart.png b/plane/code/images/restart.png new file mode 100644 index 0000000..0387599 Binary files /dev/null and b/plane/code/images/restart.png differ diff --git a/plane/code/images/started.png b/plane/code/images/started.png new file mode 100644 index 0000000..d6a0a0b Binary files /dev/null and b/plane/code/images/started.png differ diff --git a/plane/code/images/stopped.png b/plane/code/images/stopped.png new file mode 100644 index 0000000..0f58768 Binary files /dev/null and b/plane/code/images/stopped.png differ diff --git a/plane/code/images/upgrade.png b/plane/code/images/upgrade.png new file mode 100644 index 0000000..b78fbbb Binary files /dev/null and b/plane/code/images/upgrade.png differ diff --git a/plane/code/install.sh b/plane/code/install.sh new file mode 100755 index 0000000..8fd2e3e --- /dev/null +++ b/plane/code/install.sh @@ -0,0 +1,559 @@ +#!/bin/bash + +BRANCH=${BRANCH:-master} +SCRIPT_DIR=$PWD +SERVICE_FOLDER=plane-app +PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER +export APP_RELEASE="stable" +export DOCKERHUB_USER=makeplane +export PULL_POLICY=${PULL_POLICY:-if_not_present} + +CPU_ARCH=$(uname -m) + +mkdir -p $PLANE_INSTALL_DIR/archive +DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yaml +DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/plane.env + +function print_header() { +clear + +cat <<"EOF" +-------------------------------------------- + ____ _ ///////// +| _ \| | __ _ _ __ ___ ///////// +| |_) | |/ _` | '_ \ / _ \ ///// ///// +| __/| | (_| | | | | __/ ///// ///// +|_| |_|\__,_|_| |_|\___| //// + //// +-------------------------------------------- +Project management tool from the future +-------------------------------------------- +EOF +} + +function spinner() { + local pid=$1 + local delay=.5 + local spinstr='|/-\' + + if ! ps -p "$pid" > /dev/null; then + echo "Invalid PID: $pid" + return 1 + fi + while ps -p "$pid" > /dev/null; do + local temp=${spinstr#?} + printf " [%c] " "$spinstr" >&2 + local spinstr=$temp${spinstr%"$temp"} + sleep $delay + printf "\b\b\b\b\b\b" >&2 + done + printf " \b\b\b\b" >&2 +} + +function initialize(){ + printf "Please wait while we check the availability of Docker images for the selected release ($APP_RELEASE) with ${CPU_ARCH^^} support." >&2 + + if [ "$CUSTOM_BUILD" == "true" ]; then + echo "" >&2 + echo "" >&2 + echo "${CPU_ARCH^^} images are not available for selected release ($APP_RELEASE)." >&2 + echo "build" + return 1 + fi + + local IMAGE_NAME=makeplane/plane-proxy + local IMAGE_TAG=${APP_RELEASE} + docker manifest inspect "${IMAGE_NAME}:${IMAGE_TAG}" | grep -q "\"architecture\": \"${CPU_ARCH}\"" & + local pid=$! + spinner "$pid" + + echo "" >&2 + + wait "$pid" + + if [ $? -eq 0 ]; then + echo "Plane supports ${CPU_ARCH}" >&2 + echo "available" + return 0 + else + echo "" >&2 + echo "" >&2 + echo "${CPU_ARCH^^} images are not available for selected release ($APP_RELEASE)." >&2 + echo "" >&2 + echo "build" + return 1 + fi +} +function getEnvValue() { + local key=$1 + local file=$2 + + if [ -z "$key" ] || [ -z "$file" ]; then + echo "Invalid arguments supplied" + exit 1 + fi + + if [ -f "$file" ]; then + grep -q "^$key=" "$file" + if [ $? -eq 0 ]; then + local value + value=$(grep "^$key=" "$file" | cut -d'=' -f2) + echo "$value" + else + echo "" + fi + fi +} +function updateEnvFile() { + local key=$1 + local value=$2 + local file=$3 + + if [ -z "$key" ] || [ -z "$value" ] || [ -z "$file" ]; then + echo "Invalid arguments supplied" + exit 1 + fi + + if [ -f "$file" ]; then + # check if key exists in the file + grep -q "^$key=" "$file" + if [ $? -ne 0 ]; then + echo "$key=$value" >> "$file" + return + else + # if key exists, update the value + sed -i "s/^$key=.*/$key=$value/g" "$file" + fi + else + echo "File not found: $file" + exit 1 + fi +} + +function updateCustomVariables(){ + echo "Updating custom variables..." >&2 + updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH" + updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH" + updateEnvFile "PULL_POLICY" "$PULL_POLICY" "$DOCKER_ENV_PATH" + updateEnvFile "CUSTOM_BUILD" "$CUSTOM_BUILD" "$DOCKER_ENV_PATH" + echo "Custom variables updated successfully" >&2 +} + +function syncEnvFile(){ + echo "Syncing environment variables..." >&2 + if [ -f "$PLANE_INSTALL_DIR/plane.env.bak" ]; then + updateCustomVariables + + # READ keys of plane.env and update the values from plane.env.bak + while IFS= read -r line + do + # ignore is the line is empty or starts with # + if [ -z "$line" ] || [[ $line == \#* ]]; then + continue + fi + key=$(echo "$line" | cut -d'=' -f1) + value=$(getEnvValue "$key" "$PLANE_INSTALL_DIR/plane.env.bak") + if [ -n "$value" ]; then + updateEnvFile "$key" "$value" "$DOCKER_ENV_PATH" + fi + done < "$DOCKER_ENV_PATH" + fi + echo "Environment variables synced successfully" >&2 +} + +function buildYourOwnImage(){ + echo "Building images locally..." + + export DOCKERHUB_USER="myplane" + export APP_RELEASE="local" + export PULL_POLICY="never" + CUSTOM_BUILD="true" + + # checkout the code to ~/tmp/plane folder and build the images + local PLANE_TEMP_CODE_DIR=~/tmp/plane + rm -rf $PLANE_TEMP_CODE_DIR + mkdir -p $PLANE_TEMP_CODE_DIR + REPO=https://github.com/makeplane/plane.git + git clone "$REPO" "$PLANE_TEMP_CODE_DIR" --branch "$BRANCH" --single-branch --depth 1 + + cp "$PLANE_TEMP_CODE_DIR/deploy/selfhost/build.yml" "$PLANE_TEMP_CODE_DIR/build.yml" + + cd "$PLANE_TEMP_CODE_DIR" || exit + + /bin/bash -c "$COMPOSE_CMD -f build.yml build --no-cache" >&2 + if [ $? -ne 0 ]; then + echo "Build failed. Exiting..." + exit 1 + fi + echo "Build completed successfully" + echo "" + echo "You can now start the services by running the command: ./setup.sh start" + echo "" +} + +function install() { + echo "Begin Installing Plane" + echo "" + + local build_image=$(initialize) + + if [ "$build_image" == "build" ]; then + # ask for confirmation to continue building the images + echo "Do you want to continue with building the Docker images locally?" + read -p "Continue? [y/N]: " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "Exiting..." + exit 0 + fi + fi + + if [ "$build_image" == "build" ]; then + download "true" + else + download "false" + fi +} + +function download() { + local LOCAL_BUILD=$1 + cd $SCRIPT_DIR + TS=$(date +%s) + if [ -f "$PLANE_INSTALL_DIR/docker-compose.yaml" ] + then + mv $PLANE_INSTALL_DIR/docker-compose.yaml $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yaml + fi + + curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/docker-compose.yaml https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/docker-compose.yml?$(date +%s) + curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/variables-upgrade.env https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/variables.env?$(date +%s) + + if [ -f "$DOCKER_ENV_PATH" ]; + then + cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/archive/$TS.env" + cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/plane.env.bak" + fi + + mv $PLANE_INSTALL_DIR/variables-upgrade.env $DOCKER_ENV_PATH + + syncEnvFile + + if [ "$LOCAL_BUILD" == "true" ]; then + export DOCKERHUB_USER="myplane" + export APP_RELEASE="local" + export PULL_POLICY="never" + CUSTOM_BUILD="true" + + buildYourOwnImage + + if [ $? -ne 0 ]; then + echo "" + echo "Build failed. Exiting..." + exit 1 + fi + updateCustomVariables + else + CUSTOM_BUILD="false" + updateCustomVariables + /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH pull --policy always" + + if [ $? -ne 0 ]; then + echo "" + echo "Failed to pull the images. Exiting..." + exit 1 + fi + fi + + echo "" + echo "Most recent version of Plane is now available for you to use" + echo "" + echo "In case of 'Upgrade', please check the 'plane.env 'file for any new variables and update them accordingly" + echo "" +} +function startServices() { + /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH up -d --pull if_not_present --quiet-pull" + + local migrator_container_id=$(docker container ls -aq -f "name=$SERVICE_FOLDER-migrator") + if [ -n "$migrator_container_id" ]; then + local idx=0 + while docker inspect --format='{{.State.Status}}' $migrator_container_id | grep -q "running"; do + local message=">> Waiting for Data Migration to finish" + local dots=$(printf '%*s' $idx | tr ' ' '.') + echo -ne "\r$message$dots" + ((idx++)) + sleep 1 + done + fi + printf "\r\033[K" + echo "" + echo " Data Migration completed successfully ✅" + + # if migrator exit status is not 0, show error message and exit + if [ -n "$migrator_container_id" ]; then + local migrator_exit_code=$(docker inspect --format='{{.State.ExitCode}}' $migrator_container_id) + if [ $migrator_exit_code -ne 0 ]; then + echo "Plane Server failed to start ❌" + # stopServices + echo + echo "Please check the logs for the 'migrator' service and resolve the issue(s)." + echo "Stop the services by running the command: ./setup.sh stop" + exit 1 + fi + fi + + local api_container_id=$(docker container ls -q -f "name=$SERVICE_FOLDER-api") + local idx2=0 + while ! docker logs $api_container_id 2>&1 | grep -m 1 -i "Application startup complete" | grep -q "."; + do + local message=">> Waiting for API Service to Start" + local dots=$(printf '%*s' $idx2 | tr ' ' '.') + echo -ne "\r$message$dots" + ((idx2++)) + sleep 1 + done + printf "\r\033[K" + echo " API Service started successfully ✅" + source "${DOCKER_ENV_PATH}" + echo " Plane Server started successfully ✅" + echo "" + echo " You can access the application at $WEB_URL" + echo "" + +} +function stopServices() { + /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH down" +} +function restartServices() { + stopServices + startServices +} +function upgrade() { + echo "***** STOPPING SERVICES ****" + stopServices + + echo + echo "***** DOWNLOADING STABLE VERSION ****" + install + + echo "***** PLEASE VALIDATE AND START SERVICES ****" +} +function viewSpecificLogs(){ + local SERVICE_NAME=$1 + + if /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH ps | grep -q '$SERVICE_NAME'"; then + echo "Service '$SERVICE_NAME' is running." + else + echo "Service '$SERVICE_NAME' is not running." + fi + + /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH logs -f $SERVICE_NAME" +} +function viewLogs(){ + + ARG_SERVICE_NAME=$2 + + if [ -z "$ARG_SERVICE_NAME" ]; + then + echo + echo "Select a Service you want to view the logs for:" + echo " 1) Web" + echo " 2) Space" + echo " 3) API" + echo " 4) Worker" + echo " 5) Beat-Worker" + echo " 6) Migrator" + echo " 7) Proxy" + echo " 8) Redis" + echo " 9) Postgres" + echo " 10) Minio" + echo " 0) Back to Main Menu" + echo + read -p "Service: " DOCKER_SERVICE_NAME + + until (( DOCKER_SERVICE_NAME >= 0 && DOCKER_SERVICE_NAME <= 10 )); do + echo "Invalid selection. Please enter a number between 1 and 11." + read -p "Service: " DOCKER_SERVICE_NAME + done + + if [ -z "$DOCKER_SERVICE_NAME" ]; + then + echo "INVALID SERVICE NAME SUPPLIED" + else + case $DOCKER_SERVICE_NAME in + 1) viewSpecificLogs "web";; + 2) viewSpecificLogs "space";; + 3) viewSpecificLogs "api";; + 4) viewSpecificLogs "worker";; + 5) viewSpecificLogs "beat-worker";; + 6) viewSpecificLogs "migrator";; + 7) viewSpecificLogs "proxy";; + 8) viewSpecificLogs "plane-redis";; + 9) viewSpecificLogs "plane-db";; + 10) viewSpecificLogs "plane-minio";; + 0) askForAction;; + *) echo "INVALID SERVICE NAME SUPPLIED";; + esac + fi + elif [ -n "$ARG_SERVICE_NAME" ]; + then + ARG_SERVICE_NAME=$(echo "$ARG_SERVICE_NAME" | tr '[:upper:]' '[:lower:]') + case $ARG_SERVICE_NAME in + web) viewSpecificLogs "web";; + space) viewSpecificLogs "space";; + api) viewSpecificLogs "api";; + worker) viewSpecificLogs "worker";; + beat-worker) viewSpecificLogs "beat-worker";; + migrator) viewSpecificLogs "migrator";; + proxy) viewSpecificLogs "proxy";; + redis) viewSpecificLogs "plane-redis";; + postgres) viewSpecificLogs "plane-db";; + minio) viewSpecificLogs "plane-minio";; + *) echo "INVALID SERVICE NAME SUPPLIED";; + esac + else + echo "INVALID SERVICE NAME SUPPLIED" + fi +} +function backupSingleVolume() { + backupFolder=$1 + selectedVolume=$2 + # Backup data from Docker volume to the backup folder + # docker run --rm -v "$selectedVolume":/source -v "$backupFolder":/backup busybox sh -c 'cp -r /source/* /backup/' + local tobereplaced="plane-app_" + local replacewith="" + + local svcName="${selectedVolume//$tobereplaced/$replacewith}" + + docker run --rm \ + -e TAR_NAME="$svcName" \ + -v "$selectedVolume":/"$svcName" \ + -v "$backupFolder":/backup \ + busybox sh -c 'tar -czf "/backup/${TAR_NAME}.tar.gz" /${TAR_NAME}' +} +function backupData() { + local datetime=$(date +"%Y%m%d-%H%M") + local BACKUP_FOLDER=$PLANE_INSTALL_DIR/backup/$datetime + mkdir -p "$BACKUP_FOLDER" + + volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads") + # Check if there are any matching volumes + if [ -z "$volumes" ]; then + echo "No volumes found starting with 'plane-app'" + exit 1 + fi + + for vol in $volumes; do + echo "Backing Up $vol" + backupSingleVolume "$BACKUP_FOLDER" "$vol" + done + + echo "" + echo "Backup completed successfully. Backup files are stored in $BACKUP_FOLDER" + echo "" + +} +function askForAction() { + local DEFAULT_ACTION=$1 + + if [ -z "$DEFAULT_ACTION" ]; + then + echo + echo "Select a Action you want to perform:" + echo " 1) Install" + echo " 2) Start" + echo " 3) Stop" + echo " 4) Restart" + echo " 5) Upgrade" + echo " 6) View Logs" + echo " 7) Backup Data" + echo " 8) Exit" + echo + read -p "Action [2]: " ACTION + until [[ -z "$ACTION" || "$ACTION" =~ ^[1-8]$ ]]; do + echo "$ACTION: invalid selection." + read -p "Action [2]: " ACTION + done + + if [ -z "$ACTION" ]; + then + ACTION=2 + fi + echo + fi + + if [ "$ACTION" == "1" ] || [ "$DEFAULT_ACTION" == "install" ]; + then + install + # askForAction + elif [ "$ACTION" == "2" ] || [ "$DEFAULT_ACTION" == "start" ]; + then + startServices + # askForAction + elif [ "$ACTION" == "3" ] || [ "$DEFAULT_ACTION" == "stop" ]; + then + stopServices + # askForAction + elif [ "$ACTION" == "4" ] || [ "$DEFAULT_ACTION" == "restart" ]; + then + restartServices + # askForAction + elif [ "$ACTION" == "5" ] || [ "$DEFAULT_ACTION" == "upgrade" ]; + then + upgrade + # askForAction + elif [ "$ACTION" == "6" ] || [ "$DEFAULT_ACTION" == "logs" ]; + then + viewLogs "$@" + askForAction + elif [ "$ACTION" == "7" ] || [ "$DEFAULT_ACTION" == "backup" ]; + then + backupData + elif [ "$ACTION" == "8" ] + then + exit 0 + else + echo "INVALID ACTION SUPPLIED" + fi +} + +# if docker-compose is installed +if command -v docker-compose &> /dev/null +then + COMPOSE_CMD="docker-compose" +else + COMPOSE_CMD="docker compose" +fi + +if [ "$CPU_ARCH" == "x86_64" ] || [ "$CPU_ARCH" == "amd64" ]; then + CPU_ARCH="amd64" +elif [ "$CPU_ARCH" == "aarch64" ] || [ "$CPU_ARCH" == "arm64" ]; then + CPU_ARCH="arm64" +fi + +if [ -f "$DOCKER_ENV_PATH" ]; then + DOCKERHUB_USER=$(getEnvValue "DOCKERHUB_USER" "$DOCKER_ENV_PATH") + APP_RELEASE=$(getEnvValue "APP_RELEASE" "$DOCKER_ENV_PATH") + PULL_POLICY=$(getEnvValue "PULL_POLICY" "$DOCKER_ENV_PATH") + CUSTOM_BUILD=$(getEnvValue "CUSTOM_BUILD" "$DOCKER_ENV_PATH") + + if [ -z "$DOCKERHUB_USER" ]; then + DOCKERHUB_USER=makeplane + updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH" + fi + + if [ -z "$APP_RELEASE" ]; then + APP_RELEASE=stable + updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH" + fi + + if [ -z "$PULL_POLICY" ]; then + PULL_POLICY=if_not_present + updateEnvFile "PULL_POLICY" "$PULL_POLICY" "$DOCKER_ENV_PATH" + fi + + if [ -z "$CUSTOM_BUILD" ]; then + CUSTOM_BUILD=false + updateEnvFile "CUSTOM_BUILD" "$CUSTOM_BUILD" "$DOCKER_ENV_PATH" + fi +fi + +print_header +askForAction "$@" diff --git a/plane/code/migration-0.13-0.14.sh b/plane/code/migration-0.13-0.14.sh new file mode 100755 index 0000000..d03f877 --- /dev/null +++ b/plane/code/migration-0.13-0.14.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +echo ' +****************************************************************** + +This script is solely for the migration purpose only. +This is a 1 time migration of volume data from v0.13.2 => v0.14.x + +Assumption: +1. Postgres data volume name ends with _pgdata +2. Minio data volume name ends with _uploads +3. Redis data volume name ends with _redisdata + +Any changes to this script can break the migration. + +Before you proceed, make sure you run the below command +to know the docker volumes + +docker volume ls -q | grep -i "_pgdata" +docker volume ls -q | grep -i "_uploads" +docker volume ls -q | grep -i "_redisdata" + +******************************************************* +' + +DOWNLOAD_FOL=./download +rm -rf ${DOWNLOAD_FOL} +mkdir -p ${DOWNLOAD_FOL} + +function volumeExists { + if [ "$(docker volume ls -f name=$1 | awk '{print $NF}' | grep -E '^'$1'$')" ]; then + return 0 + else + return 1 + fi +} + +function readPrefixes(){ + echo '' + echo 'Given below list of REDIS volumes, identify the prefix of source and destination volumes leaving "_redisdata" ' + echo '---------------------' + docker volume ls -q | grep -i "_redisdata" + echo '' + + read -p "Provide the Source Volume Prefix : " SRC_VOL_PREFIX + until [ "$SRC_VOL_PREFIX" ]; do + read -p "Provide the Source Volume Prefix : " SRC_VOL_PREFIX + done + + read -p "Provide the Destination Volume Prefix : " DEST_VOL_PREFIX + until [ "$DEST_VOL_PREFIX" ]; do + read -p "Provide the Source Volume Prefix : " DEST_VOL_PREFIX + done + + echo '' + echo 'Prefix Provided ' + echo " Source : ${SRC_VOL_PREFIX}" + echo " Destination : ${DEST_VOL_PREFIX}" + echo '---------------------------------------' +} + +function migrate(){ + + SRC_VOLUME=${SRC_VOL_PREFIX}_${VOL_NAME_SUFFIX} + DEST_VOLUME=${DEST_VOL_PREFIX}_${VOL_NAME_SUFFIX} + + if volumeExists $SRC_VOLUME; then + if volumeExists $DEST_VOLUME; then + GOOD_TO_GO=1 + else + echo "Destination Volume '$DEST_VOLUME' does not exist" + echo '' + fi + else + echo "Source Volume '$SRC_VOLUME' does not exist" + echo '' + fi + + if [ $GOOD_TO_GO = 1 ]; then + + echo "MIGRATING ${VOL_NAME_SUFFIX} FROM ${SRC_VOLUME} => ${DEST_VOLUME}" + + TEMP_CONTAINER=$(docker run -d -v $SRC_VOLUME:$CONTAINER_VOL_FOLDER busybox true) + docker cp -q $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX} + docker rm $TEMP_CONTAINER &> /dev/null + + TEMP_CONTAINER=$(docker run -d -v $DEST_VOLUME:$CONTAINER_VOL_FOLDER busybox true) + if [ "$VOL_NAME_SUFFIX" = "pgdata" ]; then + docker cp -q ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX} $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER/_temp + docker run --rm -v $DEST_VOLUME:$CONTAINER_VOL_FOLDER \ + -e DATA_FOLDER="${CONTAINER_VOL_FOLDER}" \ + busybox /bin/sh -c 'cp -Rf $DATA_FOLDER/_temp/* $DATA_FOLDER ' + else + docker cp -q ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX} $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER + fi + docker rm $TEMP_CONTAINER &> /dev/null + + echo '' + fi +} + +readPrefixes + +# MIGRATE DB +CONTAINER_VOL_FOLDER=/var/lib/postgresql/data +VOL_NAME_SUFFIX=pgdata +migrate + +# MIGRATE REDIS +CONTAINER_VOL_FOLDER=/data +VOL_NAME_SUFFIX=redisdata +migrate + +# MIGRATE MINIO +CONTAINER_VOL_FOLDER=/export +VOL_NAME_SUFFIX=uploads +migrate + diff --git a/plane/code/restore.sh b/plane/code/restore.sh new file mode 100755 index 0000000..cd453b2 --- /dev/null +++ b/plane/code/restore.sh @@ -0,0 +1,121 @@ +#!/bin/bash + +function print_header() { +clear + +cat <<"EOF" +-------------------------------------------- + ____ _ ///////// +| _ \| | __ _ _ __ ___ ///////// +| |_) | |/ _` | '_ \ / _ \ ///// ///// +| __/| | (_| | | | | __/ ///// ///// +|_| |_|\__,_|_| |_|\___| //// + //// +-------------------------------------------- +Project management tool from the future +-------------------------------------------- +EOF +} + +function restoreSingleVolume() { + selectedVolume=$1 + backupFolder=$2 + restoreFile=$3 + + docker volume rm "$selectedVolume" > /dev/null 2>&1 + + if [ $? -ne 0 ]; then + echo "Error: Failed to remove volume $selectedVolume" + echo "" + return 1 + fi + + docker volume create "$selectedVolume" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error: Failed to create volume $selectedVolume" + echo "" + return 1 + fi + + docker run --rm \ + -e TAR_NAME="$restoreFile" \ + -v "$selectedVolume":"/vol" \ + -v "$backupFolder":/backup \ + busybox sh -c 'mkdir -p /restore && tar -xzf "/backup/${TAR_NAME}.tar.gz" -C /restore && mv /restore/${TAR_NAME}/* /vol' + + if [ $? -ne 0 ]; then + echo "Error: Failed to restore volume ${selectedVolume} from ${restoreFile}.tar.gz" + echo "" + return 1 + fi + echo ".....Successfully restored volume $selectedVolume from ${restoreFile}.tar.gz" + echo "" +} + +function restoreData() { + print_header + local BACKUP_FOLDER=${1:-$PWD} + + local dockerServiceStatus + dockerServiceStatus=$($COMPOSE_CMD ls --filter name=plane-app --format=json | jq -r .[0].Status) + local dockerServicePrefix + dockerServicePrefix="running" + + if [[ $dockerServiceStatus == $dockerServicePrefix* ]]; then + echo "Plane App is running. Please STOP the Plane App before restoring data." + exit 1 + fi + + local volumes + volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads") + # Check if there are any matching volumes + if [ -z "$volumes" ]; then + echo ".....No volumes found starting with 'plane-app'" + exit 1 + fi + + + for BACKUP_FILE in $BACKUP_FOLDER/*.tar.gz; do + if [ -e "$BACKUP_FILE" ]; then + + local restoreFileName + restoreFileName=$(basename "$BACKUP_FILE") + restoreFileName="${restoreFileName%.tar.gz}" + + local restoreVolName + restoreVolName="plane-app_${restoreFileName}" + echo "Found $BACKUP_FILE" + + local docVol + docVol=$(docker volume ls -f "name=$restoreVolName" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads") + + if [ -z "$docVol" ]; then + echo "Skipping: No volume found with name $restoreVolName" + else + echo ".....Restoring $docVol" + restoreSingleVolume "$docVol" "$BACKUP_FOLDER" "$restoreFileName" + fi + else + echo "No .tar.gz files found in the current directory." + echo "" + echo "Please provide the path to the backup file." + echo "" + echo "Usage: ./restore.sh /path/to/backup" + exit 1 + fi + done + + echo "" + echo "Restore completed successfully." + echo "" +} + +# if docker-compose is installed +if command -v docker-compose &> /dev/null +then + COMPOSE_CMD="docker-compose" +else + COMPOSE_CMD="docker compose" +fi + +restoreData "$@" \ No newline at end of file diff --git a/plane/update.sh b/plane/update.sh new file mode 100644 index 0000000..3bd7313 --- /dev/null +++ b/plane/update.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +if [ ! -d "./repo" ]; then + git clone --depth 1 --branch preview --single-branch https://github.com/makeplane/plane.git repo +else + cd repo + git pull + cd .. +fi + +cp -r ./repo/deploy/selfhost/. ./code +mv ./code/variables.env ./code/.env.example + + diff --git a/supabase/update.sh b/supabase/update.sh index ae4e4dd..24abd5a 100644 --- a/supabase/update.sh +++ b/supabase/update.sh @@ -1,6 +1,5 @@ #!/bin/bash -# check if ./repo exists if [ ! -d "./repo" ]; then git clone --depth 1 --branch master --single-branch https://github.com/supabase/supabase repo else @@ -9,5 +8,4 @@ else cd .. fi -# copy files from ./repo/docker to ./code cp -r ./repo/docker/. ./code