123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- #!/usr/bin/env bash
- # _modules/scripts/core.sh
- # THIS SCRIPT IS DESIGNED TO BE RUNNING BY MAILCOW SCRIPTS ONLY!
- # DO NOT, AGAIN, NOT TRY TO RUN THIS SCRIPT STANDALONE!!!!!!
- # ANSI color for red errors
- RED='\e[31m'
- GREEN='\e[32m'
- YELLOW='\e[33m'
- BLUE='\e[34m'
- MAGENTA='\e[35m'
- LIGHT_RED='\e[91m'
- LIGHT_GREEN='\e[92m'
- NC='\e[0m'
- caller="${BASH_SOURCE[1]##*/}"
- get_installed_tools(){
- for bin in openssl curl docker git awk sha1sum grep cut jq; do
- if [[ -z $(command -v ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
- done
- if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox grep detected, please install gnu grep, \"apk add --no-cache --upgrade grep\"${NC}"; exit 1; fi
- # This will also cover sort
- if cp --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox cp detected, please install coreutils, \"apk add --no-cache --upgrade coreutils\"${NC}"; exit 1; fi
- if sed --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox sed detected, please install gnu sed, \"apk add --no-cache --upgrade sed\"${NC}"; exit 1; fi
- }
- get_docker_version(){
- # Check Docker Version (need at least 24.X)
- docker_version=$(docker version --format '{{.Server.Version}}' | cut -d '.' -f 1)
- }
- get_compose_type(){
- if docker compose > /dev/null 2>&1; then
- if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then
- COMPOSE_VERSION=native
- COMPOSE_COMMAND="docker compose"
- if [[ "$caller" == "update.sh" ]]; then
- sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf"
- fi
- echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
- echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
- sleep 2
- echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
- else
- echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
- echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
- exit 1
- fi
- elif docker-compose > /dev/null 2>&1; then
- if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
- if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
- COMPOSE_VERSION=standalone
- COMPOSE_COMMAND="docker-compose"
- if [[ "$caller" == "update.sh" ]]; then
- sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf"
- fi
- echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
- echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
- sleep 2
- echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
- else
- echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
- echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
- exit 1
- fi
- fi
- else
- echo -e "\e[31mCannot find Docker Compose.\e[0m"
- echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
- exit 1
- fi
- }
- detect_bad_asn() {
- echo -e "\e[33mDetecting if your IP is listed on Spamhaus Bad ASN List...\e[0m"
- response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
- if [ "$response" -eq 503 ]; then
- if [ -z "$SPAMHAUS_DQS_KEY" ]; then
- echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
- echo -e "\e[33mmailcow did not detected a value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf!\e[0m"
- sleep 2
- echo ""
- echo -e "\e[33mTo use the Spamhaus DNS Blocklists again, you will need to create a FREE account for their Data Query Service (DQS) at: https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account\e[0m"
- echo -e "\e[33mOnce done, enter your DQS API key in mailcow.conf and mailcow will do the rest for you!\e[0m"
- echo ""
- sleep 2
- else
- echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
- echo -e "\e[32mmailcow detected a Value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf. Postfix will use DQS with the given API key...\e[0m"
- fi
- elif [ "$response" -eq 200 ]; then
- echo -e "\e[33mCheck completed! Your IP is \e[32mclean\e[0m"
- elif [ "$response" -eq 429 ]; then
- echo -e "\e[33mCheck completed! \e[31mYour IP seems to be rate limited on the ASN Check service... please try again later!\e[0m"
- else
- echo -e "\e[31mCheck failed! \e[0mMaybe a DNS or Network problem?\e[0m"
- fi
- }
- check_online_status() {
- CHECK_ONLINE_DOMAINS=('https://github.com' 'https://hub.docker.com')
- for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
- if timeout 6 curl --head --silent --output /dev/null ${domain}; then
- return 0
- fi
- done
- return 1
- }
- prefetch_images() {
- [[ -z ${BRANCH} ]] && { echo -e "\e[33m\nUnknown branch...\e[0m"; exit 1; }
- git fetch origin #${BRANCH}
- while read image; do
- RET_C=0
- until docker pull "${image}"; do
- RET_C=$((RET_C + 1))
- echo -e "\e[33m\nError pulling $image, retrying...\e[0m"
- [ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
- sleep 1
- done
- done < <(git show "origin/${BRANCH}:docker-compose.yml" | grep "image:" | awk '{ gsub("image:","", $3); print $2 }')
- }
- docker_garbage() {
- SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
- IMGS_TO_DELETE=()
- declare -A IMAGES_INFO
- COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml"))
- for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do
- ID=$(echo "$existing_image" | cut -d ':' -f 1)
- REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2)
- TAG=$(echo "$existing_image" | cut -d ':' -f 3)
- if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then
- if [[ "$TAG" != "<none>" ]]; then
- continue
- fi
- fi
- if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then
- continue
- else
- IMGS_TO_DELETE+=("$ID")
- IMAGES_INFO["$ID"]="$REPOSITORY:$TAG"
- fi
- done
- if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
- echo "The following unused mailcow images were found:"
- for id in "${IMGS_TO_DELETE[@]}"; do
- echo " ${IMAGES_INFO[$id]} ($id)"
- done
- if [ -z "$FORCE" ]; then
- read -r -p "Do you want to delete them to free up some space? [y/N] " response
- if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
- docker rmi ${IMGS_TO_DELETE[*]}
- else
- echo "OK, skipped."
- fi
- else
- echo "Running in forced mode! Force removing old mailcow images..."
- docker rmi ${IMGS_TO_DELETE[*]}
- fi
- echo -e "\e[32mFurther cleanup...\e[0m"
- echo "If you want to cleanup further garbage collected by Docker, please make sure all containers are up and running before cleaning your system by executing \"docker system prune\""
- fi
- }
- in_array() {
- local e match="$1"
- shift
- for e; do [[ "$e" == "$match" ]] && return 0; done
- return 1
- }
- detect_major_update() {
- if [ ${BRANCH} == "master" ]; then
- # Array with major versions
- # Add major versions here
- MAJOR_VERSIONS=(
- "2025-02"
- "2025-03"
- )
- current_version=""
- if [[ -f "${SCRIPT_DIR}/data/web/inc/app_info.inc.php" ]]; then
- current_version=$(grep 'MAILCOW_GIT_VERSION' ${SCRIPT_DIR}/data/web/inc/app_info.inc.php | sed -E 's/.*MAILCOW_GIT_VERSION="([^"]+)".*/\1/')
- fi
- if [[ -z "$current_version" ]]; then
- return 1
- fi
- release_url="https://github.com/mailcow/mailcow-dockerized/releases/tag"
- updates_to_apply=()
- for version in "${MAJOR_VERSIONS[@]}"; do
- if [[ "$current_version" < "$version" ]]; then
- updates_to_apply+=("$version")
- fi
- done
- if [[ ${#updates_to_apply[@]} -gt 0 ]]; then
- echo -e "\e[33m\nMAJOR UPDATES to be applied:\e[0m"
- for update in "${updates_to_apply[@]}"; do
- echo "$update - $release_url/$update"
- done
- echo -e "\nPlease read the release notes before proceeding."
- read -p "Do you want to proceed with the update? [y/n] " response
- if [[ "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
- echo "Proceeding with the update..."
- else
- echo "Update canceled. Exiting."
- exit 1
- fi
- fi
- fi
- }
|