package com.sequenceiq.cloudbreak.converter; import static com.gs.collections.impl.utility.StringIterate.isEmpty; import static com.sequenceiq.cloudbreak.cloud.model.Platform.platform; import static org.apache.commons.lang3.StringUtils.isNoneEmpty; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import javax.inject.Inject; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Component; import com.google.common.collect.Maps; import com.sequenceiq.cloudbreak.api.model.DetailedStackStatus; import com.sequenceiq.cloudbreak.api.model.InstanceGroupRequest; import com.sequenceiq.cloudbreak.api.model.InstanceGroupType; import com.sequenceiq.cloudbreak.api.model.StackRequest; import com.sequenceiq.cloudbreak.cloud.model.Platform; import com.sequenceiq.cloudbreak.cloud.model.Region; import com.sequenceiq.cloudbreak.cloud.model.StackParamValidation; import com.sequenceiq.cloudbreak.common.type.OrchestratorConstants; import com.sequenceiq.cloudbreak.controller.BadRequestException; import com.sequenceiq.cloudbreak.core.CloudbreakException; import com.sequenceiq.cloudbreak.core.bootstrap.service.OrchestratorTypeResolver; import com.sequenceiq.cloudbreak.domain.Credential; import com.sequenceiq.cloudbreak.domain.FailurePolicy; import com.sequenceiq.cloudbreak.domain.InstanceGroup; import com.sequenceiq.cloudbreak.domain.Network; import com.sequenceiq.cloudbreak.domain.Orchestrator; import com.sequenceiq.cloudbreak.domain.Stack; import com.sequenceiq.cloudbreak.domain.StackStatus; import com.sequenceiq.cloudbreak.domain.json.Json; import com.sequenceiq.cloudbreak.service.stack.StackParameterService; @Component public class JsonToStackConverter extends AbstractConversionServiceAwareConverter<StackRequest, Stack> { @Inject private StackParameterService stackParameterService; @Inject private OrchestratorTypeResolver orchestratorTypeResolver; @Value("${cb.platform.default.regions:}") private String defaultRegions; @Value("${cb.enable.custom.image:false}") private Boolean enableCustomImage; @Override public Stack convert(StackRequest source) { Stack stack = new Stack(); stack.setName(source.getName()); stack.setRegion(getRegion(source)); stack.setTags(getTags(source.getTags())); stack.setAvailabilityZone(source.getAvailabilityZone()); stack.setOnFailureActionAction(source.getOnFailureAction()); stack.setStackStatus(new StackStatus(stack, DetailedStackStatus.PROVISION_REQUESTED.getStatus(), "", DetailedStackStatus.PROVISION_REQUESTED)); stack.setInstanceGroups(convertInstanceGroups(source, stack)); stack.setFailurePolicy(getConversionService().convert(source.getFailurePolicy(), FailurePolicy.class)); stack.setParameters(getValidParameters(source)); stack.setCreated(Calendar.getInstance().getTimeInMillis()); stack.setPlatformVariant(source.getPlatformVariant()); stack.setOrchestrator(getConversionService().convert(source.getOrchestrator(), Orchestrator.class)); stack.setRelocateDocker(source.getRelocateDocker() == null ? true : source.getRelocateDocker()); if (source.getCredential() != null) { stack.setCredential(getConversionService().convert(source.getCredential(), Credential.class)); } if (source.getNetwork() != null) { stack.setNetwork(getConversionService().convert(source.getNetwork(), Network.class)); } stack.setUuid(UUID.randomUUID().toString()); validateCustomImage(source); return stack; } private void validateCustomImage(StackRequest source) { if ((source.getCustomImage() != null && !source.getCustomImage().isEmpty()) && !enableCustomImage) { throw new BadRequestException("Custom image feature was not enabled. Please enable it with -Dcb.enable.custom.image=true."); } } private Json getTags(Map<String, Object> tags) { try { if (tags == null || tags.isEmpty()) { return new Json(new HashMap<>()); } return new Json(tags); } catch (Exception e) { throw new BadRequestException("Failed to convert dynamic tags."); } } private String getRegion(StackRequest source) { boolean containerOrchestrator = false; try { containerOrchestrator = orchestratorTypeResolver.resolveType(source.getOrchestrator().getType()).containerOrchestrator(); } catch (CloudbreakException e) { throw new BadRequestException("Orchestrator not supported."); } if (OrchestratorConstants.YARN.equals(source.getOrchestrator().getType())) { return OrchestratorConstants.YARN; } if (isEmpty(source.getRegion()) && !containerOrchestrator) { Map<Platform, Region> regions = Maps.newHashMap(); if (isNoneEmpty(defaultRegions)) { for (String entry : defaultRegions.split(",")) { String[] keyValue = entry.split(":"); regions.put(platform(keyValue[0]), Region.region(keyValue[1])); } Region platformRegion = regions.get(platform(source.getCloudPlatform())); if (platformRegion == null || isEmpty(platformRegion.value())) { throw new BadRequestException(String.format("No default region specified for: %s. Region cannot be empty.", source.getCloudPlatform())); } return platformRegion.value(); } else { throw new BadRequestException("No default region is specified. Region cannot be empty."); } } return source.getRegion(); } private Map<String, String> getValidParameters(StackRequest stackRequest) { Map<String, String> params = new HashMap<>(); Map<String, String> userParams = stackRequest.getParameters(); if (userParams != null) { for (StackParamValidation stackParamValidation : stackParameterService.getStackParams(stackRequest)) { String paramName = stackParamValidation.getName(); String value = userParams.get(paramName); if (value != null) { params.put(paramName, value); } } } return params; } private Set<InstanceGroup> convertInstanceGroups(StackRequest source, Stack stack) { List<InstanceGroupRequest> instanceGroupRequests = source.getInstanceGroups(); Set<InstanceGroup> convertedSet = (Set<InstanceGroup>) getConversionService().convert(instanceGroupRequests, TypeDescriptor.forObject(instanceGroupRequests), TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(InstanceGroup.class))); boolean gatewaySpecified = false; for (InstanceGroup instanceGroup : convertedSet) { instanceGroup.setStack(stack); if (!gatewaySpecified) { if (InstanceGroupType.GATEWAY.equals(instanceGroup.getInstanceGroupType())) { gatewaySpecified = true; } } else if (InstanceGroupType.GATEWAY.equals(instanceGroup.getInstanceGroupType())) { throw new BadRequestException("Only 1 Ambari server can be specified"); } } boolean containerOrchestrator = false; try { containerOrchestrator = orchestratorTypeResolver.resolveType(source.getOrchestrator().getType()).containerOrchestrator(); } catch (CloudbreakException e) { throw new BadRequestException("Orchestrator not supported."); } if (!gatewaySpecified && !containerOrchestrator) { throw new BadRequestException("Ambari server must be specified"); } return convertedSet; } }