This is an automated email from the ASF dual-hosted git repository.

broustant pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-sandbox.git


The following commit(s) were added to refs/heads/main by this push:
     new e5cce7e  Support follower replicas fetching encrypted index files. 
(#116)
e5cce7e is described below

commit e5cce7ea14281b6372917d28f2a4f7b09534865d
Author: Bruno Roustant <[email protected]>
AuthorDate: Mon Aug 4 15:41:56 2025 +0200

    Support follower replicas fetching encrypted index files. (#116)
---
 encryption/build.gradle                            |   8 +-
 .../solr/encryption/EncryptionDirectory.java       |  29 +++++-
 .../encryption/EncryptionDirectoryFactory.java     |  24 +++++
 .../solr/encryption/EncryptionRequestHandler.java  |   6 +-
 .../encryption/EncryptionBackupRepositoryTest.java |   7 +-
 .../encryption/EncryptionIndexFetchingTest.java    | 107 +++++++++++++++++++++
 .../encryption/EncryptionRequestHandlerTest.java   |  15 ++-
 .../apache/solr/encryption/EncryptionTestUtil.java |  99 +++++++++++++------
 8 files changed, 244 insertions(+), 51 deletions(-)

diff --git a/encryption/build.gradle b/encryption/build.gradle
index 3eadcf4..c14c04a 100644
--- a/encryption/build.gradle
+++ b/encryption/build.gradle
@@ -33,8 +33,8 @@ sourceSets {
 }
 
 dependencies {
-    implementation 'org.apache.solr:solr-core:9.8.0'
-    implementation 'org.apache.lucene:lucene-core:9.11.1'
+    implementation 'org.apache.solr:solr-core:9.9.0'
+    implementation 'org.apache.lucene:lucene-core:9.12.2'
     implementation 'com.google.code.findbugs:jsr305:3.0.2'
 
     // Optional, used by the KmsKeySupplier example.
@@ -47,8 +47,8 @@ dependencies {
     implementation 'commons-io:commons-io:2.18.0'
     implementation 'commons-codec:commons-codec:1.18.0'
 
-    testImplementation 'org.apache.solr:solr-test-framework:9.8.0'
-    testImplementation 'org.apache.lucene:lucene-test-framework:9.11.1'
+    testImplementation 'org.apache.solr:solr-test-framework:9.9.0'
+    testImplementation 'org.apache.lucene:lucene-test-framework:9.12.2'
 }
 
 test {
diff --git 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectory.java 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectory.java
index 74a7e31..fe4cd26 100644
--- 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectory.java
+++ 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectory.java
@@ -34,6 +34,7 @@ import org.apache.solr.encryption.crypto.DecryptingIndexInput;
 import org.apache.solr.encryption.crypto.EncryptingIndexOutput;
 
 import javax.annotation.Nullable;
+import java.io.EOFException;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
@@ -49,6 +50,7 @@ import java.util.stream.Collectors;
 import static org.apache.lucene.codecs.CodecUtil.readBEInt;
 import static org.apache.lucene.codecs.CodecUtil.writeBEInt;
 import static org.apache.solr.encryption.EncryptionUtil.*;
+import static org.apache.solr.encryption.crypto.AesCtrUtil.IV_LENGTH;
 
 /**
  * {@link FilterDirectory} that wraps a delegate {@link Directory} to 
encrypt/decrypt files on the fly.
@@ -81,6 +83,9 @@ public class EncryptionDirectory extends FilterDirectory {
    */
   public static final int ENCRYPTION_MAGIC = 0x2E5BF271; // 777777777 in 
decimal
 
+  // An encrypted file starts with a 4-bytes "magic header", then 4-bytes key 
reference, then a 16-bytes random IV.
+  private static final int ENCRYPTION_HEADER_LENGTH = 8 + IV_LENGTH;
+
   protected final AesCtrEncrypterFactory encrypterFactory;
 
   protected final KeySupplier keySupplier;
@@ -278,7 +283,13 @@ public class EncryptionDirectory extends FilterDirectory {
     // issue because it will be read immediately again when the IndexInput is 
returned, to
     // check the index header (CodecUtil.checkIndexHeader()).
     long filePointer = indexInput.getFilePointer();
-    int magic = readBEInt(indexInput);
+    int magic;
+    try {
+      magic = readBEInt(indexInput);
+    } catch (EOFException e) {
+      // The file contains less than 4 bytes (not expected to happen with 
Lucene). It is not encrypted.
+      magic = 0;
+    }
     if (magic == ENCRYPTION_MAGIC) {
       // This file is encrypted.
       // Read the key reference that follows.
@@ -327,6 +338,22 @@ public class EncryptionDirectory extends FilterDirectory {
     return segmentsWithOldKeyId == null ? Collections.emptyList() : 
segmentsWithOldKeyId;
   }
 
+  /**
+   * Returns the logical length of the file. If the file is encrypted, its 
logical length ignores the encryption header.
+   *
+   * @param fileName the name of an existing file.
+   * @return the logical length of the file, in bytes.
+   */
+  @Override
+  public long fileLength(String fileName) throws IOException {
+    // Read the first 4 bytes to check the encryption "magic header".
+    try (IndexInput indexInput = in.openInput(fileName, IOContext.READONCE)) {
+      long fileLength = indexInput.length();
+      return fileLength >= 4 && readBEInt(indexInput) == ENCRYPTION_MAGIC ?
+          fileLength - ENCRYPTION_HEADER_LENGTH : fileLength;
+    }
+  }
+
   /**
    * Keeps the {@link SegmentInfos commit} file name and user data.
    */
diff --git 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectoryFactory.java
 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectoryFactory.java
index ab88bef..4232723 100644
--- 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectoryFactory.java
+++ 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionDirectoryFactory.java
@@ -17,6 +17,7 @@
 package org.apache.solr.encryption;
 
 import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FilterDirectory;
 import org.apache.lucene.store.LockFactory;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.NamedList;
@@ -77,6 +78,21 @@ public class EncryptionDirectoryFactory extends 
MMapDirectoryFactory {
   private AesCtrEncrypterFactory encrypterFactory;
   private InnerFactory innerFactory;
 
+  public EncryptionDirectoryFactory() {}
+
+  /**
+   * Visible for tests only.
+   */
+  EncryptionDirectoryFactory(
+      KeySupplier keySupplier,
+      AesCtrEncrypterFactory encrypterFactory,
+      InnerFactory innerFactory) {
+    super.init(new NamedList<>());
+    this.keySupplier = keySupplier;
+    this.encrypterFactory = encrypterFactory;
+    this.innerFactory = innerFactory;
+  }
+
   @Override
   public void init(NamedList<?> args) {
     super.init(args);
@@ -144,6 +160,14 @@ public class EncryptionDirectoryFactory extends 
MMapDirectoryFactory {
     return innerFactory.create(super.create(path, lockFactory, dirContext), 
getEncrypterFactory(), getKeySupplier());
   }
 
+  @Override
+  protected Directory filterDirectory(Directory dir, DirContext dirContext) {
+    // Do not unwrap for DirContext.BACKUP, as it is managed by the 
EncryptionBackupRepository.
+    // EncryptionBackupRepository needs to both unwrap when copying file 
content, and also not
+    // unwrap when checking the checksum of the cleartext content.
+    return dirContext == DirContext.REPLICATION ? FilterDirectory.unwrap(dir) 
: dir;
+  }
+
   @Override
   public void close() throws IOException {
     keySupplier.close();
diff --git 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionRequestHandler.java
 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionRequestHandler.java
index a4346fe..a124e46 100644
--- 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionRequestHandler.java
+++ 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionRequestHandler.java
@@ -363,13 +363,13 @@ public class EncryptionRequestHandler extends 
RequestHandlerBase {
       Collection<Slice> slices = docCollection.getActiveSlices();
       Collection<Callable<State>> encryptRequests = new 
ArrayList<>(slices.size());
       for (Slice slice : slices) {
-        Replica replica = slice.getLeader();
-        if (replica == null) {
+        Replica leader = slice.getLeader();
+        if (leader == null) {
           log.error("No leader found for shard {}", slice.getName());
           collectionState = State.ERROR;
           continue;
         }
-        encryptRequests.add(() -> sendEncryptionRequestWithRetry(replica, req, 
params, keyId));
+        encryptRequests.add(() -> sendEncryptionRequestWithRetry(leader, req, 
params, keyId));
       }
       try {
         List<Future<State>> responses = timeOut == null ?
diff --git 
a/encryption/src/test/java/org/apache/solr/encryption/EncryptionBackupRepositoryTest.java
 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionBackupRepositoryTest.java
index 8624aaa..9f36a19 100644
--- 
a/encryption/src/test/java/org/apache/solr/encryption/EncryptionBackupRepositoryTest.java
+++ 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionBackupRepositoryTest.java
@@ -96,14 +96,17 @@ public class EncryptionBackupRepositoryTest extends 
AbstractBackupRepositoryTest
         AesCtrEncrypterFactory encrypterFactory = random().nextBoolean() ? 
CipherAesCtrEncrypter.FACTORY : LightAesCtrEncrypter.FACTORY;
         KeySupplier keySupplier = new TestingKeySupplier.Factory().create();
         try (Directory fsSourceDir = FSDirectory.open(sourcePath);
-             Directory encSourceDir = new TestEncryptionDirectory(fsSourceDir, 
encrypterFactory, keySupplier);
-             Directory destinationDir = 
FSDirectory.open(createTempDir().toAbsolutePath())) {
+             Directory destinationDir = 
FSDirectory.open(createTempDir().toAbsolutePath());
+             EncryptionDirectoryFactory encDirFactory = new 
EncryptionDirectoryFactory(keySupplier, encrypterFactory, 
TestEncryptionDirectory::new);
+             Directory encSourceDir = encDirFactory.get(sourcePath.toString(), 
DirectoryFactory.DirContext.BACKUP, null)) {
             String fileName = "source-file";
             String content = "content";
             try (IndexOutput out = encSourceDir.createOutput(fileName, 
IOContext.DEFAULT)) {
                 byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
                 out.writeBytes(bytes, bytes.length);
                 CodecUtil.writeFooter(out);
+            } finally {
+              encDirFactory.release(encSourceDir);
             }
 
             BackupRepositoryFactory repoFactory = new 
BackupRepositoryFactory(plugins);
diff --git 
a/encryption/src/test/java/org/apache/solr/encryption/EncryptionIndexFetchingTest.java
 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionIndexFetchingTest.java
new file mode 100644
index 0000000..f37c5ac
--- /dev/null
+++ 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionIndexFetchingTest.java
@@ -0,0 +1,107 @@
+package org.apache.solr.encryption;
+
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.cloud.MiniSolrCloudCluster;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.util.TimeOut;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import static 
org.apache.solr.encryption.EncryptionDirectoryFactory.PROPERTY_INNER_ENCRYPTION_DIRECTORY_FACTORY;
+import static org.apache.solr.encryption.TestingKeySupplier.KEY_ID_1;
+
+/**
+ * Tests encrypted index fetching, when follower replicas fetch index from the 
leader.
+ */
+public class EncryptionIndexFetchingTest extends SolrCloudTestCase {
+
+  private static final String COLLECTION_PREFIX = 
EncryptionIndexFetchingTest.class.getSimpleName() + "-collection-";
+
+  private String collectionName;
+  private CloudSolrClient solrClient;
+  private EncryptionTestUtil testUtil;
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    System.setProperty(PROPERTY_INNER_ENCRYPTION_DIRECTORY_FACTORY, 
EncryptionRequestHandlerTest.MockFactory.class.getName());
+    EncryptionTestUtil.setInstallDirProperty();
+    cluster = new MiniSolrCloudCluster.Builder(2, createTempDir())
+        .addConfig("config", EncryptionTestUtil.getConfigPath("kms"))
+        .configure();
+  }
+
+  @AfterClass
+  public static void afterClass() throws Exception {
+    cluster.shutdown();
+  }
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    collectionName = COLLECTION_PREFIX + UUID.randomUUID();
+    solrClient = cluster.getSolrClient();
+    CollectionAdminRequest.createCollection(collectionName, null, 1, 1, 0, 1)
+        .process(solrClient);
+    cluster.waitForActiveCollection(collectionName, 1, 2);
+    testUtil = new EncryptionTestUtil(solrClient, collectionName);
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+    
CollectionAdminRequest.deleteCollection(collectionName).process(solrClient);
+    super.tearDown();
+  }
+
+  @Test
+  public void testIndexFetchingWithPullReplica() throws Exception {
+    // GIVEN a Solr Cloud cluster composed of 2 nodes, 1 shard, 1 NRT replica 
and 1 PULL replica.
+    // GIVEN an encrypted index containing 3 docs.
+    testUtil.encryptAndExpectCompletion(KEY_ID_1);
+    testUtil.indexDocsAndCommit("weather broadcast", "sunny weather", "foggy 
weather");
+
+    // WHEN the follower PULL replica is queried.
+    Replica follower = getFollowerReplica();
+    try (Http2SolrClient followerClient = new 
Http2SolrClient.Builder(follower.getCoreUrl()).build()) {
+      new TimeOut(10, TimeUnit.SECONDS, TimeSource.NANO_TIME)
+          .waitFor(null, () -> {
+            try {
+
+              // THEN eventually the PULL replica is able to fetch the 
encrypted index
+              // and search it to find the 3 matching docs.
+              QueryResponse response = followerClient.query(new 
SolrQuery("weather"));
+              return response.getResults().size() == 3;
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+          });
+    }
+
+    // THEN verify that the index is encrypted on all replicas, including the 
follower.
+    EncryptionRequestHandlerTest.forceClearText = true;
+    testUtil.assertCannotReloadCores(false);
+    EncryptionRequestHandlerTest.forceClearText = false;
+    testUtil.reloadCores(false);
+  }
+
+  private Replica getFollowerReplica() {
+    for (Slice slice : 
solrClient.getClusterState().getCollection(collectionName).getSlices()) {
+      for (Replica replica : slice.getReplicas()) {
+        if (!replica.isLeader()) {
+          return replica;
+        }
+      }
+    }
+    throw new IllegalStateException("No follower replica found");
+  }
+}
diff --git 
a/encryption/src/test/java/org/apache/solr/encryption/EncryptionRequestHandlerTest.java
 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionRequestHandlerTest.java
index e0014a6..32fac67 100644
--- 
a/encryption/src/test/java/org/apache/solr/encryption/EncryptionRequestHandlerTest.java
+++ 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionRequestHandlerTest.java
@@ -52,7 +52,7 @@ public class EncryptionRequestHandlerTest extends 
SolrCloudTestCase {
 
   protected static String configDir = "collection1";
 
-  private static volatile boolean forceClearText;
+  static volatile boolean forceClearText;
   private static volatile String soleKeyIdAllowed;
 
   private String collectionName;
@@ -80,11 +80,7 @@ public class EncryptionRequestHandlerTest extends 
SolrCloudTestCase {
     solrClient = cluster.getSolrClient();
     CollectionAdminRequest.createCollection(collectionName, 2, 
2).process(solrClient);
     cluster.waitForActiveCollection(collectionName, 2, 4);
-    testUtil = createEncryptionTestUtil(solrClient, collectionName);
-  }
-
-  protected EncryptionTestUtil createEncryptionTestUtil(CloudSolrClient 
solrClient, String collectionName) {
-    return new EncryptionTestUtil(solrClient, collectionName);
+    testUtil = new EncryptionTestUtil(solrClient, collectionName);
   }
 
   @Override
@@ -272,15 +268,16 @@ public class EncryptionRequestHandlerTest extends 
SolrCloudTestCase {
       restartSolrServer(1);
       waitForState("Timed out waiting for shards to be active",
           collectionName,
-          SolrCloudTestCase.activeClusterShape(2, 4),
           30,
-          TimeUnit.SECONDS);
-    } catch (InterruptedException | TimeoutException e) {
+          TimeUnit.SECONDS,
+          SolrCloudTestCase.activeClusterShape(2, 4));
+    } catch (InterruptedException | TimeoutException | AssertionError e) {
       // Sometimes restarting Solr nodes hangs, or waiting for shards to 
become active times out.
       // In this case, exit silently the test.
       return;
     }
 
+    // Now commit.
     testUtil.commit();
     testUtil.waitUntilEncryptionIsComplete(KEY_ID_1);
 
diff --git 
a/encryption/src/test/java/org/apache/solr/encryption/EncryptionTestUtil.java 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionTestUtil.java
index 2cb6aa5..2aab0fa 100644
--- 
a/encryption/src/test/java/org/apache/solr/encryption/EncryptionTestUtil.java
+++ 
b/encryption/src/test/java/org/apache/solr/encryption/EncryptionTestUtil.java
@@ -35,10 +35,11 @@ import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.RetryUtil;
 import org.apache.solr.encryption.kms.TestingKmsClient;
-import org.junit.Assert;
 
 import java.io.IOException;
 import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
@@ -53,6 +54,7 @@ import static 
org.apache.solr.encryption.kms.KmsEncryptionRequestHandler.PARAM_E
 import static 
org.apache.solr.encryption.kms.KmsEncryptionRequestHandler.PARAM_TENANT_ID;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * Utility methods for encryption tests.
@@ -238,39 +240,78 @@ public class EncryptionTestUtil {
   }
 
   /**
-   * Reloads the leader replica core of the first shard of the collection.
+   * Reloads the replicas of the collection defined in the constructor.
+   * <p>
+   * If {@link #shouldDistributeEncryptRequest()} returns true, then only the 
leader replicas are reloaded
+   * (because only them receive the distributed encryption request).
    */
-  public void reloadCores() throws Exception {
+  public void reloadCores() {
+    reloadCores(shouldDistributeEncryptRequest());
+  }
+
+  /**
+   * Reloads the replicas of the collection defined in the constructor.
+   *
+   * @param onlyLeaders whether to only reload leader replicas, or all 
replicas.
+   */
+  public void reloadCores(boolean onlyLeaders) {
+    forAllReplicas(onlyLeaders, this::reloadCore);
+  }
+
+  /**
+   * Reloads a specific replica.
+   */
+  public void reloadCore(Replica replica) {
     try {
-      forAllReplicas(shouldDistributeEncryptRequest(), replica -> {
-        try {
-          CoreAdminRequest req = new CoreAdminRequest();
-          req.setCoreName(replica.getCoreName());
-          req.setAction(CoreAdminParams.CoreAdminAction.RELOAD);
-          try (Http2SolrClient httpSolrClient = new 
Http2SolrClient.Builder(replica.getBaseUrl()).build()) {
-            httpSolrClient.request(req);
-          }
-        } catch (SolrServerException e) {
-          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
-        } catch (IOException e) {
-          throw new RuntimeException(e);
-        }
-      });
-    } catch (SolrException e) {
-      throw new CoreReloadException("The index cannot be reloaded. There is 
probably an issue with the encryption key ids.", e);
+      CoreAdminRequest req = new CoreAdminRequest();
+      req.setCoreName(replica.getCoreName());
+      req.setAction(CoreAdminParams.CoreAdminAction.RELOAD);
+      try (Http2SolrClient httpSolrClient = new 
Http2SolrClient.Builder(replica.getBaseUrl()).build()) {
+        httpSolrClient.request(req);
+      }
+    } catch (SolrServerException | SolrException e) {
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "The index 
cannot be reloaded. There is probably an issue with the encryption key ids.", 
e);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
     }
   }
 
   /**
-   * Verifies that {@link #reloadCores()} fails.
+   * Verifies that the replicas of the collection defined in the constructor 
fail to reload.
+   * <p>
+   * If {@link #shouldDistributeEncryptRequest()} returns true, then only the 
leader replicas are reloaded
+   * (because only them receive the distributed encryption request).
    */
-  public void assertCannotReloadCores() throws Exception {
-    try {
-      reloadCores();
-      Assert.fail("Core reloaded whereas it was not expected to be possible");
-    } catch (CoreReloadException e) {
-      // Expected.
+  public void assertCannotReloadCores() {
+    assertCannotReloadCores(shouldDistributeEncryptRequest());
+  }
+
+  /**
+   * Verifies that the replicas of the collection defined in the constructor 
fail to reload.
+   *
+   * @param onlyLeaders whether to only reload leader replicas, or all 
replicas.
+   */
+  public void assertCannotReloadCores(boolean onlyLeaders) {
+    Map<String, Integer> numReloadedPerShard = new HashMap<>();
+    forAllReplicas(onlyLeaders, replica -> {
+      try {
+        numReloadedPerShard.putIfAbsent(replica.getShard(), 0);
+        reloadCore(replica);
+        numReloadedPerShard.compute(replica.getShard(), (k, v) -> v == null ? 
1 : v + 1);
+      } catch (SolrException e) {
+        // Expected.
+      }
+    });
+    // It is tricky to check that index is encrypted. We check that by 
reloading the cores, and
+    // forcing the mock EncryptionDirectory to consider clear text, and 
attempting to open the index
+    // files. But in our tests, the small index files are not in all shards. 
So we check here that
+    // at least one shard has no cores successfully reloaded.
+    for (Map.Entry<String, Integer> entry : numReloadedPerShard.entrySet()) {
+      if (entry.getValue() == 0) {
+        return;
+      }
     }
+    fail("Core reloaded whereas it was not expected to be possible");
   }
 
   /** Processes the given {@code action} for all replicas of the collection 
defined in the constructor. */
@@ -297,12 +338,6 @@ public class EncryptionTestUtil {
     }
   }
 
-  private static class CoreReloadException extends Exception {
-    CoreReloadException(String msg, SolrException cause) {
-      super(msg, cause);
-    }
-  }
-
   /** Status of the encryption of potentially multiple cores. */
   public static class EncryptionStatus {
 

Reply via email to