| /** |
| * 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.controller.internal; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.ambari.server.AmbariException; |
| import org.apache.ambari.server.ClusterNotFoundException; |
| import org.apache.ambari.server.DuplicateResourceException; |
| import org.apache.ambari.server.ObjectNotFoundException; |
| import org.apache.ambari.server.ParentObjectNotFoundException; |
| import org.apache.ambari.server.ServiceNotFoundException; |
| import org.apache.ambari.server.api.services.AmbariMetaInfo; |
| import org.apache.ambari.server.controller.AmbariManagementController; |
| import org.apache.ambari.server.controller.RequestStatusResponse; |
| import org.apache.ambari.server.controller.ServiceComponentHostRequest; |
| import org.apache.ambari.server.controller.ServiceComponentHostResponse; |
| import org.apache.ambari.server.controller.ServiceRequest; |
| import org.apache.ambari.server.controller.ServiceResponse; |
| import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; |
| import org.apache.ambari.server.controller.spi.NoSuchResourceException; |
| import org.apache.ambari.server.controller.spi.Predicate; |
| import org.apache.ambari.server.controller.spi.Request; |
| import org.apache.ambari.server.controller.spi.RequestStatus; |
| import org.apache.ambari.server.controller.spi.Resource; |
| import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException; |
| import org.apache.ambari.server.controller.spi.SystemException; |
| import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; |
| import org.apache.ambari.server.controller.utilities.PropertyHelper; |
| import org.apache.ambari.server.state.Cluster; |
| import org.apache.ambari.server.state.Clusters; |
| import org.apache.ambari.server.state.ComponentInfo; |
| import org.apache.ambari.server.state.Config; |
| 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.StackId; |
| import org.apache.ambari.server.state.State; |
| import org.apache.commons.lang.StringUtils; |
| |
| /** |
| * Resource provider for service resources. |
| */ |
| class ServiceResourceProvider extends AbstractControllerResourceProvider { |
| |
| |
| // ----- Property ID constants --------------------------------------------- |
| |
| // Services |
| protected static final String SERVICE_CLUSTER_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "cluster_name"); |
| protected static final String SERVICE_SERVICE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "service_name"); |
| protected static final String SERVICE_SERVICE_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "state"); |
| |
| //Parameters from the predicate |
| private static final String QUERY_PARAMETERS_RUN_SMOKE_TEST_ID = |
| "params/run_smoke_test"; |
| |
| private static final String QUERY_PARAMETERS_RECONFIGURE_CLIENT = |
| "params/reconfigure_client"; |
| |
| private static Set<String> pkPropertyIds = |
| new HashSet<String>(Arrays.asList(new String[]{ |
| SERVICE_CLUSTER_NAME_PROPERTY_ID, |
| SERVICE_SERVICE_NAME_PROPERTY_ID})); |
| |
| // Service state calculation |
| private static final Map<String, ServiceState> serviceStateMap = new HashMap<String, ServiceState>(); |
| static { |
| serviceStateMap.put("HDFS", new HDFSServiceState()); |
| serviceStateMap.put("HBASE", new HBaseServiceState()); |
| } |
| |
| private static final ServiceState DEFAULT_SERVICE_STATE = new DefaultServiceState(); |
| |
| |
| // ----- Constructors ---------------------------------------------------- |
| |
| /** |
| * Create a new resource provider for the given management controller. |
| * |
| * @param propertyIds the property ids |
| * @param keyPropertyIds the key property ids |
| * @param managementController the management controller |
| */ |
| ServiceResourceProvider(Set<String> propertyIds, |
| Map<Resource.Type, String> keyPropertyIds, |
| AmbariManagementController managementController) { |
| super(propertyIds, keyPropertyIds, managementController); |
| } |
| |
| // ----- ResourceProvider ------------------------------------------------ |
| |
| @Override |
| public RequestStatus createResources(Request request) |
| throws SystemException, |
| UnsupportedPropertyException, |
| ResourceAlreadyExistsException, |
| NoSuchParentResourceException { |
| |
| final Set<ServiceRequest> requests = new HashSet<ServiceRequest>(); |
| for (Map<String, Object> propertyMap : request.getProperties()) { |
| requests.add(getRequest(propertyMap)); |
| } |
| createResources(new Command<Void>() { |
| @Override |
| public Void invoke() throws AmbariException { |
| createServices(requests); |
| return null; |
| } |
| }); |
| notifyCreate(Resource.Type.Service, request); |
| |
| return getRequestStatus(null); |
| } |
| |
| @Override |
| public Set<Resource> getResources(Request request, Predicate predicate) throws |
| SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { |
| |
| final Set<ServiceRequest> requests = new HashSet<ServiceRequest>(); |
| |
| for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { |
| requests.add(getRequest(propertyMap)); |
| } |
| |
| Set<ServiceResponse> responses = getResources(new Command<Set<ServiceResponse>>() { |
| @Override |
| public Set<ServiceResponse> invoke() throws AmbariException { |
| return getServices(requests); |
| } |
| }); |
| |
| Set<String> requestedIds = getRequestPropertyIds(request, predicate); |
| Set<Resource> resources = new HashSet<Resource>(); |
| |
| for (ServiceResponse response : responses) { |
| Resource resource = new ResourceImpl(Resource.Type.Service); |
| setResourceProperty(resource, SERVICE_CLUSTER_NAME_PROPERTY_ID, |
| response.getClusterName(), requestedIds); |
| setResourceProperty(resource, SERVICE_SERVICE_NAME_PROPERTY_ID, |
| response.getServiceName(), requestedIds); |
| setResourceProperty(resource, SERVICE_SERVICE_STATE_PROPERTY_ID, |
| calculateServiceState(response.getClusterName(), response.getServiceName()), |
| requestedIds); |
| resources.add(resource); |
| } |
| return resources; |
| } |
| |
| @Override |
| public RequestStatus updateResources(final Request request, Predicate predicate) |
| throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { |
| |
| final Set<ServiceRequest> requests = new HashSet<ServiceRequest>(); |
| RequestStatusResponse response = null; |
| |
| Iterator<Map<String,Object>> iterator = request.getProperties().iterator(); |
| if (iterator.hasNext()) { |
| for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) { |
| requests.add(getRequest(propertyMap)); |
| } |
| |
| final boolean runSmokeTest = "true".equals(getQueryParameterValue( |
| QUERY_PARAMETERS_RUN_SMOKE_TEST_ID, predicate)); |
| |
| final boolean reconfigureClients = !"false".equals(getQueryParameterValue( |
| QUERY_PARAMETERS_RECONFIGURE_CLIENT, predicate)); |
| |
| response = modifyResources(new Command<RequestStatusResponse>() { |
| @Override |
| public RequestStatusResponse invoke() throws AmbariException { |
| return updateServices(requests, |
| request.getRequestInfoProperties(), runSmokeTest, reconfigureClients); |
| } |
| }); |
| } |
| notifyUpdate(Resource.Type.Service, request, predicate); |
| |
| return getRequestStatus(response); |
| } |
| |
| @Override |
| public RequestStatus deleteResources(Predicate predicate) |
| throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { |
| |
| final Set<ServiceRequest> requests = new HashSet<ServiceRequest>(); |
| for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { |
| requests.add(getRequest(propertyMap)); |
| } |
| RequestStatusResponse response = modifyResources(new Command<RequestStatusResponse>() { |
| @Override |
| public RequestStatusResponse invoke() throws AmbariException { |
| return deleteServices(requests); |
| } |
| }); |
| |
| notifyDelete(Resource.Type.Service, predicate); |
| return getRequestStatus(response); |
| } |
| |
| @Override |
| public Set<String> checkPropertyIds(Set<String> propertyIds) { |
| propertyIds = super.checkPropertyIds(propertyIds); |
| |
| if (propertyIds.isEmpty()) { |
| return propertyIds; |
| } |
| Set<String> unsupportedProperties = new HashSet<String>(); |
| |
| for (String propertyId : propertyIds) { |
| if (!propertyId.equals("config")) { |
| String propertyCategory = PropertyHelper.getPropertyCategory(propertyId); |
| if (propertyCategory == null || !propertyCategory.equals("config")) { |
| unsupportedProperties.add(propertyId); |
| } |
| } |
| } |
| return unsupportedProperties; |
| } |
| |
| |
| // ----- AbstractResourceProvider ---------------------------------------- |
| |
| @Override |
| protected Set<String> getPKPropertyIds() { |
| return pkPropertyIds; |
| } |
| |
| |
| // ----- utility methods ------------------------------------------------- |
| /** |
| * Get a service request object from a map of property values. |
| * |
| * @param properties the predicate |
| * |
| * @return the service request object |
| */ |
| private ServiceRequest getRequest(Map<String, Object> properties) { |
| 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)); |
| |
| return svcRequest; |
| } |
| |
| // Create services from the given request. |
| protected synchronized void createServices(Set<ServiceRequest> requests) |
| throws AmbariException { |
| |
| if (requests.isEmpty()) { |
| LOG.warn("Received an empty requests set"); |
| return; |
| } |
| |
| Clusters clusters = getManagementController().getClusters(); |
| AmbariMetaInfo ambariMetaInfo = getManagementController().getAmbariMetaInfo(); |
| |
| // do all validation checks |
| Map<String, Set<String>> serviceNames = new HashMap<String, Set<String>>(); |
| Set<String> duplicates = new HashSet<String>(); |
| for (ServiceRequest request : requests) { |
| if (request.getClusterName() == null |
| || request.getClusterName().isEmpty() |
| || request.getServiceName() == null |
| || request.getServiceName().isEmpty()) { |
| throw new IllegalArgumentException("Cluster name and service name" |
| + " should be provided when creating a service"); |
| } |
| |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Received a createService request" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + request.getServiceName() |
| + ", request=" + request); |
| } |
| |
| if (!serviceNames.containsKey(request.getClusterName())) { |
| serviceNames.put(request.getClusterName(), new HashSet<String>()); |
| } |
| if (serviceNames.get(request.getClusterName()) |
| .contains(request.getServiceName())) { |
| // throw error later for dup |
| duplicates.add(request.getServiceName()); |
| continue; |
| } |
| serviceNames.get(request.getClusterName()).add(request.getServiceName()); |
| |
| if (request.getDesiredState() != null |
| && !request.getDesiredState().isEmpty()) { |
| State state = State.valueOf(request.getDesiredState()); |
| if (!state.isValidDesiredState() |
| || state != State.INIT) { |
| throw new IllegalArgumentException("Invalid desired state" |
| + " only INIT state allowed during creation" |
| + ", providedDesiredState=" + request.getDesiredState()); |
| } |
| } |
| |
| Cluster cluster; |
| try { |
| cluster = clusters.getCluster(request.getClusterName()); |
| } catch (ClusterNotFoundException e) { |
| throw new ParentObjectNotFoundException("Attempted to add a service to a cluster which doesn't exist", e); |
| } |
| try { |
| Service s = cluster.getService(request.getServiceName()); |
| if (s != null) { |
| // throw error later for dup |
| duplicates.add(request.getServiceName()); |
| continue; |
| } |
| } catch (ServiceNotFoundException e) { |
| // Expected |
| } |
| |
| StackId stackId = cluster.getDesiredStackVersion(); |
| if (!ambariMetaInfo.isValidService(stackId.getStackName(), |
| stackId.getStackVersion(), request.getServiceName())) { |
| throw new IllegalArgumentException("Unsupported or invalid service" |
| + " in stack" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + request.getServiceName() |
| + ", stackInfo=" + stackId.getStackId()); |
| } |
| } |
| |
| // ensure only a single cluster update |
| if (serviceNames.size() != 1) { |
| throw new IllegalArgumentException("Invalid arguments, updates allowed" |
| + "on only one cluster at a time"); |
| } |
| |
| // Validate dups |
| if (!duplicates.isEmpty()) { |
| StringBuilder svcNames = new StringBuilder(); |
| boolean first = true; |
| for (String svcName : duplicates) { |
| if (!first) { |
| svcNames.append(","); |
| } |
| first = false; |
| svcNames.append(svcName); |
| } |
| String clusterName = requests.iterator().next().getClusterName(); |
| String msg; |
| if (duplicates.size() == 1) { |
| msg = "Attempted to create a service which already exists: " |
| + ", clusterName=" + clusterName + " serviceName=" + svcNames.toString(); |
| } else { |
| msg = "Attempted to create services which already exist: " |
| + ", clusterName=" + clusterName + " serviceNames=" + svcNames.toString(); |
| } |
| throw new DuplicateResourceException(msg); |
| } |
| |
| ServiceFactory serviceFactory = getManagementController().getServiceFactory(); |
| |
| // now to the real work |
| for (ServiceRequest request : requests) { |
| Cluster cluster = clusters.getCluster(request.getClusterName()); |
| |
| State state = State.INIT; |
| |
| // Already checked that service does not exist |
| Service s = serviceFactory.createNew(cluster, request.getServiceName()); |
| |
| s.setDesiredState(state); |
| s.setDesiredStackVersion(cluster.getDesiredStackVersion()); |
| cluster.addService(s); |
| s.persist(); |
| } |
| } |
| |
| // Get services from the given set of requests. |
| protected Set<ServiceResponse> getServices(Set<ServiceRequest> requests) |
| throws AmbariException { |
| Set<ServiceResponse> response = new HashSet<ServiceResponse>(); |
| for (ServiceRequest request : requests) { |
| try { |
| response.addAll(getServices(request)); |
| } catch (ServiceNotFoundException e) { |
| if (requests.size() == 1) { |
| // only throw exception if 1 request. |
| // there will be > 1 request in case of OR predicate |
| throw e; |
| } |
| } |
| } |
| return response; |
| } |
| |
| // Get services from the given request. |
| private synchronized Set<ServiceResponse> getServices(ServiceRequest request) |
| throws AmbariException { |
| if (request.getClusterName() == null |
| || request.getClusterName().isEmpty()) { |
| throw new AmbariException("Invalid arguments, cluster name" |
| + " cannot be null"); |
| } |
| Clusters clusters = getManagementController().getClusters(); |
| String clusterName = request.getClusterName(); |
| |
| final Cluster cluster; |
| try { |
| cluster = clusters.getCluster(clusterName); |
| } catch (ObjectNotFoundException e) { |
| throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e); |
| } |
| |
| Set<ServiceResponse> response = new HashSet<ServiceResponse>(); |
| if (request.getServiceName() != null) { |
| Service s = cluster.getService(request.getServiceName()); |
| response.add(s.convertToResponse()); |
| return response; |
| } |
| |
| // TODO support search on predicates? |
| |
| boolean checkDesiredState = false; |
| State desiredStateToCheck = null; |
| if (request.getDesiredState() != null |
| && !request.getDesiredState().isEmpty()) { |
| desiredStateToCheck = State.valueOf(request.getDesiredState()); |
| if (!desiredStateToCheck.isValidDesiredState()) { |
| throw new IllegalArgumentException("Invalid arguments, invalid desired" |
| + " state, desiredState=" + desiredStateToCheck); |
| } |
| checkDesiredState = true; |
| } |
| |
| for (Service s : cluster.getServices().values()) { |
| if (checkDesiredState |
| && (desiredStateToCheck != s.getDesiredState())) { |
| // skip non matching state |
| continue; |
| } |
| response.add(s.convertToResponse()); |
| } |
| return response; |
| } |
| |
| // Update services based on the given requests. |
| protected synchronized RequestStatusResponse updateServices( |
| Set<ServiceRequest> requests, Map<String, String> requestProperties, |
| boolean runSmokeTest, boolean reconfigureClients) throws AmbariException { |
| |
| AmbariManagementController controller = getManagementController(); |
| |
| if (requests.isEmpty()) { |
| LOG.warn("Received an empty requests set"); |
| return null; |
| } |
| |
| Map<State, List<Service>> changedServices |
| = new HashMap<State, List<Service>>(); |
| Map<State, List<ServiceComponent>> changedComps = |
| new HashMap<State, List<ServiceComponent>>(); |
| Map<String, Map<State, List<ServiceComponentHost>>> changedScHosts = |
| new HashMap<String, Map<State, List<ServiceComponentHost>>>(); |
| Collection<ServiceComponentHost> ignoredScHosts = |
| new ArrayList<ServiceComponentHost>(); |
| |
| Set<String> clusterNames = new HashSet<String>(); |
| Map<String, Set<String>> serviceNames = new HashMap<String, Set<String>>(); |
| Set<State> seenNewStates = new HashSet<State>(); |
| |
| Clusters clusters = controller.getClusters(); |
| AmbariMetaInfo ambariMetaInfo = controller.getAmbariMetaInfo(); |
| |
| for (ServiceRequest request : requests) { |
| if (request.getClusterName() == null |
| || request.getClusterName().isEmpty() |
| || request.getServiceName() == null |
| || request.getServiceName().isEmpty()) { |
| throw new IllegalArgumentException("Invalid arguments, cluster name" |
| + " and service name should be provided to update services"); |
| } |
| |
| LOG.info("Received a updateService request" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + request.getServiceName() |
| + ", request=" + request.toString()); |
| |
| clusterNames.add(request.getClusterName()); |
| |
| if (clusterNames.size() > 1) { |
| throw new IllegalArgumentException("Updates to multiple clusters is not" |
| + " supported"); |
| } |
| |
| if (!serviceNames.containsKey(request.getClusterName())) { |
| serviceNames.put(request.getClusterName(), new HashSet<String>()); |
| } |
| if (serviceNames.get(request.getClusterName()) |
| .contains(request.getServiceName())) { |
| // TODO throw single exception |
| throw new IllegalArgumentException("Invalid request contains duplicate" |
| + " service names"); |
| } |
| serviceNames.get(request.getClusterName()).add(request.getServiceName()); |
| |
| Cluster cluster = clusters.getCluster(request.getClusterName()); |
| Service s = cluster.getService(request.getServiceName()); |
| State oldState = s.getDesiredState(); |
| State newState = null; |
| if (request.getDesiredState() != null) { |
| newState = State.valueOf(request.getDesiredState()); |
| if (!newState.isValidDesiredState()) { |
| throw new IllegalArgumentException("Invalid arguments, invalid" |
| + " desired state, desiredState=" + newState); |
| } |
| } |
| |
| if (newState == null) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Nothing to do for new updateService request" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + request.getServiceName() |
| + ", newDesiredState=null"); |
| } |
| continue; |
| } |
| |
| seenNewStates.add(newState); |
| |
| if (newState != oldState) { |
| if (!State.isValidDesiredStateTransition(oldState, newState)) { |
| throw new AmbariException("Invalid transition for" |
| + " service" |
| + ", clusterName=" + cluster.getClusterName() |
| + ", clusterId=" + cluster.getClusterId() |
| + ", serviceName=" + s.getName() |
| + ", currentDesiredState=" + oldState |
| + ", newDesiredState=" + newState); |
| |
| } |
| if (!changedServices.containsKey(newState)) { |
| changedServices.put(newState, new ArrayList<Service>()); |
| } |
| changedServices.get(newState).add(s); |
| } |
| |
| // TODO should we check whether all servicecomponents and |
| // servicecomponenthosts are in the required desired state? |
| |
| for (ServiceComponent sc : s.getServiceComponents().values()) { |
| State oldScState = sc.getDesiredState(); |
| if (newState != oldScState) { |
| if (sc.isClientComponent() && |
| !newState.isValidClientComponentState()) { |
| continue; |
| } |
| if (!State.isValidDesiredStateTransition(oldScState, newState)) { |
| throw new AmbariException("Invalid transition for" |
| + " servicecomponent" |
| + ", clusterName=" + cluster.getClusterName() |
| + ", clusterId=" + cluster.getClusterId() |
| + ", serviceName=" + sc.getServiceName() |
| + ", componentName=" + sc.getName() |
| + ", currentDesiredState=" + oldScState |
| + ", newDesiredState=" + newState); |
| } |
| if (!changedComps.containsKey(newState)) { |
| changedComps.put(newState, new ArrayList<ServiceComponent>()); |
| } |
| changedComps.get(newState).add(sc); |
| } |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Handling update to ServiceComponent" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + s.getName() |
| + ", componentName=" + sc.getName() |
| + ", currentDesiredState=" + oldScState |
| + ", newDesiredState=" + newState); |
| } |
| for (ServiceComponentHost sch : sc.getServiceComponentHosts().values()){ |
| State oldSchState = sch.getState(); |
| if (oldSchState == State.MAINTENANCE || oldSchState == State.UNKNOWN) { |
| //Ignore host components updates in this state |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Ignoring ServiceComponentHost" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + s.getName() |
| + ", componentName=" + sc.getName() |
| + ", hostname=" + sch.getHostName() |
| + ", currentState=" + oldSchState |
| + ", newDesiredState=" + newState); |
| } |
| continue; |
| } |
| if (newState == oldSchState) { |
| ignoredScHosts.add(sch); |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Ignoring ServiceComponentHost" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + s.getName() |
| + ", componentName=" + sc.getName() |
| + ", hostname=" + sch.getHostName() |
| + ", currentState=" + oldSchState |
| + ", newDesiredState=" + newState); |
| } |
| continue; |
| } |
| if (sc.isClientComponent() && |
| !newState.isValidClientComponentState()) { |
| continue; |
| } |
| /** |
| * This is hack for now wherein we don't fail if the |
| * sch is in INSTALL_FAILED |
| */ |
| if (!State.isValidStateTransition(oldSchState, newState)) { |
| String error = "Invalid transition for" |
| + " servicecomponenthost" |
| + ", clusterName=" + cluster.getClusterName() |
| + ", clusterId=" + cluster.getClusterId() |
| + ", serviceName=" + sch.getServiceName() |
| + ", componentName=" + sch.getServiceComponentName() |
| + ", hostname=" + sch.getHostName() |
| + ", currentState=" + oldSchState |
| + ", newDesiredState=" + newState; |
| StackId sid = cluster.getDesiredStackVersion(); |
| |
| if ( ambariMetaInfo.getComponentCategory( |
| sid.getStackName(), sid.getStackVersion(), sc.getServiceName(), |
| sch.getServiceComponentName()).isMaster()) { |
| throw new AmbariException(error); |
| } else { |
| LOG.warn("Ignoring: " + error); |
| continue; |
| } |
| } |
| if (!changedScHosts.containsKey(sc.getName())) { |
| changedScHosts.put(sc.getName(), |
| new HashMap<State, List<ServiceComponentHost>>()); |
| } |
| if (!changedScHosts.get(sc.getName()).containsKey(newState)) { |
| changedScHosts.get(sc.getName()).put(newState, |
| new ArrayList<ServiceComponentHost>()); |
| } |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Handling update to ServiceComponentHost" |
| + ", clusterName=" + request.getClusterName() |
| + ", serviceName=" + s.getName() |
| + ", componentName=" + sc.getName() |
| + ", hostname=" + sch.getHostName() |
| + ", currentState=" + oldSchState |
| + ", newDesiredState=" + newState); |
| } |
| changedScHosts.get(sc.getName()).get(newState).add(sch); |
| } |
| } |
| } |
| |
| if (seenNewStates.size() > 1) { |
| // TODO should we handle this scenario |
| throw new IllegalArgumentException("Cannot handle different desired state" |
| + " changes for a set of services at the same time"); |
| } |
| |
| Cluster cluster = clusters.getCluster(clusterNames.iterator().next()); |
| |
| return controller.createStages(cluster, requestProperties, null, changedServices, changedComps, changedScHosts, |
| ignoredScHosts, runSmokeTest, reconfigureClients); |
| } |
| |
| // Delete services based on the given set of requests |
| protected RequestStatusResponse deleteServices(Set<ServiceRequest> request) |
| throws AmbariException { |
| |
| Clusters clusters = getManagementController().getClusters(); |
| |
| for (ServiceRequest serviceRequest : request) { |
| if (StringUtils.isEmpty(serviceRequest.getClusterName()) || StringUtils.isEmpty(serviceRequest.getServiceName())) { |
| // FIXME throw correct error |
| throw new AmbariException("invalid arguments"); |
| } else { |
| clusters.getCluster(serviceRequest.getClusterName()).deleteService(serviceRequest.getServiceName()); |
| } |
| } |
| return null; |
| } |
| |
| // Get the State of a host component |
| private static State getHostComponentState(ServiceComponentHostResponse hostComponent) { |
| return State.valueOf(hostComponent.getLiveState()); |
| } |
| |
| // calculate the service state, accounting for the state of the host components |
| private String calculateServiceState(String clusterName, String serviceName) { |
| |
| ServiceState serviceState = serviceStateMap.get(serviceName); |
| if (serviceState == null) { |
| serviceState = DEFAULT_SERVICE_STATE; |
| } |
| State state = serviceState.getState(getManagementController(), clusterName, serviceName); |
| |
| return state.toString(); |
| } |
| |
| |
| // ----- inner class ServiceState ------------------------------------------ |
| |
| /** |
| * Interface to allow for different state calculations for different services. |
| * TODO : see if this functionality can be moved to service definitions. |
| */ |
| protected interface ServiceState { |
| public State getState(AmbariManagementController controller, String clusterName, String serviceName); |
| } |
| |
| /** |
| * Default calculator of service state. |
| */ |
| protected static class DefaultServiceState implements ServiceState { |
| |
| @Override |
| public State getState(AmbariManagementController controller, String clusterName, String serviceName) { |
| AmbariMetaInfo ambariMetaInfo = controller.getAmbariMetaInfo(); |
| Clusters clusters = controller.getClusters(); |
| |
| if (clusterName != null && clusterName.length() > 0) { |
| try { |
| Cluster cluster = clusters.getCluster(clusterName); |
| if (cluster != null) { |
| StackId stackId = cluster.getDesiredStackVersion(); |
| |
| ServiceComponentHostRequest request = new ServiceComponentHostRequest(clusterName, |
| serviceName, null, null, null); |
| |
| Set<ServiceComponentHostResponse> hostComponentResponses = |
| controller.getHostComponents(Collections.singleton(request)); |
| |
| for (ServiceComponentHostResponse hostComponentResponse : hostComponentResponses ) { |
| ComponentInfo componentInfo = ambariMetaInfo.getComponentCategory(stackId.getStackName(), |
| stackId.getStackVersion(), hostComponentResponse.getServiceName(), |
| hostComponentResponse.getComponentName()); |
| |
| if (componentInfo != null) { |
| if (componentInfo.isMaster()) { |
| State state = getHostComponentState(hostComponentResponse); |
| switch (state) { |
| case STARTED: |
| case MAINTENANCE: |
| break; |
| default: |
| return state; |
| } |
| } |
| } |
| } |
| return State.STARTED; |
| } |
| } catch (AmbariException e) { |
| LOG.error("Can't determine service state.", e); |
| } |
| } |
| return State.UNKNOWN; |
| } |
| } |
| |
| /** |
| * Calculator of HDFS service state. |
| */ |
| protected static class HDFSServiceState implements ServiceState { |
| |
| @Override |
| public State getState(AmbariManagementController controller,String clusterName, String serviceName) { |
| AmbariMetaInfo ambariMetaInfo = controller.getAmbariMetaInfo(); |
| Clusters clusters = controller.getClusters(); |
| |
| if (clusterName != null && clusterName.length() > 0) { |
| try { |
| Cluster cluster = clusters.getCluster(clusterName); |
| if (cluster != null) { |
| StackId stackId = cluster.getDesiredStackVersion(); |
| |
| ServiceComponentHostRequest request = new ServiceComponentHostRequest(clusterName, |
| serviceName, null, null, null); |
| |
| Set<ServiceComponentHostResponse> hostComponentResponses = |
| controller.getHostComponents(Collections.singleton(request)); |
| |
| int nameNodeCount = 0; |
| int nameNodeActiveCount = 0; |
| boolean hasSecondary = false; |
| boolean hasJournal = false; |
| State nonStartedState = null; |
| |
| for (ServiceComponentHostResponse hostComponentResponse : hostComponentResponses ) { |
| ComponentInfo componentInfo = ambariMetaInfo.getComponentCategory(stackId.getStackName(), |
| stackId.getStackVersion(), hostComponentResponse.getServiceName(), |
| hostComponentResponse.getComponentName()); |
| |
| if (componentInfo != null) { |
| if (componentInfo.isMaster()) { |
| |
| String componentName = hostComponentResponse.getComponentName(); |
| boolean isNameNode = false; |
| |
| if (componentName.equals("NAMENODE")) { |
| ++nameNodeCount; |
| isNameNode = true; |
| } else if (componentName.equals("SECONDARY_NAMENODE")) { |
| hasSecondary = true; |
| } else if (componentName.equals("JOURNALNODE")) { |
| hasJournal = true; |
| } |
| |
| State state = getHostComponentState(hostComponentResponse); |
| |
| switch (state) { |
| case STARTED: |
| case MAINTENANCE: |
| if (isNameNode) { |
| ++nameNodeActiveCount; |
| } |
| break; |
| default: |
| nonStartedState = state; |
| } |
| } |
| } |
| } |
| |
| if ( nonStartedState == null || // all started |
| ((nameNodeCount > 0 && !hasSecondary || hasJournal) && |
| nameNodeActiveCount > 0)) { // at least one active namenode |
| return State.STARTED; |
| } |
| return nonStartedState; |
| } |
| } catch (AmbariException e) { |
| LOG.error("Can't determine service state.", e); |
| } |
| } |
| return State.UNKNOWN; |
| } |
| } |
| |
| /** |
| * Calculator of HBase service state. |
| */ |
| protected static class HBaseServiceState implements ServiceState { |
| |
| @Override |
| public State getState(AmbariManagementController controller,String clusterName, String serviceName) { |
| AmbariMetaInfo ambariMetaInfo = controller.getAmbariMetaInfo(); |
| Clusters clusters = controller.getClusters(); |
| |
| if (clusterName != null && clusterName.length() > 0) { |
| try { |
| Cluster cluster = clusters.getCluster(clusterName); |
| if (cluster != null) { |
| StackId stackId = cluster.getDesiredStackVersion(); |
| |
| ServiceComponentHostRequest request = new ServiceComponentHostRequest(clusterName, |
| serviceName, null, null, null); |
| |
| Set<ServiceComponentHostResponse> hostComponentResponses = |
| controller.getHostComponents(Collections.singleton(request)); |
| |
| int hBaseMasterActiveCount = 0; |
| State nonStartedState = null; |
| |
| for (ServiceComponentHostResponse hostComponentResponse : hostComponentResponses ) { |
| ComponentInfo componentInfo = ambariMetaInfo.getComponentCategory(stackId.getStackName(), |
| stackId.getStackVersion(), hostComponentResponse.getServiceName(), |
| hostComponentResponse.getComponentName()); |
| |
| if (componentInfo != null) { |
| if (componentInfo.isMaster()) { |
| |
| State state = getHostComponentState(hostComponentResponse); |
| |
| switch (state) { |
| case STARTED: |
| case MAINTENANCE: |
| String componentName = hostComponentResponse.getComponentName(); |
| if (componentName.equals("HBASE_MASTER")) { |
| ++hBaseMasterActiveCount; |
| } |
| break; |
| default: |
| nonStartedState = state; |
| } |
| } |
| } |
| } |
| |
| if ( nonStartedState == null || // all started |
| hBaseMasterActiveCount > 0) { // at least one active hbase_master |
| return State.STARTED; |
| } |
| return nonStartedState; |
| } |
| } catch (AmbariException e) { |
| LOG.error("Can't determine service state.", e); |
| } |
| } |
| return State.UNKNOWN; } |
| } |
| } |