b85ffab733542e89cb9e9da213a84dbc4cb84363
[aai/babel.git] / src / main / java / org / onap / aai / babel / parser / ArtifactGeneratorToscaParser.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 European Software Marketing Ltd.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.aai.babel.parser;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32 import java.util.stream.Collectors;
33 import org.onap.aai.babel.logging.ApplicationMsgs;
34 import org.onap.aai.babel.logging.LogHelper;
35 import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil;
36 import org.onap.aai.babel.xml.generator.model.AllotedResource;
37 import org.onap.aai.babel.xml.generator.model.InstanceGroup;
38 import org.onap.aai.babel.xml.generator.model.L3NetworkWidget;
39 import org.onap.aai.babel.xml.generator.model.Model;
40 import org.onap.aai.babel.xml.generator.model.ProvidingService;
41 import org.onap.aai.babel.xml.generator.model.Resource;
42 import org.onap.aai.babel.xml.generator.model.Service;
43 import org.onap.aai.babel.xml.generator.model.TunnelXconnectWidget;
44 import org.onap.aai.babel.xml.generator.model.VfModule;
45 import org.onap.aai.babel.xml.generator.model.Widget;
46 import org.onap.aai.babel.xml.generator.types.ModelType;
47 import org.onap.aai.cl.api.Logger;
48 import org.onap.sdc.tosca.parser.api.ISdcCsarHelper;
49 import org.onap.sdc.toscaparser.api.Group;
50 import org.onap.sdc.toscaparser.api.NodeTemplate;
51 import org.onap.sdc.toscaparser.api.Property;
52 import org.onap.sdc.toscaparser.api.elements.Metadata;
53
54 public class ArtifactGeneratorToscaParser {
55
56     private static Logger log = LogHelper.INSTANCE;
57
58     public static final String PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE = "artifactgenerator.config";
59     public static final String PROPERTY_GROUP_FILTERS_CONFIG_FILE = "groupfilter.config";
60
61     private static final String GENERATOR_AAI_CONFIGFILE_NOT_FOUND =
62             "Cannot generate artifacts. Artifact Generator Configuration file not found at %s";
63     private static final String GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND =
64             "Cannot generate artifacts. System property %s not configured";
65     private static final String GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING =
66             "Cannot generate artifacts. Providing Service Metadata is missing for allotted resource %s";
67     private static final String GENERATOR_AAI_PROVIDING_SERVICE_MISSING =
68             "Cannot generate artifacts. Providing Service is missing for allotted resource %s";
69
70     // Metadata properties
71     private static final String CATEGORY = "category";
72     private static final String ALLOTTED_RESOURCE = "Allotted Resource";
73     private static final String SUBCATEGORY = "subcategory";
74     private static final String TUNNEL_XCONNECT = "Tunnel XConnect";
75
76     private static final String VERSION = "version";
77
78     private ISdcCsarHelper csarHelper;
79
80     /**
81      * Constructs using csarHelper
82      *
83      * @param csarHelper The csar helper
84      */
85     public ArtifactGeneratorToscaParser(ISdcCsarHelper csarHelper) {
86         this.csarHelper = csarHelper;
87     }
88
89     /**
90      * Returns the artifact description
91      *
92      * @param model the artifact model
93      * @return the artifact model's description
94      */
95     public static String getArtifactDescription(Model model) {
96         String artifactDesc = model.getModelDescription();
97         if (model.getModelType().equals(ModelType.SERVICE)) {
98             artifactDesc = "AAI Service Model";
99         } else if (model.getModelType().equals(ModelType.RESOURCE)) {
100             artifactDesc = "AAI Resource Model";
101         }
102         return artifactDesc;
103     }
104
105     /**
106      * Initialises the widget configuration.
107      *
108      * @throws IOException
109      */
110     public static void initWidgetConfiguration() throws IOException {
111         log.debug("Getting Widget Configuration");
112         String configLocation = System.getProperty(PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE);
113         if (configLocation != null) {
114             File file = new File(configLocation);
115             if (file.exists()) {
116                 Properties properties = new Properties();
117                 properties.load(new FileInputStream(file));
118                 WidgetConfigurationUtil.setConfig(properties);
119             } else {
120                 throw new IllegalArgumentException(String.format(GENERATOR_AAI_CONFIGFILE_NOT_FOUND, configLocation));
121             }
122         } else {
123             throw new IllegalArgumentException(
124                     String.format(GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND, PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE));
125         }
126     }
127
128     /**
129      * Initialises the group filter configuration.
130      *
131      * @throws IOException
132      */
133     public static void initGroupFilterConfiguration() throws IOException {
134         log.debug("Getting Filter Tyoes Configuration");
135         String configLocation = System.getProperty(PROPERTY_GROUP_FILTERS_CONFIG_FILE);
136         if (configLocation != null) {
137             File file = new File(configLocation);
138             if (file.exists()) {
139                 Properties properties = new Properties();
140                 properties.load(new FileInputStream(file));
141                 WidgetConfigurationUtil.setFilterConfig(properties);
142             } else {
143                 throw new IllegalArgumentException(String.format(GENERATOR_AAI_CONFIGFILE_NOT_FOUND, configLocation));
144             }
145         } else {
146             throw new IllegalArgumentException(
147                     String.format(GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND, PROPERTY_GROUP_FILTERS_CONFIG_FILE));
148         }
149     }
150
151     /**
152      * Process the service TOSCA.
153      *
154      * @param service model of the service artifact
155      * @param idTypeStore ID->Type mapping
156      * @param nodeTemplates a list of service nodes
157      *
158      */
159     public void processServiceTosca(Service service, Map<String, String> idTypeStore,
160             List<NodeTemplate> nodeTemplates) {
161         log.debug("Processing (TOSCA) Service object");
162
163         for (NodeTemplate nodeTemplate : nodeTemplates) {
164             if (nodeTemplate.getMetaData() != null) {
165                 addNodeToService(idTypeStore, service, nodeTemplate);
166             } else {
167                 log.warn(ApplicationMsgs.MISSING_SERVICE_METADATA, nodeTemplate.getName());
168             }
169         }
170     }
171
172     /**
173      * Generates a Resource List using input Service Node Templates.
174      *
175      * @param serviceNodes input Service Node Templates
176      * @param idTypeStore ID->Type mapping
177      *
178      * @return the processed resource models
179      */
180     public List<Resource> processResourceToscas(List<NodeTemplate> serviceNodes, Map<String, String> idTypeStore) {
181         List<Resource> resources = new LinkedList<>();
182         for (NodeTemplate serviceNode : serviceNodes) {
183             if (serviceNode.getMetaData() != null) {
184                 resources.addAll(processResourceTosca(idTypeStore, serviceNode,
185                         csarHelper.getNodeTemplateChildren(serviceNode)));
186             } else {
187                 log.warn(ApplicationMsgs.MISSING_SERVICE_METADATA, serviceNode.getName());
188             }
189         }
190         return resources;
191     }
192
193     /**
194      * @param idTypeStore ID->Type mapping
195      * @param serviceNode
196      * @param resourceNodes
197      * @return the processed resource models
198      */
199     private List<Resource> processResourceTosca(Map<String, String> idTypeStore, NodeTemplate serviceNode,
200             List<NodeTemplate> resourceNodes) {
201         List<Resource> resources = new LinkedList<>();
202         String resourceUuId = serviceNode.getMetaData().getValue("UUID");
203         String nodeTypeName = idTypeStore.get(resourceUuId);
204         if (nodeTypeName != null) {
205             Model resourceModel = Model.getModelFor(nodeTypeName, serviceNode.getMetaData().getValue("type"));
206
207             log.debug("Processing resource " + nodeTypeName + ": " + resourceUuId);
208             Map<String, String> serviceMetadata = serviceNode.getMetaData().getAllProperties();
209             resourceModel.populateModelIdentificationInformation(serviceMetadata);
210
211             idTypeStore.remove(resourceModel.getModelNameVersionId());
212             processVfTosca(idTypeStore, resourceModel, resourceNodes);
213
214             if (csarHelper.getServiceVfList() != null) {
215                 processVfModules(resources, resourceModel, serviceNode);
216             }
217
218             if (hasSubCategoryTunnelXConnect(serviceMetadata) && hasAllottedResource(serviceMetadata)) {
219                 resourceModel.addWidget(new TunnelXconnectWidget());
220             }
221
222             resources.addAll(processInstanceGroups(resourceModel, serviceNode));
223             resources.add((Resource) resourceModel);
224         }
225         return resources;
226     }
227
228     /**
229      * Process groups for this service node, according to the defined filter.
230      *
231      * @param resourceModel
232      * @param serviceNode
233      * @return resources for which XML Models should be generated
234      */
235     private List<Resource> processInstanceGroups(Model resourceModel, NodeTemplate serviceNode) {
236         List<Resource> resources = new ArrayList<>();
237         if (csarHelper.getNodeTemplateByName(serviceNode.getName()).getSubMappingToscaTemplate() != null) {
238             List<Group> serviceGroups = csarHelper.getGroupsOfOriginOfNodeTemplate(serviceNode);
239             for (Group group : serviceGroups) {
240                 if (WidgetConfigurationUtil.isSupportedInstanceGroup(group.getType())) {
241                     resources.addAll(processInstanceGroup(resourceModel, group));
242                 }
243             }
244         }
245         return resources;
246     }
247
248     /**
249      * Create an Instance Group Model for the supplied Service Group and relate this to the supplied resource Model.
250      *
251      * @param resourceModel the Resource node template Model
252      * @param group the Service Group
253      * @return the Instance Group and Member resource models
254      */
255     private List<Resource> processInstanceGroup(Model resourceModel, Group group) {
256         List<Resource> resources = new ArrayList<>();
257
258         Resource groupModel = new InstanceGroup();
259         groupModel.populateModelIdentificationInformation(group.getMetadata().getAllProperties());
260         groupModel.populateModelIdentificationInformation(populateStringProperties(group.getProperties()));
261
262         resourceModel.addResource(groupModel);
263         resources.add(groupModel);
264
265         List<NodeTemplate> members = group.getMemberNodes();
266         if (members != null && !members.isEmpty()) {
267             for (NodeTemplate nodeTemplate : members) {
268                 String nodeTypeName = normaliseNodeTypeName(nodeTemplate);
269                 Model memberModel = Model.getModelFor(nodeTypeName, nodeTemplate.getMetaData().getValue("type"));
270                 memberModel.populateModelIdentificationInformation(nodeTemplate.getMetaData().getAllProperties());
271                 if (memberModel instanceof Resource) {
272                     log.debug("Generating grouped Resource " + nodeTypeName);
273                     groupModel.addResource((Resource) memberModel);
274                     resources.add((Resource) memberModel);
275                 } else {
276                     log.debug("Generating grouped Widget " + nodeTypeName);
277                     groupModel.addWidget((Widget) memberModel);
278                 }
279             }
280         }
281
282         return resources;
283     }
284
285     /**
286      * Add the supplied Node Template to the Service, provided that it is a valid Resource or Widget. If the Node
287      * Template is a Resource type, this is also recorded in the supplied nodesById Map.
288      *
289      * @param nodesById a map of Resource node type names, keyed by UUID
290      * @param service the Service to which the Node Template should be added
291      * @param nodeTemplate the Node Template to add (only if this is a Resource or Widget type)
292      */
293     private void addNodeToService(Map<String, String> nodesById, Service service, NodeTemplate nodeTemplate) {
294         String nodeTypeName = normaliseNodeTypeName(nodeTemplate);
295         Model model = Model.getModelFor(nodeTypeName, nodeTemplate.getMetaData().getValue("type"));
296         if (model != null) {
297             if (nodeTemplate.getMetaData() != null) {
298                 model.populateModelIdentificationInformation(nodeTemplate.getMetaData().getAllProperties());
299             }
300
301             if (model instanceof Resource) {
302                 nodesById.put(model.getModelNameVersionId(), nodeTypeName);
303                 service.addResource((Resource) model);
304             } else {
305                 service.addWidget((Widget) model);
306             }
307         }
308     }
309
310     /**
311      * Process TOSCA Group information for VF Modules.
312      *
313      * @param resources
314      * @param model
315      * @param serviceNode
316      */
317     private void processVfModules(List<Resource> resources, Model resourceModel, NodeTemplate serviceNode) {
318         // Get the customisation UUID for each VF node and use it to get its Groups
319         String uuid = csarHelper.getNodeTemplateCustomizationUuid(serviceNode);
320         List<Group> serviceGroups = csarHelper.getVfModulesByVf(uuid);
321
322         // Process each VF Group
323         for (Group serviceGroup : serviceGroups) {
324             Model groupModel = Model.getModelFor(serviceGroup.getType());
325             if (groupModel instanceof VfModule) {
326                 processVfModule(resources, resourceModel, serviceGroup, serviceNode, (VfModule) groupModel);
327             }
328         }
329     }
330
331     private void processVfModule(List<Resource> resources, Model model, Group groupDefinition, NodeTemplate serviceNode,
332             VfModule groupModel) {
333         // Populate group with metadata properties
334         groupModel.populateModelIdentificationInformation(groupDefinition.getMetadata().getAllProperties());
335         // Populate group with non-metadata properties
336         Map<String, Property> groupProperties = groupDefinition.getProperties();
337         Map<String, String> properties = populateStringProperties(groupProperties);
338         groupModel.populateModelIdentificationInformation(properties);
339         processVfModuleGroup(resources, model, groupDefinition, serviceNode, groupModel);
340     }
341
342     private void processVfModuleGroup(List<Resource> resources, Model model, Group groupDefinition,
343             NodeTemplate serviceNode, VfModule groupModel) {
344         // Get names of the members of the service group
345         List<NodeTemplate> members = csarHelper.getMembersOfVfModule(serviceNode, groupDefinition);
346         if (members != null && !members.isEmpty()) {
347             List<String> memberNames = members.stream().map(NodeTemplate::getName).collect(Collectors.toList());
348             groupModel.setMembers(memberNames);
349             for (NodeTemplate member : members) {
350                 processGroupMembers(groupModel, member);
351             }
352         }
353
354         model.addResource(groupModel); // Added group (VfModule) to the (VF) model
355         // Check if we have already encountered the same VfModule across all the artifacts
356         if (!resources.contains(groupModel)) {
357             resources.add(groupModel);
358         }
359     }
360
361     private void processGroupMembers(Model group, NodeTemplate member) {
362         Model resourceNode;
363         // L3-network inside vf-module to be generated as Widget a special handling.
364         if (member.getType().contains("org.openecomp.resource.vl")) {
365             resourceNode = new L3NetworkWidget();
366         } else {
367             resourceNode = Model.getModelFor(member.getType());
368         }
369         if (resourceNode != null && !(resourceNode instanceof Resource)) {
370             Widget widget = (Widget) resourceNode;
371             widget.addKey(member.getName());
372             // Add the widget element encountered to the Group model
373             group.addWidget(widget);
374         }
375     }
376
377     private String normaliseNodeTypeName(NodeTemplate nodeType) {
378         String nodeTypeName = nodeType.getType();
379         Metadata metadata = nodeType.getMetaData();
380         if (metadata != null && hasAllottedResource(metadata.getAllProperties())) {
381             if (nodeType.getType().contains("org.openecomp.resource.vf.")) {
382                 nodeTypeName = "org.openecomp.resource.vf.allottedResource";
383             }
384             if (nodeType.getType().contains("org.openecomp.resource.vfc.")) {
385                 nodeTypeName = "org.openecomp.resource.vfc.AllottedResource";
386             }
387         }
388         return nodeTypeName;
389     }
390
391     private boolean hasAllottedResource(Map<String, String> metadata) {
392         return ALLOTTED_RESOURCE.equals(metadata.get(CATEGORY));
393     }
394
395     private boolean hasSubCategoryTunnelXConnect(Map<String, String> metadata) {
396         return TUNNEL_XCONNECT.equals(metadata.get(SUBCATEGORY));
397     }
398
399     /**
400      * Create a Map of property name against String property value from the input Map
401      *
402      * @param inputMap The input Map
403      * @return Map of property name against String property value
404      */
405     private Map<String, String> populateStringProperties(Map<String, Property> inputMap) {
406         return inputMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
407                 e -> e.getValue().getValue() == null ? "" : e.getValue().getValue().toString()));
408     }
409
410     private void processVfTosca(Map<String, String> idTypeStore, Model resourceModel,
411             List<NodeTemplate> resourceNodes) {
412         boolean foundProvidingService = false;
413
414         for (NodeTemplate resourceNodeTemplate : resourceNodes) {
415             String nodeTypeName = normaliseNodeTypeName(resourceNodeTemplate);
416             Model resourceNode = Model.getModelFor(nodeTypeName);
417             if (resourceNode instanceof ProvidingService) {
418                 foundProvidingService = true;
419                 Map<String, Property> nodeProperties = resourceNodeTemplate.getProperties();
420                 if (nodeProperties.get("providing_service_uuid") == null
421                         || nodeProperties.get("providing_service_invariant_uuid") == null) {
422                     throw new IllegalArgumentException(String.format(GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING,
423                             resourceModel.getModelId()));
424                 }
425                 Map<String, String> properties = populateStringProperties(nodeProperties);
426                 properties.put(VERSION, "1.0");
427                 resourceNode.populateModelIdentificationInformation(properties);
428                 resourceModel.addResource((Resource) resourceNode);
429             } else if (resourceNode instanceof Resource && !(resourceNode.getWidgetType().equals(Widget.Type.L3_NET))) {
430                 idTypeStore.put(resourceNode.getModelNameVersionId(), nodeTypeName);
431                 resourceModel.addResource((Resource) resourceNode);
432             }
433         }
434
435         if (resourceModel instanceof AllotedResource && !foundProvidingService) {
436             throw new IllegalArgumentException(
437                     String.format(GENERATOR_AAI_PROVIDING_SERVICE_MISSING, resourceModel.getModelId()));
438         }
439     }
440
441 }