summaryrefslogtreecommitdiffstats
path: root/openecomp-be
diff options
context:
space:
mode:
authorshiria <shiri.amichai@amdocs.com>2018-03-21 09:11:30 +0200
committerOren Kleks <orenkle@amdocs.com>2018-03-21 12:24:17 +0000
commit298c383225d728eb6a04e4b8cb03472f4990de7e (patch)
tree5b975c4620ad350ff46060f1427a6accfc12ec2c /openecomp-be
parentf59a22539d5b372e2425c39963547985379d6990 (diff)
Handle OperationDefinition in Tosca Data Model
Change-Id: Ib1a7f0c5548fc9c7a98cff1182ff02300353443d Issue-ID: SDC-1154 Signed-off-by: shiria <shiri.amichai@amdocs.com>
Diffstat (limited to 'openecomp-be')
-rw-r--r--openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java24
-rw-r--r--openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/DataModelUtil.java33
-rw-r--r--openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/datatypes/ToscaModelTest.java107
-rw-r--r--openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTemplateInterface.yaml5
-rw-r--r--openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTypeInterface.yaml117
5 files changed, 237 insertions, 49 deletions
diff --git a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java
index 18750e4d0a..206eae3491 100644
--- a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java
+++ b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java
@@ -37,6 +37,7 @@ import org.openecomp.sdc.common.errors.Messages;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -176,11 +177,34 @@ public class CommonUtil {
Map<String, Object> objectAsMap = getObjectAsMap(objectCandidate);
T result = classToCreate.newInstance();
+
+ Field[] declaredFields = classToCreate.getDeclaredFields();
+ for( Field field : declaredFields){
+ if(isComplexClass(field)){
+ Optional<?> objectUsingSetters =
+ createObjectUsingSetters(objectAsMap.get(field.getName()), field.getType());
+ if( objectUsingSetters.isPresent()){
+ objectAsMap.remove(field.getName());
+ objectAsMap.put(field.getName(), objectUsingSetters.get());
+ }
+ }
+ }
BeanUtils.populate(result, objectAsMap);
return Optional.of(result);
}
+ private static boolean isComplexClass(Field field) {
+ return !field.getType().equals(Map.class)
+ && !field.getType().equals(String.class)
+ && !field.getType().equals(Integer.class)
+ && !field.getType().equals(Float.class)
+ && !field.getType().equals(Double.class)
+ && !field.getType().equals(Set.class)
+ && !field.getType().equals(Object.class)
+ && !field.getType().equals(List.class);
+ }
+
public static Map<String, Object> getObjectAsMap(Object obj) {
Map<String, Object> objectAsMap = obj instanceof Map ? (Map<String, Object>) obj
: new ObjectMapper().convertValue(obj, Map.class);
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/DataModelUtil.java b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/DataModelUtil.java
index 6b1046bb45..97932289b9 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/DataModelUtil.java
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/DataModelUtil.java
@@ -40,11 +40,14 @@ import org.openecomp.sdc.tosca.datatypes.model.EntrySchema;
import org.openecomp.sdc.tosca.datatypes.model.GroupDefinition;
import org.openecomp.sdc.tosca.datatypes.model.Import;
import org.openecomp.sdc.tosca.datatypes.model.InterfaceDefinition;
+import org.openecomp.sdc.tosca.datatypes.model.InterfaceDefinitionTemplate;
import org.openecomp.sdc.tosca.datatypes.model.InterfaceDefinitionType;
import org.openecomp.sdc.tosca.datatypes.model.InterfaceType;
import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
import org.openecomp.sdc.tosca.datatypes.model.NodeType;
import org.openecomp.sdc.tosca.datatypes.model.OperationDefinition;
+import org.openecomp.sdc.tosca.datatypes.model.OperationDefinitionTemplate;
+import org.openecomp.sdc.tosca.datatypes.model.OperationDefinitionType;
import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition;
import org.openecomp.sdc.tosca.datatypes.model.PolicyDefinition;
import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition;
@@ -1226,8 +1229,8 @@ public class DataModelUtil {
return interfaceDefinition;
} catch (Exception ex) {
throw new CoreException(
- new CreateInterfaceObjectErrorBuilder(InterfaceDefinitionType.class.getName(), interfaceId,
- ex.getMessage()).build());
+ new CreateInterfaceObjectErrorBuilder(InterfaceDefinitionType.class.getName(),
+ interfaceId, ex.getMessage()).build());
}
}
@@ -1280,19 +1283,21 @@ public class DataModelUtil {
Set<String> fieldNames = CommonUtil.getClassFieldNames(InterfaceType.class);
for (Map.Entry<String, Object> entry : interfaceAsMap.entrySet()) {
- Optional<OperationDefinition> operationDefinition =
- createOperation(entry.getKey(), entry.getValue(), fieldNames);
+ Optional<? extends OperationDefinition> operationDefinition =
+ createOperation(entry.getKey(), entry.getValue(), fieldNames,
+ OperationDefinitionType.class);
operationDefinition
.ifPresent(operation -> interfaceType.addOperation(entry.getKey(), operation));
}
}
- private static Optional<OperationDefinition> createOperation(String propertyName,
- Object operationCandidate,
- Set<String> fieldNames) {
+ private static Optional<? extends OperationDefinition> createOperation(String propertyName,
+ Object operationCandidate,
+ Set<String> fieldNames,
+ Class<? extends OperationDefinition> operationClass) {
if (!fieldNames.contains(propertyName)) {
try {
- return CommonUtil.createObjectUsingSetters(operationCandidate, OperationDefinition.class);
+ return CommonUtil.createObjectUsingSetters(operationCandidate, operationClass);
} catch (Exception ex) {
throw new CoreException(
new CreateInterfaceOperationObjectErrorBuilder(propertyName, ex.getMessage()).build());
@@ -1302,14 +1307,18 @@ public class DataModelUtil {
return Optional.empty();
}
- private static void updateInterfaceDefinitionOperations(Map<String, Object> interfaceAsMap,
- InterfaceDefinition interfaceDefinition) {
+ private static <T extends OperationDefinition> void updateInterfaceDefinitionOperations(
+ Map<String, Object> interfaceAsMap,
+ InterfaceDefinition interfaceDefinition) {
Set<String> fieldNames = CommonUtil.getClassFieldNames(InterfaceDefinitionType.class);
+ Optional<? extends OperationDefinition> operationDefinition = Optional.empty();
for (Map.Entry<String, Object> entry : interfaceAsMap.entrySet()) {
- Optional<OperationDefinition> operationDefinition =
- createOperation(entry.getKey(), entry.getValue(), fieldNames);
+ operationDefinition = createOperation(entry.getKey(), entry.getValue(), fieldNames,
+ interfaceDefinition instanceof InterfaceDefinitionType ? OperationDefinitionType.class :
+ OperationDefinitionTemplate.class);
+
operationDefinition
.ifPresent(operation -> interfaceDefinition.addOperation(entry.getKey(), operation));
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/datatypes/ToscaModelTest.java b/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/datatypes/ToscaModelTest.java
index ced108380e..4b58c838e0 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/datatypes/ToscaModelTest.java
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/datatypes/ToscaModelTest.java
@@ -28,14 +28,17 @@ import org.openecomp.sdc.tosca.datatypes.model.CapabilityAssignment;
import org.openecomp.sdc.tosca.datatypes.model.CapabilityDefinition;
import org.openecomp.sdc.tosca.datatypes.model.Constraint;
import org.openecomp.sdc.tosca.datatypes.model.Directive;
+import org.openecomp.sdc.tosca.datatypes.model.Implementation;
import org.openecomp.sdc.tosca.datatypes.model.Import;
import org.openecomp.sdc.tosca.datatypes.model.InterfaceDefinition;
+import org.openecomp.sdc.tosca.datatypes.model.InterfaceDefinitionTemplate;
import org.openecomp.sdc.tosca.datatypes.model.InterfaceDefinitionType;
import org.openecomp.sdc.tosca.datatypes.model.InterfaceType;
import org.openecomp.sdc.tosca.datatypes.model.NodeFilter;
import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
import org.openecomp.sdc.tosca.datatypes.model.NodeType;
import org.openecomp.sdc.tosca.datatypes.model.OperationDefinition;
+import org.openecomp.sdc.tosca.datatypes.model.OperationDefinitionTemplate;
import org.openecomp.sdc.tosca.datatypes.model.OperationDefinitionType;
import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition;
import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition;
@@ -64,13 +67,22 @@ public class ToscaModelTest {
private YamlUtil yamlUtil = new YamlUtil();
private static final String INTERFACE_ID = "inter_1";
private static final String NODE_TEMPLATE_ID = "firstNodeTemplate";
+ private static final String NODE_TYPE_ID = "compute_node_type";
private static final String BASE_DIR = "/mock/model";
private static final String ST = "/serviceTemplate.yaml";
private static final String ST_WITH_INTERFACE = "/serviceTemplateWithInterface.yaml";
private static final String ST_WITH_OPERATIONS = "/serviceTemplateWithInterfaceAndOperation.yaml";
private static final String ST_WITH_INTERFACE_DEF =
"/serviceTemplateWithNodeTemplateInterface.yaml";
-
+ private static final String ST_WITH_NODE_INTERFACE_DEF =
+ "/serviceTemplateWithNodeTypeInterface.yaml";
+ private static final String INTERFACE_TYPE_VALUE = "tosca.interfaces.node.lifecycle.Standard";
+ private static final String OPERATION_START = "start";
+ private static final String OPERATION_DESC = "start operation";
+ private static final String IMPLEMENTATION_NAME = "startWorkFlow.json";
+ private static final String PRIMARY_IMPL = "myImpl.yaml";
+ private static final String DEPENDENCY_NAME = "script1.sh";
+ private static final String STRING_TYPE = "string";
@Test
public void testServiceTemplateJavaToYaml() {
@@ -306,7 +318,7 @@ public class ToscaModelTest {
getServiceTemplate(BASE_DIR + ST_WITH_OPERATIONS);
Assert.assertNotNull(serviceTemplateWithOperation);
- InterfaceType expectedInterfaceType = getInterfaceType();
+ InterfaceType expectedInterfaceType = createInterfaceType();
Map<String, InterfaceType> interfaceTypes =
DataModelUtil.getInterfaceTypes(serviceTemplateWithOperation);
@@ -323,10 +335,10 @@ public class ToscaModelTest {
ServiceTemplate serviceTemplateWithOperation =
getServiceTemplate(BASE_DIR + ST_WITH_OPERATIONS);
- OperationDefinition operationDefinition = getOperationDefinition();
+ OperationDefinition operationDefinition = createOperationDefinition();
DataModelUtil
- .addInterfaceOperation(serviceTemplateWithInterface, INTERFACE_ID, "start",
+ .addInterfaceOperation(serviceTemplateWithInterface, INTERFACE_ID, OPERATION_START,
operationDefinition);
String expectedServiceTemplate = yamlUtil.objectToYaml(serviceTemplateWithOperation);
String actualServiceTemplate = yamlUtil.objectToYaml(serviceTemplateWithInterface);
@@ -339,7 +351,7 @@ public class ToscaModelTest {
getServiceTemplate(BASE_DIR + ST_WITH_INTERFACE);
ServiceTemplate serviceTemplateWithOperation =
getServiceTemplate(BASE_DIR + ST_WITH_OPERATIONS);
- InterfaceType interfaceType = getInterfaceType();
+ InterfaceType interfaceType = createInterfaceType();
Optional<Object> interfaceAsObj = DataModelUtil.convertInterfaceTypeToObj(interfaceType);
Assert.assertTrue(interfaceAsObj.isPresent());
@@ -363,35 +375,32 @@ public class ToscaModelTest {
DataModelUtil.convertObjToInterfaceType(INTERFACE_ID, interfaceObj);
Assert.assertTrue(actualInterfaceType.isPresent());
- InterfaceType expectedInterfaceType = getInterfaceType();
+ InterfaceType expectedInterfaceType = createInterfaceType();
Assert.assertEquals(expectedInterfaceType, actualInterfaceType.get());
}
@Test
- public void testInterfaceDefinitionToObjConversion() throws IOException {
- ServiceTemplate serviceTemplate =
- getServiceTemplate(BASE_DIR + ST);
+ public void testObjToInterfaceDefinitionTypeConversion()
+ throws IOException, ReflectiveOperationException {
ServiceTemplate serviceTemplateWithInterfaceDef =
- getServiceTemplate(BASE_DIR + ST_WITH_INTERFACE_DEF);
+ getServiceTemplate(BASE_DIR + ST_WITH_NODE_INTERFACE_DEF);
+ NodeType nodeTypeWithInterface =
+ DataModelUtil.getNodeType(serviceTemplateWithInterfaceDef, NODE_TYPE_ID);
+ Map<String, Object> interfaces = nodeTypeWithInterface.getInterfaces();
+ Object interfaceObj = interfaces.get(INTERFACE_ID);
- NodeTemplate nodeTemplate =
- DataModelUtil.getNodeTemplate(serviceTemplate, NODE_TEMPLATE_ID);
- InterfaceDefinitionType interfaceDefinitionType = getInterfaceDefinition();
- Optional<Object> interfaceObj = DataModelUtil.convertInterfaceDefinitionToObj(
- interfaceDefinitionType);
+ Optional<? extends InterfaceDefinition> actualInterfaceDefinition =
+ DataModelUtil.convertObjToInterfaceDefinition(INTERFACE_ID, interfaceObj,
+ InterfaceDefinitionType.class);
- Assert.assertTrue(interfaceObj.isPresent());
- Map<String, Object> interfaces = new HashMap<>();
- interfaces.put(INTERFACE_ID, interfaceObj.get());
- nodeTemplate.setInterfaces(interfaces);
+ Assert.assertTrue(actualInterfaceDefinition.isPresent());
- String expectedServiceTemplate = yamlUtil.objectToYaml(serviceTemplateWithInterfaceDef);
- String actualServiceTemplate = yamlUtil.objectToYaml(serviceTemplate);
- Assert.assertEquals(expectedServiceTemplate, actualServiceTemplate);
+ InterfaceDefinitionType expectedInterfaceDefinitionType = createInterfaceDefinitionType();
+ Assert.assertEquals(expectedInterfaceDefinitionType, actualInterfaceDefinition.get());
}
@Test
- public void testObjToInterfaceDefinitionConversion()
+ public void testObjToInterfaceDefinitionTemplateConversion()
throws IOException, ReflectiveOperationException {
ServiceTemplate serviceTemplateWithInterfaceDef =
getServiceTemplate(BASE_DIR + ST_WITH_INTERFACE_DEF);
@@ -402,12 +411,11 @@ public class ToscaModelTest {
Optional<? extends InterfaceDefinition> actualInterfaceDefinition =
DataModelUtil.convertObjToInterfaceDefinition(INTERFACE_ID, interfaceObj,
- InterfaceDefinitionType.class);
+ InterfaceDefinitionTemplate.class);
Assert.assertTrue(actualInterfaceDefinition.isPresent());
-
- InterfaceDefinitionType expectedInterfaceDefinitionType = getInterfaceDefinition();
- Assert.assertEquals(expectedInterfaceDefinitionType, actualInterfaceDefinition.get());
+ InterfaceDefinitionTemplate expectedInterfaceDefinitionTemplate = createInterfaceDefinitionTemplate();
+ Assert.assertEquals(expectedInterfaceDefinitionTemplate, actualInterfaceDefinition.get());
}
@Test
@@ -432,28 +440,55 @@ public class ToscaModelTest {
}
}
- private InterfaceType getInterfaceType() {
- OperationDefinition operationDefinition = getOperationDefinition();
+ private InterfaceType createInterfaceType() {
+ OperationDefinition operationDefinition = createOperationDefinition();
InterfaceType interfaceType = new InterfaceType();
interfaceType.setDescription("test interface");
- interfaceType.addOperation("start", operationDefinition);
+ interfaceType.addOperation(OPERATION_START, operationDefinition);
return interfaceType;
}
- private OperationDefinition getOperationDefinition() {
+ private OperationDefinition createOperationDefinition() {
OperationDefinition operationDefinition = new OperationDefinition();
- operationDefinition.setDescription("start operation");
+ operationDefinition.setDescription(OPERATION_DESC);
return operationDefinition;
}
- private InterfaceDefinitionType getInterfaceDefinition() {
- OperationDefinition operationDefinition = getOperationDefinition();
+ private InterfaceDefinitionType createInterfaceDefinitionType() {
+ OperationDefinitionType operationDefinitionType = createOperationDefinitionType();
InterfaceDefinitionType interfaceDefinitionType = new InterfaceDefinitionType();
- interfaceDefinitionType.setType("test interface");
- interfaceDefinitionType.addOperation("start", operationDefinition);
+ interfaceDefinitionType.setType(INTERFACE_TYPE_VALUE);
+ interfaceDefinitionType.addOperation(OPERATION_START, operationDefinitionType);
return interfaceDefinitionType;
}
+ private InterfaceDefinitionTemplate createInterfaceDefinitionTemplate() {
+ OperationDefinitionTemplate operationDefinitionTemplate = createOperationDefinitionTemplate();
+ InterfaceDefinitionTemplate interfaceDefinitionTemplate = new InterfaceDefinitionTemplate();
+ interfaceDefinitionTemplate.addOperation(OPERATION_START, operationDefinitionTemplate);
+ return interfaceDefinitionTemplate;
+ }
+
+ private OperationDefinitionTemplate createOperationDefinitionTemplate() {
+ OperationDefinitionTemplate operationDefinitionTemplate = new OperationDefinitionTemplate();
+ operationDefinitionTemplate.setDescription(OPERATION_DESC);
+ Implementation implementation = new Implementation();
+ implementation.setPrimary(PRIMARY_IMPL);
+ List<String> dependencies = new ArrayList<>();
+ dependencies.add(DEPENDENCY_NAME);
+ implementation.setDependencies(dependencies);
+ operationDefinitionTemplate.setImplementation(implementation);
+ return operationDefinitionTemplate;
+ }
+
+ private OperationDefinitionType createOperationDefinitionType() {
+ OperationDefinitionType operationDefinitionType = new OperationDefinitionType();
+ operationDefinitionType.setDescription(OPERATION_DESC);
+ operationDefinitionType.setImplementation(IMPLEMENTATION_NAME);
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setType(STRING_TYPE);
+ return operationDefinitionType;
+ }
}
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTemplateInterface.yaml b/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTemplateInterface.yaml
index 3f63ee9825..29ce7c9eac 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTemplateInterface.yaml
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTemplateInterface.yaml
@@ -100,9 +100,12 @@ topology_template:
relationship: relationB
interfaces:
inter_1:
- type: test interface
start:
description: start operation
+ implementation:
+ primary: myImpl.yaml
+ dependencies:
+ - script1.sh
substitution_mappings:
node_type: myNodeType.node
capabilities:
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTypeInterface.yaml b/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTypeInterface.yaml
new file mode 100644
index 0000000000..4cbb5163e9
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/mock/model/serviceTemplateWithNodeTypeInterface.yaml
@@ -0,0 +1,117 @@
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+metadata:
+ template_name: Test
+ template_author: OPENECOMP
+ template_version: 1.0.0
+description: testing desc tosca service template
+imports:
+- myfile1:
+ file: path1/path2/file1.yaml
+- myfile2:
+ file: path1/path2/file2.yaml
+artifact_types:
+ one_artifact:
+ mime_type: application/java-archive
+ file_ext:
+ - yaml
+ - xml
+interface_types:
+ inter_1:
+ description: test interface
+ start:
+ description: start operation
+node_types:
+ compute_node_type:
+ derived_from: tosca.nodes.Root
+ version: 1.0.0
+ description: tosca compute test
+ properties:
+ cpu_num:
+ type: integer
+ description: Number of CPUs requested for a software node instance
+ required: true
+ default: 1
+ status: SUPPORTED
+ constraints:
+ - greater_or_equal: 5.0
+ - equal: 5
+ - greater_than: 6.02
+ - in_range:
+ - 0
+ - UNBOUNDED
+ attributes:
+ attDef1:
+ type: string
+ default: hi
+ status: SUPPORTED
+ requirements:
+ - re1:
+ capability: tosca.cap1
+ occurrences:
+ - 5
+ - 1
+ capabilities:
+ cap1:
+ type: tosca.cap
+ valid_source_types:
+ - node1
+ - node2
+ occurrences:
+ - 1
+ - UNBOUNDED
+ interfaces:
+ inter_1:
+ type: tosca.interfaces.node.lifecycle.Standard
+ start:
+ description: start operation
+ implementation: startWorkFlow.json
+topology_template:
+ description: topologi template descroption
+ inputs:
+ inParam1:
+ type: string
+ description: desc
+ required: false
+ default: my default val
+ constraints:
+ - greater_than: 6
+ - greater_or_equal: 9
+ entry_schema:
+ type: tosca.myType
+ node_templates:
+ firstNodeTemplate:
+ type: nodeTypeRef
+ directives:
+ - selectable
+ - substitutable
+ properties:
+ prop2: '{ get_input: my_mysql_rootpw }'
+ prop1: abcd
+ attributes:
+ att2: '{ get_input: my_mysql_rootpw }'
+ att1: att1Val
+ requirements:
+ - req1:
+ capability: capA
+ node: nodeA
+ relationship: relationB
+ node_filter:
+ properties:
+ propName1:
+ - greater_or_equal: 9
+ propName2:
+ - min_length: 1
+ - max_length: 2
+ occurrences:
+ - 1
+ - 2
+ - req2:
+ capability: capA
+ node: nodeA
+ relationship: relationB
+ substitution_mappings:
+ node_type: myNodeType.node
+ capabilities:
+ database_endpoint:
+ - database
+ - database_endpoint