├── .dockleignore ├── .gitattributes ├── .github ├── CODEOWNERS ├── actions │ ├── check-if-latest-lts-release │ │ └── action.yml │ ├── check-redhat-service-status │ │ └── action.yml │ └── slack-notification │ │ └── action.yml ├── containerscan │ ├── .snyk │ ├── .trivyignore │ └── trivy.yaml ├── dependabot.yml ├── scripts │ ├── abstract-simple-smoke-test.sh │ ├── base-image-updated.sh │ ├── build.functions.sh │ ├── build.functions_tests.sh │ ├── cluster-verification.sh │ ├── docker.functions.sh │ ├── ee-build.functions.sh │ ├── ee-build.functions_tests.sh │ ├── generate-docker-hub-description.sh │ ├── get-tags-to-push.sh │ ├── get-tags-to-push_tests.sh │ ├── log.functions.sh │ ├── logging.functions.sh │ ├── maven.functions_tests.sh │ ├── oss-build.functions.sh │ ├── oss-build.functions_tests.sh │ ├── packages-updated.sh │ ├── publish-rhel.sh │ ├── simple-smoke-test.sh │ ├── test_scripts.sh │ ├── version.functions.sh │ └── version.functions_tests.sh └── workflows │ ├── build-pr.yml │ ├── check-base-images.yml │ ├── check-redhat-service-status.yml │ ├── ee-nlc-snapshot-push.yml │ ├── ee-nlc-tag-push.yml │ ├── ee_latest_snapshot_push.yml │ ├── get-supported-jdks.yaml │ ├── oss_latest_snapshot_push.yml │ ├── retag.yml │ ├── rhel-smoke-test.yml │ ├── scheduled_vulnerability_scan.yml │ ├── tag_image_push.yml │ ├── tag_image_push_rhel.yml │ ├── test_published_images.yml │ ├── update_readme.yml │ ├── vulnerability_scan.yml │ └── vulnerability_scan_subworkflow.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── hazelcast-enterprise ├── Dockerfile ├── jmx_agent_config.yaml ├── licenses │ ├── ELA.pdf │ ├── EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf │ └── LICENSE ├── log4j2-json.properties ├── log4j2.properties └── maven.functions.sh ├── hazelcast-oss ├── Dockerfile ├── jmx_agent_config.yaml ├── log4j2-json.properties ├── log4j2.properties └── maven.functions.sh └── scripts └── artifactory-docker-cleaner.sh /.dockleignore: -------------------------------------------------------------------------------- 1 | # Add ignored checkpoints in new lines below 2 | 3 | # Caused by the EE upstream image: redhat/ubi8-minimal 4 | CIS-DI-0009 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # linux line-endings 2 | *.sh text eol=lf -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @hazelcast/dev-infra 2 | -------------------------------------------------------------------------------- /.github/actions/check-if-latest-lts-release/action.yml: -------------------------------------------------------------------------------- 1 | name: Check if latest EE LTS release 2 | description: Check if latest EE LTS release 3 | inputs: 4 | release_version: 5 | description: Version to be released 6 | required: true 7 | is_lts_override: 8 | description: Override is LTS release or not 9 | required: true 10 | outputs: 11 | is_latest_lts: 12 | value: ${{ steps.is_latest_lts.outputs.is_latest_lts }} 13 | description: Returns 'true' if the release if the latest LTS 14 | runs: 15 | using: "composite" 16 | steps: 17 | - name: Set Environment Variables 18 | shell: bash 19 | run: | 20 | echo "IS_LTS_FILE=.github/lts" >> $GITHUB_ENV 21 | 22 | - name: Check if EE LTS release 23 | shell: bash 24 | run: | 25 | if [ -n "${{inputs.is_lts_override}}" ]; then 26 | echo "IS_LTS overridden to '${{inputs.is_lts_override}}'" 27 | echo "IS_LTS=${{inputs.is_lts_override}}" >> $GITHUB_ENV 28 | elif [ -f $IS_LTS_FILE ]; then 29 | echo "IS_LTS=true" >> $GITHUB_ENV 30 | echo "File '$IS_LTS_FILE' exists. Assuming LTS release" 31 | else 32 | echo "File '$IS_LTS_FILE' does not exist. Assuming non-LTS release" 33 | fi 34 | 35 | - name: Check if latest EE LTS release 36 | if: env.IS_LTS == 'true' 37 | id: is_latest_lts 38 | shell: bash 39 | run: | 40 | . .github/scripts/version.functions.sh 41 | CURRENT_LATEST_LTS_VERSION=$(get_last_version_with_file "$IS_LTS_FILE") 42 | RELEASE_VERSION="${{ inputs.release_version }}" 43 | if version_less_or_equal "$CURRENT_LATEST_LTS_VERSION" "$RELEASE_VERSION"; then 44 | echo "is_latest_lts=true" >> $GITHUB_OUTPUT 45 | else 46 | echo "is_latest_lts=false" >> $GITHUB_OUTPUT 47 | fi 48 | -------------------------------------------------------------------------------- /.github/actions/check-redhat-service-status/action.yml: -------------------------------------------------------------------------------- 1 | name: Check RedHat Service Status 2 | runs: 3 | using: "composite" 4 | steps: 5 | - name: Check RedHat status 6 | shell: bash 7 | run: | 8 | # shellcheck source=../.github/scripts/logging.functions.sh 9 | . .github/scripts/logging.functions.sh 10 | 11 | # https://status.redhat.com/api 12 | STATUS=$(curl --silent https://status.redhat.com/api/v2/status.json) 13 | 14 | if jq --exit-status '.status.indicator != "none"' <<< "${STATUS}"; then 15 | echoerr "❌ RedHat service status" 16 | echoerr "$(jq '.status' <<< ${STATUS})" 17 | echoerr "$(curl --silent https://status.redhat.com/api/v2/incidents/unresolved.json | jq)" 18 | exit 1 19 | fi 20 | -------------------------------------------------------------------------------- /.github/actions/slack-notification/action.yml: -------------------------------------------------------------------------------- 1 | name: Slack notification 2 | description: Slack notification 3 | inputs: 4 | slack-webhook-url: 5 | description: Slack webhook url 6 | required: true 7 | runs: 8 | using: "composite" 9 | steps: 10 | - uses: 8398a7/action-slack@v3 11 | with: 12 | fields: all 13 | status: ${{ job.status }} 14 | channel: "#hazelcast-docker-notifications" 15 | env: 16 | SLACK_WEBHOOK_URL: ${{ inputs.slack-webhook-url }} 17 | 18 | -------------------------------------------------------------------------------- /.github/containerscan/.snyk: -------------------------------------------------------------------------------- 1 | ignore: 2 | SNYK-JAVA-COMGOOGLEPROTOBUF-2331703: 3 | - '*': 4 | reason: See https://github.com/hazelcast/hazelcast/issues/20807 and https://issues.apache.org/jira/browse/HADOOP-18197 5 | expires: 2023-11-01T00:00:00.000Z 6 | SNYK-JAVA-COMGOOGLEPROTOBUF-3167772: 7 | - '*': 8 | reason: See https://github.com/hazelcast/hazelcast/issues/20807 and https://issues.apache.org/jira/browse/HADOOP-18197 9 | expires: 2023-11-01T00:00:00.000Z 10 | -------------------------------------------------------------------------------- /.github/containerscan/.trivyignore: -------------------------------------------------------------------------------- 1 | # Add ignored CVEs in new lines below 2 | 3 | #See https://github.com/hazelcast/hazelcast/issues/20807 and https://issues.apache.org/jira/browse/HADOOP-18197 4 | CVE-2022-3171 5 | 6 | #See https://github.com/hazelcast/hazelcast/issues/20807 and https://issues.apache.org/jira/browse/HADOOP-18197 7 | CVE-2021-22570 8 | 9 | #See https://github.com/hazelcast/hazelcast/issues/24981 10 | CVE-2023-2976 11 | -------------------------------------------------------------------------------- /.github/containerscan/trivy.yaml: -------------------------------------------------------------------------------- 1 | dependency-tree: true 2 | exit-code: 1 3 | ignorefile: .github/containerscan/.trivyignore 4 | severity: 5 | - CRITICAL 6 | - HIGH 7 | vulnerability: 8 | ignore-unfixed: true 9 | debug: true -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "docker" 4 | directory: "/hazelcast-oss" 5 | target-branch: "master" 6 | schedule: 7 | interval: "daily" 8 | 9 | - package-ecosystem: "docker" 10 | directory: "/hazelcast-enterprise" 11 | target-branch: "master" 12 | schedule: 13 | interval: "daily" 14 | 15 | - package-ecosystem: "github-actions" 16 | directory: "/" 17 | target-branch: "master" 18 | schedule: 19 | interval: "daily" 20 | -------------------------------------------------------------------------------- /.github/scripts/abstract-simple-smoke-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit -o nounset -o pipefail ${RUNNER_DEBUG:+-x} 4 | 5 | # shellcheck source=../.github/scripts/logging.functions.sh 6 | . .github/scripts/logging.functions.sh 7 | 8 | # Performs simple validation tests on an already-running Hazelcast instance 9 | # Abstract as could be from Docker, Homebrew, local binary etc 10 | # Because abstract, expects callers to implement required, but absent functions 11 | function test_package() { 12 | local expected_distribution_type=$1 13 | local expected_version=$2 14 | 15 | test_health 16 | test_map_read_write 17 | 18 | # Deliberately last step as it doesn't block-and-wait until the instance is initialized 19 | # Otherwise would have false positives if instance still starting and logs empty 20 | check_metadata "${expected_distribution_type}" "${expected_version}" 21 | } 22 | 23 | # Search logs for entries _like_: 24 | # Hazelcast Platform 5.5.0 (20240725) starting at [172.17.0.2]:5701 25 | # To validate the version and distribution is correct 26 | function check_metadata() { 27 | local expected_distribution_type=$1 28 | local expected_version=$2 29 | 30 | logs=$(get_hz_logs) 31 | 32 | if [[ -z "${logs}" ]]; then 33 | echoerr "Failed to read logs" 34 | exit 1; 35 | fi 36 | 37 | if grep -q "${expected_distribution_type} ${expected_version}" <<< "${logs}"; then 38 | echo "Expected contents (${expected_distribution_type}) and version (${expected_version}) identified." 39 | else 40 | echoerr "Failed to find ${expected_distribution_type} ${expected_version} in logs:" 41 | echoerr "${logs}" 42 | exit 1; 43 | fi 44 | } 45 | 46 | function test_health() { 47 | local attempts=0 48 | local max_attempts=30 49 | until curl --silent --fail "127.0.0.1:5701/hazelcast/health/ready"; do 50 | if [[ ${attempts} -eq ${max_attempts} ]];then 51 | echoerr "Hazelcast not responding" 52 | exit 1; 53 | fi 54 | printf '.' 55 | attempts=$((attempts+1)) 56 | sleep 2 57 | done 58 | } 59 | 60 | function test_map_read_write() { 61 | install_clc 62 | 63 | local key="some-key" 64 | local expected="some-value" 65 | echo "Putting value '${expected}' for key '${key}'" 66 | clc --timeout 5s map set -n some-map "${key}" "${expected}" --log.path stderr 67 | echo "Getting value for key '${key}'" 68 | local actual 69 | actual=$(clc map get --format delimited -n some-map "${key}" --log.path stderr) 70 | 71 | if [[ "${expected}" != "${actual}" ]]; then 72 | echoerr "Expected to read '${expected}' but got '${actual}'" 73 | exit 1; 74 | fi 75 | } 76 | 77 | function install_clc() { 78 | while ! curl https://hazelcast.com/clc/install.sh | bash 79 | do 80 | echo "Retrying clc installation..." 81 | sleep 3 82 | done 83 | export PATH=${PATH}:${HOME}/.hazelcast/bin 84 | clc config add default cluster.name=dev cluster.address=localhost 85 | } 86 | -------------------------------------------------------------------------------- /.github/scripts/base-image-updated.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function findScriptDir() { 4 | CURRENT=$PWD 5 | 6 | DIR=$(dirname "$0") 7 | cd "$DIR" || exit 8 | TARGET_FILE=$(basename "$0") 9 | 10 | # Iterate down a (possible) chain of symlinks 11 | while [ -L "$TARGET_FILE" ]; do 12 | TARGET_FILE=$(readlink "$TARGET_FILE") 13 | DIR=$(dirname "$TARGET_FILE") 14 | cd "$DIR" || exit 15 | TARGET_FILE=$(basename "$TARGET_FILE") 16 | done 17 | 18 | SCRIPT_DIR=$(pwd -P) 19 | # Restore current directory 20 | cd "$CURRENT" || exit 21 | } 22 | 23 | findScriptDir 24 | 25 | function get_base_image_name() { 26 | local DOCKERFILE=$1 27 | grep '^FROM ' $DOCKERFILE | cut -d' ' -f2 28 | } 29 | 30 | function base_image_updated() { 31 | local CURRENT_IMAGE=$1 32 | local DOCKERFILE=$2 33 | local BASE_IMAGE=$(get_base_image_name "$DOCKERFILE") 34 | docker pull "$BASE_IMAGE" 35 | docker pull "$CURRENT_IMAGE" 36 | local BASE_IMAGE_SHA=$(docker image inspect "$BASE_IMAGE" | jq -r '.[].RootFS.Layers[0]') 37 | local CURRENT_IMAGE_SHA=$(docker image inspect "$CURRENT_IMAGE" | jq -r '.[].RootFS.Layers[0]') 38 | if [ "$CURRENT_IMAGE_SHA" = "$BASE_IMAGE_SHA" ]; then 39 | return 1 40 | fi 41 | return 0 42 | } 43 | -------------------------------------------------------------------------------- /.github/scripts/build.functions.sh: -------------------------------------------------------------------------------- 1 | set -euo pipefail ${RUNNER_DEBUG:+-x} 2 | 3 | # Checks if we should build the OSS artefacts. 4 | # Returns "yes" if we should build it or "no" if we shouldn't. 5 | function should_build_oss() { 6 | 7 | local release_type=$1 8 | if [[ $release_type =~ ^(ALL|OSS)$ ]]; then 9 | echo "yes" 10 | else 11 | echo "no" 12 | fi 13 | } 14 | 15 | # Checks if we should build EE artefacts. 16 | function should_build_ee() { 17 | 18 | local release_type=$1 19 | if [[ $release_type =~ ^(ALL|EE)$ ]]; then 20 | echo "yes" 21 | else 22 | echo "no" 23 | fi 24 | } 25 | -------------------------------------------------------------------------------- /.github/scripts/build.functions_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu ${RUNNER_DEBUG:+-x} 4 | 5 | SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" 6 | 7 | # Source the latest version of assert.sh unit testing library and include in current shell 8 | assert_script_content=$(curl --silent https://raw.githubusercontent.com/hazelcast/assert.sh/main/assert.sh) 9 | # shellcheck source=/dev/null 10 | . <(echo "${assert_script_content}") 11 | . "$SCRIPT_DIR"/build.functions.sh 12 | 13 | TESTS_RESULT=0 14 | 15 | function assert_should_build_oss { 16 | local release_type=$1 17 | local expected_should_build_os=$2 18 | local actual=$(should_build_oss "$release_type") 19 | local MSG="For release_type=$release_type we should$( [ "$expected_should_build_os" = "no" ] && echo " NOT") build OS" 20 | assert_eq "$expected_should_build_os" "$actual" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 21 | } 22 | 23 | function assert_should_build_ee { 24 | local release_type=$1 25 | local expected_should_build_ee=$2 26 | local actual=$(should_build_ee "$release_type") 27 | local MSG="For release_type=$release_type we should$( [ "$expected_should_build_ee" = "no" ] && echo " NOT") build EE" 28 | assert_eq "$expected_should_build_ee" "$actual" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 29 | } 30 | 31 | log_header "Tests for should_build_oss" 32 | assert_should_build_oss "ALL" "yes" 33 | assert_should_build_oss "OSS" "yes" 34 | assert_should_build_oss "EE" "no" 35 | assert_should_build_oss "dummy value" "no" 36 | 37 | log_header "Tests for should_build_ee" 38 | assert_should_build_ee "ALL" "yes" 39 | assert_should_build_ee "OSS" "no" 40 | assert_should_build_ee "EE" "yes" 41 | assert_should_build_ee "dummy value" "no" 42 | 43 | 44 | 45 | assert_eq 0 "$TESTS_RESULT" "All tests should pass" 46 | -------------------------------------------------------------------------------- /.github/scripts/cluster-verification.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail ${RUNNER_DEBUG:+-x} 4 | 5 | # shellcheck source=../.github/scripts/logging.functions.sh 6 | . .github/scripts/logging.functions.sh 7 | 8 | #CHECK IF THE LAST MEMBER POD IS READY 9 | wait_for_last_member_initialization() { 10 | local SIZE=$1 11 | local LAST_MEMBER=$(( $SIZE - 1 )) 12 | for i in `seq 1 10`; do 13 | if [[ $(kubectl get pods "${PROJECT_NAME}-${NAME}-${LAST_MEMBER}" -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" ]]; then 14 | kubectl get pods 15 | echo "waiting for pod ${PROJECT_NAME}-${NAME}-${LAST_MEMBER} to be ready..." && sleep 30 16 | if [ "$i" = "10" ]; then 17 | echoerr "${PROJECT_NAME}-${NAME}-${LAST_MEMBER} pod failed to be ready!" 18 | kubectl get pods 19 | echo "" 20 | kubectl logs "${PROJECT_NAME}-${NAME}-${LAST_MEMBER}" 21 | return 1 22 | fi 23 | else 24 | echo "${PROJECT_NAME}-${NAME}-${LAST_MEMBER} is ready!" 25 | return 0 26 | fi 27 | done 28 | } 29 | 30 | #CHECK IF CLUSTER SIZE IS CORRECT 31 | verify_cluster_size() { 32 | local SIZE=$1 33 | local LAST_MEMBER=$(( $SIZE - 1 )) 34 | for i in `seq 1 5`; do 35 | num=$(kubectl logs "${PROJECT_NAME}-${NAME}-${LAST_MEMBER}" | grep "Members {size:${SIZE}, ver:${SIZE}}" | wc -l) 36 | if [ "$num" = "1" ]; then 37 | echo "Hazelcast cluster size is ${SIZE}!" 38 | return 0 39 | else 40 | echo "Waiting for cluster size to be ${SIZE}..." && sleep 4 41 | if [ "$i" = "5" ]; then 42 | echoerr "Hazelcast cluster size is not ${SIZE}!" 43 | kubectl get pods 44 | echo "" 45 | kubectl logs "${PROJECT_NAME}-${NAME}-${LAST_MEMBER}" 46 | return 1 47 | fi 48 | fi 49 | done 50 | } 51 | 52 | 53 | #CHECK IF ALL MEMBERS CAN COMMUNICATE WITH MANAGEMENT CENTER 54 | verify_management_center() { 55 | local SIZE=$1 56 | echo "Verifying Management Center" 57 | for i in `seq 1 5`; do 58 | local MEMBER_COUNT=$(kubectl logs "${PROJECT_NAME}-${NAME}-mancenter-0" | grep -E "Started communication with (a new )?member" | wc -l) 59 | if [ "$MEMBER_COUNT" = "${SIZE}" ]; then 60 | echo "Management Center monitoring ${SIZE} members!" 61 | return 0 62 | else 63 | echo "Waiting for Management Center to find all ${SIZE} members..." && sleep 4 64 | if [ "$i" = "5" ]; then 65 | echoerr "Management Center could not find all ${SIZE} members!" 66 | kubectl get pods 67 | echo "" 68 | kubectl logs "${PROJECT_NAME}-${NAME}-mancenter-0" 69 | return 1 70 | fi 71 | fi 72 | done 73 | } -------------------------------------------------------------------------------- /.github/scripts/docker.functions.sh: -------------------------------------------------------------------------------- 1 | function get_default_jdk() { 2 | local DIR=$1 3 | awk -F= '/^ARG JDK_VERSION=/{print $2}' "$DIR/Dockerfile" | tr -d '"' 4 | } 5 | 6 | function get_alpine_supported_platforms() { 7 | local JDK=$1 8 | local PLATFORMS="linux/arm64,linux/amd64,linux/s390x" 9 | #already fixed on alpine:edge, probably will be released in alpine:3.20 10 | if [[ "$JDK" -lt 17 ]]; then 11 | PLATFORMS="$PLATFORMS,linux/ppc64le" 12 | fi 13 | echo $PLATFORMS 14 | } 15 | 16 | function get_ubi_supported_platforms() { 17 | local JDK=$1 18 | echo "linux/arm64,linux/amd64,linux/s390x,linux/ppc64le" 19 | } 20 | 21 | function get_dockerfile_arg_value() { 22 | local dockerfile=$1 23 | local arg_name=$2 24 | awk -F= "/^ARG $arg_name=/{print \$2}" $dockerfile | sed 's/"//g' 25 | } 26 | -------------------------------------------------------------------------------- /.github/scripts/ee-build.functions.sh: -------------------------------------------------------------------------------- 1 | set -euo pipefail ${RUNNER_DEBUG:+-x} 2 | 3 | # This is a simple script imitating what maven does for snapshot versions. We are not using maven because currently Docker Buildx and QEMU on Github Actions 4 | # don't work with Java on architectures ppc64le and s390x. When the problem is fixed we will revert back to using maven. 5 | # If the version is snapshot, the script downloads the 'maven-metadata.xml' and parses it for the snapshot version. 'maven-metadata.xml' only holds the values for 6 | # the latest snapshot version. Thus, the [1] in snapshotVersion[1] is arbitrary because all of elements in the list have same value. The list consists of 'jar', 'pom', 'sources' and 'javadoc'. 7 | # 8 | # 'maven-metadata.xml' example - https://repo1.maven.org/maven2/com/hazelcast/hazelcast/maven-metadata.xml 9 | function get_hz_dist_zip() { 10 | local hz_variant=$1 11 | local hz_version=$2 12 | 13 | # The slim is an artifact with a classifier, need to add `-` there 14 | suffix=${hz_variant:+-${hz_variant}} 15 | 16 | if [[ "${hz_version}" == *"SNAPSHOT"* ]] 17 | then 18 | repository=snapshot 19 | else 20 | repository=release 21 | fi 22 | 23 | echo "https://repository.hazelcast.com/${repository}/com/hazelcast/hazelcast-enterprise-distribution/${hz_version}/hazelcast-enterprise-distribution-${hz_version}${suffix}.zip" 24 | } 25 | -------------------------------------------------------------------------------- /.github/scripts/ee-build.functions_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu ${RUNNER_DEBUG:+-x} 4 | 5 | function find_script_dir() { 6 | CURRENT=$PWD 7 | 8 | DIR=$(dirname "$0") 9 | cd "$DIR" || exit 10 | TARGET_FILE=$(basename "$0") 11 | 12 | while [ -L "$TARGET_FILE" ] 13 | do 14 | TARGET_FILE=$(readlink "$TARGET_FILE") 15 | DIR=$(dirname "$TARGET_FILE") 16 | cd "$DIR" || exit 17 | TARGET_FILE=$(basename "$TARGET_FILE") 18 | done 19 | 20 | local SCRIPT_DIR=$(pwd -P) 21 | cd "$CURRENT" || exit 22 | echo "$SCRIPT_DIR" 23 | } 24 | 25 | SCRIPT_DIR=$(find_script_dir) 26 | 27 | # Source the latest version of assert.sh unit testing library and include in current shell 28 | assert_script_content=$(curl --silent https://raw.githubusercontent.com/hazelcast/assert.sh/main/assert.sh) 29 | # shellcheck source=/dev/null 30 | . <(echo "${assert_script_content}") 31 | . "$SCRIPT_DIR"/ee-build.functions.sh 32 | 33 | TESTS_RESULT=0 34 | 35 | function assert_get_hz_dist_zip { 36 | local hz_variant=$1 37 | local hz_version=$2 38 | local expected_url=$3 39 | local actual_url=$(get_hz_dist_zip "$hz_variant" "$hz_version") 40 | local MSG="Expected URL for variant \"$hz_variant\", version \"$hz_version\"" 41 | assert_eq "$expected_url" "$actual_url" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 42 | } 43 | 44 | function assert_get_hz_dist_zip_for_snapshot { 45 | local hz_variant=$1 46 | local hz_version=$2 47 | local expected_url=$3 48 | local actual_url=$(get_hz_dist_zip "$hz_variant" "$hz_version") 49 | local MSG="Expected URL for variant \"$hz_variant\", version \"$hz_version\" should contain $expected_url" 50 | assert_contain "$actual_url" "$expected_url" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 51 | } 52 | 53 | log_header "Tests for get_hz_dist_zip" 54 | assert_get_hz_dist_zip slim 5.4.0 https://repository.hazelcast.com/release/com/hazelcast/hazelcast-enterprise-distribution/5.4.0/hazelcast-enterprise-distribution-5.4.0-slim.zip 55 | assert_get_hz_dist_zip "" 5.4.0 https://repository.hazelcast.com/release/com/hazelcast/hazelcast-enterprise-distribution/5.4.0/hazelcast-enterprise-distribution-5.4.0.zip 56 | assert_get_hz_dist_zip "" 5.4.1-SNAPSHOT https://repository.hazelcast.com/snapshot/com/hazelcast/hazelcast-enterprise-distribution/5.4.1-SNAPSHOT/hazelcast-enterprise-distribution-5.4.1-SNAPSHOT.zip 57 | 58 | assert_eq 0 "$TESTS_RESULT" "All tests should pass" 59 | -------------------------------------------------------------------------------- /.github/scripts/generate-docker-hub-description.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eEuo pipefail ${RUNNER_DEBUG:+-x} 4 | 5 | get_formatted_latest_docker_tags() { 6 | local REPO_NAME=$1 7 | local PAGE=1 8 | local TAGS="" 9 | while true; do 10 | local RESPONSE=$(curl -s "https://hub.docker.com/v2/repositories/$REPO_NAME/tags/?page=${PAGE}&page_size=100") 11 | local CURRENT_TAGS=$(echo "${RESPONSE}" | jq -r '.results | group_by(.full_size) | .[] | {image: .[0].name, tags: [.[].name]}') 12 | local TAGS="${TAGS}${CURRENT_TAGS}" 13 | local HAS_NEXT=$(echo "${RESPONSE}" | jq -r '.next') 14 | if [ "$HAS_NEXT" == "null" ]; then 15 | break 16 | else 17 | PAGE=$((PAGE + 1)) 18 | fi 19 | done 20 | 21 | local LATEST_TAGS=$(echo "${TAGS}" | jq -sr '.[] | select( 22 | any(.tags[]; match("^5\\..(-slim)?$|latest")) 23 | )') 24 | 25 | echo "${LATEST_TAGS}"| jq -sr '.[] | " - " + (.tags | sort_by(.) | join(", "))' | sort -V 26 | } 27 | 28 | fill_readme_with_tags() { 29 | local filename=$1 30 | local repo_name=$2 31 | local matching_line="$3" 32 | local tags_file="tags-$(basename "$repo_name").md" 33 | get_formatted_latest_docker_tags "$repo_name" > "$tags_file" 34 | 35 | sed -i -e "/$matching_line/ { 36 | a\ 37 | 38 | a\ 39 | #### Latest Versions 40 | a\ 41 | 42 | r $tags_file 43 | }" "$filename" 44 | 45 | rm "$tags_file" 46 | } 47 | 48 | cp README.md README-docker.md 49 | fill_readme_with_tags README-docker.md "hazelcast/hazelcast" "### Hazelcast Versions" 50 | fill_readme_with_tags README-docker.md "hazelcast/hazelcast-enterprise" "### Hazelcast Enterprise Versions" 51 | -------------------------------------------------------------------------------- /.github/scripts/get-tags-to-push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function find_last_matching_version() { 4 | FILTER=$1 5 | git tag | grep -v BETA | grep -v DEVEL | grep '^v' | cut -c2- | grep "^$FILTER" | tail -n 1 6 | } 7 | 8 | function get_latest_version() { 9 | find_last_matching_version "" 10 | } 11 | 12 | function version_less_or_equal() { 13 | [ "$1" = "$(echo -e "$1\n$2" | sort -V | head -n1)" ] 14 | } 15 | 16 | function get_version_only_tags_to_push() { 17 | local VERSION_TO_RELEASE=$1 18 | local IS_LATEST_LTS=$2 19 | 20 | if [ "$#" -ne 2 ]; then 21 | echo "Error: Incorrect number of arguments. Usage: ${FUNCNAME[0]} VERSION_TO_RELEASE IS_LATEST_LTS" 22 | exit 1; 23 | fi 24 | 25 | if [[ "$VERSION_TO_RELEASE" =~ BETA|DEVEL ]]; then 26 | echo "$VERSION_TO_RELEASE" 27 | return 28 | fi 29 | 30 | local MINOR_VERSION_TO_RELEASE=${VERSION_TO_RELEASE%.*} 31 | local MAJOR_VERSION_TO_RELEASE=${MINOR_VERSION_TO_RELEASE%.*} 32 | 33 | local LATEST_FOR_MINOR=$(find_last_matching_version $MINOR_VERSION_TO_RELEASE) 34 | local LATEST_FOR_MAJOR=$(find_last_matching_version $MAJOR_VERSION_TO_RELEASE) 35 | local LATEST=$(get_latest_version) 36 | 37 | local TAGS_TO_PUSH+=($VERSION_TO_RELEASE) 38 | 39 | if version_less_or_equal "$LATEST_FOR_MINOR" "$VERSION_TO_RELEASE"; then 40 | TAGS_TO_PUSH+=($MINOR_VERSION_TO_RELEASE) 41 | fi 42 | 43 | if version_less_or_equal "$LATEST_FOR_MAJOR" "$VERSION_TO_RELEASE"; then 44 | TAGS_TO_PUSH+=($MAJOR_VERSION_TO_RELEASE) 45 | fi 46 | 47 | if version_less_or_equal "$LATEST" "$VERSION_TO_RELEASE"; then 48 | TAGS_TO_PUSH+=("latest") 49 | fi 50 | if [ "$IS_LATEST_LTS" == "true" ] ; then 51 | TAGS_TO_PUSH+=("latest-lts") 52 | fi 53 | 54 | echo "${TAGS_TO_PUSH[@]}" 55 | } 56 | 57 | function get_tags_to_push() { 58 | 59 | if [ "$#" -ne 5 ]; then 60 | echo "Error: Incorrect number of arguments. Usage: ${FUNCNAME[0]} VERSION_TO_RELEASE SUFFIX CURRENT_JDK DEFAULT_JDK IS_LATEST_LTS" 61 | exit 1; 62 | fi 63 | 64 | local VERSION_TO_RELEASE=$1 65 | local SUFFIX=$2 66 | local CURRENT_JDK=$3 67 | local DEFAULT_JDK=$4 68 | local IS_LATEST_LTS=$5 69 | local VERSION_ONLY_TAGS_TO_PUSH=$(get_version_only_tags_to_push "$VERSION_TO_RELEASE" "$IS_LATEST_LTS") 70 | augment_with_suffixed_tags "${VERSION_ONLY_TAGS_TO_PUSH[*]}" "$SUFFIX" "$CURRENT_JDK" "$DEFAULT_JDK" 71 | } 72 | 73 | function augment_with_suffixed_tags() { 74 | 75 | if [ "$#" -ne 4 ]; then 76 | echo "Error: Incorrect number of arguments. Usage: ${FUNCNAME[0]} INITIAL_TAGS SUFFIX CURRENT_JDK DEFAULT_JDK" 77 | exit 1; 78 | fi 79 | 80 | local INITIAL_TAGS=$1 81 | local SUFFIX=$2 82 | local CURRENT_JDK=$3 83 | local DEFAULT_JDK=$4 84 | 85 | for tag in ${INITIAL_TAGS[@]} 86 | do 87 | if [[ "$CURRENT_JDK" == "$DEFAULT_JDK" ]]; then 88 | TAGS_TO_PUSH+=(${tag}$SUFFIX) 89 | fi 90 | TAGS_TO_PUSH+=(${tag}${SUFFIX}-jdk${CURRENT_JDK}) 91 | done 92 | 93 | echo "${TAGS_TO_PUSH[@]}" 94 | } 95 | -------------------------------------------------------------------------------- /.github/scripts/get-tags-to-push_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu ${RUNNER_DEBUG:+-x} 4 | 5 | 6 | SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" 7 | 8 | # Source the latest version of assert.sh unit testing library and include in current shell 9 | assert_script_content=$(curl --silent https://raw.githubusercontent.com/hazelcast/assert.sh/main/assert.sh) 10 | # shellcheck source=/dev/null 11 | . <(echo "${assert_script_content}") 12 | . "$SCRIPT_DIR"/get-tags-to-push.sh 13 | 14 | TESTS_RESULT=0 15 | 16 | function assert_get_version_only_tags_to_push { 17 | local VERSION_TO_RELEASE=$1 18 | local IS_LTS=$2 19 | local EXPECTED_TAGS_TO_PUSH=$3 20 | local ACTUAL_TAGS_TO_PUSH=$(get_version_only_tags_to_push "$VERSION_TO_RELEASE" "$IS_LTS") 21 | local MSG="Tags to push for version $VERSION_TO_RELEASE and is_lts = '$IS_LTS' should be equal to $EXPECTED_TAGS_TO_PUSH" 22 | assert_eq "$EXPECTED_TAGS_TO_PUSH" "$ACTUAL_TAGS_TO_PUSH" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 23 | } 24 | 25 | function assert_augment_with_suffixed_tags { 26 | local INITIAL_TAGS=($1) 27 | local SUFFIX=$2 28 | local CURRENT_JDK=$3 29 | local DEFAULT_JDK=$4 30 | local EXPECTED_TAGS_TO_PUSH=$5 31 | local ACTUAL_TAGS_TO_PUSH=$(augment_with_suffixed_tags "${INITIAL_TAGS[*]}" "$SUFFIX" "$CURRENT_JDK" "$DEFAULT_JDK") 32 | local MSG="Suffixed tags to push for (tags=$INITIAL_TAGS suffix=$SUFFIX current_jdk=$CURRENT_JDK default_jdk=$DEFAULT_JDK) should be equal to: $EXPECTED_TAGS_TO_PUSH" 33 | assert_eq "$EXPECTED_TAGS_TO_PUSH" "$ACTUAL_TAGS_TO_PUSH" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 34 | } 35 | 36 | function assert_get_tags_to_push { 37 | local VERSION_TO_RELEASE=$1 38 | local SUFFIX=$2 39 | local CURRENT_JDK=$3 40 | local DEFAULT_JDK=$4 41 | local IS_LATEST_LTS=$5 42 | local EXPECTED_TAGS_TO_PUSH=$6 43 | local ACTUAL_TAGS_TO_PUSH=$(get_tags_to_push "$VERSION_TO_RELEASE" "$SUFFIX" "$CURRENT_JDK" "$DEFAULT_JDK" "$IS_LATEST_LTS") 44 | local MSG="Tags to push for (version_to_release=$VERSION_TO_RELEASE suffix=$SUFFIX current_jdk=$CURRENT_JDK default_jdk=$DEFAULT_JDK is_latest_lts=$IS_LATEST_LTS) should be equal to: $EXPECTED_TAGS_TO_PUSH " 45 | assert_eq "$EXPECTED_TAGS_TO_PUSH" "$ACTUAL_TAGS_TO_PUSH" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 46 | } 47 | 48 | log_header "Tests for get_version_only_tags_to_push" 49 | assert_get_version_only_tags_to_push "5.2.0" "false" "5.2.0" 50 | assert_get_version_only_tags_to_push "5.2.1" "false" "5.2.1" 51 | assert_get_version_only_tags_to_push "5.1.99" "false" "5.1.99 5.1" 52 | assert_get_version_only_tags_to_push "4.99.0" "false" "4.99.0 4.99 4" 53 | assert_get_version_only_tags_to_push "99.0.0" "false" "99.0.0 99.0 99 latest" 54 | assert_get_version_only_tags_to_push "5.3.0-BETA-1" "false" "5.3.0-BETA-1" 55 | assert_get_version_only_tags_to_push "5.4.0-DEVEL-9" "false" "5.4.0-DEVEL-9" 56 | assert_get_version_only_tags_to_push "5.99.0-BETA-1" "false" "5.99.0-BETA-1" 57 | assert_get_version_only_tags_to_push "99.0.0-BETA-1" "false" "99.0.0-BETA-1" 58 | assert_get_version_only_tags_to_push "99.0.0" "true" "99.0.0 99.0 99 latest latest-lts" 59 | assert_get_version_only_tags_to_push "5.2.0" "true" "5.2.0 latest-lts" 60 | 61 | log_header "Tests for augment_with_suffixed_tags" 62 | assert_augment_with_suffixed_tags "1.2.3" "" "11" "11" "1.2.3 1.2.3-jdk11" 63 | assert_augment_with_suffixed_tags "1.2.3 latest" "" "11" "11" "1.2.3 1.2.3-jdk11 latest latest-jdk11" 64 | assert_augment_with_suffixed_tags "1.2.3" "" "17" "11" "1.2.3-jdk17" 65 | assert_augment_with_suffixed_tags "1.2.3 latest" "" "17" "11" "1.2.3-jdk17 latest-jdk17" 66 | assert_augment_with_suffixed_tags "1.2.3" "-slim" "11" "11" "1.2.3-slim 1.2.3-slim-jdk11" 67 | assert_augment_with_suffixed_tags "1.2.3" "-slim" "17" "11" "1.2.3-slim-jdk17" 68 | assert_augment_with_suffixed_tags "1.2.3 latest" "-slim" "17" "11" "1.2.3-slim-jdk17 latest-slim-jdk17" 69 | assert_augment_with_suffixed_tags "1.2.3 latest-lts" "-slim" "17" "11" "1.2.3-slim-jdk17 latest-lts-slim-jdk17" 70 | tags_array=(1.2.3 latest) 71 | assert_augment_with_suffixed_tags "${tags_array[*]}" "-slim" "17" "11" "1.2.3-slim-jdk17 latest-slim-jdk17" 72 | assert_augment_with_suffixed_tags "1.2.3 1.2" "-slim" "17" "11" "1.2.3-slim-jdk17 1.2-slim-jdk17" 73 | 74 | log_header "Tests for get_tags_to_push" 75 | assert_get_tags_to_push "5.2.0" "" "11" "11" "false" "5.2.0 5.2.0-jdk11" 76 | assert_get_tags_to_push "99.0.0" "" "11" "11" "false" "99.0.0 99.0.0-jdk11 99.0 99.0-jdk11 99 99-jdk11 latest latest-jdk11" 77 | assert_get_tags_to_push "99.0.0-BETA-1" "" "17" "11" "false" "99.0.0-BETA-1-jdk17" 78 | assert_get_tags_to_push "5.4.0-DEVEL-9" "-slim" "17" "false" "11" "5.4.0-DEVEL-9-slim-jdk17" 79 | assert_get_tags_to_push "5.2.0" "" "11" "11" "true" "5.2.0 5.2.0-jdk11 latest-lts latest-lts-jdk11" 80 | assert_get_tags_to_push "99.0.0" "" "11" "11" "true" "99.0.0 99.0.0-jdk11 99.0 99.0-jdk11 99 99-jdk11 latest latest-jdk11 latest-lts latest-lts-jdk11" 81 | 82 | assert_eq 0 "$TESTS_RESULT" "All tests should pass" 83 | -------------------------------------------------------------------------------- /.github/scripts/log.functions.sh: -------------------------------------------------------------------------------- 1 | if command -v tput &>/dev/null && tty -s; then 2 | RED=$(tput setaf 1) 3 | GREEN=$(tput setaf 2) 4 | YELLOW=$(tput setaf 3) 5 | MAGENTA=$(tput setaf 5) 6 | NORMAL=$(tput sgr0) 7 | BOLD=$(tput bold) 8 | else 9 | RED=$(echo -en "\e[31m") 10 | GREEN=$(echo -en "\e[32m") 11 | YELLOW=$(echo -en "\e[33m") 12 | MAGENTA=$(echo -en "\e[35m") 13 | NORMAL=$(echo -en "\e[00m") 14 | BOLD=$(echo -en "\e[01m") 15 | fi 16 | 17 | log_info() { 18 | printf "${GREEN}%s${NORMAL}\n" "$@" >&2 19 | } 20 | 21 | log_warn() { 22 | printf "${YELLOW}%s${NORMAL}\n" "$@" >&2 23 | } 24 | 25 | log_error() { 26 | printf "${RED}%s${NORMAL}\n" "$@" >&2 27 | } 28 | -------------------------------------------------------------------------------- /.github/scripts/logging.functions.sh: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions 2 | 3 | # Prints the given message to stderr 4 | function echoerr() { 5 | # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-error-message 6 | # Support multi-line strings by replacing line separator with GitHub Actions compatible one 7 | echo "::error::ERROR - ${*//$'\n'/%0A}" 1>&2; 8 | } 9 | 10 | # Prints the given message to debug logs, _if enabled_ 11 | function echodebug() { 12 | # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-a-debug-message 13 | echo "::debug::$*" 1>&2; 14 | } 15 | 16 | # Create group 17 | function echo_group() { 18 | # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#grouping-log-lines 19 | local TITLE=$1 20 | echo "::group::${TITLE}" 21 | } 22 | 23 | # Ends group after calling echo_group() 24 | function echo_group_end() { 25 | # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#grouping-log-lines 26 | echo "::endgroup::" 27 | } 28 | -------------------------------------------------------------------------------- /.github/scripts/maven.functions_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu ${RUNNER_DEBUG:+-x} 4 | 5 | function find_script_dir() { 6 | CURRENT=$PWD 7 | 8 | DIR=$(dirname "$0") 9 | cd "$DIR" || exit 10 | TARGET_FILE=$(basename "$0") 11 | 12 | while [ -L "$TARGET_FILE" ] 13 | do 14 | TARGET_FILE=$(readlink "$TARGET_FILE") 15 | DIR=$(dirname "$TARGET_FILE") 16 | cd "$DIR" || exit 17 | TARGET_FILE=$(basename "$TARGET_FILE") 18 | done 19 | 20 | local SCRIPT_DIR=$(pwd -P) 21 | cd "$CURRENT" || exit 22 | echo "$SCRIPT_DIR" 23 | } 24 | 25 | SCRIPT_DIR=$(find_script_dir) 26 | 27 | # Source the latest version of assert.sh unit testing library and include in current shell 28 | assert_script_content=$(curl --silent https://raw.githubusercontent.com/hazelcast/assert.sh/main/assert.sh) 29 | # shellcheck source=/dev/null 30 | . <(echo "${assert_script_content}") 31 | 32 | TESTS_RESULT=0 33 | 34 | # Functions overlap, so likely only testing one implementation - but as are duplicated, *shouldn't* be an issue 35 | OSS_SCRIPT="$SCRIPT_DIR"/../../hazelcast-oss/maven.functions.sh 36 | EE_SCRIPT="$SCRIPT_DIR"/../../hazelcast-enterprise/maven.functions.sh 37 | MSG="Contents of $OSS_SCRIPT and $EE_SCRIPT should be the same" 38 | assert_eq "$(cat "$OSS_SCRIPT")" "$(cat "$EE_SCRIPT")" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 39 | 40 | . "$OSS_SCRIPT" 41 | . "$EE_SCRIPT" 42 | 43 | 44 | function assert_get_latest_version { 45 | local group_id=$1 46 | local artifact_id=$2 47 | local repository_url=$3 48 | local expected_version=$4 49 | local actual_version=$(get_latest_version "$group_id" "$artifact_id" "$repository_url") 50 | local msg="Latest version of $group_id:$artifact_id expected to be equal to $expected_version" 51 | assert_eq "$expected_version" "$actual_version" "$msg" && log_success "$msg" || TESTS_RESULT=$? 52 | } 53 | 54 | 55 | function assert_get_latest_url_without_extension { 56 | local group_id=$1 57 | local artifact_id=$2 58 | local repository_url=$3 59 | local expected_url=$4 60 | local actual_url=$(get_latest_url_without_extension "$group_id" "$artifact_id" "$repository_url") 61 | local msg="Latest URL of $group_id:$artifact_id expected to be equal to $expected_url" 62 | assert_eq "$expected_url" "$actual_url" "$msg" && log_success "$msg" || TESTS_RESULT=$? 63 | } 64 | 65 | log_header "Tests for get_latest_version" 66 | assert_get_latest_version com.google.guava listenablefuture https://repo1.maven.org/maven2 9999.0-empty-to-avoid-conflict-with-guava 67 | assert_get_latest_version com.google.guava listenablefuture https://maven-central.storage.googleapis.com/maven2 9999.0-empty-to-avoid-conflict-with-guava 68 | 69 | log_header "Tests for get_latest_url_without_extension" 70 | assert_get_latest_url_without_extension com.google.guava listenablefuture https://repo1.maven.org/maven2 https://repo1.maven.org/maven2/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava 71 | assert_get_latest_url_without_extension com.google.guava listenablefuture https://maven-central.storage.googleapis.com/maven2 https://maven-central.storage.googleapis.com/maven2/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava 72 | 73 | assert_eq 0 "$TESTS_RESULT" "All tests should pass" 74 | -------------------------------------------------------------------------------- /.github/scripts/oss-build.functions.sh: -------------------------------------------------------------------------------- 1 | set -euo pipefail ${RUNNER_DEBUG:+-x} 2 | 3 | function get_hz_dist_zip() { 4 | local hz_variant=$1 5 | local hz_version=$2 6 | 7 | # The slim is an artifact with a classifier, need to add `-` there 8 | suffix=${hz_variant:+-$hz_variant} 9 | 10 | if [[ "${hz_version}" == *"SNAPSHOT"* ]] 11 | then 12 | url="https://${HZ_SNAPSHOT_INTERNAL_USERNAME}:${HZ_SNAPSHOT_INTERNAL_PASSWORD}@repository.hazelcast.com/snapshot-internal/com/hazelcast/hazelcast-distribution/${hz_version}/hazelcast-distribution-${hz_version}${suffix}.zip" 13 | else 14 | url="https://repo1.maven.org/maven2/com/hazelcast/hazelcast-distribution/${hz_version}/hazelcast-distribution-${hz_version}${suffix}.zip" 15 | fi 16 | 17 | echo "$url" 18 | } 19 | -------------------------------------------------------------------------------- /.github/scripts/oss-build.functions_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu ${RUNNER_DEBUG:+-x} 4 | 5 | function find_script_dir() { 6 | CURRENT=$PWD 7 | 8 | DIR=$(dirname "$0") 9 | cd "$DIR" || exit 10 | TARGET_FILE=$(basename "$0") 11 | 12 | while [ -L "$TARGET_FILE" ] 13 | do 14 | TARGET_FILE=$(readlink "$TARGET_FILE") 15 | DIR=$(dirname "$TARGET_FILE") 16 | cd "$DIR" || exit 17 | TARGET_FILE=$(basename "$TARGET_FILE") 18 | done 19 | 20 | local SCRIPT_DIR=$(pwd -P) 21 | cd "$CURRENT" || exit 22 | echo "$SCRIPT_DIR" 23 | } 24 | 25 | SCRIPT_DIR=$(find_script_dir) 26 | 27 | # Source the latest version of assert.sh unit testing library and include in current shell 28 | assert_script_content=$(curl --silent https://raw.githubusercontent.com/hazelcast/assert.sh/main/assert.sh) 29 | # shellcheck source=/dev/null 30 | . <(echo "${assert_script_content}") 31 | . "$SCRIPT_DIR"/oss-build.functions.sh 32 | 33 | TESTS_RESULT=0 34 | 35 | 36 | function assert_get_hz_dist_zip { 37 | local hz_variant=$1 38 | local hz_version=$2 39 | local expected_url=$3 40 | local actual_url=$(get_hz_dist_zip "$hz_variant" "$hz_version") 41 | local msg="Expected URL for variant \"$hz_variant\", version \"$hz_version\"" 42 | assert_eq "$expected_url" "$actual_url" "$msg" && log_success "$msg" || TESTS_RESULT=$? 43 | } 44 | 45 | log_header "Tests for get_hz_dist_zip" 46 | assert_get_hz_dist_zip slim 5.4.0 https://repo1.maven.org/maven2/com/hazelcast/hazelcast-distribution/5.4.0/hazelcast-distribution-5.4.0-slim.zip 47 | assert_get_hz_dist_zip "" 5.4.0 https://repo1.maven.org/maven2/com/hazelcast/hazelcast-distribution/5.4.0/hazelcast-distribution-5.4.0.zip 48 | 49 | assert_eq 0 "$TESTS_RESULT" "All tests should pass" 50 | -------------------------------------------------------------------------------- /.github/scripts/packages-updated.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function findScriptDir() { 4 | CURRENT=$PWD 5 | 6 | DIR=$(dirname "$0") 7 | cd "$DIR" || exit 8 | TARGET_FILE=$(basename "$0") 9 | 10 | # Iterate down a (possible) chain of symlinks 11 | while [ -L "$TARGET_FILE" ]; do 12 | TARGET_FILE=$(readlink "$TARGET_FILE") 13 | DIR=$(dirname "$TARGET_FILE") 14 | cd "$DIR" || exit 15 | TARGET_FILE=$(basename "$TARGET_FILE") 16 | done 17 | 18 | SCRIPT_DIR=$(pwd -P) 19 | # Restore current directory 20 | cd "$CURRENT" || exit 21 | } 22 | 23 | findScriptDir 24 | 25 | 26 | function packages_updated_oss() { 27 | local IMAGE=$1 28 | docker pull "$IMAGE" 29 | local OUTPUT=$(docker run --user 0 --rm $IMAGE sh -c 'apk update && apk upgrade -s') 30 | echo "$OUTPUT" 31 | PACKAGE_UPGRADES=$(echo "$OUTPUT" | grep --count Upgrading) 32 | if [ "$PACKAGE_UPGRADES" -ne 0 ]; then 33 | return 0 34 | fi 35 | return 1 36 | } 37 | 38 | function packages_updated_ee() { 39 | local IMAGE=$1 40 | docker pull "$IMAGE" 41 | local OUTPUT=$(docker run --user 0 --rm $IMAGE sh -c 'microdnf -y upgrade --nodocs') 42 | echo "$OUTPUT" 43 | PACKAGE_UPGRADES=$(echo "$OUTPUT" | grep --count Upgrading) 44 | if [ "$PACKAGE_UPGRADES" -ne 0 ]; then 45 | return 0 46 | fi 47 | return 1 48 | } 49 | -------------------------------------------------------------------------------- /.github/scripts/publish-rhel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail ${RUNNER_DEBUG:+-x} 4 | 5 | # shellcheck source=../.github/scripts/logging.functions.sh 6 | . .github/scripts/logging.functions.sh 7 | 8 | get_image() 9 | { 10 | local PUBLISHED=$1 11 | local RHEL_PROJECT_ID=$2 12 | local IMAGE_ID=$3 13 | local RHEL_API_KEY=$4 14 | 15 | case "${PUBLISHED}" in 16 | "published") 17 | local PUBLISHED_FILTER="repositories.published==true" 18 | ;; 19 | "not_published") 20 | local PUBLISHED_FILTER="repositories.published!=true" 21 | ;; 22 | *) 23 | echoerr "Need first parameter as 'published' or 'not_published', not '${PUBLISHED}'." ; return 1 24 | ;; 25 | esac 26 | 27 | local FILTER="filter=deleted==false;${PUBLISHED_FILTER};_id==${IMAGE_ID}" 28 | local INCLUDE="include=total,data.repositories,data.certified,data.container_grades,data._id,data.creation_date" 29 | 30 | local RESPONSE 31 | # https://catalog.redhat.com/api/containers/docs/endpoints/RESTGetImagesForCertProjectById.html 32 | RESPONSE=$( \ 33 | curl --silent \ 34 | --request GET \ 35 | --header "X-API-KEY: ${RHEL_API_KEY}" \ 36 | "https://catalog.redhat.com/api/containers/v1/projects/certification/id/${RHEL_PROJECT_ID}/images?${FILTER}&${INCLUDE}") 37 | 38 | echo "${RESPONSE}" 39 | } 40 | 41 | wait_for_container_scan() 42 | { 43 | local RHEL_PROJECT_ID=$1 44 | local IMAGE_ID=$2 45 | local RHEL_API_KEY=$3 46 | local TIMEOUT_IN_MINS=$4 47 | 48 | local IMAGE 49 | local IS_PUBLISHED 50 | 51 | IMAGE=$(get_image published "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}") 52 | IS_PUBLISHED=$(echo "${IMAGE}" | jq -r '.total') 53 | 54 | if [[ ${IS_PUBLISHED} == "1" ]]; then 55 | echo "Image is already published, exiting" 56 | return 0 57 | fi 58 | 59 | local NOF_RETRIES=$(( TIMEOUT_IN_MINS / 2 )) 60 | # Wait until the image is scanned 61 | for i in $(seq 1 "${NOF_RETRIES}"); do 62 | local IMAGE 63 | local SCAN_STATUS 64 | local IMAGE_CERTIFIED 65 | 66 | IMAGE=$(get_image not_published "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}") 67 | SCAN_STATUS=$(echo "${IMAGE}" | jq -r '.data[0].container_grades.status') 68 | IMAGE_CERTIFIED=$(echo "${IMAGE}" | jq -r '.data[0].certified') 69 | 70 | if [[ ${SCAN_STATUS} == "pending" ]]; then 71 | echo "Scanning pending, waiting..." 72 | elif [[ ${SCAN_STATUS} == "in progress" ]]; then 73 | echo "Scanning in progress, waiting..." 74 | elif [[ ${SCAN_STATUS} == "null" ]]; then 75 | echo "Image is still not present in the registry!" 76 | elif [[ ${SCAN_STATUS} == "completed" && "${IMAGE_CERTIFIED}" == "true" ]]; then 77 | echo "Scan passed!" ; return 0 78 | else 79 | echoerr "Scan failed with '${SCAN_STATUS}!" 80 | echoerr "${IMAGE}" 81 | return 1 82 | fi 83 | 84 | sleep 120 85 | 86 | if [[ ${i} == "${NOF_RETRIES}" ]]; then 87 | echoerr "Timeout! Scan could not be finished" 88 | echoerr "${IMAGE}" 89 | return 42 90 | fi 91 | done 92 | } 93 | 94 | publish_the_image() 95 | { 96 | local RHEL_PROJECT_ID=$1 97 | local IMAGE_ID=$2 98 | local RHEL_API_KEY=$3 99 | 100 | echo "Starting publishing the image for ${IMAGE_ID}" 101 | 102 | local IMAGE 103 | local IMAGE_EXISTS 104 | 105 | IMAGE=$(get_image not_published "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}") 106 | IMAGE_EXISTS=$(echo "${IMAGE}" | jq -r '.total') 107 | 108 | if [[ ${IMAGE_EXISTS} == "1" ]]; then 109 | local SCAN_STATUS 110 | local IMAGE_CERTIFIED 111 | 112 | SCAN_STATUS=$(echo "${IMAGE}" | jq -r '.data[0].container_grades.status') 113 | IMAGE_CERTIFIED=$(echo "${IMAGE}" | jq -r '.data[0].certified') 114 | 115 | if [[ ${SCAN_STATUS} != "completed" || "${IMAGE_CERTIFIED}" != "true" ]]; then 116 | echoerr "Image you are trying to publish did not pass the certification test, its status is \"${SCAN_STATUS}\" and certified is \"${IMAGE_CERTIFIED}\"" 117 | return 1 118 | fi 119 | else 120 | echoerr "Image you are trying to publish does not exist." 121 | echoerr "${IMAGE}" 122 | return 1 123 | fi 124 | 125 | echo "Publishing the image ${IMAGE_ID}..." 126 | # https://catalog.redhat.com/api/containers/docs/endpoints/RESTPostImageRequestByCertProjectId.html 127 | RESPONSE=$( \ 128 | curl --silent \ 129 | --retry 5 --retry-all-errors \ 130 | --request POST \ 131 | --header "X-API-KEY: ${RHEL_API_KEY}" \ 132 | --header 'Cache-Control: no-cache' \ 133 | --header 'Content-Type: application/json' \ 134 | --data "{\"image_id\":\"${IMAGE_ID}\" , \"operation\" : \"publish\" }" \ 135 | "https://catalog.redhat.com/api/containers/v1/projects/certification/id/${RHEL_PROJECT_ID}/requests/images") 136 | 137 | echo "Response: ${RESPONSE}" 138 | echo "Created a publish request, please check if the image is published." 139 | } 140 | 141 | sync_tags() 142 | { 143 | local RHEL_PROJECT_ID=$1 144 | local IMAGE_ID=$2 145 | local RHEL_API_KEY=$3 146 | 147 | echo "Starting sync tags for ${IMAGE_ID}" 148 | 149 | local IMAGE 150 | local IMAGE_EXISTS 151 | 152 | IMAGE=$(get_image published "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}") 153 | IMAGE_EXISTS=$(echo "${IMAGE}" | jq -r '.total') 154 | 155 | if [[ ${IMAGE_EXISTS} == "0" ]]; then 156 | echo "Image you are trying to sync does not exist." 157 | return 1 158 | fi 159 | 160 | echo "Syncing tags of the image ${IMAGE_ID}..." 161 | # https://catalog.redhat.com/api/containers/docs/endpoints/RESTPostImageRequestByCertProjectId.html 162 | RESPONSE=$( \ 163 | curl --silent \ 164 | --retry 5 --retry-all-errors \ 165 | --request POST \ 166 | --header "X-API-KEY: ${RHEL_API_KEY}" \ 167 | --header 'Cache-Control: no-cache' \ 168 | --header 'Content-Type: application/json' \ 169 | --data "{\"image_id\":\"${IMAGE_ID}\" , \"operation\" : \"sync-tags\" }" \ 170 | "https://catalog.redhat.com/api/containers/v1/projects/certification/id/${RHEL_PROJECT_ID}/requests/images") 171 | 172 | echo "Response: ${RESPONSE}" 173 | echo "Created a sync-tags request, please check if the tags image are in sync." 174 | } 175 | 176 | wait_for_container_publish() 177 | { 178 | local RHEL_PROJECT_ID=$1 179 | local IMAGE_ID=$2 180 | local RHEL_API_KEY=$3 181 | local TIMEOUT_IN_MINS=$4 182 | 183 | local NOF_RETRIES=$(( TIMEOUT_IN_MINS * 2 )) 184 | # Wait until the image is published 185 | for i in $(seq 1 "${NOF_RETRIES}"); do 186 | local IMAGE 187 | local IS_PUBLISHED 188 | 189 | IMAGE=$(get_image published "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}") 190 | IS_PUBLISHED=$(echo "${IMAGE}" | jq -r '.total') 191 | 192 | if [[ ${IS_PUBLISHED} == "1" ]]; then 193 | echo "Image is published, exiting." 194 | return 0 195 | else 196 | echo "Image is still not published, waiting..." 197 | fi 198 | 199 | sleep 30 200 | 201 | if [[ ${i} == "${NOF_RETRIES}" ]]; then 202 | echoerr "Timeout! Publish could not be finished" 203 | echoerr "Image Status:" 204 | echoerr "${IMAGE}" 205 | 206 | # Add additional logging context if possible 207 | echoerr "Test Results:" 208 | # https://catalog.redhat.com/api/containers/docs/endpoints/RESTGetTestResultsById.html 209 | get_image not_published "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}" | jq -r '.data[]._links.test_results.href' | while read -r TEST_RESULTS_ENDPOINT; do 210 | local TEST_RESULTS 211 | TEST_RESULTS=$(curl --silent \ 212 | --request GET \ 213 | --header "X-API-KEY: ${RHEL_API_KEY}" \ 214 | "https://catalog.redhat.com/api/containers/${TEST_RESULTS_ENDPOINT}") 215 | echoerr "${TEST_RESULTS}" 216 | done 217 | 218 | return 42 219 | fi 220 | done 221 | } 222 | -------------------------------------------------------------------------------- /.github/scripts/simple-smoke-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit ${RUNNER_DEBUG:+-x} 4 | 5 | # shellcheck source=../.github/scripts/abstract-simple-smoke-test.sh 6 | . .github/scripts/abstract-simple-smoke-test.sh 7 | 8 | function remove_container_if_exists() { 9 | local containers 10 | containers=$(docker ps --all --quiet --filter name="${container_name}") 11 | 12 | if [[ -n "${containers}" ]]; then 13 | echo "Removing existing '${container_name}' container" 14 | docker container rm --force "${container_name}" 15 | fi 16 | } 17 | 18 | function start_container() { 19 | echo "Starting container '${container_name}' from image '${image}'" 20 | docker run -it --name "${container_name}" -e HZ_LICENSEKEY -e HZ_INSTANCETRACKING_FILENAME -d -p5701:5701 "${image}" 21 | } 22 | 23 | function get_hz_logs() { 24 | docker logs "${container_name}" 25 | } 26 | 27 | function stop_container() { 28 | echo "Stopping container ${container_name}" 29 | docker stop "${container_name}" 30 | } 31 | 32 | function check_java_version() { 33 | local expected_major_version=$1 34 | local actual_major_version 35 | actual_major_version=$(docker run --rm "${image}" sh -c 'java -version 2>&1 | head -n 1 | awk -F "\"" "{print \$2}" | awk -F "." "{print \$1}"') 36 | 37 | if [[ "${expected_major_version}" == "${actual_major_version}" ]]; then 38 | echo "Expected Java version (${expected_distribution_type}) identified." 39 | else 40 | echoerr "Expected Java version '${expected_major_version}' but got '${actual_major_version}'" 41 | exit 1; 42 | fi 43 | } 44 | 45 | function derive_expected_distribution_type() { 46 | local input_distribution_type=$1 47 | 48 | case "${input_distribution_type}" in 49 | "oss") 50 | echo "Hazelcast Platform" 51 | ;; 52 | "ee") 53 | echo "Hazelcast Enterprise" 54 | ;; 55 | *) 56 | echoerr "Unrecognized distribution type ${input_distribution_type}" 57 | exit 1 58 | ;; 59 | esac 60 | } 61 | 62 | image=$1 63 | container_name=$2 64 | input_distribution_type=$3 65 | expected_version=$4 66 | expected_java_major_version=$5 67 | 68 | 69 | remove_container_if_exists 70 | start_container 71 | 72 | trap stop_container EXIT 73 | 74 | expected_distribution_type=$(derive_expected_distribution_type "${input_distribution_type}") 75 | test_package "${expected_distribution_type}" "${expected_version}" 76 | check_java_version "${expected_java_major_version}" 77 | -------------------------------------------------------------------------------- /.github/scripts/test_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function findScriptDir() { 4 | CURRENT=$PWD 5 | 6 | DIR=$(dirname "$0") 7 | cd "$DIR" || exit 8 | TARGET_FILE=$(basename "$0") 9 | 10 | # Iterate down a (possible) chain of symlinks 11 | while [ -L "$TARGET_FILE" ] 12 | do 13 | TARGET_FILE=$(readlink "$TARGET_FILE") 14 | DIR=$(dirname "$TARGET_FILE") 15 | cd "$DIR" || exit 16 | TARGET_FILE=$(basename "$TARGET_FILE") 17 | done 18 | 19 | SCRIPT_DIR=$(pwd -P) 20 | # Restore current directory 21 | cd "$CURRENT" || exit 22 | } 23 | 24 | findScriptDir 25 | 26 | find "$SCRIPT_DIR" -name "*_tests.sh" -print0 | xargs -0 -n1 bash 27 | -------------------------------------------------------------------------------- /.github/scripts/version.functions.sh: -------------------------------------------------------------------------------- 1 | function get_supported_versions() { 2 | local MINIMAL_VERSION=$1 3 | git tag | sort -V | grep '^v' | cut -c2- | sed -n "/^${MINIMAL_VERSION}.*\$/,\$p" | grep -v BETA | grep -v DEVEL 4 | } 5 | 6 | function get_minor_versions() { 7 | local MINIMAL_VERSION=$1 8 | get_supported_versions "$MINIMAL_VERSION" | cut -d'-' -f1 | cut -d'.' -f1,2 | uniq 9 | } 10 | 11 | function get_latest_patch_version() { 12 | local MINOR_VERSION=$(echo "$1" | cut -d'-' -f1 | cut -d'.' -f1,2) 13 | get_supported_versions "" | grep "^$MINOR_VERSION" | tail -n 1 14 | } 15 | 16 | function get_latest_patch_versions() { 17 | local MINIMAL_VERSION=$1 18 | MINOR_VERSIONS=$(get_minor_versions "$MINIMAL_VERSION") 19 | LATEST_PATCH_VERSIONS=() 20 | for minor in ${MINOR_VERSIONS} 21 | do 22 | LATEST_PATCH_VERSIONS+=($(get_latest_patch_version "$minor")) 23 | done 24 | echo "${LATEST_PATCH_VERSIONS[@]}" 25 | } 26 | 27 | function version_less_or_equal() { 28 | [ "$1" = "$(echo -e "$1\n$2" | sort -V | head -n1)" ] 29 | } 30 | 31 | function get_tags_descending() { 32 | git tag -l "v*" | sort -V -r | grep -v '-' 33 | } 34 | 35 | function file_exists_in_tag() { 36 | local file=$1 37 | local tag=$2 38 | if [ "$#" -ne 2 ]; then 39 | echo "Error: Incorrect number of arguments. Usage: ${FUNCNAME[0]} " 40 | exit 1 41 | fi 42 | # subshell to wrap directory change 43 | ( 44 | set -e 45 | cd -- "$(git rev-parse --show-toplevel)" 46 | git ls-tree -r "$tag" --name-only | grep "^$file$" | grep -q "^$file$" 47 | ) 48 | } 49 | 50 | function get_last_version_with_file() { 51 | local file=$1 52 | if [ "$#" -ne 1 ]; then 53 | echo "Error: Incorrect number of arguments. Usage: ${FUNCNAME[0]} " 54 | exit 1 55 | fi 56 | for tag in $(get_tags_descending); do 57 | if file_exists_in_tag "$file" "$tag"; then 58 | echo "$tag" | cut -c2- 59 | return 60 | fi 61 | done 62 | } 63 | -------------------------------------------------------------------------------- /.github/scripts/version.functions_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" 4 | 5 | # Source the latest version of assert.sh unit testing library and include in current shell 6 | assert_script_content=$(curl --silent https://raw.githubusercontent.com/hazelcast/assert.sh/main/assert.sh) 7 | # shellcheck source=/dev/null 8 | . <(echo "${assert_script_content}") 9 | . "$SCRIPT_DIR"/version.functions.sh 10 | 11 | TESTS_RESULT=0 12 | 13 | function assert_minor_versions_contain { 14 | local MINIMAL_SUPPORTED_VERSION=$1 15 | local EXPECTED_VERSION=$2 16 | local ACTUAL_MINOR_VERSIONS=$(get_minor_versions "$MINIMAL_SUPPORTED_VERSION") 17 | local MSG="Minor versions starting from $MINIMAL_SUPPORTED_VERSION should contain $EXPECTED_VERSION " 18 | assert_contain "$ACTUAL_MINOR_VERSIONS" "$EXPECTED_VERSION" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 19 | } 20 | 21 | function assert_minor_versions_not_contain { 22 | local MINIMAL_SUPPORTED_VERSION=$1 23 | local EXPECTED_VERSION=$2 24 | local ACTUAL_MINOR_VERSIONS=$(get_minor_versions "$MINIMAL_SUPPORTED_VERSION") 25 | local MSG="Minor versions starting from $MINIMAL_SUPPORTED_VERSION should NOT contain $EXPECTED_VERSION" 26 | assert_not_contain "$ACTUAL_MINOR_VERSIONS" "$EXPECTED_VERSION" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 27 | } 28 | 29 | function assert_latest_patch_version { 30 | local MINOR_VERSION=$1 31 | local EXPECTED_VERSION=$2 32 | local ACTUAL_VERSION=$(get_latest_patch_version "$MINOR_VERSION") 33 | local MSG="Latest patch version of $MINOR_VERSION should be $EXPECTED_VERSION" 34 | assert_eq "$ACTUAL_VERSION" "$EXPECTED_VERSION" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 35 | } 36 | 37 | 38 | function assert_latest_patch_versions_contain { 39 | local MINIMAL_SUPPORTED_VERSION=$1 40 | local EXPECTED_VERSION=$2 41 | local ACTUAL_LATEST_PATCH_VERSIONS=$(get_latest_patch_versions "$MINIMAL_SUPPORTED_VERSION") 42 | local MSG="Latest patch versions starting from $MINIMAL_SUPPORTED_VERSION should contain $EXPECTED_VERSION" 43 | assert_contain "$ACTUAL_LATEST_PATCH_VERSIONS" "$EXPECTED_VERSION" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 44 | } 45 | 46 | function assert_latest_patch_versions_not_contain { 47 | local MINIMAL_SUPPORTED_VERSION=$1 48 | local EXPECTED_VERSION=$2 49 | local ACTUAL_LATEST_PATCH_VERSIONS=$(get_latest_patch_versions "$MINIMAL_SUPPORTED_VERSION") 50 | local MSG="Latest patch versions starting from $MINIMAL_SUPPORTED_VERSION should NOT contain $EXPECTED_VERSION" 51 | assert_not_contain "$ACTUAL_LATEST_PATCH_VERSIONS" "$EXPECTED_VERSION" "$MSG" && log_success "$MSG" || TESTS_RESULT=$? 52 | } 53 | 54 | function assert_get_last_version_with_file { 55 | local FILE=$1 56 | local EXPECTED_LAST_VERSION=$2 57 | local ACTUAL_LAST_VERSION=$(get_last_version_with_file "$FILE") 58 | assert_eq "$ACTUAL_LAST_VERSION" "$EXPECTED_LAST_VERSION" "Last version of $FILE should be ${EXPECTED_LAST_VERSION:-} " || TESTS_RESULT=$? 59 | } 60 | 61 | log_header "Tests for get_latest_patch_version" 62 | assert_latest_patch_version "4.2.1" "4.2.8" 63 | assert_latest_patch_version "4.2" "4.2.8" 64 | assert_latest_patch_version "4.2" "4.2.8" 65 | assert_latest_patch_version "4.0" "4.0.6" 66 | assert_latest_patch_version "4.1-BETA-1" "4.1.10" 67 | assert_latest_patch_version "4.1" "4.1.10" 68 | assert_latest_patch_version "3.9" "3.9.4" 69 | 70 | log_header "Tests for get_minor_versions" 71 | assert_minor_versions_contain "3.12" "3.12" 72 | assert_minor_versions_contain "4.2" "4.2" 73 | assert_minor_versions_contain "4.2" "5.0" 74 | assert_minor_versions_contain "4.2" "5.1" 75 | assert_minor_versions_contain "4.2" "5.2" 76 | assert_minor_versions_not_contain "4.2" "4.1" 77 | assert_minor_versions_not_contain "4.2" "4.0" 78 | assert_minor_versions_not_contain "4.2" "3.9" 79 | 80 | log_header "Tests for get_latest_patch_versions" 81 | assert_latest_patch_versions_contain "3.9" "3.9.4" 82 | assert_latest_patch_versions_contain "3.12" "3.12.12-1" 83 | assert_latest_patch_versions_contain "4.0.1" "4.0.6" 84 | assert_latest_patch_versions_contain "4.0-BETA-2" "4.0.6" 85 | assert_latest_patch_versions_contain "4.1" "4.1.10" 86 | assert_latest_patch_versions_not_contain "3.12" "3.12.11" 87 | assert_latest_patch_versions_not_contain "4.2" "3.9.4" 88 | assert_latest_patch_versions_not_contain "4.2" "4.1.10" 89 | LATEST_5_4_DEVEL="$(git tag | sort -V | grep 'v5.4.0-DEVEL-' | tail -n 1 | cut -c2-)" 90 | assert_latest_patch_versions_not_contain "5.3" "$LATEST_5_4_DEVEL" 91 | 92 | log_header "Tests for get_last_version_with_file" 93 | assert_get_last_version_with_file ".github/containerscan/allowedlist.yaml" "5.3.1" # it was removed in 5.3.2 94 | assert_get_last_version_with_file ".github/actions/install-xmllint/action.yml" "5.4.1" # it was removed in 5.4.2 95 | assert_get_last_version_with_file "dummy-non-existing-file" "" 96 | 97 | assert_eq 0 "$TESTS_RESULT" "All tests should pass" 98 | -------------------------------------------------------------------------------- /.github/workflows/build-pr.yml: -------------------------------------------------------------------------------- 1 | name: Build PR 2 | 3 | on: 4 | pull_request: 5 | 6 | env: 7 | test_container_name_oss: hazelcast-oss-test 8 | test_container_name_ee: hazelcast-ee-test 9 | docker_log_file_oss: docker-hazelcast-oss-test.log 10 | docker_log_file_ee: docker-hazelcast-ee-test.log 11 | 12 | jobs: 13 | prepare: 14 | runs-on: ubuntu-latest 15 | name: Prepare environment 16 | outputs: 17 | HZ_VERSION_OSS: ${{ steps.get_oss_vars.outputs.HZ_VERSION_OSS }} 18 | HZ_VERSION_EE: ${{ steps.get_ee_vars.outputs.HZ_VERSION_EE }} 19 | LAST_RELEASED_HZ_VERSION_OSS: ${{ steps.get_oss_vars.outputs.LAST_RELEASED_HZ_VERSION_OSS }} 20 | HAZELCAST_EE_ZIP_URL: ${{ steps.get_ee_vars.outputs.HAZELCAST_EE_ZIP_URL }} 21 | steps: 22 | - name: Checkout Code 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Forbid .github/release_type file 28 | run: | 29 | if [ -f ".github/release_type" ]; then 30 | echo "Error: .github/release_type file is not allowed in the PRs. It's used only during release creation" 31 | exit 1 32 | fi 33 | 34 | - name: Test scripts 35 | run: | 36 | .github/scripts/test_scripts.sh 37 | 38 | - name: Setup OSS variables 39 | id: get_oss_vars 40 | run: | 41 | HZ_VERSION_OSS=$(awk -F '=' '/^ARG HZ_VERSION=/ {print $2}' hazelcast-oss/Dockerfile) 42 | echo "HZ_VERSION_OSS=$HZ_VERSION_OSS" >> $GITHUB_OUTPUT 43 | 44 | source hazelcast-oss/maven.functions.sh 45 | LAST_RELEASED_HZ_VERSION_OSS="$(get_latest_version com.hazelcast hazelcast-distribution https://repo1.maven.org/maven2)"; 46 | echo "LAST_RELEASED_HZ_VERSION_OSS=$LAST_RELEASED_HZ_VERSION_OSS" >> $GITHUB_OUTPUT 47 | 48 | - name: Setup EE variables 49 | id: get_ee_vars 50 | run: | 51 | HZ_VERSION_EE=$(awk -F '=' '/^ARG HZ_VERSION=/ {print $2}' hazelcast-enterprise/Dockerfile) 52 | . .github/scripts/ee-build.functions.sh 53 | echo "HZ_VERSION_EE=$HZ_VERSION_EE" >> $GITHUB_OUTPUT 54 | echo "HAZELCAST_EE_ZIP_URL=$(get_hz_dist_zip "" ${HZ_VERSION_EE})" >> $GITHUB_OUTPUT 55 | 56 | build-pr: 57 | runs-on: ubuntu-latest 58 | name: Build with default JDK 59 | needs: [ prepare ] 60 | steps: 61 | - name: Checkout Code 62 | uses: actions/checkout@v4 63 | with: 64 | ref: refs/pull/${{ github.event.pull_request.number }}/merge 65 | fetch-depth: 0 66 | 67 | - name: Set up Docker 68 | uses: docker/setup-buildx-action@v3 69 | 70 | - name: Build OSS image 71 | run: | 72 | DOCKER_PATH=hazelcast-oss 73 | HZ_VERSION="${{ needs.prepare.outputs.HZ_VERSION_OSS }}" 74 | 75 | # duplicated block as GH doesn't support passing sensitive data between jobs 76 | . .github/scripts/oss-build.functions.sh 77 | export HZ_SNAPSHOT_INTERNAL_PASSWORD=${{ secrets.HZ_SNAPSHOT_INTERNAL_PASSWORD }} 78 | export HZ_SNAPSHOT_INTERNAL_USERNAME=${{ secrets.HZ_SNAPSHOT_INTERNAL_USERNAME }} 79 | HAZELCAST_OSS_ZIP_URL=$(get_hz_dist_zip "" "${HZ_VERSION}") 80 | 81 | curl --fail --silent --show-error --location "$HAZELCAST_OSS_ZIP_URL" --output $DOCKER_PATH/hazelcast-distribution.zip; 82 | 83 | docker buildx build --load \ 84 | --build-arg HZ_VERSION=${HZ_VERSION} \ 85 | --tag hazelcast-oss:test \ 86 | "${DOCKER_PATH}" 87 | 88 | - name: Run smoke test against OSS image 89 | timeout-minutes: 2 90 | run: | 91 | . .github/scripts/docker.functions.sh 92 | .github/scripts/simple-smoke-test.sh hazelcast-oss:test "${{ env.test_container_name_oss }}" oss "${{ needs.prepare.outputs.HZ_VERSION_OSS }}" "$(get_default_jdk hazelcast-oss)" 93 | 94 | - name: Build Test EE image 95 | run: | 96 | DOCKER_PATH=hazelcast-enterprise 97 | HZ_VERSION="${{ needs.prepare.outputs.HZ_VERSION_EE }}" 98 | curl --fail --silent --show-error --location "${{ needs.prepare.outputs.HAZELCAST_EE_ZIP_URL }}" --output $DOCKER_PATH/hazelcast-enterprise-distribution.zip; 99 | 100 | docker buildx build --load \ 101 | --build-arg HZ_VERSION=${HZ_VERSION} \ 102 | --tag hazelcast-ee:test \ 103 | "${DOCKER_PATH}" 104 | 105 | - name: Run smoke test against EE image 106 | timeout-minutes: 2 107 | run: | 108 | . .github/scripts/docker.functions.sh 109 | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} 110 | .github/scripts/simple-smoke-test.sh hazelcast-ee:test "${{ env.test_container_name_ee }}" ee "${{ needs.prepare.outputs.HZ_VERSION_EE }}" "$(get_default_jdk hazelcast-enterprise)" 111 | 112 | - name: Get docker logs 113 | if: ${{ always() }} 114 | run: | 115 | docker logs "${{ env.test_container_name_oss }}" > "${{ env.docker_log_file_oss }}" 116 | docker logs "${{ env.test_container_name_ee }}" > "${{ env.docker_log_file_ee }}" 117 | 118 | - name: Store docker logs as artifact 119 | if: ${{ always() }} 120 | uses: actions/upload-artifact@v4 121 | with: 122 | name: docker-logs-${{ github.job }} 123 | path: | 124 | ${{ env.docker_log_file_oss }} 125 | ${{ env.docker_log_file_ee }} 126 | 127 | jdks: 128 | uses: ./.github/workflows/get-supported-jdks.yaml 129 | 130 | build-pr-custom-jdk: 131 | runs-on: ubuntu-latest 132 | needs: [ jdks, prepare ] 133 | name: Build with jdk-${{ matrix.jdk }} 134 | strategy: 135 | fail-fast: false 136 | matrix: 137 | jdk: ${{ fromJSON(needs.jdks.outputs.jdks) }} 138 | steps: 139 | - name: Checkout Code 140 | uses: actions/checkout@v4 141 | with: 142 | ref: refs/pull/${{ github.event.pull_request.number }}/merge 143 | fetch-depth: 0 144 | 145 | - name: Set up Docker 146 | uses: docker/setup-buildx-action@v3 147 | 148 | - name: Build OSS image 149 | run: | 150 | DOCKER_PATH=hazelcast-oss 151 | HZ_VERSION="${{ needs.prepare.outputs.HZ_VERSION_OSS }}" 152 | 153 | # duplicated block as GH doesn't support passing sensitive data between jobs 154 | . .github/scripts/oss-build.functions.sh 155 | export HZ_SNAPSHOT_INTERNAL_PASSWORD=${{ secrets.HZ_SNAPSHOT_INTERNAL_PASSWORD }} 156 | export HZ_SNAPSHOT_INTERNAL_USERNAME=${{ secrets.HZ_SNAPSHOT_INTERNAL_USERNAME }} 157 | HAZELCAST_OSS_ZIP_URL=$(get_hz_dist_zip "" "${HZ_VERSION}") 158 | 159 | curl --fail --silent --show-error --location "$HAZELCAST_OSS_ZIP_URL" --output $DOCKER_PATH/hazelcast-distribution.zip; 160 | 161 | docker buildx build --load \ 162 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 163 | --build-arg HZ_VERSION=${HZ_VERSION} \ 164 | --tag hazelcast-oss:test \ 165 | "${DOCKER_PATH}" 166 | 167 | - name: Run smoke test against OSS image 168 | timeout-minutes: 2 169 | run: | 170 | .github/scripts/simple-smoke-test.sh hazelcast-oss:test "${{ env.test_container_name_oss }}" oss "${{ needs.prepare.outputs.HZ_VERSION_OSS }}" "${{ matrix.jdk }}" 171 | 172 | - name: Build Test EE image 173 | run: | 174 | DOCKER_PATH=hazelcast-enterprise 175 | HZ_VERSION="${{ needs.prepare.outputs.HZ_VERSION_EE }}" 176 | curl --fail --silent --show-error --location "${{ needs.prepare.outputs.HAZELCAST_EE_ZIP_URL }}" --output $DOCKER_PATH/hazelcast-enterprise-distribution.zip; 177 | 178 | docker buildx build --load \ 179 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 180 | --build-arg HZ_VERSION=${HZ_VERSION} \ 181 | --tag hazelcast-ee:test \ 182 | "${DOCKER_PATH}" 183 | 184 | - name: Run smoke test against EE image 185 | timeout-minutes: 2 186 | run: | 187 | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} 188 | .github/scripts/simple-smoke-test.sh hazelcast-ee:test "${{ env.test_container_name_ee }}" ee "${{ needs.prepare.outputs.HZ_VERSION_EE }}" "${{ matrix.jdk }}" 189 | 190 | - name: Get docker logs 191 | if: ${{ always() }} 192 | run: | 193 | docker logs "${{ env.test_container_name_oss }}" > "${{ env.docker_log_file_oss }}" 194 | docker logs "${{ env.test_container_name_ee }}" > "${{ env.docker_log_file_ee }}" 195 | 196 | - name: Store docker logs as artifact 197 | if: ${{ always() }} 198 | uses: actions/upload-artifact@v4 199 | with: 200 | name: docker-logs-${{ github.job }}-jdk${{ matrix.jdk }} 201 | path: | 202 | ${{ env.docker_log_file_oss }} 203 | ${{ env.docker_log_file_ee }} 204 | 205 | test-push: 206 | name: Test pushing image (dry run) 207 | needs: [ prepare ] 208 | uses: ./.github/workflows/tag_image_push.yml 209 | with: 210 | HZ_VERSION: ${{ needs.prepare.outputs.LAST_RELEASED_HZ_VERSION_OSS }} 211 | RELEASE_TYPE: ALL 212 | DRY_RUN: true 213 | secrets: inherit 214 | 215 | test-push-rhel: 216 | name: Test pushing RHEL image (dry run) 217 | needs: [ prepare ] 218 | uses: ./.github/workflows/tag_image_push_rhel.yml 219 | with: 220 | HZ_VERSION: ${{ needs.prepare.outputs.LAST_RELEASED_HZ_VERSION_OSS }} 221 | DRY_RUN: true 222 | secrets: inherit 223 | -------------------------------------------------------------------------------- /.github/workflows/check-base-images.yml: -------------------------------------------------------------------------------- 1 | name: Check base images 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | MINIMAL_SUPPORTED_VERSION: 7 | description: 'Minimal supported version from which we should start checking images, e.g. 5.1, 5.0.1, 4.2.3. Default derived from supported maintenance versions' 8 | required: false 9 | schedule: 10 | - cron: '0 6 * * *' 11 | 12 | jobs: 13 | get-latest-patch-versions: 14 | runs-on: ubuntu-latest 15 | name: Get latest patch versions 16 | outputs: 17 | matrix: ${{ steps.set-matrix.outputs.matrix }} 18 | env: 19 | MINIMAL_SUPPORTED_VERSION: ${{ inputs.MINIMAL_SUPPORTED_VERSION }} 20 | steps: 21 | - name: Checkout Code 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | - id: get-maintenance-versions 26 | uses: hazelcast/hazelcast/.github/actions/get-supported-maintenance-versions@master 27 | - name: Calculate minimal supported version 28 | run: echo "DEFAULT_MINIMAL_SUPPORTED_VERSION=$(echo '${{ steps.get-maintenance-versions.outputs.versions }}' | jq '.[0]')" >> $GITHUB_ENV 29 | - id: set-matrix 30 | name: Get latest patch versions 31 | run: | 32 | . .github/scripts/version.functions.sh 33 | MIN_VERSION=${MINIMAL_SUPPORTED_VERSION:-$DEFAULT_MINIMAL_SUPPORTED_VERSION} 34 | echo "Getting latest patch versions starting from $MIN_VERSION" 35 | versions=$(printf '%s\n' $(get_latest_patch_versions "${MIN_VERSION}") | jq -R . | jq -c -s .) 36 | echo "Found latest patch versions: $versions" 37 | echo "matrix={\"version\":$versions}" >> $GITHUB_OUTPUT 38 | - name: Slack notification 39 | uses: ./.github/actions/slack-notification 40 | if: failure() 41 | with: 42 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 43 | 44 | trigger-rebuilds: 45 | runs-on: ubuntu-latest 46 | name: Rebuild ${{ matrix.version }} if base image changed 47 | needs: get-latest-patch-versions 48 | env: 49 | NLC_IMAGE_NAME: ${{ secrets.NLC_IMAGE_NAME }} 50 | strategy: 51 | fail-fast: false 52 | matrix: ${{ fromJSON(needs.get-latest-patch-versions.outputs.matrix) }} 53 | steps: 54 | - name: Checkout Code 55 | uses: actions/checkout@v4 56 | - name: Checkout version ${{ matrix.version }} 57 | uses: actions/checkout@v4 58 | with: 59 | ref: v${{ matrix.version }} 60 | path: v${{ matrix.version }} 61 | token: ${{ secrets.GITHUB_TOKEN }} 62 | - name: Login to NLC Docker Repository 63 | uses: docker/login-action@v3 64 | with: 65 | registry: ${{ secrets.NLC_REPOSITORY }} 66 | username: ${{ secrets.NLC_REPO_USERNAME }} 67 | password: ${{ secrets.NLC_REPO_TOKEN }} 68 | - name: Check if ${{ matrix.version }} base images updated 69 | run: | 70 | . .github/scripts/base-image-updated.sh 71 | . .github/scripts/packages-updated.sh 72 | . .github/scripts/log.functions.sh 73 | echo "Checking OSS ${{ matrix.version }} image" 74 | if base_image_updated hazelcast/hazelcast:${{ matrix.version }} v${{ matrix.version }}/hazelcast-oss/Dockerfile; then 75 | echo "OSS_NEEDS_REBUILD=yes" >> $GITHUB_ENV 76 | log_info "Image OSS ${{ matrix.version }} needs rebuild" 77 | else 78 | log_info "Image OSS ${{ matrix.version }} is up-to-date" 79 | fi 80 | echo "Checking system package upgrades for OSS ${{ matrix.version }} image" 81 | if packages_updated_oss hazelcast/hazelcast:${{ matrix.version }}; then 82 | echo "OSS_NEEDS_REBUILD=yes" >> $GITHUB_ENV 83 | log_info "System package upgrades for OSS ${{ matrix.version }} image available" 84 | else 85 | log_info "System packages for OSS ${{ matrix.version }} image are up-to-date" 86 | fi 87 | echo "Checking EE ${{ matrix.version }} image" 88 | if base_image_updated hazelcast/hazelcast-enterprise:${{ matrix.version }} v${{ matrix.version }}/hazelcast-enterprise/Dockerfile; then 89 | echo "EE_NEEDS_REBUILD=yes" >> $GITHUB_ENV 90 | log_info "Image EE ${{ matrix.version }} needs rebuild" 91 | else 92 | log_info "Image EE ${{ matrix.version }} is up-to-date" 93 | fi 94 | echo "Checking system package upgrades for EE ${{ matrix.version }} image" 95 | if packages_updated_ee hazelcast/hazelcast-enterprise:${{ matrix.version }}; then 96 | echo "EE_NEEDS_REBUILD=yes" >> $GITHUB_ENV 97 | log_info "System package upgrades for EE ${{ matrix.version }} image available" 98 | else 99 | log_info "System packages for EE ${{ matrix.version }} image are up-to-date" 100 | fi 101 | echo "Checking EE NLC ${{ matrix.version }} image" 102 | if base_image_updated ${NLC_IMAGE_NAME}:${{ matrix.version }} v${{ matrix.version }}/hazelcast-enterprise/Dockerfile; then 103 | echo "EE_NLC_NEEDS_REBUILD=yes" >> $GITHUB_ENV 104 | log_info "Image EE NLC ${{ matrix.version }} needs rebuild" 105 | else 106 | log_info "Image EE NLC ${{ matrix.version }} is up-to-date" 107 | fi 108 | echo "Checking system package upgrades for EE NLC ${{ matrix.version }} image" 109 | if packages_updated_ee ${NLC_IMAGE_NAME}:${{ matrix.version }}; then 110 | echo "EE_NLC_NEEDS_REBUILD=yes" >> $GITHUB_ENV 111 | log_info "System package upgrades for EE NLC ${{ matrix.version }} image available" 112 | else 113 | log_info "System packages for EE NLC ${{ matrix.version }} image are up-to-date" 114 | fi 115 | - name: Rebuild ${{ matrix.version }} EE image 116 | if: env.EE_NEEDS_REBUILD == 'yes' 117 | run: | 118 | echo "Rebuilding ${{ matrix.version }} EE image" 119 | gh workflow run tag_image_push.yml --ref v${{ matrix.version }} -f HZ_VERSION=${{ matrix.version }} -f RELEASE_TYPE=EE 120 | gh workflow run tag_image_push_rhel.yml --ref v${{ matrix.version }} -f HZ_VERSION=${{ matrix.version }} 121 | env: 122 | GH_TOKEN: ${{ github.token }} 123 | - name: Rebuild ${{ matrix.version }} EE NLC image 124 | if: env.EE_NLC_NEEDS_REBUILD == 'yes' 125 | run: | 126 | echo "Rebuilding ${{ matrix.version }} EE NLC image" 127 | gh workflow run ee-nlc-tag-push.yml --ref v${{ matrix.version }} -f HZ_VERSION=${{ matrix.version }} 128 | env: 129 | GH_TOKEN: ${{ github.token }} 130 | - name: Slack notification 131 | uses: ./.github/actions/slack-notification 132 | if: failure() && github.event_name != 'workflow_dispatch' 133 | with: 134 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 135 | -------------------------------------------------------------------------------- /.github/workflows/check-redhat-service-status.yml: -------------------------------------------------------------------------------- 1 | name: Redhat status test 2 | # Entry point to debug the `check-redhat-service-status` action 3 | 4 | on: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | push: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: ./.github/actions/check-redhat-service-status 13 | -------------------------------------------------------------------------------- /.github/workflows/ee-nlc-snapshot-push.yml: -------------------------------------------------------------------------------- 1 | name: Build EE NLC snapshot image 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | HZ_VERSION: 7 | description: 'Version of Hazelcast to build the image for' 8 | required: true 9 | HZ_EE_REVISION: 10 | description: 'Commit id of Hazelcast Enterprise snapshot jar' 11 | required: true 12 | env: 13 | test_container_name_ee: hazelcast-ee-test 14 | 15 | jobs: 16 | jdks: 17 | uses: ./.github/workflows/get-supported-jdks.yaml 18 | 19 | push: 20 | runs-on: ubuntu-latest 21 | needs: jdks 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | jdk: ${{ fromJSON(needs.jdks.outputs.jdks) }} 26 | env: 27 | HZ_VERSION : ${{ inputs.HZ_VERSION }} 28 | NLC_IMAGE_NAME: ${{ secrets.NLC_IMAGE_NAME }} 29 | S3_NLC_URL: ${{ secrets.S3_NLC_URL }} 30 | steps: 31 | - name: Checkout Code 32 | uses: actions/checkout@v4 33 | 34 | - name: Configure AWS credentials 35 | uses: aws-actions/configure-aws-credentials@v4 36 | with: 37 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 38 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 39 | aws-region: 'us-east-1' 40 | 41 | - name: Get presigned NLC URL from S3 42 | run: | 43 | ZIP_NAME=hazelcast-enterprise-${HZ_VERSION}-nlc.zip 44 | S3_NLC_ZIP_URL=${S3_NLC_URL}/snapshot/${ZIP_NAME} 45 | 46 | HAZELCAST_ZIP_URL="$(aws s3 presign ${S3_NLC_ZIP_URL} --expires-in 600)" 47 | echo "HAZELCAST_ZIP_URL=${HAZELCAST_ZIP_URL}" >> $GITHUB_ENV 48 | 49 | - name: Login to Docker Hub 50 | uses: docker/login-action@v3 51 | with: 52 | registry: ${{ secrets.NLC_REPOSITORY }} 53 | username: ${{ secrets.NLC_REPO_USERNAME }} 54 | password: ${{ secrets.NLC_REPO_TOKEN }} 55 | 56 | - name: Set up QEMU 57 | uses: docker/setup-qemu-action@v3.6.0 58 | 59 | - name: Set up Docker Buildx 60 | uses: docker/setup-buildx-action@v3 61 | with: 62 | version: v0.5.1 63 | 64 | - name: Build EE image 65 | run: | 66 | docker buildx build --load \ 67 | --build-arg HZ_VERSION=${HZ_VERSION} \ 68 | --build-arg HAZELCAST_ZIP_URL=${HAZELCAST_ZIP_URL} \ 69 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 70 | --label hazelcast.ee.revision=${{ inputs.HZ_EE_REVISION }} \ 71 | --tag hazelcast-nlc:test hazelcast-enterprise 72 | 73 | - name: Run smoke test against EE image 74 | timeout-minutes: 2 75 | run: | 76 | export HZ_INSTANCETRACKING_FILENAME=instance-tracking.txt 77 | .github/scripts/simple-smoke-test.sh hazelcast-nlc:test "${{ env.test_container_name_ee }}" ee ${HZ_VERSION} "${{ matrix.jdk }}" 78 | 79 | - name: Get docker logs 80 | if: ${{ always() }} 81 | run: | 82 | DOCKER_LOG_FILE_EE=docker-${{ env.test_container_name_ee }}-jdk${{ matrix.jdk }}.log 83 | echo "DOCKER_LOG_FILE_EE=${DOCKER_LOG_FILE_EE}" >> $GITHUB_ENV 84 | docker logs "${{ env.test_container_name_ee }}" > "${DOCKER_LOG_FILE_EE}" 85 | 86 | - name: Store docker logs as artifact 87 | if: ${{ always() }} 88 | uses: actions/upload-artifact@v4 89 | with: 90 | name: docker-logs-${{ github.job }}-jdk${{ matrix.jdk }} 91 | path: | 92 | ${{ env.DOCKER_LOG_FILE_EE }} 93 | 94 | - name: Build/Push EE image 95 | run: | 96 | . .github/scripts/get-tags-to-push.sh 97 | . .github/scripts/docker.functions.sh 98 | 99 | DOCKER_DIR=hazelcast-enterprise 100 | IMAGE_NAME=${NLC_IMAGE_NAME} 101 | DEFAULT_JDK="$(get_default_jdk $DOCKER_DIR)" 102 | 103 | TAGS_TO_PUSH=$(augment_with_suffixed_tags "$HZ_VERSION" "" "${{ matrix.jdk }}" "$DEFAULT_JDK") 104 | echo "TAGS_TO_PUSH=$TAGS_TO_PUSH" 105 | TAGS_ARG="" 106 | for tag in ${TAGS_TO_PUSH[@]} 107 | do 108 | TAGS_ARG="${TAGS_ARG} --tag ${IMAGE_NAME}:${tag}" 109 | done 110 | 111 | PLATFORMS="$(get_ubi_supported_platforms "${{ matrix.jdk }}")" 112 | docker buildx build --push \ 113 | --build-arg HZ_VERSION=${HZ_VERSION} \ 114 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 115 | --build-arg HAZELCAST_ZIP_URL=${HAZELCAST_ZIP_URL} \ 116 | --label hazelcast.ee.revision=${{ inputs.HZ_EE_REVISION }} \ 117 | ${TAGS_ARG} \ 118 | --platform=${PLATFORMS} $DOCKER_DIR 119 | - name: Check RedHat service status 120 | if: failure() 121 | uses: ./.github/actions/check-redhat-service-status 122 | - name: Slack notification 123 | uses: ./.github/actions/slack-notification 124 | if: failure() && github.triggering_actor == 'devOpsHazelcast' 125 | with: 126 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 127 | -------------------------------------------------------------------------------- /.github/workflows/ee-nlc-tag-push.yml: -------------------------------------------------------------------------------- 1 | name: Build EE NLC tag image 2 | 3 | on: 4 | push: 5 | branches: 6 | - "!*" 7 | tags: 8 | - "v5.*" 9 | - "v6.*" 10 | - '!*DEVEL*' 11 | workflow_dispatch: 12 | inputs: 13 | HZ_VERSION: 14 | description: 'Version of Hazelcast to build the image for, e.g. 5.3.2, 5.1.1, 5.0.1' 15 | required: true 16 | 17 | env: 18 | test_container_name_ee: hazelcast-ee-test 19 | 20 | jobs: 21 | jdks: 22 | uses: ./.github/workflows/get-supported-jdks.yaml 23 | 24 | push: 25 | runs-on: ubuntu-latest 26 | needs: jdks 27 | strategy: 28 | fail-fast: false 29 | matrix: 30 | jdk: ${{ fromJSON(needs.jdks.outputs.jdks) }} 31 | env: 32 | NLC_IMAGE_NAME: ${{ secrets.NLC_IMAGE_NAME }} 33 | S3_NLC_URL: ${{ secrets.S3_NLC_URL }} 34 | HZ_VERSION: ${{ inputs.HZ_VERSION }} 35 | steps: 36 | - name: Checkout Code 37 | uses: actions/checkout@v4 38 | 39 | - name: Set HZ version 40 | if: env.HZ_VERSION == '' 41 | run: | 42 | echo "HZ_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV 43 | 44 | - name: Set NLC zip URL 45 | run: | 46 | S3_NLC_ZIP_URL=${S3_NLC_URL}/hazelcast-enterprise-${HZ_VERSION}-nlc.zip 47 | 48 | echo "S3_NLC_ZIP_URL=${S3_NLC_ZIP_URL}" >> $GITHUB_ENV 49 | 50 | - name: Configure AWS credentials 51 | uses: aws-actions/configure-aws-credentials@v4 52 | with: 53 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 54 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 55 | aws-region: 'us-east-1' 56 | 57 | - name: Get presigned NLC URL from S3 58 | run: | 59 | HAZELCAST_ZIP_URL="$(aws s3 presign ${S3_NLC_ZIP_URL} --expires-in 600)" 60 | echo "HAZELCAST_ZIP_URL=${HAZELCAST_ZIP_URL}" >> $GITHUB_ENV 61 | 62 | - name: Login to Docker Hub 63 | uses: docker/login-action@v3 64 | with: 65 | registry: ${{ secrets.NLC_REPOSITORY }} 66 | username: ${{ secrets.NLC_REPO_USERNAME }} 67 | password: ${{ secrets.NLC_REPO_TOKEN }} 68 | 69 | - name: Set up QEMU 70 | uses: docker/setup-qemu-action@v3.6.0 71 | 72 | - name: Set up Docker Buildx 73 | uses: docker/setup-buildx-action@v3 74 | with: 75 | version: v0.5.1 76 | 77 | - name: Build EE image 78 | run: | 79 | docker buildx build --load \ 80 | --build-arg HZ_VERSION=${HZ_VERSION} \ 81 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 82 | --build-arg HAZELCAST_ZIP_URL=${HAZELCAST_ZIP_URL} \ 83 | --tag hazelcast-nlc:test hazelcast-enterprise 84 | 85 | - name: Run smoke test against EE image 86 | timeout-minutes: 2 87 | run: | 88 | export HZ_INSTANCETRACKING_FILENAME=instance-tracking.txt 89 | .github/scripts/simple-smoke-test.sh hazelcast-nlc:test "${{ env.test_container_name_ee }}" ee ${HZ_VERSION} "${{ matrix.jdk }}" 90 | 91 | - name: Get docker logs 92 | if: ${{ always() }} 93 | run: | 94 | DOCKER_LOG_FILE_EE=docker-${{ env.test_container_name_ee }}-jdk${{ matrix.jdk }}.log 95 | echo "DOCKER_LOG_FILE_EE=${DOCKER_LOG_FILE_EE}" >> $GITHUB_ENV 96 | docker logs "${{ env.test_container_name_ee }}" > "${DOCKER_LOG_FILE_EE}" 97 | 98 | - name: Store docker logs as artifact 99 | if: ${{ always() }} 100 | uses: actions/upload-artifact@v4 101 | with: 102 | name: docker-logs-${{ github.job }}-jdk${{ matrix.jdk }} 103 | path: | 104 | ${{ env.DOCKER_LOG_FILE_EE }} 105 | 106 | - name: Build/Push EE image 107 | run: | 108 | . .github/scripts/get-tags-to-push.sh 109 | . .github/scripts/docker.functions.sh 110 | 111 | DOCKER_DIR=hazelcast-enterprise 112 | IMAGE_NAME=${NLC_IMAGE_NAME} 113 | DEFAULT_JDK="$(get_default_jdk $DOCKER_DIR)" 114 | 115 | TAGS_TO_PUSH=$(augment_with_suffixed_tags "$HZ_VERSION" "" "${{ matrix.jdk }}" "$DEFAULT_JDK") 116 | echo "TAGS_TO_PUSH=$TAGS_TO_PUSH" 117 | TAGS_ARG="" 118 | for tag in ${TAGS_TO_PUSH[@]} 119 | do 120 | TAGS_ARG="${TAGS_ARG} --tag ${IMAGE_NAME}:${tag}" 121 | done 122 | 123 | PLATFORMS="$(get_ubi_supported_platforms "${{ matrix.jdk }}")" 124 | docker buildx build --push \ 125 | --build-arg HZ_VERSION=${HZ_VERSION} \ 126 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 127 | --build-arg HAZELCAST_ZIP_URL=${HAZELCAST_ZIP_URL} \ 128 | ${TAGS_ARG} \ 129 | --platform=${PLATFORMS} $DOCKER_DIR 130 | - name: Check RedHat service status 131 | if: failure() 132 | uses: ./.github/actions/check-redhat-service-status 133 | - name: Slack notification 134 | uses: ./.github/actions/slack-notification 135 | if: failure() && github.triggering_actor == 'devOpsHazelcast' 136 | with: 137 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 138 | -------------------------------------------------------------------------------- /.github/workflows/ee_latest_snapshot_push.yml: -------------------------------------------------------------------------------- 1 | name: Build EE snapshot image 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | HZ_VERSION: 7 | description: 'Version of Hazelcast to build the image for' 8 | required: true 9 | HZ_EE_REVISION: 10 | description: 'Commit id of Hazelcast Enterprise snapshot jar' 11 | required: true 12 | env: 13 | test_container_name_ee: hazelcast-ee-test 14 | 15 | jobs: 16 | jdks: 17 | uses: ./.github/workflows/get-supported-jdks.yaml 18 | 19 | push: 20 | runs-on: ubuntu-latest 21 | needs: jdks 22 | strategy: 23 | matrix: 24 | jdk: ${{ fromJSON(needs.jdks.outputs.jdks) }} 25 | variant: [ 'slim','' ] 26 | include: 27 | - variant: slim 28 | - variant: '' 29 | env: 30 | DOCKER_ORG: hazelcast 31 | HZ_VERSION : ${{ inputs.HZ_VERSION }} 32 | steps: 33 | - name: Compute Suffix 34 | run: | 35 | if [ -n "${{ matrix.variant }}" ]; then 36 | SUFFIX=-${{ matrix.variant }} 37 | else 38 | SUFFIX= 39 | fi 40 | echo "SUFFIX=${SUFFIX}" >> $GITHUB_ENV 41 | 42 | - name: Checkout Code 43 | uses: actions/checkout@v4 44 | 45 | - name: Set up QEMU 46 | uses: docker/setup-qemu-action@v3.6.0 47 | 48 | - name: Set up Docker Buildx 49 | uses: docker/setup-buildx-action@v3 50 | with: 51 | version: v0.5.1 52 | 53 | - name: Configure AWS credentials 54 | uses: aws-actions/configure-aws-credentials@v4 55 | with: 56 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 57 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 58 | aws-region: 'us-east-1' 59 | 60 | - name: Get EE dist ZIP URL 61 | run: | 62 | . .github/scripts/ee-build.functions.sh 63 | echo "HAZELCAST_EE_ZIP_URL=$(get_hz_dist_zip "${{ matrix.variant }}" "${HZ_VERSION}")" >> $GITHUB_ENV 64 | 65 | - name: Build Test EE image 66 | run: | 67 | docker buildx build --load \ 68 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 69 | --build-arg HZ_VERSION=${HZ_VERSION} \ 70 | --build-arg HAZELCAST_ZIP_URL=$HAZELCAST_EE_ZIP_URL \ 71 | --tag hazelcast-ee:test \ 72 | hazelcast-enterprise 73 | 74 | - name: Run smoke test against EE image 75 | timeout-minutes: 2 76 | run: | 77 | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} 78 | .github/scripts/simple-smoke-test.sh hazelcast-ee:test "${{ env.test_container_name_ee }}" ee ${HZ_VERSION} "${{ matrix.jdk }}" 79 | 80 | - name: Get docker logs 81 | if: ${{ always() }} 82 | run: | 83 | DOCKER_LOG_FILE_EE=docker-${{ env.test_container_name_ee }}${{ env.SUFFIX }}-jdk${{ matrix.jdk }}.log 84 | echo "DOCKER_LOG_FILE_EE=${DOCKER_LOG_FILE_EE}" >> $GITHUB_ENV 85 | docker logs "${{ env.test_container_name_ee }}" > "${DOCKER_LOG_FILE_EE}" 86 | 87 | - name: Store docker logs as artifact 88 | if: ${{ always() }} 89 | uses: actions/upload-artifact@v4 90 | with: 91 | name: docker-logs${{ env.SUFFIX }}-${{ github.job }}-jdk${{ matrix.jdk }} 92 | path: | 93 | ${{ env.DOCKER_LOG_FILE_EE }} 94 | 95 | - name: Login to Docker Hub 96 | uses: docker/login-action@v3 97 | with: 98 | username: ${{ secrets.DOCKER_USERNAME }} 99 | password: ${{ secrets.DOCKER_PASSWORD }} 100 | 101 | - name: Build/Push EE image 102 | run: | 103 | . .github/scripts/get-tags-to-push.sh 104 | . .github/scripts/docker.functions.sh 105 | 106 | VERSIONS=("$HZ_VERSION") 107 | if [[ "${{ github.ref }}" == "refs/heads/master" ]]; then 108 | VERSIONS+=(latest-snapshot) 109 | fi 110 | 111 | DOCKER_DIR=hazelcast-enterprise 112 | IMAGE_NAME=${{ env.DOCKER_ORG }}/hazelcast-enterprise 113 | DEFAULT_JDK="$(get_default_jdk $DOCKER_DIR)" 114 | 115 | TAGS_TO_PUSH=$(augment_with_suffixed_tags "${VERSIONS[*]}" "${{ env.SUFFIX }}" "${{ matrix.jdk }}" "$DEFAULT_JDK") 116 | echo "TAGS_TO_PUSH=$TAGS_TO_PUSH" 117 | TAGS_ARG="" 118 | for tag in ${TAGS_TO_PUSH[@]} 119 | do 120 | TAGS_ARG="${TAGS_ARG} --tag ${IMAGE_NAME}:${tag}" 121 | done 122 | 123 | PLATFORMS="$(get_ubi_supported_platforms "${{ matrix.jdk }}")" 124 | docker buildx build --push \ 125 | --build-arg HZ_VERSION=${HZ_VERSION} \ 126 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 127 | --label hazelcast.ee.revision=${{ inputs.HZ_EE_REVISION }} \ 128 | --build-arg HAZELCAST_ZIP_URL=$HAZELCAST_EE_ZIP_URL \ 129 | ${TAGS_ARG} \ 130 | --platform=${PLATFORMS} $DOCKER_DIR 131 | - name: Slack notification 132 | uses: ./.github/actions/slack-notification 133 | if: failure() && github.triggering_actor == 'devOpsHazelcast' 134 | with: 135 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 136 | -------------------------------------------------------------------------------- /.github/workflows/get-supported-jdks.yaml: -------------------------------------------------------------------------------- 1 | name: Get supported JDKs 2 | 3 | on: 4 | workflow_call: 5 | outputs: 6 | jdks: 7 | value: ${{ jobs.get-supported-jdks.outputs.jdks }} 8 | 9 | jobs: 10 | get-supported-jdks: 11 | runs-on: ubuntu-latest 12 | outputs: 13 | jdks: "['17', '21']" 14 | steps: 15 | - run: exit 0 16 | -------------------------------------------------------------------------------- /.github/workflows/oss_latest_snapshot_push.yml: -------------------------------------------------------------------------------- 1 | name: Build OSS snapshot image 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | HZ_VERSION: 7 | description: 'Version of Hazelcast to build the image for' 8 | required: true 9 | HZ_REVISION: 10 | description: 'Commit id of Hazelcast snapshot jar' 11 | required: true 12 | env: 13 | test_container_name_oss: hazelcast-oss-test 14 | 15 | jobs: 16 | jdks: 17 | uses: ./.github/workflows/get-supported-jdks.yaml 18 | 19 | push: 20 | runs-on: ubuntu-latest 21 | needs: jdks 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | jdk: ${{ fromJSON(needs.jdks.outputs.jdks) }} 26 | variant: [ 'slim','' ] 27 | include: 28 | - variant: slim 29 | - variant: '' 30 | env: 31 | DOCKER_REGISTRY: ${{ secrets.HZ_SNAPSHOT_INTERNAL_DOCKER_REGISTRY }} 32 | 33 | # required by OSS get_hz_dist_zip function 34 | HZ_SNAPSHOT_INTERNAL_USERNAME: ${{ secrets.HZ_SNAPSHOT_INTERNAL_USERNAME }} 35 | HZ_SNAPSHOT_INTERNAL_PASSWORD: ${{ secrets.HZ_SNAPSHOT_INTERNAL_PASSWORD }} 36 | 37 | HZ_VERSION: ${{ inputs.HZ_VERSION }} 38 | steps: 39 | - name: Compute Suffix 40 | run: | 41 | if [ -n "${{ matrix.variant }}" ]; then 42 | SUFFIX=-${{ matrix.variant }} 43 | else 44 | SUFFIX= 45 | fi 46 | echo "SUFFIX=${SUFFIX}" >> $GITHUB_ENV 47 | 48 | 49 | - name: Checkout Code 50 | uses: actions/checkout@v4 51 | 52 | - name: Set up QEMU 53 | uses: docker/setup-qemu-action@v3.6.0 54 | 55 | - name: Set up Docker Buildx 56 | uses: docker/setup-buildx-action@v3 57 | with: 58 | version: v0.5.1 59 | 60 | - name: Configure AWS credentials 61 | uses: aws-actions/configure-aws-credentials@v4 62 | with: 63 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 64 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 65 | aws-region: 'us-east-1' 66 | 67 | - name: Get OSS dist ZIP 68 | run: | 69 | . .github/scripts/oss-build.functions.sh 70 | HAZELCAST_OSS_ZIP_URL=$(get_hz_dist_zip "${{ matrix.variant }}" "${HZ_VERSION}") 71 | 72 | curl --fail --silent --show-error --location "$HAZELCAST_OSS_ZIP_URL" --output hazelcast-oss/hazelcast-distribution.zip; 73 | 74 | - name: Build Test OSS image 75 | run: | 76 | docker buildx build --load \ 77 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 78 | --tag hazelcast-oss:test \ 79 | hazelcast-oss 80 | 81 | - name: Run smoke test against OSS image 82 | timeout-minutes: 2 83 | run: | 84 | .github/scripts/simple-smoke-test.sh hazelcast-oss:test "${{ env.test_container_name_oss }}" oss ${HZ_VERSION} "${{ matrix.jdk }}" 85 | 86 | - name: Get docker logs 87 | if: ${{ always() }} 88 | run: | 89 | DOCKER_LOG_FILE_OSS=docker-${{ env.test_container_name_oss }}${{ env.SUFFIX }}-jdk${{ matrix.jdk }}.log 90 | echo "DOCKER_LOG_FILE_OSS=${DOCKER_LOG_FILE_OSS}" >> $GITHUB_ENV 91 | docker logs "${{ env.test_container_name_oss }}" > "${DOCKER_LOG_FILE_OSS}" 92 | 93 | - name: Store docker logs as artifact 94 | if: ${{ always() }} 95 | uses: actions/upload-artifact@v4 96 | with: 97 | name: docker-logs${{ env.SUFFIX }}-${{ github.job }}-jdk${{ matrix.jdk }} 98 | path: | 99 | ${{ env.DOCKER_LOG_FILE_OSS }} 100 | 101 | - name: Login to Docker Registry 102 | uses: docker/login-action@v3 103 | with: 104 | registry: ${{ env.DOCKER_REGISTRY }} 105 | username: ${{ secrets.JFROG_USERNAME }} 106 | password: ${{ secrets.JFROG_PASSWORD }} 107 | 108 | - name: Build/Push OSS image 109 | run: | 110 | set -eEuo pipefail ${RUNNER_DEBUG:+-x} 111 | . .github/scripts/get-tags-to-push.sh 112 | . .github/scripts/docker.functions.sh 113 | 114 | VERSIONS=("$HZ_VERSION") 115 | 116 | DOCKER_DIR=hazelcast-oss 117 | IMAGE_NAME=$DOCKER_REGISTRY/docker/hazelcast/hazelcast 118 | DEFAULT_JDK="$(get_default_jdk $DOCKER_DIR)" 119 | 120 | TAGS_TO_PUSH=$(augment_with_suffixed_tags "${VERSIONS[*]}" "${{ env.SUFFIX }}" "${{ matrix.jdk }}" "$DEFAULT_JDK") 121 | echo "TAGS_TO_PUSH=$TAGS_TO_PUSH" 122 | TAGS_ARG="" 123 | for tag in ${TAGS_TO_PUSH[@]} 124 | do 125 | TAGS_ARG="${TAGS_ARG} --tag ${IMAGE_NAME}:${tag}" 126 | done 127 | 128 | PLATFORMS="$(get_alpine_supported_platforms "${{ matrix.jdk }}")" 129 | docker buildx build --push \ 130 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 131 | --label hazelcast.revision=${{ inputs.HZ_REVISION }} \ 132 | $TAGS_ARG \ 133 | --platform=${PLATFORMS} $DOCKER_DIR 134 | - name: Slack notification 135 | uses: ./.github/actions/slack-notification 136 | if: failure() && github.triggering_actor == 'devOpsHazelcast' 137 | with: 138 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 139 | -------------------------------------------------------------------------------- /.github/workflows/retag.yml: -------------------------------------------------------------------------------- 1 | name: Recreate tags on release branch change 2 | 3 | on: 4 | push: 5 | branches: 6 | - '[0-9]+.[0-9]+.[0-9]+' 7 | workflow_dispatch: 8 | inputs: 9 | BRANCH_NAME: 10 | description: The branch to recreate the tag from 11 | 12 | jobs: 13 | retag: 14 | runs-on: ubuntu-latest 15 | env: 16 | BRANCH_NAME: ${{ inputs.BRANCH_NAME }} 17 | steps: 18 | - name: Set branch name 19 | if: env.BRANCH_NAME == '' 20 | run: | 21 | echo "BRANCH_NAME=${GITHUB_REF_NAME}" >> ${GITHUB_ENV} 22 | 23 | - name: Calculate tag name 24 | run: | 25 | echo "TAG_NAME=v${BRANCH_NAME}" >> ${GITHUB_ENV} 26 | 27 | - name: Check `${{ env.TAG_NAME }}` tag exists 28 | run: | 29 | if ! gh release view --repo ${GITHUB_REPOSITORY} ${TAG_NAME}; then 30 | echo "::notice::\"${TAG_NAME}\" tag not found to replace, skipping" 31 | echo "SKIP=true" >> ${GITHUB_ENV} 32 | fi 33 | env: 34 | GH_TOKEN: ${{ github.token }} 35 | 36 | - uses: actions/checkout@v4 37 | if: ${{ env.SKIP != 'true' }} 38 | with: 39 | ref: ${{ env.BRANCH_NAME }} 40 | fetch-depth: 0 41 | 42 | - name: List tags 43 | if: runner.debug == '1' 44 | run: | 45 | git tag --list 46 | 47 | - name: Recreate `${{ env.TAG_NAME }}` tag 48 | if: ${{ env.SKIP != 'true' }} 49 | run: | 50 | # Delete local tag 51 | git tag -d ${TAG_NAME} 52 | 53 | # Create local tag 54 | git tag ${TAG_NAME} origin/${BRANCH_NAME} 55 | 56 | # Delete remote tag 57 | git push origin :refs/tags/${TAG_NAME} 58 | 59 | # Create remote tag 60 | git push origin ${TAG_NAME} 61 | -------------------------------------------------------------------------------- /.github/workflows/rhel-smoke-test.yml: -------------------------------------------------------------------------------- 1 | name: Test EE RHEL image 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | HZ_VERSION: 7 | description: 'Version of Hazelcast to build the image for, e.g. 5.1.1, 5.0.1' 8 | required: true 9 | RELEASE_VERSION: 10 | description: 'Version of the docker image e.g. 5.1.1, 5.1.1-1, defaults to HZ_VERSION' 11 | required: false 12 | 13 | jobs: 14 | test: 15 | env: 16 | SCAN_REGISTRY: "quay.io" 17 | HZ_VERSION: ${{ inputs.HZ_VERSION }} 18 | RELEASE_VERSION: ${{ inputs.RELEASE_VERSION }} 19 | PROJECT_NAME: test-${{ github.run_id }}-${{ github.run_attempt }} 20 | 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Set HZ version as environment variable 24 | if: env.HZ_VERSION == '' 25 | run: | 26 | echo "HZ_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV 27 | 28 | - name: Set Release version as environment variable 29 | if: env.RELEASE_VERSION == '' 30 | run: | 31 | echo "RELEASE_VERSION=${{ env.HZ_VERSION }}" >> $GITHUB_ENV 32 | 33 | - name: Checkout Code 34 | uses: actions/checkout@v4 35 | 36 | - uses: madhead/semver-utils@latest 37 | id: version 38 | with: 39 | version: ${{ env.HZ_VERSION }} 40 | 41 | - name: Set up QEMU 42 | uses: docker/setup-qemu-action@v3.6.0 43 | 44 | - name: Set up Docker Buildx 45 | uses: docker/setup-buildx-action@v3 46 | with: 47 | version: v0.5.1 48 | 49 | - name: Configure AWS credentials 50 | uses: aws-actions/configure-aws-credentials@v4 51 | with: 52 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 53 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 54 | aws-region: 'us-east-1' 55 | 56 | - name: Get Secrets 57 | uses: aws-actions/aws-secretsmanager-get-secrets@v2 58 | with: 59 | secret-ids: | 60 | OCP_LOGIN_USERNAME,CN/OCP_USERNAME 61 | OCP_LOGIN_PASSWORD,CN/OCP_PASSWORD 62 | OCP_CLUSTER_URL,CN/OCP_CLUSTER_URL 63 | 64 | - name: Set scan registry secrets 65 | run: | 66 | echo "SCAN_REGISTRY_USER=${{ secrets[format('SCAN_REGISTRY_USER_V{0}', steps.version.outputs.major)] }}" >> $GITHUB_ENV 67 | echo "SCAN_REGISTRY_PASSWORD=${{ secrets[format('SCAN_REGISTRY_PASSWORD_V{0}', steps.version.outputs.major)] }}" >> $GITHUB_ENV 68 | 69 | - name: Log in to Red Hat Scan Registry 70 | uses: docker/login-action@v3 71 | with: 72 | registry: ${{ env.SCAN_REGISTRY }} 73 | username: ${{ env.SCAN_REGISTRY_USER }} 74 | password: ${{ env.SCAN_REGISTRY_PASSWORD }} 75 | 76 | - name: Install `oc` OpenShift tool from mirror 77 | uses: redhat-actions/openshift-tools-installer@v1 78 | with: 79 | oc: "latest" 80 | source: mirror 81 | skip_cache: true 82 | 83 | - uses: redhat-actions/oc-login@v1 84 | with: 85 | openshift_server_url: ${{ env.OCP_CLUSTER_URL }} 86 | openshift_username: ${{ env.OCP_LOGIN_USERNAME }} 87 | openshift_password: ${{ env.OCP_LOGIN_PASSWORD }} 88 | insecure_skip_tls_verify: true 89 | 90 | - name: Deploy Hazelcast Cluster from RedHat Registry 91 | run: | 92 | # CREATE PROJECT 93 | oc new-project "${PROJECT_NAME}" 94 | 95 | oc create secret generic hz-license-secret \ 96 | --from-literal=key="${{ secrets.HZ_ENTERPRISE_LICENSE }}" 97 | 98 | helm repo add hazelcast https://hazelcast-charts.s3.amazonaws.com/ 99 | helm repo update 100 | 101 | CHART=hazelcast/hazelcast-enterprise 102 | 103 | HZ_MC_VERSION=$(helm show values "${CHART}" | yq '.mancenter.image.tag') 104 | 105 | helm install "${PROJECT_NAME}" "${CHART}" \ 106 | --set image.repository="registry.connect.redhat.com/hazelcast/hazelcast-enterprise-${{ steps.version.outputs.major }}-rhel8" \ 107 | --set image.tag="${RELEASE_VERSION}" \ 108 | --set image.pullPolicy="Always" \ 109 | --set hazelcast.licenseKeySecretName="hz-license-secret" \ 110 | --set securityContext.enabled=false \ 111 | --set mancenter.enabled=true \ 112 | --set mancenter.image.pullPolicy="Always" \ 113 | --set mancenter.image.repository="registry.connect.redhat.com/hazelcast/management-center-${HZ_MC_VERSION:0:1}-rhel8" 114 | 115 | - name: Validate Cluster Size 116 | run: | 117 | NAME=hazelcast-enterprise 118 | 119 | source .github/scripts/cluster-verification.sh 120 | 121 | CLUSTER_SIZE=$(helm get values "${PROJECT_NAME}" --all | yq '.cluster.memberCount') 122 | 123 | wait_for_last_member_initialization ${CLUSTER_SIZE} 124 | 125 | verify_cluster_size ${CLUSTER_SIZE} 126 | 127 | echo "Waiting for ${PROJECT_NAME}-${NAME}-mancenter-0 pod to be ready" 128 | oc wait --for=condition=Ready --timeout=300s pod "${PROJECT_NAME}-${NAME}-mancenter-0" 129 | 130 | verify_management_center ${CLUSTER_SIZE} 131 | 132 | - name: Get OpenShift logs 133 | if: ${{ always() }} 134 | run: | 135 | kubectl get events -n "${PROJECT_NAME}" > events.log 136 | kubectl describe pods > pods.log 137 | kubectl get pods -n "${PROJECT_NAME}" --output json | jq -r '.items[].metadata.name' | while read pod; do 138 | kubectl logs --all-containers "${pod}" -n "${PROJECT_NAME}" > "${pod}.log" 139 | done 140 | 141 | - name: Store OpenShift logs as artifact 142 | if: ${{ always() }} 143 | uses: actions/upload-artifact@v4 144 | with: 145 | name: openshift-logs-${{ github.job }} 146 | path: '*.log' 147 | 148 | - name: Clean up After Test 149 | if: ${{ always() }} 150 | run: | 151 | helm uninstall "${PROJECT_NAME}" --timeout 30s 152 | oc delete project "${PROJECT_NAME}" 153 | -------------------------------------------------------------------------------- /.github/workflows/scheduled_vulnerability_scan.yml: -------------------------------------------------------------------------------- 1 | name: Scheduled Vulnerability Scans 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 2 * * *' 7 | 8 | jobs: 9 | get-branches-to-scan: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | branches: ${{ steps.branches.outputs.branches }} 13 | steps: 14 | - id: get-maintenance-versions 15 | uses: hazelcast/hazelcast/.github/actions/get-supported-maintenance-versions@master 16 | - id: branches 17 | run: | 18 | # Convert maintenance versions -> Docker branches, and check `master`, too 19 | echo "branches=$(jq --compact-output 'map(. | tostring + ".z") + ["master"]' <<< '${{ steps.get-maintenance-versions.outputs.versions }}')" >> ${GITHUB_OUTPUT} 20 | 21 | trigger-vulnerability-scan: 22 | needs: get-branches-to-scan 23 | name: Scan ${{ matrix.ref }} 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | ref: ${{ fromJSON(needs.get-branches-to-scan.outputs.branches) }} 28 | uses: ./.github/workflows/vulnerability_scan_subworkflow.yml 29 | with: 30 | ref: ${{ matrix.ref }} 31 | secrets: inherit 32 | -------------------------------------------------------------------------------- /.github/workflows/tag_image_push.yml: -------------------------------------------------------------------------------- 1 | name: Build OS and EE image 2 | 3 | on: 4 | push: 5 | branches: 6 | - "!*" 7 | tags: 8 | - "v5.*" 9 | - "v6.*" 10 | - '!*DEVEL*' 11 | workflow_dispatch: 12 | inputs: 13 | HZ_VERSION: 14 | description: 'Version of Hazelcast to build the image for, e.g. 5.1.1, 5.0.1, 4.2.3' 15 | required: true 16 | RELEASE_VERSION: 17 | description: 'Version of the docker image e.g. 5.1.1, 5.1.1-1, defaults to HZ_VERSION' 18 | required: false 19 | RELEASE_TYPE: 20 | description: 'What should be built' 21 | required: true 22 | default: 'EE' 23 | type: choice 24 | options: 25 | - ALL 26 | - OSS 27 | - EE 28 | IS_LTS_OVERRIDE: 29 | description: 'Override is LTS release' 30 | required: false 31 | type: choice 32 | default: '' 33 | options: 34 | - '' 35 | - 'false' 36 | - 'true' 37 | DRY_RUN: 38 | description: 'Skip pushing the images to remote registry' 39 | default: 'false' 40 | type: choice 41 | options: 42 | - 'false' 43 | - 'true' 44 | workflow_call: 45 | inputs: 46 | HZ_VERSION: 47 | type: string 48 | description: 'Version of Hazelcast to build the image for, e.g. 5.1.1, 5.0.1, 4.2.3' 49 | required: true 50 | RELEASE_VERSION: 51 | type: string 52 | description: 'Version of the docker image e.g. 5.1.1, 5.1.1-1, defaults to HZ_VERSION' 53 | required: false 54 | RELEASE_TYPE: 55 | description: 'What should be built' 56 | required: true 57 | default: 'EE' 58 | type: string 59 | IS_LTS_OVERRIDE: 60 | description: 'Override is LTS release' 61 | required: false 62 | type: string 63 | default: '' 64 | DRY_RUN: 65 | description: 'Skip pushing the images to remote registry' 66 | default: 'false' 67 | type: string 68 | 69 | env: 70 | test_container_name_oss: hazelcast-oss-test 71 | test_container_name_ee: hazelcast-ee-test 72 | 73 | jobs: 74 | jdks: 75 | uses: ./.github/workflows/get-supported-jdks.yaml 76 | 77 | prepare: 78 | runs-on: ubuntu-latest 79 | env: 80 | RELEASE_TYPE: ${{ inputs.RELEASE_TYPE || 'EE' }} 81 | outputs: 82 | should_build_oss: ${{ steps.which_editions.outputs.should_build_oss }} 83 | should_build_ee: ${{ steps.which_editions.outputs.should_build_ee }} 84 | steps: 85 | - name: Checkout Code 86 | uses: actions/checkout@v4 87 | 88 | - name: Read release type from the file 89 | if: github.event_name == 'push' 90 | run: | 91 | RELEASE_TYPE_FILE=.github/release_type 92 | if [ -f $RELEASE_TYPE_FILE ]; then 93 | echo "RELEASE_TYPE=$(cat $RELEASE_TYPE_FILE)" >> $GITHUB_ENV 94 | else 95 | echo "File '$RELEASE_TYPE_FILE' does not exist." 96 | exit 1 97 | fi 98 | 99 | - name: Check which editions should be built 100 | id: which_editions 101 | run: | 102 | . .github/scripts/build.functions.sh 103 | 104 | release_type=${{ env.RELEASE_TYPE }} 105 | triggered_by=${{ github.event_name }} 106 | should_build_oss=$(should_build_oss "$release_type") 107 | should_build_ee=$(should_build_ee "$release_type") 108 | echo "should_build_ee=${should_build_ee}" >> $GITHUB_OUTPUT 109 | echo "should_build_oss=${should_build_oss}" >> $GITHUB_OUTPUT 110 | 111 | push: 112 | runs-on: ubuntu-latest 113 | needs: [ jdks, prepare ] 114 | strategy: 115 | matrix: 116 | jdk: ${{ fromJSON(needs.jdks.outputs.jdks) }} 117 | variant: [ 'slim','' ] 118 | include: 119 | - variant: slim 120 | - variant: '' 121 | env: 122 | DOCKER_ORG: hazelcast 123 | HZ_VERSION: ${{ inputs.HZ_VERSION }} 124 | RELEASE_VERSION: ${{ inputs.RELEASE_VERSION }} 125 | steps: 126 | - name: Set HZ version as environment variable 127 | if: env.HZ_VERSION == '' 128 | run: | 129 | echo "HZ_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV 130 | 131 | - name: Set Release version as environment variable 132 | if: env.RELEASE_VERSION == '' 133 | run: | 134 | echo "RELEASE_VERSION=${{ env.HZ_VERSION }}" >> $GITHUB_ENV 135 | 136 | - name: Set environment variables 137 | run: | 138 | if [ -n "${{ matrix.variant }}" ]; then 139 | SUFFIX=-${{ matrix.variant }} 140 | else 141 | SUFFIX= 142 | fi 143 | echo "SUFFIX=${SUFFIX}" >> $GITHUB_ENV 144 | 145 | echo "DOCKER_LOG_FILE_OSS=docker-${{ env.test_container_name_oss }}${SUFFIX}-jdk${{ matrix.jdk }}.log" >> $GITHUB_ENV 146 | echo "DOCKER_LOG_FILE_EE=docker-${{ env.test_container_name_ee }}${SUFFIX}-jdk${{ matrix.jdk }}.log" >> $GITHUB_ENV 147 | 148 | - name: Checkout Code 149 | uses: actions/checkout@v4 150 | with: 151 | fetch-depth: 0 152 | 153 | - name: Set up QEMU 154 | uses: docker/setup-qemu-action@v3.6.0 155 | 156 | - name: Set up Docker Buildx 157 | uses: docker/setup-buildx-action@v3 158 | with: 159 | version: v0.5.1 160 | 161 | - name: Configure AWS credentials 162 | uses: aws-actions/configure-aws-credentials@v4 163 | with: 164 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 165 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 166 | aws-region: 'us-east-1' 167 | 168 | - name: Login to Docker Hub 169 | if: inputs.DRY_RUN != 'true' 170 | uses: docker/login-action@v3 171 | with: 172 | username: ${{ secrets.DOCKER_USERNAME }} 173 | password: ${{ secrets.DOCKER_PASSWORD }} 174 | 175 | - name: Get OSS dist ZIP URL 176 | if: needs.prepare.outputs.should_build_oss == 'yes' 177 | run: | 178 | . .github/scripts/oss-build.functions.sh 179 | echo "HAZELCAST_OSS_ZIP_URL=$(get_hz_dist_zip "${{ matrix.variant }}" "${{ env.HZ_VERSION }}")" >> $GITHUB_ENV 180 | 181 | - name: Build Test OSS image 182 | if: needs.prepare.outputs.should_build_oss == 'yes' 183 | run: | 184 | docker buildx build --load \ 185 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 186 | --build-arg HAZELCAST_ZIP_URL=$HAZELCAST_OSS_ZIP_URL \ 187 | --tag hazelcast-oss:test \ 188 | hazelcast-oss 189 | 190 | - name: Run smoke test against OSS image 191 | if: needs.prepare.outputs.should_build_oss == 'yes' 192 | timeout-minutes: 2 193 | run: | 194 | .github/scripts/simple-smoke-test.sh hazelcast-oss:test "${{ env.test_container_name_oss }}" oss "${{ env.HZ_VERSION }}" "${{ matrix.jdk }}" 195 | 196 | - name: Get EE dist ZIP URL 197 | if: needs.prepare.outputs.should_build_ee == 'yes' 198 | run: | 199 | . .github/scripts/ee-build.functions.sh 200 | echo "HAZELCAST_EE_ZIP_URL=$(get_hz_dist_zip "${{ matrix.variant }}" "${{ env.HZ_VERSION }}")" >> $GITHUB_ENV 201 | 202 | - name: Build Test EE image 203 | if: needs.prepare.outputs.should_build_ee == 'yes' 204 | run: | 205 | . .github/scripts/ee-build.functions.sh 206 | docker buildx build --load \ 207 | --build-arg HZ_VERSION=${{ env.HZ_VERSION }} \ 208 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 209 | --build-arg HAZELCAST_ZIP_URL=$HAZELCAST_EE_ZIP_URL \ 210 | --tag hazelcast-ee:test \ 211 | hazelcast-enterprise 212 | 213 | - name: Run smoke test against EE image 214 | if: needs.prepare.outputs.should_build_ee == 'yes' 215 | timeout-minutes: 2 216 | run: | 217 | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} 218 | .github/scripts/simple-smoke-test.sh hazelcast-ee:test "${{ env.test_container_name_ee }}" ee "${{ env.HZ_VERSION }}" "${{ matrix.jdk }}" 219 | 220 | - name: Get docker logs 221 | if: ${{ always() }} 222 | run: | 223 | docker logs "${{ env.test_container_name_oss }}" > "${{ env.DOCKER_LOG_FILE_OSS }}" || true 224 | docker logs "${{ env.test_container_name_ee }}" > "${{ env.DOCKER_LOG_FILE_EE }}" || true 225 | 226 | - name: Store docker logs as artifact 227 | if: ${{ always() && ( needs.prepare.outputs.should_build_ee == 'yes' || needs.prepare.outputs.should_build_oss == 'yes') }} 228 | uses: actions/upload-artifact@v4 229 | with: 230 | name: docker-logs${{ env.SUFFIX }}-${{ github.job }}-jdk${{ matrix.jdk }} 231 | path: docker-*.log 232 | 233 | - name: Build and Push OSS image 234 | if: needs.prepare.outputs.should_build_oss == 'yes' 235 | run: | 236 | . .github/scripts/get-tags-to-push.sh 237 | . .github/scripts/docker.functions.sh 238 | 239 | DOCKER_DIR=hazelcast-oss 240 | IMAGE_NAME=${{ env.DOCKER_ORG }}/hazelcast 241 | DEFAULT_JDK="$(get_default_jdk $DOCKER_DIR)" 242 | 243 | # OSS has no LTS releases 244 | IS_LATEST_LTS=false 245 | TAGS_TO_PUSH=$(get_tags_to_push "${{ env.RELEASE_VERSION }}" "${{ env.SUFFIX }}" "${{ matrix.jdk }}" "$DEFAULT_JDK" "$IS_LATEST_LTS") 246 | echo "TAGS_TO_PUSH=$TAGS_TO_PUSH" 247 | TAGS_ARG="" 248 | for tag in ${TAGS_TO_PUSH[@]} 249 | do 250 | TAGS_ARG="${TAGS_ARG} --tag ${IMAGE_NAME}:${tag}" 251 | done 252 | 253 | output= 254 | 255 | PLATFORMS="$(get_alpine_supported_platforms "${{ matrix.jdk }}")" 256 | 257 | if [ "${{ inputs.DRY_RUN }}" == "true" ] ; then 258 | echo "DRY RUN: Skipping push for platforms ${PLATFORMS} and tags: ${TAGS_TO_PUSH}" 259 | else 260 | output=--push 261 | fi 262 | 263 | docker buildx build ${output} \ 264 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 265 | --build-arg HAZELCAST_ZIP_URL=${HAZELCAST_OSS_ZIP_URL} \ 266 | ${TAGS_ARG} \ 267 | --platform=${PLATFORMS} "${DOCKER_DIR}" 268 | 269 | - name: Check if latest EE LTS release 270 | id: is_latest_lts 271 | uses: ./.github/actions/check-if-latest-lts-release 272 | with: 273 | release_version: ${{ env.RELEASE_VERSION }} 274 | is_lts_override: ${{ inputs.IS_LTS_OVERRIDE }} 275 | 276 | - name: Build/Push EE image 277 | if: needs.prepare.outputs.should_build_ee == 'yes' 278 | run: | 279 | . .github/scripts/get-tags-to-push.sh 280 | . .github/scripts/docker.functions.sh 281 | . .github/scripts/ee-build.functions.sh 282 | 283 | DOCKER_DIR=hazelcast-enterprise 284 | IMAGE_NAME=${{ env.DOCKER_ORG }}/hazelcast-enterprise 285 | DEFAULT_JDK="$(get_default_jdk $DOCKER_DIR)" 286 | 287 | IS_LATEST_LTS="${{ steps.is_latest_lts.outputs.is_latest_lts }}" 288 | TAGS_TO_PUSH=$(get_tags_to_push "${{ env.RELEASE_VERSION }}" "${{ env.SUFFIX }}" "${{ matrix.jdk }}" "$DEFAULT_JDK" "$IS_LATEST_LTS") 289 | echo "TAGS_TO_PUSH=$TAGS_TO_PUSH" 290 | TAGS_ARG="" 291 | for tag in ${TAGS_TO_PUSH[@]} 292 | do 293 | TAGS_ARG="${TAGS_ARG} --tag ${IMAGE_NAME}:${tag}" 294 | done 295 | 296 | output= 297 | 298 | PLATFORMS="$(get_ubi_supported_platforms "${{ matrix.jdk }}")" 299 | 300 | if [ "${{ inputs.DRY_RUN }}" == "true" ] ; then 301 | echo "DRY RUN: Skipping push for platforms ${PLATFORMS} and tags: ${TAGS_TO_PUSH}" 302 | else 303 | output=--push 304 | fi 305 | 306 | docker buildx build ${output} \ 307 | --build-arg HZ_VERSION=${{ env.HZ_VERSION }} \ 308 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 309 | --build-arg HAZELCAST_ZIP_URL=${HAZELCAST_EE_ZIP_URL} \ 310 | ${TAGS_ARG} \ 311 | --platform=${PLATFORMS} "${DOCKER_DIR}" 312 | 313 | - name: Create release 314 | if: github.event_name == 'push' 315 | uses: ncipollo/release-action@v1 316 | with: 317 | token: ${{ secrets.GITHUB_TOKEN }} 318 | allowUpdates: true 319 | 320 | - name: Slack notification 321 | uses: ./.github/actions/slack-notification 322 | if: failure() && github.triggering_actor == 'devOpsHazelcast' 323 | with: 324 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 325 | 326 | readme: 327 | needs: [ prepare, push ] 328 | if: inputs.DRY_RUN != 'true' && (needs.prepare.outputs.should_build_ee == 'yes' || needs.prepare.outputs.should_build_oss == 'yes') 329 | uses: ./.github/workflows/update_readme.yml 330 | secrets: inherit 331 | -------------------------------------------------------------------------------- /.github/workflows/tag_image_push_rhel.yml: -------------------------------------------------------------------------------- 1 | name: Build EE RHEL image 2 | 3 | on: 4 | push: 5 | branches: 6 | - "!*" 7 | tags: 8 | - "v5.*" 9 | - "v6.*" 10 | - '!*DEVEL*' 11 | workflow_dispatch: 12 | inputs: 13 | HZ_VERSION: 14 | description: 'Version of Hazelcast to build the image for, e.g. 5.1.1, 5.0.1' 15 | required: true 16 | RELEASE_VERSION: 17 | description: 'Version of the docker image e.g. 5.1.1, 5.1.1-1, defaults to HZ_VERSION' 18 | required: false 19 | IS_LTS_OVERRIDE: 20 | description: 'Override is LTS release' 21 | required: false 22 | type: choice 23 | default: '' 24 | options: 25 | - '' 26 | - 'false' 27 | - 'true' 28 | DRY_RUN: 29 | description: 'Skip pushing the images to remote registry' 30 | default: 'false' 31 | type: choice 32 | options: 33 | - 'false' 34 | - 'true' 35 | workflow_call: 36 | inputs: 37 | HZ_VERSION: 38 | type: string 39 | description: 'Version of Hazelcast to build the image for, e.g. 5.1.1, 5.0.1' 40 | required: true 41 | RELEASE_VERSION: 42 | type: string 43 | description: 'Version of the docker image e.g. 5.1.1, 5.1.1-1, defaults to HZ_VERSION' 44 | required: false 45 | IS_LTS_OVERRIDE: 46 | description: 'Override is LTS release' 47 | required: false 48 | type: string 49 | default: '' 50 | DRY_RUN: 51 | description: 'Skip pushing the images to remote registry' 52 | default: 'false' 53 | type: string 54 | jobs: 55 | jdks: 56 | uses: ./.github/workflows/get-supported-jdks.yaml 57 | 58 | build: 59 | env: 60 | SCAN_REGISTRY: "quay.io" 61 | TIMEOUT_IN_MINS: 240 62 | RHEL_API_KEY: ${{ secrets.RHEL_API_KEY }} 63 | HZ_VERSION: ${{ inputs.HZ_VERSION }} 64 | RELEASE_VERSION: ${{ inputs.RELEASE_VERSION }} 65 | 66 | runs-on: ubuntu-latest 67 | needs: jdks 68 | strategy: 69 | fail-fast: false 70 | matrix: 71 | jdk: ${{ fromJSON(needs.jdks.outputs.jdks) }} 72 | steps: 73 | - name: Set HZ version as environment variable 74 | if: env.HZ_VERSION == '' 75 | run: | 76 | echo "HZ_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV 77 | 78 | - name: Set Release version as environment variable 79 | if: env.RELEASE_VERSION == '' 80 | run: | 81 | echo "RELEASE_VERSION=${{ env.HZ_VERSION }}" >> $GITHUB_ENV 82 | 83 | - name: Checkout Code 84 | uses: actions/checkout@v4 85 | with: 86 | fetch-depth: 0 87 | 88 | - name: Set up QEMU 89 | uses: docker/setup-qemu-action@v3.6.0 90 | 91 | - name: Set up Docker Buildx 92 | uses: docker/setup-buildx-action@v3 93 | with: 94 | version: v0.5.1 95 | 96 | - uses: madhead/semver-utils@latest 97 | id: version 98 | with: 99 | version: ${{ env.HZ_VERSION }} 100 | 101 | - name: Configure AWS credentials 102 | uses: aws-actions/configure-aws-credentials@v4 103 | with: 104 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 105 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 106 | aws-region: 'us-east-1' 107 | 108 | - name: Get Secrets 109 | uses: aws-actions/aws-secretsmanager-get-secrets@v2 110 | with: 111 | secret-ids: | 112 | OCP_LOGIN_USERNAME,CN/OCP_USERNAME 113 | OCP_LOGIN_PASSWORD,CN/OCP_PASSWORD 114 | OCP_CLUSTER_URL,CN/OCP_CLUSTER_URL 115 | 116 | - name: Set scan registry secrets 117 | run: | 118 | echo "SCAN_REGISTRY_USER=${{ secrets[format('SCAN_REGISTRY_USER_V{0}', steps.version.outputs.major)] }}" >> $GITHUB_ENV 119 | echo "SCAN_REGISTRY_PASSWORD=${{ secrets[format('SCAN_REGISTRY_PASSWORD_V{0}', steps.version.outputs.major)] }}" >> $GITHUB_ENV 120 | echo "RHEL_PROJECT_ID=${{ secrets[format('RHEL_PROJECT_ID_V{0}', steps.version.outputs.major)] }}" >> $GITHUB_ENV 121 | 122 | - name: Set RHEL image as environment variable 123 | run: | 124 | SCAN_REPOSITORY=${SCAN_REGISTRY}/redhat-isv-containers/${RHEL_PROJECT_ID} 125 | echo "SCAN_REPOSITORY=${SCAN_REPOSITORY}" >> $GITHUB_ENV 126 | echo "RHEL_IMAGE=${SCAN_REPOSITORY}:${RELEASE_VERSION}-jdk${{ matrix.jdk }}" >> $GITHUB_ENV 127 | 128 | - name: Log in to Red Hat Scan Registry 129 | uses: docker/login-action@v3 130 | with: 131 | registry: ${{ env.SCAN_REGISTRY }} 132 | username: ${{ env.SCAN_REGISTRY_USER }} 133 | password: ${{ env.SCAN_REGISTRY_PASSWORD }} 134 | 135 | - name: Check if latest EE LTS release 136 | id: is_latest_lts 137 | uses: ./.github/actions/check-if-latest-lts-release 138 | with: 139 | release_version: ${{ env.RELEASE_VERSION }} 140 | is_lts_override: ${{ inputs.IS_LTS_OVERRIDE }} 141 | 142 | - name: Build the Hazelcast Enterprise image 143 | run: | 144 | . .github/scripts/get-tags-to-push.sh 145 | . .github/scripts/docker.functions.sh 146 | . .github/scripts/ee-build.functions.sh 147 | 148 | DOCKER_DIR=hazelcast-enterprise 149 | IMAGE_NAME=${SCAN_REPOSITORY} 150 | DEFAULT_JDK="$(get_default_jdk $DOCKER_DIR)" 151 | 152 | IS_LATEST_LTS="${{ steps.is_latest_lts.outputs.is_latest_lts }}" 153 | TAGS_TO_PUSH=$(get_tags_to_push "${{ env.RELEASE_VERSION }}" "" "${{ matrix.jdk }}" "$DEFAULT_JDK" "$IS_LATEST_LTS") 154 | echo "TAGS_TO_PUSH=$TAGS_TO_PUSH" 155 | TAGS_ARG="" 156 | for tag in ${TAGS_TO_PUSH[@]} 157 | do 158 | TAGS_ARG="${TAGS_ARG} --tag ${IMAGE_NAME}:${tag}" 159 | done 160 | 161 | output= 162 | 163 | PLATFORMS="linux/amd64" 164 | 165 | if [ "${{ inputs.DRY_RUN }}" == "true" ] ; then 166 | echo "DRY RUN: Skipping push for platforms ${PLATFORMS} and tags: ${TAGS_TO_PUSH}" 167 | else 168 | output=--push 169 | fi 170 | 171 | docker buildx build ${output} \ 172 | --build-arg HZ_VERSION=${{ env.HZ_VERSION }} \ 173 | --build-arg JDK_VERSION=${{ matrix.jdk }} \ 174 | --build-arg HAZELCAST_ZIP_URL=$(get_hz_dist_zip "" "${{ env.HZ_VERSION }}") \ 175 | ${TAGS_ARG} \ 176 | --platform=${PLATFORMS} "${DOCKER_DIR}" 177 | 178 | - name: Install `preflight` OpenShift tool from GitHub 179 | uses: redhat-actions/openshift-tools-installer@v1 180 | with: 181 | preflight: "latest" 182 | source: github 183 | skip_cache: true 184 | 185 | - name: Run preflight scan 186 | if: inputs.DRY_RUN != 'true' 187 | run: | 188 | source .github/scripts/logging.functions.sh 189 | 190 | PREFLIGHT_OUTPUT=$(preflight check container "${RHEL_IMAGE}" \ 191 | --submit --pyxis-api-token=${RHEL_API_KEY} \ 192 | --certification-component-id=${RHEL_PROJECT_ID} \ 193 | --docker-config ~/.docker/config.json \ 194 | 2>&1) 195 | 196 | echodebug "${PREFLIGHT_OUTPUT}" 197 | 198 | IMAGE_ID=$(grep --perl-regexp --only-matching "image id is: \K[a-f0-9]+" <<< "${PREFLIGHT_OUTPUT}" || true) 199 | 200 | if [[ -n "${IMAGE_ID}" ]]; then 201 | echo "IMAGE_ID=${IMAGE_ID}" >> $GITHUB_ENV 202 | else 203 | echoerr "Unable to extract image ID from preflight output:" 204 | echoerr "${PREFLIGHT_OUTPUT}" 205 | exit 1 206 | fi 207 | 208 | - name: Wait for Scan to Complete 209 | if: inputs.DRY_RUN != 'true' 210 | run: | 211 | source .github/scripts/publish-rhel.sh 212 | 213 | wait_for_container_scan "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}" "${TIMEOUT_IN_MINS}" 214 | 215 | - name: Publish the Hazelcast Enterprise image 216 | if: inputs.DRY_RUN != 'true' 217 | run: | 218 | source .github/scripts/publish-rhel.sh 219 | 220 | publish_the_image "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}" 221 | wait_for_container_publish "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}" "${TIMEOUT_IN_MINS}" 222 | sync_tags "${RHEL_PROJECT_ID}" "${IMAGE_ID}" "${RHEL_API_KEY}" 223 | 224 | - name: Check RedHat service status 225 | if: failure() 226 | uses: ./.github/actions/check-redhat-service-status 227 | 228 | - name: Slack notification 229 | uses: ./.github/actions/slack-notification 230 | if: failure() && github.triggering_actor == 'devOpsHazelcast' 231 | with: 232 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 233 | -------------------------------------------------------------------------------- /.github/workflows/test_published_images.yml: -------------------------------------------------------------------------------- 1 | name: Test published images 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | IMAGE_VERSION: 7 | required: true 8 | description: The version/label of the image e.g. `5.4.1`, `latest` etc 9 | EXPECTED_HZ_VERSION: 10 | description: The expected Hazelcast version (fully-qualified), e.g. `5.4.1` 11 | required: true 12 | DISTRIBUTION_TYPE: 13 | required: true 14 | description: The distribution(s) to test 15 | type: choice 16 | options: 17 | - oss 18 | - ee 19 | - all 20 | EXPECTED_DEFAULT_JAVA_VERSION: 21 | required: true 22 | description: The expected Java major version (e.g. `21`, `8`) used by default in the image 23 | OTHER_JDKS: 24 | required: true 25 | description: The other Java variant images to test (e.g. `5-jdk21`) - supplied as a comma-separated list of major Java versions (e.g. `8, 11, 17`) 26 | 27 | env: 28 | CONTAINER_NAME: my-container 29 | 30 | jobs: 31 | set-matrix: 32 | runs-on: ubuntu-latest 33 | outputs: 34 | distribution-type-matrix: ${{ steps.set-matrix.outputs.distribution-type-matrix }} 35 | jdk-image-variants-matrix: ${{ steps.set-matrix.outputs.jdk-image-variants-matrix }} 36 | steps: 37 | - name: Checkout Code 38 | uses: actions/checkout@v4 39 | - name: Parse input into matrix 40 | id: set-matrix 41 | run: | 42 | # shellcheck source=../.github/scripts/logging.functions.sh 43 | . .github/scripts/logging.functions.sh 44 | 45 | case "${{ inputs.DISTRIBUTION_TYPE }}" in 46 | "oss") 47 | matrix='["oss"]' 48 | ;; 49 | "ee") 50 | matrix='["ee"]' 51 | ;; 52 | "all") 53 | matrix='["oss","ee"]' 54 | ;; 55 | *) 56 | echoerr "Unrecognized distribution type ${{ inputs.DISTRIBUTION_TYPE }}" 57 | exit 1 58 | ;; 59 | esac 60 | echo "distribution-type-matrix=${matrix}" >> $GITHUB_OUTPUT 61 | 62 | # https://unix.stackexchange.com/a/719752 + trim 63 | # Add an "empty" option for base image 64 | matrix=$(echo '"${{ inputs.OTHER_JDKS }}"' | jq --compact-output 'split(",") + [""] | map(gsub("^\\s+|\\s+$"; ""))' ) 65 | echo "jdk-image-variants-matrix=${matrix}" >> $GITHUB_OUTPUT 66 | 67 | test: 68 | runs-on: ubuntu-latest 69 | needs: set-matrix 70 | strategy: 71 | fail-fast: false 72 | matrix: 73 | variant: 74 | - '' 75 | - 'slim' 76 | distribution-type: ${{ fromJson(needs.set-matrix.outputs.distribution-type-matrix) }} 77 | jdk-image-variant: ${{ fromJson(needs.set-matrix.outputs.jdk-image-variants-matrix) }} 78 | 79 | steps: 80 | - name: Checkout Code 81 | uses: actions/checkout@v4 82 | 83 | - uses: madhead/semver-utils@latest 84 | id: image-version 85 | with: 86 | version: ${{ inputs.IMAGE_VERSION }} 87 | 88 | - uses: madhead/semver-utils@latest 89 | id: expected-hz-version 90 | with: 91 | version: ${{ inputs.EXPECTED_HZ_VERSION }} 92 | 93 | - name: Configure AWS credentials 94 | uses: aws-actions/configure-aws-credentials@v4 95 | with: 96 | aws-access-key-id: ${{ secrets.AWS_DEV_INFRA_ACCESS_KEY_ID }} 97 | aws-secret-access-key: ${{ secrets.AWS_DEV_INFRA_SECRET_ACCESS_KEY }} 98 | aws-region: 'us-east-1' 99 | 100 | - name: Get Secrets 101 | uses: aws-actions/aws-secretsmanager-get-secrets@v2 102 | with: 103 | secret-ids: | 104 | REDHAT_CATALOG_REGISTRY_CONNECT_ROBOT,REDHAT/REDHAT_CATALOG_REGISTRY_CONNECT_ROBOT 105 | parse-json-secrets: true 106 | 107 | - name: Login to Docker Hub 108 | uses: docker/login-action@v3 109 | with: 110 | username: ${{ secrets.DOCKER_USERNAME }} 111 | password: ${{ secrets.DOCKER_PASSWORD }} 112 | 113 | - name: Login to NLC Repository 114 | if: matrix.distribution-type == 'ee' 115 | uses: docker/login-action@v3 116 | with: 117 | registry: ${{ secrets.NLC_REPOSITORY }} 118 | username: ${{ secrets.NLC_REPO_USERNAME }} 119 | password: ${{ secrets.NLC_REPO_TOKEN }} 120 | 121 | - name: Login to Red Hat Catalog 122 | if: matrix.distribution-type == 'ee' 123 | uses: docker/login-action@v3 124 | with: 125 | registry: registry.connect.redhat.com 126 | username: ${{ env.REDHAT_CATALOG_REGISTRY_CONNECT_ROBOT_USERNAME }} 127 | password: ${{ env.REDHAT_CATALOG_REGISTRY_CONNECT_ROBOT_PASSWORD }} 128 | 129 | - name: Run smoke test against image 130 | timeout-minutes: 10 131 | run: | 132 | set -o errexit -o nounset -o pipefail ${RUNNER_DEBUG:+-x} 133 | 134 | # shellcheck source=../.github/scripts/logging.functions.sh 135 | . .github/scripts/logging.functions.sh 136 | 137 | function simple-smoke-test() { 138 | local organization=$1 139 | local image_name=$2 140 | 141 | local expected_jdk_version 142 | if [ -n "${{ matrix.jdk-image-variant }}" ]; then 143 | expected_jdk_version=${{ matrix.jdk-image-variant }} 144 | else 145 | expected_jdk_version=${{ inputs.EXPECTED_DEFAULT_JAVA_VERSION }} 146 | fi 147 | 148 | # Compute tag by concatenating tag_elements 149 | .github/scripts/simple-smoke-test.sh "${organization}/${image_name}":$(IFS=- ; echo "${tag_elements[*]}") "${CONTAINER_NAME}" "${{ matrix.distribution-type }}" "${{ inputs.EXPECTED_HZ_VERSION }}" "${expected_jdk_version}" 150 | } 151 | 152 | case "${{ matrix.distribution-type }}" in 153 | "oss") 154 | image_name="hazelcast" 155 | ;; 156 | "ee") 157 | image_name="hazelcast-enterprise" 158 | ;; 159 | *) 160 | # Impossible as validated earlier 161 | echoerr "Unrecognized distribution type ${{ matrix.distribution-type }}" 162 | exit 1 163 | ;; 164 | esac 165 | 166 | if [[ "${{ matrix.distribution-type }}" == "ee" ]]; then 167 | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} 168 | export HZ_INSTANCETRACKING_FILENAME=instance-tracking.txt 169 | fi 170 | 171 | # To allow computing the required tag, store the elements in an array 172 | tag_elements=("${{ inputs.IMAGE_VERSION }}") 173 | 174 | if [[ -n "${{ matrix.variant }}" ]]; then 175 | tag_elements+=("${{ matrix.variant }}") 176 | fi 177 | 178 | if [[ -n "${{ matrix.jdk-image-variant }}" ]]; then 179 | tag_elements+=("jdk${{ matrix.jdk-image-variant }}") 180 | fi 181 | 182 | echo "Testing Docker registry" 183 | organization=hazelcast 184 | simple-smoke-test "${organization}" "${image_name}" 185 | 186 | # Check additional EE repos 187 | # Only populated for default variant, not "slim" 188 | if [[ "${{ matrix.distribution-type }}" == "ee" && -z "${{ matrix.variant }}" ]]; then 189 | # NLC repo only populated for absolute versions - not "latest", "latest-lts" etc tags 190 | # Identify absolute version based on earlier parsing of version number 191 | if [[ -n "${{ steps.image-version.outputs.major }}" ]]; then 192 | echo "Testing NLC" 193 | simple-smoke-test "${{ secrets.NLC_REPOSITORY }}/hazelcast_cloud" "hazelcast-nlc" 194 | fi 195 | 196 | echo "Testing Red Hat Catalog" 197 | simple-smoke-test "registry.connect.redhat.com/hazelcast" "${image_name}-${{ steps.expected-hz-version.outputs.major }}-rhel8" 198 | fi 199 | 200 | - name: Get docker logs 201 | if: always() 202 | run: | 203 | docker logs "${CONTAINER_NAME}" 204 | -------------------------------------------------------------------------------- /.github/workflows/update_readme.yml: -------------------------------------------------------------------------------- 1 | name: Update `README` on Docker Hub 2 | 3 | on: 4 | workflow_dispatch: 5 | workflow_call: 6 | 7 | jobs: 8 | update-readme: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | repository: 13 | - hazelcast/hazelcast 14 | - hazelcast/hazelcast-enterprise 15 | include: 16 | - repository: hazelcast/hazelcast 17 | short-description: Hazelcast Docker Image 18 | - repository: hazelcast/hazelcast-enterprise 19 | short-description: Hazelcast Enterprise Docker Image 20 | 21 | steps: 22 | - name: Checkout Code 23 | uses: actions/checkout@v4 24 | with: 25 | # Regardless of how triggered, only use the latest `README` 26 | ref: master 27 | 28 | - name: Generate Docker Hub Description 29 | run: | 30 | .github/scripts/generate-docker-hub-description.sh 31 | 32 | - name: Update Docker Hub Description 33 | uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4.0.2 34 | with: 35 | username: ${{ secrets.DOCKER_USERNAME }} 36 | password: ${{ secrets.DOCKER_PASSWORD }} 37 | repository: ${{ matrix.repository }} 38 | short-description: ${{ matrix.short-description }} 39 | readme-filepath: ./README-docker.md 40 | 41 | - name: Slack notification 42 | uses: ./.github/actions/slack-notification 43 | if: failure() && github.event_name != 'workflow_dispatch' 44 | with: 45 | slack-webhook-url: ${{ secrets.SLACK_WEBHOOK }} 46 | -------------------------------------------------------------------------------- /.github/workflows/vulnerability_scan.yml: -------------------------------------------------------------------------------- 1 | name: Vulnerability Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ opened, synchronize, edited ] 9 | 10 | jobs: 11 | trigger-vulnerability-scan-master: 12 | uses: ./.github/workflows/vulnerability_scan_subworkflow.yml 13 | with: 14 | ref: ${{ github.ref }} 15 | secrets: inherit 16 | -------------------------------------------------------------------------------- /.github/workflows/vulnerability_scan_subworkflow.yml: -------------------------------------------------------------------------------- 1 | name: Vulnerability Scan 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | ref: 7 | required: true 8 | type: string 9 | secrets: 10 | SNYK_TOKEN: 11 | required: true 12 | workflow_dispatch: 13 | inputs: 14 | ref: 15 | required: true 16 | type: string 17 | 18 | jobs: 19 | scan: 20 | runs-on: ubuntu-latest 21 | strategy: 22 | matrix: 23 | image: 24 | - label: oss 25 | distribution_zip_name: hazelcast-distribution.zip 26 | - label: enterprise 27 | distribution_zip_name: hazelcast-enterprise-distribution.zip 28 | env: 29 | DIRECTORY: hazelcast-${{ matrix.image.label }} 30 | IMAGE_TAG: hazelcast/${{ matrix.image.label }}:${{ github.sha }} 31 | steps: 32 | - name: Checkout Code at ${{ inputs.ref }} branch 33 | uses: actions/checkout@v4 34 | with: 35 | ref: ${{ inputs.ref }} 36 | 37 | - name: Generate ${{ matrix.image.label }} dist ZIP 38 | run: | 39 | # Make a dummy empty ZIP file to avoid scanning Java dependencies, as managed downstream 40 | # DI-50 - Remove java artifacts scanning from hazelcast-docker 41 | working_directory=hazelcast-distribution 42 | mkdir -p "${working_directory}/lib" 43 | mkdir -p "${working_directory}/bin" 44 | touch "${working_directory}/bin/empty" 45 | 46 | zip -r "${{ env.DIRECTORY }}/${{ matrix.image.distribution_zip_name }}" "${working_directory}" 47 | 48 | - name: Build ${{ matrix.image.label }} image 49 | run: | 50 | docker build -t "${{ env.IMAGE_TAG }}" "${{ env.DIRECTORY }}" 51 | 52 | - name: Scan ${{ matrix.image.label }} image by Trivy 53 | if: always() 54 | uses: aquasecurity/trivy-action@0.31.0 55 | with: 56 | image-ref: ${{ env.IMAGE_TAG }} 57 | trivy-config: .github/containerscan/trivy.yaml 58 | env: 59 | # https://github.com/aquasecurity/trivy/issues/2432 60 | DOCKLE_HOST: "unix:///var/run/docker.sock" 61 | 62 | - name: Scan ${{ matrix.image.label }} image by Dockle 63 | if: always() 64 | # https://github.com/goodwithtech/dockle-action/releases/tag/v0.4.15 65 | uses: goodwithtech/dockle-action@e30e6af832aad6ea7dca2a248d31a85eab6dbd68 66 | with: 67 | image: ${{ env.IMAGE_TAG }} 68 | format: 'list' 69 | exit-code: '1' 70 | exit-level: 'warn' 71 | # too many false positives, we don't use credentials in Dockerfile 72 | ignore: 'CIS-DI-0010' 73 | 74 | - name: Scan ${{ matrix.image.label }} image by Snyk 75 | if: always() 76 | uses: snyk/actions/docker@master 77 | env: 78 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} 79 | with: 80 | image: ${{ env.IMAGE_TAG }} 81 | args: --file=${{ env.DIRECTORY }}/Dockerfile --policy-path=.github/containerscan --severity-threshold=high --exclude-base-image-vulns 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | #!! ERROR: i is undefined. Use list command to see defined gitignore types !!# 4 | 5 | ### Intellij ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 7 | 8 | *.iml 9 | 10 | ## Directory-based project format: 11 | .idea/ 12 | # if you remove the above rule, at least ignore the following: 13 | 14 | # User-specific stuff: 15 | # .idea/workspace.xml 16 | # .idea/tasks.xml 17 | # .idea/dictionaries 18 | 19 | # Sensitive or high-churn files: 20 | # .idea/dataSources.ids 21 | # .idea/dataSources.xml 22 | # .idea/sqlDataSources.xml 23 | # .idea/dynamic.xml 24 | # .idea/uiDesigner.xml 25 | 26 | # Gradle: 27 | # .idea/gradle.xml 28 | # .idea/libraries 29 | 30 | # Mongo Explorer plugin: 31 | # .idea/mongoSettings.xml 32 | 33 | ## File-based project format: 34 | *.ipr 35 | *.iws 36 | 37 | ## Plugin-specific files: 38 | 39 | # IntelliJ 40 | /out/ 41 | 42 | # mpeltonen/sbt-idea plugin 43 | .idea_modules/ 44 | 45 | # JIRA plugin 46 | atlassian-ide-plugin.xml 47 | 48 | # Crashlytics plugin (for Android Studio and IntelliJ) 49 | com_crashlytics_export_strings.xml 50 | crashlytics.properties 51 | crashlytics-build.properties 52 | 53 | hazelcast-oss/hazelcast-distribution.zip 54 | hazelcast-enterprise/hazelcast-enterprise-distribution.zip 55 | 56 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `hazelcast-docker` 2 | 3 | Pull requests must be created from a branch within the repo, rather than from an external fork. 4 | 5 | This is to ensure that validation GitHub actions (e.g. [`vulnerability_scan.yml`](.github/workflows/vulnerability_scan.yml)) have access to repository secrets. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hazelcast Docker 2 | 3 | This repository contains Dockerfiles for the official Hazelcast Docker images. 4 | 5 | ## Quick Start 6 | 7 | ### Hazelcast 8 | 9 | You can launch a Hazelcast Docker Container by running the following command. Check [Hazelcast Versions](#hazelcast-versions) for the versions to replace $HAZELCAST_VERSION. 10 | 11 | ``` 12 | $ docker run hazelcast/hazelcast:$HAZELCAST_VERSION 13 | ``` 14 | This command will pull a Hazelcast Docker image and run a new Hazelcast instance. 15 | 16 | 17 | ### Hazelcast Versions 18 | 19 | You can find the full list of Hazelcast versions at the [Official Hazelcast Docker Hub](https://store.docker.com/community/images/hazelcast/hazelcast/tags). 20 | 21 | 22 | ### Hazelcast Hello World 23 | 24 | For the simplest end-to-end scenario, you can create a Hazelcast cluster with two Docker containers and access it from the client application. 25 | 26 | ``` 27 | $ docker run -e HZ_NETWORK_PUBLICADDRESS=:5701 -p 5701:5701 hazelcast/hazelcast:$HAZELCAST_VERSION 28 | $ docker run -e HZ_NETWORK_PUBLICADDRESS=:5702 -p 5702:5701 hazelcast/hazelcast:$HAZELCAST_VERSION 29 | ``` 30 | 31 | Note that: 32 | * each container must publish the `5701` port under a different host machine port (`5701` and `5702` in the example) 33 | * supplying a custom `HZ_NETWORK_PUBLICADDRESS` is critical for autodiscovery. Otherwise, Hazelcast will bind to Docker's internal ports. 34 | * `` needs to be the host machine address that will be used for the Hazelcast communication 35 | 36 | After setting up the cluster, you can start the [client](https://github.com/hazelcast/hazelcast-code-samples/tree/master/clients/basic) application to check if it works correctly. 37 | 38 | ### Hazelcast Enterprise 39 | 40 | You can launch a Hazelcast Enterprise Docker Container by running the following command. Check [Hazelcast Enterprise Versions](#hazelcast-enterprise-versions) for the versions to replace $HAZELCAST_VERSION. 41 | 42 | Please request a trial license [here](https://hazelcast.com/hazelcast-enterprise-download/) or contact sales@hazelcast.com. 43 | 44 | ``` 45 | $ docker run -e HZ_LICENSEKEY= hazelcast/hazelcast-enterprise:$HAZELCAST_VERSION 46 | ``` 47 | 48 | 49 | ### Hazelcast Enterprise Versions 50 | 51 | You can find the full list of Hazelcast Enterprise versions at the [Official Hazelcast Docker Hub](https://store.docker.com/community/images/hazelcast/hazelcast-enterprise/tags). 52 | 53 | ### Hazelcast Enterprise Hello World 54 | 55 | To run two Hazelcast nodes, use the following commands. 56 | 57 | ``` 58 | $ docker run -p 5701:5701 -e HZ_LICENSEKEY= -e HZ_NETWORK_PUBLICADDRESS=:5701 hazelcast/hazelcast-enterprise:$HAZELCAST_VERSION 59 | $ docker run -p 5702:5701 -e HZ_LICENSEKEY= -e HZ_NETWORK_PUBLICADDRESS=:5702 hazelcast/hazelcast-enterprise:$HAZELCAST_VERSION 60 | ``` 61 | 62 | Note that: 63 | * This example assumes unencrypted communication channels for Hazelcast members and clients. Hazelcast allows you to encrypt socket-level communication between Hazelcast members and between Hazelcast clients and members. Refer to [this section](https://github.com/hazelcast/hazelcast-docker#tls_enabled-hazelcast-enterprise-only) to learn about enabling TLS/SSL encryption. 64 | 65 | ### Management Center Hello World 66 | 67 | Whether you started the Hazelcast or Hazelcast Enterprise cluster, you could use the Management Center application to monitor and manage your cluster. 68 | 69 | ``` 70 | docker run \ 71 | -e MC_INIT_CMD="./bin/hz-mc conf cluster add -H=/data -ma :5701 -cn dev" \ 72 | -p 8080:8080 hazelcast/management-center:$MANAGEMENT_CENTER_VERSION 73 | ``` 74 | 75 | Now, you can access Management Center from your browser using the following URL: `https://localhost:8080`. You can read more about the Management Center Docker image [here](https://github.com/hazelcast/management-center-docker). 76 | 77 | Note that the way the Management Center is started changed since Hazelcast 4.0. If you use Hazelcast 3.x, please find the instructions [here](https://github.com/hazelcast/hazelcast-docker/tree/3.12.z). 78 | 79 | ## Hazelcast Defined Environment Variables 80 | 81 | ### JAVA_OPTS 82 | 83 | As shown below, you can use `JAVA_OPTS` environment variable if you need to pass multiple VM arguments to your Hazelcast member. 84 | 85 | ``` 86 | $ docker run -e JAVA_OPTS="-Xms512M -Xmx1024M" hazelcast/hazelcast 87 | ``` 88 | 89 | ### PROMETHEUS_PORT 90 | 91 | The port of the JMX Prometheus agent. For example, if you set `PROMETHEUS_PORT=8080`, then you can access metrics at: `http://:8080/metrics`. You can also use `PROMETHEUS_CONFIG` to set a path to the custom configuration. 92 | 93 | ### LOGGING_LEVEL 94 | 95 | The logging level can be changed using the `LOGGING_LEVEL` variable, for example, to see the `DEBUG` logs. 96 | 97 | ``` 98 | $ docker run -e LOGGING_LEVEL=DEBUG hazelcast/hazelcast 99 | ``` 100 | 101 | Available logging levels are (from highest to lowest): `OFF`, `FATAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE` and `ALL`. The default logging level is `INFO`. Invalid levels will be assumed `OFF`. 102 | 103 | Note that if you need some more custom logging configuration, you can specify a configuration file. 104 | 105 | ``` 106 | $ docker run -v :/opt/hazelcast/config/log4j2.properties hazelcast/hazelcast 107 | ``` 108 | 109 | ### LOGGING_CONFIG 110 | 111 | _since version 5.1_ 112 | 113 | The logging configuration can be changed using the `LOGGING_CONFIG` variable, for example you can mount your own Log4j2 configuration file and set the path using this variable. 114 | The default value is set to `/opt/hazelcast/config/log4j2.properties`. 115 | A relative or an absolute path can be provided. 116 | 117 | We also provide `log4j2-json.properties` file in the image. This is using the Log4j2 [log4j-layout-template-json](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html) module. To use it you can do the following: 118 | 119 | ``` 120 | $ docker run -e LOGGING_CONFIG=log4j2-json.properties hazelcast/hazelcast 121 | ``` 122 | 123 | See the [Log4j2 manual](https://logging.apache.org/log4j/2.x/manual/) for reference. 124 | 125 | ## Customizing Hazelcast 126 | 127 | ### Memory 128 | 129 | Hazelcast Docker image respects the container memory limits, so you can specify it with the `-m` parameter. 130 | 131 | ``` 132 | $ docker run -m 512M hazelcast/hazelcast:$HAZELCAST_VERSION 133 | ``` 134 | 135 | Note that by default Hazelcast uses up to 80% of the container memory limit, but you can configure it by adding `-XX:MaxRAMPercentage` to the `JAVA_OPTS` variable. 136 | 137 | ### Configuring Hazelcast via Environment Variables 138 | 139 | Configuration entries of your cluster can be overritten without changing the declarative configuration files (XML/YAML), see [Overriding Configuration documentation section](https://docs.hazelcast.com/hazelcast/latest/configuration/configuring-with-system-properties). 140 | 141 | Assume that you want to have the following configuration for your cluster, represented as YAML: 142 | ```yaml 143 | hazelcast: 144 | cluster-name: dev 145 | network: 146 | port: 147 | auto-increment: true 148 | port-count: 100 149 | port: 5701 150 | ``` 151 | 152 | If you want to use the environment variables, the above would be represented as a set of the following environment variables: 153 | ```bash 154 | $ docker run -e HZ_CLUSTERNAME=dev \ 155 | -e HZ_NETWORK_PORT_AUTOINCREMENT=true \ 156 | -e HZ_NETWORK_PORT_PORTCOUNT=100 \ 157 | -e HZ_NETWORK_PORT_PORT=5701 \ 158 | hazelcast/hazelcast 159 | ``` 160 | 161 | ### Using Custom Hazelcast Configuration File 162 | 163 | If you need to configure Hazelcast with your own `hazelcast.yaml` (or `hazelcast.xml`), you can mount the host folder which contains Hazelcast configuration and pass `hazelcast.config` JVM property. For example, assuming you placed Hazelcast configuration as `/home/ubuntu/hazelcast/hazelcast.yaml`, you can execute the following command. 164 | 165 | ``` 166 | $ docker run -e JAVA_OPTS="-Dhazelcast.config=/opt/hazelcast/config_ext/hazelcast.yaml" -v /home/ubuntu/hazelcast:/opt/hazelcast/config_ext hazelcast/hazelcast 167 | ``` 168 | 169 | Alternatively, you can [extend Hazelcast base image](#extending-hazelcast-base-image) adding your Hazelcast configuration file. 170 | 171 | ### Extending CLASSPATH with new jars or files 172 | 173 | Hazelcast has several extension points i.e MapStore API where you can provide your own implementation to add specific functionality into Hazelcast Cluster. If you have custom jars or files to put into classpath of docker container, you can simply use Docker volume and use `CLASSPATH` environment variable in the `docker run` command. For example, assuming you placed your custom JARs into `/home/ubuntu/hazelcast/`, you can execute the following command. 174 | 175 | ``` 176 | $ docker run -e CLASSPATH="/opt/hazelcast/CLASSPATH_EXT/*" -v /home/ubuntu/hazelcast:/opt/hazelcast/CLASSPATH_EXT hazelcast/hazelcast 177 | ``` 178 | 179 | Alternatively, you can [extend Hazelcast base image](#extending-hazelcast-base-image) adding your custom JARs. 180 | 181 | 182 | ### Using TLS (Hazelcast Enterprise Only) 183 | 184 | The `HZ_NETWORK_SSL_ENABLED` environment variable can be used to enable TLS for the communication. The key material folder should be mounted and properly referenced by using `JAVA_OPTS` variable. 185 | 186 | 1. Generate a sample key material (self-signed certificate) 187 | ```bash 188 | $ mkdir keystore 189 | $ keytool -validity 365 -genkeypair -alias server -keyalg EC -keystore ./keystore/server.keystore -storepass 123456 -keypass 123456 -dname CN=localhost 190 | $ keytool -export -alias server -keystore ./keystore/server.keystore -storepass 123456 -file ./keystore/server.crt 191 | $ keytool -import -noprompt -alias server -keystore ./keystore/server.truststore -storepass 123456 -file ./keystore/server.crt 192 | ``` 193 | 194 | 2. Run Hazelcast Enterprise with TLS enabled: 195 | ```bash 196 | $ docker run -e HZ_LICENSEKEY= \ 197 | -e HZ_NETWORK_SSL_ENABLED=true \ 198 | -v `pwd`/keystore:/keystore \ 199 | -e "JAVA_OPTS=-Djavax.net.ssl.keyStore=/keystore/server.keystore -Djavax.net.ssl.keyStorePassword=123456 200 | -Djavax.net.ssl.trustStore=/keystore/server.truststore -Djavax.net.ssl.trustStorePassword=123456" \ 201 | hazelcast/hazelcast-enterprise 202 | ``` 203 | 204 | 205 | ### Extending Hazelcast Base Image 206 | 207 | If you'd like to customize your Hazelcast member, you can extend the Hazelcast base image and provide your configuration file or/and custom JARs. To do that, you need to create a new `Dockerfile` and build it with `docker build` command. 208 | 209 | In the `Dockerfile` example below, we are creating a new image based on the Hazelcast image and adding our configuration file and a custom JAR from our host to the container, which will be used with Hazelcast when the container runs. 210 | 211 | ``` 212 | FROM hazelcast/hazelcast:$HAZELCAST_VERSION 213 | 214 | # Adding custom hazelcast.yaml 215 | ADD hazelcast.yaml ${HZ_HOME} 216 | ENV JAVA_OPTS -Dhazelcast.config=${HZ_HOME}/hazelcast.yaml 217 | 218 | # Adding custom JARs to the classpath 219 | ADD custom-library.jar ${HZ_HOME} 220 | ``` 221 | 222 | ## Graceful Shutdown 223 | 224 | You can `stop` the member using the docker command: `docker stop `. 225 | 226 | By default, Hazelcast is configured to `TERMINATE` on receiving the SIGTERM signal from Docker, which means that a container stops quickly, but the cluster's data safety relies on the backup stored by other Hazelcast members. 227 | 228 | The other option is to use the `GRACEFUL` shutdown, which triggers the partition migration before shutting down the Hazelcast member. Note that it may take some time, depending on your data size. To use that approach, configure the following properties: 229 | 230 | * Add `hazelcast.shutdownhook.policy=GRACEFUL` to your `JAVA_OPTS` environment variable 231 | * Add `hazelcast.graceful.shutdown.max.wait=` to your `JAVA_OPTS` environment variable 232 | * Default value is 600 seconds 233 | * Stop the container using `docker stop --time ` 234 | * It defines how much time Docker waits before sending SIGKILL 235 | * Default value is 10 seconds 236 | * Value should be greater or equal `hazelcast.graceful.shutdown.max.wait` 237 | * Alternatively, you can configure the Docker timeout upfront by `docker run --stop-timeout ` 238 | 239 | You can debug and monitor Hazelcast instances running inside Docker containers. 240 | 241 | ## Managing and Monitoring 242 | 243 | You can use JMX or Prometheus for application monitoring. 244 | 245 | ### JMX 246 | 247 | You can use the standard JMX protocol to monitor your Hazelcast instance. Start a Hazelcast container with the following parameters. 248 | 249 | ``` 250 | $ docker run -p 9999:9999 -e JAVA_OPTS='-Dhazelcast.jmx=true -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false' hazelcast/hazelcast 251 | ``` 252 | 253 | Now you can connect using the address: `localhost:9999`. 254 | 255 | ### Prometheus 256 | 257 | You can use the JMX Prometheus agent and expose JVM and JMX Hazelcast metrics. 258 | 259 | ``` 260 | $ docker run -p 8080:8080 -e PROMETHEUS_PORT=8080 261 | ``` 262 | 263 | Then, the metrics are available at: `http://localhost:8080/metrics`. Note that you can add also `-e JAVA_OPTS='-Dhazelcast.jmx=true'` to expose JMX via Prometheus (otherwise, just JVM metrics are visible). 264 | 265 | ## Debugging 266 | 267 | ### Remote Debugger 268 | 269 | To debug your Hazelcast with the standard Java Tools support, use the following command to start Hazelcast container: 270 | 271 | ``` 272 | $ docker run -p 5005:5005 -e JAVA_TOOL_OPTIONS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005' hazelcast/hazelcast 273 | ``` 274 | 275 | Now you can connect with your remote debugger using the address: `localhost:5005`. 276 | 277 | ### Building Your Hazelcast Image 278 | 279 | You may want to build your own Hazelcast Docker image with some custom JARs. For example, if you want to test if your change in the Hazelcast Root repository works fine in the Kubernetes environment or you just need to use an entry processor JAR. To do it, place your JARs into the current directory, build the image, and push it into the Docker registry. 280 | 281 | Taking our first example, imagine you did some change in the Hazelcast Root repository and would like to test it on Kubernetes. You need to build `hazelcast-SNAPSHOT.jar` and then do the following. 282 | 283 | ``` 284 | $ cd hazelcast-oss 285 | $ cp ./ 286 | $ docker build -t /hazelcast:test . 287 | $ docker push /hazelcast:test 288 | ``` 289 | 290 | Then, use the image `/hazelcast:test` in your Kubernetes environment to test your change. 291 | 292 | Additional documentation can be found [here](https://hazelcast.atlassian.net/wiki/spaces/DI/pages/5110693890/How+to+build+local+Hazelcast+Docker+image+from+hazelcast-mono). 293 | 294 | ## Docker Images Usages 295 | 296 | ### Hazelcast Docker Repositories 297 | 298 | You can find all Hazelcast Docker Images on Docker Store Hazelcast Page. 299 | https://store.docker.com/profiles/hazelcast 300 | 301 | You can find Docker files by going to the corresponding `hazelcast-docker` repo tag. 302 | See the full list here: https://github.com/hazelcast/hazelcast-docker/releases 303 | 304 | ### Management Center 305 | 306 | Please see [Management Center Repository](https://github.com/hazelcast/management-center-docker) for Dockerfile definitions and have a look at available images on [Docker Hub](https://store.docker.com/community/images/hazelcast/management-center) page. 307 | 308 | ### Hazelcast Kubernetes 309 | 310 | Hazelcast is prepared to work in the Kubernetes environment. For details, please check: 311 | 312 | * [Hazelcast Platform Operator](https://github.com/hazelcast/hazelcast-platform-operator) 313 | * Hazelcast Helm Charts: 314 | * [Hazelcast](https://github.com/hazelcast/charts/tree/master/stable/hazelcast) 315 | * [Hazelcast Enterprise](https://github.com/hazelcast/charts/tree/master/stable/hazelcast-enterprise) 316 | 317 | ### Automatic rebuilding (Hazelcast Enterprise only) 318 | 319 | Every 24 hours maintained Hazelcast Enterprise docker images are checked against updates of the base system or system libraries. If any of them are present the images are rebuilt and republished. 320 | -------------------------------------------------------------------------------- /hazelcast-enterprise/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redhat/ubi9-minimal:9.6 2 | 3 | # Used for image metadata only 4 | # Describes the version of the Dockerfile, *not* the version of the bundled Hazelcast binary as this is/can be controlled externally 5 | # Dockerfile needs some concept of versioning so that the release pipeline can tag/archive with an appropriate label 6 | ARG HZ_VERSION=6.0.0-SNAPSHOT 7 | ARG JDK_VERSION="21" 8 | 9 | # Build constants 10 | ARG HZ_HOME="/opt/hazelcast" 11 | ARG USER_NAME="hazelcast" 12 | # Optional, defaults to latest released version 13 | ARG HAZELCAST_ZIP_URL="" 14 | 15 | # Runtime variables 16 | ENV HZ_HOME="${HZ_HOME}" \ 17 | CLASSPATH_DEFAULT="${HZ_HOME}/*" \ 18 | JAVA_OPTS_DEFAULT="-Djava.net.preferIPv4Stack=true -XX:MaxRAMPercentage=80.0" \ 19 | PROMETHEUS_PORT="" \ 20 | PROMETHEUS_CONFIG="${HZ_HOME}/config/jmx_agent_config.yaml" \ 21 | CLASSPATH="" \ 22 | JAVA_OPTS="" \ 23 | HAZELCAST_CONFIG=config/hazelcast-docker.xml \ 24 | LANG=C.UTF-8 \ 25 | PATH=${HZ_HOME}/bin:$PATH 26 | 27 | LABEL name="Hazelcast Enterprise" \ 28 | maintainer="info@hazelcast.com" \ 29 | vendor="Hazelcast, Inc." \ 30 | version="${HZ_VERSION}" \ 31 | release="1" \ 32 | summary="Hazelcast Enterprise Image" \ 33 | description="Hazelcast Enterprise Image" 34 | 35 | # Expose port 36 | EXPOSE 5701 37 | 38 | COPY licenses /licenses 39 | COPY *.jar hazelcast-*.zip maven.functions.sh ${HZ_HOME}/ 40 | 41 | # Install 42 | RUN echo "Installing new packages" \ 43 | && microdnf -y update --nodocs \ 44 | && microdnf -y --nodocs --disablerepo=* --enablerepo=ubi-9-appstream-rpms --enablerepo=ubi-9-baseos-rpms \ 45 | --disableplugin=subscription-manager install shadow-utils java-${JDK_VERSION}-openjdk-headless zip tar tzdata-java util-linux \ 46 | && if [[ ! -f ${HZ_HOME}/hazelcast-enterprise-distribution.zip ]]; then \ 47 | if [ -z ${HAZELCAST_ZIP_URL} ]; then \ 48 | source ${HZ_HOME}/maven.functions.sh; \ 49 | HAZELCAST_ZIP_URL="$(get_latest_url_without_extension com.hazelcast hazelcast-enterprise-distribution https://repository.hazelcast.com/release)".zip; \ 50 | fi; \ 51 | echo "Downloading Hazelcast distribution zip from ${HAZELCAST_ZIP_URL}..."; \ 52 | mkdir --parents ${HZ_HOME}; \ 53 | curl --fail --silent --show-error --location ${HAZELCAST_ZIP_URL} --output ${HZ_HOME}/hazelcast-enterprise-distribution.zip; \ 54 | else \ 55 | echo "Using local hazelcast-enterprise-distribution.zip"; \ 56 | fi \ 57 | && unzip -qq ${HZ_HOME}/hazelcast-enterprise-distribution.zip 'hazelcast-*/**' -d ${HZ_HOME}/tmp/ \ 58 | && mv ${HZ_HOME}/tmp/*/* ${HZ_HOME}/ \ 59 | && echo "Setting Pardot ID to 'docker'" \ 60 | && echo 'hazelcastDownloadId=docker' > "${HZ_HOME}/lib/hazelcast-download.properties" \ 61 | && echo "Granting read permission to ${HZ_HOME}" \ 62 | && chmod -R +r ${HZ_HOME} \ 63 | && echo "Removing cached package data and unnecessary tools" \ 64 | && microdnf -y remove zip unzip \ 65 | && microdnf -y clean all \ 66 | && rm -rf ${HZ_HOME}/maven.functions.sh ${HZ_HOME}/hazelcast-enterprise-distribution.zip maven.functions.sh${HZ_HOME}/tmp \ 67 | # Grant execute permission to scripts in order to address the issue of permissions not being accurately propagated on Windows OS 68 | && chmod +x ${HZ_HOME}/bin/* 69 | 70 | COPY log4j2.properties log4j2-json.properties jmx_agent_config.yaml ${HZ_HOME}/config/ 71 | 72 | RUN echo "Adding non-root user" \ 73 | && groupadd --system hazelcast \ 74 | && useradd --no-log-init --system --gid hazelcast --create-home ${USER_NAME} 75 | 76 | WORKDIR ${HZ_HOME} 77 | 78 | ### Switch to hazelcast user 79 | USER ${USER_NAME} 80 | 81 | # Start Hazelcast server 82 | CMD ["hz", "start"] 83 | -------------------------------------------------------------------------------- /hazelcast-enterprise/jmx_agent_config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ssl: false 3 | whitelistObjectNames: ["com.hazelcast*:type=Metrics,*"] 4 | -------------------------------------------------------------------------------- /hazelcast-enterprise/licenses/ELA.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hazelcast/hazelcast-docker/c2c97836bc1612e173d7003810cd53b960d0c9d2/hazelcast-enterprise/licenses/ELA.pdf -------------------------------------------------------------------------------- /hazelcast-enterprise/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hazelcast/hazelcast-docker/c2c97836bc1612e173d7003810cd53b960d0c9d2/hazelcast-enterprise/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf -------------------------------------------------------------------------------- /hazelcast-enterprise/licenses/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright hazelcast all rights reserved. And then software to be used in conjunction with the license provided to you by Hazelcast. 2 | 3 | We have Master License Agreements with companies. They are usually custom. So those licenses cannot be embedded in a directory in the bundle. 4 | 5 | The license key, either trial or subscription, also needs to be added to the software at runtime. -------------------------------------------------------------------------------- /hazelcast-enterprise/log4j2-json.properties: -------------------------------------------------------------------------------- 1 | # Logging Configuration with JsonLayout template 2 | 3 | appender.console.type=Console 4 | appender.console.name=STDOUT 5 | appender.console.layout.type=JsonTemplateLayout 6 | appender.console.layout.eventTemplateUri=${env:LOGGING_JSON_TEMPLATE:-classpath:JsonLayout.json} 7 | 8 | rootLogger.level=${env:LOGGING_LEVEL:-INFO} 9 | rootLogger.appenderRef.stdout.ref=STDOUT 10 | -------------------------------------------------------------------------------- /hazelcast-enterprise/log4j2.properties: -------------------------------------------------------------------------------- 1 | # Default Logging Configuration 2 | 3 | appender.console.type=Console 4 | appender.console.name=STDOUT 5 | appender.console.layout.type=PatternLayout 6 | appender.console.layout.pattern=${env:LOGGING_PATTERN} 7 | appender.console.layout.alwaysWriteExceptions=false 8 | 9 | rootLogger.level=${env:LOGGING_LEVEL:-INFO} 10 | rootLogger.appenderRef.stdout.ref=STDOUT 11 | -------------------------------------------------------------------------------- /hazelcast-enterprise/maven.functions.sh: -------------------------------------------------------------------------------- 1 | set -euo pipefail ${RUNNER_DEBUG:+-x} 2 | 3 | # THIS FILE IS DUPLICATED AND MUST BE KEPT IN SYNC MANUALLY 4 | # Docker requires any included script to be in the current folder, hence we must duplicate this script for OS and EE 5 | 6 | # Prints the latest version in the Maven repository 7 | # 8 | # Parameters: 9 | # group_id e.g. com.google.guava 10 | # artifact_id e.g. guava 11 | # repository_url e.g. https://repo1.maven.org 12 | # 13 | # Prints the latest released version of the given artifact in the provided Maven repository 14 | # E.G. `33.2.0-jre` 15 | 16 | function get_latest_version() { 17 | local group_id=$1 18 | local artifact_id=$2 19 | local repository_url=$3 20 | 21 | curl --fail --silent --show-error --location "${repository_url}/${group_id//./\/}/${artifact_id}/maven-metadata.xml" | awk -F'|' 'NF>1 {print $2; exit}' 22 | } 23 | 24 | # Prints a URL to the latest version in the Maven repository, without a file extension 25 | # 26 | # Parameters: 27 | # group_id e.g. com.google.guava 28 | # artifact_id e.g. guava 29 | # repository_url e.g. https://repo1.maven.org 30 | # 31 | # Prints a URL to the latest released version of a given artifact in the Maven repository, without a file extension, assuming a "typical" naming format 32 | # E.G. `https://repo1.maven.org/maven2/com/google/guava/guava/33.2.0-jre/guava-33.2.0-jre` 33 | function get_latest_url_without_extension() { 34 | local group_id=$1 35 | local artifact_id=$2 36 | local repository_url=$3 37 | 38 | latest_version=$(get_latest_version "${group_id}" "${artifact_id}" "${repository_url}") 39 | echo "${repository_url}/${group_id//./\/}/${artifact_id}/${latest_version}/${artifact_id}-${latest_version}" 40 | } 41 | -------------------------------------------------------------------------------- /hazelcast-oss/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3 2 | 3 | # Describes the version of the Dockerfile, *not* the version of the bundled Hazelcast binary as this is/can be controlled externally 4 | # Dockerfile needs some concept of versioning so that the release pipeline can tag/archive with an appropriate label 5 | ARG HZ_VERSION=6.0.0-SNAPSHOT 6 | 7 | # Build constants 8 | ARG HZ_HOME="/opt/hazelcast" 9 | ARG JDK_VERSION="21" 10 | # Optional, defaults to latest released version 11 | ARG HAZELCAST_ZIP_URL="" 12 | 13 | # Runtime variables 14 | ENV HZ_HOME="${HZ_HOME}" \ 15 | CLASSPATH_DEFAULT="${HZ_HOME}/*" \ 16 | JAVA_OPTS_DEFAULT="-Djava.net.preferIPv4Stack=true -XX:MaxRAMPercentage=80.0" \ 17 | PROMETHEUS_PORT="" \ 18 | PROMETHEUS_CONFIG="${HZ_HOME}/config/jmx_agent_config.yaml" \ 19 | CLASSPATH="" \ 20 | JAVA_OPTS="" \ 21 | HAZELCAST_CONFIG=config/hazelcast-docker.xml \ 22 | LANG=C.UTF-8 \ 23 | PATH=${HZ_HOME}/bin:$PATH 24 | 25 | # Expose port 26 | EXPOSE 5701 27 | 28 | COPY *.jar hazelcast-*.zip maven.functions.sh ${HZ_HOME}/ 29 | 30 | # Install 31 | RUN echo "Upgrading APK packages" \ 32 | && apk upgrade --no-cache \ 33 | && echo "Installing new APK packages" \ 34 | && apk add --no-cache openjdk${JDK_VERSION}-jre-headless bash curl libxml2-utils zip unzip \ 35 | && if [[ ! -f ${HZ_HOME}/hazelcast-distribution.zip ]]; then \ 36 | if [ -z ${HAZELCAST_ZIP_URL} ]; then \ 37 | source ${HZ_HOME}/maven.functions.sh; \ 38 | HAZELCAST_ZIP_URL="$(get_latest_url_without_extension com.hazelcast hazelcast-distribution https://repo1.maven.org/maven2)".zip; \ 39 | fi; \ 40 | echo "Downloading Hazelcast distribution zip from ${HAZELCAST_ZIP_URL}..."; \ 41 | mkdir --parents ${HZ_HOME}; \ 42 | curl --fail --silent --show-error --location ${HAZELCAST_ZIP_URL} --output ${HZ_HOME}/hazelcast-distribution.zip; \ 43 | else \ 44 | echo "Using local hazelcast-distribution.zip"; \ 45 | fi \ 46 | && unzip -qq ${HZ_HOME}/hazelcast-distribution.zip 'hazelcast-*/**' -d ${HZ_HOME}/tmp/ \ 47 | && mv ${HZ_HOME}/tmp/*/* ${HZ_HOME}/ \ 48 | && echo "Setting Pardot ID to 'docker'" \ 49 | && echo 'hazelcastDownloadId=docker' > "${HZ_HOME}/lib/hazelcast-download.properties" \ 50 | && echo "Granting read permission to ${HZ_HOME}" \ 51 | && chmod -R +r ${HZ_HOME} \ 52 | && echo "Cleaning APK packages and redundant files/folders" \ 53 | && apk del libxml2-utils zip unzip \ 54 | && rm -rf /var/cache/apk/* ${HZ_HOME}/maven.functions.sh ${HZ_HOME}/hazelcast-distribution.zip ${HZ_HOME}/tmp \ 55 | # Grant execute permission to scripts in order to address the issue of permissions not being accurately propagated on Windows OS 56 | && chmod +x ${HZ_HOME}/bin/* 57 | 58 | COPY log4j2.properties log4j2-json.properties jmx_agent_config.yaml ${HZ_HOME}/config/ 59 | 60 | WORKDIR ${HZ_HOME} 61 | 62 | RUN addgroup -S hazelcast && adduser -S hazelcast -G hazelcast 63 | USER hazelcast 64 | 65 | # Start Hazelcast server 66 | CMD ["hz", "start"] 67 | -------------------------------------------------------------------------------- /hazelcast-oss/jmx_agent_config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ssl: false 3 | whitelistObjectNames: ["com.hazelcast*:type=Metrics,*"] 4 | -------------------------------------------------------------------------------- /hazelcast-oss/log4j2-json.properties: -------------------------------------------------------------------------------- 1 | # Logging Configuration with JsonLayout template 2 | 3 | appender.console.type=Console 4 | appender.console.name=STDOUT 5 | appender.console.layout.type=JsonTemplateLayout 6 | appender.console.layout.eventTemplateUri=${env:LOGGING_JSON_TEMPLATE:-classpath:JsonLayout.json} 7 | 8 | rootLogger.level=${env:LOGGING_LEVEL:-INFO} 9 | rootLogger.appenderRef.stdout.ref=STDOUT 10 | -------------------------------------------------------------------------------- /hazelcast-oss/log4j2.properties: -------------------------------------------------------------------------------- 1 | # Default Logging Configuration 2 | 3 | appender.console.type=Console 4 | appender.console.name=STDOUT 5 | appender.console.layout.type=PatternLayout 6 | appender.console.layout.pattern=${env:LOGGING_PATTERN} 7 | appender.console.layout.alwaysWriteExceptions=false 8 | 9 | rootLogger.level=${env:LOGGING_LEVEL:-INFO} 10 | rootLogger.appenderRef.stdout.ref=STDOUT 11 | -------------------------------------------------------------------------------- /hazelcast-oss/maven.functions.sh: -------------------------------------------------------------------------------- 1 | set -euo pipefail ${RUNNER_DEBUG:+-x} 2 | 3 | # THIS FILE IS DUPLICATED AND MUST BE KEPT IN SYNC MANUALLY 4 | # Docker requires any included script to be in the current folder, hence we must duplicate this script for OS and EE 5 | 6 | # Prints the latest version in the Maven repository 7 | # 8 | # Parameters: 9 | # group_id e.g. com.google.guava 10 | # artifact_id e.g. guava 11 | # repository_url e.g. https://repo1.maven.org 12 | # 13 | # Prints the latest released version of the given artifact in the provided Maven repository 14 | # E.G. `33.2.0-jre` 15 | 16 | function get_latest_version() { 17 | local group_id=$1 18 | local artifact_id=$2 19 | local repository_url=$3 20 | 21 | curl --fail --silent --show-error --location "${repository_url}/${group_id//./\/}/${artifact_id}/maven-metadata.xml" | awk -F'|' 'NF>1 {print $2; exit}' 22 | } 23 | 24 | # Prints a URL to the latest version in the Maven repository, without a file extension 25 | # 26 | # Parameters: 27 | # group_id e.g. com.google.guava 28 | # artifact_id e.g. guava 29 | # repository_url e.g. https://repo1.maven.org 30 | # 31 | # Prints a URL to the latest released version of a given artifact in the Maven repository, without a file extension, assuming a "typical" naming format 32 | # E.G. `https://repo1.maven.org/maven2/com/google/guava/guava/33.2.0-jre/guava-33.2.0-jre` 33 | function get_latest_url_without_extension() { 34 | local group_id=$1 35 | local artifact_id=$2 36 | local repository_url=$3 37 | 38 | latest_version=$(get_latest_version "${group_id}" "${artifact_id}" "${repository_url}") 39 | echo "${repository_url}/${group_id//./\/}/${artifact_id}/${latest_version}/${artifact_id}-${latest_version}" 40 | } 41 | -------------------------------------------------------------------------------- /scripts/artifactory-docker-cleaner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script finds and deletes orphaned docker layers that were skipped by flawed tag retention logic in Artifactory. 4 | # 5 | # It's a workaround for a bug in JFrog artifactory that leaves untagged images in the storage despite Tag retention set to 1 6 | # 7 | # More details: 8 | # - support.jfrog.com/s/tickets/500Tc00000Er7WN/digestbased-docker-images-are-not-deleted-when-removing-tags-that-reference-them 9 | # - jfrog.atlassian.net/browse/RTFACT-30850 10 | 11 | set -euo pipefail 12 | 13 | BASE_URL="https://repository.hazelcast.com" 14 | REPOSITORY_NAME="docker" 15 | 16 | if [[ $# -lt 1 || $# -gt 2 ]]; then 17 | echo "Usage: $0 [--remove]" 18 | echo " IMAGE_NAME - name of the image in the artifactory repository, e.g. hazelcast/hazelcast" 19 | echo "" 20 | echo " Options:" 21 | echo " --remove Remove unreferenced images. Run without this option to only list unreferenced images" 22 | exit 1 23 | fi 24 | 25 | IMAGE_NAME="$1" 26 | 27 | REMOVE=false 28 | if [[ "${2:-}" == "--remove" ]]; then 29 | REMOVE=true 30 | fi 31 | 32 | if [[ -z "${JFROG_USER:-}" ]]; then 33 | echo "Error: JFROG_USER environment variable must be set." 34 | exit 1 35 | fi 36 | 37 | if [[ -z "${JFROG_TOKEN:-}" ]]; then 38 | echo "Error: JFROG_TOKEN environment variable must be set." 39 | exit 1 40 | fi 41 | 42 | tags=$(curl -s -u "$JFROG_USER:$JFROG_TOKEN" "$BASE_URL/api/docker/$REPOSITORY_NAME/v2/$IMAGE_NAME/tags/list" | jq -r '.tags[]') 43 | 44 | declare -A referenced_images 45 | 46 | for tag in $tags; do 47 | echo "" 48 | echo "Checking tag $tag" 49 | manifest_url="$BASE_URL/$REPOSITORY_NAME/$IMAGE_NAME/$tag/list.manifest.json" 50 | manifest_content=$(curl -s -u "$JFROG_USER:$JFROG_TOKEN" "$manifest_url") 51 | 52 | if [[ $(echo "$manifest_content" | jq -e '.manifests') ]]; then 53 | while IFS= read -r digest; do 54 | referenced_images["digest_$digest"]=$tag 55 | echo "Found reference to $digest" 56 | done < <(echo "$manifest_content" | jq -r ".manifests[].digest[7:]") 57 | fi 58 | done 59 | 60 | all_images=$(curl -s -u "$JFROG_USER:$JFROG_TOKEN" "$BASE_URL/api/storage/$REPOSITORY_NAME/$IMAGE_NAME" | jq -r '.children[].uri | select(. | startswith("/sha256:")) | .[8:]') 61 | 62 | FOUND_UNREFERENCED_IMAGE=false 63 | echo "" 64 | echo "Summary:" 65 | for image in $all_images; do 66 | if [[ -z "${referenced_images[digest_$image]:-}" ]]; then 67 | FOUND_UNREFERENCED_IMAGE=true 68 | if [[ "$REMOVE" == true ]]; then 69 | echo "REMOVING unreferenced image $image" 70 | curl -s --show-error -u "$JFROG_USER:$JFROG_TOKEN" -X DELETE "$BASE_URL/$REPOSITORY_NAME/$IMAGE_NAME/sha256:$image" || echo "Failed to delete image $image" 71 | else 72 | echo "Found unreferenced image: $image" 73 | fi 74 | fi 75 | done 76 | 77 | if [[ "$FOUND_UNREFERENCED_IMAGE" == false ]]; then 78 | echo "No unreferenced images found" 79 | fi 80 | --------------------------------------------------------------------------------