/** * Get the path to secret keys for a specific topology * * @param type the service the secret is for. * @param topologyId the topology the secret is for. * @return the path to the list of secret keys. */ public static String secretKeysPath(WorkerTokenServiceType type, String topologyId) { return secretKeysPath(type) + ZK_SEPERATOR + topologyId; }
/** * Get the path to a specific secret key. * * @param type the service the secret is for. * @param topologyId the topology the secret is for. * @param version the version the secret is for. * @return the path to the secret. */ public static String secretKeysPath(WorkerTokenServiceType type, String topologyId, long version) { return secretKeysPath(type, topologyId) + ZK_SEPERATOR + version; }
@Override public Set<String> idsOfTopologiesWithPrivateWorkerKeys() { HashSet<String> ret = new HashSet<>(); for (WorkerTokenServiceType type : WorkerTokenServiceType.values()) { String path = ClusterUtils.secretKeysPath(type); try { ret.addAll(stateStorage.get_children(path, false)); } catch (RuntimeException e) { //If the node does not exist it is fine/expected... if (!Utils.exceptionCauseIsInstanceOf(KeeperException.NoNodeException.class, e)) { throw e; } } } return ret; } }
@Override public long getNextPrivateWorkerKeyVersion(WorkerTokenServiceType type, String topologyId) { String path = ClusterUtils.secretKeysPath(type, topologyId); try { List<String> versions = stateStorage.get_children(path, false); return versions.stream().mapToLong(Long::valueOf).max().orElse(0); } catch (RuntimeException e) { if (Utils.exceptionCauseIsInstanceOf(KeeperException.NoNodeException.class, e)) { //If the node does not exist, then the version must be 0 return 0; } throw e; } }
@Override public void removeAllPrivateWorkerKeys(String topologyId) { for (WorkerTokenServiceType type : WorkerTokenServiceType.values()) { String path = ClusterUtils.secretKeysPath(type, topologyId); try { LOG.info("Removing worker keys under {}", path); stateStorage.delete_node(path); } catch (RuntimeException e) { //This should never happen because only the primary nimbus is active, but just in case // declare the race safe, even if we lose it. if (!Utils.exceptionCauseIsInstanceOf(KeeperException.NoNodeException.class, e)) { throw e; } } } }
@Override public PrivateWorkerKey getPrivateWorkerKey(WorkerTokenServiceType type, String topologyId, long keyVersion) { String path = ClusterUtils.secretKeysPath(type, topologyId, keyVersion); byte[] data = stateStorage.get_data(path, false); if (data == null) { LOG.debug("Could not find entry at {} will sync to see if that fixes it", path); //We didn't find it, but there are races, so we want to check again after a sync stateStorage.sync_path(path); data = stateStorage.get_data(path, false); } return ClusterUtils.maybeDeserialize(data, PrivateWorkerKey.class); }
@Override public void addPrivateWorkerKey(WorkerTokenServiceType type, String topologyId, long keyVersion, PrivateWorkerKey key) { assert context.getDaemonType() == DaemonType.NIMBUS; stateStorage.mkdirs(ClusterUtils.SECRET_KEYS_SUBTREE, defaultAcls); List<ACL> secretAcls = context.getZkSecretAcls(type); String path = ClusterUtils.secretKeysPath(type, topologyId, keyVersion); LOG.info("Storing private key for {} connecting to a {} at {} with ACL {}", topologyId, type, path, secretAcls); stateStorage.set_data(path, Utils.serialize(key), secretAcls); }
@Override public void removeExpiredPrivateWorkerKeys(String topologyId) { for (WorkerTokenServiceType type : WorkerTokenServiceType.values()) { String basePath = ClusterUtils.secretKeysPath(type, topologyId); try { for (String version : stateStorage.get_children(basePath, false)) { String fullPath = basePath + ClusterUtils.ZK_SEPERATOR + version; try { PrivateWorkerKey key = ClusterUtils.maybeDeserialize(stateStorage.get_data(fullPath, false), PrivateWorkerKey.class); if (Time.currentTimeMillis() > key.get_expirationTimeMillis()) { LOG.info("Removing expired worker key {}", fullPath); stateStorage.delete_node(fullPath); } } catch (RuntimeException e) { //This should never happen because only the primary nimbus is active, but just in case // declare the race safe, even if we lose it. if (!Utils.exceptionCauseIsInstanceOf(KeeperException.NoNodeException.class, e)) { throw e; } } } } catch (RuntimeException e) { //No node for basePath is OK, nothing to remove if (!Utils.exceptionCauseIsInstanceOf(KeeperException.NoNodeException.class, e)) { throw e; } } } }
verifyAclStrictRecursive(zk, superAcl, ClusterUtils.secretKeysPath(WorkerTokenServiceType.NIMBUS), fixUp); verifyAclStrictRecursive(zk, drpcFullAcl, ClusterUtils.secretKeysPath(WorkerTokenServiceType.DRPC), fixUp);