package com.sequenceiq.cloudbreak.service.cluster.flow; import static com.sequenceiq.cloudbreak.core.bootstrap.service.ClusterDeletionBasedExitCriteriaModel.clusterDeletionBasedExitCriteriaModel; import static com.sequenceiq.cloudbreak.service.cluster.flow.RecipeEngine.DEFAULT_RECIPES; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.commons.codec.binary.Base64; import org.springframework.stereotype.Component; import com.google.api.client.util.Joiner; import com.sequenceiq.cloudbreak.api.model.Status; import com.sequenceiq.cloudbreak.core.CloudbreakException; import com.sequenceiq.cloudbreak.core.bootstrap.service.host.HostOrchestratorResolver; import com.sequenceiq.cloudbreak.domain.HostGroup; import com.sequenceiq.cloudbreak.domain.InstanceGroup; import com.sequenceiq.cloudbreak.domain.InstanceMetaData; import com.sequenceiq.cloudbreak.domain.Recipe; import com.sequenceiq.cloudbreak.domain.Stack; import com.sequenceiq.cloudbreak.orchestrator.exception.CloudbreakOrchestratorFailedException; import com.sequenceiq.cloudbreak.orchestrator.host.HostOrchestrator; import com.sequenceiq.cloudbreak.orchestrator.model.GatewayConfig; import com.sequenceiq.cloudbreak.orchestrator.model.Node; import com.sequenceiq.cloudbreak.orchestrator.model.RecipeModel; import com.sequenceiq.cloudbreak.service.GatewayConfigService; import com.sequenceiq.cloudbreak.service.events.CloudbreakEventService; import com.sequenceiq.cloudbreak.service.messages.CloudbreakMessagesService; @Component public class OrchestratorRecipeExecutor { @Inject private HostOrchestratorResolver hostOrchestratorResolver; @Inject private GatewayConfigService gatewayConfigService; @Inject private CloudbreakEventService cloudbreakEventService; @Inject private CloudbreakMessagesService cloudbreakMessagesService; public void uploadRecipes(Stack stack, Set<HostGroup> hostGroups) throws CloudbreakException { HostOrchestrator hostOrchestrator = hostOrchestratorResolver.get(stack.getOrchestrator().getType()); Map<String, List<RecipeModel>> recipeMap = hostGroups.stream().filter(hg -> !hg.getRecipes().isEmpty()) .collect(Collectors.toMap(HostGroup::getName, h -> convert(h.getRecipes()))); List<GatewayConfig> allGatewayConfigs = gatewayConfigService.getAllGatewayConfigs(stack); recipesEvent(stack.getId(), stack.getStatus(), recipeMap); try { hostOrchestrator.uploadRecipes(allGatewayConfigs, recipeMap, collectNodes(stack), clusterDeletionBasedExitCriteriaModel(stack.getId(), stack.getCluster().getId())); } catch (CloudbreakOrchestratorFailedException e) { throw new CloudbreakException(e); } } public void preInstall(Stack stack) throws CloudbreakException { HostOrchestrator hostOrchestrator = hostOrchestratorResolver.get(stack.getOrchestrator().getType()); GatewayConfig gatewayConfig = gatewayConfigService.getPrimaryGatewayConfig(stack); try { hostOrchestrator.preInstallRecipes(gatewayConfig, collectNodes(stack), clusterDeletionBasedExitCriteriaModel(stack.getId(), stack.getCluster().getId())); } catch (CloudbreakOrchestratorFailedException e) { throw new CloudbreakException(e); } } public void postInstall(Stack stack) throws CloudbreakException { HostOrchestrator hostOrchestrator = hostOrchestratorResolver.get(stack.getOrchestrator().getType()); GatewayConfig gatewayConfig = gatewayConfigService.getPrimaryGatewayConfig(stack); try { hostOrchestrator.postInstallRecipes(gatewayConfig, collectNodes(stack), clusterDeletionBasedExitCriteriaModel(stack.getId(), stack.getCluster().getId())); } catch (CloudbreakOrchestratorFailedException e) { throw new CloudbreakException(e); } } private List<RecipeModel> convert(Set<Recipe> recipes) { List<RecipeModel> result = new ArrayList<>(); for (Recipe recipe : recipes) { String decodedContent = new String(Base64.decodeBase64(recipe.getContent())); RecipeModel recipeModel = new RecipeModel(recipe.getName(), recipe.getRecipeType(), decodedContent); result.add(recipeModel); } return result; } private Set<Node> collectNodes(Stack stack) { Set<Node> agents = new HashSet<>(); for (InstanceGroup instanceGroup : stack.getInstanceGroups()) { for (InstanceMetaData instanceMetaData : instanceGroup.getInstanceMetaData()) { Node node = new Node(instanceMetaData.getPrivateIp(), instanceMetaData.getPublicIp(), instanceMetaData.getDiscoveryFQDN()); node.setHostGroup(instanceGroup.getGroupName()); agents.add(node); } } return agents; } private void recipesEvent(Long stackId, Status status, Map<String, List<RecipeModel>> recipeMap) { List<String> recipes = new ArrayList<>(); for (String hostGroupName : recipeMap.keySet()) { List<String> recipeNamesPerHostgroup = new ArrayList<>(); List<RecipeModel> recipeModels = recipeMap.get(hostGroupName); for (RecipeModel rm : recipeModels) { //filter out default recipes if (!DEFAULT_RECIPES.contains(rm.getName())) { recipeNamesPerHostgroup.add(rm.getName()); } } if (!recipeNamesPerHostgroup.isEmpty()) { String recipeNamesStr = Joiner.on(',').join(recipeNamesPerHostgroup); recipes.add(String.format("%s:[%s]", hostGroupName, recipeNamesStr)); } } if (!recipes.isEmpty()) { Collections.sort(recipes); String messageStr = Joiner.on(';').join(recipes); cloudbreakEventService.fireCloudbreakEvent(stackId, status.name(), cloudbreakMessagesService.getMessage(OrchestratorRecipeExecutor.Msg.EXECUTE_RECIPES.code(), Collections.singletonList(messageStr))); } } private enum Msg { EXECUTE_RECIPES("recipes.execute"); private String code; Msg(String msgCode) { code = msgCode; } public String code() { return code; } } }