Skip to content

Commit

Permalink
Filtering of Features based on the used Deployment Technology
Browse files Browse the repository at this point in the history
  • Loading branch information
lharzenetter authored and miwurster committed Aug 13, 2020
1 parent dab8e1f commit c9a29d3
Show file tree
Hide file tree
Showing 18 changed files with 186 additions and 37 deletions.
8 changes: 7 additions & 1 deletion org.eclipse.winery.crawler/pom.xml
Expand Up @@ -70,8 +70,14 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.18</version>
<version>${org.apache.commons.compress.version}</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.tukaani</groupId>
<artifactId>xz</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.winery.generators.ia/pom.xml
Expand Up @@ -49,7 +49,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.6</version>
<version>${org.apache.commons.compress.version}</version>
<exclusions>
<exclusion>
<groupId>org.tukaani</groupId>
Expand Down
Expand Up @@ -205,16 +205,18 @@ private static void addAllDAsAndIAsToImplementation(TNodeTypeImplementation targ
* Note: If feature NodeTypes are used in the topology, they cannot be enhanced with more features.
* </p>
*
* @param topology The topology to update.
* @param topology The topology to update.
* @param deploymentTechnology The underlying deployment technology the application was deployed with.
*/
public static Map<String, Map<QName, String>> getAvailableFeaturesForTopology(TTopologyTemplate topology) {
public static Map<String, Map<QName, String>> getAvailableFeaturesForTopology(TTopologyTemplate topology, String deploymentTechnology) {
IRepository repository = RepositoryFactory.getRepository();

Map<String, Map<QName, String>> availableFeatures = new HashMap<>();
Map<QName, TNodeType> nodeTypes = repository.getQNameToElementMapping(NodeTypeId.class);

topology.getNodeTemplates().forEach(node -> {
Map<TNodeType, String> featureChildren = ModelUtilities.getAvailableFeaturesOfType(node.getType(), nodeTypes);
Map<TNodeType, String> featureChildren =
ModelUtilities.getAvailableFeaturesOfType(node.getType(), nodeTypes, deploymentTechnology);
Map<QName, String> applicableFeatures = new HashMap<>();

// Check requirements
Expand Down Expand Up @@ -258,12 +260,12 @@ public static Map<String, Map<QName, String>> getAvailableFeaturesForTopology(TT

/**
* This method applies selected features to the given topology. Hereby the <code>featureMap</code> as generated by
* {@link EnhancementUtils#getAvailableFeaturesForTopology(TTopologyTemplate)} is expected. However, the list may
* differ from the originally generated one, since a user may want to have only a specific feature, i.e., all of the
* specified features in the given list are applied.
* {@link EnhancementUtils#getAvailableFeaturesForTopology(TTopologyTemplate, String)} is expected. However, the
* list may differ from the originally generated one, since a user may want to have only a specific feature, i.e.,
* all of the specified features in the given list are applied.
*
* @param topology The topology, the features will be applied to. It must be the same topology which was passed to
* the {@link EnhancementUtils#getAvailableFeaturesForTopology(TTopologyTemplate)}.
* the {@link EnhancementUtils#getAvailableFeaturesForTopology(TTopologyTemplate, String)}.
* @param featureMap The list of features to apply to the topology.
* @return The updated topology in which all matching NodeTypes will be replaced with the corresponding feature
* NodeTypes.
Expand Down Expand Up @@ -310,7 +312,8 @@ public static TTopologyTemplate applyFeaturesForTopology(TTopologyTemplate topol
* respective implementations.
*
* @param nodeTemplate The NodeTemplate that is updated with the selected features.
* @param featureTypes The list of selected features as generated by {@link EnhancementUtils#getAvailableFeaturesForTopology(TTopologyTemplate)}.
* @param featureTypes The list of selected features as generated by {@link EnhancementUtils#getAvailableFeaturesForTopology(TTopologyTemplate,
* String)}.
* @return The mapping of the generated merged NodeType and the QName of the NodeType it replaces.
*/
public static TNodeType createFeatureNodeType(TNodeTemplate nodeTemplate, Map<QName, String> featureTypes) {
Expand Down
Expand Up @@ -145,7 +145,7 @@ void getAvailableFeatures() throws Exception {

Map<String, Map<QName, String>> availableFeaturesForTopology =
EnhancementUtils.getAvailableFeaturesForTopology
(serviceTemplate.getTopologyTemplate());
(serviceTemplate.getTopologyTemplate(), null);

assertEquals(2, availableFeaturesForTopology.size());
assertEquals(1, availableFeaturesForTopology.get("MySQL-Database_w1").size());
Expand All @@ -164,7 +164,7 @@ void getAvailableFeaturesWhereNoUbuntuIsAvailableInTheStack() throws Exception {
);

Map<String, Map<QName, String>> availableFeaturesForTopology =
EnhancementUtils.getAvailableFeaturesForTopology(serviceTemplate.getTopologyTemplate());
EnhancementUtils.getAvailableFeaturesForTopology(serviceTemplate.getTopologyTemplate(), null);

assertEquals(1, availableFeaturesForTopology.size());
assertEquals(1, availableFeaturesForTopology.get("MySQL-Database_w2").size()
Expand All @@ -184,7 +184,7 @@ void getAvailableFeaturesWhereASpecificRequirementIsSatisfied() throws Exception

Map<String, Map<QName, String>> availableFeaturesForTopology =
EnhancementUtils.getAvailableFeaturesForTopology
(serviceTemplate.getTopologyTemplate());
(serviceTemplate.getTopologyTemplate(), null);

assertEquals(2, availableFeaturesForTopology.size());
assertEquals(2, availableFeaturesForTopology.get("MySQL-Database_w2").size());
Expand Down Expand Up @@ -246,7 +246,7 @@ void applyFeaturesToTopology() throws Exception {
)
).getTopologyTemplate();

EnhancementUtils.applyFeaturesForTopology(topology, EnhancementUtils.getAvailableFeaturesForTopology(topology));
EnhancementUtils.applyFeaturesForTopology(topology, EnhancementUtils.getAvailableFeaturesForTopology(topology, null));

String ubuntuNodeTemplateId = "Ubuntu_16.04-w1";
String mySqlNodeTemplateId = "MySQL-Database_w1";
Expand All @@ -268,4 +268,37 @@ void applyFeaturesToTopology() throws Exception {
assertNotNull(topology.getNodeTemplate(mySqlNodeTemplateId).getProperties());
assertEquals(3, topology.getNodeTemplate(mySqlNodeTemplateId).getProperties().getKVProperties().size());
}

@Test
void getAvailableFeaturesFilteredByDeploymentTechnology() throws Exception {
this.setRevisionTo("origin/plain");

TServiceTemplate serviceTemplate = RepositoryFactory.getRepository()
.getElement(
new ServiceTemplateId(
// This ST is the same as the other ones only without a annotated deployment technology.
// This is required for the integration tests, as the deployment technology is determined by
// the resource.
QName.valueOf("{http://opentosca.org/add/management/to/instances/servicetemplates}STWithBasicManagementOnly_noDeplTech-w1-wip1")
)
);

Map<String, Map<QName, String>> openStackFeatures =
EnhancementUtils.getAvailableFeaturesForTopology(serviceTemplate.getTopologyTemplate(), "OpenStackHeat");
assertEquals(1, openStackFeatures.size());
Map<QName, String> openStackFeature = openStackFeatures.get("NodeTypeWithDifferentFeatures_w1-wip1_0");
assertEquals(1, openStackFeature.size());
assertEquals("scalable AWS and Heat", openStackFeature.get(QName.valueOf("{http://opentosca.org/add/management/to/instances/nodetypes}ScaleFeature_AWS-OpenStack-w1-wip1")));

Map<String, Map<QName, String>> kubernetesFeatures =
EnhancementUtils.getAvailableFeaturesForTopology(serviceTemplate.getTopologyTemplate(), "Kubernetes");
assertEquals(1, kubernetesFeatures.size());
Map<QName, String> kubernetesFeature = kubernetesFeatures.get("NodeTypeWithDifferentFeatures_w1-wip1_0");
assertEquals(1, kubernetesFeature.size());
assertEquals("scalable Kubernetes", kubernetesFeature.get(QName.valueOf("{http://opentosca.org/add/management/to/instances/nodetypes}ScaleFeature_Kubernetes-w1-wip1")));

Map<String, Map<QName, String>> nonExisting =
EnhancementUtils.getAvailableFeaturesForTopology(serviceTemplate.getTopologyTemplate(), "Chef");
assertEquals(0, nonExisting.size());
}
}
@@ -0,0 +1,20 @@
/*******************************************************************************
* Copyright (c) 2020 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;

public interface HasTags {

TTags getTags();
}
Expand Up @@ -53,7 +53,7 @@
TArtifactType.class,
TPolicyType.class
})
public abstract class TEntityType extends TExtensibleElements implements HasName, HasInheritance, HasTargetNamespace {
public abstract class TEntityType extends TExtensibleElements implements HasName, HasInheritance, HasTargetNamespace, HasTags {
public static final String NS_SUFFIX_PROPERTIESDEFINITION_WINERY = "propertiesdefinition/winery";

@XmlElement(name = "Tags")
Expand Down
Expand Up @@ -37,7 +37,7 @@
"topologyTemplate",
"plans"
})
public class TServiceTemplate extends HasId implements HasName, HasTargetNamespace {
public class TServiceTemplate extends HasId implements HasName, HasTargetNamespace, HasTags {

@XmlElement(name = "Tags")
protected TTags tags;
Expand Down Expand Up @@ -179,7 +179,7 @@ public static class Builder extends HasId.Builder<Builder> {
private String name;
private String targetNamespace;
private QName substitutableNodeType;

public Builder(String id) {
super(id);
topologyTemplate = null;
Expand Down
Expand Up @@ -760,15 +760,23 @@ public static <T extends TEntityType> Map<QName, T> getChildrenOf(QName givenTyp
return children;
}

public static <T extends TEntityType> Map<T, String> getAvailableFeaturesOfType(QName givenType, Map<QName, T> elements) {
public static <T extends TEntityType> Map<T, String> getAvailableFeaturesOfType(QName givenType, Map<QName, T> elements,
String deploymentTechnology) {
HashMap<T, String> features = new HashMap<>();
getChildrenOf(givenType, elements).forEach((qName, t) -> {
if (Objects.nonNull(t.getTags())) {
List<TTag> list = t.getTags().getTag();
list.stream()
.filter(tag -> "feature".equals(tag.getName()))
.findFirst()
.ifPresent(tTag -> features.put(elements.get(qName), tTag.getValue()));

if (deploymentTechnology == null
|| list.stream().anyMatch(
// To enable the usage of "technology" and "technologies", we only check for "technolog"
tag -> tag.getName().toLowerCase().contains("deploymentTechnolog".toLowerCase())
&& tag.getValue().toLowerCase().contains(deploymentTechnology.toLowerCase()))) {
list.stream()
.filter(tag -> "feature".equals(tag.getName().toLowerCase()))
.findFirst()
.ifPresent(tTag -> features.put(elements.get(qName), tTag.getValue()));
}
}
});
return features;
Expand Down
4 changes: 2 additions & 2 deletions org.eclipse.winery.repository.rest/pom.xml
Expand Up @@ -90,7 +90,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.6</version>
<version>${org.apache.commons.compress.version}</version>
<scope>compile</scope>
<exclusions>
<exclusion>
Expand All @@ -114,7 +114,7 @@
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.9.1</version>
<version>${xerces.xercesImpl.version}</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.websocket/javax.websocket-api -->
Expand Down
Expand Up @@ -52,6 +52,7 @@
import org.eclipse.winery.common.RepositoryFileReference;
import org.eclipse.winery.common.Util;
import org.eclipse.winery.common.configuration.Environments;
import org.eclipse.winery.common.configuration.UiConfigurationObject;
import org.eclipse.winery.common.constants.MimeTypes;
import org.eclipse.winery.common.edmm.EdmmConverter;
import org.eclipse.winery.common.edmm.EdmmType;
Expand Down Expand Up @@ -379,14 +380,14 @@ public static Class<? extends DefinitionsChildId> getComponentIdClassForComponen
* @return the absolute path for the given id
*/
public static String getAbsoluteURL(GenericId id) {
return Environments.getInstance().getUiConfig().getEndpoints().get("repositoryApiUrl") + "/" + Util.getUrlPath(id);
return Environments.getInstance().getUiConfig().getEndpoints().get(UiConfigurationObject.apiUrl) + "/" + Util.getUrlPath(id);
}

/**
* @return the absolute path for the given id
*/
public static String getAbsoluteURL(RepositoryFileReference ref) {
return Environments.getInstance().getUiConfig().getEndpoints().get("repositoryApiUrl") + "/" + Util.getUrlPath(ref);
return Environments.getInstance().getUiConfig().getEndpoints().get(UiConfigurationObject.apiUrl) + "/" + Util.getUrlPath(ref);
}

public static URI getAbsoluteURI(GenericId id) {
Expand Down
Expand Up @@ -50,11 +50,13 @@
import org.eclipse.winery.model.adaptation.problemsolving.SolutionFactory;
import org.eclipse.winery.model.adaptation.problemsolving.SolutionInputData;
import org.eclipse.winery.model.adaptation.problemsolving.SolutionStrategy;
import org.eclipse.winery.model.tosca.HasTags;
import org.eclipse.winery.model.tosca.TEntityTemplate;
import org.eclipse.winery.model.tosca.TEntityType;
import org.eclipse.winery.model.tosca.TNodeTemplate;
import org.eclipse.winery.model.tosca.TNodeType;
import org.eclipse.winery.model.tosca.TRelationshipTemplate;
import org.eclipse.winery.model.tosca.TTag;
import org.eclipse.winery.model.tosca.TTopologyTemplate;
import org.eclipse.winery.model.tosca.kvproperties.PropertyDefinitionKV;
import org.eclipse.winery.model.tosca.utils.ModelUtilities;
Expand Down Expand Up @@ -275,7 +277,7 @@ public Response composeServiceTemplates(CompositionData compositionData, @Contex
Splitting splitting = new Splitting();
String newComposedSolutionServiceTemplateId = compositionData.getTargetid();
List<ServiceTemplateId> compositionServiceTemplateIDs = new ArrayList<>();
compositionData.getCspath().stream().forEach(entry -> {
compositionData.getCspath().forEach(entry -> {
QName qName = QName.valueOf(entry);
compositionServiceTemplateIDs.add(new ServiceTemplateId(qName.getNamespaceURI(), qName.getLocalPart(), false));
});
Expand Down Expand Up @@ -461,13 +463,24 @@ public TTopologyTemplate cleanFreezableComponents() {
public ArrayList<AvailableFeaturesApiData> getAvailableFeatures() {
ArrayList<AvailableFeaturesApiData> apiData = new ArrayList<>();

EnhancementUtils.getAvailableFeaturesForTopology(this.topologyTemplate).forEach((nodeTemplateId, featuresMap) -> {
ArrayList<AvailableFeaturesApiData.Features> features = new ArrayList<>();
featuresMap.forEach(
(featureType, featureName) -> features.add(new AvailableFeaturesApiData.Features(featureType, featureName))
);
apiData.add(new AvailableFeaturesApiData(nodeTemplateId, features));
});
String deploymentTechnology = null;
if (this.parent.getElement() instanceof HasTags && ((HasTags) this.parent.getElement()).getTags() != null) {
for (TTag tag : ((HasTags) this.parent.getElement()).getTags().getTag()) {
if (tag.getName().toLowerCase().contains("deploymentTechnology".toLowerCase())) {
deploymentTechnology = tag.getValue();
break;
}
}
}

EnhancementUtils.getAvailableFeaturesForTopology(this.topologyTemplate, deploymentTechnology)
.forEach((nodeTemplateId, featuresMap) -> {
ArrayList<AvailableFeaturesApiData.Features> features = new ArrayList<>();
featuresMap.forEach(
(featureType, featureName) -> features.add(new AvailableFeaturesApiData.Features(featureType, featureName))
);
apiData.add(new AvailableFeaturesApiData(nodeTemplateId, features));
});

return apiData;
}
Expand Down
Expand Up @@ -19,6 +19,7 @@
import org.eclipse.winery.repository.backend.RepositoryFactory;
import org.eclipse.winery.repository.rest.resources.AbstractResourceTest;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand Down Expand Up @@ -185,4 +186,25 @@ public void getNewVersionListWithoutFeaturesAndGeneratedTypes() throws Exception
this.assertGet("servicetemplates/http%253A%252F%252Fplain.winery.opentosca.org%252Fservicetemplates/STWithUpdateableComponent_w1-wip1/topologytemplate/newversions",
"servicetemplates/nodeTemplateVersionListWithoutFeatures.json");
}

@Test
public void getAvailableFeaturesFilteredByDeploymentTechnologyOpenStack() throws Exception {
this.setRevisionTo("origin/plain");
this.assertGet("servicetemplates/http%253A%252F%252Fopentosca.org%252Fadd%252Fmanagement%252Fto%252Finstances%252Fservicetemplates/STWithBasicManagementOnly_OpenStackHeat-w1-wip1/topologytemplate/availablefeatures",
"servicetemplates/topologytemplates/availableFeatures-openStack.json");
}

@Test
public void getAvailableFeaturesFilteredByDeploymentTechnologyPuppet() throws Exception {
this.setRevisionTo("origin/plain");
this.assertGet("servicetemplates/http%253A%252F%252Fopentosca.org%252Fadd%252Fmanagement%252Fto%252Finstances%252Fservicetemplates/STWithBasicManagementOnly_puppet-w1-wip1/topologytemplate/availablefeatures",
"servicetemplates/topologytemplates/availableFeatures-puppet.json");
}

@Test
public void getAvailableFeaturesNoDeploymentTechnologyAnnotated() throws Exception {
this.setRevisionTo("origin/plain");
this.assertGet("servicetemplates/http%253A%252F%252Fopentosca.org%252Fadd%252Fmanagement%252Fto%252Finstances%252Fservicetemplates/STWithBasicManagementOnly_noDeplTech-w1-wip1/topologytemplate/availablefeatures",
"servicetemplates/topologytemplates/availableFeatures.json");
}
}
@@ -0,0 +1,11 @@
[
{
"nodeTemplateId": "NodeTypeWithDifferentFeatures_w1-wip1_0",
"features": [
{
"type": "{http://opentosca.org/add/management/to/instances/nodetypes}ScaleFeature_AWS-OpenStack-w1-wip1",
"featureName": "scalable AWS and Heat"
}
]
}
]

0 comments on commit c9a29d3

Please sign in to comment.