Repository: ambari Updated Branches: refs/heads/trunk a8727af88 -> 33a411953
AMBARI-18744: Ambari-server: REST API changes to GET and PUT credential store information Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/33a41195 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/33a41195 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/33a41195 Branch: refs/heads/trunk Commit: 33a4119539107b781270a4347a5364e0f40652d7 Parents: a8727af Author: Nahappan Somasundaram <[email protected]> Authored: Wed Nov 2 10:37:27 2016 -0700 Committer: Nahappan Somasundaram <[email protected]> Committed: Wed Nov 2 12:18:57 2016 -0700 ---------------------------------------------------------------------- .../server/controller/ServiceRequest.java | 32 ++- .../server/controller/ServiceResponse.java | 47 +++- .../server/controller/StackServiceRequest.java | 46 +++- .../server/controller/StackServiceResponse.java | 51 +++++ .../internal/ServiceResourceProvider.java | 78 ++++++- .../internal/StackServiceResourceProvider.java | 16 +- .../server/state/CredentialStoreInfo.java | 96 ++++++++ .../apache/ambari/server/state/ServiceImpl.java | 5 +- .../apache/ambari/server/state/ServiceInfo.java | 85 ++++++- .../src/main/resources/properties.json | 4 + .../internal/ServiceResourceProviderTest.java | 45 +++- .../ambari/server/state/ServiceInfoTest.java | 224 +++++++++++++++++++ 12 files changed, 710 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java index eb874b5..ec45a85 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java @@ -25,12 +25,23 @@ public class ServiceRequest { private String serviceName; // GET/CREATE/UPDATE/DELETE private String desiredState; // CREATE/UPDATE private String maintenanceState; // UPDATE + private String credentialStoreEnabled; // CREATE/UPDATE/GET public ServiceRequest(String clusterName, String serviceName, String desiredState) { + this(clusterName, serviceName, desiredState, null); + } + + public ServiceRequest(String clusterName, String serviceName, + String desiredState, + String credentialStoreEnabled) { this.clusterName = clusterName; this.serviceName = serviceName; this.desiredState = desiredState; + this.credentialStoreEnabled = credentialStoreEnabled; + // Credential store supported cannot be changed after + // creation since it comes from the stack definition. + // We can update credential store enabled alone. } /** @@ -74,14 +85,14 @@ public class ServiceRequest { public void setClusterName(String clusterName) { this.clusterName = clusterName; } - + /** * @param state the new maintenance state */ public void setMaintenanceState(String state) { maintenanceState = state; } - + /** * @return the maintenance state */ @@ -89,11 +100,26 @@ public class ServiceRequest { return maintenanceState; } + /** + * @return credential store enabled + */ + public String getCredentialStoreEnabled() { + return credentialStoreEnabled; + } + + /** + * @param credentialStoreEnabled the new credential store enabled + */ + public void setCredentialStoreEnabled(String credentialStoreEnabled) { + this.credentialStoreEnabled = credentialStoreEnabled; + } + public String toString() { StringBuilder sb = new StringBuilder(); sb.append("clusterName=" + clusterName + ", serviceName=" + serviceName - + ", desiredState=" + desiredState); + + ", desiredState=" + desiredState + + ", credentialStoreEnabled=" + credentialStoreEnabled); return sb.toString(); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java index c4881b8..3e35c0c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java @@ -27,15 +27,20 @@ public class ServiceResponse { private String desiredStackVersion; private String desiredState; private String maintenanceState; + private boolean credentialStoreSupported; + private boolean credentialStoreEnabled; public ServiceResponse(Long clusterId, String clusterName, String serviceName, - String desiredStackVersion, String desiredState) { + String desiredStackVersion, String desiredState, + boolean credentialStoreSupported, boolean credentialStoreEnabled) { this.clusterId = clusterId; this.clusterName = clusterName; this.serviceName = serviceName; this.setDesiredStackVersion(desiredStackVersion); this.setDesiredState(desiredState); + this.credentialStoreSupported = credentialStoreSupported; + this.credentialStoreEnabled = credentialStoreEnabled; } @@ -141,6 +146,46 @@ public class ServiceResponse { return maintenanceState; } + /** + * Get a true or false value indicating if the service supports + * credential store use or not. + * + * @return true or false + */ + public boolean isCredentialStoreSupported() { + return credentialStoreSupported; + } + + /** + * Set a true or false value indicating whether the service + * supports credential store or not. + * + * @param credentialStoreSupported + */ + public void setCredentialStoreSupported(boolean credentialStoreSupported) { + this.credentialStoreSupported = credentialStoreSupported; + } + + /** + * Get a true or false value indicating if the service is enabled + * for credential store use or not. + * + * @return true or false + */ + public boolean isCredentialStoreEnabled() { + return credentialStoreEnabled; + } + + /** + * Set a true or false value indicating whether the service is + * enabled for credential store use or not. + * + * @param credentialStoreEnabled + */ + public void setCredentialStoreEnabled(boolean credentialStoreEnabled) { + this.credentialStoreEnabled = credentialStoreEnabled; + } + @Override public int hashCode() { int result = clusterId != null? clusterId.intValue() : 0; http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceRequest.java index b11d47c..260e48d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceRequest.java @@ -22,13 +22,19 @@ package org.apache.ambari.server.controller; public class StackServiceRequest extends StackVersionRequest { private String serviceName; + private String credentialStoreSupported; + private String credentialStoreEnabled; public StackServiceRequest(String stackName, String stackVersion, String serviceName) { + this(stackName, stackVersion, serviceName, null, null); + } + + public StackServiceRequest(String stackName, String stackVersion, + String serviceName, String credentialStoreSupported, String credentialStoreEnabled) { super(stackName, stackVersion); this.setServiceName(serviceName); - } public String getServiceName() { @@ -39,4 +45,42 @@ public class StackServiceRequest extends StackVersionRequest { this.serviceName = serviceName; } + /** + * Get whether credential store is supported. If value is null, + * this property was not specified. + * + * @return null, "true", "false" + */ + public String getCredentialStoreSupported() { + return credentialStoreSupported; + } + + /** + * Set whether credential store is supported. Null indicates unspecified. + * + * @param credentialStoreSupported null, "true", "false" + */ + public void setCredentialStoreSupported(String credentialStoreSupported) { + this.credentialStoreSupported = credentialStoreSupported; + } + + /** + * Get whether credential store is enabled. If value is null, + * this property was not specified. + * + * @return null, "true", "false" + */ + public String getCredentialStoreEnabled() { + return credentialStoreEnabled; + } + + /** + * Set whether credential store is supported. Null indicates unspecified. + * + * @param credentialStoreEnabled null, "true", "false" + */ + public void setCredentialStoreEnabled(String credentialStoreEnabled) { + this.credentialStoreEnabled = credentialStoreEnabled; + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceResponse.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceResponse.java index 75f65c0..a6dd31f 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceResponse.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceResponse.java @@ -58,6 +58,18 @@ public class StackServiceResponse { private File kerberosDescriptorFile; /** + * Indicates if the stack definition says this service supports + * credential store. If not specified, this will be false. + */ + private boolean credentialStoreSupported; + + /** + * Indicates if the stack definition says this service is enabled + * for credential store use. If not specified, this will be false. + */ + private boolean credentialStoreEnabled; + + /** * Constructor. * * @param service @@ -90,6 +102,10 @@ public class StackServiceResponse { kerberosDescriptorFile = service.getKerberosDescriptorFile(); serviceProperties = service.getServiceProperties(); + + credentialStoreSupported = service.isCredentialStoreSupported(); + + credentialStoreEnabled = service.isCredentialStoreEnabled(); } public ServiceInfo.Selection getSelection() { @@ -230,4 +246,39 @@ public class StackServiceResponse { return serviceProperties; } + /** + * Get whether credential store is supported by the service + * + * @return true or false. + */ + public boolean isCredentialStoreSupported() { + return credentialStoreSupported; + } + + /** + * Set credential store supported value + * + * @param credentialStoreSupported + */ + public void setCredentialStoreSupported(boolean credentialStoreSupported) { + this.credentialStoreSupported = credentialStoreSupported; + } + + /** + * Get whether credential store use is enabled + * + * @return true or false + */ + public boolean isCredentialStoreEnabled() { + return credentialStoreEnabled; + } + + /** + * Set credential store enabled value. + * + * @param credentialStoreEnabled + */ + public void setCredentialStoreEnabled(boolean credentialStoreEnabled) { + this.credentialStoreEnabled = credentialStoreEnabled; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java index 13f822e..a08d153 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java @@ -69,6 +69,7 @@ import org.apache.ambari.server.state.MaintenanceState; import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.ServiceComponentHost; +import org.apache.ambari.server.state.ServiceInfo; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.State; import org.apache.commons.lang.StringUtils; @@ -91,6 +92,10 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider public static final String SERVICE_SERVICE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "service_name"); public static final String SERVICE_SERVICE_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "state"); public static final String SERVICE_MAINTENANCE_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "maintenance_state"); + public static final String SERVICE_CREDENTIAL_STORE_SUPPORTED_PROPERTY_ID = + PropertyHelper.getPropertyId("ServiceInfo", "credential_store_supported"); + public static final String SERVICE_CREDENTIAL_STORE_ENABLED_PROPERTY_ID = + PropertyHelper.getPropertyId("ServiceInfo", "credential_store_enabled"); public static final String SERVICE_ATTRIBUTES_PROPERTY_ID = PropertyHelper.getPropertyId("Services", "attributes"); @@ -197,6 +202,10 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider requestedIds); setResourceProperty(resource, SERVICE_MAINTENANCE_STATE_PROPERTY_ID, response.getMaintenanceState(), requestedIds); + setResourceProperty(resource, SERVICE_CREDENTIAL_STORE_SUPPORTED_PROPERTY_ID, + String.valueOf(response.isCredentialStoreSupported()), requestedIds); + setResourceProperty(resource, SERVICE_CREDENTIAL_STORE_ENABLED_PROPERTY_ID, + String.valueOf(response.isCredentialStoreEnabled()), requestedIds); Map<String, Object> serviceSpecificProperties = getServiceSpecificProperties( response.getClusterName(), response.getServiceName(), requestedIds); @@ -322,7 +331,8 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider ServiceRequest svcRequest = new ServiceRequest( (String) properties.get(SERVICE_CLUSTER_NAME_PROPERTY_ID), (String) properties.get(SERVICE_SERVICE_NAME_PROPERTY_ID), - (String) properties.get(SERVICE_SERVICE_STATE_PROPERTY_ID)); + (String) properties.get(SERVICE_SERVICE_STATE_PROPERTY_ID), + (String) properties.get(SERVICE_CREDENTIAL_STORE_ENABLED_PROPERTY_ID)); Object o = properties.get(SERVICE_MAINTENANCE_STATE_PROPERTY_ID); if (null != o) { @@ -350,6 +360,33 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider // Already checked that service does not exist Service s = cluster.addService(request.getServiceName()); + /** + * Get the credential_store_supported field only from the stack definition. + * Not possible to update the value through a request. + */ + StackId stackId = cluster.getDesiredStackVersion(); + AmbariMetaInfo ambariMetaInfo = getManagementController().getAmbariMetaInfo(); + ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(), + stackId.getStackVersion(), request.getServiceName()); + s.setCredentialStoreSupported(serviceInfo.isCredentialStoreSupported()); + LOG.info("Service: {}, credential_store_supported from stack definition:{}", request.getServiceName(), + serviceInfo.isCredentialStoreSupported()); + + /** + * 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); + } else { + s.setCredentialStoreEnabled(serviceInfo.isCredentialStoreEnabled()); + LOG.info("Service: {}, credential_store_enabled from stack definition:{}", s.getName(), + serviceInfo.isCredentialStoreEnabled()); + } + // Initialize service widgets getManagementController().initializeWidgetsAndLayouts(cluster, s); } @@ -447,6 +484,7 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider Set<String> clusterNames = new HashSet<String>(); Map<String, Set<String>> serviceNames = new HashMap<String, Set<String>>(); Set<State> seenNewStates = new HashSet<State>(); + Map<Service, Boolean> serviceCredentialStoreEnabledMap = new HashMap<>(); // Determine operation level Resource.Type reqOpLvl; @@ -530,6 +568,25 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider } } + /** + * Get the credential_store_supported field only from the stack definition during creation. + * Not possible to update the value of credential_store_supported through a request. + */ + + /** + * Gather the credential_store_enabled field per service. + */ + if (StringUtils.isNotEmpty(request.getCredentialStoreEnabled())) { + boolean credentialStoreEnabled = Boolean.parseBoolean(request.getCredentialStoreEnabled()); + if (!s.isCredentialStoreSupported() && credentialStoreEnabled) { + throw new IllegalArgumentException("Invalid arguments, cannot enable credential store " + + "as it is not supported by the service. Service=" + s.getName()); + } + serviceCredentialStoreEnabledMap.put(s, credentialStoreEnabled); + LOG.info("Service: {}, credential_store_enabled from request: {}", request.getServiceName(), + credentialStoreEnabled); + } + if (newState == null) { if (LOG.isDebugEnabled()) { LOG.debug("Nothing to do for new updateService request" @@ -603,6 +660,13 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider + " changes for a set of services at the same time"); } + // update the credential store enabled information + for (Map.Entry<Service, Boolean> serviceCredential : serviceCredentialStoreEnabledMap.entrySet()) { + Service service = serviceCredential.getKey(); + Boolean credentialStoreEnabled = serviceCredential.getValue(); + service.setCredentialStoreEnabled(credentialStoreEnabled); + } + Cluster cluster = clusters.getCluster(clusterNames.iterator().next()); return controller.addStages(requestStages, cluster, requestProperties, @@ -944,6 +1008,18 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider throw new IllegalArgumentException("Unsupported or invalid service in stack, clusterName=" + clusterName + ", serviceName=" + serviceName + ", stackInfo=" + stackId.getStackId()); } + + // validate the credential store input provided + ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(), + stackId.getStackVersion(), request.getServiceName()); + + if (StringUtils.isNotEmpty(request.getCredentialStoreEnabled())) { + boolean credentialStoreEnabled = Boolean.parseBoolean(request.getCredentialStoreEnabled()); + if (!serviceInfo.isCredentialStoreSupported() && credentialStoreEnabled) { + throw new IllegalArgumentException("Invalid arguments, cannot enable credential store " + + "as it is not supported by the service. Service=" + request.getServiceName()); + } + } } // ensure only a single cluster update if (serviceNames.size() != 1) { http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java index 0fc65eb..504da49 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java @@ -88,6 +88,12 @@ public class StackServiceResourceProvider extends ReadOnlyResourceProvider { private static final String SERVICE_PROPERTIES_PROPERTY_ID = PropertyHelper.getPropertyId( "StackServices", "properties"); + private static final String CREDENTIAL_STORE_SUPPORTED = PropertyHelper.getPropertyId( + "StackServices", "credential_store_supported"); + + private static final String CREDENTIAL_STORE_ENABLED = PropertyHelper.getPropertyId( + "StackServices", "credential_store_enabled"); + private static Set<String> pkPropertyIds = new HashSet<String>( Arrays.asList(new String[]{STACK_NAME_PROPERTY_ID, STACK_VERSION_PROPERTY_ID, SERVICE_NAME_PROPERTY_ID})); @@ -187,6 +193,12 @@ public class StackServiceResourceProvider extends ReadOnlyResourceProvider { setResourceProperty(resource, SERVICE_PROPERTIES_PROPERTY_ID, response.getServiceProperties(), requestedIds); + setResourceProperty(resource, CREDENTIAL_STORE_SUPPORTED, + response.isCredentialStoreSupported(), requestedIds); + + setResourceProperty(resource, CREDENTIAL_STORE_ENABLED, + response.isCredentialStoreEnabled(), requestedIds); + return resource; } @@ -194,7 +206,9 @@ public class StackServiceResourceProvider extends ReadOnlyResourceProvider { return new StackServiceRequest( (String) properties.get(STACK_NAME_PROPERTY_ID), (String) properties.get(STACK_VERSION_PROPERTY_ID), - (String) properties.get(SERVICE_NAME_PROPERTY_ID)); + (String) properties.get(SERVICE_NAME_PROPERTY_ID), + (String) properties.get(CREDENTIAL_STORE_SUPPORTED), + (String) properties.get(CREDENTIAL_STORE_ENABLED)); } @Override http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/state/CredentialStoreInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/CredentialStoreInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/CredentialStoreInfo.java new file mode 100644 index 0000000..605de99 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/CredentialStoreInfo.java @@ -0,0 +1,96 @@ +/** + * 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.state; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; + +/** + * Represents credential store information + */ +@XmlAccessorType(XmlAccessType.FIELD) +public class CredentialStoreInfo { + /** + * Use Boolean data-type internally, so that we can validate + * the XML. + */ + + @XmlElement(name="supported") + private Boolean supported = null; + + @XmlElement(name="enabled") + private Boolean enabled = null; + + /** + * 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; + } + + /** + * Set whether a service supports credential store. + * + * @param supported + */ + public void setSupported(Boolean supported) { + this.supported = 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 the service is enabled for credential + * store use. + * + * @param enabled - true, false, null. + */ + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + /** + * String representation of this object + * @return + */ + @Override + public String toString() { + return "CredentialStoreInfo{" + + "supported=" + supported + + ", enabled=" + enabled + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java index 6f8d306..f87b99c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java @@ -307,7 +307,8 @@ public class ServiceImpl implements Service { @Override public ServiceResponse convertToResponse() { ServiceResponse r = new ServiceResponse(cluster.getClusterId(), cluster.getClusterName(), - getName(), getDesiredStackVersion().getStackId(), getDesiredState().toString()); + getName(), getDesiredStackVersion().getStackId(), getDesiredState().toString(), + isCredentialStoreSupported(), isCredentialStoreEnabled()); r.setMaintenanceState(getMaintenanceState().name()); return r; @@ -358,7 +359,7 @@ public class ServiceImpl implements Service { if (desiredStateEntity != null) { desiredStateEntity.setCredentialStoreSupported(credentialStoreSupported); - serviceDesiredStateDAO.merge(desiredStateEntity); + desiredStateEntity = serviceDesiredStateDAO.merge(desiredStateEntity); } else { LOG.warn("Setting a member on an entity object that may have been " http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java index 7f83604..16042e1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java @@ -118,6 +118,12 @@ public class ServiceInfo implements Validable{ @XmlTransient private volatile Map<String, PropertyInfo> requiredProperties; + /** + * Credential store information + */ + @XmlElements(@XmlElement(name = "credential-store")) + private CredentialStoreInfo credentialStoreInfo; + public Boolean isRestartRequiredAfterChange() { return restartRequiredAfterChange; } @@ -156,8 +162,6 @@ public class ServiceInfo implements Validable{ @XmlElement(name="property") private List<ServicePropertyInfo> servicePropertyList = Lists.newArrayList(); - - @XmlTransient private Map<String, String> servicePropertyMap = ImmutableMap.copyOf(ensureMandatoryServiceProperties(Maps.<String, String>newHashMap())); @@ -439,6 +443,60 @@ public String getVersion() { this.advisorName = advisorName; } + /** + * Indicates if this service supports credential store. + * False, it was not specified. + * + * @return true or false + */ + public boolean isCredentialStoreSupported() { + if (credentialStoreInfo != null) { + if (credentialStoreInfo.isSupported() != null) { + return credentialStoreInfo.isSupported(); + } + } + + return false; + } + + /** + * Set a value indicating if this service supports credential store. + * @param credentialStoreSupported + */ + public void setCredentialStoreSupported(boolean credentialStoreSupported) { + if (credentialStoreInfo == null) { + credentialStoreInfo = new CredentialStoreInfo(); + } + credentialStoreInfo.setSupported(credentialStoreSupported); + } + + /** + * Indicates if this service is enabled for credential store use. + * False if it was not specified. + * + * @return true or false + */ + public boolean isCredentialStoreEnabled() { + if (credentialStoreInfo != null) { + if (credentialStoreInfo.isEnabled() != null) { + return credentialStoreInfo.isEnabled(); + } + } + + return false; + } + + /** + * Set a value indicating if this service is enabled for credential store use. + * @param credentialStoreEnabled + */ + public void setCredentialStoreEnabled(boolean credentialStoreEnabled) { + if (credentialStoreInfo == null) { + credentialStoreInfo = new CredentialStoreInfo(); + } + credentialStoreInfo.setEnabled(credentialStoreEnabled); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -996,6 +1054,29 @@ public String getVersion() { addError("More than one primary log exists for the component " + component.getName()); } } + + // validate credential store information + if (credentialStoreInfo != null) { + // if both are specified, supported must be true if enabled is false or true. + if (credentialStoreInfo.isSupported() != null && credentialStoreInfo.isEnabled() != null) { + if (!credentialStoreInfo.isSupported() && credentialStoreInfo.isEnabled()) { + setValid(false); + addError("Credential store cannot be enabled for service " + getName() + " as it does not support it."); + } + } + + // Must be specified + if (credentialStoreInfo.isSupported() == null) { + setValid(false); + addError("Credential store supported is not specified for service " + getName()); + } + + // Must be specified + if (credentialStoreInfo.isEnabled() == null) { + setValid(false); + addError("Credential store enabled is not specified for service " + getName()); + } + } } public enum Selection { http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/main/resources/properties.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json index 34d4641..6bbb323 100644 --- a/ambari-server/src/main/resources/properties.json +++ b/ambari-server/src/main/resources/properties.json @@ -17,6 +17,8 @@ "ServiceInfo/cluster_name", "ServiceInfo/state", "ServiceInfo/maintenance_state", + "ServiceInfo/credential_store_supported", + "ServiceInfo/credential_store_enabled", "Services/description", "Services/display_name", "Services/attributes", @@ -217,6 +219,8 @@ "StackServices/service_check_supported", "StackServices/custom_commands", "StackServices/required_services", + "StackServices/credential_store_supported", + "StackServices/credential_store_enabled", "StackServices/properties", "_" ], http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java index f99b5ff..716be62 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java @@ -72,6 +72,7 @@ import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.ServiceComponentHost; 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.easymock.Capture; @@ -114,22 +115,27 @@ public class ServiceResourceProviderTest { StackId stackId = createNiceMock(StackId.class); ServiceFactory serviceFactory = createNiceMock(ServiceFactory.class); AmbariMetaInfo ambariMetaInfo = createNiceMock(AmbariMetaInfo.class); + ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class); expect(managementController.getClusters()).andReturn(clusters).anyTimes(); - expect(managementController.getAmbariMetaInfo()).andReturn(ambariMetaInfo); + expect(managementController.getAmbariMetaInfo()).andReturn(ambariMetaInfo).anyTimes(); expect(cluster.addService("Service100")).andReturn(service); expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes(); expect(cluster.getService("Service100")).andReturn(null); - expect(cluster.getDesiredStackVersion()).andReturn(stackId); + expect(cluster.getDesiredStackVersion()).andReturn(stackId).anyTimes(); expect(cluster.getClusterId()).andReturn(2L).anyTimes(); + expect(stackId.getStackName()).andReturn("HDP").anyTimes(); + expect(stackId.getStackVersion()).andReturn("2.5").anyTimes(); + expect(ambariMetaInfo.isValidService( (String) anyObject(), (String) anyObject(), (String) anyObject())).andReturn(true); + expect(ambariMetaInfo.getService((String)anyObject(), (String)anyObject(), (String)anyObject())).andReturn(serviceInfo).anyTimes(); // replay - replay(managementController, clusters, cluster, service, ambariMetaInfo, stackId, serviceFactory); + replay(managementController, clusters, cluster, service, ambariMetaInfo, stackId, serviceFactory, serviceInfo); SecurityContextHolder.getContext().setAuthentication(authentication); @@ -154,7 +160,7 @@ public class ServiceResourceProviderTest { provider.createResources(request); // verify - verify(managementController, clusters, cluster, service, ambariMetaInfo, stackId, serviceFactory); + verify(managementController, clusters, cluster, service, ambariMetaInfo, stackId, serviceFactory, serviceInfo); } @Test @@ -599,6 +605,8 @@ public class ServiceResourceProviderTest { RequestStageContainer requestStages = createNiceMock(RequestStageContainer.class); RequestStatusResponse requestStatusResponse = createNiceMock(RequestStatusResponse.class); RoleCommandOrder rco = createNiceMock(RoleCommandOrder.class); + StackId stackId = createNiceMock(StackId.class); + ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class); Map<String, String> mapRequestProps = new HashMap<String, String>(); mapRequestProps.put("context", "Called from a test"); @@ -615,6 +623,15 @@ public class ServiceResourceProviderTest { expect(service0.getDesiredState()).andReturn(State.INSTALLED).anyTimes(); expect(service0.getServiceComponents()).andReturn(Collections.<String, ServiceComponent>emptyMap()).anyTimes(); + expect(stackId.getStackId()).andReturn("HDP-2.5").anyTimes(); + expect(stackId.getStackName()).andReturn("HDP").anyTimes(); + expect(stackId.getStackVersion()).andReturn("2.5").anyTimes(); + expect(service0.getDesiredStackVersion()).andReturn(stackId).anyTimes(); + expect(service0.getName()).andReturn("Service102").anyTimes(); + expect(serviceInfo.isCredentialStoreSupported()).andReturn(true).anyTimes(); + expect(serviceInfo.isCredentialStoreEnabled()).andReturn(false).anyTimes(); + expect(ambariMetaInfo.getService("HDP", "2.5", "Service102")).andReturn(serviceInfo).anyTimes(); + Capture<Map<String, String>> requestPropertiesCapture = newCapture(); Capture<Map<State, List<Service>>> changedServicesCapture = newCapture(); Capture<Map<State, List<ServiceComponent>>> changedCompsCapture = newCapture(); @@ -639,7 +656,7 @@ public class ServiceResourceProviderTest { // replay replay(managementController, clusters, cluster, rco, maintenanceStateHelper, - service0, serviceFactory, ambariMetaInfo, requestStages, requestStatusResponse); + service0, serviceFactory, ambariMetaInfo, requestStages, requestStatusResponse, stackId, serviceInfo); SecurityContextHolder.getContext().setAuthentication(authentication); @@ -660,7 +677,7 @@ public class ServiceResourceProviderTest { // verify verify(managementController, clusters, cluster, maintenanceStateHelper, - service0, serviceFactory, ambariMetaInfo, requestStages, requestStatusResponse); + service0, serviceFactory, ambariMetaInfo, requestStages, requestStatusResponse, stackId, serviceInfo); } @Test @@ -696,6 +713,9 @@ public class ServiceResourceProviderTest { .class); RoleCommandOrder rco = createNiceMock(RoleCommandOrder.class); + StackId stackId = createNiceMock(StackId.class); + ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class); + Map<String, String> mapRequestProps = new HashMap<String, String>(); mapRequestProps.put("context", "Called from a test"); @@ -716,6 +736,15 @@ public class ServiceResourceProviderTest { expect(cluster.getClusterId()).andReturn(2L).anyTimes(); expect(cluster.getService("Service102")).andReturn(service0).anyTimes(); + expect(stackId.getStackId()).andReturn("HDP-2.5").anyTimes(); + expect(stackId.getStackName()).andReturn("HDP").anyTimes(); + expect(stackId.getStackVersion()).andReturn("2.5").anyTimes(); + expect(service0.getDesiredStackVersion()).andReturn(stackId).anyTimes(); + expect(service0.getName()).andReturn("Service102").anyTimes(); + expect(serviceInfo.isCredentialStoreSupported()).andReturn(true).anyTimes(); + expect(serviceInfo.isCredentialStoreEnabled()).andReturn(false).anyTimes(); + expect(ambariMetaInfo.getService("HDP", "2.5", "Service102")).andReturn(serviceInfo).anyTimes(); + expect(service0.convertToResponse()).andReturn(serviceResponse0).anyTimes(); expect(service0.getDesiredState()).andReturn(State.INSTALLED).anyTimes(); expect(service0.getServiceComponents()).andReturn(Collections.<String, ServiceComponent>emptyMap()).anyTimes(); @@ -759,7 +788,7 @@ public class ServiceResourceProviderTest { // replay replay(managementController1, response1, managementController2, requestStages1, requestStages2, response2, - clusters, cluster, service0, serviceResponse0, ambariMetaInfo, rco, maintenanceStateHelper); + clusters, cluster, service0, serviceResponse0, ambariMetaInfo, rco, maintenanceStateHelper, stackId, serviceInfo); SecurityContextHolder.getContext().setAuthentication(authentication); @@ -794,7 +823,7 @@ public class ServiceResourceProviderTest { // verify verify(managementController1, response1, managementController2, requestStages1, requestStages2, response2, - clusters, cluster, service0, serviceResponse0, ambariMetaInfo, maintenanceStateHelper); + clusters, cluster, service0, serviceResponse0, ambariMetaInfo, maintenanceStateHelper, stackId, serviceInfo); } @Test http://git-wip-us.apache.org/repos/asf/ambari/blob/33a41195/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java index 9986ee3..3034459 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java @@ -141,6 +141,230 @@ public class ServiceInfoTest { assertTrue(defaultSi.isSelectionEmpty()); } + /** + * Tests the presence and absence of the credential-store block. + * @throws Exception + */ + @Test + public void testCredentialStoreFields() throws Exception { + /* + * <credential-store> supported and enabled. + */ + String serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " <supported>true</supported>\n" + + " <enabled>true</enabled>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); + ServiceInfo service = serviceInfoMap.get("RANGER"); + assertTrue(service.isCredentialStoreSupported()); + assertTrue(service.isCredentialStoreEnabled()); + + /* + * <credential-store> supported but not enabled. + */ + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>HIVE</name>\n" + + " <credential-store>\n" + + " <supported>true</supported>\n" + + " <enabled>false</enabled>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + serviceInfoMap = getServiceInfo(serviceInfoXml); + service = serviceInfoMap.get("HIVE"); + assertTrue(service.isCredentialStoreSupported()); + assertFalse(service.isCredentialStoreEnabled()); + + /* + * <credential-store> is missing + */ + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>AMBARI_METRICS</name>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + serviceInfoMap = getServiceInfo(serviceInfoXml); + service = serviceInfoMap.get("AMBARI_METRICS"); + assertFalse(service.isCredentialStoreSupported()); + assertFalse(service.isCredentialStoreEnabled()); + + /* + * <credential-store><enabled> is missing. Invalid + * scenario. So both values should be false. + */ + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>HBASE</name>\n" + + " <credential-store>\n" + + " <supported>true</supported>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + serviceInfoMap = getServiceInfo(serviceInfoXml); + service = serviceInfoMap.get("HBASE"); + assertTrue(service.isCredentialStoreSupported()); + assertFalse(service.isCredentialStoreEnabled()); + } + + @Test + public void testCredentialStoreInfoValidity() throws Exception + { + // Valid: Supported->True, Enabled->False + String serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " <supported>true</supported>\n" + + " <enabled>false</enabled>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); + ServiceInfo serviceInfo = serviceInfoMap.get("RANGER"); + assertTrue(serviceInfo.isValid()); + + // Valid: Supported->True, Enabled->True + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " <supported>true</supported>\n" + + " <enabled>true</enabled>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + serviceInfoMap = getServiceInfo(serviceInfoXml); + serviceInfo = serviceInfoMap.get("RANGER"); + assertTrue(serviceInfo.isValid()); + + // Valid: Supported->False, Enabled->False + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " <supported>false</supported>\n" + + " <enabled>false</enabled>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + serviceInfoMap = getServiceInfo(serviceInfoXml); + serviceInfo = serviceInfoMap.get("RANGER"); + assertTrue(serviceInfo.isValid()); + + // Valid: credential-store not specified + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + serviceInfoMap = getServiceInfo(serviceInfoXml); + serviceInfo = serviceInfoMap.get("RANGER"); + assertTrue(serviceInfo.isValid()); + + // Specified but invalid + // Invalid: Supported->False, Enabled->True + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " <supported>false</supported>\n" + + " <enabled>true</enabled>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + serviceInfoMap = getServiceInfo(serviceInfoXml); + serviceInfo = serviceInfoMap.get("RANGER"); + assertFalse("Credential store is enabled for a service that does not support it", serviceInfo.isValid()); + + // Invalid: Supported->Unspecified, Enabled->Unspecified + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + serviceInfoMap = getServiceInfo(serviceInfoXml); + serviceInfo = serviceInfoMap.get("RANGER"); + assertFalse("Credential store details not specified", serviceInfo.isValid()); + + // Invalid: Supported->Specified, Enabled->Unspecified + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " <supported>true</supported>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + serviceInfoMap = getServiceInfo(serviceInfoXml); + serviceInfo = serviceInfoMap.get("RANGER"); + assertFalse("Credential store enabled not specified", serviceInfo.isValid()); + + // Invalid: Supported->Unspecified, Enabled->Specified + serviceInfoXml = "<metainfo>\n" + + " <schemaVersion>2.0</schemaVersion>\n" + + " <services>\n" + + " <service>\n" + + " <name>RANGER</name>\n" + + " <credential-store>\n" + + " <enabled>true</enabled>\n" + + " </credential-store>\n" + + " </service>\n" + + " </services>\n" + + "</metainfo>\n"; + + serviceInfoMap = getServiceInfo(serviceInfoXml); + serviceInfo = serviceInfoMap.get("RANGER"); + assertFalse("Credential store supported not specified", serviceInfo.isValid()); + } + @Test public void testSetRestartRequiredAfterRackChange() throws Exception { ServiceInfo serviceInfo = new ServiceInfo();
