/**
* 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.EnumSet;
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 org.apache.ambari.server.AmbariException;
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.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.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO;
import org.apache.ambari.server.orm.dao.StageDAO;
import org.apache.ambari.server.orm.dao.UpgradeDAO;
import org.apache.ambari.server.orm.entities.StageEntity;
import org.apache.ambari.server.orm.entities.StageEntityPK;
import org.apache.ambari.server.orm.entities.UpgradeEntity;
import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
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.utils.SecretReference;
import org.apache.commons.lang.StringUtils;
import com.google.inject.Inject;
/**
* Manages the ability to get the status of upgrades.
*/
@StaticallyInject
public class UpgradeItemResourceProvider extends ReadOnlyResourceProvider {
public static final String UPGRADE_CLUSTER_NAME = "UpgradeItem/cluster_name";
public static final String UPGRADE_REQUEST_ID = "UpgradeItem/request_id";
public static final String UPGRADE_GROUP_ID = "UpgradeItem/group_id";
public static final String UPGRADE_ITEM_STAGE_ID = "UpgradeItem/stage_id";
public static final String UPGRADE_ITEM_TEXT = "UpgradeItem/text";
private static final Set<String> PK_PROPERTY_IDS = new HashSet<>(
Arrays.asList(UPGRADE_REQUEST_ID, UPGRADE_ITEM_STAGE_ID));
private static final Set<String> PROPERTY_IDS = new HashSet<>();
private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<>();
private static Map<String, String> STAGE_MAPPED_IDS = new HashMap<>();
@Inject
private static UpgradeDAO s_dao;
@Inject
private static StageDAO s_stageDao;
@Inject
private static HostRoleCommandDAO s_hostRoleCommandDAO;
static {
// properties
PROPERTY_IDS.add(UPGRADE_ITEM_STAGE_ID);
PROPERTY_IDS.add(UPGRADE_GROUP_ID);
PROPERTY_IDS.add(UPGRADE_REQUEST_ID);
PROPERTY_IDS.add(UPGRADE_ITEM_TEXT);
// !!! boo
for (String p : StageResourceProvider.PROPERTY_IDS) {
STAGE_MAPPED_IDS.put(p, p.replace("Stage/", "UpgradeItem/"));
}
PROPERTY_IDS.addAll(STAGE_MAPPED_IDS.values());
// keys
KEY_PROPERTY_IDS.put(Resource.Type.UpgradeItem, UPGRADE_ITEM_STAGE_ID);
KEY_PROPERTY_IDS.put(Resource.Type.UpgradeGroup, UPGRADE_GROUP_ID);
KEY_PROPERTY_IDS.put(Resource.Type.Upgrade, UPGRADE_REQUEST_ID);
KEY_PROPERTY_IDS.put(Resource.Type.Cluster, UPGRADE_CLUSTER_NAME);
}
/**
* Constructor.
*
* @param controller the controller
*/
UpgradeItemResourceProvider(AmbariManagementController controller) {
super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller);
}
@Override
public RequestStatus updateResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
// the request should contain a single map of update properties...
Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
if (iterator.hasNext()) {
Map<String,Object> updateProperties = iterator.next();
String statusPropertyId = STAGE_MAPPED_IDS.get(StageResourceProvider.STAGE_STATUS);
String stageStatus = (String) updateProperties.get(statusPropertyId);
if (null == stageStatus) {
throw new IllegalArgumentException("Upgrade items can only have their status changed.");
}
HostRoleStatus desiredStatus = HostRoleStatus.valueOf(stageStatus);
Set<Resource> resources = getResources(PropertyHelper.getReadRequest(), predicate);
for (Resource resource : resources) {
final String clusterName = (String)resource.getPropertyValue(UPGRADE_CLUSTER_NAME);
final Cluster cluster;
try {
cluster = getManagementController().getClusters().getCluster(clusterName);
} catch (AmbariException e) {
throw new NoSuchParentResourceException(
String.format("Cluster %s could not be loaded", clusterName));
}
if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(),
EnumSet.of(RoleAuthorization.CLUSTER_UPGRADE_DOWNGRADE_STACK))) {
throw new AuthorizationException("The authenticated user does not have authorization to " +
"manage upgrade and downgrade");
}
// Set the desired status on the underlying stage.
Long requestId = (Long) resource.getPropertyValue(UPGRADE_REQUEST_ID);
Long stageId = (Long) resource.getPropertyValue(UPGRADE_ITEM_STAGE_ID);
StageEntityPK primaryKey = new StageEntityPK();
primaryKey.setRequestId(requestId);
primaryKey.setStageId(stageId);
StageEntity stageEntity = s_stageDao.findByPK(primaryKey);
if (null == stageEntity) {
LOG.warn(
"Unable to change the status of request {} and stage {} to {} because it does not exist",
requestId, stageId, desiredStatus);
return getRequestStatus(null);
}
s_stageDao.updateStageStatus(stageEntity, desiredStatus,
getManagementController().getActionManager());
}
}
notifyUpdate(Resource.Type.UpgradeItem, request, predicate);
return getRequestStatus(null);
}
@Override
public Set<Resource> getResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
Set<Resource> results = new LinkedHashSet<>();
Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
String clusterName = (String) propertyMap.get(UPGRADE_CLUSTER_NAME);
String requestIdStr = (String) propertyMap.get(UPGRADE_REQUEST_ID);
String groupIdStr = (String) propertyMap.get(UPGRADE_GROUP_ID);
String stageIdStr = (String) propertyMap.get(UPGRADE_ITEM_STAGE_ID);
if (null == requestIdStr || requestIdStr.isEmpty()) {
throw new IllegalArgumentException("The upgrade id is required when querying for upgrades");
}
if (null == groupIdStr || groupIdStr.isEmpty()) {
throw new IllegalArgumentException("The upgrade group id is required when querying for upgrades");
}
Long requestId = Long.valueOf(requestIdStr);
Long groupId = Long.valueOf(groupIdStr);
Long stageId = null;
if (null != stageIdStr) {
stageId = Long.valueOf(stageIdStr);
}
List<UpgradeItemEntity> entities = new ArrayList<>();
if (null == stageId) {
UpgradeGroupEntity group = s_dao.findUpgradeGroup(groupId);
if (null == group || null == group.getItems()) {
throw new NoSuchResourceException(String.format("Cannot load upgrade for %s", requestIdStr));
}
entities = group.getItems();
} else {
UpgradeItemEntity entity = s_dao.findUpgradeItemByRequestAndStage(requestId, stageId);
if (null != entity) {
entities.add(entity);
}
}
Map<Long, HostRoleCommandStatusSummaryDTO> requestAggregateCounts = s_hostRoleCommandDAO.findAggregateCounts(requestId);
Map<Long, Map<Long, HostRoleCommandStatusSummaryDTO>> cache = new HashMap<>();
cache.put(requestId, requestAggregateCounts);
// !!! need to do some lookup for stages, so use a stageid -> resource for
// when that happens
for (UpgradeItemEntity entity : entities) {
Resource upgradeItemResource = toResource(entity, requestPropertyIds);
StageEntityPK stagePrimaryKey = new StageEntityPK();
stagePrimaryKey.setRequestId(requestId);
stagePrimaryKey.setStageId(entity.getStageId());
StageEntity stageEntity = s_stageDao.findByPK(stagePrimaryKey);
Resource stageResource = StageResourceProvider.toResource(cache, stageEntity,
StageResourceProvider.PROPERTY_IDS);
for (String propertyId : StageResourceProvider.PROPERTY_IDS) {
// Attempt to mask any passwords in fields that are property maps.
Object value = stageResource.getPropertyValue(propertyId);
if (StageResourceProvider.PROPERTIES_TO_MASK_PASSWORD_IN.contains(propertyId)
&& value.getClass().equals(String.class) && !StringUtils.isBlank((String) value)) {
value = SecretReference.maskPasswordInPropertyMap((String) value);
}
setResourceProperty(upgradeItemResource, STAGE_MAPPED_IDS.get(propertyId), value,
requestPropertyIds);
}
results.add(upgradeItemResource);
}
}
return results;
}
@Override
protected Set<String> getPKPropertyIds() {
return PK_PROPERTY_IDS;
}
private Resource toResource(UpgradeItemEntity item, Set<String> requestedIds) {
ResourceImpl resource = new ResourceImpl(Resource.Type.UpgradeItem);
UpgradeGroupEntity group = item.getGroupEntity();
UpgradeEntity upgrade = group.getUpgradeEntity();
setResourceProperty(resource, UPGRADE_REQUEST_ID, upgrade.getRequestId(), requestedIds);
setResourceProperty(resource, UPGRADE_GROUP_ID, group.getId(), requestedIds);
setResourceProperty(resource, UPGRADE_ITEM_STAGE_ID, item.getStageId(), requestedIds);
setResourceProperty(resource, UPGRADE_ITEM_TEXT, item.getText(), requestedIds);
return resource;
}
}