diff --git a/README.md b/README.md index 1d6ed91..7b70c10 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,28 @@ # Easy Docker Deployment (UBUNTU ONLY) With this script we can easily deploy docker containers of Joomla and Openssh. This combination of these tools give rise to a powerful and very secure shared development environment. -Both the installation and deployment script has **command input** options as seen in the menus below, but these command ar _not the only way_ to set these values. When the values are **omitted** you will be _asked in the terminal_ to manually enter the required values as needed. Furthermore, the use of **env variables** are also heavily used across the script. There are more than one .env file and the script will set those up for you whenever you run a task that make use of env variables the script will check if those values exist, and if they don't it will ask for them, and store them automatically for future use. That same time the output message to the terminal will show you where the specific .env file can be found. +This program has **command input** options as seen in the menus below, but these command are _not the only way_ to set these values. +When the values are **omitted** you will be _asked in the terminal_ to manually enter the required values as needed. +Furthermore, the use of **env variables** are also heavily used across the script. +There are more than one .env file and the script will set those up for you whenever you run a task that make use of env variables +the script will check if those values exist, and if they don't it will ask for them, and store them automatically for future use. +That same time the output message to the terminal will show you where the specific .env file can be found. --- # Install ```shell -$ git clone https://git.vdm.dev/octoleo/docker-deploy.git -$ cd docker-deploy/src -$ sudo chmod +x install.sh -$ sudo ./install.sh -``` -> To see the installation help menu: -```shell -$ ./install.sh -h +$ sudo curl -L "https://git.vdm.dev/api/v1/repos/octoleo/docker-deploy/raw/src/docker-deploy?access_token=xxxx" -o /usr/local/bin/docker-deploy +$ sudo chmod +x /usr/local/bin/docker-deploy ``` -### Help Menu (install) -```txt -Usage: ./install.sh [OPTION...] - Options - ====================================================== - --src-path=|--src= - set path to the script source folder - example: ./install.sh --src=/home/username/Docker/src - example: ./install.sh --src-path=/home/username/Docker/src - ====================================================== - --repo-path=|--repo= - set path to the repository folder - example: ./install.sh --repo=/home/username/Docker - example: ./install.sh --repo-path=/home/username/Docker - ====================================================== - --project-path=|--project= - set path to the projects folder - example: ./install.sh --project=/home/username/Projects - example: ./install.sh --project-path=/home/username/Projects - ====================================================== - -f|--force - force installation - example: ./install.sh -f - example: ./install.sh --force - ====================================================== - --host - always update your host file - example: ./install.sh --host - ====================================================== - -h|--help - display this help menu - example: ./install.sh -h - example: ./install.sh --help - ====================================================== - docker-deploy v1.0 - ====================================================== -``` +### How to get the Access Token +Sign in to [https://git.vdm.dev/](https://git.vdm.dev/user/login) with your **GitHub** or **Gitlab** account. +Then open your [applications settings](https://git.vdm.dev/user/settings/applications) and create a new access token. + +![image](https://user-images.githubusercontent.com/5607939/143513412-946843be-acd8-4973-be44-00902226f6ba.png) + +The first time you use the program, it will ask for the access token again, so it can do updates in the future. + --- # Usage @@ -73,10 +43,23 @@ Usage: docker-deploy [OPTION...] set type of task you would like to perform example: docker-deploy --task setup ====================================================== + --container + Directly enabling or disabling a container with + the type=joomla and task=enable/disable set + The container must exist, which means it was + setup previously + Used without type and task Joomla-Enable is (default) + example: docker-deploy --container "io.vdm.dev" + ====================================================== --update to update your install example: docker-deploy --update ====================================================== + --access-token + to update the program you will need an access token + from https://git.vdm.dev/user/settings/applications + example: docker-deploy --access-token xxxxxxxxxxx + ====================================================== --uninstall to uninstall this script example: docker-deploy --uninstall @@ -162,7 +145,7 @@ Usage: docker-deploy [OPTION...] example: docker-deploy -h example: docker-deploy --help ====================================================== - docker-deploy v1.0 + Docker Deploy v2.0 ====================================================== ``` --- diff --git a/src/delete.sh b/src/delete.sh deleted file mode 100644 index acf6f46..0000000 --- a/src/delete.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/bash - -# check that our enabled containers path is correct -[ -e "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available" ] || { - echo "[error] Available containers path ${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available does not exist." - exit 1 -} - -# action to delete -function askToDelete() { - # some house cleaning - PS3_old=$PS3 - # set the local value - local question - local path - local target - # now set the values - question="$1" - path="$2" - target="$3" - # some defaults - echo "${question}" - # set the terminal - export PS3="[select]: " - # Start our little Menu - select yn in "Yes" "No"; do - case $yn in - Yes ) sudo rm -rf "${path}"; echo "[notice] ${target} was deleted.";; - No ) echo "[notice] ${target} was not deleted.";; - esac - break - done - # restore the default - export PS3=$PS3_old -} - -# get container available for deletion -function getContainer() { - # some house cleaning - PS3_old=$PS3 - # some defaults - export PS3="Please select ${VDM_CONTAINER_TYPE} container deploy files to delete: " - # Start our little Menu - select menu in $(ls "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/"); do - case $REPLY in - *) - SELECTED="$menu" - ;; - esac - break - done - # restore the default - export PS3=$PS3_old - # return selection - echo "$SELECTED" -} - -# set the container -CONTAINER="${1:-$CONTAINER}" -[ ${#CONTAINER} -ge 1 ] && [ -e "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${CONTAINER}" ] || { - CONTAINER=$(getContainer) - # make sure value was entered - [ ${#CONTAINER} -ge 1 ] && [ -e "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${CONTAINER}" ] || exit -} - -# disable -if [ -e "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/${CONTAINER}" ]; then - # make sure the docker image is stopped - docker-compose --file "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/${CONTAINER}/docker-compose.yml" down - # then remove soft link - rm "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/${CONTAINER}" -fi - -# remove the files with one last confirmation -askToDelete \ - "Are you absolutely sure you would like to complete delete the ${VDM_CONTAINER_TYPE} ${CONTAINER} deploy files?" \ - "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${CONTAINER}" \ - "${CONTAINER}" - -# check that our project path is correct -[ -e "${VDM_PROJECT_PATH}" ] || { - echo "[error] Project path (${VDM_PROJECT_PATH}) does not exist." - exit 1 -} - -# make sites available selection -function getProjectsAvailable() { - # some house cleaning - PS3_old=$PS3 - # some defaults - export PS3="Please select persistent volume folder to delete: " - # Start our little Menu - select menu in $(ls "${VDM_PROJECT_PATH}"); do - case $REPLY in - *) - SELECTED="$menu" - ;; - esac - break - done - # restore the default - export PS3=$PS3_old - # return selection - echo "$SELECTED" -} - -# set the local values -VDM_PROJECT="${2:-$VDM_PROJECT}" -# check that we have what we need -# shellcheck disable=SC2015 -[ ${#VDM_PROJECT} -ge 1 ] && [ -d "${VDM_PROJECT_PATH}/${VDM_PROJECT}" ] || { - VDM_PROJECT=$(getProjectsAvailable) - # make sure value was entered - [ ${#VDM_PROJECT} -ge 1 ] && [ -d "${VDM_PROJECT_PATH}/${VDM_PROJECT}" ] || exit -} - -# remove the files with one last confirmation -askToDelete \ - "Are you absolutely sure you would like to delete the ${VDM_PROJECT} persistent volume folders?" \ - "${VDM_PROJECT_PATH}/${VDM_PROJECT}" \ - "${VDM_PROJECT}" diff --git a/src/disable.sh b/src/disable.sh deleted file mode 100644 index 153c6c2..0000000 --- a/src/disable.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -# check that our enabled containers path is correct -[ -e "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled" ] || { - echo "[error] Enabled containers path ${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled does not exist." - exit 1 -} - -# get container enabled selection -function getContainerEnabled() { - # some house cleaning - PS3_old=$PS3 - # some defaults - export PS3="Please select container to disable: " - # Start our little Menu - select menu in $(ls "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/"); do - case $REPLY in - *) - SELECTED="$menu" - ;; - esac - break - done - # restore the default - export PS3=$PS3_old - # return selection - echo "$SELECTED" -} - -# set the container -CONTAINER="${1:-$CONTAINER}" -# check that we have what we need -# shellcheck disable=SC2015 -[ ${#CONTAINER} -ge 1 ] && [ -e "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/${CONTAINER}" ] || { - CONTAINER=$(getContainerEnabled) - # make sure value was entered - [ ${#CONTAINER} -ge 1 ] && [ -e "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/${CONTAINER}" ] || exit -} - -# make sure the docker image is stopped -docker-compose --file "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/${CONTAINER}/docker-compose.yml" down -# then remove soft link -rm "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/enabled/${CONTAINER}" diff --git a/src/docker-deploy b/src/docker-deploy new file mode 100755 index 0000000..f113638 --- /dev/null +++ b/src/docker-deploy @@ -0,0 +1,2598 @@ +#!/bin/bash + +# The most recent program version. +_VERSION="2.0.0" +_V="2.0" + +# The program full name +PROGRAM_NAME="Docker Deployment" + +# make sure whiptail is installed +command -v whiptail >/dev/null 2>&1 || { + echo >&2 "ERROR: ${PROGRAM_NAME} v${_VERSION} script require whiptail." + exit 1 +} +# make sure docker is installed +command -v docker >/dev/null 2>&1 || { + echo >&2 "ERROR: ${PROGRAM_NAME} v${_VERSION} script require docker." + exit 1 +} +# make sure docker-compose is installed +command -v docker-compose >/dev/null 2>&1 || { + echo >&2 "ERROR: ${PROGRAM_NAME} v${_VERSION} script require docker-compose." + exit 1 +} +# just clear the screen +clear + +#####################################################################################################################VDM +######################################## The main method +function main() { + # we check if we have a type and a task + # we use the __TRuST__ convention AS "PUBLIC METHODS" to avoid wrong calls, and hide other functions + if [ ${#VDM_CONTAINER_TYPE} -ge 1 ] && [ ${#VDM_TASK} -ge 1 ] && isFunc "${VDM_CONTAINER_TYPE}__TRuST__${VDM_TASK}"; then + "${VDM_CONTAINER_TYPE}__TRuST__${VDM_TASK}" + else + mainMenu + fi +} + +#####################################################################################################################VDM +######################################## SETUP TRAEFIK +function traefik__TRuST__setup() { + # load this container type globals + # shellcheck disable=SC1090 + [ -f "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" ] && source "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" + # check if we have secure switch set + if [ "${VDM_SECURE:-not}" = 'not' ]; then + # check the security switch + if (whiptail --yesno "Would you like to use Letsencrypt auto setup for your containers [only for server with public static IP]" --defaultno --title "Letsencrypt" 8 112); then + # we set the secure switch + VDM_SECURE=true + else + VDM_SECURE=false + fi + fi + # setup letsencrypt stuff + if $VDM_SECURE; then + VDM_REMOVE_SECURE='' + VDM_HTTP_SCHEME="https" + # get the email if not set + [ ${#VDM_SECURE_EMAIL} -ge 1 ] || { + echo -n "[enter] Email: " + read -r VDM_SECURE_EMAIL + # make sure value was entered + [ ${#VDM_SECURE_EMAIL} -ge 1 ] || exit + } + else + VDM_REMOVE_SECURE="#" + VDM_HTTP_SCHEME="http" + fi + # set the main domain if not set + while [ ${#VDM_DOMAIN} -le 1 ]; do + # get the value + VDM_DOMAIN=$(getInput "Enter main domain of all your containers.\n[only one main domain allowed for now, must have at least one dot]" \ + "vdm.dev" 'Enter Main Domain') + # keep asking if empty or does exist + [ ${#VDM_DOMAIN} -ge 1 ] || { + showError "You must enter a domain name!" + } + done + # add this value if not set variable + setEnvVariable "VDM_DOMAIN=\"${VDM_DOMAIN}\"" + # add this value if not set variable + setEnvVariable "VDM_SECURE=${VDM_SECURE}" + ########################## + ### export all we need + # global + export VDM_CONTAINER_TYPE + export VDM_REPO_PATH + export VDM_PROJECT_PATH + export VDM_DOMAIN + export VDM_SECURE + # container + export VDM_REMOVE_SECURE + export VDM_HTTP_SCHEME + export VDM_SECURE_EMAIL + ## create the directory if it does not yet already exist + # shellcheck disable=SC2174 + mkdir -p -m 700 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}" + ## place this docker composer file in its place + traefikContainer >"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" + ## set permissions + chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" + # saved the file + showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" + # ask if we should continue to enable + if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then + enableContainer "${VDM_CONTAINER_TYPE}" + fi + ########################## + ### unset all no longer needed + # container + unset VDM_REMOVE_SECURE + unset VDM_HTTP_SCHEME + unset VDM_SECURE_EMAIL + # return a success + return 0 +} + +# return the Traefik Container setup yml +function traefikContainer() { + # we build the yml file + cat <"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" + ## set permissions + chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" + # saved the file + showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" + # ask if we should continue to enable + if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then + enableContainer "${VDM_CONTAINER_TYPE}" + fi + ########################## + ### unset all no longer needed + # container + unset VDM_REMOVE_SECURE + unset VDM_ENTRY_POINT + # return a success + return 0 +} + +# return the Portainer Container setup yml +function portainerContainer() { + # we build the yml file + cat <>"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" + # get the database name needed + while [ ${#vdm_database_name} -le 1 ]; do + # get the value + vdm_database_name=$(getInput "Enter Database Name\n[Text with no spaces that is only underscore and alphabetical]" \ + "vdm_io" 'Enter Database Name') + # keep asking if empty or does exist + [ ${#vdm_database_name} -ge 1 ] || { + showError "You must enter a database name!" + } + done + # get the database user name needed + while [ ${#vdm_database_user} -le 1 ]; do + # get the value + vdm_database_user=$(getInput "Enter Database Username\n[Text with no spaces that is only underscore and alphabetical]" \ + "vdm_user" 'Enter Database Username') + # keep asking if empty or does exist + [ ${#vdm_database_user} -ge 1 ] || { + showError "You must enter a database username!" + } + done + # get the database user password needed + while [ ${#vdm_database_pass} -le 1 ]; do + # get the value + vdm_database_pass=$(getPassword "Enter Database User Password" \ + "$(getRandomPass 20)" 'Enter Database User Password') + # keep asking if empty or does exist + [ ${#vdm_database_pass} -ge 1 ] || { + showError "You must enter a database user password!" + } + done + # get the database root password + while [ ${#vdm_database_rootpass} -le 1 ]; do + # get the value + vdm_database_rootpass=$(getPassword "Enter Database Root Password" \ + "$(getRandomPass 40)" 'Enter Database Root Password') + # keep asking if empty or does exist + [ ${#vdm_database_rootpass} -ge 1 ] || { + showError "You must enter a database root password!" + } + done + } + # add this value if not set variable + setEnvVariable "VDM_DOMAIN=\"${VDM_DOMAIN}\"" + # add this value if not set variable + setEnvVariable "VDM_SECURE=${VDM_SECURE}" + # add this value if not set variable + setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB=\"${vdm_database_name}\"" + # add this value if not set variable + setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB_USER=\"${vdm_database_user}\"" + # add this value if not set variable + setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB_PASS=\"${vdm_database_pass}\"" + # add this value if not set variable + setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB_ROOT=\"${vdm_database_rootpass}\"" + # add the projects path + setContainerEnvVariable "VDM_PROJECT_PATH=\"${VDM_PROJECT_PATH}\"" + ########################## + ### export all we need + # global + export VDM_CONTAINER_TYPE + export VDM_REPO_PATH + export VDM_PROJECT_PATH + export VDM_DOMAIN + export VDM_SECURE + export VDM_UPDATE_HOST + # container + export VDM_SUBDOMAIN + export VDM_JV + export VDM_KEY + export VDM_ENV_KEY + export VDM_REMOVE_SECURE + export VDM_ENTRY_POINT + # container lower + export vdm_database_name + export vdm_database_user + export vdm_database_pass + export vdm_database_rootpass + # set host file if needed + updateHostFile + # create the directory if it does not yet already exist + # shellcheck disable=SC2174 + mkdir -p -m 700 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_SUBDOMAIN}.${VDM_DOMAIN}" + # place this docker composer file in its place + joomlaContainer >"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_SUBDOMAIN}.${VDM_DOMAIN}/docker-compose.yml" + # set permissions + chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_SUBDOMAIN}.${VDM_DOMAIN}/docker-compose.yml" + # saved the file + showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" + # ask if we should continue to enable + if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then + # we set the container details + export VDM_CONTAINER="${VDM_SUBDOMAIN}.${VDM_DOMAIN}" + # then we enable it + enableContainer "${VDM_CONTAINER_TYPE}" + fi + ########################## + ### unset all no longer needed + # container + unset VDM_SUBDOMAIN + unset VDM_JV + unset VDM_KEY + unset VDM_ENV_KEY + unset VDM_REMOVE_SECURE + unset VDM_ENTRY_POINT + # container lower + unset vdm_database_name + unset vdm_database_user + unset vdm_database_pass + unset vdm_database_rootpass + # return a success + return 0 +} + +# return the Joomla Container setup yml +function joomlaContainer() { + # we build the yml file + cat <"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_USER_NAME}.${VDM_DOMAIN}/docker-compose.yml" + # set permissions + chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_USER_NAME}.${VDM_DOMAIN}/docker-compose.yml" + # saved the file + showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" + # ask if we should continue to enable + if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then + # we set the container details + export VDM_CONTAINER="${VDM_USER_NAME}.${VDM_DOMAIN}" + # then we enable it + enableContainer "${VDM_CONTAINER_TYPE}" + fi + ########################## + ### unset all no longer needed + # container + unset VDM_PORT + unset VDM_USER_NAME + unset VDM_KEY + unset VDM_ENV_KEY + unset VDM_PUBLIC_KEY_GLOBAL_DIR + unset VDM_PUBLIC_KEY_U_DIR + unset VDM_PROJECT_U_PATH + # return a success + return 0 +} + +# return the Openssh Container setup yml +function opensshContainer() { + # get the projects to mount + local mount_projects="$1" + # we build the yml file + # we use 33 as this is the www-data ID + cat </dev/null; then + # give success message + echo "SUCCESS: Update was successful." + # do we have a backup + if [ -f /usr/local/bin/docker-deploy.bak ]; then + # lets remove it now + sudo rm -f /usr/local/bin/docker-deploy.bak + fi + else + # show the error + echo >&2 "ERROR: Update failed please try again later." + # do we have a backup + if [ -f /usr/local/bin/docker-deploy.bak ]; then + # move backup back + sudo mv /usr/local/bin/docker-deploy.bak /usr/local/bin/docker-deploy + fi + fi + # always set the permission again if we have a file + if [ -f /usr/local/bin/docker-deploy ]; then + # the we make sure its executable + sudo chmod +x /usr/local/bin/docker-deploy + fi + # always exit so the new script can load + exit 0 +} + +# make an uninstall +function runUninstall() { + # little notice + showNotice "We have three uninstall options: 1) Complete. 2) Just Script. 3) Make your selection." + # first safety check + if (whiptail --yesno "We are just trying to be careful here, therefore we have a few questions. Please remember there is an auto update option!\n\ + Are you absolutely sure you want to continue with the uninstalling process?" --defaultno --title "Uninstalling ${PROGRAM_NAME} v${_VERSION} " 12 112); then + # we have four main options + if (whiptail --yesno "Okay, So do you want to completely remove everything? This is the most dangerous option! IT CAN'T BE UNDONE!\ + We will remove literally everything like this script was never here." --defaultno --title "Complete Uninstall of ${PROGRAM_NAME} v${_VERSION} " 12 112); then + if [ -d "${VDM_REPO_PATH}/joomla" ]; then + # take down all joomla containers + downContainers 'joomla' + # now completely remove Joomla configurations + sudo rm -fr "${VDM_REPO_PATH}/joomla" + fi + # Remove all of Openssh Docker stuff + if [ -d "${VDM_REPO_PATH}/openssh" ]; then + # take down all joomla containers + downContainers 'openssh' + # now completely remove Joomla configurations + sudo rm -fr "${VDM_REPO_PATH}/openssh" + fi + # Remove all of Portainer Docker stuff + if [ -d "${VDM_REPO_PATH}/portainer" ]; then + # take down all portainer containers + disableContainer 'portainer' + # now completely remove Portainer configurations + sudo rm -fr "${VDM_REPO_PATH}/portainer" + fi + # Remove all of Traefik Docker stuff + if [ -d "${VDM_REPO_PATH}/traefik" ]; then + # take down all traefik containers + disableContainer 'traefik' + # now completely remove Traefik configurations + sudo rm -fr "${VDM_REPO_PATH}/traefik" + fi + # remove config if found + if [ -d "${VDM_SRC_PATH}" ]; then + sudo rm -fr "${VDM_SRC_PATH}" + fi + # remove config if found + if [ -d "${VDM_REPO_PATH}" ]; then + sudo rm -fr "${VDM_REPO_PATH}" + fi + elif (whiptail --yesno "Would you like to only remove the actual ${PROGRAM_NAME} v${_V} script but keep all the Docker stuff?" --title "Keep Docker Stuff" 8 112); then + # now remove the docker-deploy script + if [ -f /usr/local/bin/docker-deploy ]; then + sudo rm -f /usr/local/bin/docker-deploy + fi + # give the final message + whiptail --title "${PROGRAM_NAME} v${_VERSION} is UNINSTALLED" --msgbox "\n\ + ${PROGRAM_NAME} v${_V} has been uninstalled.\n\n\ + We have not touched any of the Docker stuff.\n\ + To also remove these you will have to manually pull down the Docker containers (if their are any running) and then remove the following directories.\n\n\ + DOCKER: ${VDM_REPO_PATH} \n\ + VOLUMES: ${VDM_PROJECT_PATH} \n\ + CONFIG: ${VDM_SRC_PATH}" 20 112 + # we exit here... where done! + exit 0 + else + # little notice + showNotice "This option lets you choose what you keep, so read the questions carefully! IT CAN'T BE UNDONE!" + # shellcheck disable=SC1090 + # ----------------------------------------------------- MULTI CONTAINERS + # Remove all of Joomla Docker stuff + if [ -d "${VDM_REPO_PATH}/joomla" ] && + (whiptail --yesno "Would you like to completely remove the Joomla Docker yml configurations in (${VDM_REPO_PATH}/joomla)?" --defaultno --title "Remove Docker Config" 12 112); then + # take down all joomla containers + downContainers 'joomla' + # now completely remove Joomla configurations + sudo rm -fr "${VDM_REPO_PATH}/joomla" + fi + # check if we have possible joomla containers (this will only run if they did not remove it above) + if [ -e "${VDM_REPO_PATH}/joomla/enabled" ] && + (whiptail --yesno "Would you like to take down Joomla containers?" --defaultno --title "Take Down Containers" 8 112); then + # take down all joomla containers + downContainers 'joomla' + # remove all enabled + rm -fr "${VDM_REPO_PATH}/joomla/enabled" + fi + # Remove all of Openssh Docker stuff + if [ -d "${VDM_REPO_PATH}/openssh" ] && + (whiptail --yesno "Would you like to completely remove the Openssh Docker yml configurations in (${VDM_REPO_PATH}/openssh)?" --defaultno --title "Remove Docker Config" 12 112); then + # take down all joomla containers + downContainers 'openssh' + # now completely remove Joomla configurations + sudo rm -fr "${VDM_REPO_PATH}/openssh" + fi + # check if we have possible openssh containers (this will only run if they did not remove it above) + if [ -e "${VDM_REPO_PATH}/openssh/enabled" ] && + (whiptail --yesno "Would you like to take down Openssh containers?" --defaultno --title "Take Down Containers" 8 112); then + # take down all joomla containers + downContainers 'openssh' + # remove all enabled + rm -fr "${VDM_REPO_PATH}/openssh/enabled" + fi + # ----------------------------------------------------- SINGLE CONTAINER + # Remove all of Portainer Docker stuff + if [ -d "${VDM_REPO_PATH}/portainer" ] && + (whiptail --yesno "Would you like to completely remove the Portainer Docker yml configurations in (${VDM_REPO_PATH}/portainer)?" --defaultno --title "Remove Docker Config" 12 112); then + # take down all portainer containers + disableContainer 'portainer' + # now completely remove Portainer configurations + sudo rm -fr "${VDM_REPO_PATH}/portainer" + fi + # check if we have possible portainer container (this will only run if they did not remove it above) + if [ -f "${VDM_REPO_PATH}/portainer/docker-compose.yml" ] && + (whiptail --yesno "Would you like to take down Portainer container?" --defaultno --title "Take Down Container" 8 112); then + # take down the container + disableContainer 'portainer' + fi + # Remove all of Traefik Docker stuff + if [ -d "${VDM_REPO_PATH}/traefik" ] && + (whiptail --yesno "Would you like to completely remove the Traefik Docker yml configurations in (${VDM_REPO_PATH}/traefik)?" --defaultno --title "Remove Docker Config" 12 112); then + # take down all traefik containers + disableContainer 'traefik' + # now completely remove Traefik configurations + sudo rm -fr "${VDM_REPO_PATH}/traefik" + fi + # check if we have possible traefik container (this will only run if they did not remove it above) + if [ -f "${VDM_REPO_PATH}/traefik/docker-compose.yml" ] && + (whiptail --yesno "Would you like to take down Traefik container?" --defaultno --title "Take Down Container" 8 112); then + # take down the container + disableContainer 'traefik' + fi + # remove config if found + if [ -d "${VDM_SRC_PATH}" ] && + (whiptail --yesno "Would you like to remove the global docker configurations?" --defaultno --title "Remove Docker Config" 8 112); then + sudo rm -fr "${VDM_SRC_PATH}" + fi + fi + # now remove the docker-deploy script + if [ -f /usr/local/bin/docker-deploy ]; then + sudo rm -f /usr/local/bin/docker-deploy + fi + # last and final question as this is most dangerous and serious issue. + if [ -d "${VDM_PROJECT_PATH}" ] && + (whiptail --yesno "Last question, would you like to remove all persistent volumes of your containers in (${VDM_PROJECT_PATH})?" --defaultno --title "Completely DELETE persistent volumes" 12 112); then + sudo rm -rf "${VDM_PROJECT_PATH}" + fi + # give the final message + whiptail --title "${PROGRAM_NAME} v${_VERSION} is UNINSTALLED" --msgbox "\n\n\ + ${PROGRAM_NAME} v${_V} has been uninstalled." 10 112 + # exit the program right now + exit 0 + fi +} + +# we show the octoleo info quietly +octoleoQuietly(){ + local message + # now set the message + message=" https://git.vdm.dev/octoleo/docker-deploy + + Welcome to an Octoleo Program (${PROGRAM_NAME} v$_VERSION) + + Description + With this script we can easily deploy docker containers of Joomla and Openssh. + This combination of these tools give rise to a powerful and very secure shared + development environment. + This program has **command input** options as seen in the menus item called + **Show command help**, but these command are _not the only way_ to set these + values. When the values are **omitted** you will be _asked in the terminal_ to + manually enter the required values as needed. Furthermore, the use of + **env variables** are also heavily used across the script. There are more + than one .env file and the script will set those up for you whenever you run a + task that make use of env variables the script will check if those values exist, + and if they don't it will ask for them, and store them automatically for future use. + That same time the output message to the terminal will show you where the specific + .env file can be found. + + Author Licence + Llewellyn van der Merwe GNU GENERAL PUBLIC LICENSE Version 2 + + --quiet" + + whiptail --msgbox --scrolltext "${message}" 30 112 +} + +# show the help menu +function showHelpMenu() { + help=$(showHelp) + whiptail --msgbox --scrolltext "${help}" 30 112 +} + +#####################################################################################################################VDM +######################################## MENUS + +# show Joomla menu +function showJoomla() { + CHOICE=$( + whiptail --title "Joomla | ${PROGRAM_NAME} v${_V}" --menu "Make your selection" 16 112 7 \ + "1)" "<-- Return to the main menu." \ + "2)" "Setup new container" \ + "3)" "Enable existing container" \ + "4)" "Disable enabled container" \ + "5)" "Delete a container" \ + "6)" "Take all enabled containers down" \ + "7)" "Pull up all enabled containers" \ + "8)" "Fix permissions of folders and files of a container" 3>&2 2>&1 1>&3 + ) + + case $CHOICE in + "2)") + setupContainer 'joomla' + ;; + "3)") + enableContainer 'joomla' + ;; + "4)") + disableContainer 'joomla' + ;; + "5)") + deleteContainer 'joomla' + ;; + "6)") + downContainers 'joomla' + ;; + "7)") + upContainers 'joomla' + ;; + "8)") + fixContainerPermissions + ;; + esac +} + +# show Openssh menu +function showOpenssh() { + CHOICE=$( + whiptail --title "Openssh | ${PROGRAM_NAME} v${_V}" --menu "Make your selection" 16 112 6 \ + "1)" "<-- Return to the main menu." \ + "2)" "Setup new container" \ + "3)" "Enable existing container" \ + "4)" "Disable enabled container" \ + "5)" "Delete a container" \ + "6)" "Take all enabled containers down" \ + "7)" "Pull up all enabled containers" 3>&2 2>&1 1>&3 + ) + + case $CHOICE in + "2)") + setupContainer 'openssh' + ;; + "3)") + enableContainer 'openssh' + ;; + "4)") + disableContainer 'openssh' + ;; + "5)") + deleteContainer 'openssh' + ;; + "6)") + downContainers 'openssh' + ;; + "7)") + upContainers 'openssh' + ;; + esac +} + +# show Traefik menu +function showTraefik() { + CHOICE=$( + whiptail --title "Traefik | ${PROGRAM_NAME} v${_V}" --menu "Make your selection" 16 112 4 \ + "1)" "<-- Return to the main menu." \ + "2)" "Setup Traefik" \ + "3)" "Enable Traefik" \ + "4)" "Disable Traefik" 3>&2 2>&1 1>&3 + ) + + case $CHOICE in + "2)") + setupContainer 'traefik' + ;; + "3)") + enableContainer 'traefik' + ;; + "4)") + disableContainer 'traefik' + ;; + esac +} + +# show Portainer menu +function showPortainer() { + CHOICE=$( + whiptail --title "Portainer | ${PROGRAM_NAME} v${_V}" --menu "Make your selection" 16 112 4 \ + "1)" "<-- Return to the main menu." \ + "2)" "Setup Portainer" \ + "3)" "Enable Portainer" \ + "4)" "Disable Portainer" 3>&2 2>&1 1>&3 + ) + + case $CHOICE in + "2)") + setupContainer 'portainer' + ;; + "3)") + enableContainer 'portainer' + ;; + "4)") + disableContainer 'portainer' + ;; + esac +} + +# MAIN MENU +function mainMenu() { + while true; do + CHOICE=$( + whiptail --title "${PROGRAM_NAME} v${_V}" --menu "Make your selection" 16 112 10 \ + "1)" "Joomla containers" \ + "2)" "Openssh containers" \ + "3)" "Traefik container" \ + "4)" "Portainer container" \ + "5)" "Delete Persistent Volumes" \ + "6)" "Update ${PROGRAM_NAME,,}" \ + "7)" "Uninstall ${PROGRAM_NAME,,}" \ + "8)" "Show command help" \ + "9)" "Octoleo" \ + "10)" "Quit" 3>&2 2>&1 1>&3 + ) + + case $CHOICE in + "1)") + showJoomla + ;; + "2)") + showOpenssh + ;; + "3)") + showTraefik + ;; + "4)") + showPortainer + ;; + "5)") + deletePersistentVolumes + ;; + "6)") + runUpdate + ;; + "7)") + runUninstall + ;; + "8)") + showHelpMenu + ;; + "9)") + octoleoQuietly + ;; + "10)") exit ;; + esac + done +} + +#####################################################################################################################VDM +######################################## GENERAL SHARED FUNCTIONS + +# show error +function showError() { + whiptail --title "ERROR | ${PROGRAM_NAME} v${_V}" --msgbox "${1}" 12 112 +} + +# show info +function showInfo() { + whiptail --title "INFO | ${PROGRAM_NAME} v${_V}" --infobox "${1}" 12 112 +} + +# show notice +function showNotice() { + whiptail --title "NOTICE | ${PROGRAM_NAME} v${_V}" --msgbox "${1}" 12 112 +} + +# we must get a random key +function getRandomPass() { + # simple basic random + # shellcheck disable=SC2046 + echo $(tr -dc 'A-HJ-NP-Za-km-z2-9' &1 1>&2 2>&3) + # return the answer + echo "${answer}" +} + +# get a selected directory +function getSelectedDirectory() { + # the selected folder + local answer + # set the local path + local path="${2:-}" + # set local var + local folder="${3:-}" + # we start the selection array + local selected=() + # our counter + local i=0 + # now check if this dir has sub dirs + # shellcheck disable=SC2046 + # shellcheck disable=SC2012 + if [ -d "${path}" ] && [ $(ls -A "$path" | wc -l) -ne 0 ]; then + # loop over the directory + for dir_ in "${path%/}/"*; do + # remove the full path + dir_="${dir_/$path/}" + # load the selection + [ "$folder" = "${dir_#/}" ] && selected+=("${dir_#/}" "${dir_#/}" "ON") || selected+=("${dir_#/}" "${dir_#/}" "OFF") + # increment our pointer + i=$((i + 1)) + done + # now make the selection + answer=$(whiptail --title "${4:-Make a Selection}" --radiolist \ + "${1}" 20 112 $i \ + "${selected[@]}" --nocancel --notags 3>&1 1>&2 2>&3) + fi + # return the answer + echo "${answer:-$folder}" +} + +# select multiple directories from one directory +function getSelectedDirectories() { + # the selected folder + local answer + # set the local path + local path="${2:-}" + # we start the selection array + local selected=() + # our counter + local i=0 + # now check if this dir has sub dirs + # shellcheck disable=SC2046 + # shellcheck disable=SC2012 + if [ -d "${path}" ] && [ $(ls -A "$path" | wc -l) -ne 0 ]; then + # loop over the directory + for dir_ in "${path%/}/"*; do + # remove the full path + dir_="${dir_/$path/}" + # load the selection + selected+=("${dir_#/}" "${dir_#/}" "OFF") + # increment our pointer + i=$((i + 1)) + done + # now make the selection + answer=$(whiptail --title "${3:-Make a Selection}" --checklist \ + "${1}" 20 112 $i \ + "${selected[@]}" --nocancel --notags 3>&1 1>&2 2>&3) + # return the answer + echo "${answer[@]}" + else + echo '' + fi +} + +# create a yml dashed line +function getYMLDashLine() { + # get the projects to mount + local line="$1" + # return line + cat <&1 1>&2 2>&3) + # return the password + echo "${PASSWORD}" +} + +# get and set the access token +function getAccessToken(){ + # we try getting the token twice + local t=0 + local new_token=false + # check that we have an access token, els ask for it + while [ ${#VDM_ACCESS_TOKEN} -le 30 ]; do + # this is a new token + new_token=true + # get the value + VDM_ACCESS_TOKEN=$(getInput "Enter access token for updates.\n[You can get an access token from https://git.vdm.dev/user/settings/applications]" \ + '' 'Access Token') + # keep asking if empty + if [ ${#VDM_ACCESS_TOKEN} -le 30 ]; then + showError "Updates can only be done if you have an access token." + # increment our try + t=$((t + 1)) + # when the user for the second time does not supply the correct value we return + if [ $t -eq 2 ]; then + return 12 + fi + fi + done + # make the token available + export VDM_ACCESS_TOKEN + # store the token for next time + $new_token && setEnvVariable "VDM_ACCESS_TOKEN=\"${VDM_ACCESS_TOKEN}\"" && + showNotice "The token has been stored in the environment variable file (${VDM_SRC_PATH}/.env)." + # we have success + return 0 +} + +# set the networks in place +function setNetworks() { + # we create the networks + docker network inspect traefik_webgateway >/dev/null 2>&1 || + docker network create traefik_webgateway + docker network inspect openssh_gateway >/dev/null 2>&1 || + docker network create openssh_gateway +} + +# to set a global Env Variable +function setEnvVariable() { + # check if the env file exist + if [ -f "${VDM_SRC_PATH}/.env" ]; then + grep -q "${1}" "${VDM_SRC_PATH}/.env" || echo "${1}" >>"${VDM_SRC_PATH}/.env" + elif (whiptail --yesno "Can we create the ${VDM_SRC_PATH}/.env file" --title "Environment Variable File" 8 112); then + # make sure the folder exist + mkdir -p "${VDM_SRC_PATH}" + # so we creat the file + echo "${1}" >"${VDM_SRC_PATH}/.env" + # make sure the permissions are secured + chmod 600 "${VDM_SRC_PATH}/.env" + else + showError "The ${VDM_SRC_PATH}/.env file does not exist. So ${1} could not be added!" + # we return false + return 12 + fi + # we return true + return 0 +} + +# to set a container Env Variable +function setContainerEnvVariable() { + # check if the env file exist + if [ -f "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" ]; then + grep -q "${1}" "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" || echo "${1}" >>"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" + elif (whiptail --yesno "Can we create the ${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env file" --title "Container Environment Variable File" 8 112); then + # make sure the folder exist + mkdir -p "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}" + # so we creat the file + echo "${1}" >"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" + # make sure the permissions are secured + chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" + else + showError "The ${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env file does not exist. So ${1} could not be added!" + fi +} + +# take down apache +function downApache() { + # make sure port 80 is not used by apache + command -v apache2 >/dev/null 2>&1 && [[ $(service apache2 status) == *"active (running)"* ]] && { + if (whiptail --yesno "Traefik needs port 80/443 and since Apache is also enabled (we dont know if is using these ports) so Traefik may not work. Can we disable Apache?" --defaultno --title "Disable Apache" 12 112); then + sudo systemctl stop apache2.service + sudo systemctl disable apache2.service + fi + } +} + +# check if some thing is a function +function isFunc() { + declare -F "$1" >/dev/null +} + +# update the host file +function updateHostFile(){ + # check if we have secure switch set + if [ "${VDM_UPDATE_HOST:-not}" = 'not' ]; then + # check the security switch + if (whiptail --yesno "Would you like to update your host file with each new domain you add?" --defaultno --title "Update /etc/hosts" 8 112); then + # we set the secure switch + VDM_UPDATE_HOST=true + else + VDM_UPDATE_HOST=false + fi + # add this value since its not set variable + setEnvVariable "VDM_UPDATE_HOST=${VDM_UPDATE_HOST}" + fi + # check if we should add to host file + if $VDM_UPDATE_HOST; then + # check if already in host file + if grep -q "${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN}" /etc/hosts; then + showNotice "${USER^}, ${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN} is already in the /etc/hosts file." + elif (whiptail --yesno "${USER^}, to add the ${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN} entry to your host file we need sudo privileges." --title "Give sudo Privileges" 8 112); then + # add the domain to the host file + echo "127.0.0.1 ${VDM_SUBDOMAIN}.${VDM_DOMAIN}" | sudo tee -a /etc/hosts > /dev/null + # show notice + showNotice "${USER^}, ${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN} was added to the /etc/hosts file." + fi + fi +} + +#####################################################################################################################VDM +######################################## CLI MENU ʕ•ᴥ•ʔ + +# help message +function showHelp() { + cat < + set type you would like to work with + example: ${0##*/:-} --type joomla + ====================================================== + --task + set type of task you would like to perform + example: ${0##*/:-} --task setup + ====================================================== + --container + Directly enabling or disabling a container with + the type=joomla and task=enable/disable set + The container must exist, which means it was + setup previously + Used without type and task Joomla-Enable is (default) + example: ${0##*/:-} --container "io.vdm.dev" + ====================================================== + --update + to update your install + example: ${0##*/:-} --update + ====================================================== + --access-token + to update the program you will need an access token + from https://git.vdm.dev/user/settings/applications + example: docker-deploy --access-token xxxxxxxxxxx + ====================================================== + --uninstall + to uninstall this script + example: ${0##*/:-} --uninstall + ====================================================== + AVAILABLE FOR TO ANY CONTAINER + ====================================================== + -k|--key + set key for the docker compose container naming + !! no spaces allowed in the key !! + example: ${0##*/:-} -k="vdm" + example: ${0##*/:-} --key="vdm" + ====================================================== + -e|--env-key + set key for the environment variable naming + !! no spaces allowed in the key & must be UPPERCASE !! + example: ${0##*/:-} -e="VDM" + example: ${0##*/:-} --env-key="VDM" + ====================================================== + -d|--domain + set key website domain + !! must be domain.tld !! + example: ${0##*/:-} -d="vdm.dev" + example: ${0##*/:-} --domain="vdm.dev" + ====================================================== + AVAILABLE FOR JOOMLA CONTAINER + ====================================================== + -j|--joomla-version + set Joomla version number + !! only number allowed !! + example: ${0##*/:-} -j=3.10 + example: ${0##*/:-} --joomla-version=3.10 + ====================================================== + -s|--sub-domain + set key website sub domain + !! no spaces allowed in the sub domain !! + example: ${0##*/:-} -s="jcb" + example: ${0##*/:-} --sub-domain="jcb" + ====================================================== + AVAILABLE FOR OPENSSH CONTAINER + ====================================================== + -u|--username + set username of the container + example: ${0##*/:-} -u="ubuntu" + example: ${0##*/:-} --username="ubuntu" + ====================================================== + --uid + set container user id + example: ${0##*/:-} --uid=1000 + ====================================================== + --gid + set container user group id + example: ${0##*/:-} --gid=1000 + ====================================================== + -p|--port + set ssh port to use + !! do not use 22 !! + example: ${0##*/:-} -p=2239 + example: ${0##*/:-} --port=2239 + ====================================================== + --ssh-dir + set ssh directory name found in the .ssh dir + of this repo for the container keys + This directory has separate files for + each public key allowed to access + the container + example: ${0##*/:-} --ssh-dir="teamname" + ====================================================== + --sudo + switch to add the container user to the + sudo group of the container + example: ${0##*/:-} --sudo + ====================================================== + -t|--time-zone