/* * Copyright (c) 2013 Technische Universitat Wien (TUW), Distributed Systems Group. http://dsg.tuwien.ac.at * * This work was partially supported by the European Commission in terms of the CELAR FP7 project (FP7-ICT-2011-8 #317790), http://www.celarcloud.eu/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.ac.tuwien.dsg.cloud.salsa.engine.impl.genericCapability; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.CloudService; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.PrimitiveOperation; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.ServiceInstance; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.ServiceTopology; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.ServiceUnit; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.enums.SalsaEntityState; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.enums.SalsaEntityType; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.enums.SalsaRelationshipType; import at.ac.tuwien.dsg.cloud.salsa.engine.utils.SalsaCenterConnector; import at.ac.tuwien.dsg.cloud.salsa.engine.exceptions.EngineConnectionException; import at.ac.tuwien.dsg.cloud.salsa.common.interfaces.SalsaException; import at.ac.tuwien.dsg.cloud.salsa.engine.exceptions.AppDescriptionException; import at.ac.tuwien.dsg.cloud.salsa.engine.utils.EngineLogger; import at.ac.tuwien.dsg.cloud.salsa.engine.utils.SalsaConfiguration; import at.ac.tuwien.dsg.cloud.salsa.domainmodels.types.SalsaArtifactType; import at.ac.tuwien.dsg.cloud.salsa.domainmodels.types.ServiceCategory; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaMappingProperties; import at.ac.tuwien.dsg.cloud.salsa.engine.dataprocessing.ToscaStructureQuery; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaInstanceDescription_Docker; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaInstanceDescription_SystemProcess; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaInstanceDescription_VM; import generated.oasis.tosca.TArtifactTemplate; import generated.oasis.tosca.TCapability; import generated.oasis.tosca.TDefinitions; import generated.oasis.tosca.TDeploymentArtifact; import generated.oasis.tosca.TEntityTemplate; import generated.oasis.tosca.TNodeTemplate; import generated.oasis.tosca.TRelationshipTemplate; import generated.oasis.tosca.TRequirement; import generated.oasis.tosca.TServiceTemplate; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; /** * * @author Duc-Hung Le */ public class InfoParser { static SalsaCenterConnector centerCon; static { try { centerCon = new SalsaCenterConnector(SalsaConfiguration.getSalsaCenterEndpointLocalhost(), "/tmp", EngineLogger.logger); } catch (EngineConnectionException ex) { EngineLogger.logger.error("Cannot connect to SALSA service in localhost: " + SalsaConfiguration.getSalsaCenterEndpointLocalhost() + ". This is a fatal error !"); } } public static void cloneDataForReferenceNodes(CloudService service) throws SalsaException { List<ServiceUnit> units = service.getAllComponent(); // clone data of all reference node for (ServiceUnit unit : units) { ServiceUnit refUnit = InfoParser.getReferenceServiceUnit(unit); if (refUnit != null) { EngineLogger.logger.debug("orchestrateNewService-Clone ref data for node: " + unit.getId()); String topoID = service.getTopologyOfNode(refUnit.getId()).getId(); InfoParser.updateInstancesForReferenceNode(refUnit, service.getId(), topoID, unit.getId()); } } } public static void updateInstancesForReferenceNode(ServiceUnit sourceSU, String targetServiceID, String targetTopoID, String targetSUID) throws SalsaException { for (ServiceInstance instance : sourceSU.getInstancesList()) { EngineLogger.logger.debug("Adding instance to: " + targetServiceID + "/" + targetSUID + "/" + instance.getInstanceId()); Object tmpProp = null; if (instance.getProperties() != null) { tmpProp = instance.getProperties().getAny(); } instance.setProperties(null); centerCon.addInstanceUnitMetaData(targetServiceID, targetTopoID, targetSUID, instance); if (tmpProp != null) { centerCon.updateInstanceUnitProperty(targetServiceID, targetTopoID, targetSUID, instance.getInstanceId(), tmpProp); } } } public static ServiceUnit getReferenceServiceUnit(ServiceUnit input) throws SalsaException { EngineLogger.logger.debug("Checking the reference for ServiceUnit: " + input.getId()); if (input.getReference() == null) { EngineLogger.logger.debug("Checking the reference for ServiceUnit: " + input.getId() + " => Not be a reference node."); return null; } EngineLogger.logger.debug("Checking the referece for ServiceUnit: " + input.getId() + " => We got the reference string: " + input.getReference()); String[] refStr = input.getReference().split("/"); if (refStr.length < 2) { throw new AppDescriptionException(input.getId(), "Too short reference String, should be in format [serviceID/serviceunitID], but number of elements is only" + refStr.length); } SalsaCenterConnector otherSalsa; String otherCloudServiceID; String otherServiceUnitID; if (refStr.length == 3) { EngineLogger.logger.debug("Parsing reference node of other salsa at: " + refStr[0].trim()); String otherSalsaEndpoint = "http://" + refStr[0] + "/salsa-engine"; otherSalsa = new SalsaCenterConnector(otherSalsaEndpoint, "/tmp", EngineLogger.logger); otherCloudServiceID = refStr[1]; otherServiceUnitID = refStr[2]; } else { otherSalsa = centerCon; otherCloudServiceID = refStr[0]; otherServiceUnitID = refStr[1]; } EngineLogger.logger.debug("Getting information from other SALSA for service: " + otherCloudServiceID + ", node:" + otherServiceUnitID); CloudService service = otherSalsa.getUpdateCloudServiceRuntime(otherCloudServiceID); if (service != null) { EngineLogger.logger.debug("Checking the reference for ServiceUnit: " + input.getId() + " => FOUND !"); return service.getComponentById(otherServiceUnitID); } throw new AppDescriptionException(input.getId(), "A reference but could not find the target service to refer to."); } public static CloudService buildRuntimeDataFromTosca(TDefinitions def) { EngineLogger.logger.info("Start building runtime from Tosca file"); CloudService service = new CloudService(); service.setState(SalsaEntityState.UNDEPLOYED); List<TServiceTemplate> serviceTemplateLst = ToscaStructureQuery.getServiceTemplateList(def); for (TServiceTemplate st : serviceTemplateLst) { ServiceTopology topo = new ServiceTopology(); topo.setId(st.getId()); topo.setName(st.getName()); // all other nodes List<TNodeTemplate> nodes = ToscaStructureQuery.getNodeTemplateList(st); List<TRelationshipTemplate> relas_hoston = ToscaStructureQuery .getRelationshipTemplateList(SalsaRelationshipType.HOSTON.getRelationshipTypeString(), st); List<TRelationshipTemplate> relas_connectto = ToscaStructureQuery .getRelationshipTemplateList(SalsaRelationshipType.CONNECTTO.getRelationshipTypeString(), st); EngineLogger.logger.debug("Number of HostOn relationships: " + relas_hoston.size()); for (TNodeTemplate node : nodes) { /** * TRANSLATE BASIC INFORMATION AS Name, Min/max, Reference */ ServiceUnit nodeData = new ServiceUnit(node.getId(), node.getType().getLocalPart()); nodeData.setState(SalsaEntityState.UNDEPLOYED); nodeData.setName(node.getName()); nodeData.setMin(node.getMinInstances()); nodeData.setReference(node.getReference()); /** * TRANSLATE CAPABILITIES FIELD */ if (node.getCapabilities() != null && node.getCapabilities().getCapability() != null) { for (TCapability capa : node.getCapabilities().getCapability()) { if (!capa.getId().trim().isEmpty()) { nodeData.getCapabilityVars().add(capa.getId().trim()); } } } if (node.getMaxInstances().equals("unbounded")) { nodeData.setMax(100); // max for experiments } else { nodeData.setMax(Integer.parseInt(node.getMaxInstances())); } /** * TRANSLATE ACTION MAPPING PROPERTIES */ if (node.getProperties() != null) { if (node.getProperties().getAny() != null) { SalsaMappingProperties props = (SalsaMappingProperties) node.getProperties().getAny(); SalsaMappingProperties.SalsaMappingProperty p = props.getByType("action"); if (p != null) { for (SalsaMappingProperties.SalsaMappingProperty.Property pp : p.getPropertiesList()) { nodeData.addPrimitiveOperation(PrimitiveOperation.newCommandType(pp.getName(), pp.getValue())); } } } } /** * TRANSLATE THE HOSTED ON RELATIONSHIP */ EngineLogger.logger.debug("debugggg Sep 8.1 - 1"); // find what is the host of this node, add to hostId for (TRelationshipTemplate rela : relas_hoston) { // search on all relationship, find the host of this "node" // note that, after convert, the capa and req are reverted. TEntityTemplate targetRela = (TEntityTemplate) rela.getTargetElement().getRef(); TEntityTemplate sourceRela = (TEntityTemplate) rela.getSourceElement().getRef(); TNodeTemplate target; TNodeTemplate source; if (targetRela.getClass().equals(TRequirement.class)) { target = ToscaStructureQuery.getNodetemplateOfRequirementOrCapability(targetRela.getId(), def); source = ToscaStructureQuery.getNodetemplateOfRequirementOrCapability(sourceRela.getId(), def); } else { target = (TNodeTemplate) sourceRela; source = (TNodeTemplate) targetRela; } EngineLogger.logger.debug("Is the source with id: " + target.getId() + " same with " + nodeData.getId()); if (target.getId().equals(nodeData.getId())) { nodeData.setHostedId(source.getId()); EngineLogger.logger.debug("Found the host of node " + nodeData.getId() + " which is id = " + source.getId()); } } EngineLogger.logger.debug("debugggg Sep 8.1 - 2"); /** * TRANSLATE CONNECT-TO RELATIONSHIPS */ // find the connect to node, add it to connecttoId, this node will be the requirement, connect to capability (reverse with the Tosca) for (TRelationshipTemplate rela : relas_connectto) { EngineLogger.logger.debug("buildRuntimeDataFromTosca. Let's see relationship connectto: " + rela.getId()); if (rela.getSourceElement().getRef().getClass().equals(TNodeTemplate.class)) { TNodeTemplate sourceNode = (TNodeTemplate) rela.getSourceElement().getRef(); TNodeTemplate targetNode = (TNodeTemplate) rela.getTargetElement().getRef(); if (sourceNode.getId().equals(node.getId())) { nodeData.getConnecttoId().add(targetNode.getId()); } } else { // requirement and capability connect to TRequirement targetReq = (TRequirement) rela.getTargetElement().getRef(); TNodeTemplate target = ToscaStructureQuery.getNodetemplateOfRequirementOrCapability(targetReq.getId(), def); TCapability sourceCapa = (TCapability) rela.getSourceElement().getRef(); TNodeTemplate source = ToscaStructureQuery.getNodetemplateOfRequirementOrCapability(sourceCapa.getId(), def); EngineLogger.logger.debug("buildRuntimeDataFromTosca. Found the target id: {}", target.getId()); EngineLogger.logger.debug("buildRuntimeDataFromTosca. Source capa: {}", sourceCapa.getId()); EngineLogger.logger.debug("buildRuntimeDataFromTosca. Source: {}", source.getId()); if (target.getId().equals(node.getId())) { nodeData.getConnecttoId().add(source.getId()); } } } EngineLogger.logger.debug("debugggg Sep 8.1 - 3"); /** * TRANSLATE DEPLOYMENT ARTIFACT FIELDS */ if (node.getDeploymentArtifacts() != null && node.getDeploymentArtifacts().getDeploymentArtifact() != null) { for (TDeploymentArtifact art : node.getDeploymentArtifacts().getDeploymentArtifact()) { TArtifactTemplate artTemp = ToscaStructureQuery.getArtifactTemplateById(art.getArtifactRef().getLocalPart(), def); nodeData.addArtifact(art.getName(), art.getArtifactType().getLocalPart(), artTemp.getArtifactReferences().getArtifactReference().get(0).getReference()); } } // add the artifact type for deploying the node. The first artifact type which is not misc or metadata will be selected. // we know docker, it is a bit hack, but work if (node.getType().getLocalPart().equals(SalsaEntityType.DOCKER.getEntityTypeString())) { nodeData.setArtifactType(SalsaArtifactType.dockerfile.getString()); } else if (node.getDeploymentArtifacts() != null && node.getDeploymentArtifacts().getDeploymentArtifact() != null) { for (TDeploymentArtifact tArt : node.getDeploymentArtifacts().getDeploymentArtifact()) { if (!tArt.getArtifactType().getLocalPart().equals(SalsaArtifactType.misc.getString()) && !tArt.getArtifactType().getLocalPart().equals(SalsaArtifactType.metadata.getString()) && !tArt.getArtifactType().getLocalPart().equals(SalsaArtifactType.contract.getString())) { nodeData.setArtifactType(tArt.getArtifactType().getLocalPart()); } } } /** * ADD MAPPING PROPERTIES BASED ON ENTITY TYPE FOR SERVICE UNIT */ if (node.getProperties() != null) { SalsaMappingProperties mapProp = (SalsaMappingProperties) node.getProperties().getAny(); ServiceUnit.Properties props = new ServiceUnit.Properties(); if (node.getType().getLocalPart().equals(SalsaEntityType.OPERATING_SYSTEM.getEntityTypeString())) { SalsaInstanceDescription_VM instanceDesc = new SalsaInstanceDescription_VM(); instanceDesc.updateFromMappingProperties(mapProp); props.setAny(instanceDesc); } else if (node.getType().getLocalPart().equals(SalsaEntityType.SERVICE.getEntityTypeString())) { SalsaInstanceDescription_SystemProcess instanceDesc = new SalsaInstanceDescription_SystemProcess(); instanceDesc.updateFromMappingProperties(mapProp); props.setAny(instanceDesc); } else if (node.getType().getLocalPart().equals(SalsaEntityType.DOCKER.getEntityTypeString())) { SalsaInstanceDescription_Docker dockerDesc = new SalsaInstanceDescription_Docker(); dockerDesc.updateFromMappingProperties(mapProp); props.setAny(dockerDesc); } nodeData.setProperties(props); } topo.addComponent(nodeData); } EngineLogger.logger.debug("debugggg Sep 8.1 - last"); service.addComponentTopology(topo); } return service; } public static ServiceCategory mapOldAndNewCategory(SalsaEntityType type) { switch (type) { case ARTIFACT: case SOFTWARE: case EXECUTABLE: return ServiceCategory.ExecutableApp; case DOCKER: return ServiceCategory.docker; case TOMCAT: return ServiceCategory.TomcatContainer; case OPERATING_SYSTEM: return ServiceCategory.VirtualMachine; case SERVICE: return ServiceCategory.SystemService; case WAR: return ServiceCategory.JavaWebApp; default: return ServiceCategory.SystemService; } } }