/** * 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.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; import javax.inject.Provider; import org.apache.ambari.server.StaticallyInject; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.spi.ExtendedResourceProvider; 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.QueryResponse; 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.PredicateHelper; import org.apache.ambari.server.orm.dao.HostRoleCommandDAO; import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO; import org.apache.ambari.server.orm.dao.RequestDAO; import org.apache.ambari.server.orm.dao.StageDAO; import org.apache.ambari.server.orm.entities.StageEntity; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.topology.LogicalRequest; import org.apache.ambari.server.topology.TopologyManager; import org.apache.ambari.server.utils.SecretReference; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import com.google.common.collect.Sets; /** * ResourceProvider for Stage */ @StaticallyInject public class StageResourceProvider extends AbstractControllerResourceProvider implements ExtendedResourceProvider { /** * Used for querying stage resources. */ @Inject private static StageDAO dao = null; /** * Used for querying task resources. */ @Inject private static HostRoleCommandDAO hostRoleCommandDAO = null; @Inject private static Provider<Clusters> clustersProvider = null; @Inject private static TopologyManager topologyManager; /** * Stage property constants. */ public static final String STAGE_STAGE_ID = "Stage/stage_id"; public static final String STAGE_CLUSTER_NAME = "Stage/cluster_name"; public static final String STAGE_REQUEST_ID = "Stage/request_id"; public static final String STAGE_LOG_INFO = "Stage/log_info"; public static final String STAGE_CONTEXT = "Stage/context"; public static final String STAGE_COMMAND_PARAMS = "Stage/command_params"; public static final String STAGE_HOST_PARAMS = "Stage/host_params"; public static final String STAGE_SKIPPABLE = "Stage/skippable"; public static final String STAGE_PROGRESS_PERCENT = "Stage/progress_percent"; public static final String STAGE_STATUS = "Stage/status"; public static final String STAGE_DISPLAY_STATUS = "Stage/display_status"; public static final String STAGE_START_TIME = "Stage/start_time"; public static final String STAGE_END_TIME = "Stage/end_time"; /** * The property ids for a stage resource. */ static final Set<String> PROPERTY_IDS = new HashSet<>(); /** * The key property ids for a stage resource. */ private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<>(); static { // properties PROPERTY_IDS.add(STAGE_STAGE_ID); PROPERTY_IDS.add(STAGE_CLUSTER_NAME); PROPERTY_IDS.add(STAGE_REQUEST_ID); PROPERTY_IDS.add(STAGE_LOG_INFO); PROPERTY_IDS.add(STAGE_CONTEXT); PROPERTY_IDS.add(STAGE_COMMAND_PARAMS); PROPERTY_IDS.add(STAGE_HOST_PARAMS); PROPERTY_IDS.add(STAGE_SKIPPABLE); PROPERTY_IDS.add(STAGE_PROGRESS_PERCENT); PROPERTY_IDS.add(STAGE_STATUS); PROPERTY_IDS.add(STAGE_DISPLAY_STATUS); PROPERTY_IDS.add(STAGE_START_TIME); PROPERTY_IDS.add(STAGE_END_TIME); // keys KEY_PROPERTY_IDS.put(Resource.Type.Stage, STAGE_STAGE_ID); KEY_PROPERTY_IDS.put(Resource.Type.Cluster, STAGE_CLUSTER_NAME); KEY_PROPERTY_IDS.put(Resource.Type.Request, STAGE_REQUEST_ID); } /** * These fields may contain password in them, so have to mask with. */ static final Set<String> PROPERTIES_TO_MASK_PASSWORD_IN = Sets.newHashSet(STAGE_COMMAND_PARAMS, STAGE_HOST_PARAMS); // ----- Constructors ------------------------------------------------------ /** * Constructor. * * @param managementController the Ambari management controller */ StageResourceProvider(AmbariManagementController managementController) { super(PROPERTY_IDS, KEY_PROPERTY_IDS, managementController); } // ----- AbstractResourceProvider ------------------------------------------ @Override protected Set<String> getPKPropertyIds() { return new HashSet<>(KEY_PROPERTY_IDS.values()); } // ----- ResourceProvider -------------------------------------------------- @Override public RequestStatus createResources(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException { throw new UnsupportedOperationException(); } @Override public RequestStatus updateResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Iterator<Map<String,Object>> iterator = request.getProperties().iterator(); if (iterator.hasNext()) { Map<String,Object> updateProperties = iterator.next(); List<StageEntity> entities = dao.findAll(request, predicate); for (StageEntity entity : entities) { String stageStatus = (String) updateProperties.get(STAGE_STATUS); if (stageStatus != null) { HostRoleStatus desiredStatus = HostRoleStatus.valueOf(stageStatus); dao.updateStageStatus(entity, desiredStatus, getManagementController().getActionManager()); } } } notifyUpdate(Resource.Type.Stage, request, predicate); return getRequestStatus(null); } @Override public RequestStatus deleteResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { throw new UnsupportedOperationException(); } @Override public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Set<Resource> results = new LinkedHashSet<>(); Set<String> propertyIds = getRequestPropertyIds(request, predicate); // !!! poor mans cache. toResource() shouldn't be calling the db // every time, when the request id is likely the same for each stageEntity Map<Long, Map<Long, HostRoleCommandStatusSummaryDTO>> cache = new HashMap<>(); List<StageEntity> entities = dao.findAll(request, predicate); for (StageEntity entity : entities) { results.add(StageResourceProvider.toResource(cache, entity, propertyIds)); } cache.clear(); // !!! check the id passed to see if it's a LogicalRequest. This safeguards against // iterating all stages for all requests. That is a problem when the request // is for an Upgrade, but was pulling the data anyway. Map<String, Object> map = PredicateHelper.getProperties(predicate); if (map.containsKey(STAGE_REQUEST_ID)) { Long requestId = NumberUtils.toLong(map.get(STAGE_REQUEST_ID).toString()); LogicalRequest lr = topologyManager.getRequest(requestId); if (null != lr) { Collection<StageEntity> topologyManagerStages = lr.getStageEntities(); // preload summaries as it contains summaries for all stages within this request Map<Long, HostRoleCommandStatusSummaryDTO> summary = topologyManager.getStageSummaries(requestId); cache.put(requestId, summary); for (StageEntity entity : topologyManagerStages) { Resource stageResource = toResource(cache, entity, propertyIds); if (predicate.evaluate(stageResource)) { results.add(stageResource); } } } } else { Collection<StageEntity> topologyManagerStages = topologyManager.getStages(); for (StageEntity entity : topologyManagerStages) { if (!cache.containsKey(entity.getRequestId())) { Map<Long, HostRoleCommandStatusSummaryDTO> summary = topologyManager.getStageSummaries(entity.getRequestId()); cache.put(entity.getRequestId(), summary); } Resource stageResource = toResource(cache, entity, propertyIds); if (predicate.evaluate(stageResource)) { results.add(stageResource); } } } return results; } // ----- ExtendedResourceProvider ------------------------------------------ @Override public QueryResponse queryForResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Set<Resource> results = getResources(request, predicate); return new QueryResponseImpl(results, request.getSortRequest() != null, false, results.size()); } /** * Converts the {@link StageEntity} to a {@link Resource}. * * @param entity the entity to convert (not {@code null}) * @param requestedIds the properties requested (not {@code null}) * * @return the new resource */ static Resource toResource( Map<Long, Map<Long, HostRoleCommandStatusSummaryDTO>> cache, StageEntity entity, Set<String> requestedIds) { Resource resource = new ResourceImpl(Resource.Type.Stage); Long clusterId = entity.getClusterId(); if (clusterId != null && !clusterId.equals(Long.valueOf(-1L))) { try { Cluster cluster = clustersProvider.get().getClusterById(clusterId); setResourceProperty(resource, STAGE_CLUSTER_NAME, cluster.getClusterName(), requestedIds); } catch (Exception e) { LOG.error("Can not get information for cluster " + clusterId + ".", e ); } } if (!cache.containsKey(entity.getRequestId())) { cache.put(entity.getRequestId(), hostRoleCommandDAO.findAggregateCounts(entity.getRequestId())); } Map<Long, HostRoleCommandStatusSummaryDTO> summary = cache.get(entity.getRequestId()); setResourceProperty(resource, STAGE_STAGE_ID, entity.getStageId(), requestedIds); setResourceProperty(resource, STAGE_REQUEST_ID, entity.getRequestId(), requestedIds); setResourceProperty(resource, STAGE_CONTEXT, entity.getRequestContext(), requestedIds); if (isPropertyRequested(STAGE_COMMAND_PARAMS, requestedIds)) { String value = entity.getCommandParamsStage(); if (!StringUtils.isBlank(value)) { value = SecretReference.maskPasswordInPropertyMap(value); } resource.setProperty(STAGE_COMMAND_PARAMS, value); } // this property is lazy loaded in JPA; don't use it unless requested if (isPropertyRequested(STAGE_HOST_PARAMS, requestedIds)) { String value = entity.getHostParamsStage(); if (!StringUtils.isBlank(value)) { value = SecretReference.maskPasswordInPropertyMap(value); } resource.setProperty(STAGE_HOST_PARAMS, value); } setResourceProperty(resource, STAGE_SKIPPABLE, entity.isSkippable(), requestedIds); Long startTime = Long.MAX_VALUE; Long endTime = 0L; if (summary.containsKey(entity.getStageId())) { startTime = summary.get(entity.getStageId()).getStartTime(); endTime = summary.get(entity.getStageId()).getEndTime(); } setResourceProperty(resource, STAGE_START_TIME, startTime, requestedIds); setResourceProperty(resource, STAGE_END_TIME, endTime, requestedIds); CalculatedStatus status; if (summary.isEmpty()) { // Delete host might have cleared all HostRoleCommands status = CalculatedStatus.COMPLETED; } else { status = CalculatedStatus.statusFromStageSummary(summary, Collections.singleton(entity.getStageId())); } setResourceProperty(resource, STAGE_PROGRESS_PERCENT, status.getPercent(), requestedIds); setResourceProperty(resource, STAGE_STATUS, status.getStatus(), requestedIds); setResourceProperty(resource, STAGE_DISPLAY_STATUS, status.getDisplayStatus(), requestedIds); return resource; } }