countsMap, String errMsg)
throws IOException {
for (int i = 1; i <= numDecomNodes; i++) {
- if (datanode.getHostName().equals(counts.get("tag.datanode." + i).asText())) {
+ String datanodeHostName =
+ (counts.get("tag.datanode." + i) != null) ? (counts.get("tag.datanode." + i).asText()) : "";
+ if (datanode.getHostName().equals(datanodeHostName)) {
JsonNode pipelinesDN = counts.get("PipelinesWaitingToCloseDN." + i);
JsonNode underReplicatedDN = counts.get("UnderReplicatedDN." + i);
JsonNode unclosedDN = counts.get("UnclosedContainersDN." + i);
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/DelegatingProperties.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/DelegatingProperties.java
new file mode 100644
index 000000000000..bbf18aff8dc9
--- /dev/null
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/DelegatingProperties.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hdds.conf;
+
+import org.apache.hadoop.ozone.OzoneConfigKeys;
+import org.apache.hadoop.util.StringUtils;
+
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SECURITY_CRYPTO_COMPLIANCE_MODE_UNRESTRICTED;
+
+/**
+ * Delegating properties helper class. It's needed for configuration related classes, so we are able
+ * to delegate the operations that are happening on their Properties object to their parent's
+ * Properties object. This is needed because of the configuration compliance checks.
+ */
+public class DelegatingProperties extends Properties {
+ private final Properties properties;
+ private final String complianceMode;
+ private final boolean checkCompliance;
+ private final Properties cryptoProperties;
+
+ public DelegatingProperties(Properties properties, String complianceMode, Properties cryptoProperties) {
+ this.properties = properties;
+ this.complianceMode = complianceMode;
+ this.checkCompliance = !complianceMode.equals(OZONE_SECURITY_CRYPTO_COMPLIANCE_MODE_UNRESTRICTED);
+ this.cryptoProperties = cryptoProperties;
+ }
+
+ public String checkCompliance(String config, String value) {
+ // Don't check the ozone.security.crypto.compliance.mode config, even though it's tagged as a crypto config
+ if (checkCompliance && cryptoProperties.containsKey(config) &&
+ !config.equals(OzoneConfigKeys.OZONE_SECURITY_CRYPTO_COMPLIANCE_MODE)) {
+
+ String whitelistConfig = config + "." + complianceMode + ".whitelist";
+ String whitelistValue = properties.getProperty(whitelistConfig, "");
+
+ if (whitelistValue != null) {
+ Collection whitelistOptions = StringUtils.getTrimmedStringCollection(whitelistValue);
+
+ if (!whitelistOptions.contains(value)) {
+ throw new ConfigurationException("Not allowed configuration value! Compliance mode is set to " +
+ complianceMode + " and " + config + " configuration's value is not allowed. Please check the " +
+ whitelistConfig + " configuration.");
+ }
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public String getProperty(String key) {
+ String value = properties.getProperty(key);
+ return checkCompliance(key, value);
+ }
+
+ @Override
+ public Object setProperty(String key, String value) {
+ return properties.setProperty(key, value);
+ }
+
+ @Override
+ public synchronized Object remove(Object key) {
+ return properties.remove(key);
+ }
+
+ @Override
+ public synchronized void clear() {
+ properties.clear();
+ }
+
+ @Override
+ public Enumeration