Merge branch 'stable-3.3'

* stable-3.3:
  Align testcontainers with v1.15 in Gerrit
  Add zookeeper-refdb jar compiled with zookeeper 3.5.x
  Add SSL support for Zookeeper client
  Jenkinsfile: use gerrit-ci-library pipeline for plugin validation
  Revert "Add SSL support for Zookeeper client"
  Add SSL support for Zookeeper client

Change-Id: I7736637c9467e8ad3ba3b975abc8dae73aec07bf
diff --git a/BUILD b/BUILD
index d5d34bf..f6dd094 100644
--- a/BUILD
+++ b/BUILD
@@ -7,6 +7,28 @@
 )
 
 gerrit_plugin(
+    name = "zookeeper-refdb-zk-3.5",
+    srcs = glob(["src/main/java/**/*.java"]),
+    manifest_entries = [
+        "Gerrit-PluginName: zookeeper-refdb",
+        "Gerrit-Module: com.googlesource.gerrit.plugins.validation.dfsrefdb.zookeeper.ZkValidationModule",
+        "Implementation-Title: zookeeper ref-db plugin",
+        "Implementation-URL: https://review.gerrithub.io/admin/repos/GerritForge/plugins_zookeeper",
+    ],
+    resources = glob(["src/main/resources/**/*"]),
+    dir_name = "zookeeper-refdb",
+    deps = [
+        "@curator-client//jar",
+        "@curator-framework//jar",
+        "@curator-recipes//jar",
+        "@global-refdb//jar",
+        "@zookeeper_3.5//jar",
+        "@zookeeper-jute_3.5//jar",
+        "@netty-all_3.5//jar",
+    ],
+)
+
+gerrit_plugin(
     name = "zookeeper-refdb",
     srcs = glob(["src/main/java/**/*.java"]),
     manifest_entries = [
@@ -21,7 +43,7 @@
         "@curator-framework//jar",
         "@curator-recipes//jar",
         "@global-refdb//jar",
-        "@zookeeper//jar",
+        "@zookeeper_3.4//jar",
     ],
 )
 
@@ -43,7 +65,7 @@
     testonly = 1,
     visibility = ["//visibility:public"],
     exports = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
-        ":zookeeper-refdb__plugin",
+        ":zookeeper-refdb-zk-3.5__plugin",
         "@curator-framework//jar",
         "@curator-recipes//jar",
         "@curator-test//jar",
diff --git a/Jenkinsfile b/Jenkinsfile
index 5aa8082..25b721e 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,56 +1,2 @@
-pipeline {
-    options { skipDefaultCheckout true }
-    agent { label 'bazel-debian' }
-    stages {
-        stage('Checkout') {
-            steps {
-                sh "git clone -b ${env.GERRIT_BRANCH} https://gerrit.googlesource.com/plugins/zookeeper-refdb"
-                sh "cd zookeeper-refdb && git fetch origin refs/changes/${BRANCH_NAME} && git merge FETCH_HEAD"
-            }
-        }
-        stage('Formatting') {
-            steps {
-                gerritCheck (checks: ['gerritforge:zookeeper-refdb-format-8b1e7fb8ce34448cc425': 'RUNNING'], url: "${env.BUILD_URL}console")
-                sh "find zookeeper-refdb -name '*.java' | xargs /home/jenkins/format/google-java-format-1.7 -i"
-                script {
-                    def formatOut = sh (script: 'cd zookeeper-refdb && git status --porcelain', returnStdout: true)
-                    if (formatOut.trim()) {
-                        def files = formatOut.split('\n').collect { it.split(' ').last() }
-                        files.each { gerritComment path:it, message: 'Needs reformatting with GJF' }
-                        gerritCheck (checks: ['gerritforge:zookeeper-refdb-format-8b1e7fb8ce34448cc425': 'FAILED'], url: "${env.BUILD_URL}console")
-                    } else {
-                        gerritCheck (checks: ['gerritforge:zookeeper-refdb-format-8b1e7fb8ce34448cc425': 'SUCCESSFUL'], url: "${env.BUILD_URL}console")
-                    }
-                }
-            }
-        }
-        stage('build') {
-             environment {
-                 DOCKER_HOST = """${sh(
-                     returnStdout: true,
-                     script: "/sbin/ip route|awk '/default/ {print  \"tcp://\"\$3\":2375\"}'"
-                 )}"""
-            }
-            steps {
-                gerritCheck (checks: ['gerritforge:zookeeper-refdb-8b1e7fb8ce34448cc425': 'RUNNING'], url: "${env.BUILD_URL}console")
-                sh 'git clone --recursive -b $GERRIT_BRANCH https://gerrit.googlesource.com/gerrit'
-                sh 'cd gerrit/plugins && ln -sf ../../zookeeper-refdb . && ln -sf zookeeper-refdb/external_plugin_deps.bzl .'
-                dir ('gerrit') {
-                    sh 'bazelisk build plugins/zookeeper-refdb'
-                    sh 'bazelisk test --test_env DOCKER_HOST=$DOCKER_HOST plugins/zookeeper-refdb:zookeeper-refdb_tests'
-                }
-            }
-        }
-    }
-    post {
-        success {
-          gerritCheck (checks: ['gerritforge:zookeeper-refdb-8b1e7fb8ce34448cc425': 'SUCCESSFUL'], url: "${env.BUILD_URL}console")
-        }
-        unstable {
-          gerritCheck (checks: ['gerritforge:zookeeper-refdb-8b1e7fb8ce34448cc425': 'FAILED'], url: "${env.BUILD_URL}console")
-        }
-        failure {
-          gerritCheck (checks: ['gerritforge:zookeeper-refdb-8b1e7fb8ce34448cc425': 'FAILED'], url: "${env.BUILD_URL}console")
-        }
-    }
-}
+pluginPipeline(formatCheckId: 'gerritforge:zookeeper-refdb-format-8b1e7fb8ce34448cc425',
+               buildCheckId: 'gerritforge:zookeeper-refdb-8b1e7fb8ce34448cc425')
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index 79b1208..3ddf846 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -28,7 +28,25 @@
     )
 
     maven_jar(
-        name = "zookeeper",
+        name = "zookeeper_3.5",
+        artifact = "org.apache.zookeeper:zookeeper:3.5.7",
+        sha1 = "12bdf55ba8be7fc891996319d37f35eaad7e63ea",
+    )
+
+    maven_jar(
+        name = "zookeeper-jute_3.5",
+        artifact = "org.apache.zookeeper:zookeeper-jute:3.5.7",
+        sha1 = "1270f80b08904499a6839a2ee1800da687ad96b4",
+    )
+
+    maven_jar(
+        name = "netty-all_3.5",
+        artifact = "io.netty:netty-all:4.1.45.Final",
+        sha1 = "e830eae36d22f2bba3118a3bc08e17f15263a01d",
+    )
+
+    maven_jar(
+        name = "zookeeper_3.4",
         artifact = "org.apache.zookeeper:zookeeper:3.4.14",
         sha1 = "c114c1e1c8172a7cd3f6ae39209a635f7a06c1a1",
     )
diff --git a/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperConfig.java b/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperConfig.java
index 7523d1f..d9c7a4a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperConfig.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.Inject;
+import java.util.Optional;
 import org.apache.commons.lang.StringUtils;
 import org.apache.curator.RetryPolicy;
 import org.apache.curator.framework.CuratorFramework;
@@ -41,6 +42,7 @@
   private final int DEFAULT_CAS_RETRY_POLICY_MAX_SLEEP_TIME_MS = 300;
   private final int DEFAULT_CAS_RETRY_POLICY_MAX_RETRIES = 3;
   private final int DEFAULT_TRANSACTION_LOCK_TIMEOUT = 1000;
+  private final boolean DEFAULT_SSL_CONNECTION = false;
 
   static {
     CuratorFrameworkFactory.Builder b = CuratorFrameworkFactory.builder();
@@ -56,6 +58,13 @@
   public static final String KEY_RETRY_POLICY_MAX_SLEEP_TIME_MS = "retryPolicyMaxSleepTimeMs";
   public static final String KEY_RETRY_POLICY_MAX_RETRIES = "retryPolicyMaxRetries";
   public static final String KEY_ROOT_NODE = "rootNode";
+  public static final String SSL_CONNECTION = "sslConnection";
+  public static final String SSL_KEYSTORE_LOCATION = "sslKeyStoreLocation";
+  public static final String SSL_TRUSTSTORE_LOCATION = "sslTrustStoreLocation";
+
+  public static final String SSL_KEYSTORE_PASSWORD = "sslKeyStorePassword";
+  public static final String SSL_TRUSTSTORE_PASSWORD = "sslTrustStorePassword";
+
   public final String KEY_CAS_RETRY_POLICY_BASE_SLEEP_TIME_MS = "casRetryPolicyBaseSleepTimeMs";
   public final String KEY_CAS_RETRY_POLICY_MAX_SLEEP_TIME_MS = "casRetryPolicyMaxSleepTimeMs";
   public final String KEY_CAS_RETRY_POLICY_MAX_RETRIES = "casRetryPolicyMaxRetries";
@@ -72,6 +81,12 @@
   private final int casMaxSleepTimeMs;
   private final int casMaxRetries;
 
+  private Boolean isSSLEnabled;
+  private Optional<String> sslKeyStoreLocation;
+  private Optional<String> sslTrustStoreLocation;
+  private Optional<String> sslKeyStorePassword;
+  private Optional<String> sslTrustStorePassword;
+
   public static final String SECTION = "ref-database";
   private final Long transactionLockTimeOut;
 
@@ -145,10 +160,39 @@
             TRANSACTION_LOCK_TIMEOUT_KEY,
             DEFAULT_TRANSACTION_LOCK_TIMEOUT);
 
+    isSSLEnabled =
+        getBoolean(zkConfig, SECTION, SUBSECTION, SSL_CONNECTION, DEFAULT_SSL_CONNECTION);
+
+    sslKeyStoreLocation = getOptionalString(zkConfig, SECTION, SUBSECTION, SSL_KEYSTORE_LOCATION);
+
+    sslTrustStoreLocation =
+        getOptionalString(zkConfig, SECTION, SUBSECTION, SSL_TRUSTSTORE_LOCATION);
+
+    sslKeyStorePassword = getOptionalString(zkConfig, SECTION, SUBSECTION, SSL_KEYSTORE_PASSWORD);
+
+    sslTrustStorePassword =
+        getOptionalString(zkConfig, SECTION, SUBSECTION, SSL_TRUSTSTORE_PASSWORD);
+
     checkArgument(StringUtils.isNotEmpty(connectionString), "zookeeper.%s contains no servers");
   }
 
   public CuratorFramework buildCurator() {
+    if (isSSLEnabled) {
+
+      System.setProperty(
+          "zookeeper.clientCnxnSocket", "org.apache.zookeeper.ClientCnxnSocketNetty");
+      System.setProperty("zookeeper.client.secure", "true");
+
+      sslKeyStoreLocation.ifPresent(
+          location -> System.setProperty("zookeeper.ssl.keyStore.location", location));
+      sslTrustStoreLocation.ifPresent(
+          location -> System.setProperty("zookeeper.ssl.trustStore.location", location));
+      sslKeyStorePassword.ifPresent(
+          passw -> System.setProperty("zookeeper.ssl.keyStore.password", passw));
+      sslTrustStorePassword.ifPresent(
+          passw -> System.setProperty("zookeeper.ssl.trustStore.password", passw));
+    }
+
     if (build == null) {
       this.build =
           CuratorFrameworkFactory.builder()
@@ -194,6 +238,11 @@
     }
   }
 
+  private Optional<String> getOptionalString(
+      Config cfg, String section, String subsection, String name) {
+    return Optional.ofNullable(cfg.getString(section, subsection, name)).filter(s -> !s.isEmpty());
+  }
+
   private String getString(
       Config cfg, String section, String subsection, String name, String defaultValue) {
     String value = cfg.getString(section, subsection, name);
@@ -202,4 +251,9 @@
     }
     return defaultValue;
   }
+
+  private Boolean getBoolean(
+      Config cfg, String section, String subSection, String name, Boolean defaultValue) {
+    return cfg.getBoolean(section, subSection, name, defaultValue);
+  }
 }
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index 03ffab4..f3f6563 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -9,6 +9,10 @@
 
 Originally this code was a part of [multi-site plugin](https://gerrit.googlesource.com/plugins/multi-site/) but currently can be use independently.
 
+## Requirements
+
+Supported Zookeeper version is 3.5.x. For SSL connection minimal Zookeeper version is 3.5.1[ZOOKEEPER-2125](https://issues.apache.org/jira/browse/ZOOKEEPER-2125).
+
 ## Setup
 
 * Install @PLUGIN@ plugin
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 5cd89a5..00a2468 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -16,6 +16,15 @@
   transactionLockTimeoutMs = 1000
 ```
 
+## Sample SSL configuration
+```
+[ref-database "zookeeper"]
+  connectString = "zookeeperhost:2281"
+  sslConnection = true
+  rootNode = "/gerrit/multi-site"
+  transactionLockTimeoutMs = 1000
+```
+
 ## Configuration parameters
 
 ```ref-database.zookeeper.connectString```
@@ -81,3 +90,25 @@
     acquires the exclusive lock for a reference.
 
     Defaults: 1000
+
+```ref-database.zookeeper.sslConnection```
+:   Enable ssl for Zookeeper connection.
+
+    Defaults: false
+
+```ref-database.zookeeper.sslKeyStoreLocation```
+:   Optional configuration of the path to the ssl key store location.
+
+```ref-database.zookeeper.sslTrustStoreLocation```
+:   Optional configuration of the path to the ssl trust store for server-side X.509 certificate validation.
+
+File '@PLUGIN@.secure.config'
+--------------------
+
+## Configuration parameters
+
+```ref-database.zookeeper.sslKeyStorePassword```
+:   Optional configuration for the password to the ssl key store.
+
+```ref-database.zookeeper.sslTrustStorePassword```
+:   Optional configuration for the password to the ssl trust store.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperTestContainerSupport.java b/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperTestContainerSupport.java
index 59b7afd..107ece9 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperTestContainerSupport.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZookeeperTestContainerSupport.java
@@ -33,7 +33,7 @@
 public class ZookeeperTestContainerSupport {
 
   static class ZookeeperContainer extends GenericContainer<ZookeeperContainer> {
-    public static String ZOOKEEPER_VERSION = "3.4.13";
+    public static String ZOOKEEPER_VERSION = "3.5.5";
 
     public ZookeeperContainer() {
       super("zookeeper:" + ZOOKEEPER_VERSION);