Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CURATOR-728: Not issue ZooKeeper::create if possible in ZkPaths::mkdirs #518

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
Original file line number Diff line number Diff line change
Expand Up @@ -282,28 +282,29 @@ public static void mkdirs(ZooKeeper zookeeper, String path, boolean makeLastNode
*/
public static void mkdirs(
ZooKeeper zookeeper,
String path,
final String path,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Params are by default not be mutated. I suppose we don't need final to params.

kezhuw marked this conversation as resolved.
Show resolved Hide resolved
boolean makeLastNode,
InternalACLProvider aclProvider,
boolean asContainers)
throws InterruptedException, KeeperException {
PathUtils.validatePath(path);

int pos = path.length();
String subPath;

// This first loop locates the first parent that doesn't exist from leaf nodes towards root
// This first loop locates the first node that doesn't exist from leaf nodes towards root
// this way, it is not required to have read access on all parents.
// This is relevant after https://issues.apache.org/jira/browse/ZOOKEEPER-2590.

int pos = path.length();
do {
String subPath = path.substring(0, pos);
if (zookeeper.exists(subPath, false) != null) {
break;
}
pos = path.lastIndexOf(PATH_SEPARATOR_CHAR, pos - 1);
subPath = path.substring(0, pos);
} while (pos > 0 && zookeeper.exists(subPath, false) == null);
} while (pos > 0);

// Start creating the subtree after the longest path that exists, assuming root always exists.

do {
while (pos < path.length()) {
pos = path.indexOf(PATH_SEPARATOR_CHAR, pos + 1);

if (pos == -1) {
Expand All @@ -314,7 +315,7 @@ public static void mkdirs(
}
}

subPath = path.substring(0, pos);
String subPath = path.substring(0, pos);

// All the paths from the initial `pos` do not exist.
try {
Expand All @@ -332,8 +333,8 @@ public static void mkdirs(
} catch (KeeperException.NodeExistsException ignore) {
// ignore... someone else has created it since we checked
}

} while (pos < path.length());
}
;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

public class TestCreate extends BaseClassForTests {
Expand Down Expand Up @@ -684,6 +685,7 @@ public void testProtectedUtils() throws Exception {
* but just to the first ancestor parent. (See https://issues.apache.org/jira/browse/ZOOKEEPER-2590)
*/
@Test
@Tag("ZOOKEEPER-2590")
public void testForbiddenAncestors() throws Exception {
CuratorFramework client = createClient(testACLProvider);
try {
Expand All @@ -696,9 +698,10 @@ public void testForbiddenAncestors() throws Exception {

// In creation attempts where the parent ("/bat") has ACL that restricts read, creation request fails.
try {
client.create().creatingParentsIfNeeded().forPath("/bat/bost");
client.create().creatingParentsIfNeeded().forPath("/bat/foo/bost");
fail("Expected NoAuthException when not authorized to read new node grandparent");
} catch (KeeperException.NoAuthException noAuthException) {
assertEquals(noAuthException.getPath(), "/bat");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old test reported NoAuth on creating /bat/bost. I think this is not the target CURATOR-715 trying to assert.

}

// But creating a node in the same subtree where its grandparent has read access is allowed and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@

package org.apache.curator.framework.imps;

import static org.apache.zookeeper.ZooDefs.Ids.ANYONE_ID_UNSAFE;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Collections;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.EnsureContainers;
import org.apache.curator.retry.RetryOneTime;
import org.apache.curator.test.BaseClassForTests;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.junit.jupiter.api.Test;

public class TestEnsureContainers extends BaseClassForTests {
Expand Down Expand Up @@ -63,4 +69,31 @@ public void testSingleExecution() throws Exception {
CloseableUtils.closeQuietly(client);
}
}

@Test
public void testNodeExistsButNoCreatePermission() throws Exception {
CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), new RetryOneTime(1));
try {
client.start();

// given: "/bar/foo" created
client.create().creatingParentsIfNeeded().forPath("/bar/foo");
// given: only permission read to "/bar"
client.setACL()
.withACL(Collections.singletonList(new ACL(ZooDefs.Perms.READ, ANYONE_ID_UNSAFE)))
.forPath("/bar");

// check: create "/bar/foo" will fail with NoAuth
assertThrows(KeeperException.NoAuthException.class, () -> {
client.create().forPath("/bar/foo");
});

// when: mkdirs("/bar/foo")
// then: everything fine as "/bar/foo" exists, and we have READ permission
EnsureContainers ensureContainers = new EnsureContainers(client, "/bar/foo");
ensureContainers.ensure();
} finally {
CloseableUtils.closeQuietly(client);
}
}
}
2 changes: 1 addition & 1 deletion curator-test-zk37/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@
<dependency>org.apache.curator:curator-recipes</dependency>
<dependency>org.apache.curator:curator-client</dependency>
</dependenciesToScan>
<excludedGroups>master</excludedGroups>
<excludedGroups>master,ZOOKEEPER-2590</excludedGroups>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZOOKEEPER-2590 is never landed in 3.7 though it is tagged with 3.7.3.

</configuration>
</plugin>
</plugins>
Expand Down
2 changes: 1 addition & 1 deletion curator-test-zk38/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<artifactId>curator-test-zk38</artifactId>

<properties>
<zookeeper-38-version>3.8.3</zookeeper-38-version>
<zookeeper-38-version>3.8.4</zookeeper-38-version>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZOOKEEPER-2590 is landed in 3.8.4.

</properties>

<dependencies>
Expand Down
Loading