You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by gr...@apache.org on 2018/10/16 19:56:25 UTC

[1/5] kudu git commit: [sentry] Fill out more sentry client API

Repository: kudu
Updated Branches:
  refs/heads/master 02e82ca14 -> 8c184e2a9


[sentry] Fill out more sentry client API

This commit adds more sentry client APIs, e.g list/grant sentry
privileges as well as grant roles to groups, for the upcoming sentry
authorization provider.

Change-Id: I34695cd4cc6723b70617164d58f8681cefd09ddd
Reviewed-on: http://gerrit.cloudera.org:8080/11657
Reviewed-by: Dan Burkert <da...@apache.org>
Tested-by: Kudu Jenkins
Reviewed-by: Andrew Wong <aw...@cloudera.com>


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/e3b1e059
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/e3b1e059
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/e3b1e059

Branch: refs/heads/master
Commit: e3b1e05990c88ae2d330738f512af59202cbe87d
Parents: 02e82ca
Author: Hao Hao <ha...@cloudera.com>
Authored: Wed Oct 10 16:10:59 2018 -0700
Committer: Hao Hao <ha...@cloudera.com>
Committed: Tue Oct 16 18:06:58 2018 +0000

----------------------------------------------------------------------
 src/kudu/hms/hms_catalog-test.cc      |   2 +-
 src/kudu/sentry/sentry_client-test.cc | 221 +++++++++++++++++++++++------
 src/kudu/sentry/sentry_client.cc      |  30 ++++
 src/kudu/sentry/sentry_client.h       |  20 ++-
 4 files changed, 229 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/e3b1e059/src/kudu/hms/hms_catalog-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/hms/hms_catalog-test.cc b/src/kudu/hms/hms_catalog-test.cc
index 53bd462..20f975f 100644
--- a/src/kudu/hms/hms_catalog-test.cc
+++ b/src/kudu/hms/hms_catalog-test.cc
@@ -167,8 +167,8 @@ class HmsCatalogTest : public KuduTest {
   }
 
   void TearDown() override {
-    ASSERT_OK(hms_->Stop());
     ASSERT_OK(hms_client_->Stop());
+    ASSERT_OK(hms_->Stop());
   }
 
   Status StopHms() {

http://git-wip-us.apache.org/repos/asf/kudu/blob/e3b1e059/src/kudu/sentry/sentry_client-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/sentry/sentry_client-test.cc b/src/kudu/sentry/sentry_client-test.cc
index 519e277..d8c845d 100644
--- a/src/kudu/sentry/sentry_client-test.cc
+++ b/src/kudu/sentry/sentry_client-test.cc
@@ -18,6 +18,8 @@
 #include "kudu/sentry/sentry_client.h"
 
 #include <map>
+#include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -33,7 +35,9 @@
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
 
+using std::set;
 using std::string;
+using std::unique_ptr;
 using std::vector;
 
 namespace kudu {
@@ -45,20 +49,63 @@ class SentryClientTest : public KuduTest,
   bool KerberosEnabled() const {
     return GetParam();
   }
+
+  void SetUp() override {
+    bool enable_kerberos = KerberosEnabled();
+
+    thrift::ClientOptions sentry_client_opts;
+
+    sentry_.reset(new MiniSentry());
+    if (enable_kerberos) {
+      kdc_.reset(new MiniKdc());
+      ASSERT_OK(kdc_->Start());
+
+      // Create a service principal for Sentry, and configure it to use it.
+      string spn = "sentry/127.0.0.1@KRBTEST.COM";
+      string ktpath;
+      ASSERT_OK(kdc_->CreateServiceKeytab("sentry/127.0.0.1", &ktpath));
+
+      ASSERT_OK(rpc::SaslInit());
+      sentry_->EnableKerberos(kdc_->GetEnvVars()["KRB5_CONFIG"], spn, ktpath);
+
+      ASSERT_OK(kdc_->CreateUserPrincipal("kudu"));
+      ASSERT_OK(kdc_->Kinit("kudu"));
+      ASSERT_OK(kdc_->SetKrb5Environment());
+      sentry_client_opts.enable_kerberos = true;
+      sentry_client_opts.service_principal = "sentry";
+    }
+    ASSERT_OK(sentry_->Start());
+
+    sentry_client_.reset(new SentryClient(sentry_->address(),
+                                          sentry_client_opts));
+    ASSERT_OK(sentry_client_->Start());
+  }
+
+  void TearDown() override {
+    ASSERT_OK(sentry_client_->Stop());
+    ASSERT_OK(sentry_->Stop());
+  }
+
+ protected:
+  unique_ptr<SentryClient> sentry_client_;
+  unique_ptr<MiniSentry> sentry_;
+  unique_ptr<MiniKdc> kdc_;
 };
 INSTANTIATE_TEST_CASE_P(KerberosEnabled, SentryClientTest, ::testing::Bool());
 
-TEST_F(SentryClientTest, TestMiniSentryLifecycle) {
-  MiniSentry mini_sentry;
-  ASSERT_OK(mini_sentry.Start());
-
+TEST_P(SentryClientTest, TestMiniSentryLifecycle) {
   // Create an HA Sentry client and ensure it automatically reconnects after service interruption.
   thrift::HaClient<SentryClient> client;
+  thrift::ClientOptions sentry_client_opts;
+  if (KerberosEnabled()) {
+    sentry_client_opts.enable_kerberos = true;
+    sentry_client_opts.service_principal = "sentry";
+  }
 
-  ASSERT_OK(client.Start(vector<HostPort>({ mini_sentry.address() }), thrift::ClientOptions()));
-
-  auto smoketest = [&] () -> Status {
-    return client.Execute([] (SentryClient* client) -> Status {
+  ASSERT_OK(client.Start(vector<HostPort>({sentry_->address()}),
+                         sentry_client_opts));
+  auto smoketest = [&]() -> Status {
+    return client.Execute([](SentryClient* client) -> Status {
         ::sentry::TCreateSentryRoleRequest create_req;
         create_req.requestorUserName = "test-admin";
         create_req.roleName = "test-role";
@@ -74,12 +121,12 @@ TEST_F(SentryClientTest, TestMiniSentryLifecycle) {
 
   ASSERT_OK(smoketest());
 
-  ASSERT_OK(mini_sentry.Stop());
-  ASSERT_OK(mini_sentry.Start());
+  ASSERT_OK(sentry_->Stop());
+  ASSERT_OK(sentry_->Start());
   ASSERT_OK(smoketest());
 
-  ASSERT_OK(mini_sentry.Pause());
-  ASSERT_OK(mini_sentry.Resume());
+  ASSERT_OK(sentry_->Pause());
+  ASSERT_OK(sentry_->Resume());
   ASSERT_OK(smoketest());
 }
 
@@ -88,39 +135,15 @@ TEST_F(SentryClientTest, TestMiniSentryLifecycle) {
 // communicate with the Sentry service, and errors are converted to Status
 // instances.
 TEST_P(SentryClientTest, TestCreateDropRole) {
-  MiniKdc kdc;
-  MiniSentry sentry;
-  thrift::ClientOptions sentry_client_opts;
-
-  if (KerberosEnabled()) {
-    ASSERT_OK(kdc.Start());
-
-    string spn = "sentry/127.0.0.1@KRBTEST.COM";
-    string ktpath;
-    ASSERT_OK(kdc.CreateServiceKeytab("sentry/127.0.0.1", &ktpath));
-
-    ASSERT_OK(rpc::SaslInit());
-    sentry.EnableKerberos(kdc.GetEnvVars()["KRB5_CONFIG"], spn, ktpath);
-
-    ASSERT_OK(kdc.CreateUserPrincipal("kudu"));
-    ASSERT_OK(kdc.Kinit("kudu"));
-    ASSERT_OK(kdc.SetKrb5Environment());
-    sentry_client_opts.enable_kerberos = true;
-    sentry_client_opts.service_principal = "sentry";
-  }
-  ASSERT_OK(sentry.Start());
-
-  SentryClient client(sentry.address(), sentry_client_opts);
-  ASSERT_OK(client.Start());
 
   { // Create a role
     ::sentry::TCreateSentryRoleRequest req;
     req.requestorUserName = "test-admin";
     req.roleName = "viewer";
-    ASSERT_OK(client.CreateRole(req));
+    ASSERT_OK(sentry_client_->CreateRole(req));
 
     // Attempt to create the role again.
-    Status s = client.CreateRole(req);
+    Status s = sentry_client_->CreateRole(req);
     ASSERT_TRUE(s.IsAlreadyPresent()) << s.ToString();
   }
 
@@ -128,7 +151,7 @@ TEST_P(SentryClientTest, TestCreateDropRole) {
     ::sentry::TCreateSentryRoleRequest req;
     req.requestorUserName = "joe-interloper";
     req.roleName = "fuzz";
-    Status s = client.CreateRole(req);
+    Status s = sentry_client_->CreateRole(req);
     ASSERT_TRUE(s.IsNotAuthorized()) << s.ToString();
   }
 
@@ -136,7 +159,7 @@ TEST_P(SentryClientTest, TestCreateDropRole) {
     ::sentry::TDropSentryRoleRequest req;
     req.requestorUserName = "joe-interloper";
     req.roleName = "viewer";
-    Status s = client.DropRole(req);
+    Status s = sentry_client_->DropRole(req);
     ASSERT_TRUE(s.IsNotAuthorized()) << s.ToString();
   }
 
@@ -144,12 +167,126 @@ TEST_P(SentryClientTest, TestCreateDropRole) {
     ::sentry::TDropSentryRoleRequest req;
     req.requestorUserName = "test-admin";
     req.roleName = "viewer";
-    ASSERT_OK(client.DropRole(req));
+    ASSERT_OK(sentry_client_->DropRole(req));
 
     // Attempt to drop the role again.
-    Status s = client.DropRole(req);
+    Status s = sentry_client_->DropRole(req);
     ASSERT_TRUE(s.IsNotFound()) << s.ToString();
   }
 }
+
+// Similar to above test to verify that the client can communicate with the
+// Sentry service to list privileges, and errors are converted to Status
+// instances.
+TEST_P(SentryClientTest, TestListPrivilege) {
+  // Attempt to access Sentry privileges by a non admin user.
+  ::sentry::TSentryAuthorizable authorizable;
+  authorizable.server = "server";
+  authorizable.db = "db";
+  authorizable.table = "table";
+  ::sentry::TListSentryPrivilegesRequest request;
+  request.requestorUserName = "joe-interloper";
+  request.authorizableHierarchy = authorizable;
+  request.__set_principalName("viewer");
+  ::sentry::TListSentryPrivilegesResponse response;
+  Status s = sentry_client_->ListPrivilegesByUser(request, &response);
+  ASSERT_TRUE(s.IsNotAuthorized()) << s.ToString();
+
+  // Attempt to access Sentry privileges by a user without
+  // group mapping.
+  request.requestorUserName = "user-without-mapping";
+  s = sentry_client_->ListPrivilegesByUser(request, &response);
+  ASSERT_TRUE(s.IsNotAuthorized()) << s.ToString();
+
+  // Attempt to access Sentry privileges of a non-exist user.
+  request.requestorUserName = "test-admin";
+  s = sentry_client_->ListPrivilegesByUser(request, &response);
+  ASSERT_TRUE(s.IsNotAuthorized()) << s.ToString();
+
+  // List the privileges of user 'test-user' .
+  request.__set_principalName("test-user");
+  ASSERT_OK(sentry_client_->ListPrivilegesByUser(request, &response));
+}
+
+// Similar to above test to verify that the client can communicate with the
+// Sentry service to grant roles, and errors are converted to Status
+// instances.
+TEST_P(SentryClientTest, TestGrantRole) {
+  // Attempt to alter role by a non admin user.
+
+  ::sentry::TSentryGroup group;
+  group.groupName = "user";
+  set<::sentry::TSentryGroup> groups;
+  groups.insert(group);
+
+  ::sentry::TAlterSentryRoleAddGroupsRequest group_request;
+  ::sentry::TAlterSentryRoleAddGroupsResponse group_response;
+  group_request.requestorUserName = "joe-interloper";
+  group_request.roleName = "viewer";
+  group_request.groups = groups;
+
+  Status s = sentry_client_->AlterRoleAddGroups(group_request, &group_response);
+  ASSERT_TRUE(s.IsNotAuthorized()) << s.ToString();
+
+  // Attempt to alter a non-exist role.
+  group_request.requestorUserName = "test-admin";
+  s = sentry_client_->AlterRoleAddGroups(group_request, &group_response);
+  ASSERT_TRUE(s.IsNotFound()) << s.ToString();
+
+  // Alter role 'viewer' to add group 'user'.
+  ::sentry::TCreateSentryRoleRequest role_request;
+  role_request.requestorUserName = "test-admin";
+  role_request.roleName = "viewer";
+  ASSERT_OK(sentry_client_->CreateRole(role_request));
+  ASSERT_OK(sentry_client_->AlterRoleAddGroups(group_request, &group_response));
+}
+
+// Similar to above test to verify that the client can communicate with the
+// Sentry service to grant privileges, and errors are converted to Status
+// instances.
+TEST_P(SentryClientTest, TestGrantPrivilege) {
+  // Alter role 'viewer' to add group 'user'.
+
+  ::sentry::TSentryGroup group;
+  group.groupName = "user";
+  set<::sentry::TSentryGroup> groups;
+  groups.insert(group);
+
+  ::sentry::TAlterSentryRoleAddGroupsRequest group_request;
+  ::sentry::TAlterSentryRoleAddGroupsResponse group_response;
+  group_request.requestorUserName = "test-admin";
+  group_request.roleName = "viewer";
+  group_request.groups = groups;
+
+  ::sentry::TCreateSentryRoleRequest role_request;
+  role_request.requestorUserName = "test-admin";
+  role_request.roleName = "viewer";
+  ASSERT_OK(sentry_client_->CreateRole(role_request));
+  ASSERT_OK(sentry_client_->AlterRoleAddGroups(group_request, &group_response));
+
+  // Attempt to alter role by a non admin user.
+  ::sentry::TAlterSentryRoleGrantPrivilegeRequest privilege_request;
+  ::sentry::TAlterSentryRoleGrantPrivilegeResponse privilege_response;
+  privilege_request.requestorUserName = "joe-interloper";
+  privilege_request.roleName = "viewer";
+  ::sentry::TSentryPrivilege privilege;
+  privilege.serverName = "server";
+  privilege.dbName = "db";
+  privilege.tableName = "table";
+  privilege.action = "SELECT";
+  privilege_request.__set_privilege(privilege);
+  Status s = sentry_client_->AlterRoleGrantPrivilege(privilege_request, &privilege_response);
+  ASSERT_TRUE(s.IsNotAuthorized()) << s.ToString();
+
+  // Attempt to alter a non-exist role.
+  privilege_request.requestorUserName = "test-admin";
+  privilege_request.roleName = "not-exist";
+  s = sentry_client_->AlterRoleGrantPrivilege(privilege_request, &privilege_response);
+  ASSERT_TRUE(s.IsNotFound()) << s.ToString();
+
+  privilege_request.roleName = "viewer";
+  ASSERT_OK(sentry_client_->AlterRoleGrantPrivilege(privilege_request, &privilege_response));
+}
+
 } // namespace sentry
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/e3b1e059/src/kudu/sentry/sentry_client.cc
----------------------------------------------------------------------
diff --git a/src/kudu/sentry/sentry_client.cc b/src/kudu/sentry/sentry_client.cc
index a9d08db..ff29e23 100644
--- a/src/kudu/sentry/sentry_client.cc
+++ b/src/kudu/sentry/sentry_client.cc
@@ -152,5 +152,35 @@ Status SentryClient::DropRole(const ::sentry::TDropSentryRoleRequest& request) {
   return Status::OK();
 }
 
+Status SentryClient::ListPrivilegesByUser(
+    const ::sentry::TListSentryPrivilegesRequest& request,
+    ::sentry::TListSentryPrivilegesResponse* response)  {
+  SCOPED_LOG_SLOW_EXECUTION(WARNING, kSlowExecutionWarningThresholdMs,
+                            "list Sentry privilege by user");
+  SENTRY_RET_NOT_OK(client_.list_sentry_privileges_by_user_and_itsgroups(*response, request),
+                    response->status, "failed to list Sentry privilege by user");
+  return Status::OK();
+}
+
+Status SentryClient::AlterRoleAddGroups(
+    const ::sentry::TAlterSentryRoleAddGroupsRequest& request,
+    ::sentry::TAlterSentryRoleAddGroupsResponse* response)  {
+  SCOPED_LOG_SLOW_EXECUTION(WARNING, kSlowExecutionWarningThresholdMs,
+                            "alter Sentry role add groups");
+  SENTRY_RET_NOT_OK(client_.alter_sentry_role_add_groups(*response, request),
+                    response->status, "failed to alter Sentry role add groups");
+  return Status::OK();
+}
+
+Status SentryClient::AlterRoleGrantPrivilege(
+    const ::sentry::TAlterSentryRoleGrantPrivilegeRequest& request,
+    ::sentry::TAlterSentryRoleGrantPrivilegeResponse* response)  {
+  SCOPED_LOG_SLOW_EXECUTION(WARNING, kSlowExecutionWarningThresholdMs,
+                            "alter Sentry role grant privileges");
+  SENTRY_RET_NOT_OK(client_.alter_sentry_role_grant_privilege(*response, request),
+                    response->status, "failed to alter Sentry role grant privileges");
+  return Status::OK();
+}
+
 } // namespace sentry
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/e3b1e059/src/kudu/sentry/sentry_client.h
----------------------------------------------------------------------
diff --git a/src/kudu/sentry/sentry_client.h b/src/kudu/sentry/sentry_client.h
index 2956476..41d5f87 100644
--- a/src/kudu/sentry/sentry_client.h
+++ b/src/kudu/sentry/sentry_client.h
@@ -24,8 +24,14 @@
 #include "kudu/util/status.h"
 
 namespace sentry {
+class TAlterSentryRoleAddGroupsRequest;
+class TAlterSentryRoleAddGroupsResponse;
+class TAlterSentryRoleGrantPrivilegeRequest;
+class TAlterSentryRoleGrantPrivilegeResponse;
 class TCreateSentryRoleRequest;
 class TDropSentryRoleRequest;
+class TListSentryPrivilegesRequest;
+class TListSentryPrivilegesResponse;
 }
 
 namespace kudu {
@@ -82,7 +88,19 @@ class SentryClient {
   // Drops a role in Sentry.
   Status DropRole(const ::sentry::TDropSentryRoleRequest& request) WARN_UNUSED_RESULT;
 
- private:
+  // List Sentry privileges by user.
+  Status ListPrivilegesByUser(const ::sentry::TListSentryPrivilegesRequest& request,
+      ::sentry::TListSentryPrivilegesResponse* response) WARN_UNUSED_RESULT;
+
+  // Alter role to add groups in Sentry.
+  Status AlterRoleAddGroups(const ::sentry::TAlterSentryRoleAddGroupsRequest& request,
+      ::sentry::TAlterSentryRoleAddGroupsResponse* response) WARN_UNUSED_RESULT;
+
+  // Alter role to grant privileges in Sentry.
+  Status AlterRoleGrantPrivilege(const ::sentry::TAlterSentryRoleGrantPrivilegeRequest& request,
+     ::sentry::TAlterSentryRoleGrantPrivilegeResponse* response) WARN_UNUSED_RESULT;
+
+private:
   ::sentry::SentryPolicyServiceClient client_;
 };
 


[5/5] kudu git commit: [Java] Remove the Maven Build

Posted by gr...@apache.org.
[Java] Remove the Maven Build

This patch removes the Maven poms and remaining
references to the Maven build. Going forward the
Gradle build will be used.

Change-Id: If3c1b6b5bc2218a6285bde10d9ab7e1d9013a023
Reviewed-on: http://gerrit.cloudera.org:8080/11667
Reviewed-by: Dan Burkert <da...@apache.org>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/8c184e2a
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/8c184e2a
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/8c184e2a

Branch: refs/heads/master
Commit: 8c184e2a972729cbb026b6962d6bf558b86e9cf5
Parents: acf1dee
Author: Grant Henke <gr...@apache.org>
Authored: Fri Oct 12 10:54:57 2018 -0500
Committer: Grant Henke <gr...@apache.org>
Committed: Tue Oct 16 19:55:53 2018 +0000

----------------------------------------------------------------------
 RELEASING.adoc                            |   7 -
 build-support/jenkins/build-and-test.sh   | 119 +++-----
 build-support/jenkins/post-build-clean.sh |   2 +-
 docs/developing.adoc                      |   4 +-
 docs/installation.adoc                    |   3 +-
 docs/support/scripts/make_site.sh         |   8 +-
 java/README.adoc                          |  29 --
 java/kudu-backup/pom.xml                  | 338 -----------------------
 java/kudu-client-tools/pom.xml            | 159 -----------
 java/kudu-client/pom.xml                  | 305 --------------------
 java/kudu-flume-sink/pom.xml              | 139 ----------
 java/kudu-hive/pom.xml                    | 116 --------
 java/kudu-jepsen/README.adoc              |  22 +-
 java/kudu-jepsen/pom.xml                  | 150 ----------
 java/kudu-mapreduce/pom.xml               | 133 ---------
 java/kudu-spark-tools/pom.xml             | 203 --------------
 java/kudu-spark/pom.xml                   | 177 ------------
 java/pom.xml                              | 368 -------------------------
 18 files changed, 60 insertions(+), 2222 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/RELEASING.adoc
----------------------------------------------------------------------
diff --git a/RELEASING.adoc b/RELEASING.adoc
index 4f68b75..40cbbcd 100644
--- a/RELEASING.adoc
+++ b/RELEASING.adoc
@@ -85,13 +85,6 @@ branch with the same name and the previously-noted SHA1.
 
 . Check out the `master` branch and bump the version in `version.txt`.
 
-. Update the version for the Java client from within the `java` directory:
-+
-----
-  cd java
-  mvn versions:set -DnewVersion=1.x.y-SNAPSHOT
-----
-
 . Update the version in `java/gradle.properties`.
 
 . If the python API has changed since the previous release, bump the Python version

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/build-support/jenkins/build-and-test.sh
----------------------------------------------------------------------
diff --git a/build-support/jenkins/build-and-test.sh b/build-support/jenkins/build-and-test.sh
index 6ba91c9..b74c2ef 100755
--- a/build-support/jenkins/build-and-test.sh
+++ b/build-support/jenkins/build-and-test.sh
@@ -57,12 +57,6 @@
 #   BUILD_JAVA        Default: 1
 #     Build and test java code if this is set to 1.
 #
-#   BUILD_MAVEN       Default: 0
-#     When building java code, build with Maven if this is set to 1.
-#
-#   BUILD_GRADLE      Default: 1
-#     When building java code, build with Gradle if this is set to 1.
-#
 #   BUILD_PYTHON       Default: 1
 #     Build and test the Python wrapper of the client API.
 #
@@ -75,11 +69,6 @@
 #     Extra flags which are passed to 'pip install' when setting up the build
 #     environment for the Python wrapper.
 #
-#   MVN_FLAGS          Default: ""
-#     Extra flags which are passed to 'mvn' when building and running Java
-#     tests. This can be useful, for example, to choose a different maven
-#     repository location.
-#
 #   GRADLE_FLAGS       Default: ""
 #     Extra flags which are passed to 'gradle' when running Gradle commands.
 #
@@ -120,7 +109,6 @@ export KUDU_ALLOW_SLOW_TESTS=${KUDU_ALLOW_SLOW_TESTS:-$DEFAULT_ALLOW_SLOW_TESTS}
 export KUDU_COMPRESS_TEST_OUTPUT=${KUDU_COMPRESS_TEST_OUTPUT:-1}
 export TEST_TMPDIR=${TEST_TMPDIR:-/tmp/kudutest-$UID}
 BUILD_JAVA=${BUILD_JAVA:-1}
-BUILD_MAVEN=${BUILD_MAVEN:-0}
 BUILD_GRADLE=${BUILD_GRADLE:-1}
 BUILD_PYTHON=${BUILD_PYTHON:-1}
 BUILD_PYTHON3=${BUILD_PYTHON3:-1}
@@ -144,7 +132,6 @@ rm -rf $BUILD_ROOT
 mkdir -p $BUILD_ROOT
 
 # Same for the Java tests, which aren't inside BUILD_ROOT
-rm -rf $SOURCE_ROOT/java/*/target
 rm -rf $SOURCE_ROOT/java/*/build
 
 list_flaky_tests() {
@@ -167,11 +154,6 @@ if [ -n "$BUILD_ID" ]; then
   trap cleanup EXIT
 fi
 
-export TOOLCHAIN_DIR=/opt/toolchain
-if [ -d "$TOOLCHAIN_DIR" ]; then
-  PATH=$TOOLCHAIN_DIR/apache-maven-3.0/bin:$PATH
-fi
-
 THIRDPARTY_TYPE=
 if [ "$BUILD_TYPE" = "TSAN" ]; then
   THIRDPARTY_TYPE=tsan
@@ -393,47 +375,32 @@ if [ "$BUILD_JAVA" == "1" ]; then
   pushd $SOURCE_ROOT/java
   set -x
 
-  # Run the full Maven build.
-  if [ "$BUILD_MAVEN" == "1" ]; then
-    EXTRA_MVN_FLAGS="-B"
-    EXTRA_MVN_FLAGS="$EXTRA_MVN_FLAGS -Dsurefire.rerunFailingTestsCount=3"
-    EXTRA_MVN_FLAGS="$EXTRA_MVN_FLAGS -Dfailsafe.rerunFailingTestsCount=3"
-    EXTRA_MVN_FLAGS="$EXTRA_MVN_FLAGS -Dmaven.javadoc.skip"
-    EXTRA_MVN_FLAGS="$EXTRA_MVN_FLAGS $MVN_FLAGS"
-    if ! mvn $EXTRA_MVN_FLAGS clean verify ; then
-      TESTS_FAILED=1
-      FAILURES="$FAILURES"$'Java Maven build/test failed\n'
-    fi
-  fi
-
   # Run the full Gradle build.
-  if [ "$BUILD_GRADLE" == "1" ]; then
-    export EXTRA_GRADLE_FLAGS="--console=plain"
-    EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS --no-daemon"
-    EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS --continue"
-    EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS -DrerunFailingTestsCount=3"
-    # KUDU-2524: temporarily disable scalafmt until we can work out its JDK
-    # incompatibility issue.
-    EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS -DskipFormat"
-    EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS $GRADLE_FLAGS"
-    # If we're running distributed Java tests, submit them asynchronously.
-    if [ "$ENABLE_DIST_TEST" == "1" ]; then
-      echo
-      echo Submitting Java distributed-test job.
-      echo ------------------------------------------------------------
-      # dist-test uses DIST_TEST_JOB_PATH to define where to output it's id file.
-      export DIST_TEST_JOB_PATH=$BUILD_ROOT/java-dist-test-job-id
-      rm -f $DIST_TEST_JOB_PATH
-      if ! $SOURCE_ROOT/build-support/dist_test.py --no-wait java run-all ; then
-        EXIT_STATUS=1
-        FAILURES="$FAILURES"$'Could not submit Java distributed test job\n'
-      fi
-    else
-      # TODO: Run `gradle check` in BUILD_TYPE DEBUG when static code analysis is fixed
-      if ! ./gradlew $EXTRA_GRADLE_FLAGS clean test ; then
-        TESTS_FAILED=1
-        FAILURES="$FAILURES"$'Java Gradle build/test failed\n'
-      fi
+  export EXTRA_GRADLE_FLAGS="--console=plain"
+  EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS --no-daemon"
+  EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS --continue"
+  EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS -DrerunFailingTestsCount=3"
+  # KUDU-2524: temporarily disable scalafmt until we can work out its JDK
+  # incompatibility issue.
+  EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS -DskipFormat"
+  EXTRA_GRADLE_FLAGS="$EXTRA_GRADLE_FLAGS $GRADLE_FLAGS"
+  # If we're running distributed Java tests, submit them asynchronously.
+  if [ "$ENABLE_DIST_TEST" == "1" ]; then
+    echo
+    echo Submitting Java distributed-test job.
+    echo ------------------------------------------------------------
+    # dist-test uses DIST_TEST_JOB_PATH to define where to output it's id file.
+    export DIST_TEST_JOB_PATH=$BUILD_ROOT/java-dist-test-job-id
+    rm -f $DIST_TEST_JOB_PATH
+    if ! $SOURCE_ROOT/build-support/dist_test.py --no-wait java run-all ; then
+      EXIT_STATUS=1
+      FAILURES="$FAILURES"$'Could not submit Java distributed test job\n'
+    fi
+  else
+    # TODO: Run `gradle check` in BUILD_TYPE DEBUG when static code analysis is fixed
+    if ! ./gradlew $EXTRA_GRADLE_FLAGS clean test ; then
+      TESTS_FAILED=1
+      FAILURES="$FAILURES"$'Java Gradle build/test failed\n'
     fi
   fi
 
@@ -613,26 +580,24 @@ if [ "$ENABLE_DIST_TEST" == "1" ]; then
     rm -Rf $arch_dir
   done
 
-  if [ "$BUILD_GRADLE" == "1" ]; then
-    echo
-    echo Fetching previously submitted Java dist-test results...
-    echo ------------------------------------------------------------
-    JAVA_DIST_TEST_ID=`cat $BUILD_ROOT/java-dist-test-job-id`
-    if ! $DIST_TEST_HOME/bin/client watch $JAVA_DIST_TEST_ID ; then
-      TESTS_FAILED=1
-      FAILURES="$FAILURES"$'Distributed Java tests failed\n'
-    fi
-    DT_DIR=$TEST_LOGDIR/java-dist-test-out
-    rm -Rf $DT_DIR
-    $DIST_TEST_HOME/bin/client fetch --artifacts -d $DT_DIR $JAVA_DIST_TEST_ID
-    # Fetching the artifacts expands each log into its own directory.
-    # Move them back into the main log directory
-    rm -f $DT_DIR/*zip
-    for arch_dir in $DT_DIR/* ; do
-      mv $arch_dir/build/java/test-logs/* $TEST_LOGDIR
-      rm -Rf $arch_dir
-    done
+  echo
+  echo Fetching previously submitted Java dist-test results...
+  echo ------------------------------------------------------------
+  JAVA_DIST_TEST_ID=`cat $BUILD_ROOT/java-dist-test-job-id`
+  if ! $DIST_TEST_HOME/bin/client watch $JAVA_DIST_TEST_ID ; then
+    TESTS_FAILED=1
+    FAILURES="$FAILURES"$'Distributed Java tests failed\n'
   fi
+  DT_DIR=$TEST_LOGDIR/java-dist-test-out
+  rm -Rf $DT_DIR
+  $DIST_TEST_HOME/bin/client fetch --artifacts -d $DT_DIR $JAVA_DIST_TEST_ID
+  # Fetching the artifacts expands each log into its own directory.
+  # Move them back into the main log directory
+  rm -f $DT_DIR/*zip
+  for arch_dir in $DT_DIR/* ; do
+    mv $arch_dir/build/java/test-logs/* $TEST_LOGDIR
+    rm -Rf $arch_dir
+  done
 fi
 
 if [ "$TESTS_FAILED" != "0" -o "$EXIT_STATUS" != "0" ]; then

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/build-support/jenkins/post-build-clean.sh
----------------------------------------------------------------------
diff --git a/build-support/jenkins/post-build-clean.sh b/build-support/jenkins/post-build-clean.sh
index def3e21..385e4d9 100755
--- a/build-support/jenkins/post-build-clean.sh
+++ b/build-support/jenkins/post-build-clean.sh
@@ -28,7 +28,7 @@ ROOT=$(cd $(dirname "$BASH_SOURCE")/../..; pwd)
 cd $ROOT
 
 # Note that we use simple shell commands instead of "make clean"
-# or "mvn clean". This is more foolproof even if something ends
+# or "gradle clean". This is more foolproof even if something ends
 # up partially compiling, etc.
 
 # Clean up intermediate object files in the src tree

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/docs/developing.adoc
----------------------------------------------------------------------
diff --git a/docs/developing.adoc b/docs/developing.adoc
index 49d8c7e..74702d3 100644
--- a/docs/developing.adoc
+++ b/docs/developing.adoc
@@ -72,12 +72,12 @@ The following Maven `<dependency>` element is valid for the Apache Kudu public r
 <dependency>
   <groupId>org.apache.kudu</groupId>
   <artifactId>kudu-client</artifactId>
-  <version>1.1.0</version>
+  <version>1.8.0</version>
 </dependency>
 ----
 
 Convenience binary artifacts for the Java client and various Java integrations (e.g. Spark, Flume)
-are also now available via the link:http://repository.apache.org[ASF Maven repository] and
+are also available via the link:http://repository.apache.org[ASF Maven repository] and
 link:https://mvnrepository.com/artifact/org.apache.kudu[Maven Central repository].
 
 == Example Impala Commands With Kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/docs/installation.adoc
----------------------------------------------------------------------
diff --git a/docs/installation.adoc b/docs/installation.adoc
index 4b2fc84..fe9bf16 100644
--- a/docs/installation.adoc
+++ b/docs/installation.adoc
@@ -665,7 +665,6 @@ Other libraries and headers are internal to Kudu and have no stability guarantee
 
 .Requirements
 - JDK 7 or JDK 8
-- Apache Maven 3.x
 
 WARNING: Support for Java 7 is deprecated as of Kudu 1.5.0 and may be removed in
 the next major release.
@@ -675,7 +674,7 @@ repository, change to the `java` directory, and issue the following command:
 
 [source,bash]
 ----
-$ mvn install -DskipTests
+$ ./gradlew assemble
 ----
 
 For more information about building the Java API, as well as Eclipse integration,

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/docs/support/scripts/make_site.sh
----------------------------------------------------------------------
diff --git a/docs/support/scripts/make_site.sh b/docs/support/scripts/make_site.sh
index e645b6c..c675813 100755
--- a/docs/support/scripts/make_site.sh
+++ b/docs/support/scripts/make_site.sh
@@ -105,13 +105,13 @@ fi
 if [ -n "$OPT_JAVADOC" ]; then
   JAVADOC_SUBDIR="apidocs"
   cd "$SOURCE_ROOT/java"
-  mvn clean install -DskipTests
-  if mvn clean javadoc:aggregate | tee /dev/stdout | fgrep -q "Javadoc Warnings"; then
+  ./gradlew clean assemble
+  if ./gradlew clean javadocAggregate | tee /dev/stdout | fgrep -q "Javadoc Warnings"; then
     echo "There are Javadoc warnings. Please fix them."
     exit 1
   fi
 
-  if [ -f "$SOURCE_ROOT/java/target/site/$JAVADOC_SUBDIR/index.html" ]; then
+  if [ -f "$SOURCE_ROOT/java/build/docs/javadoc/index.html" ]; then
     echo "Successfully built Javadocs."
   else
     echo "Javadocs failed to build."
@@ -119,7 +119,7 @@ if [ -n "$OPT_JAVADOC" ]; then
   fi
 
   rm -Rf "$SITE_OUTPUT_DIR/$JAVADOC_SUBDIR"
-  cp -a "$SOURCE_ROOT/java/target/site/$JAVADOC_SUBDIR" "$SITE_OUTPUT_DIR/"
+  cp -a "$SOURCE_ROOT/java/build/docs/javadoc/." "$SITE_OUTPUT_DIR/$JAVADOC_SUBDIR"
 fi
 
 if [ -n "$OPT_DOXYGEN" ]; then

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/README.adoc
----------------------------------------------------------------------
diff --git a/java/README.adoc b/java/README.adoc
index 42da7e7..5049b51 100644
--- a/java/README.adoc
+++ b/java/README.adoc
@@ -130,35 +130,6 @@ $ ./gradlew install
 NOTE: Additional Gradle command line flag options can be found
 https://docs.gradle.org/current/userguide/command_line_interface.html[here].
 
-== Building with Maven
-
-WARNING: The Maven build is deprecated and may be removed in
-a future release.
-
-Though the Gradle build is the preferred way to build,
-the Maven build still exists and can be used.
-
-=== Running a Full Build
-
-[source,bash]
-----
-$ mvn package -DskipTests
-----
-
-=== Running the Tests
-
-[source,bash]
-----
-$ mvn test
-----
-
-=== Running the Integration Tests
-
-[source,bash]
-----
-$ mvn verify
-----
-
 == Tips for IDEs
 
 === IntelliJ

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-backup/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-backup/pom.xml b/java/kudu-backup/pom.xml
deleted file mode 100644
index ca1f1c8..0000000
--- a/java/kudu-backup/pom.xml
+++ /dev/null
@@ -1,338 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-//
-// 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-backup${spark.version.label}_${scala.binary.version}</artifactId>
-    <name>Kudu Backup</name>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-${spark.version.label}_${scala.binary.version}</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.protobuf</groupId>
-            <artifactId>protobuf-java</artifactId>
-            <version>${protobuf.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.protobuf</groupId>
-            <artifactId>protobuf-java-util</artifactId>
-            <version>${protobuf.version}</version>
-            <exclusions>
-                <exclusion>
-                    <!-- Make sure wrong Guava version is not pulled in. -->
-                    <groupId>com.google.guava</groupId>
-                    <artifactId>guava</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>com.github.scopt</groupId>
-            <artifactId>scopt_${scala.binary.version}</artifactId>
-            <version>${scopt.version}</version>
-            <exclusions>
-                <exclusion>
-                    <!-- Make sure wrong Scala version is not pulled in. -->
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scala-library</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <!-- TODO(KUDU-2500): Spark uses reflection which requires the annotations at runtime. -->
-        <dependency>
-            <groupId>org.apache.yetus</groupId>
-            <artifactId>audience-annotations</artifactId>
-            <version>${yetus.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.databricks</groupId>
-            <artifactId>spark-avro_${scala.binary.version}</artifactId>
-            <version>${sparkavro.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-core_${scala.binary.version}</artifactId>
-            <version>${spark.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-sql_${scala.binary.version}</artifactId>
-            <version>${spark.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.scala-lang</groupId>
-            <artifactId>scala-library</artifactId>
-            <version>${scala.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-${spark.version.label}_${scala.binary.version}</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>${log4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.scalatest</groupId>
-            <artifactId>scalatest_${scala.binary.version}</artifactId>
-            <version>${scalatest.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <!-- set source dirs explicitly for the scalafmt plugin -->
-        <sourceDirectory>src/main/scala</sourceDirectory>
-        <testSourceDirectory>src/test/scala</testSourceDirectory>
-        <extensions>
-            <!-- Used in the protobuf plugin to find the right protoc artifact
-                 with the property os.detected.classifier -->
-            <extension>
-                <groupId>kr.motd.maven</groupId>
-                <artifactId>os-maven-plugin</artifactId>
-                <version>${maven-os-plugin.version}</version>
-            </extension>
-        </extensions>
-        <plugins>
-            <plugin>
-                <groupId>org.xolstice.maven.plugins</groupId>
-                <artifactId>protobuf-maven-plugin</artifactId>
-                <version>${maven-protoc-plugin.version}</version>
-                <extensions>true</extensions>
-                <configuration>
-                    <!-- Documented at:
-                         https://www.xolstice.org/protobuf-maven-plugin/usage.html -->
-                    <checkStaleness>true</checkStaleness>
-                    <protoSourceRoot>src/main/protobuf</protoSourceRoot>
-                    <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>compile</goal>
-                        </goals>
-                        <phase>generate-sources</phase>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-shade-plugin</artifactId>
-                <version>${maven-shade-plugin.version}</version>
-                <configuration>
-                    <artifactSet>
-                        <includes>
-                            <include>com.google.guava:guava</include>
-                            <include>com.google.gson:protobuf-gson</include>
-                            <include>com.google.protobuf:protobuf-java</include>
-                            <include>com.google.protobuf:protobuf-java</include>
-                        </includes>
-                    </artifactSet>
-                    <relocations>
-                        <relocation>
-                            <pattern>com.google.common</pattern>
-                            <shadedPattern>org.apache.kudu.shaded.com.google.common</shadedPattern>
-                        </relocation>
-                        <relocation>
-                            <pattern>com.google.gson</pattern>
-                            <shadedPattern>org.apache.kudu.shaded.com.google.gson</shadedPattern>
-                        </relocation>
-                        <relocation>
-                            <pattern>com.google.protobuf</pattern>
-                            <shadedPattern>org.apache.kudu.shaded.com.google.protobuf</shadedPattern>
-                        </relocation>
-                        <relocation>
-                            <pattern>com.google.thirdparty</pattern>
-                            <shadedPattern>org.apache.kudu.shaded.com.google.thirdparty</shadedPattern>
-                        </relocation>
-                        <relocation>
-                            <pattern>com.github.scopt</pattern>
-                            <shadedPattern>org.apache.kudu.shaded.scopt</shadedPattern>
-                        </relocation>
-                    </relocations>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>net.alchim31.maven</groupId>
-                <artifactId>scala-maven-plugin</artifactId>
-                <version>${scala-maven-plugin.version}</version>
-                <configuration>
-                    <charset>${project.build.sourceEncoding}</charset>
-                    <scalaVersion>${scala.version}</scalaVersion>
-                    <args>
-                        <!-- Emit warning and location for usages of features that should be imported explicitly. -->
-                        <arg>-feature</arg>
-                        <!-- Emit various static analysis warnings. -->
-                        <arg>-Xlint</arg>
-                    </args>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>scala-compile-first</id>
-                        <phase>process-resources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                            <goal>compile</goal>
-                        </goals>
-                    </execution>
-                    <execution>
-                        <id>scala-test-compile</id>
-                        <phase>process-test-resources</phase>
-                        <goals>
-                            <goal>testCompile</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-shade-plugin</artifactId>
-                <version>${maven-shade-plugin.version}</version>
-            </plugin>
-            <plugin>
-                <groupId>org.antipathy</groupId>
-                <artifactId>mvn-scalafmt</artifactId>
-            </plugin>
-        </plugins>
-
-
-        <pluginManagement>
-            <plugins>
-                <plugin>
-                    <!-- kudu-backup has no public Javadoc. -->
-                    <groupId>org.apache.maven.plugins</groupId>
-                    <artifactId>maven-javadoc-plugin</artifactId>
-                    <configuration>
-                        <skip>true</skip>
-                    </configuration>
-                </plugin>
-                <plugin>
-                    <!-- Skip publishing kudu-backup until it's ready to be supported long-term. -->
-                    <groupId>org.apache.maven.plugins</groupId>
-                    <artifactId>maven-deploy-plugin</artifactId>
-                    <configuration>
-                        <skip>true</skip>
-                    </configuration>
-                </plugin>
-                <!-- This big ol' block of nonsense tells the m2e Eclipse plugin what
-                     to do with maven plugins that don't have m2e "extensions" available.
-                     It doesn't affect the Maven build at all. -->
-                <plugin>
-                    <groupId>org.eclipse.m2e</groupId>
-                    <artifactId>lifecycle-mapping</artifactId>
-                    <version>1.0.0</version>
-                    <configuration>
-                        <lifecycleMappingMetadata>
-                            <pluginExecutions>
-                                <pluginExecution>
-                                    <pluginExecutionFilter>
-                                        <groupId>org.apache.maven.plugins</groupId>
-                                        <artifactId>maven-antrun-plugin</artifactId>
-                                        <versionRange>[${maven-antrun-plugin.version},)</versionRange>
-                                        <goals>
-                                            <goal>run</goal>
-                                        </goals>
-                                    </pluginExecutionFilter>
-                                    <action>
-                                        <execute>
-                                            <runOnIncremental>false</runOnIncremental>
-                                        </execute>
-                                    </action>
-                                </pluginExecution>
-                                <pluginExecution>
-                                    <pluginExecutionFilter>
-                                        <groupId>org.xolstice.maven.plugins</groupId>
-                                        <artifactId>protobuf-maven-plugin</artifactId>
-                                        <versionRange>[${maven-protoc-plugin.version},)</versionRange>
-                                        <goals>
-                                            <goal>compile</goal>
-                                        </goals>
-                                    </pluginExecutionFilter>
-                                    <action>
-                                        <execute>
-                                            <runOnIncremental>false</runOnIncremental>
-                                        </execute>
-                                    </action>
-                                </pluginExecution>
-                            </pluginExecutions>
-                        </lifecycleMappingMetadata>
-                    </configuration>
-                </plugin>
-            </plugins>
-        </pluginManagement>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-client-tools/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-client-tools/pom.xml b/java/kudu-client-tools/pom.xml
deleted file mode 100644
index e1b6f9f..0000000
--- a/java/kudu-client-tools/pom.xml
+++ /dev/null
@@ -1,159 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-//
-// 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-client-tools</artifactId>
-    <name>Kudu Client Tools</name>
-    <description>Collection of tools that interact directly with Kudu</description>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-mapreduce</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-            <version>${guava.version}</version>
-            <exclusions>
-                <!-- Ignore the transitive annotations libraries that are -->
-                <!-- not marked as optional in version 22.0+ -->
-                <exclusion>
-                    <groupId>*</groupId>
-                    <artifactId>*</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-common</artifactId>
-            <version>${hadoop.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-mapreduce-client-common</artifactId>
-            <version>${hadoop.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.parquet</groupId>
-            <artifactId>parquet-hadoop</artifactId>
-            <version>${parquet.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.yetus</groupId>
-            <artifactId>audience-annotations</artifactId>
-            <version>${yetus.version}</version>
-            <optional>true</optional>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-mapreduce</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>${commons-io.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>${log4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-failsafe-plugin</artifactId>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-shade-plugin</artifactId>
-                <version>${maven-shade-plugin.version}</version>
-                <configuration>
-                    <artifactSet>
-                        <includes>
-                            <include>com.google.guava:guava</include>
-                            <include>org.apache.kudu:kudu-client</include>
-                            <include>org.apache.kudu:kudu-mapreduce</include>
-                        </includes>
-                    </artifactSet>
-                    <relocations>
-                        <relocation>
-                            <pattern>com.google.common</pattern>
-                            <shadedPattern>org.apache.kudu.shaded.com.google.common</shadedPattern>
-                        </relocation>
-                        <relocation>
-                            <pattern>com.google.thirdparty</pattern>
-                            <shadedPattern>org.apache.kudu.shaded.com.google.thirdparty</shadedPattern>
-                        </relocation>
-                    </relocations>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-client/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-client/pom.xml b/java/kudu-client/pom.xml
deleted file mode 100644
index 3b3babe..0000000
--- a/java/kudu-client/pom.xml
+++ /dev/null
@@ -1,305 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-//
-// 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-client</artifactId>
-    <name>Kudu Java Client</name>
-
-    <dependencies>
-        <dependency>
-            <!-- Not shaded or included in the client JAR because it's part
-                 of the public API. -->
-            <groupId>com.stumbleupon</groupId>
-            <artifactId>async</artifactId>
-            <version>${async.version}</version>
-            <exclusions>
-                <!-- Explicitly exclude slf4j because async uses version ranges
-                     for the dependency -->
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-api</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-            <version>${guava.version}</version>
-            <exclusions>
-                <!-- Ignore the transitive annotations libraries that are -->
-                <!-- not marked as optional in version 22.0+ -->
-                <exclusion>
-                    <groupId>*</groupId>
-                    <artifactId>*</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>com.google.protobuf</groupId>
-            <artifactId>protobuf-java</artifactId>
-            <version>${protobuf.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.sangupta</groupId>
-            <artifactId>murmur</artifactId>
-            <version>${murmur.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>io.netty</groupId>
-            <artifactId>netty</artifactId>
-            <version>${netty.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.google.code.findbugs</groupId>
-            <artifactId>jsr305</artifactId>
-            <version>${jsr305.version}</version>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.yetus</groupId>
-            <artifactId>audience-annotations</artifactId>
-            <version>${yetus.version}</version>
-            <optional>true</optional>
-        </dependency>
-
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>${log4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-core</artifactId>
-            <version>${hamcrest-core.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <version>${mockito-core.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <extensions>
-            <!-- Used in the protobuf plugin to find the right protoc artifact
-                 with the property os.detected.classifier -->
-            <extension>
-              <groupId>kr.motd.maven</groupId>
-              <artifactId>os-maven-plugin</artifactId>
-              <version>${maven-os-plugin.version}</version>
-            </extension>
-        </extensions>
-        <plugins>
-            <plugin>
-                <groupId>org.xolstice.maven.plugins</groupId>
-                <artifactId>protobuf-maven-plugin</artifactId>
-                <version>${maven-protoc-plugin.version}</version>
-                <extensions>true</extensions>
-                <configuration>
-                    <!-- Documented at:
-                         https://www.xolstice.org/protobuf-maven-plugin/usage.html -->
-                    <checkStaleness>true</checkStaleness>
-                    <protoSourceRoot>${project.basedir}/../../src</protoSourceRoot>
-                    <excludes>
-                      <exclude>**/*test*.proto</exclude>
-                    </excludes>
-                    <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>compile</goal>
-                        </goals>
-                        <phase>generate-sources</phase>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-shade-plugin</artifactId>
-              <version>${maven-shade-plugin.version}</version>
-              <configuration>
-                <artifactSet>
-                  <includes>
-                    <include>com.google.guava:guava</include>
-                    <include>com.google.protobuf:protobuf-java</include>
-                    <include>com.sangupta:murmur</include>
-                    <include>io.netty:netty</include>
-                  </includes>
-                </artifactSet>
-                <relocations>
-                  <relocation>
-                    <pattern>com.google.common</pattern>
-                    <shadedPattern>org.apache.kudu.shaded.com.google.common</shadedPattern>
-                  </relocation>
-                  <relocation>
-                    <pattern>com.google.thirdparty</pattern>
-                    <shadedPattern>org.apache.kudu.shaded.com.google.thirdparty</shadedPattern>
-                  </relocation>
-                  <relocation>
-                    <pattern>com.google.protobuf</pattern>
-                    <shadedPattern>org.apache.kudu.shaded.com.google.protobuf</shadedPattern>
-                  </relocation>
-                  <relocation>
-                    <pattern>com.sangupta</pattern>
-                    <shadedPattern>org.apache.kudu.shaded.com.sangupta</shadedPattern>
-                  </relocation>
-                  <relocation>
-                    <pattern>org.jboss.netty</pattern>
-                    <shadedPattern>org.apache.kudu.shaded.org.jboss.netty</shadedPattern>
-                  </relocation>
-                </relocations>
-              </configuration>
-            </plugin>
-            <!-- Attach source and javadoc to packaged jar -->
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-source-plugin</artifactId>
-              <version>2.4</version>
-              <executions>
-                <execution>
-                  <id>attach-sources</id>
-                  <goals>
-                    <goal>jar</goal>
-                  </goals>
-                </execution>
-                <execution>
-                  <id>attach-test-sources</id>
-                  <goals>
-                    <goal>test-jar</goal>
-                  </goals>
-                </execution>
-              </executions>
-            </plugin>
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-javadoc-plugin</artifactId>
-              <version>2.10.3</version>
-              <executions>
-                <execution>
-                  <id>attach-javadocs</id>
-                  <goals>
-                    <goal>jar</goal>
-                  </goals>
-                </execution>
-              </executions>
-            </plugin>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-jar-plugin</artifactId>
-            <version>2.6</version>
-            <executions>
-              <execution>
-                <goals>
-                  <goal>test-jar</goal>
-                </goals>
-              </execution>
-            </executions>
-          </plugin>
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-surefire-plugin</artifactId>
-            </plugin>
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-failsafe-plugin</artifactId>
-            </plugin>
-          </plugins>
-
-        <!-- This big ol' block of nonsense tells the m2e Eclipse plugin what
-             to do with maven plugins that don't have m2e "extensions" available.
-
-             It doesn't affect the Maven build at all. -->
-        <pluginManagement>
-          <plugins>
-            <plugin>
-              <groupId>org.eclipse.m2e</groupId>
-              <artifactId>lifecycle-mapping</artifactId>
-              <version>1.0.0</version>
-              <configuration>
-                <lifecycleMappingMetadata>
-                  <pluginExecutions>
-                    <pluginExecution>
-                      <pluginExecutionFilter>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-antrun-plugin</artifactId>
-                        <versionRange>[${maven-antrun-plugin.version},)</versionRange>
-                        <goals>
-                          <goal>run</goal>
-                        </goals>
-                      </pluginExecutionFilter>
-                      <action>
-                        <execute>
-                          <runOnIncremental>false</runOnIncremental>
-                        </execute>
-                      </action>
-                    </pluginExecution>
-                    <pluginExecution>
-                      <pluginExecutionFilter>
-                        <groupId>org.xolstice.maven.plugins</groupId>
-                        <artifactId>protobuf-maven-plugin</artifactId>
-                        <versionRange>[${maven-protoc-plugin.version},)</versionRange>
-                        <goals>
-                          <goal>compile</goal>
-                        </goals>
-                      </pluginExecutionFilter>
-                      <action>
-                        <execute>
-                          <runOnIncremental>false</runOnIncremental>
-                        </execute>
-                      </action>
-                    </pluginExecution>
-                  </pluginExecutions>
-                </lifecycleMappingMetadata>
-              </configuration>
-            </plugin>
-          </plugins>
-        </pluginManagement>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-flume-sink/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-flume-sink/pom.xml b/java/kudu-flume-sink/pom.xml
deleted file mode 100644
index c2eaef0..0000000
--- a/java/kudu-flume-sink/pom.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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. -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <artifactId>kudu-parent</artifactId>
-    <groupId>org.apache.kudu</groupId>
-    <version>1.9.0-SNAPSHOT</version>
-  </parent>
-  <artifactId>kudu-flume-sink</artifactId>
-  <name>Kudu Flume NG Sink</name>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.apache.kudu</groupId>
-      <artifactId>kudu-client</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-      <version>${guava.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.flume</groupId>
-      <artifactId>flume-ng-core</artifactId>
-      <version>${flume.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.flume</groupId>
-      <artifactId>flume-ng-configuration</artifactId>
-      <version>${flume.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.avro</groupId>
-      <artifactId>avro</artifactId>
-      <version>${avro.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.hadoop</groupId>
-      <artifactId>hadoop-common</artifactId>
-      <version>${hadoop.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-      <version>${slf4j.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.yetus</groupId>
-      <artifactId>audience-annotations</artifactId>
-      <version>${yetus.version}</version>
-      <optional>true</optional>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.kudu</groupId>
-      <artifactId>kudu-client</artifactId>
-      <version>${project.version}</version>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>${junit.version}</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-        <version>${maven-shade-plugin.version}</version>
-        <configuration>
-          <artifactSet>
-            <includes>
-              <include>org.apache.kudu:kudu-client</include>
-              <include>com.stumbleupon:async</include>
-            </includes>
-          </artifactSet>
-          <relocations>
-            <relocation>
-              <pattern>com.google.common</pattern>
-              <shadedPattern>org.apache.kudu.shaded.com.google.common</shadedPattern>
-            </relocation>
-            <relocation>
-              <pattern>com.google.protobuf</pattern>
-              <shadedPattern>org.apache.kudu.shaded.com.google.protobuf</shadedPattern>
-            </relocation>
-            <relocation>
-              <pattern>com.google.thirdparty</pattern>
-              <shadedPattern>org.apache.kudu.shaded.com.google.thirdparty</shadedPattern>
-            </relocation>
-          </relocations>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.avro</groupId>
-        <artifactId>avro-maven-plugin</artifactId>
-        <version>${avro.version}</version>
-        <executions>
-          <execution>
-            <phase>generate-test-sources</phase>
-              <goals>
-                <goal>schema</goal>
-              </goals>
-              <configuration>
-                <!-- Configure the Avro plugin to compile the schemas in the
-                     resource directory so the schemas are available in tests. -->
-                <testSourceDirectory>${basedir}/src/test/resources</testSourceDirectory>
-                <enableDecimalLogicalType>true</enableDecimalLogicalType>
-              </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-hive/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-hive/pom.xml b/java/kudu-hive/pom.xml
deleted file mode 100644
index 7239c7e..0000000
--- a/java/kudu-hive/pom.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-// 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-hive</artifactId>
-    <name>Kudu Hive</name>
-
-    <dependencies>
-        <!-- NOTE: The build currently expects all dependencies will be available
-             via the hive-metastore classpath. Therefore, all dependencies should
-             be provided scope.-->
-        <dependency>
-            <groupId>org.apache.hive</groupId>
-            <artifactId>hive-metastore</artifactId>
-            <version>${hive.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <!-- Transitively required through hive-metastore, which has marked it
-             as an optional dependency. -->
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-common</artifactId>
-            <version>${hadoop.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-mapreduce-client-common</artifactId>
-            <version>${hadoop.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.hive</groupId>
-            <artifactId>hive-metastore</artifactId>
-            <version>${hive.version}</version>
-            <classifier>tests</classifier>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>${log4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <!-- kudu-hive has no public Javadoc. -->
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
-                <configuration>
-                    <skip>true</skip>
-                </configuration>
-            </plugin>
-            <plugin>
-                <!-- Skip publishing kudu-hive until it's ready to be supported long-term. -->
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-deploy-plugin</artifactId>
-                <configuration>
-                    <skip>true</skip>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-jepsen/README.adoc
----------------------------------------------------------------------
diff --git a/java/kudu-jepsen/README.adoc b/java/kudu-jepsen/README.adoc
index fc7663b..562bcdd 100644
--- a/java/kudu-jepsen/README.adoc
+++ b/java/kudu-jepsen/README.adoc
@@ -32,10 +32,10 @@ server nodes. Tested to work on Debian 8 Jessie.
 
 == Overview
 The Clojure code is integrated into the project using the
-link:https://github.com/talios/clojure-maven-plugin[clojure-maven-plugin].
-The kudu-jepsen tests are invoked by executing the `clojure:run`
-plugin-specific goal. The parameters are passed via the standard
-`-D<property>=<value>` notation. There is a dedicated Clojure wrapper script
+link:https://github.com/nebula-plugins/nebula-clojure-plugin[nebula-clojure-plugin].
+The kudu-jepsen tests are invoked by executing the `runJepsen` task.
+The parameters are passed via the standard `-D<property>=<value>` notation.
+There is a dedicated Clojure wrapper script
 `kudu_test_runner.clj` in `$KUDU_HOME/java/kudu-jepsen/src/utils` which
 populates the test environment with appropriate properties and iteratively
 runs all the registered tests with different nemeses scenarios.
@@ -45,13 +45,12 @@ runs all the registered tests with different nemeses scenarios.
 To build the library the following components are required:
 
 * JDK 8
-* Apache Maven version 3.3.6 or higher
 
-To build the project and install necessary Java packages into the local mvn
+To build the project and install necessary Java packages into the local Maven
 repository, run in the parent directory (i.e. `$KUDU_HOME/java`)
 [listing]
 ----
-$ mvn -Pjepsen -DskipTests clean install
+$ ./gradlew -Pjepsen clean install
 ----
 
 === Running
@@ -62,7 +61,6 @@ be up and running when starting the test.
 To run the test, the following components are required at the control node:
 
 * JDK 8
-* Apache Maven version 3.3.6 or higher
 * SSH client (and optionally, SSH authentication agent)
 * gnuplot (to visualize test results)
 
@@ -80,14 +78,14 @@ If using SSH authentication agent to hold the SSH key for DB nodes access,
 run in the current directory:
 [listing]
 ----
-$ mvn clojure:run -DtserverNodes="t0,t1,t2,t3,t4" -DmasterNodes="m0"
+$ ./gradlew -Pjepsen runJepsen -DtserverNodes="t0,t1,t2,t3,t4" -DmasterNodes="m0"
 ----
 
 If not using SSH authentication agent, specify the SSH key location via the
 `sshKeyPath` property:
 [listing]
 ----
-$ mvn clojure:run -DtserverNodes="t0,t1,t2,t3,t4" -DmasterNodes="m0" -DsshKeyPath="./vm_root_id_rsa"
+$ ./gradlew -Pjepsen runJepsen -DtserverNodes="t0,t1,t2,t3,t4" -DmasterNodes="m0" -DsshKeyPath="./vm_root_id_rsa"
 ----
 
 Note that commas (not spaces) are used to separate the names of the nodes. The
@@ -99,7 +97,7 @@ Kudu tablet servers. The `masterNodes` property is used to specify the set of
 nodes to run Kudu master servers.
 
 In the Jepsen terminology, Kudu master and tserver nodes are playing
-*Jepsen DB node* roles. The machine where the above mentioned maven command
+*Jepsen DB node* roles. The machine where the above mentioned Gradle command
 is run plays *Jepsen control node* role.
 
 === A reference script to build Kudu and run Jepsen tests
@@ -136,7 +134,7 @@ summary message below reports on 10 errors in 10 tests ran:
 21:41:42 Ran 10  tests containing 10 assertions.
 21:41:42 0 failures, 10 errors.
 ----
-To get more details, take a closer look at the output of `mvn clojure:run`
+To get more details, take a closer look at the output of `./gradlew -Pjepsen runJepsen`
 or at particular `jepsen.log` files in
 `$KUDU_HOME/java/kudu-jepsen/store/rw-register/<test_timestamp>` directory. A
 quick way to locate the corresponding section in the error log is to search for

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-jepsen/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-jepsen/pom.xml b/java/kudu-jepsen/pom.xml
deleted file mode 100644
index 535ffbc..0000000
--- a/java/kudu-jepsen/pom.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-// Licensed 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-jepsen</artifactId>
-    <name>Kudu Jepsen Tests</name>
-
-    <properties>
-        <!-- Jepsen tests require specific infrastructure and do not run as part of the
-             regular java tests.-->
-        <skipTests>true</skipTests>
-        <!-- List of Kudu Master nodes (e.g. "m0" or "m0,m1,m2") -->
-        <masterNodes>m0</masterNodes>
-        <!-- List of Kudu Tablet Server nodes (e.g. "t0,t1,t2") -->
-        <tserverNodes>t0,t1,t2,t3,t4</tserverNodes>
-        <!-- Path to the SSH key to access Kudu Master and
-             Tablet Server nodes as the 'root' user.  If left empty, the test
-             will try to use keys from the SSH agent, if any. -->
-        <sshKeyPath></sshKeyPath>
-        <!-- Number of iterations to run the test suite in cycle. -->
-        <iterNum>1</iterNum>
-    </properties>
-
-    <packaging>clojure</packaging>
-
-    <repositories>
-        <repository>
-            <id>clojars</id>
-            <url>http://clojars.org/repo/</url>
-        </repository>
-    </repositories>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.clojure</groupId>
-            <artifactId>clojure</artifactId>
-            <version>${clojure.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>jepsen</groupId>
-            <artifactId>jepsen</artifactId>
-            <version>${jepsen.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.clojure</groupId>
-            <artifactId>tools.cli</artifactId>
-            <version>${clojure.tools.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-api</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <!-- Jepsen imports its own slf4j-->
-            <exclusions>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-api</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.yetus</groupId>
-            <artifactId>audience-annotations</artifactId>
-            <version>${yetus.version}</version>
-            <optional>true</optional>
-        </dependency>
-
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-              <groupId>com.theoryinpractise</groupId>
-              <artifactId>clojure-maven-plugin</artifactId>
-              <version>${clojure-maven-plugin.version}</version>
-              <!-- Load maven extensions (like type and packaging handlers) for
-                   the clojure maven plugin-->
-              <extensions>true</extensions>
-              <configuration>
-                <script>src/utils/kudu_test_runner.clj</script>
-                <args>
-                  --masters=${masterNodes}
-                  --tservers=${tserverNodes}
-                  --ssh-key-path=${sshKeyPath}
-                  --iter-num=${iterNum}
-                </args>
-              </configuration>
-            </plugin>
-            <plugin>
-              <!-- Do not run the checkstyle plugin for clojure sources -->
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-checkstyle-plugin</artifactId>
-              <version>${maven-checkstyle-plugin.version}</version>
-              <executions>
-                <execution>
-                  <id>validate</id>
-                  <phase>none</phase>
-                </execution>
-              </executions>
-            </plugin>
-        </plugins>
-        <resources>
-          <resource>
-            <directory>resources</directory>
-            <filtering>false</filtering>
-            <includes>
-              <include>kudu.flags</include>
-              <include>ntp.conf.common</include>
-              <include>ntp.conf.server</include>
-            </includes>
-          </resource>
-        </resources>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-mapreduce/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-mapreduce/pom.xml b/java/kudu-mapreduce/pom.xml
deleted file mode 100644
index 126cfd9..0000000
--- a/java/kudu-mapreduce/pom.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-//
-// 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-mapreduce</artifactId>
-    <name>Kudu MapReduce bindings</name>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-            <version>${guava.version}</version>
-            <exclusions>
-                <!-- Ignore the transitive annotations libraries that are -->
-                <!-- not marked as optional in version 22.0+ -->
-                <exclusion>
-                    <groupId>*</groupId>
-                    <artifactId>*</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>com.stumbleupon</groupId>
-            <artifactId>async</artifactId>
-            <version>${async.version}</version>
-            <exclusions>
-                <!-- Explicitly exclude slf4j because async uses version ranges
-                     for the dependency -->
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-api</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-common</artifactId>
-            <version>${hadoop.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.hadoop</groupId>
-            <artifactId>hadoop-mapreduce-client-common</artifactId>
-            <version>${hadoop.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.yetus</groupId>
-            <artifactId>audience-annotations</artifactId>
-            <version>${yetus.version}</version>
-            <optional>true</optional>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>${commons-io.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>${log4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-failsafe-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-spark-tools/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-spark-tools/pom.xml b/java/kudu-spark-tools/pom.xml
deleted file mode 100644
index 29017ae..0000000
--- a/java/kudu-spark-tools/pom.xml
+++ /dev/null
@@ -1,203 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-//
-// 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-${spark.version.label}-tools_${scala.binary.version}</artifactId>
-    <name>Kudu Spark Tools</name>
-    <description>Collection of tools using Spark and Kudu</description>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client-tools</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-${spark.version.label}_${scala.binary.version}</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <!-- TODO(KUDU-2500): Spark uses reflection which requires the annotations at runtime. -->
-        <dependency>
-            <groupId>org.apache.yetus</groupId>
-            <artifactId>audience-annotations</artifactId>
-            <version>${yetus.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.databricks</groupId>
-            <artifactId>spark-avro_${scala.binary.version}</artifactId>
-            <version>${sparkavro.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-core_${scala.binary.version}</artifactId>
-            <version>${spark.version}</version>
-            <scope>provided</scope>
-            <exclusions>
-                <exclusion>
-                    <!-- make sure wrong scala version is not pulled in -->
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scala-library</artifactId>
-                </exclusion>
-                <exclusion>
-                    <!-- make sure wrong scala version is not pulled in -->
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scalap</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-sql_${scala.binary.version}</artifactId>
-            <version>${spark.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.scala-lang</groupId>
-            <artifactId>scala-library</artifactId>
-            <version>${scala.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-${spark.version.label}_${scala.binary.version}</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>${log4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.scalatest</groupId>
-            <artifactId>scalatest_${scala.binary.version}</artifactId>
-            <version>${scalatest.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <!-- set source dirs explicitly for the scalafmt plugin -->
-        <sourceDirectory>src/main/scala</sourceDirectory>
-        <testSourceDirectory>src/test/scala</testSourceDirectory>
-        <plugins>
-            <plugin>
-                <groupId>net.alchim31.maven</groupId>
-                <artifactId>scala-maven-plugin</artifactId>
-                <version>${scala-maven-plugin.version}</version>
-                <configuration>
-                    <charset>${project.build.sourceEncoding}</charset>
-                    <scalaVersion>${scala.version}</scalaVersion>
-                    <args>
-                        <!-- Emit warning and location for usages of features that should be imported explicitly. -->
-                        <arg>-feature</arg>
-                        <!-- Emit various static analysis warnings. -->
-                        <arg>-Xlint</arg>
-                    </args>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>scala-compile-first</id>
-                        <phase>process-resources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                            <goal>compile</goal>
-                        </goals>
-                    </execution>
-                    <execution>
-                        <id>scala-test-compile</id>
-                        <phase>process-test-resources</phase>
-                        <goals>
-                            <goal>testCompile</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-shade-plugin</artifactId>
-                <version>${maven-shade-plugin.version}</version>
-                <configuration>
-                    <artifactSet>
-                        <includes>
-                            <include>org.apache.kudu:kudu-client</include>
-                            <include>org.apache.kudu:kudu-client-tools</include>
-                            <include>org.apache.kudu:kudu-${spark.version.label}_${scala.binary.version}</include>
-                        </includes>
-                    </artifactSet>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.antipathy</groupId>
-                <artifactId>mvn-scalafmt</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-</project>


[3/5] kudu git commit: [tools] Add checking for row existence to the locate_row tool

Posted by gr...@apache.org.
[tools] Add checking for row existence to the locate_row tool

This enhances the `kudu tablet locate_row` tool to that, in addition to
locating which tablet a row with a given primary key would end up in, it
also will check if the row actually exists when the -check_row_existence
flag is supplied. If the row does not exist, the tool returns an error;
if it does, it prints the row.

Example invocation:

$ bin/kudu table locate_row localhost:7053 default.loadgen_auto_49c97e85f6aa43b5a89723c7eee396b0 "[0]" -check_row_existence
850632cee25b43368cb6f226b53e76eb
(int64 key=0, int32 int_val=1, string string_val="2.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

Change-Id: I760d3fbb2e30a3ffba7143d3b51da6f3fd62b034
Reviewed-on: http://gerrit.cloudera.org:8080/11684
Tested-by: Will Berkeley <wd...@gmail.com>
Reviewed-by: Alexey Serbin <as...@cloudera.com>


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/acf1dee8
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/acf1dee8
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/acf1dee8

Branch: refs/heads/master
Commit: acf1dee87ce347398ca86cc4959e38bf8794efe3
Parents: fa5a0db
Author: Will Berkeley <wd...@gmail.org>
Authored: Mon Oct 15 01:37:30 2018 -0700
Committer: Will Berkeley <wd...@gmail.com>
Committed: Tue Oct 16 19:41:54 2018 +0000

----------------------------------------------------------------------
 src/kudu/tools/kudu-admin-test.cc   | 70 ++++++++++++++++++++++++++++++++
 src/kudu/tools/tool_action_table.cc | 29 +++++++++++++
 2 files changed, 99 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/acf1dee8/src/kudu/tools/kudu-admin-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-admin-test.cc b/src/kudu/tools/kudu-admin-test.cc
index edb0c4d..d68fb4b 100644
--- a/src/kudu/tools/kudu-admin-test.cc
+++ b/src/kudu/tools/kudu-admin-test.cc
@@ -39,6 +39,7 @@
 #include "kudu/client/client.h"
 #include "kudu/client/schema.h"
 #include "kudu/client/shared_ptr.h"
+#include "kudu/client/write_op.h"
 #include "kudu/common/common.pb.h"
 #include "kudu/common/partial_row.h"
 #include "kudu/common/wire_protocol.pb.h"
@@ -79,8 +80,10 @@ DECLARE_int32(num_tablet_servers);
 using kudu::client::KuduClient;
 using kudu::client::KuduClientBuilder;
 using kudu::client::KuduColumnSchema;
+using kudu::client::KuduInsert;
 using kudu::client::KuduSchema;
 using kudu::client::KuduSchemaBuilder;
+using kudu::client::KuduTable;
 using kudu::client::KuduTableAlterer;
 using kudu::client::KuduTableCreator;
 using kudu::client::sp::shared_ptr;
@@ -1742,5 +1745,72 @@ TEST_F(AdminCliTest, TestLocateRowMore) {
   ASSERT_STR_CONTAINS(stderr,
                       "Wrong type during field extraction: expected object array");
 }
+
+TEST_F(AdminCliTest, TestLocateRowAndCheckRowPresence) {
+  FLAGS_num_tablet_servers = 1;
+  FLAGS_num_replicas = 1;
+
+  NO_FATALS(BuildAndStart());
+
+  // Grab list of tablet_ids from any tserver so we can check the output.
+  vector<TServerDetails*> tservers;
+  vector<string> tablet_ids;
+  AppendValuesFromMap(tablet_servers_, &tservers);
+  ListRunningTabletIds(tservers.front(),
+                       MonoDelta::FromSeconds(30),
+                       &tablet_ids);
+  ASSERT_EQ(1, tablet_ids.size());
+  const string& expected_tablet_id = tablet_ids[0];
+
+  // Test the case when the row does not exist.
+  string stdout, stderr;
+  Status s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kTableId,
+    "[0]",
+    "-check_row_existence",
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(stdout, expected_tablet_id);
+  ASSERT_STR_CONTAINS(stderr, "row does not exist");
+
+  // Insert row with key = 0.
+  client::sp::shared_ptr<KuduClient> client;
+  CreateClient(&client);
+  client::sp::shared_ptr<KuduTable> table;
+  ASSERT_OK(client->OpenTable(kTableId, &table));
+  unique_ptr<KuduInsert> insert(table->NewInsert());
+  auto* row = insert->mutable_row();
+  ASSERT_OK(row->SetInt32("key", 0));
+  ASSERT_OK(row->SetInt32("int_val", 12345));
+  ASSERT_OK(row->SetString("string_val", "hello"));
+  const string row_str = row->ToString();
+  auto session = client->NewSession();
+  ASSERT_OK(session->Apply(insert.release()));
+  ASSERT_OK(session->Flush());
+  ASSERT_OK(session->Close());
+
+  // Test the case when the row exists. Since the scan is done by a subprocess
+  // using a different client instance, it's possible the scan will not
+  // immediately retrieve the row even though the write has already succeeded,
+  // so we ASSERT_EVENTUALLY.
+  ASSERT_EVENTUALLY([&]() {
+    stdout.clear();
+    stderr.clear();
+    s = RunKuduTool({
+      "table",
+      "locate_row",
+      cluster_->master()->bound_rpc_addr().ToString(),
+      kTableId,
+      "[0]",
+      "-check_row_existence",
+    }, &stdout, &stderr);
+    ASSERT_TRUE(s.ok()) << ToolRunInfo(s, stdout, stderr);
+    ASSERT_STR_CONTAINS(stdout, expected_tablet_id);
+    ASSERT_STR_CONTAINS(stdout, row_str);
+  });
+}
 } // namespace tools
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/acf1dee8/src/kudu/tools/tool_action_table.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_table.cc b/src/kudu/tools/tool_action_table.cc
index 30ce6a6..2156dba 100644
--- a/src/kudu/tools/tool_action_table.cc
+++ b/src/kudu/tools/tool_action_table.cc
@@ -38,6 +38,7 @@
 #include "kudu/common/schema.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/stl_util.h"
+#include "kudu/gutil/strings/join.h"
 #include "kudu/gutil/strings/split.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/tools/tool_action.h"
@@ -46,6 +47,11 @@
 #include "kudu/util/status.h"
 
 DECLARE_string(tables);
+DEFINE_bool(check_row_existence, false,
+            "Also check for the existence of the row on the leader replica of "
+            "the tablet. If found, the full row will be printed; if not found, "
+            "an error message will be printed and the command will return a "
+            "non-zero status.");
 DEFINE_bool(modify_external_catalogs, true,
             "Whether to modify external catalogs, such as the Hive Metastore, "
             "when renaming or dropping a table.");
@@ -59,6 +65,7 @@ using client::KuduClient;
 using client::KuduClientBuilder;
 using client::KuduColumnSchema;
 using client::KuduPredicate;
+using client::KuduScanner;
 using client::KuduScanToken;
 using client::KuduScanTokenBuilder;
 using client::KuduTable;
@@ -268,6 +275,8 @@ Status LocateRow(const RunnerContext& context) {
   vector<KuduScanToken*> tokens;
   ElementDeleter deleter(&tokens);
   KuduScanTokenBuilder builder(table.get());
+  // In case we go on to check for existence of the row.
+  RETURN_NOT_OK(builder.SetSelection(KuduClient::ReplicaSelection::LEADER_ONLY));
   for (auto& predicate : predicates) {
     RETURN_NOT_OK(builder.AddConjunctPredicate(predicate.release()));
   }
@@ -282,6 +291,25 @@ Status LocateRow(const RunnerContext& context) {
         "all primary key columns specified but more than one matching tablet?");
   }
   cout << tokens[0]->tablet().id() << endl;
+
+  if (FLAGS_check_row_existence) {
+    KuduScanner* scanner_ptr;
+    RETURN_NOT_OK(tokens[0]->IntoKuduScanner(&scanner_ptr));
+    unique_ptr<KuduScanner> scanner(scanner_ptr);
+    vector<string> row_str;
+    RETURN_NOT_OK(ScanToStrings(scanner.get(), &row_str));
+    if (row_str.empty()) {
+      return Status::NotFound("row does not exist");
+    }
+    // There should be exactly one result, but if somehow there are more, print
+    // them all before returning an error.
+    cout << JoinStrings(row_str, "\n") << endl;
+    if (row_str.size() != 1) {
+      // This should be impossible.
+      return Status::IllegalState(
+          Substitute("expected 1 row but received $0", row_str.size()));
+    }
+  }
   return Status::OK();
 }
 
@@ -355,6 +383,7 @@ unique_ptr<Mode> BuildTableMode() {
       .AddRequiredParameter({ kKeyArg,
                               "String representation of the row's primary key "
                               "as a JSON array" })
+      .AddOptionalParameter("check_row_existence")
       .Build();
 
   unique_ptr<Action> rename_column =


[2/5] kudu git commit: [tools] Add locate row tool

Posted by gr...@apache.org.
[tools] Add locate row tool

Sometimes while debugging I find it frustrating that it's very difficult
to tell what tablet a particular row belongs to. This basic tool
provides a way to find out, by providing a simple interface that accepts
a primary key as a JSON array and will print out the tablet id of the
corresponding tablet, or an error if there is no such tablet.

For example, with a table created like

CREATE TABLE test (
  key0 STRING NOT NULL,
  key1 INT32 NOT NULL,
  PRIMARY KEY(key0, key1)
)

an invocation of the tool looks like

$ kudu table locate_row localhost:7053 test "[\"foo\", 2]"

The choice of a JSON array is a compromise between CSV, which is easiest
and fastest to type in the common case, and a verbose JSON object like
{ "key0" : "foo", "key1" : 2 }, which is most explicit but long and
difficult to type on the command line. A JSON array has the benefit of
having well-defined escaping rules and formatting while being almost as
easy to type out as CSV.

A note about tests: it's difficult to verify the answer of the tool
independently. However, the implementation is just scan tokens, so the
tablet-finding logic should be well-exercised by lots of other client
tests. Consequently, the tests focus on error cases and sanity checks.

Change-Id: Idcdcf10bfe6b9df686e86b7134e8634fc0efaac3
Reviewed-on: http://gerrit.cloudera.org:8080/11666
Reviewed-by: Alexey Serbin <as...@cloudera.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/fa5a0db5
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/fa5a0db5
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/fa5a0db5

Branch: refs/heads/master
Commit: fa5a0db5a21c0f9d6554857ce6641b95b670f25e
Parents: e3b1e05
Author: Will Berkeley <wd...@gmail.org>
Authored: Fri Oct 12 01:20:12 2018 -0700
Committer: Will Berkeley <wd...@gmail.com>
Committed: Tue Oct 16 19:39:06 2018 +0000

----------------------------------------------------------------------
 src/kudu/tools/kudu-admin-test.cc   | 264 +++++++++++++++++++++++++++++++
 src/kudu/tools/tool_action_table.cc | 128 ++++++++++++++-
 2 files changed, 391 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/fa5a0db5/src/kudu/tools/kudu-admin-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-admin-test.cc b/src/kudu/tools/kudu-admin-test.cc
index 046e8db..edb0c4d 100644
--- a/src/kudu/tools/kudu-admin-test.cc
+++ b/src/kudu/tools/kudu-admin-test.cc
@@ -21,6 +21,7 @@
 #include <cstdio>
 #include <deque>
 #include <iterator>
+#include <limits>
 #include <memory>
 #include <ostream>
 #include <string>
@@ -48,6 +49,7 @@
 #include "kudu/gutil/gscoped_ptr.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/strings/split.h"
+#include "kudu/gutil/strings/strip.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/integration-tests/cluster_itest_util.h"
 #include "kudu/integration-tests/cluster_verifier.h"
@@ -1478,5 +1480,267 @@ TEST_F(AdminCliTest, TestDescribeTable) {
       ")\n"
       "REPLICAS 1");
 }
+
+TEST_F(AdminCliTest, TestLocateRow) {
+  FLAGS_num_tablet_servers = 1;
+  FLAGS_num_replicas = 1;
+
+  NO_FATALS(BuildAndStart());
+
+  // Test an OK case. Not much going on here since the table has only one
+  // tablet, which covers the whole universe.
+  string stdout, stderr;
+  Status s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kTableId,
+    "[-1]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.ok()) << ToolRunInfo(s, stdout, stderr);
+
+  // Grab list of tablet_ids from any tserver and check the output.
+  vector<TServerDetails*> tservers;
+  vector<string> tablet_ids;
+  AppendValuesFromMap(tablet_servers_, &tservers);
+  ListRunningTabletIds(tservers.front(),
+                       MonoDelta::FromSeconds(30),
+                       &tablet_ids);
+  ASSERT_EQ(1, tablet_ids.size());
+  ASSERT_STR_CONTAINS(stdout, tablet_ids[0]);
+
+  // Test a couple of error cases.
+  // String instead of int.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kTableId,
+    "[\"foo\"]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError());
+  ASSERT_STR_CONTAINS(stderr, "unable to parse");
+
+  // Float instead of int.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kTableId,
+    "[1.2]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError());
+  ASSERT_STR_CONTAINS(stderr, "unable to parse");
+
+  // Overflow (recall the key is INT32).
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kTableId,
+    Substitute("[$0]", std::to_string(std::numeric_limits<int64_t>::max()))
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError());
+  ASSERT_STR_CONTAINS(stderr, "out of range");
+}
+
+TEST_F(AdminCliTest, TestLocateRowMore) {
+  FLAGS_num_tablet_servers = 1;
+  FLAGS_num_replicas = 1;
+
+  NO_FATALS(BuildAndStart());
+
+  // Make a complex schema with multiple columns in the primary key, hash and
+  // range partitioning, and non-covered ranges.
+  const string kAnotherTableId = "TestAnotherTable";
+  KuduSchema schema;
+
+  // Build the schema.
+  KuduSchemaBuilder builder;
+  builder.AddColumn("key_hash")->Type(KuduColumnSchema::STRING)->NotNull();
+  builder.AddColumn("key_range")->Type(KuduColumnSchema::INT32)->NotNull();
+  builder.SetPrimaryKey({ "key_hash", "key_range" });
+  ASSERT_OK(builder.Build(&schema));
+
+  // Set up partitioning and create the table.
+  unique_ptr<KuduPartialRow> lower_bound0(schema.NewRow());
+  ASSERT_OK(lower_bound0->SetInt32("key_range", 0));
+  unique_ptr<KuduPartialRow> upper_bound0(schema.NewRow());
+  ASSERT_OK(upper_bound0->SetInt32("key_range", 1));
+  unique_ptr<KuduPartialRow> lower_bound1(schema.NewRow());
+  ASSERT_OK(lower_bound1->SetInt32("key_range", 2));
+  unique_ptr<KuduPartialRow> upper_bound1(schema.NewRow());
+  ASSERT_OK(upper_bound1->SetInt32("key_range", 3));
+  unique_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
+  ASSERT_OK(table_creator->table_name(kAnotherTableId)
+           .schema(&schema)
+           .add_hash_partitions({ "key_hash" }, 2)
+           .set_range_partition_columns({ "key_range" })
+           .add_range_partition(lower_bound0.release(), upper_bound0.release())
+           .add_range_partition(lower_bound1.release(), upper_bound1.release())
+           .num_replicas(FLAGS_num_replicas)
+           .Create());
+
+  vector<TServerDetails*> tservers;
+  vector<string> tablet_ids;
+  AppendValuesFromMap(tablet_servers_, &tservers);
+  ListRunningTabletIds(tservers.front(),
+                       MonoDelta::FromSeconds(30),
+                       &tablet_ids);
+  std::unordered_set<string> tablet_id_set(tablet_ids.begin(), tablet_ids.end());
+
+  // Since there isn't a great alternative way to validate the answer the tool
+  // gives, and the scan token code underlying the implementation is extensively
+  // tested, we won't overexert ourselves checking correctness, and instead just
+  // do sanity checks and tool usability checks.
+  string stdout, stderr;
+  Status s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[\"foo\",0]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.ok()) << ToolRunInfo(s, stdout, stderr);
+  StripWhiteSpace(&stdout);
+  const auto tablet_id_for_0 = stdout;
+  ASSERT_TRUE(ContainsKey(tablet_id_set, tablet_id_for_0))
+      << "expected to find tablet id " << tablet_id_for_0;
+
+  // A row in a different range partition should be in a different tablet.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[\"foo\",2]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.ok()) << ToolRunInfo(s, stdout, stderr);
+  StripWhiteSpace(&stdout);
+  const auto tablet_id_for_2 = stdout;
+  ASSERT_TRUE(ContainsKey(tablet_id_set, tablet_id_for_0))
+      << "expected to find tablet id " << tablet_id_for_2;
+  ASSERT_NE(tablet_id_for_0, tablet_id_for_2);
+
+  // Test locating a row lying in a non-covered range.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[\"foo\",1]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(stderr, "row does not belong to any currently existing tablet");
+
+  // Test providing a missing or incomplete primary key.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(
+      stderr,
+      "wrong number of key columns specified: expected 2 but received 0");
+
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[\"foo\"]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(
+      stderr,
+      "wrong number of key columns specified: expected 2 but received 1");
+
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[\"foo\",]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(
+      stderr,
+      "JSON text is corrupt");
+
+  // Test providing too many key column values.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[\"foo\",2,\"bar\"]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(
+      stderr,
+      "wrong number of key columns specified: expected 2 but received 3");
+
+  // Test providing an invalid value for a key column when there's multiple
+  // key columns.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "[\"foo\",\"bar\"]"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(stderr, "unable to parse");
+
+  // Test providing bad json.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "["
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(stderr, "JSON text is corrupt");
+
+  // Test providing valid JSON that's not an array.
+  stdout.clear();
+  stderr.clear();
+  s = RunKuduTool({
+    "table",
+    "locate_row",
+    cluster_->master()->bound_rpc_addr().ToString(),
+    kAnotherTableId,
+    "{ \"key_hash\" : \"foo\", \"key_range\" : 2 }"
+  }, &stdout, &stderr);
+  ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+  ASSERT_STR_CONTAINS(stderr,
+                      "Wrong type during field extraction: expected object array");
+}
 } // namespace tools
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/fa5a0db5/src/kudu/tools/tool_action_table.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_table.cc b/src/kudu/tools/tool_action_table.cc
index 33d6eb7..30ce6a6 100644
--- a/src/kudu/tools/tool_action_table.cc
+++ b/src/kudu/tools/tool_action_table.cc
@@ -25,12 +25,15 @@
 
 #include <gflags/gflags.h>
 #include <gflags/gflags_declare.h>
+#include <rapidjson/document.h>
 
 #include "kudu/client/client-test-util.h"
 #include "kudu/client/client.h"
 #include "kudu/client/replica_controller-internal.h"
+#include "kudu/client/scan_predicate.h"
 #include "kudu/client/schema.h"
 #include "kudu/client/shared_ptr.h"
+#include "kudu/client/value.h"
 #include "kudu/common/partition.h"
 #include "kudu/common/schema.h"
 #include "kudu/gutil/map-util.h"
@@ -39,6 +42,7 @@
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/tools/tool_action.h"
 #include "kudu/tools/tool_action_common.h"
+#include "kudu/util/jsonreader.h"
 #include "kudu/util/status.h"
 
 DECLARE_string(tables);
@@ -53,6 +57,8 @@ namespace tools {
 
 using client::KuduClient;
 using client::KuduClientBuilder;
+using client::KuduColumnSchema;
+using client::KuduPredicate;
 using client::KuduScanToken;
 using client::KuduScanTokenBuilder;
 using client::KuduTable;
@@ -64,6 +70,7 @@ using std::string;
 using std::unique_ptr;
 using std::vector;
 using strings::Split;
+using strings::Substitute;
 
 // This class only exists so that ListTables() can easily be friended by
 // KuduReplica, KuduReplica::Data, and KuduClientBuilder.
@@ -98,7 +105,7 @@ class TableLister {
         for (const auto* replica : token->tablet().replicas()) {
           const bool is_voter = ReplicaController::is_voter(*replica);
           const bool is_leader = replica->is_leader();
-          cout << strings::Substitute("    $0 $1 $2:$3",
+          cout << Substitute("    $0 $1 $2:$3",
               is_leader ? "L" : (is_voter ? "V" : "N"), replica->ts().uuid(),
               replica->ts().hostname(), replica->ts().port()) << endl;
         }
@@ -116,6 +123,7 @@ const char* const kTableNameArg = "table_name";
 const char* const kNewTableNameArg = "new_table_name";
 const char* const kColumnNameArg = "column_name";
 const char* const kNewColumnNameArg = "new_column_name";
+const char* const kKeyArg = "primary_key";
 
 Status CreateKuduClient(const RunnerContext& context,
                         client::sp::shared_ptr<KuduClient>* client) {
@@ -176,6 +184,107 @@ Status DescribeTable(const RunnerContext& context) {
   return Status::OK();
 }
 
+Status LocateRow(const RunnerContext& context) {
+  client::sp::shared_ptr<KuduClient> client;
+  RETURN_NOT_OK(CreateKuduClient(context, &client));
+
+  const string& table_name = FindOrDie(context.required_args, kTableNameArg);
+  client::sp::shared_ptr<KuduTable> table;
+  RETURN_NOT_OK(client->OpenTable(table_name, &table));
+
+  // Create an equality predicate for each primary key column.
+  const string& row_str = FindOrDie(context.required_args, kKeyArg);
+  JsonReader reader(row_str);
+  RETURN_NOT_OK(reader.Init());
+  vector<const rapidjson::Value*> values;
+  RETURN_NOT_OK(reader.ExtractObjectArray(reader.root(), nullptr, &values));
+
+  const auto& schema = table->schema();
+  vector<int> key_indexes;
+  schema.GetPrimaryKeyColumnIndexes(&key_indexes);
+  if (values.size() != key_indexes.size()) {
+    return Status::InvalidArgument(
+        Substitute("wrong number of key columns specified: expected $0 but received $1",
+                   key_indexes.size(),
+                   values.size()));
+  }
+
+  vector<unique_ptr<KuduPredicate>> predicates;
+  for (int i = 0; i < values.size(); i++) {
+    const auto key_index = key_indexes[i];
+    const auto& column = schema.Column(key_index);
+    const auto& col_name = column.name();
+    const auto type = column.type();
+    switch (type) {
+      case KuduColumnSchema::INT8:
+      case KuduColumnSchema::INT16:
+      case KuduColumnSchema::INT32:
+      case KuduColumnSchema::INT64:
+      case KuduColumnSchema::UNIXTIME_MICROS: {
+        int64_t value;
+        RETURN_NOT_OK_PREPEND(
+            reader.ExtractInt64(values[i], nullptr, &value),
+            Substitute("unable to parse value for column '$0' of type $1",
+                       col_name,
+                       KuduColumnSchema::DataTypeToString(type)));
+        predicates.emplace_back(
+            table->NewComparisonPredicate(col_name,
+                                          client::KuduPredicate::EQUAL,
+                                          client::KuduValue::FromInt(value)));
+        break;
+      }
+      case KuduColumnSchema::BINARY:
+      case KuduColumnSchema::STRING: {
+        string value;
+        RETURN_NOT_OK_PREPEND(
+            reader.ExtractString(values[i], nullptr, &value),
+            Substitute("unable to parse value for column '$0' of type $1",
+                       col_name,
+                       KuduColumnSchema::DataTypeToString(type)));
+        predicates.emplace_back(
+            table->NewComparisonPredicate(col_name,
+                                          client::KuduPredicate::EQUAL,
+                                          client::KuduValue::CopyString(value)));
+        break;
+      }
+      case KuduColumnSchema::DECIMAL:
+        return Status::NotSupported(
+            Substitute("unsupported type $0 for key column '$1': "
+                       "$0 key columns are not supported by this tool",
+                       KuduColumnSchema::DataTypeToString(type),
+                       col_name));
+      default:
+        return Status::NotSupported(
+            Substitute("unsupported type $0 for key column '$1': "
+                       "is this tool out of date?",
+                       KuduColumnSchema::DataTypeToString(type),
+                       col_name));
+    }
+  }
+
+  // Find the tablet by constructing scan tokens for a scan with equality
+  // predicates on all key columns. At most one tablet will match, so there
+  // will be at most one token, and we can report the id of its tablet.
+  vector<KuduScanToken*> tokens;
+  ElementDeleter deleter(&tokens);
+  KuduScanTokenBuilder builder(table.get());
+  for (auto& predicate : predicates) {
+    RETURN_NOT_OK(builder.AddConjunctPredicate(predicate.release()));
+  }
+  RETURN_NOT_OK(builder.Build(&tokens));
+  if (tokens.empty()) {
+    // Must be in a non-covered range partition.
+    return Status::NotFound("row does not belong to any currently existing tablet");
+  }
+  if (tokens.size() > 1) {
+    // This should be impossible.
+    return Status::IllegalState(
+        "all primary key columns specified but more than one matching tablet?");
+  }
+  cout << tokens[0]->tablet().id() << endl;
+  return Status::OK();
+}
+
 Status RenameTable(const RunnerContext& context) {
   const string& table_name = FindOrDie(context.required_args, kTableNameArg);
   const string& new_table_name = FindOrDie(context.required_args, kNewTableNameArg);
@@ -232,6 +341,22 @@ unique_ptr<Mode> BuildTableMode() {
       .AddOptionalParameter("list_tablets")
       .Build();
 
+  unique_ptr<Action> locate_row =
+      ActionBuilder("locate_row", &LocateRow)
+      .Description("Locate which tablet a row belongs to")
+      .ExtraDescription("Provide the primary key as a JSON array of primary "
+                        "key values, e.g. '[1, \"foo\", 2, \"bar\"]'. The "
+                        "output will be the tablet id associated with the row "
+                        "key. If there is no such tablet, an error message "
+                        "will be printed and the command will return a "
+                        "non-zero status")
+      .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+      .AddRequiredParameter({ kTableNameArg, "Name of the table to look up against" })
+      .AddRequiredParameter({ kKeyArg,
+                              "String representation of the row's primary key "
+                              "as a JSON array" })
+      .Build();
+
   unique_ptr<Action> rename_column =
       ActionBuilder("rename_column", &RenameColumn)
       .Description("Rename a column")
@@ -255,6 +380,7 @@ unique_ptr<Mode> BuildTableMode() {
       .AddAction(std::move(delete_table))
       .AddAction(std::move(describe_table))
       .AddAction(std::move(list_tables))
+      .AddAction(std::move(locate_row))
       .AddAction(std::move(rename_column))
       .AddAction(std::move(rename_table))
       .Build();


[4/5] kudu git commit: [Java] Remove the Maven Build

Posted by gr...@apache.org.
http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/kudu-spark/pom.xml
----------------------------------------------------------------------
diff --git a/java/kudu-spark/pom.xml b/java/kudu-spark/pom.xml
deleted file mode 100644
index 56196f5..0000000
--- a/java/kudu-spark/pom.xml
+++ /dev/null
@@ -1,177 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-// Licensed 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.kudu</groupId>
-        <artifactId>kudu-parent</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>kudu-${spark.version.label}_${scala.binary.version}</artifactId>
-    <name>Kudu Spark Bindings</name>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <!-- TODO(KUDU-2500): Spark uses reflection which requires the annotations at runtime. -->
-        <dependency>
-            <groupId>org.apache.yetus</groupId>
-            <artifactId>audience-annotations</artifactId>
-            <version>${yetus.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-core_${scala.binary.version}</artifactId>
-            <version>${spark.version}</version>
-            <scope>provided</scope>
-            <exclusions>
-                <exclusion>
-                    <!-- make sure wrong scala version is not pulled in -->
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scala-library</artifactId>
-                </exclusion>
-                <exclusion>
-                    <!-- make sure wrong scala version is not pulled in -->
-                    <groupId>org.scala-lang</groupId>
-                    <artifactId>scalap</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-sql_${scala.binary.version}</artifactId>
-            <version>${spark.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.scala-lang</groupId>
-            <artifactId>scala-library</artifactId>
-            <version>${scala.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.scala-lang</groupId>
-            <artifactId>scalap</artifactId>
-            <version>${scala.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.kudu</groupId>
-            <artifactId>kudu-client</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-          </dependency>
-          <dependency>
-            <groupId>org.apache.spark</groupId>
-            <artifactId>spark-sql_${scala.binary.version}</artifactId>
-            <version>${spark.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-          </dependency>
-          <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.scalatest</groupId>
-            <artifactId>scalatest_${scala.binary.version}</artifactId>
-            <version>${scalatest.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <!-- Set source dirs explicitly for the scalafmt plugin. -->
-        <sourceDirectory>src/main/scala</sourceDirectory>
-        <testSourceDirectory>src/test/scala</testSourceDirectory>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-            </plugin>
-
-            <plugin>
-                <groupId>net.alchim31.maven</groupId>
-                <artifactId>scala-maven-plugin</artifactId>
-                <version>${scala-maven-plugin.version}</version>
-                <configuration>
-                    <charset>${project.build.sourceEncoding}</charset>
-                    <scalaVersion>${scala.version}</scalaVersion>
-                    <args>
-                        <!-- Emit warning and location for usages of features that should be imported explicitly. -->
-                        <arg>-feature</arg>
-                        <!-- Emit various static analysis warnings. -->
-                        <arg>-Xlint</arg>
-                    </args>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>scala-compile-first</id>
-                        <phase>process-resources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                            <goal>compile</goal>
-                        </goals>
-                    </execution>
-                    <execution>
-                        <id>scala-test-compile</id>
-                        <phase>process-test-resources</phase>
-                        <goals>
-                            <goal>testCompile</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-surefire-plugin</artifactId>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-shade-plugin</artifactId>
-                <version>${maven-shade-plugin.version}</version>
-                <configuration>
-                    <artifactSet>
-                        <includes>
-                            <include>org.apache.kudu:kudu-client</include>
-                            <include>com.stumbleupon:async</include>
-                        </includes>
-                    </artifactSet>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.antipathy</groupId>
-                <artifactId>mvn-scalafmt</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/kudu/blob/8c184e2a/java/pom.xml
----------------------------------------------------------------------
diff --git a/java/pom.xml b/java/pom.xml
deleted file mode 100644
index ce13307..0000000
--- a/java/pom.xml
+++ /dev/null
@@ -1,368 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-//
-// 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <groupId>org.apache.kudu</groupId>
-    <artifactId>kudu-parent</artifactId>
-    <version>1.9.0-SNAPSHOT</version>
-    <packaging>pom</packaging>
-
-    <!-- inherit from the ASF POM for distribution management -->
-    <parent>
-        <groupId>org.apache</groupId>
-        <artifactId>apache</artifactId>
-        <version>18</version>
-    </parent>
-
-    <name>Kudu</name>
-
-    <description>
-        Kudu.
-    </description>
-
-    <!-- Properties Management -->
-    <properties>
-        <!-- Platform encoding override -->
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
-        <!-- Maven plugins -->
-        <clojure-maven-plugin.version>1.8.1</clojure-maven-plugin.version>
-        <maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>
-        <maven-assembly-plugin.version>3.1.0</maven-assembly-plugin.version>
-        <maven-checkstyle-plugin.version>3.0.0</maven-checkstyle-plugin.version>
-        <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
-        <maven-enforcer-plugin.version>1.4.1</maven-enforcer-plugin.version>
-        <!-- Note: Bumping maven-failsafe-plugin to 2.19+ (2.21) breaks the integration tests due to shading issues -->
-        <maven-failsafe-plugin.version>2.18</maven-failsafe-plugin.version>
-        <maven-os-plugin.version>1.5.0.Final</maven-os-plugin.version>
-        <maven-jar-plugin.version>3.1.0</maven-jar-plugin.version>
-        <maven-javadoc-plugin.version>3.0.0</maven-javadoc-plugin.version>
-        <maven-protoc-plugin.version>0.5.1</maven-protoc-plugin.version>
-        <maven-shade-plugin.version>3.1.1</maven-shade-plugin.version>
-        <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
-        <scala-maven-plugin.version>3.3.2</scala-maven-plugin.version>
-        <mvn-scalafmt-plugin.version>0.7_1.4.0</mvn-scalafmt-plugin.version>
-
-        <!-- Library dependencies -->
-        <async.version>1.4.1</async.version>
-        <avro.version>1.8.2</avro.version>
-        <clojure.tools.version>0.3.5</clojure.tools.version>
-        <clojure.version>1.9.0</clojure.version>
-        <commons-io.version>2.6</commons-io.version>
-        <flume.version>1.8.0</flume.version>
-
-        <guava.version>26.0-android</guava.version>
-        <hadoop.version>3.1.1</hadoop.version>
-        <hamcrest-core.version>1.3</hamcrest-core.version>
-        <hive.version>2.3.3</hive.version>
-        <jepsen.version>0.1.5</jepsen.version>
-        <jsr305.version>3.0.2</jsr305.version>
-        <junit.version>4.12</junit.version>
-        <log4j.version>1.2.17</log4j.version>
-        <mockito-core.version>2.22.0</mockito-core.version>
-        <murmur.version>1.0.0</murmur.version>
-        <netty.version>3.10.6.Final</netty.version>
-        <parquet.version>1.10.0</parquet.version>
-        <protobuf.version>3.6.1</protobuf.version>
-        <scopt.version>3.7.0</scopt.version>
-        <slf4j.version>1.7.25</slf4j.version>
-        <sparkavro.version>4.0.0</sparkavro.version>
-        <yetus.version>0.8.0</yetus.version>
-
-        <!-- Scala Library dependencies -->
-        <scala.binary.version>2.11</scala.binary.version>
-        <scala.version>2.11.12</scala.version>
-        <scalatest.version>3.0.5</scalatest.version>
-        <spark.version>2.3.2</spark.version>
-        <spark.version.label>spark2</spark.version.label>
-
-        <!-- Misc variables -->
-        <testdata.dir>${project.build.directory}/testdata</testdata.dir>
-        <testArgLine>-enableassertions -Xmx1900m
-            -Djava.security.egd=file:/dev/urandom -Djava.net.preferIPv4Stack=true
-            -Djava.awt.headless=true
-        </testArgLine>
-    </properties>
-
-    <modules>
-        <module>kudu-backup</module>
-        <module>kudu-client-tools</module>
-        <module>kudu-client</module>
-        <module>kudu-flume-sink</module>
-        <module>kudu-hive</module>
-        <module>kudu-mapreduce</module>
-        <module>kudu-spark-tools</module>
-        <module>kudu-spark</module>
-    </modules>
-
-    <build>
-        <pluginManagement>
-            <plugins>
-                <plugin>
-                    <groupId>org.apache.maven.plugins</groupId>
-                    <artifactId>maven-enforcer-plugin</artifactId>
-                    <version>${maven-enforcer-plugin.version}</version>
-                    <configuration>
-                        <rules>
-                            <requireMavenVersion>
-                                <version>[3.0.2,)</version>
-                            </requireMavenVersion>
-                            <requireJavaVersion>
-                                <version>[1.7,)</version>
-                            </requireJavaVersion>
-                        </rules>
-                    </configuration>
-                </plugin>
-                <plugin>
-                    <groupId>org.apache.maven.plugins</groupId>
-                    <artifactId>maven-failsafe-plugin</artifactId>
-                    <version>${maven-failsafe-plugin.version}</version>
-                    <executions>
-                        <execution>
-                            <goals>
-                                <goal>integration-test</goal>
-                                <goal>verify</goal>
-                            </goals>
-                        </execution>
-                    </executions>
-                    <configuration>
-                        <failIfNoTests>false</failIfNoTests>
-                        <reuseForks>false</reuseForks>
-                        <redirectTestOutputToFile>true</redirectTestOutputToFile>
-                        <argLine>${testArgLine}</argLine>
-                        <systemPropertyVariables>
-                            <kuduBinDir>${project.basedir}/../../build/latest/bin</kuduBinDir>
-                        </systemPropertyVariables>
-                    </configuration>
-                </plugin>
-                <plugin>
-                    <groupId>org.apache.maven.plugins</groupId>
-                    <artifactId>maven-surefire-plugin</artifactId>
-                    <version>${maven-surefire-plugin.version}</version>
-                    <configuration>
-                        <failIfNoTests>false</failIfNoTests>
-                        <reuseForks>false</reuseForks>
-                        <redirectTestOutputToFile>true</redirectTestOutputToFile>
-                        <argLine>${testArgLine}</argLine>
-                        <systemPropertyVariables>
-                            <kuduBinDir>${project.basedir}/../../build/latest/bin</kuduBinDir>
-                        </systemPropertyVariables>
-                    </configuration>
-                </plugin>
-                <plugin>
-                    <groupId>org.apache.maven.plugins</groupId>
-                    <artifactId>maven-shade-plugin</artifactId>
-                    <version>${maven-shade-plugin.version}</version>
-                    <configuration>
-                        <shadeTestJar>true</shadeTestJar>
-                    </configuration>
-                    <executions>
-                        <execution>
-                            <phase>package</phase>
-                            <goals>
-                                <goal>shade</goal>
-                            </goals>
-                        </execution>
-                    </executions>
-                </plugin>
-                <plugin>
-                    <groupId>org.antipathy</groupId>
-                    <artifactId>mvn-scalafmt</artifactId>
-                    <version>${mvn-scalafmt-plugin.version}</version>
-                    <configuration>
-                        <configLocation>.scalafmt.conf</configLocation>
-                    </configuration>
-                    <executions>
-                        <execution>
-                            <phase>validate</phase>
-                            <goals>
-                                <goal>format</goal>
-                            </goals>
-                        </execution>
-                    </executions>
-                </plugin>
-            </plugins>
-        </pluginManagement>
-
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-enforcer-plugin</artifactId>
-                <inherited>false</inherited>
-                <executions>
-                    <execution>
-                        <id>clean</id>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
-                        <phase>pre-clean</phase>
-                    </execution>
-                    <execution>
-                        <id>default</id>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
-                        <phase>validate</phase>
-                    </execution>
-                    <execution>
-                        <id>site</id>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
-                        <phase>pre-site</phase>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <version>${maven-compiler-plugin.version}</version>
-                <configuration>
-                    <source>1.7</source>
-                    <target>1.7</target>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <version>${maven-jar-plugin.version}</version>
-                <executions>
-                    <execution>
-                        <phase>prepare-package</phase>
-                        <goals>
-                            <goal>test-jar</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-antrun-plugin</artifactId>
-                <version>${maven-antrun-plugin.version}</version>
-                <executions>
-                    <execution>
-                        <phase>test-compile</phase>
-                        <configuration>
-                            <target>
-                                <delete dir="${testdata.dir}"/>
-                                <mkdir dir="${testdata.dir}"/>
-                            </target>
-                        </configuration>
-                        <goals>
-                            <goal>run</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
-                <version>${maven-javadoc-plugin.version}</version>
-                <configuration>
-                    <maxmemory>2048m</maxmemory>
-                    <notimestamp>true</notimestamp>
-                    <doclet>
-                        org.apache.yetus.audience.tools.IncludePublicAnnotationsStandardDoclet
-                    </doclet>
-                    <docletArtifact>
-                        <groupId>org.apache.yetus</groupId>
-                        <artifactId>audience-annotations-jdiff</artifactId>
-                        <version>${yetus.version}</version>
-                    </docletArtifact>
-                    <name>User API</name>
-                    <description>The Kudu Application Programmer's API</description>
-                    <excludePackageNames>
-                      com.google:org.apache.kudu.cfile:org.apache.kudu.consensus:org.apache.kudu.log:org.apache.kudu.master:org.apache.kudu.rpc:org.apache.kudu.server:org.apache.kudu.tablet:org.apache.kudu.tserver:org.apache.kudu.hive
-                    </excludePackageNames>
-                    <includeDependencySources>false</includeDependencySources>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-checkstyle-plugin</artifactId>
-                <version>${maven-checkstyle-plugin.version}</version>
-                <dependencies>
-                    <dependency>
-                        <groupId>com.puppycrawl.tools</groupId>
-                        <artifactId>checkstyle</artifactId>
-                        <version>6.19</version>
-                    </dependency>
-                </dependencies>
-                <executions>
-                    <execution>
-                        <id>validate</id>
-                        <phase>validate</phase>
-                        <configuration>
-                            <configLocation>kudu_style.xml</configLocation>
-                            <suppressionsLocation>checkstyle_suppressions.xml</suppressionsLocation>
-                            <suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
-                            <encoding>UTF-8</encoding>
-                            <consoleOutput>true</consoleOutput>
-                            <failsOnError>false</failsOnError>
-                        </configuration>
-                        <goals>
-                            <goal>check</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <!-- Enforce that all of our code uses Java 7 and not Java 8 APIs. -->
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>animal-sniffer-maven-plugin</artifactId>
-                <version>1.16</version>
-                <configuration>
-                    <signature>
-                        <groupId>org.codehaus.mojo.signature</groupId>
-                        <artifactId>java17</artifactId>
-                        <version>1.0</version>
-                    </signature>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>check-java7-apis</id>
-                        <phase>process-classes</phase>
-                        <goals>
-                            <goal>check</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <profiles>
-        <!-- Build the jepsen test for Kudu.
-
-             Disabled by default since Java 8 and maven >= 3.3.6 is required to
-             build the kudu-jepsen artifact.  To enable, add '-Pjepsen'
-             to the maven command line. -->
-        <profile>
-            <id>jepsen</id>
-            <modules>
-                <module>kudu-jepsen</module>
-            </modules>
-        </profile>
-    </profiles>
-</project>