This is an automated email from the ASF dual-hosted git repository.
jongyoul pushed a commit to branch branch-0.12
in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/branch-0.12 by this push:
new b5c54d684c [ZEPPELIN-6163] HBase interpreter supports hbase-2.x
b5c54d684c is described below
commit b5c54d684cb8b0ff30c90aa81b5cc8006d27527e
Author: Paul Zhang <[email protected]>
AuthorDate: Tue Apr 22 14:42:13 2025 +0800
[ZEPPELIN-6163] HBase interpreter supports hbase-2.x
### What is this PR for?
Currently in Zeppelin HBase interpreter does not support HBase 2.x ruby
syntax.
This patch added hbase-2.x support.
This closes ZEPPELIN-6163
### What type of PR is it?
Improvement
### Todos
### What is the Jira issue?
* Open an issue on Jira https://issues.apache.org/jira/browse/ZEPPELIN/
* Put link here, and add [ZEPPELIN-*Jira number*] in PR title, eg.
[ZEPPELIN-533]
[ZEPPELIN-6163](https://issues.apache.org/jira/browse/ZEPPELIN-6163)
### How should this be tested?
* Strongly recommended: add automated unit tests for any new or changed
behavior
* Outline any manual steps to test the PR here.
Compiled and tested manually.
### Screenshots (if appropriate)
### Questions:
* Does the license files need to update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No
Closes #4908 from paul8263/hbase-2.x.
Signed-off-by: Jongyoul Lee <[email protected]>
(cherry picked from commit 52ea80f312b7a19dcce865a6ca8249a2f5fb49cd)
Signed-off-by: Jongyoul Lee <[email protected]>
---
docs/interpreter/hbase.md | 24 +--
hbase/pom.xml | 10 +-
.../apache/zeppelin/hbase/HbaseInterpreter.java | 206 +++++++++++----------
hbase/src/main/resources/interpreter-setting.json | 12 --
.../zeppelin/hbase/HbaseInterpreterTest.java | 36 +---
.../zeppelin/integration/HBaseIntegrationTest.java | 91 +++++++++
.../integration/HBaseIntegrationTest172.java | 36 ++++
.../integration/HBaseIntegrationTest2418.java | 36 ++++
.../org/apache/zeppelin/test/DownloadUtils.java | 47 ++++-
.../apache/zeppelin/test/DownloadUtilsTest.java | 10 +-
10 files changed, 339 insertions(+), 169 deletions(-)
diff --git a/docs/interpreter/hbase.md b/docs/interpreter/hbase.md
index 50228407c9..0afbc726fa 100644
--- a/docs/interpreter/hbase.md
+++ b/docs/interpreter/hbase.md
@@ -28,19 +28,7 @@ limitations under the License.
To get start with HBase, please see [HBase
Quickstart](https://hbase.apache.org/book.html#quickstart).
## HBase release supported
-By default, Zeppelin is built against HBase 1.0.x releases. To work with HBase
1.1.x releases, use the following build command:
-
-```bash
-# HBase 1.1.4
-./mvnw clean package -DskipTests -Phadoop-2.6 -Dhadoop.version=2.6.0 -P
build-distr -Dhbase.hbase.version=1.1.4 -Dhbase.hadoop.version=2.6.0
-```
-
-To work with HBase 1.2.0+, use the following build command:
-
-```bash
-# HBase 1.2.0
-./mvnw clean package -DskipTests -Phadoop-2.6 -Dhadoop.version=2.6.0 -P
build-distr -Dhbase.hbase.version=1.2.0 -Dhbase.hadoop.version=2.6.0
-```
+Zeppelin is built against HBase 1.x and 2.x releases.
## Configuration
@@ -55,16 +43,6 @@ To work with HBase 1.2.0+, use the following build command:
<td>/usr/lib/hbase</td>
<td>Installation directory of HBase, defaults to HBASE_HOME in
environment</td>
</tr>
- <tr>
- <td>hbase.ruby.sources</td>
- <td>lib/ruby</td>
- <td>Path to Ruby scripts relative to 'hbase.home'</td>
- </tr>
- <tr>
- <td>zeppelin.hbase.test.mode</td>
- <td>false</td>
- <td>Disable checks for unit and manual tests</td>
- </tr>
</table>
If you want to connect to HBase running on a cluster, you'll need to follow
the next step.
diff --git a/hbase/pom.xml b/hbase/pom.xml
index 4c33d68c1e..b468216e6f 100644
--- a/hbase/pom.xml
+++ b/hbase/pom.xml
@@ -33,14 +33,16 @@
<properties>
<!--library versions-->
<interpreter.name>hbase</interpreter.name>
- <jruby.version>1.6.8</jruby.version>
</properties>
<dependencies>
<dependency>
- <groupId>org.jruby</groupId>
- <artifactId>jruby-complete</artifactId>
- <version>${jruby.version}</version>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
diff --git
a/hbase/src/main/java/org/apache/zeppelin/hbase/HbaseInterpreter.java
b/hbase/src/main/java/org/apache/zeppelin/hbase/HbaseInterpreter.java
index 6400fae479..fd8952ba65 100644
--- a/hbase/src/main/java/org/apache/zeppelin/hbase/HbaseInterpreter.java
+++ b/hbase/src/main/java/org/apache/zeppelin/hbase/HbaseInterpreter.java
@@ -14,118 +14,135 @@
package org.apache.zeppelin.hbase;
-import org.jruby.embed.LocalContextScope;
-import org.jruby.embed.ScriptingContainer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
+import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.StringWriter;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Properties;
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ExecuteException;
+import org.apache.commons.exec.ExecuteWatchdog;
+import org.apache.commons.exec.Executor;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterException;
import org.apache.zeppelin.interpreter.InterpreterResult;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.scheduler.Scheduler;
import org.apache.zeppelin.scheduler.SchedulerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
- * Support for HBase Shell. All the commands documented here
- * http://hbase.apache.org/book.html#shell is supported.
- *
- * Requirements:
- * HBase Shell should be installed on the same machine. To be more specific,
the following dir.
- * should be available:
https://github.com/apache/hbase/tree/master/hbase-shell/src/main/ruby
- * HBase Shell should be able to connect to the HBase cluster from terminal.
This makes sure
- * that the client is configured properly.
- *
- * The interpreter takes 3 config parameters:
- * hbase.home: Root directory where HBase is installed. Default is
/usr/lib/hbase/
- * hbase.ruby.sources: Dir where shell ruby code is installed.
- * Path is relative to hbase.home. Default: lib/ruby
- * zeppelin.hbase.test.mode: (Testing only) Disable checks for unit and manual
tests. Default: false
+ * HBase interpreter. It uses the hbase shell to interpret the commands.
*/
public class HbaseInterpreter extends Interpreter {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(HbaseInterpreter.class);
+
public static final String HBASE_HOME = "hbase.home";
- public static final String HBASE_RUBY_SRC = "hbase.ruby.sources";
- public static final String HBASE_TEST_MODE = "zeppelin.hbase.test.mode";
- private static final Logger LOGGER =
LoggerFactory.getLogger(HbaseInterpreter.class);
- private ScriptingContainer scriptingContainer;
+ private static final Path TEMP_FOLDER =
Paths.get(System.getProperty("java.io.tmpdir"),
+ "zeppelin-hbase-scripts");
- private StringWriter writer;
+ private Map<String, Executor> runningProcesses = new HashMap<>();
- public HbaseInterpreter(Properties property) {
- super(property);
+ private Map<String, File> tempFiles = new HashMap<>();
+
+ private static final int SIGTERM_CODE = 143;
+
+ private long commandTimeout = 60000;
+
+ public HbaseInterpreter(Properties properties) {
+ super(properties);
}
@Override
public void open() throws InterpreterException {
- this.scriptingContainer = new
ScriptingContainer(LocalContextScope.SINGLETON);
- this.writer = new StringWriter();
- scriptingContainer.setOutput(this.writer);
-
- if (!Boolean.parseBoolean(getProperty(HBASE_TEST_MODE))) {
- String hbaseHome = getProperty(HBASE_HOME);
- String rubySrc = getProperty(HBASE_RUBY_SRC);
- Path absRubySrc = Paths.get(hbaseHome, rubySrc).toAbsolutePath();
-
- LOGGER.info("Home:" + hbaseHome);
- LOGGER.info("Ruby Src:" + rubySrc);
-
- File f = absRubySrc.toFile();
- if (!f.exists() || !f.isDirectory()) {
- throw new InterpreterException("HBase ruby sources is not available at
'" + absRubySrc
- + "'");
- }
-
- LOGGER.info("Absolute Ruby Source:" + absRubySrc.toString());
- // hirb.rb:41 requires the following system properties to be set.
- Properties sysProps = System.getProperties();
- sysProps.setProperty(HBASE_RUBY_SRC, absRubySrc.toString());
-
- Path absHirbPath = Paths.get(hbaseHome, "bin/hirb.rb");
- try {
- FileInputStream fis = new FileInputStream(absHirbPath.toFile());
- this.scriptingContainer.runScriptlet(fis, "hirb.rb");
- fis.close();
- } catch (IOException e) {
- throw new InterpreterException(e.getCause());
- }
- }
+ // Do nothing
}
@Override
public void close() {
- if (this.scriptingContainer != null) {
- this.scriptingContainer.terminate();
- }
+ runningProcesses.clear();
+ runningProcesses = null;
+ tempFiles.clear();
+ tempFiles = null;
}
@Override
- public InterpreterResult interpret(String cmd, InterpreterContext
interpreterContext) {
+ public InterpreterResult interpret(String st, InterpreterContext context) {
+ LOGGER.debug("Run HBase shell script: {}", st);
+
+ if (StringUtils.isEmpty(st)) {
+ return new InterpreterResult(InterpreterResult.Code.SUCCESS);
+ }
+
+ String paragraphId = context.getParagraphId();
+ final File scriptFile;
+ try {
+ // Write script in a temporary file
+ // The script is enriched with extensions
+ scriptFile = createTempFile(paragraphId);
+ FileUtils.write(scriptFile, st + "\nexit");
+ } catch (IOException e) {
+ LOGGER.error("Can not write script in temp file", e);
+ return new InterpreterResult(InterpreterResult.Code.ERROR,
e.getMessage());
+ }
+
+ InterpreterResult result = new
InterpreterResult(InterpreterResult.Code.SUCCESS);
+
+ final DefaultExecutor executor = new DefaultExecutor();
+ final ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
+
+ executor.setStreamHandler(new PumpStreamHandler(context.out, errorStream));
+ executor.setWatchdog(new ExecuteWatchdog(commandTimeout));
+
+ String hbaseCmdPath = Paths.get(getProperty(HBASE_HOME), "bin",
"hbase").toString();
+ final CommandLine cmdLine = CommandLine.parse(hbaseCmdPath);
+ cmdLine.addArgument("shell", false);
+ cmdLine.addArgument(scriptFile.getAbsolutePath(), false);
+
try {
- LOGGER.info(cmd);
- this.writer.getBuffer().setLength(0);
- this.scriptingContainer.runScriptlet(cmd);
- this.writer.flush();
- LOGGER.debug(writer.toString());
- return new InterpreterResult(InterpreterResult.Code.SUCCESS,
writer.getBuffer().toString());
- } catch (Throwable t) {
- LOGGER.error("Can not run '" + cmd + "'", t);
- return new InterpreterResult(InterpreterResult.Code.ERROR,
t.getMessage());
+ executor.execute(cmdLine);
+ runningProcesses.put(paragraphId, executor);
+ } catch (ExecuteException e) {
+ LOGGER.error("Can not run script in paragraph {}", paragraphId, e);
+
+ final int exitValue = e.getExitValue();
+ InterpreterResult.Code code = InterpreterResult.Code.ERROR;
+ String msg = errorStream.toString();
+
+ if (exitValue == SIGTERM_CODE) {
+ code = InterpreterResult.Code.INCOMPLETE;
+ msg = msg + "Paragraph received a SIGTERM.\n";
+ LOGGER.info("The paragraph {} stopped executing: {}", paragraphId,
msg);
+ }
+
+ msg += "ExitValue: " + exitValue;
+ result = new InterpreterResult(code, msg);
+ } catch (IOException e) {
+ LOGGER.error("Can not run script in paragraph {}", paragraphId, e);
+ result = new InterpreterResult(InterpreterResult.Code.ERROR,
e.getMessage());
+ } finally {
+ deleteTempFile(paragraphId);
+ stopProcess(paragraphId);
}
+ return result;
}
@Override
- public void cancel(InterpreterContext context) {}
+ public void cancel(InterpreterContext context) {
+ stopProcess(context.getParagraphId());
+ deleteTempFile(context.getParagraphId());
+ }
@Override
public FormType getFormType() {
@@ -143,30 +160,27 @@ public class HbaseInterpreter extends Interpreter {
HbaseInterpreter.class.getName() + this.hashCode());
}
- @Override
- public List<InterpreterCompletion> completion(String buf, int cursor,
- InterpreterContext interpreterContext) {
- return null;
+ private void stopProcess(String paragraphId) {
+ Executor executor = runningProcesses.remove(paragraphId);
+ if (null != executor) {
+ final ExecuteWatchdog watchdog = executor.getWatchdog();
+ watchdog.destroyProcess();
+ }
}
- private static String getSystemDefault(
- String envName,
- String propertyName,
- String defaultValue) {
-
- if (envName != null && !envName.isEmpty()) {
- String envValue = System.getenv().get(envName);
- if (envValue != null) {
- return envValue;
- }
+ private File createTempFile(String paragraphId) throws IOException {
+ if (!Files.exists(TEMP_FOLDER)) {
+ Files.createDirectory(TEMP_FOLDER);
}
+ File temp = Files.createTempFile(TEMP_FOLDER, paragraphId,
".txt").toFile();
+ tempFiles.put(paragraphId, temp);
+ return temp;
+ }
- if (propertyName != null && !propertyName.isEmpty()) {
- String propValue = System.getProperty(propertyName);
- if (propValue != null) {
- return propValue;
- }
+ private void deleteTempFile(String paragraphId) {
+ File tmpFile = tempFiles.remove(paragraphId);
+ if (null != tmpFile) {
+ FileUtils.deleteQuietly(tmpFile);
}
- return defaultValue;
}
}
diff --git a/hbase/src/main/resources/interpreter-setting.json
b/hbase/src/main/resources/interpreter-setting.json
index c5d89f083d..6d7a79c185 100644
--- a/hbase/src/main/resources/interpreter-setting.json
+++ b/hbase/src/main/resources/interpreter-setting.json
@@ -10,18 +10,6 @@
"defaultValue": "/usr/lib/hbase/",
"description": "Installation directory of HBase",
"type": "string"
- },
- "hbase.ruby.sources": {
- "propertyName": "hbase.ruby.sources",
- "defaultValue": "lib/ruby",
- "description": "Path to Ruby scripts relative to 'hbase.home'",
- "type": "string"
- },
- "zeppelin.hbase.test.mode": {
- "propertyName": "zeppelin.hbase.test.mode",
- "defaultValue": false,
- "description": "Disable checks for unit and manual tests",
- "type": "checkbox"
}
},
"editor": {
diff --git
a/hbase/src/test/java/org/apache/zeppelin/hbase/HbaseInterpreterTest.java
b/hbase/src/test/java/org/apache/zeppelin/hbase/HbaseInterpreterTest.java
index 5af152243b..460fc1f061 100644
--- a/hbase/src/test/java/org/apache/zeppelin/hbase/HbaseInterpreterTest.java
+++ b/hbase/src/test/java/org/apache/zeppelin/hbase/HbaseInterpreterTest.java
@@ -14,16 +14,14 @@
package org.apache.zeppelin.hbase;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-import java.util.Properties;
-
import org.apache.zeppelin.interpreter.InterpreterException;
-import org.apache.zeppelin.interpreter.InterpreterResult;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import java.util.Properties;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
/**
* Tests for HBase Interpreter.
*/
@@ -34,8 +32,6 @@ public class HbaseInterpreterTest {
public static void setUp() throws NullPointerException, InterpreterException
{
Properties properties = new Properties();
properties.put("hbase.home", "");
- properties.put("hbase.ruby.sources", "");
- properties.put("zeppelin.hbase.test.mode", "true");
hbaseInterpreter = new HbaseInterpreter(properties);
hbaseInterpreter.open();
@@ -45,28 +41,4 @@ public class HbaseInterpreterTest {
void newObject() {
assertNotNull(hbaseInterpreter);
}
-
- @Test
- void putsTest() {
- InterpreterResult result = hbaseInterpreter.interpret("puts \"Hello
World\"", null);
- assertEquals(InterpreterResult.Code.SUCCESS, result.code());
- assertEquals(InterpreterResult.Type.TEXT,
result.message().get(0).getType());
- assertEquals("Hello World\n", result.message().get(0).getData());
- }
-
- public void putsLoadPath() {
- InterpreterResult result = hbaseInterpreter.interpret(
- "require 'two_power'; puts twoToThePowerOf(4)", null);
- assertEquals(InterpreterResult.Code.SUCCESS, result.code());
- assertEquals(InterpreterResult.Type.TEXT,
result.message().get(0).getType());
- assertEquals("16\n", result.message().get(0).getData());
- }
-
- @Test
- void testException() {
- InterpreterResult result = hbaseInterpreter.interpret("plot practical
joke", null);
- assertEquals(InterpreterResult.Code.ERROR, result.code());
- assertEquals("(NameError) undefined local variable or method `joke' for
main:Object",
- result.message().get(0).getData());
- }
}
diff --git
a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest.java
b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest.java
new file mode 100644
index 0000000000..b8e7e18693
--- /dev/null
+++
b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.integration;
+
+
+import org.apache.zeppelin.test.DownloadUtils;
+import org.apache.zeppelin.MiniZeppelinServer;
+import org.apache.zeppelin.interpreter.ExecutionContext;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterFactory;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterSetting;
+import org.apache.zeppelin.interpreter.InterpreterSettingManager;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public abstract class HBaseIntegrationTest {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(HBaseIntegrationTest.class);
+
+ private static InterpreterFactory interpreterFactory;
+ protected static InterpreterSettingManager interpreterSettingManager;
+
+ private String hbaseHome;
+
+ private static MiniZeppelinServer zepServer;
+
+ public void prepareHBase(String hbaseVersion) {
+ LOGGER.info("Testing HBase Version: " + hbaseVersion);
+ this.hbaseHome = DownloadUtils.downloadHBase(hbaseVersion);
+ }
+
+ @BeforeAll
+ static void init() throws Exception {
+ zepServer = new
MiniZeppelinServer(HBaseIntegrationTest.class.getSimpleName());
+ zepServer.addInterpreter("hbase");
+ zepServer.copyBinDir();
+ zepServer.copyLogProperties();
+ zepServer.start();
+ }
+
+ @AfterAll
+ public static void tearDown() throws Exception {
+ zepServer.destroy();
+ }
+
+ @BeforeEach
+ void setup() {
+ interpreterSettingManager =
zepServer.getService(InterpreterSettingManager.class);
+ interpreterFactory = new InterpreterFactory(interpreterSettingManager);
+ }
+
+ @Test
+ public void testHBaseInterpreter() throws Exception {
+ InterpreterSetting hbaseInterpreterSetting =
interpreterSettingManager.getInterpreterSettingByName("hbase");
+ hbaseInterpreterSetting.setProperty("hbase.home", hbaseHome);
+
+ Interpreter hbaseInterpreter = interpreterFactory.getInterpreter("hbase",
new ExecutionContext("user1", "note1", "hbase"));
+
+ InterpreterContext context = new
InterpreterContext.Builder().setNoteId("note1").setParagraphId("paragraph_1").build();
+ InterpreterResult interpreterResult = hbaseInterpreter.interpret("puts
'hello'", context);
+
+ assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code(),
interpreterResult.toString());
+ assertTrue(interpreterResult.message().get(0).getData().contains("hello"));
+
+ interpreterSettingManager.close();
+ }
+
+}
diff --git
a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest172.java
b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest172.java
new file mode 100644
index 0000000000..2979959869
--- /dev/null
+++
b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest172.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.integration;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+
+public class HBaseIntegrationTest172 {
+
+ @Nested
+ @DisplayName("HBase 1.x")
+ public class HBase172 extends HBaseIntegrationTest {
+
+ @BeforeEach
+ public void downloadHBase() {
+ prepareHBase("1.7.2");
+ }
+ }
+
+}
diff --git
a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest2418.java
b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest2418.java
new file mode 100644
index 0000000000..d495d73a6c
--- /dev/null
+++
b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/HBaseIntegrationTest2418.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.integration;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+
+public class HBaseIntegrationTest2418 {
+
+ @Nested
+ @DisplayName("HBase 2.x")
+ public class HBase2418 extends HBaseIntegrationTest {
+
+ @BeforeEach
+ public void downloadHBase() {
+ prepareHBase("2.4.18");
+ }
+ }
+
+}
diff --git
a/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java
b/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java
index 37332b6c22..684b740de9 100644
--- a/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java
+++ b/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java
@@ -198,7 +198,6 @@ public class DownloadUtils {
return targetSparkHomeFolder.getAbsolutePath();
}
-
public static void download(String url, int retries, File dst) throws
IOException {
download(new URL(url), retries, dst);
}
@@ -626,4 +625,50 @@ public class DownloadUtils {
}
return "incubator/livy/" + livyVersion + "/apache-livy-" + livyVersion +
"-bin.zip";
}
+
+ /**
+ * Download of a HBase distribution
+ *
+ * @param version HBase version
+ * @return home of HBase installation
+ */
+ public static String downloadHBase(String version) {
+ File hbaseDownloadFolder = new File(downloadFolder, "hbase");
+ hbaseDownloadFolder.mkdir();
+ File targetHBaseHomeFolder = new File(hbaseDownloadFolder, "hbase-" +
version);
+ if (targetHBaseHomeFolder.exists()) {
+ LOGGER.info("Skip to download HBase {} as it is already downloaded.",
version);
+ return targetHBaseHomeFolder.getAbsolutePath();
+ }
+ File hbaseTGZ = new File(hbaseDownloadFolder, "hbase-" + version +
".tar.gz");
+ try {
+ URL mirrorURL = new URL(MIRROR_URL + generateHBaseDownloadUrl(version));
+ URL archiveURL = new URL(ARCHIVE_URL +
generateHBaseDownloadUrl(version));
+ LOGGER.info("Download HBase {}", version);
+ download(new DownloadRequest(mirrorURL, archiveURL), hbaseTGZ);
+ ProgressBarBuilder pbb = new ProgressBarBuilder()
+ .setTaskName("Unarchive")
+ .setUnit("MiB", 1048576) // setting the progress bar to use MiB as
the unit
+ .setStyle(ProgressBarStyle.ASCII)
+ .setUpdateIntervalMillis(1000)
+ .setConsumer(new DelegatingProgressBarConsumer(LOGGER::info));
+ try (
+ InputStream fis = Files.newInputStream(hbaseTGZ.toPath());
+ InputStream pbis = ProgressBar.wrap(fis, pbb);
+ InputStream bis = new BufferedInputStream(pbis);
+ InputStream gzis = new GzipCompressorInputStream(bis);
+ ArchiveInputStream<TarArchiveEntry> o = new
TarArchiveInputStream(gzis)) {
+ LOGGER.info("Unarchive HBase {} to {}", version,
targetHBaseHomeFolder);
+ unarchive(o, targetHBaseHomeFolder, 1);
+ LOGGER.info("Unarchive HBase {} done", version);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to download HBase");
+ }
+ return targetHBaseHomeFolder.getAbsolutePath();
+ }
+
+ private static String generateHBaseDownloadUrl(String hbaseVersion) {
+ return "hbase/" + hbaseVersion + "/hbase-" + hbaseVersion + "-bin.tar.gz";
+ }
}
diff --git
a/zeppelin-test/src/test/java/org/apache/zeppelin/test/DownloadUtilsTest.java
b/zeppelin-test/src/test/java/org/apache/zeppelin/test/DownloadUtilsTest.java
index 6bed71683c..ffe357729f 100644
---
a/zeppelin-test/src/test/java/org/apache/zeppelin/test/DownloadUtilsTest.java
+++
b/zeppelin-test/src/test/java/org/apache/zeppelin/test/DownloadUtilsTest.java
@@ -76,5 +76,13 @@ class DownloadUtilsTest {
assertTrue(sparkHomePath.toFile().exists());
assertTrue(sparkHomePath.toFile().isDirectory());
}
-
+
+ @Test
+ void downloadHBase() {
+ String hbaseHome = DownloadUtils.downloadHBase("2.14.8");
+ Path hbaseHomePath = Paths.get(hbaseHome);
+ assertTrue(hbaseHomePath.toFile().exists());
+ assertTrue(hbaseHomePath.toFile().isDirectory());
+ }
+
}