HDFS-11403. Zookeper ACLs on NN HA enabled clusters should be handled consistently. Contributed by Hanisha Koneru.
This commit is contained in:
parent
33c62d2d19
commit
32a0c2b5e7
|
@ -346,8 +346,13 @@ public class ActiveStandbyElector implements StatCallback, StringCallback {
|
||||||
createWithRetries(prefixPath, new byte[]{}, zkAcl, CreateMode.PERSISTENT);
|
createWithRetries(prefixPath, new byte[]{}, zkAcl, CreateMode.PERSISTENT);
|
||||||
} catch (KeeperException e) {
|
} catch (KeeperException e) {
|
||||||
if (isNodeExists(e.code())) {
|
if (isNodeExists(e.code())) {
|
||||||
// This is OK - just ensuring existence.
|
// Set ACLs for parent node, if they do not exist or are different
|
||||||
continue;
|
try {
|
||||||
|
setAclsWithRetries(prefixPath);
|
||||||
|
} catch (KeeperException e1) {
|
||||||
|
throw new IOException("Couldn't set ACLs on parent ZNode: " +
|
||||||
|
prefixPath, e1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("Couldn't create " + prefixPath, e);
|
throw new IOException("Couldn't create " + prefixPath, e);
|
||||||
}
|
}
|
||||||
|
@ -1066,14 +1071,36 @@ public class ActiveStandbyElector implements StatCallback, StringCallback {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setAclsWithRetries(final String path)
|
||||||
|
throws KeeperException, InterruptedException {
|
||||||
|
Stat stat = new Stat();
|
||||||
|
zkDoWithRetries(new ZKAction<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws KeeperException, InterruptedException {
|
||||||
|
List<ACL> acl = zkClient.getACL(path, stat);
|
||||||
|
if (acl == null || !acl.containsAll(zkAcl) ||
|
||||||
|
!zkAcl.containsAll(acl)) {
|
||||||
|
zkClient.setACL(path, zkAcl, stat.getVersion());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, Code.BADVERSION);
|
||||||
|
}
|
||||||
|
|
||||||
private <T> T zkDoWithRetries(ZKAction<T> action) throws KeeperException,
|
private <T> T zkDoWithRetries(ZKAction<T> action) throws KeeperException,
|
||||||
InterruptedException {
|
InterruptedException {
|
||||||
|
return zkDoWithRetries(action, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T zkDoWithRetries(ZKAction<T> action, Code retryCode)
|
||||||
|
throws KeeperException, InterruptedException {
|
||||||
int retry = 0;
|
int retry = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
return action.run();
|
return action.run();
|
||||||
} catch (KeeperException ke) {
|
} catch (KeeperException ke) {
|
||||||
if (shouldRetry(ke.code()) && ++retry < maxRetryNum) {
|
if ((shouldRetry(ke.code()) || shouldRetry(ke.code(), retryCode))
|
||||||
|
&& ++retry < maxRetryNum) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
throw ke;
|
throw ke;
|
||||||
|
@ -1189,6 +1216,10 @@ public class ActiveStandbyElector implements StatCallback, StringCallback {
|
||||||
private static boolean shouldRetry(Code code) {
|
private static boolean shouldRetry(Code code) {
|
||||||
return code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT;
|
return code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean shouldRetry(Code code, Code retryIfCode) {
|
||||||
|
return (retryIfCode == null ? false : retryIfCode == code);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -715,6 +715,37 @@ public class TestActiveStandbyElector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that ACLs are set on parent zNode even if the node already exists.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParentZNodeACLs() throws Exception {
|
||||||
|
KeeperException ke = new KeeperException(Code.NODEEXISTS) {
|
||||||
|
@Override
|
||||||
|
public Code code() {
|
||||||
|
return super.code();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mockito.when(mockZK.create(Mockito.anyString(), Mockito.eq(new byte[]{}),
|
||||||
|
Mockito.anyListOf(ACL.class),
|
||||||
|
Mockito.eq(CreateMode.PERSISTENT))).thenThrow(ke);
|
||||||
|
|
||||||
|
elector.ensureParentZNode();
|
||||||
|
|
||||||
|
StringBuilder prefix = new StringBuilder();
|
||||||
|
for (String part : ZK_PARENT_NAME.split("/")) {
|
||||||
|
if (part.isEmpty()) continue;
|
||||||
|
prefix.append("/").append(part);
|
||||||
|
if (!"/".equals(prefix.toString())) {
|
||||||
|
Mockito.verify(mockZK).getACL(Mockito.eq(prefix.toString()),
|
||||||
|
Mockito.eq(new Stat()));
|
||||||
|
Mockito.verify(mockZK).setACL(Mockito.eq(prefix.toString()),
|
||||||
|
Mockito.eq(Ids.OPEN_ACL_UNSAFE), Mockito.anyInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for a bug encountered during development of HADOOP-8163:
|
* Test for a bug encountered during development of HADOOP-8163:
|
||||||
|
|
Loading…
Reference in New Issue