Skip to content

Commit 13b8d57

Browse files
committed
HBASE-30087: Create GitHub Actions for testing Read-Replica feature
Change-Id: I17da2eba97f7385540a564ba31c462d796347e4d
1 parent bf473e5 commit 13b8d57

29 files changed

Lines changed: 2457 additions & 0 deletions
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
name: Read-Replica Integration Tests
2+
3+
on:
4+
pull_request:
5+
types: [labeled, synchronize, opened, reopened, ready_for_review]
6+
7+
# Cancel running tests for previous commits on the same PR to save time/resources
8+
concurrency:
9+
group: read-replica-tests-${{ github.event.pull_request.number }}
10+
cancel-in-progress: true
11+
12+
jobs:
13+
read-replica-integration-test:
14+
# Trigger only if the 'read-replica' label is attached and the PR is not a draft
15+
if: ${{ contains(github.event.pull_request.labels.*.name, 'read-replica') && !github.event.pull_request.draft }}
16+
env:
17+
REPLICA_BASE_DIR: ./dev-support/integration-test/read-replica
18+
defaults:
19+
run:
20+
# Change default working directory from GITHUB_WORKSPACE to this
21+
working-directory: ${{ env.REPLICA_BASE_DIR }}
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Checkout HBase Repository with Pull Request's SHA
25+
uses: actions/checkout@v4
26+
27+
- name: Checkout HBase Respoitory Again Inside read-replica Directory
28+
uses: actions/checkout@v4
29+
with:
30+
# Place repo inside dev-support/integration-test/read-replica
31+
# Use this repo to build the hbase-docker image
32+
path: ${{ env.REPLICA_BASE_DIR }}/hbase
33+
34+
- name: Show Working Directory
35+
run: |
36+
echo "The previous default working directory was: GITHUB_WORKSPACE=${GITHUB_WORKSPACE}"
37+
echo "The current and default working directory is now: $(pwd)"
38+
echo "The working directory now has an HBase repo:"
39+
ls -la
40+
echo "Showing the most recent commit in this HBase repo:"
41+
cd hbase && git log --oneline | head
42+
43+
- name: Load .env File into GitHub Actions Environment
44+
run: |
45+
# Turn on auto-export and source the file
46+
set -a
47+
source .env
48+
set +a
49+
50+
# Filter out comments, grab the keys, and write the expanded values to GITHUB_ENV
51+
grep -E "^[A-Za-z0-9_]+=" .env | cut -d= -f1 | while read -r key; do
52+
echo "$key=${!key}"
53+
echo "$key=${!key}" >> $GITHUB_ENV
54+
done
55+
56+
- name: Set up Docker Compose
57+
uses: docker/setup-compose-action@v2
58+
59+
- name: Install Python Requirements
60+
run: |
61+
pip install -r requirements.txt
62+
63+
- name: Set Python Path
64+
run: |
65+
echo "Setting PYTHONPATH=$(pwd) for GITHUB_ENV=${GITHUB_ENV}"
66+
echo "PYTHONPATH=$(pwd)" >> ${GITHUB_ENV}
67+
68+
- name: Compile Protobuf
69+
run: |
70+
echo "Copying ActiveClusterSuffix.proto from HBase repo to have latest version"
71+
cp hbase/hbase-protocol-shaded/src/main/protobuf/server/ActiveClusterSuffix.proto \
72+
python/proto
73+
python3 python/proto/proto_compiler.py
74+
75+
- name: Build Docker Image
76+
run: |
77+
echo "Building docker image"
78+
./build-images.sh
79+
echo "Listing Docker images"
80+
docker image ls
81+
82+
- name: Verify Can't Start Two Active Clusters at Once
83+
run: |
84+
# This script automatically prepares the HBASE_DATA_STORE_ROOT defined in .env.
85+
# This directory and its sub-directories need 777 permissions to prevent HBase
86+
# from failing on startup. The directories are deleted when the containers are stopped
87+
python3 python/scripts/test_dual_active_cluster_startup.py --clean-up-containers
88+
89+
- name: Properly Start HBase Docker Containers
90+
run: |
91+
# This script also prepares HBASE_DATA_STORE_ROOT, similar to the previous step
92+
echo "Starting one active and one replica HBase cluster and waiting for them to initialize..."
93+
python3 python/scripts/verify_hbase_start.py
94+
95+
- name: Test Table Create/Drop Behavior
96+
run: python3 python/scripts/test_create_drop_behavior.py --skip-table-cleanup-on-start
97+
98+
- name: Test Put/Get/Delete Behavior
99+
run: python3 python/scripts/test_put_get_delete_behavior.py --skip-table-cleanup-on-start
100+
101+
- name: Test Read-Only Flag Flipping
102+
run: |
103+
python3 python/scripts/test_read_only_flag_flipping.py --skip-container-start-or-restart
104+
105+
- name: Test Cannot Promote Replica to Second Active Cluster
106+
run: |
107+
python3 python/scripts/test_cannot_promote_second_active_cluster.py --skip-container-start-or-restart
108+
109+
- name: Test Bulkloaded Data and Region Splitting
110+
run: |
111+
python3 python/scripts/test_bulkloaded_data_and_region_splits.py --skip-container-start-or-restart
112+
113+
- name: Clean up
114+
run: docker compose -f docker-compose.yml down
115+
116+
- name: Dump Logs on Failure
117+
if: failure()
118+
run: |
119+
docker logs hbase-docker
120+
docker logs hbase-docker-2
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# The name of the HBase Docker image
2+
HBASE_IMAGE=kgeisz/hbase-docker:read-replica-gha
3+
# The name of the HBase docker container
4+
HBASE_CONTAINER_NAME=hbase-docker
5+
# The directory within the docker container that contains the config files
6+
HBASE_CONF_DIR=/opt/hbase/conf
7+
# The directory containing the 'data-store/<hbase.rootdir>' directory.
8+
# This directory is mounted with the HBase Docker container.
9+
HBASE_DATA_STORE_ROOT=${RUNNER_TEMP}/tmp
10+
# The port for the active cluster's HBase UI (used for cluster readiness)
11+
ACTIVE_CLUSTER_PORT=16010
12+
# The port for the replica cluster's HBase UI (used for cluster readiness)
13+
REPLICA_CLUSTER_PORT=26010
14+
# Local path to the active cluster's HBase config file.
15+
# This file is part of a mounted volume, so modifying it
16+
# locally also modifies it within the container (and vise-versa).
17+
ACTIVE_CLUSTER_CONF_DIR=${GITHUB_WORKSPACE}/dev-support/integration-test/read-replica/conf1
18+
# Same as above, except for the replica cluster
19+
REPLICA_CLUSTER_CONF_DIR=${GITHUB_WORKSPACE}/dev-support/integration-test/read-replica/conf2
20+
# The path to the docker-compose file
21+
DOCKER_COMPOSE_FILE=${GITHUB_WORKSPACE}/dev-support/integration-test/read-replica/docker-compose.yml
22+
# The location of the utils directory within the docker container
23+
CONTAINER_UTILS_DIR=/opt/utils
24+
# The log level for the Python scripts
25+
LOG_LEVEL=DEBUG
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Stage 0: Cache Maven dependencies
2+
ARG BASE_IMAGE=registry.access.redhat.com/ubi8/openjdk-17
3+
FROM ${BASE_IMAGE} AS cache-stage
4+
5+
USER root
6+
7+
# Install necessary packages for building Maven dependencies
8+
RUN INITRD=no DEBIAN_FRONTEND=noninteractive microdnf update -y && microdnf install -y maven git hostname diffutils
9+
10+
# Copy the entire source code to cache dependencies
11+
COPY ./hbase /opt/hbase-src
12+
13+
WORKDIR /opt/hbase-src
14+
15+
# Download and cache all dependencies
16+
RUN mvn clean install -DskipTests -Dskip.license.check=true
17+
18+
# Stage 1: Build the HBase source code
19+
FROM ${BASE_IMAGE} AS build-stage
20+
21+
USER root
22+
23+
# Install necessary build packages
24+
RUN INITRD=no DEBIAN_FRONTEND=noninteractive microdnf update -y && microdnf install -y maven git hostname diffutils
25+
26+
# Copy the cached Maven dependencies
27+
COPY --from=cache-stage /root/.m2 /root/.m2
28+
29+
# Copy the HBase source code
30+
COPY ./hbase /opt/hbase-src
31+
32+
WORKDIR /opt/hbase-src
33+
34+
# Build HBase source code using cached dependencies and enable parallel build
35+
RUN mvn clean package -DskipTests -Dskip.license.check=true assembly:single -T 1C
36+
37+
# Stage 2: Create the final Docker image
38+
FROM ${BASE_IMAGE}
39+
40+
USER root
41+
42+
# Set environment variables
43+
ENV HBASE_HOME=/opt/hbase
44+
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk \
45+
HBASE_USER=hbase \
46+
HBASE_CONF_DIR=${HBASE_HOME}/conf \
47+
HBASE_LIB_DIR=${HBASE_HOME}/lib \
48+
HBASE_LOGS_DIR=${HBASE_HOME}/logs \
49+
DATA_DIR=/data-store
50+
51+
# Install necessary runtime packages
52+
RUN INITRD=no DEBIAN_FRONTEND=noninteractive microdnf update -y && microdnf install -y unzip gzip wget hostname maven git diffutils vim openssh-clients python3 procps
53+
54+
# Copy the built HBase binaries from the build-stage
55+
COPY --from=build-stage /opt/hbase-src/hbase-assembly/target/hbase-4.0.0-alpha-1-SNAPSHOT-bin.tar.gz /opt/
56+
57+
# Extract HBase binaries
58+
RUN tar -xzf /opt/hbase-4.0.0-alpha-1-SNAPSHOT-bin.tar.gz -C /opt \
59+
&& ln -s /opt/hbase-4.0.0-alpha-1-SNAPSHOT /opt/hbase \
60+
&& rm /opt/hbase-4.0.0-alpha-1-SNAPSHOT-bin.tar.gz
61+
62+
COPY --from=build-stage /root/.m2/repository/org/apache/hadoop/hadoop-mapreduce-client-common/*/hadoop-mapreduce-client-common-*.jar \
63+
${HBASE_HOME}/lib/
64+
65+
# Apply custom HBase build steps
66+
RUN sed -i "s,^. export JAVA_HOME.*,export JAVA_HOME=$JAVA_HOME," ${HBASE_CONF_DIR}/hbase-env.sh \
67+
&& sed -E -i 's/(.*)hbase\-daemons\.sh(.*zookeeper)/\1hbase-daemon.sh\2/g' ${HBASE_HOME}/bin/start-hbase.sh \
68+
&& echo -e "JAVA_HOME=$JAVA_HOME\nexport JAVA_HOME\nexport PATH=$JAVA_HOME/jre/bin:$PATH" > /etc/profile.d/defaults.sh \
69+
&& ln -sf ${HBASE_HOME}/bin/* /usr/bin
70+
71+
# Create HBase user and home directory
72+
RUN useradd -u 1000 -m ${HBASE_USER} \
73+
&& mkdir -p /home/${HBASE_USER} \
74+
&& chown -R ${HBASE_USER}:${HBASE_USER} /opt /home/${HBASE_USER} \
75+
&& mkdir "$DATA_DIR" && chown -R ${HBASE_USER}:${HBASE_USER} "$DATA_DIR"
76+
77+
# Set permissions for jboss home directory
78+
RUN chown -R ${HBASE_USER}:${HBASE_USER} /home/jboss
79+
80+
# Copy configuration files - Removed in order to mount config files individually #
81+
82+
# Expose required ports for HBase and related services
83+
EXPOSE 8000 8080 8085 9090 9095 2181 16000 16010 16020 16030
84+
85+
# Set up the utils directory as a volume
86+
VOLUME ["/opt/utils"]
87+
88+
# Switch to the HBase user
89+
USER ${HBASE_USER}
90+
91+
# Create necessary directories for HBase to run
92+
RUN mkdir -p "$DATA_DIR"/hbase "$DATA_DIR"/run "$DATA_DIR"/logs
93+
RUN chmod -R 777 "$DATA_DIR"
94+
95+
# Add the 'ls -l' alias
96+
RUN echo 'alias ll="ls -l"' >> /home/hbase/.bashrc
97+
RUN echo 'alias ll="ls -l"' >> /home/jboss/.bashrc
98+
99+
# Start HBase and keep it running
100+
ENTRYPOINT ["/bin/bash", "-c", "${HBASE_HOME}/bin/start-hbase.sh && tail -f ${HBASE_LOGS_DIR}/*.log"]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/bash
2+
3+
# Load environment variables from .env file
4+
set -a
5+
. ./.env
6+
set +a
7+
8+
# Check if required environment variables are set
9+
if [ -z "$HBASE_IMAGE" ]; then
10+
echo "Error: HBASE_IMAGE is not set in .env file."
11+
exit 1
12+
fi
13+
14+
# HBase source directory
15+
HBASE_SOURCE_DIR="./hbase"
16+
17+
# Check if HBase source directory exists
18+
if [ ! -d "$HBASE_SOURCE_DIR" ]; then
19+
echo "Error: HBase source directory does not exist at $HBASE_SOURCE_DIR."
20+
exit 1
21+
fi
22+
23+
# Run Maven clean to remove previous build artifacts
24+
echo "Running 'mvn clean' in $HBASE_SOURCE_DIR..."
25+
cd "$HBASE_SOURCE_DIR" || exit 1
26+
mvn clean
27+
28+
if [ $? -ne 0 ]; then
29+
echo "Error: 'mvn clean' failed."
30+
exit 1
31+
else
32+
echo "'mvn clean' completed successfully."
33+
fi
34+
35+
# Return to the original directory
36+
cd - || exit 1
37+
38+
# Build HBase Docker image
39+
echo "Building HBase Docker image: ${HBASE_IMAGE}"
40+
docker build -t "${HBASE_IMAGE}" ./
41+
42+
if [ $? -ne 0 ]; then
43+
echo "Error: Failed to build HBase Docker image."
44+
exit 1
45+
else
46+
echo "HBase Docker image built successfully."
47+
fi
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
2+
<configuration>
3+
4+
<property>
5+
<name>hbase.zookeeper.quorum</name>
6+
<value>hbase-docker</value>
7+
</property>
8+
<property>
9+
<name>hbase.zookeeper.property.dataDir</name>
10+
<value>/data-store/zk</value>
11+
</property>
12+
<property>
13+
<name>hbase.rootdir</name>
14+
<value>file:///data-store/hbase</value>
15+
</property>
16+
<property>
17+
<name>hbase.wal.dir</name>
18+
<value>file:///data-store/wal</value>
19+
</property>
20+
<property>
21+
<name>hbase.store.file-tracker.impl</name>
22+
<value>FILE</value>
23+
</property>
24+
25+
<property>
26+
<name>hbase.master.info.bindAddress</name>
27+
<value>hbase-docker</value>
28+
</property>
29+
<property>
30+
<name>hbase.regionserver.info.bindAddress</name>
31+
<value>hbase-docker</value>
32+
</property>
33+
<property>
34+
<name>hbase.unsafe.stream.capability.enforce</name>
35+
<value>false</value>
36+
</property>
37+
<property>
38+
<name>hbase.cluster.distributed</name>
39+
<value>true</value>
40+
</property>
41+
<property>
42+
<name>hbase.rest.port</name>
43+
<value>8000</value>
44+
</property>
45+
46+
<property>
47+
<name>hbase.global.readonly.enabled</name>
48+
<value>false</value>
49+
</property>
50+
<property>
51+
<name>hbase.master.hbck.chore.interval</name>
52+
<value>0</value>
53+
</property>
54+
</configuration>

0 commit comments

Comments
 (0)