core.sh 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #!/bin/bash
  2. caller="${BASH_SOURCE[1]##*/}"
  3. get_installed_tools(){
  4. for bin in openssl curl docker git awk sha1sum grep cut; do
  5. if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
  6. done
  7. if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox grep detected, please install gnu grep, \"apk add --no-cache --upgrade grep\""; exit 1; fi
  8. # This will also cover sort
  9. if cp --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox cp detected, please install coreutils, \"apk add --no-cache --upgrade coreutils\""; exit 1; fi
  10. if sed --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox sed detected, please install gnu sed, \"apk add --no-cache --upgrade sed\""; exit 1; fi
  11. }
  12. get_docker_version(){
  13. # Check Docker Version (need at least 24.X)
  14. docker_version=$(docker version --format '{{.Server.Version}}' | cut -d '.' -f 1)
  15. }
  16. get_compose_type(){
  17. if docker compose > /dev/null 2>&1; then
  18. if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then
  19. COMPOSE_VERSION=native
  20. COMPOSE_COMMAND="docker compose"
  21. if [[ "$caller" == "update.sh" ]]; then
  22. sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf"
  23. fi
  24. echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
  25. echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
  26. sleep 2
  27. echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
  28. else
  29. echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
  30. echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
  31. exit 1
  32. fi
  33. elif docker-compose > /dev/null 2>&1; then
  34. if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
  35. if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
  36. COMPOSE_VERSION=standalone
  37. COMPOSE_COMMAND="docker-compose"
  38. if [[ "$caller" == "update.sh" ]]; then
  39. sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf"
  40. fi
  41. echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
  42. echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
  43. sleep 2
  44. 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"
  45. else
  46. echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
  47. echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
  48. exit 1
  49. fi
  50. fi
  51. else
  52. echo -e "\e[31mCannot find Docker Compose.\e[0m"
  53. echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
  54. exit 1
  55. fi
  56. }
  57. detect_bad_asn() {
  58. echo -e "\e[33mDetecting if your IP is listed on Spamhaus Bad ASN List...\e[0m"
  59. response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
  60. if [ "$response" -eq 503 ]; then
  61. if [ -z "$SPAMHAUS_DQS_KEY" ]; then
  62. 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"
  63. echo -e "\e[33mmailcow did not detected a value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf!\e[0m"
  64. sleep 2
  65. echo ""
  66. 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"
  67. echo -e "\e[33mOnce done, enter your DQS API key in mailcow.conf and mailcow will do the rest for you!\e[0m"
  68. echo ""
  69. sleep 2
  70. else
  71. 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"
  72. 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"
  73. fi
  74. elif [ "$response" -eq 200 ]; then
  75. echo -e "\e[33mCheck completed! Your IP is \e[32mclean\e[0m"
  76. elif [ "$response" -eq 429 ]; then
  77. echo -e "\e[33mCheck completed! \e[31mYour IP seems to be rate limited on the ASN Check service... please try again later!\e[0m"
  78. else
  79. echo -e "\e[31mCheck failed! \e[0mMaybe a DNS or Network problem?\e[0m"
  80. fi
  81. }
  82. check_online_status() {
  83. CHECK_ONLINE_DOMAINS=('https://github.com' 'https://hub.docker.com')
  84. for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
  85. if timeout 6 curl --head --silent --output /dev/null ${domain}; then
  86. return 0
  87. fi
  88. done
  89. return 1
  90. }
  91. prefetch_images() {
  92. [[ -z ${BRANCH} ]] && { echo -e "\e[33m\nUnknown branch...\e[0m"; exit 1; }
  93. git fetch origin #${BRANCH}
  94. while read image; do
  95. RET_C=0
  96. until docker pull "${image}"; do
  97. RET_C=$((RET_C + 1))
  98. echo -e "\e[33m\nError pulling $image, retrying...\e[0m"
  99. [ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
  100. sleep 1
  101. done
  102. done < <(git show "origin/${BRANCH}:docker-compose.yml" | grep "image:" | awk '{ gsub("image:","", $3); print $2 }')
  103. }
  104. docker_garbage() {
  105. SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  106. IMGS_TO_DELETE=()
  107. declare -A IMAGES_INFO
  108. COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml"))
  109. for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do
  110. ID=$(echo "$existing_image" | cut -d ':' -f 1)
  111. REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2)
  112. TAG=$(echo "$existing_image" | cut -d ':' -f 3)
  113. if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then
  114. if [[ "$TAG" != "<none>" ]]; then
  115. continue
  116. fi
  117. fi
  118. if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then
  119. continue
  120. else
  121. IMGS_TO_DELETE+=("$ID")
  122. IMAGES_INFO["$ID"]="$REPOSITORY:$TAG"
  123. fi
  124. done
  125. if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
  126. echo "The following unused mailcow images were found:"
  127. for id in "${IMGS_TO_DELETE[@]}"; do
  128. echo " ${IMAGES_INFO[$id]} ($id)"
  129. done
  130. if [ -z "$FORCE" ]; then
  131. read -r -p "Do you want to delete them to free up some space? [y/N] " response
  132. if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
  133. docker rmi ${IMGS_TO_DELETE[*]}
  134. else
  135. echo "OK, skipped."
  136. fi
  137. else
  138. echo "Running in forced mode! Force removing old mailcow images..."
  139. docker rmi ${IMGS_TO_DELETE[*]}
  140. fi
  141. echo -e "\e[32mFurther cleanup...\e[0m"
  142. 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\""
  143. fi
  144. }
  145. in_array() {
  146. local e match="$1"
  147. shift
  148. for e; do [[ "$e" == "$match" ]] && return 0; done
  149. return 1
  150. }