Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/deploymentmodelcompletion #289

Draft
wants to merge 18 commits into
base: ustutt
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,20 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import javax.xml.namespace.QName;

import org.eclipse.winery.model.ids.definitions.ServiceTemplateId;
import org.eclipse.winery.model.tosca.TBoundaryDefinitions;
import org.eclipse.winery.model.tosca.TBoundaryXML;
import org.eclipse.winery.model.tosca.TEntityTemplate;
import org.eclipse.winery.model.tosca.TNodeTemplate;
import org.eclipse.winery.model.tosca.TPolicy;
import org.eclipse.winery.model.tosca.TPropertyMapping;
import org.eclipse.winery.model.tosca.TQProvUrl;
import org.eclipse.winery.model.tosca.TRelationshipTemplate;
import org.eclipse.winery.model.tosca.TSelfServiceApplicationUrl;
import org.eclipse.winery.model.tosca.TServiceTemplate;
import org.eclipse.winery.model.tosca.TTag;
import org.eclipse.winery.model.tosca.TTopologyTemplate;
Expand Down Expand Up @@ -104,7 +113,7 @@ public static TTopologyTemplate groupAndPlaceComponents(ServiceTemplateId servic
topology = deepCopy(topologyBackup, false);
assignToLocation(topology, blackList);
assignToProviders(topology, blackList);
completedTopology = completeModel(serviceTemplateId, topology, blackList);
completedTopology = completeModel(serviceTemplateId, topology);
}
return completedTopology;
}
Expand All @@ -116,13 +125,10 @@ public static TTopologyTemplate groupAndPlaceComponents(ServiceTemplateId servic
*
* @param serviceTemplateId the ID of the ServiceTemplate to complete
* @param topology the incomplete TopologyTemplate to complete
* @param blackList the black list containing the NodeTemplates with the providers that are not usable for
* them
* @return the completed TopologyTemplate if completion is successful, the cleared and blacklisted TopologyTemplate
* otherwise
*/
private static TTopologyTemplate completeModel(ServiceTemplateId serviceTemplateId, TTopologyTemplate topology,
Map<String, List<String>> blackList) {
public static TTopologyTemplate completeModel(ServiceTemplateId serviceTemplateId, TTopologyTemplate topology) {
Splitting splitting = new Splitting();
IRepository repo = RepositoryFactory.getRepository();

Expand Down Expand Up @@ -637,4 +643,184 @@ private static String getNextProvider(HashMap<String, List<TNodeTemplate>> provi
}
return bestProv;
}

/**
* Completes the model based on given nodetype requirements.
*
* @param incompleteServiceTemplateId the ID of the ServiceTemplate to complete
* @param topology the incomplete TopologyTemplate to complete
* @return the completed TopologyTemplate if completion is successful, the cleared and blacklisted TopologyTemplate
* otherwise
*/
public static ServiceTemplateId completeModelBasedOnReqs(ServiceTemplateId incompleteServiceTemplateId, TTopologyTemplate topology, List<QName> blacklist, Map<String, String> policies) throws Exception {
Splitting splitting = new Splitting();
IRepository repo = RepositoryFactory.getRepository();

try {
ServiceTemplateId newId = null;
// create new temporary ServiceTemplate as working copy
TServiceTemplate incompleteServiceTemplate = repo.getElement(incompleteServiceTemplateId);
ServiceTemplateId placementId = new ServiceTemplateId(incompleteServiceTemplateId.getNamespace().getDecoded(),
VersionSupport.getNewComponentVersionId(incompleteServiceTemplateId, "placement"), false);
repo.forceDelete(placementId);
TServiceTemplate placementServiceTemplate = new TServiceTemplate.Builder(placementId.getXmlId().getDecoded(), topology)
.setName(placementId.getXmlId().getDecoded())
.setTargetNamespace(incompleteServiceTemplateId.getNamespace().getDecoded())
// .setBoundaryDefinitions(incompleteServiceTemplate.getBoundaryDefinitions())
.setTags(incompleteServiceTemplate.getTags())
.build();

// resolve open requirements until the topology is completed
while (topology != null && !splitting.getOpenRequirements(placementServiceTemplate).isEmpty()) {
// add a target label to the topology based on the provider and location assignment
assignNodesToTargetLabels(topology);
placementServiceTemplate.setTopologyTemplate(topology);
repo.setElement(placementId, placementServiceTemplate);

// complete next level of requirements
ServiceTemplateId newServiceTemplateId = splitting.completeNextRequirement(placementId, blacklist, policies);
topology = repo.getElement(newServiceTemplateId).getTopologyTemplate();

// delete intermediate result to avoid cluttering
repo.forceDelete(placementId);
placementId = newServiceTemplateId;
}

// Set selfserviceUrl for completed Templates that DO SPECIFY BOUNDARYDEFINITIONS required for selfserviceurl
TServiceTemplate completedST = repo.getElement(placementId);

final List<String> allowedPortNames = List.of("VMOpenPorts");
final List<String> allowedIPNames = List.of("VMIP");

TBoundaryDefinitions definitions = new TBoundaryDefinitions();
TBoundaryDefinitions.Properties properties = new TBoundaryDefinitions.Properties();
List<TPropertyMapping> propertyMappings = new ArrayList<>();

assert completedST.getTopologyTemplate() != null;
for (TEntityTemplate nt : completedST.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) {
String suitableIPKey = null;
String suitablePortKey = null;
if (nt.getProperties() != null) {
LinkedHashMap<String, String> kvProperties = ((TEntityTemplate.WineryKVProperties) nt.getProperties()).getKVProperties();
for (Map.Entry<String, String> entry : kvProperties.entrySet()) {
if (allowedIPNames.contains(entry.getKey())) {
suitableIPKey = entry.getKey();
}
if (allowedPortNames.contains(entry.getKey())) {
suitablePortKey = entry.getKey();
}
}
if (suitableIPKey != null && suitablePortKey != null) {
String targetPropertyRef = "concat('http://', " + nt.getId() + ".Properties." + suitableIPKey + ", ':', " + nt.getId() + ".Properties." + suitablePortKey + ")";
TPropertyMapping selfserviceProperty = new TPropertyMapping("/*/*[local-name()='selfServiceApplicationUrl']", nt, targetPropertyRef);
propertyMappings.add(selfserviceProperty);

String targetPropertyRefQProv = nt.getId() + ".Properties.QProvEndpoint";
TPropertyMapping qprovProperty = new TPropertyMapping("/*/*[local-name()='qProvUrl']", nt, targetPropertyRefQProv);
propertyMappings.add(qprovProperty);

TBoundaryXML boundaryXML = new TBoundaryXML();
boundaryXML.setNamespace("http://www.eclipse.org/winery/model/selfservice");
boundaryXML.setQProvUrl(new TQProvUrl("http://www.eclipse.org/winery/model/selfservice"));
boundaryXML.setSelfserviceApplicationUrl(new TSelfServiceApplicationUrl("http://www.eclipse.org/winery/model/selfservice"));
properties.setBoundaryXML(boundaryXML);

properties.setPropertyMappings(propertyMappings);

definitions.setProperties(properties);
completedST.setBoundaryDefinitions(definitions);

//save completed ServiceTemplate using originalname + completed
newId = new ServiceTemplateId(
incompleteServiceTemplateId.getNamespace().getDecoded(),
VersionSupport.getNewComponentVersionId(incompleteServiceTemplateId, "completed"),
false);
completedST.setId(newId.getXmlId().getDecoded());
completedST.setName(newId.getXmlId().getDecoded());
repo.setElement(newId, completedST);
repo.forceDelete(placementId);
break;
}
}
}
// returned completed topologyId
return newId;
} catch (Exception e) {
LOGGER.error("Exception while completing topology: {}", e.getMessage());
throw new Exception(e);
}
}

/**
* Checks if the repository contains equivalent servicetemplates
*
* @param serviceTemplateId Id of the servicetemplate to check for equivalency
* @param topology topology of the servicetemplate to check for equivalency
* @return
*/
public static List<ServiceTemplateId> checkServiceTemplateForEquivalency(ServiceTemplateId serviceTemplateId, TTopologyTemplate topology, Boolean includeSelf) {
List<TNodeTemplate> nodeTemplates = topology.getNodeTemplates();
List<TRelationshipTemplate> relationshipTemplates = topology.getRelationshipTemplates();
Set<ServiceTemplateId> serviceTemplateIds = RepositoryFactory.getRepository().getAllDefinitionsChildIds(ServiceTemplateId.class);
if (!includeSelf) {
serviceTemplateIds = serviceTemplateIds.stream().filter(id -> !id.equals(serviceTemplateId)).collect(Collectors.toSet());
}

return serviceTemplateIds.stream()
// remove topologies that contain different nodetemplates/relationshiptemplates
.filter(id -> {
TServiceTemplate serviceTemplateFilter = RepositoryFactory.getRepository().getElement(id);
TTopologyTemplate topologyTemplateFilter = serviceTemplateFilter.getTopologyTemplate();
assert topologyTemplateFilter != null;

// check if number of nodetemplates matches
if (topology.getNodeTemplateOrRelationshipTemplate().size() != topologyTemplateFilter.getNodeTemplateOrRelationshipTemplate().size()) {
return false;
}

// check if type of all nodetemplates match
List<TNodeTemplate> nodeTemplatesFilter = topologyTemplateFilter.getNodeTemplates();
if (!nodeTemplates.stream().allMatch( nt -> nodeTemplatesFilter.stream().anyMatch( ntFilter -> nt.getType().equals(ntFilter.getType())))) {
return false;
}

// check if deployment artifacts of all nodetemplates match
if (!nodeTemplates.stream().allMatch( nt -> nodeTemplatesFilter.stream().anyMatch( ntFilter -> {
// if both nodetemplates have no DAs return match
if (ntFilter.getDeploymentArtifacts() == null && nt.getDeploymentArtifacts() == null) {
return true;
}
// if one of the nodetemplates does not have any DAs but the other does, return no match
if (ntFilter.getDeploymentArtifacts() == null || nt.getDeploymentArtifacts() == null) {
return false;
}

// check if the artifactRef of all DAs of the nodetemplate also exist in the other nodetemplate
return nt.getDeploymentArtifacts().stream().allMatch(da -> ntFilter.getDeploymentArtifacts().stream().anyMatch(daFilter -> da.getArtifactRef().equals(daFilter.getArtifactRef())));
}))) {
return false;
}

// check if types of all relationship templates match
List<TRelationshipTemplate> relationshipTemplatesFilter = topologyTemplateFilter.getRelationshipTemplates();
if (!relationshipTemplates.stream().allMatch( rt -> relationshipTemplatesFilter.stream().anyMatch( rtFilter -> rt.getType().equals(rtFilter.getType())))) {
return false;
}
return true;
})
.toList();
}

/**
* Checks if the a given servicetemplate is complete
*
* @param serviceTemplateId Id of the servicetemplate to check for equivalency
* @param topology topology of the servicetemplate to check for equivalency
* @return true if deployment model is complete, false if incomplete
*/
public static boolean checkIfDeploymentModelIsComplete(ServiceTemplateId serviceTemplateId, TTopologyTemplate topology) {
Splitting splitting = new Splitting();
TServiceTemplate serviceTemplate = RepositoryFactory.getRepository().getElement(serviceTemplateId);
return splitting.getOpenRequirements(serviceTemplate).isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,10 @@ public void accept(Visitor visitor) {
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"any",
"propertyMappings"
"propertyMappings",
"selfServiceApplicationUrl",
"qprovUrl",
"boundaryXML"
})
public static class Properties implements Serializable {

Expand All @@ -159,6 +162,42 @@ public static class Properties implements Serializable {
@XmlElementWrapper(name = "PropertyMappings")
@XmlElement(name = "PropertyMapping", required = true)
protected List<TPropertyMapping> propertyMappings;
@XmlElement(name = "selfServiceApplicationUrl")
protected TSelfServiceApplicationUrl selfServiceApplicationUrl;

@XmlElement(name = "qprovUrl")
protected TQProvUrl qprovUrl;

@XmlElement(name = "ServiceTemplateProperties")
protected TBoundaryXML boundaryXML;

public TBoundaryXML getBoundaryXML() {
return boundaryXML;
}

public void setBoundaryXML(TBoundaryXML boundaryXML) {
this.boundaryXML = boundaryXML;
}


public TQProvUrl getQprovUrl() {
return qprovUrl;
}

public void setQprovUrl(TQProvUrl qprovUrl) {
this.qprovUrl = qprovUrl;
}


@Nullable
public TSelfServiceApplicationUrl getSelfServiceApplicationUrl() {
return selfServiceApplicationUrl;
}

public void setSelfServiceApplicationUrl(TSelfServiceApplicationUrl selfServiceApplicationUrl) {
this.selfServiceApplicationUrl = selfServiceApplicationUrl;
}


@Nullable
public Object getAny() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*******************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*******************************************************************************/

package org.eclipse.winery.model.tosca;

import java.io.Serializable;
import java.util.Objects;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

import org.eclipse.winery.model.tosca.visitor.Visitor;

import org.eclipse.jdt.annotation.NonNull;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"qProvUrl",
"selfServiceApplicationUrl"
})
public class TBoundaryXML implements Serializable {
@XmlAttribute(name = "xmlns")
protected String namespace;

@XmlElement(name = "qProvUrl")
protected TQProvUrl qProvUrl;

@XmlElement(name = "selfServiceApplicationUrl")
protected TSelfServiceApplicationUrl selfServiceApplicationUrl;

public TSelfServiceApplicationUrl getSelfserviceApplicationUrl() {
return selfServiceApplicationUrl;
}

public void setSelfserviceApplicationUrl(TSelfServiceApplicationUrl selfServiceApplicationUrl) {
this.selfServiceApplicationUrl = selfServiceApplicationUrl;
}

public TQProvUrl getQProvUrl() {
return qProvUrl;
}

public void setQProvUrl(TQProvUrl qProvUrl) {
this.qProvUrl = qProvUrl;
}

public String getNamespace() {
return namespace;
}

public void setNamespace(String namespace) {
this.namespace = namespace;
}

@Deprecated // used for XML deserialization of API request content
public TBoundaryXML() {
}

public TBoundaryXML(@NonNull TSelfServiceApplicationUrl selfServiceApplicationUrl, @NonNull TQProvUrl qProvUrl, @NonNull String namespace) {
this.qProvUrl = qProvUrl;
this.selfServiceApplicationUrl = selfServiceApplicationUrl;
this.namespace = namespace;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TBoundaryXML)) return false;
TBoundaryXML that = (TBoundaryXML) o;
return Objects.equals(qProvUrl, that.qProvUrl);
}

@Override
public int hashCode() {
return Objects.hash(qProvUrl);
}

public void accept(Visitor visitor) {
visitor.visit(this);
}
}
Loading
Loading