runtipi/scripts/app.sh

285 lines
6.7 KiB
Bash
Raw Normal View History

2022-03-29 20:40:04 +00:00
#!/usr/bin/env bash
echo "Starting app script"
source "${BASH_SOURCE%/*}/common.sh"
2022-03-29 20:40:04 +00:00
set -euo pipefail
ensure_pwd
2022-03-30 19:26:01 +00:00
ROOT_FOLDER="${PWD}"
STATE_FOLDER="${ROOT_FOLDER}/state"
ENV_FILE="${ROOT_FOLDER}/.env"
2022-03-29 20:40:04 +00:00
# Root folder in host system
ROOT_FOLDER_HOST=$(grep -v '^#' "${ENV_FILE}" | xargs -n 1 | grep ROOT_FOLDER_HOST | cut -d '=' -f2)
REPO_ID=$(grep -v '^#' "${ENV_FILE}" | xargs -n 1 | grep APPS_REPO_ID | cut -d '=' -f2)
STORAGE_PATH=$(grep -v '^#' "${ENV_FILE}" | xargs -n 1 | grep STORAGE_PATH | cut -d '=' -f2)
2022-03-29 20:40:04 +00:00
write_log "Running app script: ROOT_FOLDER=${ROOT_FOLDER}, ROOT_FOLDER_HOST=${ROOT_FOLDER_HOST}, REPO_ID=${REPO_ID}, STORAGE_PATH=${STORAGE_PATH}"
2022-03-29 20:40:04 +00:00
if [ -z ${1+x} ]; then
command=""
else
command="$1"
fi
if [ -z ${2+x} ]; then
exit 1
else
app="$2"
app_dir="${ROOT_FOLDER}/apps/${app}"
if [[ ! -d "${app_dir}" ]]; then
# copy from repo
echo "Copying app from repo"
mkdir -p "${app_dir}"
cp -r "${ROOT_FOLDER}/repos/${REPO_ID}/apps/${app}"/* "${app_dir}"
fi
app_data_dir="${STORAGE_PATH}/app-data/${app}"
2022-03-29 20:40:04 +00:00
if [[ -z "${app}" ]] || [[ ! -d "${app_dir}" ]]; then
echo "Error: \"${app}\" is not a valid app"
exit 1
fi
fi
# Function below has been modified from Umbrel
# Required Notice: Copyright
# Umbrel (https://umbrel.com)
2022-03-29 20:40:04 +00:00
compose() {
local app="${1}"
shift
arch=$(uname -m)
local architecture="${arch}"
if [[ "$architecture" == "aarch64" ]]; then
architecture="arm64"
fi
2022-03-29 20:40:04 +00:00
# App data folder
local app_compose_file="${app_dir}/docker-compose.yml"
2022-05-13 06:53:35 +00:00
# Pick arm architecture if running on arm and if the app has a docker-compose.arm.yml file
if [[ "$architecture" == "arm"* ]] && [[ -f "${app_dir}/docker-compose.arm.yml" ]]; then
app_compose_file="${app_dir}/docker-compose.arm.yml"
2022-05-18 18:13:58 +00:00
fi
# Pick arm architecture if running on arm and if the app has a docker-compose.arm64.yml file
if [[ "$architecture" == "arm64" ]] && [[ -f "${app_dir}/docker-compose.arm64.yml" ]]; then
app_compose_file="${app_dir}/docker-compose.arm64.yml"
fi
local common_compose_file="${ROOT_FOLDER}/repos/${REPO_ID}/apps/docker-compose.common.yml"
2022-03-29 20:40:04 +00:00
Release/1.0.0 (#316) * fix: create default media folder structure on install * feat: add link to open exposed app to domain * [ImgBot] Optimize images *Total -- 2,048.42kb -> 1,263.43kb (38.32%) /screenshots/darkmode.png -- 998.43kb -> 609.77kb (38.93%) /screenshots/appstore.png -- 1,006.73kb -> 620.12kb (38.4%) /packages/dashboard/public/error.png -- 42.38kb -> 32.70kb (22.84%) /packages/dashboard/public/empty.svg -- 0.87kb -> 0.85kb (2.35%) Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com> * chore: bump version 0.8.1 * refactor: move all dashboard's files into a client folder * feat: setup trpc and create system router * test: split jest config for client and server * refactor: replace grapqhl queries with trpc in the frontend * refactor: remove now un-used system queries/mutations/resolvers from both client and server * chore: bump dependencies * feat: setup prisma and configure it for tests and development * feat: create trpc router for auth service * refactor: migrate client auth queries to trpc procedures * refactor: cleanup now un-used graphql resolvers and services * feat: create sql migrations by replicating typeorm ones in an idempotent manner * feat: create server-preload script to run migrations upon server start * chore: remove legacy migrations steps * feat: add redis_host as an env variable * refactor: remove prisma from context and use client directly in service * feat: create trpc router & service for apps * refactor: migrate client app queries/mutations to trpc * refactor: removal and replace usage of old graphql generated types * refactor: move from node --require to custom next server * test: fix tests and bump various dependencies * chore: cleanup system-api from now un-used files * refactor(dashboard): remove code related to apollo * refactor: serve static files through next's server instead of system-api * refactor(server): move auth and system services to class * refactor(client): remove layoutv2 abstraction * fix: return correct update info * chore: remove legacy system-api folder * refactor: remove system-api from docker files * feat: create scheduler to run cron jobs and setup periodic repo update * fix: failing build caused by remark-mdx * refactor: move migrations to server folder * feat: compile server using esbuild * refactor: ts issue mis-used file from client in server * ci: make pipeline pass by cd into dashboard before each step (temp) * chore: drop armv7 support * refactor: move dashboard files in root folder * feat(db): create migration to add operator field on user * feat(user): create routes and services for password reset * feat(auth): add reset password page, container & form * refactor(dashboard): change layout and page of auth to be url based instead of state based * feat(script): add reset-password script * fix(dashboard): only check status if restart or update has been requested * test: increase coverage for get-server-auth-session * fix(start.sh): prompt for network interface only if there is not an internal ip set * feat(script): support user docker-compose.yml and app.env * chore: bump version * fix: add missing postgres variables to start script * fix: check for 32 bits before installing/starting * fix: create default media folder structure on install * Updated demo instance link Changed demo.runtipi.com to https://demo.runtipi.com * feat: adding config for codespaces * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com> Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com> Co-authored-by: Freddie Sackur <github@dustyfox.uk> Co-authored-by: Kieran Klukas <92754843+kcoderhtml@users.noreply.github.com> Co-authored-by: alwerner <alexander.werner@bonprix.net> Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-03-02 19:19:20 +00:00
local user_compose_file="${ROOT_FOLDER}/user-config/${app}/docker-compose.yml"
local user_compose_args=
if [[ -f ${user_compose_file} ]]; then
user_compose_args="--file ${user_compose_file}"
fi
local user_env_file="${ROOT_FOLDER}/user-config/${app}/app.env"
local user_env_args=
if [[ -f ${user_env_file} ]]; then
user_env_args="--env-file ${user_env_file}"
fi
2022-03-29 20:40:04 +00:00
# Vars to use in compose file
export APP_DATA_DIR="${STORAGE_PATH}/app-data/${app}"
export ROOT_FOLDER_HOST="${ROOT_FOLDER_HOST}"
2022-03-29 20:40:04 +00:00
write_log "Running docker compose -f ${app_compose_file} -f ${common_compose_file} ${*}"
write_log "APP_DATA_DIR=${APP_DATA_DIR}"
write_log "ROOT_FOLDER_HOST=${ROOT_FOLDER_HOST}"
docker compose \
--env-file "${app_data_dir}/app.env" \
Release/1.0.0 (#316) * fix: create default media folder structure on install * feat: add link to open exposed app to domain * [ImgBot] Optimize images *Total -- 2,048.42kb -> 1,263.43kb (38.32%) /screenshots/darkmode.png -- 998.43kb -> 609.77kb (38.93%) /screenshots/appstore.png -- 1,006.73kb -> 620.12kb (38.4%) /packages/dashboard/public/error.png -- 42.38kb -> 32.70kb (22.84%) /packages/dashboard/public/empty.svg -- 0.87kb -> 0.85kb (2.35%) Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com> * chore: bump version 0.8.1 * refactor: move all dashboard's files into a client folder * feat: setup trpc and create system router * test: split jest config for client and server * refactor: replace grapqhl queries with trpc in the frontend * refactor: remove now un-used system queries/mutations/resolvers from both client and server * chore: bump dependencies * feat: setup prisma and configure it for tests and development * feat: create trpc router for auth service * refactor: migrate client auth queries to trpc procedures * refactor: cleanup now un-used graphql resolvers and services * feat: create sql migrations by replicating typeorm ones in an idempotent manner * feat: create server-preload script to run migrations upon server start * chore: remove legacy migrations steps * feat: add redis_host as an env variable * refactor: remove prisma from context and use client directly in service * feat: create trpc router & service for apps * refactor: migrate client app queries/mutations to trpc * refactor: removal and replace usage of old graphql generated types * refactor: move from node --require to custom next server * test: fix tests and bump various dependencies * chore: cleanup system-api from now un-used files * refactor(dashboard): remove code related to apollo * refactor: serve static files through next's server instead of system-api * refactor(server): move auth and system services to class * refactor(client): remove layoutv2 abstraction * fix: return correct update info * chore: remove legacy system-api folder * refactor: remove system-api from docker files * feat: create scheduler to run cron jobs and setup periodic repo update * fix: failing build caused by remark-mdx * refactor: move migrations to server folder * feat: compile server using esbuild * refactor: ts issue mis-used file from client in server * ci: make pipeline pass by cd into dashboard before each step (temp) * chore: drop armv7 support * refactor: move dashboard files in root folder * feat(db): create migration to add operator field on user * feat(user): create routes and services for password reset * feat(auth): add reset password page, container & form * refactor(dashboard): change layout and page of auth to be url based instead of state based * feat(script): add reset-password script * fix(dashboard): only check status if restart or update has been requested * test: increase coverage for get-server-auth-session * fix(start.sh): prompt for network interface only if there is not an internal ip set * feat(script): support user docker-compose.yml and app.env * chore: bump version * fix: add missing postgres variables to start script * fix: check for 32 bits before installing/starting * fix: create default media folder structure on install * Updated demo instance link Changed demo.runtipi.com to https://demo.runtipi.com * feat: adding config for codespaces * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com> Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com> Co-authored-by: Freddie Sackur <github@dustyfox.uk> Co-authored-by: Kieran Klukas <92754843+kcoderhtml@users.noreply.github.com> Co-authored-by: alwerner <alexander.werner@bonprix.net> Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-03-02 19:19:20 +00:00
${user_env_args} \
2022-03-29 20:40:04 +00:00
--project-name "${app}" \
--file "${app_compose_file}" \
2022-04-07 08:34:18 +00:00
--file "${common_compose_file}" \
Release/1.0.0 (#316) * fix: create default media folder structure on install * feat: add link to open exposed app to domain * [ImgBot] Optimize images *Total -- 2,048.42kb -> 1,263.43kb (38.32%) /screenshots/darkmode.png -- 998.43kb -> 609.77kb (38.93%) /screenshots/appstore.png -- 1,006.73kb -> 620.12kb (38.4%) /packages/dashboard/public/error.png -- 42.38kb -> 32.70kb (22.84%) /packages/dashboard/public/empty.svg -- 0.87kb -> 0.85kb (2.35%) Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com> * chore: bump version 0.8.1 * refactor: move all dashboard's files into a client folder * feat: setup trpc and create system router * test: split jest config for client and server * refactor: replace grapqhl queries with trpc in the frontend * refactor: remove now un-used system queries/mutations/resolvers from both client and server * chore: bump dependencies * feat: setup prisma and configure it for tests and development * feat: create trpc router for auth service * refactor: migrate client auth queries to trpc procedures * refactor: cleanup now un-used graphql resolvers and services * feat: create sql migrations by replicating typeorm ones in an idempotent manner * feat: create server-preload script to run migrations upon server start * chore: remove legacy migrations steps * feat: add redis_host as an env variable * refactor: remove prisma from context and use client directly in service * feat: create trpc router & service for apps * refactor: migrate client app queries/mutations to trpc * refactor: removal and replace usage of old graphql generated types * refactor: move from node --require to custom next server * test: fix tests and bump various dependencies * chore: cleanup system-api from now un-used files * refactor(dashboard): remove code related to apollo * refactor: serve static files through next's server instead of system-api * refactor(server): move auth and system services to class * refactor(client): remove layoutv2 abstraction * fix: return correct update info * chore: remove legacy system-api folder * refactor: remove system-api from docker files * feat: create scheduler to run cron jobs and setup periodic repo update * fix: failing build caused by remark-mdx * refactor: move migrations to server folder * feat: compile server using esbuild * refactor: ts issue mis-used file from client in server * ci: make pipeline pass by cd into dashboard before each step (temp) * chore: drop armv7 support * refactor: move dashboard files in root folder * feat(db): create migration to add operator field on user * feat(user): create routes and services for password reset * feat(auth): add reset password page, container & form * refactor(dashboard): change layout and page of auth to be url based instead of state based * feat(script): add reset-password script * fix(dashboard): only check status if restart or update has been requested * test: increase coverage for get-server-auth-session * fix(start.sh): prompt for network interface only if there is not an internal ip set * feat(script): support user docker-compose.yml and app.env * chore: bump version * fix: add missing postgres variables to start script * fix: check for 32 bits before installing/starting * fix: create default media folder structure on install * Updated demo instance link Changed demo.runtipi.com to https://demo.runtipi.com * feat: adding config for codespaces * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com> Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com> Co-authored-by: Freddie Sackur <github@dustyfox.uk> Co-authored-by: Kieran Klukas <92754843+kcoderhtml@users.noreply.github.com> Co-authored-by: alwerner <alexander.werner@bonprix.net> Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-03-02 19:19:20 +00:00
${user_compose_args} \
2022-03-29 20:40:04 +00:00
"${@}"
}
function ensure_permissions() {
local app="${1}"
# if app_data_dir/data does not exist, create it
if [[ ! -d "${app_data_dir}/data" ]]; then
mkdir -p "${app_data_dir}/data"
fi
# Check if app requires special uid and gid
if [[ -f "${app_dir}/config.json" ]]; then
uid=$(get_json_field "${app_dir}/config.json" uid)
gid=$(get_json_field "${app_dir}/config.json" gid)
write_log "App requires uid=${uid} and gid=${gid}"
if [[ "$uid" != "null" ]] && [[ "$gid" != "null" ]]; then
write_log "Setting uid and gid to ${uid}:${gid}"
if ! chown -R "${uid}:${gid}" "${app_data_dir}/data"; then
write_log "Failed to set uid and gid to ${uid}:${gid}"
fi
fi
fi
# Remove all .gitkeep files from app data dir
find "${app_data_dir}" -name ".gitkeep" -exec rm -f {} \;
chmod -R a+rwx "${app_data_dir}"
}
function install_app() {
local app="${1}"
# Write to file script.log
write_log "Installing app ${app}..."
if ! compose "${app}" pull; then
write_log "Failed to pull app ${app}"
exit 1
fi
2022-04-07 08:34:18 +00:00
2022-04-13 21:47:07 +00:00
# Copy default data dir to app data dir if it exists
if [[ -d "${app_dir}/data" ]]; then
cp -r "${app_dir}/data" "${app_data_dir}/data"
2022-04-13 21:47:07 +00:00
fi
2022-04-13 18:34:24 +00:00
ensure_permissions "${app}"
if ! compose "${app}" up -d; then
write_log "Failed to start app ${app}"
exit 1
fi
exit 0
}
function start_app() {
local app="${1}"
write_log "Starting app ${app}..."
ensure_permissions "${app}"
2022-12-06 13:20:47 +00:00
# Pull images
if ! compose "${app}" pull; then
write_log "Failed to pull app ${app}"
fi
if ! compose "${app}" up --detach --force-recreate --remove-orphans; then
write_log "Failed to start app ${app}"
exit 1
fi
exit 0
}
function uninstall_app() {
local app="${1}"
2022-04-07 08:34:18 +00:00
write_log "Removing images for app ${app}..."
if ! compose "${app}" down --rmi all --remove-orphans; then
# just stop it if we can't remove the images
if ! compose "${app}" rm --force --stop; then
write_log "Failed to uninstall app ${app}"
exit 1
fi
fi
2022-03-29 20:40:04 +00:00
write_log "Deleting app data for app ${app}..."
2022-03-29 20:40:04 +00:00
if [[ -d "${app_data_dir}" ]]; then
rm -rf "${app_data_dir}"
2022-03-29 20:40:04 +00:00
fi
if [[ -d "${app_dir}" ]]; then
rm -rf "${app_dir}"
fi
write_log "Successfully uninstalled app ${app}"
2022-03-29 20:40:04 +00:00
exit
}
function update_app() {
local app="${1}"
2022-03-29 20:40:04 +00:00
if ! compose "${app}" up --detach --force-recreate --remove-orphans; then
write_log "Failed to update app ${app}"
fi
if ! compose "${app}" down --rmi all --remove-orphans; then
# just stop it if we can't remove the images
if ! compose "${app}" rm --force --stop; then
write_log "Failed to update app ${app}"
exit 1
fi
fi
# Remove app
if [[ -d "${app_dir}" ]]; then
rm -rf "${app_dir}"
fi
# Copy app from repo
cp -r "${ROOT_FOLDER}/repos/${REPO_ID}/apps/${app}" "${app_dir}"
ensure_permissions "${app}"
compose "${app}" pull
exit 0
}
function stop_app() {
local app="${1}"
write_log "Stopping app ${app}..."
if ! compose "${app}" rm --force --stop; then
write_log "Failed to stop app ${app}"
exit 1
fi
exit 0
}
# Install new app
if [[ "$command" = "install" ]]; then
install_app "${app}"
2022-03-29 20:40:04 +00:00
fi
# Removes images and destroys all data for an app
if [[ "$command" = "uninstall" ]]; then
uninstall_app "${app}"
2022-03-29 20:40:04 +00:00
fi
# Update an app
if [[ "$command" = "update" ]]; then
update_app "${app}"
fi
# Stops an installed app
if [[ "$command" = "stop" ]]; then
stop_app "${app}"
fi
# Starts an installed app
if [[ "$command" = "start" ]]; then
start_app "${app}"
2022-03-29 20:40:04 +00:00
fi
if [[ "$command" = "clean" ]]; then
# Remove all stopped containers and unused images
write_log "Cleaning up..."
docker system prune --all --force
exit 0
fi
2022-05-18 18:13:58 +00:00
exit 1