package com.sequenceiq.cloudbreak.core.flow2.stack.provision.action;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.cloud.event.Selectable;
import com.sequenceiq.cloudbreak.cloud.event.setup.CheckImageResult;
import com.sequenceiq.cloudbreak.core.flow2.PayloadConverter;
import com.sequenceiq.cloudbreak.core.flow2.stack.StackContext;
import com.sequenceiq.cloudbreak.core.flow2.stack.provision.PrepareImageResultToStackEventConverter;
import com.sequenceiq.cloudbreak.core.flow2.stack.provision.StackCreationEvent;
import com.sequenceiq.cloudbreak.reactor.api.event.StackEvent;
import com.sequenceiq.cloudbreak.service.CloudbreakServiceException;
import reactor.fn.timer.Timer;
@Component("CheckImageAction")
public class CheckImageAction extends AbstractStackCreationAction<StackEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(CheckImageAction.class);
private static final int REPEAT_TIME = 5000;
private static final int FAULT_TOLERANCE = 5;
private static final String IMAGE_COPY_FAULT_NUM = "IMAGE_COPY_FAULT_NUM";
@Inject
private StackCreationService stackCreationService;
@Inject
private Timer timer;
public CheckImageAction() {
super(StackEvent.class);
}
@Override
protected void doExecute(final StackContext context, StackEvent payload, Map<Object, Object> variables) {
CheckImageResult checkImageResult = stackCreationService.checkImage(context);
switch (checkImageResult.getImageStatus()) {
case IN_PROGRESS:
repeat(context);
break;
case CREATE_FINISHED:
sendEvent(context);
break;
case CREATE_FAILED:
LOGGER.error("Error during image status check: {}", payload);
int faultNum = getFaultNum(variables) + 1;
if (faultNum == FAULT_TOLERANCE) {
removeFaultNum(variables);
throw new CloudbreakServiceException("Image copy failed.");
} else {
setFaultNum(variables, faultNum);
repeat(context);
}
break;
default:
LOGGER.error("Unknown imagestatus: {}", checkImageResult.getImageStatus());
break;
}
}
@Override
protected Selectable createRequest(StackContext context) {
return new StackEvent(StackCreationEvent.IMAGE_COPY_FINISHED_EVENT.event(), context.getStack().getId());
}
@Override
protected void initPayloadConverterMap(List<PayloadConverter<StackEvent>> payloadConverters) {
payloadConverters.add(new PrepareImageResultToStackEventConverter());
}
private void repeat(final StackContext context) {
timer.submit(aLong -> sendEvent(context.getFlowId(), new StackEvent(StackCreationEvent.IMAGE_COPY_CHECK_EVENT.event(),
context.getStack().getId())), REPEAT_TIME, TimeUnit.MILLISECONDS);
}
private int getFaultNum(Map<Object, Object> variables) {
Integer faultNum = (Integer) variables.get(IMAGE_COPY_FAULT_NUM);
return faultNum == null ? 0 : faultNum;
}
private void setFaultNum(Map<Object, Object> variables, int faultNum) {
variables.put(IMAGE_COPY_FAULT_NUM, faultNum);
}
private void removeFaultNum(Map<Object, Object> variables) {
variables.remove(IMAGE_COPY_FAULT_NUM);
}
}