package com.sequenceiq.cloudbreak.core.flow2.cluster.upscale;
import static com.sequenceiq.cloudbreak.core.flow2.cluster.upscale.ClusterUpscaleEvent.FAIL_HANDLED_EVENT;
import static com.sequenceiq.cloudbreak.core.flow2.cluster.upscale.ClusterUpscaleEvent.FINALIZED_EVENT;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.action.Action;
import com.sequenceiq.cloudbreak.cloud.event.Payload;
import com.sequenceiq.cloudbreak.cloud.event.Selectable;
import com.sequenceiq.cloudbreak.core.flow2.AbstractAction;
import com.sequenceiq.cloudbreak.core.flow2.event.ClusterScaleTriggerEvent;
import com.sequenceiq.cloudbreak.core.flow2.stack.AbstractStackFailureAction;
import com.sequenceiq.cloudbreak.core.flow2.stack.StackFailureContext;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.logger.MDCBuilder;
import com.sequenceiq.cloudbreak.reactor.api.event.StackFailureEvent;
import com.sequenceiq.cloudbreak.reactor.api.event.cluster.UpscaleClusterRequest;
import com.sequenceiq.cloudbreak.reactor.api.event.cluster.UpscaleClusterResult;
import com.sequenceiq.cloudbreak.reactor.api.event.orchestration.UpscaleAmbariRequest;
import com.sequenceiq.cloudbreak.reactor.api.event.orchestration.UpscaleAmbariResult;
import com.sequenceiq.cloudbreak.reactor.api.event.recipe.UpscalePostRecipesRequest;
import com.sequenceiq.cloudbreak.reactor.api.event.recipe.UpscalePostRecipesResult;
import com.sequenceiq.cloudbreak.reactor.api.event.recipe.UpscalePreRecipesRequest;
import com.sequenceiq.cloudbreak.reactor.api.event.recipe.UpscalePreRecipesResult;
import com.sequenceiq.cloudbreak.service.stack.StackService;
@Configuration
public class ClusterUpscaleActions {
private static final Logger LOGGER = LoggerFactory.getLogger(ClusterUpscaleActions.class);
@Inject
private ClusterUpscaleFlowService clusterUpscaleFlowService;
@Bean(name = "UPSCALING_AMBARI_STATE")
public Action upscalingAmbariAction() {
return new AbstractClusterUpscaleAction<ClusterScaleTriggerEvent>(ClusterScaleTriggerEvent.class) {
@Override
protected void prepareExecution(ClusterScaleTriggerEvent payload, Map<Object, Object> variables) {
variables.put(HOSTGROUPNAME, payload.getHostGroupName());
variables.put(ADJUSTMENT, payload.getAdjustment());
}
@Override
protected void doExecute(final ClusterUpscaleContext context, final ClusterScaleTriggerEvent payload, Map<Object, Object> variables)
throws Exception {
clusterUpscaleFlowService.upscalingAmbari(context.getStack());
sendEvent(context);
}
@Override
protected Selectable createRequest(ClusterUpscaleContext context) {
return new UpscaleAmbariRequest(context.getStack().getId(), context.getHostGroupName(), context.getAdjustment());
}
};
}
@Bean(name = "EXECUTING_PRERECIPES_STATE")
public Action executingPrerecipesAction() {
return new AbstractClusterUpscaleAction<UpscaleAmbariResult>(UpscaleAmbariResult.class) {
@Override
protected void doExecute(final ClusterUpscaleContext context, final UpscaleAmbariResult payload, Map<Object, Object> variables)
throws Exception {
sendEvent(context);
}
@Override
protected Selectable createRequest(ClusterUpscaleContext context) {
return new UpscalePreRecipesRequest(context.getStack().getId(), context.getHostGroupName());
}
};
}
@Bean(name = "UPSCALING_CLUSTER_STATE")
public Action installServicesAction() {
return new AbstractClusterUpscaleAction<UpscalePreRecipesResult>(UpscalePreRecipesResult.class) {
@Override
protected void doExecute(final ClusterUpscaleContext context, final UpscalePreRecipesResult payload, Map<Object, Object> variables)
throws Exception {
sendEvent(context);
}
@Override
protected Selectable createRequest(ClusterUpscaleContext context) {
return new UpscaleClusterRequest(context.getStack().getId(), context.getHostGroupName());
}
};
}
@Bean(name = "EXECUTING_POSTRECIPES_STATE")
public Action executePostRecipesAction() {
return new AbstractClusterUpscaleAction<UpscaleClusterResult>(UpscaleClusterResult.class) {
@Override
protected void doExecute(final ClusterUpscaleContext context, final UpscaleClusterResult payload, Map<Object, Object> variables)
throws Exception {
sendEvent(context);
}
@Override
protected Selectable createRequest(ClusterUpscaleContext context) {
return new UpscalePostRecipesRequest(context.getStack().getId(), context.getHostGroupName());
}
};
}
@Bean(name = "FINALIZE_UPSCALE_STATE")
public Action upscaleFinishedAction() {
return new AbstractClusterUpscaleAction<UpscalePostRecipesResult>(UpscalePostRecipesResult.class) {
@Override
protected void doExecute(ClusterUpscaleContext context, UpscalePostRecipesResult payload, Map<Object, Object> variables) throws Exception {
clusterUpscaleFlowService.clusterUpscaleFinished(context.getStack(), payload.getHostGroupName());
sendEvent(context.getFlowId(), FINALIZED_EVENT.event(), payload);
}
@Override
protected Selectable createRequest(ClusterUpscaleContext context) {
return null;
}
};
}
@Bean(name = "CLUSTER_UPSCALE_FAILED_STATE")
public Action clusterUpscaleFailedAction() {
return new AbstractStackFailureAction<ClusterUpscaleState, ClusterUpscaleEvent>() {
@Override
protected void doExecute(StackFailureContext context, StackFailureEvent payload, Map<Object, Object> variables) throws Exception {
clusterUpscaleFlowService.clusterUpscaleFailed(context.getStack(), payload.getException());
sendEvent(context.getFlowId(), FAIL_HANDLED_EVENT.event(), payload);
}
};
}
private abstract class AbstractClusterUpscaleAction<P extends Payload>
extends AbstractAction<ClusterUpscaleState, ClusterUpscaleEvent, ClusterUpscaleContext, P> {
protected static final String HOSTGROUPNAME = "HOSTGROUPNAME";
protected static final String ADJUSTMENT = "ADJUSTMENT";
@Inject
private StackService stackService;
protected AbstractClusterUpscaleAction(Class<P> payloadClass) {
super(payloadClass);
}
@Override
protected Object getFailurePayload(P payload, Optional<ClusterUpscaleContext> flowContext, Exception ex) {
return new StackFailureEvent(payload.getStackId(), ex);
}
@Override
protected ClusterUpscaleContext createFlowContext(String flowId, StateContext<ClusterUpscaleState, ClusterUpscaleEvent> stateContext, P payload) {
Map<Object, Object> variables = stateContext.getExtendedState().getVariables();
Stack stack = stackService.getById(payload.getStackId());
MDCBuilder.buildMdcContext(stack.getCluster());
return new ClusterUpscaleContext(flowId, stack, getHostgroupName(variables), getAdjustment(variables));
}
private String getHostgroupName(Map<Object, Object> variables) {
return (String) variables.get(HOSTGROUPNAME);
}
private Integer getAdjustment(Map<Object, Object> variables) {
return (Integer) variables.get(ADJUSTMENT);
}
}
}