3b716da1ca22552d01acdec5a3e29f49fd647327
[sdc.git] /
1 /*
2  * Copyright © 2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  * ================================================================================
16  * Modifications copyright (c) 2019 Nokia
17  * ================================================================================
18  */
19
20 package org.openecomp.sdc.healing.healers;
21
22 import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element;
23 import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo;
24 import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement;
25 import com.amdocs.zusammen.datatypes.Id;
26 import com.amdocs.zusammen.datatypes.SessionContext;
27 import com.amdocs.zusammen.datatypes.item.Action;
28 import com.amdocs.zusammen.datatypes.item.ElementContext;
29 import com.amdocs.zusammen.utils.fileutils.FileUtils;
30 import org.apache.commons.io.IOUtils;
31 import org.apache.commons.lang.ArrayUtils;
32 import org.apache.commons.lang.StringUtils;
33 import org.openecomp.core.utilities.file.FileContentHandler;
34 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
35 import org.openecomp.core.zusammen.api.ZusammenAdaptor;
36 import org.openecomp.core.zusammen.api.ZusammenAdaptorFactory;
37 import org.openecomp.sdc.common.errors.CoreException;
38 import org.openecomp.sdc.common.errors.ErrorCode;
39 import org.openecomp.sdc.common.utils.CommonUtil;
40 import org.openecomp.sdc.datatypes.error.ErrorLevel;
41 import org.openecomp.sdc.datatypes.model.ElementType;
42 import org.openecomp.sdc.healing.interfaces.Healer;
43 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao;
44 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDaoFactory;
45 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OnboardingMethod;
46 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData;
47 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateEntity;
48 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
49 import org.openecomp.sdc.vendorsoftwareproduct.factory.CandidateServiceFactory;
50 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.CandidateService;
51 import org.openecomp.sdc.vendorsoftwareproduct.services.utils.CandidateEntityBuilder;
52 import org.openecomp.sdc.versioning.dao.types.Version;
53
54 import java.io.ByteArrayInputStream;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.nio.ByteBuffer;
58 import java.util.Collection;
59 import java.util.Objects;
60
61 import static org.openecomp.core.zusammen.api.ZusammenUtil.*;
62
63 public class NetworkPackageHealer implements Healer {
64
65     private static final byte[] EMPTY_DATA_BYTES = "{}".getBytes();
66     private static final String MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_ERROR =
67             "Vsp with invalid structure: does not contain element OrchestrationTemplateCandidate";
68     private static final String MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_CONTENT_ERROR =
69             "Vsp with invalid structure: does not contain element OrchestrationTemplateCandidateContent"
70                     + " under OrchestrationTemplateCandidate";
71
72     private static final String MISSING_VSP_MODEL_ERROR =
73             "Vsp with invalid structure: does not contain element VspModel";
74     private static final String MISSING_ORCHESTRATION_TEMPLATE_ERROR =
75             "Vsp with invalid structure: does not contain element OrchestrationTemplate" + " under VspModel element";
76     private static final String MISSING_ORCHESTRATION_TEMPLATE_VALIDATE_DATA_ERROR =
77             "Vsp with invalid structure: does not contain element OrchestrationTemplateValidationData"
78                     + " under OrchestrationTemplate element";
79
80     private final VendorSoftwareProductInfoDao vspInfoDao;
81     private final ZusammenAdaptor zusammenAdaptor;
82     private final CandidateEntityBuilder candidateEntityBuilder;
83
84     public NetworkPackageHealer() {
85         this(VendorSoftwareProductInfoDaoFactory.getInstance().createInterface(),
86                 ZusammenAdaptorFactory.getInstance().createInterface(),
87                 CandidateServiceFactory.getInstance().createInterface());
88     }
89
90     private NetworkPackageHealer(VendorSoftwareProductInfoDao vspInfoDao, ZusammenAdaptor zusammenAdaptor,
91             CandidateService candidateService) {
92         this(vspInfoDao, zusammenAdaptor, new CandidateEntityBuilder(candidateService));
93     }
94
95     NetworkPackageHealer(VendorSoftwareProductInfoDao vspInfoDao, ZusammenAdaptor zusammenAdaptor,
96             CandidateEntityBuilder candidateEntityBuilder) {
97         this.vspInfoDao = vspInfoDao;
98         this.zusammenAdaptor = zusammenAdaptor;
99         this.candidateEntityBuilder = candidateEntityBuilder;
100     }
101
102     @Override
103     public boolean isHealingNeeded(String itemId, Version version) {
104         return OnboardingMethod.NetworkPackage.name()
105                        .equals(vspInfoDao.get(new VspDetails(itemId, version)).getOnboardingMethod())
106                        && isVspMissingAddedElements(itemId, version);
107     }
108
109     @Override
110     public void heal(String itemId, Version version) throws Exception {
111         SessionContext context = createSessionContext();
112         ElementContext elementContext = new ElementContext(itemId, version.getId());
113
114         Element candidateElement = getElement(context, elementContext, null, ElementType.OrchestrationTemplateCandidate,
115                 MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_ERROR);
116
117         Collection<Element> candidateSubs =
118                 zusammenAdaptor.listElementData(context, elementContext, candidateElement.getElementId());
119
120         Id candidateValidationElementId =
121                 creatIfAbsentCandidateValidationElementId(candidateSubs, context, elementContext, candidateElement);
122
123         Element orchestrationTemplateElement = getOrchestrationTemplateElement(context, elementContext);
124
125         Collection<Element> orchestrationTemplateSubs =
126                 zusammenAdaptor.listElementData(context, elementContext, orchestrationTemplateElement.getElementId());
127
128         Id structureElementId = createIfAbsentStructureElementId(orchestrationTemplateSubs, context, elementContext,
129                 orchestrationTemplateElement);
130
131         Element orchestrationTemplateValidationElement =
132                 getOrchestrationTemplateValidationElement(orchestrationTemplateSubs);
133
134         OrchestrationTemplateEntity orchestrationTemplateEntity =
135                 getOrchestrationTemplateEntity(orchestrationTemplateElement, orchestrationTemplateValidationElement);
136
137         if (StringUtils.isEmpty(orchestrationTemplateEntity.getFileSuffix())) {
138             return;
139         }
140
141         Element candidateContentElement = getCandidateContentElement(candidateSubs);
142
143         VspDetails vspDetails = vspInfoDao.get(new VspDetails(itemId, version));
144         if (isEqual(orchestrationTemplateEntity, getCandidateData(candidateElement, candidateContentElement))) {
145
146             if (isProcessedEntityValid(orchestrationTemplateEntity)) {
147                 emptyStructureElementAndSub(context, elementContext, candidateElement.getElementId(),
148                         ElementType.OrchestrationTemplateCandidate, candidateContentElement.getElementId(),
149                         ElementType.OrchestrationTemplateCandidateContent);
150
151                 populateOrchestrationTemplateStructure(orchestrationTemplateElement.getData(), structureElementId,
152                         vspDetails, context, elementContext);
153             } else {
154                 emptyStructureElementAndSub(context, elementContext, orchestrationTemplateElement.getElementId(),
155                         ElementType.OrchestrationTemplate, orchestrationTemplateValidationElement.getElementId(),
156                         ElementType.OrchestrationTemplateValidationData);
157
158                 populateCandidateValidationData(context, elementContext, candidateValidationElementId,
159                         orchestrationTemplateEntity.getValidationData());
160             }
161         } else {
162             populateOrchestrationTemplateStructure(orchestrationTemplateElement.getData(), structureElementId,
163                     vspDetails, context, elementContext);
164         }
165     }
166
167     private boolean isVspMissingAddedElements(String vspId, Version version) {
168         SessionContext context = createSessionContext();
169         ElementContext elementContext = new ElementContext(vspId, version.getId());
170
171         return zusammenAdaptor.listElementsByName(context, elementContext, null,
172                 ElementType.OrchestrationTemplateCandidate.name()).stream().noneMatch(
173                 candidateSub -> ElementType.OrchestrationTemplateCandidateValidationData.name()
174                                         .equals(candidateSub.getInfo().getName()));
175     }
176
177     private boolean isEqual(OrchestrationTemplateEntity orchestrationTemplateEntity,
178             OrchestrationTemplateCandidateData orchestrationTemplateCandidateData) {
179         return orchestrationTemplateEntity.getFileName().equals(orchestrationTemplateCandidateData.getFileName())
180                        && orchestrationTemplateEntity.getFileSuffix()
181                                   .equals(orchestrationTemplateCandidateData.getFileSuffix());
182     }
183
184     private boolean isProcessedEntityValid(OrchestrationTemplateEntity orchestrationTemplateEntity) {
185         return !orchestrationTemplateEntity.getValidationData().contains(ErrorLevel.ERROR.name());
186     }
187
188     private void populateCandidateValidationData(SessionContext context, ElementContext elementContext,
189             Id candidateValidationElementId, String validationData) {
190         ZusammenElement candidateValidationElement =
191                 buildStructuralElement(ElementType.OrchestrationTemplateCandidateValidationData, Action.UPDATE);
192         candidateValidationElement.setElementId(candidateValidationElementId);
193         candidateValidationElement.setData(new ByteArrayInputStream(validationData.getBytes()));
194
195         zusammenAdaptor.saveElement(context, elementContext, candidateValidationElement,
196                 "Healed Orchestration Template Candidate Validation data");
197     }
198
199     private void populateOrchestrationTemplateStructure(InputStream processedFile, Id structureElementId,
200             VspDetails vspDetails, SessionContext context, ElementContext elementContext) throws Exception {
201         byte[] byteData = FileUtils.toByteArray(processedFile);
202         FileContentHandler contentMap = CommonUtil.validateAndUploadFileContent(OnboardingTypesEnum.ZIP, byteData);
203         OrchestrationTemplateCandidateData orchestrationTemplateEntityData =
204                 candidateEntityBuilder
205                         .buildCandidateEntityFromZip(vspDetails, byteData, contentMap, null);
206         String fileDataStructure = orchestrationTemplateEntityData.getFilesDataStructure();
207
208         ZusammenElement orchestrationTemplateStructure =
209                 buildStructuralElement(ElementType.OrchestrationTemplateStructure, Action.UPDATE);
210         orchestrationTemplateStructure.setElementId(structureElementId);
211         orchestrationTemplateStructure.setData(new ByteArrayInputStream(fileDataStructure.getBytes()));
212
213         zusammenAdaptor.saveElement(context, elementContext, orchestrationTemplateStructure,
214                 "Healed Orchestration Template Structure");
215     }
216
217     private Element getOrchestrationTemplateElement(SessionContext context, ElementContext elementContext) {
218         ElementInfo vspModelElement =
219                 zusammenAdaptor.getElementInfoByName(context, elementContext, null, ElementType.VspModel.name())
220                         .orElseThrow(() -> new CoreException(
221                                 new ErrorCode.ErrorCodeBuilder().withMessage(MISSING_VSP_MODEL_ERROR).build()));
222
223         return getElement(context, elementContext, vspModelElement.getId(), ElementType.OrchestrationTemplate,
224                 MISSING_ORCHESTRATION_TEMPLATE_ERROR);
225     }
226
227     private Element getOrchestrationTemplateValidationElement(Collection<Element> orchestrationTemplateSubs) {
228         return orchestrationTemplateSubs.stream()
229                        .filter(orchestrationTemplateSub -> ElementType.OrchestrationTemplateValidationData.name()
230                                                                    .equals(orchestrationTemplateSub.getInfo()
231                                                                                    .getName())).findFirst().orElseThrow(
232                         () -> new CoreException(new ErrorCode.ErrorCodeBuilder()
233                                                         .withMessage(MISSING_ORCHESTRATION_TEMPLATE_VALIDATE_DATA_ERROR)
234                                                         .build()));
235
236     }
237
238     private Element getCandidateContentElement(Collection<Element> candidateSubs) {
239         return candidateSubs.stream().filter(candidateSub -> ElementType.OrchestrationTemplateCandidateContent.name()
240                                                                      .equals(candidateSub.getInfo().getName()))
241                        .findFirst().orElseThrow(() -> new CoreException(new ErrorCode.ErrorCodeBuilder().withMessage(
242                         MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_CONTENT_ERROR).build()));
243     }
244
245     private Id createIfAbsentStructureElementId(Collection<Element> orchestrationTemplateSubs, SessionContext context,
246             ElementContext elementContext, Element orchestrationTemplateElement) {
247         return orchestrationTemplateSubs.stream()
248                        .filter(orchestrationTemplateSub -> ElementType.OrchestrationTemplateStructure.name()
249                                                                    .equals(orchestrationTemplateSub.getInfo()
250                                                                                    .getName())).findFirst()
251                        .map(Element::getElementId).orElse(addStructureSubElement(context, elementContext,
252                         ElementType.OrchestrationTemplateStructure, orchestrationTemplateElement.getElementId()));
253     }
254
255     private Id creatIfAbsentCandidateValidationElementId(Collection<Element> candidateSubs, SessionContext context,
256             ElementContext elementContext, Element candidateElement) {
257         return candidateSubs.stream()
258                        .filter(candidateSub -> ElementType.OrchestrationTemplateCandidateValidationData.name()
259                                                        .equals(candidateSub.getInfo().getName())).findFirst()
260                        .map(Element::getElementId).orElse(addStructureSubElement(context, elementContext,
261                         ElementType.OrchestrationTemplateCandidateValidationData, candidateElement.getElementId()));
262     }
263
264     private Element getElement(SessionContext context, ElementContext elementContext, Id parentElementId,
265             ElementType elementType, String errorMessage) {
266         return zusammenAdaptor.getElementByName(context, elementContext, parentElementId, elementType.name())
267                        .orElseThrow(() -> new CoreException(
268                                new ErrorCode.ErrorCodeBuilder().withMessage(errorMessage).build()));
269     }
270
271     private OrchestrationTemplateEntity getOrchestrationTemplateEntity(Element orchestrationTemplateElement,
272             Element validationDataElement) {
273         OrchestrationTemplateEntity orchestrationTemplateEntity = new OrchestrationTemplateEntity();
274
275         if (isNotEmpty(orchestrationTemplateElement.getData())) {
276             orchestrationTemplateEntity
277                     .setContentData(ByteBuffer.wrap(FileUtils.toByteArray(orchestrationTemplateElement.getData())));
278         }
279         orchestrationTemplateEntity
280                 .setFileSuffix(validationDataElement.getInfo().getProperty(InfoPropertyName.FILE_SUFFIX.getVal()));
281         orchestrationTemplateEntity
282                 .setFileName(validationDataElement.getInfo().getProperty(InfoPropertyName.FILE_NAME.getVal()));
283         if (isNotEmpty(validationDataElement.getData())) {
284             orchestrationTemplateEntity
285                     .setValidationData(new String(FileUtils.toByteArray(validationDataElement.getData())));
286         }
287         return orchestrationTemplateEntity;
288     }
289
290     private OrchestrationTemplateCandidateData getCandidateData(Element candidateElement,
291             Element candidateContentElement) {
292         OrchestrationTemplateCandidateData candidateData = new OrchestrationTemplateCandidateData();
293         candidateData.setFilesDataStructure(new String(FileUtils.toByteArray(candidateElement.getData())));
294         candidateData.setContentData(ByteBuffer.wrap(FileUtils.toByteArray(candidateContentElement.getData())));
295         candidateData
296                 .setFileSuffix(candidateContentElement.getInfo().getProperty(InfoPropertyName.FILE_SUFFIX.getVal()));
297         candidateData.setFileName(candidateContentElement.getInfo().getProperty(InfoPropertyName.FILE_NAME.getVal()));
298         return candidateData;
299     }
300
301     private Id addStructureSubElement(SessionContext context, ElementContext elementContext, ElementType elementType,
302             Id parentElementId) {
303         ZusammenElement newElement = buildStructuralElement(elementType, Action.CREATE);
304
305         ZusammenElement parentElement = buildElement(parentElementId, Action.IGNORE);
306         parentElement.addSubElement(newElement);
307
308         return zusammenAdaptor.saveElement(context, elementContext, parentElement,
309                 String.format("Add element %s under element id %s", elementType.name(), parentElementId))
310                        .getSubElements().iterator().next().getElementId();
311     }
312
313     private void emptyStructureElementAndSub(SessionContext context, ElementContext elementContext, Id elementId,
314             ElementType elementType, Id subElementId, ElementType subElementType) {
315         ZusammenElement subElement = buildStructuralElement(subElementType, Action.UPDATE);
316         subElement.setElementId(subElementId);
317         subElement.setData(new ByteArrayInputStream(EMPTY_DATA_BYTES));
318
319         ZusammenElement element = buildStructuralElement(elementType, Action.UPDATE);
320         element.setElementId(elementId);
321         element.setData(new ByteArrayInputStream(EMPTY_DATA_BYTES));
322         element.addSubElement(subElement);
323
324         zusammenAdaptor.saveElement(context, elementContext, element,
325                 String.format("Empty element %s and its sub element %s", elementType.name(), subElementType.name()));
326     }
327
328     public enum InfoPropertyName {
329         FILE_SUFFIX("fileSuffix"), FILE_NAME("fileName");
330
331         private String val;
332
333         InfoPropertyName(String val) {
334             this.val = val;
335         }
336
337         private String getVal() {
338             return val;
339         }
340     }
341
342     private boolean isNotEmpty(InputStream elementData) {
343         byte[] byteElementData;
344         if (Objects.isNull(elementData)) {
345             return false;
346         }
347         try {
348             byteElementData = IOUtils.toByteArray(elementData);
349         } catch (IOException e) {
350             return true;
351         }
352         return !ArrayUtils.isEmpty(byteElementData);
353     }
354 }