You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by ti...@apache.org on 2023/04/03 08:22:47 UTC
[curator] branch master updated: CURATOR-665: Convey mkdirs exception to create backgorund (#453)
This is an automated email from the ASF dual-hosted git repository.
tison pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/curator.git
The following commit(s) were added to refs/heads/master by this push:
new d1b64d63 CURATOR-665: Convey mkdirs exception to create backgorund (#453)
d1b64d63 is described below
commit d1b64d63d9772495e22154260b1c2634432cd436
Author: tison <wa...@gmail.com>
AuthorDate: Mon Apr 3 16:22:39 2023 +0800
CURATOR-665: Convey mkdirs exception to create backgorund (#453)
Signed-off-by: tison <wa...@gmail.com>
---
.../java/org/apache/curator/utils/ZKPaths.java | 8 +--
.../curator/framework/imps/CreateBuilderImpl.java | 40 ++++++++---
.../x/async/modeled/TestModeledFramework.java | 78 ++++++++++++++++++++--
3 files changed, 107 insertions(+), 19 deletions(-)
diff --git a/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java b/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
index 0e762573..9ac88e16 100644
--- a/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
+++ b/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
@@ -21,6 +21,8 @@ package org.apache.curator.utils;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
+import java.util.Collections;
+import java.util.List;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
@@ -28,8 +30,6 @@ import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collections;
-import java.util.List;
public class ZKPaths
{
@@ -228,7 +228,7 @@ public class ZKPaths
/**
* Extracts the ten-digit suffix from a sequential znode path. Does not currently perform validation on the
* provided path; it will just return a string comprising the last ten characters.
- *
+ *
* @param path the path of a sequential znodes
* @return the sequential suffix
*/
@@ -350,7 +350,7 @@ public class ZKPaths
}
zookeeper.create(subPath, new byte[0], acl, getCreateMode(asContainers));
}
- catch ( KeeperException.NodeExistsException e )
+ catch (KeeperException.NodeExistsException ignore)
{
// ignore... someone else has created it since we checked
}
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
index adca0160..6b52e662 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
@@ -22,9 +22,32 @@ package org.apache.curator.framework.imps;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.curator.RetryLoop;
import org.apache.curator.drivers.OperationTrace;
-import org.apache.curator.framework.api.*;
+import org.apache.curator.framework.api.ACLBackgroundPathAndBytesable;
+import org.apache.curator.framework.api.ACLCreateModeBackgroundPathAndBytesable;
+import org.apache.curator.framework.api.ACLCreateModePathAndBytesable;
+import org.apache.curator.framework.api.ACLCreateModeStatBackgroundPathAndBytesable;
+import org.apache.curator.framework.api.ACLPathAndBytesable;
+import org.apache.curator.framework.api.BackgroundCallback;
+import org.apache.curator.framework.api.BackgroundPathAndBytesable;
+import org.apache.curator.framework.api.CreateBackgroundModeACLable;
+import org.apache.curator.framework.api.CreateBackgroundModeStatACLable;
+import org.apache.curator.framework.api.CreateBuilder;
+import org.apache.curator.framework.api.CreateBuilder2;
+import org.apache.curator.framework.api.CreateBuilderMain;
+import org.apache.curator.framework.api.CreateProtectACLCreateModePathAndBytesable;
+import org.apache.curator.framework.api.CuratorEvent;
+import org.apache.curator.framework.api.CuratorEventType;
+import org.apache.curator.framework.api.ErrorListenerPathAndBytesable;
+import org.apache.curator.framework.api.PathAndBytesable;
+import org.apache.curator.framework.api.ProtectACLCreateModePathAndBytesable;
+import org.apache.curator.framework.api.ProtectACLCreateModeStatPathAndBytesable;
+import org.apache.curator.framework.api.UnhandledErrorListener;
import org.apache.curator.framework.api.transaction.OperationType;
import org.apache.curator.framework.api.transaction.TransactionCreateBuilder;
import org.apache.curator.framework.api.transaction.TransactionCreateBuilder2;
@@ -40,10 +63,6 @@ import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.DataTree;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, BackgroundOperation<PathAndBytes>, ErrorListenerPathAndBytesable<String>
{
@@ -778,6 +797,8 @@ public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, Backgro
{
if ( !client.getZookeeperClient().getRetryPolicy().allowRetry(e) )
{
+ final CuratorEvent event = makeCuratorEvent(client, e.code().intValue(), e.getPath(), null, e.getPath(), null);
+ client.processBackgroundOperation(mainOperationAndData, event);
throw e;
}
// otherwise safe to ignore as it will get retried
@@ -873,12 +894,15 @@ public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, Backgro
}
private void sendBackgroundResponse(int rc, String path, Object ctx, String name, Stat stat, OperationAndData<PathAndBytes> operationAndData)
+ {
+ client.processBackgroundOperation(operationAndData, makeCuratorEvent(client, rc, path, ctx, name, stat));
+ }
+
+ private static CuratorEvent makeCuratorEvent(CuratorFrameworkImpl client, int rc, String path, Object ctx, String name, Stat stat)
{
path = client.unfixForNamespace(path);
name = client.unfixForNamespace(name);
-
- CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.CREATE, rc, path, name, ctx, stat, null, null, null, null, null);
- client.processBackgroundOperation(operationAndData, event);
+ return new CuratorEventImpl(client, CuratorEventType.CREATE, rc, path, name, ctx, stat, null, null, null, null, null);
}
private ACLCreateModePathAndBytesable<String> asACLCreateModePathAndBytesable()
diff --git a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
index a7a22bfd..7f5c6816 100644
--- a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
+++ b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
@@ -25,19 +25,32 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import com.google.common.collect.Sets;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.api.ACLProvider;
import org.apache.curator.framework.schema.Schema;
import org.apache.curator.framework.schema.SchemaSet;
import org.apache.curator.framework.schema.SchemaViolation;
import org.apache.curator.retry.RetryOneTime;
import org.apache.curator.x.async.AsyncCuratorFramework;
import org.apache.curator.x.async.AsyncStage;
+import org.apache.curator.x.async.api.CreateOption;
import org.apache.curator.x.async.api.DeleteOption;
import org.apache.curator.x.async.modeled.models.TestModel;
import org.apache.curator.x.async.modeled.models.TestNewerModel;
import org.apache.curator.x.async.modeled.versioned.Versioned;
import org.apache.curator.x.async.modeled.versioned.VersionedModeledFramework;
+import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
@@ -46,13 +59,6 @@ import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import org.junit.jupiter.api.Test;
-import java.math.BigInteger;
-import java.security.NoSuchAlgorithmException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-
public class TestModeledFramework extends TestModeledFrameworkBase
{
@Test
@@ -222,4 +228,62 @@ public class TestModeledFramework extends TestModeledFrameworkBase
complete(authClient.update(new TestModel("John", "Galt", "Galt's Gulch", 42, BigInteger.valueOf(66))), (__, e) -> assertNull(e, "Should've succeeded"));
}
}
+
+ @Test
+ public void testExceptionHandling() throws Exception
+ {
+ final List<ACL> writeAcl = Collections.singletonList(new ACL(ZooDefs.Perms.WRITE, new Id("digest", DigestAuthenticationProvider.generateDigest("test:test"))));
+
+ // An ACLProvider is used to get the Write ACL (for the test user) for any path "/test/**".
+ final ACLProvider aclProvider = new ACLProvider() {
+ @Override
+ public List<ACL> getDefaultAcl() { return ZooDefs.Ids.READ_ACL_UNSAFE; }
+
+ @Override
+ public List<ACL> getAclForPath(String path)
+ {
+ // Any sub-path "/test/**" should only be writeable by the test user.
+ return path.startsWith("/test") ? writeAcl : getDefaultAcl();
+ }
+ };
+
+ try (CuratorFramework authorizedFramework = CuratorFrameworkFactory.builder()
+ .connectString(server.getConnectString())
+ .retryPolicy(new RetryOneTime(1))
+ .aclProvider(aclProvider)
+ .authorization("digest", "test:test".getBytes())
+ .build()) {
+
+ authorizedFramework.start();
+
+ // Create the parent path using the authorized framework, which will initially set the ACL accordingly.
+ authorizedFramework.create().withMode(CreateMode.PERSISTENT).forPath("/test");
+ }
+
+ // Now attempt to set the sub-node using an unauthorized client.
+ try (CuratorFramework unauthorizedFramework = CuratorFrameworkFactory.builder()
+ .connectString(server.getConnectString())
+ .retryPolicy(new RetryOneTime(1))
+ .aclProvider(aclProvider)
+ .build()) {
+ unauthorizedFramework.start();
+
+ // I overrode the TestModel provided path with a multi-component path under the "/test" parent path
+ // (which was previously created with ACL protection).
+ ModelSpec<TestModel> aclModelSpec = ModelSpec.builder(ZPath.parse("/test/foo/bar"), modelSpec.serializer())
+ .withCreateOptions(EnumSet.of(CreateOption.createParentsIfNeeded, CreateOption.createParentsAsContainers))
+ .build();
+
+ ModeledFramework<TestModel> noAuthClient = ModeledFramework.wrap(AsyncCuratorFramework.wrap(unauthorizedFramework), aclModelSpec);
+
+ noAuthClient.set(new TestModel("John", "Galt", "Galt's Gulch", 42, BigInteger.valueOf(66)))
+ .toCompletableFuture()
+ .get(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS);
+ fail("expect to throw a NoAuth KeeperException");
+ }
+ catch (ExecutionException | CompletionException e)
+ {
+ assertTrue(e.getCause() instanceof KeeperException.NoAuthException);
+ }
+ }
}