package com.sequenceiq.cloudbreak.core.flow2.cluster.provision;
import static com.sequenceiq.cloudbreak.api.model.Status.AVAILABLE;
import static com.sequenceiq.cloudbreak.api.model.Status.CREATE_FAILED;
import static com.sequenceiq.cloudbreak.api.model.Status.UPDATE_IN_PROGRESS;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.api.model.DetailedStackStatus;
import com.sequenceiq.cloudbreak.core.CloudbreakException;
import com.sequenceiq.cloudbreak.core.bootstrap.service.OrchestratorType;
import com.sequenceiq.cloudbreak.core.bootstrap.service.OrchestratorTypeResolver;
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.Orchestrator;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.repository.StackUpdater;
import com.sequenceiq.cloudbreak.service.cluster.ClusterService;
import com.sequenceiq.cloudbreak.service.cluster.flow.ClusterTerminationService;
import com.sequenceiq.cloudbreak.service.cluster.flow.EmailSenderService;
import com.sequenceiq.cloudbreak.service.stack.flow.TerminationFailedException;
import com.sequenceiq.cloudbreak.util.StackUtil;
@Component
public class ClusterCreationService {
private static final Logger LOGGER = LoggerFactory.getLogger(ClusterCreationService.class);
@Inject
private StackUpdater stackUpdater;
@Inject
private FlowMessageService flowMessageService;
@Inject
private OrchestratorTypeResolver orchestratorTypeResolver;
@Inject
private ClusterService clusterService;
@Inject
private EmailSenderService emailSenderService;
@Inject
private ClusterTerminationService clusterTerminationService;
@Inject
private StackUtil stackUtil;
public void bootstrappingMachines(Stack stack) {
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.BOOTSTRAPPING_MACHINES);
flowMessageService.fireEventAndLog(stack.getId(), Msg.STACK_INFRASTRUCTURE_BOOTSTRAP, UPDATE_IN_PROGRESS.name());
}
public void collectingHostMetadata(Stack stack) {
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.COLLECTING_HOST_METADATA);
flowMessageService.fireEventAndLog(stack.getId(), Msg.STACK_INFRASTRUCTURE_METADATA_SETUP, UPDATE_IN_PROGRESS.name());
}
public void startingAmbariServices(Stack stack, Cluster cluster) throws CloudbreakException {
Orchestrator orchestrator = stack.getOrchestrator();
OrchestratorType orchestratorType = orchestratorTypeResolver.resolveType(orchestrator.getType());
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.STARTING_AMBARI_SERVICES, "Running cluster services.");
if (orchestratorType.containerOrchestrator()) {
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_RUN_CONTAINERS, UPDATE_IN_PROGRESS.name());
} else if (orchestratorType.hostOrchestrator()) {
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_RUN_SERVICES, UPDATE_IN_PROGRESS.name());
} else {
LOGGER.info(String.format("Please implement %s orchestrator because it is not on classpath.", orchestrator.getType()));
throw new CloudbreakException(String.format("Please implement %s orchestrator because it is not on classpath.", orchestrator.getType()));
}
}
public void startingAmbari(Stack stack) {
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.CLUSTER_OPERATION, "Ambari cluster is now starting.");
clusterService.updateClusterStatusByStackId(stack.getId(), UPDATE_IN_PROGRESS);
}
public void installingCluster(Stack stack) {
String ambariIp = stackUtil.extractAmbariIp(stack);
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.CLUSTER_OPERATION,
String.format("Building the Ambari cluster. Ambari ip:%s", ambariIp));
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_BUILDING, UPDATE_IN_PROGRESS.name(), ambariIp);
}
public void clusterInstallationFinished(Stack stack, Cluster cluster) {
String ambariIp = stackUtil.extractAmbariIp(stack);
clusterService.updateClusterStatusByStackId(stack.getId(), AVAILABLE);
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.AVAILABLE, "Cluster creation finished.");
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_BUILT, AVAILABLE.name(), ambariIp);
if (cluster.getEmailNeeded()) {
emailSenderService.sendProvisioningSuccessEmail(cluster.getOwner(), stack.getCluster().getEmailTo(), ambariIp,
cluster.getName());
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_NOTIFICATION_EMAIL, AVAILABLE.name());
}
}
public void handleClusterCreationFailure(Stack stack, Exception exception) {
if (stack.getCluster() != null) {
Cluster cluster = clusterService.getById(stack.getCluster().getId());
String errorMessage = exception instanceof CloudbreakException && exception.getCause() != null
? exception.getCause().getMessage() : exception.getMessage();
clusterService.updateClusterStatusByStackId(stack.getId(), CREATE_FAILED, errorMessage);
stackUpdater.updateStackStatus(stack.getId(), DetailedStackStatus.AVAILABLE);
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_CREATE_FAILED, CREATE_FAILED.name(), errorMessage);
try {
OrchestratorType orchestratorType = orchestratorTypeResolver.resolveType(stack.getOrchestrator().getType());
if (cluster != null && orchestratorType.containerOrchestrator()) {
clusterTerminationService.deleteClusterContainers(cluster);
}
} catch (CloudbreakException | TerminationFailedException ex) {
LOGGER.error("Cluster containers could not be deleted, preparation for reinstall failed: ", ex);
}
if (cluster != null && cluster.getEmailNeeded()) {
emailSenderService.sendProvisioningFailureEmail(cluster.getOwner(), stack.getCluster().getEmailTo(), cluster.getName());
flowMessageService.fireEventAndLog(stack.getId(), Msg.AMBARI_CLUSTER_NOTIFICATION_EMAIL, AVAILABLE.name());
}
} else {
LOGGER.error("Cluster was null. Flow action was not required.");
}
}
}