package com.sequenceiq.cloudbreak.core.flow2.cluster.downscale;
import static com.sequenceiq.cloudbreak.api.model.Status.AVAILABLE;
import static com.sequenceiq.cloudbreak.api.model.Status.UPDATE_FAILED;
import static com.sequenceiq.cloudbreak.common.type.CloudConstants.BYOS;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.sequenceiq.cloudbreak.api.model.DetailedStackStatus;
import com.sequenceiq.cloudbreak.api.model.InstanceStatus;
import com.sequenceiq.cloudbreak.api.model.Status;
import com.sequenceiq.cloudbreak.core.flow2.stack.FlowMessageService;
import com.sequenceiq.cloudbreak.core.flow2.stack.Msg;
import com.sequenceiq.cloudbreak.domain.Cluster;
import com.sequenceiq.cloudbreak.domain.HostGroup;
import com.sequenceiq.cloudbreak.domain.HostMetadata;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.logger.MDCBuilder;
import com.sequenceiq.cloudbreak.repository.StackUpdater;
import com.sequenceiq.cloudbreak.service.cluster.ClusterService;
import com.sequenceiq.cloudbreak.service.events.CloudbreakEventService;
import com.sequenceiq.cloudbreak.service.hostgroup.HostGroupService;
import com.sequenceiq.cloudbreak.service.messages.CloudbreakMessagesService;
import com.sequenceiq.cloudbreak.service.stack.StackService;
@Service
public class ClusterDownscaleService {
private static final Logger LOGGER = LoggerFactory.getLogger(ClusterDownscaleService.class);
@Inject
private StackService stackService;
@Inject
private StackUpdater stackUpdater;
@Inject
private ClusterService clusterService;
@Inject
private FlowMessageService flowMessageService;
@Inject
private CloudbreakMessagesService messagesService;
@Inject
private CloudbreakEventService cloudbreakEventService;
@Inject
private HostGroupService hostGroupService;
public void clusterDownscaleStarted(Stack stack, String hostGroupName, Integer scalingAdjustment, Set<String> hostNames) {
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_SCALING_DOWN, Status.UPDATE_IN_PROGRESS.name());
clusterService.updateClusterStatusByStackId(stack.getId(), Status.UPDATE_IN_PROGRESS);
if (scalingAdjustment != null) {
LOGGER.info("Decommissioning {} hosts from host group '{}'", scalingAdjustment, hostGroupName);
flowMessageService.fireInstanceGroupEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_REMOVING_NODE_FROM_HOSTGROUP, Status.UPDATE_IN_PROGRESS.name(),
hostGroupName, scalingAdjustment, hostGroupName);
} else if (!CollectionUtils.isEmpty(hostNames)) {
LOGGER.info("Decommissioning {} hosts from host group '{}'", hostNames, hostGroupName);
flowMessageService.fireInstanceGroupEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_REMOVING_NODE_FROM_HOSTGROUP, Status.UPDATE_IN_PROGRESS.name(),
hostGroupName, hostNames, hostGroupName);
}
}
public void updateMetadata(Long stackId, Set<String> hostNames, String hostGroupName) {
Stack stack = stackService.getById(stackId);
Cluster cluster = stack.getCluster();
hostNames.forEach(hn -> {
HostGroup hostGroup = hostGroupService.getByClusterIdAndName(cluster.getId(), hostGroupName);
List<HostMetadata> hostMetaToRemove = hostGroup.getHostMetadata().stream()
.filter(md -> hostNames.contains(md.getHostName())).collect(Collectors.toList());
hostGroup.getHostMetadata().removeAll(hostMetaToRemove);
hostGroupService.save(hostGroup);
});
if (!BYOS.equals(stack.cloudPlatform())) {
MDCBuilder.buildMdcContext(stack);
LOGGER.info("Start updating metadata");
for (String hostName : hostNames) {
stackService.updateMetaDataStatus(stack.getId(), hostName, InstanceStatus.DECOMMISSIONED);
}
}
clusterService.updateClusterStatusByStackId(stack.getId(), Status.AVAILABLE);
flowMessageService.fireEventAndLog(stackId, Msg.AMBARI_CLUSTER_SCALED_DOWN, AVAILABLE.name());
}
public void handleClusterDownscaleFailure(Stack stack, Exception error) {
String errorDetailes = error.getMessage();
LOGGER.error("Error during Cluster downscale flow: ", error);
clusterService.updateClusterStatusByStackId(stack.getId(), UPDATE_FAILED, errorDetailes);
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.AVAILABLE, "Node(s) could not be removed from the cluster: " + errorDetailes);
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_SCALING_FAILED, UPDATE_FAILED.name(), "removed from", errorDetailes);
}
}