Skip to content

Commit

Permalink
[apache#2411] Add Apache Ranger Docker CI image and integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
xunliu committed Mar 10, 2024
1 parent 1bc35a3 commit fb8b3d7
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 4 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ on:
- 'gravitino-ci-hive'
- 'gravitino-ci-trino'
- 'gravitino-ci-doris'
- 'gravitino-ci-ranger'
- 'trino'
- 'hive'
- 'ranger'
tag:
description: 'Docker tag to apply to this image'
required: true
Expand Down Expand Up @@ -43,6 +45,9 @@ jobs:
elif [ "${{ github.event.inputs.image }}" == "gravitino-ci-doris" ]; then
echo "image_type=doris" >> $GITHUB_ENV
echo "image_name=datastrato/gravitino-ci-doris" >> $GITHUB_ENV
elif [ "${{ github.event.inputs.image }}" == "gravitino-ci-ranger" ]; then
echo "image_type=ranger" >> $GITHUB_ENV
echo "image_name=datastrato/gravitino-ci-ranger" >> $GITHUB_ENV
elif [ "${{ github.event.inputs.image }}" == "gravitino" ]; then
echo "image_type=gravitino" >> $GITHUB_ENV
echo "image_name=datastrato/gravitino" >> $GITHUB_ENV
Expand All @@ -52,6 +57,9 @@ jobs:
elif [ "${{ github.event.inputs.image }}" == "hive" ]; then
echo "image_type=hive" >> $GITHUB_ENV
echo "image_name=datastrato/hive" >> $GITHUB_ENV
elif [ "${{ github.event.inputs.image }}" == "ranger" ]; then
echo "image_type=ranger" >> $GITHUB_ENV
echo "image_name=datastrato/ranger" >> $GITHUB_ENV
fi
- name: Check publish Docker token
Expand Down
8 changes: 6 additions & 2 deletions dev/docker/build-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ usage() {
cat << EOF
Usage:
./build-docker.sh --platform [all|linux/amd64|linux/arm64] --type [gravitino|hive|trino|doris] --image {image_name} --tag {tag_name} --latest
./build-docker.sh --platform [all|linux/amd64|linux/arm64] --type [gravitino|hive|trino|doris|ranger] --image {image_name} --tag {tag_name} --latest
Notice: You shouldn't use 'all' for the platform if you don't use the Github action to publish the Docker image.
EOF
Expand Down Expand Up @@ -81,6 +81,10 @@ elif [ "${component_type}" == "gravitino" ]; then
elif [ "${component_type}" == "doris" ]; then
. ${script_dir}/doris/doris-dependency.sh --platform ${platform_type}
build_args="--build-arg DORIS_VERSION=${DORIS_VERSION}"
elif [ "${component_type}" == "ranger" ]; then
# Multiple plugins can be passed using commas, e.g. `plugin-trino,plugin-hive`
build_args="--build-arg RANGER_VERSION=2.4.0 --build-arg RANGER_PLUGINS=plugin-trino"
true # Placeholder, do nothing
else
echo "ERROR : ${component_type} is not a valid component type"
usage
Expand All @@ -96,7 +100,7 @@ if echo "${builders}" | grep -q "${BUILDER_NAME}"; then
echo "BuildKit builder '${BUILDER_NAME}' already exists."
else
echo "BuildKit builder '${BUILDER_NAME}' does not exist."
docker buildx create --platform linux/amd64,linux/arm64 --use --name ${BUILDER_NAME}
docker buildx create --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=10000000 --platform linux/amd64,linux/arm64 --use --name ${BUILDER_NAME}
fi

cd ${script_dir}/${component_type}
Expand Down
79 changes: 79 additions & 0 deletions dev/docker/ranger/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#
# Copyright 2023 Datastrato Pvt Ltd.
# This software is licensed under the Apache License version 2.
#
# Apache Ranger compile Docker image
FROM debian:buster as compile-ranger
LABEL maintainer="[email protected]"

ARG RANGER_VERSION=2.4.0
# Multiple plugins can be passed using commas, e.g. `plugin-trino,plugin-hive`
ARG RANGER_PLUGINS=plugin-trino

WORKDIR /root

RUN apt-get -q update && \
apt-get install -y -q python python3 gcc mariadb-server vim curl wget openjdk-11-jdk git procps

RUN wget https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.tar.gz && \
tar zxvf apache-maven-3.6.3-bin.tar.gz && \
ln -s /root/apache-maven-3.6.3/bin/mvn /usr/local/bin/mvn

ENV JAVA_HOME=/usr/local/jdk
RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \
ln -s /usr/lib/jvm/java-11-openjdk-arm64 ${JAVA_HOME}; \
else \
ln -s /usr/lib/jvm/java-11-openjdk-amd64 ${JAVA_HOME}; \
fi

RUN wget https://downloads.apache.org/ranger/${RANGER_VERSION}/apache-ranger-${RANGER_VERSION}.tar.gz && \
tar zxvf apache-ranger-${RANGER_VERSION}.tar.gz && \
ln -s apache-ranger-${RANGER_VERSION} apache-ranger && \
cd apache-ranger && \
mvn -pl ${RANGER_PLUGINS},jisql,agents-audit,agents-common,agents-cred,agents-installer,credentialbuilder,embeddedwebserver,security-admin,ranger-util,ranger-plugin-classloader,ranger-tools,distro -am -DskipTests=true compile package

# Apache Ranger Admin runtime Docker image
FROM debian:buster
LABEL maintainer="[email protected]"

ARG RANGER_VERSION=2.4.0
# Multiple plugins can be passed using commas, e.g. `plugin-trino,plugin-hive`
ARG RANGER_PLUGINS=plugin-trino
ENV RANGER_PASSWORD=rangerR0cks!

WORKDIR /root

COPY init-mysql.sql.template /tmp/
COPY start-ranger-services.sh /tmp/
RUN chmod +x /tmp/start-ranger-services.sh

RUN apt-get -q update && \
apt-get install -y -q python python3 gcc mariadb-server vim curl wget openjdk-11-jdk git procps

ENV JAVA_HOME=/usr/local/jdk
RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \
ln -s /usr/lib/jvm/java-11-openjdk-arm64 ${JAVA_HOME}; \
else \
ln -s /usr/lib/jvm/java-11-openjdk-amd64 ${JAVA_HOME}; \
fi

COPY --from=compile-ranger /root/apache-ranger/target/ranger-${RANGER_VERSION}-admin.tar.gz /opt
RUN cd /opt && \
tar zxvf ranger-${RANGER_VERSION}-admin.tar.gz && \
ln -s ranger-${RANGER_VERSION}-admin ranger-admin

# Initialize Ranger envirioment
RUN curl -L https://search.maven.org/remotecontent?filepath=mysql/mysql-connector-java/8.0.28/mysql-connector-java-8.0.28.jar --output /opt/ranger-admin/ews/webapp/WEB-INF/lib/mysql-connector-java-8.0.28.jar && \
cp /opt/ranger-admin/ews/webapp/WEB-INF/lib/mysql-connector-java-8.0.28.jar /opt/ranger-admin/jisql/lib/ && \
curl -L https://repo1.maven.org/maven2/com/googlecode/log4jdbc/log4jdbc/1.2/log4jdbc-1.2.jar --output /opt/ranger-admin/ews/webapp/WEB-INF/lib/log4jdbc-1.2.jar && \
cp -r /opt/ranger-admin/ews/webapp/WEB-INF/classes/conf.dist/ /opt/ranger-admin/ews/webapp/WEB-INF/classes/conf && \
mkdir /opt/ranger-admin/ews/logs

# Clean up
RUN rm -rf /var/lib/apt/lists/*

EXPOSE 6080

ENTRYPOINT ["/bin/bash", "-c", "/tmp/start-ranger-services.sh"]
9 changes: 9 additions & 0 deletions dev/docker/ranger/init-mysql.sql.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
-- Copyright 2023 Datastrato Pvt Ltd.
-- This software is licensed under the Apache License version 2.
---
CREATE USER 'rangeradmin'@'localhost' IDENTIFIED BY 'PLACEHOLDER_RANGER_PASSWORD';
CREATE DATABASE ranger;
GRANT ALL PRIVILEGES ON ranger.* TO 'rangeradmin'@'localhost';
UPDATE mysql.user SET plugin='mysql_native_password' WHERE User='root';
FLUSH PRIVILEGES;
30 changes: 30 additions & 0 deletions dev/docker/ranger/start-ranger-services.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash
#
# Copyright 2023 Datastrato Pvt Ltd.
# This software is licensed under the Apache License version 2.
#

# Initial Ranger database in MySQL
sed "s/PLACEHOLDER_RANGER_PASSWORD/${RANGER_PASSWORD}/g" "/tmp/init-mysql.sql.template" > "/tmp/init-mysql.sql"
service mysql start && mysql -uroot < /tmp/init-mysql.sql

# Update Ranger Admin password and setup Ranger Admin
sed -i 's/audit_store=solr/audit_store=DB/g' /opt/ranger-admin/install.properties
sed -i "s/db_password=/db_password=${RANGER_PASSWORD}/g" /opt/ranger-admin/install.properties
sed -i "s/rangerAdmin_password=/rangerAdmin_password=${RANGER_PASSWORD}/g" /opt/ranger-admin/install.properties
sed -i "s/rangerTagsync_password=/rangerTagsync_password=${RANGER_PASSWORD}/g" /opt/ranger-admin/install.properties
sed -i "s/rangerUsersync_password=/rangerUsersync_password=${RANGER_PASSWORD}/g" /opt/ranger-admin/install.properties
sed -i "s/keyadmin_password=/keyadmin_password=${RANGER_PASSWORD}/g" /opt/ranger-admin/install.properties
sed -i 's/check_java_version/#check_java_version/g' /opt/ranger-admin/setup.sh
sed -i 's/#check_java_version()/check_java_version()/g' /opt/ranger-admin/setup.sh
sed -i 's/check_db_connector/#check_db_connector/g' /opt/ranger-admin/setup.sh
sed -i 's/#check_db_connector()/check_db_connector()/g' /opt/ranger-admin/setup.sh
sed -i 's/copy_db_connector/#copy_db_connector/g' /opt/ranger-admin/setup.sh
sed -i 's/#copy_db_connector()/copy_db_connector()/g' /opt/ranger-admin/setup.sh
cd /opt/ranger-admin && /opt/ranger-admin/setup.sh

# Start Ranger Admin
/opt/ranger-admin/ews/ranger-admin-services.sh start

# persist the container
tail -f /dev/null
13 changes: 13 additions & 0 deletions docs/docker-image-details.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,16 @@ Changelog
- Expose ports:
- `8030` Doris FE HTTP port
- `9030` Doris FE MySQL server port

## Gravitino CI Apache Ranger image

You can use this image to control permissions Trino.

Changelog

- gravitino-ci-ranger:0.1.0
- Docker image `datastrato/gravitino-ci-ranger:0.1.0`
- Support Apache Ranger 2.4.0
- Use environment variable `RANGER_PASSWORD` to set up Apache Ranger admin password, Please notice Apache Ranger Password should be minimum 8 characters with min one alphabet and one numeric.
- Expose ports:
- `6080` Apache Ranger admin port
3 changes: 2 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ rauschig = "1.2.0"
mybatis = "3.5.6"
h2db = "1.4.200"
kyuubi = "1.8.0"
ranger = "2.4.0"

protobuf-plugin = "0.9.2"
spotless-plugin = '6.11.0'
Expand Down Expand Up @@ -146,7 +147,7 @@ minikdc = { group = "org.apache.hadoop", name = "hadoop-minikdc", version.ref =
immutables-value = { module = "org.immutables:value", version.ref = "immutables-value" }
commons-cli = { group = "commons-cli", name = "commons-cli", version.ref = "commons-cli" }
sun-activation = { group = "com.sun.activation", name = "javax.activation", version.ref = "sun-activation-version" }

ranger-intg = { group = "org.apache.ranger", name = "ranger-intg", version.ref = "ranger" }
selenium = { group = "org.seleniumhq.selenium", name = "selenium-java", version.ref = "selenium" }
rauschig = { group = "org.rauschig", name = "jarchivelib", version.ref = "rauschig" }
mybatis = { group = "org.mybatis", name = "mybatis", version.ref = "mybatis"}
Expand Down
2 changes: 2 additions & 0 deletions integration-test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ dependencies {
exclude("jakarta.annotation")
}
testImplementation(libs.trino.jdbc)
testImplementation(libs.ranger.intg)
testRuntimeOnly(libs.junit.jupiter.engine)
}

Expand Down Expand Up @@ -320,6 +321,7 @@ tasks.test {
// Gravitino CI Docker image
environment("GRAVITINO_CI_HIVE_DOCKER_IMAGE", "datastrato/gravitino-ci-hive:0.1.8")
environment("GRAVITINO_CI_TRINO_DOCKER_IMAGE", "datastrato/gravitino-ci-trino:0.1.5")
environment("GRAVITINO_CI_RANGER_DOCKER_IMAGE", "datastrato/gravitino-ci-ranger:0.1.0")

// Change poll image pause time from 30s to 60s
environment("TESTCONTAINERS_PULL_PAUSE_TIMEOUT", "60")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class ContainerSuite implements Closeable {
private static HiveContainer hiveContainer;
private static TrinoContainer trinoContainer;
private static TrinoITContainers trinoITContainers;

private static RangerContainer rangerContainer;
protected static final CloseableGroup closer = CloseableGroup.create();

private ContainerSuite() {
Expand Down Expand Up @@ -86,6 +86,20 @@ public void startHiveContainer() {
hiveContainer.start();
}

public void startRangerContainer() {
if (rangerContainer != null) {
return;
}
// Start Ranger container
RangerContainer.Builder rangerBuilder = RangerContainer.builder().withNetwork(network);
rangerContainer = closer.register(rangerBuilder.build());
rangerContainer.start();
}

public RangerContainer getRangerContainer() {
return rangerContainer;
}

public void startTrinoContainer(
String trinoConfDir,
String trinoConnectorLibDir,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2023 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.integration.test.container;

import static java.lang.String.format;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import lombok.Getter;
import org.apache.ranger.RangerClient;
import org.apache.ranger.RangerServiceException;
import org.rnorth.ducttape.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.Network;

public class RangerContainer extends BaseContainer {
public static final Logger LOG = LoggerFactory.getLogger(RangerContainer.class);

public static final String DEFAULT_IMAGE = System.getenv("GRAVITINO_CI_RANGER_DOCKER_IMAGE");
public static final String HOST_NAME = "gravitino-ci-ranger";
public static final int RANGER_PORT = 6080;
@Getter public RangerClient rangerClient;
private String rangerUrl;
private static final String username = "admin";
// Apache Ranger Password should be minimum 8 characters with min one alphabet and one numeric.
private static final String password = "rangerR0cks!";
/* for kerberos authentication:
authType = "kerberos"
username = principal
password = path of the keytab file */
private static final String authType = "simple";

public static Builder builder() {
return new Builder();
}

protected RangerContainer(
String image,
String hostName,
Set<Integer> ports,
Map<String, String> extraHosts,
Map<String, String> filesToMount,
Map<String, String> envVars,
Optional<Network> network) {
super(image, hostName, ports, extraHosts, filesToMount, envVars, network);
}

@Override
protected void setupContainer() {
super.setupContainer();
withLogConsumer(new PrintingContainerLog(format("%-15s| ", "RangerContainer")));
}

@Override
public void start() {
super.start();

rangerUrl = String.format("http://localhost:%s", this.getMappedPort(6080));
rangerClient = new RangerClient(rangerUrl, authType, username, password, null);

Preconditions.check("Ranger container startup failed!", checkContainerStatus(10));
}

@Override
protected boolean checkContainerStatus(int retryLimit) {
int nRetry = 0;
boolean isRangerContainerReady = false;
int sleepTimeMillis = 3_000;
while (nRetry++ < retryLimit) {
try {
rangerClient.getPluginsInfo();
isRangerContainerReady = true;
LOG.info("Ranger container startup success!");
break;
} catch (RangerServiceException e) {
LOG.warn("Check Ranger startup status... {}", e.getMessage());
}
if (!isRangerContainerReady) {
try {
Thread.sleep(sleepTimeMillis);
LOG.warn("Waiting for Ranger server to be ready... ({}ms)", nRetry * sleepTimeMillis);
} catch (InterruptedException e) {
// ignore
}
}
}

return isRangerContainerReady;
}

@Override
public void close() {
super.close();
}

public static class Builder
extends BaseContainer.Builder<RangerContainer.Builder, RangerContainer> {

private Builder() {
this.image = DEFAULT_IMAGE;
this.hostName = HOST_NAME;
this.exposePorts = ImmutableSet.of(RANGER_PORT);
this.envVars = ImmutableMap.<String, String>builder()
.put("RANGER_PASSWORD", password)
.build();
}

@Override
public RangerContainer build() {
return new RangerContainer(
image, hostName, exposePorts, extraHosts, filesToMount, envVars, network);
}
}
}
Loading

0 comments on commit fb8b3d7

Please sign in to comment.