package com.sequenceiq.cloudbreak.service.cluster.flow;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sequenceiq.ambari.client.AmbariClient;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.service.ClusterBasedStatusCheckerTask;
import com.sequenceiq.cloudbreak.service.cluster.AmbariOperationFailedException;
import com.sequenceiq.cloudbreak.service.notification.Notification;
import com.sequenceiq.cloudbreak.service.notification.NotificationSender;
@Component
public class AmbariOperationsStatusCheckerTask extends ClusterBasedStatusCheckerTask<AmbariOperations> {
public static final BigDecimal COMPLETED = new BigDecimal(100.0);
public static final BigDecimal FAILED = new BigDecimal(-1.0);
public static final BigDecimal PENDING = BigDecimal.ZERO;
private static final Logger LOGGER = LoggerFactory.getLogger(AmbariOperationsStatusCheckerTask.class);
private static final int MAX_RETRY = 3;
@Inject
private NotificationSender notificationSender;
@Override
public boolean checkStatus(AmbariOperations t) {
Map<String, Integer> installRequests = t.getRequests();
boolean allFinished = true;
for (Entry<String, Integer> request : installRequests.entrySet()) {
AmbariClient ambariClient = t.getAmbariClient();
BigDecimal installProgress = Optional.ofNullable(ambariClient.getRequestProgress(request.getValue())).orElse(PENDING);
LOGGER.info("Ambari operation: '{}', Progress: {}", request.getKey(), installProgress);
notificationSender.send(getAmbariProgressNotification(installProgress.longValue(), t.getStack(), t.getAmbariOperationType()));
if (FAILED.compareTo(installProgress) == 0) {
boolean failed = true;
for (int i = 0; i < MAX_RETRY; i++) {
if (ambariClient.getRequestProgress(request.getValue()).compareTo(FAILED) != 0) {
failed = false;
break;
}
}
if (failed) {
notificationSender.send(getAmbariProgressNotification(Long.parseLong("100"), t.getStack(), t.getAmbariOperationType()));
throw new AmbariOperationFailedException(String.format("Ambari operation failed: [component: '%s', requestID: '%s']", request.getKey(),
request.getValue()));
}
}
allFinished = allFinished && COMPLETED.compareTo(installProgress) == 0;
}
return allFinished;
}
private Notification getAmbariProgressNotification(Long progressValue, Stack stack, AmbariOperationType ambariOperationType) {
Notification notification = new Notification();
notification.setEventType(ambariOperationType.name());
notification.setEventTimestamp(new Date());
notification.setEventMessage(String.valueOf(progressValue));
notification.setOwner(stack.getOwner());
notification.setAccount(stack.getAccount());
notification.setCloud(stack.cloudPlatform());
notification.setRegion(stack.getRegion());
notification.setStackId(stack.getId());
notification.setStackName(stack.getName());
notification.setStackStatus(stack.getStatus());
if (stack.getCluster() != null) {
notification.setClusterId(stack.getCluster().getId());
notification.setClusterName(stack.getCluster().getName());
}
return notification;
}
@Override
public void handleTimeout(AmbariOperations t) {
throw new IllegalStateException(String.format("Ambari operations timed out: %s", t.getRequests()));
}
@Override
public String successMessage(AmbariOperations t) {
return String.format("Requested Ambari operations completed: %s", t.getRequests().toString());
}
@Override
public void handleException(Exception e) {
LOGGER.error("Ambari operation failed.", e);
}
}