浏览代码

AMBARI-20136. Services should be able to specify that credential store is always enabled (smohanty)

Sumit Mohanty 8 年之前
父节点
当前提交
503d95f80b
共有 19 个文件被更改,包括 333 次插入105 次删除
  1. 18 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java
  2. 24 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceResponse.java
  3. 31 9
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
  4. 12 6
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java
  5. 90 68
      ambari-server/src/main/java/org/apache/ambari/server/state/CredentialStoreInfo.java
  6. 7 0
      ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
  7. 13 1
      ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
  8. 29 0
      ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
  9. 1 0
      ambari-server/src/main/resources/properties.json
  10. 0 4
      ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml
  11. 0 4
      ambari-server/src/main/resources/stacks/HDP/2.4/services/RANGER/metainfo.xml
  12. 0 4
      ambari-server/src/main/resources/stacks/HDP/2.5/services/RANGER/metainfo.xml
  13. 0 4
      ambari-server/src/main/resources/stacks/HDP/2.6/services/RANGER/metainfo.xml
  14. 83 0
      ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
  15. 5 2
      ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
  16. 4 0
      ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java
  17. 5 1
      ambari-server/src/test/resources/stacks/HDP/2.2.0/services/HDFS/metainfo.xml
  18. 6 0
      ambari-server/src/test/resources/stacks/HDP/2.2.0/services/STORM/metainfo.xml
  19. 5 1
      ambari-server/src/test/resources/stacks/HDP/2.2.0/services/ZOOKEEPER/metainfo.xml

+ 18 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java

@@ -26,6 +26,7 @@ public class ServiceRequest {
   private String desiredState; // CREATE/UPDATE
   private String maintenanceState; // UPDATE
   private String credentialStoreEnabled; // CREATE/UPDATE/GET
+  private String credentialStoreSupported; //GET
 
   public ServiceRequest(String clusterName, String serviceName,
                         String desiredState) {
@@ -107,6 +108,14 @@ public class ServiceRequest {
     return credentialStoreEnabled;
   }
 
+
+  /**
+   * @return credential store supported
+   */
+  public String getCredentialStoreSupported() {
+    return credentialStoreSupported;
+  }
+
   /**
    * @param credentialStoreEnabled the new credential store enabled
    */
@@ -114,12 +123,20 @@ public class ServiceRequest {
     this.credentialStoreEnabled = credentialStoreEnabled;
   }
 
+  /**
+   * @param credentialStoreSupported the new credential store supported
+   */
+  public void setCredentialStoreSupported(String credentialStoreSupported) {
+    this.credentialStoreSupported = credentialStoreSupported;
+  }
+
   public String toString() {
     StringBuilder sb = new StringBuilder();
     sb.append("clusterName=" + clusterName
         + ", serviceName=" + serviceName
         + ", desiredState=" + desiredState
-        + ", credentialStoreEnabled=" + credentialStoreEnabled);
+        + ", credentialStoreEnabled=" + credentialStoreEnabled
+        + ", credentialStoreSupported=" + credentialStoreSupported);
     return sb.toString();
   }
 }

+ 24 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceResponse.java

@@ -69,6 +69,12 @@ public class StackServiceResponse {
    */
   private boolean credentialStoreEnabled;
 
+  /**
+   * Indicates if the stack definition says this service requires
+   * credential store use. If not specified, this will be false.
+   */
+  private boolean credentialStoreRequired;
+
   /**
    * Constructor.
    *
@@ -281,4 +287,22 @@ public class StackServiceResponse {
   public void setCredentialStoreEnabled(boolean credentialStoreEnabled) {
     this.credentialStoreEnabled = credentialStoreEnabled;
   }
+
+  /**
+   * Get whether credential store use is required
+   *
+   * @return true or false
+   */
+  public boolean isCredentialStoreRequired() {
+    return credentialStoreRequired;
+  }
+
+  /**
+   * Set credential store required value.
+   *
+   * @param credentialStoreRequired
+   */
+  public void setCredentialStoreRequired(boolean credentialStoreRequired) {
+    this.credentialStoreRequired = credentialStoreRequired;
+  }
 }

+ 31 - 9
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java

@@ -339,6 +339,11 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
       svcRequest.setMaintenanceState(o.toString());
     }
 
+    o = properties.get(SERVICE_CREDENTIAL_STORE_SUPPORTED_PROPERTY_ID);
+    if (null != o) {
+      svcRequest.setMaintenanceState(o.toString());
+    }
+
     return svcRequest;
   }
 
@@ -368,22 +373,30 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
       AmbariMetaInfo ambariMetaInfo = getManagementController().getAmbariMetaInfo();
       ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(),
           stackId.getStackVersion(), request.getServiceName());
-      LOG.info("Service: {}, credential_store_supported from stack definition:{}", request.getServiceName(),
-          serviceInfo.isCredentialStoreSupported());
 
+      boolean credentialStoreSupported = serviceInfo.isCredentialStoreSupported();
+      boolean credentialStoreRequired = serviceInfo.isCredentialStoreRequired();
+
+      LOG.info("Service: {}, credential_store_supported = {} and credential_store_required = {} from stack definition",
+               request.getServiceName(), credentialStoreSupported, credentialStoreRequired);
       /**
        * If request does not have credential_store_enabled field,
        * then get the default from the stack definition.
        */
       if (StringUtils.isNotEmpty(request.getCredentialStoreEnabled())) {
         boolean credentialStoreEnabled = Boolean.parseBoolean(request.getCredentialStoreEnabled());
-        s.setCredentialStoreEnabled(credentialStoreEnabled);
-        LOG.info("Service: {}, credential_store_enabled from request: {}", request.getServiceName(),
-            credentialStoreEnabled);
+        boolean enableCredStore = credentialStoreSupported && (credentialStoreRequired || credentialStoreEnabled);
+        s.setCredentialStoreEnabled(enableCredStore);
+        LOG.info("Service: {}, credential_store_enabled = {} from request and resulting" +
+                 " credential store enabled status is = {}",
+                 request.getServiceName(), credentialStoreEnabled, enableCredStore);
       } else {
-        s.setCredentialStoreEnabled(serviceInfo.isCredentialStoreEnabled());
-        LOG.info("Service: {}, credential_store_enabled from stack definition:{}", s.getName(),
-            serviceInfo.isCredentialStoreEnabled());
+        boolean enableCredStore = credentialStoreSupported &&
+                                  (credentialStoreRequired || serviceInfo.isCredentialStoreEnabled());
+        s.setCredentialStoreEnabled(enableCredStore);
+        LOG.info("Service: {}, credential_store_enabled = {} from stack definition and resulting" +
+                 " credential store enabled status is = {}",
+                 s.getName(), serviceInfo.isCredentialStoreEnabled(), enableCredStore);
       }
 
       // Initialize service widgets
@@ -498,7 +511,7 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
       reqOpLvl = Resource.Type.Cluster;
     }
 
-    Clusters       clusters        = controller.getClusters();
+    Clusters clusters = controller.getClusters();
 
     // We don't expect batch requests for different clusters, that's why
     // nothing bad should happen if value is overwritten few times
@@ -581,11 +594,20 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
           throw new IllegalArgumentException("Invalid arguments, cannot enable credential store " +
               "as it is not supported by the service. Service=" + s.getName());
         }
+        if (s.isCredentialStoreRequired() && !credentialStoreEnabled) {
+          throw new IllegalArgumentException("Invalid arguments, cannot disable credential store " +
+                                             "as it is required by the service. Service=" + s.getName());
+        }
         serviceCredentialStoreEnabledMap.put(s, credentialStoreEnabled);
         LOG.info("Service: {}, credential_store_enabled from request: {}", request.getServiceName(),
             credentialStoreEnabled);
       }
 
+      if (StringUtils.isNotEmpty(request.getCredentialStoreSupported())) {
+        throw new IllegalArgumentException("Invalid arguments, cannot update credential_store_supported " +
+                                           "as it is set only via service definition. Service=" + s.getName());
+      }
+
       if (newState == null) {
         if (LOG.isDebugEnabled()) {
           LOG.debug("Nothing to do for new updateService request"

+ 12 - 6
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java

@@ -86,13 +86,16 @@ public class StackServiceResourceProvider extends ReadOnlyResourceProvider {
       "StackServices", "custom_commands");
 
   private static final String SERVICE_PROPERTIES_PROPERTY_ID = PropertyHelper.getPropertyId(
-    "StackServices", "properties");
+      "StackServices", "properties");
 
   private static final String CREDENTIAL_STORE_SUPPORTED = PropertyHelper.getPropertyId(
-          "StackServices", "credential_store_supported");
+      "StackServices", "credential_store_supported");
+
+  private static final String CREDENTIAL_STORE_REQUIRED = PropertyHelper.getPropertyId(
+      "StackServices", "credential_store_required");
 
   private static final String CREDENTIAL_STORE_ENABLED = PropertyHelper.getPropertyId(
-          "StackServices", "credential_store_enabled");
+      "StackServices", "credential_store_enabled");
 
   private static Set<String> pkPropertyIds = new HashSet<String>(
       Arrays.asList(new String[]{STACK_NAME_PROPERTY_ID,
@@ -191,13 +194,16 @@ public class StackServiceResourceProvider extends ReadOnlyResourceProvider {
         response.getCustomCommands(), requestedIds);
 
     setResourceProperty(resource, SERVICE_PROPERTIES_PROPERTY_ID,
-      response.getServiceProperties(), requestedIds);
+        response.getServiceProperties(), requestedIds);
 
     setResourceProperty(resource, CREDENTIAL_STORE_SUPPORTED,
-      response.isCredentialStoreSupported(), requestedIds);
+        response.isCredentialStoreSupported(), requestedIds);
+
+    setResourceProperty(resource, CREDENTIAL_STORE_REQUIRED,
+        response.isCredentialStoreRequired(), requestedIds);
 
     setResourceProperty(resource, CREDENTIAL_STORE_ENABLED,
-      response.isCredentialStoreEnabled(), requestedIds);
+        response.isCredentialStoreEnabled(), requestedIds);
 
     return resource;
   }

+ 90 - 68
ambari-server/src/main/java/org/apache/ambari/server/state/CredentialStoreInfo.java

@@ -27,81 +27,103 @@ import javax.xml.bind.annotation.XmlElement;
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 public class CredentialStoreInfo {
-    /**
-     * Use Boolean data-type internally, so that we can validate
-     * the XML.
-     */
+  /**
+   * Use Boolean data-type internally, so that we can validate the XML.
+   */
 
-    @XmlElement(name="supported")
-    private Boolean supported = null;
+  @XmlElement(name = "supported")
+  private Boolean supported = null;
 
-    @XmlElement(name="enabled")
-    private Boolean enabled = null;
+  @XmlElement(name = "required")
+  private Boolean required = null;
 
-    /**
-     * Default constructor
-     */
-    public CredentialStoreInfo() {
-    }
+  @XmlElement(name = "enabled")
+  private Boolean enabled = null;
 
-    /**
-     * Constructor taking in values for supported and enabled
-     *
-     * @param supported
-     * @param enabled
-     */
-    public CredentialStoreInfo(Boolean supported, Boolean enabled) {
-        this.supported = supported;
-        this.enabled = enabled;
-    }
+  /**
+   * Default constructor
+   */
+  public CredentialStoreInfo() {
+  }
 
-    /**
-     * Gets a value indicating if the service supports
-     * credential store. If null, this was not specified.
-     * @return
-     */
-    public Boolean isSupported() {
-        return supported;
-    }
+  /**
+   * Constructor taking in values for supported and enabled
+   *
+   * @param supported
+   * @param enabled
+   * @param required
+   */
+  public CredentialStoreInfo(Boolean supported, Boolean enabled, Boolean required) {
+    this.supported = supported;
+    this.enabled = enabled;
+    this.required = required;
+  }
 
-    /**
-     * Set whether a service supports credential store.
-     *
-     * @param supported
-     */
-    public void setSupported(Boolean supported) {
-        this.supported = supported;
-    }
+  /**
+   * Gets a value indicating if the service supports credential store. If null, this was not specified.
+   *
+   * @return
+   */
+  public Boolean isSupported() {
+    return supported;
+  }
 
-    /**
-     * Gets a value indicating whether the service is
-     * enabled for credential store use.
-     *
-     * @return - true, false, null if not specified.
-     */
-    public Boolean isEnabled() {
-        return enabled;
-    }
+  /**
+   * Set whether a service supports credential store.
+   *
+   * @param supported
+   */
+  public void setSupported(Boolean supported) {
+    this.supported = supported;
+  }
 
-    /**
-     * Set whether the service is enabled for credential
-     * store use.
-     *
-     * @param enabled - true, false, null.
-     */
-    public void setEnabled(Boolean enabled) {
-        this.enabled = enabled;
-    }
+  /**
+   * Gets a value indicating whether the service is enabled for credential store use.
+   *
+   * @return - true, false, null if not specified.
+   */
+  public Boolean isEnabled() {
+    return enabled;
+  }
 
-    /**
-     * String representation of this object
-     * @return
-     */
-    @Override
-    public String toString() {
-        return "CredentialStoreInfo{" +
-                "supported=" + supported +
-                ", enabled=" + enabled +
-                '}';
-    }
+  /**
+   * Set whether the service is enabled for credential store use.
+   *
+   * @param enabled - true, false, null.
+   */
+  public void setEnabled(Boolean enabled) {
+    this.enabled = enabled;
+  }
+
+  /**
+   * Gets a value indicating whether the service requires credential store.
+   *
+   * @return - true, false, null if not specified.
+   */
+  public Boolean isRequired() {
+    return required;
+  }
+
+  /**
+   * Set whether the service requires credential store
+   *
+   * @param required - true, false, null.
+   */
+  public void setRequired(Boolean required) {
+    this.required = required;
+  }
+
+  /**
+   * String representation of this object
+   *
+   * @return
+   */
+  @Override
+  public String toString() {
+    return "CredentialStoreInfo{" +
+           "supported=" + supported +
+           ", required=" + required +
+           ", enabled=" + enabled +
+           '}';
+  }
 }

+ 7 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/Service.java

@@ -109,6 +109,13 @@ public interface Service {
    */
   boolean isCredentialStoreSupported();
 
+  /**
+   * Get a true or false value specifying
+   * whether credential store is required by this service.
+   * @return true or false
+   */
+  boolean isCredentialStoreRequired();
+
   /**
    * Get a true or false value specifying whether
    * credential store use is enabled for this service.

+ 13 - 1
ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java

@@ -71,6 +71,7 @@ public class ServiceImpl implements Service {
   private final ConcurrentMap<String, ServiceComponent> components = new ConcurrentHashMap<>();
   private final boolean isClientOnlyService;
   private final boolean isCredentialStoreSupported;
+  private final boolean isCredentialStoreRequired;
 
   @Inject
   private ServiceConfigDAO serviceConfigDAO;
@@ -132,6 +133,7 @@ public class ServiceImpl implements Service {
     isClientOnlyService = sInfo.isClientOnlyService();
 
     isCredentialStoreSupported = sInfo.isCredentialStoreSupported();
+    isCredentialStoreRequired = sInfo.isCredentialStoreRequired();
 
     persist(serviceEntity);
   }
@@ -178,6 +180,7 @@ public class ServiceImpl implements Service {
         stackId.getStackVersion(), getName());
     isClientOnlyService = sInfo.isClientOnlyService();
     isCredentialStoreSupported = sInfo.isCredentialStoreSupported();
+    isCredentialStoreRequired = sInfo.isCredentialStoreRequired();
   }
 
   @Override
@@ -334,7 +337,16 @@ public class ServiceImpl implements Service {
     return isCredentialStoreSupported;
   }
 
-
+  /**
+   * Get a true or false value specifying whether
+   * credential store is required by this service.
+   *
+   * @return true or false
+   */
+  @Override
+  public boolean isCredentialStoreRequired() {
+    return isCredentialStoreRequired;
+  }
 
 
   /**

+ 29 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java

@@ -30,6 +30,8 @@ import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.map.annotate.JsonFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlAccessType;
@@ -475,6 +477,33 @@ public String getVersion() {
     credentialStoreInfo.setSupported(credentialStoreSupported);
   }
 
+  /**
+   * Indicates if this service is requires credential store.
+   * False if it was not specified.
+   *
+   * @return true or false
+   */
+  public boolean isCredentialStoreRequired() {
+    if (credentialStoreInfo != null) {
+      if (credentialStoreInfo.isRequired() != null) {
+        return credentialStoreInfo.isRequired();
+      }
+    }
+
+    return false;
+  }
+
+  /**
+   * Set a value indicating if this service requires credential store.
+   * @param credentialStoreRequired
+   */
+  public void setCredentialStoreRequired(boolean credentialStoreRequired) {
+    if (credentialStoreInfo == null) {
+      credentialStoreInfo = new CredentialStoreInfo();
+    }
+    credentialStoreInfo.setRequired(credentialStoreRequired);
+  }
+
   /**
    * Indicates if this service is enabled for credential store use.
    * False if it was not specified.

+ 1 - 0
ambari-server/src/main/resources/properties.json

@@ -222,6 +222,7 @@
         "StackServices/required_services",
         "StackServices/credential_store_supported",
         "StackServices/credential_store_enabled",
+        "StackServices/credential_store_required",
         "StackServices/properties",
         "_"
     ],

+ 0 - 4
ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml

@@ -27,10 +27,6 @@
       <comment>Comprehensive security for Hadoop</comment>
       <extends>common-services/RANGER/0.5.0</extends>
       <version>0.5.0.2.3</version>
-      <credential-store>
-        <supported>true</supported>
-        <enabled>false</enabled>
-      </credential-store>
     </service>
   </services>
 </metainfo>

+ 0 - 4
ambari-server/src/main/resources/stacks/HDP/2.4/services/RANGER/metainfo.xml

@@ -24,10 +24,6 @@
     <service>
       <name>RANGER</name>
       <version>0.5.0.2.4</version>
-      <credential-store>
-        <supported>true</supported>
-        <enabled>false</enabled>
-      </credential-store>
     </service>
   </services>
 </metainfo>

+ 0 - 4
ambari-server/src/main/resources/stacks/HDP/2.5/services/RANGER/metainfo.xml

@@ -25,10 +25,6 @@
       <name>RANGER</name>
       <extends>common-services/RANGER/0.6.0</extends>
       <version>0.6.0.2.5</version>
-      <credential-store>
-        <supported>true</supported>
-	<enabled>false</enabled>
-      </credential-store>
     </service>
   </services>
 </metainfo>

+ 0 - 4
ambari-server/src/main/resources/stacks/HDP/2.6/services/RANGER/metainfo.xml

@@ -25,10 +25,6 @@
       <name>RANGER</name>
       <extends>common-services/RANGER/0.7.0</extends>
       <version>0.7.0.2.6</version>
-      <credential-store>
-        <supported>true</supported>
-        <enabled>false</enabled>
-      </credential-store>
     </service>
   </services>
 </metainfo>

+ 83 - 0
ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java

@@ -10379,6 +10379,89 @@ public class AmbariManagementControllerTest {
     }
   }
 
+  @Test
+  public void testCredentialStoreRelatedAPICallsToUpdateSettings() throws Exception {
+    String cluster1 = getUniqueName();
+    createCluster(cluster1);
+    clusters.getCluster(cluster1).setDesiredStackVersion(
+        new StackId("HDP-2.2.0"));
+
+    String service1Name = "HDFS";
+    String service2Name = "STORM";
+    String service3Name = "ZOOKEEPER";
+    createService(cluster1, service1Name, null);
+    createService(cluster1, service2Name, null);
+    createService(cluster1, service3Name, null);
+    String component1Name = "NAMENODE";
+    String component2Name = "DRPC_SERVER";
+    String component3Name = "ZOOKEEPER_SERVER";
+    createServiceComponent(cluster1, service1Name, component1Name, State.INIT);
+    createServiceComponent(cluster1, service2Name, component2Name, State.INIT);
+    createServiceComponent(cluster1, service3Name, component3Name, State.INIT);
+    String host1 = getUniqueName();
+    addHostToCluster(host1, cluster1);
+    createServiceComponentHost(cluster1, service1Name, component1Name, host1, null);
+    createServiceComponentHost(cluster1, service2Name, component2Name, host1, null);
+    createServiceComponentHost(cluster1, service3Name, component3Name, host1, null);
+
+    Map<String, String> requestProperties = new HashMap<String, String>();
+    requestProperties.put("context", "Called from a test");
+
+    Cluster cluster = clusters.getCluster(cluster1);
+    Service service1 = cluster.getService(service1Name);
+
+    MaintenanceStateHelper
+        maintenanceStateHelper =
+        MaintenanceStateHelperTest.getMaintenanceStateHelperInstance(clusters);
+
+    // test updating a service
+    ServiceRequest sr = new ServiceRequest(cluster1, service1Name, null);
+    sr.setCredentialStoreEnabled("true");
+
+    ServiceResourceProviderTest.updateServices(controller,
+                                               Collections.singleton(sr), requestProperties, false, false,
+                                               maintenanceStateHelper);
+    Assert.assertTrue(service1.isCredentialStoreEnabled());
+    Assert.assertTrue(service1.isCredentialStoreSupported());
+    Assert.assertFalse(service1.isCredentialStoreRequired());
+
+    ServiceRequest sr2 = new ServiceRequest(cluster1, service2Name, null);
+    sr2.setCredentialStoreEnabled("true");
+    try {
+      ServiceResourceProviderTest.updateServices(controller,
+                                                 Collections.singleton(sr2), requestProperties, false, false,
+                                                 maintenanceStateHelper);
+      Assert.assertTrue("Expected exception not thrown - service does not support cred store", true);
+    }catch(IllegalArgumentException iaex) {
+      Assert.assertTrue(iaex.getMessage(), iaex.getMessage().contains(
+          "Invalid arguments, cannot enable credential store as it is not supported by the service. Service=STORM"));
+    }
+
+    ServiceRequest sr3 = new ServiceRequest(cluster1, service3Name, null);
+    sr3.setCredentialStoreEnabled("false");
+    try {
+      ServiceResourceProviderTest.updateServices(controller,
+                                                 Collections.singleton(sr3), requestProperties, false, false,
+                                                 maintenanceStateHelper);
+      Assert.assertTrue("Expected exception not thrown - service does not support disabling of cred store", true);
+    }catch(IllegalArgumentException iaex) {
+      Assert.assertTrue(iaex.getMessage(), iaex.getMessage().contains(
+          "Invalid arguments, cannot disable credential store as it is required by the service. Service=ZOOKEEPER"));
+    }
+
+    ServiceRequest sr4 = new ServiceRequest(cluster1, service3Name, null);
+    sr4.setCredentialStoreSupported("true");
+    try {
+      ServiceResourceProviderTest.updateServices(controller,
+                                                 Collections.singleton(sr4), requestProperties, false, false,
+                                                 maintenanceStateHelper);
+      Assert.assertTrue("Expected exception not thrown - service does not support updating cred store support", true);
+    }catch(IllegalArgumentException iaex) {
+      Assert.assertTrue(iaex.getMessage(), iaex.getMessage().contains(
+          "Invalid arguments, cannot update credential_store_supported as it is set only via service definition. Service=ZOOKEEPER"));
+    }
+  }
+
   @Test
   public void testPassiveSkipServices() throws Exception {
     String cluster1 = getUniqueName();

+ 5 - 2
ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java

@@ -978,8 +978,8 @@ public class ServiceModuleTest {
    */
   @Test
   public void testResolve_CredentialStoreInfo() throws Exception {
-    CredentialStoreInfo credentialStoreInfoChild = new CredentialStoreInfo(true /* supported */, false /* enabled */);
-    CredentialStoreInfo credentialStoreInfoParent = new CredentialStoreInfo(true /* supported */, true /* enabled */);
+    CredentialStoreInfo credentialStoreInfoChild = new CredentialStoreInfo(true /* supported */, false /* enabled */, true /*required*/);
+    CredentialStoreInfo credentialStoreInfoParent = new CredentialStoreInfo(true /* supported */, true /* enabled */, false /*required*/);
     ServiceInfo childInfo = new ServiceInfo();
     ServiceInfo parentInfo = new ServiceInfo();
     ServiceModule service;
@@ -990,6 +990,7 @@ public class ServiceModuleTest {
     service = resolveService(childInfo, parentInfo);
     assertEquals(credentialStoreInfoChild.isSupported(), service.getModuleInfo().isCredentialStoreSupported());
     assertEquals(credentialStoreInfoChild.isEnabled(), service.getModuleInfo().isCredentialStoreEnabled());
+    assertEquals(credentialStoreInfoChild.isRequired(), service.getModuleInfo().isCredentialStoreRequired());
 
     // specified in parent only, parent wins
     childInfo.setCredentialStoreInfo(null);
@@ -997,6 +998,7 @@ public class ServiceModuleTest {
     service = resolveService(childInfo, parentInfo);
     assertEquals(credentialStoreInfoParent.isSupported(), service.getModuleInfo().isCredentialStoreSupported());
     assertEquals(credentialStoreInfoParent.isEnabled(), service.getModuleInfo().isCredentialStoreEnabled());
+    assertEquals(credentialStoreInfoParent.isRequired(), service.getModuleInfo().isCredentialStoreRequired());
 
     // specified in both, child wins
     childInfo.setCredentialStoreInfo(credentialStoreInfoChild);
@@ -1004,6 +1006,7 @@ public class ServiceModuleTest {
     service = resolveService(childInfo, parentInfo);
     assertEquals(credentialStoreInfoChild.isSupported(), service.getModuleInfo().isCredentialStoreSupported());
     assertEquals(credentialStoreInfoChild.isEnabled(), service.getModuleInfo().isCredentialStoreEnabled());
+    assertEquals(credentialStoreInfoChild.isRequired(), service.getModuleInfo().isCredentialStoreRequired());
   }
 
   @Test

+ 4 - 0
ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java

@@ -158,6 +158,7 @@ public class ServiceInfoTest {
             "      <credential-store>\n" +
             "          <supported>true</supported>\n" +
             "          <enabled>true</enabled>\n" +
+            "          <required>true</required>\n" +
             "      </credential-store>\n" +
             "    </service>\n" +
             "  </services>\n" +
@@ -166,6 +167,7 @@ public class ServiceInfoTest {
     ServiceInfo service = serviceInfoMap.get("RANGER");
     assertTrue(service.isCredentialStoreSupported());
     assertTrue(service.isCredentialStoreEnabled());
+    assertTrue(service.isCredentialStoreRequired());
 
     /*
      * <credential-store> supported but not enabled.
@@ -178,6 +180,7 @@ public class ServiceInfoTest {
             "      <credential-store>\n" +
             "          <supported>true</supported>\n" +
             "          <enabled>false</enabled>\n" +
+            "          <required>false</required>\n" +
             "      </credential-store>\n" +
             "    </service>\n" +
             "  </services>\n" +
@@ -186,6 +189,7 @@ public class ServiceInfoTest {
     service = serviceInfoMap.get("HIVE");
     assertTrue(service.isCredentialStoreSupported());
     assertFalse(service.isCredentialStoreEnabled());
+    assertFalse(service.isCredentialStoreRequired());
 
     /*
      * <credential-store> is missing

+ 5 - 1
ambari-server/src/test/resources/stacks/HDP/2.2.0/services/HDFS/metainfo.xml

@@ -22,7 +22,11 @@
       <name>HDFS</name>
       <comment>Apache Hadoop Distributed File System</comment>
       <version>2.1.0.2.0.6.0</version>
-
+      <credential-store>
+        <supported>true</supported>
+        <enabled>true</enabled>
+        <required>false</required>
+      </credential-store>
       <components>
         <component>
           <name>NAMENODE</name>

+ 6 - 0
ambari-server/src/test/resources/stacks/HDP/2.2.0/services/STORM/metainfo.xml

@@ -23,6 +23,12 @@
       <name>STORM</name>
       <comment>Apache Hadoop Stream processing framework</comment>
       <version>0.9.0.1</version>
+      <credential-store>
+        <supported>false</supported>
+        <enabled>false</enabled>
+        <required>false</required>
+      </credential-store>
+
       <components>
 
         <component>

+ 5 - 1
ambari-server/src/test/resources/stacks/HDP/2.2.0/services/ZOOKEEPER/metainfo.xml

@@ -23,7 +23,11 @@
       <displayName>ZooKeeper</displayName>
       <comment>Centralized service which provides highly reliable distributed coordination</comment>
       <version>3.4.5.2.0</version>
-
+      <credential-store>
+        <supported>true</supported>
+        <enabled>false</enabled>
+        <required>true</required>
+      </credential-store>
       <components>
         <component>
           <name>ZOOKEEPER_SERVER</name>