diff --git a/bitnami/appsmith/1/debian-11/Dockerfile b/bitnami/appsmith/1/debian-11/Dockerfile new file mode 100644 index 000000000000..448809ea778b --- /dev/null +++ b/bitnami/appsmith/1/debian-11/Dockerfile @@ -0,0 +1,60 @@ +FROM docker.io/bitnami/minideb:bullseye + +ARG TARGETARCH + +LABEL org.opencontainers.image.authors="https://bitnami.com/contact" \ + org.opencontainers.image.description="Application packaged by Bitnami" \ + org.opencontainers.image.ref.name="1.8.8-debian-11-r0" \ + org.opencontainers.image.source="https://github.com/bitnami/containers/tree/main/bitnami/appsmith" \ + org.opencontainers.image.title="appsmith" \ + org.opencontainers.image.vendor="VMware, Inc." \ + org.opencontainers.image.version="1.8.8" + +ENV HOME="/" \ + OS_ARCH="${TARGETARCH:-amd64}" \ + OS_FLAVOUR="debian-11" \ + OS_NAME="linux" + +COPY prebuildfs / +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +# Install required system packages and dependencies +RUN install_packages acl ca-certificates curl gettext libbz2-1.0 libcom-err2 libcrypt1 libffi7 libgcc-s1 libgeoip1 libgssapi-krb5-2 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 liblzma5 libncursesw6 libnsl2 libpcre3 libreadline8 libsqlite3-0 libssl1.1 libstdc++6 libtinfo6 libtirpc3 procps zlib1g +RUN mkdir -p /tmp/bitnami/pkg/cache/ && cd /tmp/bitnami/pkg/cache/ && \ + COMPONENTS=( \ + "python-3.8.15-2-linux-${OS_ARCH}-debian-11" \ + "wait-for-port-1.0.5-0-linux-${OS_ARCH}-debian-11" \ + "render-template-1.0.4-0-linux-${OS_ARCH}-debian-11" \ + "node-16.18.1-0-linux-${OS_ARCH}-debian-11" \ + "nginx-1.23.2-1-linux-${OS_ARCH}-debian-11" \ + "mongodb-shell-1.6.0-1-linux-${OS_ARCH}-debian-11" \ + "java-11.0.17-7-1-linux-${OS_ARCH}-debian-11" \ + "gosu-1.14.0-155-linux-${OS_ARCH}-debian-11" \ + "appsmith-1.8.8-0-linux-${OS_ARCH}-debian-11" \ + ) && \ + for COMPONENT in "${COMPONENTS[@]}"; do \ + if [ ! -f "${COMPONENT}.tar.gz" ]; then \ + curl -SsLf "https://downloads.bitnami.com/files/stacksmith/${COMPONENT}.tar.gz" -O ; \ + curl -SsLf "https://downloads.bitnami.com/files/stacksmith/${COMPONENT}.tar.gz.sha256" -O ; \ + fi && \ + sha256sum -c "${COMPONENT}.tar.gz.sha256" && \ + tar -zxf "${COMPONENT}.tar.gz" -C /opt/bitnami --strip-components=2 --no-same-owner --wildcards '*/files' && \ + rm -rf "${COMPONENT}".tar.gz{,.sha256} ; \ + done +RUN apt-get update && apt-get upgrade -y && \ + apt-get clean && rm -rf /var/lib/apt/lists /var/cache/apt/archives +RUN chmod g+rwX /opt/bitnami + +COPY rootfs / +RUN /opt/bitnami/scripts/appsmith/postunpack.sh +RUN /opt/bitnami/scripts/nginx/postunpack.sh +ENV APP_VERSION="1.8.8" \ + BITNAMI_APP_NAME="appsmith" \ + NGINX_HTTPS_PORT_NUMBER="" \ + NGINX_HTTP_PORT_NUMBER="" \ + PATH="/opt/bitnami/python/bin:/opt/bitnami/common/bin:/opt/bitnami/node/bin:/opt/bitnami/nginx/sbin:/opt/bitnami/mongodb/bin:/opt/bitnami/java/bin:$PATH" + +EXPOSE 3000 8080 8091 8443 + +USER 1001 +ENTRYPOINT [ "/opt/bitnami/scripts/appsmith/entrypoint.sh" ] +CMD [ "/opt/bitnami/scripts/appsmith/run.sh" ] diff --git a/bitnami/appsmith/1/debian-11/docker-compose.yml b/bitnami/appsmith/1/debian-11/docker-compose.yml new file mode 100644 index 000000000000..048ede7aad18 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/docker-compose.yml @@ -0,0 +1,80 @@ +version: '2' +services: + mongodb: + image: docker.io/bitnami/mongodb:6.0 + volumes: + - 'mongodb_data:/bitnami/mongodb' + environment: + - MONGODB_ADVERTISED_HOSTNAME=mongodb + - MONGODB_USERNAME=bn_appsmith + - MONGODB_DATABASE=bitnami_appsmith + - MONGODB_PASSWORD=bitnami123 + - MONGODB_ROOT_PASSWORD=password123 + - MONGODB_REPLICA_SET_MODE=primary + - MONGODB_REPLICA_SET_KEY=replicasetkey123 + + mongodb-secondary: + image: docker.io/bitnami/mongodb:6.0 + depends_on: + - mongodb + volumes: + - 'mongodb_secondary_data:/bitnami/mongodb' + environment: + - MONGODB_ADVERTISED_HOSTNAME=mongodb-secondary + - MONGODB_REPLICA_SET_MODE=secondary + - MONGODB_INITIAL_PRIMARY_HOST=mongodb + - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123 + - MONGODB_REPLICA_SET_KEY=replicasetkey123 + redis: + image: docker.io/bitnami/redis:7.0 + volumes: + - 'redis_data:/bitnami/redis' + environment: + - REDIS_PASSWORD=bitmame123 + appsmith: + image: docker.io/bitnami/appsmith:1 + environment: + - APPSMITH_MODE=client + - APPSMITH_API_HOST=appsmith-api + - APPSMITH_RTS_HOST=appsmith-rts + ports: + - 80:8080 + appsmith-api: + image: docker.io/bitnami/appsmith:1 + environment: + - APPSMITH_MODE=backend + - BITNAMI_DEBUG=true + - APPSMITH_API_HOST=appsmith-api + - APPSMITH_DATABASE_HOST=mongodb,mongodb-secondary + - APPSMITH_DATABASE_PORT_NUMBER=27017 + - APPSMITH_DATABASE_USER=bn_appsmith + - APPSMITH_DATABASE_NAME=bitnami_appsmith + - APPSMITH_DATABASE_PASSWORD=bitnami123 + - APPSMITH_REDIS_PASSWORD=bitmame123 + - APPSMITH_ENCRYPTION_PASSWORD=test123 + - APPSMITH_ENCRYPTION_SALT=testsalt123 + # Hack: This is only necessary in docker-compose + - APPSMITH_DATABASE_INIT_DELAY=90 + volumes: + - 'appsmith_backend_data:/bitnami/appsmith' + appsmith-rts: + image: docker.io/bitnami/appsmith:1 + environment: + - APPSMITH_MODE=rts + - APPSMITH_API_HOST=appsmith-api + - APPSMITH_DATABASE_HOST=mongodb,mongodb-secondary + - APPSMITH_DATABASE_PORT_NUMBER=27017 + - APPSMITH_DATABASE_USER=bn_appsmith + - APPSMITH_DATABASE_NAME=bitnami_appsmith + - APPSMITH_DATABASE_PASSWORD=bitnami123 + # Hack: This is only necessary in docker-compose + - APPSMITH_DATABASE_INIT_DELAY=60 +volumes: + mongodb_data: + driver: local + mongodb_secondary_data: + driver: local + redis_data: + driver: local + appsmith_backend_data: + driver: local diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/.bitnami_components.json b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/.bitnami_components.json new file mode 100644 index 000000000000..d66abeb9c0bb --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/.bitnami_components.json @@ -0,0 +1,65 @@ +{ + "appsmith": { + "arch": "amd64", + "digest": "3f0a20327a1b57ca924434a3113434133de989ba74dee60de2b377e44daa5e03", + "distro": "debian-11", + "type": "NAMI", + "version": "1.8.8-0" + }, + "gosu": { + "arch": "amd64", + "digest": "f21869b27c26b9c3053bce8b419a0fdf1dc45fcf13a7c2058e0afb6996d3687f", + "distro": "debian-11", + "type": "NAMI", + "version": "1.14.0-155" + }, + "java": { + "arch": "amd64", + "digest": "972009952c7ab083836ce1943c7768daac74ec3cbea63eb5994b38e7c9794b75", + "distro": "debian-11", + "type": "NAMI", + "version": "11.0.17-7-1" + }, + "mongodb-shell": { + "arch": "amd64", + "digest": "62f93a1f29257014cb2ce2183e7ee9fcf926321f5fb592a7e1033107230e1baf", + "distro": "debian-11", + "type": "NAMI", + "version": "1.6.0-1" + }, + "nginx": { + "arch": "amd64", + "digest": "8643036fdd3909a1f96fc8d2d09fa936c5c77cdb0ff424223f856b7a75c5e924", + "distro": "debian-11", + "type": "NAMI", + "version": "1.23.2-1" + }, + "node": { + "arch": "amd64", + "digest": "4116530a13d5a1d33cdde22778351bd5becc8f2344daa37a4c5a0c9659619e24", + "distro": "debian-11", + "type": "NAMI", + "version": "16.18.1-0" + }, + "python": { + "arch": "amd64", + "digest": "12887092173822ca8be66e0431a14fadb8bec7e01b97b666e0a04da57b99eb69", + "distro": "debian-11", + "type": "NAMI", + "version": "3.8.15-2" + }, + "render-template": { + "arch": "amd64", + "digest": "f0e1eb23624312a8ee0c4e5bab439960831424ecd76c88bdc24141a338406f05", + "distro": "debian-11", + "type": "NAMI", + "version": "1.0.4-0" + }, + "wait-for-port": { + "arch": "amd64", + "digest": "e72ab0985310f6108f77bc573939cf6b4b27867d6a61cb914d3cfedac60d306c", + "distro": "debian-11", + "type": "NAMI", + "version": "1.0.5-0" + } +} \ No newline at end of file diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/licenses/licenses.txt b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/licenses/licenses.txt new file mode 100644 index 000000000000..c76ba31f3b8a --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/licenses/licenses.txt @@ -0,0 +1,3 @@ +Bitnami containers ship with software bundles. You can find the licenses under: +/opt/bitnami/nami/COPYING +/opt/bitnami/[name-of-bundle]/licenses/[bundle-version].txt diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libbitnami.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libbitnami.sh new file mode 100644 index 000000000000..4242023f9415 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libbitnami.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Bitnami custom library + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/liblog.sh + +# Constants +BOLD='\033[1m' + +# Functions + +######################## +# Print the welcome page +# Globals: +# DISABLE_WELCOME_MESSAGE +# BITNAMI_APP_NAME +# Arguments: +# None +# Returns: +# None +######################### +print_welcome_page() { + if [[ -z "${DISABLE_WELCOME_MESSAGE:-}" ]]; then + if [[ -n "$BITNAMI_APP_NAME" ]]; then + print_image_welcome_page + fi + fi +} + +######################## +# Print the welcome page for a Bitnami Docker image +# Globals: +# BITNAMI_APP_NAME +# Arguments: +# None +# Returns: +# None +######################### +print_image_welcome_page() { + local github_url="https://github.com/bitnami/containers" + + log "" + log "${BOLD}Welcome to the Bitnami ${BITNAMI_APP_NAME} container${RESET}" + log "Subscribe to project updates by watching ${BOLD}${github_url}${RESET}" + log "Submit issues and feature requests at ${BOLD}${github_url}/issues${RESET}" + log "" +} + diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libfile.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libfile.sh new file mode 100644 index 000000000000..41ebaf7464f6 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libfile.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# +# Library for managing files + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/libos.sh + +# Functions + +######################## +# Replace a regex-matching string in a file +# Arguments: +# $1 - filename +# $2 - match regex +# $3 - substitute regex +# $4 - use POSIX regex. Default: true +# Returns: +# None +######################### +replace_in_file() { + local filename="${1:?filename is required}" + local match_regex="${2:?match regex is required}" + local substitute_regex="${3:?substitute regex is required}" + local posix_regex=${4:-true} + + local result + + # We should avoid using 'sed in-place' substitutions + # 1) They are not compatible with files mounted from ConfigMap(s) + # 2) We found incompatibility issues with Debian10 and "in-place" substitutions + local -r del=$'\001' # Use a non-printable character as a 'sed' delimiter to avoid issues + if [[ $posix_regex = true ]]; then + result="$(sed -E "s${del}${match_regex}${del}${substitute_regex}${del}g" "$filename")" + else + result="$(sed "s${del}${match_regex}${del}${substitute_regex}${del}g" "$filename")" + fi + echo "$result" > "$filename" +} + +######################## +# Replace a regex-matching multiline string in a file +# Arguments: +# $1 - filename +# $2 - match regex +# $3 - substitute regex +# Returns: +# None +######################### +replace_in_file_multiline() { + local filename="${1:?filename is required}" + local match_regex="${2:?match regex is required}" + local substitute_regex="${3:?substitute regex is required}" + + local result + local -r del=$'\001' # Use a non-printable character as a 'sed' delimiter to avoid issues + result="$(perl -pe "BEGIN{undef $/;} s${del}${match_regex}${del}${substitute_regex}${del}sg" "$filename")" + echo "$result" > "$filename" +} + +######################## +# Remove a line in a file based on a regex +# Arguments: +# $1 - filename +# $2 - match regex +# $3 - use POSIX regex. Default: true +# Returns: +# None +######################### +remove_in_file() { + local filename="${1:?filename is required}" + local match_regex="${2:?match regex is required}" + local posix_regex=${3:-true} + local result + + # We should avoid using 'sed in-place' substitutions + # 1) They are not compatible with files mounted from ConfigMap(s) + # 2) We found incompatibility issues with Debian10 and "in-place" substitutions + if [[ $posix_regex = true ]]; then + result="$(sed -E "/$match_regex/d" "$filename")" + else + result="$(sed "/$match_regex/d" "$filename")" + fi + echo "$result" > "$filename" +} + +######################## +# Appends text after the last line matching a pattern +# Arguments: +# $1 - file +# $2 - match regex +# $3 - contents to add +# Returns: +# None +######################### +append_file_after_last_match() { + local file="${1:?missing file}" + local match_regex="${2:?missing pattern}" + local value="${3:?missing value}" + + # We read the file in reverse, replace the first match (0,/pattern/s) and then reverse the results again + result="$(tac "$file" | sed -E "0,/($match_regex)/s||${value}\n\1|" | tac)" + echo "$result" > "$file" +} + +######################## +# Wait until certain entry is present in a log file +# Arguments: +# $1 - entry to look for +# $2 - log file +# $3 - max retries. Default: 12 +# $4 - sleep between retries (in seconds). Default: 5 +# Returns: +# Boolean +######################### +wait_for_log_entry() { + local -r entry="${1:-missing entry}" + local -r log_file="${2:-missing log file}" + local -r retries="${3:-12}" + local -r interval_time="${4:-5}" + local attempt=0 + + check_log_file_for_entry() { + if ! grep -qE "$entry" "$log_file"; then + debug "Entry \"${entry}\" still not present in ${log_file} (attempt $((++attempt))/${retries})" + return 1 + fi + } + debug "Checking that ${log_file} log file contains entry \"${entry}\"" + if retry_while check_log_file_for_entry "$retries" "$interval_time"; then + debug "Found entry \"${entry}\" in ${log_file}" + true + else + error "Could not find entry \"${entry}\" in ${log_file} after ${retries} retries" + debug_execute cat "$log_file" + return 1 + fi +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libfs.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libfs.sh new file mode 100644 index 000000000000..801b9412bd99 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libfs.sh @@ -0,0 +1,191 @@ +#!/bin/bash +# +# Library for file system actions + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/liblog.sh + +# Functions + +######################## +# Ensure a file/directory is owned (user and group) but the given user +# Arguments: +# $1 - filepath +# $2 - owner +# Returns: +# None +######################### +owned_by() { + local path="${1:?path is missing}" + local owner="${2:?owner is missing}" + local group="${3:-}" + + if [[ -n $group ]]; then + chown "$owner":"$group" "$path" + else + chown "$owner":"$owner" "$path" + fi +} + +######################## +# Ensure a directory exists and, optionally, is owned by the given user +# Arguments: +# $1 - directory +# $2 - owner +# Returns: +# None +######################### +ensure_dir_exists() { + local dir="${1:?directory is missing}" + local owner_user="${2:-}" + local owner_group="${3:-}" + + mkdir -p "${dir}" + if [[ -n $owner_user ]]; then + owned_by "$dir" "$owner_user" "$owner_group" + fi +} + +######################## +# Checks whether a directory is empty or not +# arguments: +# $1 - directory +# returns: +# boolean +######################### +is_dir_empty() { + local -r path="${1:?missing directory}" + # Calculate real path in order to avoid issues with symlinks + local -r dir="$(realpath "$path")" + if [[ ! -e "$dir" ]] || [[ -z "$(ls -A "$dir")" ]]; then + true + else + false + fi +} + +######################## +# Checks whether a mounted directory is empty or not +# arguments: +# $1 - directory +# returns: +# boolean +######################### +is_mounted_dir_empty() { + local dir="${1:?missing directory}" + + if is_dir_empty "$dir" || find "$dir" -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" -exec false {} +; then + true + else + false + fi +} + +######################## +# Checks whether a file can be written to or not +# arguments: +# $1 - file +# returns: +# boolean +######################### +is_file_writable() { + local file="${1:?missing file}" + local dir + dir="$(dirname "$file")" + + if [[ (-f "$file" && -w "$file") || (! -f "$file" && -d "$dir" && -w "$dir") ]]; then + true + else + false + fi +} + +######################## +# Relativize a path +# arguments: +# $1 - path +# $2 - base +# returns: +# None +######################### +relativize() { + local -r path="${1:?missing path}" + local -r base="${2:?missing base}" + pushd "$base" >/dev/null || exit + realpath -q --no-symlinks --relative-base="$base" "$path" | sed -e 's|^/$|.|' -e 's|^/||' + popd >/dev/null || exit +} + +######################## +# Configure permisions and ownership recursively +# Globals: +# None +# Arguments: +# $1 - paths (as a string). +# Flags: +# -f|--file-mode - mode for directories. +# -d|--dir-mode - mode for files. +# -u|--user - user +# -g|--group - group +# Returns: +# None +######################### +configure_permissions_ownership() { + local -r paths="${1:?paths is missing}" + local dir_mode="" + local file_mode="" + local user="" + local group="" + + # Validate arguments + shift 1 + while [ "$#" -gt 0 ]; do + case "$1" in + -f | --file-mode) + shift + file_mode="${1:?missing mode for files}" + ;; + -d | --dir-mode) + shift + dir_mode="${1:?missing mode for directories}" + ;; + -u | --user) + shift + user="${1:?missing user}" + ;; + -g | --group) + shift + group="${1:?missing group}" + ;; + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + + read -r -a filepaths <<<"$paths" + for p in "${filepaths[@]}"; do + if [[ -e "$p" ]]; then + find -L "$p" -printf "" + if [[ -n $dir_mode ]]; then + find -L "$p" -type d ! -perm "$dir_mode" -print0 | xargs -r -0 chmod "$dir_mode" + fi + if [[ -n $file_mode ]]; then + find -L "$p" -type f ! -perm "$file_mode" -print0 | xargs -r -0 chmod "$file_mode" + fi + if [[ -n $user ]] && [[ -n $group ]]; then + find -L "$p" -print0 | xargs -r -0 chown "${user}:${group}" + elif [[ -n $user ]] && [[ -z $group ]]; then + find -L "$p" -print0 | xargs -r -0 chown "${user}" + elif [[ -z $user ]] && [[ -n $group ]]; then + find -L "$p" -print0 | xargs -r -0 chgrp "${group}" + fi + else + stderr_print "$p does not exist" + fi + done +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libhook.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libhook.sh new file mode 100644 index 000000000000..9694852a7d25 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libhook.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# Library to use for scripts expected to be used as Kubernetes lifecycle hooks + +# shellcheck disable=SC1091 + +# Load generic libraries +. /opt/bitnami/scripts/liblog.sh +. /opt/bitnami/scripts/libos.sh + +# Override functions that log to stdout/stderr of the current process, so they print to process 1 +for function_to_override in stderr_print debug_execute; do + # Output is sent to output of process 1 and thus end up in the container log + # The hook output in general isn't saved + eval "$(declare -f "$function_to_override") >/proc/1/fd/1 2>/proc/1/fd/2" +done diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/liblog.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/liblog.sh new file mode 100644 index 000000000000..c7c0f6d4422a --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/liblog.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# +# Library for logging functions + +# Constants +RESET='\033[0m' +RED='\033[38;5;1m' +GREEN='\033[38;5;2m' +YELLOW='\033[38;5;3m' +MAGENTA='\033[38;5;5m' +CYAN='\033[38;5;6m' + +# Functions + +######################## +# Print to STDERR +# Arguments: +# Message to print +# Returns: +# None +######################### +stderr_print() { + # 'is_boolean_yes' is defined in libvalidations.sh, but depends on this file so we cannot source it + local bool="${BITNAMI_QUIET:-false}" + # comparison is performed without regard to the case of alphabetic characters + shopt -s nocasematch + if ! [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then + printf "%b\\n" "${*}" >&2 + fi +} + +######################## +# Log message +# Arguments: +# Message to log +# Returns: +# None +######################### +log() { + stderr_print "${CYAN}${MODULE:-} ${MAGENTA}$(date "+%T.%2N ")${RESET}${*}" +} +######################## +# Log an 'info' message +# Arguments: +# Message to log +# Returns: +# None +######################### +info() { + log "${GREEN}INFO ${RESET} ==> ${*}" +} +######################## +# Log message +# Arguments: +# Message to log +# Returns: +# None +######################### +warn() { + log "${YELLOW}WARN ${RESET} ==> ${*}" +} +######################## +# Log an 'error' message +# Arguments: +# Message to log +# Returns: +# None +######################### +error() { + log "${RED}ERROR${RESET} ==> ${*}" +} +######################## +# Log a 'debug' message +# Globals: +# BITNAMI_DEBUG +# Arguments: +# None +# Returns: +# None +######################### +debug() { + # 'is_boolean_yes' is defined in libvalidations.sh, but depends on this file so we cannot source it + local bool="${BITNAMI_DEBUG:-false}" + # comparison is performed without regard to the case of alphabetic characters + shopt -s nocasematch + if [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then + log "${MAGENTA}DEBUG${RESET} ==> ${*}" + fi +} + +######################## +# Indent a string +# Arguments: +# $1 - string +# $2 - number of indentation characters (default: 4) +# $3 - indentation character (default: " ") +# Returns: +# None +######################### +indent() { + local string="${1:-}" + local num="${2:?missing num}" + local char="${3:-" "}" + # Build the indentation unit string + local indent_unit="" + for ((i = 0; i < num; i++)); do + indent_unit="${indent_unit}${char}" + done + # shellcheck disable=SC2001 + # Complex regex, see https://github.com/koalaman/shellcheck/wiki/SC2001#exceptions + echo "$string" | sed "s/^/${indent_unit}/" +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libnet.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libnet.sh new file mode 100644 index 000000000000..8bbf165e3e2a --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libnet.sh @@ -0,0 +1,163 @@ +#!/bin/bash +# +# Library for network functions + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/liblog.sh + +# Functions + +######################## +# Resolve IP address for a host/domain (i.e. DNS lookup) +# Arguments: +# $1 - Hostname to resolve +# $2 - IP address version (v4, v6), leave empty for resolving to any version +# Returns: +# IP +######################### +dns_lookup() { + local host="${1:?host is missing}" + local ip_version="${2:-}" + getent "ahosts${ip_version}" "$host" | awk '/STREAM/ {print $1 }' | head -n 1 +} + +######################### +# Wait for a hostname and return the IP +# Arguments: +# $1 - hostname +# $2 - number of retries +# $3 - seconds to wait between retries +# Returns: +# - IP address that corresponds to the hostname +######################### +wait_for_dns_lookup() { + local hostname="${1:?hostname is missing}" + local retries="${2:-5}" + local seconds="${3:-1}" + check_host() { + if [[ $(dns_lookup "$hostname") == "" ]]; then + false + else + true + fi + } + # Wait for the host to be ready + retry_while "check_host ${hostname}" "$retries" "$seconds" + dns_lookup "$hostname" +} + +######################## +# Get machine's IP +# Arguments: +# None +# Returns: +# Machine IP +######################### +get_machine_ip() { + local -a ip_addresses + local hostname + hostname="$(hostname)" + read -r -a ip_addresses <<< "$(dns_lookup "$hostname" | xargs echo)" + if [[ "${#ip_addresses[@]}" -gt 1 ]]; then + warn "Found more than one IP address associated to hostname ${hostname}: ${ip_addresses[*]}, will use ${ip_addresses[0]}" + elif [[ "${#ip_addresses[@]}" -lt 1 ]]; then + error "Could not find any IP address associated to hostname ${hostname}" + exit 1 + fi + echo "${ip_addresses[0]}" +} + +######################## +# Check if the provided argument is a resolved hostname +# Arguments: +# $1 - Value to check +# Returns: +# Boolean +######################### +is_hostname_resolved() { + local -r host="${1:?missing value}" + if [[ -n "$(dns_lookup "$host")" ]]; then + true + else + false + fi +} + +######################## +# Parse URL +# Globals: +# None +# Arguments: +# $1 - uri - String +# $2 - component to obtain. Valid options (scheme, authority, userinfo, host, port, path, query or fragment) - String +# Returns: +# String +parse_uri() { + local uri="${1:?uri is missing}" + local component="${2:?component is missing}" + + # Solution based on https://tools.ietf.org/html/rfc3986#appendix-B with + # additional sub-expressions to split authority into userinfo, host and port + # Credits to Patryk Obara (see https://stackoverflow.com/a/45977232/6694969) + local -r URI_REGEX='^(([^:/?#]+):)?(//((([^@/?#]+)@)?([^:/?#]+)(:([0-9]+))?))?(/([^?#]*))?(\?([^#]*))?(#(.*))?' + # || | ||| | | | | | | | | | + # |2 scheme | ||6 userinfo 7 host | 9 port | 11 rpath | 13 query | 15 fragment + # 1 scheme: | |5 userinfo@ 8 :... 10 path 12 ?... 14 #... + # | 4 authority + # 3 //... + local index=0 + case "$component" in + scheme) + index=2 + ;; + authority) + index=4 + ;; + userinfo) + index=6 + ;; + host) + index=7 + ;; + port) + index=9 + ;; + path) + index=10 + ;; + query) + index=13 + ;; + fragment) + index=14 + ;; + *) + stderr_print "unrecognized component $component" + return 1 + ;; + esac + [[ "$uri" =~ $URI_REGEX ]] && echo "${BASH_REMATCH[${index}]}" +} + +######################## +# Wait for a HTTP connection to succeed +# Globals: +# * +# Arguments: +# $1 - URL to wait for +# $2 - Maximum amount of retries (optional) +# $3 - Time between retries (optional) +# Returns: +# true if the HTTP connection succeeded, false otherwise +######################### +wait_for_http_connection() { + local url="${1:?missing url}" + local retries="${2:-}" + local sleep_time="${3:-}" + if ! retry_while "debug_execute curl --silent ${url}" "$retries" "$sleep_time"; then + error "Could not connect to ${url}" + return 1 + fi +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libos.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libos.sh new file mode 100644 index 000000000000..5e141d4ce3f1 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libos.sh @@ -0,0 +1,555 @@ +#!/bin/bash +# +# Library for operating system actions + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/liblog.sh +. /opt/bitnami/scripts/libfs.sh +. /opt/bitnami/scripts/libvalidations.sh + +# Functions + +######################## +# Check if an user exists in the system +# Arguments: +# $1 - user +# Returns: +# Boolean +######################### +user_exists() { + local user="${1:?user is missing}" + id "$user" >/dev/null 2>&1 +} + +######################## +# Check if a group exists in the system +# Arguments: +# $1 - group +# Returns: +# Boolean +######################### +group_exists() { + local group="${1:?group is missing}" + getent group "$group" >/dev/null 2>&1 +} + +######################## +# Create a group in the system if it does not exist already +# Arguments: +# $1 - group +# Flags: +# -i|--gid - the ID for the new group +# -s|--system - Whether to create new user as system user (uid <= 999) +# Returns: +# None +######################### +ensure_group_exists() { + local group="${1:?group is missing}" + local gid="" + local is_system_user=false + + # Validate arguments + shift 1 + while [ "$#" -gt 0 ]; do + case "$1" in + -i | --gid) + shift + gid="${1:?missing gid}" + ;; + -s | --system) + is_system_user=true + ;; + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + + if ! group_exists "$group"; then + local -a args=("$group") + if [[ -n "$gid" ]]; then + if group_exists "$gid"; then + error "The GID $gid is already in use." >&2 + return 1 + fi + args+=("--gid" "$gid") + fi + $is_system_user && args+=("--system") + groupadd "${args[@]}" >/dev/null 2>&1 + fi +} + +######################## +# Create an user in the system if it does not exist already +# Arguments: +# $1 - user +# Flags: +# -i|--uid - the ID for the new user +# -g|--group - the group the new user should belong to +# -a|--append-groups - comma-separated list of supplemental groups to append to the new user +# -h|--home - the home directory for the new user +# -s|--system - whether to create new user as system user (uid <= 999) +# Returns: +# None +######################### +ensure_user_exists() { + local user="${1:?user is missing}" + local uid="" + local group="" + local append_groups="" + local home="" + local is_system_user=false + + # Validate arguments + shift 1 + while [ "$#" -gt 0 ]; do + case "$1" in + -i | --uid) + shift + uid="${1:?missing uid}" + ;; + -g | --group) + shift + group="${1:?missing group}" + ;; + -a | --append-groups) + shift + append_groups="${1:?missing append_groups}" + ;; + -h | --home) + shift + home="${1:?missing home directory}" + ;; + -s | --system) + is_system_user=true + ;; + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + + if ! user_exists "$user"; then + local -a user_args=("-N" "$user") + if [[ -n "$uid" ]]; then + if user_exists "$uid"; then + error "The UID $uid is already in use." + return 1 + fi + user_args+=("--uid" "$uid") + else + $is_system_user && user_args+=("--system") + fi + useradd "${user_args[@]}" >/dev/null 2>&1 + fi + + if [[ -n "$group" ]]; then + local -a group_args=("$group") + $is_system_user && group_args+=("--system") + ensure_group_exists "${group_args[@]}" + usermod -g "$group" "$user" >/dev/null 2>&1 + fi + + if [[ -n "$append_groups" ]]; then + local -a groups + read -ra groups <<<"$(tr ',;' ' ' <<<"$append_groups")" + for group in "${groups[@]}"; do + ensure_group_exists "$group" + usermod -aG "$group" "$user" >/dev/null 2>&1 + done + fi + + if [[ -n "$home" ]]; then + mkdir -p "$home" + usermod -d "$home" "$user" >/dev/null 2>&1 + configure_permissions_ownership "$home" -d "775" -f "664" -u "$user" -g "$group" + fi +} + +######################## +# Check if the script is currently running as root +# Arguments: +# $1 - user +# $2 - group +# Returns: +# Boolean +######################### +am_i_root() { + if [[ "$(id -u)" = "0" ]]; then + true + else + false + fi +} + +######################## +# Print OS metadata +# Arguments: +# $1 - Flag name +# Flags: +# --id - Distro ID +# --version - Distro version +# --branch - Distro branch +# --codename - Distro codename +# --name - Distro name +# --pretty-name - Distro pretty name +# Returns: +# String +######################### +get_os_metadata() { + local -r flag_name="${1:?missing flag}" + # Helper function + get_os_release_metadata() { + local -r env_name="${1:?missing environment variable name}" + ( + . /etc/os-release + echo "${!env_name}" + ) + } + case "$flag_name" in + --id) + get_os_release_metadata ID + ;; + --version) + get_os_release_metadata VERSION_ID + ;; + --branch) + get_os_release_metadata VERSION_ID | sed 's/\..*//' + ;; + --codename) + get_os_release_metadata VERSION_CODENAME + ;; + --name) + get_os_release_metadata NAME + ;; + --pretty-name) + get_os_release_metadata PRETTY_NAME + ;; + *) + error "Unknown flag ${flag_name}" + return 1 + ;; + esac +} + +######################## +# Get total memory available +# Arguments: +# None +# Returns: +# Memory in bytes +######################### +get_total_memory() { + echo $(($(grep MemTotal /proc/meminfo | awk '{print $2}') / 1024)) +} + +######################## +# Get machine size depending on specified memory +# Globals: +# None +# Arguments: +# None +# Flags: +# --memory - memory size (optional) +# Returns: +# Detected instance size +######################### +get_machine_size() { + local memory="" + # Validate arguments + while [[ "$#" -gt 0 ]]; do + case "$1" in + --memory) + shift + memory="${1:?missing memory}" + ;; + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + if [[ -z "$memory" ]]; then + debug "Memory was not specified, detecting available memory automatically" + memory="$(get_total_memory)" + fi + sanitized_memory=$(convert_to_mb "$memory") + if [[ "$sanitized_memory" -gt 26000 ]]; then + echo 2xlarge + elif [[ "$sanitized_memory" -gt 13000 ]]; then + echo xlarge + elif [[ "$sanitized_memory" -gt 6000 ]]; then + echo large + elif [[ "$sanitized_memory" -gt 3000 ]]; then + echo medium + elif [[ "$sanitized_memory" -gt 1500 ]]; then + echo small + else + echo micro + fi +} + +######################## +# Get machine size depending on specified memory +# Globals: +# None +# Arguments: +# $1 - memory size (optional) +# Returns: +# Detected instance size +######################### +get_supported_machine_sizes() { + echo micro small medium large xlarge 2xlarge +} + +######################## +# Convert memory size from string to amount of megabytes (i.e. 2G -> 2048) +# Globals: +# None +# Arguments: +# $1 - memory size +# Returns: +# Result of the conversion +######################### +convert_to_mb() { + local amount="${1:-}" + if [[ $amount =~ ^([0-9]+)(m|M|g|G) ]]; then + size="${BASH_REMATCH[1]}" + unit="${BASH_REMATCH[2]}" + if [[ "$unit" = "g" || "$unit" = "G" ]]; then + amount="$((size * 1024))" + else + amount="$size" + fi + fi + echo "$amount" +} + +######################### +# Redirects output to /dev/null if debug mode is disabled +# Globals: +# BITNAMI_DEBUG +# Arguments: +# $@ - Command to execute +# Returns: +# None +######################### +debug_execute() { + if is_boolean_yes "${BITNAMI_DEBUG:-false}"; then + "$@" + else + "$@" >/dev/null 2>&1 + fi +} + +######################## +# Retries a command a given number of times +# Arguments: +# $1 - cmd (as a string) +# $2 - max retries. Default: 12 +# $3 - sleep between retries (in seconds). Default: 5 +# Returns: +# Boolean +######################### +retry_while() { + local cmd="${1:?cmd is missing}" + local retries="${2:-12}" + local sleep_time="${3:-5}" + local return_value=1 + + read -r -a command <<<"$cmd" + for ((i = 1; i <= retries; i += 1)); do + "${command[@]}" && return_value=0 && break + sleep "$sleep_time" + done + return $return_value +} + +######################## +# Generate a random string +# Arguments: +# -t|--type - String type (ascii, alphanumeric, numeric), defaults to ascii +# -c|--count - Number of characters, defaults to 32 +# Arguments: +# None +# Returns: +# None +# Returns: +# String +######################### +generate_random_string() { + local type="ascii" + local count="32" + local filter + local result + # Validate arguments + while [[ "$#" -gt 0 ]]; do + case "$1" in + -t | --type) + shift + type="$1" + ;; + -c | --count) + shift + count="$1" + ;; + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + # Validate type + case "$type" in + ascii) + filter="[:print:]" + ;; + alphanumeric) + filter="a-zA-Z0-9" + ;; + numeric) + filter="0-9" + ;; + *) + echo "Invalid type ${type}" >&2 + return 1 + ;; + esac + # Obtain count + 10 lines from /dev/urandom to ensure that the resulting string has the expected size + # Note there is a very small chance of strings starting with EOL character + # Therefore, the higher amount of lines read, this will happen less frequently + result="$(head -n "$((count + 10))" /dev/urandom | tr -dc "$filter" | head -c "$count")" + echo "$result" +} + +######################## +# Create md5 hash from a string +# Arguments: +# $1 - string +# Returns: +# md5 hash - string +######################### +generate_md5_hash() { + local -r str="${1:?missing input string}" + echo -n "$str" | md5sum | awk '{print $1}' +} + +######################## +# Create sha1 hash from a string +# Arguments: +# $1 - string +# $2 - algorithm - 1 (default), 224, 256, 384, 512 +# Returns: +# sha1 hash - string +######################### +generate_sha_hash() { + local -r str="${1:?missing input string}" + local -r algorithm="${2:-1}" + echo -n "$str" | "sha${algorithm}sum" | awk '{print $1}' +} + +######################## +# Converts a string to its hexadecimal representation +# Arguments: +# $1 - string +# Returns: +# hexadecimal representation of the string +######################### +convert_to_hex() { + local -r str=${1:?missing input string} + local -i iterator + local char + for ((iterator = 0; iterator < ${#str}; iterator++)); do + char=${str:iterator:1} + printf '%x' "'${char}" + done +} + +######################## +# Get boot time +# Globals: +# None +# Arguments: +# None +# Returns: +# Boot time metadata +######################### +get_boot_time() { + stat /proc --format=%Y +} + +######################## +# Get machine ID +# Globals: +# None +# Arguments: +# None +# Returns: +# Machine ID +######################### +get_machine_id() { + local machine_id + if [[ -f /etc/machine-id ]]; then + machine_id="$(cat /etc/machine-id)" + fi + if [[ -z "$machine_id" ]]; then + # Fallback to the boot-time, which will at least ensure a unique ID in the current session + machine_id="$(get_boot_time)" + fi + echo "$machine_id" +} + +######################## +# Get the root partition's disk device ID (e.g. /dev/sda1) +# Globals: +# None +# Arguments: +# None +# Returns: +# Root partition disk ID +######################### +get_disk_device_id() { + local device_id="" + if grep -q ^/dev /proc/mounts; then + device_id="$(grep ^/dev /proc/mounts | awk '$2 == "/" { print $1 }' | tail -1)" + fi + # If it could not be autodetected, fallback to /dev/sda1 as a default + if [[ -z "$device_id" || ! -b "$device_id" ]]; then + device_id="/dev/sda1" + fi + echo "$device_id" +} + +######################## +# Get the root disk device ID (e.g. /dev/sda) +# Globals: +# None +# Arguments: +# None +# Returns: +# Root disk ID +######################### +get_root_disk_device_id() { + get_disk_device_id | sed -E 's/p?[0-9]+$//' +} + +######################## +# Get the root disk size in bytes +# Globals: +# None +# Arguments: +# None +# Returns: +# Root disk size in bytes +######################### +get_root_disk_size() { + fdisk -l "$(get_root_disk_device_id)" | grep 'Disk.*bytes' | sed -E 's/.*, ([0-9]+) bytes,.*/\1/' || true +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libpersistence.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libpersistence.sh new file mode 100644 index 000000000000..99df69681c27 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libpersistence.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# +# Bitnami persistence library +# Used for bringing persistence capabilities to applications that don't have clear separation of data and logic + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/libfs.sh +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/liblog.sh +. /opt/bitnami/scripts/libversion.sh + +# Functions + +######################## +# Persist an application directory +# Globals: +# BITNAMI_ROOT_DIR +# BITNAMI_VOLUME_DIR +# Arguments: +# $1 - App folder name +# $2 - List of app files to persist +# Returns: +# true if all steps succeeded, false otherwise +######################### +persist_app() { + local -r app="${1:?missing app}" + local -a files_to_restore + read -r -a files_to_persist <<< "$(tr ',;:' ' ' <<< "$2")" + local -r install_dir="${BITNAMI_ROOT_DIR}/${app}" + local -r persist_dir="${BITNAMI_VOLUME_DIR}/${app}" + # Persist the individual files + if [[ "${#files_to_persist[@]}" -le 0 ]]; then + warn "No files are configured to be persisted" + return + fi + pushd "$install_dir" >/dev/null || exit + local file_to_persist_relative file_to_persist_destination file_to_persist_destination_folder + local -r tmp_file="/tmp/perms.acl" + for file_to_persist in "${files_to_persist[@]}"; do + if [[ ! -f "$file_to_persist" && ! -d "$file_to_persist" ]]; then + error "Cannot persist '${file_to_persist}' because it does not exist" + return 1 + fi + file_to_persist_relative="$(relativize "$file_to_persist" "$install_dir")" + file_to_persist_destination="${persist_dir}/${file_to_persist_relative}" + file_to_persist_destination_folder="$(dirname "$file_to_persist_destination")" + # Get original permissions for existing files, which will be applied later + # Exclude the root directory with 'sed', to avoid issues when copying the entirety of it to a volume + getfacl -R "$file_to_persist_relative" | sed -E '/# file: (\..+|[^.])/,$!d' > "$tmp_file" + # Copy directories to the volume + ensure_dir_exists "$file_to_persist_destination_folder" + cp -Lr --preserve=links "$file_to_persist_relative" "$file_to_persist_destination_folder" + # Restore permissions + pushd "$persist_dir" >/dev/null || exit + if am_i_root; then + setfacl --restore="$tmp_file" + else + # When running as non-root, don't change ownership + setfacl --restore=<(grep -E -v '^# (owner|group):' "$tmp_file") + fi + popd >/dev/null || exit + done + popd >/dev/null || exit + rm -f "$tmp_file" + # Install the persisted files into the installation directory, via symlinks + restore_persisted_app "$@" +} + +######################## +# Restore a persisted application directory +# Globals: +# BITNAMI_ROOT_DIR +# BITNAMI_VOLUME_DIR +# FORCE_MAJOR_UPGRADE +# Arguments: +# $1 - App folder name +# $2 - List of app files to restore +# Returns: +# true if all steps succeeded, false otherwise +######################### +restore_persisted_app() { + local -r app="${1:?missing app}" + local -a files_to_restore + read -r -a files_to_restore <<< "$(tr ',;:' ' ' <<< "$2")" + local -r install_dir="${BITNAMI_ROOT_DIR}/${app}" + local -r persist_dir="${BITNAMI_VOLUME_DIR}/${app}" + # Restore the individual persisted files + if [[ "${#files_to_restore[@]}" -le 0 ]]; then + warn "No persisted files are configured to be restored" + return + fi + local file_to_restore_relative file_to_restore_origin file_to_restore_destination + for file_to_restore in "${files_to_restore[@]}"; do + file_to_restore_relative="$(relativize "$file_to_restore" "$install_dir")" + # We use 'realpath --no-symlinks' to ensure that the case of '.' is covered and the directory is removed + file_to_restore_origin="$(realpath --no-symlinks "${install_dir}/${file_to_restore_relative}")" + file_to_restore_destination="$(realpath --no-symlinks "${persist_dir}/${file_to_restore_relative}")" + rm -rf "$file_to_restore_origin" + ln -sfn "$file_to_restore_destination" "$file_to_restore_origin" + done +} + +######################## +# Check if an application directory was already persisted +# Globals: +# BITNAMI_VOLUME_DIR +# Arguments: +# $1 - App folder name +# Returns: +# true if all steps succeeded, false otherwise +######################### +is_app_initialized() { + local -r app="${1:?missing app}" + local -r persist_dir="${BITNAMI_VOLUME_DIR}/${app}" + if ! is_mounted_dir_empty "$persist_dir"; then + true + else + false + fi +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libservice.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libservice.sh new file mode 100644 index 000000000000..f964ab09fcba --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libservice.sh @@ -0,0 +1,410 @@ +#!/bin/bash +# +# Library for managing services + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/libvalidations.sh +. /opt/bitnami/scripts/liblog.sh + +# Functions + +######################## +# Read the provided pid file and returns a PID +# Arguments: +# $1 - Pid file +# Returns: +# PID +######################### +get_pid_from_file() { + local pid_file="${1:?pid file is missing}" + + if [[ -f "$pid_file" ]]; then + if [[ -n "$(< "$pid_file")" ]] && [[ "$(< "$pid_file")" -gt 0 ]]; then + echo "$(< "$pid_file")" + fi + fi +} + +######################## +# Check if a provided PID corresponds to a running service +# Arguments: +# $1 - PID +# Returns: +# Boolean +######################### +is_service_running() { + local pid="${1:?pid is missing}" + + kill -0 "$pid" 2>/dev/null +} + +######################## +# Stop a service by sending a termination signal to its pid +# Arguments: +# $1 - Pid file +# $2 - Signal number (optional) +# Returns: +# None +######################### +stop_service_using_pid() { + local pid_file="${1:?pid file is missing}" + local signal="${2:-}" + local pid + + pid="$(get_pid_from_file "$pid_file")" + [[ -z "$pid" ]] || ! is_service_running "$pid" && return + + if [[ -n "$signal" ]]; then + kill "-${signal}" "$pid" + else + kill "$pid" + fi + + local counter=10 + while [[ "$counter" -ne 0 ]] && is_service_running "$pid"; do + sleep 1 + counter=$((counter - 1)) + done +} + +######################## +# Start cron daemon +# Arguments: +# None +# Returns: +# true if started correctly, false otherwise +######################### +cron_start() { + if [[ -x "/usr/sbin/cron" ]]; then + /usr/sbin/cron + elif [[ -x "/usr/sbin/crond" ]]; then + /usr/sbin/crond + else + false + fi +} + +######################## +# Generate a cron configuration file for a given service +# Arguments: +# $1 - Service name +# $2 - Command +# Flags: +# --run-as - User to run as (default: root) +# --schedule - Cron schedule configuration (default: * * * * *) +# Returns: +# None +######################### +generate_cron_conf() { + local service_name="${1:?service name is missing}" + local cmd="${2:?command is missing}" + local run_as="root" + local schedule="* * * * *" + local clean="true" + + local clean="true" + + # Parse optional CLI flags + shift 2 + while [[ "$#" -gt 0 ]]; do + case "$1" in + --run-as) + shift + run_as="$1" + ;; + --schedule) + shift + schedule="$1" + ;; + --no-clean) + clean="false" + ;; + *) + echo "Invalid command line flag ${1}" >&2 + return 1 + ;; + esac + shift + done + + mkdir -p /etc/cron.d + if "$clean"; then + echo "${schedule} ${run_as} ${cmd}" > /etc/cron.d/"$service_name" + else + echo "${schedule} ${run_as} ${cmd}" >> /etc/cron.d/"$service_name" + fi +} + +######################## +# Remove a cron configuration file for a given service +# Arguments: +# $1 - Service name +# Returns: +# None +######################### +remove_cron_conf() { + local service_name="${1:?service name is missing}" + local cron_conf_dir="/etc/monit/conf.d" + rm -f "${cron_conf_dir}/${service_name}" +} + +######################## +# Generate a monit configuration file for a given service +# Arguments: +# $1 - Service name +# $2 - Pid file +# $3 - Start command +# $4 - Stop command +# Flags: +# --disable - Whether to disable the monit configuration +# Returns: +# None +######################### +generate_monit_conf() { + local service_name="${1:?service name is missing}" + local pid_file="${2:?pid file is missing}" + local start_command="${3:?start command is missing}" + local stop_command="${4:?stop command is missing}" + local monit_conf_dir="/etc/monit/conf.d" + local disabled="no" + + # Parse optional CLI flags + shift 4 + while [[ "$#" -gt 0 ]]; do + case "$1" in + --disable) + disabled="yes" + ;; + *) + echo "Invalid command line flag ${1}" >&2 + return 1 + ;; + esac + shift + done + + is_boolean_yes "$disabled" && conf_suffix=".disabled" + mkdir -p "$monit_conf_dir" + cat >"${monit_conf_dir}/${service_name}.conf${conf_suffix:-}" <&2 + return 1 + ;; + esac + shift + done + + mkdir -p "$logrotate_conf_dir" + cat <"${logrotate_conf_dir}/${service_name}" +${log_path} { + ${period} + rotate ${rotations} + dateext + compress + copytruncate + missingok +$(indent "$extra" 2) +} +EOF +} + +######################## +# Remove a logrotate configuration file +# Arguments: +# $1 - Service name +# Returns: +# None +######################### +remove_logrotate_conf() { + local service_name="${1:?service name is missing}" + local logrotate_conf_dir="/etc/logrotate.d" + rm -f "${logrotate_conf_dir}/${service_name}" +} + +######################## +# Generate a Systemd configuration file +# Arguments: +# $1 - Service name +# Flags: +# --exec-start - Start command (required) +# --exec-stop - Stop command (optional) +# --exec-reload - Reload command (optional) +# --name - Service full name (e.g. Apache HTTP Server, defaults to $1) +# --restart - When to restart the Systemd service after being stopped (defaults to always) +# --pid-file - Service PID file (required when --restart is set to always) +# --type - Systemd unit type (defaults to forking) +# --user - System user to start the service with +# --group - System group to start the service with +# --environment - Environment variable to define (multiple --environment options may be passed) +# Returns: +# None +######################### +generate_systemd_conf() { + local -r service_name="${1:?service name is missing}" + local -r systemd_units_dir="/etc/systemd/system" + local -r service_file="${systemd_units_dir}/bitnami.${service_name}.service" + # Default values + local name="$service_name" + local type="forking" + local user="" + local group="" + local environment="" + local exec_start="" + local exec_stop="" + local exec_reload="" + local restart="always" + local pid_file="" + # Parse CLI flags + shift + while [[ "$#" -gt 0 ]]; do + case "$1" in + --name \ + | --type \ + | --user \ + | --group \ + | --exec-start \ + | --exec-stop \ + | --exec-reload \ + | --restart \ + | --pid-file \ + ) + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + shift + declare "$var_name"="${1:?"$var_name" is missing}" + ;; + --environment) + shift + # It is possible to add multiple environment lines + [[ -n "$environment" ]] && environment+=$'\n' + environment+="Environment=${1:?"environment" is missing}" + ;; + *) + echo "Invalid command line flag ${1}" >&2 + return 1 + ;; + esac + shift + done + # Validate inputs + local error="no" + if [[ -z "$exec_start" ]]; then + error "The --exec-start option is required" + error="yes" + fi + if [[ "$restart" = "always" && -z "$pid_file" ]]; then + error "The --restart option cannot be set to 'always' if --pid-file is not set" + error="yes" + fi + if [[ "$error" != "no" ]]; then + return 1 + fi + # Generate the Systemd unit + cat > "$service_file" <> "$service_file" <> "$service_file" <> "$service_file" <> "$service_file" <> "$service_file" <> "$service_file" <<< "$environment" + fi + cat >> "$service_file" <= 0 )); then + true + else + false + fi +} + +######################## +# Check if the provided argument is a boolean or is the string 'yes/true' +# Arguments: +# $1 - Value to check +# Returns: +# Boolean +######################### +is_boolean_yes() { + local -r bool="${1:-}" + # comparison is performed without regard to the case of alphabetic characters + shopt -s nocasematch + if [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then + true + else + false + fi +} + +######################## +# Check if the provided argument is a boolean yes/no value +# Arguments: +# $1 - Value to check +# Returns: +# Boolean +######################### +is_yes_no_value() { + local -r bool="${1:-}" + if [[ "$bool" =~ ^(yes|no)$ ]]; then + true + else + false + fi +} + +######################## +# Check if the provided argument is a boolean true/false value +# Arguments: +# $1 - Value to check +# Returns: +# Boolean +######################### +is_true_false_value() { + local -r bool="${1:-}" + if [[ "$bool" =~ ^(true|false)$ ]]; then + true + else + false + fi +} + +######################## +# Check if the provided argument is a boolean 1/0 value +# Arguments: +# $1 - Value to check +# Returns: +# Boolean +######################### +is_1_0_value() { + local -r bool="${1:-}" + if [[ "$bool" =~ ^[10]$ ]]; then + true + else + false + fi +} + +######################## +# Check if the provided argument is an empty string or not defined +# Arguments: +# $1 - Value to check +# Returns: +# Boolean +######################### +is_empty_value() { + local -r val="${1:-}" + if [[ -z "$val" ]]; then + true + else + false + fi +} + +######################## +# Validate if the provided argument is a valid port +# Arguments: +# $1 - Port to validate +# Returns: +# Boolean and error message +######################### +validate_port() { + local value + local unprivileged=0 + + # Parse flags + while [[ "$#" -gt 0 ]]; do + case "$1" in + -unprivileged) + unprivileged=1 + ;; + --) + shift + break + ;; + -*) + stderr_print "unrecognized flag $1" + return 1 + ;; + *) + break + ;; + esac + shift + done + + if [[ "$#" -gt 1 ]]; then + echo "too many arguments provided" + return 2 + elif [[ "$#" -eq 0 ]]; then + stderr_print "missing port argument" + return 1 + else + value=$1 + fi + + if [[ -z "$value" ]]; then + echo "the value is empty" + return 1 + else + if ! is_int "$value"; then + echo "value is not an integer" + return 2 + elif [[ "$value" -lt 0 ]]; then + echo "negative value provided" + return 2 + elif [[ "$value" -gt 65535 ]]; then + echo "requested port is greater than 65535" + return 2 + elif [[ "$unprivileged" = 1 && "$value" -lt 1024 ]]; then + echo "privileged port requested" + return 3 + fi + fi +} + +######################## +# Validate if the provided argument is a valid IPv4 address +# Arguments: +# $1 - IP to validate +# Returns: +# Boolean +######################### +validate_ipv4() { + local ip="${1:?ip is missing}" + local stat=1 + + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + read -r -a ip_array <<< "$(tr '.' ' ' <<< "$ip")" + [[ ${ip_array[0]} -le 255 && ${ip_array[1]} -le 255 \ + && ${ip_array[2]} -le 255 && ${ip_array[3]} -le 255 ]] + stat=$? + fi + return $stat +} + +######################## +# Validate a string format +# Arguments: +# $1 - String to validate +# Returns: +# Boolean +######################### +validate_string() { + local string + local min_length=-1 + local max_length=-1 + + # Parse flags + while [ "$#" -gt 0 ]; do + case "$1" in + -min-length) + shift + min_length=${1:-} + ;; + -max-length) + shift + max_length=${1:-} + ;; + --) + shift + break + ;; + -*) + stderr_print "unrecognized flag $1" + return 1 + ;; + *) + break + ;; + esac + shift + done + + if [ "$#" -gt 1 ]; then + stderr_print "too many arguments provided" + return 2 + elif [ "$#" -eq 0 ]; then + stderr_print "missing string" + return 1 + else + string=$1 + fi + + if [[ "$min_length" -ge 0 ]] && [[ "${#string}" -lt "$min_length" ]]; then + echo "string length is less than $min_length" + return 1 + fi + if [[ "$max_length" -ge 0 ]] && [[ "${#string}" -gt "$max_length" ]]; then + echo "string length is great than $max_length" + return 1 + fi +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libversion.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libversion.sh new file mode 100644 index 000000000000..f3bc7568bfa5 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libversion.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Library for managing versions strings + +# shellcheck disable=SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/liblog.sh + +# Functions +######################## +# Gets semantic version +# Arguments: +# $1 - version: string to extract major.minor.patch +# $2 - section: 1 to extract major, 2 to extract minor, 3 to extract patch +# Returns: +# array with the major, minor and release +######################### +get_sematic_version () { + local version="${1:?version is required}" + local section="${2:?section is required}" + local -a version_sections + + #Regex to parse versions: x.y.z + local -r regex='([0-9]+)(\.([0-9]+)(\.([0-9]+))?)?' + + if [[ "$version" =~ $regex ]]; then + local i=1 + local j=1 + local n=${#BASH_REMATCH[*]} + + while [[ $i -lt $n ]]; do + if [[ -n "${BASH_REMATCH[$i]}" ]] && [[ "${BASH_REMATCH[$i]:0:1}" != '.' ]]; then + version_sections[$j]=${BASH_REMATCH[$i]} + ((j++)) + fi + ((i++)) + done + + local number_regex='^[0-9]+$' + if [[ "$section" =~ $number_regex ]] && (( section > 0 )) && (( section <= 3 )); then + echo "${version_sections[$section]}" + return + else + stderr_print "Section allowed values are: 1, 2, and 3" + return 1 + fi + fi +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libwebserver.sh b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libwebserver.sh new file mode 100644 index 000000000000..818c2158032b --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/opt/bitnami/scripts/libwebserver.sh @@ -0,0 +1,458 @@ +#!/bin/bash +# +# Bitnami web server handler library + +# shellcheck disable=SC1090,SC1091 + +# Load generic libraries +. /opt/bitnami/scripts/liblog.sh + +######################## +# Execute a command (or list of commands) with the web server environment and library loaded +# Globals: +# * +# Arguments: +# None +# Returns: +# None +######################### +web_server_execute() { + local -r web_server="${1:?missing web server}" + shift + # Run program in sub-shell to avoid web server environment getting loaded when not necessary + ( + . "/opt/bitnami/scripts/lib${web_server}.sh" + . "/opt/bitnami/scripts/${web_server}-env.sh" + "$@" + ) +} + +######################## +# Prints the list of enabled web servers +# Globals: +# None +# Arguments: +# None +# Returns: +# None +######################### +web_server_list() { + local -r -a supported_web_servers=(apache nginx) + local -a existing_web_servers=() + for web_server in "${supported_web_servers[@]}"; do + [[ -f "/opt/bitnami/scripts/${web_server}-env.sh" ]] && existing_web_servers+=("$web_server") + done + echo "${existing_web_servers[@]:-}" +} + +######################## +# Prints the currently-enabled web server type (only one, in order of preference) +# Globals: +# None +# Arguments: +# None +# Returns: +# None +######################### +web_server_type() { + local -a web_servers + read -r -a web_servers <<< "$(web_server_list)" + echo "${web_servers[0]:-}" +} + +######################## +# Validate that a supported web server is configured +# Globals: +# None +# Arguments: +# None +# Returns: +# None +######################### +web_server_validate() { + local error_code=0 + local supported_web_servers=("apache" "nginx") + + # Auxiliary functions + print_validation_error() { + error "$1" + error_code=1 + } + + if [[ -z "$(web_server_type)" || ! " ${supported_web_servers[*]} " == *" $(web_server_type) "* ]]; then + print_validation_error "Could not detect any supported web servers. It must be one of: ${supported_web_servers[*]}" + elif ! web_server_execute "$(web_server_type)" type -t "is_$(web_server_type)_running" >/dev/null; then + print_validation_error "Could not load the $(web_server_type) web server library from /opt/bitnami/scripts. Check that it exists and is readable." + fi + + return "$error_code" +} + +######################## +# Check whether the web server is running +# Globals: +# * +# Arguments: +# None +# Returns: +# true if the web server is running, false otherwise +######################### +is_web_server_running() { + "is_$(web_server_type)_running" +} + +######################## +# Start web server +# Globals: +# * +# Arguments: +# None +# Returns: +# None +######################### +web_server_start() { + info "Starting $(web_server_type) in background" + "${BITNAMI_ROOT_DIR}/scripts/$(web_server_type)/start.sh" +} + +######################## +# Stop web server +# Globals: +# * +# Arguments: +# None +# Returns: +# None +######################### +web_server_stop() { + info "Stopping $(web_server_type)" + "${BITNAMI_ROOT_DIR}/scripts/$(web_server_type)/stop.sh" +} + +######################## +# Restart web server +# Globals: +# * +# Arguments: +# None +# Returns: +# None +######################### +web_server_restart() { + info "Restarting $(web_server_type)" + "${BITNAMI_ROOT_DIR}/scripts/$(web_server_type)/restart.sh" +} + +######################## +# Reload web server +# Globals: +# * +# Arguments: +# None +# Returns: +# None +######################### +web_server_reload() { + "${BITNAMI_ROOT_DIR}/scripts/$(web_server_type)/reload.sh" +} + +######################## +# Ensure a web server application configuration exists (i.e. Apache virtual host format or NGINX server block) +# It serves as a wrapper for the specific web server function +# Globals: +# * +# Arguments: +# $1 - App name +# Flags: +# --type - Application type, which has an effect on which configuration template to use +# --hosts - Host listen addresses +# --server-name - Server name +# --server-aliases - Server aliases +# --allow-remote-connections - Whether to allow remote connections or to require local connections +# --disable - Whether to render server configurations with a .disabled prefix +# --disable-http - Whether to render the app's HTTP server configuration with a .disabled prefix +# --disable-https - Whether to render the app's HTTPS server configuration with a .disabled prefix +# --http-port - HTTP port number +# --https-port - HTTPS port number +# --document-root - Path to document root directory +# Apache-specific flags: +# --apache-additional-configuration - Additional vhost configuration (no default) +# --apache-additional-http-configuration - Additional HTTP vhost configuration (no default) +# --apache-additional-https-configuration - Additional HTTPS vhost configuration (no default) +# --apache-before-vhost-configuration - Configuration to add before the directive (no default) +# --apache-allow-override - Whether to allow .htaccess files (only allowed when --move-htaccess is set to 'no' and type is not defined) +# --apache-extra-directory-configuration - Extra configuration for the document root directory +# --apache-proxy-address - Address where to proxy requests +# --apache-proxy-configuration - Extra configuration for the proxy +# --apache-proxy-http-configuration - Extra configuration for the proxy HTTP vhost +# --apache-proxy-https-configuration - Extra configuration for the proxy HTTPS vhost +# --apache-move-htaccess - Move .htaccess files to a common place so they can be loaded during Apache startup (only allowed when type is not defined) +# NGINX-specific flags: +# --nginx-additional-configuration - Additional server block configuration (no default) +# --nginx-external-configuration - Configuration external to server block (no default) +# Returns: +# true if the configuration was enabled, false otherwise +######################## +ensure_web_server_app_configuration_exists() { + local app="${1:?missing app}" + shift + local -a apache_args nginx_args web_servers args_var + apache_args=("$app") + nginx_args=("$app") + # Validate arguments + while [[ "$#" -gt 0 ]]; do + case "$1" in + # Common flags + --disable \ + | --disable-http \ + | --disable-https \ + ) + apache_args+=("$1") + nginx_args+=("$1") + ;; + --hosts \ + | --server-name \ + | --server-aliases \ + | --type \ + | --allow-remote-connections \ + | --http-port \ + | --https-port \ + | --document-root \ + ) + apache_args+=("$1" "${2:?missing value}") + nginx_args+=("$1" "${2:?missing value}") + shift + ;; + + # Specific Apache flags + --apache-additional-configuration \ + | --apache-additional-http-configuration \ + | --apache-additional-https-configuration \ + | --apache-before-vhost-configuration \ + | --apache-allow-override \ + | --apache-extra-directory-configuration \ + | --apache-proxy-address \ + | --apache-proxy-configuration \ + | --apache-proxy-http-configuration \ + | --apache-proxy-https-configuration \ + | --apache-move-htaccess \ + ) + apache_args+=("${1//apache-/}" "${2:?missing value}") + shift + ;; + + # Specific NGINX flags + --nginx-additional-configuration \ + | --nginx-external-configuration) + nginx_args+=("${1//nginx-/}" "${2:?missing value}") + shift + ;; + + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + read -r -a web_servers <<< "$(web_server_list)" + for web_server in "${web_servers[@]}"; do + args_var="${web_server}_args[@]" + web_server_execute "$web_server" "ensure_${web_server}_app_configuration_exists" "${!args_var}" + done +} + +######################## +# Ensure a web server application configuration does not exist anymore (i.e. Apache virtual host format or NGINX server block) +# It serves as a wrapper for the specific web server function +# Globals: +# * +# Arguments: +# $1 - App name +# Returns: +# true if the configuration was disabled, false otherwise +######################## +ensure_web_server_app_configuration_not_exists() { + local app="${1:?missing app}" + local -a web_servers + read -r -a web_servers <<< "$(web_server_list)" + for web_server in "${web_servers[@]}"; do + web_server_execute "$web_server" "ensure_${web_server}_app_configuration_not_exists" "$app" + done +} + +######################## +# Ensure the web server loads the configuration for an application in a URL prefix +# It serves as a wrapper for the specific web server function +# Globals: +# * +# Arguments: +# $1 - App name +# Flags: +# --allow-remote-connections - Whether to allow remote connections or to require local connections +# --document-root - Path to document root directory +# --prefix - URL prefix from where it will be accessible (i.e. /myapp) +# --type - Application type, which has an effect on what configuration template will be used +# Apache-specific flags: +# --apache-additional-configuration - Additional vhost configuration (no default) +# --apache-allow-override - Whether to allow .htaccess files (only allowed when --move-htaccess is set to 'no') +# --apache-extra-directory-configuration - Extra configuration for the document root directory +# --apache-move-htaccess - Move .htaccess files to a common place so they can be loaded during Apache startup +# NGINX-specific flags: +# --nginx-additional-configuration - Additional server block configuration (no default) +# Returns: +# true if the configuration was enabled, false otherwise +######################## +ensure_web_server_prefix_configuration_exists() { + local app="${1:?missing app}" + shift + local -a apache_args nginx_args web_servers args_var + apache_args=("$app") + nginx_args=("$app") + # Validate arguments + while [[ "$#" -gt 0 ]]; do + case "$1" in + # Common flags + --allow-remote-connections \ + | --document-root \ + | --prefix \ + | --type \ + ) + apache_args+=("$1" "${2:?missing value}") + nginx_args+=("$1" "${2:?missing value}") + shift + ;; + + # Specific Apache flags + --apache-additional-configuration \ + | --apache-allow-override \ + | --apache-extra-directory-configuration \ + | --apache-move-htaccess \ + ) + apache_args+=("${1//apache-/}" "$2") + shift + ;; + + # Specific NGINX flags + --nginx-additional-configuration) + nginx_args+=("${1//nginx-/}" "$2") + shift + ;; + + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + read -r -a web_servers <<< "$(web_server_list)" + for web_server in "${web_servers[@]}"; do + args_var="${web_server}_args[@]" + web_server_execute "$web_server" "ensure_${web_server}_prefix_configuration_exists" "${!args_var}" + done +} + +######################## +# Ensure a web server application configuration is updated with the runtime configuration (i.e. ports) +# It serves as a wrapper for the specific web server function +# Globals: +# * +# Arguments: +# $1 - App name +# Flags: +# --hosts - Host listen addresses +# --server-name - Server name +# --server-aliases - Server aliases +# --enable-http - Enable HTTP app configuration (if not enabled already) +# --enable-https - Enable HTTPS app configuration (if not enabled already) +# --disable-http - Disable HTTP app configuration (if not disabled already) +# --disable-https - Disable HTTPS app configuration (if not disabled already) +# --http-port - HTTP port number +# --https-port - HTTPS port number +# Returns: +# true if the configuration was updated, false otherwise +######################## +web_server_update_app_configuration() { + local app="${1:?missing app}" + shift + local -a args web_servers + args=("$app") + # Validate arguments + while [[ "$#" -gt 0 ]]; do + case "$1" in + # Common flags + --enable-http \ + | --enable-https \ + | --disable-http \ + | --disable-https \ + ) + args+=("$1") + ;; + --hosts \ + | --server-name \ + | --server-aliases \ + | --http-port \ + | --https-port \ + ) + args+=("$1" "${2:?missing value}") + shift + ;; + + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + read -r -a web_servers <<< "$(web_server_list)" + for web_server in "${web_servers[@]}"; do + web_server_execute "$web_server" "${web_server}_update_app_configuration" "${args[@]}" + done +} + +######################## +# Enable loading page, which shows users that the initialization process is not yet completed +# Globals: +# * +# Arguments: +# None +# Returns: +# None +######################### +web_server_enable_loading_page() { + ensure_web_server_app_configuration_exists "__loading" --hosts "_default_" \ + --apache-additional-configuration " +# Show a HTTP 503 Service Unavailable page by default +RedirectMatch 503 ^/$ +# Show index.html if server is answering with 404 Not Found or 503 Service Unavailable status codes +ErrorDocument 404 /index.html +ErrorDocument 503 /index.html" \ + --nginx-additional-configuration " +# Show a HTTP 503 Service Unavailable page by default +location / { + return 503; +} +# Show index.html if server is answering with 404 Not Found or 503 Service Unavailable status codes +error_page 404 @installing; +error_page 503 @installing; +location @installing { + rewrite ^(.*)$ /index.html break; +}" + web_server_reload +} + +######################## +# Enable loading page, which shows users that the initialization process is not yet completed +# Globals: +# * +# Arguments: +# None +# Returns: +# None +######################### +web_server_disable_install_page() { + ensure_web_server_app_configuration_not_exists "__loading" + web_server_reload +} diff --git a/bitnami/appsmith/1/debian-11/prebuildfs/usr/sbin/install_packages b/bitnami/appsmith/1/debian-11/prebuildfs/usr/sbin/install_packages new file mode 100755 index 000000000000..77857a1a57f2 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/prebuildfs/usr/sbin/install_packages @@ -0,0 +1,25 @@ +#!/bin/sh +set -eu + +n=0 +max=2 +export DEBIAN_FRONTEND=noninteractive + +until [ $n -gt $max ]; do + set +e + ( + apt-get update -qq && + apt-get install -y --no-install-recommends "$@" + ) + CODE=$? + set -e + if [ $CODE -eq 0 ]; then + break + fi + if [ $n -eq $max ]; then + exit $CODE + fi + echo "apt failed, retrying" + n=$(($n + 1)) +done +apt-get clean && rm -rf /var/lib/apt/lists /var/cache/apt/archives diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/certs/server.crt b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/certs/server.crt new file mode 100644 index 000000000000..466bbeab9ff4 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/certs/server.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICqDCCAZACCQCz8T3726LYsjANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDDAtl +eGFtcGxlLmNvbTAeFw0xMjExMTQxMTE4MjdaFw0yMjExMTIxMTE4MjdaMBYxFDAS +BgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA5NHl5TfZtO6zugau2tp5mWIcQYJhuwKTmYeXDLYAGJpoD2SixwPL5c8glneI +Rz1N2EQIZVeaWGbS0FLFlPdOkCkplpW9isYVC4XqKrk5b4HW4+YC+Cup0k+Kd4NM +eZOTUvWr5N6dIpdibkVumBc/pao8VtdwywlCL/PwGRsQtkXrRICzdtRa3MXqTmEF +foyVCGgBRtronlB9x4Plfb8Psk4GrPkjrWYgO8peKrl0O5+F+sYg7Gj95zCH73BQ +ANzCVNrgD9fs9cyx3ru9CUdEoIxAAJwQFkjm7xr6xqhIlSgnQ7B0uOSTNRcXY6rw +s+PxGneec/kRPRgzjC/QHY6n8QIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBbyMqF +RDsX8zX1EW5qA8AQ8Jb2XqWrVeSO8blMV3WagJ2airMm3+c/82FCwsd/cZ08UXhA +/Kou0gi/F16tV26PiiUdp590Qao3d8H2qxc1rzzULimZPgxH4iA4vRyMHtyZN6h4 +7Fdn7O9xNMPu8siOz8rrzsEdEX5URbOMkDLCZsbTIUWVv2XmqrR0K10d5VuLWeLi +r+4G6c6jpa244WmqT9ClqceJ12G1Wnmezy7ybiW0l5M2iuIKFEiRP5Hj0J15o1I2 +pXAbKysAdWRHsJSQOtcgO8Vh9k0wo3tKg4HDp1hbrEzoGzOv92Vjg3lG8X+hzbMJ +MQURotHkD4Gk57wL +-----END CERTIFICATE----- diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/certs/server.key b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/certs/server.key new file mode 100644 index 000000000000..1904ca7090ae --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/certs/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA5NHl5TfZtO6zugau2tp5mWIcQYJhuwKTmYeXDLYAGJpoD2Si +xwPL5c8glneIRz1N2EQIZVeaWGbS0FLFlPdOkCkplpW9isYVC4XqKrk5b4HW4+YC ++Cup0k+Kd4NMeZOTUvWr5N6dIpdibkVumBc/pao8VtdwywlCL/PwGRsQtkXrRICz +dtRa3MXqTmEFfoyVCGgBRtronlB9x4Plfb8Psk4GrPkjrWYgO8peKrl0O5+F+sYg +7Gj95zCH73BQANzCVNrgD9fs9cyx3ru9CUdEoIxAAJwQFkjm7xr6xqhIlSgnQ7B0 +uOSTNRcXY6rws+PxGneec/kRPRgzjC/QHY6n8QIDAQABAoIBACo3G131tuGtpFTu +xLW11vdYZXQklNlGuWp63IBI162yVv54B5wF9Ek6tH1uIiNaiREcRBxGVEB4/+3V +R4SbN9Ba98RDbgu7TcipdTFaqOEMqFO1bNjSXWtip14zSBmqA2Ur1AHOnFj0awGD +J8tBhsmOpcEz0Ch1VdO5ApPvLV8jH9wQiMI/Q6yYQMtmzTMCUMYdMqe+LOziIOzL +oqN/WXnKL5E5TiO1bIxSpWPbT+IVn1c3/PShmvmRrLWsFUQlkwXJKMYZPO+rCCfe +b+Q9lMLMnj+vOnM3z16WC3aiiJGCZjVTvQ+x22YrBTRPxZmHO2eZ4H/cUQM7Y/tw +I7RjEM0CgYEA9Kxt1t8bWonzBii3P0rwyx0IECvg63k+pp4BpxpeWQKL7NVdSzk3 +AyJVcNjUoZgi2kVPdxzZGLrnZfuZ691xQB3oZF0LwBzQ4GFHkTRCB0s8ZA5lcJaI +9pBu91bhz2VOZSTeQWpdMMURjXVyTXZInU1mwzmjVOIAYmO33shH9gcCgYEA72mX +UoIrFPLkOTSZOb7UbjYH01vf6ThQiYCEWg7mD3CbY7n9oobIcQMzNnt7xN4wOl/V +eKfZ7G56q8enfqm45Dyo9aCBCENVzmwO8wLe5UnvJBNL20KjvtwG8w5A6UZQzC7p +3QS+U2zxVQNEeaE6a8Wrq2d1PlhVAHYw8odgNEcCgYBN38+58xrmrz99d1oTuAt5 +6kyVsRGOgPGS4HmQMRFUbT4R7DscZSKASd4945WRtTVqmWLYe4MRnvNlfzYXX0zb +ZmmAAClsRP+qWuwHaEWXwrd+9SIOOqtvJrta1/lZJFpWUOy4j10H18Flb7sosnwc +LPWHL4Iv0xriNfDg5Iga4wKBgQDLJBU59SkJBW+Q+oho7vrg6QeK15IOGbJ8eYfT +woCC6VFwNQh5N1QsUELMH8rNKJpTba18SzAl5ThBOY9tciVnw/C5Og9CK6BLHnUw +zWbDtxAq1BSxXsIB2EAtTBLX3MoB9myJFNVJhE7hi3w2mA8yEu+u6IIa/Ghjk+XE +ZAnFUQKBgQDjMinRZrK5wA09jcetI+dNiLnKHoQG6OaXDDsNCatex0O2F36BvVXE +P78qDz/i5aBMWsLx6VDvWJAkBIpZoNS5UsOn17tFaocGUSkcm48bs8Dn6VvsE8Bd +XMPAHyKuILlKYifBvNq5T22KhqKX7yGmk/AeOOiKr2KeMnh27JYrCA== +-----END RSA PRIVATE KEY----- diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/protect-hidden-files.conf b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/protect-hidden-files.conf new file mode 100644 index 000000000000..2ddab8c9a1e0 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/bitnami/protect-hidden-files.conf @@ -0,0 +1,4 @@ +# Deny all attempts to access hidden files such as .htaccess or .htpasswd +location ~ /\. { + deny all; +} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/nginx.conf b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/nginx.conf new file mode 100644 index 000000000000..a3b50d7a4754 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/nginx/conf/nginx.conf @@ -0,0 +1,60 @@ +# Based on https://www.nginx.com/resources/wiki/start/topics/examples/full/#nginx-conf +user www www; ## Default: nobody + +worker_processes auto; +error_log "/opt/bitnami/nginx/logs/error.log"; +pid "/opt/bitnami/nginx/tmp/nginx.pid"; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log "/opt/bitnami/nginx/logs/access.log" main; + add_header X-Frame-Options SAMEORIGIN; + + client_body_temp_path "/opt/bitnami/nginx/tmp/client_body" 1 2; + proxy_temp_path "/opt/bitnami/nginx/tmp/proxy" 1 2; + fastcgi_temp_path "/opt/bitnami/nginx/tmp/fastcgi" 1 2; + scgi_temp_path "/opt/bitnami/nginx/tmp/scgi" 1 2; + uwsgi_temp_path "/opt/bitnami/nginx/tmp/uwsgi" 1 2; + + sendfile on; + tcp_nopush on; + tcp_nodelay off; + gzip on; + gzip_http_version 1.0; + gzip_comp_level 2; + gzip_proxied any; + gzip_types text/plain text/css application/javascript text/xml application/xml+rss; + keepalive_timeout 65; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + client_max_body_size 80M; + server_tokens off; + + absolute_redirect off; + port_in_redirect off; + + include "/opt/bitnami/nginx/conf/server_blocks/*.conf"; + + # HTTP Server + server { + # Port to listen on, can also be set in IP:PORT format + listen 80; + + include "/opt/bitnami/nginx/conf/bitnami/*.conf"; + + location /status { + stub_status on; + access_log off; + allow 127.0.0.1; + deny all; + } + } +} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith-env.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith-env.sh new file mode 100644 index 000000000000..e27e3dd7255f --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith-env.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# +# Environment configuration for appsmith + +# The values for all environment variables will be set in the below order of precedence +# 1. Custom environment variables defined below after Bitnami defaults +# 2. Constants defined in this file (environment variables with no default), i.e. BITNAMI_ROOT_DIR +# 3. Environment variables overridden via external files using *_FILE variables (see below) +# 4. Environment variables set externally (i.e. current Bash context/Dockerfile/userdata) + +# Load logging library +# shellcheck disable=SC1090,SC1091 +. /opt/bitnami/scripts/liblog.sh + +export BITNAMI_ROOT_DIR="/opt/bitnami" +export BITNAMI_VOLUME_DIR="/bitnami" + +# Logging configuration +export MODULE="${MODULE:-appsmith}" +export BITNAMI_DEBUG="${BITNAMI_DEBUG:-false}" + +# By setting an environment variable matching *_FILE to a file path, the prefixed environment +# variable will be overridden with the value specified in that file +appsmith_env_vars=( + ALLOW_EMPTY_PASSWORD + APPSMITH_USERNAME + APPSMITH_PASSWORD + APPSMITH_EMAIL + APPSMITH_MODE + APPSMITH_ENCRYPTION_PASSWORD + APPSMITH_ENCRYPTION_SALT + APPSMITH_API_HOST + APPSMITH_API_PORT + APPSMITH_UI_HTTP_PORT + APPSMITH_RTS_HOST + APPSMITH_RTS_PORT + APPSMITH_DATABASE_HOST + APPSMITH_DATABASE_PORT_NUMBER + APPSMITH_DATABASE_NAME + APPSMITH_DATABASE_USER + APPSMITH_DATABASE_PASSWORD + APPSMITH_DATABASE_INIT_DELAY + APPSMITH_REDIS_HOST + APPSMITH_REDIS_PORT_NUMBER + APPSMITH_REDIS_PASSWORD + APPSMITH_STARTUP_TIMEOUT + APPSMITH_STARTUP_ATTEMPTS + APPSMITH_DATA_TO_PERSIST + MONGODB_HOST + MONGODB_PORT_NUMBER + MONGODB_DATABASE_NAME + MONGODB_DATABASE_USER + MONGODB_DATABASE_PASSWORD + REDIS_HOST + REDIS_PORT_NUMBER + REDIS_PASSWORD +) +for env_var in "${appsmith_env_vars[@]}"; do + file_env_var="${env_var}_FILE" + if [[ -n "${!file_env_var:-}" ]]; then + if [[ -r "${!file_env_var:-}" ]]; then + export "${env_var}=$(< "${!file_env_var}")" + unset "${file_env_var}" + else + warn "Skipping export of '${env_var}'. '${!file_env_var:-}' is not readable." + fi + fi +done +unset appsmith_env_vars + +# Paths +export APPSMITH_BASE_DIR="${BITNAMI_ROOT_DIR}/appsmith" +export APPSMITH_VOLUME_DIR="/bitnami/appsmith" +export APPSMITH_DATA_DIR="${APPSMITH_VOLUME_DIR}/data" +export APPSMITH_LOG_DIR="${APPSMITH_BASE_DIR}/logs" +export APPSMITH_LOG_FILE="${APPSMITH_LOG_DIR}/appsmith.log" +export APPSMITH_CONF_DIR="${APPSMITH_BASE_DIR}/conf" +export APPSMITH_CONF_FILE="${APPSMITH_CONF_DIR}/docker.env" +export APPSMITH_TMP_DIR="${APPSMITH_BASE_DIR}/tmp" +export APPSMITH_PID_FILE="${APPSMITH_TMP_DIR}/appsmith.pid" + +# Appsmith configuration parameters +export ALLOW_EMPTY_PASSWORD="${ALLOW_EMPTY_PASSWORD:-no}" +export APPSMITH_USERNAME="${APPSMITH_USERNAME:-user}" # only used during the first initialization +export APPSMITH_PASSWORD="${APPSMITH_PASSWORD:-bitnami}" # only used during the first initialization +export APPSMITH_EMAIL="${APPSMITH_EMAIL:-user@example.com}" # only used during the first initialization +export APPSMITH_MODE="${APPSMITH_MODE:-backend}" +export APPSMITH_ENCRYPTION_PASSWORD="${APPSMITH_ENCRYPTION_PASSWORD:-bitnami123}" # only used during the first initialization +export APPSMITH_ENCRYPTION_SALT="${APPSMITH_ENCRYPTION_SALT:-}" +export APPSMITH_API_HOST="${APPSMITH_API_HOST:-appsmith-api}" +export APPSMITH_API_PORT="${APPSMITH_API_PORT:-8080}" +export APPSMITH_UI_HTTP_PORT="${APPSMITH_UI_HTTP_PORT:-8080}" +export APPSMITH_RTS_HOST="${APPSMITH_RTS_HOST:-appsmith-rts}" +export APPSMITH_RTS_PORT="${APPSMITH_RTS_PORT:-8091}" +APPSMITH_DATABASE_HOST="${APPSMITH_DATABASE_HOST:-"${MONGODB_HOST:-}"}" +export APPSMITH_DATABASE_HOST="${APPSMITH_DATABASE_HOST:-mongodb}" # only used during the first initialization +APPSMITH_DATABASE_PORT_NUMBER="${APPSMITH_DATABASE_PORT_NUMBER:-"${MONGODB_PORT_NUMBER:-}"}" +export APPSMITH_DATABASE_PORT_NUMBER="${APPSMITH_DATABASE_PORT_NUMBER:-27017}" # only used during the first initialization +APPSMITH_DATABASE_NAME="${APPSMITH_DATABASE_NAME:-"${MONGODB_DATABASE_NAME:-}"}" +export APPSMITH_DATABASE_NAME="${APPSMITH_DATABASE_NAME:-bitnami_appsmith}" # only used during the first initialization +APPSMITH_DATABASE_USER="${APPSMITH_DATABASE_USER:-"${MONGODB_DATABASE_USER:-}"}" +export APPSMITH_DATABASE_USER="${APPSMITH_DATABASE_USER:-bn_appsmith}" # only used during the first initialization +APPSMITH_DATABASE_PASSWORD="${APPSMITH_DATABASE_PASSWORD:-"${MONGODB_DATABASE_PASSWORD:-}"}" +export APPSMITH_DATABASE_PASSWORD="${APPSMITH_DATABASE_PASSWORD:-}" # only used during the first initialization +export APPSMITH_DATABASE_INIT_DELAY="${APPSMITH_DATABASE_INIT_DELAY:-0}" +APPSMITH_REDIS_HOST="${APPSMITH_REDIS_HOST:-"${REDIS_HOST:-}"}" +export APPSMITH_REDIS_HOST="${APPSMITH_REDIS_HOST:-redis}" # only used during the first initialization +APPSMITH_REDIS_PORT_NUMBER="${APPSMITH_REDIS_PORT_NUMBER:-"${REDIS_PORT_NUMBER:-}"}" +export APPSMITH_REDIS_PORT_NUMBER="${APPSMITH_REDIS_PORT_NUMBER:-6379}" # only used during the first initialization +APPSMITH_REDIS_PASSWORD="${APPSMITH_REDIS_PASSWORD:-"${REDIS_PASSWORD:-}"}" +export APPSMITH_REDIS_PASSWORD="${APPSMITH_REDIS_PASSWORD:-}" # only used during the first initialization +export APPSMITH_STARTUP_TIMEOUT="${APPSMITH_STARTUP_TIMEOUT:-120}" +export APPSMITH_STARTUP_ATTEMPTS="${APPSMITH_STARTUP_ATTEMPTS:-5}" +export APPSMITH_DATA_TO_PERSIST="${APPSMITH_DATA_TO_PERSIST:-$APPSMITH_CONF_FILE}" + +# Appsmith system parameters +export APPSMITH_DAEMON_USER="appsmith" +export APPSMITH_DAEMON_GROUP="bitnami" + +# Custom environment variables may be defined below diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/entrypoint.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/entrypoint.sh new file mode 100755 index 000000000000..fd6957c78153 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/entrypoint.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libbitnami.sh +. /opt/bitnami/scripts/liblog.sh + +# Load Appsmith environment variables +. /opt/bitnami/scripts/appsmith-env.sh + +print_welcome_page + +if [[ "$1" = "/opt/bitnami/scripts/appsmith/run.sh" ]]; then + info "** Starting Appsmith ${APPSMITH_MODE} setup **" + /opt/bitnami/scripts/appsmith/setup.sh + if [[ "$APPSMITH_MODE" == "client" ]]; then + # In the case of the frontend, we need to configure nginx too + /opt/bitnami/scripts/nginx/setup.sh + fi + info "** Appsmith ${APPSMITH_MODE} setup finished! **" +fi + +echo "" +exec "$@" diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/postunpack.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/postunpack.sh new file mode 100755 index 000000000000..e5ad1c9ffa01 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/postunpack.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libfs.sh +. /opt/bitnami/scripts/libappsmith.sh + +# Load Appsmith environment variables +. /opt/bitnami/scripts/appsmith-env.sh + +# System User +ensure_user_exists "$APPSMITH_DAEMON_USER" --group "$APPSMITH_DAEMON_GROUP" --system + +for dir in "${APPSMITH_CONF_DIR}" "${APPSMITH_LOG_DIR}" "${APPSMITH_TMP_DIR}" "${APPSMITH_VOLUME_DIR}"; do + ensure_dir_exists "$dir" + configure_permissions_ownership "$dir" -d "775" -f "664" -g "root" +done + +# Generate default configuration file +# https://github.com/appsmithorg/appsmith/blob/release/deploy/docker/templates/docker.env.sh#L14 +bash "${APPSMITH_BASE_DIR}/templates/docker.env.sh" "" "" "" "" "" >"${APPSMITH_CONF_FILE}" +chmod -R g+rwX "${APPSMITH_CONF_FILE}" + +# Nginx configuration. Adapted from upstream nginx configuration but removing hardcoded +# references to localhost +# https://github.com/appsmithorg/appsmith/blob/release/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh#L102 +cat <<"EOF" >"${APPSMITH_BASE_DIR}/conf/nginx-app-http.conf.template" +map $http_x_forwarded_proto $origin_scheme { + default $http_x_forwarded_proto; + '' $scheme; +} + +map $http_x_forwarded_host $origin_host { + default $http_x_forwarded_host; + '' $host; +} +server { + listen {{APPSMITH_UI_HTTP_PORT}}; + + client_max_body_size 100m; + + gzip on; + gzip_types *; + + server_tokens off; + root /opt/bitnami/appsmith/editor; + index index.html index.htm; + error_page 404 /; + + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors + add_header Content-Security-Policy "frame-ancestors 'self' *"; + + proxy_set_header X-Forwarded-Proto $origin_scheme; + proxy_set_header X-Forwarded-Host $origin_host; + + location / { + try_files $uri /index.html =404; + } + + location /api { + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_pass http://{{APPSMITH_API_HOST}}:{{APPSMITH_API_PORT}}; + } + + location /oauth2 { + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_pass http://{{APPSMITH_API_HOST}}:{{APPSMITH_API_PORT}}; + } + + location /login { + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_pass http://{{APPSMITH_API_HOST}}:{{APPSMITH_API_PORT}}; + } + + location /rts { + proxy_pass http://{{APPSMITH_RTS_HOST}}:{{APPSMITH_RTS_PORT}}; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header Connection 'upgrade'; + proxy_set_header Upgrade $http_upgrade; + } +} +EOF + +# Add symlinks to the default paths to make a similar UX as the upstream Appsmith container +# https://github.com/appsmithorg/appsmith/blob/release/Dockerfile#L6 +ln -s "${APPSMITH_BASE_DIR}" "/opt/appsmith" diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/run.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/run.sh new file mode 100755 index 000000000000..f029dfe6a0ad --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/run.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# shellcheck disable=SC1090,SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/liblog.sh +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/libvalidations.sh +. /opt/bitnami/scripts/libappsmith.sh + +# Load Appsmith environment variables +. /opt/bitnami/scripts/appsmith-env.sh + +# We need to load in the environment the Appsmith configuration file in order +# for the application to work. Using a similar approach as the upstream container +# https://github.com/appsmithorg/appsmith/blob/release/deploy/docker/entrypoint.sh#L57-L62 +set -a +eval "$(grep -v "=$" "$APPSMITH_CONF_FILE")" +set +a + +declare -a cmd=() +declare -a args=() + +if [[ "$APPSMITH_MODE" == "backend" ]]; then + # We need to be in the same folder or the application will fail for not finding + # the datasource plugins + # https://github.com/appsmithorg/appsmith/blob/release/app/server/entrypoint.sh#L15 + cd "${APPSMITH_BASE_DIR}/backend" || exit 1 + cmd+=("java") + args+=("-Dserver.port=${APPSMITH_API_PORT}" "-Dappsmith.admin.envfile=${APPSMITH_CONF_FILE}" "-Djava.security.egd=file:/dev/./urandom" "-jar" "${APPSMITH_BASE_DIR}/backend/server.jar") +elif [[ "$APPSMITH_MODE" == "rts" ]]; then + # We need to be in the same folder as the server.js script or it will fail + # https://github.com/appsmithorg/appsmith/blob/release/app/rts/start-server.sh#L5 + cd "${APPSMITH_BASE_DIR}/rts" || exit 1 + export PORT="$APPSMITH_RTS_PORT" + cmd+=("node") + args+=("--require" "source-map-support/register" "${APPSMITH_BASE_DIR}/rts/server.js") +else + # For the Client (UI) we just run nginx with the generated configuration + cmd+=("${BITNAMI_ROOT_DIR}/scripts/nginx/run.sh") +fi + +info "** Starting Appsmith ${APPSMITH_MODE} **" +if am_i_root; then + exec gosu "$APPSMITH_DAEMON_USER" "${cmd[@]}" "${args[@]}" +else + exec "${cmd[@]}" "${args[@]}" +fi diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/setup.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/setup.sh new file mode 100755 index 000000000000..801b99831d14 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/appsmith/setup.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/libappsmith.sh + +# Load Appsmith environment settings +. /opt/bitnami/scripts/appsmith-env.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +# Ensure Appsmith environment settings are valid +appsmith_validate +# Ensure Appsmith is stopped when this script ends. +trap "appsmith_backend_stop" EXIT +# Ensure 'appsmith' user exists when running as 'root' +am_i_root && ensure_user_exists "$APPSMITH_DAEMON_USER" --group "$APPSMITH_DAEMON_GROUP" + +appsmith_initialize diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/libappsmith.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/libappsmith.sh new file mode 100644 index 000000000000..e2af53fef793 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/libappsmith.sh @@ -0,0 +1,375 @@ +#!/bin/bash +# +# Bitnami Appsmith library + +# shellcheck disable=SC1090 +# shellcheck disable=SC1091 + +# Load generic libraries +. /opt/bitnami/scripts/libfs.sh +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/libnet.sh +. /opt/bitnami/scripts/libfile.sh +. /opt/bitnami/scripts/libvalidations.sh +. /opt/bitnami/scripts/libpersistence.sh +. /opt/bitnami/scripts/libservice.sh + +######################## +# Validate settings in APPSMITH_* env vars +# Globals: +# APPSMITH_* +# Arguments: +# None +# Returns: +# 0 if the validation succeeded, 1 otherwise +######################### +appsmith_validate() { + debug "Validating settings in APPSMITH_* environment variables..." + local error_code=0 + + # Auxiliary functions + print_validation_error() { + error "$1" + error_code=1 + } + check_empty_value() { + if is_empty_value "${!1}"; then + print_validation_error "${1} must be set" + fi + } + + check_multi_value() { + if [[ " ${2} " != *" ${!1} "* ]]; then + print_validation_error "The allowed values for ${1} are: ${2}" + fi + } + check_resolved_hostname() { + if ! is_hostname_resolved "$1"; then + warn "Hostname ${1} could not be resolved, this could lead to connection issues" + fi + } + check_valid_port() { + local port_var="${1:?missing port variable}" + local err + if ! err="$(validate_port "${!port_var}")"; then + print_validation_error "An invalid port was specified in the environment variable ${port_var}: ${err}." + fi + } + + # Validate user inputs + ! is_empty_value "$APPSMITH_API_PORT" && check_valid_port "APPSMITH_API_PORT" + ! is_empty_value "$APPSMITH_RTS_PORT" && check_valid_port "APPSMITH_RTS_PORT" + + if [[ "$APPSMITH_MODE" == "client" ]]; then + ! is_empty_value "$APPSMITH_UI_HTTP_PORT" && check_valid_port "APPSMITH_UI_HTTP_PORT" + fi + + # Validate credentials + if is_boolean_yes "${ALLOW_EMPTY_PASSWORD:-}"; then + warn "You set the environment variable ALLOW_EMPTY_PASSWORD=${ALLOW_EMPTY_PASSWORD:-}. For safety reasons, do not use this flag in a production environment." + else + if [[ "$APPSMITH_MODE" != "client" ]]; then + is_empty_value "${APPSMITH_DATABASE_PASSWORD}" && print_validation_error "The APPSMITH_DATABASE_PASSWORD environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow a blank password. This is only recommended for development environments." + fi + if [[ "$APPSMITH_MODE" == "backend" ]]; then + is_empty_value "${APPSMITH_REDIS_PASSWORD}" && print_validation_error "The APPSMITH_REDIS_PASSWORD environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow a blank password. This is only recommended for development environments." + fi + fi + + if [[ "$APPSMITH_MODE" == "backend" ]]; then + for empty_env_var in "APPSMITH_ENCRYPTION_PASSWORD" "APPSMITH_ENCRYPTION_SALT"; do + is_empty_value "${!empty_env_var}" && print_validation_error "The ${empty_env_var} environment variable is empty or not set." + done + fi + + if [[ "$APPSMITH_MODE" != "client" ]]; then + # Database configuration validations + check_resolved_hostname "$APPSMITH_DATABASE_HOST" + check_valid_port "APPSMITH_DATABASE_PORT_NUMBER" + + # Redis configuration validations + check_resolved_hostname "$APPSMITH_REDIS_HOST" + check_valid_port "APPSMITH_REDIS_PORT_NUMBER" + fi + # Appsmith mode + check_multi_value "APPSMITH_MODE" "backend rts client" + + if [[ $APPSMITH_MODE == "rts" ]]; then + is_empty_value "${APPSMITH_API_HOST}" && print_validation_error "For RTS mode, the APPSMITH_API_HOST variable must be set" + fi + + if [[ $APPSMITH_MODE == "client" ]]; then + is_empty_value "${APPSMITH_API_HOST}" && print_validation_error "For client mode, the APPSMITH_API_HOST variable must be set" + is_empty_value "${APPSMITH_RTS_HOST}" && print_validation_error "For client mode, the APPSMITH_API_HOST variable must be set" + fi + + return "$error_code" +} + +######################## +# Add or modify an entry in the Appsmith configuration file +# Globals: +# APPSMITH_* +# Arguments: +# $1 - XPath expression +# $2 - Value to assign to the variable +# $3 - Configuration file +# Returns: +# None +######################### +appsmith_conf_set() { + local -r key="${1:?key missing}" + local -r value="${2:?value missing}" + local -r is_literal="${3:-no}" + debug "Setting ${key} to '${value}' in Appsmith configuration (literal: ${is_literal})" + # Sanitize key (sed does not support fixed string substitutions) + local sanitized_pattern + sanitized_pattern="${key}=.*" + local entry + is_boolean_yes "$is_literal" && entry="${key}=${value}" || entry="${key}='${value}'" + # Check if the configuration exists in the file + debug "$sanitized_pattern" + if grep -q -E "$sanitized_pattern" "$APPSMITH_CONF_FILE"; then + # It exists, so replace the line + replace_in_file "$APPSMITH_CONF_FILE" "$sanitized_pattern" "$entry" + else + # The Appsmith configuration file includes all supported keys, but because of its format, + # we cannot append contents to the end. + warn "Could not set the Appsmith '${key}' configuration. Check that the file has not been modified externally." + fi +} + +######################## +# Check if Appsmith daemon is running +# Arguments: +# None +# Returns: +# Boolean +######################### +is_appsmith_backend_running() { + pid="$(get_pid_from_file "$APPSMITH_PID_FILE")" + if [[ -n "$pid" ]]; then + is_service_running "$pid" + else + false + fi +} + +######################## +# Check if Appsmith daemon is not running +# Arguments: +# None +# Returns: +# Boolean +######################### +is_appsmith_backend_not_running() { + ! is_appsmith_backend_running +} + +######################## +# Stop Appsmith daemons +# Arguments: +# None +# Returns: +# None +######################### +appsmith_backend_stop() { + ! is_appsmith_backend_running && return + stop_service_using_pid "$APPSMITH_PID_FILE" +} + +######################## +# Get a configuration setting value from the configuration file(s) +# ref: https://geode.apache.org/docs/guide/112/reference/topics/gemfire_properties.html +# Globals: +# GEODE_* +# Arguments: +# $1 - property key +# $2 - configuration file (optional) +# Returns: +# String (empty string if file or key doesn't exist) +######################### +appsmith_conf_get() { + local -r key="${1:?key missing}" + local -r file="${2:-"${APPSMITH_CONF_FILE}"}" + + # Sanitize key (sed does not support fixed string substitutions) + local sanitized_pattern + sanitized_pattern="^\s*(//\s*)?$(sed 's/[]\[^$.*/]/\\&/g' <<<"$key")=(.*)" + grep -E "$sanitized_pattern" "$file" | sed -E "s|${sanitized_pattern}|\2|" | tr -d "\"' " +} + +######################## +# Wait until the database is accessible with the currently-known credentials +# Globals: +# * +# Arguments: +# $1 - connection string +# Returns: +# true if the database connection succeeded, false otherwise +######################### +appsmith_wait_for_mongodb_connection() { + local -r connection_string="${1:?missing connection string}" + check_mongodb_connection() { + local -r mongo_args=("$connection_string" "--eval" "db.stats()") + local -r res=$(mongosh "${mongo_args[@]}") + debug "$res" + echo "$res" | grep -q 'ok: 1' + } + if ! retry_while "check_mongodb_connection"; then + error "Could not connect to the database" + return 1 + fi + # HACK: The MongoDB Replica Set initialization requires the MongoDB cluster to be + # accessible during the initial sync. After that, the secondary nodes shut downs and then + # starts again (this is how the current Bitnami MongoDB container works). In the case of + # docker-compose scenarios, we experienced several race conditions, as the cluster is ready + # (performing the initial sync) but the MongoDB container initialization logic is not finished yet. + # As a workaround, only in docker-compose we add this extra delay to ensure that Appsmith components + # do not crash. In the case of helm charts, we have readiness/liveness probes as well as init containers + # that avoid this unwanted race condition. + if [[ "$APPSMITH_DATABASE_INIT_DELAY" -ge "0" ]]; then + info "Sleeping $APPSMITH_DATABASE_INIT_DELAY seconds for the MongoDB cluster to be ready" + sleep "$APPSMITH_DATABASE_INIT_DELAY" + fi +} + +######################## +# Initialize Appsmith +# Arguments: +# None +# Returns: +# None +######################### +appsmith_initialize() { + # The logic is inspired on the upstream Appsmith container. Currently it follows a "fat-container" + # approach with all the services in the container. In the Bitnami version we want to keep them separate + # as it works better for the helm chart + # Appsmith is comprised of three components: + # - backend: API written in Java. The client (UI) component interacts with it. Connects to MongoDB and Redis + # - client: Web UI. Point of access for users. Has nginx as the backend. Connects to the API and the RTS. + # - rts: Component written in Node.js. Creates websockets for editing the applications in real-time. Connects to the API and MongoDB + # https://github.com/appsmithorg/appsmith/tree/release/deploy/docker + + if [[ "$APPSMITH_MODE" == "client" ]]; then + # The client (UI) only needs to generate the nginx vhost configuration + echo "Rendering nginx configuration" + export APPSMITH_SERVER_PROXY_PASS="http://$APPSMITH_API_HOST:$APPSMITH_API_PORT" + render-template "${APPSMITH_CONF_DIR}/nginx-app-http.conf.template" >"${NGINX_SERVER_BLOCKS_DIR}/appsmith.conf" + else + # RTS or API server + if { [[ "$APPSMITH_MODE" == "rts" ]]; } || { ! is_app_initialized "appsmith"; }; then + info "Deploying Appsmith $APPSMITH_MODE from scratch" + # First connect to the database + # Appsmith (especially the RTS component) requires the MongoDB instance to be a Replica Set. + # We performed tests with single-node replica sets but didn't work as expected in container + # re-creation scenarios. + local connection_string="mongodb://${APPSMITH_DATABASE_USER}:${APPSMITH_DATABASE_PASSWORD}@" + local add_comma=false + for host in ${APPSMITH_DATABASE_HOST//,/ }; do + if is_boolean_yes "$add_comma"; then + connection_string+="," + else + add_comma=true + fi + connection_string+="${host}:${APPSMITH_DATABASE_PORT_NUMBER}" + done + connection_string+="/${APPSMITH_DATABASE_NAME}" + appsmith_wait_for_mongodb_connection "$connection_string" + + # These parameters are common between RTS and Backend + # https://github.com/appsmithorg/appsmith/blob/658e369f4fc2f12445af5b238bc4d4a1a34d9a8b/app/rts/.env.example#L1-L3 + appsmith_conf_set "APPSMITH_MONGODB_URI" "$connection_string" + appsmith_conf_set "APPSMITH_API_BASE_URL" "http://${APPSMITH_API_HOST}:${APPSMITH_API_PORT}/api/v1" + + if [[ "$APPSMITH_MODE" == "backend" ]]; then + # Necessary configuration for the Backend. As this can be edited via the + # admin panel, we only edit it the first time + # https://github.com/appsmithorg/appsmith/blob/release/app/server/appsmith-server/src/main/resources/application.properties + appsmith_conf_set "APPSMITH_MONGODB_PASSWORD" "$APPSMITH_DATABASE_PASSWORD" + appsmith_conf_set "APPSMITH_MONGODB_USER" "$APPSMITH_DATABASE_USER" + appsmith_conf_set "APPSMITH_REDIS_URL" "redis://:${APPSMITH_REDIS_PASSWORD}@${APPSMITH_REDIS_HOST}:${APPSMITH_REDIS_PORT_NUMBER}" + appsmith_conf_set "APPSMITH_ENCRYPTION_PASSWORD" "$APPSMITH_ENCRYPTION_PASSWORD" + appsmith_conf_set "APPSMITH_ENCRYPTION_SALT" "$APPSMITH_ENCRYPTION_SALT" + info "Ensuring Appsmith directories exist" + ensure_dir_exists "$APPSMITH_VOLUME_DIR" + info "Persisting Appsmith installation" + persist_app "appsmith" "$APPSMITH_DATA_TO_PERSIST" + + # Create Appsmith user + appsmith_backend_start_bg "${APPSMITH_LOG_DIR}/appsmith_first_boot.log" + info "Creating admin user" + local -r -a create_user_cmd=("curl") + # Taken from inspecting Appsmith wizard + # https://github.com/appsmithorg/appsmith/blob/release/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/UserSignupRequestDTO.java#L26 + local -r -a create_user_args=("-X" "POST" + "--data-urlencode" "name=${APPSMITH_USERNAME}" + "--data-urlencode" "email=${APPSMITH_EMAIL}" + "--data-urlencode" "password=${APPSMITH_PASSWORD}" + # Necessary for the installer to succeed + "--data-urlencode" "allowCollectingAnnonymousData=false" + "--data-urlencode" "signupForNewsletter=false" + "--data-urlencode" "role=engineer" + "--data-urlencode" "useCase=just exploring" + "http://localhost:${APPSMITH_API_PORT}/api/v1/users/super" + ) + + if ! debug_execute "${create_user_cmd[@]}" "${create_user_args[@]}"; then + error "Installation failed. User ${APPSMITH_USERNAME} could not be created" + exit 1 + fi + + info "User created successfully" + fi + else + # The migration is done by Appsmith itself, not necessary to run + # any extra script. We just connect to the database + info "Restoring persisted Appsmith $APPSMITH_MODE installation" + restore_persisted_app "appsmith" "$APPSMITH_DATA_TO_PERSIST" + local -r connection_string="$(appsmith_conf_get APPSMITH_MONGODB_URI)" + appsmith_wait_for_mongodb_connection "$connection_string" + fi + fi + + # Avoid exit code of previous commands to affect the result of this function + true +} + +######################## +# Start Appsmith daemon +# Arguments: +# $1 - Log file to check the startup message +# Returns: +# None +######################### +appsmith_backend_start_bg() { + local -r log_file="${1:-"${APPSMITH_LOG_FILE}"}" + info "Starting Appsmith backend in background" + # We need to load in the environment the Appsmith configuration file in order + # for the application to work. Using a similar approach as the upstream container. + # We also need to load only those environment variables that are not empty, otherwise + # the Appsmith daemon crashes on startup because of not allowed empty values. + # https://github.com/appsmithorg/appsmith/blob/release/deploy/docker/entrypoint.sh#L57-L62 + set -a + eval "$(grep -v "=$" "$APPSMITH_CONF_FILE")" + set +a + + is_appsmith_backend_running && return + cd "${APPSMITH_BASE_DIR}/backend" || exit 1 + local -r cmd=("java") + local -r args=("-Dserver.port=${APPSMITH_API_PORT}" "-Dappsmith.admin.envfile=${APPSMITH_CONF_FILE}" "-Djava.security.egd=file:/dev/./urandom" "-jar" "${APPSMITH_BASE_DIR}/backend/server.jar") + if am_i_root; then + gosu "$APPSMITH_DAEMON_USER" "${cmd[@]}" "${args[@]}" >"$log_file" 2>&1 & + else + "${cmd[@]}" "${args[@]}" >"$log_file" 2>&1 & + fi + + echo "$!" >"$APPSMITH_PID_FILE" + + if ! retry_while "debug_execute wait-for-port --timeout ${APPSMITH_STARTUP_TIMEOUT} ${APPSMITH_API_PORT}" "$APPSMITH_STARTUP_ATTEMPTS"; then + error "Appsmith backend failed to start" + debug "Logs: $(cat "$log_file")" + exit 1 + fi + info "Appsmith started successfully" +} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/libnginx.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/libnginx.sh new file mode 100644 index 000000000000..cb791af18624 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/libnginx.sh @@ -0,0 +1,631 @@ +#!/bin/bash +# +# Bitnami NGINX library + +# shellcheck disable=SC1090,SC1091 + +# Load Generic Libraries +. /opt/bitnami/scripts/libfs.sh +. /opt/bitnami/scripts/libfile.sh +. /opt/bitnami/scripts/liblog.sh +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/libservice.sh +. /opt/bitnami/scripts/libvalidations.sh + +# Functions + +######################## +# Check if NGINX is running +# Globals: +# NGINX_TMP_DIR +# Arguments: +# None +# Returns: +# Boolean +######################### +is_nginx_running() { + local pid + pid="$(get_pid_from_file "$NGINX_PID_FILE")" + if [[ -n "$pid" ]]; then + is_service_running "$pid" + else + false + fi +} + +######################## +# Check if NGINX is not running +# Globals: +# NGINX_TMP_DIR +# Arguments: +# None +# Returns: +# Boolean +######################### +is_nginx_not_running() { + ! is_nginx_running +} + +######################## +# Stop NGINX +# Globals: +# NGINX_TMP_DIR +# Arguments: +# None +# Returns: +# None +######################### +nginx_stop() { + ! is_nginx_running && return + debug "Stopping NGINX" + stop_service_using_pid "$NGINX_PID_FILE" +} + +######################## +# Configure NGINX server block port +# Globals: +# NGINX_CONF_DIR +# Arguments: +# $1 - Port number +# $2 - (optional) Path to server block file +# Returns: +# None +######################### +nginx_configure_port() { + local port=${1:?missing port} + local file=${2:-"$NGINX_CONF_FILE"} + if is_file_writable "$file"; then + local nginx_configuration + debug "Setting port number to ${port} in '${file}'" + # TODO: find an appropriate NGINX parser to avoid 'sed calls' + nginx_configuration="$(sed -E "s/(listen\s+)[0-9]{1,5}(.*);/\1${port}\2;/g" "$file")" + echo "$nginx_configuration" >"$file" + fi +} + +######################## +# Configure NGINX directives +# Globals: +# NGINX_CONF_DIR +# Arguments: +# $1 - Directive to modify +# $2 - Value +# $3 - (optional) Path to server block file +# Returns: +# None +######################### +nginx_configure() { + local directive=${1:?missing directive} + local value=${2:?missing value} + local file=${3:-"$NGINX_CONF_FILE"} + if is_file_writable "$file"; then + local nginx_configuration + debug "Setting directive '${directive}' to '${value}' in '${file}'" + nginx_configuration="$(sed -E "s/(\s*${directive}\s+)(.+);/\1${value};/g" "$file")" + echo "$nginx_configuration" >"$file" + fi +} + +######################## +# Validate settings in NGINX_* env vars +# Globals: +# NGINX_* +# Arguments: +# None +# Returns: +# None +######################### +nginx_validate() { + info "Validating settings in NGINX_* env vars" + local error_code=0 + # Auxiliary functions + print_validation_error() { + error "$1" + error_code=1 + } + check_yes_no_value() { + if ! is_yes_no_value "${!1}" && ! is_true_false_value "${!1}"; then + print_validation_error "The allowed values for ${1} are: yes no" + fi + } + check_valid_port() { + local port_var="${1:?missing port variable}" + local validate_port_args=() + local err + ! am_i_root && validate_port_args+=("-unprivileged") + if ! err="$(validate_port "${validate_port_args[@]}" "${!port_var}")"; then + print_validation_error "An invalid port was specified in the environment variable ${port_var}: ${err}." + fi + } + + ! is_empty_value "$NGINX_ENABLE_ABSOLUTE_REDIRECT" && check_yes_no_value "NGINX_ENABLE_ABSOLUTE_REDIRECT" + ! is_empty_value "$NGINX_ENABLE_PORT_IN_REDIRECT" && check_yes_no_value "NGINX_ENABLE_PORT_IN_REDIRECT" + + ! is_empty_value "$NGINX_HTTP_PORT_NUMBER" && check_valid_port "NGINX_HTTP_PORT_NUMBER" + ! is_empty_value "$NGINX_HTTPS_PORT_NUMBER" && check_valid_port "NGINX_HTTPS_PORT_NUMBER" + + if ! is_file_writable "$NGINX_CONF_FILE"; then + warn "The NGINX configuration file '${NGINX_CONF_FILE}' is not writable by current user. Configurations based on environment variables will not be applied." + fi + return "$error_code" +} + +######################## +# Initialize NGINX +# Globals: +# NGINX_* +# Arguments: +# None +# Returns: +# None +######################### +nginx_initialize() { + info "Initializing NGINX" + + # This fixes an issue where the trap would kill the entrypoint.sh, if a PID was left over from a previous run + # Exec replaces the process without creating a new one, and when the container is restarted it may have the same PID + rm -f "${NGINX_TMP_DIR}/nginx.pid" + + # Persisted configuration files from old versions + if [[ -f "$NGINX_VOLUME_DIR/conf/nginx.conf" ]]; then + error "A 'nginx.conf' file was found inside '${NGINX_VOLUME_DIR}/conf'. This configuration is not supported anymore. Please mount the configuration file at '${NGINX_CONF_FILE}' instead." + exit 1 + fi + if ! is_dir_empty "$NGINX_VOLUME_DIR/conf/vhosts"; then + error "Custom server blocks files were found inside '$NGINX_VOLUME_DIR/conf/vhosts'. This configuration is not supported anymore. Please mount your custom server blocks config files at '${NGINX_SERVER_BLOCKS_DIR}' instead." + exit 1 + fi + + debug "Updating NGINX configuration based on environment variables" + local nginx_user_configuration + if am_i_root; then + debug "Ensuring NGINX daemon user/group exists" + ensure_user_exists "$NGINX_DAEMON_USER" --group "$NGINX_DAEMON_GROUP" + if [[ -n "${NGINX_DAEMON_USER:-}" ]]; then + chown -R "${NGINX_DAEMON_USER:-}" "$NGINX_TMP_DIR" + fi + nginx_configure "user" "${NGINX_DAEMON_USER:-} ${NGINX_DAEMON_GROUP:-}" + else + # The "user" directive makes sense only if the master process runs with super-user privileges + # TODO: find an appropriate NGINX parser to avoid 'sed calls' + nginx_user_configuration="$(sed -E "s/(^user)/# \1/g" "$NGINX_CONF_FILE")" + is_file_writable "$NGINX_CONF_FILE" && echo "$nginx_user_configuration" >"$NGINX_CONF_FILE" + fi + # Configure HTTP port number + if [[ -n "${NGINX_HTTP_PORT_NUMBER:-}" ]]; then + nginx_configure_port "$NGINX_HTTP_PORT_NUMBER" + fi + # Configure HTTPS port number + if [[ -n "${NGINX_HTTPS_PORT_NUMBER:-}" ]]; then + nginx_configure_port "$NGINX_HTTPS_PORT_NUMBER" "${NGINX_SERVER_BLOCKS_DIR}/default-https-server-block.conf" + fi + nginx_configure "absolute_redirect" "$(is_boolean_yes "$NGINX_ENABLE_ABSOLUTE_REDIRECT" && echo "on" || echo "off" )" + nginx_configure "port_in_redirect" "$(is_boolean_yes "$NGINX_ENABLE_PORT_IN_REDIRECT" && echo "on" || echo "off" )" +} + +######################## +# Ensure an NGINX application configuration exists (in server block format) +# Globals: +# NGINX_* +# Arguments: +# $1 - App name +# Flags: +# --type - Application type, which has an effect on what configuration template will be used, allowed values: php, (empty) +# --hosts - Host listen addresses +# --server-name - Server name (if not specified, a catch-all server block will be created) +# --server-aliases - Server aliases +# --allow-remote-connections - Whether to allow remote connections or to require local connections +# --disable - Whether to render the app's server blocks with a .disabled prefix +# --disable-http - Whether to render the app's HTTP server block with a .disabled prefix +# --disable-https - Whether to render the app's HTTPS server block with a .disabled prefix +# --http-port - HTTP port number +# --https-port - HTTPS port number +# --additional-configuration - Additional server block configuration (no default) +# --external-configuration - Configuration external to server block (no default) +# --document-root - Path to document root directory +# Returns: +# true if the configuration was enabled, false otherwise +######################## +ensure_nginx_app_configuration_exists() { + export app="${1:?missing app}" + # Default options + local type="" + local -a hosts=() + local server_name + local -a server_aliases=() + local allow_remote_connections="yes" + local disable="no" + local disable_http="no" + local disable_https="no" + # Template variables defaults + export additional_configuration="" + export external_configuration="" + export document_root="${BITNAMI_ROOT_DIR}/${app}" + export http_port="${NGINX_HTTP_PORT_NUMBER:-"$NGINX_DEFAULT_HTTP_PORT_NUMBER"}" + export https_port="${NGINX_HTTPS_PORT_NUMBER:-"$NGINX_DEFAULT_HTTPS_PORT_NUMBER"}" + # Validate arguments + local var_name + shift + while [[ "$#" -gt 0 ]]; do + case "$1" in + --hosts | \ + --server-aliases) + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + shift + read -r -a "$var_name" <<<"$1" + ;; + --disable | \ + --disable-http | \ + --disable-https) + + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + export "${var_name}=yes" + ;; + --type | \ + --server-name | \ + --allow-remote-connections | \ + --http-port | \ + --https-port | \ + --additional-configuration | \ + --external-configuration | \ + --document-root | \ + --extra-directory-configuration) + + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + shift + export "${var_name}"="$1" + ;; + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + # Construct host string in the format of "listen host1:port1", "listen host2:port2", ... + export http_listen_configuration="" + export https_listen_configuration="" + if [[ "${#hosts[@]}" -gt 0 ]]; then + for host in "${hosts[@]}"; do + http_listen=$'\n'"listen ${host}:${http_port};" + https_listen=$'\n'"listen ${host}:${https_port} ssl;" + [[ -z "${http_listen_configuration:-}" ]] && http_listen_configuration="$http_listen" || http_listen_configuration="${http_listen_configuration}${http_listen}" + [[ -z "${https_listen_configuration:-}" ]] && https_listen_configuration="$https_listen" || https_listen_configuration="${https_listen_configuration}${https_listen}" + done + else + http_listen_configuration=$'\n'"listen ${http_port} default_server;" + https_listen_configuration=$'\n'"listen ${https_port} ssl default_server;" + fi + # Construct server_name block + export server_name_configuration="" + if ! is_empty_value "${server_name:-}"; then + server_name_configuration="server_name ${server_name}" + if [[ "${#server_aliases[@]}" -gt 0 ]]; then + server_name_configuration+=" ${server_aliases[*]}" + fi + server_name_configuration+=";" + else + server_name_configuration=" +# Catch-all server block +# See: https://nginx.org/en/docs/http/server_names.html#miscellaneous_names +server_name _;" + fi + # ACL configuration + export acl_configuration="" + if ! is_boolean_yes "$allow_remote_connections"; then + acl_configuration=" +default_type text/html; +if (\$remote_addr != 127.0.0.1) { + return 403 'For security reasons, this URL is only accessible using localhost (127.0.0.1) as the hostname.'; +} +# Avoid absolute redirects when connecting through a SSH tunnel +absolute_redirect off;" + fi + # Indent configurations + server_name_configuration="$(indent $'\n'"$server_name_configuration" 4)" + acl_configuration="$(indent "$acl_configuration" 4)" + additional_configuration=$'\n'"$(indent "$additional_configuration" 4)" + external_configuration=$'\n'"$external_configuration" + http_listen_configuration="$(indent "$http_listen_configuration" 4)" + https_listen_configuration="$(indent "$https_listen_configuration" 4)" + # Render templates + # We remove lines that are empty or contain only newspaces with 'sed', so the resulting file looks better + local template_name="app" + [[ -n "$type" && "$type" != "php" ]] && template_name="app-${type}" + local template_dir="${BITNAMI_ROOT_DIR}/scripts/nginx/bitnami-templates" + local http_server_block="${NGINX_SERVER_BLOCKS_DIR}/${app}-server-block.conf" + local https_server_block="${NGINX_SERVER_BLOCKS_DIR}/${app}-https-server-block.conf" + local -r disable_suffix=".disabled" + (is_boolean_yes "$disable" || is_boolean_yes "$disable_http") && http_server_block+="$disable_suffix" + (is_boolean_yes "$disable" || is_boolean_yes "$disable_https") && https_server_block+="$disable_suffix" + if is_file_writable "$http_server_block"; then + # Create file with root group write privileges, so it can be modified in non-root containers + [[ ! -f "$http_server_block" ]] && touch "$http_server_block" && chmod g+rw "$http_server_block" + render-template "${template_dir}/${template_name}-http-server-block.conf.tpl" | sed '/^\s*$/d' >"$http_server_block" + elif [[ ! -f "$http_server_block" ]]; then + error "Could not create server block for ${app} at '${http_server_block}'. Check permissions and ownership for parent directories." + return 1 + else + warn "The ${app} server block file '${http_server_block}' is not writable. Configurations based on environment variables will not be applied for this file." + fi + if is_file_writable "$https_server_block"; then + # Create file with root group write privileges, so it can be modified in non-root containers + [[ ! -f "$https_server_block" ]] && touch "$https_server_block" && chmod g+rw "$https_server_block" + render-template "${template_dir}/${template_name}-https-server-block.conf.tpl" | sed '/^\s*$/d' >"$https_server_block" + elif [[ ! -f "$https_server_block" ]]; then + error "Could not create server block for ${app} at '${https_server_block}'. Check permissions and ownership for parent directories." + return 1 + else + warn "The ${app} server block file '${https_server_block}' is not writable. Configurations based on environment variables will not be applied for this file." + fi +} + +######################## +# Ensure an NGINX application configuration does not exist anymore (in server block format) +# Globals: +# * +# Arguments: +# $1 - App name +# Returns: +# true if the configuration was disabled, false otherwise +######################## +ensure_nginx_app_configuration_not_exists() { + local app="${1:?missing app}" + local http_server_block="${NGINX_SERVER_BLOCKS_DIR}/${app}-server-block.conf" + local https_server_block="${NGINX_SERVER_BLOCKS_DIR}/${app}-https-server-block.conf" + local -r disable_suffix=".disabled" + # Note that 'rm -f' will not fail if the files don't exist + # However if we lack permissions to remove the file, it will result in a non-zero exit code, as expected by this function + rm -f "$http_server_block" "$https_server_block" "${http_server_block}${disable_suffix}" "${https_server_block}${disable_suffix}" +} + +######################## +# Ensure NGINX loads the configuration for an application in a URL prefix +# Globals: +# NGINX_* +# Arguments: +# $1 - App name +# Flags: +# --type - Application type, which has an effect on what configuration template will be used, allowed values: php, (empty) +# --allow-remote-connections - Whether to allow remote connections or to require local connections +# --prefix - URL prefix from where it will be accessible (i.e. /myapp) +# --additional-configuration - Additional server block configuration (no default) +# --document-root - Path to document root directory +# --extra-directory-configuration - Extra configuration for the document root directory +# Returns: +# true if the configuration was enabled, false otherwise +######################## +ensure_nginx_prefix_configuration_exists() { + local app="${1:?missing app}" + # Default options + local type="" + local allow_remote_connections="yes" + local prefix="/${app}" + # Template variables defaults + export additional_configuration="" + export document_root="${BITNAMI_ROOT_DIR}/${app}" + export extra_directory_configuration="" + # Validate arguments + local var_name + shift + while [[ "$#" -gt 0 ]]; do + case "$1" in + --type | \ + --allow-remote-connections | \ + --additional-configuration | \ + --document-root | \ + --extra-directory-configuration | \ + --prefix) + + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + shift + declare "${var_name}"="$1" + ;; + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + # ACL configuration + export acl_configuration="" + if ! is_boolean_yes "$allow_remote_connections"; then + acl_configuration=" +default_type text/html; +if (\$remote_addr != 127.0.0.1) { + return 403 'For security reasons, this URL is only accessible using localhost (127.0.0.1) as the hostname.'; +} +# Avoid absolute redirects when connecting through a SSH tunnel +absolute_redirect off;" + fi + # Prefix configuration + export location="$prefix" + # Indent configurations + acl_configuration="$(indent "$acl_configuration" 4)" + additional_configuration=$'\n'"$(indent "$additional_configuration" 4)" + # Render templates + # We remove lines that are empty or contain only newspaces with 'sed', so the resulting file looks better + local template_name="app" + [[ -n "$type" ]] && template_name="app-${type}" + local template_dir="${BITNAMI_ROOT_DIR}/scripts/nginx/bitnami-templates" + local prefix_file="${NGINX_CONF_DIR}/bitnami/${app}.conf" + if is_file_writable "$prefix_file"; then + # Create file with root group write privileges, so it can be modified in non-root containers + [[ ! -f "$prefix_file" ]] && touch "$prefix_file" && chmod g+rw "$prefix_file" + render-template "${template_dir}/${template_name}-prefix.conf.tpl" | sed '/^\s*$/d' >"$prefix_file" + elif [[ ! -f "$prefix_file" ]]; then + error "Could not create web server configuration file for ${app} at '${prefix_file}'. Check permissions and ownership for parent directories." + return 1 + else + warn "The ${app} web server configuration file '${prefix_file}' is not writable. Configurations based on environment variables will not be applied for this file." + fi +} + +######################## +# Ensure NGINX application configuration is updated with the runtime configuration (i.e. ports) +# Globals: +# * +# Arguments: +# $1 - App name +# Flags: +# --hosts - Hosts to enable +# --enable-http - Enable HTTP app configuration (if not enabled already) +# --enable-https - Enable HTTPS app configuration (if not enabled already) +# --disable-http - Disable HTTP app configuration (if not disabled already) +# --disable-https - Disable HTTPS app configuration (if not disabled already) +# --http-port - HTTP port number +# --https-port - HTTPS port number +# Returns: +# true if the configuration was updated, false otherwise +######################## +nginx_update_app_configuration() { + local -r app="${1:?missing app}" + # Default options + local -a hosts=() + local enable_http="no" + local enable_https="no" + local disable_http="no" + local disable_https="no" + local http_port="${NGINX_HTTP_PORT_NUMBER:-"$NGINX_DEFAULT_HTTP_PORT_NUMBER"}" + local https_port="${NGINX_HTTPS_PORT_NUMBER:-"$NGINX_DEFAULT_HTTPS_PORT_NUMBER"}" + # Validate arguments + local var_name + shift + while [[ "$#" -gt 0 ]]; do + case "$1" in + --hosts \ + | --server-aliases \ + ) + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + shift + read -r -a "$var_name" <<<"$1" + ;; + # Common flags + --enable-http \ + | --enable-https \ + | --disable-http \ + | --disable-https \ + ) + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + declare "${var_name}=yes" + ;; + --server-name \ + | --http-port \ + | --https-port \ + ) + var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")" + shift + declare "${var_name}=${1}" + ;; + + *) + echo "Invalid command line flag $1" >&2 + return 1 + ;; + esac + shift + done + # Construct host string in the format of "listen host1:port1", "listen host2:port2", ... + export http_listen_configuration="" + export https_listen_configuration="" + if [[ "${#hosts[@]}" -gt 0 ]]; then + for host in "${hosts[@]}"; do + http_listen="listen ${host}:${http_port};" + https_listen="listen ${host}:${https_port} ssl;" + [[ -z "${http_listen_configuration:-}" ]] && http_listen_configuration="$http_listen" || http_listen_configuration="${http_listen_configuration}"$'\\\n'"${http_listen}" + [[ -z "${https_listen_configuration:-}" ]] && https_listen_configuration="$https_listen" || https_listen_configuration="${https_listen_configuration}"$'\\\n'"${https_listen}" + done + else + http_listen_configuration="listen ${http_port} default_server;" + https_listen_configuration="listen ${https_port} ssl default_server;" + fi + # Indent configurations + http_listen_configuration="$(indent "$http_listen_configuration" 4)" + https_listen_configuration="$(indent "$https_listen_configuration" 4)" + # Update configuration + local -r http_server_block="${NGINX_SERVER_BLOCKS_DIR}/${app}-server-block.conf" + local -r https_server_block="${NGINX_SERVER_BLOCKS_DIR}/${app}-https-server-block.conf" + # Helper function to avoid duplicating code + update_common_server_block_config() { + local -r server_block_file="${1:?missing server block}" + # Update server_name + if ! is_empty_value "${server_name:-}"; then + local server_name_list="$server_name" + if [[ "${#server_aliases[@]}" -gt 0 ]]; then + server_name_list+=" ${server_aliases[*]}" + fi + replace_in_file "$server_block_file" "^(\s*server_name\s+)[^;]*" "\1${server_name_list}" + fi + } + # Disable and enable configuration files + rename_conf_file() { + local -r origin="$1" + local -r destination="$2" + if is_file_writable "$origin" && is_file_writable "$destination"; then + warn "Could not rename server block file '${origin}' to '${destination}' due to lack of permissions." + else + mv "$origin" "$destination" + fi + } + is_boolean_yes "$disable_http" && [[ -e "$http_server_block" ]] && rename_conf_file "${http_server_block}${disable_suffix}" "$http_server_block" + is_boolean_yes "$disable_https" && [[ -e "$https_server_block" ]] && rename_conf_file "${https_server_block}${disable_suffix}" "$https_server_block" + is_boolean_yes "$enable_http" && [[ -e "${http_server_block}${disable_suffix}" ]] && rename_conf_file "${http_server_block}${disable_suffix}" "$http_server_block" + is_boolean_yes "$enable_https" && [[ -e "${https_server_block}${disable_suffix}" ]] && rename_conf_file "${https_server_block}${disable_suffix}" "$https_server_block" + # Update only configuration files without the '.disabled' suffix + if [[ -e "$http_server_block" ]]; then + if is_file_writable "$http_server_block"; then + update_common_server_block_config "$http_server_block" + # Update specific server block config (listen addresses) + replace_in_file "$http_server_block" "^\s*listen\s.*;" "$http_listen_configuration" + else + warn "The ${app} server block file '${http_server_block}' is not writable. Configurations based on environment variables will not be applied for this file." + fi + fi + if [[ -e "$https_server_block" ]]; then + if is_file_writable "$https_server_block"; then + update_common_server_block_config "$https_server_block" + # Update specific server block config (listen addresses) + replace_in_file "$https_server_block" "^\s*listen\s.*\sssl;" "$https_listen_configuration" + else + warn "The ${app} server block file '${https_server_block}' is not writable. Configurations based on environment variables will not be applied for this file." + fi + fi +} + +######################## +# Run custom initialization scripts +# Globals: +# NGINX_* +# Arguments: +# None +# Returns: +# None +######################### +nginx_custom_init_scripts() { + if [[ -n $(find "${NGINX_INITSCRIPTS_DIR}/" -type f -regex ".*\.sh") ]]; then + info "Loading user's custom files from $NGINX_INITSCRIPTS_DIR ..." + local -r tmp_file="/tmp/filelist" + find "${NGINX_INITSCRIPTS_DIR}/" -type f -regex ".*\.sh" | sort >"$tmp_file" + while read -r f; do + case "$f" in + *.sh) + if [[ -x "$f" ]]; then + debug "Executing $f" + "$f" + else + debug "Sourcing $f" + . "$f" + fi + ;; + *) + debug "Ignoring $f" + ;; + esac + done <$tmp_file + nginx_stop + rm -f "$tmp_file" + else + info "No custom scripts in $NGINX_INITSCRIPTS_DIR" + fi +} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx-env.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx-env.sh new file mode 100644 index 000000000000..2abd9daf2453 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx-env.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# +# Environment configuration for nginx + +# The values for all environment variables will be set in the below order of precedence +# 1. Custom environment variables defined below after Bitnami defaults +# 2. Constants defined in this file (environment variables with no default), i.e. BITNAMI_ROOT_DIR +# 3. Environment variables overridden via external files using *_FILE variables (see below) +# 4. Environment variables set externally (i.e. current Bash context/Dockerfile/userdata) + +# Load logging library +# shellcheck disable=SC1090,SC1091 +. /opt/bitnami/scripts/liblog.sh + +export BITNAMI_ROOT_DIR="/opt/bitnami" +export BITNAMI_VOLUME_DIR="/bitnami" + +# Logging configuration +export MODULE="${MODULE:-nginx}" +export BITNAMI_DEBUG="${BITNAMI_DEBUG:-false}" + +# By setting an environment variable matching *_FILE to a file path, the prefixed environment +# variable will be overridden with the value specified in that file +nginx_env_vars=( + NGINX_HTTP_PORT_NUMBER + NGINX_HTTPS_PORT_NUMBER + NGINX_ENABLE_ABSOLUTE_REDIRECT + NGINX_ENABLE_PORT_IN_REDIRECT +) +for env_var in "${nginx_env_vars[@]}"; do + file_env_var="${env_var}_FILE" + if [[ -n "${!file_env_var:-}" ]]; then + if [[ -r "${!file_env_var:-}" ]]; then + export "${env_var}=$(< "${!file_env_var}")" + unset "${file_env_var}" + else + warn "Skipping export of '${env_var}'. '${!file_env_var:-}' is not readable." + fi + fi +done +unset nginx_env_vars +export WEB_SERVER_TYPE="nginx" + +# Paths +export NGINX_BASE_DIR="${BITNAMI_ROOT_DIR}/nginx" +export NGINX_VOLUME_DIR="${BITNAMI_VOLUME_DIR}/nginx" +export NGINX_SBIN_DIR="${NGINX_BASE_DIR}/sbin" +export NGINX_CONF_DIR="${NGINX_BASE_DIR}/conf" +export NGINX_HTDOCS_DIR="${NGINX_BASE_DIR}/html" +export NGINX_TMP_DIR="${NGINX_BASE_DIR}/tmp" +export NGINX_LOGS_DIR="${NGINX_BASE_DIR}/logs" +export NGINX_SERVER_BLOCKS_DIR="${NGINX_CONF_DIR}/server_blocks" +export NGINX_INITSCRIPTS_DIR="/docker-entrypoint-initdb.d" +export NGINX_CONF_FILE="${NGINX_CONF_DIR}/nginx.conf" +export NGINX_PID_FILE="${NGINX_TMP_DIR}/nginx.pid" +export PATH="${NGINX_SBIN_DIR}:${BITNAMI_ROOT_DIR}/common/bin:${PATH}" + +# System users (when running with a privileged user) +export NGINX_DAEMON_USER="daemon" +export WEB_SERVER_DAEMON_USER="$NGINX_DAEMON_USER" +export NGINX_DAEMON_GROUP="daemon" +export WEB_SERVER_DAEMON_GROUP="$NGINX_DAEMON_GROUP" +export NGINX_DEFAULT_HTTP_PORT_NUMBER="8080" +export WEB_SERVER_DEFAULT_HTTP_PORT_NUMBER="$NGINX_DEFAULT_HTTP_PORT_NUMBER" # only used at build time +export NGINX_DEFAULT_HTTPS_PORT_NUMBER="8443" +export WEB_SERVER_DEFAULT_HTTPS_PORT_NUMBER="$NGINX_DEFAULT_HTTPS_PORT_NUMBER" # only used at build time + +# NGINX configuration +export NGINX_HTTP_PORT_NUMBER="${NGINX_HTTP_PORT_NUMBER:-}" +export WEB_SERVER_HTTP_PORT_NUMBER="$NGINX_HTTP_PORT_NUMBER" +export NGINX_HTTPS_PORT_NUMBER="${NGINX_HTTPS_PORT_NUMBER:-}" +export WEB_SERVER_HTTPS_PORT_NUMBER="$NGINX_HTTPS_PORT_NUMBER" +export NGINX_ENABLE_ABSOLUTE_REDIRECT="${NGINX_ENABLE_ABSOLUTE_REDIRECT:-no}" +export NGINX_ENABLE_PORT_IN_REDIRECT="${NGINX_ENABLE_PORT_IN_REDIRECT:-no}" + +# Custom environment variables may be defined below diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-http-server-block.conf.tpl b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-http-server-block.conf.tpl new file mode 100644 index 000000000000..4ebeed573889 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-http-server-block.conf.tpl @@ -0,0 +1,16 @@ +{{external_configuration}} + +server { + # Port to listen on, can also be set in IP:PORT format + {{http_listen_configuration}} + + root {{document_root}}; + + {{server_name_configuration}} + + {{acl_configuration}} + + {{additional_configuration}} + + include "/opt/bitnami/nginx/conf/bitnami/*.conf"; +} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-https-server-block.conf.tpl b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-https-server-block.conf.tpl new file mode 100644 index 000000000000..02acfbb055c6 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-https-server-block.conf.tpl @@ -0,0 +1,19 @@ +{{external_configuration}} + +server { + # Port to listen on, can also be set in IP:PORT format + {{https_listen_configuration}} + + root {{document_root}}; + + {{server_name_configuration}} + + ssl_certificate bitnami/certs/server.crt; + ssl_certificate_key bitnami/certs/server.key; + + {{acl_configuration}} + + {{additional_configuration}} + + include "/opt/bitnami/nginx/conf/bitnami/*.conf"; +} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-php-prefix.conf.tpl b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-php-prefix.conf.tpl new file mode 100644 index 000000000000..28bb0393aaa3 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-php-prefix.conf.tpl @@ -0,0 +1,10 @@ +location ^~ {{location}} { + alias "{{document_root}}"; + + {{acl_configuration}} + + include "/opt/bitnami/nginx/conf/bitnami/protect-hidden-files.conf"; + include "/opt/bitnami/nginx/conf/bitnami/php-fpm.conf"; +} + +{{additional_configuration}} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-prefix.conf.tpl b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-prefix.conf.tpl new file mode 100644 index 000000000000..b7d04e1e80f7 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/bitnami-templates/app-prefix.conf.tpl @@ -0,0 +1,9 @@ +location ^~ {{location}} { + alias "{{document_root}}"; + + {{acl_configuration}} + + include "/opt/bitnami/nginx/conf/bitnami/protect-hidden-files.conf"; +} + +{{additional_configuration}} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/entrypoint.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/entrypoint.sh new file mode 100755 index 000000000000..3e5da894a4ec --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libbitnami.sh +. /opt/bitnami/scripts/libnginx.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +print_welcome_page + +if [[ "$1" = "/opt/bitnami/scripts/nginx/run.sh" ]]; then + info "** Starting NGINX setup **" + /opt/bitnami/scripts/nginx/setup.sh + info "** NGINX setup finished! **" +fi + +echo "" +exec "$@" diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/postunpack.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/postunpack.sh new file mode 100755 index 000000000000..0851efcbb934 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/postunpack.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libnginx.sh +. /opt/bitnami/scripts/libfs.sh + +# Auxiliar Functions + +######################## +# Unset HTTP_PROXY header to protect vs HTTPPOXY vulnerability +# Ref: https://www.digitalocean.com/community/tutorials/how-to-protect-your-server-against-the-httpoxy-vulnerability +# Globals: +# NGINX_* +# Arguments: +# None +# Returns: +# None +######################### +nginx_patch_httpoxy_vulnerability() { + debug "Unsetting HTTP_PROXY header..." + echo '# Unset the HTTP_PROXY header' >>"${NGINX_CONF_DIR}/fastcgi_params" + echo 'fastcgi_param HTTP_PROXY "";' >>"${NGINX_CONF_DIR}/fastcgi_params" +} + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +# Remove unnecessary directories that come with the tarball +rm -rf "${BITNAMI_ROOT_DIR}/certs" "${BITNAMI_ROOT_DIR}/server_blocks" + +# Ensure non-root user has write permissions on a set of directories +for dir in "$NGINX_VOLUME_DIR" "$NGINX_CONF_DIR" "$NGINX_INITSCRIPTS_DIR" "$NGINX_SERVER_BLOCKS_DIR" "${NGINX_CONF_DIR}/bitnami" "$NGINX_LOGS_DIR" "$NGINX_TMP_DIR"; do + ensure_dir_exists "$dir" + chmod -R g+rwX "$dir" +done + +# Unset HTTP_PROXY header to protect vs HTTPPOXY vulnerability +nginx_patch_httpoxy_vulnerability + +# Configure default HTTP port +nginx_configure_port "$NGINX_DEFAULT_HTTP_PORT_NUMBER" +# Configure default HTTPS port +nginx_configure_port "$NGINX_DEFAULT_HTTPS_PORT_NUMBER" "${BITNAMI_ROOT_DIR}/scripts/nginx/server_blocks/default-https-server-block.conf" + +# shellcheck disable=SC1091 + +# Load additional libraries +. /opt/bitnami/scripts/libfs.sh + +# Users can mount their html sites at /app +mv "${NGINX_BASE_DIR}/html" /app +ln -sf /app "${NGINX_BASE_DIR}/html" + +# Users can mount their certificates at /certs +mv "${NGINX_CONF_DIR}/bitnami/certs" /certs +ln -sf /certs "${NGINX_CONF_DIR}/bitnami/certs" + +ln -sf "/dev/stdout" "${NGINX_LOGS_DIR}/access.log" +ln -sf "/dev/stderr" "${NGINX_LOGS_DIR}/error.log" diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/reload.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/reload.sh new file mode 100755 index 000000000000..875a05e38270 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/reload.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libnginx.sh +. /opt/bitnami/scripts/liblog.sh + +# Load NGINX environment +. /opt/bitnami/scripts/nginx-env.sh + +info "** Reloading NGINX configuration **" +exec "${NGINX_SBIN_DIR}/nginx" -s reload diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/restart.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/restart.sh new file mode 100755 index 000000000000..453d23f3abca --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/restart.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libnginx.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +/opt/bitnami/scripts/nginx/stop.sh +/opt/bitnami/scripts/nginx/start.sh diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/run.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/run.sh new file mode 100755 index 000000000000..339c0d11d2a1 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/run.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/liblog.sh +. /opt/bitnami/scripts/libnginx.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +info "** Starting NGINX **" +exec "${NGINX_SBIN_DIR}/nginx" -c "$NGINX_CONF_FILE" -g "daemon off;" diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/server_blocks/default-https-server-block.conf b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/server_blocks/default-https-server-block.conf new file mode 100644 index 000000000000..27284a637c31 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/server_blocks/default-https-server-block.conf @@ -0,0 +1,17 @@ +# HTTPS Server +server { + # Port to listen on, can also be set in IP:PORT format + listen 443 ssl; + + ssl_certificate bitnami/certs/server.crt; + ssl_certificate_key bitnami/certs/server.key; + + include "/opt/bitnami/nginx/conf/bitnami/*.conf"; + + location /status { + stub_status on; + access_log off; + allow 127.0.0.1; + deny all; + } +} diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/setup.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/setup.sh new file mode 100755 index 000000000000..c4239c164771 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/setup.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/libfs.sh +. /opt/bitnami/scripts/libnginx.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +# Ensure NGINX environment variables settings are valid +nginx_validate + +# Ensure NGINX is stopped when this script ends +trap "nginx_stop" EXIT + +# Ensure NGINX daemon user exists when running as 'root' +am_i_root && ensure_user_exists "$NGINX_DAEMON_USER" --group "$NGINX_DAEMON_GROUP" + +# Run init scripts +nginx_custom_init_scripts + +# Fix logging issue when running as root +! am_i_root || chmod o+w "$(readlink /dev/stdout)" "$(readlink /dev/stderr)" + +# Configure HTTPS port number +if [[ -n "${NGINX_HTTPS_PORT_NUMBER:-}" ]] && [[ ! -f "${NGINX_SERVER_BLOCKS_DIR}/default-https-server-block.conf" ]] && is_dir_empty "${NGINX_SERVER_BLOCKS_DIR}"; then + cp "${BITNAMI_ROOT_DIR}/scripts/nginx/server_blocks/default-https-server-block.conf" "${NGINX_SERVER_BLOCKS_DIR}/default-https-server-block.conf" +fi + +# Initialize NGINX +nginx_initialize + diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/start.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/start.sh new file mode 100755 index 000000000000..1c13ec73e24b --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/start.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libnginx.sh +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/liblog.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +error_code=0 + +if is_nginx_not_running; then + "${NGINX_SBIN_DIR}/nginx" -c "$NGINX_CONF_FILE" + if ! retry_while "is_nginx_running"; then + error "nginx did not start" + error_code=1 + else + info "nginx started" + fi +else + info "nginx is already running" +fi + +exit "$error_code" diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/status.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/status.sh new file mode 100755 index 000000000000..00bac3c38b2b --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/status.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libnginx.sh +. /opt/bitnami/scripts/liblog.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +if is_nginx_running; then + info "nginx is already running" +else + info "nginx is not running" +fi diff --git a/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/stop.sh b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/stop.sh new file mode 100755 index 000000000000..26a510e9d7f8 --- /dev/null +++ b/bitnami/appsmith/1/debian-11/rootfs/opt/bitnami/scripts/nginx/stop.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# shellcheck disable=SC1091 + +set -o errexit +set -o nounset +set -o pipefail +# set -o xtrace # Uncomment this line for debugging purposes + +# Load libraries +. /opt/bitnami/scripts/libnginx.sh +. /opt/bitnami/scripts/libos.sh +. /opt/bitnami/scripts/liblog.sh + +# Load NGINX environment variables +. /opt/bitnami/scripts/nginx-env.sh + +error_code=0 + +if is_nginx_running; then + BITNAMI_QUIET=1 nginx_stop + if ! retry_while "is_nginx_not_running"; then + error "nginx could not be stopped" + error_code=1 + else + info "nginx stopped" + fi +else + info "nginx is not running" +fi + +exit "$error_code" diff --git a/bitnami/appsmith/1/debian-11/tags-info.yaml b/bitnami/appsmith/1/debian-11/tags-info.yaml new file mode 100644 index 000000000000..c3e88447b5dd --- /dev/null +++ b/bitnami/appsmith/1/debian-11/tags-info.yaml @@ -0,0 +1,5 @@ +rolling-tags: + - "1" + - "1-debian-11" + - "1.8.8" + - "latest" diff --git a/bitnami/appsmith/README.md b/bitnami/appsmith/README.md new file mode 100644 index 000000000000..b44e54f14615 --- /dev/null +++ b/bitnami/appsmith/README.md @@ -0,0 +1,242 @@ +# Appsmith packaged by Bitnami + +## What is Appsmith? + +> Appsmith is an open source platform for building and maintaining internal tools, such as custom dashboards, admin panels or CRUD apps. + +[Overview of Appsmith](https://www.appsmith.com/) + +Trademarks: This software listing is packaged by Bitnami. The respective trademarks mentioned in the offering are owned by the respective companies, and use of them does not imply any affiliation or endorsement. + +## TL;DR + +```console +$ docker run -it --name appsmith bitnami/appsmith +``` + +### Docker Compose + +```console +$ curl -sSL https://raw.githubusercontent.com/bitnami/containers/main/bitnami/appsmith/docker-compose.yml > docker-compose.yml +$ docker-compose up -d +``` + +## Why use Bitnami Images? + +* Bitnami closely tracks upstream source changes and promptly publishes new versions of this image using our automated systems. +* With Bitnami images the latest bug fixes and features are available as soon as possible. +* Bitnami containers, virtual machines and cloud images use the same components and configuration approach - making it easy to switch between formats based on your project needs. +* All our images are based on [minideb](https://github.com/bitnami/minideb) a minimalist Debian based container image which gives you a small base container image and the familiarity of a leading Linux distribution. +* All Bitnami images available in Docker Hub are signed with [Docker Content Trust (DCT)](https://docs.docker.com/engine/security/trust/content_trust/). You can use `DOCKER_CONTENT_TRUST=1` to verify the integrity of the images. +* Bitnami container images are released on a regular basis with the latest distribution packages available. + +## Supported tags and respective `Dockerfile` links + +Learn more about the Bitnami tagging policy and the difference between rolling tags and immutable tags [in our documentation page](https://docs.bitnami.com/tutorials/understand-rolling-tags-containers/). + +You can see the equivalence between the different tags by taking a look at the `tags-info.yaml` file present in the branch folder, i.e `bitnami/ASSET/BRANCH/DISTRO/tags-info.yaml`. + +Subscribe to project updates by watching the [bitnami/containers GitHub repo](https://github.com/bitnami/containers). + +## Get this image + +The recommended way to get the Bitnami Appsmith Docker Image is to pull the prebuilt image from the [Docker Hub Registry](https://hub.docker.com/r/bitnami/appsmith). + +```console +$ docker pull bitnami/appsmith:latest +``` + +To use a specific version, you can pull a versioned tag. You can view the [list of available versions](https://hub.docker.com/r/bitnami/appsmith/tags/) in the Docker Hub Registry. + +```console +$ docker pull bitnami/appsmith:[TAG] +``` + +If you wish, you can also build the image yourself by cloning the repository, changing to the directory containing the Dockerfile and executing the `docker build` command. Remember to replace the `APP`, `VERSION` and `OPERATING-SYSTEM` path placeholders in the example command below with the correct values. + +```console +$ git clone https://github.com/bitnami/containers.git +$ cd bitnami/APP/VERSION/OPERATING-SYSTEM +$ docker build -t bitnami/APP:latest . +``` + +## Maintenance + +### Upgrade this image + +Bitnami provides up-to-date versions of Appsmith, including security patches, soon after they are made upstream. We recommend that you follow these steps to upgrade your container. + +#### Step 1: Get the updated image + +```console +$ docker pull bitnami/appsmith:latest +``` + +or if you're using Docker Compose, update the value of the image property to `bitnami/appsmith:latest`. + +#### Step 2: Remove the currently running container + +```console +$ docker rm -v appsmith +``` + +or using Docker Compose: + +```console +$ docker-compose rm -v appsmith +``` + +#### Step 3: Run the new image + +Re-create your container from the new image. + +```console +$ docker run --name appsmith bitnami/appsmith:latest +``` + +or using Docker Compose: + +```console +$ docker-compose up appsmith +``` + +## Configuration + +### Environment variables + +When you start the Appsmith image, you can adjust the configuration of the instance by passing one or more environment variables either on the docker-compose file or on the `docker run` command line. Please note that some variables are only considered when the container is started for the first time. If you want to add a new environment variable: + +- For docker-compose add the variable name and value under the application section in the [`docker-compose.yml`](https://github.com/bitnami/containers/blob/main/bitnami/appsmith/docker-compose.yml) file present in this repository: + + ```yaml + appsmith-api: + ... + environment: + - APPSMITH_PASSWORD=my_password + ... + ``` + +- For manual execution add a `--env` option with each variable and value: + + ```console + $ docker run -d --name appsmith-api -p 80:8080 -p 443:8443 \ + --env APPSMITH_PASSWORD=my_password \ + --env APPSMITH_MODE=backend \ + --network appsmith-tier \ + --volume /path/to/appsmith-persistence:/bitnami \ + bitnami/appsmith:latest + ``` + +Available environment variables: + +#### Run mode + +Appsmith supports three running modes: + +- Backend: The Appsmith API. It is the essential functional element of Appsmith. +- RTS: Necessary for performing real-time editing of the applications created by Appsmith. +- Client: Contains the UI of Appsmith. This is the main entrypoint for users. + +The running mode is defined via the `APPSMITH_MODE` environment variable. The possible values are `backend`, `rts` and `client`. + +##### User and Site configuration + +- `APPSMITH_UI_HTTP_PORT`: Port used by the Client for HTTP. Default: **8080** +- `APPSMITH_USERNAME`: Appsmith application username. Default: **user** +- `APPSMITH_PASSWORD`: Appsmith application password. Default: **bitnami** +- `APPSMITH_EMAIL`: Appsmith application email. Default: **user@example.com** +- `APPSMITH_DATA_TO_PERSIST`: Space separated list of files and directories to persist. Use a space to persist no data: `" "`. Default: **"docker.env"** + +##### Salt and keys configuration + +Authentication unique keys and salts. Specify these values to prevent cookies from being invalidated when creating a new container or when using multiple containers to serve the same Appsmith instance. By default these values are generated randomly: + +- `APPSMITH_ENCRYPTION_PASSWORD`: Database encryption password. Default: **bitnami**. +- `APPSMITH_ENCRYPTION_SALT`: Database encryption salt. Default: **bitnami**. + +##### Database connection configuration + +- `APPSMITH_DATABASE_HOST`: Hostname for the MongoDB(TM) servers (comma separated). Default: **mongodb** +- `APPSMITH_DATABASE_PORT_NUMBER`: Port used by the MongoDB(TM) server. Default: **27017** +- `APPSMITH_DATABASE_NAME`: Database name that Appsmith will use to connect with the database. Default: **bitnami_appsmith** +- `APPSMITH_DATABASE_USER`: Database user that Appsmith will use to connect with the database. Default: **bn_appsmith** +- `APPSMITH_DATABASE_PASSWORD`: Database password that Appsmith will use to connect with the database. No defaults. +- `APPSMITH_REDIS_HOST`: Hostname for the Redis(TM) server. Default: **redis** +- `APPSMITH_REDIS_PORT_NUMBER`: Port used by the Redis(TM) server. Default: **6379** +- `APPSMITH_REDIS_PASSWORD`: Database password that Appsmith will use to connect with the database. No defaults. +- `ALLOW_EMPTY_PASSWORD`: It can be used to allow blank passwords. Default: **no** + +##### Connect Appsmith container to an existing database + +The Bitnami Appsmith container supports connecting the Appsmith application to an external database. This would be an example of using an external database for Appsmith. + +- Modify the [`docker-compose.yml`](https://github.com/bitnami/containers/blob/main/bitnami/appsmith/docker-compose.yml) file present in this repository: + + ```diff + appsmith: + ... + environment: + - - APPSMITH_DATABASE_HOST=mongodb + + - APPSMITH_DATABASE_HOST=mongodb_host + - APPSMITH_DATABASE_PORT_NUMBER=27017 + - APPSMITH_DATABASE_NAME=appsmith_db + - APPSMITH_DATABASE_USER=appsmith_user + - - ALLOW_EMPTY_PASSWORD=yes + + - APPSMITH_DATABASE_PASSWORD=appsmith_password + ... + ``` + +- For manual execution: + + ```console + $ docker run -d --name appsmith\ + -p 8080:8080 -p 8443:8443 \ + --network appsmith-network \ + --env APPSMITH_DATABASE_HOST=mongodb_host \ + --env APPSMITH_DATABASE_PORT_NUMBER=27017 \ + --env APPSMITH_DATABASE_NAME=appsmith_db \ + --env APPSMITH_DATABASE_USER=appsmith_user \ + --env APPSMITH_DATABASE_PASSWORD=appsmith_password \ + --volume appsmith_data:/bitnami/appsmith \ + bitnami/appsmith:latest + ``` + +## Logging + +The Bitnami Appsmith Docker image sends the container logs to `stdout`. To view the logs: + +```console +$ docker logs wordpress +``` + +Or using Docker Compose: + +```console +$ docker-compose logs wordpress +``` + +You can configure the containers [logging driver](https://docs.docker.com/engine/admin/logging/overview/) using the `--log-driver` option if you wish to consume the container logs differently. In the default configuration docker uses the `json-file` driver. + +## Contributing + +We'd love for you to contribute to this Docker image. You can request new features by creating an [issue](https://github.com/bitnami/containers/issues) or submitting a [pull request](https://github.com/bitnami/containers/pulls) with your contribution. + +## Issues + +If you encountered a problem running this container, you can file an [issue](https://github.com/bitnami/containers/issues/new/choose). For us to provide better support, be sure to fill the issue template. + +## License + +Copyright © 2022 Bitnami + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bitnami/appsmith/docker-compose.yml b/bitnami/appsmith/docker-compose.yml new file mode 100644 index 000000000000..048ede7aad18 --- /dev/null +++ b/bitnami/appsmith/docker-compose.yml @@ -0,0 +1,80 @@ +version: '2' +services: + mongodb: + image: docker.io/bitnami/mongodb:6.0 + volumes: + - 'mongodb_data:/bitnami/mongodb' + environment: + - MONGODB_ADVERTISED_HOSTNAME=mongodb + - MONGODB_USERNAME=bn_appsmith + - MONGODB_DATABASE=bitnami_appsmith + - MONGODB_PASSWORD=bitnami123 + - MONGODB_ROOT_PASSWORD=password123 + - MONGODB_REPLICA_SET_MODE=primary + - MONGODB_REPLICA_SET_KEY=replicasetkey123 + + mongodb-secondary: + image: docker.io/bitnami/mongodb:6.0 + depends_on: + - mongodb + volumes: + - 'mongodb_secondary_data:/bitnami/mongodb' + environment: + - MONGODB_ADVERTISED_HOSTNAME=mongodb-secondary + - MONGODB_REPLICA_SET_MODE=secondary + - MONGODB_INITIAL_PRIMARY_HOST=mongodb + - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123 + - MONGODB_REPLICA_SET_KEY=replicasetkey123 + redis: + image: docker.io/bitnami/redis:7.0 + volumes: + - 'redis_data:/bitnami/redis' + environment: + - REDIS_PASSWORD=bitmame123 + appsmith: + image: docker.io/bitnami/appsmith:1 + environment: + - APPSMITH_MODE=client + - APPSMITH_API_HOST=appsmith-api + - APPSMITH_RTS_HOST=appsmith-rts + ports: + - 80:8080 + appsmith-api: + image: docker.io/bitnami/appsmith:1 + environment: + - APPSMITH_MODE=backend + - BITNAMI_DEBUG=true + - APPSMITH_API_HOST=appsmith-api + - APPSMITH_DATABASE_HOST=mongodb,mongodb-secondary + - APPSMITH_DATABASE_PORT_NUMBER=27017 + - APPSMITH_DATABASE_USER=bn_appsmith + - APPSMITH_DATABASE_NAME=bitnami_appsmith + - APPSMITH_DATABASE_PASSWORD=bitnami123 + - APPSMITH_REDIS_PASSWORD=bitmame123 + - APPSMITH_ENCRYPTION_PASSWORD=test123 + - APPSMITH_ENCRYPTION_SALT=testsalt123 + # Hack: This is only necessary in docker-compose + - APPSMITH_DATABASE_INIT_DELAY=90 + volumes: + - 'appsmith_backend_data:/bitnami/appsmith' + appsmith-rts: + image: docker.io/bitnami/appsmith:1 + environment: + - APPSMITH_MODE=rts + - APPSMITH_API_HOST=appsmith-api + - APPSMITH_DATABASE_HOST=mongodb,mongodb-secondary + - APPSMITH_DATABASE_PORT_NUMBER=27017 + - APPSMITH_DATABASE_USER=bn_appsmith + - APPSMITH_DATABASE_NAME=bitnami_appsmith + - APPSMITH_DATABASE_PASSWORD=bitnami123 + # Hack: This is only necessary in docker-compose + - APPSMITH_DATABASE_INIT_DELAY=60 +volumes: + mongodb_data: + driver: local + mongodb_secondary_data: + driver: local + redis_data: + driver: local + appsmith_backend_data: + driver: local