Skip to content

Commit c58eefb

Browse files
finish raw workflows
1 parent 6119419 commit c58eefb

4 files changed

Lines changed: 90 additions & 32 deletions

File tree

plugins/iac/nimble/src/main/java/org/apache/cloudstack/tosca/model/ToscaNodeTemplate.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ public String getName() {
3535
return name;
3636
}
3737

38+
public ToscaNodeType getType() {
39+
return type;
40+
}
41+
3842
public boolean hasProperty(String name) {
3943
return properties.containsKey(name);
4044
}

plugins/iac/nimble/src/main/java/org/apache/cloudstack/tosca/model/ToscaNodeType.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ public Map<String, ToscaAttributeDefinition> getAttributes() {
4343
return attributes;
4444
}
4545

46+
public ToscaAttributeDefinition getAttributeDefinition(String name) {
47+
return attributes.get(name);
48+
}
49+
50+
public boolean hasAttribute(String name) {
51+
return attributes.containsKey(name);
52+
}
53+
4654
@Override
4755
public String toString() {
4856
return String.format("%s: %s", name,

plugins/iac/nimble/src/main/java/org/apache/cloudstack/tosca/parser/ToscaParser.java

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.cloudstack.tosca.model.ToscaPropertyDefinition;
3333
import org.apache.cloudstack.tosca.model.ToscaServiceTemplate;
3434
import org.apache.cloudstack.tosca.model.ToscaTypeDefinition;
35+
import org.apache.commons.collections.CollectionUtils;
3536
import org.apache.commons.collections.MapUtils;
3637
import org.apache.commons.lang3.EnumUtils;
3738
import org.apache.logging.log4j.LogManager;
@@ -56,6 +57,7 @@ protected enum TypeOfToscaField {
5657

5758
private static final String NODE_TYPES_ATTRIBUTES_KEY = "attributes";
5859
private static final String PROPERTIES_KEY = "properties";
60+
private static final String DEPENDENCY_KEY = "properties";
5961
private static final String NODE_TEMPLATES_REQUIREMENTS_KEY = "requirements";
6062

6163
private static final String FIELDS_TYPE_KEY = "type";
@@ -216,12 +218,12 @@ public ToscaServiceTemplate parseServiceTemplate(String content, Map<String, Tos
216218
ToscaServiceTemplateParsingContext context = new ToscaServiceTemplateParsingContext(toscaProfile);
217219

218220
checkRootServiceTemplateYamlKeys(rawToscaTemplate, context);
219-
220221
Map<String, Object> rawServiceTemplate = ToscaYamlHelper.asMap(rawToscaTemplate.get(SERVICE_TEMPLATE_SERVICE_TEMPLATE_KEY));
221222
Map<String, ToscaInputDefinition> inputs = parseInputs(ToscaYamlHelper.asMap(rawServiceTemplate.get(SERVICE_TEMPLATE_INPUTS_KEY)), context);
222223
Map<String, ToscaNodeTemplate> nodeTemplates = parseNodeTemplates(ToscaYamlHelper.asMap(rawServiceTemplate.get(SERVICE_TEMPLATE_INPUTS_KEY)), context);
223224

224-
checkUnresolvedPropertiesByGetProperty(nodeTemplates, context);
225+
checkUnresolvedProperties(nodeTemplates, "$get_property", context);
226+
checkUnresolvedProperties(nodeTemplates, "$get_attribute", context);
225227
Map<String, Set<ToscaNodeTemplate>> serviceTemplateDependencies = buildGraphDependencies(nodeTemplates, context);
226228

227229
if (context.hasErrors()) {
@@ -231,34 +233,48 @@ public ToscaServiceTemplate parseServiceTemplate(String content, Map<String, Tos
231233
return new ToscaServiceTemplate();
232234
}
233235

234-
private void checkUnresolvedPropertiesByGetProperty(Map<String, ToscaNodeTemplate> nodeTemplates, ToscaServiceTemplateParsingContext context) {
235-
for (Map.Entry<String, Set<ToscaProperty>> entry : context.getUnresolvedByGetProperty().entrySet()) {
236-
String node = entry.getKey();
237-
Set<ToscaProperty> unresolvedProperties = entry.getValue();
238-
239-
unresolvedProperties.forEach(property -> {
240-
Map<String, Object> functionCall = ToscaYamlHelper.asMap(property.getRawValue());
241-
List<?> arguments = (List<?>) functionCall.get("$get_property");
242-
String targetNode = ToscaYamlHelper.asString(arguments.get(0));
243-
String targetProperty = ToscaYamlHelper.asString(arguments.get(1));
244-
if (!nodeTemplates.containsKey(targetNode)) {
245-
return;
246-
}
236+
private void checkUnresolvedProperties(Map<String, ToscaNodeTemplate> nodeTemplates, String function, ToscaServiceTemplateParsingContext context) {
237+
Map<String, Set<ToscaProperty>> unresolvedProperties = "$get_property".equals(function) ? context.getUnresolvedByGetProperty() : context.getUnresolvedByGetAttribute();
238+
for (Map.Entry<String, Set<ToscaProperty>> entry : unresolvedProperties.entrySet()) {
239+
Set<ToscaProperty> properties = entry.getValue();
240+
if (!CollectionUtils.isEmpty(properties)) {
241+
checkUnresolvedPropertiesOfANode(entry.getKey(), properties, nodeTemplates, function, context);
242+
}
243+
}
244+
}
247245

248-
ToscaNodeTemplate targetNodeTemplate = nodeTemplates.get(targetNode);
249-
if (!targetNodeTemplate.hasProperty(targetProperty)) {
250-
context.addError(String.format("The node [%s] references an invalid property of the node [%s].", node, targetNode), "node templates section");
251-
return;
252-
}
246+
private void checkUnresolvedPropertiesOfANode(String node, Set<ToscaProperty> unresolvedProperties, Map<String, ToscaNodeTemplate> nodeTemplates, String function, ToscaServiceTemplateParsingContext context) {
247+
unresolvedProperties.forEach(property -> {
248+
Map<String, Object> functionCall = ToscaYamlHelper.asMap(property.getRawValue());
249+
List<?> arguments = (List<?>) functionCall.get(function);
250+
String targetNode = ToscaYamlHelper.asString(arguments.get(0));
251+
String targetField = ToscaYamlHelper.asString(arguments.get(1));
253252

254-
ToscaPropertyDefinition targetPropertyDefinition = targetNodeTemplate.getProperty(targetProperty).getDefinition();
255-
if (!property.getDefinition().getType().isAssignableFrom(targetPropertyDefinition.getType())) {
256-
context.addError(String.format("Unmatching types between [node: %s, property: %s] and [node: %s, property: %s].", node, property.getDefinition().getName(), targetNode, targetProperty), "node templates section");
257-
}
253+
if (!nodeTemplates.containsKey(targetNode)) {
254+
context.addError(String.format("The node [%s] has a dependency to a non-existent node [%s].", node, targetNode), "node templates section");
255+
return;
256+
}
258257

259-
context.addNodeDependency(node, targetNode);
260-
});
261-
}
258+
ToscaNodeTemplate targetNodeTemplate = nodeTemplates.get(targetNode);
259+
if ("$get_property".equals(function) && !targetNodeTemplate.hasProperty(targetField)) {
260+
context.addError(String.format("The node [%s] references an invalid property of the node [%s].", node, targetNode), "node templates section");
261+
return;
262+
}
263+
264+
if ("$get_attribute".equals(function) && !targetNodeTemplate.getType().hasAttribute(targetField)) {
265+
context.addError(String.format("The node [%s] references an invalid attribute of the node [%s].", node, targetNode), "node templates section");
266+
return;
267+
}
268+
269+
ToscaFieldDefinition targetFieldDefinition = "$get_property".equals(function) ?
270+
targetNodeTemplate.getProperty(targetField).getDefinition() : targetNodeTemplate.getType().getAttributeDefinition(targetField);
271+
if (!property.getDefinition().getType().isAssignableFrom(targetFieldDefinition.getType())) {
272+
context.addError(String.format("Unmatching types between [node: %s, field: %s] and [node: %s, field: %s].", node, property.getDefinition().getName(), targetNode, targetField), "node templates section");
273+
return;
274+
}
275+
276+
context.addNodeDependency(node, targetNode);
277+
});
262278
}
263279

264280
private Map<String, Set<ToscaNodeTemplate>> buildGraphDependencies(Map<String, ToscaNodeTemplate> nodeTemplates, ToscaServiceTemplateParsingContext context) {
@@ -275,10 +291,10 @@ private Map<String, Set<ToscaNodeTemplate>> buildGraphDependencies(Map<String, T
275291

276292
if (context.getNodeDependencies().getOrDefault(dependency, new HashSet<>()).contains(node)) {
277293
context.addError(String.format("The nodes [%s] and [%s] have a circular dependency with each other.", node, dependency), "node templates section");
294+
return;
278295
}
279296

280-
serviceTemplateDependencies.computeIfAbsent(node, (n) -> new HashSet<>())
281-
.add(nodeTemplates.get(dependency));
297+
serviceTemplateDependencies.computeIfAbsent(node, (n) -> new HashSet<>()).add(nodeTemplates.get(dependency));
282298
});
283299
}
284300
return serviceTemplateDependencies;
@@ -309,7 +325,7 @@ private Map<String, ToscaNodeTemplate> parseNodeTemplates(Map<String, Object> no
309325
return nodeTemplateDefinitions;
310326
}
311327

312-
private ToscaNodeTemplate parseNodeTemplate(String name, Map<String, Object> body, ToscaServiceTemplateParsingContext context) {
328+
private ToscaNodeTemplate parseNodeTemplate(String nodeTemplateName, Map<String, Object> body, ToscaServiceTemplateParsingContext context) {
313329
String nodeTypeName = ToscaYamlHelper.asString(body.get(FIELDS_TYPE_KEY));
314330
if (nodeTypeName == null || !context.getProfile().containsKey(nodeTypeName)) {
315331
context.addError(String.format("The node type [%s] is not valid.", nodeTypeName), "node templates section");
@@ -318,8 +334,29 @@ private ToscaNodeTemplate parseNodeTemplate(String name, Map<String, Object> bod
318334

319335
ToscaNodeType nodeType = context.getProfile().get(nodeTypeName);
320336
validateKnownToscaKeys(body, Set.of(PROPERTIES_KEY, NODE_TEMPLATES_REQUIREMENTS_KEY), "node templates section", context);
321-
Map<String, ToscaProperty> properties = parseNodeTemplateProperties(name, ToscaYamlHelper.asMap(body.get(PROPERTIES_KEY)), nodeType, context);
322-
return new ToscaNodeTemplate(name, nodeType, properties);
337+
validateRequiredToscaKeys(body, Set.of(PROPERTIES_KEY), "node templates section", context);
338+
339+
Map<String, ToscaProperty> properties = parseNodeTemplateProperties(nodeTemplateName, ToscaYamlHelper.asMap(body.get(PROPERTIES_KEY)), nodeType, context);
340+
parseNodeTemplateRequirements(nodeTemplateName, ToscaYamlHelper.asMap(body.get(NODE_TEMPLATES_REQUIREMENTS_KEY)), context);
341+
return new ToscaNodeTemplate(nodeTemplateName, nodeType, properties);
342+
}
343+
344+
private void parseNodeTemplateRequirements(String nodeTemplateName, Map<String, Object> requirements, ToscaServiceTemplateParsingContext context) {
345+
if (MapUtils.isEmpty(requirements)) {
346+
return;
347+
}
348+
349+
validateKnownToscaKeys(requirements, Set.of(DEPENDENCY_KEY), "node templates section", context);
350+
validateRequiredToscaKeys(requirements, Set.of(DEPENDENCY_KEY), "node templates section", context);
351+
List<?> dependencies = ToscaYamlHelper.asList(requirements.get(DEPENDENCY_KEY));
352+
if (dependencies == null) {
353+
// no error message will be returned here?
354+
return;
355+
}
356+
357+
dependencies.forEach(dependency -> {
358+
context.addNodeDependency(nodeTemplateName, ToscaYamlHelper.asString(dependency));
359+
});
323360
}
324361

325362
// what about duplicate node templates?

plugins/iac/nimble/src/main/java/org/apache/cloudstack/tosca/parser/ToscaYamlHelper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.commons.lang.BooleanUtils;
2020
import org.yaml.snakeyaml.Yaml;
2121

22+
import java.util.List;
2223
import java.util.Map;
2324

2425
public class ToscaYamlHelper {
@@ -51,6 +52,14 @@ public static boolean asBoolean(Object rawObject) {
5152
return false;
5253
}
5354

55+
public static List<?> asList(Object rawObject) {
56+
if (!(rawObject instanceof List)) {
57+
return null;
58+
}
59+
60+
return (List<?>) rawObject;
61+
}
62+
5463
public static Object loadYaml(String yamlContent) {
5564
return new Yaml().load(yamlContent);
5665
}

0 commit comments

Comments
 (0)