package com.sequenceiq.cloudbreak.orchestrator.yarn;
import static com.sequenceiq.cloudbreak.common.type.OrchestratorConstants.YARN;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.orchestrator.OrchestratorBootstrap;
import com.sequenceiq.cloudbreak.orchestrator.OrchestratorBootstrapRunner;
import com.sequenceiq.cloudbreak.orchestrator.container.SimpleContainerOrchestrator;
import com.sequenceiq.cloudbreak.orchestrator.exception.CloudbreakOrchestratorException;
import com.sequenceiq.cloudbreak.orchestrator.exception.CloudbreakOrchestratorFailedException;
import com.sequenceiq.cloudbreak.orchestrator.model.ContainerConfig;
import com.sequenceiq.cloudbreak.orchestrator.model.ContainerConstraint;
import com.sequenceiq.cloudbreak.orchestrator.model.ContainerInfo;
import com.sequenceiq.cloudbreak.orchestrator.model.GatewayConfig;
import com.sequenceiq.cloudbreak.orchestrator.model.Node;
import com.sequenceiq.cloudbreak.orchestrator.model.OrchestrationCredential;
import com.sequenceiq.cloudbreak.orchestrator.state.ExitCriteria;
import com.sequenceiq.cloudbreak.orchestrator.state.ExitCriteriaModel;
import com.sequenceiq.cloudbreak.orchestrator.yarn.client.YarnHttpClient;
import com.sequenceiq.cloudbreak.orchestrator.yarn.handler.ApplicationDetailHandler;
import com.sequenceiq.cloudbreak.orchestrator.yarn.handler.ApplicationSubmissionHandler;
import com.sequenceiq.cloudbreak.orchestrator.yarn.model.request.DeleteApplicationRequest;
import com.sequenceiq.cloudbreak.orchestrator.yarn.poller.YarnAppBootstrap;
import com.sequenceiq.cloudbreak.orchestrator.yarn.util.ApplicationUtils;
@Component
public class YarnContainerOrchestrator extends SimpleContainerOrchestrator {
private static final Logger LOGGER = LoggerFactory.getLogger(YarnContainerOrchestrator.class);
@Value("${cb.docker.container.yarn.ambari.agent:}")
private String ambariAgent;
@Value("${cb.docker.container.yarn.ambari.server:}")
private String ambariServer;
@Value("${cb.docker.container.yarn.ambari.db:}")
private String postgresDockerImageName;
@Value("${cb.max.yarn.orchestrator.retry:300}")
private int maxRetry;
@Value("${cb.max.yarn.orchestrator.sleep:3000}")
private int sleepTime;
@Inject
private ApplicationDetailHandler detailHandler;
@Inject
private ApplicationSubmissionHandler submitHandler;
@Inject
private ApplicationUtils applicationUtils;
@Override
public void validateApiEndpoint(OrchestrationCredential cred) throws CloudbreakOrchestratorException {
YarnHttpClient yarnHttpClient = new YarnHttpClient(cred.getApiEndpoint());
try {
yarnHttpClient.validateApiEndpoint();
} catch (Exception e) {
throw new CloudbreakOrchestratorFailedException(e.getMessage(), e);
}
}
@Override
public List<ContainerInfo> runContainer(ContainerConfig config, OrchestrationCredential cred, ContainerConstraint constraint,
ExitCriteriaModel exitCriteriaModel) throws CloudbreakOrchestratorException {
// Create an application per component
List<ContainerInfo> containerInfos = new ArrayList<>();
for (int componentNumber = 1; componentNumber <= constraint.getInstances(); componentNumber++) {
try {
submitHandler.submitApplication(config, cred, constraint, componentNumber);
String applicationName = applicationUtils.getApplicationName(constraint, componentNumber);
YarnAppBootstrap bootstrap = new YarnAppBootstrap(applicationName, cred.getApiEndpoint());
Callable<Boolean> runner = runner(bootstrap, getExitCriteria(), exitCriteriaModel);
Future<Boolean> appFuture = getParallelOrchestratorComponentRunner().submit(runner);
appFuture.get();
containerInfos.add(detailHandler.getContainerInfo(config, cred, constraint, componentNumber));
} catch (CloudbreakOrchestratorException | InterruptedException | ExecutionException e) {
throw new CloudbreakOrchestratorFailedException(e);
}
}
return containerInfos;
}
@Override
public void deleteContainer(List<ContainerInfo> containerInfo, OrchestrationCredential cred) throws CloudbreakOrchestratorException {
for (ContainerInfo container: containerInfo) {
DeleteApplicationRequest deleteApplicationRequest = new DeleteApplicationRequest();
deleteApplicationRequest.setName(container.getName());
YarnHttpClient yarnHttpClient = new YarnHttpClient(cred.getApiEndpoint());
try {
yarnHttpClient.deleteApplication(deleteApplicationRequest);
} catch (Exception e) {
throw new CloudbreakOrchestratorFailedException(e.getMessage(), e);
}
}
}
@Override
public String name() {
return YARN;
}
//
// The remaining methods are all unused, but required by the interface.
// The default values provided match other implementations where these methods are unused.
//
@Override
public List<String> getAvailableNodes(GatewayConfig gatewayConfig, Set<Node> nodes) {
return null;
}
@Override
public void bootstrapNewNodes(GatewayConfig gatewayConfig, ContainerConfig containerConfig, Set<Node> nodes, ExitCriteriaModel exitCriteriaModel)
throws CloudbreakOrchestratorException {
assert false;
}
@Override
public void bootstrap(GatewayConfig gatewayConfig, ContainerConfig config, Set<Node> nodes, int consulServerCount, ExitCriteriaModel exitCriteriaModel)
throws CloudbreakOrchestratorException {
assert false;
}
private Callable<Boolean> runner(OrchestratorBootstrap bootstrap, ExitCriteria exitCriteria, ExitCriteriaModel exitCriteriaModel) {
return new OrchestratorBootstrapRunner(bootstrap, exitCriteria, exitCriteriaModel, MDC.getCopyOfContextMap(), maxRetry, sleepTime);
}
@Override
public int getMaxBootstrapNodes() {
return 0;
}
@Override
public List<String> getMissingNodes(GatewayConfig gatewayConfig, Set<Node> nodes) {
return null;
}
@Override
public void startContainer(List<ContainerInfo> info, OrchestrationCredential cred) {
assert false;
}
@Override
public void stopContainer(List<ContainerInfo> info, OrchestrationCredential cred) {
assert false;
}
@Override
public boolean isBootstrapApiAvailable(GatewayConfig gatewayConfig) {
return false;
}
@Override
public String ambariServerContainer(Optional<String> name) {
return name.isPresent() ? name.get() : ambariServer;
}
@Override
public String ambariClientContainer(Optional<String> name) {
return name.isPresent() ? name.get() : ambariAgent;
}
@Override
public String ambariDbContainer(Optional<String> name) {
return name.isPresent() ? name.get() : postgresDockerImageName;
}
}