package com.sequenceiq.cloudbreak.shell.util;
import java.util.Date;
import java.util.Map;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.api.model.Status;
import com.sequenceiq.cloudbreak.client.CloudbreakClient;
@Component
public class CloudbreakShellUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(CloudbreakShellUtil.class);
private static final int MAX_RETRY = 360;
private static final int POLLING_INTERVAL = 10000;
private static final int MAX_ATTEMPT = 3;
private static final int MILISECOND = 1000;
@Inject
private CloudbreakClient cloudbreakClient;
public void checkResponse(String operation, Response response) {
if (Response.Status.Family.SUCCESSFUL != response.getStatusInfo().getFamily()) {
String errormsg = "Error happened during " + operation + " rest operation: status: " + response.getStatus() + ", error: "
+ response.readEntity(String.class);
LOGGER.error(errormsg);
throw new RuntimeException(errormsg);
}
}
public WaitResult waitAndCheckStackStatus(Long stackId, String desiredStatus, Long timeout) {
return waitAndCheckStatus(stackId, desiredStatus, "status", timeout);
}
public WaitResult waitAndCheckClusterStatus(Long stackId, String desiredStatus, Long timeout) {
return waitAndCheckStatus(stackId, desiredStatus, "clusterStatus", timeout);
}
private WaitResult waitAndCheckStatus(Long stackId, String desiredStatus, String statusPath, Long timeout) {
for (int i = 0; i < MAX_ATTEMPT; i++) {
WaitResult waitResult = waitForStatus(stackId, desiredStatus, statusPath, timeout);
if (waitResult.getWaitResultStatus().equals(WaitResultStatus.FAILED)) {
return waitResult;
}
}
return new WaitResult(WaitResultStatus.SUCCESSFUL, "");
}
private WaitResult waitForStatus(Long stackId, String desiredStatus, String statusPath, Long timeout) {
WaitResult waitResult = new WaitResult(WaitResultStatus.SUCCESSFUL, "");
String status = null;
String statusReason;
int retryCount = 0;
long fullTime = 0;
do {
Date start = new Date();
LOGGER.info("Waiting for status {}, stack id: {}, current status {} ...", desiredStatus, stackId, status);
sleep();
Map<String, Object> statusResult = cloudbreakClient.stackEndpoint().status(stackId);
if (statusResult == null || statusResult.isEmpty()) {
return new WaitResult(WaitResultStatus.FAILED, "Status result is empty.");
}
status = (String) statusResult.get(statusPath);
statusReason = (String) statusResult.get(statusPath + "Reason");
retryCount++;
Date end = new Date();
fullTime += (end.getTime() - start.getTime()) / MILISECOND;
} while (!desiredStatus.equals(status) && !status.contains("FAILED") && !Status.DELETE_COMPLETED.name().equals(status)
&& shouldNotExitFromPolling(retryCount, timeout, fullTime));
LOGGER.info("Status {} for {} is in desired status {}", statusPath, stackId, status);
if (status.contains("FAILED") || (!Status.DELETE_COMPLETED.name().equals(desiredStatus) && Status.DELETE_COMPLETED.name().equals(status))) {
waitResult = new WaitResult(WaitResultStatus.FAILED, statusReason);
} else if (retryCount == MAX_RETRY) {
waitResult = new WaitResult(WaitResultStatus.FAILED, "Timeout while trying to fetch status.");
} else if (timeout != null && fullTime >= timeout) {
waitResult = new WaitResult(WaitResultStatus.FAILED, "Timeout while trying to fetch status.");
}
return waitResult;
}
private boolean shouldNotExitFromPolling(int retryCount, Long timeout, Long fullTime) {
if (timeout == null) {
return retryCount < MAX_RETRY;
}
return fullTime < timeout;
}
private static void sleep() {
try {
Thread.sleep(POLLING_INTERVAL);
} catch (InterruptedException e) {
LOGGER.warn("Ex during wait: {}", e);
}
}
public enum WaitResultStatus {
SUCCESSFUL,
FAILED
}
public class WaitResult {
private WaitResultStatus waitResultStatus;
private String reason;
public WaitResult(WaitResultStatus waitResultStatus, String reason) {
this.waitResultStatus = waitResultStatus;
this.reason = reason;
}
public WaitResultStatus getWaitResultStatus() {
return waitResultStatus;
}
public String getReason() {
return reason;
}
}
}