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

dlmarion pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git

commit 9426881c145dbe45fd8fea1cf3a09306d58bc974
Merge: b9bf07e68f f02d6a880e
Author: Dave Marion <dlmar...@apache.org>
AuthorDate: Thu Apr 3 13:24:58 2025 +0000

    Merge branch '2.1'

 .../accumulo/manager/FateServiceHandler.java       |  19 ++-
 .../accumulo/manager/tableOps/clone/CloneInfo.java |  74 ++++++++++--
 .../manager/tableOps/clone/CloneMetadata.java      |  11 +-
 .../manager/tableOps/clone/ClonePermissions.java   |   8 +-
 .../manager/tableOps/clone/CloneTable.java         |  30 ++---
 .../manager/tableOps/clone/CloneZookeeper.java     |  30 ++---
 .../manager/tableOps/clone/FinishCloneTable.java   |  28 +++--
 .../accumulo/test/functional/CloneTestIT.java      | 132 +++++++++++++++++++++
 8 files changed, 260 insertions(+), 72 deletions(-)

diff --cc 
server/manager/src/main/java/org/apache/accumulo/manager/FateServiceHandler.java
index 0dac7412cf,c9ecd1d4d8..56ce16b7b1
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/FateServiceHandler.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/FateServiceHandler.java
@@@ -363,9 -345,9 +372,9 @@@ class FateServiceHandler implements Fat
            goalMessage += " and keep offline.";
          }
  
-         manager.fate(type).seedTransaction(
-             op, fateId, new TraceRepo<>(new CloneTable(c.getPrincipal(), 
namespaceId, srcTableId,
-                 tableName, propertiesToSet, propertiesToExclude, 
keepOffline)),
 -        manager.fate().seedTransaction(op.toString(), opid,
++        manager.fate(type).seedTransaction(op, fateId,
+             new TraceRepo<>(new CloneTable(c.getPrincipal(), srcNamespaceId, 
srcTableId,
+                 namespaceId, tableName, propertiesToSet, propertiesToExclude, 
keepOffline)),
              autoCleanup, goalMessage);
  
          break;
diff --cc 
server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneInfo.java
index 676e4d88e7,2a697827ad..5403cffc55
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneInfo.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneInfo.java
@@@ -29,14 -29,73 +29,68 @@@ class CloneInfo implements Serializabl
  
    private static final long serialVersionUID = 1L;
  
-   TableId srcTableId;
-   String tableName;
-   TableId tableId;
-   NamespaceId namespaceId;
-   NamespaceId srcNamespaceId;
-   Map<String,String> propertiesToSet;
-   Set<String> propertiesToExclude;
-   boolean keepOffline;
- 
-   public String user;
+   private final TableId srcTableId;
+   private final String tableName;
+   private TableId tableId;
 -  // TODO: Make final in 3.1
 -  private NamespaceId namespaceId;
++  private final NamespaceId namespaceId;
+   private final NamespaceId srcNamespaceId;
+   private final Map<String,String> propertiesToSet;
+   private final Set<String> propertiesToExclude;
+   private final boolean keepOffline;
+   private final String user;
+ 
+   public CloneInfo(NamespaceId srcNamespaceId, TableId srcTableId, 
NamespaceId dstNamespaceId,
+       String dstTableName, Map<String,String> propertiesToSet, Set<String> 
propertiesToExclude,
+       boolean keepOffline, String user) {
+     super();
+     this.srcNamespaceId = srcNamespaceId;
+     this.srcTableId = srcTableId;
+     this.tableName = dstTableName;
+     this.namespaceId = dstNamespaceId;
+     this.propertiesToSet = propertiesToSet;
+     this.propertiesToExclude = propertiesToExclude;
+     this.keepOffline = keepOffline;
+     this.user = user;
+   }
+ 
+   public TableId getSrcTableId() {
+     return srcTableId;
+   }
+ 
+   public String getTableName() {
+     return tableName;
+   }
+ 
+   public void setTableId(TableId dstTableId) {
+     this.tableId = dstTableId;
+   }
+ 
+   public TableId getTableId() {
+     return tableId;
+   }
+ 
+   public NamespaceId getNamespaceId() {
+     return namespaceId;
+   }
+ 
 -  public void setNamespaceId(NamespaceId nid) {
 -    this.namespaceId = nid;
 -  }
 -
+   public NamespaceId getSrcNamespaceId() {
+     return srcNamespaceId;
+   }
+ 
+   public Map<String,String> getPropertiesToSet() {
+     return propertiesToSet;
+   }
+ 
+   public Set<String> getPropertiesToExclude() {
+     return propertiesToExclude;
+   }
+ 
+   public boolean isKeepOffline() {
+     return keepOffline;
+   }
+ 
+   public String getUser() {
+     return user;
+   }
+ 
  }
diff --cc 
server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneMetadata.java
index e7b554b559,82f73d0383..8f82ddbf3d
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneMetadata.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneMetadata.java
@@@ -40,21 -39,22 +40,22 @@@ class CloneMetadata extends ManagerRep
    }
  
    @Override
 -  public Repo<Manager> call(long tid, Manager environment) throws Exception {
 +  public Repo<Manager> call(FateId fateId, Manager environment) throws 
Exception {
      LoggerFactory.getLogger(CloneMetadata.class)
-         .info(String.format("Cloning %s with tableId %s from srcTableId %s", 
cloneInfo.tableName,
-             cloneInfo.tableId, cloneInfo.srcTableId));
+         .info(String.format("Cloning %s with tableId %s from srcTableId %s",
+             cloneInfo.getTableName(), cloneInfo.getTableId(), 
cloneInfo.getSrcTableId()));
      // need to clear out any metadata entries for tableId just in case this
      // died before and is executing again
-     MetadataTableUtil.deleteTable(cloneInfo.tableId, false, 
environment.getContext(),
+     MetadataTableUtil.deleteTable(cloneInfo.getTableId(), false, 
environment.getContext(),
          environment.getManagerLock());
-     MetadataTableUtil.cloneTable(environment.getContext(), 
cloneInfo.srcTableId, cloneInfo.tableId);
+     MetadataTableUtil.cloneTable(environment.getContext(), 
cloneInfo.getSrcTableId(),
+         cloneInfo.getTableId());
      return new FinishCloneTable(cloneInfo);
    }
  
    @Override
 -  public void undo(long tid, Manager environment) throws Exception {
 +  public void undo(FateId fateId, Manager environment) throws Exception {
-     MetadataTableUtil.deleteTable(cloneInfo.tableId, false, 
environment.getContext(),
+     MetadataTableUtil.deleteTable(cloneInfo.getTableId(), false, 
environment.getContext(),
          environment.getManagerLock());
    }
  
diff --cc 
server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/ClonePermissions.java
index 474aab0a14,ac1432c3d2..79ba23a940
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/ClonePermissions.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/ClonePermissions.java
@@@ -72,8 -71,8 +72,8 @@@ class ClonePermissions extends ManagerR
    }
  
    @Override
 -  public void undo(long tid, Manager environment) throws Exception {
 +  public void undo(FateId fateId, Manager environment) throws Exception {
      
environment.getContext().getSecurityOperation().deleteTable(environment.getContext().rpcCreds(),
-         cloneInfo.tableId, cloneInfo.namespaceId);
+         cloneInfo.getTableId(), cloneInfo.getNamespaceId());
    }
  }
diff --cc 
server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneTable.java
index 4899723952,c5587ee692..a389bfe981
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneTable.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneTable.java
@@@ -49,10 -42,10 +44,10 @@@ public class CloneTable extends Manager
    }
  
    @Override
 -  public long isReady(long tid, Manager environment) throws Exception {
 -    long val = Utils.reserveNamespace(environment, 
cloneInfo.getNamespaceId(), tid, false, true,
 -        TableOperation.CLONE);
 -    val += Utils.reserveTable(environment, cloneInfo.getSrcTableId(), tid, 
false, true,
 +  public long isReady(FateId fateId, Manager environment) throws Exception {
-     long val = Utils.reserveNamespace(environment, cloneInfo.srcNamespaceId, 
fateId, LockType.READ,
-         true, TableOperation.CLONE);
-     val += Utils.reserveTable(environment, cloneInfo.srcTableId, fateId, 
LockType.READ, true,
++    long val = Utils.reserveNamespace(environment, 
cloneInfo.getNamespaceId(), fateId,
++        LockType.READ, true, TableOperation.CLONE);
++    val += Utils.reserveTable(environment, cloneInfo.getSrcTableId(), fateId, 
LockType.READ, true,
          TableOperation.CLONE);
      return val;
    }
@@@ -72,9 -64,9 +66,9 @@@
    }
  
    @Override
 -  public void undo(long tid, Manager environment) {
 -    Utils.unreserveNamespace(environment, cloneInfo.getNamespaceId(), tid, 
false);
 -    Utils.unreserveTable(environment, cloneInfo.getSrcTableId(), tid, false);
 +  public void undo(FateId fateId, Manager environment) {
-     Utils.unreserveNamespace(environment, cloneInfo.srcNamespaceId, fateId, 
LockType.READ);
-     Utils.unreserveTable(environment, cloneInfo.srcTableId, fateId, 
LockType.READ);
++    Utils.unreserveNamespace(environment, cloneInfo.getNamespaceId(), fateId, 
LockType.READ);
++    Utils.unreserveTable(environment, cloneInfo.getSrcTableId(), fateId, 
LockType.READ);
    }
  
  }
diff --cc 
server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneZookeeper.java
index c9872e7051,fe9c9fcd13..0cb1dde6bd
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneZookeeper.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/CloneZookeeper.java
@@@ -20,12 -20,10 +20,10 @@@ package org.apache.accumulo.manager.tab
  
  import org.apache.accumulo.core.client.NamespaceNotFoundException;
  import org.apache.accumulo.core.clientImpl.ClientContext;
--import org.apache.accumulo.core.clientImpl.Namespaces;
  import org.apache.accumulo.core.clientImpl.thrift.TableOperation;
 +import org.apache.accumulo.core.fate.FateId;
  import org.apache.accumulo.core.fate.Repo;
 -import org.apache.accumulo.core.util.tables.TableNameUtil;
 +import 
org.apache.accumulo.core.fate.zookeeper.DistributedReadWriteLock.LockType;
- import org.apache.accumulo.core.util.tables.TableNameUtil;
  import org.apache.accumulo.manager.Manager;
  import org.apache.accumulo.manager.tableOps.ManagerRepo;
  import org.apache.accumulo.manager.tableOps.Utils;
@@@ -39,20 -37,24 +37,18 @@@ class CloneZookeeper extends ManagerRep
    public CloneZookeeper(CloneInfo cloneInfo, ClientContext context)
        throws NamespaceNotFoundException {
      this.cloneInfo = cloneInfo;
-     this.cloneInfo.namespaceId = Namespaces.getNamespaceId(context,
-         TableNameUtil.qualify(this.cloneInfo.tableName).getFirst());
 -    if (this.cloneInfo.getNamespaceId() == null) {
 -      // Prior to 2.1.4 the namespaceId was calculated in this
 -      // step and set on the cloneInfo object here. If for some
 -      // reason we are processing a pre-2.1.3 CloneTable operation,
 -      // then we need to continue to set this here as it will be
 -      // null in the deserialized CloneInfo object.
 -      //
 -      // TODO: Remove this check in 3.1 as Fate operations
 -      // need to be cleaned up before a major upgrade.
 -      this.cloneInfo.setNamespaceId(Namespaces.getNamespaceId(context,
 -          TableNameUtil.qualify(this.cloneInfo.getTableName()).getFirst()));
 -    }
    }
  
    @Override
 -  public long isReady(long tid, Manager environment) throws Exception {
 -    return Utils.reserveTable(environment, cloneInfo.getTableId(), tid, true, 
false,
 +  public long isReady(FateId fateId, Manager environment) throws Exception {
 +    long val = 0;
-     if (!cloneInfo.srcNamespaceId.equals(cloneInfo.namespaceId)) {
-       val += Utils.reserveNamespace(environment, cloneInfo.namespaceId, 
fateId, LockType.READ, true,
-           TableOperation.CLONE);
++    if (!cloneInfo.getSrcNamespaceId().equals(cloneInfo.getNamespaceId())) {
++      val += Utils.reserveNamespace(environment, cloneInfo.getNamespaceId(), 
fateId, LockType.READ,
++          true, TableOperation.CLONE);
 +    }
-     val += Utils.reserveTable(environment, cloneInfo.tableId, fateId, 
LockType.WRITE, false,
++    val += Utils.reserveTable(environment, cloneInfo.getTableId(), fateId, 
LockType.WRITE, false,
          TableOperation.CLONE);
 +    return val;
    }
  
    @Override
@@@ -76,12 -78,9 +72,12 @@@
    }
  
    @Override
 -  public void undo(long tid, Manager environment) throws Exception {
 +  public void undo(FateId fateId, Manager environment) throws Exception {
-     environment.getTableManager().removeTable(cloneInfo.tableId);
-     if (!cloneInfo.srcNamespaceId.equals(cloneInfo.namespaceId)) {
-       Utils.unreserveNamespace(environment, cloneInfo.namespaceId, fateId, 
LockType.READ);
+     environment.getTableManager().removeTable(cloneInfo.getTableId());
 -    Utils.unreserveTable(environment, cloneInfo.getTableId(), tid, true);
++    if (!cloneInfo.getSrcNamespaceId().equals(cloneInfo.getNamespaceId())) {
++      Utils.unreserveNamespace(environment, cloneInfo.getNamespaceId(), 
fateId, LockType.READ);
 +    }
-     Utils.unreserveTable(environment, cloneInfo.tableId, fateId, 
LockType.WRITE);
++    Utils.unreserveTable(environment, cloneInfo.getTableId(), fateId, 
LockType.WRITE);
      environment.getContext().clearTableListCache();
    }
  
diff --cc 
server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/FinishCloneTable.java
index 1730a81792,5fedbcfed7..dd7c0fa908
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/FinishCloneTable.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/clone/FinishCloneTable.java
@@@ -52,27 -50,23 +52,29 @@@ class FinishCloneTable extends ManagerR
      // that are not used... tablet will create directories as needed
  
      final EnumSet<TableState> expectedCurrStates = EnumSet.of(TableState.NEW);
-     if (cloneInfo.keepOffline) {
-       environment.getTableManager().transitionTableState(cloneInfo.tableId, 
TableState.OFFLINE,
+     if (cloneInfo.isKeepOffline()) {
+       
environment.getTableManager().transitionTableState(cloneInfo.getTableId(), 
TableState.OFFLINE,
            expectedCurrStates);
      } else {
 -      
environment.getTableManager().transitionTableState(cloneInfo.getTableId(), 
TableState.ONLINE,
 +      // transition clone table state to state of original table
-       TableState ts = 
environment.getTableManager().getTableState(cloneInfo.srcTableId);
-       environment.getTableManager().transitionTableState(cloneInfo.tableId, 
ts, expectedCurrStates);
++      TableState ts = 
environment.getTableManager().getTableState(cloneInfo.getSrcTableId());
++      
environment.getTableManager().transitionTableState(cloneInfo.getTableId(), ts,
+           expectedCurrStates);
      }
 -    Utils.unreserveTable(environment, cloneInfo.getTableId(), tid, true);
 -    Utils.unreserveNamespace(environment, cloneInfo.getNamespaceId(), tid, 
false);
 -    Utils.unreserveTable(environment, cloneInfo.getSrcTableId(), tid, false);
  
-     Utils.unreserveNamespace(environment, cloneInfo.srcNamespaceId, fateId, 
LockType.READ);
-     if (!cloneInfo.srcNamespaceId.equals(cloneInfo.namespaceId)) {
-       Utils.unreserveNamespace(environment, cloneInfo.namespaceId, fateId, 
LockType.READ);
 -    environment.getEventCoordinator().event("Cloned table %s from %s", 
cloneInfo.getTableName(),
 -        cloneInfo.getSrcTableId());
++    Utils.unreserveNamespace(environment, cloneInfo.getSrcNamespaceId(), 
fateId, LockType.READ);
++    if (!cloneInfo.getSrcNamespaceId().equals(cloneInfo.getNamespaceId())) {
++      Utils.unreserveNamespace(environment, cloneInfo.getNamespaceId(), 
fateId, LockType.READ);
 +    }
-     Utils.unreserveTable(environment, cloneInfo.srcTableId, fateId, 
LockType.READ);
-     Utils.unreserveTable(environment, cloneInfo.tableId, fateId, 
LockType.WRITE);
++    Utils.unreserveTable(environment, cloneInfo.getSrcTableId(), fateId, 
LockType.READ);
++    Utils.unreserveTable(environment, cloneInfo.getTableId(), fateId, 
LockType.WRITE);
 +
-     environment.getEventCoordinator().event(cloneInfo.tableId, "Cloned table 
%s from %s",
-         cloneInfo.tableName, cloneInfo.srcTableId);
++    environment.getEventCoordinator().event(cloneInfo.getTableId(), "Cloned 
table %s from %s",
++        cloneInfo.getTableName(), cloneInfo.getSrcTableId());
  
-     LoggerFactory.getLogger(FinishCloneTable.class).debug("Cloned table " + 
cloneInfo.srcTableId
-         + " " + cloneInfo.tableId + " " + cloneInfo.tableName);
+     LoggerFactory.getLogger(FinishCloneTable.class)
+         .debug("Cloned table " + cloneInfo.getSrcTableId() + " " + 
cloneInfo.getTableId() + " "
+             + cloneInfo.getTableName());
  
      return null;
    }
diff --cc 
test/src/main/java/org/apache/accumulo/test/functional/CloneTestIT.java
index a586bd4c7e,7963043049..71e3dfdad0
--- a/test/src/main/java/org/apache/accumulo/test/functional/CloneTestIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/CloneTestIT.java
@@@ -62,7 -64,9 +65,9 @@@ import org.apache.accumulo.core.metadat
  import 
org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.DataFileColumnFamily;
  import 
org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ServerColumnFamily;
  import org.apache.accumulo.core.security.Authorizations;
+ import org.apache.accumulo.core.security.NamespacePermission;
+ import org.apache.accumulo.core.security.TablePermission;
 -import org.apache.accumulo.harness.AccumuloClusterHarness;
 +import org.apache.accumulo.harness.SharedMiniClusterBase;
  import org.apache.accumulo.miniclusterImpl.MiniAccumuloClusterImpl;
  import org.apache.hadoop.fs.FileStatus;
  import org.apache.hadoop.fs.FileSystem;
@@@ -362,8 -351,135 +367,135 @@@ public class CloneTestIT extends Shared
    @Test
    public void testCloneMetadataTable() {
      try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
 -      assertThrows(AccumuloException.class, () -> 
client.tableOperations().clone(MetadataTable.NAME,
 -          "mc1", CloneConfiguration.empty()));
 +      assertThrows(AccumuloException.class, () -> client.tableOperations()
 +          .clone(AccumuloTable.METADATA.tableName(), "mc1", 
CloneConfiguration.empty()));
      }
    }
+ 
+   private void baseCloneNamespace(AccumuloClient client, String src, String 
dest) throws Exception {
+     writeData(src, client).close();
+     // Don't force a flush on the table, let's make sure the
+     // clone operation does this
+     client.tableOperations().clone(src, dest, CloneConfiguration.empty());
+     checkData(dest, client);
+   }
+ 
+   @Test
+   public void testCloneSameNamespace() throws Exception {
+     try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
+       String tableName = getUniqueNames(1)[0];
 -      client.namespaceOperations().create("old");
 -      client.tableOperations().create("old." + tableName);
++      client.namespaceOperations().create("old3");
++      client.tableOperations().create("old3." + tableName);
+       assertThrows(TableExistsException.class,
 -          () -> baseCloneNamespace(client, "old." + tableName, "old." + 
tableName));
++          () -> baseCloneNamespace(client, "old3." + tableName, "old3." + 
tableName));
+     }
+   }
+ 
+   @Test
+   public void testCloneIntoDiffNamespace() throws Exception {
+     try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
+       String tableName = getUniqueNames(1)[0];
 -      client.namespaceOperations().create("old");
 -      client.tableOperations().create("old." + tableName);
 -      client.namespaceOperations().create("new");
 -      baseCloneNamespace(client, "old." + tableName, "new." + tableName);
++      client.namespaceOperations().create("old4");
++      client.tableOperations().create("old4." + tableName);
++      client.namespaceOperations().create("new4");
++      baseCloneNamespace(client, "old4." + tableName, "new4." + tableName);
+     }
+   }
+ 
+   @Test
+   public void testCloneIntoDiffNamespaceTableExists() throws Exception {
+     try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
+       String tableName = getUniqueNames(1)[0];
 -      client.namespaceOperations().create("old");
 -      client.tableOperations().create("old." + tableName);
 -      client.namespaceOperations().create("new");
 -      client.tableOperations().create("new." + tableName);
++      client.namespaceOperations().create("old5");
++      client.tableOperations().create("old5." + tableName);
++      client.namespaceOperations().create("new5");
++      client.tableOperations().create("new5." + tableName);
+       assertThrows(TableExistsException.class,
 -          () -> baseCloneNamespace(client, "old." + tableName, "new." + 
tableName));
++          () -> baseCloneNamespace(client, "old5." + tableName, "new5." + 
tableName));
+     }
+   }
+ 
+   @Test
+   public void testCloneIntoDiffNamespaceDoesntExist() throws Exception {
+     try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
+       String tableName = getUniqueNames(1)[0];
 -      client.namespaceOperations().create("old");
 -      client.tableOperations().create("old." + tableName);
++      client.namespaceOperations().create("old1");
++      client.tableOperations().create("old1." + tableName);
+       assertThrows(AccumuloException.class,
 -          () -> baseCloneNamespace(client, "old." + tableName, "missing." + 
tableName));
++          () -> baseCloneNamespace(client, "old1." + tableName, "missing." + 
tableName));
+     }
+   }
+ 
+   @Test
+   public void testCloneIntoAccumuloNamespace() throws Exception {
+     try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
+       String tableName = getUniqueNames(1)[0];
 -      client.namespaceOperations().create("old");
 -      client.tableOperations().create("old." + tableName);
++      client.namespaceOperations().create("old2");
++      client.tableOperations().create("old2." + tableName);
+       assertThrows(AccumuloException.class,
 -          () -> baseCloneNamespace(client, "old." + tableName, "accumulo." + 
tableName));
++          () -> baseCloneNamespace(client, "old2." + tableName, "accumulo." + 
tableName));
+     }
+   }
+ 
+   @Test
+   public void testCloneNamespaceIncorrectPermissions() throws Exception {
+     final String tableName = getUniqueNames(1)[0];
+     final String newUserName = "NEW_USER";
+     final String srcNs = "src";
+     final String srcTableName = srcNs + "." + tableName;
+     final String destNs = "dst";
+     final String dstTableName = destNs + "." + tableName;
+ 
+     try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
+       client.namespaceOperations().create(srcNs);
+       client.tableOperations().create(srcTableName);
+       client.namespaceOperations().create(destNs);
+       client.securityOperations().createLocalUser(newUserName, new 
PasswordToken(newUserName));
+       // User needs WRITE or ALTER_TABLE on the src table to flush it as part 
of the clone operation
+       client.securityOperations().grantTablePermission(newUserName, 
srcTableName,
+           TablePermission.ALTER_TABLE);
+       client.securityOperations().grantNamespacePermission(newUserName, 
destNs,
+           NamespacePermission.READ);
+       client.securityOperations().grantNamespacePermission(newUserName, 
destNs,
+           NamespacePermission.CREATE_TABLE);
+     }
+ 
+     try (AccumuloClient client =
+         Accumulo.newClient().to(getCluster().getInstanceName(), 
getCluster().getZooKeepers())
+             .as(newUserName, newUserName).build()) {
+       // READ permission is needed on the src table, not the dst namespace
+       assertThrows(AccumuloSecurityException.class, () -> 
client.tableOperations()
+           .clone(srcTableName, dstTableName, CloneConfiguration.empty()));
+     }
+   }
+ 
+   @Test
+   public void testCloneNamespacePermissions() throws Exception {
+     final String tableName = getUniqueNames(1)[0];
 -    final String newUserName = "NEW_USER";
 -    final String srcNs = "src";
++    final String newUserName = "NEW_USER2";
++    final String srcNs = "src2";
+     final String srcTableName = srcNs + "." + tableName;
 -    final String destNs = "dst";
++    final String destNs = "dst2";
+     final String dstTableName = destNs + "." + tableName;
+ 
+     try (AccumuloClient client = 
Accumulo.newClient().from(getClientProps()).build()) {
+       client.namespaceOperations().create(srcNs);
+       client.tableOperations().create(srcTableName);
+       client.namespaceOperations().create(destNs);
+       client.securityOperations().createLocalUser(newUserName, new 
PasswordToken(newUserName));
+       // User needs WRITE or ALTER_TABLE on the src table to flush it as part 
of the clone operation
+       client.securityOperations().grantTablePermission(newUserName, 
srcTableName,
+           TablePermission.ALTER_TABLE);
+       client.securityOperations().grantTablePermission(newUserName, 
srcTableName,
+           TablePermission.READ);
+       client.securityOperations().grantNamespacePermission(newUserName, 
destNs,
+           NamespacePermission.CREATE_TABLE);
+     }
+ 
+     try (AccumuloClient client =
+         Accumulo.newClient().to(getCluster().getInstanceName(), 
getCluster().getZooKeepers())
+             .as(newUserName, newUserName).build()) {
+       client.tableOperations().clone(srcTableName, dstTableName, 
CloneConfiguration.empty());
+     }
+   }
  }

Reply via email to