package com.sequenceiq.cloudbreak.converter; import java.io.IOException; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.JsonNode; import com.sequenceiq.cloudbreak.api.model.BlueprintRequest; import com.sequenceiq.cloudbreak.common.type.ResourceStatus; import com.sequenceiq.cloudbreak.controller.BadRequestException; import com.sequenceiq.cloudbreak.controller.json.JsonHelper; import com.sequenceiq.cloudbreak.converter.util.URLUtils; import com.sequenceiq.cloudbreak.domain.Blueprint; import com.sequenceiq.cloudbreak.service.blueprint.BlueprintUtils; import com.sequenceiq.cloudbreak.util.JsonUtil; @Component public class JsonToBlueprintConverter extends AbstractConversionServiceAwareConverter<BlueprintRequest, Blueprint> { private static final Logger LOGGER = LoggerFactory.getLogger(JsonToBlueprintConverter.class); @Inject private JsonHelper jsonHelper; @Inject private BlueprintUtils blueprintUtils; @Override public Blueprint convert(BlueprintRequest json) { Blueprint blueprint = new Blueprint(); if (json.getUrl() != null && !json.getUrl().isEmpty()) { String sourceUrl = json.getUrl().trim(); try { String urlText = URLUtils.readUrl(sourceUrl); jsonHelper.createJsonFromString(urlText); blueprint.setBlueprintText(urlText); } catch (Exception e) { throw new BadRequestException("Cannot download ambari blueprint from: " + sourceUrl, e); } } else { blueprint.setBlueprintText(json.getAmbariBlueprint()); } validateBlueprint(blueprint.getBlueprintText()); blueprint.setName(json.getName()); blueprint.setDescription(json.getDescription()); blueprint.setStatus(ResourceStatus.USER_MANAGED); try { JsonNode root = JsonUtil.readTree(blueprint.getBlueprintText()); blueprint.setBlueprintName(blueprintUtils.getBlueprintName(root)); blueprint.setHostGroupCount(blueprintUtils.countHostGroups(root)); } catch (IOException e) { throw new BadRequestException("Invalid Blueprint: Failed to parse JSON.", e); } return blueprint; } public Blueprint convert(String name, String blueprintText, boolean publicInAccount) { Blueprint blueprint = new Blueprint(); blueprint.setName(name); blueprint.setBlueprintText(blueprintText); blueprint.setPublicInAccount(publicInAccount); validateBlueprint(blueprint.getBlueprintText()); try { JsonNode root = JsonUtil.readTree(blueprint.getBlueprintText()); blueprint.setBlueprintName(blueprintUtils.getBlueprintName(root)); blueprint.setHostGroupCount(blueprintUtils.countHostGroups(root)); } catch (IOException e) { throw new BadRequestException("Invalid Blueprint: Failed to parse JSON.", e); } return blueprint; } private void validateBlueprint(String blueprintText) { try { JsonNode root = JsonUtil.readTree(blueprintText); hasBlueprintInBlueprint(root); hasBlueprintNameInBlueprint(root); validateHostGroups(root); } catch (IOException e) { throw new BadRequestException("Invalid Blueprint: Failed to parse JSON.", e); } } private void validateHostGroups(JsonNode root) { JsonNode hostGroups = root.path("host_groups"); if (hostGroups.isMissingNode() || !hostGroups.isArray() || hostGroups.size() == 0) { throw new BadRequestException("Invalid blueprint: 'host_groups' node is missing from JSON or is not an array or empty."); } for (JsonNode hostGroup : hostGroups) { JsonNode hostGroupName = hostGroup.path("name"); if (hostGroupName.isMissingNode() || !hostGroupName.isTextual() || hostGroupName.asText().isEmpty()) { throw new BadRequestException("Invalid blueprint: one of the 'host_groups' has no name."); } validateComponentsInHostgroup(hostGroup, hostGroupName.asText()); } } private void validateComponentsInHostgroup(JsonNode hostGroup, String hostGroupName) { JsonNode components = hostGroup.path("components"); if (components.isMissingNode() || !components.isArray() || components.size() == 0) { throw new BadRequestException( String.format("Invalid blueprint: '%s' hostgroup's 'components' node is missing from JSON or is not an array or empty.", hostGroupName)); } for (JsonNode component : components) { JsonNode componentName = component.path("name"); if (componentName.isMissingNode() || !componentName.isTextual() || componentName.asText().isEmpty()) { throw new BadRequestException(String.format("Invalid blueprint: one fo the 'components' has no name in '%s' hostgroup.", hostGroupName)); } } } private void hasBlueprintNameInBlueprint(JsonNode root) { if (root.path("Blueprints").path("blueprint_name").isMissingNode()) { throw new BadRequestException("Invalid blueprint: 'blueprint_name' under 'Blueprints' is missing from JSON."); } } private void hasBlueprintInBlueprint(JsonNode root) { if (root.path("Blueprints").isMissingNode()) { throw new BadRequestException("Invalid blueprint: 'Blueprints' node is missing from JSON."); } } }