Java tutorial
/** * 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.EnumMap; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.google.inject.Inject; import com.google.inject.Injector; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.configuration.ComponentSSLConfiguration; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.MaintenanceStateHelper; 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.predicate.AndPredicate; import org.apache.ambari.server.controller.predicate.EqualsPredicate; import org.apache.ambari.server.controller.predicate.NotPredicate; import org.apache.ambari.server.controller.predicate.OrPredicate; 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.PropertyProvider; 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 com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.AssistedInject; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.MaintenanceState; import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.ServiceComponentHostEvent; import org.apache.ambari.server.state.State; import org.apache.ambari.server.state.fsm.InvalidStateTransitionException; import org.apache.ambari.server.state.svccomphost.ServiceComponentHostDisableEvent; import org.apache.ambari.server.state.svccomphost.ServiceComponentHostRestoreEvent; import org.apache.commons.lang.StringUtils; /** * Resource provider for host component resources. */ public class HostComponentResourceProvider extends AbstractControllerResourceProvider { // ----- Property ID constants --------------------------------------------- // Host Components protected static final String HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "cluster_name"); protected static final String HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "service_name"); protected static final String HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "component_name"); protected static final String HOST_COMPONENT_HOST_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("HostRoles", "host_name"); protected static final String HOST_COMPONENT_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("HostRoles", "state"); protected static final String HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "desired_state"); protected static final String HOST_COMPONENT_STACK_ID_PROPERTY_ID = PropertyHelper.getPropertyId("HostRoles", "stack_id"); protected static final String HOST_COMPONENT_DESIRED_STACK_ID_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "desired_stack_id"); protected static final String HOST_COMPONENT_ACTUAL_CONFIGS_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "actual_configs"); protected static final String HOST_COMPONENT_STALE_CONFIGS_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "stale_configs"); protected static final String HOST_COMPONENT_DESIRED_ADMIN_STATE_PROPERTY_ID = PropertyHelper .getPropertyId("HostRoles", "desired_admin_state"); protected static final String HOST_COMPONENT_MAINTENANCE_STATE_PROPERTY_ID = "HostRoles/maintenance_state"; //Component name mappings private final Map<String, PropertyProvider> HOST_COMPONENT_PROPERTIES_PROVIDER = new HashMap<String, PropertyProvider>(); private static final int HOST_COMPONENT_HTTP_PROPERTY_REQUEST_CONNECT_TIMEOUT = 1500; //milliseconds private static final int HOST_COMPONENT_HTTP_PROPERTY_REQUEST_READ_TIMEOUT = 10000; //milliseconds //Parameters from the predicate private static final String QUERY_PARAMETERS_RUN_SMOKE_TEST_ID = "params/run_smoke_test"; private static Set<String> pkPropertyIds = new HashSet<String>(Arrays .asList(new String[] { HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID, HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID, HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID, HOST_COMPONENT_HOST_NAME_PROPERTY_ID })); /** * maintenance state helper */ @Inject private MaintenanceStateHelper maintenanceStateHelper; // ----- 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 */ @AssistedInject public HostComponentResourceProvider(@Assisted Set<String> propertyIds, @Assisted Map<Resource.Type, String> keyPropertyIds, @Assisted AmbariManagementController managementController, Injector injector) { super(propertyIds, keyPropertyIds, managementController); ComponentSSLConfiguration configuration = ComponentSSLConfiguration.instance(); URLStreamProvider streamProvider = new URLStreamProvider( HOST_COMPONENT_HTTP_PROPERTY_REQUEST_CONNECT_TIMEOUT, HOST_COMPONENT_HTTP_PROPERTY_REQUEST_READ_TIMEOUT, configuration.getTruststorePath(), configuration.getTruststorePassword(), configuration.getTruststoreType()); HttpProxyPropertyProvider httpPropertyProvider = new HttpProxyPropertyProvider(streamProvider, configuration, injector, PropertyHelper.getPropertyId("HostRoles", "cluster_name"), PropertyHelper.getPropertyId("HostRoles", "host_name"), PropertyHelper.getPropertyId("HostRoles", "component_name")); HOST_COMPONENT_PROPERTIES_PROVIDER.put("RESOURCEMANAGER", httpPropertyProvider); } // ----- ResourceProvider ------------------------------------------------ @Override public RequestStatus createResources(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException { final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>(); for (Map<String, Object> propertyMap : request.getProperties()) { requests.add(getRequest(propertyMap)); } createResources(new Command<Void>() { @Override public Void invoke() throws AmbariException { getManagementController().createHostComponents(requests); return null; } }); notifyCreate(Resource.Type.HostComponent, request); return getRequestStatus(null); } @Override public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>(); for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { requests.add(getRequest(propertyMap)); } Set<Resource> resources = new HashSet<Resource>(); Set<String> requestedIds = getRequestPropertyIds(request, predicate); // We always need host_name for sch requestedIds.add(HOST_COMPONENT_HOST_NAME_PROPERTY_ID); Set<ServiceComponentHostResponse> responses = getResources( new Command<Set<ServiceComponentHostResponse>>() { @Override public Set<ServiceComponentHostResponse> invoke() throws AmbariException { return getManagementController().getHostComponents(requests); } }); for (ServiceComponentHostResponse response : responses) { Resource resource = new ResourceImpl(Resource.Type.HostComponent); setResourceProperty(resource, HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID, response.getClusterName(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID, response.getServiceName(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID, response.getComponentName(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_HOST_NAME_PROPERTY_ID, response.getHostname(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_STATE_PROPERTY_ID, response.getLiveState(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID, response.getDesiredState(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_STACK_ID_PROPERTY_ID, response.getStackVersion(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_DESIRED_STACK_ID_PROPERTY_ID, response.getDesiredStackVersion(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_ACTUAL_CONFIGS_PROPERTY_ID, response.getActualConfigs(), requestedIds); setResourceProperty(resource, HOST_COMPONENT_STALE_CONFIGS_PROPERTY_ID, response.isStaleConfig(), requestedIds); if (response.getAdminState() != null) { setResourceProperty(resource, HOST_COMPONENT_DESIRED_ADMIN_STATE_PROPERTY_ID, response.getAdminState(), requestedIds); } if (null != response.getMaintenanceState()) { setResourceProperty(resource, HOST_COMPONENT_MAINTENANCE_STATE_PROPERTY_ID, response.getMaintenanceState(), requestedIds); } String componentName = (String) resource.getPropertyValue(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID); PropertyProvider propertyProvider = HOST_COMPONENT_PROPERTIES_PROVIDER.get(componentName); if (propertyProvider != null) { Set<Resource> resourcesToPopulate = new HashSet<Resource>(); resourcesToPopulate.add(resource); propertyProvider.populateResources(resourcesToPopulate, request, predicate); } resources.add(resource); } return resources; } @Override public RequestStatus updateResources(final Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { if (request.getProperties().isEmpty()) { throw new IllegalArgumentException("Received an update request with no properties"); } RequestStageContainer requestStages = doUpdateResources(null, request, predicate, false); RequestStatusResponse response = null; if (requestStages != null) { try { requestStages.persist(); } catch (AmbariException e) { throw new SystemException(e.getMessage(), e); } response = requestStages.getRequestStatusResponse(); notifyUpdate(Resource.Type.HostComponent, request, predicate); } return getRequestStatus(response); } @Override public RequestStatus deleteResources(Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>(); for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { requests.add(getRequest(propertyMap)); } RequestStatusResponse response = modifyResources(new Command<RequestStatusResponse>() { @Override public RequestStatusResponse invoke() throws AmbariException { return getManagementController().deleteHostComponents(requests); } }); notifyDelete(Resource.Type.HostComponent, 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; } RequestStatusResponse installAndStart(String cluster, Collection<String> hosts) throws SystemException, UnsupportedPropertyException, NoSuchParentResourceException { final RequestStageContainer requestStages; Map<String, Object> installProperties = new HashMap<String, Object>(); installProperties.put(HOST_COMPONENT_STATE_PROPERTY_ID, "INSTALLED"); Map<String, String> requestInfo = new HashMap<String, String>(); requestInfo.put("context", "?"); Request installRequest = PropertyHelper.getUpdateRequest(installProperties, requestInfo); Collection<EqualsPredicate> hostPredicates = new ArrayList<EqualsPredicate>(); for (String host : hosts) { hostPredicates.add(new EqualsPredicate<String>(HOST_COMPONENT_HOST_NAME_PROPERTY_ID, host)); } Predicate statePredicate = new EqualsPredicate<String>(HOST_COMPONENT_STATE_PROPERTY_ID, "INIT"); Predicate clusterPredicate = new EqualsPredicate<String>(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID, cluster); Predicate hostPredicate = new OrPredicate(hostPredicates.toArray(new Predicate[hostPredicates.size()])); Predicate hostAndStatePredicate = new AndPredicate(statePredicate, hostPredicate); Predicate installPredicate = new AndPredicate(hostAndStatePredicate, clusterPredicate); try { LOG.info("Installing all components on added hosts"); requestStages = doUpdateResources(null, installRequest, installPredicate, true); notifyUpdate(Resource.Type.HostComponent, installRequest, installPredicate); Map<String, Object> startProperties = new HashMap<String, Object>(); startProperties.put(HOST_COMPONENT_STATE_PROPERTY_ID, "STARTED"); Request startRequest = PropertyHelper.getUpdateRequest(startProperties, requestInfo); // Important to query against desired_state as this has been updated when install stage was created // If I query against state, then the getRequest compares predicate prop against desired_state and then when the predicate // is later applied explicitly, it gets compared to live_state. Since live_state == INSTALLED == INIT at this point and // desired_state == INSTALLED, we will always get 0 matches since both comparisons can't be true :( Predicate installedStatePredicate = new EqualsPredicate<String>( HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID, "INSTALLED"); Predicate notClientPredicate = new NotPredicate(new ClientComponentPredicate()); Predicate clusterAndClientPredicate = new AndPredicate(clusterPredicate, notClientPredicate); hostAndStatePredicate = new AndPredicate(installedStatePredicate, hostPredicate); Predicate startPredicate = new AndPredicate(clusterAndClientPredicate, hostAndStatePredicate); LOG.info("Starting all non-client components on added hosts"); //todo: if a host in in state HEARTBEAT_LOST, no stage will be created, so if this occurs during INSTALL //todo: then no INSTALL stage will exist which will result in invalid state transition INIT->STARTED doUpdateResources(requestStages, startRequest, startPredicate, true); notifyUpdate(Resource.Type.HostComponent, startRequest, startPredicate); try { requestStages.persist(); } catch (AmbariException e) { throw new SystemException(e.getMessage(), e); } return requestStages.getRequestStatusResponse(); } catch (NoSuchResourceException e) { // shouldn't encounter this exception here throw new SystemException("An unexpected exception occurred while processing add hosts", e); } } /** * Update the host component identified by the given request object with the * values carried by the given request object. * * @param stages stages of the associated request * @param requests the request object which defines which host component to * update and the values to set * @param requestProperties the request properties * @param runSmokeTest indicates whether or not to run a smoke test * * @return a track action response * * @throws AmbariException thrown if the resource cannot be updated */ //todo: This was moved from AmbariManagementController and needs a lot of refactoring. //todo: Look into using the predicate instead of Set<ServiceComponentHostRequest> //todo: change to private access when all AMC tests have been moved. protected synchronized RequestStageContainer updateHostComponents(RequestStageContainer stages, Set<ServiceComponentHostRequest> requests, Map<String, String> requestProperties, boolean runSmokeTest) throws AmbariException { Clusters clusters = getManagementController().getClusters(); 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, Map<String, Map<String, Set<String>>>> requestClusters = new HashMap<String, Map<String, Map<String, Set<String>>>>(); Map<ServiceComponentHost, State> directTransitionScHosts = new HashMap<ServiceComponentHost, State>(); Resource.Type reqOpLvl = determineOperationLevel(requestProperties); String clusterName = requestProperties.get(RequestOperationLevel.OPERATION_CLUSTER_ID); if (clusterName != null && !clusterName.isEmpty()) { clusterNames.add(clusterName); } for (ServiceComponentHostRequest request : requests) { validateServiceComponentHostRequest(request); Cluster cluster = clusters.getCluster(request.getClusterName()); if (StringUtils.isEmpty(request.getServiceName())) { request.setServiceName( getManagementController().findServiceName(cluster, request.getComponentName())); } ServiceComponent sc = getServiceComponent(request.getClusterName(), request.getServiceName(), request.getComponentName()); logRequestInfo("Received a updateHostComponent request", request); if ((clusterName == null || clusterName.isEmpty()) && (request.getClusterName() != null && !request.getClusterName().isEmpty())) { clusterNames.add(request.getClusterName()); } if (clusterNames.size() > 1) { throw new IllegalArgumentException("Updates to multiple clusters is not" + " supported"); } // maps of cluster->services, services->components, components->hosts Map<String, Map<String, Set<String>>> clusterServices = requestClusters.get(request.getClusterName()); if (clusterServices == null) { clusterServices = new HashMap<String, Map<String, Set<String>>>(); requestClusters.put(request.getClusterName(), clusterServices); } Map<String, Set<String>> serviceComponents = clusterServices.get(request.getServiceName()); if (serviceComponents == null) { serviceComponents = new HashMap<String, Set<String>>(); clusterServices.put(request.getServiceName(), serviceComponents); } Set<String> componentHosts = serviceComponents.get(request.getComponentName()); if (componentHosts == null) { componentHosts = new HashSet<String>(); serviceComponents.put(request.getComponentName(), componentHosts); } if (componentHosts.contains(request.getHostname())) { throw new IllegalArgumentException("Invalid request contains duplicate hostcomponents"); } componentHosts.add(request.getHostname()); ServiceComponentHost sch = sc.getServiceComponentHost(request.getHostname()); State oldState = sch.getState(); State newState = null; if (request.getDesiredState() != null) { // set desired state on host component newState = State.valueOf(request.getDesiredState()); // throw exception if desired state isn't a valid desired state (static check) if (!newState.isValidDesiredState()) { throw new IllegalArgumentException( "Invalid arguments, invalid" + " desired state, desiredState=" + newState.toString()); } } // Setting Maintenance state for host component if (null != request.getMaintenanceState()) { MaintenanceState newMaint = MaintenanceState.valueOf(request.getMaintenanceState()); MaintenanceState oldMaint = maintenanceStateHelper.getEffectiveState(sch); if (newMaint != oldMaint) { if (sc.isClientComponent()) { throw new IllegalArgumentException( "Invalid arguments, cannot set maintenance state on a client component"); } else if (newMaint.equals(MaintenanceState.IMPLIED_FROM_HOST) || newMaint.equals(MaintenanceState.IMPLIED_FROM_SERVICE)) { throw new IllegalArgumentException( "Invalid arguments, can only set maintenance state to one of " + EnumSet.of(MaintenanceState.OFF, MaintenanceState.ON)); } else { sch.setMaintenanceState(newMaint); } } } if (newState == null) { logComponentInfo("Nothing to do for new updateServiceComponentHost", request, oldState, null); continue; } if (sc.isClientComponent() && !newState.isValidClientComponentState()) { throw new IllegalArgumentException("Invalid desired state for a client" + " component"); } State oldSchState = sch.getState(); // Client component reinstall allowed if (newState == oldSchState && !sc.isClientComponent() && !requestProperties.containsKey(sch.getServiceComponentName().toLowerCase())) { ignoredScHosts.add(sch); logComponentInfo("Ignoring ServiceComponentHost", request, oldState, newState); continue; } if (!maintenanceStateHelper.isOperationAllowed(reqOpLvl, sch)) { ignoredScHosts.add(sch); logComponentInfo("Ignoring ServiceComponentHost", request, oldState, newState); continue; } if (!isValidStateTransition(stages, oldSchState, newState, sch)) { throw new AmbariException("Invalid state transition for host component" + ", clusterName=" + cluster.getClusterName() + ", clusterId=" + cluster.getClusterId() + ", serviceName=" + sch.getServiceName() + ", componentName=" + sch.getServiceComponentName() + ", hostname=" + sch.getHostName() + ", currentState=" + oldSchState + ", newDesiredState=" + newState); } if (isDirectTransition(oldSchState, newState)) { logComponentInfo("Handling direct transition update to host component", request, oldState, newState); directTransitionScHosts.put(sch, newState); } else { if (!changedScHosts.containsKey(sc.getName())) { changedScHosts.put(sc.getName(), new EnumMap<State, List<ServiceComponentHost>>(State.class)); } if (!changedScHosts.get(sc.getName()).containsKey(newState)) { changedScHosts.get(sc.getName()).put(newState, new ArrayList<ServiceComponentHost>()); } logComponentInfo("Handling update to host component", request, oldState, newState); changedScHosts.get(sc.getName()).get(newState).add(sch); } } doDirectTransitions(directTransitionScHosts); // just getting the first cluster Cluster cluster = clusters.getCluster(clusterNames.iterator().next()); return getManagementController().addStages(stages, cluster, requestProperties, null, null, null, changedScHosts, ignoredScHosts, runSmokeTest, false); } @Override protected Set<String> getPKPropertyIds() { return pkPropertyIds; } // ----- utility methods ------------------------------------------------- /** * Get a component request object from a map of property values. * * @param properties the predicate * @return the component request object */ private ServiceComponentHostRequest getRequest(Map<String, Object> properties) { ServiceComponentHostRequest serviceComponentHostRequest = new ServiceComponentHostRequest( (String) properties.get(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID), (String) properties.get(HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID), (String) properties.get(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID), (String) properties.get(HOST_COMPONENT_HOST_NAME_PROPERTY_ID), (String) properties.get(HOST_COMPONENT_STATE_PROPERTY_ID)); serviceComponentHostRequest.setDesiredStackId((String) properties.get(HOST_COMPONENT_STACK_ID_PROPERTY_ID)); if (properties.get(HOST_COMPONENT_STALE_CONFIGS_PROPERTY_ID) != null) { serviceComponentHostRequest.setStaleConfig( properties.get(HOST_COMPONENT_STALE_CONFIGS_PROPERTY_ID).toString().toLowerCase()); } if (properties.get(HOST_COMPONENT_DESIRED_ADMIN_STATE_PROPERTY_ID) != null) { serviceComponentHostRequest .setAdminState(properties.get(HOST_COMPONENT_DESIRED_ADMIN_STATE_PROPERTY_ID).toString()); } Object o = properties.get(HOST_COMPONENT_MAINTENANCE_STATE_PROPERTY_ID); if (null != o) { serviceComponentHostRequest.setMaintenanceState(o.toString()); } return serviceComponentHostRequest; } /** * Update resources. * * @param stages request stage container * @param request request * @param predicate request predicate * @param performQueryEvaluation should query be evaluated for matching resource set * @return * @throws UnsupportedPropertyException an unsupported property was specified in the request * @throws SystemException an unknown exception occurred * @throws NoSuchResourceException the query didn't match any resources * @throws NoSuchParentResourceException a specified parent resource doesn't exist */ private RequestStageContainer doUpdateResources(final RequestStageContainer stages, final Request request, Predicate predicate, boolean performQueryEvaluation) throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException { final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>(); final boolean runSmokeTest = "true" .equals(getQueryParameterValue(QUERY_PARAMETERS_RUN_SMOKE_TEST_ID, predicate)); Set<String> queryIds = Collections.singleton(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID); Request queryRequest = PropertyHelper.getReadRequest(queryIds); // will take care of 404 exception Set<Resource> matchingResources = getResources(queryRequest, predicate); for (Resource queryResource : matchingResources) { //todo: predicate evaluation was removed for BUG-28737 and the removal of this breaks //todo: the new "add hosts" api. BUG-4818 is the root cause and needs to be addressed //todo: and then this predicate evaluation should always be performed and the //todo: temporary performQueryEvaluation flag hack should be removed. if (!performQueryEvaluation || predicate.evaluate(queryResource)) { Map<String, Object> updateRequestProperties = new HashMap<String, Object>(); // add props from query resource updateRequestProperties.putAll(PropertyHelper.getProperties(queryResource)); // add properties from update request //todo: should we flag value size > 1? if (request.getProperties() != null && request.getProperties().size() != 0) { updateRequestProperties.putAll(request.getProperties().iterator().next()); } requests.add(getRequest(updateRequestProperties)); } } RequestStageContainer requestStages = modifyResources(new Command<RequestStageContainer>() { @Override public RequestStageContainer invoke() throws AmbariException { return updateHostComponents(stages, requests, request.getRequestInfoProperties(), runSmokeTest); } }); notifyUpdate(Resource.Type.HostComponent, request, predicate); return requestStages; } /** * Determine whether a host component state change is valid. * Looks at projected state from the current stages associated with the request. * * * @param stages request stages * @param startState host component start state * @param desiredState host component desired state * @param host host where state change is occurring * * @return whether the state transition is valid */ private boolean isValidStateTransition(RequestStageContainer stages, State startState, State desiredState, ServiceComponentHost host) { if (stages != null) { State projectedState = stages.getProjectedState(host.getHostName(), host.getServiceComponentName()); startState = projectedState == null ? startState : projectedState; } return State.isValidStateTransition(startState, desiredState); } /** * Checks if assigning new state does not require performing * any additional actions */ public boolean isDirectTransition(State oldState, State newState) { switch (newState) { case INSTALLED: if (oldState == State.DISABLED) { return true; } break; case DISABLED: if (oldState == State.INSTALLED || oldState == State.INSTALL_FAILED || oldState == State.UNKNOWN) { return true; } break; default: break; } return false; } private ServiceComponent getServiceComponent(String clusterName, String serviceName, String componentName) throws AmbariException { Clusters clusters = getManagementController().getClusters(); return clusters.getCluster(clusterName).getService(serviceName).getServiceComponent(componentName); } // Perform direct transitions (without task generation) private void doDirectTransitions(Map<ServiceComponentHost, State> directTransitionScHosts) throws AmbariException { for (Map.Entry<ServiceComponentHost, State> entry : directTransitionScHosts.entrySet()) { ServiceComponentHost componentHost = entry.getKey(); State newState = entry.getValue(); long timestamp = System.currentTimeMillis(); ServiceComponentHostEvent event; componentHost.setDesiredState(newState); switch (newState) { case DISABLED: event = new ServiceComponentHostDisableEvent(componentHost.getServiceComponentName(), componentHost.getHostName(), timestamp); break; case INSTALLED: event = new ServiceComponentHostRestoreEvent(componentHost.getServiceComponentName(), componentHost.getHostName(), timestamp); break; default: throw new AmbariException("Direct transition from " + componentHost.getState() + " to " + newState + " not supported"); } try { componentHost.handleEvent(event); } catch (InvalidStateTransitionException e) { //Should not occur, must be covered by previous checks throw new AmbariException("Internal error - not supported transition", e); } } } /** * Logs request info. * * @param msg base log msg * @param request the request to log */ private void logRequestInfo(String msg, ServiceComponentHostRequest request) { LOG.info("{}, clusterName={}, serviceName={}, componentName={}, hostname={}, request={}", msg, request.getClusterName(), request.getServiceName(), request.getComponentName(), request.getHostname(), request); } /** * Logs component info. * * @param msg base log msg * @param request the request to log * @param oldState current state * @param newDesiredState new desired state */ private void logComponentInfo(String msg, ServiceComponentHostRequest request, State oldState, State newDesiredState) { LOG.debug( "{}, clusterName={}, serviceName={}, componentName={}, hostname={}, currentState={}, newDesiredState={}", msg, request.getClusterName(), request.getServiceName(), request.getComponentName(), request.getHostname(), oldState == null ? "null" : oldState, newDesiredState == null ? "null" : newDesiredState); } /** * Get the "operation level" from the request. * * @param requestProperties request properties * @return the "operation level" */ private Resource.Type determineOperationLevel(Map<String, String> requestProperties) { // Determine operation level Resource.Type reqOpLvl; if (requestProperties.containsKey(RequestOperationLevel.OPERATION_LEVEL_ID)) { reqOpLvl = new RequestOperationLevel(requestProperties).getLevel(); } else { String message = "Can not determine request operation level. " + "Operation level property should " + "be specified for this request."; LOG.warn(message); reqOpLvl = Resource.Type.Cluster; } return reqOpLvl; } /** * Validate a host component request. * * @param request request to validate * @throws IllegalArgumentException if the request is invalid */ private void validateServiceComponentHostRequest(ServiceComponentHostRequest request) { if (request.getClusterName() == null || request.getClusterName().isEmpty() || request.getComponentName() == null || request.getComponentName().isEmpty() || request.getHostname() == null || request.getHostname().isEmpty()) { throw new IllegalArgumentException( "Invalid arguments" + ", cluster name, component name and host name should be" + " provided"); } if (request.getAdminState() != null) { throw new IllegalArgumentException("Property adminState cannot be modified through update. Use service " + "specific DECOMMISSION action to decommision/recommission components."); } } // ----- inner classes --------------------------------------------------- /** * Predicate that identifies client components. */ private class ClientComponentPredicate implements Predicate { @Override public boolean evaluate(Resource resource) { boolean isClient = false; String componentName = (String) resource.getPropertyValue(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID); try { if (componentName != null && !componentName.isEmpty()) { AmbariManagementController managementController = getManagementController(); String clusterName = (String) resource .getPropertyValue(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID); String serviceName = (String) resource .getPropertyValue(HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID); if (StringUtils.isEmpty(serviceName)) { Cluster cluster = managementController.getClusters().getCluster(clusterName); serviceName = managementController.findServiceName(cluster, componentName); } ServiceComponent sc = getServiceComponent( (String) resource.getPropertyValue(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID), serviceName, componentName); isClient = sc.isClientComponent(); } } catch (AmbariException e) { // this is really a system exception since cluster/service should have been already verified throw new RuntimeException( "An unexpected exception occurred while trying to determine if a component is a client", e); } return isClient; } } }