Repository: ambari Updated Branches: refs/heads/branch-2.1 03ef6cbe8 -> eb693f80d refs/heads/trunk 2ff92a914 -> 1ff22dffe
AMBARI-13498. Passwords for components should not be readable by end-users (echekanskiy via dlysnichenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/eb693f80 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/eb693f80 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/eb693f80 Branch: refs/heads/branch-2.1 Commit: eb693f80d978077ac2cc522a455158d2b7c849b4 Parents: 03ef6cb Author: Lisnichenko Dmitro <dlysniche...@hortonworks.com> Authored: Thu Oct 22 19:46:13 2015 +0300 Committer: Lisnichenko Dmitro <dlysniche...@hortonworks.com> Committed: Thu Oct 22 19:46:13 2015 +0300 ---------------------------------------------------------------------- .../AmbariManagementControllerImpl.java | 48 +++++- .../controller/ConfigurationResponse.java | 43 +++++- .../org/apache/ambari/server/state/Cluster.java | 19 ++- .../org/apache/ambari/server/state/Config.java | 4 + .../apache/ambari/server/state/ConfigImpl.java | 24 +++ .../server/state/cluster/ClusterImpl.java | 60 +++++++- .../ambari/server/utils/SecretReference.java | 77 ++++++++++ .../AmbariManagementControllerTest.java | 145 +++++++++++++++++++ .../services/HDFS/configuration/hdfs-site.xml | 6 + 9 files changed, 419 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java index d2203fc..60c60cf 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java @@ -160,6 +160,7 @@ import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEve import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent; import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStopEvent; import org.apache.ambari.server.state.svccomphost.ServiceComponentHostUpgradeEvent; +import org.apache.ambari.server.utils.SecretReference; import org.apache.ambari.server.utils.StageUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.IOUtils; @@ -718,6 +719,27 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle Cluster cluster = clusters.getCluster(request.getClusterName()); + Map<String, String> requestProperties = request.getProperties(); + + Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes = cluster.getConfigPropertiesTypes(request.getType()); + if(propertiesTypes.containsKey(PropertyType.PASSWORD)) { + for(String passwordProperty : propertiesTypes.get(PropertyType.PASSWORD)) { + if(requestProperties.containsKey(passwordProperty)) { + String passwordPropertyValue = requestProperties.get(passwordProperty); + if (!SecretReference.isSecret(passwordPropertyValue)) + continue; + SecretReference ref = new SecretReference(passwordPropertyValue, passwordProperty, cluster); + if (!ref.getClusterName().equals(request.getClusterName())) + throw new AmbariException("Can not reference to different cluster in SECRET"); + String refValue = ref.getValue(); + requestProperties.put(passwordProperty, refValue); + } + } + } + + + + Map<String, Config> configs = cluster.getConfigsByType( request.getType()); if (null == configs) { @@ -738,7 +760,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle handleGlobalsBackwardsCompability(request, propertiesAttributes); - Config config = createConfig(cluster, request.getType(), request.getProperties(), + Config config = createConfig(cluster, request.getType(), requestProperties, request.getVersionTag(), propertiesAttributes); return new ConfigurationResponse(cluster.getClusterName(), config); @@ -1214,7 +1236,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle request.getType(), config.getTag(), entry.getValue().getVersion(), includeProps ? config.getProperties() : new HashMap<String, String>(), - includeProps ? config.getPropertiesAttributes() : new HashMap<String, Map<String,String>>()); + includeProps ? config.getPropertiesAttributes() : new HashMap<String, Map<String,String>>(), + config.getPropertiesTypes()); responses.add(response); } } @@ -1227,7 +1250,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle cluster.getClusterName(), config.getStackId(), config.getType(), config.getTag(), config.getVersion(), includeProps ? config.getProperties() : new HashMap<String, String>(), - includeProps ? config.getPropertiesAttributes() : new HashMap<String, Map<String,String>>()); + includeProps ? config.getPropertiesAttributes() : new HashMap<String, Map<String,String>>(), + config.getPropertiesTypes()); responses.add(response); } @@ -1364,6 +1388,24 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle if (request.getDesiredConfig() != null) { for (ConfigurationRequest desiredConfig : request.getDesiredConfig()) { Map<String, String> requestConfigProperties = desiredConfig.getProperties(); + + // processing password properties + if(requestConfigProperties != null && !requestConfigProperties.isEmpty()) { + Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes = cluster.getConfigPropertiesTypes( + desiredConfig.getType() + ); + for (Entry<String, String> property : requestConfigProperties.entrySet()) { + String propertyName = property.getKey(); + String propertyValue = property.getValue(); + if (propertiesTypes.containsKey(PropertyType.PASSWORD) && + propertiesTypes.get(PropertyType.PASSWORD).contains(propertyName)) { + if (SecretReference.isSecret(propertyValue)) { + SecretReference ref = new SecretReference(propertyValue, propertyName, cluster); + requestConfigProperties.put(propertyName, ref.getValue()); + } + } + } + } Map<String,Map<String,String>> requestConfigAttributes = desiredConfig.getPropertiesAttributes(); Config clusterConfig = cluster.getDesiredConfigByType(desiredConfig.getType()); Map<String, String> clusterConfigProperties = null; http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java index d6b95c8..3ed9306 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java @@ -19,9 +19,12 @@ package org.apache.ambari.server.controller; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.ambari.server.state.Config; +import org.apache.ambari.server.state.PropertyInfo; import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.utils.SecretReference; /** * This class encapsulates a configuration update request. @@ -46,6 +49,8 @@ public class ConfigurationResponse { private Map<String, Map<String, String>> configAttributes; + private Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes; + public ConfigurationResponse(String clusterName, StackId stackId, String type, String versionTag, Long version, Map<String, String> configs, @@ -60,6 +65,23 @@ public class ConfigurationResponse { this.configAttributes = configAttributes; } + public ConfigurationResponse(String clusterName, StackId stackId, + String type, String versionTag, Long version, + Map<String, String> configs, + Map<String, Map<String, String>> configAttributes, + Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes) { + this.clusterName = clusterName; + this.stackId = stackId; + this.configs = configs; + this.type = type; + this.versionTag = versionTag; + this.version = version; + this.configs = configs; + this.configAttributes = configAttributes; + this.propertiesTypes = propertiesTypes; + stubPasswords(); + } + /** * Constructor. * @@ -69,7 +91,7 @@ public class ConfigurationResponse { public ConfigurationResponse(String clusterName, Config config) { this(clusterName, config.getStackId(), config.getType(), config.getTag(), config.getVersion(), config.getProperties(), - config.getPropertiesAttributes()); + config.getPropertiesAttributes(), config.getPropertiesTypes()); } /** @@ -185,4 +207,23 @@ public class ConfigurationResponse { public void setServiceConfigVersions(List<Long> serviceConfigVersions) { this.serviceConfigVersions = serviceConfigVersions; } + + public Map<PropertyInfo.PropertyType, Set<String>> getPropertiesTypes() { + return propertiesTypes; + } + + public void setPropertiesTypes(Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes) { + this.propertiesTypes = propertiesTypes; + } + + private void stubPasswords(){ + if(propertiesTypes != null && propertiesTypes.containsKey(PropertyInfo.PropertyType.PASSWORD)) { + for(String pwdPropertyName: propertiesTypes.get(PropertyInfo.PropertyType.PASSWORD)) { + if(configs.containsKey(pwdPropertyName)){ + String stub = SecretReference.generateStub(clusterName, type, version); + configs.put(pwdPropertyName, stub); + } + } + } + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java index 2f3641d..affd3a8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java @@ -301,16 +301,33 @@ public interface Cluster { Map<String, Config> getConfigsByType(String configType); /** + * Gets all properties types that mach the specified type. + * @param configType the config type to return + * @return properties types for given config type + */ + Map<PropertyInfo.PropertyType, Set<String>> getConfigPropertiesTypes(String configType); + + /** * Gets the specific config that matches the specified type and tag. This not * necessarily a DESIRED configuration that applies to a cluster. * @param configType the config type to find - * @param versionTag the config version to find + * @param versionTag the config version tag to find * @return a {@link Config} object, or <code>null</code> if the specific type * and version have not been set. */ Config getConfig(String configType, String versionTag); /** + * Gets the specific config that matches the specified type and version. This not + * necessarily a DESIRED configuration that applies to a cluster. + * @param configType the config type to find + * @param configVersion the config version to find + * @return a {@link Config} object, or <code>null</code> if the specific type + * and version have not been set. + */ + Config getConfigByVersion(String configType, Long configVersion); + + /** * Sets a specific config. NOTE: This is not a DESIRED configuration that * applies to a cluster. * @param config the config instance to add http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java index e18505a..b35aad9 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java @@ -20,11 +20,15 @@ package org.apache.ambari.server.state; import java.util.List; import java.util.Map; +import java.util.Set; /** * Represents a single instance of a 'Config Type' */ public interface Config { + Map<PropertyInfo.PropertyType, Set<String>> getPropertiesTypes(); + + void setPropertiesTypes(Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes); void setStackId(StackId stackId); http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java index ea6aecd..2cc3d00 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -58,6 +59,7 @@ public class ConfigImpl implements Config { private volatile Map<String, String> properties; private volatile Map<String, Map<String, String>> propertiesAttributes; private ClusterConfigEntity entity; + private volatile Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes; @Inject private ClusterDAO clusterDAO; @@ -81,6 +83,7 @@ public class ConfigImpl implements Config { stackId = cluster.getDesiredStackVersion(); injector.injectMembers(this); + propertiesTypes = cluster.getConfigPropertiesTypes(type); } @@ -96,6 +99,7 @@ public class ConfigImpl implements Config { this.entity = entity; injector.injectMembers(this); + propertiesTypes = cluster.getConfigPropertiesTypes(type); } /** @@ -120,6 +124,26 @@ public class ConfigImpl implements Config { } @Override + public Map<PropertyInfo.PropertyType, Set<String>> getPropertiesTypes() { + readWriteLock.readLock().lock(); + try { + return propertiesTypes; + } finally { + readWriteLock.readLock().unlock(); + } + } + + @Override + public void setPropertiesTypes(Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes) { + readWriteLock.writeLock().lock(); + try { + this.propertiesTypes = propertiesTypes; + } finally { + readWriteLock.writeLock().unlock(); + } + } + + @Override public void setStackId(StackId stackId) { readWriteLock.writeLock().lock(); try { http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java index 45369ee..4e37e14 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java @@ -109,6 +109,8 @@ import org.apache.ambari.server.state.ServiceFactory; import org.apache.ambari.server.state.ServiceInfo; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.State; +import org.apache.ambari.server.state.PropertyInfo; +import org.apache.ambari.server.state.StackInfo; import org.apache.ambari.server.state.configgroup.ConfigGroup; import org.apache.ambari.server.state.configgroup.ConfigGroupFactory; import org.apache.ambari.server.state.fsm.InvalidStateTransitionException; @@ -253,6 +255,8 @@ public class ClusterImpl implements Cluster { private volatile Multimap<String, String> serviceConfigTypes; + private Map<String, Map<PropertyInfo.PropertyType, Set<String>>> configProperiesTypesCache; + @Inject public ClusterImpl(@Assisted ClusterEntity clusterEntity, Injector injector) throws AmbariException { @@ -267,6 +271,8 @@ public class ClusterImpl implements Cluster { desiredStackVersion = new StackId(clusterEntity.getDesiredStack()); + configProperiesTypesCache = new HashMap<>(); + cacheConfigurations(); if (desiredStackVersion != null && !StringUtils.isEmpty(desiredStackVersion.getStackName()) && ! @@ -1251,7 +1257,7 @@ public class ClusterImpl implements Cluster { // Also returns when have a mix of CURRENT and INSTALLING|INSTALLED|UPGRADING|UPGRADED LOG.warn("have a mix of CURRENT and INSTALLING|INSTALLED|UPGRADING|UPGRADED host versions, " + - "returning OUT_OF_SYNC as cluster version. Host version states: " + stateToHosts.toString()); + "returning OUT_OF_SYNC as cluster version. Host version states: " + stateToHosts.toString()); return RepositoryVersionState.OUT_OF_SYNC; } @@ -1779,6 +1785,23 @@ public class ClusterImpl implements Cluster { } @Override + public Config getConfigByVersion(String configType, Long configVersion) { + clusterGlobalLock.readLock().lock(); + try { + if (!allConfigs.containsKey(configType)) { + return null; + } + for(Map.Entry<String, Config> entry: allConfigs.get(configType).entrySet()) { + if(entry.getValue().getVersion().equals(configVersion)) + return entry.getValue(); + } + return null; + } finally { + clusterGlobalLock.readLock().unlock(); + } + } + + @Override public void addConfig(Config config) { clusterGlobalLock.writeLock().lock(); try { @@ -2205,7 +2228,7 @@ public class ClusterImpl implements Cluster { serviceConfigVersionResponse.getConfigurations().add( new ConfigurationResponse(getClusterName(), config.getStackId(), config.getType(), config.getTag(), config.getVersion(), - config.getProperties(), config.getPropertiesAttributes())); + config.getProperties(), config.getPropertiesAttributes(), config.getPropertiesTypes())); } serviceConfigVersionResponses.add(serviceConfigVersionResponse); @@ -2889,6 +2912,39 @@ public class ClusterImpl implements Cluster { * {@inheritDoc} */ @Override + public synchronized Map<PropertyInfo.PropertyType, Set<String>> getConfigPropertiesTypes(String configType){ + if(configProperiesTypesCache.containsKey(configType)) { + return configProperiesTypesCache.get(configType); + } else { + Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes = new HashMap<>(); + try { + StackId stackId = this.getCurrentStackVersion(); + StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion()); + Collection<ServiceInfo> services = stackInfo.getServices(); + for (ServiceInfo serviceInfo : services) { + for (PropertyInfo propertyInfo : serviceInfo.getProperties()) { + if (propertyInfo.getFilename().contains(configType) && !propertyInfo.getPropertyTypes().isEmpty()) { + Set<PropertyInfo.PropertyType> types = propertyInfo.getPropertyTypes(); + for (PropertyInfo.PropertyType propertyType : types) { + if (!propertiesTypes.containsKey(propertyType)) + propertiesTypes.put(propertyType, new HashSet<String>()); + propertiesTypes.get(propertyType).add(propertyInfo.getName()); + } + } + } + } + } catch (Exception e) { + + } + configProperiesTypesCache.put(configType, propertiesTypes); + return propertiesTypes; + } + } + + /** + * {@inheritDoc} + */ + @Override @Transactional public void removeConfigurations(StackId stackId) { clusterGlobalLock.writeLock().lock(); http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java new file mode 100644 index 0000000..2b1aeae --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java @@ -0,0 +1,77 @@ +/** + * 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.ambari.server.utils; + +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Config; + +import java.util.Map; + +public class SecretReference { + private String clusterName; + private String configType; + private Long version; + private String value; + private String reference; + + public SecretReference(String reference, String propertyName, Cluster cluster) throws AmbariException{ + String[] values = reference.split(":"); + clusterName = values[1]; + configType = values[2]; + version = Long.valueOf(values[3]); + Config refConfig = cluster.getConfigByVersion(configType, version); + + if(refConfig == null) + throw new AmbariException(String.format("Cluster: %s does not contain ConfigType: %s ConfigVersion: %s", + cluster.getClusterName(), configType, version)); + Map<String, String> refProperties = refConfig.getProperties(); + if(!refProperties.containsKey(propertyName)) + throw new AmbariException(String.format("Cluster: %s ConfigType: %s ConfigVersion: %s does not contain property '%s'", + cluster.getClusterName(), configType, version, propertyName)); + this.value = refProperties.get(propertyName); + + this.reference = reference; + } + + public String getClusterName() { + return clusterName; + } + + public void setConfigType(String configType) { + this.configType = configType; + } + + public Long getVersion() { + return version; + } + + public String getValue() { + return value; + } + + public static boolean isSecret(String value) { + String[] values = value.split(":"); + return values.length == 4 && values[0].equals("SECRET"); + } + + public static String generateStub(String clusterName, String configType, Long configVersion) { + return "SECRET:" + clusterName + ":" + configType + ":" + configVersion.toString(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java index 204b865..1aa1a6f 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java @@ -10542,6 +10542,151 @@ public class AmbariManagementControllerTest { } @Test + public void testSecretReferences() throws AmbariException { + + final String host1 = "h1"; + final String host2 = "h2"; + Long clusterId = 1L; + String clusterName = "foo1"; + Cluster cl = setupClusterWithHosts(clusterName, "HDP-2.0.5", new ArrayList<String>() { + { + add(host1); + add(host2); + } + }, "centos5"); + String serviceName = "HDFS"; + createService(clusterName, serviceName, null); + String componentName1 = "NAMENODE"; + String componentName2 = "DATANODE"; + String componentName3 = "HDFS_CLIENT"; + + createServiceComponent(clusterName, serviceName, componentName1, State.INIT); + createServiceComponent(clusterName, serviceName, componentName2, State.INIT); + createServiceComponent(clusterName, serviceName, componentName3, State.INIT); + + createServiceComponentHost(clusterName, serviceName, componentName1, host1, null); + createServiceComponentHost(clusterName, serviceName, componentName2, host1, null); + createServiceComponentHost(clusterName, serviceName, componentName3, host1, null); + createServiceComponentHost(clusterName, serviceName, componentName2, host2, null); + createServiceComponentHost(clusterName, serviceName, componentName3, host2, null); + + // Install + installService(clusterName, serviceName, false, false); + + ClusterRequest crReq; + ConfigurationRequest cr; + + cr = new ConfigurationRequest(clusterName, + "hdfs-site", + "version1", + new HashMap<String, String>(){{ + put("test.password", "first"); + }}, + new HashMap<String, Map<String, String>>() + ); + crReq = new ClusterRequest(clusterId, clusterName, null, null); + crReq.setDesiredConfig(Collections.singletonList(cr)); + controller.updateClusters(Collections.singleton(crReq), null); + // update config with secret reference + cr = new ConfigurationRequest(clusterName, + "hdfs-site", + "version2", + new HashMap<String, String>(){{ + put("test.password", "SECRET:c1:hdfs-site:1"); + put("new", "new");//need this to mark config as "changed" + }}, + new HashMap<String, Map<String, String>>() + ); + crReq = new ClusterRequest(clusterId, clusterName, null, null); + crReq.setDesiredConfig(Collections.singletonList(cr)); + controller.updateClusters(Collections.singleton(crReq), null); + // change password to new value + cr = new ConfigurationRequest(clusterName, + "hdfs-site", + "version3", + new HashMap<String, String>(){{ + put("test.password", "brandNewPassword"); + }}, + new HashMap<String, Map<String, String>>() + ); + crReq = new ClusterRequest(clusterId, clusterName, null, null); + crReq.setDesiredConfig(Collections.singletonList(cr)); + controller.updateClusters(Collections.singleton(crReq), null); + // wrong secret reference + cr = new ConfigurationRequest(clusterName, + "hdfs-site", + "version3", + new HashMap<String, String>(){{ + put("test.password", "SECRET:c1:hdfs-site:666"); + }}, + new HashMap<String, Map<String, String>>() + ); + crReq = new ClusterRequest(clusterId, clusterName, null, null); + crReq.setDesiredConfig(Collections.singletonList(cr)); + try { + controller.updateClusters(Collections.singleton(crReq), null); + fail("Request need to be failed with wrong secret reference"); + } catch (AmbariException e){ + + } + // reference to config which does not contain requested property + cr = new ConfigurationRequest(clusterName, + "hdfs-site", + "version4", + new HashMap<String, String>(){{ + put("foo", "bar"); + }}, + new HashMap<String, Map<String, String>>() + ); + crReq = new ClusterRequest(clusterId, clusterName, null, null); + crReq.setDesiredConfig(Collections.singletonList(cr)); + controller.updateClusters(Collections.singleton(crReq), null); + cr = new ConfigurationRequest(clusterName, + "hdfs-site", + "version5", + new HashMap<String, String>(){{ + put("test.password", "SECRET:c1:hdfs-site:4"); + put("new", "new"); + }}, + new HashMap<String, Map<String, String>>() + ); + crReq = new ClusterRequest(clusterId, clusterName, null, null); + crReq.setDesiredConfig(Collections.singletonList(cr)); + try { + controller.updateClusters(Collections.singleton(crReq), null); + fail("Request need to be failed with wrong secret reference"); + } catch (AmbariException e) { + assertEquals("Cluster: foo1 ConfigType: hdfs-site ConfigVersion: 4 does not contain property 'test.password'", + e.getMessage()); + } + cl.getAllConfigs(); + assertEquals(cl.getAllConfigs().size(), 4); + + Config v1 = cl.getConfigByVersion("hdfs-site", 1l); + Config v2 = cl.getConfigByVersion("hdfs-site", 2l); + Config v3 = cl.getConfigByVersion("hdfs-site", 3l); + Config v4 = cl.getConfigByVersion("hdfs-site", 4l); + + assertEquals(v1.getProperties().get("test.password"), "first"); + assertEquals(v2.getProperties().get("test.password"), "first"); + assertEquals(v3.getProperties().get("test.password"), "brandNewPassword"); + assertFalse(v4.getProperties().containsKey("test.password")); + + // check if we have masked secret in responce + final ConfigurationRequest configRequest = new ConfigurationRequest(clusterName, "hdfs-site", null, null, null); + configRequest.setIncludeProperties(true); + Set<ConfigurationResponse> requestedConfigs = controller.getConfigurations(new HashSet<ConfigurationRequest>() {{ + add(configRequest); + }}); + for(ConfigurationResponse resp : requestedConfigs) { + String secretName = "SECRET:foo1:hdfs-site:"+resp.getVersion().toString(); + if(resp.getConfigs().containsKey("test.password")) { + assertEquals(resp.getConfigs().get("test.password"), secretName); + } + } + } + + @Test public void testTargetedProcessCommand() throws Exception { final String host1 = "h1"; String clusterName = "c1"; http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml index 246b2f9..f53c667 100644 --- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml +++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml @@ -23,6 +23,12 @@ <configuration> <!-- file system properties --> + <property> + <name>test.password</name> + <property-type>PASSWORD</property-type> + <value>test</value> + <description>1</description> + </property> <property> <name>dfs.namenode.name.dir</name>