0a78c54de316eed758d0a2654b2eec8df000244e
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021-2022 Nordix Foundation.
4  * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.clamp.acm.runtime.commissioning;
23
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.stream.Collectors;
30 import javax.ws.rs.core.Response.Status;
31 import org.apache.commons.collections4.CollectionUtils;
32 import org.apache.commons.collections4.MapUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
35 import org.onap.policy.clamp.models.acm.concepts.Participant;
36 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
37 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
38 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
39 import org.onap.policy.clamp.models.acm.persistence.provider.ServiceTemplateProvider;
40 import org.onap.policy.common.utils.coder.Coder;
41 import org.onap.policy.common.utils.coder.CoderException;
42 import org.onap.policy.common.utils.coder.StandardCoder;
43 import org.onap.policy.models.base.PfModelException;
44 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter;
49 import org.springframework.stereotype.Service;
50 import org.springframework.transaction.annotation.Transactional;
51
52 /**
53  * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
54  * database to the callers.
55  */
56 @Service
57 @Transactional
58 public class CommissioningProvider {
59     public static final String AUTOMATION_COMPOSITION_NODE_TYPE = "org.onap.policy.clamp.acm.AutomationComposition";
60     private static final String HYPHEN = "-";
61
62     private final ServiceTemplateProvider serviceTemplateProvider;
63     private final AutomationCompositionProvider acProvider;
64     private static final Coder CODER = new StandardCoder();
65     private final ParticipantProvider participantProvider;
66     private final SupervisionHandler supervisionHandler;
67
68     /**
69      * Create a commissioning provider.
70      *
71      * @param serviceTemplateProvider the ServiceTemplate Provider
72      * @param acProvider the AutomationComposition Provider
73      * @param supervisionHandler the Supervision Handler
74      * @param participantProvider the Participant Provider
75      */
76     public CommissioningProvider(ServiceTemplateProvider serviceTemplateProvider,
77             AutomationCompositionProvider acProvider, SupervisionHandler supervisionHandler,
78             ParticipantProvider participantProvider) {
79         this.serviceTemplateProvider = serviceTemplateProvider;
80         this.acProvider = acProvider;
81         this.supervisionHandler = supervisionHandler;
82         this.participantProvider = participantProvider;
83     }
84
85     /**
86      * Create automation compositions from a service template.
87      *
88      * @param serviceTemplate the service template
89      * @return the result of the commissioning operation
90      * @throws PfModelException on creation errors
91      */
92     public CommissioningResponse createAutomationCompositionDefinitions(ToscaServiceTemplate serviceTemplate)
93             throws PfModelException {
94
95         if (verifyIfInstancePropertiesExists()) {
96             throw new PfModelException(Status.BAD_REQUEST,
97                     "Delete instances, to commission automation composition definitions");
98         }
99         serviceTemplate = serviceTemplateProvider.createServiceTemplate(serviceTemplate);
100         List<Participant> participantList = participantProvider.getParticipants();
101         if (!participantList.isEmpty()) {
102             supervisionHandler.handleSendCommissionMessage(serviceTemplate.getName(), serviceTemplate.getVersion());
103         }
104         var response = new CommissioningResponse();
105         // @formatter:off
106         response.setAffectedAutomationCompositionDefinitions(
107             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
108                 .values()
109                 .stream()
110                 .map(template -> template.getKey().asIdentifier())
111                 .collect(Collectors.toList()));
112         // @formatter:on
113
114         return response;
115     }
116
117     /**
118      * Delete the automation composition definition with the given name and version.
119      *
120      * @param name the name of the automation composition definition to delete
121      * @param version the version of the automation composition to delete
122      * @return the result of the deletion
123      * @throws PfModelException on deletion errors
124      */
125     public CommissioningResponse deleteAutomationCompositionDefinition(String name, String version)
126             throws PfModelException {
127
128         if (verifyIfInstancePropertiesExists()) {
129             throw new PfModelException(Status.BAD_REQUEST,
130                     "Delete instances, to commission automation composition definitions");
131         }
132         List<Participant> participantList = participantProvider.getParticipants();
133         if (!participantList.isEmpty()) {
134             supervisionHandler.handleSendDeCommissionMessage();
135         }
136         serviceTemplateProvider.deleteServiceTemplate(name, version);
137         var response = new CommissioningResponse();
138         response.setAffectedAutomationCompositionDefinitions(List.of(new ToscaConceptIdentifier(name, version)));
139
140         return response;
141     }
142
143     /**
144      * Get automation composition node templates.
145      *
146      * @param acName the name of the automation composition, null for all
147      * @param acVersion the version of the automation composition, null for all
148      * @return list of automation composition node templates
149      * @throws PfModelException on errors getting automation composition definitions
150      */
151     @Transactional(readOnly = true)
152     public List<ToscaNodeTemplate> getAutomationCompositionDefinitions(String acName, String acVersion)
153             throws PfModelException {
154
155         // @formatter:off
156         ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
157                 .<ToscaNodeTemplate>builder()
158                 .name(acName)
159                 .version(acVersion)
160                 .type(AUTOMATION_COMPOSITION_NODE_TYPE)
161                 .build();
162         // @formatter:on
163
164         return acProvider.getFilteredNodeTemplates(nodeTemplateFilter);
165     }
166
167     /**
168      * Get the automation composition elements from a automation composition node template.
169      *
170      * @param automationCompositionNodeTemplate the automation composition node template
171      * @return a list of the automation composition element node templates in a automation composition node template
172      * @throws PfModelException on errors get automation composition element node templates
173      */
174     @Transactional(readOnly = true)
175     public List<ToscaNodeTemplate> getAutomationCompositionElementDefinitions(
176             ToscaNodeTemplate automationCompositionNodeTemplate) throws PfModelException {
177         if (!AUTOMATION_COMPOSITION_NODE_TYPE.equals(automationCompositionNodeTemplate.getType())) {
178             return Collections.emptyList();
179         }
180
181         if (MapUtils.isEmpty(automationCompositionNodeTemplate.getProperties())) {
182             return Collections.emptyList();
183         }
184
185         @SuppressWarnings("unchecked")
186         List<Map<String, String>> automationCompositionElements =
187                 (List<Map<String, String>>) automationCompositionNodeTemplate.getProperties().get("elements");
188
189         if (CollectionUtils.isEmpty(automationCompositionElements)) {
190             return Collections.emptyList();
191         }
192
193         List<ToscaNodeTemplate> automationCompositionElementList = new ArrayList<>();
194         // @formatter:off
195         automationCompositionElementList.addAll(
196                 automationCompositionElements
197                         .stream()
198                         .map(elementMap -> acProvider.getNodeTemplates(elementMap.get("name"),
199                                 elementMap.get("version")))
200                         .flatMap(List::stream)
201                         .collect(Collectors.toList())
202         );
203         // @formatter:on
204
205         return automationCompositionElementList;
206     }
207
208     /**
209      * Get node templates with common properties added.
210      *
211      * @param name the name of the definition to use, null for all definitions
212      * @param version the version of the definition to use, null for all definitions
213      * @param instanceName automation composition name
214      * @param common boolean indicating common or instance properties to be used
215      * @return the nodes templates with common or instance properties
216      * @throws PfModelException on errors getting common or instance properties from node_templates
217      */
218     @Transactional(readOnly = true)
219     public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(
220             final String name, final String version, final String instanceName, final boolean common)
221             throws PfModelException {
222
223         if (common && verifyIfInstancePropertiesExists()) {
224             throw new PfModelException(Status.BAD_REQUEST,
225                     "Cannot create or edit common properties, delete all the instantiations first");
226         }
227
228         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
229
230         if (serviceTemplateList.isEmpty()) {
231             throw new PfModelException(Status.BAD_REQUEST,
232                     "Tosca service template has to be commissioned before saving instance properties");
233         }
234
235         var commonOrInstanceNodeTypeProps =
236                 serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
237
238         var serviceTemplates = new ToscaServiceTemplates();
239         serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList, instanceName));
240
241         return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
242                 serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
243                 commonOrInstanceNodeTypeProps);
244     }
245
246     /**
247      * Get the requested automation composition definitions.
248      *
249      * @param name the name of the definition to get, null for all definitions
250      * @param version the version of the definition to get, null for all definitions
251      * @return the automation composition definitions
252      * @throws PfModelException on errors getting automation composition definitions
253      */
254     @Transactional(readOnly = true)
255     public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
256         return serviceTemplateProvider.getToscaServiceTemplate(name, version);
257     }
258
259     /**
260      * Get All the requested automation composition definitions.
261      *
262      * @return the automation composition definitions
263      * @throws PfModelException on errors getting automation composition definitions
264      */
265     @Transactional(readOnly = true)
266     public List<ToscaServiceTemplate> getAllToscaServiceTemplate() throws PfModelException {
267         return serviceTemplateProvider.getAllServiceTemplates();
268     }
269
270     /**
271      * Get the tosca service template with only required sections.
272      *
273      * @param name the name of the template to get, null for all definitions
274      * @param version the version of the template to get, null for all definitions
275      * @param instanceName automation composition name
276      * @return the tosca service template
277      * @throws PfModelException on errors getting tosca service template
278      */
279     @Transactional(readOnly = true)
280     public String getToscaServiceTemplateReduced(
281             final String name, final String version, final String instanceName)
282             throws PfModelException {
283
284         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
285
286         List<ToscaServiceTemplate> filteredServiceTemplateList =
287                 filterToscaNodeTemplateInstance(serviceTemplateList, instanceName);
288
289         if (filteredServiceTemplateList.isEmpty()) {
290             throw new PfModelException(Status.BAD_REQUEST, "Invalid Service Template");
291         }
292
293         ToscaServiceTemplate fullTemplate = filteredServiceTemplateList.get(0);
294
295         var template = new HashMap<String, Object>();
296         template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
297         template.put("data_types", fullTemplate.getDataTypes());
298         template.put("policy_types", fullTemplate.getPolicyTypes());
299         template.put("node_types", fullTemplate.getNodeTypes());
300         template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
301
302         try {
303             return CODER.encode(template);
304
305         } catch (CoderException e) {
306             throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
307         }
308     }
309
310     /**
311      * Filters service templates if is not an instantiation type.
312      *
313      * @param serviceTemplates tosca service template
314      * @param instanceName     automation composition name
315      * @return List of tosca service templates
316      */
317     private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(
318             List<ToscaServiceTemplate> serviceTemplates, String instanceName) {
319
320         List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
321
322         serviceTemplates.forEach(serviceTemplate -> {
323
324             Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
325
326             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
327                 if (StringUtils.isNotEmpty(instanceName) && nodeTemplate.getName().contains(instanceName)) {
328                     toscaNodeTemplates.put(key, nodeTemplate);
329                 } else if (!nodeTemplate.getName().contains(HYPHEN)) {
330                     toscaNodeTemplates.put(key, nodeTemplate);
331                 }
332             });
333
334             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
335             serviceTemplate.getToscaTopologyTemplate().setNodeTemplates(toscaNodeTemplates);
336
337             toscaServiceTemplates.add(serviceTemplate);
338         });
339
340         return toscaServiceTemplates;
341     }
342
343     /**
344      * Validates to see if there is any instance properties saved.
345      *
346      * @return true if exists instance properties
347      */
348     private boolean verifyIfInstancePropertiesExists() {
349         return acProvider.getAllNodeTemplates().stream()
350                 .anyMatch(nodeTemplate -> nodeTemplate.getKey().getName().contains(HYPHEN));
351
352     }
353 }