/*
* 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 static org.apache.ambari.server.controller.internal.HostComponentResourceProvider.HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID;
import static org.apache.ambari.server.controller.internal.HostComponentResourceProvider.HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID;
import static org.apache.ambari.server.controller.internal.HostComponentResourceProvider.HOST_COMPONENT_HOST_NAME_PROPERTY_ID;
import static org.apache.ambari.server.controller.internal.HostComponentResourceProvider.HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID;
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.StaticallyInject;
import org.apache.ambari.server.actionmanager.ActionManager;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.api.predicate.InvalidQueryException;
import org.apache.ambari.server.api.predicate.PredicateCompiler;
import org.apache.ambari.server.api.services.BaseRequest;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.ExecuteActionRequest;
import org.apache.ambari.server.controller.RequestRequest;
import org.apache.ambari.server.controller.RequestStatusResponse;
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.ResourceProvider;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.controller.utilities.PredicateBuilder;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.customactions.ActionDefinition;
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.entities.RequestEntity;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.security.authorization.AuthorizationHelper;
import org.apache.ambari.server.security.authorization.ResourceType;
import org.apache.ambari.server.security.authorization.RoleAuthorization;
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 com.google.common.collect.Sets;
import com.google.inject.Inject;
/**
* Resource provider for request resources.
*/
@StaticallyInject
public class RequestResourceProvider extends AbstractControllerResourceProvider {
@Inject
private static RequestDAO s_requestDAO = null;
@Inject
private static HostRoleCommandDAO s_hostRoleCommandDAO = null;
@Inject
private static TopologyManager topologyManager;
// ----- Property ID constants ---------------------------------------------
// Requests
public static final String REQUEST_CLUSTER_NAME_PROPERTY_ID = "Requests/cluster_name";
public static final String REQUEST_CLUSTER_ID_PROPERTY_ID = "Requests/cluster_id";
public static final String REQUEST_ID_PROPERTY_ID = "Requests/id";
protected static final String REQUEST_STATUS_PROPERTY_ID = "Requests/request_status";
protected static final String REQUEST_ABORT_REASON_PROPERTY_ID = "Requests/abort_reason";
protected static final String REQUEST_CONTEXT_ID = "Requests/request_context";
public static final String REQUEST_SOURCE_SCHEDULE = "Requests/request_schedule";
public static final String REQUEST_SOURCE_SCHEDULE_ID = "Requests/request_schedule/schedule_id";
public static final String REQUEST_SOURCE_SCHEDULE_HREF = "Requests/request_schedule/href";
protected static final String REQUEST_TYPE_ID = "Requests/type";
protected static final String REQUEST_INPUTS_ID = "Requests/inputs";
protected static final String REQUEST_CLUSTER_HOST_INFO_ID = "Requests/cluster_host_info";
protected static final String REQUEST_RESOURCE_FILTER_ID = "Requests/resource_filters";
protected static final String REQUEST_OPERATION_LEVEL_ID = "Requests/operation_level";
protected static final String REQUEST_CREATE_TIME_ID = "Requests/create_time";
protected static final String REQUEST_START_TIME_ID = "Requests/start_time";
protected static final String REQUEST_END_TIME_ID = "Requests/end_time";
protected static final String REQUEST_EXCLUSIVE_ID = "Requests/exclusive";
protected static final String REQUEST_TASK_CNT_ID = "Requests/task_count";
protected static final String REQUEST_FAILED_TASK_CNT_ID = "Requests/failed_task_count";
protected static final String REQUEST_ABORTED_TASK_CNT_ID = "Requests/aborted_task_count";
protected static final String REQUEST_TIMED_OUT_TASK_CNT_ID = "Requests/timed_out_task_count";
protected static final String REQUEST_COMPLETED_TASK_CNT_ID = "Requests/completed_task_count";
protected static final String REQUEST_QUEUED_TASK_CNT_ID = "Requests/queued_task_count";
protected static final String REQUEST_PROGRESS_PERCENT_ID = "Requests/progress_percent";
protected static final String REQUEST_REMOVE_PENDING_HOST_REQUESTS_ID = "Requests/remove_pending_host_requests";
protected static final String REQUEST_PENDING_HOST_REQUEST_COUNT_ID = "Requests/pending_host_request_count";
protected static final String COMMAND_ID = "command";
protected static final String SERVICE_ID = "service_name";
protected static final String COMPONENT_ID = "component_name";
protected static final String HOSTS_ID = "hosts"; // This is actually a list of hosts
protected static final String HOSTS_PREDICATE = "hosts_predicate";
protected static final String ACTION_ID = "action";
protected static final String INPUTS_ID = "parameters";
protected static final String EXLUSIVE_ID = "exclusive";
private static Set<String> pkPropertyIds =
new HashSet<>(Arrays.asList(new String[]{
REQUEST_ID_PROPERTY_ID}));
private PredicateCompiler predicateCompiler = new PredicateCompiler();
static Set<String> PROPERTY_IDS = Sets.newHashSet(
REQUEST_CLUSTER_NAME_PROPERTY_ID,
REQUEST_CLUSTER_ID_PROPERTY_ID,
REQUEST_STATUS_PROPERTY_ID,
REQUEST_ABORT_REASON_PROPERTY_ID,
REQUEST_CONTEXT_ID,
REQUEST_SOURCE_SCHEDULE,
REQUEST_SOURCE_SCHEDULE_ID,
REQUEST_SOURCE_SCHEDULE_HREF,
REQUEST_TYPE_ID,
REQUEST_INPUTS_ID,
REQUEST_RESOURCE_FILTER_ID,
REQUEST_OPERATION_LEVEL_ID,
REQUEST_CREATE_TIME_ID,
REQUEST_START_TIME_ID,
REQUEST_END_TIME_ID,
REQUEST_EXCLUSIVE_ID,
REQUEST_TASK_CNT_ID,
REQUEST_FAILED_TASK_CNT_ID,
REQUEST_ABORTED_TASK_CNT_ID,
REQUEST_TIMED_OUT_TASK_CNT_ID,
REQUEST_COMPLETED_TASK_CNT_ID,
REQUEST_QUEUED_TASK_CNT_ID,
REQUEST_PROGRESS_PERCENT_ID,
REQUEST_REMOVE_PENDING_HOST_REQUESTS_ID,
REQUEST_PENDING_HOST_REQUEST_COUNT_ID,
REQUEST_CLUSTER_HOST_INFO_ID
);
// ----- 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
*/
RequestResourceProvider(Set<String> propertyIds,
Map<Resource.Type, String> keyPropertyIds,
AmbariManagementController managementController) {
super(propertyIds, keyPropertyIds, managementController);
}
// ----- ResourceProvider ------------------------------------------------
@Override
public RequestStatus createResources(Request request)
throws SystemException, UnsupportedPropertyException, NoSuchParentResourceException, ResourceAlreadyExistsException {
if (request.getProperties().size() > 1) {
throw new UnsupportedOperationException("Multiple actions/commands cannot be executed at the same time.");
}
final ExecuteActionRequest actionRequest = getActionRequest(request);
final Map<String, String> requestInfoProperties = request.getRequestInfoProperties();
return getRequestStatus(createResources(new Command<RequestStatusResponse>() {
@Override
public RequestStatusResponse invoke() throws AmbariException, AuthorizationException {
String clusterName = actionRequest.getClusterName();
ResourceType resourceType;
Long resourceId;
if (StringUtils.isEmpty(clusterName)) {
resourceType = ResourceType.AMBARI;
resourceId = null;
} else {
resourceType = ResourceType.CLUSTER;
resourceId = getClusterResourceId(clusterName);
}
if (actionRequest.isCommand()) {
String commandName = actionRequest.getCommandName();
if (StringUtils.isEmpty(commandName)) {
commandName = "_unknown_command_";
}
if (commandName.endsWith("_SERVICE_CHECK")) {
if (!AuthorizationHelper.isAuthorized(resourceType, resourceId, RoleAuthorization.SERVICE_RUN_SERVICE_CHECK)) {
throw new AuthorizationException("The authenticated user is not authorized to execute service checks.");
}
} else if (commandName.equals("DECOMMISSION")) {
if (!AuthorizationHelper.isAuthorized(resourceType, resourceId, RoleAuthorization.SERVICE_DECOMMISSION_RECOMMISSION)) {
throw new AuthorizationException("The authenticated user is not authorized to decommission services.");
}
} else {
if (!AuthorizationHelper.isAuthorized(resourceType, resourceId, RoleAuthorization.SERVICE_RUN_CUSTOM_COMMAND)) {
throw new AuthorizationException(String.format("The authenticated user is not authorized to execute the command, %s.",
commandName));
}
}
} else {
String actionName = actionRequest.getActionName();
if (StringUtils.isEmpty(actionName)) {
actionName = "_unknown_action_";
}
if (actionName.contains("SERVICE_CHECK")) {
if (!AuthorizationHelper.isAuthorized(resourceType, resourceId, RoleAuthorization.SERVICE_RUN_SERVICE_CHECK)) {
throw new AuthorizationException("The authenticated user is not authorized to execute service checks.");
}
} else {
// A custom action has been requested
ActionDefinition actionDefinition = (actionName == null)
? null
: getManagementController().getAmbariMetaInfo().getActionDefinition(actionName);
Set<RoleAuthorization> permissions = (actionDefinition == null)
? null
: actionDefinition.getPermissions();
if (!AuthorizationHelper.isAuthorized(resourceType, resourceId, permissions)) {
throw new AuthorizationException(String.format("The authenticated user is not authorized to execute the action %s.", actionName));
}
}
}
return getManagementController().createAction(actionRequest, requestInfoProperties);
}
}));
}
@Override
public Set<Resource> getResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
Set<String> requestedIds = getRequestPropertyIds(request, predicate);
Set<Resource> resources = new HashSet<>();
String maxResultsRaw = request.getRequestInfoProperties().get(BaseRequest.PAGE_SIZE_PROPERTY_KEY);
String ascOrderRaw = request.getRequestInfoProperties().get(BaseRequest.ASC_ORDER_PROPERTY_KEY);
Integer maxResults = (maxResultsRaw == null ? null : Integer.parseInt(maxResultsRaw));
Boolean ascOrder = (ascOrderRaw == null ? null : Boolean.parseBoolean(ascOrderRaw));
if (null == predicate) {
// the no-arg call to /requests is here
resources.addAll(
getRequestResources(null, null, null, maxResults, ascOrder, requestedIds));
} else {
// process /requests with a predicate
// process /clusters/[cluster]/requests
// process /clusters/[cluster]/requests with a predicate
for (Map<String, Object> properties : getPropertyMaps(predicate)) {
String clusterName = (String) properties.get(REQUEST_CLUSTER_NAME_PROPERTY_ID);
Long requestId = null;
if (properties.get(REQUEST_ID_PROPERTY_ID) != null) {
requestId = Long.valueOf((String) properties.get(REQUEST_ID_PROPERTY_ID));
}
String requestStatus = null;
if (properties.get(REQUEST_STATUS_PROPERTY_ID) != null) {
requestStatus = (String) properties.get(REQUEST_STATUS_PROPERTY_ID);
}
resources.addAll(getRequestResources(clusterName, requestId, requestStatus, maxResults,
ascOrder, requestedIds));
}
}
return resources;
}
@Override
public RequestStatus updateResources(Request requestInfo, Predicate predicate)
throws SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
AmbariManagementController amc = getManagementController();
final Set<RequestRequest> requests = new HashSet<>();
Iterator<Map<String,Object>> iterator = requestInfo.getProperties().iterator();
if (iterator.hasNext()) {
for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) {
requests.add(getRequest(propertyMap));
}
}
// Validate
List<org.apache.ambari.server.actionmanager.Request> targets =
new ArrayList<>();
for (RequestRequest updateRequest : requests) {
ActionManager actionManager = amc.getActionManager();
List<org.apache.ambari.server.actionmanager.Request> internalRequests =
actionManager.getRequests(Collections.singletonList(updateRequest.getRequestId()));
if (internalRequests.size() == 0) {
throw new IllegalArgumentException(
String.format("Request %s does not exist", updateRequest.getRequestId()));
}
// There should be only one request with this id (or no request at all)
org.apache.ambari.server.actionmanager.Request internalRequest = internalRequests.get(0);
if (updateRequest.isRemovePendingHostRequests()) {
if (internalRequest instanceof LogicalRequest) {
targets.add(internalRequest);
} else {
throw new IllegalArgumentException("Request with id: " + internalRequest.getRequestId() + "is not a Logical Request.");
}
} else {
// Validate update request (check constraints on state value and presence of abort reason)
if (updateRequest.getAbortReason() == null || updateRequest.getAbortReason().isEmpty()) {
throw new IllegalArgumentException("Abort reason can not be empty.");
}
if (updateRequest.getStatus() != HostRoleStatus.ABORTED) {
throw new IllegalArgumentException(
String.format("%s is wrong value. The only allowed value " +
"for updating request status is ABORTED",
updateRequest.getStatus()));
}
HostRoleStatus internalRequestStatus =
CalculatedStatus.statusFromStages(internalRequest.getStages()).getStatus();
if (internalRequestStatus.isCompletedState()) {
// Ignore updates to completed requests to avoid throwing exception on race condition
} else {
// Validation passed
targets.add(internalRequest);
}
}
}
// Perform update
Iterator<RequestRequest> reqIterator = requests.iterator();
for (org.apache.ambari.server.actionmanager.Request target : targets) {
if (target instanceof LogicalRequest) {
topologyManager.removePendingHostRequests(target.getClusterName(), target.getRequestId());
} else {
String reason = reqIterator.next().getAbortReason();
amc.getActionManager().cancelRequest(target.getRequestId(), reason);
}
}
return getRequestStatus(null);
}
private RequestRequest getRequest(Map<String, Object> propertyMap) {
// Cluster name may be empty for custom actions
String clusterNameStr = (String) propertyMap.get(REQUEST_CLUSTER_NAME_PROPERTY_ID);
String requestIdStr = (String) propertyMap.get(REQUEST_ID_PROPERTY_ID);
long requestId = Integer.valueOf(requestIdStr);
String requestStatusStr = (String) propertyMap.get(REQUEST_STATUS_PROPERTY_ID);
HostRoleStatus requestStatus = null;
if (requestStatusStr != null) {
// This conversion may throw IllegalArgumentException, it is OK
// in this case it will be mapped to HTTP 400 Bad Request
requestStatus = HostRoleStatus.valueOf(requestStatusStr);
}
String abortReason = (String) propertyMap.get(REQUEST_ABORT_REASON_PROPERTY_ID);
String removePendingHostRequests = (String) propertyMap.get(REQUEST_REMOVE_PENDING_HOST_REQUESTS_ID);
RequestRequest requestRequest = new RequestRequest(clusterNameStr, requestId);
requestRequest.setStatus(requestStatus);
requestRequest.setAbortReason(abortReason);
if (removePendingHostRequests != null) {
requestRequest.setRemovePendingHostRequests(Boolean.valueOf(removePendingHostRequests));
}
return requestRequest;
}
@Override
public RequestStatus deleteResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
throw new UnsupportedOperationException("Not currently supported.");
}
// ----- AbstractResourceProvider -----------------------------------------
@Override
protected Set<String> getPKPropertyIds() {
return pkPropertyIds;
}
// ----- utility methods --------------------------------------------------
// Get request to execute an action/command
@SuppressWarnings("unchecked")
private ExecuteActionRequest getActionRequest(Request request)
throws UnsupportedOperationException, SystemException {
Map<String, String> requestInfoProperties = request.getRequestInfoProperties();
Map<String, Object> propertyMap = request.getProperties().iterator().next();
Boolean isCommand = requestInfoProperties.containsKey(COMMAND_ID);
String commandName = null;
String actionName = null;
if (isCommand) {
if (requestInfoProperties.containsKey(ACTION_ID)) {
throw new UnsupportedOperationException("Both command and action cannot be specified.");
}
commandName = requestInfoProperties.get(COMMAND_ID);
} else {
if (!requestInfoProperties.containsKey(ACTION_ID)) {
throw new UnsupportedOperationException("Either command or action must be specified.");
}
actionName = requestInfoProperties.get(ACTION_ID);
}
List<RequestResourceFilter> resourceFilterList = null;
Set<Map<String, Object>> resourceFilters;
Object resourceFilterObj = propertyMap.get(REQUEST_RESOURCE_FILTER_ID);
if (resourceFilterObj != null && resourceFilterObj instanceof HashSet) {
resourceFilters = (HashSet<Map<String, Object>>) resourceFilterObj;
resourceFilterList = new ArrayList<>();
for (Map<String, Object> resourceMap : resourceFilters) {
resourceFilterList.addAll(parseRequestResourceFilter(resourceMap,
(String) propertyMap.get(REQUEST_CLUSTER_NAME_PROPERTY_ID)));
}
LOG.debug("RequestResourceFilters : " + resourceFilters);
}
// Extract operation level property
RequestOperationLevel operationLevel = null;
if (requestInfoProperties.containsKey(RequestOperationLevel.OPERATION_LEVEL_ID)) {
operationLevel = new RequestOperationLevel(requestInfoProperties);
}
Map<String, String> params = new HashMap<>();
String keyPrefix = INPUTS_ID + "/";
for (String key : requestInfoProperties.keySet()) {
if (key.startsWith(keyPrefix)) {
params.put(key.substring(keyPrefix.length()), requestInfoProperties.get(key));
}
}
boolean exclusive = false;
if (requestInfoProperties.containsKey(EXLUSIVE_ID)) {
exclusive = Boolean.valueOf(requestInfoProperties.get(EXLUSIVE_ID).trim());
}
return new ExecuteActionRequest(
(String) propertyMap.get(REQUEST_CLUSTER_NAME_PROPERTY_ID),
commandName,
actionName,
resourceFilterList,
operationLevel,
params, exclusive);
}
/**
* Allow host component resource predicate to decide hosts to operate on.
* @param resourceMap Properties
* @param clusterName clusterName
* @return Populated resource filter
* @throws SystemException
*/
private List<RequestResourceFilter> parseRequestResourceFilter(Map<String, Object> resourceMap,
String clusterName) throws SystemException {
List<RequestResourceFilter> resourceFilterList = new ArrayList<>();
String serviceName = (String) resourceMap.get(SERVICE_ID);
String componentName = (String) resourceMap.get(COMPONENT_ID);
String hostsPredicate = (String) resourceMap.get(HOSTS_PREDICATE);
Object hostListStr = resourceMap.get(HOSTS_ID);
List<String> hostList = Collections.emptyList();
if (hostListStr != null) {
hostList = new ArrayList<>();
for (String hostName : ((String) hostListStr).split(",")) {
hostList.add(hostName.trim());
}
resourceFilterList.add(new RequestResourceFilter(serviceName, componentName, hostList));
} else if (hostsPredicate != null) {
// Parse the predicate as key=value and apply to the ResourceProvider predicate
Predicate filterPredicate;
try {
filterPredicate = predicateCompiler.compile(hostsPredicate);
} catch (InvalidQueryException e) {
String msg = "Invalid predicate expression provided: " + hostsPredicate;
LOG.warn(msg, e);
throw new SystemException(msg, e);
}
ResourceProvider resourceProvider = getResourceProvider(Resource.Type.HostComponent);
Set<String> propertyIds = new HashSet<>();
propertyIds.add(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID);
propertyIds.add(HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID);
propertyIds.add(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID);
Request request = PropertyHelper.getReadRequest(propertyIds);
Predicate finalPredicate = new PredicateBuilder(filterPredicate)
.property(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID).equals(clusterName).and()
.property(HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID).equals(serviceName).and()
.property(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID).equals(componentName)
.toPredicate();
try {
Set<Resource> resources = resourceProvider.getResources(request, finalPredicate);
if (resources != null && !resources.isEmpty()) {
// Allow request to span services / components using just the predicate
Map<ServiceComponentTuple, List<String>> dupleListMap = new HashMap<>();
for (Resource resource : resources) {
String hostnameStr = (String) resource.getPropertyValue(HOST_COMPONENT_HOST_NAME_PROPERTY_ID);
if (hostnameStr != null) {
String computedServiceName = (String) resource.getPropertyValue(HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID);
String computedComponentName = (String) resource.getPropertyValue(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID);
ServiceComponentTuple duple =
new ServiceComponentTuple(computedServiceName, computedComponentName);
if (!dupleListMap.containsKey(duple)) {
hostList = new ArrayList<>();
hostList.add(hostnameStr);
dupleListMap.put(duple, hostList);
} else {
dupleListMap.get(duple).add(hostnameStr);
}
}
}
if (!dupleListMap.isEmpty()) {
for (Map.Entry<ServiceComponentTuple, List<String>> entry : dupleListMap.entrySet()) {
resourceFilterList.add(new RequestResourceFilter(
entry.getKey().getServiceName(),
entry.getKey().getComponentName(),
entry.getValue()
));
}
}
}
} catch (Exception e) {
LOG.warn("Exception finding requested resources with serviceName = " + serviceName +
", componentName = " + componentName +
", hostPredicate" + " = " + hostsPredicate, e);
}
} else {
resourceFilterList.add(new RequestResourceFilter(serviceName, componentName, hostList));
}
return resourceFilterList;
}
/**
* Represent a map key as a ServiceComponent
*/
class ServiceComponentTuple {
final String serviceName;
final String componentName;
ServiceComponentTuple(String serviceName, String componentName) {
this.serviceName = serviceName;
this.componentName = componentName;
}
public String getServiceName() {
return serviceName;
}
public String getComponentName() {
return componentName;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ServiceComponentTuple that = (ServiceComponentTuple) o;
if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) {
return false;
}
return !(componentName != null ? !componentName.equals(that.componentName) : that.componentName != null);
}
@Override
public int hashCode() {
int result = serviceName != null ? serviceName.hashCode() : 0;
result = 31 * result + (componentName != null ? componentName.hashCode() : 0);
return result;
}
}
/**
* Gets all of the request resources for the given properties.
*/
private Set<Resource> getRequestResources(String clusterName,
Long requestId,
String requestStatus,
Integer maxResults,
Boolean ascOrder,
Set<String> requestedPropertyIds)
throws NoSuchResourceException, NoSuchParentResourceException {
Set<Resource> response = new HashSet<>();
ActionManager actionManager = getManagementController().getActionManager();
Long clusterId = null;
if (clusterName != null) {
Clusters clusters = getManagementController().getClusters();
//validate that cluster exists, throws exception if it doesn't.
try {
Cluster cluster = clusters.getCluster(clusterName);
clusterId = cluster.getClusterId();
} catch (AmbariException e) {
throw new NoSuchParentResourceException(e.getMessage(), e);
}
}
List<Long> requestIds = Collections.emptyList();
if (requestId == null) {
org.apache.ambari.server.actionmanager.RequestStatus status = null;
if (requestStatus != null) {
status = org.apache.ambari.server.actionmanager.RequestStatus.valueOf(requestStatus);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Received a Get Request Status request"
+ ", requestId=null"
+ ", requestStatus=" + status);
}
maxResults = (maxResults != null) ? maxResults : BaseRequest.DEFAULT_PAGE_SIZE;
ascOrder = (ascOrder != null) ? ascOrder : false;
if (null == status) {
if (null != clusterId) {
// !!! don't mix results of cluster vs non-cluster
requestIds = s_requestDAO.findAllRequestIds(maxResults, ascOrder, clusterId);
} else {
// !!! not a cluster, so get all requests NOT affiliated with a cluster
requestIds = s_requestDAO.findAllRequestIds(maxResults, ascOrder, null);
}
} else {
// !!! this call will result in mixed results of cluster and non-cluster. this
// will get fixed in a future iteration, as the host_role_command table does not
// currently have direct cluster affinity, and changing that is a tad destructive.
requestIds = actionManager.getRequestsByStatus(status,
maxResults != null ? maxResults : BaseRequest.DEFAULT_PAGE_SIZE,
ascOrder != null ? ascOrder : false);
}
LOG.debug("List<Long> requestIds = actionManager.getRequestsByStatus = {}", requestIds.size());
response.addAll(getRequestResources(clusterId, clusterName, requestIds,
requestedPropertyIds));
} else {
Collection<Resource> responses = getRequestResources(
clusterId, clusterName, Collections.singletonList(requestId), requestedPropertyIds);
if (responses.isEmpty()) {
throw new NoSuchResourceException("Request resource doesn't exist.");
}
response.addAll(responses);
}
return response;
}
// Get all of the request resources for the given set of request ids
private Collection<Resource> getRequestResources(Long clusterId, String clusterName,
List<Long> requestIds, Set<String> requestedPropertyIds) {
Map<Long, Resource> resourceMap = new HashMap<>();
List<RequestEntity> requests = s_requestDAO.findByPks(requestIds, true);
//todo: this was (and still is) in ActionManager but this class was changed to not use ActionManager recently
List<RequestEntity> topologyRequestEntities = new ArrayList<>();
Collection<? extends org.apache.ambari.server.actionmanager.Request> topologyRequests =
topologyManager.getRequests(requestIds);
for (org.apache.ambari.server.actionmanager.Request request : topologyRequests) {
topologyRequestEntities.add(request.constructNewPersistenceEntity());
}
// if requests is empty, map is Collections.emptyMap() which can't be added to so create a new map
if (requests.isEmpty()) {
requests = new ArrayList<>();
}
requests.addAll(topologyRequestEntities);
for (RequestEntity re : requests) {
if ((null == clusterId && (null == re.getClusterId() || -1L == re.getClusterId())) || // if cluster IS NOT requested AND the db request is not for a cluster
(null != clusterId && null != re.getRequestId() && re.getClusterId().equals(clusterId))) { // if cluster IS requested and the request has a cluster id equal to the one requested
Resource r = getRequestResource(re, clusterName, requestedPropertyIds);
resourceMap.put(re.getRequestId(), r);
}
}
return resourceMap.values();
}
private Resource getRequestResource(RequestEntity entity, String clusterName,
Set<String> requestedPropertyIds) {
Resource resource = new ResourceImpl(Resource.Type.Request);
if (null != clusterName) {
setResourceProperty(resource, REQUEST_CLUSTER_NAME_PROPERTY_ID, clusterName, requestedPropertyIds);
} else if (null != entity.getClusterId() && -1L != entity.getClusterId()) {
setResourceProperty(resource, REQUEST_CLUSTER_ID_PROPERTY_ID, entity.getClusterId(), requestedPropertyIds);
}
setResourceProperty(resource, REQUEST_ID_PROPERTY_ID, entity.getRequestId(), requestedPropertyIds);
setResourceProperty(resource, REQUEST_CONTEXT_ID, entity.getRequestContext(), requestedPropertyIds);
setResourceProperty(resource, REQUEST_TYPE_ID, entity.getRequestType(), requestedPropertyIds);
// Mask any sensitive data fields in the inputs data structure
if (isPropertyRequested(REQUEST_INPUTS_ID, requestedPropertyIds)) {
String value = entity.getInputs();
if (!StringUtils.isBlank(value)) {
value = SecretReference.maskPasswordInPropertyMap(value);
}
resource.setProperty(REQUEST_INPUTS_ID, value);
}
if (isPropertyRequested(REQUEST_CLUSTER_HOST_INFO_ID, requestedPropertyIds)) {
resource.setProperty(REQUEST_CLUSTER_HOST_INFO_ID, entity.getClusterHostInfo());
}
setResourceProperty(resource, REQUEST_RESOURCE_FILTER_ID,
org.apache.ambari.server.actionmanager.Request.filtersFromEntity(entity),
requestedPropertyIds);
RequestOperationLevel operationLevel = org.apache.ambari.server.actionmanager.Request.operationLevelFromEntity(entity);
String opLevelStr = null;
if (operationLevel != null) {
opLevelStr = RequestOperationLevel.getExternalLevelName(
operationLevel.getLevel().toString());
}
setResourceProperty(resource, REQUEST_OPERATION_LEVEL_ID, opLevelStr, requestedPropertyIds);
setResourceProperty(resource, REQUEST_CREATE_TIME_ID, entity.getCreateTime(), requestedPropertyIds);
setResourceProperty(resource, REQUEST_START_TIME_ID, entity.getStartTime(), requestedPropertyIds);
setResourceProperty(resource, REQUEST_END_TIME_ID, entity.getEndTime(), requestedPropertyIds);
setResourceProperty(resource, REQUEST_EXCLUSIVE_ID, entity.isExclusive(), requestedPropertyIds);
if (entity.getRequestScheduleId() != null) {
setResourceProperty(resource, REQUEST_SOURCE_SCHEDULE_ID, entity.getRequestScheduleId(), requestedPropertyIds);
} else {
setResourceProperty(resource, REQUEST_SOURCE_SCHEDULE, null, requestedPropertyIds);
}
Map<Long, HostRoleCommandStatusSummaryDTO> summary = s_hostRoleCommandDAO.findAggregateCounts(entity.getRequestId());
// get summaries from TopologyManager for logical requests
summary.putAll(topologyManager.getStageSummaries(entity.getRequestId()));
// summary might be empty due to delete host have cleared all
// HostRoleCommands or due to hosts haven't registered yet with the cluster
// when the cluster is provisioned with a Blueprint
final CalculatedStatus status;
LogicalRequest logicalRequest = topologyManager.getRequest(entity.getRequestId());
if (summary.isEmpty() && null != logicalRequest) {
// in this case, it appears that there are no tasks but this is a logical
// topology request, so it's a matter of hosts simply not registering yet
// for tasks to be created
if (logicalRequest.hasPendingHostRequests()) {
status = CalculatedStatus.PENDING;
} else {
status = CalculatedStatus.COMPLETED;
}
} else {
// there are either tasks or this is not a logical request, so do normal
// status calculations
status = CalculatedStatus.statusFromStageSummary(summary, summary.keySet());
}
if (null != logicalRequest) {
setResourceProperty(resource, REQUEST_PENDING_HOST_REQUEST_COUNT_ID, logicalRequest.getPendingHostRequestCount(), requestedPropertyIds);
}
setResourceProperty(resource, REQUEST_STATUS_PROPERTY_ID, status.getStatus().toString(), requestedPropertyIds);
setResourceProperty(resource, REQUEST_PROGRESS_PERCENT_ID, status.getPercent(), requestedPropertyIds);
int taskCount = 0;
for (HostRoleCommandStatusSummaryDTO dto : summary.values()) {
taskCount += dto.getTaskTotal();
}
Map<HostRoleStatus, Integer> hostRoleStatusCounters = CalculatedStatus.calculateTaskStatusCounts(
summary, summary.keySet());
setResourceProperty(resource, REQUEST_TASK_CNT_ID, taskCount, requestedPropertyIds);
setResourceProperty(resource, REQUEST_FAILED_TASK_CNT_ID,
hostRoleStatusCounters.get(HostRoleStatus.FAILED), requestedPropertyIds);
setResourceProperty(resource, REQUEST_ABORTED_TASK_CNT_ID,
hostRoleStatusCounters.get(HostRoleStatus.ABORTED), requestedPropertyIds);
setResourceProperty(resource, REQUEST_TIMED_OUT_TASK_CNT_ID,
hostRoleStatusCounters.get(HostRoleStatus.TIMEDOUT), requestedPropertyIds);
setResourceProperty(resource, REQUEST_QUEUED_TASK_CNT_ID,
hostRoleStatusCounters.get(HostRoleStatus.QUEUED), requestedPropertyIds);
setResourceProperty(resource, REQUEST_COMPLETED_TASK_CNT_ID,
hostRoleStatusCounters.get(HostRoleStatus.COMPLETED), requestedPropertyIds);
return resource;
}
}