package com.sequenceiq.cloudbreak.core.bootstrap.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.api.model.InstanceGroupType;
import com.sequenceiq.cloudbreak.api.model.InstanceStatus;
import com.sequenceiq.cloudbreak.client.HttpClientConfig;
import com.sequenceiq.cloudbreak.common.type.HostMetadataState;
import com.sequenceiq.cloudbreak.core.CloudbreakException;
import com.sequenceiq.cloudbreak.core.CloudbreakSecuritySetupException;
import com.sequenceiq.cloudbreak.core.bootstrap.service.container.ClusterContainerRunner;
import com.sequenceiq.cloudbreak.core.bootstrap.service.host.ClusterHostServiceRunner;
import com.sequenceiq.cloudbreak.domain.Cluster;
import com.sequenceiq.cloudbreak.domain.Container;
import com.sequenceiq.cloudbreak.domain.InstanceMetaData;
import com.sequenceiq.cloudbreak.domain.Orchestrator;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.logger.MDCBuilder;
import com.sequenceiq.cloudbreak.orchestrator.container.DockerContainer;
import com.sequenceiq.cloudbreak.repository.StackUpdater;
import com.sequenceiq.cloudbreak.service.GatewayConfigService;
import com.sequenceiq.cloudbreak.service.TlsSecurityService;
import com.sequenceiq.cloudbreak.service.cluster.ClusterService;
import com.sequenceiq.cloudbreak.service.stack.InstanceMetadataService;
import com.sequenceiq.cloudbreak.service.stack.StackService;
@Component
public class ClusterServiceRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(ClusterServiceRunner.class);
@Inject
private StackService stackService;
@Inject
private ClusterService clusterService;
@Inject
private StackUpdater stackUpdater;
@Inject
private OrchestratorTypeResolver orchestratorTypeResolver;
@Inject
private InstanceMetadataService instanceMetadataService;
@Inject
private TlsSecurityService tlsSecurityService;
@Inject
private ClusterContainerRunner containerRunner;
@Inject
private ClusterHostServiceRunner hostRunner;
@Inject
private GatewayConfigService gatewayConfigService;
public void runAmbariServices(Long stackId) throws CloudbreakException {
Stack stack = stackService.getById(stackId);
Orchestrator orchestrator = stack.getOrchestrator();
Cluster cluster = clusterService.retrieveClusterByStackId(stack.getId());
MDCBuilder.buildMdcContext(cluster);
OrchestratorType orchestratorType = orchestratorTypeResolver.resolveType(orchestrator.getType());
if (orchestratorType.containerOrchestrator()) {
Map<String, List<Container>> containers = containerRunner.runClusterContainers(stack);
Container ambariServerContainer = containers.get(DockerContainer.AMBARI_SERVER.name()).stream().findFirst().get();
String ambariServerIp = ambariServerContainer.getHost();
HttpClientConfig ambariClientConfig = buildAmbariClientConfig(stack, ambariServerIp);
clusterService.updateAmbariClientConfig(cluster.getId(), ambariClientConfig);
Map<String, List<String>> hostsPerHostGroup = new HashMap<>();
for (Map.Entry<String, List<Container>> containersEntry : containers.entrySet()) {
List<String> hostNames = new ArrayList<>();
for (Container container : containersEntry.getValue()) {
hostNames.add(container.getHost());
}
hostsPerHostGroup.put(containersEntry.getKey(), hostNames);
}
clusterService.updateHostMetadata(cluster.getId(), hostsPerHostGroup, HostMetadataState.CONTAINER_RUNNING);
} else if (orchestratorType.hostOrchestrator()) {
hostRunner.runAmbariServices(stack, cluster);
String gatewayIp = gatewayConfigService.getPrimaryGatewayIp(stack);
HttpClientConfig ambariClientConfig = buildAmbariClientConfig(stack, gatewayIp);
clusterService.updateAmbariClientConfig(cluster.getId(), ambariClientConfig);
Map<String, List<String>> hostsPerHostGroup = new HashMap<>();
for (InstanceMetaData instanceMetaData : stack.getRunningInstanceMetaData()) {
String groupName = instanceMetaData.getInstanceGroup().getGroupName();
if (!hostsPerHostGroup.keySet().contains(groupName)) {
hostsPerHostGroup.put(groupName, new ArrayList<>());
}
hostsPerHostGroup.get(groupName).add(instanceMetaData.getDiscoveryFQDN());
}
clusterService.updateHostMetadata(cluster.getId(), hostsPerHostGroup, HostMetadataState.SERVICES_RUNNING);
} 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 String changePrimaryGateway(Long stackId) throws CloudbreakException {
Stack stack = stackService.getById(stackId);
Orchestrator orchestrator = stack.getOrchestrator();
if (orchestratorTypeResolver.resolveType(orchestrator.getType()).hostOrchestrator()) {
return hostRunner.changePrimaryGateway(stack);
}
throw new CloudbreakException(String.format("Change primary gateway is not supported on orchestrator %s", orchestrator.getType()));
}
private HttpClientConfig buildAmbariClientConfig(Stack stack, String gatewayPublicIp) throws CloudbreakSecuritySetupException {
Map<InstanceGroupType, InstanceStatus> newStatusByGroupType = new HashMap<>();
newStatusByGroupType.put(InstanceGroupType.GATEWAY, InstanceStatus.REGISTERED);
newStatusByGroupType.put(InstanceGroupType.CORE, InstanceStatus.UNREGISTERED);
instanceMetadataService.updateInstanceStatus(stack.getInstanceGroups(), newStatusByGroupType);
return tlsSecurityService.buildTLSClientConfigForPrimaryGateway(stack.getId(), gatewayPublicIp);
}
}